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_address.h>
13 #include <linux/platform_device.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
= cpu_to_le16(brightness
& WLED3_SINK_REG_BRIGHT_MAX
);
238 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
239 rc
= regmap_bulk_write(wled
->regmap
, wled
->ctrl_addr
+
240 WLED3_SINK_REG_BRIGHT(wled
->cfg
.enabled_strings
[i
]),
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
= cpu_to_le16(brightness
& WLED3_SINK_REG_BRIGHT_MAX
);
261 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
262 rc
= regmap_bulk_write(wled
->regmap
, wled
->sink_addr
+
263 WLED4_SINK_REG_BRIGHT(wled
->cfg
.enabled_strings
[i
]),
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
= cpu_to_le16(brightness
& WLED5_SINK_REG_BRIGHT_MAX_15B
);
284 offset
= (wled
->cfg
.mod_sel
== MOD_A
) ?
285 WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB
:
286 WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB
;
288 rc
= regmap_bulk_write(wled
->regmap
, wled
->sink_addr
+ offset
,
293 static void wled_ovp_work(struct work_struct
*work
)
295 struct wled
*wled
= container_of(work
,
296 struct wled
, ovp_work
.work
);
297 enable_irq(wled
->ovp_irq
);
300 static int wled_module_enable(struct wled
*wled
, int val
)
304 if (wled
->disabled_by_short
)
307 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
308 WLED3_CTRL_REG_MOD_EN
,
309 WLED3_CTRL_REG_MOD_EN_MASK
,
310 val
<< WLED3_CTRL_REG_MOD_EN_SHIFT
);
314 if (wled
->ovp_irq
> 0) {
317 * The hardware generates a storm of spurious OVP
318 * interrupts during soft start operations. So defer
319 * enabling the IRQ for 10ms to ensure that the
320 * soft start is complete.
322 schedule_delayed_work(&wled
->ovp_work
, HZ
/ 100);
324 if (!cancel_delayed_work_sync(&wled
->ovp_work
))
325 disable_irq(wled
->ovp_irq
);
332 static int wled3_sync_toggle(struct wled
*wled
)
335 unsigned int mask
= GENMASK(wled
->max_string_count
- 1, 0);
337 rc
= regmap_update_bits(wled
->regmap
,
338 wled
->sink_addr
+ WLED3_SINK_REG_SYNC
,
339 mask
, WLED3_SINK_REG_SYNC_CLEAR
);
343 rc
= regmap_update_bits(wled
->regmap
,
344 wled
->sink_addr
+ WLED3_SINK_REG_SYNC
,
350 static int wled5_mod_sync_toggle(struct wled
*wled
)
355 rc
= regmap_update_bits(wled
->regmap
,
356 wled
->sink_addr
+ WLED5_SINK_REG_MOD_SYNC_BIT
,
357 WLED5_SINK_REG_SYNC_MASK
, 0);
361 val
= (wled
->cfg
.mod_sel
== MOD_A
) ? WLED5_SINK_REG_SYNC_MOD_A_BIT
:
362 WLED5_SINK_REG_SYNC_MOD_B_BIT
;
363 return regmap_update_bits(wled
->regmap
,
364 wled
->sink_addr
+ WLED5_SINK_REG_MOD_SYNC_BIT
,
365 WLED5_SINK_REG_SYNC_MASK
, val
);
368 static int wled_ovp_fault_status(struct wled
*wled
, bool *fault_set
)
371 u32 int_rt_sts
, fault_sts
;
374 rc
= regmap_read(wled
->regmap
,
375 wled
->ctrl_addr
+ WLED3_CTRL_REG_INT_RT_STS
,
378 dev_err(wled
->dev
, "Failed to read INT_RT_STS rc=%d\n", rc
);
382 rc
= regmap_read(wled
->regmap
,
383 wled
->ctrl_addr
+ WLED3_CTRL_REG_FAULT_STATUS
,
386 dev_err(wled
->dev
, "Failed to read FAULT_STATUS rc=%d\n", rc
);
390 if (int_rt_sts
& WLED3_CTRL_REG_OVP_FAULT_STATUS
)
393 if (wled
->version
== 4 && (fault_sts
& WLED3_CTRL_REG_OVP_FAULT_BIT
))
396 if (wled
->version
== 5 && (fault_sts
& (WLED3_CTRL_REG_OVP_FAULT_BIT
|
397 WLED5_CTRL_REG_OVP_PRE_ALARM_BIT
)))
401 dev_dbg(wled
->dev
, "WLED OVP fault detected, int_rt_sts=0x%x fault_sts=0x%x\n",
402 int_rt_sts
, fault_sts
);
407 static int wled4_ovp_delay(struct wled
*wled
)
409 return WLED_SOFT_START_DLY_US
;
412 static int wled5_ovp_delay(struct wled
*wled
)
416 u8 ovp_timer_ms
[8] = {1, 2, 4, 8, 12, 16, 20, 24};
418 /* For WLED5, get the delay based on OVP timer */
419 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
420 WLED5_CTRL_REG_OVP_INT_CTL
, &val
);
423 ovp_timer_ms
[val
& WLED5_CTRL_REG_OVP_INT_TIMER_MASK
] * 1000;
425 delay_us
= 2 * WLED_SOFT_START_DLY_US
;
427 dev_dbg(wled
->dev
, "delay_time_us: %d\n", delay_us
);
432 static int wled_update_status(struct backlight_device
*bl
)
434 struct wled
*wled
= bl_get_data(bl
);
435 u16 brightness
= backlight_get_brightness(bl
);
438 mutex_lock(&wled
->lock
);
440 rc
= wled
->wled_set_brightness(wled
, brightness
);
442 dev_err(wled
->dev
, "wled failed to set brightness rc:%d\n",
447 if (wled
->version
< 5) {
448 rc
= wled
->wled_sync_toggle(wled
);
450 dev_err(wled
->dev
, "wled sync failed rc:%d\n", rc
);
455 * For WLED5 toggling the MOD_SYNC_BIT updates the
458 rc
= wled5_mod_sync_toggle(wled
);
460 dev_err(wled
->dev
, "wled mod sync failed rc:%d\n",
467 if (!!brightness
!= !!wled
->brightness
) {
468 rc
= wled_module_enable(wled
, !!brightness
);
470 dev_err(wled
->dev
, "wled enable failed rc:%d\n", rc
);
475 wled
->brightness
= brightness
;
478 mutex_unlock(&wled
->lock
);
483 static int wled4_cabc_config(struct wled
*wled
, bool enable
)
488 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
489 j
= wled
->cfg
.enabled_strings
[i
];
491 val
= enable
? WLED4_SINK_REG_STR_CABC_MASK
: 0;
492 rc
= regmap_update_bits(wled
->regmap
, wled
->sink_addr
+
493 WLED4_SINK_REG_STR_CABC(j
),
494 WLED4_SINK_REG_STR_CABC_MASK
, val
);
502 static int wled5_cabc_config(struct wled
*wled
, bool enable
)
507 if (wled
->cabc_disabled
)
510 reg
= enable
? wled
->cfg
.cabc_sel
: 0;
511 offset
= (wled
->cfg
.mod_sel
== MOD_A
) ? WLED5_SINK_REG_MOD_A_SRC_SEL
:
512 WLED5_SINK_REG_MOD_B_SRC_SEL
;
514 rc
= regmap_update_bits(wled
->regmap
, wled
->sink_addr
+ offset
,
515 WLED5_SINK_REG_MOD_SRC_SEL_MASK
, reg
);
517 pr_err("Error in configuring CABC rc=%d\n", rc
);
521 if (!wled
->cfg
.cabc_sel
)
522 wled
->cabc_disabled
= true;
527 #define WLED_SHORT_DLY_MS 20
528 #define WLED_SHORT_CNT_MAX 5
529 #define WLED_SHORT_RESET_CNT_DLY_US USEC_PER_SEC
531 static irqreturn_t
wled_short_irq_handler(int irq
, void *_wled
)
533 struct wled
*wled
= _wled
;
538 mutex_lock(&wled
->lock
);
539 rc
= wled_module_enable(wled
, false);
541 dev_err(wled
->dev
, "wled disable failed rc:%d\n", rc
);
545 elapsed_time
= ktime_us_delta(ktime_get(),
546 wled
->last_short_event
);
547 if (elapsed_time
> WLED_SHORT_RESET_CNT_DLY_US
)
548 wled
->short_count
= 1;
550 if (wled
->short_count
> WLED_SHORT_CNT_MAX
) {
551 dev_err(wled
->dev
, "Short triggered %d times, disabling WLED forever!\n",
553 wled
->disabled_by_short
= true;
557 wled
->last_short_event
= ktime_get();
559 msleep(WLED_SHORT_DLY_MS
);
560 rc
= wled_module_enable(wled
, true);
562 dev_err(wled
->dev
, "wled enable failed rc:%d\n", rc
);
565 mutex_unlock(&wled
->lock
);
570 #define AUTO_DETECT_BRIGHTNESS 200
572 static void wled_auto_string_detection(struct wled
*wled
)
574 int rc
= 0, i
, j
, delay_time_us
;
576 u8 sink_test
= 0, sink_valid
= 0, val
;
579 /* Read configured sink configuration */
580 rc
= regmap_read(wled
->regmap
, wled
->sink_addr
+
581 WLED4_SINK_REG_CURR_SINK
, &sink_config
);
583 dev_err(wled
->dev
, "Failed to read SINK configuration rc=%d\n",
588 /* Disable the module before starting detection */
589 rc
= regmap_update_bits(wled
->regmap
,
590 wled
->ctrl_addr
+ WLED3_CTRL_REG_MOD_EN
,
591 WLED3_CTRL_REG_MOD_EN_MASK
, 0);
593 dev_err(wled
->dev
, "Failed to disable WLED module rc=%d\n", rc
);
597 /* Set low brightness across all sinks */
598 rc
= wled4_set_brightness(wled
, AUTO_DETECT_BRIGHTNESS
);
600 dev_err(wled
->dev
, "Failed to set brightness for auto detection rc=%d\n",
605 if (wled
->cfg
.cabc
) {
606 rc
= wled
->wled_cabc_config(wled
, false);
611 /* Disable all sinks */
612 rc
= regmap_write(wled
->regmap
,
613 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
, 0);
615 dev_err(wled
->dev
, "Failed to disable all sinks rc=%d\n", rc
);
619 /* Iterate through the strings one by one */
620 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
621 j
= wled
->cfg
.enabled_strings
[i
];
622 sink_test
= BIT((WLED4_SINK_REG_CURR_SINK_SHFT
+ j
));
624 /* Enable feedback control */
625 rc
= regmap_write(wled
->regmap
, wled
->ctrl_addr
+
626 WLED3_CTRL_REG_FEEDBACK_CONTROL
, j
+ 1);
628 dev_err(wled
->dev
, "Failed to enable feedback for SINK %d rc = %d\n",
633 /* Enable the sink */
634 rc
= regmap_write(wled
->regmap
, wled
->sink_addr
+
635 WLED4_SINK_REG_CURR_SINK
, sink_test
);
637 dev_err(wled
->dev
, "Failed to configure SINK %d rc=%d\n",
642 /* Enable the module */
643 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
644 WLED3_CTRL_REG_MOD_EN
,
645 WLED3_CTRL_REG_MOD_EN_MASK
,
646 WLED3_CTRL_REG_MOD_EN_MASK
);
648 dev_err(wled
->dev
, "Failed to enable WLED module rc=%d\n",
653 delay_time_us
= wled
->wled_ovp_delay(wled
);
654 usleep_range(delay_time_us
, delay_time_us
+ 1000);
656 rc
= wled_ovp_fault_status(wled
, &fault_set
);
658 dev_err(wled
->dev
, "Error in getting OVP fault_sts, rc=%d\n",
664 dev_dbg(wled
->dev
, "WLED OVP fault detected with SINK %d\n",
667 sink_valid
|= sink_test
;
669 /* Disable the module */
670 rc
= regmap_update_bits(wled
->regmap
,
671 wled
->ctrl_addr
+ WLED3_CTRL_REG_MOD_EN
,
672 WLED3_CTRL_REG_MOD_EN_MASK
, 0);
674 dev_err(wled
->dev
, "Failed to disable WLED module rc=%d\n",
681 dev_err(wled
->dev
, "No valid WLED sinks found\n");
682 wled
->disabled_by_short
= true;
686 if (sink_valid
!= sink_config
) {
687 dev_warn(wled
->dev
, "%x is not a valid sink configuration - using %x instead\n",
688 sink_config
, sink_valid
);
689 sink_config
= sink_valid
;
692 /* Write the new sink configuration */
693 rc
= regmap_write(wled
->regmap
,
694 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
697 dev_err(wled
->dev
, "Failed to reconfigure the default sink rc=%d\n",
702 /* Enable valid sinks */
703 if (wled
->version
== 4) {
704 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
705 j
= wled
->cfg
.enabled_strings
[i
];
707 BIT(WLED4_SINK_REG_CURR_SINK_SHFT
+ j
))
708 val
= WLED4_SINK_REG_STR_MOD_MASK
;
710 /* Disable modulator_en for unused sink */
713 rc
= regmap_write(wled
->regmap
, wled
->sink_addr
+
714 WLED4_SINK_REG_STR_MOD_EN(j
), val
);
716 dev_err(wled
->dev
, "Failed to configure MODULATOR_EN rc=%d\n",
724 rc
= wled
->wled_cabc_config(wled
, true);
728 /* Restore the feedback setting */
729 rc
= regmap_write(wled
->regmap
,
730 wled
->ctrl_addr
+ WLED3_CTRL_REG_FEEDBACK_CONTROL
, 0);
732 dev_err(wled
->dev
, "Failed to restore feedback setting rc=%d\n",
737 /* Restore brightness */
738 rc
= wled4_set_brightness(wled
, wled
->brightness
);
740 dev_err(wled
->dev
, "Failed to set brightness after auto detection rc=%d\n",
745 rc
= regmap_update_bits(wled
->regmap
,
746 wled
->ctrl_addr
+ WLED3_CTRL_REG_MOD_EN
,
747 WLED3_CTRL_REG_MOD_EN_MASK
,
748 WLED3_CTRL_REG_MOD_EN_MASK
);
750 dev_err(wled
->dev
, "Failed to enable WLED module rc=%d\n", rc
);
758 #define WLED_AUTO_DETECT_OVP_COUNT 5
759 #define WLED_AUTO_DETECT_CNT_DLY_US USEC_PER_SEC
761 static bool wled4_auto_detection_required(struct wled
*wled
)
765 if (!wled
->cfg
.auto_detection_enabled
)
769 * Check if the OVP fault was an occasional one
770 * or if it's firing continuously, the latter qualifies
771 * for an auto-detection check.
773 if (!wled
->auto_detection_ovp_count
) {
774 wled
->start_ovp_fault_time
= ktime_get();
775 wled
->auto_detection_ovp_count
++;
777 elapsed_time_us
= ktime_us_delta(ktime_get(),
778 wled
->start_ovp_fault_time
);
779 if (elapsed_time_us
> WLED_AUTO_DETECT_CNT_DLY_US
)
780 wled
->auto_detection_ovp_count
= 0;
782 wled
->auto_detection_ovp_count
++;
784 if (wled
->auto_detection_ovp_count
>=
785 WLED_AUTO_DETECT_OVP_COUNT
) {
786 wled
->auto_detection_ovp_count
= 0;
794 static bool wled5_auto_detection_required(struct wled
*wled
)
796 if (!wled
->cfg
.auto_detection_enabled
)
800 * Unlike WLED4, WLED5 has OVP fault density interrupt configuration
801 * i.e. to count the number of OVP alarms for a certain duration before
802 * triggering OVP fault interrupt. By default, number of OVP fault
803 * events counted before an interrupt is fired is 32 and the time
804 * interval is 12 ms. If we see one OVP fault interrupt, then that
805 * should qualify for a real OVP fault condition to run auto detection
811 static int wled_auto_detection_at_init(struct wled
*wled
)
816 if (!wled
->cfg
.auto_detection_enabled
)
819 rc
= wled_ovp_fault_status(wled
, &fault_set
);
821 dev_err(wled
->dev
, "Error in getting OVP fault_sts, rc=%d\n",
827 mutex_lock(&wled
->lock
);
828 wled_auto_string_detection(wled
);
829 mutex_unlock(&wled
->lock
);
835 static irqreturn_t
wled_ovp_irq_handler(int irq
, void *_wled
)
837 struct wled
*wled
= _wled
;
839 u32 int_sts
, fault_sts
;
841 rc
= regmap_read(wled
->regmap
,
842 wled
->ctrl_addr
+ WLED3_CTRL_REG_INT_RT_STS
, &int_sts
);
844 dev_err(wled
->dev
, "Error in reading WLED3_INT_RT_STS rc=%d\n",
849 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
850 WLED3_CTRL_REG_FAULT_STATUS
, &fault_sts
);
852 dev_err(wled
->dev
, "Error in reading WLED_FAULT_STATUS rc=%d\n",
857 if (fault_sts
& (WLED3_CTRL_REG_OVP_FAULT_BIT
|
858 WLED3_CTRL_REG_ILIM_FAULT_BIT
))
859 dev_dbg(wled
->dev
, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
862 if (fault_sts
& WLED3_CTRL_REG_OVP_FAULT_BIT
) {
863 if (wled
->wled_auto_detection_required(wled
)) {
864 mutex_lock(&wled
->lock
);
865 wled_auto_string_detection(wled
);
866 mutex_unlock(&wled
->lock
);
873 static int wled3_setup(struct wled
*wled
)
879 rc
= regmap_update_bits(wled
->regmap
,
880 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
881 WLED3_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
885 rc
= regmap_update_bits(wled
->regmap
,
886 wled
->ctrl_addr
+ WLED3_CTRL_REG_ILIMIT
,
887 WLED3_CTRL_REG_ILIMIT_MASK
,
888 wled
->cfg
.boost_i_limit
);
892 rc
= regmap_update_bits(wled
->regmap
,
893 wled
->ctrl_addr
+ WLED3_CTRL_REG_FREQ
,
894 WLED3_CTRL_REG_FREQ_MASK
,
895 wled
->cfg
.switch_freq
);
899 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
900 j
= wled
->cfg
.enabled_strings
[i
];
901 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_MOD_EN(j
);
902 rc
= regmap_update_bits(wled
->regmap
, addr
,
903 WLED3_SINK_REG_STR_MOD_MASK
,
904 WLED3_SINK_REG_STR_MOD_MASK
);
908 if (wled
->cfg
.ext_gen
) {
909 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_MOD_SRC(j
);
910 rc
= regmap_update_bits(wled
->regmap
, addr
,
911 WLED3_SINK_REG_STR_MOD_SRC_MASK
,
912 WLED3_SINK_REG_STR_MOD_SRC_EXT
);
917 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_FULL_SCALE_CURR(j
);
918 rc
= regmap_update_bits(wled
->regmap
, addr
,
919 WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK
,
920 wled
->cfg
.string_i_limit
);
924 addr
= wled
->ctrl_addr
+ WLED3_SINK_REG_STR_CABC(j
);
925 rc
= regmap_update_bits(wled
->regmap
, addr
,
926 WLED3_SINK_REG_STR_CABC_MASK
,
928 WLED3_SINK_REG_STR_CABC_MASK
: 0);
932 sink_en
|= BIT(j
+ WLED3_SINK_REG_CURR_SINK_SHFT
);
935 rc
= regmap_update_bits(wled
->regmap
,
936 wled
->ctrl_addr
+ WLED3_SINK_REG_CURR_SINK
,
937 WLED3_SINK_REG_CURR_SINK_MASK
, sink_en
);
944 static const struct wled_config wled3_config_defaults
= {
946 .string_i_limit
= 20,
953 .enabled_strings
= {0, 1, 2},
956 static int wled4_setup(struct wled
*wled
)
963 rc
= regmap_update_bits(wled
->regmap
,
964 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
965 WLED3_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
969 rc
= regmap_update_bits(wled
->regmap
,
970 wled
->ctrl_addr
+ WLED3_CTRL_REG_ILIMIT
,
971 WLED3_CTRL_REG_ILIMIT_MASK
,
972 wled
->cfg
.boost_i_limit
);
976 rc
= regmap_update_bits(wled
->regmap
,
977 wled
->ctrl_addr
+ WLED3_CTRL_REG_FREQ
,
978 WLED3_CTRL_REG_FREQ_MASK
,
979 wled
->cfg
.switch_freq
);
983 if (wled
->cfg
.external_pfet
) {
984 /* Unlock the secure register access */
985 rc
= regmap_write(wled
->regmap
, wled
->ctrl_addr
+
986 WLED4_CTRL_REG_SEC_ACCESS
,
987 WLED4_CTRL_REG_SEC_UNLOCK
);
991 rc
= regmap_write(wled
->regmap
,
992 wled
->ctrl_addr
+ WLED4_CTRL_REG_TEST1
,
993 WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2
);
998 rc
= regmap_read(wled
->regmap
, wled
->sink_addr
+
999 WLED4_SINK_REG_CURR_SINK
, &sink_cfg
);
1003 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
1004 j
= wled
->cfg
.enabled_strings
[i
];
1005 temp
= j
+ WLED4_SINK_REG_CURR_SINK_SHFT
;
1006 sink_en
|= 1 << temp
;
1009 if (sink_cfg
== sink_en
) {
1010 rc
= wled_auto_detection_at_init(wled
);
1014 rc
= regmap_update_bits(wled
->regmap
,
1015 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
1016 WLED4_SINK_REG_CURR_SINK_MASK
, 0);
1020 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
1021 WLED3_CTRL_REG_MOD_EN
,
1022 WLED3_CTRL_REG_MOD_EN_MASK
, 0);
1026 /* Per sink/string configuration */
1027 for (i
= 0; i
< wled
->cfg
.num_strings
; i
++) {
1028 j
= wled
->cfg
.enabled_strings
[i
];
1030 addr
= wled
->sink_addr
+
1031 WLED4_SINK_REG_STR_MOD_EN(j
);
1032 rc
= regmap_update_bits(wled
->regmap
, addr
,
1033 WLED4_SINK_REG_STR_MOD_MASK
,
1034 WLED4_SINK_REG_STR_MOD_MASK
);
1038 addr
= wled
->sink_addr
+
1039 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j
);
1040 rc
= regmap_update_bits(wled
->regmap
, addr
,
1041 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK
,
1042 wled
->cfg
.string_i_limit
);
1047 rc
= wled4_cabc_config(wled
, wled
->cfg
.cabc
);
1051 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
1052 WLED3_CTRL_REG_MOD_EN
,
1053 WLED3_CTRL_REG_MOD_EN_MASK
,
1054 WLED3_CTRL_REG_MOD_EN_MASK
);
1058 rc
= regmap_update_bits(wled
->regmap
,
1059 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
1060 WLED4_SINK_REG_CURR_SINK_MASK
, sink_en
);
1064 rc
= wled
->wled_sync_toggle(wled
);
1066 dev_err(wled
->dev
, "Failed to toggle sync reg rc:%d\n", rc
);
1070 rc
= wled_auto_detection_at_init(wled
);
1075 static const struct wled_config wled4_config_defaults
= {
1077 .string_i_limit
= 10,
1082 .external_pfet
= false,
1083 .auto_detection_enabled
= false,
1084 .enabled_strings
= {0, 1, 2, 3},
1087 static int wled5_setup(struct wled
*wled
)
1089 int rc
, temp
, i
, j
, offset
;
1094 rc
= regmap_update_bits(wled
->regmap
,
1095 wled
->ctrl_addr
+ WLED3_CTRL_REG_OVP
,
1096 WLED5_CTRL_REG_OVP_MASK
, wled
->cfg
.ovp
);
1100 rc
= regmap_update_bits(wled
->regmap
,
1101 wled
->ctrl_addr
+ WLED3_CTRL_REG_ILIMIT
,
1102 WLED3_CTRL_REG_ILIMIT_MASK
,
1103 wled
->cfg
.boost_i_limit
);
1107 rc
= regmap_update_bits(wled
->regmap
,
1108 wled
->ctrl_addr
+ WLED3_CTRL_REG_FREQ
,
1109 WLED3_CTRL_REG_FREQ_MASK
,
1110 wled
->cfg
.switch_freq
);
1114 /* Per sink/string configuration */
1115 for (i
= 0; i
< wled
->cfg
.num_strings
; ++i
) {
1116 j
= wled
->cfg
.enabled_strings
[i
];
1117 addr
= wled
->sink_addr
+
1118 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j
);
1119 rc
= regmap_update_bits(wled
->regmap
, addr
,
1120 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK
,
1121 wled
->cfg
.string_i_limit
);
1125 addr
= wled
->sink_addr
+ WLED5_SINK_REG_STR_SRC_SEL(j
);
1126 rc
= regmap_update_bits(wled
->regmap
, addr
,
1127 WLED5_SINK_REG_SRC_SEL_MASK
,
1128 wled
->cfg
.mod_sel
== MOD_A
?
1129 WLED5_SINK_REG_SRC_SEL_MOD_A
:
1130 WLED5_SINK_REG_SRC_SEL_MOD_B
);
1132 temp
= j
+ WLED4_SINK_REG_CURR_SINK_SHFT
;
1133 sink_en
|= 1 << temp
;
1136 rc
= wled5_cabc_config(wled
, wled
->cfg
.cabc_sel
? true : false);
1140 /* Enable one of the modulators A or B based on mod_sel */
1141 addr
= wled
->sink_addr
+ WLED5_SINK_REG_MOD_A_EN
;
1142 val
= (wled
->cfg
.mod_sel
== MOD_A
) ? WLED5_SINK_REG_MOD_EN_MASK
: 0;
1143 rc
= regmap_update_bits(wled
->regmap
, addr
,
1144 WLED5_SINK_REG_MOD_EN_MASK
, val
);
1148 addr
= wled
->sink_addr
+ WLED5_SINK_REG_MOD_B_EN
;
1149 val
= (wled
->cfg
.mod_sel
== MOD_B
) ? WLED5_SINK_REG_MOD_EN_MASK
: 0;
1150 rc
= regmap_update_bits(wled
->regmap
, addr
,
1151 WLED5_SINK_REG_MOD_EN_MASK
, val
);
1155 offset
= (wled
->cfg
.mod_sel
== MOD_A
) ?
1156 WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL
:
1157 WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL
;
1159 addr
= wled
->sink_addr
+ offset
;
1160 val
= (wled
->max_brightness
== WLED5_SINK_REG_BRIGHT_MAX_15B
) ?
1161 WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B
:
1162 WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B
;
1163 rc
= regmap_write(wled
->regmap
, addr
, val
);
1167 rc
= regmap_update_bits(wled
->regmap
,
1168 wled
->sink_addr
+ WLED4_SINK_REG_CURR_SINK
,
1169 WLED4_SINK_REG_CURR_SINK_MASK
, sink_en
);
1173 /* This updates only FSC configuration in WLED5 */
1174 rc
= wled
->wled_sync_toggle(wled
);
1176 pr_err("Failed to toggle sync reg rc:%d\n", rc
);
1180 rc
= wled_auto_detection_at_init(wled
);
1187 static const struct wled_config wled5_config_defaults
= {
1189 .string_i_limit
= 10,
1196 .external_pfet
= false,
1197 .auto_detection_enabled
= false,
1198 .enabled_strings
= {0, 1, 2, 3},
1201 static const u32 wled3_boost_i_limit_values
[] = {
1202 105, 385, 525, 805, 980, 1260, 1400, 1680,
1205 static const struct wled_var_cfg wled3_boost_i_limit_cfg
= {
1206 .values
= wled3_boost_i_limit_values
,
1207 .size
= ARRAY_SIZE(wled3_boost_i_limit_values
),
1210 static const u32 wled4_boost_i_limit_values
[] = {
1211 105, 280, 450, 620, 970, 1150, 1300, 1500,
1214 static const struct wled_var_cfg wled4_boost_i_limit_cfg
= {
1215 .values
= wled4_boost_i_limit_values
,
1216 .size
= ARRAY_SIZE(wled4_boost_i_limit_values
),
1219 static inline u32
wled5_boost_i_limit_values_fn(u32 idx
)
1221 return 525 + (idx
* 175);
1224 static const struct wled_var_cfg wled5_boost_i_limit_cfg
= {
1225 .fn
= wled5_boost_i_limit_values_fn
,
1229 static const u32 wled3_ovp_values
[] = {
1233 static const struct wled_var_cfg wled3_ovp_cfg
= {
1234 .values
= wled3_ovp_values
,
1235 .size
= ARRAY_SIZE(wled3_ovp_values
),
1238 static const u32 wled4_ovp_values
[] = {
1239 31100, 29600, 19600, 18100,
1242 static const struct wled_var_cfg wled4_ovp_cfg
= {
1243 .values
= wled4_ovp_values
,
1244 .size
= ARRAY_SIZE(wled4_ovp_values
),
1247 static inline u32
wled5_ovp_values_fn(u32 idx
)
1254 return 38500 - (idx
* 1500);
1257 static const struct wled_var_cfg wled5_ovp_cfg
= {
1258 .fn
= wled5_ovp_values_fn
,
1262 static u32
wled3_switch_freq_values_fn(u32 idx
)
1264 return 19200 / (2 * (1 + idx
));
1267 static const struct wled_var_cfg wled3_switch_freq_cfg
= {
1268 .fn
= wled3_switch_freq_values_fn
,
1272 static const struct wled_var_cfg wled3_string_i_limit_cfg
= {
1276 static const u32 wled4_string_i_limit_values
[] = {
1277 0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000,
1278 22500, 25000, 27500, 30000,
1281 static const struct wled_var_cfg wled4_string_i_limit_cfg
= {
1282 .values
= wled4_string_i_limit_values
,
1283 .size
= ARRAY_SIZE(wled4_string_i_limit_values
),
1286 static const struct wled_var_cfg wled5_mod_sel_cfg
= {
1290 static const struct wled_var_cfg wled5_cabc_sel_cfg
= {
1294 static u32
wled_values(const struct wled_var_cfg
*cfg
, u32 idx
)
1296 if (idx
>= cfg
->size
)
1299 return cfg
->fn(idx
);
1301 return cfg
->values
[idx
];
1305 static int wled_configure(struct wled
*wled
)
1307 struct wled_config
*cfg
= &wled
->cfg
;
1308 struct device
*dev
= wled
->dev
;
1309 const __be32
*prop_addr
;
1311 int rc
, i
, j
, string_len
;
1313 const struct wled_u32_opts
*u32_opts
= NULL
;
1314 const struct wled_u32_opts wled3_opts
[] = {
1316 .name
= "qcom,current-boost-limit",
1317 .val_ptr
= &cfg
->boost_i_limit
,
1318 .cfg
= &wled3_boost_i_limit_cfg
,
1321 .name
= "qcom,current-limit",
1322 .val_ptr
= &cfg
->string_i_limit
,
1323 .cfg
= &wled3_string_i_limit_cfg
,
1327 .val_ptr
= &cfg
->ovp
,
1328 .cfg
= &wled3_ovp_cfg
,
1331 .name
= "qcom,switching-freq",
1332 .val_ptr
= &cfg
->switch_freq
,
1333 .cfg
= &wled3_switch_freq_cfg
,
1337 const struct wled_u32_opts wled4_opts
[] = {
1339 .name
= "qcom,current-boost-limit",
1340 .val_ptr
= &cfg
->boost_i_limit
,
1341 .cfg
= &wled4_boost_i_limit_cfg
,
1344 .name
= "qcom,current-limit-microamp",
1345 .val_ptr
= &cfg
->string_i_limit
,
1346 .cfg
= &wled4_string_i_limit_cfg
,
1349 .name
= "qcom,ovp-millivolt",
1350 .val_ptr
= &cfg
->ovp
,
1351 .cfg
= &wled4_ovp_cfg
,
1354 .name
= "qcom,switching-freq",
1355 .val_ptr
= &cfg
->switch_freq
,
1356 .cfg
= &wled3_switch_freq_cfg
,
1360 const struct wled_u32_opts wled5_opts
[] = {
1362 .name
= "qcom,current-boost-limit",
1363 .val_ptr
= &cfg
->boost_i_limit
,
1364 .cfg
= &wled5_boost_i_limit_cfg
,
1367 .name
= "qcom,current-limit-microamp",
1368 .val_ptr
= &cfg
->string_i_limit
,
1369 .cfg
= &wled4_string_i_limit_cfg
,
1372 .name
= "qcom,ovp-millivolt",
1373 .val_ptr
= &cfg
->ovp
,
1374 .cfg
= &wled5_ovp_cfg
,
1377 .name
= "qcom,switching-freq",
1378 .val_ptr
= &cfg
->switch_freq
,
1379 .cfg
= &wled3_switch_freq_cfg
,
1382 .name
= "qcom,modulator-sel",
1383 .val_ptr
= &cfg
->mod_sel
,
1384 .cfg
= &wled5_mod_sel_cfg
,
1387 .name
= "qcom,cabc-sel",
1388 .val_ptr
= &cfg
->cabc_sel
,
1389 .cfg
= &wled5_cabc_sel_cfg
,
1393 const struct wled_bool_opts bool_opts
[] = {
1394 { "qcom,cs-out", &cfg
->cs_out_en
, },
1395 { "qcom,ext-gen", &cfg
->ext_gen
, },
1396 { "qcom,cabc", &cfg
->cabc
, },
1397 { "qcom,external-pfet", &cfg
->external_pfet
, },
1398 { "qcom,auto-string-detection", &cfg
->auto_detection_enabled
, },
1401 prop_addr
= of_get_address(dev
->of_node
, 0, NULL
, NULL
);
1403 dev_err(wled
->dev
, "invalid IO resources\n");
1406 wled
->ctrl_addr
= be32_to_cpu(*prop_addr
);
1408 rc
= of_property_read_string(dev
->of_node
, "label", &wled
->name
);
1410 wled
->name
= devm_kasprintf(dev
, GFP_KERNEL
, "%pOFn", dev
->of_node
);
1412 switch (wled
->version
) {
1414 u32_opts
= wled3_opts
;
1415 size
= ARRAY_SIZE(wled3_opts
);
1416 *cfg
= wled3_config_defaults
;
1417 wled
->wled_set_brightness
= wled3_set_brightness
;
1418 wled
->wled_sync_toggle
= wled3_sync_toggle
;
1419 wled
->max_string_count
= 3;
1420 wled
->sink_addr
= wled
->ctrl_addr
;
1424 u32_opts
= wled4_opts
;
1425 size
= ARRAY_SIZE(wled4_opts
);
1426 *cfg
= wled4_config_defaults
;
1427 wled
->wled_set_brightness
= wled4_set_brightness
;
1428 wled
->wled_sync_toggle
= wled3_sync_toggle
;
1429 wled
->wled_cabc_config
= wled4_cabc_config
;
1430 wled
->wled_ovp_delay
= wled4_ovp_delay
;
1431 wled
->wled_auto_detection_required
=
1432 wled4_auto_detection_required
;
1433 wled
->max_string_count
= 4;
1435 prop_addr
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
1437 dev_err(wled
->dev
, "invalid IO resources\n");
1440 wled
->sink_addr
= be32_to_cpu(*prop_addr
);
1444 u32_opts
= wled5_opts
;
1445 size
= ARRAY_SIZE(wled5_opts
);
1446 *cfg
= wled5_config_defaults
;
1447 wled
->wled_set_brightness
= wled5_set_brightness
;
1448 wled
->wled_sync_toggle
= wled3_sync_toggle
;
1449 wled
->wled_cabc_config
= wled5_cabc_config
;
1450 wled
->wled_ovp_delay
= wled5_ovp_delay
;
1451 wled
->wled_auto_detection_required
=
1452 wled5_auto_detection_required
;
1453 wled
->max_string_count
= 4;
1455 prop_addr
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
1457 dev_err(wled
->dev
, "invalid IO resources\n");
1460 wled
->sink_addr
= be32_to_cpu(*prop_addr
);
1464 dev_err(wled
->dev
, "Invalid WLED version\n");
1468 for (i
= 0; i
< size
; ++i
) {
1469 rc
= of_property_read_u32(dev
->of_node
, u32_opts
[i
].name
, &val
);
1470 if (rc
== -EINVAL
) {
1473 dev_err(dev
, "error reading '%s'\n", u32_opts
[i
].name
);
1478 for (j
= 0; c
!= val
; j
++) {
1479 c
= wled_values(u32_opts
[i
].cfg
, j
);
1480 if (c
== UINT_MAX
) {
1481 dev_err(dev
, "invalid value for '%s'\n",
1490 dev_dbg(dev
, "'%s' = %u\n", u32_opts
[i
].name
, c
);
1491 *u32_opts
[i
].val_ptr
= j
;
1494 for (i
= 0; i
< ARRAY_SIZE(bool_opts
); ++i
) {
1495 if (of_property_read_bool(dev
->of_node
, bool_opts
[i
].name
))
1496 *bool_opts
[i
].val_ptr
= true;
1499 string_len
= of_property_count_elems_of_size(dev
->of_node
,
1500 "qcom,enabled-strings",
1502 if (string_len
> 0) {
1503 if (string_len
> wled
->max_string_count
) {
1504 dev_err(dev
, "Cannot have more than %d strings\n",
1505 wled
->max_string_count
);
1509 rc
= of_property_read_u32_array(dev
->of_node
,
1510 "qcom,enabled-strings",
1511 wled
->cfg
.enabled_strings
,
1514 dev_err(dev
, "Failed to read %d elements from qcom,enabled-strings: %d\n",
1519 for (i
= 0; i
< string_len
; ++i
) {
1520 if (wled
->cfg
.enabled_strings
[i
] >= wled
->max_string_count
) {
1522 "qcom,enabled-strings index %d at %d is out of bounds\n",
1523 wled
->cfg
.enabled_strings
[i
], i
);
1528 cfg
->num_strings
= string_len
;
1531 rc
= of_property_read_u32(dev
->of_node
, "qcom,num-strings", &val
);
1533 if (val
< 1 || val
> wled
->max_string_count
) {
1534 dev_err(dev
, "qcom,num-strings must be between 1 and %d\n",
1535 wled
->max_string_count
);
1539 if (string_len
> 0) {
1540 dev_warn(dev
, "Only one of qcom,num-strings or qcom,enabled-strings"
1541 " should be set\n");
1542 if (val
> string_len
) {
1543 dev_err(dev
, "qcom,num-strings exceeds qcom,enabled-strings\n");
1548 cfg
->num_strings
= val
;
1554 static int wled_configure_short_irq(struct wled
*wled
,
1555 struct platform_device
*pdev
)
1559 if (!wled
->has_short_detect
)
1562 rc
= regmap_update_bits(wled
->regmap
, wled
->ctrl_addr
+
1563 WLED4_CTRL_REG_SHORT_PROTECT
,
1564 WLED4_CTRL_REG_SHORT_EN_MASK
,
1565 WLED4_CTRL_REG_SHORT_EN_MASK
);
1569 wled
->short_irq
= platform_get_irq_byname(pdev
, "short");
1570 if (wled
->short_irq
< 0) {
1571 dev_dbg(&pdev
->dev
, "short irq is not used\n");
1575 rc
= devm_request_threaded_irq(wled
->dev
, wled
->short_irq
,
1576 NULL
, wled_short_irq_handler
,
1578 "wled_short_irq", wled
);
1580 dev_err(wled
->dev
, "Unable to request short_irq (err:%d)\n",
1586 static int wled_configure_ovp_irq(struct wled
*wled
,
1587 struct platform_device
*pdev
)
1592 wled
->ovp_irq
= platform_get_irq_byname(pdev
, "ovp");
1593 if (wled
->ovp_irq
< 0) {
1594 dev_dbg(&pdev
->dev
, "OVP IRQ not found - disabling automatic string detection\n");
1598 rc
= devm_request_threaded_irq(wled
->dev
, wled
->ovp_irq
, NULL
,
1599 wled_ovp_irq_handler
, IRQF_ONESHOT
,
1600 "wled_ovp_irq", wled
);
1602 dev_err(wled
->dev
, "Unable to request ovp_irq (err:%d)\n",
1608 rc
= regmap_read(wled
->regmap
, wled
->ctrl_addr
+
1609 WLED3_CTRL_REG_MOD_EN
, &val
);
1613 /* Keep OVP irq disabled until module is enabled */
1614 if (!(val
& WLED3_CTRL_REG_MOD_EN_MASK
))
1615 disable_irq(wled
->ovp_irq
);
1620 static const struct backlight_ops wled_ops
= {
1621 .update_status
= wled_update_status
,
1624 static int wled_probe(struct platform_device
*pdev
)
1626 struct backlight_properties props
;
1627 struct backlight_device
*bl
;
1629 struct regmap
*regmap
;
1633 regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
1635 dev_err(&pdev
->dev
, "Unable to get regmap\n");
1639 wled
= devm_kzalloc(&pdev
->dev
, sizeof(*wled
), GFP_KERNEL
);
1643 wled
->regmap
= regmap
;
1644 wled
->dev
= &pdev
->dev
;
1646 wled
->version
= (uintptr_t)of_device_get_match_data(&pdev
->dev
);
1647 if (!wled
->version
) {
1648 dev_err(&pdev
->dev
, "Unknown device version\n");
1652 mutex_init(&wled
->lock
);
1653 rc
= wled_configure(wled
);
1657 val
= WLED3_SINK_REG_BRIGHT_MAX
;
1658 of_property_read_u32(pdev
->dev
.of_node
, "max-brightness", &val
);
1659 wled
->max_brightness
= val
;
1661 switch (wled
->version
) {
1663 wled
->cfg
.auto_detection_enabled
= false;
1664 rc
= wled3_setup(wled
);
1666 dev_err(&pdev
->dev
, "wled3_setup failed\n");
1672 wled
->has_short_detect
= true;
1673 rc
= wled4_setup(wled
);
1675 dev_err(&pdev
->dev
, "wled4_setup failed\n");
1681 wled
->has_short_detect
= true;
1682 if (wled
->cfg
.cabc_sel
)
1683 wled
->max_brightness
= WLED5_SINK_REG_BRIGHT_MAX_12B
;
1685 rc
= wled5_setup(wled
);
1687 dev_err(&pdev
->dev
, "wled5_setup failed\n");
1693 dev_err(wled
->dev
, "Invalid WLED version\n");
1697 INIT_DELAYED_WORK(&wled
->ovp_work
, wled_ovp_work
);
1699 rc
= wled_configure_short_irq(wled
, pdev
);
1703 rc
= wled_configure_ovp_irq(wled
, pdev
);
1707 val
= WLED_DEFAULT_BRIGHTNESS
;
1708 of_property_read_u32(pdev
->dev
.of_node
, "default-brightness", &val
);
1710 memset(&props
, 0, sizeof(struct backlight_properties
));
1711 props
.type
= BACKLIGHT_RAW
;
1712 props
.brightness
= val
;
1713 props
.max_brightness
= wled
->max_brightness
;
1714 bl
= devm_backlight_device_register(&pdev
->dev
, wled
->name
,
1717 return PTR_ERR_OR_ZERO(bl
);
1720 static void wled_remove(struct platform_device
*pdev
)
1722 struct wled
*wled
= platform_get_drvdata(pdev
);
1724 mutex_destroy(&wled
->lock
);
1725 cancel_delayed_work_sync(&wled
->ovp_work
);
1726 disable_irq(wled
->short_irq
);
1727 disable_irq(wled
->ovp_irq
);
1730 static const struct of_device_id wled_match_table
[] = {
1731 { .compatible
= "qcom,pm8941-wled", .data
= (void *)3 },
1732 { .compatible
= "qcom,pmi8950-wled", .data
= (void *)4 },
1733 { .compatible
= "qcom,pmi8994-wled", .data
= (void *)4 },
1734 { .compatible
= "qcom,pmi8998-wled", .data
= (void *)4 },
1735 { .compatible
= "qcom,pm660l-wled", .data
= (void *)4 },
1736 { .compatible
= "qcom,pm6150l-wled", .data
= (void *)5 },
1737 { .compatible
= "qcom,pm8150l-wled", .data
= (void *)5 },
1740 MODULE_DEVICE_TABLE(of
, wled_match_table
);
1742 static struct platform_driver wled_driver
= {
1743 .probe
= wled_probe
,
1744 .remove
= wled_remove
,
1746 .name
= "qcom,wled",
1747 .of_match_table
= wled_match_table
,
1751 module_platform_driver(wled_driver
);
1753 MODULE_DESCRIPTION("Qualcomm WLED driver");
1754 MODULE_LICENSE("GPL v2");