Lines Matching +full:led +full:- +full:2
1 // SPDX-License-Identifier: GPL-2.0-only
14 #include <linux/led-class-multicolor.h>
110 #define MT6370_CHEN_BIT(id) BIT(MT6370_LED_ISNK4 - id)
113 #define MT6370_PWM_DUTY (BIT(5) - 1)
114 #define MT6372_PWM_DUTY (BIT(8) - 1)
118 * If the color of the LED in DT is set to
119 * - 'LED_COLOR_ID_RGB'
120 * - 'LED_COLOR_ID_MULTI'
123 * If so, this LED will choose 'struct led_classdev_mc mc' to use.
125 * 'MT6370_LED_ISNK1' ~ 'MT6370_LED_ISNK4', then this LED will choose
146 /* Per LED access lock */
162 [F_LED1_CURR] = REG_FIELD(MT6370_REG_RGB1_ISNK, 0, 2),
163 [F_LED2_CURR] = REG_FIELD(MT6370_REG_RGB2_ISNK, 0, 2),
164 [F_LED3_CURR] = REG_FIELD(MT6370_REG_RGB3_ISNK, 0, 2),
177 [F_LED4_FREQ] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 2, 4),
196 [F_LED2_FREQ] = REG_FIELD(MT6372_REG_RGB12_FREQ, 2, 4),
198 [F_LED4_FREQ] = REG_FIELD(MT6372_REG_RGB34_FREQ, 2, 4),
237 .reg_rgb_chrind_tr = -1,
261 return regmap_field_write(priv->fields[sel_field], level); in mt6370_set_led_brightness()
271 return regmap_field_read(priv->fields[sel_field], level); in mt6370_get_led_brightness()
277 const struct mt6370_pdata *pdata = priv->pdata; in mt6370_set_led_duty()
281 divisor = pdata->pwm_duty; in mt6370_set_led_duty()
299 return regmap_field_write(priv->fields[sel_field], ratio); in mt6370_set_led_duty()
305 const struct mt6370_pdata *pdata = priv->pdata; in mt6370_set_led_freq()
307 unsigned int tfreq_len = pdata->tfreq_len; in mt6370_set_led_freq()
312 if (tsum > pdata->tfreq[0] || tsum < pdata->tfreq[tfreq_len - 1]) in mt6370_set_led_freq()
313 return -EOPNOTSUPP; in mt6370_set_led_freq()
315 sel = find_closest_descending(tsum, pdata->tfreq, tfreq_len); in mt6370_set_led_freq()
332 return regmap_field_write(priv->fields[sel_field], sel); in mt6370_set_led_freq()
338 const struct mt6370_pdata *pdata = priv->pdata; in mt6370_get_breath_reg_base()
340 if (pdata->reg_rgb_chrind_tr < 0) { in mt6370_get_breath_reg_base()
341 *base = pdata->reg_rgb1_tr + led_no * 3; in mt6370_get_breath_reg_base()
349 *base = pdata->reg_rgb1_tr + led_no * 3; in mt6370_get_breath_reg_base()
352 *base = pdata->reg_rgb_chrind_tr; in mt6370_get_breath_reg_base()
366 if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2) in mt6370_gen_breath_pattern()
367 return -EINVAL; in mt6370_gen_breath_pattern()
375 * ton: byte 2, b'[7:4] in mt6370_gen_breath_pattern()
376 * toff: byte 2, b'[3:0] in mt6370_gen_breath_pattern()
383 linear_range_get_selector_within(priv->ranges + sel_range, curr->delta_t, &sel); in mt6370_gen_breath_pattern()
385 if (i % 2) { in mt6370_gen_breath_pattern()
418 return regmap_field_write(priv->fields[sel_field], mode); in mt6370_set_led_mode()
424 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_brightness_set() local
425 struct mt6370_priv *priv = led->priv; in mt6370_mc_brightness_set()
430 mutex_lock(&priv->lock); in mt6370_mc_brightness_set()
434 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_mc_brightness_set()
440 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_brightness_set()
443 subled = mccdev->subled_info + i; in mt6370_mc_brightness_set()
444 brightness = min(subled->brightness, lcdev->max_brightness); in mt6370_mc_brightness_set()
445 disable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
448 enable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
450 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_REG_MODE); in mt6370_mc_brightness_set()
458 enable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
462 enable |= MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
464 ret = mt6370_set_led_brightness(priv, subled->channel, brightness); in mt6370_mc_brightness_set()
469 ret = regmap_field_write(priv->fields[F_RGB_EN], disable); in mt6370_mc_brightness_set()
473 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_mc_brightness_set()
476 mutex_unlock(&priv->lock); in mt6370_mc_brightness_set()
486 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_blink_set() local
487 struct mt6370_priv *priv = led->priv; in mt6370_mc_blink_set()
492 mutex_lock(&priv->lock); in mt6370_mc_blink_set()
497 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_mc_blink_set()
503 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_blink_set()
504 subled = mccdev->subled_info + i; in mt6370_mc_blink_set()
506 disable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_blink_set()
508 ret = mt6370_set_led_duty(priv, subled->channel, *delay_on, *delay_off); in mt6370_mc_blink_set()
512 ret = mt6370_set_led_freq(priv, subled->channel, *delay_on, *delay_off); in mt6370_mc_blink_set()
516 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_PWM_MODE); in mt6370_mc_blink_set()
522 ret = regmap_field_write(priv->fields[F_RGB_EN], disable); in mt6370_mc_blink_set()
526 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_mc_blink_set()
529 mutex_unlock(&priv->lock); in mt6370_mc_blink_set()
538 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_pattern_set() local
539 struct mt6370_priv *priv = led->priv; in mt6370_mc_pattern_set()
542 u8 params[P_MAX_PATTERNS / 2]; in mt6370_mc_pattern_set()
545 mutex_lock(&priv->lock); in mt6370_mc_pattern_set()
551 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_mc_pattern_set()
557 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_pattern_set()
558 subled = mccdev->subled_info + i; in mt6370_mc_pattern_set()
560 mt6370_get_breath_reg_base(priv, subled->channel, ®_base); in mt6370_mc_pattern_set()
561 disable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_pattern_set()
563 ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); in mt6370_mc_pattern_set()
567 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_BREATH_MODE); in mt6370_mc_pattern_set()
573 ret = regmap_field_write(priv->fields[F_RGB_EN], disable); in mt6370_mc_pattern_set()
577 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_mc_pattern_set()
580 mutex_unlock(&priv->lock); in mt6370_mc_pattern_set()
588 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_pattern_clear() local
589 struct mt6370_priv *priv = led->priv; in mt6370_mc_pattern_clear()
593 mutex_lock(&led->priv->lock); in mt6370_mc_pattern_clear()
595 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_pattern_clear()
596 subled = mccdev->subled_info + i; in mt6370_mc_pattern_clear()
598 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_REG_MODE); in mt6370_mc_pattern_clear()
603 mutex_unlock(&led->priv->lock); in mt6370_mc_pattern_clear()
611 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_brightness_set() local
612 struct mt6370_priv *priv = led->priv; in mt6370_isnk_brightness_set()
616 mutex_lock(&priv->lock); in mt6370_isnk_brightness_set()
618 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_isnk_brightness_set()
623 enable &= ~MT6370_CHEN_BIT(led->index); in mt6370_isnk_brightness_set()
625 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); in mt6370_isnk_brightness_set()
629 enable |= MT6370_CHEN_BIT(led->index); in mt6370_isnk_brightness_set()
631 ret = mt6370_set_led_brightness(priv, led->index, level); in mt6370_isnk_brightness_set()
636 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_isnk_brightness_set()
639 mutex_unlock(&priv->lock); in mt6370_isnk_brightness_set()
647 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_blink_set() local
648 struct mt6370_priv *priv = led->priv; in mt6370_isnk_blink_set()
651 mutex_lock(&priv->lock); in mt6370_isnk_blink_set()
656 ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off); in mt6370_isnk_blink_set()
660 ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off); in mt6370_isnk_blink_set()
664 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE); in mt6370_isnk_blink_set()
667 mutex_unlock(&priv->lock); in mt6370_isnk_blink_set()
675 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_pattern_set() local
676 struct mt6370_priv *priv = led->priv; in mt6370_isnk_pattern_set()
678 u8 params[P_MAX_PATTERNS / 2]; in mt6370_isnk_pattern_set()
681 mutex_lock(&priv->lock); in mt6370_isnk_pattern_set()
687 mt6370_get_breath_reg_base(priv, led->index, ®_base); in mt6370_isnk_pattern_set()
689 ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); in mt6370_isnk_pattern_set()
693 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE); in mt6370_isnk_pattern_set()
696 mutex_unlock(&priv->lock); in mt6370_isnk_pattern_set()
703 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_pattern_clear() local
704 struct mt6370_priv *priv = led->priv; in mt6370_isnk_pattern_clear()
707 mutex_lock(&led->priv->lock); in mt6370_isnk_pattern_clear()
708 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); in mt6370_isnk_pattern_clear()
709 mutex_unlock(&led->priv->lock); in mt6370_isnk_pattern_clear()
714 static int mt6370_assign_multicolor_info(struct device *dev, struct mt6370_led *led, in mt6370_assign_multicolor_info() argument
717 struct mt6370_priv *priv = led->priv; in mt6370_assign_multicolor_info()
725 return -ENOMEM; in mt6370_assign_multicolor_info()
731 if (ret || reg > MT6370_LED_ISNK3 || priv->leds_active & BIT(reg)) { in mt6370_assign_multicolor_info()
733 return -EINVAL; in mt6370_assign_multicolor_info()
739 return dev_err_probe(dev, ret, "LED %d, no color specified\n", led->index); in mt6370_assign_multicolor_info()
742 priv->leds_active |= BIT(reg); in mt6370_assign_multicolor_info()
749 if (num_color < 2) in mt6370_assign_multicolor_info()
750 return dev_err_probe(dev, -EINVAL, in mt6370_assign_multicolor_info()
751 "Multicolor must include 2 or more LED channels\n"); in mt6370_assign_multicolor_info()
753 led->mc.num_colors = num_color; in mt6370_assign_multicolor_info()
754 led->mc.subled_info = sub_led; in mt6370_assign_multicolor_info()
759 static int mt6370_init_led_properties(struct device *dev, struct mt6370_led *led, in mt6370_init_led_properties() argument
762 struct mt6370_priv *priv = led->priv; in mt6370_init_led_properties()
768 if (led->index == MT6370_VIRTUAL_MULTICOLOR) { in mt6370_init_led_properties()
769 ret = mt6370_assign_multicolor_info(dev, led, init_data->fwnode); in mt6370_init_led_properties()
773 lcdev = &led->mc.led_cdev; in mt6370_init_led_properties()
774 lcdev->brightness_set_blocking = mt6370_mc_brightness_set; in mt6370_init_led_properties()
775 lcdev->blink_set = mt6370_mc_blink_set; in mt6370_init_led_properties()
776 lcdev->pattern_set = mt6370_mc_pattern_set; in mt6370_init_led_properties()
777 lcdev->pattern_clear = mt6370_mc_pattern_clear; in mt6370_init_led_properties()
779 lcdev = &led->isink; in mt6370_init_led_properties()
780 lcdev->brightness_set_blocking = mt6370_isnk_brightness_set; in mt6370_init_led_properties()
781 lcdev->blink_set = mt6370_isnk_blink_set; in mt6370_init_led_properties()
782 lcdev->pattern_set = mt6370_isnk_pattern_set; in mt6370_init_led_properties()
783 lcdev->pattern_clear = mt6370_isnk_pattern_clear; in mt6370_init_led_properties()
786 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &max_uA); in mt6370_init_led_properties()
788 dev_warn(dev, "Not specified led-max-microamp, config to the minimum\n"); in mt6370_init_led_properties()
792 if (led->index == MT6370_LED_ISNK4) in mt6370_init_led_properties()
797 linear_range_get_selector_within(priv->ranges + sel_range, max_uA, &max_level); in mt6370_init_led_properties()
799 lcdev->max_brightness = max_level; in mt6370_init_led_properties()
801 led->default_state = led_init_default_state_get(init_data->fwnode); in mt6370_init_led_properties()
806 static int mt6370_isnk_init_default_state(struct mt6370_led *led) in mt6370_isnk_init_default_state() argument
808 struct mt6370_priv *priv = led->priv; in mt6370_isnk_init_default_state()
812 ret = mt6370_get_led_brightness(priv, led->index, &level); in mt6370_isnk_init_default_state()
816 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_isnk_init_default_state()
820 if (!(enable & MT6370_CHEN_BIT(led->index))) in mt6370_isnk_init_default_state()
823 switch (led->default_state) { in mt6370_isnk_init_default_state()
825 led->isink.brightness = led->isink.max_brightness; in mt6370_isnk_init_default_state()
828 led->isink.brightness = min(level, led->isink.max_brightness); in mt6370_isnk_init_default_state()
831 led->isink.brightness = 0; in mt6370_isnk_init_default_state()
835 return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness); in mt6370_isnk_init_default_state()
838 static int mt6370_multicolor_led_register(struct device *dev, struct mt6370_led *led, in mt6370_multicolor_led_register() argument
843 ret = mt6370_mc_brightness_set(&led->mc.led_cdev, 0); in mt6370_multicolor_led_register()
847 ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc, init_data); in mt6370_multicolor_led_register()
854 static int mt6370_led_register(struct device *dev, struct mt6370_led *led, in mt6370_led_register() argument
857 struct mt6370_priv *priv = led->priv; in mt6370_led_register()
860 if (led->index == MT6370_VIRTUAL_MULTICOLOR) in mt6370_led_register()
861 return mt6370_multicolor_led_register(dev, led, init_data); in mt6370_led_register()
864 if (led->index == MT6370_LED_ISNK4) { in mt6370_led_register()
865 ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1); in mt6370_led_register()
870 ret = mt6370_isnk_init_default_state(led); in mt6370_led_register()
872 return dev_err_probe(dev, ret, "Failed to init %d isnk state\n", led->index); in mt6370_led_register()
874 ret = devm_led_classdev_register_ext(dev, &led->isink, init_data); in mt6370_led_register()
876 return dev_err_probe(dev, ret, "Couldn't register isink %d\n", led->index); in mt6370_led_register()
886 ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo); in mt6370_check_vendor_info()
892 priv->reg_fields = mt6372_reg_fields; in mt6370_check_vendor_info()
893 priv->ranges = mt6372_led_ranges; in mt6370_check_vendor_info()
894 priv->pdata = &mt6372_pdata; in mt6370_check_vendor_info()
897 priv->reg_fields = common_reg_fields; in mt6370_check_vendor_info()
898 priv->ranges = common_led_ranges; in mt6370_check_vendor_info()
899 priv->pdata = &common_pdata; in mt6370_check_vendor_info()
907 struct device *dev = &pdev->dev; in mt6370_leds_probe()
916 return dev_err_probe(dev, -EINVAL, in mt6370_leds_probe()
917 "No child node or node count over max LED number %zu\n", in mt6370_leds_probe()
922 return -ENOMEM; in mt6370_leds_probe()
924 priv->leds_count = count; in mt6370_leds_probe()
925 mutex_init(&priv->lock); in mt6370_leds_probe()
927 priv->regmap = dev_get_regmap(dev->parent, NULL); in mt6370_leds_probe()
928 if (!priv->regmap) in mt6370_leds_probe()
929 return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n"); in mt6370_leds_probe()
935 ret = devm_regmap_field_bulk_alloc(dev, priv->regmap, priv->fields, priv->reg_fields, in mt6370_leds_probe()
941 struct mt6370_led *led = priv->leds + i++; in mt6370_leds_probe() local
952 ret = -EINVAL; in mt6370_leds_probe()
966 if (priv->leds_active & BIT(reg)) { in mt6370_leds_probe()
967 ret = -EINVAL; in mt6370_leds_probe()
972 priv->leds_active |= BIT(reg); in mt6370_leds_probe()
974 led->index = reg; in mt6370_leds_probe()
975 led->priv = priv; in mt6370_leds_probe()
977 ret = mt6370_init_led_properties(dev, led, &init_data); in mt6370_leds_probe()
981 ret = mt6370_led_register(dev, led, &init_data); in mt6370_leds_probe()
994 { .compatible = "mediatek,mt6370-indicator" },
1001 .name = "mt6370-indicator",
1010 MODULE_DESCRIPTION("MediaTek MT6370 RGB LED Driver");