Lines Matching +full:led +full:- +full:3

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)
112 #define MC_CHANNEL_NUM 3
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 */
173 [F_LED1_FREQ] = REG_FIELD(MT6370_REG_RGB1_ISNK, 3, 5),
174 [F_LED2_FREQ] = REG_FIELD(MT6370_REG_RGB2_ISNK, 3, 5),
175 [F_LED3_FREQ] = REG_FIELD(MT6370_REG_RGB3_ISNK, 3, 5),
181 [F_CHGIND_EN] = REG_FIELD(MT6372_REG_RGB_EN, 3, 3),
182 [F_LED1_CURR] = REG_FIELD(MT6372_REG_RGB1_ISNK, 0, 3),
183 [F_LED2_CURR] = REG_FIELD(MT6372_REG_RGB2_ISNK, 0, 3),
184 [F_LED3_CURR] = REG_FIELD(MT6372_REG_RGB3_ISNK, 0, 3),
185 [F_LED4_CURR] = REG_FIELD(MT6372_REG_RGB4_ISNK, 0, 3),
203 [R_LED4_CURR] = { 2000, 1, 3, 2000 },
236 .reg_rgb_chrind_tr = -1,
260 return regmap_field_write(priv->fields[sel_field], level); in mt6370_set_led_brightness()
270 return regmap_field_read(priv->fields[sel_field], level); in mt6370_get_led_brightness()
276 const struct mt6370_pdata *pdata = priv->pdata; in mt6370_set_led_duty()
280 divisor = pdata->pwm_duty; in mt6370_set_led_duty()
298 return regmap_field_write(priv->fields[sel_field], ratio); in mt6370_set_led_duty()
304 const struct mt6370_pdata *pdata = priv->pdata; in mt6370_set_led_freq()
306 unsigned int tfreq_len = pdata->tfreq_len; in mt6370_set_led_freq()
311 if (tsum > pdata->tfreq[0] || tsum < pdata->tfreq[tfreq_len - 1]) in mt6370_set_led_freq()
312 return -EOPNOTSUPP; in mt6370_set_led_freq()
314 sel = find_closest_descending(tsum, pdata->tfreq, tfreq_len); in mt6370_set_led_freq()
331 return regmap_field_write(priv->fields[sel_field], sel); in mt6370_set_led_freq()
337 const struct mt6370_pdata *pdata = priv->pdata; in mt6370_get_breath_reg_base()
339 if (pdata->reg_rgb_chrind_tr < 0) { in mt6370_get_breath_reg_base()
340 *base = pdata->reg_rgb1_tr + led_no * 3; in mt6370_get_breath_reg_base()
348 *base = pdata->reg_rgb1_tr + led_no * 3; in mt6370_get_breath_reg_base()
351 *base = pdata->reg_rgb_chrind_tr; in mt6370_get_breath_reg_base()
366 return -EINVAL; in mt6370_gen_breath_pattern()
371 * tr2: byte 0, b'[3:0] in mt6370_gen_breath_pattern()
373 * tf2: byte 1, b'[3:0] in mt6370_gen_breath_pattern()
375 * toff: byte 2, b'[3:0] in mt6370_gen_breath_pattern()
382 linear_range_get_selector_within(priv->ranges + sel_range, curr->delta_t, &sel); in mt6370_gen_breath_pattern()
417 return regmap_field_write(priv->fields[sel_field], mode); in mt6370_set_led_mode()
423 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_brightness_set() local
424 struct mt6370_priv *priv = led->priv; in mt6370_mc_brightness_set()
429 mutex_lock(&priv->lock); in mt6370_mc_brightness_set()
433 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_mc_brightness_set()
439 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_brightness_set()
442 subled = mccdev->subled_info + i; in mt6370_mc_brightness_set()
443 brightness = min(subled->brightness, lcdev->max_brightness); in mt6370_mc_brightness_set()
444 disable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
447 enable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
449 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_REG_MODE); in mt6370_mc_brightness_set()
457 enable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
461 enable |= MT6370_CHEN_BIT(subled->channel); in mt6370_mc_brightness_set()
463 ret = mt6370_set_led_brightness(priv, subled->channel, brightness); in mt6370_mc_brightness_set()
468 ret = regmap_field_write(priv->fields[F_RGB_EN], disable); in mt6370_mc_brightness_set()
472 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_mc_brightness_set()
475 mutex_unlock(&priv->lock); in mt6370_mc_brightness_set()
485 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_blink_set() local
486 struct mt6370_priv *priv = led->priv; in mt6370_mc_blink_set()
491 mutex_lock(&priv->lock); in mt6370_mc_blink_set()
496 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_mc_blink_set()
502 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_blink_set()
503 subled = mccdev->subled_info + i; in mt6370_mc_blink_set()
505 disable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_blink_set()
507 ret = mt6370_set_led_duty(priv, subled->channel, *delay_on, *delay_off); in mt6370_mc_blink_set()
511 ret = mt6370_set_led_freq(priv, subled->channel, *delay_on, *delay_off); in mt6370_mc_blink_set()
515 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_PWM_MODE); in mt6370_mc_blink_set()
521 ret = regmap_field_write(priv->fields[F_RGB_EN], disable); in mt6370_mc_blink_set()
525 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_mc_blink_set()
528 mutex_unlock(&priv->lock); in mt6370_mc_blink_set()
537 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_pattern_set() local
538 struct mt6370_priv *priv = led->priv; in mt6370_mc_pattern_set()
544 mutex_lock(&priv->lock); in mt6370_mc_pattern_set()
550 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_mc_pattern_set()
556 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_pattern_set()
557 subled = mccdev->subled_info + i; in mt6370_mc_pattern_set()
559 mt6370_get_breath_reg_base(priv, subled->channel, &reg_base); in mt6370_mc_pattern_set()
560 disable &= ~MT6370_CHEN_BIT(subled->channel); in mt6370_mc_pattern_set()
562 ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); in mt6370_mc_pattern_set()
566 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_BREATH_MODE); in mt6370_mc_pattern_set()
572 ret = regmap_field_write(priv->fields[F_RGB_EN], disable); in mt6370_mc_pattern_set()
576 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_mc_pattern_set()
579 mutex_unlock(&priv->lock); in mt6370_mc_pattern_set()
587 struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); in mt6370_mc_pattern_clear() local
588 struct mt6370_priv *priv = led->priv; in mt6370_mc_pattern_clear()
592 mutex_lock(&led->priv->lock); in mt6370_mc_pattern_clear()
594 for (i = 0; i < mccdev->num_colors; i++) { in mt6370_mc_pattern_clear()
595 subled = mccdev->subled_info + i; in mt6370_mc_pattern_clear()
597 ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_REG_MODE); in mt6370_mc_pattern_clear()
602 mutex_unlock(&led->priv->lock); in mt6370_mc_pattern_clear()
610 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_brightness_set() local
611 struct mt6370_priv *priv = led->priv; in mt6370_isnk_brightness_set()
615 mutex_lock(&priv->lock); in mt6370_isnk_brightness_set()
617 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_isnk_brightness_set()
622 enable &= ~MT6370_CHEN_BIT(led->index); in mt6370_isnk_brightness_set()
624 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); in mt6370_isnk_brightness_set()
628 enable |= MT6370_CHEN_BIT(led->index); in mt6370_isnk_brightness_set()
630 ret = mt6370_set_led_brightness(priv, led->index, level); in mt6370_isnk_brightness_set()
635 ret = regmap_field_write(priv->fields[F_RGB_EN], enable); in mt6370_isnk_brightness_set()
638 mutex_unlock(&priv->lock); in mt6370_isnk_brightness_set()
646 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_blink_set() local
647 struct mt6370_priv *priv = led->priv; in mt6370_isnk_blink_set()
650 mutex_lock(&priv->lock); in mt6370_isnk_blink_set()
655 ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off); in mt6370_isnk_blink_set()
659 ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off); in mt6370_isnk_blink_set()
663 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE); in mt6370_isnk_blink_set()
666 mutex_unlock(&priv->lock); in mt6370_isnk_blink_set()
674 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_pattern_set() local
675 struct mt6370_priv *priv = led->priv; in mt6370_isnk_pattern_set()
680 mutex_lock(&priv->lock); in mt6370_isnk_pattern_set()
686 mt6370_get_breath_reg_base(priv, led->index, &reg_base); in mt6370_isnk_pattern_set()
688 ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); in mt6370_isnk_pattern_set()
692 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE); in mt6370_isnk_pattern_set()
695 mutex_unlock(&priv->lock); in mt6370_isnk_pattern_set()
702 struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); in mt6370_isnk_pattern_clear() local
703 struct mt6370_priv *priv = led->priv; in mt6370_isnk_pattern_clear()
706 mutex_lock(&led->priv->lock); in mt6370_isnk_pattern_clear()
707 ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); in mt6370_isnk_pattern_clear()
708 mutex_unlock(&led->priv->lock); in mt6370_isnk_pattern_clear()
713 static int mt6370_assign_multicolor_info(struct device *dev, struct mt6370_led *led, in mt6370_assign_multicolor_info() argument
716 struct mt6370_priv *priv = led->priv; in mt6370_assign_multicolor_info()
724 return -ENOMEM; in mt6370_assign_multicolor_info()
730 if (ret || reg > MT6370_LED_ISNK3 || priv->leds_active & BIT(reg)) { in mt6370_assign_multicolor_info()
732 return -EINVAL; in mt6370_assign_multicolor_info()
738 return dev_err_probe(dev, ret, "LED %d, no color specified\n", led->index); in mt6370_assign_multicolor_info()
741 priv->leds_active |= BIT(reg); in mt6370_assign_multicolor_info()
749 return dev_err_probe(dev, -EINVAL, in mt6370_assign_multicolor_info()
750 "Multicolor must include 2 or more LED channels\n"); in mt6370_assign_multicolor_info()
752 led->mc.num_colors = num_color; in mt6370_assign_multicolor_info()
753 led->mc.subled_info = sub_led; in mt6370_assign_multicolor_info()
758 static int mt6370_init_led_properties(struct device *dev, struct mt6370_led *led, in mt6370_init_led_properties() argument
761 struct mt6370_priv *priv = led->priv; in mt6370_init_led_properties()
767 if (led->index == MT6370_VIRTUAL_MULTICOLOR) { in mt6370_init_led_properties()
768 ret = mt6370_assign_multicolor_info(dev, led, init_data->fwnode); in mt6370_init_led_properties()
772 lcdev = &led->mc.led_cdev; in mt6370_init_led_properties()
773 lcdev->brightness_set_blocking = mt6370_mc_brightness_set; in mt6370_init_led_properties()
774 lcdev->blink_set = mt6370_mc_blink_set; in mt6370_init_led_properties()
775 lcdev->pattern_set = mt6370_mc_pattern_set; in mt6370_init_led_properties()
776 lcdev->pattern_clear = mt6370_mc_pattern_clear; in mt6370_init_led_properties()
778 lcdev = &led->isink; in mt6370_init_led_properties()
779 lcdev->brightness_set_blocking = mt6370_isnk_brightness_set; in mt6370_init_led_properties()
780 lcdev->blink_set = mt6370_isnk_blink_set; in mt6370_init_led_properties()
781 lcdev->pattern_set = mt6370_isnk_pattern_set; in mt6370_init_led_properties()
782 lcdev->pattern_clear = mt6370_isnk_pattern_clear; in mt6370_init_led_properties()
785 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &max_uA); in mt6370_init_led_properties()
787 dev_warn(dev, "Not specified led-max-microamp, config to the minimum\n"); in mt6370_init_led_properties()
791 if (led->index == MT6370_LED_ISNK4) in mt6370_init_led_properties()
796 linear_range_get_selector_within(priv->ranges + sel_range, max_uA, &max_level); in mt6370_init_led_properties()
798 lcdev->max_brightness = max_level; in mt6370_init_led_properties()
800 led->default_state = led_init_default_state_get(init_data->fwnode); in mt6370_init_led_properties()
805 static int mt6370_isnk_init_default_state(struct mt6370_led *led) in mt6370_isnk_init_default_state() argument
807 struct mt6370_priv *priv = led->priv; in mt6370_isnk_init_default_state()
811 ret = mt6370_get_led_brightness(priv, led->index, &level); in mt6370_isnk_init_default_state()
815 ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); in mt6370_isnk_init_default_state()
819 if (!(enable & MT6370_CHEN_BIT(led->index))) in mt6370_isnk_init_default_state()
822 switch (led->default_state) { in mt6370_isnk_init_default_state()
824 led->isink.brightness = led->isink.max_brightness; in mt6370_isnk_init_default_state()
827 led->isink.brightness = min(level, led->isink.max_brightness); in mt6370_isnk_init_default_state()
830 led->isink.brightness = 0; in mt6370_isnk_init_default_state()
834 return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness); in mt6370_isnk_init_default_state()
837 static int mt6370_multicolor_led_register(struct device *dev, struct mt6370_led *led, in mt6370_multicolor_led_register() argument
842 ret = mt6370_mc_brightness_set(&led->mc.led_cdev, 0); in mt6370_multicolor_led_register()
846 ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc, init_data); in mt6370_multicolor_led_register()
853 static int mt6370_led_register(struct device *dev, struct mt6370_led *led, in mt6370_led_register() argument
856 struct mt6370_priv *priv = led->priv; in mt6370_led_register()
859 if (led->index == MT6370_VIRTUAL_MULTICOLOR) in mt6370_led_register()
860 return mt6370_multicolor_led_register(dev, led, init_data); in mt6370_led_register()
863 if (led->index == MT6370_LED_ISNK4) { in mt6370_led_register()
864 ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1); in mt6370_led_register()
869 ret = mt6370_isnk_init_default_state(led); in mt6370_led_register()
871 return dev_err_probe(dev, ret, "Failed to init %d isnk state\n", led->index); in mt6370_led_register()
873 ret = devm_led_classdev_register_ext(dev, &led->isink, init_data); in mt6370_led_register()
875 return dev_err_probe(dev, ret, "Couldn't register isink %d\n", led->index); in mt6370_led_register()
885 ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo); in mt6370_check_vendor_info()
891 priv->reg_fields = mt6372_reg_fields; in mt6370_check_vendor_info()
892 priv->ranges = mt6372_led_ranges; in mt6370_check_vendor_info()
893 priv->pdata = &mt6372_pdata; in mt6370_check_vendor_info()
896 priv->reg_fields = common_reg_fields; in mt6370_check_vendor_info()
897 priv->ranges = common_led_ranges; in mt6370_check_vendor_info()
898 priv->pdata = &common_pdata; in mt6370_check_vendor_info()
906 struct device *dev = &pdev->dev; in mt6370_leds_probe()
915 return dev_err_probe(dev, -EINVAL, in mt6370_leds_probe()
916 "No child node or node count over max LED number %zu\n", in mt6370_leds_probe()
921 return -ENOMEM; in mt6370_leds_probe()
923 priv->leds_count = count; in mt6370_leds_probe()
924 mutex_init(&priv->lock); in mt6370_leds_probe()
926 priv->regmap = dev_get_regmap(dev->parent, NULL); in mt6370_leds_probe()
927 if (!priv->regmap) in mt6370_leds_probe()
928 return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n"); in mt6370_leds_probe()
934 ret = devm_regmap_field_bulk_alloc(dev, priv->regmap, priv->fields, priv->reg_fields, in mt6370_leds_probe()
940 struct mt6370_led *led = priv->leds + i++; in mt6370_leds_probe() local
951 ret = -EINVAL; in mt6370_leds_probe()
965 if (priv->leds_active & BIT(reg)) { in mt6370_leds_probe()
966 ret = -EINVAL; in mt6370_leds_probe()
971 priv->leds_active |= BIT(reg); in mt6370_leds_probe()
973 led->index = reg; in mt6370_leds_probe()
974 led->priv = priv; in mt6370_leds_probe()
976 ret = mt6370_init_led_properties(dev, led, &init_data); in mt6370_leds_probe()
980 ret = mt6370_led_register(dev, led, &init_data); in mt6370_leds_probe()
993 { .compatible = "mediatek,mt6370-indicator" },
1000 .name = "mt6370-indicator",
1009 MODULE_DESCRIPTION("MediaTek MT6370 RGB LED Driver");