Lines Matching +full:flash +full:- +full:max +full:- +full:microamp
1 // SPDX-License-Identifier: GPL-2.0-only
9 #include <linux/led-class-flash.h>
14 #include <media/v4l2-flash-led-class.h>
163 struct led_classdev_flash flash; member
177 struct qcom_flash_data *flash_data = led->flash_data; in set_flash_module_en()
181 for (i = 0; i < led->chan_count; i++) in set_flash_module_en()
182 led_mask |= BIT(led->chan_id[i]); in set_flash_module_en()
184 mutex_lock(&flash_data->lock); in set_flash_module_en()
186 flash_data->chan_en_bits |= led_mask; in set_flash_module_en()
188 flash_data->chan_en_bits &= ~led_mask; in set_flash_module_en()
190 enable = !!flash_data->chan_en_bits; in set_flash_module_en()
191 rc = regmap_field_write(flash_data->r_fields[REG_MODULE_EN], enable); in set_flash_module_en()
193 dev_err(led->flash.led_cdev.dev, "write module_en failed, rc=%d\n", rc); in set_flash_module_en()
194 mutex_unlock(&flash_data->lock); in set_flash_module_en()
201 struct qcom_flash_data *flash_data = led->flash_data; in update_allowed_flash_current()
205 mutex_lock(&flash_data->lock); in update_allowed_flash_current()
211 if (!strobe || led->current_in_use_ma != 0) { in update_allowed_flash_current()
212 if (flash_data->total_ma >= led->current_in_use_ma) in update_allowed_flash_current()
213 flash_data->total_ma -= led->current_in_use_ma; in update_allowed_flash_current()
215 flash_data->total_ma = 0; in update_allowed_flash_current()
217 led->current_in_use_ma = 0; in update_allowed_flash_current()
224 * reading over-temp real time status. If over-temp has been triggered at the lowest in update_allowed_flash_current()
226 * when more flash current is requested. Prevent device from triggering over-temp condition in update_allowed_flash_current()
227 * by limiting the flash current for the new request. in update_allowed_flash_current()
229 rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH1], &thrsh[0]); in update_allowed_flash_current()
233 rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH2], &thrsh[1]); in update_allowed_flash_current()
237 if (flash_data->hw_type == QCOM_MVFLASH_3CH) { in update_allowed_flash_current()
238 rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH3], &thrsh[2]); in update_allowed_flash_current()
244 if (flash_data->hw_type == QCOM_MVFLASH_4CH) in update_allowed_flash_current()
245 min_thrsh = (flash_data->revision == FLASH_4CH_REVISION_V0P1) ? in update_allowed_flash_current()
248 rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH1], min_thrsh); in update_allowed_flash_current()
252 if (flash_data->hw_type == QCOM_MVFLASH_4CH) in update_allowed_flash_current()
259 rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH2], min_thrsh); in update_allowed_flash_current()
263 if (flash_data->hw_type == QCOM_MVFLASH_3CH) { in update_allowed_flash_current()
264 rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH3], min_thrsh); in update_allowed_flash_current()
269 /* Read thermal level status to get corresponding derating flash current */ in update_allowed_flash_current()
270 rc = regmap_field_read(flash_data->r_fields[REG_STATUS2], &sts); in update_allowed_flash_current()
275 if (flash_data->hw_type == QCOM_MVFLASH_3CH) { in update_allowed_flash_current()
289 /* Calculate the allowed flash current for the request */ in update_allowed_flash_current()
290 if (therm_ma <= flash_data->total_ma) in update_allowed_flash_current()
293 avail_ma = therm_ma - flash_data->total_ma; in update_allowed_flash_current()
296 led->current_in_use_ma = *current_ma; in update_allowed_flash_current()
297 flash_data->total_ma += led->current_in_use_ma; in update_allowed_flash_current()
299 dev_dbg(led->flash.led_cdev.dev, "allowed flash current: %dmA, total current: %dmA\n", in update_allowed_flash_current()
300 led->current_in_use_ma, flash_data->total_ma); in update_allowed_flash_current()
304 rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH1], thrsh[0]); in update_allowed_flash_current()
308 rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH2], thrsh[1]); in update_allowed_flash_current()
312 if (flash_data->hw_type == QCOM_MVFLASH_3CH) in update_allowed_flash_current()
313 rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH3], thrsh[2]); in update_allowed_flash_current()
316 mutex_unlock(&flash_data->lock); in update_allowed_flash_current()
322 struct qcom_flash_data *flash_data = led->flash_data; in set_flash_current()
331 itarg_ua = (current_ma * UA_PER_MA) / led->chan_count + 1; in set_flash_current()
334 for (i = 0; i < led->chan_count; i++) { in set_flash_current()
338 itarget = itarg_ua / ires_ua - 1; in set_flash_current()
340 chan_id = led->chan_id[i]; in set_flash_current()
342 rc = regmap_fields_write(flash_data->r_fields[REG_ITARGET], chan_id, itarget); in set_flash_current()
346 if (flash_data->hw_type == QCOM_MVFLASH_3CH) { in set_flash_current()
352 } else if (flash_data->hw_type == QCOM_MVFLASH_4CH) { in set_flash_current()
359 dev_err(led->flash.led_cdev.dev, in set_flash_current()
360 "HW type %d is not supported\n", flash_data->hw_type); in set_flash_current()
361 return -EOPNOTSUPP; in set_flash_current()
365 return regmap_field_update_bits(flash_data->r_fields[REG_IRESOLUTION], ires_mask, ires_val); in set_flash_current()
370 struct qcom_flash_data *flash_data = led->flash_data; in set_flash_timeout()
375 timeout_ms = min_t(u32, timeout_ms, led->max_timeout_ms); in set_flash_timeout()
377 for (i = 0; i < led->chan_count; i++) { in set_flash_timeout()
378 chan_id = led->chan_id[i]; in set_flash_timeout()
386 rc = regmap_fields_write(flash_data->r_fields[REG_CHAN_TIMER], chan_id, timer); in set_flash_timeout()
396 struct qcom_flash_data *flash_data = led->flash_data; in set_flash_strobe()
401 for (i = 0; i < led->chan_count; i++) { in set_flash_strobe()
402 chan_id = led->chan_id[i]; in set_flash_strobe()
414 flash_data->r_fields[REG_CHAN_STROBE], chan_id, strobe_sel); in set_flash_strobe()
421 /* Enable/disable flash channels */ in set_flash_strobe()
423 rc = regmap_field_update_bits(flash_data->r_fields[REG_CHAN_EN], chan_mask, chan_en); in set_flash_strobe()
427 led->enabled = state; in set_flash_strobe()
433 return container_of(flcdev, struct qcom_flash_led, flash); in flcdev_to_qcom_fled()
440 led->flash_current_ma = min_t(u32, led->max_flash_current_ma, brightness / UA_PER_MA); in qcom_flash_brightness_set()
448 led->flash_timeout_ms = timeout / USEC_PER_MSEC; in qcom_flash_timeout_set()
461 rc = update_allowed_flash_current(led, &led->flash_current_ma, state); in qcom_flash_strobe_set()
465 rc = set_flash_current(led, led->flash_current_ma, FLASH_MODE); in qcom_flash_strobe_set()
469 rc = set_flash_timeout(led, led->flash_timeout_ms); in qcom_flash_strobe_set()
484 *state = led->enabled; in qcom_flash_strobe_get()
491 struct qcom_flash_data *flash_data = led->flash_data; in qcom_flash_fault_get()
497 rc = regmap_field_read(flash_data->r_fields[REG_STATUS1], &val); in qcom_flash_fault_get()
501 for (i = 0; i < led->chan_count; i++) { in qcom_flash_fault_get()
502 chan_id = led->chan_id[i]; in qcom_flash_fault_get()
511 rc = regmap_field_read(flash_data->r_fields[REG_STATUS2], &val); in qcom_flash_fault_get()
515 if (flash_data->hw_type == QCOM_MVFLASH_3CH) { in qcom_flash_fault_get()
524 } else if (flash_data->hw_type == QCOM_MVFLASH_4CH) { in qcom_flash_fault_get()
543 rc = regmap_field_read(flash_data->r_fields[REG_STATUS3], &val); in qcom_flash_fault_get()
547 if (flash_data->hw_type == QCOM_MVFLASH_3CH) { in qcom_flash_fault_get()
550 } else if (flash_data->hw_type == QCOM_MVFLASH_4CH) { in qcom_flash_fault_get()
551 for (i = 0; i < led->chan_count; i++) { in qcom_flash_fault_get()
552 chan_id = led->chan_id[i]; in qcom_flash_fault_get()
569 u32 current_ma = brightness * led->max_torch_current_ma / LED_FULL; in qcom_flash_led_brightness_set()
589 /* Disable flash timeout for torch LED */ in qcom_flash_led_brightness_set()
612 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; in qcom_flash_external_strobe_set()
629 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; in qcom_flash_intensity_to_led_brightness()
633 current_ma = min_t(u32, current_ma, led->max_torch_current_ma); in qcom_flash_intensity_to_led_brightness()
637 return (current_ma * LED_FULL) / led->max_torch_current_ma; in qcom_flash_intensity_to_led_brightness()
643 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; in qcom_flash_brightness_to_led_intensity()
646 return (brightness * led->max_torch_current_ma * UA_PER_MA) / LED_FULL; in qcom_flash_brightness_to_led_intensity()
658 struct qcom_flash_data *flash_data = led->flash_data; in qcom_flash_v4l2_init()
663 if (!(led->flash.led_cdev.flags & LED_DEV_CAP_FLASH)) in qcom_flash_v4l2_init()
666 intensity->min = intensity->step = TORCH_IRES_UA * led->chan_count; in qcom_flash_v4l2_init()
667 intensity->max = led->max_torch_current_ma * UA_PER_MA; in qcom_flash_v4l2_init()
668 intensity->val = min_t(u32, intensity->max, TORCH_CURRENT_DEFAULT_UA); in qcom_flash_v4l2_init()
670 strscpy(v4l2_cfg.dev_name, led->flash.led_cdev.dev->kobj.name, in qcom_flash_v4l2_init()
680 v4l2_flash = v4l2_flash_init(dev, fwnode, &led->flash, &qcom_v4l2_flash_ops, &v4l2_cfg); in qcom_flash_v4l2_init()
684 flash_data->v4l2_flash[flash_data->leds_count] = v4l2_flash; in qcom_flash_v4l2_init()
698 struct qcom_flash_data *flash_data = led->flash_data; in qcom_flash_register_led_device()
700 struct led_classdev_flash *flash = &led->flash; in qcom_flash_register_led_device() local
706 count = fwnode_property_count_u32(node, "led-sources"); in qcom_flash_register_led_device()
708 dev_err(dev, "No led-sources specified\n"); in qcom_flash_register_led_device()
709 return -ENODEV; in qcom_flash_register_led_device()
712 if (count > flash_data->max_channels) { in qcom_flash_register_led_device()
713 dev_err(dev, "led-sources count %u exceeds maximum channel count %u\n", in qcom_flash_register_led_device()
714 count, flash_data->max_channels); in qcom_flash_register_led_device()
715 return -EINVAL; in qcom_flash_register_led_device()
718 rc = fwnode_property_read_u32_array(node, "led-sources", channels, count); in qcom_flash_register_led_device()
720 dev_err(dev, "Failed to read led-sources property, rc=%d\n", rc); in qcom_flash_register_led_device()
724 led->chan_count = count; in qcom_flash_register_led_device()
725 led->chan_id = devm_kcalloc(dev, count, sizeof(u8), GFP_KERNEL); in qcom_flash_register_led_device()
726 if (!led->chan_id) in qcom_flash_register_led_device()
727 return -ENOMEM; in qcom_flash_register_led_device()
730 if ((channels[i] == 0) || (channels[i] > flash_data->max_channels)) { in qcom_flash_register_led_device()
731 dev_err(dev, "led-source out of HW support range [1-%u]\n", in qcom_flash_register_led_device()
732 flash_data->max_channels); in qcom_flash_register_led_device()
733 return -EINVAL; in qcom_flash_register_led_device()
737 led->chan_id[i] = channels[i] - 1; in qcom_flash_register_led_device()
740 rc = fwnode_property_read_u32(node, "led-max-microamp", ¤t_ua); in qcom_flash_register_led_device()
742 dev_err(dev, "Failed to read led-max-microamp property, rc=%d\n", rc); in qcom_flash_register_led_device()
747 dev_err(dev, "led-max-microamp shouldn't be 0\n"); in qcom_flash_register_led_device()
748 return -EINVAL; in qcom_flash_register_led_device()
751 current_ua = min_t(u32, current_ua, TORCH_CURRENT_MAX_UA * led->chan_count); in qcom_flash_register_led_device()
752 led->max_torch_current_ma = current_ua / UA_PER_MA; in qcom_flash_register_led_device()
754 if (fwnode_property_present(node, "flash-max-microamp")) { in qcom_flash_register_led_device()
755 flash->led_cdev.flags |= LED_DEV_CAP_FLASH; in qcom_flash_register_led_device()
757 rc = fwnode_property_read_u32(node, "flash-max-microamp", ¤t_ua); in qcom_flash_register_led_device()
759 dev_err(dev, "Failed to read flash-max-microamp property, rc=%d\n", in qcom_flash_register_led_device()
764 current_ua = min_t(u32, current_ua, FLASH_CURRENT_MAX_UA * led->chan_count); in qcom_flash_register_led_device()
767 /* Initialize flash class LED device brightness settings */ in qcom_flash_register_led_device()
768 brightness = &flash->brightness; in qcom_flash_register_led_device()
769 brightness->min = brightness->step = FLASH_IRES_UA * led->chan_count; in qcom_flash_register_led_device()
770 brightness->max = current_ua; in qcom_flash_register_led_device()
771 brightness->val = min_t(u32, current_ua, FLASH_CURRENT_DEFAULT_UA); in qcom_flash_register_led_device()
773 led->max_flash_current_ma = current_ua / UA_PER_MA; in qcom_flash_register_led_device()
774 led->flash_current_ma = brightness->val / UA_PER_MA; in qcom_flash_register_led_device()
776 rc = fwnode_property_read_u32(node, "flash-max-timeout-us", &timeout_us); in qcom_flash_register_led_device()
778 dev_err(dev, "Failed to read flash-max-timeout-us property, rc=%d\n", in qcom_flash_register_led_device()
785 /* Initialize flash class LED device timeout settings */ in qcom_flash_register_led_device()
786 timeout = &flash->timeout; in qcom_flash_register_led_device()
787 timeout->min = timeout->step = FLASH_TIMEOUT_STEP_US; in qcom_flash_register_led_device()
788 timeout->val = timeout->max = timeout_us; in qcom_flash_register_led_device()
790 led->max_timeout_ms = led->flash_timeout_ms = timeout_us / USEC_PER_MSEC; in qcom_flash_register_led_device()
792 flash->ops = &qcom_flash_ops; in qcom_flash_register_led_device()
795 flash->led_cdev.brightness_set_blocking = qcom_flash_led_brightness_set; in qcom_flash_register_led_device()
802 rc = devm_led_classdev_flash_register_ext(dev, flash, &init_data); in qcom_flash_register_led_device()
804 dev_err(dev, "Register flash LED classdev failed, rc=%d\n", rc); in qcom_flash_register_led_device()
816 struct device *dev = &pdev->dev; in qcom_flash_led_probe()
824 return -ENOMEM; in qcom_flash_led_probe()
826 regmap = dev_get_regmap(dev->parent, NULL); in qcom_flash_led_probe()
829 return -EINVAL; in qcom_flash_led_probe()
832 rc = fwnode_property_read_u32(dev->fwnode, "reg", ®_base); in qcom_flash_led_probe()
840 dev_err(dev, "Read flash LED module type failed, rc=%d\n", rc); in qcom_flash_led_probe()
845 dev_err(dev, "type %#x is not a flash LED module\n", val); in qcom_flash_led_probe()
846 return -ENODEV; in qcom_flash_led_probe()
851 dev_err(dev, "Read flash LED module subtype failed, rc=%d\n", rc); in qcom_flash_led_probe()
856 flash_data->hw_type = QCOM_MVFLASH_3CH; in qcom_flash_led_probe()
857 flash_data->max_channels = 3; in qcom_flash_led_probe()
860 flash_data->hw_type = QCOM_MVFLASH_4CH; in qcom_flash_led_probe()
861 flash_data->max_channels = 4; in qcom_flash_led_probe()
866 dev_err(dev, "Failed to read flash LED module revision, rc=%d\n", rc); in qcom_flash_led_probe()
870 flash_data->revision = val; in qcom_flash_led_probe()
872 dev_err(dev, "flash LED subtype %#x is not yet supported\n", val); in qcom_flash_led_probe()
873 return -ENODEV; in qcom_flash_led_probe()
879 rc = devm_regmap_field_bulk_alloc(dev, regmap, flash_data->r_fields, regs, REG_MAX_COUNT); in qcom_flash_led_probe()
886 mutex_init(&flash_data->lock); in qcom_flash_led_probe()
889 if (count == 0 || count > flash_data->max_channels) { in qcom_flash_led_probe()
890 dev_err(dev, "No child or child count exceeds %d\n", flash_data->max_channels); in qcom_flash_led_probe()
891 return -EINVAL; in qcom_flash_led_probe()
894 flash_data->v4l2_flash = devm_kcalloc(dev, count, in qcom_flash_led_probe()
895 sizeof(*flash_data->v4l2_flash), GFP_KERNEL); in qcom_flash_led_probe()
896 if (!flash_data->v4l2_flash) in qcom_flash_led_probe()
897 return -ENOMEM; in qcom_flash_led_probe()
902 rc = -ENOMEM; in qcom_flash_led_probe()
906 led->flash_data = flash_data; in qcom_flash_led_probe()
911 flash_data->leds_count++; in qcom_flash_led_probe()
918 while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) in qcom_flash_led_probe()
919 v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); in qcom_flash_led_probe()
927 while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) in qcom_flash_led_remove()
928 v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); in qcom_flash_led_remove()
930 mutex_destroy(&flash_data->lock); in qcom_flash_led_remove()
934 { .compatible = "qcom,spmi-flash-led" },
941 .name = "leds-qcom-flash",
950 MODULE_DESCRIPTION("QCOM Flash LED driver");