1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Silergy SY7802 flash LED driver with an I2C interface
4 *
5 * Copyright 2024 André Apitzsch <git@apitzsch.eu>
6 */
7
8 #include <linux/gpio/consumer.h>
9 #include <linux/i2c.h>
10 #include <linux/kernel.h>
11 #include <linux/led-class-flash.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/regmap.h>
15 #include <linux/regulator/consumer.h>
16
17 #define SY7802_MAX_LEDS 2
18 #define SY7802_LED_JOINT 2
19
20 #define SY7802_REG_ENABLE 0x10
21 #define SY7802_REG_TORCH_BRIGHTNESS 0xa0
22 #define SY7802_REG_FLASH_BRIGHTNESS 0xb0
23 #define SY7802_REG_FLASH_DURATION 0xc0
24 #define SY7802_REG_FLAGS 0xd0
25 #define SY7802_REG_CONFIG_1 0xe0
26 #define SY7802_REG_CONFIG_2 0xf0
27 #define SY7802_REG_VIN_MONITOR 0x80
28 #define SY7802_REG_LAST_FLASH 0x81
29 #define SY7802_REG_VLED_MONITOR 0x30
30 #define SY7802_REG_ADC_DELAY 0x31
31 #define SY7802_REG_DEV_ID 0xff
32
33 #define SY7802_MODE_OFF 0
34 #define SY7802_MODE_TORCH 2
35 #define SY7802_MODE_FLASH 3
36 #define SY7802_MODE_MASK GENMASK(1, 0)
37
38 #define SY7802_LEDS_SHIFT 3
39 #define SY7802_LEDS_MASK(_id) (BIT(_id) << SY7802_LEDS_SHIFT)
40 #define SY7802_LEDS_MASK_ALL (SY7802_LEDS_MASK(0) | SY7802_LEDS_MASK(1))
41
42 #define SY7802_TORCH_CURRENT_SHIFT 3
43 #define SY7802_TORCH_CURRENT_MASK(_id) \
44 (GENMASK(2, 0) << (SY7802_TORCH_CURRENT_SHIFT * (_id)))
45 #define SY7802_TORCH_CURRENT_MASK_ALL \
46 (SY7802_TORCH_CURRENT_MASK(0) | SY7802_TORCH_CURRENT_MASK(1))
47
48 #define SY7802_FLASH_CURRENT_SHIFT 4
49 #define SY7802_FLASH_CURRENT_MASK(_id) \
50 (GENMASK(3, 0) << (SY7802_FLASH_CURRENT_SHIFT * (_id)))
51 #define SY7802_FLASH_CURRENT_MASK_ALL \
52 (SY7802_FLASH_CURRENT_MASK(0) | SY7802_FLASH_CURRENT_MASK(1))
53
54 #define SY7802_TIMEOUT_DEFAULT_US 512000U
55 #define SY7802_TIMEOUT_MIN_US 32000U
56 #define SY7802_TIMEOUT_MAX_US 1024000U
57 #define SY7802_TIMEOUT_STEPSIZE_US 32000U
58
59 #define SY7802_TORCH_BRIGHTNESS_MAX 8
60
61 #define SY7802_FLASH_BRIGHTNESS_DEFAULT 14
62 #define SY7802_FLASH_BRIGHTNESS_MIN 0
63 #define SY7802_FLASH_BRIGHTNESS_MAX 15
64 #define SY7802_FLASH_BRIGHTNESS_STEP 1
65
66 #define SY7802_FLAG_TIMEOUT BIT(0)
67 #define SY7802_FLAG_THERMAL_SHUTDOWN BIT(1)
68 #define SY7802_FLAG_LED_FAULT BIT(2)
69 #define SY7802_FLAG_TX1_INTERRUPT BIT(3)
70 #define SY7802_FLAG_TX2_INTERRUPT BIT(4)
71 #define SY7802_FLAG_LED_THERMAL_FAULT BIT(5)
72 #define SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW BIT(6)
73 #define SY7802_FLAG_INPUT_VOLTAGE_LOW BIT(7)
74
75 #define SY7802_CHIP_ID 0x51
76
77 static const struct reg_default sy7802_regmap_defs[] = {
78 { SY7802_REG_ENABLE, SY7802_LEDS_MASK_ALL },
79 { SY7802_REG_TORCH_BRIGHTNESS, 0x92 },
80 { SY7802_REG_FLASH_BRIGHTNESS, SY7802_FLASH_BRIGHTNESS_DEFAULT |
81 SY7802_FLASH_BRIGHTNESS_DEFAULT << SY7802_FLASH_CURRENT_SHIFT },
82 { SY7802_REG_FLASH_DURATION, 0x6f },
83 { SY7802_REG_FLAGS, 0x0 },
84 { SY7802_REG_CONFIG_1, 0x68 },
85 { SY7802_REG_CONFIG_2, 0xf0 },
86 };
87
88 struct sy7802_led {
89 struct led_classdev_flash flash;
90 struct sy7802 *chip;
91 u8 led_id;
92 };
93
94 struct sy7802 {
95 struct device *dev;
96 struct regmap *regmap;
97 struct mutex mutex;
98
99 struct gpio_desc *enable_gpio;
100 struct regulator *vin_regulator;
101
102 unsigned int fled_strobe_used;
103 unsigned int fled_torch_used;
104 unsigned int leds_active;
105 int num_leds;
106 struct sy7802_led leds[] __counted_by(num_leds);
107 };
108
sy7802_torch_brightness_set(struct led_classdev * lcdev,enum led_brightness brightness)109 static int sy7802_torch_brightness_set(struct led_classdev *lcdev, enum led_brightness brightness)
110 {
111 struct sy7802_led *led = container_of(lcdev, struct sy7802_led, flash.led_cdev);
112 struct sy7802 *chip = led->chip;
113 u32 fled_torch_used_tmp;
114 u32 led_enable_mask;
115 u32 enable_mask;
116 u32 torch_mask;
117 u32 val;
118 int ret;
119
120 mutex_lock(&chip->mutex);
121
122 if (chip->fled_strobe_used) {
123 dev_warn(chip->dev, "Cannot set torch brightness whilst strobe is enabled\n");
124 ret = -EBUSY;
125 goto unlock;
126 }
127
128 if (brightness)
129 fled_torch_used_tmp = chip->fled_torch_used | BIT(led->led_id);
130 else
131 fled_torch_used_tmp = chip->fled_torch_used & ~BIT(led->led_id);
132
133 led_enable_mask = led->led_id == SY7802_LED_JOINT ?
134 SY7802_LEDS_MASK_ALL :
135 SY7802_LEDS_MASK(led->led_id);
136
137 val = brightness ? led_enable_mask : SY7802_MODE_OFF;
138 if (fled_torch_used_tmp)
139 val |= SY7802_MODE_TORCH;
140
141 /* Disable torch to apply brightness */
142 ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, SY7802_MODE_MASK,
143 SY7802_MODE_OFF);
144 if (ret)
145 goto unlock;
146
147 torch_mask = led->led_id == SY7802_LED_JOINT ?
148 SY7802_TORCH_CURRENT_MASK_ALL :
149 SY7802_TORCH_CURRENT_MASK(led->led_id);
150
151 /* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */
152 if (brightness)
153 brightness -= 1;
154
155 brightness |= (brightness << SY7802_TORCH_CURRENT_SHIFT);
156
157 ret = regmap_update_bits(chip->regmap, SY7802_REG_TORCH_BRIGHTNESS, torch_mask, brightness);
158 if (ret)
159 goto unlock;
160
161 enable_mask = SY7802_MODE_MASK | led_enable_mask;
162 ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val);
163 if (ret)
164 goto unlock;
165
166 chip->fled_torch_used = fled_torch_used_tmp;
167
168 unlock:
169 mutex_unlock(&chip->mutex);
170 return ret;
171 }
172
sy7802_flash_brightness_set(struct led_classdev_flash * fl_cdev,u32 brightness)173 static int sy7802_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness)
174 {
175 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
176 struct led_flash_setting *s = &fl_cdev->brightness;
177 u32 val = (brightness - s->min) / s->step;
178 struct sy7802 *chip = led->chip;
179 u32 flash_mask;
180 int ret;
181
182 val |= (val << SY7802_FLASH_CURRENT_SHIFT);
183 flash_mask = led->led_id == SY7802_LED_JOINT ?
184 SY7802_FLASH_CURRENT_MASK_ALL :
185 SY7802_FLASH_CURRENT_MASK(led->led_id);
186
187 mutex_lock(&chip->mutex);
188 ret = regmap_update_bits(chip->regmap, SY7802_REG_FLASH_BRIGHTNESS, flash_mask, val);
189 mutex_unlock(&chip->mutex);
190
191 return ret;
192 }
193
sy7802_strobe_set(struct led_classdev_flash * fl_cdev,bool state)194 static int sy7802_strobe_set(struct led_classdev_flash *fl_cdev, bool state)
195 {
196 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
197 struct sy7802 *chip = led->chip;
198 u32 fled_strobe_used_tmp;
199 u32 led_enable_mask;
200 u32 enable_mask;
201 u32 val;
202 int ret;
203
204 mutex_lock(&chip->mutex);
205
206 if (chip->fled_torch_used) {
207 dev_warn(chip->dev, "Cannot set strobe brightness whilst torch is enabled\n");
208 ret = -EBUSY;
209 goto unlock;
210 }
211
212 if (state)
213 fled_strobe_used_tmp = chip->fled_strobe_used | BIT(led->led_id);
214 else
215 fled_strobe_used_tmp = chip->fled_strobe_used & ~BIT(led->led_id);
216
217 led_enable_mask = led->led_id == SY7802_LED_JOINT ?
218 SY7802_LEDS_MASK_ALL :
219 SY7802_LEDS_MASK(led->led_id);
220
221 val = state ? led_enable_mask : SY7802_MODE_OFF;
222 if (fled_strobe_used_tmp)
223 val |= SY7802_MODE_FLASH;
224
225 enable_mask = SY7802_MODE_MASK | led_enable_mask;
226 ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val);
227
228 if (ret)
229 goto unlock;
230
231 chip->fled_strobe_used = fled_strobe_used_tmp;
232
233 unlock:
234 mutex_unlock(&chip->mutex);
235 return ret;
236 }
237
sy7802_strobe_get(struct led_classdev_flash * fl_cdev,bool * state)238 static int sy7802_strobe_get(struct led_classdev_flash *fl_cdev, bool *state)
239 {
240 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
241 struct sy7802 *chip = led->chip;
242
243 mutex_lock(&chip->mutex);
244 *state = !!(chip->fled_strobe_used & BIT(led->led_id));
245 mutex_unlock(&chip->mutex);
246
247 return 0;
248 }
249
sy7802_timeout_set(struct led_classdev_flash * fl_cdev,u32 timeout)250 static int sy7802_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout)
251 {
252 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
253 struct led_flash_setting *s = &fl_cdev->timeout;
254 u32 val = (timeout - s->min) / s->step;
255 struct sy7802 *chip = led->chip;
256
257 return regmap_write(chip->regmap, SY7802_REG_FLASH_DURATION, val);
258 }
259
sy7802_fault_get(struct led_classdev_flash * fl_cdev,u32 * fault)260 static int sy7802_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault)
261 {
262 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
263 struct sy7802 *chip = led->chip;
264 u32 val, led_faults = 0;
265 int ret;
266
267 /* NOTE: reading register clears fault status */
268 ret = regmap_read(chip->regmap, SY7802_REG_FLAGS, &val);
269 if (ret)
270 return ret;
271
272 if (val & (SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW | SY7802_FLAG_INPUT_VOLTAGE_LOW))
273 led_faults |= LED_FAULT_INPUT_VOLTAGE;
274
275 if (val & SY7802_FLAG_THERMAL_SHUTDOWN)
276 led_faults |= LED_FAULT_OVER_TEMPERATURE;
277
278 if (val & SY7802_FLAG_TIMEOUT)
279 led_faults |= LED_FAULT_TIMEOUT;
280
281 *fault = led_faults;
282 return 0;
283 }
284
285 static const struct led_flash_ops sy7802_flash_ops = {
286 .flash_brightness_set = sy7802_flash_brightness_set,
287 .strobe_set = sy7802_strobe_set,
288 .strobe_get = sy7802_strobe_get,
289 .timeout_set = sy7802_timeout_set,
290 .fault_get = sy7802_fault_get,
291 };
292
sy7802_init_flash_brightness(struct led_classdev_flash * fl_cdev)293 static void sy7802_init_flash_brightness(struct led_classdev_flash *fl_cdev)
294 {
295 struct led_flash_setting *s;
296
297 /* Init flash brightness setting */
298 s = &fl_cdev->brightness;
299 s->min = SY7802_FLASH_BRIGHTNESS_MIN;
300 s->max = SY7802_FLASH_BRIGHTNESS_MAX;
301 s->step = SY7802_FLASH_BRIGHTNESS_STEP;
302 s->val = SY7802_FLASH_BRIGHTNESS_DEFAULT;
303 }
304
sy7802_init_flash_timeout(struct led_classdev_flash * fl_cdev)305 static void sy7802_init_flash_timeout(struct led_classdev_flash *fl_cdev)
306 {
307 struct led_flash_setting *s;
308
309 /* Init flash timeout setting */
310 s = &fl_cdev->timeout;
311 s->min = SY7802_TIMEOUT_MIN_US;
312 s->max = SY7802_TIMEOUT_MAX_US;
313 s->step = SY7802_TIMEOUT_STEPSIZE_US;
314 s->val = SY7802_TIMEOUT_DEFAULT_US;
315 }
316
sy7802_led_register(struct device * dev,struct sy7802_led * led,struct device_node * np)317 static int sy7802_led_register(struct device *dev, struct sy7802_led *led,
318 struct device_node *np)
319 {
320 struct led_init_data init_data = {};
321 int ret;
322
323 init_data.fwnode = of_fwnode_handle(np);
324
325 ret = devm_led_classdev_flash_register_ext(dev, &led->flash, &init_data);
326 if (ret) {
327 dev_err(dev, "Couldn't register flash %d\n", led->led_id);
328 return ret;
329 }
330
331 return 0;
332 }
333
sy7802_init_flash_properties(struct device * dev,struct sy7802_led * led,struct device_node * np)334 static int sy7802_init_flash_properties(struct device *dev, struct sy7802_led *led,
335 struct device_node *np)
336 {
337 struct led_classdev_flash *flash = &led->flash;
338 struct led_classdev *lcdev = &flash->led_cdev;
339 u32 sources[SY7802_MAX_LEDS];
340 int i, num, ret;
341
342 num = of_property_count_u32_elems(np, "led-sources");
343 if (num < 1) {
344 dev_err(dev, "Not specified or wrong number of led-sources\n");
345 return -EINVAL;
346 }
347
348 ret = of_property_read_u32_array(np, "led-sources", sources, num);
349 if (ret)
350 return ret;
351
352 for (i = 0; i < num; i++) {
353 if (sources[i] >= SY7802_MAX_LEDS)
354 return -EINVAL;
355 if (led->chip->leds_active & BIT(sources[i]))
356 return -EINVAL;
357 led->chip->leds_active |= BIT(sources[i]);
358 }
359
360 /* If both channels are specified in 'led-sources', joint flash output mode is used */
361 led->led_id = num == 2 ? SY7802_LED_JOINT : sources[0];
362
363 lcdev->max_brightness = SY7802_TORCH_BRIGHTNESS_MAX;
364 lcdev->brightness_set_blocking = sy7802_torch_brightness_set;
365 lcdev->flags |= LED_DEV_CAP_FLASH;
366
367 flash->ops = &sy7802_flash_ops;
368
369 sy7802_init_flash_brightness(flash);
370 sy7802_init_flash_timeout(flash);
371
372 return 0;
373 }
374
sy7802_chip_check(struct sy7802 * chip)375 static int sy7802_chip_check(struct sy7802 *chip)
376 {
377 struct device *dev = chip->dev;
378 u32 chipid;
379 int ret;
380
381 ret = regmap_read(chip->regmap, SY7802_REG_DEV_ID, &chipid);
382 if (ret)
383 return dev_err_probe(dev, ret, "Failed to read chip ID\n");
384
385 if (chipid != SY7802_CHIP_ID)
386 return dev_err_probe(dev, -ENODEV, "Unsupported chip detected: %x\n", chipid);
387
388 return 0;
389 }
390
sy7802_enable(struct sy7802 * chip)391 static void sy7802_enable(struct sy7802 *chip)
392 {
393 gpiod_set_value_cansleep(chip->enable_gpio, 1);
394 usleep_range(200, 300);
395 }
396
sy7802_disable(struct sy7802 * chip)397 static void sy7802_disable(struct sy7802 *chip)
398 {
399 gpiod_set_value_cansleep(chip->enable_gpio, 0);
400 }
401
sy7802_probe_dt(struct sy7802 * chip)402 static int sy7802_probe_dt(struct sy7802 *chip)
403 {
404 struct device_node *np = dev_of_node(chip->dev);
405 int child_num;
406 int ret;
407
408 regmap_write(chip->regmap, SY7802_REG_ENABLE, SY7802_MODE_OFF);
409 regmap_write(chip->regmap, SY7802_REG_TORCH_BRIGHTNESS, LED_OFF);
410
411 child_num = 0;
412 for_each_available_child_of_node_scoped(np, child) {
413 struct sy7802_led *led = chip->leds + child_num;
414
415 led->chip = chip;
416 led->led_id = child_num;
417
418 ret = sy7802_init_flash_properties(chip->dev, led, child);
419 if (ret)
420 return ret;
421
422 ret = sy7802_led_register(chip->dev, led, child);
423 if (ret)
424 return ret;
425
426 child_num++;
427 }
428 return 0;
429 }
430
sy7802_chip_disable_action(void * data)431 static void sy7802_chip_disable_action(void *data)
432 {
433 struct sy7802 *chip = data;
434
435 sy7802_disable(chip);
436 }
437
sy7802_regulator_disable_action(void * data)438 static void sy7802_regulator_disable_action(void *data)
439 {
440 struct sy7802 *chip = data;
441
442 regulator_disable(chip->vin_regulator);
443 }
444
445 static const struct regmap_config sy7802_regmap_config = {
446 .reg_bits = 8,
447 .val_bits = 8,
448 .max_register = 0xff,
449 .cache_type = REGCACHE_MAPLE,
450 .reg_defaults = sy7802_regmap_defs,
451 .num_reg_defaults = ARRAY_SIZE(sy7802_regmap_defs),
452 };
453
sy7802_probe(struct i2c_client * client)454 static int sy7802_probe(struct i2c_client *client)
455 {
456 struct device *dev = &client->dev;
457 struct sy7802 *chip;
458 size_t count;
459 int ret;
460
461 count = device_get_child_node_count(dev);
462 if (!count || count > SY7802_MAX_LEDS)
463 return dev_err_probe(dev, -EINVAL, "Invalid amount of LED nodes %zu\n", count);
464
465 chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL);
466 if (!chip)
467 return -ENOMEM;
468
469 chip->num_leds = count;
470
471 chip->dev = dev;
472 i2c_set_clientdata(client, chip);
473
474 chip->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
475 ret = PTR_ERR_OR_ZERO(chip->enable_gpio);
476 if (ret)
477 return dev_err_probe(dev, ret, "Failed to request enable gpio\n");
478
479 chip->vin_regulator = devm_regulator_get(dev, "vin");
480 ret = PTR_ERR_OR_ZERO(chip->vin_regulator);
481 if (ret)
482 return dev_err_probe(dev, ret, "Failed to request regulator\n");
483
484 ret = regulator_enable(chip->vin_regulator);
485 if (ret)
486 return dev_err_probe(dev, ret, "Failed to enable regulator\n");
487
488 ret = devm_add_action_or_reset(dev, sy7802_regulator_disable_action, chip);
489 if (ret)
490 return ret;
491
492 ret = devm_mutex_init(dev, &chip->mutex);
493 if (ret)
494 return ret;
495
496 mutex_lock(&chip->mutex);
497
498 chip->regmap = devm_regmap_init_i2c(client, &sy7802_regmap_config);
499 if (IS_ERR(chip->regmap)) {
500 ret = PTR_ERR(chip->regmap);
501 dev_err_probe(dev, ret, "Failed to allocate register map\n");
502 goto error;
503 }
504
505 ret = sy7802_probe_dt(chip);
506 if (ret < 0)
507 goto error;
508
509 sy7802_enable(chip);
510
511 ret = devm_add_action_or_reset(dev, sy7802_chip_disable_action, chip);
512 if (ret)
513 goto error;
514
515 ret = sy7802_chip_check(chip);
516
517 error:
518 mutex_unlock(&chip->mutex);
519 return ret;
520 }
521
522 static const struct of_device_id __maybe_unused sy7802_leds_match[] = {
523 { .compatible = "silergy,sy7802", },
524 {}
525 };
526 MODULE_DEVICE_TABLE(of, sy7802_leds_match);
527
528 static struct i2c_driver sy7802_driver = {
529 .driver = {
530 .name = "sy7802",
531 .of_match_table = of_match_ptr(sy7802_leds_match),
532 },
533 .probe = sy7802_probe,
534 };
535 module_i2c_driver(sy7802_driver);
536
537 MODULE_AUTHOR("André Apitzsch <git@apitzsch.eu>");
538 MODULE_DESCRIPTION("Silergy SY7802 flash LED driver");
539 MODULE_LICENSE("GPL");
540