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), &regval);
396 	if (ret)
397 		return ret;
398 	level = regval & MT6360_ISNK_MASK;
399 
400 	ret = regmap_read(priv->regmap, MT6360_REG_RGBEN, &regval);
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 			  &regval);
432 	if (ret)
433 		return ret;
434 	level = regval & MT6360_ITORCH_MASK;
435 
436 	ret = regmap_read(priv->regmap, MT6360_REG_FLEDEN, &regval);
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", &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", &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