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
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
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)
34 #define WLED3_CTRL_REG_INT_RT_STS 0x10
35 #define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1)
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
41 #define WLED3_CTRL_REG_FEEDBACK_CONTROL 0x48
43 #define WLED3_CTRL_REG_FREQ 0x4c
44 #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0)
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)
50 #define WLED3_CTRL_REG_ILIMIT 0x4e
51 #define WLED3_CTRL_REG_ILIMIT_MASK GENMASK(2, 0)
53 /* WLED3/WLED4 sink registers */
54 #define WLED3_SINK_REG_SYNC 0x47
55 #define WLED3_SINK_REG_SYNC_CLEAR 0x00
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
61 /* WLED3 specific per-'string' registers below */
62 #define WLED3_SINK_REG_BRIGHT(n) (0x40 + n)
64 #define WLED3_SINK_REG_STR_MOD_EN(n) (0x60 + (n * 0x10))
65 #define WLED3_SINK_REG_STR_MOD_MASK BIT(7)
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)
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
75 #define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10))
76 #define WLED3_SINK_REG_STR_CABC_MASK BIT(7)
78 /* WLED4 specific control registers */
79 #define WLED4_CTRL_REG_SHORT_PROTECT 0x5e
80 #define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7)
82 #define WLED4_CTRL_REG_SEC_ACCESS 0xd0
83 #define WLED4_CTRL_REG_SEC_UNLOCK 0xa5
85 #define WLED4_CTRL_REG_TEST1 0xe2
86 #define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09
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
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)
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)
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
105 #define WLED4_SINK_REG_STR_CABC(n) (0x56 + (n * 0x10))
106 #define WLED4_SINK_REG_STR_CABC_MASK BIT(7)
108 #define WLED4_SINK_REG_BRIGHT(n) (0x57 + (n * 0x10))
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)
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)
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)
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
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
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)
140 /* WLED5 specific per-'string' registers below */
141 #define WLED5_SINK_REG_STR_FULL_SCALE_CURR(n) (0x72 + (n * 0x10))
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)
148 struct wled_var_cfg
{
154 struct wled_u32_opts
{
157 const struct wled_var_cfg
*cfg
;
160 struct wled_bool_opts
{
171 u32 enabled_strings
[WLED_MAX_STRINGS
];
178 bool auto_detection_enabled
;
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
;
190 u16 max_string_count
;
191 u16 auto_detection_ovp_count
;
195 u32 auto_detect_count
;
197 bool disabled_by_short
;
198 bool has_short_detect
;
203 struct wled_config cfg
;
204 struct delayed_work ovp_work
;
206 /* Configures the brightness. Applicable for wled3, wled4 and wled5 */
207 int (*wled_set_brightness
)(struct wled
*wled
, u16 brightness
);
209 /* Configures the cabc register. Applicable for wled4 and wled5 */
210 int (*wled_cabc_config
)(struct wled
*wled
, bool enable
);
213 * Toggles the sync bit for the brightness update to take place.
214 * Applicable for WLED3, WLED4 and WLED5.
216 int (*wled_sync_toggle
)(struct wled
*wled
);
219 * Time to wait before checking the OVP status after wled module enable.
220 * Applicable for WLED4 and WLED5.
222 int (*wled_ovp_delay
)(struct wled
*wled
);
225 * Determines if the auto string detection is required.
226 * Applicable for WLED4 and WLED5
228 bool (*wled_auto_detection_required
)(struct wled
*wled
);
231 static int wled3_set_brightness(struct wled
*wled
, u16 brightness
)
236 v
[0] = brightness
& 0xff;
237 v
[1] = (brightness
>> 8) & 0xf;
239 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
240 rc
= regmap_bulk_write(wled
->regmap
, wled
->ctrl_addr
+
241 WLED3_SINK_REG_BRIGHT(i
), v
, 2);
249 static int wled4_set_brightness(struct wled
*wled
, u16 brightness
)
252 u16 low_limit
= wled
->max_brightness
* 4 / 1000;
255 /* WLED4's lower limit of operation is 0.4% */
256 if (brightness
> 0 && brightness
< low_limit
)
257 brightness
= low_limit
;
259 v
[0] = brightness
& 0xff;
260 v
[1] = (brightness
>> 8) & 0xf;
262 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
263 rc
= regmap_bulk_write(wled
->regmap
, wled
->sink_addr
+
264 WLED4_SINK_REG_BRIGHT(i
), v
, 2);
272 static int wled5_set_brightness(struct wled
*wled
, u16 brightness
)
275 u16 low_limit
= wled
->max_brightness
* 1 / 1000;
278 /* WLED5's lower limit is 0.1% */
279 if (brightness
< low_limit
)
280 brightness
= low_limit
;
282 v
[0] = brightness
& 0xff;
283 v
[1] = (brightness
>> 8) & 0x7f;
285 offset
= (wled
->cfg
.mod_sel
== MOD_A
) ?
286 WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB
:
287 WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB
;
289 rc
= regmap_bulk_write(wled
->regmap
, wled
->sink_addr
+ offset
,
294 static void wled_ovp_work(struct work_struct
*work
)
296 struct wled
*wled
= container_of(work
,
297 struct wled
, ovp_work
.work
);
298 enable_irq(wled
->ovp_irq
);
301 static int wled_module_enable(struct wled
*wled
, int val
)
305 if (wled
->disabled_by_short
)
308 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
309 WLED3_CTRL_REG_MOD_EN
,
310 WLED3_CTRL_REG_MOD_EN_MASK
,
311 val
<< WLED3_CTRL_REG_MOD_EN_SHIFT
);
315 if (wled
->ovp_irq
> 0) {
318 * The hardware generates a storm of spurious OVP
319 * interrupts during soft start operations. So defer
320 * enabling the IRQ for 10ms to ensure that the
321 * soft start is complete.
323 schedule_delayed_work(&wled
->ovp_work
, HZ
/ 100);
325 if (!cancel_delayed_work_sync(&wled
->ovp_work
))
326 disable_irq(wled
->ovp_irq
);
333 static int wled3_sync_toggle(struct wled
*wled
)
336 unsigned int mask
= GENMASK(wled
->max_string_count
- 1, 0);
338 rc
= regmap_update_bits(wled
->regmap
,
339 wled
->ctrl_addr
+ WLED3_SINK_REG_SYNC
,
344 rc
= regmap_update_bits(wled
->regmap
,
345 wled
->ctrl_addr
+ WLED3_SINK_REG_SYNC
,
346 mask
, WLED3_SINK_REG_SYNC_CLEAR
);
351 static int wled5_sync_toggle(struct wled
*wled
)
356 val
= (wled
->cfg
.mod_sel
== MOD_A
) ? WLED5_SINK_REG_SYNC_MOD_A_BIT
:
357 WLED5_SINK_REG_SYNC_MOD_B_BIT
;
358 rc
= regmap_update_bits(wled
->regmap
,
359 wled
->sink_addr
+ WLED5_SINK_REG_MOD_SYNC_BIT
,
360 WLED5_SINK_REG_SYNC_MASK
, val
);
364 return regmap_update_bits(wled
->regmap
,
365 wled
->sink_addr
+ WLED5_SINK_REG_MOD_SYNC_BIT
,
366 WLED5_SINK_REG_SYNC_MASK
, 0);
369 static int wled_ovp_fault_status(struct wled
*wled
, bool *fault_set
)
372 u32 int_rt_sts
, fault_sts
;
375 rc
= regmap_read(wled
->regmap
,
376 wled
->ctrl_addr
+ WLED3_CTRL_REG_INT_RT_STS
,
379 dev_err(wled
->dev
, "Failed to read INT_RT_STS rc=%d\n", rc
);
383 rc
= regmap_read(wled
->regmap
,
384 wled
->ctrl_addr
+ WLED3_CTRL_REG_FAULT_STATUS
,
387 dev_err(wled
->dev
, "Failed to read FAULT_STATUS rc=%d\n", rc
);
391 if (int_rt_sts
& WLED3_CTRL_REG_OVP_FAULT_STATUS
)
394 if (wled
->version
== 4 && (fault_sts
& WLED3_CTRL_REG_OVP_FAULT_BIT
))
397 if (wled
->version
== 5 && (fault_sts
& (WLED3_CTRL_REG_OVP_FAULT_BIT
|
398 WLED5_CTRL_REG_OVP_PRE_ALARM_BIT
)))
402 dev_dbg(wled
->dev
, "WLED OVP fault detected, int_rt_sts=0x%x fault_sts=0x%x\n",
403 int_rt_sts
, fault_sts
);
408 static int wled4_ovp_delay(struct wled
*wled
)
410 return WLED_SOFT_START_DLY_US
;
413 static int wled5_ovp_delay(struct wled
*wled
)
417 u8 ovp_timer_ms
[8] = {1, 2, 4, 8, 12, 16, 20, 24};
419 /* For WLED5, get the delay based on OVP timer */
420 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
421 WLED5_CTRL_REG_OVP_INT_CTL
, &val
);
424 ovp_timer_ms
[val
& WLED5_CTRL_REG_OVP_INT_TIMER_MASK
] * 1000;
426 delay_us
= 2 * WLED_SOFT_START_DLY_US
;
428 dev_dbg(wled
->dev
, "delay_time_us: %d\n", delay_us
);
433 static int wled_update_status(struct backlight_device
*bl
)
435 struct wled
*wled
= bl_get_data(bl
);
436 u16 brightness
= backlight_get_brightness(bl
);
439 mutex_lock(&wled
->lock
);
441 rc
= wled
->wled_set_brightness(wled
, brightness
);
443 dev_err(wled
->dev
, "wled failed to set brightness rc:%d\n",
448 rc
= wled
->wled_sync_toggle(wled
);
450 dev_err(wled
->dev
, "wled sync failed rc:%d\n", rc
);
455 if (!!brightness
!= !!wled
->brightness
) {
456 rc
= wled_module_enable(wled
, !!brightness
);
458 dev_err(wled
->dev
, "wled enable failed rc:%d\n", rc
);
463 wled
->brightness
= brightness
;
466 mutex_unlock(&wled
->lock
);
471 static int wled4_cabc_config(struct wled
*wled
, bool enable
)
476 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
477 j
= wled
->cfg
.enabled_strings
[i
];
479 val
= enable
? WLED4_SINK_REG_STR_CABC_MASK
: 0;
480 rc
= regmap_update_bits(wled
->regmap
, wled
->sink_addr
+
481 WLED4_SINK_REG_STR_CABC(j
),
482 WLED4_SINK_REG_STR_CABC_MASK
, val
);
490 static int wled5_cabc_config(struct wled
*wled
, bool enable
)
495 if (wled
->cabc_disabled
)
498 reg
= enable
? wled
->cfg
.cabc_sel
: 0;
499 offset
= (wled
->cfg
.mod_sel
== MOD_A
) ? WLED5_SINK_REG_MOD_A_SRC_SEL
:
500 WLED5_SINK_REG_MOD_B_SRC_SEL
;
502 rc
= regmap_update_bits(wled
->regmap
, wled
->sink_addr
+ offset
,
503 WLED5_SINK_REG_MOD_SRC_SEL_MASK
, reg
);
505 pr_err("Error in configuring CABC rc=%d\n", rc
);
509 if (!wled
->cfg
.cabc_sel
)
510 wled
->cabc_disabled
= true;
515 #define WLED_SHORT_DLY_MS 20
516 #define WLED_SHORT_CNT_MAX 5
517 #define WLED_SHORT_RESET_CNT_DLY_US USEC_PER_SEC
519 static irqreturn_t
wled_short_irq_handler(int irq
, void *_wled
)
521 struct wled
*wled
= _wled
;
526 mutex_lock(&wled
->lock
);
527 rc
= wled_module_enable(wled
, false);
529 dev_err(wled
->dev
, "wled disable failed rc:%d\n", rc
);
533 elapsed_time
= ktime_us_delta(ktime_get(),
534 wled
->last_short_event
);
535 if (elapsed_time
> WLED_SHORT_RESET_CNT_DLY_US
)
536 wled
->short_count
= 1;
538 if (wled
->short_count
> WLED_SHORT_CNT_MAX
) {
539 dev_err(wled
->dev
, "Short triggered %d times, disabling WLED forever!\n",
541 wled
->disabled_by_short
= true;
545 wled
->last_short_event
= ktime_get();
547 msleep(WLED_SHORT_DLY_MS
);
548 rc
= wled_module_enable(wled
, true);
550 dev_err(wled
->dev
, "wled enable failed rc:%d\n", rc
);
553 mutex_unlock(&wled
->lock
);
558 #define AUTO_DETECT_BRIGHTNESS 200
560 static void wled_auto_string_detection(struct wled
*wled
)
562 int rc
= 0, i
, delay_time_us
;
564 u8 sink_test
= 0, sink_valid
= 0, val
;
567 /* Read configured sink configuration */
568 rc
= regmap_read(wled
->regmap
, wled
->sink_addr
+
569 WLED4_SINK_REG_CURR_SINK
, &sink_config
);
571 dev_err(wled
->dev
, "Failed to read SINK configuration rc=%d\n",
576 /* Disable the module before starting detection */
577 rc
= regmap_update_bits(wled
->regmap
,
578 wled
->ctrl_addr
+ WLED3_CTRL_REG_MOD_EN
,
579 WLED3_CTRL_REG_MOD_EN_MASK
, 0);
581 dev_err(wled
->dev
, "Failed to disable WLED module rc=%d\n", rc
);
585 /* Set low brightness across all sinks */
586 rc
= wled4_set_brightness(wled
, AUTO_DETECT_BRIGHTNESS
);
588 dev_err(wled
->dev
, "Failed to set brightness for auto detection rc=%d\n",
593 if (wled
->cfg
.cabc
) {
594 rc
= wled
->wled_cabc_config(wled
, false);
599 /* Disable all sinks */
600 rc
= regmap_write(wled
->regmap
,
601 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
, 0);
603 dev_err(wled
->dev
, "Failed to disable all sinks rc=%d\n", rc
);
607 /* Iterate through the strings one by one */
608 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
609 sink_test
= BIT((WLED4_SINK_REG_CURR_SINK_SHFT
+ i
));
611 /* Enable feedback control */
612 rc
= regmap_write(wled
->regmap
, wled
->ctrl_addr
+
613 WLED3_CTRL_REG_FEEDBACK_CONTROL
, i
+ 1);
615 dev_err(wled
->dev
, "Failed to enable feedback for SINK %d rc = %d\n",
620 /* Enable the sink */
621 rc
= regmap_write(wled
->regmap
, wled
->sink_addr
+
622 WLED4_SINK_REG_CURR_SINK
, sink_test
);
624 dev_err(wled
->dev
, "Failed to configure SINK %d rc=%d\n",
629 /* Enable the module */
630 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
631 WLED3_CTRL_REG_MOD_EN
,
632 WLED3_CTRL_REG_MOD_EN_MASK
,
633 WLED3_CTRL_REG_MOD_EN_MASK
);
635 dev_err(wled
->dev
, "Failed to enable WLED module rc=%d\n",
640 delay_time_us
= wled
->wled_ovp_delay(wled
);
641 usleep_range(delay_time_us
, delay_time_us
+ 1000);
643 rc
= wled_ovp_fault_status(wled
, &fault_set
);
645 dev_err(wled
->dev
, "Error in getting OVP fault_sts, rc=%d\n",
651 dev_dbg(wled
->dev
, "WLED OVP fault detected with SINK %d\n",
654 sink_valid
|= sink_test
;
656 /* Disable the module */
657 rc
= regmap_update_bits(wled
->regmap
,
658 wled
->ctrl_addr
+ WLED3_CTRL_REG_MOD_EN
,
659 WLED3_CTRL_REG_MOD_EN_MASK
, 0);
661 dev_err(wled
->dev
, "Failed to disable WLED module rc=%d\n",
668 dev_err(wled
->dev
, "No valid WLED sinks found\n");
669 wled
->disabled_by_short
= true;
673 if (sink_valid
!= sink_config
) {
674 dev_warn(wled
->dev
, "%x is not a valid sink configuration - using %x instead\n",
675 sink_config
, sink_valid
);
676 sink_config
= sink_valid
;
679 /* Write the new sink configuration */
680 rc
= regmap_write(wled
->regmap
,
681 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
684 dev_err(wled
->dev
, "Failed to reconfigure the default sink rc=%d\n",
689 /* Enable valid sinks */
690 if (wled
->version
== 4) {
691 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
693 BIT(WLED4_SINK_REG_CURR_SINK_SHFT
+ i
))
694 val
= WLED4_SINK_REG_STR_MOD_MASK
;
696 /* Disable modulator_en for unused sink */
699 rc
= regmap_write(wled
->regmap
, wled
->sink_addr
+
700 WLED4_SINK_REG_STR_MOD_EN(i
), val
);
702 dev_err(wled
->dev
, "Failed to configure MODULATOR_EN rc=%d\n",
710 rc
= wled
->wled_cabc_config(wled
, true);
714 /* Restore the feedback setting */
715 rc
= regmap_write(wled
->regmap
,
716 wled
->ctrl_addr
+ WLED3_CTRL_REG_FEEDBACK_CONTROL
, 0);
718 dev_err(wled
->dev
, "Failed to restore feedback setting rc=%d\n",
723 /* Restore brightness */
724 rc
= wled4_set_brightness(wled
, wled
->brightness
);
726 dev_err(wled
->dev
, "Failed to set brightness after auto detection rc=%d\n",
731 rc
= regmap_update_bits(wled
->regmap
,
732 wled
->ctrl_addr
+ WLED3_CTRL_REG_MOD_EN
,
733 WLED3_CTRL_REG_MOD_EN_MASK
,
734 WLED3_CTRL_REG_MOD_EN_MASK
);
736 dev_err(wled
->dev
, "Failed to enable WLED module rc=%d\n", rc
);
744 #define WLED_AUTO_DETECT_OVP_COUNT 5
745 #define WLED_AUTO_DETECT_CNT_DLY_US USEC_PER_SEC
747 static bool wled4_auto_detection_required(struct wled
*wled
)
751 if (!wled
->cfg
.auto_detection_enabled
)
755 * Check if the OVP fault was an occasional one
756 * or if it's firing continuously, the latter qualifies
757 * for an auto-detection check.
759 if (!wled
->auto_detection_ovp_count
) {
760 wled
->start_ovp_fault_time
= ktime_get();
761 wled
->auto_detection_ovp_count
++;
763 elapsed_time_us
= ktime_us_delta(ktime_get(),
764 wled
->start_ovp_fault_time
);
765 if (elapsed_time_us
> WLED_AUTO_DETECT_CNT_DLY_US
)
766 wled
->auto_detection_ovp_count
= 0;
768 wled
->auto_detection_ovp_count
++;
770 if (wled
->auto_detection_ovp_count
>=
771 WLED_AUTO_DETECT_OVP_COUNT
) {
772 wled
->auto_detection_ovp_count
= 0;
780 static bool wled5_auto_detection_required(struct wled
*wled
)
782 if (!wled
->cfg
.auto_detection_enabled
)
786 * Unlike WLED4, WLED5 has OVP fault density interrupt configuration
787 * i.e. to count the number of OVP alarms for a certain duration before
788 * triggering OVP fault interrupt. By default, number of OVP fault
789 * events counted before an interrupt is fired is 32 and the time
790 * interval is 12 ms. If we see one OVP fault interrupt, then that
791 * should qualify for a real OVP fault condition to run auto detection
797 static int wled_auto_detection_at_init(struct wled
*wled
)
802 if (!wled
->cfg
.auto_detection_enabled
)
805 rc
= wled_ovp_fault_status(wled
, &fault_set
);
807 dev_err(wled
->dev
, "Error in getting OVP fault_sts, rc=%d\n",
813 mutex_lock(&wled
->lock
);
814 wled_auto_string_detection(wled
);
815 mutex_unlock(&wled
->lock
);
821 static irqreturn_t
wled_ovp_irq_handler(int irq
, void *_wled
)
823 struct wled
*wled
= _wled
;
825 u32 int_sts
, fault_sts
;
827 rc
= regmap_read(wled
->regmap
,
828 wled
->ctrl_addr
+ WLED3_CTRL_REG_INT_RT_STS
, &int_sts
);
830 dev_err(wled
->dev
, "Error in reading WLED3_INT_RT_STS rc=%d\n",
835 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
836 WLED3_CTRL_REG_FAULT_STATUS
, &fault_sts
);
838 dev_err(wled
->dev
, "Error in reading WLED_FAULT_STATUS rc=%d\n",
843 if (fault_sts
& (WLED3_CTRL_REG_OVP_FAULT_BIT
|
844 WLED3_CTRL_REG_ILIM_FAULT_BIT
))
845 dev_dbg(wled
->dev
, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
848 if (fault_sts
& WLED3_CTRL_REG_OVP_FAULT_BIT
) {
849 if (wled
->wled_auto_detection_required(wled
)) {
850 mutex_lock(&wled
->lock
);
851 wled_auto_string_detection(wled
);
852 mutex_unlock(&wled
->lock
);
859 static int wled3_setup(struct wled
*wled
)
865 rc
= regmap_update_bits(wled
->regmap
,
866 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
867 WLED3_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
871 rc
= regmap_update_bits(wled
->regmap
,
872 wled
->ctrl_addr
+ WLED3_CTRL_REG_ILIMIT
,
873 WLED3_CTRL_REG_ILIMIT_MASK
,
874 wled
->cfg
.boost_i_limit
);
878 rc
= regmap_update_bits(wled
->regmap
,
879 wled
->ctrl_addr
+ WLED3_CTRL_REG_FREQ
,
880 WLED3_CTRL_REG_FREQ_MASK
,
881 wled
->cfg
.switch_freq
);
885 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
886 j
= wled
->cfg
.enabled_strings
[i
];
887 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_MOD_EN(j
);
888 rc
= regmap_update_bits(wled
->regmap
, addr
,
889 WLED3_SINK_REG_STR_MOD_MASK
,
890 WLED3_SINK_REG_STR_MOD_MASK
);
894 if (wled
->cfg
.ext_gen
) {
895 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_MOD_SRC(j
);
896 rc
= regmap_update_bits(wled
->regmap
, addr
,
897 WLED3_SINK_REG_STR_MOD_SRC_MASK
,
898 WLED3_SINK_REG_STR_MOD_SRC_EXT
);
903 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_FULL_SCALE_CURR(j
);
904 rc
= regmap_update_bits(wled
->regmap
, addr
,
905 WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK
,
906 wled
->cfg
.string_i_limit
);
910 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_CABC(j
);
911 rc
= regmap_update_bits(wled
->regmap
, addr
,
912 WLED3_SINK_REG_STR_CABC_MASK
,
914 WLED3_SINK_REG_STR_CABC_MASK
: 0);
918 sink_en
|= BIT(j
+ WLED3_SINK_REG_CURR_SINK_SHFT
);
921 rc
= regmap_update_bits(wled
->regmap
,
922 wled
->ctrl_addr
+ WLED3_SINK_REG_CURR_SINK
,
923 WLED3_SINK_REG_CURR_SINK_MASK
, sink_en
);
930 static const struct wled_config wled3_config_defaults
= {
932 .string_i_limit
= 20,
939 .enabled_strings
= {0, 1, 2, 3},
942 static int wled4_setup(struct wled
*wled
)
949 rc
= regmap_update_bits(wled
->regmap
,
950 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
951 WLED3_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
955 rc
= regmap_update_bits(wled
->regmap
,
956 wled
->ctrl_addr
+ WLED3_CTRL_REG_ILIMIT
,
957 WLED3_CTRL_REG_ILIMIT_MASK
,
958 wled
->cfg
.boost_i_limit
);
962 rc
= regmap_update_bits(wled
->regmap
,
963 wled
->ctrl_addr
+ WLED3_CTRL_REG_FREQ
,
964 WLED3_CTRL_REG_FREQ_MASK
,
965 wled
->cfg
.switch_freq
);
969 if (wled
->cfg
.external_pfet
) {
970 /* Unlock the secure register access */
971 rc
= regmap_write(wled
->regmap
, wled
->ctrl_addr
+
972 WLED4_CTRL_REG_SEC_ACCESS
,
973 WLED4_CTRL_REG_SEC_UNLOCK
);
977 rc
= regmap_write(wled
->regmap
,
978 wled
->ctrl_addr
+ WLED4_CTRL_REG_TEST1
,
979 WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2
);
984 rc
= regmap_read(wled
->regmap
, wled
->sink_addr
+
985 WLED4_SINK_REG_CURR_SINK
, &sink_cfg
);
989 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
990 j
= wled
->cfg
.enabled_strings
[i
];
991 temp
= j
+ WLED4_SINK_REG_CURR_SINK_SHFT
;
992 sink_en
|= 1 << temp
;
995 if (sink_cfg
== sink_en
) {
996 rc
= wled_auto_detection_at_init(wled
);
1000 rc
= regmap_update_bits(wled
->regmap
,
1001 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
1002 WLED4_SINK_REG_CURR_SINK_MASK
, 0);
1006 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
1007 WLED3_CTRL_REG_MOD_EN
,
1008 WLED3_CTRL_REG_MOD_EN_MASK
, 0);
1012 /* Per sink/string configuration */
1013 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
1014 j
= wled
->cfg
.enabled_strings
[i
];
1016 addr
= wled
->sink_addr
+
1017 WLED4_SINK_REG_STR_MOD_EN(j
);
1018 rc
= regmap_update_bits(wled
->regmap
, addr
,
1019 WLED4_SINK_REG_STR_MOD_MASK
,
1020 WLED4_SINK_REG_STR_MOD_MASK
);
1024 addr
= wled
->sink_addr
+
1025 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j
);
1026 rc
= regmap_update_bits(wled
->regmap
, addr
,
1027 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK
,
1028 wled
->cfg
.string_i_limit
);
1033 rc
= wled4_cabc_config(wled
, wled
->cfg
.cabc
);
1037 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
1038 WLED3_CTRL_REG_MOD_EN
,
1039 WLED3_CTRL_REG_MOD_EN_MASK
,
1040 WLED3_CTRL_REG_MOD_EN_MASK
);
1044 rc
= regmap_update_bits(wled
->regmap
,
1045 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
1046 WLED4_SINK_REG_CURR_SINK_MASK
, sink_en
);
1050 rc
= wled
->wled_sync_toggle(wled
);
1052 dev_err(wled
->dev
, "Failed to toggle sync reg rc:%d\n", rc
);
1056 rc
= wled_auto_detection_at_init(wled
);
1061 static const struct wled_config wled4_config_defaults
= {
1063 .string_i_limit
= 10,
1068 .external_pfet
= false,
1069 .auto_detection_enabled
= false,
1072 static int wled5_setup(struct wled
*wled
)
1074 int rc
, temp
, i
, j
, offset
;
1079 rc
= regmap_update_bits(wled
->regmap
,
1080 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
1081 WLED5_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
1085 rc
= regmap_update_bits(wled
->regmap
,
1086 wled
->ctrl_addr
+ WLED3_CTRL_REG_ILIMIT
,
1087 WLED3_CTRL_REG_ILIMIT_MASK
,
1088 wled
->cfg
.boost_i_limit
);
1092 rc
= regmap_update_bits(wled
->regmap
,
1093 wled
->ctrl_addr
+ WLED3_CTRL_REG_FREQ
,
1094 WLED3_CTRL_REG_FREQ_MASK
,
1095 wled
->cfg
.switch_freq
);
1099 /* Per sink/string configuration */
1100 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
1101 j
= wled
->cfg
.enabled_strings
[i
];
1102 addr
= wled
->sink_addr
+
1103 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j
);
1104 rc
= regmap_update_bits(wled
->regmap
, addr
,
1105 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK
,
1106 wled
->cfg
.string_i_limit
);
1110 addr
= wled
->sink_addr
+ WLED5_SINK_REG_STR_SRC_SEL(j
);
1111 rc
= regmap_update_bits(wled
->regmap
, addr
,
1112 WLED5_SINK_REG_SRC_SEL_MASK
,
1113 wled
->cfg
.mod_sel
== MOD_A
?
1114 WLED5_SINK_REG_SRC_SEL_MOD_A
:
1115 WLED5_SINK_REG_SRC_SEL_MOD_B
);
1117 temp
= j
+ WLED4_SINK_REG_CURR_SINK_SHFT
;
1118 sink_en
|= 1 << temp
;
1121 rc
= wled5_cabc_config(wled
, wled
->cfg
.cabc_sel
? true : false);
1125 /* Enable one of the modulators A or B based on mod_sel */
1126 addr
= wled
->sink_addr
+ WLED5_SINK_REG_MOD_A_EN
;
1127 val
= (wled
->cfg
.mod_sel
== MOD_A
) ? WLED5_SINK_REG_MOD_EN_MASK
: 0;
1128 rc
= regmap_update_bits(wled
->regmap
, addr
,
1129 WLED5_SINK_REG_MOD_EN_MASK
, val
);
1133 addr
= wled
->sink_addr
+ WLED5_SINK_REG_MOD_B_EN
;
1134 val
= (wled
->cfg
.mod_sel
== MOD_B
) ? WLED5_SINK_REG_MOD_EN_MASK
: 0;
1135 rc
= regmap_update_bits(wled
->regmap
, addr
,
1136 WLED5_SINK_REG_MOD_EN_MASK
, val
);
1140 offset
= (wled
->cfg
.mod_sel
== MOD_A
) ?
1141 WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL
:
1142 WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL
;
1144 addr
= wled
->sink_addr
+ offset
;
1145 val
= (wled
->max_brightness
== WLED5_SINK_REG_BRIGHT_MAX_15B
) ?
1146 WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B
:
1147 WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B
;
1148 rc
= regmap_write(wled
->regmap
, addr
, val
);
1152 rc
= regmap_update_bits(wled
->regmap
,
1153 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
1154 WLED4_SINK_REG_CURR_SINK_MASK
, sink_en
);
1158 /* This updates only FSC configuration in WLED5 */
1159 rc
= wled
->wled_sync_toggle(wled
);
1161 pr_err("Failed to toggle sync reg rc:%d\n", rc
);
1165 rc
= wled_auto_detection_at_init(wled
);
1172 static const struct wled_config wled5_config_defaults
= {
1174 .string_i_limit
= 10,
1181 .external_pfet
= false,
1182 .auto_detection_enabled
= false,
1185 static const u32 wled3_boost_i_limit_values
[] = {
1186 105, 385, 525, 805, 980, 1260, 1400, 1680,
1189 static const struct wled_var_cfg wled3_boost_i_limit_cfg
= {
1190 .values
= wled3_boost_i_limit_values
,
1191 .size
= ARRAY_SIZE(wled3_boost_i_limit_values
),
1194 static const u32 wled4_boost_i_limit_values
[] = {
1195 105, 280, 450, 620, 970, 1150, 1300, 1500,
1198 static const struct wled_var_cfg wled4_boost_i_limit_cfg
= {
1199 .values
= wled4_boost_i_limit_values
,
1200 .size
= ARRAY_SIZE(wled4_boost_i_limit_values
),
1203 static inline u32
wled5_boost_i_limit_values_fn(u32 idx
)
1205 return 525 + (idx
* 175);
1208 static const struct wled_var_cfg wled5_boost_i_limit_cfg
= {
1209 .fn
= wled5_boost_i_limit_values_fn
,
1213 static const u32 wled3_ovp_values
[] = {
1217 static const struct wled_var_cfg wled3_ovp_cfg
= {
1218 .values
= wled3_ovp_values
,
1219 .size
= ARRAY_SIZE(wled3_ovp_values
),
1222 static const u32 wled4_ovp_values
[] = {
1223 31100, 29600, 19600, 18100,
1226 static const struct wled_var_cfg wled4_ovp_cfg
= {
1227 .values
= wled4_ovp_values
,
1228 .size
= ARRAY_SIZE(wled4_ovp_values
),
1231 static inline u32
wled5_ovp_values_fn(u32 idx
)
1238 return 38500 - (idx
* 1500);
1241 static const struct wled_var_cfg wled5_ovp_cfg
= {
1242 .fn
= wled5_ovp_values_fn
,
1246 static u32
wled3_num_strings_values_fn(u32 idx
)
1251 static const struct wled_var_cfg wled3_num_strings_cfg
= {
1252 .fn
= wled3_num_strings_values_fn
,
1256 static const struct wled_var_cfg wled4_num_strings_cfg
= {
1257 .fn
= wled3_num_strings_values_fn
,
1261 static u32
wled3_switch_freq_values_fn(u32 idx
)
1263 return 19200 / (2 * (1 + idx
));
1266 static const struct wled_var_cfg wled3_switch_freq_cfg
= {
1267 .fn
= wled3_switch_freq_values_fn
,
1271 static const struct wled_var_cfg wled3_string_i_limit_cfg
= {
1275 static const u32 wled4_string_i_limit_values
[] = {
1276 0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000,
1277 22500, 25000, 27500, 30000,
1280 static const struct wled_var_cfg wled4_string_i_limit_cfg
= {
1281 .values
= wled4_string_i_limit_values
,
1282 .size
= ARRAY_SIZE(wled4_string_i_limit_values
),
1285 static const struct wled_var_cfg wled5_mod_sel_cfg
= {
1289 static const struct wled_var_cfg wled5_cabc_sel_cfg
= {
1293 static u32
wled_values(const struct wled_var_cfg
*cfg
, u32 idx
)
1295 if (idx
>= cfg
->size
)
1298 return cfg
->fn(idx
);
1300 return cfg
->values
[idx
];
1304 static int wled_configure(struct wled
*wled
)
1306 struct wled_config
*cfg
= &wled
->cfg
;
1307 struct device
*dev
= wled
->dev
;
1308 const __be32
*prop_addr
;
1310 int rc
, i
, j
, string_len
;
1312 const struct wled_u32_opts
*u32_opts
= NULL
;
1313 const struct wled_u32_opts wled3_opts
[] = {
1315 .name
= "qcom,current-boost-limit",
1316 .val_ptr
= &cfg
->boost_i_limit
,
1317 .cfg
= &wled3_boost_i_limit_cfg
,
1320 .name
= "qcom,current-limit",
1321 .val_ptr
= &cfg
->string_i_limit
,
1322 .cfg
= &wled3_string_i_limit_cfg
,
1326 .val_ptr
= &cfg
->ovp
,
1327 .cfg
= &wled3_ovp_cfg
,
1330 .name
= "qcom,switching-freq",
1331 .val_ptr
= &cfg
->switch_freq
,
1332 .cfg
= &wled3_switch_freq_cfg
,
1335 .name
= "qcom,num-strings",
1336 .val_ptr
= &cfg
->num_strings
,
1337 .cfg
= &wled3_num_strings_cfg
,
1341 const struct wled_u32_opts wled4_opts
[] = {
1343 .name
= "qcom,current-boost-limit",
1344 .val_ptr
= &cfg
->boost_i_limit
,
1345 .cfg
= &wled4_boost_i_limit_cfg
,
1348 .name
= "qcom,current-limit-microamp",
1349 .val_ptr
= &cfg
->string_i_limit
,
1350 .cfg
= &wled4_string_i_limit_cfg
,
1353 .name
= "qcom,ovp-millivolt",
1354 .val_ptr
= &cfg
->ovp
,
1355 .cfg
= &wled4_ovp_cfg
,
1358 .name
= "qcom,switching-freq",
1359 .val_ptr
= &cfg
->switch_freq
,
1360 .cfg
= &wled3_switch_freq_cfg
,
1363 .name
= "qcom,num-strings",
1364 .val_ptr
= &cfg
->num_strings
,
1365 .cfg
= &wled4_num_strings_cfg
,
1369 const struct wled_u32_opts wled5_opts
[] = {
1371 .name
= "qcom,current-boost-limit",
1372 .val_ptr
= &cfg
->boost_i_limit
,
1373 .cfg
= &wled5_boost_i_limit_cfg
,
1376 .name
= "qcom,current-limit-microamp",
1377 .val_ptr
= &cfg
->string_i_limit
,
1378 .cfg
= &wled4_string_i_limit_cfg
,
1381 .name
= "qcom,ovp-millivolt",
1382 .val_ptr
= &cfg
->ovp
,
1383 .cfg
= &wled5_ovp_cfg
,
1386 .name
= "qcom,switching-freq",
1387 .val_ptr
= &cfg
->switch_freq
,
1388 .cfg
= &wled3_switch_freq_cfg
,
1391 .name
= "qcom,num-strings",
1392 .val_ptr
= &cfg
->num_strings
,
1393 .cfg
= &wled4_num_strings_cfg
,
1396 .name
= "qcom,modulator-sel",
1397 .val_ptr
= &cfg
->mod_sel
,
1398 .cfg
= &wled5_mod_sel_cfg
,
1401 .name
= "qcom,cabc-sel",
1402 .val_ptr
= &cfg
->cabc_sel
,
1403 .cfg
= &wled5_cabc_sel_cfg
,
1407 const struct wled_bool_opts bool_opts
[] = {
1408 { "qcom,cs-out", &cfg
->cs_out_en
, },
1409 { "qcom,ext-gen", &cfg
->ext_gen
, },
1410 { "qcom,cabc", &cfg
->cabc
, },
1411 { "qcom,external-pfet", &cfg
->external_pfet
, },
1412 { "qcom,auto-string-detection", &cfg
->auto_detection_enabled
, },
1415 prop_addr
= of_get_address(dev
->of_node
, 0, NULL
, NULL
);
1417 dev_err(wled
->dev
, "invalid IO resources\n");
1420 wled
->ctrl_addr
= be32_to_cpu(*prop_addr
);
1422 rc
= of_property_read_string(dev
->of_node
, "label", &wled
->name
);
1424 wled
->name
= devm_kasprintf(dev
, GFP_KERNEL
, "%pOFn", dev
->of_node
);
1426 switch (wled
->version
) {
1428 u32_opts
= wled3_opts
;
1429 size
= ARRAY_SIZE(wled3_opts
);
1430 *cfg
= wled3_config_defaults
;
1431 wled
->wled_set_brightness
= wled3_set_brightness
;
1432 wled
->wled_sync_toggle
= wled3_sync_toggle
;
1433 wled
->max_string_count
= 3;
1434 wled
->sink_addr
= wled
->ctrl_addr
;
1438 u32_opts
= wled4_opts
;
1439 size
= ARRAY_SIZE(wled4_opts
);
1440 *cfg
= wled4_config_defaults
;
1441 wled
->wled_set_brightness
= wled4_set_brightness
;
1442 wled
->wled_sync_toggle
= wled3_sync_toggle
;
1443 wled
->wled_cabc_config
= wled4_cabc_config
;
1444 wled
->wled_ovp_delay
= wled4_ovp_delay
;
1445 wled
->wled_auto_detection_required
=
1446 wled4_auto_detection_required
;
1447 wled
->max_string_count
= 4;
1449 prop_addr
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
1451 dev_err(wled
->dev
, "invalid IO resources\n");
1454 wled
->sink_addr
= be32_to_cpu(*prop_addr
);
1458 u32_opts
= wled5_opts
;
1459 size
= ARRAY_SIZE(wled5_opts
);
1460 *cfg
= wled5_config_defaults
;
1461 wled
->wled_set_brightness
= wled5_set_brightness
;
1462 wled
->wled_sync_toggle
= wled5_sync_toggle
;
1463 wled
->wled_cabc_config
= wled5_cabc_config
;
1464 wled
->wled_ovp_delay
= wled5_ovp_delay
;
1465 wled
->wled_auto_detection_required
=
1466 wled5_auto_detection_required
;
1467 wled
->max_string_count
= 4;
1469 prop_addr
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
1471 dev_err(wled
->dev
, "invalid IO resources\n");
1474 wled
->sink_addr
= be32_to_cpu(*prop_addr
);
1478 dev_err(wled
->dev
, "Invalid WLED version\n");
1482 for (i
= 0; i
< size
; ++i
) {
1483 rc
= of_property_read_u32(dev
->of_node
, u32_opts
[i
].name
, &val
);
1484 if (rc
== -EINVAL
) {
1487 dev_err(dev
, "error reading '%s'\n", u32_opts
[i
].name
);
1492 for (j
= 0; c
!= val
; j
++) {
1493 c
= wled_values(u32_opts
[i
].cfg
, j
);
1494 if (c
== UINT_MAX
) {
1495 dev_err(dev
, "invalid value for '%s'\n",
1504 dev_dbg(dev
, "'%s' = %u\n", u32_opts
[i
].name
, c
);
1505 *u32_opts
[i
].val_ptr
= j
;
1508 for (i
= 0; i
< ARRAY_SIZE(bool_opts
); ++i
) {
1509 if (of_property_read_bool(dev
->of_node
, bool_opts
[i
].name
))
1510 *bool_opts
[i
].val_ptr
= true;
1513 cfg
->num_strings
= cfg
->num_strings
+ 1;
1515 string_len
= of_property_count_elems_of_size(dev
->of_node
,
1516 "qcom,enabled-strings",
1519 of_property_read_u32_array(dev
->of_node
,
1520 "qcom,enabled-strings",
1521 wled
->cfg
.enabled_strings
,
1527 static int wled_configure_short_irq(struct wled
*wled
,
1528 struct platform_device
*pdev
)
1532 if (!wled
->has_short_detect
)
1535 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
1536 WLED4_CTRL_REG_SHORT_PROTECT
,
1537 WLED4_CTRL_REG_SHORT_EN_MASK
,
1538 WLED4_CTRL_REG_SHORT_EN_MASK
);
1542 wled
->short_irq
= platform_get_irq_byname(pdev
, "short");
1543 if (wled
->short_irq
< 0) {
1544 dev_dbg(&pdev
->dev
, "short irq is not used\n");
1548 rc
= devm_request_threaded_irq(wled
->dev
, wled
->short_irq
,
1549 NULL
, wled_short_irq_handler
,
1551 "wled_short_irq", wled
);
1553 dev_err(wled
->dev
, "Unable to request short_irq (err:%d)\n",
1559 static int wled_configure_ovp_irq(struct wled
*wled
,
1560 struct platform_device
*pdev
)
1565 wled
->ovp_irq
= platform_get_irq_byname(pdev
, "ovp");
1566 if (wled
->ovp_irq
< 0) {
1567 dev_dbg(&pdev
->dev
, "OVP IRQ not found - disabling automatic string detection\n");
1571 rc
= devm_request_threaded_irq(wled
->dev
, wled
->ovp_irq
, NULL
,
1572 wled_ovp_irq_handler
, IRQF_ONESHOT
,
1573 "wled_ovp_irq", wled
);
1575 dev_err(wled
->dev
, "Unable to request ovp_irq (err:%d)\n",
1581 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
1582 WLED3_CTRL_REG_MOD_EN
, &val
);
1586 /* Keep OVP irq disabled until module is enabled */
1587 if (!(val
& WLED3_CTRL_REG_MOD_EN_MASK
))
1588 disable_irq(wled
->ovp_irq
);
1593 static const struct backlight_ops wled_ops
= {
1594 .update_status
= wled_update_status
,
1597 static int wled_probe(struct platform_device
*pdev
)
1599 struct backlight_properties props
;
1600 struct backlight_device
*bl
;
1602 struct regmap
*regmap
;
1606 regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
1608 dev_err(&pdev
->dev
, "Unable to get regmap\n");
1612 wled
= devm_kzalloc(&pdev
->dev
, sizeof(*wled
), GFP_KERNEL
);
1616 wled
->regmap
= regmap
;
1617 wled
->dev
= &pdev
->dev
;
1619 wled
->version
= (uintptr_t)of_device_get_match_data(&pdev
->dev
);
1620 if (!wled
->version
) {
1621 dev_err(&pdev
->dev
, "Unknown device version\n");
1625 mutex_init(&wled
->lock
);
1626 rc
= wled_configure(wled
);
1630 val
= WLED3_SINK_REG_BRIGHT_MAX
;
1631 of_property_read_u32(pdev
->dev
.of_node
, "max-brightness", &val
);
1632 wled
->max_brightness
= val
;
1634 switch (wled
->version
) {
1636 wled
->cfg
.auto_detection_enabled
= false;
1637 rc
= wled3_setup(wled
);
1639 dev_err(&pdev
->dev
, "wled3_setup failed\n");
1645 wled
->has_short_detect
= true;
1646 rc
= wled4_setup(wled
);
1648 dev_err(&pdev
->dev
, "wled4_setup failed\n");
1654 wled
->has_short_detect
= true;
1655 if (wled
->cfg
.cabc_sel
)
1656 wled
->max_brightness
= WLED5_SINK_REG_BRIGHT_MAX_12B
;
1658 rc
= wled5_setup(wled
);
1660 dev_err(&pdev
->dev
, "wled5_setup failed\n");
1666 dev_err(wled
->dev
, "Invalid WLED version\n");
1670 INIT_DELAYED_WORK(&wled
->ovp_work
, wled_ovp_work
);
1672 rc
= wled_configure_short_irq(wled
, pdev
);
1676 rc
= wled_configure_ovp_irq(wled
, pdev
);
1680 val
= WLED_DEFAULT_BRIGHTNESS
;
1681 of_property_read_u32(pdev
->dev
.of_node
, "default-brightness", &val
);
1683 memset(&props
, 0, sizeof(struct backlight_properties
));
1684 props
.type
= BACKLIGHT_RAW
;
1685 props
.brightness
= val
;
1686 props
.max_brightness
= wled
->max_brightness
;
1687 bl
= devm_backlight_device_register(&pdev
->dev
, wled
->name
,
1690 return PTR_ERR_OR_ZERO(bl
);
1693 static int wled_remove(struct platform_device
*pdev
)
1695 struct wled
*wled
= dev_get_drvdata(&pdev
->dev
);
1697 mutex_destroy(&wled
->lock
);
1698 cancel_delayed_work_sync(&wled
->ovp_work
);
1699 disable_irq(wled
->short_irq
);
1700 disable_irq(wled
->ovp_irq
);
1705 static const struct of_device_id wled_match_table
[] = {
1706 { .compatible
= "qcom,pm8941-wled", .data
= (void *)3 },
1707 { .compatible
= "qcom,pmi8998-wled", .data
= (void *)4 },
1708 { .compatible
= "qcom,pm660l-wled", .data
= (void *)4 },
1709 { .compatible
= "qcom,pm8150l-wled", .data
= (void *)5 },
1712 MODULE_DEVICE_TABLE(of
, wled_match_table
);
1714 static struct platform_driver wled_driver
= {
1715 .probe
= wled_probe
,
1716 .remove
= wled_remove
,
1718 .name
= "qcom,wled",
1719 .of_match_table
= wled_match_table
,
1723 module_platform_driver(wled_driver
);
1725 MODULE_DESCRIPTION("Qualcomm WLED driver");
1726 MODULE_LICENSE("GPL v2");