Lines Matching +full:flash +full:- +full:max +full:- +full:timeout +full:- +full:us

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
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()
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()
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()
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()
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()
253 if (state == !!(BIT(led->led_no) & prev)) { in mt6360_strobe_set()
254 dev_info(lcdev->dev, "No change in strobe state [0x%x]\n", prev); in mt6360_strobe_set()
259 * Only one set of flash control logic, use the flag to avoid torch is in mt6360_strobe_set()
262 if (priv->fled_torch_used) { in mt6360_strobe_set()
263 dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", in mt6360_strobe_set()
264 priv->fled_torch_used); in mt6360_strobe_set()
265 ret = -EBUSY; in mt6360_strobe_set()
270 curr = prev | BIT(led->led_no); in mt6360_strobe_set()
272 curr = prev & ~BIT(led->led_no); in mt6360_strobe_set()
277 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, enable_mask, in mt6360_strobe_set()
280 dev_err(lcdev->dev, "[%d] control current source %d fail\n", in mt6360_strobe_set()
281 led->led_no, state); in mt6360_strobe_set()
286 * If the flash need to be on, config the flash current ramping up to in mt6360_strobe_set()
290 ret = _mt6360_flash_brightness_set(fl_cdev, state ? s->val : s->min); in mt6360_strobe_set()
295 * For the flash turn on/off, HW rampping up/down time is 5ms/500us, in mt6360_strobe_set()
303 priv->fled_strobe_used = curr; in mt6360_strobe_set()
306 mutex_unlock(&priv->lock); in mt6360_strobe_set()
313 container_of(fl_cdev, struct mt6360_led, flash); in mt6360_strobe_get()
314 struct mt6360_priv *priv = led->priv; in mt6360_strobe_get()
316 mutex_lock(&priv->lock); in mt6360_strobe_get()
317 *state = !!(priv->fled_strobe_used & BIT(led->led_no)); in mt6360_strobe_get()
318 mutex_unlock(&priv->lock); in mt6360_strobe_get()
323 static int mt6360_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout) in mt6360_timeout_set() argument
326 container_of(fl_cdev, struct mt6360_led, flash); in mt6360_timeout_set()
327 struct mt6360_priv *priv = led->priv; in mt6360_timeout_set()
328 struct led_flash_setting *s = &fl_cdev->timeout; in mt6360_timeout_set()
329 u32 val = (timeout - s->min) / s->step; in mt6360_timeout_set()
332 mutex_lock(&priv->lock); in mt6360_timeout_set()
333 ret = regmap_update_bits(priv->regmap, MT6360_REG_STRBTO, in mt6360_timeout_set()
335 mutex_unlock(&priv->lock); in mt6360_timeout_set()
343 container_of(fl_cdev, struct mt6360_led, flash); in mt6360_fault_get()
344 struct mt6360_priv *priv = led->priv; in mt6360_fault_get()
350 mutex_lock(&priv->lock); in mt6360_fault_get()
351 ret = regmap_read(priv->regmap, MT6360_REG_CHGSTAT2, &chg_stat); in mt6360_fault_get()
355 ret = regmap_raw_read(priv->regmap, MT6360_REG_FLEDSTAT1, &fled_stat, in mt6360_fault_get()
360 if (led->led_no == MT6360_LED_FLASH1) { in mt6360_fault_get()
382 mutex_unlock(&priv->lock); in mt6360_fault_get()
396 struct mt6360_priv *priv = led->priv; in mt6360_isnk_init_default_state()
401 ret = regmap_read(priv->regmap, MT6360_REG_ISNK(led->led_no), &regval); in mt6360_isnk_init_default_state()
406 ret = regmap_read(priv->regmap, MT6360_REG_RGBEN, &regval); in mt6360_isnk_init_default_state()
410 if (!(regval & MT6360_ISNK_ENMASK(led->led_no))) in mt6360_isnk_init_default_state()
413 switch (led->default_state) { in mt6360_isnk_init_default_state()
415 led->isnk.brightness = led->isnk.max_brightness; in mt6360_isnk_init_default_state()
418 led->isnk.brightness = min(level, led->isnk.max_brightness); in mt6360_isnk_init_default_state()
421 led->isnk.brightness = LED_OFF; in mt6360_isnk_init_default_state()
424 return mt6360_isnk_brightness_set(&led->isnk, led->isnk.brightness); in mt6360_isnk_init_default_state()
429 struct led_classdev_flash *flash = &led->flash; in mt6360_flash_init_default_state() local
430 struct mt6360_priv *priv = led->priv; in mt6360_flash_init_default_state()
431 u32 enable_mask = MT6360_TORCHEN_MASK | MT6360_FLCSEN_MASK(led->led_no); in mt6360_flash_init_default_state()
436 ret = regmap_read(priv->regmap, MT6360_REG_FLEDITOR(led->led_no), in mt6360_flash_init_default_state()
442 ret = regmap_read(priv->regmap, MT6360_REG_FLEDEN, &regval); in mt6360_flash_init_default_state()
451 switch (led->default_state) { in mt6360_flash_init_default_state()
453 flash->led_cdev.brightness = flash->led_cdev.max_brightness; in mt6360_flash_init_default_state()
456 flash->led_cdev.brightness = in mt6360_flash_init_default_state()
457 min(level, flash->led_cdev.max_brightness); in mt6360_flash_init_default_state()
460 flash->led_cdev.brightness = LED_OFF; in mt6360_flash_init_default_state()
463 return mt6360_torch_brightness_set(&flash->led_cdev, in mt6360_flash_init_default_state()
464 flash->led_cdev.brightness); in mt6360_flash_init_default_state()
471 struct led_classdev_flash *flash = v4l2_flash->fled_cdev; in mt6360_flash_external_strobe_set() local
472 struct mt6360_led *led = container_of(flash, struct mt6360_led, flash); in mt6360_flash_external_strobe_set()
473 struct mt6360_priv *priv = led->priv; in mt6360_flash_external_strobe_set()
474 u32 mask = MT6360_FLCSEN_MASK(led->led_no); in mt6360_flash_external_strobe_set()
478 mutex_lock(&priv->lock); in mt6360_flash_external_strobe_set()
480 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, mask, val); in mt6360_flash_external_strobe_set()
485 priv->fled_strobe_used |= BIT(led->led_no); in mt6360_flash_external_strobe_set()
487 priv->fled_strobe_used &= ~BIT(led->led_no); in mt6360_flash_external_strobe_set()
490 mutex_unlock(&priv->lock); in mt6360_flash_external_strobe_set()
502 struct led_flash_setting *s = &config->intensity; in mt6360_init_v4l2_flash_config()
504 lcdev = &led->flash.led_cdev; in mt6360_init_v4l2_flash_config()
506 s->min = MT6360_ITORCH_MINUA; in mt6360_init_v4l2_flash_config()
507 s->step = MT6360_ITORCH_STEPUA; in mt6360_init_v4l2_flash_config()
508 s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step; in mt6360_init_v4l2_flash_config()
510 config->has_external_strobe = 1; in mt6360_init_v4l2_flash_config()
511 strscpy(config->dev_name, lcdev->dev->kobj.name, in mt6360_init_v4l2_flash_config()
512 sizeof(config->dev_name)); in mt6360_init_v4l2_flash_config()
514 config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT | in mt6360_init_v4l2_flash_config()
529 struct mt6360_priv *priv = led->priv; in mt6360_led_register()
533 if ((led->led_no == MT6360_LED_ISNK1 || in mt6360_led_register()
534 led->led_no == MT6360_VIRTUAL_MULTICOLOR) && in mt6360_led_register()
535 (priv->leds_active & BIT(MT6360_LED_ISNK1))) { in mt6360_led_register()
540 ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN, in mt6360_led_register()
549 switch (led->led_no) { in mt6360_led_register()
551 ret = mt6360_mc_brightness_set(&led->mc.led_cdev, LED_OFF); in mt6360_led_register()
559 &led->mc, init_data); in mt6360_led_register()
569 led->led_no); in mt6360_led_register()
573 ret = devm_led_classdev_register_ext(parent, &led->isnk, in mt6360_led_register()
577 led->led_no); in mt6360_led_register()
584 dev_err(parent, "Failed to init %d flash state\n", in mt6360_led_register()
585 led->led_no); in mt6360_led_register()
589 ret = devm_led_classdev_flash_register_ext(parent, &led->flash, in mt6360_led_register()
592 dev_err(parent, "Couldn't register flash %d\n", in mt6360_led_register()
593 led->led_no); in mt6360_led_register()
598 led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode, in mt6360_led_register()
599 &led->flash, in mt6360_led_register()
602 if (IS_ERR(led->v4l2_flash)) { in mt6360_led_register()
604 led->led_no); in mt6360_led_register()
605 return PTR_ERR(led->v4l2_flash); in mt6360_led_register()
612 static u32 clamp_align(u32 val, u32 min, u32 max, u32 step) in clamp_align() argument
616 retval = clamp_val(val, min, max); in clamp_align()
618 retval = rounddown(retval - min, step) + min; in clamp_align()
627 struct mt6360_priv *priv = led->priv; in mt6360_init_isnk_properties()
633 if (led->led_no == MT6360_VIRTUAL_MULTICOLOR) { in mt6360_init_isnk_properties()
636 sub_led = devm_kzalloc(priv->dev, in mt6360_init_isnk_properties()
639 return -ENOMEM; in mt6360_init_isnk_properties()
641 fwnode_for_each_child_node(init_data->fwnode, child) { in mt6360_init_isnk_properties()
646 priv->leds_active & BIT(reg)) { in mt6360_init_isnk_properties()
648 return -EINVAL; in mt6360_init_isnk_properties()
653 dev_err(priv->dev, in mt6360_init_isnk_properties()
655 led->led_no); in mt6360_init_isnk_properties()
660 priv->leds_active |= BIT(reg); in mt6360_init_isnk_properties()
667 dev_err(priv->dev, in mt6360_init_isnk_properties()
669 return -EINVAL; in mt6360_init_isnk_properties()
672 led->mc.num_colors = num_color; in mt6360_init_isnk_properties()
673 led->mc.subled_info = sub_led; in mt6360_init_isnk_properties()
675 lcdev = &led->mc.led_cdev; in mt6360_init_isnk_properties()
676 lcdev->brightness_set_blocking = mt6360_mc_brightness_set; in mt6360_init_isnk_properties()
678 if (led->led_no == MT6360_LED_ISNKML) { in mt6360_init_isnk_properties()
683 lcdev = &led->isnk; in mt6360_init_isnk_properties()
684 lcdev->brightness_set_blocking = mt6360_isnk_brightness_set; in mt6360_init_isnk_properties()
687 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", in mt6360_init_isnk_properties()
690 dev_warn(priv->dev, in mt6360_init_isnk_properties()
691 "Not specified led-max-microamp, config to the minimum\n"); in mt6360_init_isnk_properties()
696 lcdev->max_brightness = val / step_uA; in mt6360_init_isnk_properties()
698 fwnode_property_read_string(init_data->fwnode, "linux,default-trigger", in mt6360_init_isnk_properties()
699 &lcdev->default_trigger); in mt6360_init_isnk_properties()
707 struct led_classdev_flash *flash = &led->flash; in mt6360_init_flash_properties() local
708 struct led_classdev *lcdev = &flash->led_cdev; in mt6360_init_flash_properties()
709 struct mt6360_priv *priv = led->priv; in mt6360_init_flash_properties()
714 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", in mt6360_init_flash_properties()
717 dev_warn(priv->dev, in mt6360_init_flash_properties()
718 "Not specified led-max-microamp, config to the minimum\n"); in mt6360_init_flash_properties()
724 lcdev->max_brightness = in mt6360_init_flash_properties()
725 (val - MT6360_ITORCH_MINUA) / MT6360_ITORCH_STEPUA + 1; in mt6360_init_flash_properties()
726 lcdev->brightness_set_blocking = mt6360_torch_brightness_set; in mt6360_init_flash_properties()
727 lcdev->flags |= LED_DEV_CAP_FLASH; in mt6360_init_flash_properties()
729 ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", in mt6360_init_flash_properties()
732 dev_warn(priv->dev, in mt6360_init_flash_properties()
733 "Not specified flash-max-microamp, config to the minimum\n"); in mt6360_init_flash_properties()
739 s = &flash->brightness; in mt6360_init_flash_properties()
740 s->min = MT6360_ISTRB_MINUA; in mt6360_init_flash_properties()
741 s->step = MT6360_ISTRB_STEPUA; in mt6360_init_flash_properties()
742 s->val = s->max = val; in mt6360_init_flash_properties()
745 * Always configure as min level when off to prevent flash current in mt6360_init_flash_properties()
748 ret = _mt6360_flash_brightness_set(flash, s->min); in mt6360_init_flash_properties()
752 ret = fwnode_property_read_u32(init_data->fwnode, in mt6360_init_flash_properties()
753 "flash-max-timeout-us", &val); in mt6360_init_flash_properties()
755 dev_warn(priv->dev, in mt6360_init_flash_properties()
756 "Not specified flash-max-timeout-us, config to the minimum\n"); in mt6360_init_flash_properties()
762 s = &flash->timeout; in mt6360_init_flash_properties()
763 s->min = MT6360_STRBTO_MINUS; in mt6360_init_flash_properties()
764 s->step = MT6360_STRBTO_STEPUS; in mt6360_init_flash_properties()
765 s->val = s->max = val; in mt6360_init_flash_properties()
767 flash->ops = &mt6360_flash_ops; in mt6360_init_flash_properties()
776 for (i = 0; i < priv->leds_count; i++) { in mt6360_v4l2_flash_release()
777 struct mt6360_led *led = priv->leds + i; in mt6360_v4l2_flash_release()
779 if (led->v4l2_flash) in mt6360_v4l2_flash_release()
780 v4l2_flash_release(led->v4l2_flash); in mt6360_v4l2_flash_release()
791 count = device_get_child_node_count(&pdev->dev); in mt6360_led_probe()
793 dev_err(&pdev->dev, in mt6360_led_probe()
794 "No child node or node count over max led number %zu\n", in mt6360_led_probe()
796 return -EINVAL; in mt6360_led_probe()
799 priv = devm_kzalloc(&pdev->dev, in mt6360_led_probe()
802 return -ENOMEM; in mt6360_led_probe()
804 priv->leds_count = count; in mt6360_led_probe()
805 priv->dev = &pdev->dev; in mt6360_led_probe()
806 mutex_init(&priv->lock); in mt6360_led_probe()
808 priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); in mt6360_led_probe()
809 if (!priv->regmap) { in mt6360_led_probe()
810 dev_err(&pdev->dev, "Failed to get parent regmap\n"); in mt6360_led_probe()
811 return -ENODEV; in mt6360_led_probe()
814 device_for_each_child_node(&pdev->dev, child) { in mt6360_led_probe()
815 struct mt6360_led *led = priv->leds + i; in mt6360_led_probe()
832 ret = -EINVAL; in mt6360_led_probe()
837 if (priv->leds_active & BIT(reg)) { in mt6360_led_probe()
838 ret = -EINVAL; in mt6360_led_probe()
841 priv->leds_active |= BIT(reg); in mt6360_led_probe()
843 led->led_no = reg; in mt6360_led_probe()
844 led->priv = priv; in mt6360_led_probe()
845 led->default_state = led_init_default_state_get(child); in mt6360_led_probe()
856 ret = mt6360_led_register(&pdev->dev, led, &init_data); in mt6360_led_probe()
879 { .compatible = "mediatek,mt6360-led", },
886 .name = "mt6360-led",