xref: /linux/drivers/video/backlight/qcom-wled.c (revision 0526b56cbc3c489642bd6a5fe4b718dea7ef0ee8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2015, Sony Mobile Communications, AB.
3  */
4 
5 #include <linux/delay.h>
6 #include <linux/interrupt.h>
7 #include <linux/ktime.h>
8 #include <linux/kernel.h>
9 #include <linux/backlight.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_device.h>
13 #include <linux/of_address.h>
14 #include <linux/regmap.h>
15 
16 /* From DT binding */
17 #define WLED_MAX_STRINGS				4
18 #define MOD_A						0
19 #define MOD_B						1
20 
21 #define WLED_DEFAULT_BRIGHTNESS				2048
22 #define WLED_SOFT_START_DLY_US				10000
23 #define WLED3_SINK_REG_BRIGHT_MAX			0xFFF
24 #define WLED5_SINK_REG_BRIGHT_MAX_12B			0xFFF
25 #define WLED5_SINK_REG_BRIGHT_MAX_15B			0x7FFF
26 
27 /* WLED3/WLED4 control registers */
28 #define WLED3_CTRL_REG_FAULT_STATUS			0x08
29 #define  WLED3_CTRL_REG_ILIM_FAULT_BIT			BIT(0)
30 #define  WLED3_CTRL_REG_OVP_FAULT_BIT			BIT(1)
31 #define  WLED4_CTRL_REG_SC_FAULT_BIT			BIT(2)
32 #define  WLED5_CTRL_REG_OVP_PRE_ALARM_BIT		BIT(4)
33 
34 #define WLED3_CTRL_REG_INT_RT_STS			0x10
35 #define  WLED3_CTRL_REG_OVP_FAULT_STATUS		BIT(1)
36 
37 #define WLED3_CTRL_REG_MOD_EN				0x46
38 #define  WLED3_CTRL_REG_MOD_EN_MASK			BIT(7)
39 #define  WLED3_CTRL_REG_MOD_EN_SHIFT			7
40 
41 #define WLED3_CTRL_REG_FEEDBACK_CONTROL			0x48
42 
43 #define WLED3_CTRL_REG_FREQ				0x4c
44 #define  WLED3_CTRL_REG_FREQ_MASK			GENMASK(3, 0)
45 
46 #define WLED3_CTRL_REG_OVP				0x4d
47 #define  WLED3_CTRL_REG_OVP_MASK			GENMASK(1, 0)
48 #define  WLED5_CTRL_REG_OVP_MASK			GENMASK(3, 0)
49 
50 #define WLED3_CTRL_REG_ILIMIT				0x4e
51 #define  WLED3_CTRL_REG_ILIMIT_MASK			GENMASK(2, 0)
52 
53 /* WLED3/WLED4 sink registers */
54 #define WLED3_SINK_REG_SYNC				0x47
55 #define  WLED3_SINK_REG_SYNC_CLEAR			0x00
56 
57 #define WLED3_SINK_REG_CURR_SINK			0x4f
58 #define  WLED3_SINK_REG_CURR_SINK_MASK			GENMASK(7, 5)
59 #define  WLED3_SINK_REG_CURR_SINK_SHFT			5
60 
61 /* WLED3 specific per-'string' registers below */
62 #define WLED3_SINK_REG_BRIGHT(n)			(0x40 + n)
63 
64 #define WLED3_SINK_REG_STR_MOD_EN(n)			(0x60 + (n * 0x10))
65 #define  WLED3_SINK_REG_STR_MOD_MASK			BIT(7)
66 
67 #define WLED3_SINK_REG_STR_FULL_SCALE_CURR(n)		(0x62 + (n * 0x10))
68 #define  WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK	GENMASK(4, 0)
69 
70 #define WLED3_SINK_REG_STR_MOD_SRC(n)			(0x63 + (n * 0x10))
71 #define  WLED3_SINK_REG_STR_MOD_SRC_MASK		BIT(0)
72 #define  WLED3_SINK_REG_STR_MOD_SRC_INT			0x00
73 #define  WLED3_SINK_REG_STR_MOD_SRC_EXT			0x01
74 
75 #define WLED3_SINK_REG_STR_CABC(n)			(0x66 + (n * 0x10))
76 #define  WLED3_SINK_REG_STR_CABC_MASK			BIT(7)
77 
78 /* WLED4 specific control registers */
79 #define WLED4_CTRL_REG_SHORT_PROTECT			0x5e
80 #define  WLED4_CTRL_REG_SHORT_EN_MASK			BIT(7)
81 
82 #define WLED4_CTRL_REG_SEC_ACCESS			0xd0
83 #define  WLED4_CTRL_REG_SEC_UNLOCK			0xa5
84 
85 #define WLED4_CTRL_REG_TEST1				0xe2
86 #define  WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2		0x09
87 
88 /* WLED4 specific sink registers */
89 #define WLED4_SINK_REG_CURR_SINK			0x46
90 #define  WLED4_SINK_REG_CURR_SINK_MASK			GENMASK(7, 4)
91 #define  WLED4_SINK_REG_CURR_SINK_SHFT			4
92 
93 /* WLED4 specific per-'string' registers below */
94 #define WLED4_SINK_REG_STR_MOD_EN(n)			(0x50 + (n * 0x10))
95 #define  WLED4_SINK_REG_STR_MOD_MASK			BIT(7)
96 
97 #define WLED4_SINK_REG_STR_FULL_SCALE_CURR(n)		(0x52 + (n * 0x10))
98 #define  WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK	GENMASK(3, 0)
99 
100 #define WLED4_SINK_REG_STR_MOD_SRC(n)			(0x53 + (n * 0x10))
101 #define  WLED4_SINK_REG_STR_MOD_SRC_MASK		BIT(0)
102 #define  WLED4_SINK_REG_STR_MOD_SRC_INT			0x00
103 #define  WLED4_SINK_REG_STR_MOD_SRC_EXT			0x01
104 
105 #define WLED4_SINK_REG_STR_CABC(n)			(0x56 + (n * 0x10))
106 #define  WLED4_SINK_REG_STR_CABC_MASK			BIT(7)
107 
108 #define WLED4_SINK_REG_BRIGHT(n)			(0x57 + (n * 0x10))
109 
110 /* WLED5 specific control registers */
111 #define WLED5_CTRL_REG_OVP_INT_CTL			0x5f
112 #define  WLED5_CTRL_REG_OVP_INT_TIMER_MASK		GENMASK(2, 0)
113 
114 /* WLED5 specific sink registers */
115 #define WLED5_SINK_REG_MOD_A_EN				0x50
116 #define WLED5_SINK_REG_MOD_B_EN				0x60
117 #define  WLED5_SINK_REG_MOD_EN_MASK			BIT(7)
118 
119 #define WLED5_SINK_REG_MOD_A_SRC_SEL			0x51
120 #define WLED5_SINK_REG_MOD_B_SRC_SEL			0x61
121 #define  WLED5_SINK_REG_MOD_SRC_SEL_HIGH		0
122 #define  WLED5_SINK_REG_MOD_SRC_SEL_EXT			0x03
123 #define  WLED5_SINK_REG_MOD_SRC_SEL_MASK		GENMASK(1, 0)
124 
125 #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL	0x52
126 #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL	0x62
127 #define  WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B		0
128 #define  WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B		1
129 
130 #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB		0x53
131 #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_MSB		0x54
132 #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB		0x63
133 #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_MSB		0x64
134 
135 #define WLED5_SINK_REG_MOD_SYNC_BIT			0x65
136 #define  WLED5_SINK_REG_SYNC_MOD_A_BIT			BIT(0)
137 #define  WLED5_SINK_REG_SYNC_MOD_B_BIT			BIT(1)
138 #define  WLED5_SINK_REG_SYNC_MASK			GENMASK(1, 0)
139 
140 /* WLED5 specific per-'string' registers below */
141 #define WLED5_SINK_REG_STR_FULL_SCALE_CURR(n)		(0x72 + (n * 0x10))
142 
143 #define WLED5_SINK_REG_STR_SRC_SEL(n)			(0x73 + (n * 0x10))
144 #define  WLED5_SINK_REG_SRC_SEL_MOD_A			0
145 #define  WLED5_SINK_REG_SRC_SEL_MOD_B			1
146 #define  WLED5_SINK_REG_SRC_SEL_MASK			GENMASK(1, 0)
147 
148 struct wled_var_cfg {
149 	const u32 *values;
150 	u32 (*fn)(u32);
151 	int size;
152 };
153 
154 struct wled_u32_opts {
155 	const char *name;
156 	u32 *val_ptr;
157 	const struct wled_var_cfg *cfg;
158 };
159 
160 struct wled_bool_opts {
161 	const char *name;
162 	bool *val_ptr;
163 };
164 
165 struct wled_config {
166 	u32 boost_i_limit;
167 	u32 ovp;
168 	u32 switch_freq;
169 	u32 num_strings;
170 	u32 string_i_limit;
171 	u32 enabled_strings[WLED_MAX_STRINGS];
172 	u32 mod_sel;
173 	u32 cabc_sel;
174 	bool cs_out_en;
175 	bool ext_gen;
176 	bool cabc;
177 	bool external_pfet;
178 	bool auto_detection_enabled;
179 };
180 
181 struct wled {
182 	const char *name;
183 	struct device *dev;
184 	struct regmap *regmap;
185 	struct mutex lock;	/* Lock to avoid race from thread irq handler */
186 	ktime_t last_short_event;
187 	ktime_t start_ovp_fault_time;
188 	u16 ctrl_addr;
189 	u16 sink_addr;
190 	u16 max_string_count;
191 	u16 auto_detection_ovp_count;
192 	u32 brightness;
193 	u32 max_brightness;
194 	u32 short_count;
195 	u32 auto_detect_count;
196 	u32 version;
197 	bool disabled_by_short;
198 	bool has_short_detect;
199 	bool cabc_disabled;
200 	int short_irq;
201 	int ovp_irq;
202 
203 	struct wled_config cfg;
204 	struct delayed_work ovp_work;
205 
206 	/* Configures the brightness. Applicable for wled3, wled4 and wled5 */
207 	int (*wled_set_brightness)(struct wled *wled, u16 brightness);
208 
209 	/* Configures the cabc register. Applicable for wled4 and wled5 */
210 	int (*wled_cabc_config)(struct wled *wled, bool enable);
211 
212 	/*
213 	 * Toggles the sync bit for the brightness update to take place.
214 	 * Applicable for WLED3, WLED4 and WLED5.
215 	 */
216 	int (*wled_sync_toggle)(struct wled *wled);
217 
218 	/*
219 	 * Time to wait before checking the OVP status after wled module enable.
220 	 * Applicable for WLED4 and WLED5.
221 	 */
222 	int (*wled_ovp_delay)(struct wled *wled);
223 
224 	/*
225 	 * Determines if the auto string detection is required.
226 	 * Applicable for WLED4 and WLED5
227 	 */
228 	bool (*wled_auto_detection_required)(struct wled *wled);
229 };
230 
231 static int wled3_set_brightness(struct wled *wled, u16 brightness)
232 {
233 	int rc, i;
234 	__le16 v;
235 
236 	v = cpu_to_le16(brightness & WLED3_SINK_REG_BRIGHT_MAX);
237 
238 	for (i = 0; i < wled->cfg.num_strings; ++i) {
239 		rc = regmap_bulk_write(wled->regmap, wled->ctrl_addr +
240 				       WLED3_SINK_REG_BRIGHT(wled->cfg.enabled_strings[i]),
241 				       &v, sizeof(v));
242 		if (rc < 0)
243 			return rc;
244 	}
245 
246 	return 0;
247 }
248 
249 static int wled4_set_brightness(struct wled *wled, u16 brightness)
250 {
251 	int rc, i;
252 	u16 low_limit = wled->max_brightness * 4 / 1000;
253 	__le16 v;
254 
255 	/* WLED4's lower limit of operation is 0.4% */
256 	if (brightness > 0 && brightness < low_limit)
257 		brightness = low_limit;
258 
259 	v = cpu_to_le16(brightness & WLED3_SINK_REG_BRIGHT_MAX);
260 
261 	for (i = 0; i < wled->cfg.num_strings; ++i) {
262 		rc = regmap_bulk_write(wled->regmap, wled->sink_addr +
263 				       WLED4_SINK_REG_BRIGHT(wled->cfg.enabled_strings[i]),
264 				       &v, sizeof(v));
265 		if (rc < 0)
266 			return rc;
267 	}
268 
269 	return 0;
270 }
271 
272 static int wled5_set_brightness(struct wled *wled, u16 brightness)
273 {
274 	int rc, offset;
275 	u16 low_limit = wled->max_brightness * 1 / 1000;
276 	__le16 v;
277 
278 	/* WLED5's lower limit is 0.1% */
279 	if (brightness < low_limit)
280 		brightness = low_limit;
281 
282 	v = cpu_to_le16(brightness & WLED5_SINK_REG_BRIGHT_MAX_15B);
283 
284 	offset = (wled->cfg.mod_sel == MOD_A) ?
285 		  WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB :
286 		  WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB;
287 
288 	rc = regmap_bulk_write(wled->regmap, wled->sink_addr + offset,
289 			       &v, sizeof(v));
290 	return rc;
291 }
292 
293 static void wled_ovp_work(struct work_struct *work)
294 {
295 	struct wled *wled = container_of(work,
296 					 struct wled, ovp_work.work);
297 	enable_irq(wled->ovp_irq);
298 }
299 
300 static int wled_module_enable(struct wled *wled, int val)
301 {
302 	int rc;
303 
304 	if (wled->disabled_by_short)
305 		return -ENXIO;
306 
307 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
308 				WLED3_CTRL_REG_MOD_EN,
309 				WLED3_CTRL_REG_MOD_EN_MASK,
310 				val << WLED3_CTRL_REG_MOD_EN_SHIFT);
311 	if (rc < 0)
312 		return rc;
313 
314 	if (wled->ovp_irq > 0) {
315 		if (val) {
316 			/*
317 			 * The hardware generates a storm of spurious OVP
318 			 * interrupts during soft start operations. So defer
319 			 * enabling the IRQ for 10ms to ensure that the
320 			 * soft start is complete.
321 			 */
322 			schedule_delayed_work(&wled->ovp_work, HZ / 100);
323 		} else {
324 			if (!cancel_delayed_work_sync(&wled->ovp_work))
325 				disable_irq(wled->ovp_irq);
326 		}
327 	}
328 
329 	return 0;
330 }
331 
332 static int wled3_sync_toggle(struct wled *wled)
333 {
334 	int rc;
335 	unsigned int mask = GENMASK(wled->max_string_count - 1, 0);
336 
337 	rc = regmap_update_bits(wled->regmap,
338 				wled->sink_addr + WLED3_SINK_REG_SYNC,
339 				mask, WLED3_SINK_REG_SYNC_CLEAR);
340 	if (rc < 0)
341 		return rc;
342 
343 	rc = regmap_update_bits(wled->regmap,
344 				wled->sink_addr + WLED3_SINK_REG_SYNC,
345 				mask, mask);
346 
347 	return rc;
348 }
349 
350 static int wled5_mod_sync_toggle(struct wled *wled)
351 {
352 	int rc;
353 	u8 val;
354 
355 	rc = regmap_update_bits(wled->regmap,
356 				wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT,
357 				WLED5_SINK_REG_SYNC_MASK, 0);
358 	if (rc < 0)
359 		return rc;
360 
361 	val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT :
362 					     WLED5_SINK_REG_SYNC_MOD_B_BIT;
363 	return regmap_update_bits(wled->regmap,
364 				  wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT,
365 				  WLED5_SINK_REG_SYNC_MASK, val);
366 }
367 
368 static int wled_ovp_fault_status(struct wled *wled, bool *fault_set)
369 {
370 	int rc;
371 	u32 int_rt_sts, fault_sts;
372 
373 	*fault_set = false;
374 	rc = regmap_read(wled->regmap,
375 			wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS,
376 			&int_rt_sts);
377 	if (rc < 0) {
378 		dev_err(wled->dev, "Failed to read INT_RT_STS rc=%d\n", rc);
379 		return rc;
380 	}
381 
382 	rc = regmap_read(wled->regmap,
383 			wled->ctrl_addr + WLED3_CTRL_REG_FAULT_STATUS,
384 			&fault_sts);
385 	if (rc < 0) {
386 		dev_err(wled->dev, "Failed to read FAULT_STATUS rc=%d\n", rc);
387 		return rc;
388 	}
389 
390 	if (int_rt_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS)
391 		*fault_set = true;
392 
393 	if (wled->version == 4 && (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT))
394 		*fault_set = true;
395 
396 	if (wled->version == 5 && (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT |
397 				   WLED5_CTRL_REG_OVP_PRE_ALARM_BIT)))
398 		*fault_set = true;
399 
400 	if (*fault_set)
401 		dev_dbg(wled->dev, "WLED OVP fault detected, int_rt_sts=0x%x fault_sts=0x%x\n",
402 			int_rt_sts, fault_sts);
403 
404 	return rc;
405 }
406 
407 static int wled4_ovp_delay(struct wled *wled)
408 {
409 	return WLED_SOFT_START_DLY_US;
410 }
411 
412 static int wled5_ovp_delay(struct wled *wled)
413 {
414 	int rc, delay_us;
415 	u32 val;
416 	u8 ovp_timer_ms[8] = {1, 2, 4, 8, 12, 16, 20, 24};
417 
418 	/* For WLED5, get the delay based on OVP timer */
419 	rc = regmap_read(wled->regmap, wled->ctrl_addr +
420 			 WLED5_CTRL_REG_OVP_INT_CTL, &val);
421 	if (rc < 0)
422 		delay_us =
423 		ovp_timer_ms[val & WLED5_CTRL_REG_OVP_INT_TIMER_MASK] * 1000;
424 	else
425 		delay_us = 2 * WLED_SOFT_START_DLY_US;
426 
427 	dev_dbg(wled->dev, "delay_time_us: %d\n", delay_us);
428 
429 	return delay_us;
430 }
431 
432 static int wled_update_status(struct backlight_device *bl)
433 {
434 	struct wled *wled = bl_get_data(bl);
435 	u16 brightness = backlight_get_brightness(bl);
436 	int rc = 0;
437 
438 	mutex_lock(&wled->lock);
439 	if (brightness) {
440 		rc = wled->wled_set_brightness(wled, brightness);
441 		if (rc < 0) {
442 			dev_err(wled->dev, "wled failed to set brightness rc:%d\n",
443 				rc);
444 			goto unlock_mutex;
445 		}
446 
447 		if (wled->version < 5) {
448 			rc = wled->wled_sync_toggle(wled);
449 			if (rc < 0) {
450 				dev_err(wled->dev, "wled sync failed rc:%d\n", rc);
451 				goto unlock_mutex;
452 			}
453 		} else {
454 			/*
455 			 * For WLED5 toggling the MOD_SYNC_BIT updates the
456 			 * brightness
457 			 */
458 			rc = wled5_mod_sync_toggle(wled);
459 			if (rc < 0) {
460 				dev_err(wled->dev, "wled mod sync failed rc:%d\n",
461 					rc);
462 				goto unlock_mutex;
463 			}
464 		}
465 	}
466 
467 	if (!!brightness != !!wled->brightness) {
468 		rc = wled_module_enable(wled, !!brightness);
469 		if (rc < 0) {
470 			dev_err(wled->dev, "wled enable failed rc:%d\n", rc);
471 			goto unlock_mutex;
472 		}
473 	}
474 
475 	wled->brightness = brightness;
476 
477 unlock_mutex:
478 	mutex_unlock(&wled->lock);
479 
480 	return rc;
481 }
482 
483 static int wled4_cabc_config(struct wled *wled, bool enable)
484 {
485 	int i, j, rc;
486 	u8 val;
487 
488 	for (i = 0; i < wled->cfg.num_strings; i++) {
489 		j = wled->cfg.enabled_strings[i];
490 
491 		val = enable ? WLED4_SINK_REG_STR_CABC_MASK : 0;
492 		rc = regmap_update_bits(wled->regmap, wled->sink_addr +
493 					WLED4_SINK_REG_STR_CABC(j),
494 					WLED4_SINK_REG_STR_CABC_MASK, val);
495 		if (rc < 0)
496 			return rc;
497 	}
498 
499 	return 0;
500 }
501 
502 static int wled5_cabc_config(struct wled *wled, bool enable)
503 {
504 	int rc, offset;
505 	u8 reg;
506 
507 	if (wled->cabc_disabled)
508 		return 0;
509 
510 	reg = enable ? wled->cfg.cabc_sel : 0;
511 	offset = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_A_SRC_SEL :
512 						WLED5_SINK_REG_MOD_B_SRC_SEL;
513 
514 	rc = regmap_update_bits(wled->regmap, wled->sink_addr + offset,
515 				WLED5_SINK_REG_MOD_SRC_SEL_MASK, reg);
516 	if (rc < 0) {
517 		pr_err("Error in configuring CABC rc=%d\n", rc);
518 		return rc;
519 	}
520 
521 	if (!wled->cfg.cabc_sel)
522 		wled->cabc_disabled = true;
523 
524 	return 0;
525 }
526 
527 #define WLED_SHORT_DLY_MS			20
528 #define WLED_SHORT_CNT_MAX			5
529 #define WLED_SHORT_RESET_CNT_DLY_US		USEC_PER_SEC
530 
531 static irqreturn_t wled_short_irq_handler(int irq, void *_wled)
532 {
533 	struct wled *wled = _wled;
534 	int rc;
535 	s64 elapsed_time;
536 
537 	wled->short_count++;
538 	mutex_lock(&wled->lock);
539 	rc = wled_module_enable(wled, false);
540 	if (rc < 0) {
541 		dev_err(wled->dev, "wled disable failed rc:%d\n", rc);
542 		goto unlock_mutex;
543 	}
544 
545 	elapsed_time = ktime_us_delta(ktime_get(),
546 				      wled->last_short_event);
547 	if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US)
548 		wled->short_count = 1;
549 
550 	if (wled->short_count > WLED_SHORT_CNT_MAX) {
551 		dev_err(wled->dev, "Short triggered %d times, disabling WLED forever!\n",
552 			wled->short_count);
553 		wled->disabled_by_short = true;
554 		goto unlock_mutex;
555 	}
556 
557 	wled->last_short_event = ktime_get();
558 
559 	msleep(WLED_SHORT_DLY_MS);
560 	rc = wled_module_enable(wled, true);
561 	if (rc < 0)
562 		dev_err(wled->dev, "wled enable failed rc:%d\n", rc);
563 
564 unlock_mutex:
565 	mutex_unlock(&wled->lock);
566 
567 	return IRQ_HANDLED;
568 }
569 
570 #define AUTO_DETECT_BRIGHTNESS		200
571 
572 static void wled_auto_string_detection(struct wled *wled)
573 {
574 	int rc = 0, i, j, delay_time_us;
575 	u32 sink_config = 0;
576 	u8 sink_test = 0, sink_valid = 0, val;
577 	bool fault_set;
578 
579 	/* Read configured sink configuration */
580 	rc = regmap_read(wled->regmap, wled->sink_addr +
581 			 WLED4_SINK_REG_CURR_SINK, &sink_config);
582 	if (rc < 0) {
583 		dev_err(wled->dev, "Failed to read SINK configuration rc=%d\n",
584 			rc);
585 		goto failed_detect;
586 	}
587 
588 	/* Disable the module before starting detection */
589 	rc = regmap_update_bits(wled->regmap,
590 				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
591 				WLED3_CTRL_REG_MOD_EN_MASK, 0);
592 	if (rc < 0) {
593 		dev_err(wled->dev, "Failed to disable WLED module rc=%d\n", rc);
594 		goto failed_detect;
595 	}
596 
597 	/* Set low brightness across all sinks */
598 	rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS);
599 	if (rc < 0) {
600 		dev_err(wled->dev, "Failed to set brightness for auto detection rc=%d\n",
601 			rc);
602 		goto failed_detect;
603 	}
604 
605 	if (wled->cfg.cabc) {
606 		rc = wled->wled_cabc_config(wled, false);
607 		if (rc < 0)
608 			goto failed_detect;
609 	}
610 
611 	/* Disable all sinks */
612 	rc = regmap_write(wled->regmap,
613 			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0);
614 	if (rc < 0) {
615 		dev_err(wled->dev, "Failed to disable all sinks rc=%d\n", rc);
616 		goto failed_detect;
617 	}
618 
619 	/* Iterate through the strings one by one */
620 	for (i = 0; i < wled->cfg.num_strings; i++) {
621 		j = wled->cfg.enabled_strings[i];
622 		sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + j));
623 
624 		/* Enable feedback control */
625 		rc = regmap_write(wled->regmap, wled->ctrl_addr +
626 				  WLED3_CTRL_REG_FEEDBACK_CONTROL, j + 1);
627 		if (rc < 0) {
628 			dev_err(wled->dev, "Failed to enable feedback for SINK %d rc = %d\n",
629 				j + 1, rc);
630 			goto failed_detect;
631 		}
632 
633 		/* Enable the sink */
634 		rc = regmap_write(wled->regmap, wled->sink_addr +
635 				  WLED4_SINK_REG_CURR_SINK, sink_test);
636 		if (rc < 0) {
637 			dev_err(wled->dev, "Failed to configure SINK %d rc=%d\n",
638 				j + 1, rc);
639 			goto failed_detect;
640 		}
641 
642 		/* Enable the module */
643 		rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
644 					WLED3_CTRL_REG_MOD_EN,
645 					WLED3_CTRL_REG_MOD_EN_MASK,
646 					WLED3_CTRL_REG_MOD_EN_MASK);
647 		if (rc < 0) {
648 			dev_err(wled->dev, "Failed to enable WLED module rc=%d\n",
649 				rc);
650 			goto failed_detect;
651 		}
652 
653 		delay_time_us = wled->wled_ovp_delay(wled);
654 		usleep_range(delay_time_us, delay_time_us + 1000);
655 
656 		rc = wled_ovp_fault_status(wled, &fault_set);
657 		if (rc < 0) {
658 			dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n",
659 				rc);
660 			goto failed_detect;
661 		}
662 
663 		if (fault_set)
664 			dev_dbg(wled->dev, "WLED OVP fault detected with SINK %d\n",
665 				j + 1);
666 		else
667 			sink_valid |= sink_test;
668 
669 		/* Disable the module */
670 		rc = regmap_update_bits(wled->regmap,
671 					wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
672 					WLED3_CTRL_REG_MOD_EN_MASK, 0);
673 		if (rc < 0) {
674 			dev_err(wled->dev, "Failed to disable WLED module rc=%d\n",
675 				rc);
676 			goto failed_detect;
677 		}
678 	}
679 
680 	if (!sink_valid) {
681 		dev_err(wled->dev, "No valid WLED sinks found\n");
682 		wled->disabled_by_short = true;
683 		goto failed_detect;
684 	}
685 
686 	if (sink_valid != sink_config) {
687 		dev_warn(wled->dev, "%x is not a valid sink configuration - using %x instead\n",
688 			 sink_config, sink_valid);
689 		sink_config = sink_valid;
690 	}
691 
692 	/* Write the new sink configuration */
693 	rc = regmap_write(wled->regmap,
694 			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
695 			  sink_config);
696 	if (rc < 0) {
697 		dev_err(wled->dev, "Failed to reconfigure the default sink rc=%d\n",
698 			rc);
699 		goto failed_detect;
700 	}
701 
702 	/* Enable valid sinks */
703 	if (wled->version == 4) {
704 		for (i = 0; i < wled->cfg.num_strings; i++) {
705 			j = wled->cfg.enabled_strings[i];
706 			if (sink_config &
707 			    BIT(WLED4_SINK_REG_CURR_SINK_SHFT + j))
708 				val = WLED4_SINK_REG_STR_MOD_MASK;
709 			else
710 				/* Disable modulator_en for unused sink */
711 				val = 0;
712 
713 			rc = regmap_write(wled->regmap, wled->sink_addr +
714 					  WLED4_SINK_REG_STR_MOD_EN(j), val);
715 			if (rc < 0) {
716 				dev_err(wled->dev, "Failed to configure MODULATOR_EN rc=%d\n",
717 					rc);
718 				goto failed_detect;
719 			}
720 		}
721 	}
722 
723 	/* Enable CABC */
724 	rc = wled->wled_cabc_config(wled, true);
725 	if (rc < 0)
726 		goto failed_detect;
727 
728 	/* Restore the feedback setting */
729 	rc = regmap_write(wled->regmap,
730 			  wled->ctrl_addr + WLED3_CTRL_REG_FEEDBACK_CONTROL, 0);
731 	if (rc < 0) {
732 		dev_err(wled->dev, "Failed to restore feedback setting rc=%d\n",
733 			rc);
734 		goto failed_detect;
735 	}
736 
737 	/* Restore brightness */
738 	rc = wled4_set_brightness(wled, wled->brightness);
739 	if (rc < 0) {
740 		dev_err(wled->dev, "Failed to set brightness after auto detection rc=%d\n",
741 			rc);
742 		goto failed_detect;
743 	}
744 
745 	rc = regmap_update_bits(wled->regmap,
746 				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
747 				WLED3_CTRL_REG_MOD_EN_MASK,
748 				WLED3_CTRL_REG_MOD_EN_MASK);
749 	if (rc < 0) {
750 		dev_err(wled->dev, "Failed to enable WLED module rc=%d\n", rc);
751 		goto failed_detect;
752 	}
753 
754 failed_detect:
755 	return;
756 }
757 
758 #define WLED_AUTO_DETECT_OVP_COUNT		5
759 #define WLED_AUTO_DETECT_CNT_DLY_US		USEC_PER_SEC
760 
761 static bool wled4_auto_detection_required(struct wled *wled)
762 {
763 	s64 elapsed_time_us;
764 
765 	if (!wled->cfg.auto_detection_enabled)
766 		return false;
767 
768 	/*
769 	 * Check if the OVP fault was an occasional one
770 	 * or if it's firing continuously, the latter qualifies
771 	 * for an auto-detection check.
772 	 */
773 	if (!wled->auto_detection_ovp_count) {
774 		wled->start_ovp_fault_time = ktime_get();
775 		wled->auto_detection_ovp_count++;
776 	} else {
777 		elapsed_time_us = ktime_us_delta(ktime_get(),
778 						 wled->start_ovp_fault_time);
779 		if (elapsed_time_us > WLED_AUTO_DETECT_CNT_DLY_US)
780 			wled->auto_detection_ovp_count = 0;
781 		else
782 			wled->auto_detection_ovp_count++;
783 
784 		if (wled->auto_detection_ovp_count >=
785 				WLED_AUTO_DETECT_OVP_COUNT) {
786 			wled->auto_detection_ovp_count = 0;
787 			return true;
788 		}
789 	}
790 
791 	return false;
792 }
793 
794 static bool wled5_auto_detection_required(struct wled *wled)
795 {
796 	if (!wled->cfg.auto_detection_enabled)
797 		return false;
798 
799 	/*
800 	 * Unlike WLED4, WLED5 has OVP fault density interrupt configuration
801 	 * i.e. to count the number of OVP alarms for a certain duration before
802 	 * triggering OVP fault interrupt. By default, number of OVP fault
803 	 * events counted before an interrupt is fired is 32 and the time
804 	 * interval is 12 ms. If we see one OVP fault interrupt, then that
805 	 * should qualify for a real OVP fault condition to run auto detection
806 	 * algorithm.
807 	 */
808 	return true;
809 }
810 
811 static int wled_auto_detection_at_init(struct wled *wled)
812 {
813 	int rc;
814 	bool fault_set;
815 
816 	if (!wled->cfg.auto_detection_enabled)
817 		return 0;
818 
819 	rc = wled_ovp_fault_status(wled, &fault_set);
820 	if (rc < 0) {
821 		dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n",
822 			rc);
823 		return rc;
824 	}
825 
826 	if (fault_set) {
827 		mutex_lock(&wled->lock);
828 		wled_auto_string_detection(wled);
829 		mutex_unlock(&wled->lock);
830 	}
831 
832 	return rc;
833 }
834 
835 static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled)
836 {
837 	struct wled *wled = _wled;
838 	int rc;
839 	u32 int_sts, fault_sts;
840 
841 	rc = regmap_read(wled->regmap,
842 			 wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, &int_sts);
843 	if (rc < 0) {
844 		dev_err(wled->dev, "Error in reading WLED3_INT_RT_STS rc=%d\n",
845 			rc);
846 		return IRQ_HANDLED;
847 	}
848 
849 	rc = regmap_read(wled->regmap, wled->ctrl_addr +
850 			 WLED3_CTRL_REG_FAULT_STATUS, &fault_sts);
851 	if (rc < 0) {
852 		dev_err(wled->dev, "Error in reading WLED_FAULT_STATUS rc=%d\n",
853 			rc);
854 		return IRQ_HANDLED;
855 	}
856 
857 	if (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT |
858 		WLED3_CTRL_REG_ILIM_FAULT_BIT))
859 		dev_dbg(wled->dev, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
860 			int_sts, fault_sts);
861 
862 	if (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT) {
863 		if (wled->wled_auto_detection_required(wled)) {
864 			mutex_lock(&wled->lock);
865 			wled_auto_string_detection(wled);
866 			mutex_unlock(&wled->lock);
867 		}
868 	}
869 
870 	return IRQ_HANDLED;
871 }
872 
873 static int wled3_setup(struct wled *wled)
874 {
875 	u16 addr;
876 	u8 sink_en = 0;
877 	int rc, i, j;
878 
879 	rc = regmap_update_bits(wled->regmap,
880 				wled->ctrl_addr + WLED3_CTRL_REG_OVP,
881 				WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp);
882 	if (rc)
883 		return rc;
884 
885 	rc = regmap_update_bits(wled->regmap,
886 				wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT,
887 				WLED3_CTRL_REG_ILIMIT_MASK,
888 				wled->cfg.boost_i_limit);
889 	if (rc)
890 		return rc;
891 
892 	rc = regmap_update_bits(wled->regmap,
893 				wled->ctrl_addr + WLED3_CTRL_REG_FREQ,
894 				WLED3_CTRL_REG_FREQ_MASK,
895 				wled->cfg.switch_freq);
896 	if (rc)
897 		return rc;
898 
899 	for (i = 0; i < wled->cfg.num_strings; ++i) {
900 		j = wled->cfg.enabled_strings[i];
901 		addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_EN(j);
902 		rc = regmap_update_bits(wled->regmap, addr,
903 					WLED3_SINK_REG_STR_MOD_MASK,
904 					WLED3_SINK_REG_STR_MOD_MASK);
905 		if (rc)
906 			return rc;
907 
908 		if (wled->cfg.ext_gen) {
909 			addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_SRC(j);
910 			rc = regmap_update_bits(wled->regmap, addr,
911 						WLED3_SINK_REG_STR_MOD_SRC_MASK,
912 						WLED3_SINK_REG_STR_MOD_SRC_EXT);
913 			if (rc)
914 				return rc;
915 		}
916 
917 		addr = wled->ctrl_addr + WLED3_SINK_REG_STR_FULL_SCALE_CURR(j);
918 		rc = regmap_update_bits(wled->regmap, addr,
919 					WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK,
920 					wled->cfg.string_i_limit);
921 		if (rc)
922 			return rc;
923 
924 		addr = wled->ctrl_addr + WLED3_SINK_REG_STR_CABC(j);
925 		rc = regmap_update_bits(wled->regmap, addr,
926 					WLED3_SINK_REG_STR_CABC_MASK,
927 					wled->cfg.cabc ?
928 					WLED3_SINK_REG_STR_CABC_MASK : 0);
929 		if (rc)
930 			return rc;
931 
932 		sink_en |= BIT(j + WLED3_SINK_REG_CURR_SINK_SHFT);
933 	}
934 
935 	rc = regmap_update_bits(wled->regmap,
936 				wled->ctrl_addr + WLED3_SINK_REG_CURR_SINK,
937 				WLED3_SINK_REG_CURR_SINK_MASK, sink_en);
938 	if (rc)
939 		return rc;
940 
941 	return 0;
942 }
943 
944 static const struct wled_config wled3_config_defaults = {
945 	.boost_i_limit = 3,
946 	.string_i_limit = 20,
947 	.ovp = 2,
948 	.num_strings = 3,
949 	.switch_freq = 5,
950 	.cs_out_en = false,
951 	.ext_gen = false,
952 	.cabc = false,
953 	.enabled_strings = {0, 1, 2},
954 };
955 
956 static int wled4_setup(struct wled *wled)
957 {
958 	int rc, temp, i, j;
959 	u16 addr;
960 	u8 sink_en = 0;
961 	u32 sink_cfg;
962 
963 	rc = regmap_update_bits(wled->regmap,
964 				wled->ctrl_addr + WLED3_CTRL_REG_OVP,
965 				WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp);
966 	if (rc < 0)
967 		return rc;
968 
969 	rc = regmap_update_bits(wled->regmap,
970 				wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT,
971 				WLED3_CTRL_REG_ILIMIT_MASK,
972 				wled->cfg.boost_i_limit);
973 	if (rc < 0)
974 		return rc;
975 
976 	rc = regmap_update_bits(wled->regmap,
977 				wled->ctrl_addr + WLED3_CTRL_REG_FREQ,
978 				WLED3_CTRL_REG_FREQ_MASK,
979 				wled->cfg.switch_freq);
980 	if (rc < 0)
981 		return rc;
982 
983 	if (wled->cfg.external_pfet) {
984 		/* Unlock the secure register access */
985 		rc = regmap_write(wled->regmap, wled->ctrl_addr +
986 				  WLED4_CTRL_REG_SEC_ACCESS,
987 				  WLED4_CTRL_REG_SEC_UNLOCK);
988 		if (rc < 0)
989 			return rc;
990 
991 		rc = regmap_write(wled->regmap,
992 				  wled->ctrl_addr + WLED4_CTRL_REG_TEST1,
993 				  WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2);
994 		if (rc < 0)
995 			return rc;
996 	}
997 
998 	rc = regmap_read(wled->regmap, wled->sink_addr +
999 			 WLED4_SINK_REG_CURR_SINK, &sink_cfg);
1000 	if (rc < 0)
1001 		return rc;
1002 
1003 	for (i = 0; i < wled->cfg.num_strings; i++) {
1004 		j = wled->cfg.enabled_strings[i];
1005 		temp = j + WLED4_SINK_REG_CURR_SINK_SHFT;
1006 		sink_en |= 1 << temp;
1007 	}
1008 
1009 	if (sink_cfg == sink_en) {
1010 		rc = wled_auto_detection_at_init(wled);
1011 		return rc;
1012 	}
1013 
1014 	rc = regmap_update_bits(wled->regmap,
1015 				wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
1016 				WLED4_SINK_REG_CURR_SINK_MASK, 0);
1017 	if (rc < 0)
1018 		return rc;
1019 
1020 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
1021 				WLED3_CTRL_REG_MOD_EN,
1022 				WLED3_CTRL_REG_MOD_EN_MASK, 0);
1023 	if (rc < 0)
1024 		return rc;
1025 
1026 	/* Per sink/string configuration */
1027 	for (i = 0; i < wled->cfg.num_strings; i++) {
1028 		j = wled->cfg.enabled_strings[i];
1029 
1030 		addr = wled->sink_addr +
1031 				WLED4_SINK_REG_STR_MOD_EN(j);
1032 		rc = regmap_update_bits(wled->regmap, addr,
1033 					WLED4_SINK_REG_STR_MOD_MASK,
1034 					WLED4_SINK_REG_STR_MOD_MASK);
1035 		if (rc < 0)
1036 			return rc;
1037 
1038 		addr = wled->sink_addr +
1039 				WLED4_SINK_REG_STR_FULL_SCALE_CURR(j);
1040 		rc = regmap_update_bits(wled->regmap, addr,
1041 					WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK,
1042 					wled->cfg.string_i_limit);
1043 		if (rc < 0)
1044 			return rc;
1045 	}
1046 
1047 	rc = wled4_cabc_config(wled, wled->cfg.cabc);
1048 	if (rc < 0)
1049 		return rc;
1050 
1051 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
1052 				WLED3_CTRL_REG_MOD_EN,
1053 				WLED3_CTRL_REG_MOD_EN_MASK,
1054 				WLED3_CTRL_REG_MOD_EN_MASK);
1055 	if (rc < 0)
1056 		return rc;
1057 
1058 	rc = regmap_update_bits(wled->regmap,
1059 				wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
1060 				WLED4_SINK_REG_CURR_SINK_MASK, sink_en);
1061 	if (rc < 0)
1062 		return rc;
1063 
1064 	rc = wled->wled_sync_toggle(wled);
1065 	if (rc < 0) {
1066 		dev_err(wled->dev, "Failed to toggle sync reg rc:%d\n", rc);
1067 		return rc;
1068 	}
1069 
1070 	rc = wled_auto_detection_at_init(wled);
1071 
1072 	return rc;
1073 }
1074 
1075 static const struct wled_config wled4_config_defaults = {
1076 	.boost_i_limit = 4,
1077 	.string_i_limit = 10,
1078 	.ovp = 1,
1079 	.num_strings = 4,
1080 	.switch_freq = 11,
1081 	.cabc = false,
1082 	.external_pfet = false,
1083 	.auto_detection_enabled = false,
1084 	.enabled_strings = {0, 1, 2, 3},
1085 };
1086 
1087 static int wled5_setup(struct wled *wled)
1088 {
1089 	int rc, temp, i, j, offset;
1090 	u8 sink_en = 0;
1091 	u16 addr;
1092 	u32 val;
1093 
1094 	rc = regmap_update_bits(wled->regmap,
1095 				wled->ctrl_addr + WLED3_CTRL_REG_OVP,
1096 				WLED5_CTRL_REG_OVP_MASK, wled->cfg.ovp);
1097 	if (rc < 0)
1098 		return rc;
1099 
1100 	rc = regmap_update_bits(wled->regmap,
1101 				wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT,
1102 				WLED3_CTRL_REG_ILIMIT_MASK,
1103 				wled->cfg.boost_i_limit);
1104 	if (rc < 0)
1105 		return rc;
1106 
1107 	rc = regmap_update_bits(wled->regmap,
1108 				wled->ctrl_addr + WLED3_CTRL_REG_FREQ,
1109 				WLED3_CTRL_REG_FREQ_MASK,
1110 				wled->cfg.switch_freq);
1111 	if (rc < 0)
1112 		return rc;
1113 
1114 	/* Per sink/string configuration */
1115 	for (i = 0; i < wled->cfg.num_strings; ++i) {
1116 		j = wled->cfg.enabled_strings[i];
1117 		addr = wled->sink_addr +
1118 				WLED4_SINK_REG_STR_FULL_SCALE_CURR(j);
1119 		rc = regmap_update_bits(wled->regmap, addr,
1120 					WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK,
1121 					wled->cfg.string_i_limit);
1122 		if (rc < 0)
1123 			return rc;
1124 
1125 		addr = wled->sink_addr + WLED5_SINK_REG_STR_SRC_SEL(j);
1126 		rc = regmap_update_bits(wled->regmap, addr,
1127 					WLED5_SINK_REG_SRC_SEL_MASK,
1128 					wled->cfg.mod_sel == MOD_A ?
1129 					WLED5_SINK_REG_SRC_SEL_MOD_A :
1130 					WLED5_SINK_REG_SRC_SEL_MOD_B);
1131 
1132 		temp = j + WLED4_SINK_REG_CURR_SINK_SHFT;
1133 		sink_en |= 1 << temp;
1134 	}
1135 
1136 	rc = wled5_cabc_config(wled, wled->cfg.cabc_sel ? true : false);
1137 	if (rc < 0)
1138 		return rc;
1139 
1140 	/* Enable one of the modulators A or B based on mod_sel */
1141 	addr = wled->sink_addr + WLED5_SINK_REG_MOD_A_EN;
1142 	val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_EN_MASK : 0;
1143 	rc = regmap_update_bits(wled->regmap, addr,
1144 				WLED5_SINK_REG_MOD_EN_MASK, val);
1145 	if (rc < 0)
1146 		return rc;
1147 
1148 	addr = wled->sink_addr + WLED5_SINK_REG_MOD_B_EN;
1149 	val = (wled->cfg.mod_sel == MOD_B) ? WLED5_SINK_REG_MOD_EN_MASK : 0;
1150 	rc = regmap_update_bits(wled->regmap, addr,
1151 				WLED5_SINK_REG_MOD_EN_MASK, val);
1152 	if (rc < 0)
1153 		return rc;
1154 
1155 	offset = (wled->cfg.mod_sel == MOD_A) ?
1156 		  WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL :
1157 		  WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL;
1158 
1159 	addr = wled->sink_addr + offset;
1160 	val = (wled->max_brightness == WLED5_SINK_REG_BRIGHT_MAX_15B) ?
1161 		 WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B :
1162 		 WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B;
1163 	rc = regmap_write(wled->regmap, addr, val);
1164 	if (rc < 0)
1165 		return rc;
1166 
1167 	rc = regmap_update_bits(wled->regmap,
1168 				wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
1169 				WLED4_SINK_REG_CURR_SINK_MASK, sink_en);
1170 	if (rc < 0)
1171 		return rc;
1172 
1173 	/* This updates only FSC configuration in WLED5 */
1174 	rc = wled->wled_sync_toggle(wled);
1175 	if (rc < 0) {
1176 		pr_err("Failed to toggle sync reg rc:%d\n", rc);
1177 		return rc;
1178 	}
1179 
1180 	rc = wled_auto_detection_at_init(wled);
1181 	if (rc < 0)
1182 		return rc;
1183 
1184 	return 0;
1185 }
1186 
1187 static const struct wled_config wled5_config_defaults = {
1188 	.boost_i_limit = 5,
1189 	.string_i_limit = 10,
1190 	.ovp = 4,
1191 	.num_strings = 4,
1192 	.switch_freq = 11,
1193 	.mod_sel = 0,
1194 	.cabc_sel = 0,
1195 	.cabc = false,
1196 	.external_pfet = false,
1197 	.auto_detection_enabled = false,
1198 	.enabled_strings = {0, 1, 2, 3},
1199 };
1200 
1201 static const u32 wled3_boost_i_limit_values[] = {
1202 	105, 385, 525, 805, 980, 1260, 1400, 1680,
1203 };
1204 
1205 static const struct wled_var_cfg wled3_boost_i_limit_cfg = {
1206 	.values = wled3_boost_i_limit_values,
1207 	.size = ARRAY_SIZE(wled3_boost_i_limit_values),
1208 };
1209 
1210 static const u32 wled4_boost_i_limit_values[] = {
1211 	105, 280, 450, 620, 970, 1150, 1300, 1500,
1212 };
1213 
1214 static const struct wled_var_cfg wled4_boost_i_limit_cfg = {
1215 	.values = wled4_boost_i_limit_values,
1216 	.size = ARRAY_SIZE(wled4_boost_i_limit_values),
1217 };
1218 
1219 static inline u32 wled5_boost_i_limit_values_fn(u32 idx)
1220 {
1221 	return 525 + (idx * 175);
1222 }
1223 
1224 static const struct wled_var_cfg wled5_boost_i_limit_cfg = {
1225 	.fn = wled5_boost_i_limit_values_fn,
1226 	.size = 8,
1227 };
1228 
1229 static const u32 wled3_ovp_values[] = {
1230 	35, 32, 29, 27,
1231 };
1232 
1233 static const struct wled_var_cfg wled3_ovp_cfg = {
1234 	.values = wled3_ovp_values,
1235 	.size = ARRAY_SIZE(wled3_ovp_values),
1236 };
1237 
1238 static const u32 wled4_ovp_values[] = {
1239 	31100, 29600, 19600, 18100,
1240 };
1241 
1242 static const struct wled_var_cfg wled4_ovp_cfg = {
1243 	.values = wled4_ovp_values,
1244 	.size = ARRAY_SIZE(wled4_ovp_values),
1245 };
1246 
1247 static inline u32 wled5_ovp_values_fn(u32 idx)
1248 {
1249 	/*
1250 	 * 0000 - 38.5 V
1251 	 * 0001 - 37 V ..
1252 	 * 1111 - 16 V
1253 	 */
1254 	return 38500 - (idx * 1500);
1255 }
1256 
1257 static const struct wled_var_cfg wled5_ovp_cfg = {
1258 	.fn = wled5_ovp_values_fn,
1259 	.size = 16,
1260 };
1261 
1262 static u32 wled3_switch_freq_values_fn(u32 idx)
1263 {
1264 	return 19200 / (2 * (1 + idx));
1265 }
1266 
1267 static const struct wled_var_cfg wled3_switch_freq_cfg = {
1268 	.fn = wled3_switch_freq_values_fn,
1269 	.size = 16,
1270 };
1271 
1272 static const struct wled_var_cfg wled3_string_i_limit_cfg = {
1273 	.size = 26,
1274 };
1275 
1276 static const u32 wled4_string_i_limit_values[] = {
1277 	0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000,
1278 	22500, 25000, 27500, 30000,
1279 };
1280 
1281 static const struct wled_var_cfg wled4_string_i_limit_cfg = {
1282 	.values = wled4_string_i_limit_values,
1283 	.size = ARRAY_SIZE(wled4_string_i_limit_values),
1284 };
1285 
1286 static const struct wled_var_cfg wled5_mod_sel_cfg = {
1287 	.size = 2,
1288 };
1289 
1290 static const struct wled_var_cfg wled5_cabc_sel_cfg = {
1291 	.size = 4,
1292 };
1293 
1294 static u32 wled_values(const struct wled_var_cfg *cfg, u32 idx)
1295 {
1296 	if (idx >= cfg->size)
1297 		return UINT_MAX;
1298 	if (cfg->fn)
1299 		return cfg->fn(idx);
1300 	if (cfg->values)
1301 		return cfg->values[idx];
1302 	return idx;
1303 }
1304 
1305 static int wled_configure(struct wled *wled)
1306 {
1307 	struct wled_config *cfg = &wled->cfg;
1308 	struct device *dev = wled->dev;
1309 	const __be32 *prop_addr;
1310 	u32 size, val, c;
1311 	int rc, i, j, string_len;
1312 
1313 	const struct wled_u32_opts *u32_opts = NULL;
1314 	const struct wled_u32_opts wled3_opts[] = {
1315 		{
1316 			.name = "qcom,current-boost-limit",
1317 			.val_ptr = &cfg->boost_i_limit,
1318 			.cfg = &wled3_boost_i_limit_cfg,
1319 		},
1320 		{
1321 			.name = "qcom,current-limit",
1322 			.val_ptr = &cfg->string_i_limit,
1323 			.cfg = &wled3_string_i_limit_cfg,
1324 		},
1325 		{
1326 			.name = "qcom,ovp",
1327 			.val_ptr = &cfg->ovp,
1328 			.cfg = &wled3_ovp_cfg,
1329 		},
1330 		{
1331 			.name = "qcom,switching-freq",
1332 			.val_ptr = &cfg->switch_freq,
1333 			.cfg = &wled3_switch_freq_cfg,
1334 		},
1335 	};
1336 
1337 	const struct wled_u32_opts wled4_opts[] = {
1338 		{
1339 			.name = "qcom,current-boost-limit",
1340 			.val_ptr = &cfg->boost_i_limit,
1341 			.cfg = &wled4_boost_i_limit_cfg,
1342 		},
1343 		{
1344 			.name = "qcom,current-limit-microamp",
1345 			.val_ptr = &cfg->string_i_limit,
1346 			.cfg = &wled4_string_i_limit_cfg,
1347 		},
1348 		{
1349 			.name = "qcom,ovp-millivolt",
1350 			.val_ptr = &cfg->ovp,
1351 			.cfg = &wled4_ovp_cfg,
1352 		},
1353 		{
1354 			.name = "qcom,switching-freq",
1355 			.val_ptr = &cfg->switch_freq,
1356 			.cfg = &wled3_switch_freq_cfg,
1357 		},
1358 	};
1359 
1360 	const struct wled_u32_opts wled5_opts[] = {
1361 		{
1362 			.name = "qcom,current-boost-limit",
1363 			.val_ptr = &cfg->boost_i_limit,
1364 			.cfg = &wled5_boost_i_limit_cfg,
1365 		},
1366 		{
1367 			.name = "qcom,current-limit-microamp",
1368 			.val_ptr = &cfg->string_i_limit,
1369 			.cfg = &wled4_string_i_limit_cfg,
1370 		},
1371 		{
1372 			.name = "qcom,ovp-millivolt",
1373 			.val_ptr = &cfg->ovp,
1374 			.cfg = &wled5_ovp_cfg,
1375 		},
1376 		{
1377 			.name = "qcom,switching-freq",
1378 			.val_ptr = &cfg->switch_freq,
1379 			.cfg = &wled3_switch_freq_cfg,
1380 		},
1381 		{
1382 			.name = "qcom,modulator-sel",
1383 			.val_ptr = &cfg->mod_sel,
1384 			.cfg = &wled5_mod_sel_cfg,
1385 		},
1386 		{
1387 			.name = "qcom,cabc-sel",
1388 			.val_ptr = &cfg->cabc_sel,
1389 			.cfg = &wled5_cabc_sel_cfg,
1390 		},
1391 	};
1392 
1393 	const struct wled_bool_opts bool_opts[] = {
1394 		{ "qcom,cs-out", &cfg->cs_out_en, },
1395 		{ "qcom,ext-gen", &cfg->ext_gen, },
1396 		{ "qcom,cabc", &cfg->cabc, },
1397 		{ "qcom,external-pfet", &cfg->external_pfet, },
1398 		{ "qcom,auto-string-detection", &cfg->auto_detection_enabled, },
1399 	};
1400 
1401 	prop_addr = of_get_address(dev->of_node, 0, NULL, NULL);
1402 	if (!prop_addr) {
1403 		dev_err(wled->dev, "invalid IO resources\n");
1404 		return -EINVAL;
1405 	}
1406 	wled->ctrl_addr = be32_to_cpu(*prop_addr);
1407 
1408 	rc = of_property_read_string(dev->of_node, "label", &wled->name);
1409 	if (rc)
1410 		wled->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node);
1411 
1412 	switch (wled->version) {
1413 	case 3:
1414 		u32_opts = wled3_opts;
1415 		size = ARRAY_SIZE(wled3_opts);
1416 		*cfg = wled3_config_defaults;
1417 		wled->wled_set_brightness = wled3_set_brightness;
1418 		wled->wled_sync_toggle = wled3_sync_toggle;
1419 		wled->max_string_count = 3;
1420 		wled->sink_addr = wled->ctrl_addr;
1421 		break;
1422 
1423 	case 4:
1424 		u32_opts = wled4_opts;
1425 		size = ARRAY_SIZE(wled4_opts);
1426 		*cfg = wled4_config_defaults;
1427 		wled->wled_set_brightness = wled4_set_brightness;
1428 		wled->wled_sync_toggle = wled3_sync_toggle;
1429 		wled->wled_cabc_config = wled4_cabc_config;
1430 		wled->wled_ovp_delay = wled4_ovp_delay;
1431 		wled->wled_auto_detection_required =
1432 					wled4_auto_detection_required;
1433 		wled->max_string_count = 4;
1434 
1435 		prop_addr = of_get_address(dev->of_node, 1, NULL, NULL);
1436 		if (!prop_addr) {
1437 			dev_err(wled->dev, "invalid IO resources\n");
1438 			return -EINVAL;
1439 		}
1440 		wled->sink_addr = be32_to_cpu(*prop_addr);
1441 		break;
1442 
1443 	case 5:
1444 		u32_opts = wled5_opts;
1445 		size = ARRAY_SIZE(wled5_opts);
1446 		*cfg = wled5_config_defaults;
1447 		wled->wled_set_brightness = wled5_set_brightness;
1448 		wled->wled_sync_toggle = wled3_sync_toggle;
1449 		wled->wled_cabc_config = wled5_cabc_config;
1450 		wled->wled_ovp_delay = wled5_ovp_delay;
1451 		wled->wled_auto_detection_required =
1452 					wled5_auto_detection_required;
1453 		wled->max_string_count = 4;
1454 
1455 		prop_addr = of_get_address(dev->of_node, 1, NULL, NULL);
1456 		if (!prop_addr) {
1457 			dev_err(wled->dev, "invalid IO resources\n");
1458 			return -EINVAL;
1459 		}
1460 		wled->sink_addr = be32_to_cpu(*prop_addr);
1461 		break;
1462 
1463 	default:
1464 		dev_err(wled->dev, "Invalid WLED version\n");
1465 		return -EINVAL;
1466 	}
1467 
1468 	for (i = 0; i < size; ++i) {
1469 		rc = of_property_read_u32(dev->of_node, u32_opts[i].name, &val);
1470 		if (rc == -EINVAL) {
1471 			continue;
1472 		} else if (rc) {
1473 			dev_err(dev, "error reading '%s'\n", u32_opts[i].name);
1474 			return rc;
1475 		}
1476 
1477 		c = UINT_MAX;
1478 		for (j = 0; c != val; j++) {
1479 			c = wled_values(u32_opts[i].cfg, j);
1480 			if (c == UINT_MAX) {
1481 				dev_err(dev, "invalid value for '%s'\n",
1482 					u32_opts[i].name);
1483 				return -EINVAL;
1484 			}
1485 
1486 			if (c == val)
1487 				break;
1488 		}
1489 
1490 		dev_dbg(dev, "'%s' = %u\n", u32_opts[i].name, c);
1491 		*u32_opts[i].val_ptr = j;
1492 	}
1493 
1494 	for (i = 0; i < ARRAY_SIZE(bool_opts); ++i) {
1495 		if (of_property_read_bool(dev->of_node, bool_opts[i].name))
1496 			*bool_opts[i].val_ptr = true;
1497 	}
1498 
1499 	string_len = of_property_count_elems_of_size(dev->of_node,
1500 						     "qcom,enabled-strings",
1501 						     sizeof(u32));
1502 	if (string_len > 0) {
1503 		if (string_len > wled->max_string_count) {
1504 			dev_err(dev, "Cannot have more than %d strings\n",
1505 				wled->max_string_count);
1506 			return -EINVAL;
1507 		}
1508 
1509 		rc = of_property_read_u32_array(dev->of_node,
1510 						"qcom,enabled-strings",
1511 						wled->cfg.enabled_strings,
1512 						string_len);
1513 		if (rc) {
1514 			dev_err(dev, "Failed to read %d elements from qcom,enabled-strings: %d\n",
1515 				string_len, rc);
1516 			return rc;
1517 		}
1518 
1519 		for (i = 0; i < string_len; ++i) {
1520 			if (wled->cfg.enabled_strings[i] >= wled->max_string_count) {
1521 				dev_err(dev,
1522 					"qcom,enabled-strings index %d at %d is out of bounds\n",
1523 					wled->cfg.enabled_strings[i], i);
1524 				return -EINVAL;
1525 			}
1526 		}
1527 
1528 		cfg->num_strings = string_len;
1529 	}
1530 
1531 	rc = of_property_read_u32(dev->of_node, "qcom,num-strings", &val);
1532 	if (!rc) {
1533 		if (val < 1 || val > wled->max_string_count) {
1534 			dev_err(dev, "qcom,num-strings must be between 1 and %d\n",
1535 				wled->max_string_count);
1536 			return -EINVAL;
1537 		}
1538 
1539 		if (string_len > 0) {
1540 			dev_warn(dev, "Only one of qcom,num-strings or qcom,enabled-strings"
1541 				      " should be set\n");
1542 			if (val > string_len) {
1543 				dev_err(dev, "qcom,num-strings exceeds qcom,enabled-strings\n");
1544 				return -EINVAL;
1545 			}
1546 		}
1547 
1548 		cfg->num_strings = val;
1549 	}
1550 
1551 	return 0;
1552 }
1553 
1554 static int wled_configure_short_irq(struct wled *wled,
1555 				    struct platform_device *pdev)
1556 {
1557 	int rc;
1558 
1559 	if (!wled->has_short_detect)
1560 		return 0;
1561 
1562 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
1563 				WLED4_CTRL_REG_SHORT_PROTECT,
1564 				WLED4_CTRL_REG_SHORT_EN_MASK,
1565 				WLED4_CTRL_REG_SHORT_EN_MASK);
1566 	if (rc < 0)
1567 		return rc;
1568 
1569 	wled->short_irq = platform_get_irq_byname(pdev, "short");
1570 	if (wled->short_irq < 0) {
1571 		dev_dbg(&pdev->dev, "short irq is not used\n");
1572 		return 0;
1573 	}
1574 
1575 	rc = devm_request_threaded_irq(wled->dev, wled->short_irq,
1576 				       NULL, wled_short_irq_handler,
1577 				       IRQF_ONESHOT,
1578 				       "wled_short_irq", wled);
1579 	if (rc < 0)
1580 		dev_err(wled->dev, "Unable to request short_irq (err:%d)\n",
1581 			rc);
1582 
1583 	return rc;
1584 }
1585 
1586 static int wled_configure_ovp_irq(struct wled *wled,
1587 				  struct platform_device *pdev)
1588 {
1589 	int rc;
1590 	u32 val;
1591 
1592 	wled->ovp_irq = platform_get_irq_byname(pdev, "ovp");
1593 	if (wled->ovp_irq < 0) {
1594 		dev_dbg(&pdev->dev, "OVP IRQ not found - disabling automatic string detection\n");
1595 		return 0;
1596 	}
1597 
1598 	rc = devm_request_threaded_irq(wled->dev, wled->ovp_irq, NULL,
1599 				       wled_ovp_irq_handler, IRQF_ONESHOT,
1600 				       "wled_ovp_irq", wled);
1601 	if (rc < 0) {
1602 		dev_err(wled->dev, "Unable to request ovp_irq (err:%d)\n",
1603 			rc);
1604 		wled->ovp_irq = 0;
1605 		return 0;
1606 	}
1607 
1608 	rc = regmap_read(wled->regmap, wled->ctrl_addr +
1609 			 WLED3_CTRL_REG_MOD_EN, &val);
1610 	if (rc < 0)
1611 		return rc;
1612 
1613 	/* Keep OVP irq disabled until module is enabled */
1614 	if (!(val & WLED3_CTRL_REG_MOD_EN_MASK))
1615 		disable_irq(wled->ovp_irq);
1616 
1617 	return 0;
1618 }
1619 
1620 static const struct backlight_ops wled_ops = {
1621 	.update_status = wled_update_status,
1622 };
1623 
1624 static int wled_probe(struct platform_device *pdev)
1625 {
1626 	struct backlight_properties props;
1627 	struct backlight_device *bl;
1628 	struct wled *wled;
1629 	struct regmap *regmap;
1630 	u32 val;
1631 	int rc;
1632 
1633 	regmap = dev_get_regmap(pdev->dev.parent, NULL);
1634 	if (!regmap) {
1635 		dev_err(&pdev->dev, "Unable to get regmap\n");
1636 		return -EINVAL;
1637 	}
1638 
1639 	wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL);
1640 	if (!wled)
1641 		return -ENOMEM;
1642 
1643 	wled->regmap = regmap;
1644 	wled->dev = &pdev->dev;
1645 
1646 	wled->version = (uintptr_t)of_device_get_match_data(&pdev->dev);
1647 	if (!wled->version) {
1648 		dev_err(&pdev->dev, "Unknown device version\n");
1649 		return -ENODEV;
1650 	}
1651 
1652 	mutex_init(&wled->lock);
1653 	rc = wled_configure(wled);
1654 	if (rc)
1655 		return rc;
1656 
1657 	val = WLED3_SINK_REG_BRIGHT_MAX;
1658 	of_property_read_u32(pdev->dev.of_node, "max-brightness", &val);
1659 	wled->max_brightness = val;
1660 
1661 	switch (wled->version) {
1662 	case 3:
1663 		wled->cfg.auto_detection_enabled = false;
1664 		rc = wled3_setup(wled);
1665 		if (rc) {
1666 			dev_err(&pdev->dev, "wled3_setup failed\n");
1667 			return rc;
1668 		}
1669 		break;
1670 
1671 	case 4:
1672 		wled->has_short_detect = true;
1673 		rc = wled4_setup(wled);
1674 		if (rc) {
1675 			dev_err(&pdev->dev, "wled4_setup failed\n");
1676 			return rc;
1677 		}
1678 		break;
1679 
1680 	case 5:
1681 		wled->has_short_detect = true;
1682 		if (wled->cfg.cabc_sel)
1683 			wled->max_brightness = WLED5_SINK_REG_BRIGHT_MAX_12B;
1684 
1685 		rc = wled5_setup(wled);
1686 		if (rc) {
1687 			dev_err(&pdev->dev, "wled5_setup failed\n");
1688 			return rc;
1689 		}
1690 		break;
1691 
1692 	default:
1693 		dev_err(wled->dev, "Invalid WLED version\n");
1694 		break;
1695 	}
1696 
1697 	INIT_DELAYED_WORK(&wled->ovp_work, wled_ovp_work);
1698 
1699 	rc = wled_configure_short_irq(wled, pdev);
1700 	if (rc < 0)
1701 		return rc;
1702 
1703 	rc = wled_configure_ovp_irq(wled, pdev);
1704 	if (rc < 0)
1705 		return rc;
1706 
1707 	val = WLED_DEFAULT_BRIGHTNESS;
1708 	of_property_read_u32(pdev->dev.of_node, "default-brightness", &val);
1709 
1710 	memset(&props, 0, sizeof(struct backlight_properties));
1711 	props.type = BACKLIGHT_RAW;
1712 	props.brightness = val;
1713 	props.max_brightness = wled->max_brightness;
1714 	bl = devm_backlight_device_register(&pdev->dev, wled->name,
1715 					    &pdev->dev, wled,
1716 					    &wled_ops, &props);
1717 	return PTR_ERR_OR_ZERO(bl);
1718 };
1719 
1720 static void wled_remove(struct platform_device *pdev)
1721 {
1722 	struct wled *wled = platform_get_drvdata(pdev);
1723 
1724 	mutex_destroy(&wled->lock);
1725 	cancel_delayed_work_sync(&wled->ovp_work);
1726 	disable_irq(wled->short_irq);
1727 	disable_irq(wled->ovp_irq);
1728 }
1729 
1730 static const struct of_device_id wled_match_table[] = {
1731 	{ .compatible = "qcom,pm8941-wled", .data = (void *)3 },
1732 	{ .compatible = "qcom,pmi8950-wled", .data = (void *)4 },
1733 	{ .compatible = "qcom,pmi8994-wled", .data = (void *)4 },
1734 	{ .compatible = "qcom,pmi8998-wled", .data = (void *)4 },
1735 	{ .compatible = "qcom,pm660l-wled", .data = (void *)4 },
1736 	{ .compatible = "qcom,pm6150l-wled", .data = (void *)5 },
1737 	{ .compatible = "qcom,pm8150l-wled", .data = (void *)5 },
1738 	{}
1739 };
1740 MODULE_DEVICE_TABLE(of, wled_match_table);
1741 
1742 static struct platform_driver wled_driver = {
1743 	.probe = wled_probe,
1744 	.remove_new = wled_remove,
1745 	.driver	= {
1746 		.name = "qcom,wled",
1747 		.of_match_table	= wled_match_table,
1748 	},
1749 };
1750 
1751 module_platform_driver(wled_driver);
1752 
1753 MODULE_DESCRIPTION("Qualcomm WLED driver");
1754 MODULE_LICENSE("GPL v2");
1755