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 
19 #define WLED_DEFAULT_BRIGHTNESS				2048
20 #define WLED_SOFT_START_DLY_US				10000
21 #define WLED3_SINK_REG_BRIGHT_MAX			0xFFF
22 
23 /* WLED3/WLED4 control registers */
24 #define WLED3_CTRL_REG_FAULT_STATUS			0x08
25 #define  WLED3_CTRL_REG_ILIM_FAULT_BIT			BIT(0)
26 #define  WLED3_CTRL_REG_OVP_FAULT_BIT			BIT(1)
27 #define  WLED4_CTRL_REG_SC_FAULT_BIT			BIT(2)
28 
29 #define WLED3_CTRL_REG_INT_RT_STS			0x10
30 #define  WLED3_CTRL_REG_OVP_FAULT_STATUS		BIT(1)
31 
32 #define WLED3_CTRL_REG_MOD_EN				0x46
33 #define  WLED3_CTRL_REG_MOD_EN_MASK			BIT(7)
34 #define  WLED3_CTRL_REG_MOD_EN_SHIFT			7
35 
36 #define WLED3_CTRL_REG_FEEDBACK_CONTROL			0x48
37 
38 #define WLED3_CTRL_REG_FREQ				0x4c
39 #define  WLED3_CTRL_REG_FREQ_MASK			GENMASK(3, 0)
40 
41 #define WLED3_CTRL_REG_OVP				0x4d
42 #define  WLED3_CTRL_REG_OVP_MASK			GENMASK(1, 0)
43 
44 #define WLED3_CTRL_REG_ILIMIT				0x4e
45 #define  WLED3_CTRL_REG_ILIMIT_MASK			GENMASK(2, 0)
46 
47 /* WLED3/WLED4 sink registers */
48 #define WLED3_SINK_REG_SYNC				0x47
49 #define  WLED3_SINK_REG_SYNC_CLEAR			0x00
50 
51 #define WLED3_SINK_REG_CURR_SINK			0x4f
52 #define  WLED3_SINK_REG_CURR_SINK_MASK			GENMASK(7, 5)
53 #define  WLED3_SINK_REG_CURR_SINK_SHFT			5
54 
55 /* WLED3 specific per-'string' registers below */
56 #define WLED3_SINK_REG_BRIGHT(n)			(0x40 + n)
57 
58 #define WLED3_SINK_REG_STR_MOD_EN(n)			(0x60 + (n * 0x10))
59 #define  WLED3_SINK_REG_STR_MOD_MASK			BIT(7)
60 
61 #define WLED3_SINK_REG_STR_FULL_SCALE_CURR(n)		(0x62 + (n * 0x10))
62 #define  WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK	GENMASK(4, 0)
63 
64 #define WLED3_SINK_REG_STR_MOD_SRC(n)			(0x63 + (n * 0x10))
65 #define  WLED3_SINK_REG_STR_MOD_SRC_MASK		BIT(0)
66 #define  WLED3_SINK_REG_STR_MOD_SRC_INT			0x00
67 #define  WLED3_SINK_REG_STR_MOD_SRC_EXT			0x01
68 
69 #define WLED3_SINK_REG_STR_CABC(n)			(0x66 + (n * 0x10))
70 #define  WLED3_SINK_REG_STR_CABC_MASK			BIT(7)
71 
72 /* WLED4 specific control registers */
73 #define WLED4_CTRL_REG_SHORT_PROTECT			0x5e
74 #define  WLED4_CTRL_REG_SHORT_EN_MASK			BIT(7)
75 
76 #define WLED4_CTRL_REG_SEC_ACCESS			0xd0
77 #define  WLED4_CTRL_REG_SEC_UNLOCK			0xa5
78 
79 #define WLED4_CTRL_REG_TEST1				0xe2
80 #define  WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2		0x09
81 
82 /* WLED4 specific sink registers */
83 #define WLED4_SINK_REG_CURR_SINK			0x46
84 #define  WLED4_SINK_REG_CURR_SINK_MASK			GENMASK(7, 4)
85 #define  WLED4_SINK_REG_CURR_SINK_SHFT			4
86 
87 /* WLED4 specific per-'string' registers below */
88 #define WLED4_SINK_REG_STR_MOD_EN(n)			(0x50 + (n * 0x10))
89 #define  WLED4_SINK_REG_STR_MOD_MASK			BIT(7)
90 
91 #define WLED4_SINK_REG_STR_FULL_SCALE_CURR(n)		(0x52 + (n * 0x10))
92 #define  WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK	GENMASK(3, 0)
93 
94 #define WLED4_SINK_REG_STR_MOD_SRC(n)			(0x53 + (n * 0x10))
95 #define  WLED4_SINK_REG_STR_MOD_SRC_MASK		BIT(0)
96 #define  WLED4_SINK_REG_STR_MOD_SRC_INT			0x00
97 #define  WLED4_SINK_REG_STR_MOD_SRC_EXT			0x01
98 
99 #define WLED4_SINK_REG_STR_CABC(n)			(0x56 + (n * 0x10))
100 #define  WLED4_SINK_REG_STR_CABC_MASK			BIT(7)
101 
102 #define WLED4_SINK_REG_BRIGHT(n)			(0x57 + (n * 0x10))
103 
104 struct wled_var_cfg {
105 	const u32 *values;
106 	u32 (*fn)(u32);
107 	int size;
108 };
109 
110 struct wled_u32_opts {
111 	const char *name;
112 	u32 *val_ptr;
113 	const struct wled_var_cfg *cfg;
114 };
115 
116 struct wled_bool_opts {
117 	const char *name;
118 	bool *val_ptr;
119 };
120 
121 struct wled_config {
122 	u32 boost_i_limit;
123 	u32 ovp;
124 	u32 switch_freq;
125 	u32 num_strings;
126 	u32 string_i_limit;
127 	u32 enabled_strings[WLED_MAX_STRINGS];
128 	bool cs_out_en;
129 	bool ext_gen;
130 	bool cabc;
131 	bool external_pfet;
132 	bool auto_detection_enabled;
133 };
134 
135 struct wled {
136 	const char *name;
137 	struct device *dev;
138 	struct regmap *regmap;
139 	struct mutex lock;	/* Lock to avoid race from thread irq handler */
140 	ktime_t last_short_event;
141 	ktime_t start_ovp_fault_time;
142 	u16 ctrl_addr;
143 	u16 sink_addr;
144 	u16 max_string_count;
145 	u16 auto_detection_ovp_count;
146 	u32 brightness;
147 	u32 max_brightness;
148 	u32 short_count;
149 	u32 auto_detect_count;
150 	bool disabled_by_short;
151 	bool has_short_detect;
152 	int short_irq;
153 	int ovp_irq;
154 
155 	struct wled_config cfg;
156 	struct delayed_work ovp_work;
157 	int (*wled_set_brightness)(struct wled *wled, u16 brightness);
158 };
159 
160 static int wled3_set_brightness(struct wled *wled, u16 brightness)
161 {
162 	int rc, i;
163 	u8 v[2];
164 
165 	v[0] = brightness & 0xff;
166 	v[1] = (brightness >> 8) & 0xf;
167 
168 	for (i = 0;  i < wled->cfg.num_strings; ++i) {
169 		rc = regmap_bulk_write(wled->regmap, wled->ctrl_addr +
170 				       WLED3_SINK_REG_BRIGHT(i), v, 2);
171 		if (rc < 0)
172 			return rc;
173 	}
174 
175 	return 0;
176 }
177 
178 static int wled4_set_brightness(struct wled *wled, u16 brightness)
179 {
180 	int rc, i;
181 	u16 low_limit = wled->max_brightness * 4 / 1000;
182 	u8 v[2];
183 
184 	/* WLED4's lower limit of operation is 0.4% */
185 	if (brightness > 0 && brightness < low_limit)
186 		brightness = low_limit;
187 
188 	v[0] = brightness & 0xff;
189 	v[1] = (brightness >> 8) & 0xf;
190 
191 	for (i = 0;  i < wled->cfg.num_strings; ++i) {
192 		rc = regmap_bulk_write(wled->regmap, wled->sink_addr +
193 				       WLED4_SINK_REG_BRIGHT(i), v, 2);
194 		if (rc < 0)
195 			return rc;
196 	}
197 
198 	return 0;
199 }
200 
201 static void wled_ovp_work(struct work_struct *work)
202 {
203 	struct wled *wled = container_of(work,
204 					 struct wled, ovp_work.work);
205 	enable_irq(wled->ovp_irq);
206 }
207 
208 static int wled_module_enable(struct wled *wled, int val)
209 {
210 	int rc;
211 
212 	if (wled->disabled_by_short)
213 		return -ENXIO;
214 
215 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
216 				WLED3_CTRL_REG_MOD_EN,
217 				WLED3_CTRL_REG_MOD_EN_MASK,
218 				val << WLED3_CTRL_REG_MOD_EN_SHIFT);
219 	if (rc < 0)
220 		return rc;
221 
222 	if (wled->ovp_irq > 0) {
223 		if (val) {
224 			/*
225 			 * The hardware generates a storm of spurious OVP
226 			 * interrupts during soft start operations. So defer
227 			 * enabling the IRQ for 10ms to ensure that the
228 			 * soft start is complete.
229 			 */
230 			schedule_delayed_work(&wled->ovp_work, HZ / 100);
231 		} else {
232 			if (!cancel_delayed_work_sync(&wled->ovp_work))
233 				disable_irq(wled->ovp_irq);
234 		}
235 	}
236 
237 	return 0;
238 }
239 
240 static int wled_sync_toggle(struct wled *wled)
241 {
242 	int rc;
243 	unsigned int mask = GENMASK(wled->max_string_count - 1, 0);
244 
245 	rc = regmap_update_bits(wled->regmap,
246 				wled->ctrl_addr + WLED3_SINK_REG_SYNC,
247 				mask, mask);
248 	if (rc < 0)
249 		return rc;
250 
251 	rc = regmap_update_bits(wled->regmap,
252 				wled->ctrl_addr + WLED3_SINK_REG_SYNC,
253 				mask, WLED3_SINK_REG_SYNC_CLEAR);
254 
255 	return rc;
256 }
257 
258 static int wled_update_status(struct backlight_device *bl)
259 {
260 	struct wled *wled = bl_get_data(bl);
261 	u16 brightness = bl->props.brightness;
262 	int rc = 0;
263 
264 	if (bl->props.power != FB_BLANK_UNBLANK ||
265 	    bl->props.fb_blank != FB_BLANK_UNBLANK ||
266 	    bl->props.state & BL_CORE_FBBLANK)
267 		brightness = 0;
268 
269 	mutex_lock(&wled->lock);
270 	if (brightness) {
271 		rc = wled->wled_set_brightness(wled, brightness);
272 		if (rc < 0) {
273 			dev_err(wled->dev, "wled failed to set brightness rc:%d\n",
274 				rc);
275 			goto unlock_mutex;
276 		}
277 
278 		rc = wled_sync_toggle(wled);
279 		if (rc < 0) {
280 			dev_err(wled->dev, "wled sync failed rc:%d\n", rc);
281 			goto unlock_mutex;
282 		}
283 	}
284 
285 	if (!!brightness != !!wled->brightness) {
286 		rc = wled_module_enable(wled, !!brightness);
287 		if (rc < 0) {
288 			dev_err(wled->dev, "wled enable failed rc:%d\n", rc);
289 			goto unlock_mutex;
290 		}
291 	}
292 
293 	wled->brightness = brightness;
294 
295 unlock_mutex:
296 	mutex_unlock(&wled->lock);
297 
298 	return rc;
299 }
300 
301 #define WLED_SHORT_DLY_MS			20
302 #define WLED_SHORT_CNT_MAX			5
303 #define WLED_SHORT_RESET_CNT_DLY_US		USEC_PER_SEC
304 
305 static irqreturn_t wled_short_irq_handler(int irq, void *_wled)
306 {
307 	struct wled *wled = _wled;
308 	int rc;
309 	s64 elapsed_time;
310 
311 	wled->short_count++;
312 	mutex_lock(&wled->lock);
313 	rc = wled_module_enable(wled, false);
314 	if (rc < 0) {
315 		dev_err(wled->dev, "wled disable failed rc:%d\n", rc);
316 		goto unlock_mutex;
317 	}
318 
319 	elapsed_time = ktime_us_delta(ktime_get(),
320 				      wled->last_short_event);
321 	if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US)
322 		wled->short_count = 1;
323 
324 	if (wled->short_count > WLED_SHORT_CNT_MAX) {
325 		dev_err(wled->dev, "Short triggered %d times, disabling WLED forever!\n",
326 			wled->short_count);
327 		wled->disabled_by_short = true;
328 		goto unlock_mutex;
329 	}
330 
331 	wled->last_short_event = ktime_get();
332 
333 	msleep(WLED_SHORT_DLY_MS);
334 	rc = wled_module_enable(wled, true);
335 	if (rc < 0)
336 		dev_err(wled->dev, "wled enable failed rc:%d\n", rc);
337 
338 unlock_mutex:
339 	mutex_unlock(&wled->lock);
340 
341 	return IRQ_HANDLED;
342 }
343 
344 #define AUTO_DETECT_BRIGHTNESS		200
345 
346 static void wled_auto_string_detection(struct wled *wled)
347 {
348 	int rc = 0, i;
349 	u32 sink_config = 0, int_sts;
350 	u8 sink_test = 0, sink_valid = 0, val;
351 
352 	/* Read configured sink configuration */
353 	rc = regmap_read(wled->regmap, wled->sink_addr +
354 			 WLED4_SINK_REG_CURR_SINK, &sink_config);
355 	if (rc < 0) {
356 		dev_err(wled->dev, "Failed to read SINK configuration rc=%d\n",
357 			rc);
358 		goto failed_detect;
359 	}
360 
361 	/* Disable the module before starting detection */
362 	rc = regmap_update_bits(wled->regmap,
363 				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
364 				WLED3_CTRL_REG_MOD_EN_MASK, 0);
365 	if (rc < 0) {
366 		dev_err(wled->dev, "Failed to disable WLED module rc=%d\n", rc);
367 		goto failed_detect;
368 	}
369 
370 	/* Set low brightness across all sinks */
371 	rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS);
372 	if (rc < 0) {
373 		dev_err(wled->dev, "Failed to set brightness for auto detection rc=%d\n",
374 			rc);
375 		goto failed_detect;
376 	}
377 
378 	if (wled->cfg.cabc) {
379 		for (i = 0; i < wled->cfg.num_strings; i++) {
380 			rc = regmap_update_bits(wled->regmap, wled->sink_addr +
381 						WLED4_SINK_REG_STR_CABC(i),
382 						WLED4_SINK_REG_STR_CABC_MASK,
383 						0);
384 			if (rc < 0)
385 				goto failed_detect;
386 		}
387 	}
388 
389 	/* Disable all sinks */
390 	rc = regmap_write(wled->regmap,
391 			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0);
392 	if (rc < 0) {
393 		dev_err(wled->dev, "Failed to disable all sinks rc=%d\n", rc);
394 		goto failed_detect;
395 	}
396 
397 	/* Iterate through the strings one by one */
398 	for (i = 0; i < wled->cfg.num_strings; i++) {
399 		sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + i));
400 
401 		/* Enable feedback control */
402 		rc = regmap_write(wled->regmap, wled->ctrl_addr +
403 				  WLED3_CTRL_REG_FEEDBACK_CONTROL, i + 1);
404 		if (rc < 0) {
405 			dev_err(wled->dev, "Failed to enable feedback for SINK %d rc = %d\n",
406 				i + 1, rc);
407 			goto failed_detect;
408 		}
409 
410 		/* Enable the sink */
411 		rc = regmap_write(wled->regmap, wled->sink_addr +
412 				  WLED4_SINK_REG_CURR_SINK, sink_test);
413 		if (rc < 0) {
414 			dev_err(wled->dev, "Failed to configure SINK %d rc=%d\n",
415 				i + 1, rc);
416 			goto failed_detect;
417 		}
418 
419 		/* Enable the module */
420 		rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
421 					WLED3_CTRL_REG_MOD_EN,
422 					WLED3_CTRL_REG_MOD_EN_MASK,
423 					WLED3_CTRL_REG_MOD_EN_MASK);
424 		if (rc < 0) {
425 			dev_err(wled->dev, "Failed to enable WLED module rc=%d\n",
426 				rc);
427 			goto failed_detect;
428 		}
429 
430 		usleep_range(WLED_SOFT_START_DLY_US,
431 			     WLED_SOFT_START_DLY_US + 1000);
432 
433 		rc = regmap_read(wled->regmap, wled->ctrl_addr +
434 				 WLED3_CTRL_REG_INT_RT_STS, &int_sts);
435 		if (rc < 0) {
436 			dev_err(wled->dev, "Error in reading WLED3_CTRL_INT_RT_STS rc=%d\n",
437 				rc);
438 			goto failed_detect;
439 		}
440 
441 		if (int_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS)
442 			dev_dbg(wled->dev, "WLED OVP fault detected with SINK %d\n",
443 				i + 1);
444 		else
445 			sink_valid |= sink_test;
446 
447 		/* Disable the module */
448 		rc = regmap_update_bits(wled->regmap,
449 					wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
450 					WLED3_CTRL_REG_MOD_EN_MASK, 0);
451 		if (rc < 0) {
452 			dev_err(wled->dev, "Failed to disable WLED module rc=%d\n",
453 				rc);
454 			goto failed_detect;
455 		}
456 	}
457 
458 	if (!sink_valid) {
459 		dev_err(wled->dev, "No valid WLED sinks found\n");
460 		wled->disabled_by_short = true;
461 		goto failed_detect;
462 	}
463 
464 	if (sink_valid != sink_config) {
465 		dev_warn(wled->dev, "%x is not a valid sink configuration - using %x instead\n",
466 			 sink_config, sink_valid);
467 		sink_config = sink_valid;
468 	}
469 
470 	/* Write the new sink configuration */
471 	rc = regmap_write(wled->regmap,
472 			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
473 			  sink_config);
474 	if (rc < 0) {
475 		dev_err(wled->dev, "Failed to reconfigure the default sink rc=%d\n",
476 			rc);
477 		goto failed_detect;
478 	}
479 
480 	/* Enable valid sinks */
481 	for (i = 0; i < wled->cfg.num_strings; i++) {
482 		if (wled->cfg.cabc) {
483 			rc = regmap_update_bits(wled->regmap, wled->sink_addr +
484 						WLED4_SINK_REG_STR_CABC(i),
485 						WLED4_SINK_REG_STR_CABC_MASK,
486 						WLED4_SINK_REG_STR_CABC_MASK);
487 			if (rc < 0)
488 				goto failed_detect;
489 		}
490 
491 		if (sink_config & BIT(WLED4_SINK_REG_CURR_SINK_SHFT + i))
492 			val = WLED4_SINK_REG_STR_MOD_MASK;
493 		else
494 			val = 0x0; /* Disable modulator_en for unused sink */
495 
496 		rc = regmap_write(wled->regmap, wled->sink_addr +
497 				  WLED4_SINK_REG_STR_MOD_EN(i), val);
498 		if (rc < 0) {
499 			dev_err(wled->dev, "Failed to configure MODULATOR_EN rc=%d\n",
500 				rc);
501 			goto failed_detect;
502 		}
503 	}
504 
505 	/* Restore the feedback setting */
506 	rc = regmap_write(wled->regmap,
507 			  wled->ctrl_addr + WLED3_CTRL_REG_FEEDBACK_CONTROL, 0);
508 	if (rc < 0) {
509 		dev_err(wled->dev, "Failed to restore feedback setting rc=%d\n",
510 			rc);
511 		goto failed_detect;
512 	}
513 
514 	/* Restore brightness */
515 	rc = wled4_set_brightness(wled, wled->brightness);
516 	if (rc < 0) {
517 		dev_err(wled->dev, "Failed to set brightness after auto detection rc=%d\n",
518 			rc);
519 		goto failed_detect;
520 	}
521 
522 	rc = regmap_update_bits(wled->regmap,
523 				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
524 				WLED3_CTRL_REG_MOD_EN_MASK,
525 				WLED3_CTRL_REG_MOD_EN_MASK);
526 	if (rc < 0) {
527 		dev_err(wled->dev, "Failed to enable WLED module rc=%d\n", rc);
528 		goto failed_detect;
529 	}
530 
531 failed_detect:
532 	return;
533 }
534 
535 #define WLED_AUTO_DETECT_OVP_COUNT		5
536 #define WLED_AUTO_DETECT_CNT_DLY_US		USEC_PER_SEC
537 static bool wled_auto_detection_required(struct wled *wled)
538 {
539 	s64 elapsed_time_us;
540 
541 	if (!wled->cfg.auto_detection_enabled)
542 		return false;
543 
544 	/*
545 	 * Check if the OVP fault was an occasional one
546 	 * or if it's firing continuously, the latter qualifies
547 	 * for an auto-detection check.
548 	 */
549 	if (!wled->auto_detection_ovp_count) {
550 		wled->start_ovp_fault_time = ktime_get();
551 		wled->auto_detection_ovp_count++;
552 	} else {
553 		elapsed_time_us = ktime_us_delta(ktime_get(),
554 						 wled->start_ovp_fault_time);
555 		if (elapsed_time_us > WLED_AUTO_DETECT_CNT_DLY_US)
556 			wled->auto_detection_ovp_count = 0;
557 		else
558 			wled->auto_detection_ovp_count++;
559 
560 		if (wled->auto_detection_ovp_count >=
561 				WLED_AUTO_DETECT_OVP_COUNT) {
562 			wled->auto_detection_ovp_count = 0;
563 			return true;
564 		}
565 	}
566 
567 	return false;
568 }
569 
570 static int wled_auto_detection_at_init(struct wled *wled)
571 {
572 	int rc;
573 	u32 fault_status, rt_status;
574 
575 	if (!wled->cfg.auto_detection_enabled)
576 		return 0;
577 
578 	rc = regmap_read(wled->regmap,
579 			 wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS,
580 			 &rt_status);
581 	if (rc < 0) {
582 		dev_err(wled->dev, "Failed to read RT status rc=%d\n", rc);
583 		return rc;
584 	}
585 
586 	rc = regmap_read(wled->regmap,
587 			 wled->ctrl_addr + WLED3_CTRL_REG_FAULT_STATUS,
588 			 &fault_status);
589 	if (rc < 0) {
590 		dev_err(wled->dev, "Failed to read fault status rc=%d\n", rc);
591 		return rc;
592 	}
593 
594 	if ((rt_status & WLED3_CTRL_REG_OVP_FAULT_STATUS) ||
595 	    (fault_status & WLED3_CTRL_REG_OVP_FAULT_BIT)) {
596 		mutex_lock(&wled->lock);
597 		wled_auto_string_detection(wled);
598 		mutex_unlock(&wled->lock);
599 	}
600 
601 	return rc;
602 }
603 
604 static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled)
605 {
606 	struct wled *wled = _wled;
607 	int rc;
608 	u32 int_sts, fault_sts;
609 
610 	rc = regmap_read(wled->regmap,
611 			 wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, &int_sts);
612 	if (rc < 0) {
613 		dev_err(wled->dev, "Error in reading WLED3_INT_RT_STS rc=%d\n",
614 			rc);
615 		return IRQ_HANDLED;
616 	}
617 
618 	rc = regmap_read(wled->regmap, wled->ctrl_addr +
619 			 WLED3_CTRL_REG_FAULT_STATUS, &fault_sts);
620 	if (rc < 0) {
621 		dev_err(wled->dev, "Error in reading WLED_FAULT_STATUS rc=%d\n",
622 			rc);
623 		return IRQ_HANDLED;
624 	}
625 
626 	if (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT |
627 		WLED3_CTRL_REG_ILIM_FAULT_BIT))
628 		dev_dbg(wled->dev, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
629 			int_sts, fault_sts);
630 
631 	if (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT) {
632 		if (wled_auto_detection_required(wled)) {
633 			mutex_lock(&wled->lock);
634 			wled_auto_string_detection(wled);
635 			mutex_unlock(&wled->lock);
636 		}
637 	}
638 
639 	return IRQ_HANDLED;
640 }
641 
642 static int wled3_setup(struct wled *wled)
643 {
644 	u16 addr;
645 	u8 sink_en = 0;
646 	int rc, i, j;
647 
648 	rc = regmap_update_bits(wled->regmap,
649 				wled->ctrl_addr + WLED3_CTRL_REG_OVP,
650 				WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp);
651 	if (rc)
652 		return rc;
653 
654 	rc = regmap_update_bits(wled->regmap,
655 				wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT,
656 				WLED3_CTRL_REG_ILIMIT_MASK,
657 				wled->cfg.boost_i_limit);
658 	if (rc)
659 		return rc;
660 
661 	rc = regmap_update_bits(wled->regmap,
662 				wled->ctrl_addr + WLED3_CTRL_REG_FREQ,
663 				WLED3_CTRL_REG_FREQ_MASK,
664 				wled->cfg.switch_freq);
665 	if (rc)
666 		return rc;
667 
668 	for (i = 0; i < wled->cfg.num_strings; ++i) {
669 		j = wled->cfg.enabled_strings[i];
670 		addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_EN(j);
671 		rc = regmap_update_bits(wled->regmap, addr,
672 					WLED3_SINK_REG_STR_MOD_MASK,
673 					WLED3_SINK_REG_STR_MOD_MASK);
674 		if (rc)
675 			return rc;
676 
677 		if (wled->cfg.ext_gen) {
678 			addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_SRC(j);
679 			rc = regmap_update_bits(wled->regmap, addr,
680 						WLED3_SINK_REG_STR_MOD_SRC_MASK,
681 						WLED3_SINK_REG_STR_MOD_SRC_EXT);
682 			if (rc)
683 				return rc;
684 		}
685 
686 		addr = wled->ctrl_addr + WLED3_SINK_REG_STR_FULL_SCALE_CURR(j);
687 		rc = regmap_update_bits(wled->regmap, addr,
688 					WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK,
689 					wled->cfg.string_i_limit);
690 		if (rc)
691 			return rc;
692 
693 		addr = wled->ctrl_addr + WLED3_SINK_REG_STR_CABC(j);
694 		rc = regmap_update_bits(wled->regmap, addr,
695 					WLED3_SINK_REG_STR_CABC_MASK,
696 					wled->cfg.cabc ?
697 					WLED3_SINK_REG_STR_CABC_MASK : 0);
698 		if (rc)
699 			return rc;
700 
701 		sink_en |= BIT(j + WLED3_SINK_REG_CURR_SINK_SHFT);
702 	}
703 
704 	rc = regmap_update_bits(wled->regmap,
705 				wled->ctrl_addr + WLED3_SINK_REG_CURR_SINK,
706 				WLED3_SINK_REG_CURR_SINK_MASK, sink_en);
707 	if (rc)
708 		return rc;
709 
710 	return 0;
711 }
712 
713 static const struct wled_config wled3_config_defaults = {
714 	.boost_i_limit = 3,
715 	.string_i_limit = 20,
716 	.ovp = 2,
717 	.num_strings = 3,
718 	.switch_freq = 5,
719 	.cs_out_en = false,
720 	.ext_gen = false,
721 	.cabc = false,
722 	.enabled_strings = {0, 1, 2, 3},
723 };
724 
725 static int wled4_setup(struct wled *wled)
726 {
727 	int rc, temp, i, j;
728 	u16 addr;
729 	u8 sink_en = 0;
730 	u32 sink_cfg;
731 
732 	rc = regmap_update_bits(wled->regmap,
733 				wled->ctrl_addr + WLED3_CTRL_REG_OVP,
734 				WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp);
735 	if (rc < 0)
736 		return rc;
737 
738 	rc = regmap_update_bits(wled->regmap,
739 				wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT,
740 				WLED3_CTRL_REG_ILIMIT_MASK,
741 				wled->cfg.boost_i_limit);
742 	if (rc < 0)
743 		return rc;
744 
745 	rc = regmap_update_bits(wled->regmap,
746 				wled->ctrl_addr + WLED3_CTRL_REG_FREQ,
747 				WLED3_CTRL_REG_FREQ_MASK,
748 				wled->cfg.switch_freq);
749 	if (rc < 0)
750 		return rc;
751 
752 	if (wled->cfg.external_pfet) {
753 		/* Unlock the secure register access */
754 		rc = regmap_write(wled->regmap, wled->ctrl_addr +
755 				  WLED4_CTRL_REG_SEC_ACCESS,
756 				  WLED4_CTRL_REG_SEC_UNLOCK);
757 		if (rc < 0)
758 			return rc;
759 
760 		rc = regmap_write(wled->regmap,
761 				  wled->ctrl_addr + WLED4_CTRL_REG_TEST1,
762 				  WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2);
763 		if (rc < 0)
764 			return rc;
765 	}
766 
767 	rc = regmap_read(wled->regmap, wled->sink_addr +
768 			 WLED4_SINK_REG_CURR_SINK, &sink_cfg);
769 	if (rc < 0)
770 		return rc;
771 
772 	for (i = 0; i < wled->cfg.num_strings; i++) {
773 		j = wled->cfg.enabled_strings[i];
774 		temp = j + WLED4_SINK_REG_CURR_SINK_SHFT;
775 		sink_en |= 1 << temp;
776 	}
777 
778 	if (sink_cfg == sink_en) {
779 		rc = wled_auto_detection_at_init(wled);
780 		return rc;
781 	}
782 
783 	rc = regmap_update_bits(wled->regmap,
784 				wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
785 				WLED4_SINK_REG_CURR_SINK_MASK, 0);
786 	if (rc < 0)
787 		return rc;
788 
789 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
790 				WLED3_CTRL_REG_MOD_EN,
791 				WLED3_CTRL_REG_MOD_EN_MASK, 0);
792 	if (rc < 0)
793 		return rc;
794 
795 	/* Per sink/string configuration */
796 	for (i = 0; i < wled->cfg.num_strings; i++) {
797 		j = wled->cfg.enabled_strings[i];
798 
799 		addr = wled->sink_addr +
800 				WLED4_SINK_REG_STR_MOD_EN(j);
801 		rc = regmap_update_bits(wled->regmap, addr,
802 					WLED4_SINK_REG_STR_MOD_MASK,
803 					WLED4_SINK_REG_STR_MOD_MASK);
804 		if (rc < 0)
805 			return rc;
806 
807 		addr = wled->sink_addr +
808 				WLED4_SINK_REG_STR_FULL_SCALE_CURR(j);
809 		rc = regmap_update_bits(wled->regmap, addr,
810 					WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK,
811 					wled->cfg.string_i_limit);
812 		if (rc < 0)
813 			return rc;
814 
815 		addr = wled->sink_addr +
816 				WLED4_SINK_REG_STR_CABC(j);
817 		rc = regmap_update_bits(wled->regmap, addr,
818 					WLED4_SINK_REG_STR_CABC_MASK,
819 					wled->cfg.cabc ?
820 					WLED4_SINK_REG_STR_CABC_MASK : 0);
821 		if (rc < 0)
822 			return rc;
823 	}
824 
825 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
826 				WLED3_CTRL_REG_MOD_EN,
827 				WLED3_CTRL_REG_MOD_EN_MASK,
828 				WLED3_CTRL_REG_MOD_EN_MASK);
829 	if (rc < 0)
830 		return rc;
831 
832 	rc = regmap_update_bits(wled->regmap,
833 				wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
834 				WLED4_SINK_REG_CURR_SINK_MASK, sink_en);
835 	if (rc < 0)
836 		return rc;
837 
838 	rc = wled_sync_toggle(wled);
839 	if (rc < 0) {
840 		dev_err(wled->dev, "Failed to toggle sync reg rc:%d\n", rc);
841 		return rc;
842 	}
843 
844 	rc = wled_auto_detection_at_init(wled);
845 
846 	return rc;
847 }
848 
849 static const struct wled_config wled4_config_defaults = {
850 	.boost_i_limit = 4,
851 	.string_i_limit = 10,
852 	.ovp = 1,
853 	.num_strings = 4,
854 	.switch_freq = 11,
855 	.cabc = false,
856 	.external_pfet = false,
857 	.auto_detection_enabled = false,
858 };
859 
860 static const u32 wled3_boost_i_limit_values[] = {
861 	105, 385, 525, 805, 980, 1260, 1400, 1680,
862 };
863 
864 static const struct wled_var_cfg wled3_boost_i_limit_cfg = {
865 	.values = wled3_boost_i_limit_values,
866 	.size = ARRAY_SIZE(wled3_boost_i_limit_values),
867 };
868 
869 static const u32 wled4_boost_i_limit_values[] = {
870 	105, 280, 450, 620, 970, 1150, 1300, 1500,
871 };
872 
873 static const struct wled_var_cfg wled4_boost_i_limit_cfg = {
874 	.values = wled4_boost_i_limit_values,
875 	.size = ARRAY_SIZE(wled4_boost_i_limit_values),
876 };
877 
878 static const u32 wled3_ovp_values[] = {
879 	35, 32, 29, 27,
880 };
881 
882 static const struct wled_var_cfg wled3_ovp_cfg = {
883 	.values = wled3_ovp_values,
884 	.size = ARRAY_SIZE(wled3_ovp_values),
885 };
886 
887 static const u32 wled4_ovp_values[] = {
888 	31100, 29600, 19600, 18100,
889 };
890 
891 static const struct wled_var_cfg wled4_ovp_cfg = {
892 	.values = wled4_ovp_values,
893 	.size = ARRAY_SIZE(wled4_ovp_values),
894 };
895 
896 static u32 wled3_num_strings_values_fn(u32 idx)
897 {
898 	return idx + 1;
899 }
900 
901 static const struct wled_var_cfg wled3_num_strings_cfg = {
902 	.fn = wled3_num_strings_values_fn,
903 	.size = 3,
904 };
905 
906 static const struct wled_var_cfg wled4_num_strings_cfg = {
907 	.fn = wled3_num_strings_values_fn,
908 	.size = 4,
909 };
910 
911 static u32 wled3_switch_freq_values_fn(u32 idx)
912 {
913 	return 19200 / (2 * (1 + idx));
914 }
915 
916 static const struct wled_var_cfg wled3_switch_freq_cfg = {
917 	.fn = wled3_switch_freq_values_fn,
918 	.size = 16,
919 };
920 
921 static const struct wled_var_cfg wled3_string_i_limit_cfg = {
922 	.size = 26,
923 };
924 
925 static const u32 wled4_string_i_limit_values[] = {
926 	0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000,
927 	22500, 25000, 27500, 30000,
928 };
929 
930 static const struct wled_var_cfg wled4_string_i_limit_cfg = {
931 	.values = wled4_string_i_limit_values,
932 	.size = ARRAY_SIZE(wled4_string_i_limit_values),
933 };
934 
935 static const struct wled_var_cfg wled3_string_cfg = {
936 	.size = 8,
937 };
938 
939 static const struct wled_var_cfg wled4_string_cfg = {
940 	.size = 16,
941 };
942 
943 static u32 wled_values(const struct wled_var_cfg *cfg, u32 idx)
944 {
945 	if (idx >= cfg->size)
946 		return UINT_MAX;
947 	if (cfg->fn)
948 		return cfg->fn(idx);
949 	if (cfg->values)
950 		return cfg->values[idx];
951 	return idx;
952 }
953 
954 static int wled_configure(struct wled *wled, int version)
955 {
956 	struct wled_config *cfg = &wled->cfg;
957 	struct device *dev = wled->dev;
958 	const __be32 *prop_addr;
959 	u32 size, val, c;
960 	int rc, i, j, string_len;
961 
962 	const struct wled_u32_opts *u32_opts = NULL;
963 	const struct wled_u32_opts wled3_opts[] = {
964 		{
965 			.name = "qcom,current-boost-limit",
966 			.val_ptr = &cfg->boost_i_limit,
967 			.cfg = &wled3_boost_i_limit_cfg,
968 		},
969 		{
970 			.name = "qcom,current-limit",
971 			.val_ptr = &cfg->string_i_limit,
972 			.cfg = &wled3_string_i_limit_cfg,
973 		},
974 		{
975 			.name = "qcom,ovp",
976 			.val_ptr = &cfg->ovp,
977 			.cfg = &wled3_ovp_cfg,
978 		},
979 		{
980 			.name = "qcom,switching-freq",
981 			.val_ptr = &cfg->switch_freq,
982 			.cfg = &wled3_switch_freq_cfg,
983 		},
984 		{
985 			.name = "qcom,num-strings",
986 			.val_ptr = &cfg->num_strings,
987 			.cfg = &wled3_num_strings_cfg,
988 		},
989 	};
990 
991 	const struct wled_u32_opts wled4_opts[] = {
992 		{
993 			.name = "qcom,current-boost-limit",
994 			.val_ptr = &cfg->boost_i_limit,
995 			.cfg = &wled4_boost_i_limit_cfg,
996 		},
997 		{
998 			.name = "qcom,current-limit-microamp",
999 			.val_ptr = &cfg->string_i_limit,
1000 			.cfg = &wled4_string_i_limit_cfg,
1001 		},
1002 		{
1003 			.name = "qcom,ovp-millivolt",
1004 			.val_ptr = &cfg->ovp,
1005 			.cfg = &wled4_ovp_cfg,
1006 		},
1007 		{
1008 			.name = "qcom,switching-freq",
1009 			.val_ptr = &cfg->switch_freq,
1010 			.cfg = &wled3_switch_freq_cfg,
1011 		},
1012 		{
1013 			.name = "qcom,num-strings",
1014 			.val_ptr = &cfg->num_strings,
1015 			.cfg = &wled4_num_strings_cfg,
1016 		},
1017 	};
1018 
1019 	const struct wled_bool_opts bool_opts[] = {
1020 		{ "qcom,cs-out", &cfg->cs_out_en, },
1021 		{ "qcom,ext-gen", &cfg->ext_gen, },
1022 		{ "qcom,cabc", &cfg->cabc, },
1023 		{ "qcom,external-pfet", &cfg->external_pfet, },
1024 		{ "qcom,auto-string-detection", &cfg->auto_detection_enabled, },
1025 	};
1026 
1027 	prop_addr = of_get_address(dev->of_node, 0, NULL, NULL);
1028 	if (!prop_addr) {
1029 		dev_err(wled->dev, "invalid IO resources\n");
1030 		return -EINVAL;
1031 	}
1032 	wled->ctrl_addr = be32_to_cpu(*prop_addr);
1033 
1034 	rc = of_property_read_string(dev->of_node, "label", &wled->name);
1035 	if (rc)
1036 		wled->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node);
1037 
1038 	switch (version) {
1039 	case 3:
1040 		u32_opts = wled3_opts;
1041 		size = ARRAY_SIZE(wled3_opts);
1042 		*cfg = wled3_config_defaults;
1043 		wled->wled_set_brightness = wled3_set_brightness;
1044 		wled->max_string_count = 3;
1045 		wled->sink_addr = wled->ctrl_addr;
1046 		break;
1047 
1048 	case 4:
1049 		u32_opts = wled4_opts;
1050 		size = ARRAY_SIZE(wled4_opts);
1051 		*cfg = wled4_config_defaults;
1052 		wled->wled_set_brightness = wled4_set_brightness;
1053 		wled->max_string_count = 4;
1054 
1055 		prop_addr = of_get_address(dev->of_node, 1, NULL, NULL);
1056 		if (!prop_addr) {
1057 			dev_err(wled->dev, "invalid IO resources\n");
1058 			return -EINVAL;
1059 		}
1060 		wled->sink_addr = be32_to_cpu(*prop_addr);
1061 		break;
1062 
1063 	default:
1064 		dev_err(wled->dev, "Invalid WLED version\n");
1065 		return -EINVAL;
1066 	}
1067 
1068 	for (i = 0; i < size; ++i) {
1069 		rc = of_property_read_u32(dev->of_node, u32_opts[i].name, &val);
1070 		if (rc == -EINVAL) {
1071 			continue;
1072 		} else if (rc) {
1073 			dev_err(dev, "error reading '%s'\n", u32_opts[i].name);
1074 			return rc;
1075 		}
1076 
1077 		c = UINT_MAX;
1078 		for (j = 0; c != val; j++) {
1079 			c = wled_values(u32_opts[i].cfg, j);
1080 			if (c == UINT_MAX) {
1081 				dev_err(dev, "invalid value for '%s'\n",
1082 					u32_opts[i].name);
1083 				return -EINVAL;
1084 			}
1085 
1086 			if (c == val)
1087 				break;
1088 		}
1089 
1090 		dev_dbg(dev, "'%s' = %u\n", u32_opts[i].name, c);
1091 		*u32_opts[i].val_ptr = j;
1092 	}
1093 
1094 	for (i = 0; i < ARRAY_SIZE(bool_opts); ++i) {
1095 		if (of_property_read_bool(dev->of_node, bool_opts[i].name))
1096 			*bool_opts[i].val_ptr = true;
1097 	}
1098 
1099 	cfg->num_strings = cfg->num_strings + 1;
1100 
1101 	string_len = of_property_count_elems_of_size(dev->of_node,
1102 						     "qcom,enabled-strings",
1103 						     sizeof(u32));
1104 	if (string_len > 0)
1105 		of_property_read_u32_array(dev->of_node,
1106 						"qcom,enabled-strings",
1107 						wled->cfg.enabled_strings,
1108 						sizeof(u32));
1109 
1110 	return 0;
1111 }
1112 
1113 static int wled_configure_short_irq(struct wled *wled,
1114 				    struct platform_device *pdev)
1115 {
1116 	int rc;
1117 
1118 	if (!wled->has_short_detect)
1119 		return 0;
1120 
1121 	rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
1122 				WLED4_CTRL_REG_SHORT_PROTECT,
1123 				WLED4_CTRL_REG_SHORT_EN_MASK,
1124 				WLED4_CTRL_REG_SHORT_EN_MASK);
1125 	if (rc < 0)
1126 		return rc;
1127 
1128 	wled->short_irq = platform_get_irq_byname(pdev, "short");
1129 	if (wled->short_irq < 0) {
1130 		dev_dbg(&pdev->dev, "short irq is not used\n");
1131 		return 0;
1132 	}
1133 
1134 	rc = devm_request_threaded_irq(wled->dev, wled->short_irq,
1135 				       NULL, wled_short_irq_handler,
1136 				       IRQF_ONESHOT,
1137 				       "wled_short_irq", wled);
1138 	if (rc < 0)
1139 		dev_err(wled->dev, "Unable to request short_irq (err:%d)\n",
1140 			rc);
1141 
1142 	return rc;
1143 }
1144 
1145 static int wled_configure_ovp_irq(struct wled *wled,
1146 				  struct platform_device *pdev)
1147 {
1148 	int rc;
1149 	u32 val;
1150 
1151 	wled->ovp_irq = platform_get_irq_byname(pdev, "ovp");
1152 	if (wled->ovp_irq < 0) {
1153 		dev_dbg(&pdev->dev, "OVP IRQ not found - disabling automatic string detection\n");
1154 		return 0;
1155 	}
1156 
1157 	rc = devm_request_threaded_irq(wled->dev, wled->ovp_irq, NULL,
1158 				       wled_ovp_irq_handler, IRQF_ONESHOT,
1159 				       "wled_ovp_irq", wled);
1160 	if (rc < 0) {
1161 		dev_err(wled->dev, "Unable to request ovp_irq (err:%d)\n",
1162 			rc);
1163 		wled->ovp_irq = 0;
1164 		return 0;
1165 	}
1166 
1167 	rc = regmap_read(wled->regmap, wled->ctrl_addr +
1168 			 WLED3_CTRL_REG_MOD_EN, &val);
1169 	if (rc < 0)
1170 		return rc;
1171 
1172 	/* Keep OVP irq disabled until module is enabled */
1173 	if (!(val & WLED3_CTRL_REG_MOD_EN_MASK))
1174 		disable_irq(wled->ovp_irq);
1175 
1176 	return 0;
1177 }
1178 
1179 static const struct backlight_ops wled_ops = {
1180 	.update_status = wled_update_status,
1181 };
1182 
1183 static int wled_probe(struct platform_device *pdev)
1184 {
1185 	struct backlight_properties props;
1186 	struct backlight_device *bl;
1187 	struct wled *wled;
1188 	struct regmap *regmap;
1189 	int version;
1190 	u32 val;
1191 	int rc;
1192 
1193 	regmap = dev_get_regmap(pdev->dev.parent, NULL);
1194 	if (!regmap) {
1195 		dev_err(&pdev->dev, "Unable to get regmap\n");
1196 		return -EINVAL;
1197 	}
1198 
1199 	wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL);
1200 	if (!wled)
1201 		return -ENOMEM;
1202 
1203 	wled->regmap = regmap;
1204 	wled->dev = &pdev->dev;
1205 
1206 	version = (uintptr_t)of_device_get_match_data(&pdev->dev);
1207 	if (!version) {
1208 		dev_err(&pdev->dev, "Unknown device version\n");
1209 		return -ENODEV;
1210 	}
1211 
1212 	mutex_init(&wled->lock);
1213 	rc = wled_configure(wled, version);
1214 	if (rc)
1215 		return rc;
1216 
1217 	switch (version) {
1218 	case 3:
1219 		wled->cfg.auto_detection_enabled = false;
1220 		rc = wled3_setup(wled);
1221 		if (rc) {
1222 			dev_err(&pdev->dev, "wled3_setup failed\n");
1223 			return rc;
1224 		}
1225 		break;
1226 
1227 	case 4:
1228 		wled->has_short_detect = true;
1229 		rc = wled4_setup(wled);
1230 		if (rc) {
1231 			dev_err(&pdev->dev, "wled4_setup failed\n");
1232 			return rc;
1233 		}
1234 		break;
1235 
1236 	default:
1237 		dev_err(wled->dev, "Invalid WLED version\n");
1238 		break;
1239 	}
1240 
1241 	INIT_DELAYED_WORK(&wled->ovp_work, wled_ovp_work);
1242 
1243 	rc = wled_configure_short_irq(wled, pdev);
1244 	if (rc < 0)
1245 		return rc;
1246 
1247 	rc = wled_configure_ovp_irq(wled, pdev);
1248 	if (rc < 0)
1249 		return rc;
1250 
1251 	val = WLED_DEFAULT_BRIGHTNESS;
1252 	of_property_read_u32(pdev->dev.of_node, "default-brightness", &val);
1253 
1254 	memset(&props, 0, sizeof(struct backlight_properties));
1255 	props.type = BACKLIGHT_RAW;
1256 	props.brightness = val;
1257 	props.max_brightness = WLED3_SINK_REG_BRIGHT_MAX;
1258 	bl = devm_backlight_device_register(&pdev->dev, wled->name,
1259 					    &pdev->dev, wled,
1260 					    &wled_ops, &props);
1261 	return PTR_ERR_OR_ZERO(bl);
1262 };
1263 
1264 static int wled_remove(struct platform_device *pdev)
1265 {
1266 	struct wled *wled = dev_get_drvdata(&pdev->dev);
1267 
1268 	mutex_destroy(&wled->lock);
1269 	cancel_delayed_work_sync(&wled->ovp_work);
1270 	disable_irq(wled->short_irq);
1271 	disable_irq(wled->ovp_irq);
1272 
1273 	return 0;
1274 }
1275 
1276 static const struct of_device_id wled_match_table[] = {
1277 	{ .compatible = "qcom,pm8941-wled", .data = (void *)3 },
1278 	{ .compatible = "qcom,pmi8998-wled", .data = (void *)4 },
1279 	{ .compatible = "qcom,pm660l-wled", .data = (void *)4 },
1280 	{}
1281 };
1282 MODULE_DEVICE_TABLE(of, wled_match_table);
1283 
1284 static struct platform_driver wled_driver = {
1285 	.probe = wled_probe,
1286 	.remove = wled_remove,
1287 	.driver	= {
1288 		.name = "qcom,wled",
1289 		.of_match_table	= wled_match_table,
1290 	},
1291 };
1292 
1293 module_platform_driver(wled_driver);
1294 
1295 MODULE_DESCRIPTION("Qualcomm WLED driver");
1296 MODULE_LICENSE("GPL v2");
1297