Lines Matching +full:flash +full:- +full:led
1 // SPDX-License-Identifier: GPL-2.0-only
3 * LED Flash class driver for the AAT1290
4 * 1.5A Step-Up Current Regulator for Flash LEDs
13 #include <linux/led-class-flash.h>
21 #include <media/v4l2-flash-led-class.h>
50 /* maximum LED current in movie mode */
52 /* maximum LED current in flash mode */
54 /* maximum flash timeout */
58 /* max LED brightness level */
68 /* corresponding LED Flash class device */
70 /* V4L2 Flash device */
95 static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value) in aat1290_as2cwire_write() argument
99 gpiod_direction_output(led->gpio_fl_en, 0); in aat1290_as2cwire_write()
100 gpiod_direction_output(led->gpio_en_set, 0); in aat1290_as2cwire_write()
107 gpiod_direction_output(led->gpio_en_set, 0); in aat1290_as2cwire_write()
109 gpiod_direction_output(led->gpio_en_set, 1); in aat1290_as2cwire_write()
117 gpiod_direction_output(led->gpio_en_set, 0); in aat1290_as2cwire_write()
119 gpiod_direction_output(led->gpio_en_set, 1); in aat1290_as2cwire_write()
125 static void aat1290_set_flash_safety_timer(struct aat1290_led *led, in aat1290_set_flash_safety_timer() argument
128 struct led_classdev_flash *fled_cdev = &led->fled_cdev; in aat1290_set_flash_safety_timer()
129 struct led_flash_setting *flash_tm = &fled_cdev->timeout; in aat1290_set_flash_safety_timer()
130 int flash_tm_reg = AAT1290_FLASH_TM_NUM_LEVELS - in aat1290_set_flash_safety_timer()
131 (micro_sec / flash_tm->step) + 1; in aat1290_set_flash_safety_timer()
133 aat1290_as2cwire_write(led, AAT1290_FLASH_SAFETY_TIMER_ADDR, in aat1290_set_flash_safety_timer()
137 /* LED subsystem callbacks */
143 struct aat1290_led *led = fled_cdev_to_led(fled_cdev); in aat1290_led_brightness_set() local
145 mutex_lock(&led->lock); in aat1290_led_brightness_set()
148 gpiod_direction_output(led->gpio_fl_en, 0); in aat1290_led_brightness_set()
149 gpiod_direction_output(led->gpio_en_set, 0); in aat1290_led_brightness_set()
150 led->movie_mode = false; in aat1290_led_brightness_set()
152 if (!led->movie_mode) { in aat1290_led_brightness_set()
153 aat1290_as2cwire_write(led, in aat1290_led_brightness_set()
156 led->movie_mode = true; in aat1290_led_brightness_set()
159 aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CURRENT_ADDR, in aat1290_led_brightness_set()
160 AAT1290_MAX_MM_CURR_PERCENT_0 - brightness); in aat1290_led_brightness_set()
161 aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CONFIG_ADDR, in aat1290_led_brightness_set()
165 mutex_unlock(&led->lock); in aat1290_led_brightness_set()
174 struct aat1290_led *led = fled_cdev_to_led(fled_cdev); in aat1290_led_flash_strobe_set() local
175 struct led_classdev *led_cdev = &fled_cdev->led_cdev; in aat1290_led_flash_strobe_set()
176 struct led_flash_setting *timeout = &fled_cdev->timeout; in aat1290_led_flash_strobe_set()
178 mutex_lock(&led->lock); in aat1290_led_flash_strobe_set()
181 aat1290_set_flash_safety_timer(led, timeout->val); in aat1290_led_flash_strobe_set()
182 gpiod_direction_output(led->gpio_fl_en, 1); in aat1290_led_flash_strobe_set()
184 gpiod_direction_output(led->gpio_fl_en, 0); in aat1290_led_flash_strobe_set()
185 gpiod_direction_output(led->gpio_en_set, 0); in aat1290_led_flash_strobe_set()
189 * To reenter movie mode after a flash event the part must be cycled in aat1290_led_flash_strobe_set()
194 led_cdev->brightness = 0; in aat1290_led_flash_strobe_set()
195 led->movie_mode = false; in aat1290_led_flash_strobe_set()
197 mutex_unlock(&led->lock); in aat1290_led_flash_strobe_set()
206 * Don't do anything - flash timeout is cached in the led-class-flash in aat1290_led_flash_timeout_set()
214 static int aat1290_led_parse_dt(struct aat1290_led *led, in aat1290_led_parse_dt() argument
218 struct device *dev = &led->pdev->dev; in aat1290_led_parse_dt()
224 led->gpio_fl_en = devm_gpiod_get(dev, "flen", GPIOD_ASIS); in aat1290_led_parse_dt()
225 if (IS_ERR(led->gpio_fl_en)) { in aat1290_led_parse_dt()
226 ret = PTR_ERR(led->gpio_fl_en); in aat1290_led_parse_dt()
231 led->gpio_en_set = devm_gpiod_get(dev, "enset", GPIOD_ASIS); in aat1290_led_parse_dt()
232 if (IS_ERR(led->gpio_en_set)) { in aat1290_led_parse_dt()
233 ret = PTR_ERR(led->gpio_en_set); in aat1290_led_parse_dt()
239 pinctrl = devm_pinctrl_get_select_default(&led->pdev->dev); in aat1290_led_parse_dt()
241 cfg->has_external_strobe = false; in aat1290_led_parse_dt()
245 cfg->has_external_strobe = true; in aat1290_led_parse_dt()
252 dev_err(dev, "No DT child node found for connected LED.\n"); in aat1290_led_parse_dt()
253 return -EINVAL; in aat1290_led_parse_dt()
256 ret = of_property_read_u32(child_node, "led-max-microamp", in aat1290_led_parse_dt()
257 &cfg->max_mm_current); in aat1290_led_parse_dt()
259 * led-max-microamp will default to 1/20 of flash-max-microamp in aat1290_led_parse_dt()
264 "led-max-microamp DT property missing\n"); in aat1290_led_parse_dt()
266 ret = of_property_read_u32(child_node, "flash-max-microamp", in aat1290_led_parse_dt()
267 &cfg->max_flash_current); in aat1290_led_parse_dt()
270 "flash-max-microamp DT property missing\n"); in aat1290_led_parse_dt()
274 ret = of_property_read_u32(child_node, "flash-max-timeout-us", in aat1290_led_parse_dt()
275 &cfg->max_flash_tm); in aat1290_led_parse_dt()
278 "flash-max-timeout-us DT property missing\n"); in aat1290_led_parse_dt()
287 static void aat1290_led_validate_mm_current(struct aat1290_led *led, in aat1290_led_validate_mm_current() argument
292 while (e - b > 1) { in aat1290_led_validate_mm_current()
293 i = b + (e - b) / 2; in aat1290_led_validate_mm_current()
294 if (cfg->max_mm_current < led->mm_current_scale[i]) in aat1290_led_validate_mm_current()
300 cfg->max_mm_current = led->mm_current_scale[b]; in aat1290_led_validate_mm_current()
301 cfg->max_brightness = b + 1; in aat1290_led_validate_mm_current()
304 static int init_mm_current_scale(struct aat1290_led *led, in init_mm_current_scale() argument
312 AAT1290_MAX_MM_CURRENT(cfg->max_flash_current); in init_mm_current_scale()
314 led->mm_current_scale = devm_kzalloc(&led->pdev->dev, in init_mm_current_scale()
317 if (!led->mm_current_scale) in init_mm_current_scale()
318 return -ENOMEM; in init_mm_current_scale()
321 led->mm_current_scale[i] = max_mm_current * in init_mm_current_scale()
327 static int aat1290_led_get_configuration(struct aat1290_led *led, in aat1290_led_get_configuration() argument
333 ret = aat1290_led_parse_dt(led, cfg, sub_node); in aat1290_led_get_configuration()
337 * Init non-linear movie mode current scale basing in aat1290_led_get_configuration()
338 * on the max flash current from led configuration. in aat1290_led_get_configuration()
340 ret = init_mm_current_scale(led, cfg); in aat1290_led_get_configuration()
344 aat1290_led_validate_mm_current(led, cfg); in aat1290_led_get_configuration()
348 devm_kfree(&led->pdev->dev, led->mm_current_scale); in aat1290_led_get_configuration()
354 static void aat1290_init_flash_timeout(struct aat1290_led *led, in aat1290_init_flash_timeout() argument
357 struct led_classdev_flash *fled_cdev = &led->fled_cdev; in aat1290_init_flash_timeout()
360 /* Init flash timeout setting */ in aat1290_init_flash_timeout()
361 setting = &fled_cdev->timeout; in aat1290_init_flash_timeout()
362 setting->min = cfg->max_flash_tm / AAT1290_FLASH_TM_NUM_LEVELS; in aat1290_init_flash_timeout()
363 setting->max = cfg->max_flash_tm; in aat1290_init_flash_timeout()
364 setting->step = setting->min; in aat1290_init_flash_timeout()
365 setting->val = setting->max; in aat1290_init_flash_timeout()
373 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; in aat1290_intensity_to_brightness()
374 struct aat1290_led *led = fled_cdev_to_led(fled_cdev); in aat1290_intensity_to_brightness() local
377 for (i = AAT1290_MM_CURRENT_SCALE_SIZE - 1; i >= 0; --i) in aat1290_intensity_to_brightness()
378 if (intensity >= led->mm_current_scale[i]) in aat1290_intensity_to_brightness()
387 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; in aat1290_brightness_to_intensity()
388 struct aat1290_led *led = fled_cdev_to_led(fled_cdev); in aat1290_brightness_to_intensity() local
390 return led->mm_current_scale[brightness - 1]; in aat1290_brightness_to_intensity()
396 struct aat1290_led *led = fled_cdev_to_led(v4l2_flash->fled_cdev); in aat1290_led_external_strobe_set() local
397 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; in aat1290_led_external_strobe_set()
398 struct led_classdev *led_cdev = &fled_cdev->led_cdev; in aat1290_led_external_strobe_set()
401 gpiod_direction_output(led->gpio_fl_en, 0); in aat1290_led_external_strobe_set()
402 gpiod_direction_output(led->gpio_en_set, 0); in aat1290_led_external_strobe_set()
404 led->movie_mode = false; in aat1290_led_external_strobe_set()
405 led_cdev->brightness = 0; in aat1290_led_external_strobe_set()
407 pinctrl = devm_pinctrl_get_select(&led->pdev->dev, in aat1290_led_external_strobe_set()
410 dev_warn(&led->pdev->dev, "Unable to switch strobe source.\n"); in aat1290_led_external_strobe_set()
417 static void aat1290_init_v4l2_flash_config(struct aat1290_led *led, in aat1290_init_v4l2_flash_config() argument
421 struct led_classdev *led_cdev = &led->fled_cdev.led_cdev; in aat1290_init_v4l2_flash_config()
424 strscpy(v4l2_sd_cfg->dev_name, led_cdev->dev->kobj.name, in aat1290_init_v4l2_flash_config()
425 sizeof(v4l2_sd_cfg->dev_name)); in aat1290_init_v4l2_flash_config()
427 s = &v4l2_sd_cfg->intensity; in aat1290_init_v4l2_flash_config()
428 s->min = led->mm_current_scale[0]; in aat1290_init_v4l2_flash_config()
429 s->max = led_cfg->max_mm_current; in aat1290_init_v4l2_flash_config()
430 s->step = 1; in aat1290_init_v4l2_flash_config()
431 s->val = s->max; in aat1290_init_v4l2_flash_config()
433 v4l2_sd_cfg->has_external_strobe = led_cfg->has_external_strobe; in aat1290_init_v4l2_flash_config()
442 static inline void aat1290_init_v4l2_flash_config(struct aat1290_led *led, in aat1290_init_v4l2_flash_config() argument
457 struct device *dev = &pdev->dev; in aat1290_led_probe()
459 struct aat1290_led *led; in aat1290_led_probe() local
467 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); in aat1290_led_probe()
468 if (!led) in aat1290_led_probe()
469 return -ENOMEM; in aat1290_led_probe()
471 led->pdev = pdev; in aat1290_led_probe()
472 platform_set_drvdata(pdev, led); in aat1290_led_probe()
474 fled_cdev = &led->fled_cdev; in aat1290_led_probe()
475 fled_cdev->ops = &flash_ops; in aat1290_led_probe()
476 led_cdev = &fled_cdev->led_cdev; in aat1290_led_probe()
478 ret = aat1290_led_get_configuration(led, &led_cfg, &sub_node); in aat1290_led_probe()
482 mutex_init(&led->lock); in aat1290_led_probe()
484 /* Initialize LED Flash class device */ in aat1290_led_probe()
485 led_cdev->brightness_set_blocking = aat1290_led_brightness_set; in aat1290_led_probe()
486 led_cdev->max_brightness = led_cfg.max_brightness; in aat1290_led_probe()
487 led_cdev->flags |= LED_DEV_CAP_FLASH; in aat1290_led_probe()
489 aat1290_init_flash_timeout(led, &led_cfg); in aat1290_led_probe()
494 /* Register LED Flash class device */ in aat1290_led_probe()
495 ret = led_classdev_flash_register_ext(&pdev->dev, fled_cdev, in aat1290_led_probe()
500 aat1290_init_v4l2_flash_config(led, &led_cfg, &v4l2_sd_cfg); in aat1290_led_probe()
502 /* Create V4L2 Flash subdev. */ in aat1290_led_probe()
503 led->v4l2_flash = v4l2_flash_init(dev, of_fwnode_handle(sub_node), in aat1290_led_probe()
506 if (IS_ERR(led->v4l2_flash)) { in aat1290_led_probe()
507 ret = PTR_ERR(led->v4l2_flash); in aat1290_led_probe()
516 mutex_destroy(&led->lock); in aat1290_led_probe()
523 struct aat1290_led *led = platform_get_drvdata(pdev); in aat1290_led_remove() local
525 v4l2_flash_release(led->v4l2_flash); in aat1290_led_remove()
526 led_classdev_flash_unregister(&led->fled_cdev); in aat1290_led_remove()
528 mutex_destroy(&led->lock); in aat1290_led_remove()
549 MODULE_DESCRIPTION("Skyworks Current Regulator for Flash LEDs");