Lines Matching +full:flash +full:- +full:led

1 // SPDX-License-Identifier: GPL-2.0-only
8 #include <linux/led-class-flash.h>
9 #include <linux/led-class-multicolor.h>
15 #include <media/v4l2-flash-led-class.h>
29 #define MT6360_ISNK_ENMASK(_led_no) BIT(7 - (_led_no))
39 #define MT6360_REG_FLEDBASE(_id) (0x372 + 4 * (_id - MT6360_LED_FLASH1))
49 #define MT6360_FLCSEN_MASK(_id) BIT(MT6360_LED_FLASH2 - _id)
78 struct led_classdev_flash flash; member
101 struct mt6360_led *led = container_of(mccdev, struct mt6360_led, mc); in mt6360_mc_brightness_set() local
102 struct mt6360_priv *priv = led->priv; in mt6360_mc_brightness_set()
106 mutex_lock(&priv->lock); in mt6360_mc_brightness_set()
110 for (i = 0; i < mccdev->num_colors; i++) { in mt6360_mc_brightness_set()
111 struct mc_subled *subled = mccdev->subled_info + i; in mt6360_mc_brightness_set()
113 real_bright = min(lcdev->max_brightness, subled->brightness); in mt6360_mc_brightness_set()
114 ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(i), in mt6360_mc_brightness_set()
119 enable_mask |= MT6360_ISNK_ENMASK(subled->channel); in mt6360_mc_brightness_set()
121 enable |= MT6360_ISNK_ENMASK(subled->channel); in mt6360_mc_brightness_set()
124 ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN, enable_mask, in mt6360_mc_brightness_set()
128 mutex_unlock(&priv->lock); in mt6360_mc_brightness_set()
135 struct mt6360_led *led = container_of(lcdev, struct mt6360_led, isnk); in mt6360_isnk_brightness_set() local
136 struct mt6360_priv *priv = led->priv; in mt6360_isnk_brightness_set()
137 u32 enable_mask = MT6360_ISNK_ENMASK(led->led_no); in mt6360_isnk_brightness_set()
138 u32 val = level ? MT6360_ISNK_ENMASK(led->led_no) : 0; in mt6360_isnk_brightness_set()
141 mutex_lock(&priv->lock); in mt6360_isnk_brightness_set()
143 ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no), in mt6360_isnk_brightness_set()
148 ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN, enable_mask, in mt6360_isnk_brightness_set()
152 mutex_unlock(&priv->lock); in mt6360_isnk_brightness_set()
159 struct mt6360_led *led = in mt6360_torch_brightness_set() local
160 container_of(lcdev, struct mt6360_led, flash.led_cdev); in mt6360_torch_brightness_set()
161 struct mt6360_priv *priv = led->priv; in mt6360_torch_brightness_set()
162 u32 enable_mask = MT6360_TORCHEN_MASK | MT6360_FLCSEN_MASK(led->led_no); in mt6360_torch_brightness_set()
163 u32 val = level ? MT6360_FLCSEN_MASK(led->led_no) : 0; in mt6360_torch_brightness_set()
164 u32 prev = priv->fled_torch_used, curr; in mt6360_torch_brightness_set()
167 mutex_lock(&priv->lock); in mt6360_torch_brightness_set()
170 * Only one set of flash control logic, use the flag to avoid strobe is in mt6360_torch_brightness_set()
173 if (priv->fled_strobe_used) { in mt6360_torch_brightness_set()
174 dev_warn(lcdev->dev, "Please disable strobe first [%d]\n", in mt6360_torch_brightness_set()
175 priv->fled_strobe_used); in mt6360_torch_brightness_set()
176 ret = -EBUSY; in mt6360_torch_brightness_set()
181 curr = prev | BIT(led->led_no); in mt6360_torch_brightness_set()
183 curr = prev & ~BIT(led->led_no); in mt6360_torch_brightness_set()
189 ret = regmap_update_bits(priv->regmap, in mt6360_torch_brightness_set()
190 MT6360_REG_FLEDITOR(led->led_no), in mt6360_torch_brightness_set()
191 MT6360_ITORCH_MASK, level - 1); in mt6360_torch_brightness_set()
196 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, enable_mask, in mt6360_torch_brightness_set()
201 priv->fled_torch_used = curr; in mt6360_torch_brightness_set()
204 mutex_unlock(&priv->lock); in mt6360_torch_brightness_set()
212 * Due to the current spike when turning on flash, let brightness to be in mt6360_flash_brightness_set()
223 struct mt6360_led *led = in _mt6360_flash_brightness_set() local
224 container_of(fl_cdev, struct mt6360_led, flash); in _mt6360_flash_brightness_set()
225 struct mt6360_priv *priv = led->priv; in _mt6360_flash_brightness_set()
226 struct led_flash_setting *s = &fl_cdev->brightness; in _mt6360_flash_brightness_set()
227 u32 val = (brightness - s->min) / s->step; in _mt6360_flash_brightness_set()
229 return regmap_update_bits(priv->regmap, in _mt6360_flash_brightness_set()
230 MT6360_REG_FLEDISTRB(led->led_no), in _mt6360_flash_brightness_set()
236 struct mt6360_led *led = in mt6360_strobe_set() local
237 container_of(fl_cdev, struct mt6360_led, flash); in mt6360_strobe_set()
238 struct mt6360_priv *priv = led->priv; in mt6360_strobe_set()
239 struct led_classdev *lcdev = &fl_cdev->led_cdev; in mt6360_strobe_set()
240 struct led_flash_setting *s = &fl_cdev->brightness; in mt6360_strobe_set()
241 u32 enable_mask = MT6360_STROBEN_MASK | MT6360_FLCSEN_MASK(led->led_no); in mt6360_strobe_set()
242 u32 val = state ? MT6360_FLCSEN_MASK(led->led_no) : 0; in mt6360_strobe_set()
243 u32 prev = priv->fled_strobe_used, curr; in mt6360_strobe_set()
246 mutex_lock(&priv->lock); in mt6360_strobe_set()
249 * Only one set of flash control logic, use the flag to avoid torch is in mt6360_strobe_set()
252 if (priv->fled_torch_used) { in mt6360_strobe_set()
253 dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", in mt6360_strobe_set()
254 priv->fled_torch_used); in mt6360_strobe_set()
255 ret = -EBUSY; in mt6360_strobe_set()
260 curr = prev | BIT(led->led_no); in mt6360_strobe_set()
262 curr = prev & ~BIT(led->led_no); in mt6360_strobe_set()
267 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, enable_mask, in mt6360_strobe_set()
270 dev_err(lcdev->dev, "[%d] control current source %d fail\n", in mt6360_strobe_set()
271 led->led_no, state); in mt6360_strobe_set()
276 * If the flash need to be on, config the flash current ramping up to in mt6360_strobe_set()
280 ret = _mt6360_flash_brightness_set(fl_cdev, state ? s->val : s->min); in mt6360_strobe_set()
285 * For the flash turn on/off, HW rampping up/down time is 5ms/500us, in mt6360_strobe_set()
293 priv->fled_strobe_used = curr; in mt6360_strobe_set()
296 mutex_unlock(&priv->lock); in mt6360_strobe_set()
302 struct mt6360_led *led = in mt6360_strobe_get() local
303 container_of(fl_cdev, struct mt6360_led, flash); in mt6360_strobe_get()
304 struct mt6360_priv *priv = led->priv; in mt6360_strobe_get()
306 mutex_lock(&priv->lock); in mt6360_strobe_get()
307 *state = !!(priv->fled_strobe_used & BIT(led->led_no)); in mt6360_strobe_get()
308 mutex_unlock(&priv->lock); in mt6360_strobe_get()
315 struct mt6360_led *led = in mt6360_timeout_set() local
316 container_of(fl_cdev, struct mt6360_led, flash); in mt6360_timeout_set()
317 struct mt6360_priv *priv = led->priv; in mt6360_timeout_set()
318 struct led_flash_setting *s = &fl_cdev->timeout; in mt6360_timeout_set()
319 u32 val = (timeout - s->min) / s->step; in mt6360_timeout_set()
322 mutex_lock(&priv->lock); in mt6360_timeout_set()
323 ret = regmap_update_bits(priv->regmap, MT6360_REG_STRBTO, in mt6360_timeout_set()
325 mutex_unlock(&priv->lock); in mt6360_timeout_set()
332 struct mt6360_led *led = in mt6360_fault_get() local
333 container_of(fl_cdev, struct mt6360_led, flash); in mt6360_fault_get()
334 struct mt6360_priv *priv = led->priv; in mt6360_fault_get()
340 mutex_lock(&priv->lock); in mt6360_fault_get()
341 ret = regmap_read(priv->regmap, MT6360_REG_CHGSTAT2, &chg_stat); in mt6360_fault_get()
345 ret = regmap_raw_read(priv->regmap, MT6360_REG_FLEDSTAT1, &fled_stat, in mt6360_fault_get()
350 if (led->led_no == MT6360_LED_FLASH1) { in mt6360_fault_get()
372 mutex_unlock(&priv->lock); in mt6360_fault_get()
384 static int mt6360_isnk_init_default_state(struct mt6360_led *led) in mt6360_isnk_init_default_state() argument
386 struct mt6360_priv *priv = led->priv; in mt6360_isnk_init_default_state()
391 ret = regmap_read(priv->regmap, MT6360_REG_ISNK(led->led_no), &regval); in mt6360_isnk_init_default_state()
396 ret = regmap_read(priv->regmap, MT6360_REG_RGBEN, &regval); in mt6360_isnk_init_default_state()
400 if (!(regval & MT6360_ISNK_ENMASK(led->led_no))) in mt6360_isnk_init_default_state()
403 switch (led->default_state) { in mt6360_isnk_init_default_state()
405 led->isnk.brightness = led->isnk.max_brightness; in mt6360_isnk_init_default_state()
408 led->isnk.brightness = min(level, led->isnk.max_brightness); in mt6360_isnk_init_default_state()
411 led->isnk.brightness = LED_OFF; in mt6360_isnk_init_default_state()
414 return mt6360_isnk_brightness_set(&led->isnk, led->isnk.brightness); in mt6360_isnk_init_default_state()
417 static int mt6360_flash_init_default_state(struct mt6360_led *led) in mt6360_flash_init_default_state() argument
419 struct led_classdev_flash *flash = &led->flash; in mt6360_flash_init_default_state() local
420 struct mt6360_priv *priv = led->priv; in mt6360_flash_init_default_state()
421 u32 enable_mask = MT6360_TORCHEN_MASK | MT6360_FLCSEN_MASK(led->led_no); in mt6360_flash_init_default_state()
426 ret = regmap_read(priv->regmap, MT6360_REG_FLEDITOR(led->led_no), in mt6360_flash_init_default_state()
432 ret = regmap_read(priv->regmap, MT6360_REG_FLEDEN, &regval); in mt6360_flash_init_default_state()
441 switch (led->default_state) { in mt6360_flash_init_default_state()
443 flash->led_cdev.brightness = flash->led_cdev.max_brightness; in mt6360_flash_init_default_state()
446 flash->led_cdev.brightness = in mt6360_flash_init_default_state()
447 min(level, flash->led_cdev.max_brightness); in mt6360_flash_init_default_state()
450 flash->led_cdev.brightness = LED_OFF; in mt6360_flash_init_default_state()
453 return mt6360_torch_brightness_set(&flash->led_cdev, in mt6360_flash_init_default_state()
454 flash->led_cdev.brightness); in mt6360_flash_init_default_state()
461 struct led_classdev_flash *flash = v4l2_flash->fled_cdev; in mt6360_flash_external_strobe_set() local
462 struct mt6360_led *led = container_of(flash, struct mt6360_led, flash); in mt6360_flash_external_strobe_set() local
463 struct mt6360_priv *priv = led->priv; in mt6360_flash_external_strobe_set()
464 u32 mask = MT6360_FLCSEN_MASK(led->led_no); in mt6360_flash_external_strobe_set()
468 mutex_lock(&priv->lock); in mt6360_flash_external_strobe_set()
470 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, mask, val); in mt6360_flash_external_strobe_set()
475 priv->fled_strobe_used |= BIT(led->led_no); in mt6360_flash_external_strobe_set()
477 priv->fled_strobe_used &= ~BIT(led->led_no); in mt6360_flash_external_strobe_set()
480 mutex_unlock(&priv->lock); in mt6360_flash_external_strobe_set()
488 static void mt6360_init_v4l2_flash_config(struct mt6360_led *led, in mt6360_init_v4l2_flash_config() argument
492 struct led_flash_setting *s = &config->intensity; in mt6360_init_v4l2_flash_config()
494 lcdev = &led->flash.led_cdev; in mt6360_init_v4l2_flash_config()
496 s->min = MT6360_ITORCH_MINUA; in mt6360_init_v4l2_flash_config()
497 s->step = MT6360_ITORCH_STEPUA; in mt6360_init_v4l2_flash_config()
498 s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step; in mt6360_init_v4l2_flash_config()
500 config->has_external_strobe = 1; in mt6360_init_v4l2_flash_config()
501 strscpy(config->dev_name, lcdev->dev->kobj.name, in mt6360_init_v4l2_flash_config()
502 sizeof(config->dev_name)); in mt6360_init_v4l2_flash_config()
504 config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT | in mt6360_init_v4l2_flash_config()
510 static void mt6360_init_v4l2_flash_config(struct mt6360_led *led, in mt6360_init_v4l2_flash_config() argument
516 static int mt6360_led_register(struct device *parent, struct mt6360_led *led, in mt6360_led_register() argument
519 struct mt6360_priv *priv = led->priv; in mt6360_led_register()
523 if ((led->led_no == MT6360_LED_ISNK1 || in mt6360_led_register()
524 led->led_no == MT6360_VIRTUAL_MULTICOLOR) && in mt6360_led_register()
525 (priv->leds_active & BIT(MT6360_LED_ISNK1))) { in mt6360_led_register()
530 ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN, in mt6360_led_register()
539 switch (led->led_no) { in mt6360_led_register()
541 ret = mt6360_mc_brightness_set(&led->mc.led_cdev, LED_OFF); in mt6360_led_register()
549 &led->mc, init_data); in mt6360_led_register()
556 ret = mt6360_isnk_init_default_state(led); in mt6360_led_register()
559 led->led_no); in mt6360_led_register()
563 ret = devm_led_classdev_register_ext(parent, &led->isnk, in mt6360_led_register()
567 led->led_no); in mt6360_led_register()
572 ret = mt6360_flash_init_default_state(led); in mt6360_led_register()
574 dev_err(parent, "Failed to init %d flash state\n", in mt6360_led_register()
575 led->led_no); in mt6360_led_register()
579 ret = devm_led_classdev_flash_register_ext(parent, &led->flash, in mt6360_led_register()
582 dev_err(parent, "Couldn't register flash %d\n", in mt6360_led_register()
583 led->led_no); in mt6360_led_register()
587 mt6360_init_v4l2_flash_config(led, &v4l2_config); in mt6360_led_register()
588 led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode, in mt6360_led_register()
589 &led->flash, in mt6360_led_register()
592 if (IS_ERR(led->v4l2_flash)) { in mt6360_led_register()
594 led->led_no); in mt6360_led_register()
595 return PTR_ERR(led->v4l2_flash); in mt6360_led_register()
608 retval = rounddown(retval - min, step) + min; in clamp_align()
613 static int mt6360_init_isnk_properties(struct mt6360_led *led, in mt6360_init_isnk_properties() argument
617 struct mt6360_priv *priv = led->priv; in mt6360_init_isnk_properties()
623 if (led->led_no == MT6360_VIRTUAL_MULTICOLOR) { in mt6360_init_isnk_properties()
626 sub_led = devm_kzalloc(priv->dev, in mt6360_init_isnk_properties()
629 return -ENOMEM; in mt6360_init_isnk_properties()
631 fwnode_for_each_child_node(init_data->fwnode, child) { in mt6360_init_isnk_properties()
636 priv->leds_active & BIT(reg)) { in mt6360_init_isnk_properties()
638 return -EINVAL; in mt6360_init_isnk_properties()
643 dev_err(priv->dev, in mt6360_init_isnk_properties()
644 "led %d, no color specified\n", in mt6360_init_isnk_properties()
645 led->led_no); in mt6360_init_isnk_properties()
650 priv->leds_active |= BIT(reg); in mt6360_init_isnk_properties()
657 dev_err(priv->dev, in mt6360_init_isnk_properties()
658 "Multicolor must include 2 or more led channel\n"); in mt6360_init_isnk_properties()
659 return -EINVAL; in mt6360_init_isnk_properties()
662 led->mc.num_colors = num_color; in mt6360_init_isnk_properties()
663 led->mc.subled_info = sub_led; in mt6360_init_isnk_properties()
665 lcdev = &led->mc.led_cdev; in mt6360_init_isnk_properties()
666 lcdev->brightness_set_blocking = mt6360_mc_brightness_set; in mt6360_init_isnk_properties()
668 if (led->led_no == MT6360_LED_ISNKML) { in mt6360_init_isnk_properties()
673 lcdev = &led->isnk; in mt6360_init_isnk_properties()
674 lcdev->brightness_set_blocking = mt6360_isnk_brightness_set; in mt6360_init_isnk_properties()
677 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", in mt6360_init_isnk_properties()
680 dev_warn(priv->dev, in mt6360_init_isnk_properties()
681 "Not specified led-max-microamp, config to the minimum\n"); in mt6360_init_isnk_properties()
686 lcdev->max_brightness = val / step_uA; in mt6360_init_isnk_properties()
688 fwnode_property_read_string(init_data->fwnode, "linux,default-trigger", in mt6360_init_isnk_properties()
689 &lcdev->default_trigger); in mt6360_init_isnk_properties()
694 static int mt6360_init_flash_properties(struct mt6360_led *led, in mt6360_init_flash_properties() argument
697 struct led_classdev_flash *flash = &led->flash; in mt6360_init_flash_properties() local
698 struct led_classdev *lcdev = &flash->led_cdev; in mt6360_init_flash_properties()
699 struct mt6360_priv *priv = led->priv; in mt6360_init_flash_properties()
704 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", in mt6360_init_flash_properties()
707 dev_warn(priv->dev, in mt6360_init_flash_properties()
708 "Not specified led-max-microamp, config to the minimum\n"); in mt6360_init_flash_properties()
714 lcdev->max_brightness = in mt6360_init_flash_properties()
715 (val - MT6360_ITORCH_MINUA) / MT6360_ITORCH_STEPUA + 1; in mt6360_init_flash_properties()
716 lcdev->brightness_set_blocking = mt6360_torch_brightness_set; in mt6360_init_flash_properties()
717 lcdev->flags |= LED_DEV_CAP_FLASH; in mt6360_init_flash_properties()
719 ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", in mt6360_init_flash_properties()
722 dev_warn(priv->dev, in mt6360_init_flash_properties()
723 "Not specified flash-max-microamp, config to the minimum\n"); in mt6360_init_flash_properties()
729 s = &flash->brightness; in mt6360_init_flash_properties()
730 s->min = MT6360_ISTRB_MINUA; in mt6360_init_flash_properties()
731 s->step = MT6360_ISTRB_STEPUA; in mt6360_init_flash_properties()
732 s->val = s->max = val; in mt6360_init_flash_properties()
735 * Always configure as min level when off to prevent flash current in mt6360_init_flash_properties()
738 ret = _mt6360_flash_brightness_set(flash, s->min); in mt6360_init_flash_properties()
742 ret = fwnode_property_read_u32(init_data->fwnode, in mt6360_init_flash_properties()
743 "flash-max-timeout-us", &val); in mt6360_init_flash_properties()
745 dev_warn(priv->dev, in mt6360_init_flash_properties()
746 "Not specified flash-max-timeout-us, config to the minimum\n"); in mt6360_init_flash_properties()
752 s = &flash->timeout; in mt6360_init_flash_properties()
753 s->min = MT6360_STRBTO_MINUS; in mt6360_init_flash_properties()
754 s->step = MT6360_STRBTO_STEPUS; in mt6360_init_flash_properties()
755 s->val = s->max = val; in mt6360_init_flash_properties()
757 flash->ops = &mt6360_flash_ops; in mt6360_init_flash_properties()
766 for (i = 0; i < priv->leds_count; i++) { in mt6360_v4l2_flash_release()
767 struct mt6360_led *led = priv->leds + i; in mt6360_v4l2_flash_release() local
769 if (led->v4l2_flash) in mt6360_v4l2_flash_release()
770 v4l2_flash_release(led->v4l2_flash); in mt6360_v4l2_flash_release()
780 count = device_get_child_node_count(&pdev->dev); in mt6360_led_probe()
782 dev_err(&pdev->dev, in mt6360_led_probe()
783 "No child node or node count over max led number %zu\n", in mt6360_led_probe()
785 return -EINVAL; in mt6360_led_probe()
788 priv = devm_kzalloc(&pdev->dev, in mt6360_led_probe()
791 return -ENOMEM; in mt6360_led_probe()
793 priv->leds_count = count; in mt6360_led_probe()
794 priv->dev = &pdev->dev; in mt6360_led_probe()
795 mutex_init(&priv->lock); in mt6360_led_probe()
797 priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); in mt6360_led_probe()
798 if (!priv->regmap) { in mt6360_led_probe()
799 dev_err(&pdev->dev, "Failed to get parent regmap\n"); in mt6360_led_probe()
800 return -ENODEV; in mt6360_led_probe()
803 device_for_each_child_node_scoped(&pdev->dev, child) { in mt6360_led_probe()
804 struct mt6360_led *led = priv->leds + i; in mt6360_led_probe() local
821 ret = -EINVAL; in mt6360_led_probe()
826 if (priv->leds_active & BIT(reg)) { in mt6360_led_probe()
827 ret = -EINVAL; in mt6360_led_probe()
830 priv->leds_active |= BIT(reg); in mt6360_led_probe()
832 led->led_no = reg; in mt6360_led_probe()
833 led->priv = priv; in mt6360_led_probe()
834 led->default_state = led_init_default_state_get(child); in mt6360_led_probe()
838 ret = mt6360_init_isnk_properties(led, &init_data); in mt6360_led_probe()
840 ret = mt6360_init_flash_properties(led, &init_data); in mt6360_led_probe()
845 ret = mt6360_led_register(&pdev->dev, led, &init_data); in mt6360_led_probe()
869 { .compatible = "mediatek,mt6360-led", },
876 .name = "mt6360-led",
885 MODULE_DESCRIPTION("MT6360 LED Driver");