1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2023 Richtek Technology Corp.
6 * ChiYuan Huang <cy_huang@richtek.com>
7 * Alice Chen <alice_chen@richtek.com>
10 #include <linux/bitfield.h>
11 #include <linux/bitops.h>
12 #include <linux/kernel.h>
13 #include <linux/leds.h>
14 #include <linux/led-class-multicolor.h>
15 #include <linux/linear_range.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/module.h>
18 #include <linux/mutex.h>
19 #include <linux/platform_device.h>
20 #include <linux/property.h>
21 #include <linux/regmap.h>
22 #include <linux/util_macros.h>
24 #include <linux/unaligned.h>
34 enum mt6370_led_mode
{
35 MT6370_LED_PWM_MODE
= 0,
36 MT6370_LED_BREATH_MODE
,
41 enum mt6370_led_field
{
63 enum mt6370_led_ranges
{
81 #define MT6370_REG_DEV_INFO 0x100
82 #define MT6370_REG_RGB1_DIM 0x182
83 #define MT6370_REG_RGB2_DIM 0x183
84 #define MT6370_REG_RGB3_DIM 0x184
85 #define MT6370_REG_RGB_EN 0x185
86 #define MT6370_REG_RGB1_ISNK 0x186
87 #define MT6370_REG_RGB2_ISNK 0x187
88 #define MT6370_REG_RGB3_ISNK 0x188
89 #define MT6370_REG_RGB1_TR 0x189
90 #define MT6370_REG_RGB_CHRIND_DIM 0x192
91 #define MT6370_REG_RGB_CHRIND_CTRL 0x193
92 #define MT6370_REG_RGB_CHRIND_TR 0x194
94 #define MT6372_REG_RGB_EN 0x182
95 #define MT6372_REG_RGB1_ISNK 0x183
96 #define MT6372_REG_RGB2_ISNK 0x184
97 #define MT6372_REG_RGB3_ISNK 0x185
98 #define MT6372_REG_RGB4_ISNK 0x186
99 #define MT6372_REG_RGB1_DIM 0x187
100 #define MT6372_REG_RGB2_DIM 0x188
101 #define MT6372_REG_RGB3_DIM 0x189
102 #define MT6372_REG_RGB4_DIM 0x18A
103 #define MT6372_REG_RGB12_FREQ 0x18B
104 #define MT6372_REG_RGB34_FREQ 0x18C
105 #define MT6372_REG_RGB1_TR 0x18D
107 #define MT6370_VENDOR_ID_MASK GENMASK(7, 4)
108 #define MT6372_VENDOR_ID 0x9
109 #define MT6372C_VENDOR_ID 0xb
110 #define MT6370_CHEN_BIT(id) BIT(MT6370_LED_ISNK4 - id)
111 #define MT6370_VIRTUAL_MULTICOLOR 5
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'
121 * The member 'index' of this struct will be set to
122 * 'MT6370_VIRTUAL_MULTICOLOR'.
123 * If so, this LED will choose 'struct led_classdev_mc mc' to use.
124 * Instead, if the member 'index' of this struct is set to
125 * 'MT6370_LED_ISNK1' ~ 'MT6370_LED_ISNK4', then this LED will choose
126 * 'struct led_classdev isink' to use.
129 struct led_classdev isink
;
130 struct led_classdev_mc mc
;
132 struct mt6370_priv
*priv
;
133 enum led_default_state default_state
;
137 struct mt6370_pdata
{
138 const unsigned int *tfreq
;
139 unsigned int tfreq_len
;
141 s16 reg_rgb_chrind_tr
;
146 /* Per LED access lock */
148 struct regmap
*regmap
;
149 struct regmap_field
*fields
[F_MAX_FIELDS
];
150 const struct reg_field
*reg_fields
;
151 const struct linear_range
*ranges
;
152 const struct mt6370_pdata
*pdata
;
153 unsigned int leds_count
;
154 unsigned int leds_active
;
155 struct mt6370_led leds
[] __counted_by(leds_count
);
158 static const struct reg_field common_reg_fields
[F_MAX_FIELDS
] = {
159 [F_RGB_EN
] = REG_FIELD(MT6370_REG_RGB_EN
, 4, 7),
160 [F_CHGIND_EN
] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM
, 7, 7),
161 [F_LED1_CURR
] = REG_FIELD(MT6370_REG_RGB1_ISNK
, 0, 2),
162 [F_LED2_CURR
] = REG_FIELD(MT6370_REG_RGB2_ISNK
, 0, 2),
163 [F_LED3_CURR
] = REG_FIELD(MT6370_REG_RGB3_ISNK
, 0, 2),
164 [F_LED4_CURR
] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL
, 0, 1),
165 [F_LED1_MODE
] = REG_FIELD(MT6370_REG_RGB1_DIM
, 5, 6),
166 [F_LED2_MODE
] = REG_FIELD(MT6370_REG_RGB2_DIM
, 5, 6),
167 [F_LED3_MODE
] = REG_FIELD(MT6370_REG_RGB3_DIM
, 5, 6),
168 [F_LED4_MODE
] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM
, 5, 6),
169 [F_LED1_DUTY
] = REG_FIELD(MT6370_REG_RGB1_DIM
, 0, 4),
170 [F_LED2_DUTY
] = REG_FIELD(MT6370_REG_RGB2_DIM
, 0, 4),
171 [F_LED3_DUTY
] = REG_FIELD(MT6370_REG_RGB3_DIM
, 0, 4),
172 [F_LED4_DUTY
] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM
, 0, 4),
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),
176 [F_LED4_FREQ
] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL
, 2, 4),
179 static const struct reg_field mt6372_reg_fields
[F_MAX_FIELDS
] = {
180 [F_RGB_EN
] = REG_FIELD(MT6372_REG_RGB_EN
, 4, 7),
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),
186 [F_LED1_MODE
] = REG_FIELD(MT6372_REG_RGB1_ISNK
, 6, 7),
187 [F_LED2_MODE
] = REG_FIELD(MT6372_REG_RGB2_ISNK
, 6, 7),
188 [F_LED3_MODE
] = REG_FIELD(MT6372_REG_RGB3_ISNK
, 6, 7),
189 [F_LED4_MODE
] = REG_FIELD(MT6372_REG_RGB4_ISNK
, 6, 7),
190 [F_LED1_DUTY
] = REG_FIELD(MT6372_REG_RGB1_DIM
, 0, 7),
191 [F_LED2_DUTY
] = REG_FIELD(MT6372_REG_RGB2_DIM
, 0, 7),
192 [F_LED3_DUTY
] = REG_FIELD(MT6372_REG_RGB3_DIM
, 0, 7),
193 [F_LED4_DUTY
] = REG_FIELD(MT6372_REG_RGB4_DIM
, 0, 7),
194 [F_LED1_FREQ
] = REG_FIELD(MT6372_REG_RGB12_FREQ
, 5, 7),
195 [F_LED2_FREQ
] = REG_FIELD(MT6372_REG_RGB12_FREQ
, 2, 4),
196 [F_LED3_FREQ
] = REG_FIELD(MT6372_REG_RGB34_FREQ
, 5, 7),
197 [F_LED4_FREQ
] = REG_FIELD(MT6372_REG_RGB34_FREQ
, 2, 4),
200 /* Current unit: microamp, time unit: millisecond */
201 static const struct linear_range common_led_ranges
[R_MAX_RANGES
] = {
202 [R_LED123_CURR
] = { 4000, 1, 6, 4000 },
203 [R_LED4_CURR
] = { 2000, 1, 3, 2000 },
204 [R_LED_TRFON
] = { 125, 0, 15, 200 },
205 [R_LED_TOFF
] = { 250, 0, 15, 400 },
208 static const struct linear_range mt6372_led_ranges
[R_MAX_RANGES
] = {
209 [R_LED123_CURR
] = { 2000, 1, 14, 2000 },
210 [R_LED4_CURR
] = { 2000, 1, 14, 2000 },
211 [R_LED_TRFON
] = { 125, 0, 15, 250 },
212 [R_LED_TOFF
] = { 250, 0, 15, 500 },
215 static const unsigned int common_tfreqs
[] = {
216 10000, 5000, 2000, 1000, 500, 200, 5, 1,
219 static const unsigned int mt6372_tfreqs
[] = {
220 8000, 4000, 2000, 1000, 500, 250, 8, 4,
223 static const struct mt6370_pdata common_pdata
= {
224 .tfreq
= common_tfreqs
,
225 .tfreq_len
= ARRAY_SIZE(common_tfreqs
),
226 .pwm_duty
= MT6370_PWM_DUTY
,
227 .reg_rgb1_tr
= MT6370_REG_RGB1_TR
,
228 .reg_rgb_chrind_tr
= MT6370_REG_RGB_CHRIND_TR
,
231 static const struct mt6370_pdata mt6372_pdata
= {
232 .tfreq
= mt6372_tfreqs
,
233 .tfreq_len
= ARRAY_SIZE(mt6372_tfreqs
),
234 .pwm_duty
= MT6372_PWM_DUTY
,
235 .reg_rgb1_tr
= MT6372_REG_RGB1_TR
,
236 .reg_rgb_chrind_tr
= -1,
239 static enum mt6370_led_field
mt6370_get_led_current_field(unsigned int led_no
)
242 case MT6370_LED_ISNK1
:
244 case MT6370_LED_ISNK2
:
246 case MT6370_LED_ISNK3
:
253 static int mt6370_set_led_brightness(struct mt6370_priv
*priv
, unsigned int led_no
,
256 enum mt6370_led_field sel_field
;
258 sel_field
= mt6370_get_led_current_field(led_no
);
260 return regmap_field_write(priv
->fields
[sel_field
], level
);
263 static int mt6370_get_led_brightness(struct mt6370_priv
*priv
, unsigned int led_no
,
266 enum mt6370_led_field sel_field
;
268 sel_field
= mt6370_get_led_current_field(led_no
);
270 return regmap_field_read(priv
->fields
[sel_field
], level
);
273 static int mt6370_set_led_duty(struct mt6370_priv
*priv
, unsigned int led_no
, unsigned int ton
,
276 const struct mt6370_pdata
*pdata
= priv
->pdata
;
277 enum mt6370_led_field sel_field
;
278 unsigned int divisor
, ratio
;
280 divisor
= pdata
->pwm_duty
;
281 ratio
= ton
* divisor
/ (ton
+ toff
);
284 case MT6370_LED_ISNK1
:
285 sel_field
= F_LED1_DUTY
;
287 case MT6370_LED_ISNK2
:
288 sel_field
= F_LED2_DUTY
;
290 case MT6370_LED_ISNK3
:
291 sel_field
= F_LED3_DUTY
;
294 sel_field
= F_LED4_DUTY
;
298 return regmap_field_write(priv
->fields
[sel_field
], ratio
);
301 static int mt6370_set_led_freq(struct mt6370_priv
*priv
, unsigned int led_no
, unsigned int ton
,
304 const struct mt6370_pdata
*pdata
= priv
->pdata
;
305 enum mt6370_led_field sel_field
;
306 unsigned int tfreq_len
= pdata
->tfreq_len
;
307 unsigned int tsum
, sel
;
311 if (tsum
> pdata
->tfreq
[0] || tsum
< pdata
->tfreq
[tfreq_len
- 1])
314 sel
= find_closest_descending(tsum
, pdata
->tfreq
, tfreq_len
);
317 case MT6370_LED_ISNK1
:
318 sel_field
= F_LED1_FREQ
;
320 case MT6370_LED_ISNK2
:
321 sel_field
= F_LED2_FREQ
;
323 case MT6370_LED_ISNK3
:
324 sel_field
= F_LED3_FREQ
;
327 sel_field
= F_LED4_FREQ
;
331 return regmap_field_write(priv
->fields
[sel_field
], sel
);
334 static void mt6370_get_breath_reg_base(struct mt6370_priv
*priv
, unsigned int led_no
,
337 const struct mt6370_pdata
*pdata
= priv
->pdata
;
339 if (pdata
->reg_rgb_chrind_tr
< 0) {
340 *base
= pdata
->reg_rgb1_tr
+ led_no
* 3;
345 case MT6370_LED_ISNK1
:
346 case MT6370_LED_ISNK2
:
347 case MT6370_LED_ISNK3
:
348 *base
= pdata
->reg_rgb1_tr
+ led_no
* 3;
351 *base
= pdata
->reg_rgb_chrind_tr
;
356 static int mt6370_gen_breath_pattern(struct mt6370_priv
*priv
, struct led_pattern
*pattern
, u32 len
,
357 u8
*pattern_val
, u32 val_len
)
359 enum mt6370_led_ranges sel_range
;
360 struct led_pattern
*curr
;
365 if (len
< P_MAX_PATTERNS
&& val_len
< P_MAX_PATTERNS
/ 2)
370 * tr1: byte 0, b'[7:4]
371 * tr2: byte 0, b'[3:0]
372 * tf1: byte 1, b'[7:4]
373 * tf2: byte 1, b'[3:0]
374 * ton: byte 2, b'[7:4]
375 * toff: byte 2, b'[3:0]
377 for (i
= 0; i
< P_MAX_PATTERNS
; i
++) {
380 sel_range
= i
== P_LED_TOFF
? R_LED_TOFF
: R_LED_TRFON
;
382 linear_range_get_selector_within(priv
->ranges
+ sel_range
, curr
->delta_t
, &sel
);
392 put_unaligned_be24(val
, pattern_val
);
397 static int mt6370_set_led_mode(struct mt6370_priv
*priv
, unsigned int led_no
,
398 enum mt6370_led_mode mode
)
400 enum mt6370_led_field sel_field
;
403 case MT6370_LED_ISNK1
:
404 sel_field
= F_LED1_MODE
;
406 case MT6370_LED_ISNK2
:
407 sel_field
= F_LED2_MODE
;
409 case MT6370_LED_ISNK3
:
410 sel_field
= F_LED3_MODE
;
413 sel_field
= F_LED4_MODE
;
417 return regmap_field_write(priv
->fields
[sel_field
], mode
);
420 static int mt6370_mc_brightness_set(struct led_classdev
*lcdev
, enum led_brightness level
)
422 struct led_classdev_mc
*mccdev
= lcdev_to_mccdev(lcdev
);
423 struct mt6370_led
*led
= container_of(mccdev
, struct mt6370_led
, mc
);
424 struct mt6370_priv
*priv
= led
->priv
;
425 struct mc_subled
*subled
;
426 unsigned int enable
, disable
;
429 mutex_lock(&priv
->lock
);
431 led_mc_calc_color_components(mccdev
, level
);
433 ret
= regmap_field_read(priv
->fields
[F_RGB_EN
], &enable
);
439 for (i
= 0; i
< mccdev
->num_colors
; i
++) {
442 subled
= mccdev
->subled_info
+ i
;
443 brightness
= min(subled
->brightness
, lcdev
->max_brightness
);
444 disable
&= ~MT6370_CHEN_BIT(subled
->channel
);
447 enable
&= ~MT6370_CHEN_BIT(subled
->channel
);
449 ret
= mt6370_set_led_mode(priv
, subled
->channel
, MT6370_LED_REG_MODE
);
456 if (brightness
== 0) {
457 enable
&= ~MT6370_CHEN_BIT(subled
->channel
);
461 enable
|= MT6370_CHEN_BIT(subled
->channel
);
463 ret
= mt6370_set_led_brightness(priv
, subled
->channel
, brightness
);
468 ret
= regmap_field_write(priv
->fields
[F_RGB_EN
], disable
);
472 ret
= regmap_field_write(priv
->fields
[F_RGB_EN
], enable
);
475 mutex_unlock(&priv
->lock
);
480 static int mt6370_mc_blink_set(struct led_classdev
*lcdev
,
481 unsigned long *delay_on
,
482 unsigned long *delay_off
)
484 struct led_classdev_mc
*mccdev
= lcdev_to_mccdev(lcdev
);
485 struct mt6370_led
*led
= container_of(mccdev
, struct mt6370_led
, mc
);
486 struct mt6370_priv
*priv
= led
->priv
;
487 struct mc_subled
*subled
;
488 unsigned int enable
, disable
;
491 mutex_lock(&priv
->lock
);
493 if (!*delay_on
&& !*delay_off
)
494 *delay_on
= *delay_off
= 500;
496 ret
= regmap_field_read(priv
->fields
[F_RGB_EN
], &enable
);
502 for (i
= 0; i
< mccdev
->num_colors
; i
++) {
503 subled
= mccdev
->subled_info
+ i
;
505 disable
&= ~MT6370_CHEN_BIT(subled
->channel
);
507 ret
= mt6370_set_led_duty(priv
, subled
->channel
, *delay_on
, *delay_off
);
511 ret
= mt6370_set_led_freq(priv
, subled
->channel
, *delay_on
, *delay_off
);
515 ret
= mt6370_set_led_mode(priv
, subled
->channel
, MT6370_LED_PWM_MODE
);
520 /* Toggle to make pattern timing the same */
521 ret
= regmap_field_write(priv
->fields
[F_RGB_EN
], disable
);
525 ret
= regmap_field_write(priv
->fields
[F_RGB_EN
], enable
);
528 mutex_unlock(&priv
->lock
);
533 static int mt6370_mc_pattern_set(struct led_classdev
*lcdev
, struct led_pattern
*pattern
, u32 len
,
536 struct led_classdev_mc
*mccdev
= lcdev_to_mccdev(lcdev
);
537 struct mt6370_led
*led
= container_of(mccdev
, struct mt6370_led
, mc
);
538 struct mt6370_priv
*priv
= led
->priv
;
539 struct mc_subled
*subled
;
540 unsigned int reg_base
, enable
, disable
;
541 u8 params
[P_MAX_PATTERNS
/ 2];
544 mutex_lock(&priv
->lock
);
546 ret
= mt6370_gen_breath_pattern(priv
, pattern
, len
, params
, sizeof(params
));
550 ret
= regmap_field_read(priv
->fields
[F_RGB_EN
], &enable
);
556 for (i
= 0; i
< mccdev
->num_colors
; i
++) {
557 subled
= mccdev
->subled_info
+ i
;
559 mt6370_get_breath_reg_base(priv
, subled
->channel
, ®_base
);
560 disable
&= ~MT6370_CHEN_BIT(subled
->channel
);
562 ret
= regmap_raw_write(priv
->regmap
, reg_base
, params
, sizeof(params
));
566 ret
= mt6370_set_led_mode(priv
, subled
->channel
, MT6370_LED_BREATH_MODE
);
571 /* Toggle to make pattern timing be the same */
572 ret
= regmap_field_write(priv
->fields
[F_RGB_EN
], disable
);
576 ret
= regmap_field_write(priv
->fields
[F_RGB_EN
], enable
);
579 mutex_unlock(&priv
->lock
);
584 static inline int mt6370_mc_pattern_clear(struct led_classdev
*lcdev
)
586 struct led_classdev_mc
*mccdev
= lcdev_to_mccdev(lcdev
);
587 struct mt6370_led
*led
= container_of(mccdev
, struct mt6370_led
, mc
);
588 struct mt6370_priv
*priv
= led
->priv
;
589 struct mc_subled
*subled
;
592 mutex_lock(&led
->priv
->lock
);
594 for (i
= 0; i
< mccdev
->num_colors
; i
++) {
595 subled
= mccdev
->subled_info
+ i
;
597 ret
= mt6370_set_led_mode(priv
, subled
->channel
, MT6370_LED_REG_MODE
);
602 mutex_unlock(&led
->priv
->lock
);
607 static int mt6370_isnk_brightness_set(struct led_classdev
*lcdev
,
608 enum led_brightness level
)
610 struct mt6370_led
*led
= container_of(lcdev
, struct mt6370_led
, isink
);
611 struct mt6370_priv
*priv
= led
->priv
;
615 mutex_lock(&priv
->lock
);
617 ret
= regmap_field_read(priv
->fields
[F_RGB_EN
], &enable
);
622 enable
&= ~MT6370_CHEN_BIT(led
->index
);
624 ret
= mt6370_set_led_mode(priv
, led
->index
, MT6370_LED_REG_MODE
);
628 enable
|= MT6370_CHEN_BIT(led
->index
);
630 ret
= mt6370_set_led_brightness(priv
, led
->index
, level
);
635 ret
= regmap_field_write(priv
->fields
[F_RGB_EN
], enable
);
638 mutex_unlock(&priv
->lock
);
643 static int mt6370_isnk_blink_set(struct led_classdev
*lcdev
, unsigned long *delay_on
,
644 unsigned long *delay_off
)
646 struct mt6370_led
*led
= container_of(lcdev
, struct mt6370_led
, isink
);
647 struct mt6370_priv
*priv
= led
->priv
;
650 mutex_lock(&priv
->lock
);
652 if (!*delay_on
&& !*delay_off
)
653 *delay_on
= *delay_off
= 500;
655 ret
= mt6370_set_led_duty(priv
, led
->index
, *delay_on
, *delay_off
);
659 ret
= mt6370_set_led_freq(priv
, led
->index
, *delay_on
, *delay_off
);
663 ret
= mt6370_set_led_mode(priv
, led
->index
, MT6370_LED_PWM_MODE
);
666 mutex_unlock(&priv
->lock
);
671 static int mt6370_isnk_pattern_set(struct led_classdev
*lcdev
, struct led_pattern
*pattern
, u32 len
,
674 struct mt6370_led
*led
= container_of(lcdev
, struct mt6370_led
, isink
);
675 struct mt6370_priv
*priv
= led
->priv
;
676 unsigned int reg_base
;
677 u8 params
[P_MAX_PATTERNS
/ 2];
680 mutex_lock(&priv
->lock
);
682 ret
= mt6370_gen_breath_pattern(priv
, pattern
, len
, params
, sizeof(params
));
686 mt6370_get_breath_reg_base(priv
, led
->index
, ®_base
);
688 ret
= regmap_raw_write(priv
->regmap
, reg_base
, params
, sizeof(params
));
692 ret
= mt6370_set_led_mode(priv
, led
->index
, MT6370_LED_BREATH_MODE
);
695 mutex_unlock(&priv
->lock
);
700 static inline int mt6370_isnk_pattern_clear(struct led_classdev
*lcdev
)
702 struct mt6370_led
*led
= container_of(lcdev
, struct mt6370_led
, isink
);
703 struct mt6370_priv
*priv
= led
->priv
;
706 mutex_lock(&led
->priv
->lock
);
707 ret
= mt6370_set_led_mode(priv
, led
->index
, MT6370_LED_REG_MODE
);
708 mutex_unlock(&led
->priv
->lock
);
713 static int mt6370_assign_multicolor_info(struct device
*dev
, struct mt6370_led
*led
,
714 struct fwnode_handle
*fwnode
)
716 struct mt6370_priv
*priv
= led
->priv
;
717 struct fwnode_handle
*child
;
718 struct mc_subled
*sub_led
;
722 sub_led
= devm_kcalloc(dev
, MC_CHANNEL_NUM
, sizeof(*sub_led
), GFP_KERNEL
);
726 fwnode_for_each_child_node(fwnode
, child
) {
729 ret
= fwnode_property_read_u32(child
, "reg", ®
);
730 if (ret
|| reg
> MT6370_LED_ISNK3
|| priv
->leds_active
& BIT(reg
)) {
731 fwnode_handle_put(child
);
735 ret
= fwnode_property_read_u32(child
, "color", &color
);
737 fwnode_handle_put(child
);
738 return dev_err_probe(dev
, ret
, "LED %d, no color specified\n", led
->index
);
741 priv
->leds_active
|= BIT(reg
);
742 sub_led
[num_color
].color_index
= color
;
743 sub_led
[num_color
].channel
= reg
;
744 sub_led
[num_color
].intensity
= 0;
749 return dev_err_probe(dev
, -EINVAL
,
750 "Multicolor must include 2 or more LED channels\n");
752 led
->mc
.num_colors
= num_color
;
753 led
->mc
.subled_info
= sub_led
;
758 static int mt6370_init_led_properties(struct device
*dev
, struct mt6370_led
*led
,
759 struct led_init_data
*init_data
)
761 struct mt6370_priv
*priv
= led
->priv
;
762 struct led_classdev
*lcdev
;
763 enum mt6370_led_ranges sel_range
;
764 u32 max_uA
, max_level
;
767 if (led
->index
== MT6370_VIRTUAL_MULTICOLOR
) {
768 ret
= mt6370_assign_multicolor_info(dev
, led
, init_data
->fwnode
);
772 lcdev
= &led
->mc
.led_cdev
;
773 lcdev
->brightness_set_blocking
= mt6370_mc_brightness_set
;
774 lcdev
->blink_set
= mt6370_mc_blink_set
;
775 lcdev
->pattern_set
= mt6370_mc_pattern_set
;
776 lcdev
->pattern_clear
= mt6370_mc_pattern_clear
;
779 lcdev
->brightness_set_blocking
= mt6370_isnk_brightness_set
;
780 lcdev
->blink_set
= mt6370_isnk_blink_set
;
781 lcdev
->pattern_set
= mt6370_isnk_pattern_set
;
782 lcdev
->pattern_clear
= mt6370_isnk_pattern_clear
;
785 ret
= fwnode_property_read_u32(init_data
->fwnode
, "led-max-microamp", &max_uA
);
787 dev_warn(dev
, "Not specified led-max-microamp, config to the minimum\n");
791 if (led
->index
== MT6370_LED_ISNK4
)
792 sel_range
= R_LED4_CURR
;
794 sel_range
= R_LED123_CURR
;
796 linear_range_get_selector_within(priv
->ranges
+ sel_range
, max_uA
, &max_level
);
798 lcdev
->max_brightness
= max_level
;
800 led
->default_state
= led_init_default_state_get(init_data
->fwnode
);
805 static int mt6370_isnk_init_default_state(struct mt6370_led
*led
)
807 struct mt6370_priv
*priv
= led
->priv
;
808 unsigned int enable
, level
;
811 ret
= mt6370_get_led_brightness(priv
, led
->index
, &level
);
815 ret
= regmap_field_read(priv
->fields
[F_RGB_EN
], &enable
);
819 if (!(enable
& MT6370_CHEN_BIT(led
->index
)))
822 switch (led
->default_state
) {
823 case LEDS_DEFSTATE_ON
:
824 led
->isink
.brightness
= led
->isink
.max_brightness
;
826 case LEDS_DEFSTATE_KEEP
:
827 led
->isink
.brightness
= min(level
, led
->isink
.max_brightness
);
830 led
->isink
.brightness
= 0;
834 return mt6370_isnk_brightness_set(&led
->isink
, led
->isink
.brightness
);
837 static int mt6370_multicolor_led_register(struct device
*dev
, struct mt6370_led
*led
,
838 struct led_init_data
*init_data
)
842 ret
= mt6370_mc_brightness_set(&led
->mc
.led_cdev
, 0);
844 return dev_err_probe(dev
, ret
, "Couldn't set multicolor brightness\n");
846 ret
= devm_led_classdev_multicolor_register_ext(dev
, &led
->mc
, init_data
);
848 return dev_err_probe(dev
, ret
, "Couldn't register multicolor\n");
853 static int mt6370_led_register(struct device
*dev
, struct mt6370_led
*led
,
854 struct led_init_data
*init_data
)
856 struct mt6370_priv
*priv
= led
->priv
;
859 if (led
->index
== MT6370_VIRTUAL_MULTICOLOR
)
860 return mt6370_multicolor_led_register(dev
, led
, init_data
);
862 /* If ISNK4 is declared, change its mode from HW auto to SW control */
863 if (led
->index
== MT6370_LED_ISNK4
) {
864 ret
= regmap_field_write(priv
->fields
[F_CHGIND_EN
], 1);
866 return dev_err_probe(dev
, ret
, "Failed to set CHRIND to SW\n");
869 ret
= mt6370_isnk_init_default_state(led
);
871 return dev_err_probe(dev
, ret
, "Failed to init %d isnk state\n", led
->index
);
873 ret
= devm_led_classdev_register_ext(dev
, &led
->isink
, init_data
);
875 return dev_err_probe(dev
, ret
, "Couldn't register isink %d\n", led
->index
);
880 static int mt6370_check_vendor_info(struct mt6370_priv
*priv
)
882 unsigned int devinfo
, vid
;
885 ret
= regmap_read(priv
->regmap
, MT6370_REG_DEV_INFO
, &devinfo
);
889 vid
= FIELD_GET(MT6370_VENDOR_ID_MASK
, devinfo
);
890 if (vid
== MT6372_VENDOR_ID
|| vid
== MT6372C_VENDOR_ID
) {
891 priv
->reg_fields
= mt6372_reg_fields
;
892 priv
->ranges
= mt6372_led_ranges
;
893 priv
->pdata
= &mt6372_pdata
;
895 /* Common for MT6370/71 */
896 priv
->reg_fields
= common_reg_fields
;
897 priv
->ranges
= common_led_ranges
;
898 priv
->pdata
= &common_pdata
;
904 static int mt6370_leds_probe(struct platform_device
*pdev
)
906 struct device
*dev
= &pdev
->dev
;
907 struct mt6370_priv
*priv
;
912 count
= device_get_child_node_count(dev
);
913 if (!count
|| count
> MT6370_MAX_LEDS
)
914 return dev_err_probe(dev
, -EINVAL
,
915 "No child node or node count over max LED number %zu\n",
918 priv
= devm_kzalloc(dev
, struct_size(priv
, leds
, count
), GFP_KERNEL
);
922 priv
->leds_count
= count
;
923 mutex_init(&priv
->lock
);
925 priv
->regmap
= dev_get_regmap(dev
->parent
, NULL
);
927 return dev_err_probe(dev
, -ENODEV
, "Failed to get parent regmap\n");
929 ret
= mt6370_check_vendor_info(priv
);
931 return dev_err_probe(dev
, ret
, "Failed to check vendor info\n");
933 ret
= devm_regmap_field_bulk_alloc(dev
, priv
->regmap
, priv
->fields
, priv
->reg_fields
,
936 return dev_err_probe(dev
, ret
, "Failed to allocate regmap field\n");
938 device_for_each_child_node_scoped(dev
, child
) {
939 struct mt6370_led
*led
= priv
->leds
+ i
++;
940 struct led_init_data init_data
= { .fwnode
= child
};
943 ret
= fwnode_property_read_u32(child
, "reg", ®
);
945 dev_err_probe(dev
, ret
, "Failed to parse reg property\n");
947 if (reg
>= MT6370_MAX_LEDS
)
948 return dev_err_probe(dev
, -EINVAL
, "Error reg property number\n");
950 ret
= fwnode_property_read_u32(child
, "color", &color
);
952 return dev_err_probe(dev
, ret
, "Failed to parse color property\n");
954 if (color
== LED_COLOR_ID_RGB
|| color
== LED_COLOR_ID_MULTI
)
955 reg
= MT6370_VIRTUAL_MULTICOLOR
;
957 if (priv
->leds_active
& BIT(reg
))
958 return dev_err_probe(dev
, -EINVAL
, "Duplicate reg property\n");
960 priv
->leds_active
|= BIT(reg
);
965 ret
= mt6370_init_led_properties(dev
, led
, &init_data
);
969 ret
= mt6370_led_register(dev
, led
, &init_data
);
977 static const struct of_device_id mt6370_rgbled_device_table
[] = {
978 { .compatible
= "mediatek,mt6370-indicator" },
981 MODULE_DEVICE_TABLE(of
, mt6370_rgbled_device_table
);
983 static struct platform_driver mt6370_rgbled_driver
= {
985 .name
= "mt6370-indicator",
986 .of_match_table
= mt6370_rgbled_device_table
,
988 .probe
= mt6370_leds_probe
,
990 module_platform_driver(mt6370_rgbled_driver
);
992 MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
993 MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
994 MODULE_DESCRIPTION("MediaTek MT6370 RGB LED Driver");
995 MODULE_LICENSE("GPL");