1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Silergy SY7802 flash LED driver with an I2C interface
5 * Copyright 2024 André Apitzsch <git@apitzsch.eu>
8 #include <linux/gpio/consumer.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>
17 #define SY7802_MAX_LEDS 2
18 #define SY7802_LED_JOINT 2
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
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)
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))
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))
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))
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
59 #define SY7802_TORCH_BRIGHTNESS_MAX 8
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
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)
75 #define SY7802_CHIP_ID 0x51
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 },
89 struct led_classdev_flash flash
;
96 struct regmap
*regmap
;
99 struct gpio_desc
*enable_gpio
;
100 struct regulator
*vin_regulator
;
102 unsigned int fled_strobe_used
;
103 unsigned int fled_torch_used
;
104 unsigned int leds_active
;
106 struct sy7802_led leds
[] __counted_by(num_leds
);
109 static int sy7802_torch_brightness_set(struct led_classdev
*lcdev
, enum led_brightness brightness
)
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
;
120 mutex_lock(&chip
->mutex
);
122 if (chip
->fled_strobe_used
) {
123 dev_warn(chip
->dev
, "Cannot set torch brightness whilst strobe is enabled\n");
129 fled_torch_used_tmp
= chip
->fled_torch_used
| BIT(led
->led_id
);
131 fled_torch_used_tmp
= chip
->fled_torch_used
& ~BIT(led
->led_id
);
133 led_enable_mask
= led
->led_id
== SY7802_LED_JOINT
?
134 SY7802_LEDS_MASK_ALL
:
135 SY7802_LEDS_MASK(led
->led_id
);
137 val
= brightness
? led_enable_mask
: SY7802_MODE_OFF
;
138 if (fled_torch_used_tmp
)
139 val
|= SY7802_MODE_TORCH
;
141 /* Disable torch to apply brightness */
142 ret
= regmap_update_bits(chip
->regmap
, SY7802_REG_ENABLE
, SY7802_MODE_MASK
,
147 torch_mask
= led
->led_id
== SY7802_LED_JOINT
?
148 SY7802_TORCH_CURRENT_MASK_ALL
:
149 SY7802_TORCH_CURRENT_MASK(led
->led_id
);
151 /* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */
155 brightness
|= (brightness
<< SY7802_TORCH_CURRENT_SHIFT
);
157 ret
= regmap_update_bits(chip
->regmap
, SY7802_REG_TORCH_BRIGHTNESS
, torch_mask
, brightness
);
161 enable_mask
= SY7802_MODE_MASK
| led_enable_mask
;
162 ret
= regmap_update_bits(chip
->regmap
, SY7802_REG_ENABLE
, enable_mask
, val
);
166 chip
->fled_torch_used
= fled_torch_used_tmp
;
169 mutex_unlock(&chip
->mutex
);
173 static int sy7802_flash_brightness_set(struct led_classdev_flash
*fl_cdev
, u32 brightness
)
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
;
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
);
187 mutex_lock(&chip
->mutex
);
188 ret
= regmap_update_bits(chip
->regmap
, SY7802_REG_FLASH_BRIGHTNESS
, flash_mask
, val
);
189 mutex_unlock(&chip
->mutex
);
194 static int sy7802_strobe_set(struct led_classdev_flash
*fl_cdev
, bool state
)
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
;
204 mutex_lock(&chip
->mutex
);
206 if (chip
->fled_torch_used
) {
207 dev_warn(chip
->dev
, "Cannot set strobe brightness whilst torch is enabled\n");
213 fled_strobe_used_tmp
= chip
->fled_strobe_used
| BIT(led
->led_id
);
215 fled_strobe_used_tmp
= chip
->fled_strobe_used
& ~BIT(led
->led_id
);
217 led_enable_mask
= led
->led_id
== SY7802_LED_JOINT
?
218 SY7802_LEDS_MASK_ALL
:
219 SY7802_LEDS_MASK(led
->led_id
);
221 val
= state
? led_enable_mask
: SY7802_MODE_OFF
;
222 if (fled_strobe_used_tmp
)
223 val
|= SY7802_MODE_FLASH
;
225 enable_mask
= SY7802_MODE_MASK
| led_enable_mask
;
226 ret
= regmap_update_bits(chip
->regmap
, SY7802_REG_ENABLE
, enable_mask
, val
);
231 chip
->fled_strobe_used
= fled_strobe_used_tmp
;
234 mutex_unlock(&chip
->mutex
);
238 static int sy7802_strobe_get(struct led_classdev_flash
*fl_cdev
, bool *state
)
240 struct sy7802_led
*led
= container_of(fl_cdev
, struct sy7802_led
, flash
);
241 struct sy7802
*chip
= led
->chip
;
243 mutex_lock(&chip
->mutex
);
244 *state
= !!(chip
->fled_strobe_used
& BIT(led
->led_id
));
245 mutex_unlock(&chip
->mutex
);
250 static int sy7802_timeout_set(struct led_classdev_flash
*fl_cdev
, u32 timeout
)
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
;
257 return regmap_write(chip
->regmap
, SY7802_REG_FLASH_DURATION
, val
);
260 static int sy7802_fault_get(struct led_classdev_flash
*fl_cdev
, u32
*fault
)
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;
267 /* NOTE: reading register clears fault status */
268 ret
= regmap_read(chip
->regmap
, SY7802_REG_FLAGS
, &val
);
272 if (val
& (SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW
| SY7802_FLAG_INPUT_VOLTAGE_LOW
))
273 led_faults
|= LED_FAULT_INPUT_VOLTAGE
;
275 if (val
& SY7802_FLAG_THERMAL_SHUTDOWN
)
276 led_faults
|= LED_FAULT_OVER_TEMPERATURE
;
278 if (val
& SY7802_FLAG_TIMEOUT
)
279 led_faults
|= LED_FAULT_TIMEOUT
;
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
,
293 static void sy7802_init_flash_brightness(struct led_classdev_flash
*fl_cdev
)
295 struct led_flash_setting
*s
;
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
;
305 static void sy7802_init_flash_timeout(struct led_classdev_flash
*fl_cdev
)
307 struct led_flash_setting
*s
;
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
;
317 static int sy7802_led_register(struct device
*dev
, struct sy7802_led
*led
,
318 struct device_node
*np
)
320 struct led_init_data init_data
= {};
323 init_data
.fwnode
= of_fwnode_handle(np
);
325 ret
= devm_led_classdev_flash_register_ext(dev
, &led
->flash
, &init_data
);
327 dev_err(dev
, "Couldn't register flash %d\n", led
->led_id
);
334 static int sy7802_init_flash_properties(struct device
*dev
, struct sy7802_led
*led
,
335 struct device_node
*np
)
337 struct led_classdev_flash
*flash
= &led
->flash
;
338 struct led_classdev
*lcdev
= &flash
->led_cdev
;
339 u32 sources
[SY7802_MAX_LEDS
];
342 num
= of_property_count_u32_elems(np
, "led-sources");
344 dev_err(dev
, "Not specified or wrong number of led-sources\n");
348 ret
= of_property_read_u32_array(np
, "led-sources", sources
, num
);
352 for (i
= 0; i
< num
; i
++) {
353 if (sources
[i
] >= SY7802_MAX_LEDS
)
355 if (led
->chip
->leds_active
& BIT(sources
[i
]))
357 led
->chip
->leds_active
|= BIT(sources
[i
]);
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];
363 lcdev
->max_brightness
= SY7802_TORCH_BRIGHTNESS_MAX
;
364 lcdev
->brightness_set_blocking
= sy7802_torch_brightness_set
;
365 lcdev
->flags
|= LED_DEV_CAP_FLASH
;
367 flash
->ops
= &sy7802_flash_ops
;
369 sy7802_init_flash_brightness(flash
);
370 sy7802_init_flash_timeout(flash
);
375 static int sy7802_chip_check(struct sy7802
*chip
)
377 struct device
*dev
= chip
->dev
;
381 ret
= regmap_read(chip
->regmap
, SY7802_REG_DEV_ID
, &chipid
);
383 return dev_err_probe(dev
, ret
, "Failed to read chip ID\n");
385 if (chipid
!= SY7802_CHIP_ID
)
386 return dev_err_probe(dev
, -ENODEV
, "Unsupported chip detected: %x\n", chipid
);
391 static void sy7802_enable(struct sy7802
*chip
)
393 gpiod_set_value_cansleep(chip
->enable_gpio
, 1);
394 usleep_range(200, 300);
397 static void sy7802_disable(struct sy7802
*chip
)
399 gpiod_set_value_cansleep(chip
->enable_gpio
, 0);
402 static int sy7802_probe_dt(struct sy7802
*chip
)
404 struct device_node
*np
= dev_of_node(chip
->dev
);
408 regmap_write(chip
->regmap
, SY7802_REG_ENABLE
, SY7802_MODE_OFF
);
409 regmap_write(chip
->regmap
, SY7802_REG_TORCH_BRIGHTNESS
, LED_OFF
);
412 for_each_available_child_of_node_scoped(np
, child
) {
413 struct sy7802_led
*led
= chip
->leds
+ child_num
;
416 led
->led_id
= child_num
;
418 ret
= sy7802_init_flash_properties(chip
->dev
, led
, child
);
422 ret
= sy7802_led_register(chip
->dev
, led
, child
);
431 static void sy7802_chip_disable_action(void *data
)
433 struct sy7802
*chip
= data
;
435 sy7802_disable(chip
);
438 static void sy7802_regulator_disable_action(void *data
)
440 struct sy7802
*chip
= data
;
442 regulator_disable(chip
->vin_regulator
);
445 static const struct regmap_config sy7802_regmap_config
= {
448 .max_register
= 0xff,
449 .cache_type
= REGCACHE_MAPLE
,
450 .reg_defaults
= sy7802_regmap_defs
,
451 .num_reg_defaults
= ARRAY_SIZE(sy7802_regmap_defs
),
454 static int sy7802_probe(struct i2c_client
*client
)
456 struct device
*dev
= &client
->dev
;
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
);
465 chip
= devm_kzalloc(dev
, struct_size(chip
, leds
, count
), GFP_KERNEL
);
469 chip
->num_leds
= count
;
472 i2c_set_clientdata(client
, chip
);
474 chip
->enable_gpio
= devm_gpiod_get(dev
, "enable", GPIOD_OUT_LOW
);
475 ret
= PTR_ERR_OR_ZERO(chip
->enable_gpio
);
477 return dev_err_probe(dev
, ret
, "Failed to request enable gpio\n");
479 chip
->vin_regulator
= devm_regulator_get(dev
, "vin");
480 ret
= PTR_ERR_OR_ZERO(chip
->vin_regulator
);
482 return dev_err_probe(dev
, ret
, "Failed to request regulator\n");
484 ret
= regulator_enable(chip
->vin_regulator
);
486 return dev_err_probe(dev
, ret
, "Failed to enable regulator\n");
488 ret
= devm_add_action_or_reset(dev
, sy7802_regulator_disable_action
, chip
);
492 ret
= devm_mutex_init(dev
, &chip
->mutex
);
496 mutex_lock(&chip
->mutex
);
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");
505 ret
= sy7802_probe_dt(chip
);
511 ret
= devm_add_action_or_reset(dev
, sy7802_chip_disable_action
, chip
);
515 ret
= sy7802_chip_check(chip
);
518 mutex_unlock(&chip
->mutex
);
522 static const struct of_device_id __maybe_unused sy7802_leds_match
[] = {
523 { .compatible
= "silergy,sy7802", },
526 MODULE_DEVICE_TABLE(of
, sy7802_leds_match
);
528 static struct i2c_driver sy7802_driver
= {
531 .of_match_table
= of_match_ptr(sy7802_leds_match
),
533 .probe
= sy7802_probe
,
535 module_i2c_driver(sy7802_driver
);
537 MODULE_AUTHOR("André Apitzsch <git@apitzsch.eu>");
538 MODULE_DESCRIPTION("Silergy SY7802 flash LED driver");
539 MODULE_LICENSE("GPL");