blob: 3060cfa0178a840a7795bc3af417bc9be1c25487 [file] [log] [blame]
David Collins8885f792017-01-26 14:36:34 -08001/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/regmap.h>
17#include <linux/errno.h>
18#include <linux/leds.h>
19#include <linux/slab.h>
20#include <linux/of_device.h>
21#include <linux/of_address.h>
22#include <linux/spmi.h>
23#include <linux/platform_device.h>
24#include <linux/interrupt.h>
25#include <linux/err.h>
26#include <linux/delay.h>
27#include <linux/leds-qpnp-wled.h>
28#include <linux/qpnp/qpnp-revid.h>
29
30/* base addresses */
31#define QPNP_WLED_CTRL_BASE "qpnp-wled-ctrl-base"
32#define QPNP_WLED_SINK_BASE "qpnp-wled-sink-base"
33
34/* ctrl registers */
35#define QPNP_WLED_FAULT_STATUS(b) (b + 0x08)
Subbaraman Narayanamurthyb5ae3182017-02-17 15:14:06 -080036#define QPNP_WLED_INT_RT_STS(b) (b + 0x10)
David Collins8885f792017-01-26 14:36:34 -080037#define QPNP_WLED_EN_REG(b) (b + 0x46)
38#define QPNP_WLED_FDBK_OP_REG(b) (b + 0x48)
39#define QPNP_WLED_VREF_REG(b) (b + 0x49)
40#define QPNP_WLED_BOOST_DUTY_REG(b) (b + 0x4B)
41#define QPNP_WLED_SWITCH_FREQ_REG(b) (b + 0x4C)
42#define QPNP_WLED_OVP_REG(b) (b + 0x4D)
43#define QPNP_WLED_ILIM_REG(b) (b + 0x4E)
44#define QPNP_WLED_AMOLED_VOUT_REG(b) (b + 0x4F)
45#define QPNP_WLED_SOFTSTART_RAMP_DLY(b) (b + 0x53)
46#define QPNP_WLED_VLOOP_COMP_RES_REG(b) (b + 0x55)
47#define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56)
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -080048#define QPNP_WLED_EN_PSM_REG(b) (b + 0x5A)
David Collins8885f792017-01-26 14:36:34 -080049#define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B)
50#define QPNP_WLED_LCD_AUTO_PFM_REG(b) (b + 0x5C)
51#define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E)
52#define QPNP_WLED_SWIRE_AVDD_REG(b) (b + 0x5F)
53#define QPNP_WLED_CTRL_SPARE_REG(b) (b + 0xDF)
54#define QPNP_WLED_TEST1_REG(b) (b + 0xE2)
55#define QPNP_WLED_TEST4_REG(b) (b + 0xE5)
56#define QPNP_WLED_REF_7P7_TRIM_REG(b) (b + 0xF2)
57
58#define QPNP_WLED_7P7_TRIM_MASK GENMASK(3, 0)
59#define QPNP_WLED_EN_MASK 0x7F
60#define QPNP_WLED_EN_SHIFT 7
61#define QPNP_WLED_FDBK_OP_MASK 0xF8
62#define QPNP_WLED_VREF_MASK GENMASK(3, 0)
63
64#define QPNP_WLED_VLOOP_COMP_RES_MASK 0xF0
65#define QPNP_WLED_VLOOP_COMP_RES_OVERWRITE 0x80
66#define QPNP_WLED_LOOP_COMP_RES_DFLT_AMOLED_KOHM 320
67#define QPNP_WLED_LOOP_COMP_RES_STEP_KOHM 20
68#define QPNP_WLED_LOOP_COMP_RES_MIN_KOHM 20
69#define QPNP_WLED_LOOP_COMP_RES_MAX_KOHM 320
70#define QPNP_WLED_VLOOP_COMP_GM_MASK GENMASK(3, 0)
71#define QPNP_WLED_VLOOP_COMP_GM_OVERWRITE 0x80
72#define QPNP_WLED_VLOOP_COMP_AUTO_GM_EN BIT(6)
73#define QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_MASK GENMASK(5, 4)
74#define QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_SHIFT 4
75#define QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED_PMI8994 0x03
76#define QPNP_WLED_LOOP_GM_DFLT_AMOLED_PMI8998 0x09
77#define QPNP_WLED_LOOP_GM_DFLT_WLED 0x09
78#define QPNP_WLED_LOOP_EA_GM_MIN 0x0
79#define QPNP_WLED_LOOP_EA_GM_MAX 0xF
80#define QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX 3
81#define QPNP_WLED_LOOP_AUTO_GM_DFLT_THRESH 1
82#define QPNP_WLED_VREF_PSM_MASK 0xF8
83#define QPNP_WLED_VREF_PSM_STEP_MV 50
84#define QPNP_WLED_VREF_PSM_MIN_MV 400
85#define QPNP_WLED_VREF_PSM_MAX_MV 750
86#define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -080087#define QPNP_WLED_PSM_OVERWRITE_BIT BIT(7)
David Collins8885f792017-01-26 14:36:34 -080088#define QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH 1
89#define QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX 0xF
90#define QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT 7
91#define QPNP_WLED_LCD_AUTO_PFM_EN_BIT BIT(7)
92#define QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK GENMASK(3, 0)
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -080093#define QPNP_WLED_EN_PSM_BIT BIT(7)
David Collins8885f792017-01-26 14:36:34 -080094
95#define QPNP_WLED_ILIM_MASK GENMASK(2, 0)
96#define QPNP_WLED_ILIM_OVERWRITE BIT(7)
97#define PMI8994_WLED_ILIM_MIN_MA 105
98#define PMI8994_WLED_ILIM_MAX_MA 1980
99#define PMI8994_WLED_DFLT_ILIM_MA 980
100#define PMI8994_AMOLED_DFLT_ILIM_MA 385
101#define PMI8998_WLED_ILIM_MAX_MA 1500
102#define PMI8998_WLED_DFLT_ILIM_MA 970
103#define PMI8998_AMOLED_DFLT_ILIM_MA 620
104#define QPNP_WLED_BOOST_DUTY_MASK 0xFC
105#define QPNP_WLED_BOOST_DUTY_STEP_NS 52
106#define QPNP_WLED_BOOST_DUTY_MIN_NS 26
107#define QPNP_WLED_BOOST_DUTY_MAX_NS 156
108#define QPNP_WLED_DEF_BOOST_DUTY_NS 104
109#define QPNP_WLED_SWITCH_FREQ_MASK 0x70
110#define QPNP_WLED_SWITCH_FREQ_800_KHZ 800
111#define QPNP_WLED_SWITCH_FREQ_1600_KHZ 1600
112#define QPNP_WLED_SWITCH_FREQ_OVERWRITE 0x80
113#define QPNP_WLED_OVP_MASK GENMASK(1, 0)
114#define QPNP_WLED_TEST4_EN_DEB_BYPASS_ILIM_BIT BIT(6)
115#define QPNP_WLED_TEST4_EN_SH_FOR_SS_BIT BIT(5)
116#define QPNP_WLED_TEST4_EN_CLAMP_BIT BIT(4)
117#define QPNP_WLED_TEST4_EN_SOFT_START_BIT BIT(1)
118#define QPNP_WLED_TEST4_EN_VREF_UP \
119 (QPNP_WLED_TEST4_EN_SH_FOR_SS_BIT | \
120 QPNP_WLED_TEST4_EN_CLAMP_BIT | \
121 QPNP_WLED_TEST4_EN_SOFT_START_BIT)
122#define QPNP_WLED_TEST4_EN_IIND_UP 0x1
Subbaraman Narayanamurthyb5ae3182017-02-17 15:14:06 -0800123#define QPNP_WLED_ILIM_FAULT_BIT BIT(0)
124#define QPNP_WLED_OVP_FAULT_BIT BIT(1)
125#define QPNP_WLED_SC_FAULT_BIT BIT(2)
David Collins8885f792017-01-26 14:36:34 -0800126
127/* sink registers */
128#define QPNP_WLED_CURR_SINK_REG(b) (b + 0x46)
129#define QPNP_WLED_SYNC_REG(b) (b + 0x47)
130#define QPNP_WLED_MOD_REG(b) (b + 0x4A)
131#define QPNP_WLED_HYB_THRES_REG(b) (b + 0x4B)
132#define QPNP_WLED_MOD_EN_REG(b, n) (b + 0x50 + (n * 0x10))
133#define QPNP_WLED_SYNC_DLY_REG(b, n) (QPNP_WLED_MOD_EN_REG(b, n) + 0x01)
134#define QPNP_WLED_FS_CURR_REG(b, n) (QPNP_WLED_MOD_EN_REG(b, n) + 0x02)
135#define QPNP_WLED_CABC_REG(b, n) (QPNP_WLED_MOD_EN_REG(b, n) + 0x06)
136#define QPNP_WLED_BRIGHT_LSB_REG(b, n) (QPNP_WLED_MOD_EN_REG(b, n) + 0x07)
137#define QPNP_WLED_BRIGHT_MSB_REG(b, n) (QPNP_WLED_MOD_EN_REG(b, n) + 0x08)
138#define QPNP_WLED_SINK_TEST5_REG(b) (b + 0xE6)
139
140#define QPNP_WLED_MOD_FREQ_1200_KHZ 1200
141#define QPNP_WLED_MOD_FREQ_2400_KHZ 2400
142#define QPNP_WLED_MOD_FREQ_9600_KHZ 9600
143#define QPNP_WLED_MOD_FREQ_19200_KHZ 19200
144#define QPNP_WLED_MOD_FREQ_MASK 0x3F
145#define QPNP_WLED_MOD_FREQ_SHIFT 6
146#define QPNP_WLED_ACC_CLK_FREQ_MASK 0xE7
147#define QPNP_WLED_ACC_CLK_FREQ_SHIFT 3
148#define QPNP_WLED_PHASE_STAG_MASK 0xDF
149#define QPNP_WLED_PHASE_STAG_SHIFT 5
150#define QPNP_WLED_DIM_RES_MASK 0xFD
151#define QPNP_WLED_DIM_RES_SHIFT 1
152#define QPNP_WLED_DIM_HYB_MASK 0xFB
153#define QPNP_WLED_DIM_HYB_SHIFT 2
154#define QPNP_WLED_DIM_ANA_MASK 0xFE
155#define QPNP_WLED_HYB_THRES_MASK 0xF8
156#define QPNP_WLED_HYB_THRES_MIN 78
157#define QPNP_WLED_DEF_HYB_THRES 625
158#define QPNP_WLED_HYB_THRES_MAX 10000
159#define QPNP_WLED_MOD_EN_MASK 0x7F
160#define QPNP_WLED_MOD_EN_SHFT 7
161#define QPNP_WLED_MOD_EN 1
162#define QPNP_WLED_GATE_DRV_MASK 0xFE
163#define QPNP_WLED_SYNC_DLY_MASK 0xF8
164#define QPNP_WLED_SYNC_DLY_MIN_US 0
165#define QPNP_WLED_SYNC_DLY_MAX_US 1400
166#define QPNP_WLED_SYNC_DLY_STEP_US 200
167#define QPNP_WLED_DEF_SYNC_DLY_US 400
168#define QPNP_WLED_FS_CURR_MASK 0xF0
169#define QPNP_WLED_FS_CURR_MIN_UA 0
170#define QPNP_WLED_FS_CURR_MAX_UA 30000
171#define QPNP_WLED_FS_CURR_STEP_UA 2500
172#define QPNP_WLED_CABC_MASK 0x7F
173#define QPNP_WLED_CABC_SHIFT 7
174#define QPNP_WLED_CURR_SINK_SHIFT 4
175#define QPNP_WLED_BRIGHT_LSB_MASK 0xFF
176#define QPNP_WLED_BRIGHT_MSB_SHIFT 8
177#define QPNP_WLED_BRIGHT_MSB_MASK 0x0F
178#define QPNP_WLED_SYNC 0x0F
179#define QPNP_WLED_SYNC_RESET 0x00
180
181#define QPNP_WLED_SINK_TEST5_HYB 0x14
182#define QPNP_WLED_SINK_TEST5_DIG 0x1E
183#define QPNP_WLED_SINK_TEST5_HVG_PULL_STR_BIT BIT(3)
184
185#define QPNP_WLED_SWITCH_FREQ_800_KHZ_CODE 0x0B
186#define QPNP_WLED_SWITCH_FREQ_1600_KHZ_CODE 0x05
187
188#define QPNP_WLED_DISP_SEL_REG(b) (b + 0x44)
189#define QPNP_WLED_MODULE_RDY_REG(b) (b + 0x45)
190#define QPNP_WLED_MODULE_EN_REG(b) (b + 0x46)
191#define QPNP_WLED_MODULE_RDY_MASK 0x7F
192#define QPNP_WLED_MODULE_RDY_SHIFT 7
193#define QPNP_WLED_MODULE_EN_MASK BIT(7)
194#define QPNP_WLED_MODULE_EN_SHIFT 7
195#define QPNP_WLED_DISP_SEL_MASK 0x7F
196#define QPNP_WLED_DISP_SEL_SHIFT 7
197#define QPNP_WLED_EN_SC_DEB_CYCLES_MASK 0x79
198#define QPNP_WLED_EN_DEB_CYCLES_MASK 0xF9
199#define QPNP_WLED_EN_SC_SHIFT 7
200#define QPNP_WLED_SC_PRO_EN_DSCHGR 0x8
201#define QPNP_WLED_SC_DEB_CYCLES_MIN 2
202#define QPNP_WLED_SC_DEB_CYCLES_MAX 16
203#define QPNP_WLED_SC_DEB_CYCLES_SUB 2
204#define QPNP_WLED_SC_DEB_CYCLES_DFLT 4
205#define QPNP_WLED_EXT_FET_DTEST2 0x09
206
207#define QPNP_WLED_SEC_ACCESS_REG(b) (b + 0xD0)
208#define QPNP_WLED_SEC_UNLOCK 0xA5
209
210#define QPNP_WLED_MAX_STRINGS 4
211#define WLED_MAX_LEVEL_4095 4095
212#define QPNP_WLED_RAMP_DLY_MS 20
213#define QPNP_WLED_TRIGGER_NONE "none"
214#define QPNP_WLED_STR_SIZE 20
215#define QPNP_WLED_MIN_MSLEEP 20
216#define QPNP_WLED_SC_DLY_MS 20
217
218#define NUM_SUPPORTED_AVDD_VOLTAGES 6
219#define QPNP_WLED_DFLT_AVDD_MV 7600
220#define QPNP_WLED_AVDD_MIN_MV 5650
221#define QPNP_WLED_AVDD_MAX_MV 7900
222#define QPNP_WLED_AVDD_STEP_MV 150
223#define QPNP_WLED_AVDD_MIN_TRIM_VAL 0x0
224#define QPNP_WLED_AVDD_MAX_TRIM_VAL 0xF
225#define QPNP_WLED_AVDD_SEL_SPMI_BIT BIT(7)
226#define QPNP_WLED_AVDD_SET_BIT BIT(4)
227
228#define NUM_SUPPORTED_OVP_THRESHOLDS 4
229#define NUM_SUPPORTED_ILIM_THRESHOLDS 8
230
231#define QPNP_WLED_AVDD_MV_TO_REG(val) \
232 ((val - QPNP_WLED_AVDD_MIN_MV) / QPNP_WLED_AVDD_STEP_MV)
233
234/* output feedback mode */
235enum qpnp_wled_fdbk_op {
236 QPNP_WLED_FDBK_AUTO,
237 QPNP_WLED_FDBK_WLED1,
238 QPNP_WLED_FDBK_WLED2,
239 QPNP_WLED_FDBK_WLED3,
240 QPNP_WLED_FDBK_WLED4,
241};
242
243/* dimming modes */
244enum qpnp_wled_dim_mode {
245 QPNP_WLED_DIM_ANALOG,
246 QPNP_WLED_DIM_DIGITAL,
247 QPNP_WLED_DIM_HYBRID,
248};
249
250/* wled ctrl debug registers */
251static u8 qpnp_wled_ctrl_dbg_regs[] = {
252 0x44, 0x46, 0x48, 0x49, 0x4b, 0x4c, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53,
253 0x54, 0x55, 0x56, 0x57, 0x58, 0x5a, 0x5b, 0x5d, 0x5e, 0xe2
254};
255
256/* wled sink debug registers */
257static u8 qpnp_wled_sink_dbg_regs[] = {
258 0x46, 0x47, 0x48, 0x4a, 0x4b,
259 0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x58,
260 0x60, 0x61, 0x62, 0x63, 0x66, 0x67, 0x68,
261 0x70, 0x71, 0x72, 0x73, 0x76, 0x77, 0x78,
262 0x80, 0x81, 0x82, 0x83, 0x86, 0x87, 0x88,
263 0xe6,
264};
265
266static int qpnp_wled_avdd_target_voltages[NUM_SUPPORTED_AVDD_VOLTAGES] = {
267 7900, 7600, 7300, 6400, 6100, 5800,
268};
269
270static u8 qpnp_wled_ovp_reg_settings[NUM_SUPPORTED_AVDD_VOLTAGES] = {
271 0x0, 0x0, 0x1, 0x2, 0x2, 0x3,
272};
273
274static int qpnp_wled_avdd_trim_adjustments[NUM_SUPPORTED_AVDD_VOLTAGES] = {
275 3, 0, -2, 7, 3, 3,
276};
277
278static int qpnp_wled_ovp_thresholds_pmi8994[NUM_SUPPORTED_OVP_THRESHOLDS] = {
279 31000, 29500, 19400, 17800,
280};
281
282static int qpnp_wled_ovp_thresholds_pmi8998[NUM_SUPPORTED_OVP_THRESHOLDS] = {
283 31100, 29600, 19600, 18100,
284};
285
286static int qpnp_wled_ilim_settings_pmi8994[NUM_SUPPORTED_ILIM_THRESHOLDS] = {
287 105, 385, 660, 980, 1150, 1420, 1700, 1980,
288};
289
290static int qpnp_wled_ilim_settings_pmi8998[NUM_SUPPORTED_ILIM_THRESHOLDS] = {
291 105, 280, 450, 620, 970, 1150, 1300, 1500,
292};
293
294struct wled_vref_setting {
295 u32 min_uv;
296 u32 max_uv;
297 u32 step_uv;
298 u32 default_uv;
299};
300
301static struct wled_vref_setting vref_setting_pmi8994 = {
302 300000, 675000, 25000, 350000,
303};
304static struct wled_vref_setting vref_setting_pmi8998 = {
305 60000, 397500, 22500, 127500,
306};
307
308/**
309 * qpnp_wled - wed data structure
310 * @ cdev - led class device
311 * @ pdev - platform device
312 * @ work - worker for led operation
313 * @ lock - mutex lock for exclusive access
314 * @ fdbk_op - output feedback mode
315 * @ dim_mode - dimming mode
316 * @ ovp_irq - over voltage protection irq
317 * @ sc_irq - short circuit irq
318 * @ sc_cnt - short circuit irq count
319 * @ avdd_target_voltage_mv - target voltage for AVDD module in mV
320 * @ ctrl_base - base address for wled ctrl
321 * @ sink_base - base address for wled sink
322 * @ mod_freq_khz - modulator frequency in KHZ
323 * @ hyb_thres - threshold for hybrid dimming
324 * @ sync_dly_us - sync delay in us
325 * @ vref_uv - ref voltage in uv
326 * @ vref_psm_mv - ref psm voltage in mv
327 * @ loop_comp_res_kohm - control to select the compensation resistor
328 * @ loop_ea_gm - control to select the gm for the gm stage in control loop
329 * @ sc_deb_cycles - debounce time for short circuit detection
330 * @ switch_freq_khz - switching frequency in KHZ
331 * @ ovp_mv - over voltage protection in mv
332 * @ ilim_ma - current limiter in ma
333 * @ boost_duty_ns - boost duty cycle in ns
334 * @ fs_curr_ua - full scale current in ua
335 * @ ramp_ms - delay between ramp steps in ms
336 * @ ramp_step - ramp step size
337 * @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC
338 * @ strings - supported list of strings
339 * @ num_strings - number of strings
340 * @ loop_auto_gm_thresh - the clamping level for auto gm
341 * @ lcd_auto_pfm_thresh - the threshold for lcd auto pfm mode
342 * @ loop_auto_gm_en - select if auto gm is enabled
343 * @ lcd_auto_pfm_en - select if auto pfm is enabled in lcd mode
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -0800344 * @ lcd_psm_ctrl - select if psm needs to be controlled in lcd mode
David Collins8885f792017-01-26 14:36:34 -0800345 * @ avdd_mode_spmi - enable avdd programming via spmi
346 * @ en_9b_dim_res - enable or disable 9bit dimming
347 * @ en_phase_stag - enable or disable phase staggering
348 * @ en_cabc - enable or disable cabc
349 * @ disp_type_amoled - type of display: LCD/AMOLED
350 * @ en_ext_pfet_sc_pro - enable sc protection on external pfet
351 */
352struct qpnp_wled {
353 struct led_classdev cdev;
354 struct platform_device *pdev;
355 struct regmap *regmap;
356 struct pmic_revid_data *pmic_rev_id;
357 struct work_struct work;
358 struct mutex lock;
359 struct mutex bus_lock;
360 enum qpnp_wled_fdbk_op fdbk_op;
361 enum qpnp_wled_dim_mode dim_mode;
362 int ovp_irq;
363 int sc_irq;
364 u32 sc_cnt;
365 u32 avdd_target_voltage_mv;
366 u16 ctrl_base;
367 u16 sink_base;
368 u16 mod_freq_khz;
369 u16 hyb_thres;
370 u16 sync_dly_us;
371 u32 vref_uv;
372 u16 vref_psm_mv;
373 u16 loop_comp_res_kohm;
374 u16 loop_ea_gm;
375 u16 sc_deb_cycles;
376 u16 switch_freq_khz;
377 u16 ovp_mv;
378 u16 ilim_ma;
379 u16 boost_duty_ns;
380 u16 fs_curr_ua;
381 u16 ramp_ms;
382 u16 ramp_step;
383 u16 cons_sync_write_delay_us;
384 u8 strings[QPNP_WLED_MAX_STRINGS];
385 u8 num_strings;
386 u8 loop_auto_gm_thresh;
387 u8 lcd_auto_pfm_thresh;
388 bool loop_auto_gm_en;
389 bool lcd_auto_pfm_en;
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -0800390 bool lcd_psm_ctrl;
David Collins8885f792017-01-26 14:36:34 -0800391 bool avdd_mode_spmi;
392 bool en_9b_dim_res;
393 bool en_phase_stag;
394 bool en_cabc;
395 bool disp_type_amoled;
396 bool en_ext_pfet_sc_pro;
397 bool prev_state;
398 bool ovp_irq_disabled;
399};
400
401/* helper to read a pmic register */
402static int qpnp_wled_read_reg(struct qpnp_wled *wled, u16 addr, u8 *data)
403{
404 int rc;
405 uint val;
406
407 rc = regmap_read(wled->regmap, addr, &val);
408 if (rc < 0) {
409 dev_err(&wled->pdev->dev,
410 "Error reading address: %x(%d)\n", addr, rc);
411 return rc;
412 }
413
414 *data = (u8)val;
415 return 0;
416}
417
418/* helper to write a pmic register */
419static int qpnp_wled_write_reg(struct qpnp_wled *wled, u16 addr, u8 data)
420{
421 int rc;
422
423 mutex_lock(&wled->bus_lock);
424 rc = regmap_write(wled->regmap, addr, data);
425 if (rc < 0) {
426 dev_err(&wled->pdev->dev, "Error writing address: %x(%d)\n",
427 addr, rc);
428 goto out;
429 }
430
431 dev_dbg(&wled->pdev->dev, "wrote: WLED_0x%x = 0x%x\n", addr, data);
432out:
433 mutex_unlock(&wled->bus_lock);
434 return rc;
435}
436
437static int qpnp_wled_masked_write_reg(struct qpnp_wled *wled, u16 addr,
438 u8 mask, u8 data)
439{
440 int rc;
441
442 mutex_lock(&wled->bus_lock);
443 rc = regmap_update_bits(wled->regmap, addr, mask, data);
444 if (rc < 0) {
445 dev_err(&wled->pdev->dev, "Error writing address: %x(%d)\n",
446 addr, rc);
447 goto out;
448 }
449
450 dev_dbg(&wled->pdev->dev, "wrote: WLED_0x%x = 0x%x\n", addr, data);
451out:
452 mutex_unlock(&wled->bus_lock);
453 return rc;
454}
455
456static int qpnp_wled_sec_write_reg(struct qpnp_wled *wled, u16 addr, u8 data)
457{
458 int rc;
459 u8 reg = QPNP_WLED_SEC_UNLOCK;
460 u16 base_addr = addr & 0xFF00;
461
462 mutex_lock(&wled->bus_lock);
463 rc = regmap_write(wled->regmap, QPNP_WLED_SEC_ACCESS_REG(base_addr),
464 reg);
465 if (rc < 0) {
466 dev_err(&wled->pdev->dev, "Error writing address: %x(%d)\n",
467 QPNP_WLED_SEC_ACCESS_REG(base_addr), rc);
468 goto out;
469 }
470
471 rc = regmap_write(wled->regmap, addr, data);
472 if (rc < 0) {
473 dev_err(&wled->pdev->dev, "Error writing address: %x(%d)\n",
474 addr, rc);
475 goto out;
476 }
477
478 dev_dbg(&wled->pdev->dev, "wrote: WLED_0x%x = 0x%x\n", addr, data);
479out:
480 mutex_unlock(&wled->bus_lock);
481 return rc;
482}
483
484static int qpnp_wled_swire_avdd_config(struct qpnp_wled *wled)
485{
486 int rc;
487 u8 val;
488
489 if (wled->pmic_rev_id->pmic_subtype != PMI8998_SUBTYPE &&
490 wled->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE)
491 return 0;
492
493 if (!wled->disp_type_amoled || wled->avdd_mode_spmi)
494 return 0;
495
496 val = QPNP_WLED_AVDD_MV_TO_REG(wled->avdd_target_voltage_mv);
497 rc = qpnp_wled_write_reg(wled,
498 QPNP_WLED_SWIRE_AVDD_REG(wled->ctrl_base), val);
499 return rc;
500}
501
502static int qpnp_wled_sync_reg_toggle(struct qpnp_wled *wled)
503{
504 int rc;
505 u8 reg;
506
507 /* sync */
508 reg = QPNP_WLED_SYNC;
509 rc = qpnp_wled_write_reg(wled, QPNP_WLED_SYNC_REG(wled->sink_base),
510 reg);
511 if (rc < 0)
512 return rc;
513
514 if (wled->cons_sync_write_delay_us)
515 usleep_range(wled->cons_sync_write_delay_us,
516 wled->cons_sync_write_delay_us + 1);
517
518 reg = QPNP_WLED_SYNC_RESET;
519 rc = qpnp_wled_write_reg(wled, QPNP_WLED_SYNC_REG(wled->sink_base),
520 reg);
521 if (rc < 0)
522 return rc;
523
524 return 0;
525}
526
527/* set wled to a level of brightness */
528static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
529{
530 int i, rc;
531 u8 reg;
532
533 /* set brightness registers */
534 for (i = 0; i < wled->num_strings; i++) {
535 reg = level & QPNP_WLED_BRIGHT_LSB_MASK;
536 rc = qpnp_wled_write_reg(wled,
537 QPNP_WLED_BRIGHT_LSB_REG(wled->sink_base,
538 wled->strings[i]), reg);
539 if (rc < 0)
540 return rc;
541
542 reg = level >> QPNP_WLED_BRIGHT_MSB_SHIFT;
543 reg = reg & QPNP_WLED_BRIGHT_MSB_MASK;
544 rc = qpnp_wled_write_reg(wled,
545 QPNP_WLED_BRIGHT_MSB_REG(wled->sink_base,
546 wled->strings[i]), reg);
547 if (rc < 0)
548 return rc;
549 }
550
551 rc = qpnp_wled_sync_reg_toggle(wled);
552 if (rc < 0) {
553 dev_err(&wled->pdev->dev, "Failed to toggle sync reg %d\n", rc);
554 return rc;
555 }
556
557 return 0;
558}
559
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -0800560static int qpnp_wled_psm_config(struct qpnp_wled *wled, bool enable)
561{
562 int rc;
563
564 if (!wled->lcd_psm_ctrl)
565 return 0;
566
567 rc = qpnp_wled_masked_write_reg(wled,
568 QPNP_WLED_EN_PSM_REG(wled->ctrl_base),
569 QPNP_WLED_EN_PSM_BIT,
570 enable ? QPNP_WLED_EN_PSM_BIT : 0);
571 if (rc < 0)
572 return rc;
573
574 rc = qpnp_wled_masked_write_reg(wled,
575 QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base),
576 QPNP_WLED_PSM_OVERWRITE_BIT,
577 enable ? QPNP_WLED_PSM_OVERWRITE_BIT : 0);
578 if (rc < 0)
579 return rc;
580
581 return 0;
582}
583
David Collins8885f792017-01-26 14:36:34 -0800584static int qpnp_wled_module_en(struct qpnp_wled *wled,
585 u16 base_addr, bool state)
586{
587 int rc;
588
589 rc = qpnp_wled_masked_write_reg(wled,
590 QPNP_WLED_MODULE_EN_REG(base_addr),
591 QPNP_WLED_MODULE_EN_MASK,
592 state << QPNP_WLED_MODULE_EN_SHIFT);
593 if (rc < 0)
594 return rc;
595
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -0800596 /*
597 * Wait for at least 10ms before enabling OVP fault interrupt after
598 * enabling the module so that soft start is completed. Also, this
599 * delay can be used to control PSM during enable when required. Keep
600 * OVP interrupt disabled when the module is disabled.
601 */
602 if (state) {
603 usleep_range(10000, 11000);
604 rc = qpnp_wled_psm_config(wled, false);
605 if (rc < 0)
606 return rc;
607
608 if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
David Collins8885f792017-01-26 14:36:34 -0800609 enable_irq(wled->ovp_irq);
610 wled->ovp_irq_disabled = false;
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -0800611 }
612 } else {
613 if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
David Collins8885f792017-01-26 14:36:34 -0800614 disable_irq(wled->ovp_irq);
615 wled->ovp_irq_disabled = true;
616 }
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -0800617
618 rc = qpnp_wled_psm_config(wled, true);
619 if (rc < 0)
620 return rc;
David Collins8885f792017-01-26 14:36:34 -0800621 }
622
623 return 0;
624}
625
626/* sysfs store function for ramp */
627static ssize_t qpnp_wled_ramp_store(struct device *dev,
628 struct device_attribute *attr, const char *buf, size_t count)
629{
630 struct qpnp_wled *wled = dev_get_drvdata(dev);
631 int i, rc;
632
633 mutex_lock(&wled->lock);
634
635 if (!wled->cdev.brightness) {
636 rc = qpnp_wled_module_en(wled, wled->ctrl_base, true);
637 if (rc) {
638 dev_err(&wled->pdev->dev, "wled enable failed\n");
639 goto unlock_mutex;
640 }
641 }
642
643 /* ramp up */
644 for (i = 0; i <= wled->cdev.max_brightness;) {
645 rc = qpnp_wled_set_level(wled, i);
646 if (rc) {
647 dev_err(&wled->pdev->dev, "wled set level failed\n");
648 goto restore_brightness;
649 }
650
651 if (wled->ramp_ms < QPNP_WLED_MIN_MSLEEP)
652 usleep_range(wled->ramp_ms * USEC_PER_MSEC,
653 wled->ramp_ms * USEC_PER_MSEC);
654 else
655 msleep(wled->ramp_ms);
656
657 if (i == wled->cdev.max_brightness)
658 break;
659
660 i += wled->ramp_step;
661 if (i > wled->cdev.max_brightness)
662 i = wled->cdev.max_brightness;
663 }
664
665 /* ramp down */
666 for (i = wled->cdev.max_brightness; i >= 0;) {
667 rc = qpnp_wled_set_level(wled, i);
668 if (rc) {
669 dev_err(&wled->pdev->dev, "wled set level failed\n");
670 goto restore_brightness;
671 }
672
673 if (wled->ramp_ms < QPNP_WLED_MIN_MSLEEP)
674 usleep_range(wled->ramp_ms * USEC_PER_MSEC,
675 wled->ramp_ms * USEC_PER_MSEC);
676 else
677 msleep(wled->ramp_ms);
678
679 if (i == 0)
680 break;
681
682 i -= wled->ramp_step;
683 if (i < 0)
684 i = 0;
685 }
686
687 dev_info(&wled->pdev->dev, "wled ramp complete\n");
688
689restore_brightness:
690 /* restore the old brightness */
691 qpnp_wled_set_level(wled, wled->cdev.brightness);
692 if (!wled->cdev.brightness) {
693 rc = qpnp_wled_module_en(wled, wled->ctrl_base, false);
694 if (rc)
695 dev_err(&wled->pdev->dev, "wled enable failed\n");
696 }
697unlock_mutex:
698 mutex_unlock(&wled->lock);
699
700 return count;
701}
702
703static int qpnp_wled_dump_regs(struct qpnp_wled *wled, u16 base_addr,
704 u8 dbg_regs[], u8 size, char *label,
705 int count, char *buf)
706{
707 int i, rc;
708 u8 reg;
709
710 for (i = 0; i < size; i++) {
711 rc = qpnp_wled_read_reg(wled, base_addr + dbg_regs[i], &reg);
712 if (rc < 0)
713 return rc;
714
715 count += snprintf(buf + count, PAGE_SIZE - count,
716 "%s: REG_0x%x = 0x%x\n", label,
717 base_addr + dbg_regs[i], reg);
718
719 if (count >= PAGE_SIZE)
720 return PAGE_SIZE - 1;
721 }
722
723 return count;
724}
725
726/* sysfs show function for debug registers */
727static ssize_t qpnp_wled_dump_regs_show(struct device *dev,
728 struct device_attribute *attr, char *buf)
729{
730 struct qpnp_wled *wled = dev_get_drvdata(dev);
731 int count = 0;
732
733 count = qpnp_wled_dump_regs(wled, wled->ctrl_base,
734 qpnp_wled_ctrl_dbg_regs,
735 ARRAY_SIZE(qpnp_wled_ctrl_dbg_regs),
736 "wled_ctrl", count, buf);
737
738 if (count < 0 || count == PAGE_SIZE - 1)
739 return count;
740
741 count = qpnp_wled_dump_regs(wled, wled->sink_base,
742 qpnp_wled_sink_dbg_regs,
743 ARRAY_SIZE(qpnp_wled_sink_dbg_regs),
744 "wled_sink", count, buf);
745
746 if (count < 0 || count == PAGE_SIZE - 1)
747 return count;
748
749 return count;
750}
751
752/* sysfs show function for ramp delay in each step */
753static ssize_t qpnp_wled_ramp_ms_show(struct device *dev,
754 struct device_attribute *attr, char *buf)
755{
756 struct qpnp_wled *wled = dev_get_drvdata(dev);
757
758 return snprintf(buf, PAGE_SIZE, "%d\n", wled->ramp_ms);
759}
760
761/* sysfs store function for ramp delay in each step */
762static ssize_t qpnp_wled_ramp_ms_store(struct device *dev,
763 struct device_attribute *attr, const char *buf, size_t count)
764{
765 struct qpnp_wled *wled = dev_get_drvdata(dev);
766 int data, rc;
767
768 rc = kstrtoint(buf, 10, &data);
769 if (rc)
770 return rc;
771
772 wled->ramp_ms = data;
773 return count;
774}
775
776/* sysfs show function for ramp step */
777static ssize_t qpnp_wled_ramp_step_show(struct device *dev,
778 struct device_attribute *attr, char *buf)
779{
780 struct qpnp_wled *wled = dev_get_drvdata(dev);
781
782 return snprintf(buf, PAGE_SIZE, "%d\n", wled->ramp_step);
783}
784
785/* sysfs store function for ramp step */
786static ssize_t qpnp_wled_ramp_step_store(struct device *dev,
787 struct device_attribute *attr, const char *buf, size_t count)
788{
789 struct qpnp_wled *wled = dev_get_drvdata(dev);
790 int data, rc;
791
792 rc = kstrtoint(buf, 10, &data);
793 if (rc)
794 return rc;
795
796 wled->ramp_step = data;
797 return count;
798}
799
800/* sysfs show function for dim mode */
801static ssize_t qpnp_wled_dim_mode_show(struct device *dev,
802 struct device_attribute *attr, char *buf)
803{
804 struct qpnp_wled *wled = dev_get_drvdata(dev);
805 char *str;
806
807 if (wled->dim_mode == QPNP_WLED_DIM_ANALOG)
808 str = "analog";
809 else if (wled->dim_mode == QPNP_WLED_DIM_DIGITAL)
810 str = "digital";
811 else
812 str = "hybrid";
813
814 return snprintf(buf, PAGE_SIZE, "%s\n", str);
815}
816
817/* sysfs store function for dim mode*/
818static ssize_t qpnp_wled_dim_mode_store(struct device *dev,
819 struct device_attribute *attr, const char *buf, size_t count)
820{
821 struct qpnp_wled *wled = dev_get_drvdata(dev);
822 char str[QPNP_WLED_STR_SIZE + 1];
823 int rc, temp;
824 u8 reg;
825
826 if (snprintf(str, QPNP_WLED_STR_SIZE, "%s", buf) > QPNP_WLED_STR_SIZE)
827 return -EINVAL;
828
829 if (strcmp(str, "analog") == 0)
830 temp = QPNP_WLED_DIM_ANALOG;
831 else if (strcmp(str, "digital") == 0)
832 temp = QPNP_WLED_DIM_DIGITAL;
833 else
834 temp = QPNP_WLED_DIM_HYBRID;
835
836 if (temp == wled->dim_mode)
837 return count;
838
839 rc = qpnp_wled_read_reg(wled, QPNP_WLED_MOD_REG(wled->sink_base), &reg);
840 if (rc < 0)
841 return rc;
842
843 if (temp == QPNP_WLED_DIM_HYBRID) {
844 reg &= QPNP_WLED_DIM_HYB_MASK;
845 reg |= (1 << QPNP_WLED_DIM_HYB_SHIFT);
846 } else {
847 reg &= QPNP_WLED_DIM_HYB_MASK;
848 reg |= (0 << QPNP_WLED_DIM_HYB_SHIFT);
849 reg &= QPNP_WLED_DIM_ANA_MASK;
850 reg |= temp;
851 }
852
853 rc = qpnp_wled_write_reg(wled, QPNP_WLED_MOD_REG(wled->sink_base), reg);
854 if (rc)
855 return rc;
856
857 wled->dim_mode = temp;
858
859 return count;
860}
861
862/* sysfs show function for full scale current in ua*/
863static ssize_t qpnp_wled_fs_curr_ua_show(struct device *dev,
864 struct device_attribute *attr, char *buf)
865{
866 struct qpnp_wled *wled = dev_get_drvdata(dev);
867
868 return snprintf(buf, PAGE_SIZE, "%d\n", wled->fs_curr_ua);
869}
870
871/* sysfs store function for full scale current in ua*/
872static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev,
873 struct device_attribute *attr, const char *buf, size_t count)
874{
875 struct qpnp_wled *wled = dev_get_drvdata(dev);
876 int data, i, rc, temp;
877 u8 reg;
878
879 rc = kstrtoint(buf, 10, &data);
880 if (rc)
881 return rc;
882
883 for (i = 0; i < wled->num_strings; i++) {
884 if (data < QPNP_WLED_FS_CURR_MIN_UA)
885 data = QPNP_WLED_FS_CURR_MIN_UA;
886 else if (data > QPNP_WLED_FS_CURR_MAX_UA)
887 data = QPNP_WLED_FS_CURR_MAX_UA;
888
889 rc = qpnp_wled_read_reg(wled,
890 QPNP_WLED_FS_CURR_REG(wled->sink_base,
891 wled->strings[i]), &reg);
892 if (rc < 0)
893 return rc;
894 reg &= QPNP_WLED_FS_CURR_MASK;
895 temp = data / QPNP_WLED_FS_CURR_STEP_UA;
896 reg |= temp;
897 rc = qpnp_wled_write_reg(wled,
898 QPNP_WLED_FS_CURR_REG(wled->sink_base,
899 wled->strings[i]), reg);
900 if (rc)
901 return rc;
902 }
903
904 wled->fs_curr_ua = data;
905
906 rc = qpnp_wled_sync_reg_toggle(wled);
907 if (rc < 0) {
908 dev_err(&wled->pdev->dev, "Failed to toggle sync reg %d\n", rc);
909 return rc;
910 }
911
912 return count;
913}
914
915/* sysfs attributes exported by wled */
916static struct device_attribute qpnp_wled_attrs[] = {
917 __ATTR(dump_regs, 0664, qpnp_wled_dump_regs_show, NULL),
918 __ATTR(dim_mode, 0664, qpnp_wled_dim_mode_show,
919 qpnp_wled_dim_mode_store),
920 __ATTR(fs_curr_ua, 0664, qpnp_wled_fs_curr_ua_show,
921 qpnp_wled_fs_curr_ua_store),
922 __ATTR(start_ramp, 0664, NULL, qpnp_wled_ramp_store),
923 __ATTR(ramp_ms, 0664, qpnp_wled_ramp_ms_show, qpnp_wled_ramp_ms_store),
924 __ATTR(ramp_step, 0664, qpnp_wled_ramp_step_show,
925 qpnp_wled_ramp_step_store),
926};
927
928/* worker for setting wled brightness */
929static void qpnp_wled_work(struct work_struct *work)
930{
931 struct qpnp_wled *wled;
932 int level, rc;
933
934 wled = container_of(work, struct qpnp_wled, work);
935
936 level = wled->cdev.brightness;
937
938 mutex_lock(&wled->lock);
939
940 if (level) {
941 rc = qpnp_wled_set_level(wled, level);
942 if (rc) {
943 dev_err(&wled->pdev->dev, "wled set level failed\n");
944 goto unlock_mutex;
945 }
946 }
947
948 if (!!level != wled->prev_state) {
949 if (!!level) {
950 /*
951 * For AMOLED display in pmi8998, SWIRE_AVDD_DEFAULT has
952 * to be reconfigured every time the module is enabled.
953 */
954 rc = qpnp_wled_swire_avdd_config(wled);
955 if (rc < 0) {
956 pr_err("Write to SWIRE_AVDD_DEFAULT register failed rc:%d\n",
957 rc);
958 goto unlock_mutex;
959 }
960 }
961
962 rc = qpnp_wled_module_en(wled, wled->ctrl_base, !!level);
963 if (rc) {
964 dev_err(&wled->pdev->dev, "wled %sable failed\n",
965 level ? "en" : "dis");
966 goto unlock_mutex;
967 }
968 }
969
970 wled->prev_state = !!level;
971unlock_mutex:
972 mutex_unlock(&wled->lock);
973}
974
975/* get api registered with led classdev for wled brightness */
976static enum led_brightness qpnp_wled_get(struct led_classdev *led_cdev)
977{
978 struct qpnp_wled *wled;
979
980 wled = container_of(led_cdev, struct qpnp_wled, cdev);
981
982 return wled->cdev.brightness;
983}
984
985/* set api registered with led classdev for wled brightness */
986static void qpnp_wled_set(struct led_classdev *led_cdev,
987 enum led_brightness level)
988{
989 struct qpnp_wled *wled;
990
991 wled = container_of(led_cdev, struct qpnp_wled, cdev);
992
993 if (level < LED_OFF)
994 level = LED_OFF;
995 else if (level > wled->cdev.max_brightness)
996 level = wled->cdev.max_brightness;
997
998 wled->cdev.brightness = level;
999 schedule_work(&wled->work);
1000}
1001
1002static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
1003{
1004 int rc;
1005 u8 reg;
1006
1007 /* display type */
1008 rc = qpnp_wled_read_reg(wled, QPNP_WLED_DISP_SEL_REG(base_addr), &reg);
1009 if (rc < 0)
1010 return rc;
1011
1012 reg &= QPNP_WLED_DISP_SEL_MASK;
1013 reg |= (wled->disp_type_amoled << QPNP_WLED_DISP_SEL_SHIFT);
1014
1015 rc = qpnp_wled_sec_write_reg(wled, QPNP_WLED_DISP_SEL_REG(base_addr),
1016 reg);
1017 if (rc)
1018 return rc;
1019
1020 if (wled->disp_type_amoled) {
1021 /* Configure the PSM CTRL register for AMOLED */
1022 if (wled->vref_psm_mv < QPNP_WLED_VREF_PSM_MIN_MV)
1023 wled->vref_psm_mv = QPNP_WLED_VREF_PSM_MIN_MV;
1024 else if (wled->vref_psm_mv > QPNP_WLED_VREF_PSM_MAX_MV)
1025 wled->vref_psm_mv = QPNP_WLED_VREF_PSM_MAX_MV;
1026
1027 rc = qpnp_wled_read_reg(wled,
1028 QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), &reg);
1029 if (rc < 0)
1030 return rc;
1031
1032 reg &= QPNP_WLED_VREF_PSM_MASK;
1033 reg |= ((wled->vref_psm_mv - QPNP_WLED_VREF_PSM_MIN_MV)/
1034 QPNP_WLED_VREF_PSM_STEP_MV);
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -08001035 reg |= QPNP_WLED_PSM_OVERWRITE_BIT;
David Collins8885f792017-01-26 14:36:34 -08001036 rc = qpnp_wled_write_reg(wled,
1037 QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), reg);
1038 if (rc)
1039 return rc;
1040
1041 /* Configure the VLOOP COMP RES register for AMOLED */
1042 if (wled->loop_comp_res_kohm < QPNP_WLED_LOOP_COMP_RES_MIN_KOHM)
1043 wled->loop_comp_res_kohm =
1044 QPNP_WLED_LOOP_COMP_RES_MIN_KOHM;
1045 else if (wled->loop_comp_res_kohm >
1046 QPNP_WLED_LOOP_COMP_RES_MAX_KOHM)
1047 wled->loop_comp_res_kohm =
1048 QPNP_WLED_LOOP_COMP_RES_MAX_KOHM;
1049
1050 rc = qpnp_wled_read_reg(wled,
1051 QPNP_WLED_VLOOP_COMP_RES_REG(wled->ctrl_base),
1052 &reg);
1053 if (rc < 0)
1054 return rc;
1055
1056 reg &= QPNP_WLED_VLOOP_COMP_RES_MASK;
1057 reg |= ((wled->loop_comp_res_kohm -
1058 QPNP_WLED_LOOP_COMP_RES_MIN_KOHM)/
1059 QPNP_WLED_LOOP_COMP_RES_STEP_KOHM);
1060 reg |= QPNP_WLED_VLOOP_COMP_RES_OVERWRITE;
1061 rc = qpnp_wled_write_reg(wled,
1062 QPNP_WLED_VLOOP_COMP_RES_REG(wled->ctrl_base),
1063 reg);
1064 if (rc)
1065 return rc;
1066
1067 /* Configure the CTRL TEST4 register for AMOLED */
1068 rc = qpnp_wled_read_reg(wled,
1069 QPNP_WLED_TEST4_REG(wled->ctrl_base), &reg);
1070 if (rc < 0)
1071 return rc;
1072
1073 reg |= QPNP_WLED_TEST4_EN_IIND_UP;
1074 rc = qpnp_wled_sec_write_reg(wled,
1075 QPNP_WLED_TEST4_REG(base_addr), reg);
1076 if (rc)
1077 return rc;
1078 } else {
1079 /*
1080 * enable VREF_UP to avoid false ovp on low brightness for LCD
1081 */
1082 reg = QPNP_WLED_TEST4_EN_VREF_UP
1083 | QPNP_WLED_TEST4_EN_DEB_BYPASS_ILIM_BIT;
1084 rc = qpnp_wled_sec_write_reg(wled,
1085 QPNP_WLED_TEST4_REG(base_addr), reg);
1086 if (rc)
1087 return rc;
1088 }
1089
1090 return 0;
1091}
1092
1093/* ovp irq handler */
1094static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled)
1095{
1096 struct qpnp_wled *wled = _wled;
1097 int rc;
Subbaraman Narayanamurthyb5ae3182017-02-17 15:14:06 -08001098 u8 fault_sts, int_sts;
David Collins8885f792017-01-26 14:36:34 -08001099
1100 rc = qpnp_wled_read_reg(wled,
Subbaraman Narayanamurthyb5ae3182017-02-17 15:14:06 -08001101 QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts);
1102 if (rc < 0) {
1103 pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc);
1104 return IRQ_HANDLED;
1105 }
1106
1107 rc = qpnp_wled_read_reg(wled,
1108 QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &fault_sts);
David Collins8885f792017-01-26 14:36:34 -08001109 if (rc < 0) {
1110 pr_err("Error in reading WLED_FAULT_STATUS rc=%d\n", rc);
1111 return IRQ_HANDLED;
1112 }
1113
Subbaraman Narayanamurthyb5ae3182017-02-17 15:14:06 -08001114 if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT))
1115 pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
1116 int_sts, fault_sts);
David Collins8885f792017-01-26 14:36:34 -08001117 return IRQ_HANDLED;
1118}
1119
1120/* short circuit irq handler */
1121static irqreturn_t qpnp_wled_sc_irq_handler(int irq, void *_wled)
1122{
1123 struct qpnp_wled *wled = _wled;
1124 int rc;
1125 u8 val;
1126
1127 rc = qpnp_wled_read_reg(wled,
1128 QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &val);
1129 if (rc < 0) {
1130 pr_err("Error in reading WLED_FAULT_STATUS rc=%d\n", rc);
1131 return IRQ_HANDLED;
1132 }
1133
1134 pr_err("WLED short circuit detected %d times fault_status=%x\n",
1135 ++wled->sc_cnt, val);
1136 mutex_lock(&wled->lock);
1137 qpnp_wled_module_en(wled, wled->ctrl_base, false);
1138 msleep(QPNP_WLED_SC_DLY_MS);
1139 qpnp_wled_module_en(wled, wled->ctrl_base, true);
1140 mutex_unlock(&wled->lock);
1141
1142 return IRQ_HANDLED;
1143}
1144
1145static bool is_avdd_trim_adjustment_required(struct qpnp_wled *wled)
1146{
1147 int rc;
1148 u8 reg = 0;
1149
1150 /*
1151 * AVDD trim adjustment is not required for pmi8998/pm660l and not
1152 * supported for pmi8994.
1153 */
1154 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1155 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE ||
1156 wled->pmic_rev_id->pmic_subtype == PMI8994_SUBTYPE)
1157 return false;
1158
1159 /*
1160 * Configure TRIM_REG only if disp_type_amoled and it has
1161 * not already been programmed by bootloader.
1162 */
1163 if (!wled->disp_type_amoled)
1164 return false;
1165
1166 rc = qpnp_wled_read_reg(wled,
1167 QPNP_WLED_CTRL_SPARE_REG(wled->ctrl_base), &reg);
1168 if (rc < 0)
1169 return false;
1170
1171 return !(reg & QPNP_WLED_AVDD_SET_BIT);
1172}
1173
1174static int qpnp_wled_gm_config(struct qpnp_wled *wled)
1175{
1176 int rc;
1177 u8 mask = 0, reg = 0;
1178
1179 /* Configure the LOOP COMP GM register */
1180 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1181 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) {
1182 if (wled->loop_auto_gm_en)
1183 reg |= QPNP_WLED_VLOOP_COMP_AUTO_GM_EN;
1184
1185 if (wled->loop_auto_gm_thresh >
1186 QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX)
1187 wled->loop_auto_gm_thresh =
1188 QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX;
1189
1190 reg |= wled->loop_auto_gm_thresh <<
1191 QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_SHIFT;
1192 mask |= QPNP_WLED_VLOOP_COMP_AUTO_GM_EN |
1193 QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_MASK;
1194 }
1195
1196 if (wled->loop_ea_gm < QPNP_WLED_LOOP_EA_GM_MIN)
1197 wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MIN;
1198 else if (wled->loop_ea_gm > QPNP_WLED_LOOP_EA_GM_MAX)
1199 wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MAX;
1200
1201 reg |= wled->loop_ea_gm | QPNP_WLED_VLOOP_COMP_GM_OVERWRITE;
1202 mask |= QPNP_WLED_VLOOP_COMP_GM_MASK |
1203 QPNP_WLED_VLOOP_COMP_GM_OVERWRITE;
1204
1205 rc = qpnp_wled_masked_write_reg(wled,
1206 QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base), mask,
1207 reg);
1208 if (rc)
1209 pr_err("write VLOOP_COMP_GM_REG failed, rc=%d]\n", rc);
1210
1211 return rc;
1212}
1213
1214static int qpnp_wled_ovp_config(struct qpnp_wled *wled)
1215{
1216 int rc, i, *ovp_table;
1217 u8 reg;
1218
1219 /*
1220 * Configure the OVP register based on ovp_mv only if display type is
1221 * not AMOLED.
1222 */
1223 if (wled->disp_type_amoled)
1224 return 0;
1225
1226 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1227 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
1228 ovp_table = qpnp_wled_ovp_thresholds_pmi8998;
1229 else
1230 ovp_table = qpnp_wled_ovp_thresholds_pmi8994;
1231
1232 for (i = 0; i < NUM_SUPPORTED_OVP_THRESHOLDS; i++) {
1233 if (wled->ovp_mv == ovp_table[i])
1234 break;
1235 }
1236
1237 if (i == NUM_SUPPORTED_OVP_THRESHOLDS) {
1238 dev_err(&wled->pdev->dev,
1239 "Invalid ovp threshold specified in device tree\n");
1240 return -EINVAL;
1241 }
1242
1243 reg = i & QPNP_WLED_OVP_MASK;
1244 rc = qpnp_wled_masked_write_reg(wled,
1245 QPNP_WLED_OVP_REG(wled->ctrl_base),
1246 QPNP_WLED_OVP_MASK, reg);
1247 if (rc)
1248 return rc;
1249
1250 return 0;
1251}
1252
1253static int qpnp_wled_avdd_trim_config(struct qpnp_wled *wled)
1254{
1255 int rc, i;
1256 u8 reg;
1257
1258 for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) {
1259 if (wled->avdd_target_voltage_mv ==
1260 qpnp_wled_avdd_target_voltages[i])
1261 break;
1262 }
1263
1264 if (i == NUM_SUPPORTED_AVDD_VOLTAGES) {
1265 dev_err(&wled->pdev->dev,
1266 "Invalid avdd target voltage specified in device tree\n");
1267 return -EINVAL;
1268 }
1269
1270 /* Update WLED_OVP register based on desired target voltage */
1271 reg = qpnp_wled_ovp_reg_settings[i];
1272 rc = qpnp_wled_masked_write_reg(wled,
1273 QPNP_WLED_OVP_REG(wled->ctrl_base),
1274 QPNP_WLED_OVP_MASK, reg);
1275 if (rc)
1276 return rc;
1277
1278 /* Update WLED_TRIM register based on desired target voltage */
1279 rc = qpnp_wled_read_reg(wled,
1280 QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base), &reg);
1281 if (rc)
1282 return rc;
1283
1284 reg += qpnp_wled_avdd_trim_adjustments[i];
1285 if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL ||
1286 (s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VAL) {
1287 dev_dbg(&wled->pdev->dev,
1288 "adjusted trim %d is not within range, capping it\n",
1289 (s8)reg);
1290 if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL)
1291 reg = QPNP_WLED_AVDD_MIN_TRIM_VAL;
1292 else
1293 reg = QPNP_WLED_AVDD_MAX_TRIM_VAL;
1294 }
1295
1296 reg &= QPNP_WLED_7P7_TRIM_MASK;
1297 rc = qpnp_wled_sec_write_reg(wled,
1298 QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base), reg);
1299 if (rc < 0)
1300 dev_err(&wled->pdev->dev, "Write to 7P7_TRIM register failed, rc=%d\n",
1301 rc);
1302 return rc;
1303}
1304
1305static int qpnp_wled_avdd_mode_config(struct qpnp_wled *wled)
1306{
1307 int rc;
1308 u8 reg = 0;
1309
1310 /*
1311 * At present, configuring the mode to SPMI/SWIRE for controlling
1312 * AVDD voltage is available only in pmi8998/pm660l.
1313 */
1314 if (wled->pmic_rev_id->pmic_subtype != PMI8998_SUBTYPE &&
1315 wled->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE)
1316 return 0;
1317
1318 /* AMOLED_VOUT should be configured for AMOLED */
1319 if (!wled->disp_type_amoled)
1320 return 0;
1321
1322 /* Configure avdd register */
1323 if (wled->avdd_target_voltage_mv > QPNP_WLED_AVDD_MAX_MV) {
1324 dev_dbg(&wled->pdev->dev, "Capping avdd target voltage to %d\n",
1325 QPNP_WLED_AVDD_MAX_MV);
1326 wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_MAX_MV;
1327 } else if (wled->avdd_target_voltage_mv < QPNP_WLED_AVDD_MIN_MV) {
1328 dev_info(&wled->pdev->dev, "Capping avdd target voltage to %d\n",
1329 QPNP_WLED_AVDD_MIN_MV);
1330 wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_MIN_MV;
1331 }
1332
1333 if (wled->avdd_mode_spmi) {
1334 reg = QPNP_WLED_AVDD_MV_TO_REG(wled->avdd_target_voltage_mv);
1335 reg |= QPNP_WLED_AVDD_SEL_SPMI_BIT;
1336 rc = qpnp_wled_write_reg(wled,
1337 QPNP_WLED_AMOLED_VOUT_REG(wled->ctrl_base),
1338 reg);
1339 if (rc < 0)
1340 pr_err("Write to AMOLED_VOUT register failed, rc=%d\n",
1341 rc);
1342 } else {
1343 rc = qpnp_wled_swire_avdd_config(wled);
1344 if (rc < 0)
1345 pr_err("Write to SWIRE_AVDD_DEFAULT register failed rc:%d\n",
1346 rc);
1347 }
1348
1349 return rc;
1350}
1351
1352static int qpnp_wled_ilim_config(struct qpnp_wled *wled)
1353{
1354 int rc, i, *ilim_table;
1355 u8 reg;
1356
1357 if (wled->ilim_ma < PMI8994_WLED_ILIM_MIN_MA)
1358 wled->ilim_ma = PMI8994_WLED_ILIM_MIN_MA;
1359
1360 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1361 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) {
1362 ilim_table = qpnp_wled_ilim_settings_pmi8998;
1363 if (wled->ilim_ma > PMI8998_WLED_ILIM_MAX_MA)
1364 wled->ilim_ma = PMI8998_WLED_ILIM_MAX_MA;
1365 } else {
1366 ilim_table = qpnp_wled_ilim_settings_pmi8994;
1367 if (wled->ilim_ma > PMI8994_WLED_ILIM_MAX_MA)
1368 wled->ilim_ma = PMI8994_WLED_ILIM_MAX_MA;
1369 }
1370
1371 for (i = 0; i < NUM_SUPPORTED_ILIM_THRESHOLDS; i++) {
1372 if (wled->ilim_ma == ilim_table[i])
1373 break;
1374 }
1375
1376 if (i == NUM_SUPPORTED_ILIM_THRESHOLDS) {
1377 dev_err(&wled->pdev->dev,
1378 "Invalid ilim threshold specified in device tree\n");
1379 return -EINVAL;
1380 }
1381
1382 reg = (i & QPNP_WLED_ILIM_MASK) | QPNP_WLED_ILIM_OVERWRITE;
1383 rc = qpnp_wled_masked_write_reg(wled,
1384 QPNP_WLED_ILIM_REG(wled->ctrl_base),
1385 QPNP_WLED_ILIM_MASK | QPNP_WLED_ILIM_OVERWRITE, reg);
1386 if (rc < 0)
1387 dev_err(&wled->pdev->dev, "Write to ILIM register failed, rc=%d\n",
1388 rc);
1389 return rc;
1390}
1391
1392static int qpnp_wled_vref_config(struct qpnp_wled *wled)
1393{
1394
1395 struct wled_vref_setting vref_setting;
1396 int rc;
1397 u8 reg = 0;
1398
1399 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1400 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
1401 vref_setting = vref_setting_pmi8998;
1402 else
1403 vref_setting = vref_setting_pmi8994;
1404
1405 if (wled->vref_uv < vref_setting.min_uv)
1406 wled->vref_uv = vref_setting.min_uv;
1407 else if (wled->vref_uv > vref_setting.max_uv)
1408 wled->vref_uv = vref_setting.max_uv;
1409
1410 reg |= DIV_ROUND_CLOSEST(wled->vref_uv - vref_setting.min_uv,
1411 vref_setting.step_uv);
1412
1413 rc = qpnp_wled_masked_write_reg(wled,
1414 QPNP_WLED_VREF_REG(wled->ctrl_base),
1415 QPNP_WLED_VREF_MASK, reg);
1416 if (rc)
1417 pr_err("Write VREF_REG failed, rc=%d\n", rc);
1418
1419 return rc;
1420}
1421
1422/* Configure WLED registers */
1423static int qpnp_wled_config(struct qpnp_wled *wled)
1424{
1425 int rc, i, temp;
1426 u8 reg = 0;
1427
1428 /* Configure display type */
1429 rc = qpnp_wled_set_disp(wled, wled->ctrl_base);
1430 if (rc < 0)
1431 return rc;
1432
1433 /* Configure the FEEDBACK OUTPUT register */
1434 rc = qpnp_wled_read_reg(wled, QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
1435 &reg);
1436 if (rc < 0)
1437 return rc;
1438 reg &= QPNP_WLED_FDBK_OP_MASK;
1439 reg |= wled->fdbk_op;
1440 rc = qpnp_wled_write_reg(wled, QPNP_WLED_FDBK_OP_REG(wled->ctrl_base),
1441 reg);
1442 if (rc)
1443 return rc;
1444
1445 /* Configure the VREF register */
1446 rc = qpnp_wled_vref_config(wled);
1447 if (rc < 0) {
1448 pr_err("Error in configuring wled vref, rc=%d\n", rc);
1449 return rc;
1450 }
1451
1452 /* Configure VLOOP_COMP_GM register */
1453 rc = qpnp_wled_gm_config(wled);
1454 if (rc < 0) {
1455 pr_err("Error in configureing wled gm, rc=%d\n", rc);
1456 return rc;
1457 }
1458
1459 /* Configure the ILIM register */
1460 rc = qpnp_wled_ilim_config(wled);
1461 if (rc < 0) {
1462 pr_err("Error in configuring wled ilim, rc=%d\n", rc);
1463 return rc;
1464 }
1465
1466 /* Configure auto PFM mode for LCD mode only */
1467 if ((wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1468 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
1469 && !wled->disp_type_amoled) {
1470 reg = 0;
1471 reg |= wled->lcd_auto_pfm_thresh;
1472 reg |= wled->lcd_auto_pfm_en <<
1473 QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT;
1474 rc = qpnp_wled_masked_write_reg(wled,
1475 QPNP_WLED_LCD_AUTO_PFM_REG(wled->ctrl_base),
1476 QPNP_WLED_LCD_AUTO_PFM_EN_BIT |
1477 QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK, reg);
1478 if (rc < 0) {
1479 pr_err("Write LCD_AUTO_PFM failed, rc=%d\n", rc);
1480 return rc;
1481 }
1482 }
1483
1484 /* Configure the Soft start Ramp delay: for AMOLED - 0,for LCD - 2 */
1485 reg = (wled->disp_type_amoled) ? 0 : 2;
1486 rc = qpnp_wled_write_reg(wled,
1487 QPNP_WLED_SOFTSTART_RAMP_DLY(wled->ctrl_base), reg);
1488 if (rc)
1489 return rc;
1490
1491 /* Configure the MAX BOOST DUTY register */
1492 if (wled->boost_duty_ns < QPNP_WLED_BOOST_DUTY_MIN_NS)
1493 wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MIN_NS;
1494 else if (wled->boost_duty_ns > QPNP_WLED_BOOST_DUTY_MAX_NS)
1495 wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MAX_NS;
1496
1497 rc = qpnp_wled_read_reg(wled, QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base),
1498 &reg);
1499 if (rc < 0)
1500 return rc;
1501 reg &= QPNP_WLED_BOOST_DUTY_MASK;
1502 reg |= (wled->boost_duty_ns / QPNP_WLED_BOOST_DUTY_STEP_NS);
1503 rc = qpnp_wled_write_reg(wled,
1504 QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base), reg);
1505 if (rc)
1506 return rc;
1507
1508 /* Configure the SWITCHING FREQ register */
1509 if (wled->switch_freq_khz == QPNP_WLED_SWITCH_FREQ_1600_KHZ)
1510 temp = QPNP_WLED_SWITCH_FREQ_1600_KHZ_CODE;
1511 else
1512 temp = QPNP_WLED_SWITCH_FREQ_800_KHZ_CODE;
1513
1514 rc = qpnp_wled_read_reg(wled,
1515 QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base), &reg);
1516 if (rc < 0)
1517 return rc;
1518 reg &= QPNP_WLED_SWITCH_FREQ_MASK;
1519 reg |= (temp | QPNP_WLED_SWITCH_FREQ_OVERWRITE);
1520 rc = qpnp_wled_write_reg(wled,
1521 QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base), reg);
1522 if (rc)
1523 return rc;
1524
1525 rc = qpnp_wled_ovp_config(wled);
1526 if (rc < 0) {
1527 pr_err("Error in configuring OVP threshold, rc=%d\n", rc);
1528 return rc;
1529 }
1530
1531 if (is_avdd_trim_adjustment_required(wled)) {
1532 rc = qpnp_wled_avdd_trim_config(wled);
1533 if (rc < 0)
1534 return rc;
1535 }
1536
1537 rc = qpnp_wled_avdd_mode_config(wled);
1538 if (rc < 0)
1539 return rc;
1540
1541 /* Configure the MODULATION register */
1542 if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_1200_KHZ) {
1543 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_1200_KHZ;
1544 temp = 3;
1545 } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_2400_KHZ) {
1546 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_2400_KHZ;
1547 temp = 2;
1548 } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_9600_KHZ) {
1549 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ;
1550 temp = 1;
1551 } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_19200_KHZ) {
1552 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_19200_KHZ;
1553 temp = 0;
1554 } else {
1555 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ;
1556 temp = 1;
1557 }
1558
1559 rc = qpnp_wled_read_reg(wled, QPNP_WLED_MOD_REG(wled->sink_base), &reg);
1560 if (rc < 0)
1561 return rc;
1562 reg &= QPNP_WLED_MOD_FREQ_MASK;
1563 reg |= (temp << QPNP_WLED_MOD_FREQ_SHIFT);
1564
1565 reg &= QPNP_WLED_PHASE_STAG_MASK;
1566 reg |= (wled->en_phase_stag << QPNP_WLED_PHASE_STAG_SHIFT);
1567
1568 reg &= QPNP_WLED_ACC_CLK_FREQ_MASK;
1569 reg |= (temp << QPNP_WLED_ACC_CLK_FREQ_SHIFT);
1570
1571 reg &= QPNP_WLED_DIM_RES_MASK;
1572 reg |= (wled->en_9b_dim_res << QPNP_WLED_DIM_RES_SHIFT);
1573
1574 if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) {
1575 reg &= QPNP_WLED_DIM_HYB_MASK;
1576 reg |= (1 << QPNP_WLED_DIM_HYB_SHIFT);
1577 } else {
1578 reg &= QPNP_WLED_DIM_HYB_MASK;
1579 reg |= (0 << QPNP_WLED_DIM_HYB_SHIFT);
1580 reg &= QPNP_WLED_DIM_ANA_MASK;
1581 reg |= wled->dim_mode;
1582 }
1583
1584 rc = qpnp_wled_write_reg(wled, QPNP_WLED_MOD_REG(wled->sink_base), reg);
1585 if (rc)
1586 return rc;
1587
1588 /* Configure the HYBRID THRESHOLD register */
1589 if (wled->hyb_thres < QPNP_WLED_HYB_THRES_MIN)
1590 wled->hyb_thres = QPNP_WLED_HYB_THRES_MIN;
1591 else if (wled->hyb_thres > QPNP_WLED_HYB_THRES_MAX)
1592 wled->hyb_thres = QPNP_WLED_HYB_THRES_MAX;
1593
1594 rc = qpnp_wled_read_reg(wled, QPNP_WLED_HYB_THRES_REG(wled->sink_base),
1595 &reg);
1596 if (rc < 0)
1597 return rc;
1598 reg &= QPNP_WLED_HYB_THRES_MASK;
1599 temp = fls(wled->hyb_thres / QPNP_WLED_HYB_THRES_MIN) - 1;
1600 reg |= temp;
1601 rc = qpnp_wled_write_reg(wled, QPNP_WLED_HYB_THRES_REG(wled->sink_base),
1602 reg);
1603 if (rc)
1604 return rc;
1605
1606 /* Configure TEST5 register */
1607 if (wled->dim_mode == QPNP_WLED_DIM_DIGITAL) {
1608 reg = QPNP_WLED_SINK_TEST5_DIG;
1609 } else {
1610 reg = QPNP_WLED_SINK_TEST5_HYB;
1611 if (wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
1612 reg |= QPNP_WLED_SINK_TEST5_HVG_PULL_STR_BIT;
1613 }
1614
1615 rc = qpnp_wled_sec_write_reg(wled,
1616 QPNP_WLED_SINK_TEST5_REG(wled->sink_base), reg);
1617 if (rc)
1618 return rc;
1619
1620 /* disable all current sinks and enable selected strings */
1621 reg = 0x00;
1622 rc = qpnp_wled_write_reg(wled, QPNP_WLED_CURR_SINK_REG(wled->sink_base),
1623 reg);
1624
1625 for (i = 0; i < wled->num_strings; i++) {
1626 if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) {
1627 dev_err(&wled->pdev->dev, "Invalid string number\n");
1628 return -EINVAL;
1629 }
1630
1631 /* MODULATOR */
1632 rc = qpnp_wled_read_reg(wled,
1633 QPNP_WLED_MOD_EN_REG(wled->sink_base,
1634 wled->strings[i]), &reg);
1635 if (rc < 0)
1636 return rc;
1637 reg &= QPNP_WLED_MOD_EN_MASK;
1638 reg |= (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT);
1639
1640 if (wled->dim_mode == QPNP_WLED_DIM_HYBRID)
1641 reg &= QPNP_WLED_GATE_DRV_MASK;
1642 else
1643 reg |= ~QPNP_WLED_GATE_DRV_MASK;
1644
1645 rc = qpnp_wled_write_reg(wled,
1646 QPNP_WLED_MOD_EN_REG(wled->sink_base,
1647 wled->strings[i]), reg);
1648 if (rc)
1649 return rc;
1650
1651 /* SYNC DELAY */
1652 if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
1653 wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
1654
1655 rc = qpnp_wled_read_reg(wled,
1656 QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
1657 wled->strings[i]), &reg);
1658 if (rc < 0)
1659 return rc;
1660 reg &= QPNP_WLED_SYNC_DLY_MASK;
1661 temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
1662 reg |= temp;
1663 rc = qpnp_wled_write_reg(wled,
1664 QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
1665 wled->strings[i]), reg);
1666 if (rc)
1667 return rc;
1668
1669 /* FULL SCALE CURRENT */
1670 if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
1671 wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
1672
1673 rc = qpnp_wled_read_reg(wled,
1674 QPNP_WLED_FS_CURR_REG(wled->sink_base,
1675 wled->strings[i]), &reg);
1676 if (rc < 0)
1677 return rc;
1678 reg &= QPNP_WLED_FS_CURR_MASK;
1679 temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
1680 reg |= temp;
1681 rc = qpnp_wled_write_reg(wled,
1682 QPNP_WLED_FS_CURR_REG(wled->sink_base,
1683 wled->strings[i]), reg);
1684 if (rc)
1685 return rc;
1686
1687 /* CABC */
1688 rc = qpnp_wled_read_reg(wled,
1689 QPNP_WLED_CABC_REG(wled->sink_base,
1690 wled->strings[i]), &reg);
1691 if (rc < 0)
1692 return rc;
1693 reg &= QPNP_WLED_CABC_MASK;
1694 reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT);
1695 rc = qpnp_wled_write_reg(wled,
1696 QPNP_WLED_CABC_REG(wled->sink_base,
1697 wled->strings[i]), reg);
1698 if (rc)
1699 return rc;
1700
1701 /* Enable CURRENT SINK */
1702 rc = qpnp_wled_read_reg(wled,
1703 QPNP_WLED_CURR_SINK_REG(wled->sink_base), &reg);
1704 if (rc < 0)
1705 return rc;
1706 temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT;
1707 reg |= (1 << temp);
1708 rc = qpnp_wled_write_reg(wled,
1709 QPNP_WLED_CURR_SINK_REG(wled->sink_base), reg);
1710 if (rc)
1711 return rc;
1712 }
1713
1714 rc = qpnp_wled_sync_reg_toggle(wled);
1715 if (rc < 0) {
1716 dev_err(&wled->pdev->dev, "Failed to toggle sync reg %d\n", rc);
1717 return rc;
1718 }
1719
1720 /* setup ovp and sc irqs */
1721 if (wled->ovp_irq >= 0) {
1722 rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq,
1723 NULL, qpnp_wled_ovp_irq_handler, IRQF_ONESHOT,
1724 "qpnp_wled_ovp_irq", wled);
1725 if (rc < 0) {
1726 dev_err(&wled->pdev->dev,
1727 "Unable to request ovp(%d) IRQ(err:%d)\n",
1728 wled->ovp_irq, rc);
1729 return rc;
1730 }
Subbaraman Narayanamurthyb5ae3182017-02-17 15:14:06 -08001731 disable_irq(wled->ovp_irq);
1732 wled->ovp_irq_disabled = true;
David Collins8885f792017-01-26 14:36:34 -08001733 }
1734
1735 if (wled->sc_irq >= 0) {
1736 wled->sc_cnt = 0;
1737 rc = devm_request_threaded_irq(&wled->pdev->dev, wled->sc_irq,
1738 NULL, qpnp_wled_sc_irq_handler, IRQF_ONESHOT,
1739 "qpnp_wled_sc_irq", wled);
1740 if (rc < 0) {
1741 dev_err(&wled->pdev->dev,
1742 "Unable to request sc(%d) IRQ(err:%d)\n",
1743 wled->sc_irq, rc);
1744 return rc;
1745 }
1746
1747 rc = qpnp_wled_read_reg(wled,
1748 QPNP_WLED_SC_PRO_REG(wled->ctrl_base), &reg);
1749 if (rc < 0)
1750 return rc;
1751 reg &= QPNP_WLED_EN_SC_DEB_CYCLES_MASK;
1752 reg |= 1 << QPNP_WLED_EN_SC_SHIFT;
1753
1754 if (wled->sc_deb_cycles < QPNP_WLED_SC_DEB_CYCLES_MIN)
1755 wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_MIN;
1756 else if (wled->sc_deb_cycles > QPNP_WLED_SC_DEB_CYCLES_MAX)
1757 wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_MAX;
1758 temp = fls(wled->sc_deb_cycles) - QPNP_WLED_SC_DEB_CYCLES_SUB;
1759 reg |= (temp << 1);
1760
1761 if (wled->disp_type_amoled)
1762 reg |= QPNP_WLED_SC_PRO_EN_DSCHGR;
1763
1764 rc = qpnp_wled_write_reg(wled,
1765 QPNP_WLED_SC_PRO_REG(wled->ctrl_base), reg);
1766 if (rc)
1767 return rc;
1768
1769 if (wled->en_ext_pfet_sc_pro) {
1770 reg = QPNP_WLED_EXT_FET_DTEST2;
1771 rc = qpnp_wled_sec_write_reg(wled,
1772 QPNP_WLED_TEST1_REG(wled->ctrl_base),
1773 reg);
1774 if (rc)
1775 return rc;
1776 }
1777 } else {
1778 rc = qpnp_wled_read_reg(wled,
1779 QPNP_WLED_SC_PRO_REG(wled->ctrl_base), &reg);
1780 if (rc < 0)
1781 return rc;
1782 reg &= QPNP_WLED_EN_DEB_CYCLES_MASK;
1783
1784 if (wled->sc_deb_cycles < QPNP_WLED_SC_DEB_CYCLES_MIN)
1785 wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_MIN;
1786 else if (wled->sc_deb_cycles > QPNP_WLED_SC_DEB_CYCLES_MAX)
1787 wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_MAX;
1788 temp = fls(wled->sc_deb_cycles) - QPNP_WLED_SC_DEB_CYCLES_SUB;
1789 reg |= (temp << 1);
1790
1791 rc = qpnp_wled_write_reg(wled,
1792 QPNP_WLED_SC_PRO_REG(wled->ctrl_base), reg);
1793 if (rc)
1794 return rc;
1795 }
1796
1797 return 0;
1798}
1799
1800/* parse wled dtsi parameters */
1801static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
1802{
1803 struct platform_device *pdev = wled->pdev;
1804 struct property *prop;
1805 const char *temp_str;
1806 u32 temp_val;
1807 int rc, i;
1808 u8 *strings;
1809
1810 wled->cdev.name = "wled";
1811 rc = of_property_read_string(pdev->dev.of_node,
1812 "linux,name", &wled->cdev.name);
1813 if (rc && (rc != -EINVAL)) {
1814 dev_err(&pdev->dev, "Unable to read led name\n");
1815 return rc;
1816 }
1817
1818 wled->cdev.default_trigger = QPNP_WLED_TRIGGER_NONE;
1819 rc = of_property_read_string(pdev->dev.of_node, "linux,default-trigger",
1820 &wled->cdev.default_trigger);
1821 if (rc && (rc != -EINVAL)) {
1822 dev_err(&pdev->dev, "Unable to read led trigger\n");
1823 return rc;
1824 }
1825
1826 wled->disp_type_amoled = of_property_read_bool(pdev->dev.of_node,
1827 "qcom,disp-type-amoled");
1828 if (wled->disp_type_amoled) {
1829 wled->vref_psm_mv = QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV;
1830 rc = of_property_read_u32(pdev->dev.of_node,
1831 "qcom,vref-psm-mv", &temp_val);
1832 if (!rc) {
1833 wled->vref_psm_mv = temp_val;
1834 } else if (rc != -EINVAL) {
1835 dev_err(&pdev->dev, "Unable to read vref-psm\n");
1836 return rc;
1837 }
1838
1839 wled->loop_comp_res_kohm =
1840 QPNP_WLED_LOOP_COMP_RES_DFLT_AMOLED_KOHM;
1841 rc = of_property_read_u32(pdev->dev.of_node,
1842 "qcom,loop-comp-res-kohm", &temp_val);
1843 if (!rc) {
1844 wled->loop_comp_res_kohm = temp_val;
1845 } else if (rc != -EINVAL) {
1846 dev_err(&pdev->dev, "Unable to read loop-comp-res-kohm\n");
1847 return rc;
1848 }
1849
1850 wled->avdd_mode_spmi = of_property_read_bool(pdev->dev.of_node,
1851 "qcom,avdd-mode-spmi");
1852
1853 wled->avdd_target_voltage_mv = QPNP_WLED_DFLT_AVDD_MV;
1854 rc = of_property_read_u32(pdev->dev.of_node,
1855 "qcom,avdd-target-voltage-mv", &temp_val);
1856 if (!rc) {
1857 wled->avdd_target_voltage_mv = temp_val;
1858 } else if (rc != -EINVAL) {
1859 dev_err(&pdev->dev, "Unable to read avdd target voltage\n");
1860 return rc;
1861 }
1862 }
1863
1864 if (wled->disp_type_amoled) {
1865 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1866 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
1867 wled->loop_ea_gm =
1868 QPNP_WLED_LOOP_GM_DFLT_AMOLED_PMI8998;
1869 else
1870 wled->loop_ea_gm =
1871 QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED_PMI8994;
1872 } else {
1873 wled->loop_ea_gm = QPNP_WLED_LOOP_GM_DFLT_WLED;
1874 }
1875
1876 rc = of_property_read_u32(pdev->dev.of_node,
1877 "qcom,loop-ea-gm", &temp_val);
1878 if (!rc) {
1879 wled->loop_ea_gm = temp_val;
1880 } else if (rc != -EINVAL) {
1881 dev_err(&pdev->dev, "Unable to read loop-ea-gm\n");
1882 return rc;
1883 }
1884
1885 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1886 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) {
1887 wled->loop_auto_gm_en =
1888 of_property_read_bool(pdev->dev.of_node,
1889 "qcom,loop-auto-gm-en");
1890 wled->loop_auto_gm_thresh = QPNP_WLED_LOOP_AUTO_GM_DFLT_THRESH;
1891 rc = of_property_read_u8(pdev->dev.of_node,
1892 "qcom,loop-auto-gm-thresh",
1893 &wled->loop_auto_gm_thresh);
1894 if (rc && rc != -EINVAL) {
1895 dev_err(&pdev->dev,
1896 "Unable to read loop-auto-gm-thresh\n");
1897 return rc;
1898 }
1899 }
1900
1901 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1902 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) {
1903
1904 if (wled->pmic_rev_id->rev4 == PMI8998_V2P0_REV4)
1905 wled->lcd_auto_pfm_en = false;
1906 else
1907 wled->lcd_auto_pfm_en = true;
1908
1909 wled->lcd_auto_pfm_thresh = QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH;
1910 rc = of_property_read_u8(pdev->dev.of_node,
1911 "qcom,lcd-auto-pfm-thresh",
1912 &wled->lcd_auto_pfm_thresh);
1913 if (rc && rc != -EINVAL) {
1914 dev_err(&pdev->dev,
1915 "Unable to read lcd-auto-pfm-thresh\n");
1916 return rc;
1917 }
1918
1919 if (wled->lcd_auto_pfm_thresh >
1920 QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX)
1921 wled->lcd_auto_pfm_thresh =
1922 QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX;
1923 }
1924
1925 wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_DFLT;
1926 rc = of_property_read_u32(pdev->dev.of_node,
1927 "qcom,sc-deb-cycles", &temp_val);
1928 if (!rc) {
1929 wled->sc_deb_cycles = temp_val;
1930 } else if (rc != -EINVAL) {
1931 dev_err(&pdev->dev, "Unable to read sc debounce cycles\n");
1932 return rc;
1933 }
1934
1935 wled->fdbk_op = QPNP_WLED_FDBK_AUTO;
1936 rc = of_property_read_string(pdev->dev.of_node,
1937 "qcom,fdbk-output", &temp_str);
1938 if (!rc) {
1939 if (strcmp(temp_str, "wled1") == 0)
1940 wled->fdbk_op = QPNP_WLED_FDBK_WLED1;
1941 else if (strcmp(temp_str, "wled2") == 0)
1942 wled->fdbk_op = QPNP_WLED_FDBK_WLED2;
1943 else if (strcmp(temp_str, "wled3") == 0)
1944 wled->fdbk_op = QPNP_WLED_FDBK_WLED3;
1945 else if (strcmp(temp_str, "wled4") == 0)
1946 wled->fdbk_op = QPNP_WLED_FDBK_WLED4;
1947 else
1948 wled->fdbk_op = QPNP_WLED_FDBK_AUTO;
1949 } else if (rc != -EINVAL) {
1950 dev_err(&pdev->dev, "Unable to read feedback output\n");
1951 return rc;
1952 }
1953
1954 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1955 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
1956 wled->vref_uv = vref_setting_pmi8998.default_uv;
1957 else
1958 wled->vref_uv = vref_setting_pmi8994.default_uv;
1959 rc = of_property_read_u32(pdev->dev.of_node,
1960 "qcom,vref-uv", &temp_val);
1961 if (!rc) {
1962 wled->vref_uv = temp_val;
1963 } else if (rc != -EINVAL) {
1964 dev_err(&pdev->dev, "Unable to read vref\n");
1965 return rc;
1966 }
1967
1968 wled->switch_freq_khz = QPNP_WLED_SWITCH_FREQ_800_KHZ;
1969 rc = of_property_read_u32(pdev->dev.of_node,
1970 "qcom,switch-freq-khz", &temp_val);
1971 if (!rc) {
1972 wled->switch_freq_khz = temp_val;
1973 } else if (rc != -EINVAL) {
1974 dev_err(&pdev->dev, "Unable to read switch freq\n");
1975 return rc;
1976 }
1977
1978 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1979 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
1980 wled->ovp_mv = 29600;
1981 else
1982 wled->ovp_mv = 29500;
1983 rc = of_property_read_u32(pdev->dev.of_node,
1984 "qcom,ovp-mv", &temp_val);
1985 if (!rc) {
1986 wled->ovp_mv = temp_val;
1987 } else if (rc != -EINVAL) {
1988 dev_err(&pdev->dev, "Unable to read ovp\n");
1989 return rc;
1990 }
1991
1992 if (wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE ||
1993 wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) {
1994 if (wled->disp_type_amoled)
1995 wled->ilim_ma = PMI8998_AMOLED_DFLT_ILIM_MA;
1996 else
1997 wled->ilim_ma = PMI8998_WLED_DFLT_ILIM_MA;
1998 } else {
1999 if (wled->disp_type_amoled)
2000 wled->ilim_ma = PMI8994_AMOLED_DFLT_ILIM_MA;
2001 else
2002 wled->ilim_ma = PMI8994_WLED_DFLT_ILIM_MA;
2003 }
2004
2005 rc = of_property_read_u32(pdev->dev.of_node,
2006 "qcom,ilim-ma", &temp_val);
2007 if (!rc) {
2008 wled->ilim_ma = temp_val;
2009 } else if (rc != -EINVAL) {
2010 dev_err(&pdev->dev, "Unable to read ilim\n");
2011 return rc;
2012 }
2013
2014 wled->boost_duty_ns = QPNP_WLED_DEF_BOOST_DUTY_NS;
2015 rc = of_property_read_u32(pdev->dev.of_node,
2016 "qcom,boost-duty-ns", &temp_val);
2017 if (!rc) {
2018 wled->boost_duty_ns = temp_val;
2019 } else if (rc != -EINVAL) {
2020 dev_err(&pdev->dev, "Unable to read boost duty\n");
2021 return rc;
2022 }
2023
2024 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ;
2025 rc = of_property_read_u32(pdev->dev.of_node,
2026 "qcom,mod-freq-khz", &temp_val);
2027 if (!rc) {
2028 wled->mod_freq_khz = temp_val;
2029 } else if (rc != -EINVAL) {
2030 dev_err(&pdev->dev, "Unable to read modulation freq\n");
2031 return rc;
2032 }
2033
2034 wled->dim_mode = QPNP_WLED_DIM_HYBRID;
2035 rc = of_property_read_string(pdev->dev.of_node,
2036 "qcom,dim-mode", &temp_str);
2037 if (!rc) {
2038 if (strcmp(temp_str, "analog") == 0)
2039 wled->dim_mode = QPNP_WLED_DIM_ANALOG;
2040 else if (strcmp(temp_str, "digital") == 0)
2041 wled->dim_mode = QPNP_WLED_DIM_DIGITAL;
2042 else
2043 wled->dim_mode = QPNP_WLED_DIM_HYBRID;
2044 } else if (rc != -EINVAL) {
2045 dev_err(&pdev->dev, "Unable to read dim mode\n");
2046 return rc;
2047 }
2048
2049 if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) {
2050 wled->hyb_thres = QPNP_WLED_DEF_HYB_THRES;
2051 rc = of_property_read_u32(pdev->dev.of_node,
2052 "qcom,hyb-thres", &temp_val);
2053 if (!rc) {
2054 wled->hyb_thres = temp_val;
2055 } else if (rc != -EINVAL) {
2056 dev_err(&pdev->dev, "Unable to read hyb threshold\n");
2057 return rc;
2058 }
2059 }
2060
2061 wled->sync_dly_us = QPNP_WLED_DEF_SYNC_DLY_US;
2062 rc = of_property_read_u32(pdev->dev.of_node,
2063 "qcom,sync-dly-us", &temp_val);
2064 if (!rc) {
2065 wled->sync_dly_us = temp_val;
2066 } else if (rc != -EINVAL) {
2067 dev_err(&pdev->dev, "Unable to read sync delay\n");
2068 return rc;
2069 }
2070
2071 wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
2072 rc = of_property_read_u32(pdev->dev.of_node,
2073 "qcom,fs-curr-ua", &temp_val);
2074 if (!rc) {
2075 wled->fs_curr_ua = temp_val;
2076 } else if (rc != -EINVAL) {
2077 dev_err(&pdev->dev, "Unable to read full scale current\n");
2078 return rc;
2079 }
2080
2081 wled->cons_sync_write_delay_us = 0;
2082 rc = of_property_read_u32(pdev->dev.of_node,
2083 "qcom,cons-sync-write-delay-us", &temp_val);
2084 if (!rc)
2085 wled->cons_sync_write_delay_us = temp_val;
2086
2087 wled->en_9b_dim_res = of_property_read_bool(pdev->dev.of_node,
2088 "qcom,en-9b-dim-res");
2089 wled->en_phase_stag = of_property_read_bool(pdev->dev.of_node,
2090 "qcom,en-phase-stag");
2091 wled->en_cabc = of_property_read_bool(pdev->dev.of_node,
2092 "qcom,en-cabc");
2093
2094 prop = of_find_property(pdev->dev.of_node,
2095 "qcom,led-strings-list", &temp_val);
2096 if (!prop || !temp_val || temp_val > QPNP_WLED_MAX_STRINGS) {
2097 dev_err(&pdev->dev, "Invalid strings info, use default");
2098 wled->num_strings = QPNP_WLED_MAX_STRINGS;
2099 for (i = 0; i < wled->num_strings; i++)
2100 wled->strings[i] = i;
2101 } else {
2102 wled->num_strings = temp_val;
2103 strings = prop->value;
2104 for (i = 0; i < wled->num_strings; ++i)
2105 wled->strings[i] = strings[i];
2106 }
2107
2108 wled->ovp_irq = platform_get_irq_byname(pdev, "ovp-irq");
2109 if (wled->ovp_irq < 0)
2110 dev_dbg(&pdev->dev, "ovp irq is not used\n");
2111
2112 wled->sc_irq = platform_get_irq_byname(pdev, "sc-irq");
2113 if (wled->sc_irq < 0)
2114 dev_dbg(&pdev->dev, "sc irq is not used\n");
2115
2116 wled->en_ext_pfet_sc_pro = of_property_read_bool(pdev->dev.of_node,
2117 "qcom,en-ext-pfet-sc-pro");
2118
Subbaraman Narayanamurthy55698842017-02-17 15:48:47 -08002119 wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node,
2120 "qcom,lcd-psm-ctrl");
David Collins8885f792017-01-26 14:36:34 -08002121 return 0;
2122}
2123
2124static int qpnp_wled_probe(struct platform_device *pdev)
2125{
2126 struct qpnp_wled *wled;
2127 struct device_node *revid_node;
2128 int rc = 0, i;
2129 const __be32 *prop;
2130
2131 wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL);
2132 if (!wled)
2133 return -ENOMEM;
Stephen Boydd71c7f62017-03-20 15:49:04 -07002134
2135 wled->regmap = dev_get_regmap(pdev->dev.parent, NULL);
2136 if (!wled->regmap) {
2137 dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
2138 return -EINVAL;
2139 }
David Collins8885f792017-01-26 14:36:34 -08002140
2141 wled->pdev = pdev;
2142
2143 revid_node = of_parse_phandle(pdev->dev.of_node, "qcom,pmic-revid", 0);
2144 if (!revid_node) {
2145 pr_err("Missing qcom,pmic-revid property - driver failed\n");
2146 return -EINVAL;
2147 }
2148
2149 wled->pmic_rev_id = get_revid_data(revid_node);
2150 if (IS_ERR_OR_NULL(wled->pmic_rev_id)) {
2151 pr_err("Unable to get pmic_revid rc=%ld\n",
2152 PTR_ERR(wled->pmic_rev_id));
2153 /*
2154 * the revid peripheral must be registered, any failure
2155 * here only indicates that the rev-id module has not
2156 * probed yet.
2157 */
2158 return -EPROBE_DEFER;
2159 }
2160
2161 pr_debug("PMIC subtype %d Digital major %d\n",
2162 wled->pmic_rev_id->pmic_subtype, wled->pmic_rev_id->rev4);
2163
2164 prop = of_get_address_by_name(pdev->dev.of_node, QPNP_WLED_SINK_BASE,
2165 0, 0);
2166 if (!prop) {
2167 dev_err(&pdev->dev, "Couldnt find sink's addr rc %d\n", rc);
2168 return rc;
2169 }
2170 wled->sink_base = be32_to_cpu(*prop);
2171
2172 prop = of_get_address_by_name(pdev->dev.of_node, QPNP_WLED_CTRL_BASE,
2173 0, 0);
2174 if (!prop) {
2175 dev_err(&pdev->dev, "Couldnt find ctrl's addr rc = %d\n", rc);
2176 return rc;
2177 }
2178 wled->ctrl_base = be32_to_cpu(*prop);
2179
2180 dev_set_drvdata(&pdev->dev, wled);
2181
2182 rc = qpnp_wled_parse_dt(wled);
2183 if (rc) {
2184 dev_err(&pdev->dev, "DT parsing failed\n");
2185 return rc;
2186 }
2187
2188 mutex_init(&wled->bus_lock);
2189 rc = qpnp_wled_config(wled);
2190 if (rc) {
2191 dev_err(&pdev->dev, "wled config failed\n");
2192 return rc;
2193 }
2194
2195 mutex_init(&wled->lock);
2196 INIT_WORK(&wled->work, qpnp_wled_work);
2197 wled->ramp_ms = QPNP_WLED_RAMP_DLY_MS;
2198 wled->ramp_step = 1;
2199
2200 wled->cdev.brightness_set = qpnp_wled_set;
2201 wled->cdev.brightness_get = qpnp_wled_get;
2202
2203 wled->cdev.max_brightness = WLED_MAX_LEVEL_4095;
2204
2205 rc = led_classdev_register(&pdev->dev, &wled->cdev);
2206 if (rc) {
2207 dev_err(&pdev->dev, "wled registration failed(%d)\n", rc);
2208 goto wled_register_fail;
2209 }
2210
2211 for (i = 0; i < ARRAY_SIZE(qpnp_wled_attrs); i++) {
2212 rc = sysfs_create_file(&wled->cdev.dev->kobj,
2213 &qpnp_wled_attrs[i].attr);
2214 if (rc < 0) {
2215 dev_err(&pdev->dev, "sysfs creation failed\n");
2216 goto sysfs_fail;
2217 }
2218 }
2219
2220 return 0;
2221
2222sysfs_fail:
2223 for (i--; i >= 0; i--)
2224 sysfs_remove_file(&wled->cdev.dev->kobj,
2225 &qpnp_wled_attrs[i].attr);
2226 led_classdev_unregister(&wled->cdev);
2227wled_register_fail:
2228 cancel_work_sync(&wled->work);
2229 mutex_destroy(&wled->lock);
2230 return rc;
2231}
2232
2233static int qpnp_wled_remove(struct platform_device *pdev)
2234{
2235 struct qpnp_wled *wled = dev_get_drvdata(&pdev->dev);
2236 int i;
2237
2238 for (i = 0; i < ARRAY_SIZE(qpnp_wled_attrs); i++)
2239 sysfs_remove_file(&wled->cdev.dev->kobj,
2240 &qpnp_wled_attrs[i].attr);
2241
2242 led_classdev_unregister(&wled->cdev);
2243 cancel_work_sync(&wled->work);
2244 mutex_destroy(&wled->lock);
2245
2246 return 0;
2247}
2248
2249static const struct of_device_id spmi_match_table[] = {
2250 { .compatible = "qcom,qpnp-wled",},
2251 { },
2252};
2253
2254static struct platform_driver qpnp_wled_driver = {
2255 .driver = {
2256 .name = "qcom,qpnp-wled",
2257 .of_match_table = spmi_match_table,
2258 },
2259 .probe = qpnp_wled_probe,
2260 .remove = qpnp_wled_remove,
2261};
2262
2263static int __init qpnp_wled_init(void)
2264{
2265 return platform_driver_register(&qpnp_wled_driver);
2266}
2267module_init(qpnp_wled_init);
2268
2269static void __exit qpnp_wled_exit(void)
2270{
2271 platform_driver_unregister(&qpnp_wled_driver);
2272}
2273module_exit(qpnp_wled_exit);
2274
2275MODULE_DESCRIPTION("QPNP WLED driver");
2276MODULE_LICENSE("GPL v2");
2277MODULE_ALIAS("leds:leds-qpnp-wled");