xref: /linux/drivers/leds/flash/leds-sy7802.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
397 static void sy7802_disable(struct sy7802 *chip)
398 {
399 	gpiod_set_value_cansleep(chip->enable_gpio, 0);
400 }
401 
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 
431 static void sy7802_chip_disable_action(void *data)
432 {
433 	struct sy7802 *chip = data;
434 
435 	sy7802_disable(chip);
436 }
437 
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 
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