1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <linux/bitops.h>
4 #include <linux/delay.h>
5 #include <linux/init.h>
6 #include <linux/interrupt.h>
7 #include <linux/kernel.h>
8 #include <linux/led-class-flash.h>
9 #include <linux/led-class-multicolor.h>
10 #include <linux/module.h>
11 #include <linux/mutex.h>
12 #include <linux/platform_device.h>
13 #include <linux/property.h>
14 #include <linux/regmap.h>
15 #include <media/v4l2-flash-led-class.h>
16
17 enum {
18 MT6360_LED_ISNK1 = 0,
19 MT6360_LED_ISNK2,
20 MT6360_LED_ISNK3,
21 MT6360_LED_ISNKML,
22 MT6360_LED_FLASH1,
23 MT6360_LED_FLASH2,
24 MT6360_MAX_LEDS
25 };
26
27 #define MT6360_REG_RGBEN 0x380
28 #define MT6360_REG_ISNK(_led_no) (0x381 + (_led_no))
29 #define MT6360_ISNK_ENMASK(_led_no) BIT(7 - (_led_no))
30 #define MT6360_ISNK_MASK GENMASK(4, 0)
31 #define MT6360_CHRINDSEL_MASK BIT(3)
32
33 /* Virtual definition for multicolor */
34 #define MT6360_VIRTUAL_MULTICOLOR (MT6360_MAX_LEDS + 1)
35 #define MULTICOLOR_NUM_CHANNELS 3
36
37 #define MT6360_REG_FLEDEN 0x37E
38 #define MT6360_REG_STRBTO 0x373
39 #define MT6360_REG_FLEDBASE(_id) (0x372 + 4 * (_id - MT6360_LED_FLASH1))
40 #define MT6360_REG_FLEDISTRB(_id) (MT6360_REG_FLEDBASE(_id) + 2)
41 #define MT6360_REG_FLEDITOR(_id) (MT6360_REG_FLEDBASE(_id) + 3)
42 #define MT6360_REG_CHGSTAT2 0x3E1
43 #define MT6360_REG_FLEDSTAT1 0x3E9
44 #define MT6360_ITORCH_MASK GENMASK(4, 0)
45 #define MT6360_ISTROBE_MASK GENMASK(6, 0)
46 #define MT6360_STRBTO_MASK GENMASK(6, 0)
47 #define MT6360_TORCHEN_MASK BIT(3)
48 #define MT6360_STROBEN_MASK BIT(2)
49 #define MT6360_FLCSEN_MASK(_id) BIT(MT6360_LED_FLASH2 - _id)
50 #define MT6360_FLEDCHGVINOVP_MASK BIT(3)
51 #define MT6360_FLED1STRBTO_MASK BIT(11)
52 #define MT6360_FLED2STRBTO_MASK BIT(10)
53 #define MT6360_FLED1STRB_MASK BIT(9)
54 #define MT6360_FLED2STRB_MASK BIT(8)
55 #define MT6360_FLED1SHORT_MASK BIT(7)
56 #define MT6360_FLED2SHORT_MASK BIT(6)
57 #define MT6360_FLEDLVF_MASK BIT(3)
58
59 #define MT6360_ISNKRGB_STEPUA 2000
60 #define MT6360_ISNKRGB_MAXUA 24000
61 #define MT6360_ISNKML_STEPUA 5000
62 #define MT6360_ISNKML_MAXUA 150000
63
64 #define MT6360_ITORCH_MINUA 25000
65 #define MT6360_ITORCH_STEPUA 12500
66 #define MT6360_ITORCH_MAXUA 400000
67 #define MT6360_ISTRB_MINUA 50000
68 #define MT6360_ISTRB_STEPUA 12500
69 #define MT6360_ISTRB_MAXUA 1500000
70 #define MT6360_STRBTO_MINUS 64000
71 #define MT6360_STRBTO_STEPUS 32000
72 #define MT6360_STRBTO_MAXUS 2432000
73
74 #define STATE_OFF 0
75 #define STATE_KEEP 1
76 #define STATE_ON 2
77
78 struct mt6360_led {
79 union {
80 struct led_classdev isnk;
81 struct led_classdev_mc mc;
82 struct led_classdev_flash flash;
83 };
84 struct v4l2_flash *v4l2_flash;
85 struct mt6360_priv *priv;
86 u32 led_no;
87 u32 default_state;
88 };
89
90 struct mt6360_priv {
91 struct device *dev;
92 struct regmap *regmap;
93 struct mutex lock;
94 unsigned int fled_strobe_used;
95 unsigned int fled_torch_used;
96 unsigned int leds_active;
97 unsigned int leds_count;
98 struct mt6360_led leds[];
99 };
100
mt6360_mc_brightness_set(struct led_classdev * lcdev,enum led_brightness level)101 static int mt6360_mc_brightness_set(struct led_classdev *lcdev,
102 enum led_brightness level)
103 {
104 struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
105 struct mt6360_led *led = container_of(mccdev, struct mt6360_led, mc);
106 struct mt6360_priv *priv = led->priv;
107 u32 real_bright, enable_mask = 0, enable = 0;
108 int i, ret;
109
110 mutex_lock(&priv->lock);
111
112 led_mc_calc_color_components(mccdev, level);
113
114 for (i = 0; i < mccdev->num_colors; i++) {
115 struct mc_subled *subled = mccdev->subled_info + i;
116
117 real_bright = min(lcdev->max_brightness, subled->brightness);
118 ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(i),
119 MT6360_ISNK_MASK, real_bright);
120 if (ret)
121 goto out;
122
123 enable_mask |= MT6360_ISNK_ENMASK(subled->channel);
124 if (real_bright)
125 enable |= MT6360_ISNK_ENMASK(subled->channel);
126 }
127
128 ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN, enable_mask,
129 enable);
130
131 out:
132 mutex_unlock(&priv->lock);
133 return ret;
134 }
135
mt6360_isnk_brightness_set(struct led_classdev * lcdev,enum led_brightness level)136 static int mt6360_isnk_brightness_set(struct led_classdev *lcdev,
137 enum led_brightness level)
138 {
139 struct mt6360_led *led = container_of(lcdev, struct mt6360_led, isnk);
140 struct mt6360_priv *priv = led->priv;
141 u32 enable_mask = MT6360_ISNK_ENMASK(led->led_no);
142 u32 val = level ? MT6360_ISNK_ENMASK(led->led_no) : 0;
143 int ret;
144
145 mutex_lock(&priv->lock);
146
147 ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no),
148 MT6360_ISNK_MASK, level);
149 if (ret)
150 goto out;
151
152 ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN, enable_mask,
153 val);
154
155 out:
156 mutex_unlock(&priv->lock);
157 return ret;
158 }
159
mt6360_torch_brightness_set(struct led_classdev * lcdev,enum led_brightness level)160 static int mt6360_torch_brightness_set(struct led_classdev *lcdev,
161 enum led_brightness level)
162 {
163 struct mt6360_led *led =
164 container_of(lcdev, struct mt6360_led, flash.led_cdev);
165 struct mt6360_priv *priv = led->priv;
166 u32 enable_mask = MT6360_TORCHEN_MASK | MT6360_FLCSEN_MASK(led->led_no);
167 u32 val = level ? MT6360_FLCSEN_MASK(led->led_no) : 0;
168 u32 prev = priv->fled_torch_used, curr;
169 int ret;
170
171 mutex_lock(&priv->lock);
172
173 /*
174 * Only one set of flash control logic, use the flag to avoid strobe is
175 * currently used.
176 */
177 if (priv->fled_strobe_used) {
178 dev_warn(lcdev->dev, "Please disable strobe first [%d]\n",
179 priv->fled_strobe_used);
180 ret = -EBUSY;
181 goto unlock;
182 }
183
184 if (level)
185 curr = prev | BIT(led->led_no);
186 else
187 curr = prev & ~BIT(led->led_no);
188
189 if (curr)
190 val |= MT6360_TORCHEN_MASK;
191
192 if (level) {
193 ret = regmap_update_bits(priv->regmap,
194 MT6360_REG_FLEDITOR(led->led_no),
195 MT6360_ITORCH_MASK, level - 1);
196 if (ret)
197 goto unlock;
198 }
199
200 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, enable_mask,
201 val);
202 if (ret)
203 goto unlock;
204
205 priv->fled_torch_used = curr;
206
207 unlock:
208 mutex_unlock(&priv->lock);
209 return ret;
210 }
211
mt6360_flash_brightness_set(struct led_classdev_flash * fl_cdev,u32 brightness)212 static int mt6360_flash_brightness_set(struct led_classdev_flash *fl_cdev,
213 u32 brightness)
214 {
215 /*
216 * Due to the current spike when turning on flash, let brightness to be
217 * kept by framework.
218 * This empty function is used to prevent led_classdev_flash register
219 * ops check failure.
220 */
221 return 0;
222 }
223
_mt6360_flash_brightness_set(struct led_classdev_flash * fl_cdev,u32 brightness)224 static int _mt6360_flash_brightness_set(struct led_classdev_flash *fl_cdev,
225 u32 brightness)
226 {
227 struct mt6360_led *led =
228 container_of(fl_cdev, struct mt6360_led, flash);
229 struct mt6360_priv *priv = led->priv;
230 struct led_flash_setting *s = &fl_cdev->brightness;
231 u32 val = (brightness - s->min) / s->step;
232
233 return regmap_update_bits(priv->regmap,
234 MT6360_REG_FLEDISTRB(led->led_no),
235 MT6360_ISTROBE_MASK, val);
236 }
237
mt6360_strobe_set(struct led_classdev_flash * fl_cdev,bool state)238 static int mt6360_strobe_set(struct led_classdev_flash *fl_cdev, bool state)
239 {
240 struct mt6360_led *led =
241 container_of(fl_cdev, struct mt6360_led, flash);
242 struct mt6360_priv *priv = led->priv;
243 struct led_classdev *lcdev = &fl_cdev->led_cdev;
244 struct led_flash_setting *s = &fl_cdev->brightness;
245 u32 enable_mask = MT6360_STROBEN_MASK | MT6360_FLCSEN_MASK(led->led_no);
246 u32 val = state ? MT6360_FLCSEN_MASK(led->led_no) : 0;
247 u32 prev = priv->fled_strobe_used, curr;
248 int ret;
249
250 mutex_lock(&priv->lock);
251
252 /*
253 * Only one set of flash control logic, use the flag to avoid torch is
254 * currently used
255 */
256 if (priv->fled_torch_used) {
257 dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n",
258 priv->fled_torch_used);
259 ret = -EBUSY;
260 goto unlock;
261 }
262
263 if (state)
264 curr = prev | BIT(led->led_no);
265 else
266 curr = prev & ~BIT(led->led_no);
267
268 if (curr)
269 val |= MT6360_STROBEN_MASK;
270
271 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, enable_mask,
272 val);
273 if (ret) {
274 dev_err(lcdev->dev, "[%d] control current source %d fail\n",
275 led->led_no, state);
276 goto unlock;
277 }
278
279 /*
280 * If the flash need to be on, config the flash current ramping up to
281 * the setting value.
282 * Else, always recover back to the minimum one
283 */
284 ret = _mt6360_flash_brightness_set(fl_cdev, state ? s->val : s->min);
285 if (ret)
286 goto unlock;
287
288 /*
289 * For the flash turn on/off, HW rampping up/down time is 5ms/500us,
290 * respectively.
291 */
292 if (!prev && curr)
293 usleep_range(5000, 6000);
294 else if (prev && !curr)
295 udelay(500);
296
297 priv->fled_strobe_used = curr;
298
299 unlock:
300 mutex_unlock(&priv->lock);
301 return ret;
302 }
303
mt6360_strobe_get(struct led_classdev_flash * fl_cdev,bool * state)304 static int mt6360_strobe_get(struct led_classdev_flash *fl_cdev, bool *state)
305 {
306 struct mt6360_led *led =
307 container_of(fl_cdev, struct mt6360_led, flash);
308 struct mt6360_priv *priv = led->priv;
309
310 mutex_lock(&priv->lock);
311 *state = !!(priv->fled_strobe_used & BIT(led->led_no));
312 mutex_unlock(&priv->lock);
313
314 return 0;
315 }
316
mt6360_timeout_set(struct led_classdev_flash * fl_cdev,u32 timeout)317 static int mt6360_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout)
318 {
319 struct mt6360_led *led =
320 container_of(fl_cdev, struct mt6360_led, flash);
321 struct mt6360_priv *priv = led->priv;
322 struct led_flash_setting *s = &fl_cdev->timeout;
323 u32 val = (timeout - s->min) / s->step;
324 int ret;
325
326 mutex_lock(&priv->lock);
327 ret = regmap_update_bits(priv->regmap, MT6360_REG_STRBTO,
328 MT6360_STRBTO_MASK, val);
329 mutex_unlock(&priv->lock);
330
331 return ret;
332 }
333
mt6360_fault_get(struct led_classdev_flash * fl_cdev,u32 * fault)334 static int mt6360_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault)
335 {
336 struct mt6360_led *led =
337 container_of(fl_cdev, struct mt6360_led, flash);
338 struct mt6360_priv *priv = led->priv;
339 u16 fled_stat;
340 unsigned int chg_stat, strobe_timeout_mask, fled_short_mask;
341 u32 rfault = 0;
342 int ret;
343
344 mutex_lock(&priv->lock);
345 ret = regmap_read(priv->regmap, MT6360_REG_CHGSTAT2, &chg_stat);
346 if (ret)
347 goto unlock;
348
349 ret = regmap_raw_read(priv->regmap, MT6360_REG_FLEDSTAT1, &fled_stat,
350 sizeof(fled_stat));
351 if (ret)
352 goto unlock;
353
354 if (led->led_no == MT6360_LED_FLASH1) {
355 strobe_timeout_mask = MT6360_FLED1STRBTO_MASK;
356 fled_short_mask = MT6360_FLED1SHORT_MASK;
357 } else {
358 strobe_timeout_mask = MT6360_FLED2STRBTO_MASK;
359 fled_short_mask = MT6360_FLED2SHORT_MASK;
360 }
361
362 if (chg_stat & MT6360_FLEDCHGVINOVP_MASK)
363 rfault |= LED_FAULT_INPUT_VOLTAGE;
364
365 if (fled_stat & strobe_timeout_mask)
366 rfault |= LED_FAULT_TIMEOUT;
367
368 if (fled_stat & fled_short_mask)
369 rfault |= LED_FAULT_SHORT_CIRCUIT;
370
371 if (fled_stat & MT6360_FLEDLVF_MASK)
372 rfault |= LED_FAULT_UNDER_VOLTAGE;
373
374 *fault = rfault;
375 unlock:
376 mutex_unlock(&priv->lock);
377 return ret;
378 }
379
380 static const struct led_flash_ops mt6360_flash_ops = {
381 .flash_brightness_set = mt6360_flash_brightness_set,
382 .strobe_set = mt6360_strobe_set,
383 .strobe_get = mt6360_strobe_get,
384 .timeout_set = mt6360_timeout_set,
385 .fault_get = mt6360_fault_get,
386 };
387
mt6360_isnk_init_default_state(struct mt6360_led * led)388 static int mt6360_isnk_init_default_state(struct mt6360_led *led)
389 {
390 struct mt6360_priv *priv = led->priv;
391 unsigned int regval;
392 u32 level;
393 int ret;
394
395 ret = regmap_read(priv->regmap, MT6360_REG_ISNK(led->led_no), ®val);
396 if (ret)
397 return ret;
398 level = regval & MT6360_ISNK_MASK;
399
400 ret = regmap_read(priv->regmap, MT6360_REG_RGBEN, ®val);
401 if (ret)
402 return ret;
403
404 if (!(regval & MT6360_ISNK_ENMASK(led->led_no)))
405 level = LED_OFF;
406
407 switch (led->default_state) {
408 case STATE_ON:
409 led->isnk.brightness = led->isnk.max_brightness;
410 break;
411 case STATE_KEEP:
412 led->isnk.brightness = min(level, led->isnk.max_brightness);
413 break;
414 default:
415 led->isnk.brightness = LED_OFF;
416 }
417
418 return mt6360_isnk_brightness_set(&led->isnk, led->isnk.brightness);
419 }
420
mt6360_flash_init_default_state(struct mt6360_led * led)421 static int mt6360_flash_init_default_state(struct mt6360_led *led)
422 {
423 struct led_classdev_flash *flash = &led->flash;
424 struct mt6360_priv *priv = led->priv;
425 u32 enable_mask = MT6360_TORCHEN_MASK | MT6360_FLCSEN_MASK(led->led_no);
426 u32 level;
427 unsigned int regval;
428 int ret;
429
430 ret = regmap_read(priv->regmap, MT6360_REG_FLEDITOR(led->led_no),
431 ®val);
432 if (ret)
433 return ret;
434 level = regval & MT6360_ITORCH_MASK;
435
436 ret = regmap_read(priv->regmap, MT6360_REG_FLEDEN, ®val);
437 if (ret)
438 return ret;
439
440 if ((regval & enable_mask) == enable_mask)
441 level += 1;
442 else
443 level = LED_OFF;
444
445 switch (led->default_state) {
446 case STATE_ON:
447 flash->led_cdev.brightness = flash->led_cdev.max_brightness;
448 break;
449 case STATE_KEEP:
450 flash->led_cdev.brightness =
451 min(level, flash->led_cdev.max_brightness);
452 break;
453 default:
454 flash->led_cdev.brightness = LED_OFF;
455 }
456
457 return mt6360_torch_brightness_set(&flash->led_cdev,
458 flash->led_cdev.brightness);
459 }
460
461 #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
mt6360_flash_external_strobe_set(struct v4l2_flash * v4l2_flash,bool enable)462 static int mt6360_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
463 bool enable)
464 {
465 struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
466 struct mt6360_led *led = container_of(flash, struct mt6360_led, flash);
467 struct mt6360_priv *priv = led->priv;
468 u32 mask = MT6360_FLCSEN_MASK(led->led_no);
469 u32 val = enable ? mask : 0;
470 int ret;
471
472 mutex_lock(&priv->lock);
473
474 ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, mask, val);
475 if (ret)
476 goto unlock;
477
478 if (enable)
479 priv->fled_strobe_used |= BIT(led->led_no);
480 else
481 priv->fled_strobe_used &= ~BIT(led->led_no);
482
483 unlock:
484 mutex_unlock(&priv->lock);
485 return ret;
486 }
487
488 static const struct v4l2_flash_ops v4l2_flash_ops = {
489 .external_strobe_set = mt6360_flash_external_strobe_set,
490 };
491
mt6360_init_v4l2_flash_config(struct mt6360_led * led,struct v4l2_flash_config * config)492 static void mt6360_init_v4l2_flash_config(struct mt6360_led *led,
493 struct v4l2_flash_config *config)
494 {
495 struct led_classdev *lcdev;
496 struct led_flash_setting *s = &config->intensity;
497
498 lcdev = &led->flash.led_cdev;
499
500 s->min = MT6360_ITORCH_MINUA;
501 s->step = MT6360_ITORCH_STEPUA;
502 s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step;
503
504 config->has_external_strobe = 1;
505 strscpy(config->dev_name, lcdev->dev->kobj.name,
506 sizeof(config->dev_name));
507
508 config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT |
509 LED_FAULT_INPUT_VOLTAGE |
510 LED_FAULT_UNDER_VOLTAGE;
511 }
512 #else
513 static const struct v4l2_flash_ops v4l2_flash_ops;
mt6360_init_v4l2_flash_config(struct mt6360_led * led,struct v4l2_flash_config * config)514 static void mt6360_init_v4l2_flash_config(struct mt6360_led *led,
515 struct v4l2_flash_config *config)
516 {
517 }
518 #endif
519
mt6360_led_register(struct device * parent,struct mt6360_led * led,struct led_init_data * init_data)520 static int mt6360_led_register(struct device *parent, struct mt6360_led *led,
521 struct led_init_data *init_data)
522 {
523 struct mt6360_priv *priv = led->priv;
524 struct v4l2_flash_config v4l2_config = {0};
525 int ret;
526
527 if ((led->led_no == MT6360_LED_ISNK1 ||
528 led->led_no == MT6360_VIRTUAL_MULTICOLOR) &&
529 (priv->leds_active & BIT(MT6360_LED_ISNK1))) {
530 /*
531 * Change isink1 to SW control mode, disconnect it with
532 * charger state
533 */
534 ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN,
535 MT6360_CHRINDSEL_MASK,
536 MT6360_CHRINDSEL_MASK);
537 if (ret) {
538 dev_err(parent, "Failed to config ISNK1 to SW mode\n");
539 return ret;
540 }
541 }
542
543 switch (led->led_no) {
544 case MT6360_VIRTUAL_MULTICOLOR:
545 ret = mt6360_mc_brightness_set(&led->mc.led_cdev, LED_OFF);
546 if (ret) {
547 dev_err(parent,
548 "Failed to init multicolor brightness\n");
549 return ret;
550 }
551
552 ret = devm_led_classdev_multicolor_register_ext(parent,
553 &led->mc, init_data);
554 if (ret) {
555 dev_err(parent, "Couldn't register multicolor\n");
556 return ret;
557 }
558 break;
559 case MT6360_LED_ISNK1 ... MT6360_LED_ISNKML:
560 ret = mt6360_isnk_init_default_state(led);
561 if (ret) {
562 dev_err(parent, "Failed to init %d isnk state\n",
563 led->led_no);
564 return ret;
565 }
566
567 ret = devm_led_classdev_register_ext(parent, &led->isnk,
568 init_data);
569 if (ret) {
570 dev_err(parent, "Couldn't register isink %d\n",
571 led->led_no);
572 return ret;
573 }
574 break;
575 default:
576 ret = mt6360_flash_init_default_state(led);
577 if (ret) {
578 dev_err(parent, "Failed to init %d flash state\n",
579 led->led_no);
580 return ret;
581 }
582
583 ret = devm_led_classdev_flash_register_ext(parent, &led->flash,
584 init_data);
585 if (ret) {
586 dev_err(parent, "Couldn't register flash %d\n",
587 led->led_no);
588 return ret;
589 }
590
591 mt6360_init_v4l2_flash_config(led, &v4l2_config);
592 led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode,
593 &led->flash,
594 &v4l2_flash_ops,
595 &v4l2_config);
596 if (IS_ERR(led->v4l2_flash)) {
597 dev_err(parent, "Failed to register %d v4l2 sd\n",
598 led->led_no);
599 return PTR_ERR(led->v4l2_flash);
600 }
601 }
602
603 return 0;
604 }
605
clamp_align(u32 val,u32 min,u32 max,u32 step)606 static u32 clamp_align(u32 val, u32 min, u32 max, u32 step)
607 {
608 u32 retval;
609
610 retval = clamp_val(val, min, max);
611 if (step > 1)
612 retval = rounddown(retval - min, step) + min;
613
614 return retval;
615 }
616
mt6360_init_isnk_properties(struct mt6360_led * led,struct led_init_data * init_data)617 static int mt6360_init_isnk_properties(struct mt6360_led *led,
618 struct led_init_data *init_data)
619 {
620 struct led_classdev *lcdev;
621 struct mt6360_priv *priv = led->priv;
622 struct fwnode_handle *child;
623 u32 step_uA = MT6360_ISNKRGB_STEPUA, max_uA = MT6360_ISNKRGB_MAXUA;
624 u32 val;
625 int num_color = 0, ret;
626
627 if (led->led_no == MT6360_VIRTUAL_MULTICOLOR) {
628 struct mc_subled *sub_led;
629
630 sub_led = devm_kzalloc(priv->dev,
631 sizeof(*sub_led) * MULTICOLOR_NUM_CHANNELS, GFP_KERNEL);
632 if (!sub_led)
633 return -ENOMEM;
634
635 fwnode_for_each_child_node(init_data->fwnode, child) {
636 u32 reg, color;
637
638 ret = fwnode_property_read_u32(child, "reg", ®);
639 if (ret || reg > MT6360_LED_ISNK3 ||
640 priv->leds_active & BIT(reg))
641 return -EINVAL;
642
643 ret = fwnode_property_read_u32(child, "color", &color);
644 if (ret) {
645 dev_err(priv->dev,
646 "led %d, no color specified\n",
647 led->led_no);
648 return ret;
649 }
650
651 priv->leds_active |= BIT(reg);
652 sub_led[num_color].color_index = color;
653 sub_led[num_color].channel = reg;
654 num_color++;
655 }
656
657 if (num_color < 2) {
658 dev_err(priv->dev,
659 "Multicolor must include 2 or more led channel\n");
660 return -EINVAL;
661 }
662
663 led->mc.num_colors = num_color;
664 led->mc.subled_info = sub_led;
665
666 lcdev = &led->mc.led_cdev;
667 lcdev->brightness_set_blocking = mt6360_mc_brightness_set;
668 } else {
669 if (led->led_no == MT6360_LED_ISNKML) {
670 step_uA = MT6360_ISNKML_STEPUA;
671 max_uA = MT6360_ISNKML_MAXUA;
672 }
673
674 lcdev = &led->isnk;
675 lcdev->brightness_set_blocking = mt6360_isnk_brightness_set;
676 }
677
678 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp",
679 &val);
680 if (ret) {
681 dev_warn(priv->dev,
682 "Not specified led-max-microamp, config to the minimum\n");
683 val = step_uA;
684 } else
685 val = clamp_align(val, 0, max_uA, step_uA);
686
687 lcdev->max_brightness = val / step_uA;
688
689 fwnode_property_read_string(init_data->fwnode, "linux,default-trigger",
690 &lcdev->default_trigger);
691
692 return 0;
693 }
694
mt6360_init_flash_properties(struct mt6360_led * led,struct led_init_data * init_data)695 static int mt6360_init_flash_properties(struct mt6360_led *led,
696 struct led_init_data *init_data)
697 {
698 struct led_classdev_flash *flash = &led->flash;
699 struct led_classdev *lcdev = &flash->led_cdev;
700 struct mt6360_priv *priv = led->priv;
701 struct led_flash_setting *s;
702 u32 val;
703 int ret;
704
705 ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp",
706 &val);
707 if (ret) {
708 dev_warn(priv->dev,
709 "Not specified led-max-microamp, config to the minimum\n");
710 val = MT6360_ITORCH_MINUA;
711 } else
712 val = clamp_align(val, MT6360_ITORCH_MINUA, MT6360_ITORCH_MAXUA,
713 MT6360_ITORCH_STEPUA);
714
715 lcdev->max_brightness =
716 (val - MT6360_ITORCH_MINUA) / MT6360_ITORCH_STEPUA + 1;
717 lcdev->brightness_set_blocking = mt6360_torch_brightness_set;
718 lcdev->flags |= LED_DEV_CAP_FLASH;
719
720 ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp",
721 &val);
722 if (ret) {
723 dev_warn(priv->dev,
724 "Not specified flash-max-microamp, config to the minimum\n");
725 val = MT6360_ISTRB_MINUA;
726 } else
727 val = clamp_align(val, MT6360_ISTRB_MINUA, MT6360_ISTRB_MAXUA,
728 MT6360_ISTRB_STEPUA);
729
730 s = &flash->brightness;
731 s->min = MT6360_ISTRB_MINUA;
732 s->step = MT6360_ISTRB_STEPUA;
733 s->val = s->max = val;
734
735 /*
736 * Always configure as min level when off to prevent flash current
737 * spike.
738 */
739 ret = _mt6360_flash_brightness_set(flash, s->min);
740 if (ret)
741 return ret;
742
743 ret = fwnode_property_read_u32(init_data->fwnode,
744 "flash-max-timeout-us", &val);
745 if (ret) {
746 dev_warn(priv->dev,
747 "Not specified flash-max-timeout-us, config to the minimum\n");
748 val = MT6360_STRBTO_MINUS;
749 } else
750 val = clamp_align(val, MT6360_STRBTO_MINUS, MT6360_STRBTO_MAXUS,
751 MT6360_STRBTO_STEPUS);
752
753 s = &flash->timeout;
754 s->min = MT6360_STRBTO_MINUS;
755 s->step = MT6360_STRBTO_STEPUS;
756 s->val = s->max = val;
757
758 flash->ops = &mt6360_flash_ops;
759
760 return 0;
761 }
762
mt6360_init_common_properties(struct mt6360_led * led,struct led_init_data * init_data)763 static int mt6360_init_common_properties(struct mt6360_led *led,
764 struct led_init_data *init_data)
765 {
766 const char *const states[] = { "off", "keep", "on" };
767 const char *str;
768 int ret;
769
770 if (!fwnode_property_read_string(init_data->fwnode,
771 "default-state", &str)) {
772 ret = match_string(states, ARRAY_SIZE(states), str);
773 if (ret < 0)
774 ret = STATE_OFF;
775
776 led->default_state = ret;
777 }
778
779 return 0;
780 }
781
mt6360_v4l2_flash_release(struct mt6360_priv * priv)782 static void mt6360_v4l2_flash_release(struct mt6360_priv *priv)
783 {
784 int i;
785
786 for (i = 0; i < priv->leds_count; i++) {
787 struct mt6360_led *led = priv->leds + i;
788
789 if (led->v4l2_flash)
790 v4l2_flash_release(led->v4l2_flash);
791 }
792 }
793
mt6360_led_probe(struct platform_device * pdev)794 static int mt6360_led_probe(struct platform_device *pdev)
795 {
796 struct mt6360_priv *priv;
797 struct fwnode_handle *child;
798 size_t count;
799 int i = 0, ret;
800
801 count = device_get_child_node_count(&pdev->dev);
802 if (!count || count > MT6360_MAX_LEDS) {
803 dev_err(&pdev->dev,
804 "No child node or node count over max led number %zu\n",
805 count);
806 return -EINVAL;
807 }
808
809 priv = devm_kzalloc(&pdev->dev,
810 struct_size(priv, leds, count), GFP_KERNEL);
811 if (!priv)
812 return -ENOMEM;
813
814 priv->leds_count = count;
815 priv->dev = &pdev->dev;
816 mutex_init(&priv->lock);
817
818 priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
819 if (!priv->regmap) {
820 dev_err(&pdev->dev, "Failed to get parent regmap\n");
821 return -ENODEV;
822 }
823
824 device_for_each_child_node(&pdev->dev, child) {
825 struct mt6360_led *led = priv->leds + i;
826 struct led_init_data init_data = { .fwnode = child, };
827 u32 reg, led_color;
828
829 ret = fwnode_property_read_u32(child, "color", &led_color);
830 if (ret)
831 goto out_flash_release;
832
833 if (led_color == LED_COLOR_ID_RGB ||
834 led_color == LED_COLOR_ID_MULTI)
835 reg = MT6360_VIRTUAL_MULTICOLOR;
836 else {
837 ret = fwnode_property_read_u32(child, "reg", ®);
838 if (ret)
839 goto out_flash_release;
840
841 if (reg >= MT6360_MAX_LEDS) {
842 ret = -EINVAL;
843 goto out_flash_release;
844 }
845 }
846
847 if (priv->leds_active & BIT(reg)) {
848 ret = -EINVAL;
849 goto out_flash_release;
850 }
851 priv->leds_active |= BIT(reg);
852
853 led->led_no = reg;
854 led->priv = priv;
855
856 ret = mt6360_init_common_properties(led, &init_data);
857 if (ret)
858 goto out_flash_release;
859
860 if (reg == MT6360_VIRTUAL_MULTICOLOR ||
861 reg <= MT6360_LED_ISNKML)
862 ret = mt6360_init_isnk_properties(led, &init_data);
863 else
864 ret = mt6360_init_flash_properties(led, &init_data);
865
866 if (ret)
867 goto out_flash_release;
868
869 ret = mt6360_led_register(&pdev->dev, led, &init_data);
870 if (ret)
871 goto out_flash_release;
872
873 i++;
874 }
875
876 platform_set_drvdata(pdev, priv);
877 return 0;
878
879 out_flash_release:
880 mt6360_v4l2_flash_release(priv);
881 return ret;
882 }
883
mt6360_led_remove(struct platform_device * pdev)884 static int mt6360_led_remove(struct platform_device *pdev)
885 {
886 struct mt6360_priv *priv = platform_get_drvdata(pdev);
887
888 mt6360_v4l2_flash_release(priv);
889 return 0;
890 }
891
892 static const struct of_device_id __maybe_unused mt6360_led_of_id[] = {
893 { .compatible = "mediatek,mt6360-led", },
894 {}
895 };
896 MODULE_DEVICE_TABLE(of, mt6360_led_of_id);
897
898 static struct platform_driver mt6360_led_driver = {
899 .driver = {
900 .name = "mt6360-led",
901 .of_match_table = mt6360_led_of_id,
902 },
903 .probe = mt6360_led_probe,
904 .remove = mt6360_led_remove,
905 };
906 module_platform_driver(mt6360_led_driver);
907
908 MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>");
909 MODULE_DESCRIPTION("MT6360 LED Driver");
910 MODULE_LICENSE("GPL v2");
911