File Index
Files and directories
Sign in
FILE

leds-sy7802.c

File preview with syntax highlighting.

linux-6.19.14/drivers/leds/flash/leds-sy7802.c C
  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
 77static 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
 88struct sy7802_led {
 89	struct led_classdev_flash flash;
 90	struct sy7802 *chip;
 91	u8 led_id;
 92};
 93
 94struct 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
109static 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
168unlock:
169	mutex_unlock(&chip->mutex);
170	return ret;
171}
172
173static 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
194static 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
233unlock:
234	mutex_unlock(&chip->mutex);
235	return ret;
236}
237
238static 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
250static 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
260static 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
285static 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
293static 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
305static 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
317static 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
334static 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
375static 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
391static void sy7802_enable(struct sy7802 *chip)
392{
393	gpiod_set_value_cansleep(chip->enable_gpio, 1);
394	usleep_range(200, 300);
395}
396
397static void sy7802_disable(struct sy7802 *chip)
398{
399	gpiod_set_value_cansleep(chip->enable_gpio, 0);
400}
401
402static 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
431static void sy7802_chip_disable_action(void *data)
432{
433	struct sy7802 *chip = data;
434
435	sy7802_disable(chip);
436}
437
438static void sy7802_regulator_disable_action(void *data)
439{
440	struct sy7802 *chip = data;
441
442	regulator_disable(chip->vin_regulator);
443}
444
445static 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
454static 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
517error:
518	mutex_unlock(&chip->mutex);
519	return ret;
520}
521
522static const struct of_device_id __maybe_unused sy7802_leds_match[] = {
523	{ .compatible = "silergy,sy7802", },
524	{}
525};
526MODULE_DEVICE_TABLE(of, sy7802_leds_match);
527
528static 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};
535module_i2c_driver(sy7802_driver);
536
537MODULE_AUTHOR("André Apitzsch <git@apitzsch.eu>");
538MODULE_DESCRIPTION("Silergy SY7802 flash LED driver");
539MODULE_LICENSE("GPL");
~/ Read-only file preview.