1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2015, Sony Mobile Communications, AB.
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>
12 #include <linux/of_device.h>
13 #include <linux/of_address.h>
14 #include <linux/regmap.h>
17 #define WLED_MAX_STRINGS 4
19 #define WLED_DEFAULT_BRIGHTNESS 2048
20 #define WLED_SOFT_START_DLY_US 10000
21 #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF
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)
29 #define WLED3_CTRL_REG_INT_RT_STS 0x10
30 #define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1)
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
36 #define WLED3_CTRL_REG_FEEDBACK_CONTROL 0x48
38 #define WLED3_CTRL_REG_FREQ 0x4c
39 #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0)
41 #define WLED3_CTRL_REG_OVP 0x4d
42 #define WLED3_CTRL_REG_OVP_MASK GENMASK(1, 0)
44 #define WLED3_CTRL_REG_ILIMIT 0x4e
45 #define WLED3_CTRL_REG_ILIMIT_MASK GENMASK(2, 0)
47 /* WLED3/WLED4 sink registers */
48 #define WLED3_SINK_REG_SYNC 0x47
49 #define WLED3_SINK_REG_SYNC_CLEAR 0x00
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
55 /* WLED3 specific per-'string' registers below */
56 #define WLED3_SINK_REG_BRIGHT(n) (0x40 + n)
58 #define WLED3_SINK_REG_STR_MOD_EN(n) (0x60 + (n * 0x10))
59 #define WLED3_SINK_REG_STR_MOD_MASK BIT(7)
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)
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
69 #define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10))
70 #define WLED3_SINK_REG_STR_CABC_MASK BIT(7)
72 /* WLED4 specific control registers */
73 #define WLED4_CTRL_REG_SHORT_PROTECT 0x5e
74 #define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7)
76 #define WLED4_CTRL_REG_SEC_ACCESS 0xd0
77 #define WLED4_CTRL_REG_SEC_UNLOCK 0xa5
79 #define WLED4_CTRL_REG_TEST1 0xe2
80 #define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09
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
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)
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)
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
99 #define WLED4_SINK_REG_STR_CABC(n) (0x56 + (n * 0x10))
100 #define WLED4_SINK_REG_STR_CABC_MASK BIT(7)
102 #define WLED4_SINK_REG_BRIGHT(n) (0x57 + (n * 0x10))
104 struct wled_var_cfg
{
110 struct wled_u32_opts
{
113 const struct wled_var_cfg
*cfg
;
116 struct wled_bool_opts
{
127 u32 enabled_strings
[WLED_MAX_STRINGS
];
132 bool auto_detection_enabled
;
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
;
144 u16 max_string_count
;
145 u16 auto_detection_ovp_count
;
149 u32 auto_detect_count
;
150 bool disabled_by_short
;
151 bool has_short_detect
;
155 struct wled_config cfg
;
156 struct delayed_work ovp_work
;
157 int (*wled_set_brightness
)(struct wled
*wled
, u16 brightness
);
160 static int wled3_set_brightness(struct wled
*wled
, u16 brightness
)
165 v
[0] = brightness
& 0xff;
166 v
[1] = (brightness
>> 8) & 0xf;
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);
178 static int wled4_set_brightness(struct wled
*wled
, u16 brightness
)
181 u16 low_limit
= wled
->max_brightness
* 4 / 1000;
184 /* WLED4's lower limit of operation is 0.4% */
185 if (brightness
> 0 && brightness
< low_limit
)
186 brightness
= low_limit
;
188 v
[0] = brightness
& 0xff;
189 v
[1] = (brightness
>> 8) & 0xf;
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);
201 static void wled_ovp_work(struct work_struct
*work
)
203 struct wled
*wled
= container_of(work
,
204 struct wled
, ovp_work
.work
);
205 enable_irq(wled
->ovp_irq
);
208 static int wled_module_enable(struct wled
*wled
, int val
)
212 if (wled
->disabled_by_short
)
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
);
222 if (wled
->ovp_irq
> 0) {
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.
230 schedule_delayed_work(&wled
->ovp_work
, HZ
/ 100);
232 if (!cancel_delayed_work_sync(&wled
->ovp_work
))
233 disable_irq(wled
->ovp_irq
);
240 static int wled_sync_toggle(struct wled
*wled
)
243 unsigned int mask
= GENMASK(wled
->max_string_count
- 1, 0);
245 rc
= regmap_update_bits(wled
->regmap
,
246 wled
->ctrl_addr
+ WLED3_SINK_REG_SYNC
,
251 rc
= regmap_update_bits(wled
->regmap
,
252 wled
->ctrl_addr
+ WLED3_SINK_REG_SYNC
,
253 mask
, WLED3_SINK_REG_SYNC_CLEAR
);
258 static int wled_update_status(struct backlight_device
*bl
)
260 struct wled
*wled
= bl_get_data(bl
);
261 u16 brightness
= bl
->props
.brightness
;
264 if (bl
->props
.power
!= FB_BLANK_UNBLANK
||
265 bl
->props
.fb_blank
!= FB_BLANK_UNBLANK
||
266 bl
->props
.state
& BL_CORE_FBBLANK
)
269 mutex_lock(&wled
->lock
);
271 rc
= wled
->wled_set_brightness(wled
, brightness
);
273 dev_err(wled
->dev
, "wled failed to set brightness rc:%d\n",
278 rc
= wled_sync_toggle(wled
);
280 dev_err(wled
->dev
, "wled sync failed rc:%d\n", rc
);
285 if (!!brightness
!= !!wled
->brightness
) {
286 rc
= wled_module_enable(wled
, !!brightness
);
288 dev_err(wled
->dev
, "wled enable failed rc:%d\n", rc
);
293 wled
->brightness
= brightness
;
296 mutex_unlock(&wled
->lock
);
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
305 static irqreturn_t
wled_short_irq_handler(int irq
, void *_wled
)
307 struct wled
*wled
= _wled
;
312 mutex_lock(&wled
->lock
);
313 rc
= wled_module_enable(wled
, false);
315 dev_err(wled
->dev
, "wled disable failed rc:%d\n", rc
);
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;
324 if (wled
->short_count
> WLED_SHORT_CNT_MAX
) {
325 dev_err(wled
->dev
, "Short triggered %d times, disabling WLED forever!\n",
327 wled
->disabled_by_short
= true;
331 wled
->last_short_event
= ktime_get();
333 msleep(WLED_SHORT_DLY_MS
);
334 rc
= wled_module_enable(wled
, true);
336 dev_err(wled
->dev
, "wled enable failed rc:%d\n", rc
);
339 mutex_unlock(&wled
->lock
);
344 #define AUTO_DETECT_BRIGHTNESS 200
346 static void wled_auto_string_detection(struct wled
*wled
)
349 u32 sink_config
= 0, int_sts
;
350 u8 sink_test
= 0, sink_valid
= 0, val
;
352 /* Read configured sink configuration */
353 rc
= regmap_read(wled
->regmap
, wled
->sink_addr
+
354 WLED4_SINK_REG_CURR_SINK
, &sink_config
);
356 dev_err(wled
->dev
, "Failed to read SINK configuration rc=%d\n",
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);
366 dev_err(wled
->dev
, "Failed to disable WLED module rc=%d\n", rc
);
370 /* Set low brightness across all sinks */
371 rc
= wled4_set_brightness(wled
, AUTO_DETECT_BRIGHTNESS
);
373 dev_err(wled
->dev
, "Failed to set brightness for auto detection rc=%d\n",
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
,
389 /* Disable all sinks */
390 rc
= regmap_write(wled
->regmap
,
391 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
, 0);
393 dev_err(wled
->dev
, "Failed to disable all sinks rc=%d\n", rc
);
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
));
401 /* Enable feedback control */
402 rc
= regmap_write(wled
->regmap
, wled
->ctrl_addr
+
403 WLED3_CTRL_REG_FEEDBACK_CONTROL
, i
+ 1);
405 dev_err(wled
->dev
, "Failed to enable feedback for SINK %d rc = %d\n",
410 /* Enable the sink */
411 rc
= regmap_write(wled
->regmap
, wled
->sink_addr
+
412 WLED4_SINK_REG_CURR_SINK
, sink_test
);
414 dev_err(wled
->dev
, "Failed to configure SINK %d rc=%d\n",
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
);
425 dev_err(wled
->dev
, "Failed to enable WLED module rc=%d\n",
430 usleep_range(WLED_SOFT_START_DLY_US
,
431 WLED_SOFT_START_DLY_US
+ 1000);
433 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
434 WLED3_CTRL_REG_INT_RT_STS
, &int_sts
);
436 dev_err(wled
->dev
, "Error in reading WLED3_CTRL_INT_RT_STS rc=%d\n",
441 if (int_sts
& WLED3_CTRL_REG_OVP_FAULT_STATUS
)
442 dev_dbg(wled
->dev
, "WLED OVP fault detected with SINK %d\n",
445 sink_valid
|= sink_test
;
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);
452 dev_err(wled
->dev
, "Failed to disable WLED module rc=%d\n",
459 dev_err(wled
->dev
, "No valid WLED sinks found\n");
460 wled
->disabled_by_short
= true;
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
;
470 /* Write the new sink configuration */
471 rc
= regmap_write(wled
->regmap
,
472 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
475 dev_err(wled
->dev
, "Failed to reconfigure the default sink rc=%d\n",
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
);
491 if (sink_config
& BIT(WLED4_SINK_REG_CURR_SINK_SHFT
+ i
))
492 val
= WLED4_SINK_REG_STR_MOD_MASK
;
494 val
= 0x0; /* Disable modulator_en for unused sink */
496 rc
= regmap_write(wled
->regmap
, wled
->sink_addr
+
497 WLED4_SINK_REG_STR_MOD_EN(i
), val
);
499 dev_err(wled
->dev
, "Failed to configure MODULATOR_EN rc=%d\n",
505 /* Restore the feedback setting */
506 rc
= regmap_write(wled
->regmap
,
507 wled
->ctrl_addr
+ WLED3_CTRL_REG_FEEDBACK_CONTROL
, 0);
509 dev_err(wled
->dev
, "Failed to restore feedback setting rc=%d\n",
514 /* Restore brightness */
515 rc
= wled4_set_brightness(wled
, wled
->brightness
);
517 dev_err(wled
->dev
, "Failed to set brightness after auto detection rc=%d\n",
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
);
527 dev_err(wled
->dev
, "Failed to enable WLED module rc=%d\n", rc
);
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
)
541 if (!wled
->cfg
.auto_detection_enabled
)
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.
549 if (!wled
->auto_detection_ovp_count
) {
550 wled
->start_ovp_fault_time
= ktime_get();
551 wled
->auto_detection_ovp_count
++;
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;
558 wled
->auto_detection_ovp_count
++;
560 if (wled
->auto_detection_ovp_count
>=
561 WLED_AUTO_DETECT_OVP_COUNT
) {
562 wled
->auto_detection_ovp_count
= 0;
570 static int wled_auto_detection_at_init(struct wled
*wled
)
573 u32 fault_status
, rt_status
;
575 if (!wled
->cfg
.auto_detection_enabled
)
578 rc
= regmap_read(wled
->regmap
,
579 wled
->ctrl_addr
+ WLED3_CTRL_REG_INT_RT_STS
,
582 dev_err(wled
->dev
, "Failed to read RT status rc=%d\n", rc
);
586 rc
= regmap_read(wled
->regmap
,
587 wled
->ctrl_addr
+ WLED3_CTRL_REG_FAULT_STATUS
,
590 dev_err(wled
->dev
, "Failed to read fault status rc=%d\n", rc
);
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
);
604 static irqreturn_t
wled_ovp_irq_handler(int irq
, void *_wled
)
606 struct wled
*wled
= _wled
;
608 u32 int_sts
, fault_sts
;
610 rc
= regmap_read(wled
->regmap
,
611 wled
->ctrl_addr
+ WLED3_CTRL_REG_INT_RT_STS
, &int_sts
);
613 dev_err(wled
->dev
, "Error in reading WLED3_INT_RT_STS rc=%d\n",
618 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
619 WLED3_CTRL_REG_FAULT_STATUS
, &fault_sts
);
621 dev_err(wled
->dev
, "Error in reading WLED_FAULT_STATUS rc=%d\n",
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",
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
);
642 static int wled3_setup(struct wled
*wled
)
648 rc
= regmap_update_bits(wled
->regmap
,
649 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
650 WLED3_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
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
);
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
);
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
);
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
);
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
);
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
,
697 WLED3_SINK_REG_STR_CABC_MASK
: 0);
701 sink_en
|= BIT(j
+ WLED3_SINK_REG_CURR_SINK_SHFT
);
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
);
713 static const struct wled_config wled3_config_defaults
= {
715 .string_i_limit
= 20,
722 .enabled_strings
= {0, 1, 2, 3},
725 static int wled4_setup(struct wled
*wled
)
732 rc
= regmap_update_bits(wled
->regmap
,
733 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
734 WLED3_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
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
);
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
);
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
);
760 rc
= regmap_write(wled
->regmap
,
761 wled
->ctrl_addr
+ WLED4_CTRL_REG_TEST1
,
762 WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2
);
767 rc
= regmap_read(wled
->regmap
, wled
->sink_addr
+
768 WLED4_SINK_REG_CURR_SINK
, &sink_cfg
);
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
;
778 if (sink_cfg
== sink_en
) {
779 rc
= wled_auto_detection_at_init(wled
);
783 rc
= regmap_update_bits(wled
->regmap
,
784 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
785 WLED4_SINK_REG_CURR_SINK_MASK
, 0);
789 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
790 WLED3_CTRL_REG_MOD_EN
,
791 WLED3_CTRL_REG_MOD_EN_MASK
, 0);
795 /* Per sink/string configuration */
796 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
797 j
= wled
->cfg
.enabled_strings
[i
];
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
);
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
);
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
,
820 WLED4_SINK_REG_STR_CABC_MASK
: 0);
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
);
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
);
838 rc
= wled_sync_toggle(wled
);
840 dev_err(wled
->dev
, "Failed to toggle sync reg rc:%d\n", rc
);
844 rc
= wled_auto_detection_at_init(wled
);
849 static const struct wled_config wled4_config_defaults
= {
851 .string_i_limit
= 10,
856 .external_pfet
= false,
857 .auto_detection_enabled
= false,
860 static const u32 wled3_boost_i_limit_values
[] = {
861 105, 385, 525, 805, 980, 1260, 1400, 1680,
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
),
869 static const u32 wled4_boost_i_limit_values
[] = {
870 105, 280, 450, 620, 970, 1150, 1300, 1500,
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
),
878 static const u32 wled3_ovp_values
[] = {
882 static const struct wled_var_cfg wled3_ovp_cfg
= {
883 .values
= wled3_ovp_values
,
884 .size
= ARRAY_SIZE(wled3_ovp_values
),
887 static const u32 wled4_ovp_values
[] = {
888 31100, 29600, 19600, 18100,
891 static const struct wled_var_cfg wled4_ovp_cfg
= {
892 .values
= wled4_ovp_values
,
893 .size
= ARRAY_SIZE(wled4_ovp_values
),
896 static u32
wled3_num_strings_values_fn(u32 idx
)
901 static const struct wled_var_cfg wled3_num_strings_cfg
= {
902 .fn
= wled3_num_strings_values_fn
,
906 static const struct wled_var_cfg wled4_num_strings_cfg
= {
907 .fn
= wled3_num_strings_values_fn
,
911 static u32
wled3_switch_freq_values_fn(u32 idx
)
913 return 19200 / (2 * (1 + idx
));
916 static const struct wled_var_cfg wled3_switch_freq_cfg
= {
917 .fn
= wled3_switch_freq_values_fn
,
921 static const struct wled_var_cfg wled3_string_i_limit_cfg
= {
925 static const u32 wled4_string_i_limit_values
[] = {
926 0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000,
927 22500, 25000, 27500, 30000,
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
),
935 static const struct wled_var_cfg wled3_string_cfg
= {
939 static const struct wled_var_cfg wled4_string_cfg
= {
943 static u32
wled_values(const struct wled_var_cfg
*cfg
, u32 idx
)
945 if (idx
>= cfg
->size
)
950 return cfg
->values
[idx
];
954 static int wled_configure(struct wled
*wled
, int version
)
956 struct wled_config
*cfg
= &wled
->cfg
;
957 struct device
*dev
= wled
->dev
;
958 const __be32
*prop_addr
;
960 int rc
, i
, j
, string_len
;
962 const struct wled_u32_opts
*u32_opts
= NULL
;
963 const struct wled_u32_opts wled3_opts
[] = {
965 .name
= "qcom,current-boost-limit",
966 .val_ptr
= &cfg
->boost_i_limit
,
967 .cfg
= &wled3_boost_i_limit_cfg
,
970 .name
= "qcom,current-limit",
971 .val_ptr
= &cfg
->string_i_limit
,
972 .cfg
= &wled3_string_i_limit_cfg
,
976 .val_ptr
= &cfg
->ovp
,
977 .cfg
= &wled3_ovp_cfg
,
980 .name
= "qcom,switching-freq",
981 .val_ptr
= &cfg
->switch_freq
,
982 .cfg
= &wled3_switch_freq_cfg
,
985 .name
= "qcom,num-strings",
986 .val_ptr
= &cfg
->num_strings
,
987 .cfg
= &wled3_num_strings_cfg
,
991 const struct wled_u32_opts wled4_opts
[] = {
993 .name
= "qcom,current-boost-limit",
994 .val_ptr
= &cfg
->boost_i_limit
,
995 .cfg
= &wled4_boost_i_limit_cfg
,
998 .name
= "qcom,current-limit-microamp",
999 .val_ptr
= &cfg
->string_i_limit
,
1000 .cfg
= &wled4_string_i_limit_cfg
,
1003 .name
= "qcom,ovp-millivolt",
1004 .val_ptr
= &cfg
->ovp
,
1005 .cfg
= &wled4_ovp_cfg
,
1008 .name
= "qcom,switching-freq",
1009 .val_ptr
= &cfg
->switch_freq
,
1010 .cfg
= &wled3_switch_freq_cfg
,
1013 .name
= "qcom,num-strings",
1014 .val_ptr
= &cfg
->num_strings
,
1015 .cfg
= &wled4_num_strings_cfg
,
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
, },
1027 prop_addr
= of_get_address(dev
->of_node
, 0, NULL
, NULL
);
1029 dev_err(wled
->dev
, "invalid IO resources\n");
1032 wled
->ctrl_addr
= be32_to_cpu(*prop_addr
);
1034 rc
= of_property_read_string(dev
->of_node
, "label", &wled
->name
);
1036 wled
->name
= devm_kasprintf(dev
, GFP_KERNEL
, "%pOFn", dev
->of_node
);
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
;
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;
1055 prop_addr
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
1057 dev_err(wled
->dev
, "invalid IO resources\n");
1060 wled
->sink_addr
= be32_to_cpu(*prop_addr
);
1064 dev_err(wled
->dev
, "Invalid WLED version\n");
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
) {
1073 dev_err(dev
, "error reading '%s'\n", u32_opts
[i
].name
);
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",
1090 dev_dbg(dev
, "'%s' = %u\n", u32_opts
[i
].name
, c
);
1091 *u32_opts
[i
].val_ptr
= j
;
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;
1099 cfg
->num_strings
= cfg
->num_strings
+ 1;
1101 string_len
= of_property_count_elems_of_size(dev
->of_node
,
1102 "qcom,enabled-strings",
1105 of_property_read_u32_array(dev
->of_node
,
1106 "qcom,enabled-strings",
1107 wled
->cfg
.enabled_strings
,
1113 static int wled_configure_short_irq(struct wled
*wled
,
1114 struct platform_device
*pdev
)
1118 if (!wled
->has_short_detect
)
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
);
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");
1134 rc
= devm_request_threaded_irq(wled
->dev
, wled
->short_irq
,
1135 NULL
, wled_short_irq_handler
,
1137 "wled_short_irq", wled
);
1139 dev_err(wled
->dev
, "Unable to request short_irq (err:%d)\n",
1145 static int wled_configure_ovp_irq(struct wled
*wled
,
1146 struct platform_device
*pdev
)
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");
1157 rc
= devm_request_threaded_irq(wled
->dev
, wled
->ovp_irq
, NULL
,
1158 wled_ovp_irq_handler
, IRQF_ONESHOT
,
1159 "wled_ovp_irq", wled
);
1161 dev_err(wled
->dev
, "Unable to request ovp_irq (err:%d)\n",
1167 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
1168 WLED3_CTRL_REG_MOD_EN
, &val
);
1172 /* Keep OVP irq disabled until module is enabled */
1173 if (!(val
& WLED3_CTRL_REG_MOD_EN_MASK
))
1174 disable_irq(wled
->ovp_irq
);
1179 static const struct backlight_ops wled_ops
= {
1180 .update_status
= wled_update_status
,
1183 static int wled_probe(struct platform_device
*pdev
)
1185 struct backlight_properties props
;
1186 struct backlight_device
*bl
;
1188 struct regmap
*regmap
;
1193 regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
1195 dev_err(&pdev
->dev
, "Unable to get regmap\n");
1199 wled
= devm_kzalloc(&pdev
->dev
, sizeof(*wled
), GFP_KERNEL
);
1203 wled
->regmap
= regmap
;
1204 wled
->dev
= &pdev
->dev
;
1206 version
= (uintptr_t)of_device_get_match_data(&pdev
->dev
);
1208 dev_err(&pdev
->dev
, "Unknown device version\n");
1212 mutex_init(&wled
->lock
);
1213 rc
= wled_configure(wled
, version
);
1219 wled
->cfg
.auto_detection_enabled
= false;
1220 rc
= wled3_setup(wled
);
1222 dev_err(&pdev
->dev
, "wled3_setup failed\n");
1228 wled
->has_short_detect
= true;
1229 rc
= wled4_setup(wled
);
1231 dev_err(&pdev
->dev
, "wled4_setup failed\n");
1237 dev_err(wled
->dev
, "Invalid WLED version\n");
1241 INIT_DELAYED_WORK(&wled
->ovp_work
, wled_ovp_work
);
1243 rc
= wled_configure_short_irq(wled
, pdev
);
1247 rc
= wled_configure_ovp_irq(wled
, pdev
);
1251 val
= WLED_DEFAULT_BRIGHTNESS
;
1252 of_property_read_u32(pdev
->dev
.of_node
, "default-brightness", &val
);
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
,
1261 return PTR_ERR_OR_ZERO(bl
);
1264 static int wled_remove(struct platform_device
*pdev
)
1266 struct wled
*wled
= dev_get_drvdata(&pdev
->dev
);
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
);
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 },
1282 MODULE_DEVICE_TABLE(of
, wled_match_table
);
1284 static struct platform_driver wled_driver
= {
1285 .probe
= wled_probe
,
1286 .remove
= wled_remove
,
1288 .name
= "qcom,wled",
1289 .of_match_table
= wled_match_table
,
1293 module_platform_driver(wled_driver
);
1295 MODULE_DESCRIPTION("Qualcomm WLED driver");
1296 MODULE_LICENSE("GPL v2");