blob: b96150cfb6bccc29a58b5b0fe6cd5939f1213bf5 [file] [log] [blame]
Aparna Mallavarapu083766b2014-07-21 21:04:48 +05301 /* Copyright (c) 2014, The Linux Foundation. All rights reserved.
2
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <stdio.h>
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -080030#include <string.h>
31#include <stdlib.h>
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053032#include <err.h>
33#include <qpnp_wled.h>
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -080034#include <pm8x41_wled.h>
35#include <qtimer.h>
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053036
37static int fls(uint16_t n)
38{
39 int i = 0;
40 for (; n; n >>= 1, i++);
41 return i;
42}
43
44static struct qpnp_wled *gwled;
Aparna Mallavarapua42de902014-12-08 17:25:44 -080045static int qpnp_labibb_regulator_set_voltage(struct qpnp_wled *wled);
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053046
47static int qpnp_wled_sec_access(struct qpnp_wled *wled, uint16_t base_addr)
48{
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053049 uint8_t reg = QPNP_WLED_SEC_UNLOCK;
50
51 pm8x41_wled_reg_write(QPNP_WLED_SEC_ACCESS_REG(base_addr), reg);
52
53 return 0;
54}
55
56/* set wled to a level of brightness */
57static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
58{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -080059 int i;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053060 uint8_t reg;
61
62 /* set brightness registers */
63 for (i = 0; i < wled->num_strings; i++) {
64 reg = level & QPNP_WLED_BRIGHT_LSB_MASK;
65 pm8x41_wled_reg_write(QPNP_WLED_BRIGHT_LSB_REG(wled->sink_base,
66 wled->strings[i]), reg);
67
68 reg = level >> QPNP_WLED_BRIGHT_MSB_SHIFT;
69 reg = reg & QPNP_WLED_BRIGHT_MSB_MASK;
70 pm8x41_wled_reg_write(QPNP_WLED_BRIGHT_MSB_REG(wled->sink_base,
71 wled->strings[i]), reg);
72 }
73
74 /* sync */
75 reg = QPNP_WLED_SYNC;
76 pm8x41_wled_reg_write(QPNP_WLED_SYNC_REG(wled->sink_base), reg);
77
78 reg = QPNP_WLED_SYNC_RESET;
79 pm8x41_wled_reg_write(QPNP_WLED_SYNC_REG(wled->sink_base), reg);
80
81 return 0;
82}
83
84static int qpnp_wled_enable(struct qpnp_wled *wled,
85 uint16_t base_addr, bool state)
86{
87 uint8_t reg;
88
89 reg = pm8x41_wled_reg_read(
90 QPNP_WLED_MODULE_EN_REG(base_addr));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053091 reg &= QPNP_WLED_MODULE_EN_MASK;
92 reg |= (state << QPNP_WLED_MODULE_EN_SHIFT);
93 pm8x41_wled_reg_write(QPNP_WLED_MODULE_EN_REG(base_addr), reg);
94
95 return 0;
96}
97
98int qpnp_ibb_enable(bool state)
99{
100 int rc = 0;
101 uint8_t reg;
102
103 if (!gwled) {
104 dprintf(CRITICAL, "%s: wled is not initialized yet\n", __func__);
105 return ERROR;
106 }
107
108 /* enable lab */
109 if (gwled->ibb_bias_active) {
110 rc = qpnp_wled_enable(gwled, gwled->lab_base, state);
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800111 udelay(QPNP_WLED_LAB_START_DLY_US + 1);
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530112 if (rc < 0)
113 return rc;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530114 } else {
115 reg = pm8x41_wled_reg_read(QPNP_WLED_LAB_IBB_RDY_REG(gwled->lab_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530116
117 reg &= QPNP_WLED_MODULE_EN_MASK;
118 reg |= (state << QPNP_WLED_MODULE_EN_SHIFT);
119 pm8x41_wled_reg_write(QPNP_WLED_LAB_IBB_RDY_REG(gwled->lab_base), reg);
120 }
121
122 rc = qpnp_wled_enable(gwled, gwled->ibb_base, state);
123
124 return rc;
125}
126
127/* enable / disable wled brightness */
128void qpnp_wled_enable_backlight(int enable)
129{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800130 int rc;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530131
132 if (!gwled) {
133 dprintf(CRITICAL, "%s: wled is not initialized yet\n", __func__);
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800134 return;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530135 }
136
137 if (enable) {
138 rc = qpnp_wled_set_level(gwled, QPNP_WLED_MAX_BR_LEVEL);
139 if (rc) {
140 dprintf(CRITICAL,"wled set level failed\n");
141 return;
142 }
143 }
144 rc = qpnp_wled_enable(gwled, gwled->ctrl_base, enable);
145
146 if (rc) {
147 dprintf(CRITICAL,"wled %sable failed\n",
148 enable ? "en" : "dis");
149 return;
150 }
151
152}
153
154static int qpnp_wled_set_display_type(struct qpnp_wled *wled, uint16_t base_addr)
155{
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530156 uint8_t reg = 0;
157
158 /* display type */
159 reg = pm8x41_wled_reg_read(QPNP_WLED_DISP_SEL_REG(base_addr));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530160
161 reg &= QPNP_WLED_DISP_SEL_MASK;
162 reg |= (wled->disp_type_amoled << QPNP_WLED_DISP_SEL_SHIFT);
163 pm8x41_wled_reg_write(QPNP_WLED_DISP_SEL_REG(base_addr), reg);
164
165 return 0;
166}
167
168static int qpnp_wled_module_ready(struct qpnp_wled *wled, uint16_t base_addr, bool state)
169{
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530170 uint8_t reg;
171
172 reg = pm8x41_wled_reg_read(
173 QPNP_WLED_MODULE_RDY_REG(base_addr));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530174 reg &= QPNP_WLED_MODULE_RDY_MASK;
175 reg |= (state << QPNP_WLED_MODULE_RDY_SHIFT);
176 pm8x41_wled_reg_write(QPNP_WLED_MODULE_RDY_REG(base_addr), reg);
177
178 return 0;
179}
180
181/* Configure WLED registers */
182static int qpnp_wled_config(struct qpnp_wled *wled)
183{
184 int rc, i, temp;
185 uint8_t reg = 0;
186
187 /* Configure display type */
188 rc = qpnp_wled_set_display_type(wled, wled->ctrl_base);
189 if (rc < 0)
190 return rc;
191
192 /* Configure the FEEDBACK OUTPUT register */
193 reg = pm8x41_wled_reg_read(
194 QPNP_WLED_FDBK_OP_REG(wled->ctrl_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530195 reg &= QPNP_WLED_FDBK_OP_MASK;
196 reg |= wled->fdbk_op;
197 pm8x41_wled_reg_write(QPNP_WLED_FDBK_OP_REG(wled->ctrl_base), reg);
198
199 /* Configure the VREF register */
200 if (wled->vref_mv < QPNP_WLED_VREF_MIN_MV)
201 wled->vref_mv = QPNP_WLED_VREF_MIN_MV;
202 else if (wled->vref_mv > QPNP_WLED_VREF_MAX_MV)
203 wled->vref_mv = QPNP_WLED_VREF_MAX_MV;
204
205 reg = pm8x41_wled_reg_read(
206 QPNP_WLED_VREF_REG(wled->ctrl_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530207 reg &= QPNP_WLED_VREF_MASK;
208 temp = wled->vref_mv - QPNP_WLED_VREF_MIN_MV;
209 reg |= (temp / QPNP_WLED_VREF_STEP_MV);
210 pm8x41_wled_reg_write(QPNP_WLED_VREF_REG(wled->ctrl_base), reg);
211
212 /* Configure the ILIM register */
213 if (wled->ilim_ma < QPNP_WLED_ILIM_MIN_MA)
214 wled->ilim_ma = QPNP_WLED_ILIM_MIN_MA;
215 else if (wled->ilim_ma > QPNP_WLED_ILIM_MAX_MA)
216 wled->ilim_ma = QPNP_WLED_ILIM_MAX_MA;
217
218 reg = pm8x41_wled_reg_read(
219 QPNP_WLED_ILIM_REG(wled->ctrl_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530220 reg &= QPNP_WLED_ILIM_MASK;
221 reg |= (wled->ilim_ma / QPNP_WLED_ILIM_STEP_MA);
222 pm8x41_wled_reg_write(QPNP_WLED_ILIM_REG(wled->ctrl_base), reg);
223
224 /* Configure the MAX BOOST DUTY register */
225 if (wled->boost_duty_ns < QPNP_WLED_BOOST_DUTY_MIN_NS)
226 wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MIN_NS;
227 else if (wled->boost_duty_ns > QPNP_WLED_BOOST_DUTY_MAX_NS)
228 wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MAX_NS;
229
230 reg = pm8x41_wled_reg_read(
231 QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530232 reg &= QPNP_WLED_BOOST_DUTY_MASK;
233 reg |= (wled->boost_duty_ns / QPNP_WLED_BOOST_DUTY_STEP_NS);
234 pm8x41_wled_reg_write(QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base), reg);
235
236 /* Configure the SWITCHING FREQ register */
237 if (wled->switch_freq_khz == QPNP_WLED_SWITCH_FREQ_1600_KHZ)
238 temp = QPNP_WLED_SWITCH_FREQ_1600_KHZ_CODE;
239 else
240 temp = QPNP_WLED_SWITCH_FREQ_800_KHZ_CODE;
241
242 reg = pm8x41_wled_reg_read(
243 QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530244 reg &= QPNP_WLED_SWITCH_FREQ_MASK;
245 reg |= temp;
246 pm8x41_wled_reg_write(QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base), reg);
247
248 /* Configure the OVP register */
249 if (wled->ovp_mv <= QPNP_WLED_OVP_17800_MV) {
250 wled->ovp_mv = QPNP_WLED_OVP_17800_MV;
251 temp = 3;
252 } else if (wled->ovp_mv <= QPNP_WLED_OVP_19400_MV) {
253 wled->ovp_mv = QPNP_WLED_OVP_19400_MV;
254 temp = 2;
255 } else if (wled->ovp_mv <= QPNP_WLED_OVP_29500_MV) {
256 wled->ovp_mv = QPNP_WLED_OVP_29500_MV;
257 temp = 1;
258 } else {
259 wled->ovp_mv = QPNP_WLED_OVP_31000_MV;
260 temp = 0;
261 }
262
263 reg = pm8x41_wled_reg_read(
264 QPNP_WLED_OVP_REG(wled->ctrl_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530265 reg &= QPNP_WLED_OVP_MASK;
266 reg |= temp;
267 pm8x41_wled_reg_write(QPNP_WLED_OVP_REG(wled->ctrl_base), reg);
268
269 /* Configure the MODULATION register */
270 if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_1200_KHZ) {
271 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_1200_KHZ;
272 temp = 3;
273 } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_2400_KHZ) {
274 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_2400_KHZ;
275 temp = 2;
276 } else if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_9600_KHZ) {
277 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ;
278 temp = 1;
279 } else {
280 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_19200_KHZ;
281 temp = 0;
282 }
283 reg = pm8x41_wled_reg_read(QPNP_WLED_MOD_REG(wled->sink_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530284
285 reg &= QPNP_WLED_MOD_FREQ_MASK;
286 reg |= (temp << QPNP_WLED_MOD_FREQ_SHIFT);
287
288 reg &= QPNP_WLED_PHASE_STAG_MASK;
289 reg |= (wled->en_phase_stag << QPNP_WLED_PHASE_STAG_SHIFT);
290
291 reg &= QPNP_WLED_DIM_RES_MASK;
292 reg |= (wled->en_9b_dim_res << QPNP_WLED_DIM_RES_SHIFT);
293
294 if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) {
295 reg &= QPNP_WLED_DIM_HYB_MASK;
296 reg |= (1 << QPNP_WLED_DIM_HYB_SHIFT);
297 } else {
298 reg &= QPNP_WLED_DIM_HYB_MASK;
299 reg |= (0 << QPNP_WLED_DIM_HYB_SHIFT);
300 reg &= QPNP_WLED_DIM_ANA_MASK;
301 reg |= wled->dim_mode;
302 }
303
304 pm8x41_wled_reg_write(QPNP_WLED_MOD_REG(wled->sink_base), reg);
305
306 /* Configure the HYBRID THRESHOLD register */
307 if (wled->hyb_thres < QPNP_WLED_HYB_THRES_MIN)
308 wled->hyb_thres = QPNP_WLED_HYB_THRES_MIN;
309 else if (wled->hyb_thres > QPNP_WLED_HYB_THRES_MAX)
310 wled->hyb_thres = QPNP_WLED_HYB_THRES_MAX;
311
312 reg = pm8x41_wled_reg_read(
313 QPNP_WLED_HYB_THRES_REG(wled->sink_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530314
315 reg &= QPNP_WLED_HYB_THRES_MASK;
316 temp = fls(wled->hyb_thres / QPNP_WLED_HYB_THRES_MIN) - 1;
317 reg |= temp;
318 pm8x41_wled_reg_write(QPNP_WLED_HYB_THRES_REG(wled->sink_base), reg);
319
320 for (i = 0; i < wled->num_strings; i++) {
321 if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) {
322 dprintf(CRITICAL,"Invalid string number\n");
323 return ERR_NOT_VALID;
324 }
325
326 /* MODULATOR */
327 reg = pm8x41_wled_reg_read(
328 QPNP_WLED_MOD_EN_REG(wled->sink_base,
329 wled->strings[i]));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530330 reg &= QPNP_WLED_MOD_EN_MASK;
331 reg |= (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT);
332 pm8x41_wled_reg_write(QPNP_WLED_MOD_EN_REG(wled->sink_base,
333 wled->strings[i]), reg);
334
335 /* SYNC DELAY */
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800336 if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530337 wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US;
338
339 reg = pm8x41_wled_reg_read(
340 QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
341 wled->strings[i]));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530342 reg &= QPNP_WLED_SYNC_DLY_MASK;
343 temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
344 reg |= temp;
345 pm8x41_wled_reg_write(QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
346 wled->strings[i]), reg);
347
348 /* FULL SCALE CURRENT */
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800349 if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530350 wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
351
352 reg = pm8x41_wled_reg_read(
353 QPNP_WLED_FS_CURR_REG(wled->sink_base,
354 wled->strings[i]));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530355 reg &= QPNP_WLED_FS_CURR_MASK;
356 temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
357 reg |= temp;
358 pm8x41_wled_reg_write(QPNP_WLED_FS_CURR_REG(wled->sink_base,
359 wled->strings[i]), reg);
360
361 /* CABC */
362 reg = pm8x41_wled_reg_read(
363 QPNP_WLED_CABC_REG(wled->sink_base,
364 wled->strings[i]));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530365 reg &= QPNP_WLED_CABC_MASK;
366 reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT);
367 pm8x41_wled_reg_write(QPNP_WLED_CABC_REG(wled->sink_base,
368 wled->strings[i]), reg);
369
370 /* Enable CURRENT SINK */
371 reg = pm8x41_wled_reg_read(
372 QPNP_WLED_CURR_SINK_REG(wled->sink_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530373 temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT;
374 reg |= (1 << temp);
375 pm8x41_wled_reg_write(QPNP_WLED_CURR_SINK_REG(wled->sink_base), reg);
376 }
377
378 /* LAB fast precharge */
379 reg = pm8x41_wled_reg_read(
380 QPNP_WLED_LAB_FAST_PC_REG(wled->lab_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530381 reg &= QPNP_WLED_LAB_FAST_PC_MASK;
382 reg |= (wled->lab_fast_precharge << QPNP_WLED_LAB_FAST_PC_SHIFT);
383 pm8x41_wled_reg_write(QPNP_WLED_LAB_FAST_PC_REG(wled->lab_base), reg);
384
385 /* Configure lab display type */
386 rc = qpnp_wled_set_display_type(wled, wled->lab_base);
387 if (rc < 0)
388 return rc;
389
390 /* make LAB module ready */
391 rc = qpnp_wled_module_ready(wled, wled->lab_base, true);
392 if (rc < 0)
393 return rc;
394
395 /* IBB active bias */
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800396 if (wled->ibb_pwrup_dly_ms > QPNP_WLED_IBB_PWRUP_DLY_MAX_MS)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530397 wled->ibb_pwrup_dly_ms = QPNP_WLED_IBB_PWRUP_DLY_MAX_MS;
398
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800399 if (wled->ibb_pwrdn_dly_ms > QPNP_WLED_IBB_PWRDN_DLY_MAX_MS)
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800400 wled->ibb_pwrdn_dly_ms = QPNP_WLED_IBB_PWRDN_DLY_MAX_MS;
401
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530402 reg = pm8x41_wled_reg_read(
403 QPNP_WLED_IBB_BIAS_REG(wled->ibb_base));
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530404
405 reg &= QPNP_WLED_IBB_BIAS_MASK;
406 reg |= (!wled->ibb_bias_active << QPNP_WLED_IBB_BIAS_SHIFT);
407
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800408 temp = wled->ibb_pwrup_dly_ms;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530409 reg &= QPNP_WLED_IBB_PWRUP_DLY_MASK;
410 reg |= (temp << QPNP_WLED_IBB_PWRUP_DLY_SHIFT);
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800411 reg |= wled->ibb_pwrdn_dly_ms;
412 reg |= (wled->ibb_discharge_en << 2);
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530413
414 rc = qpnp_wled_sec_access(wled, wled->ibb_base);
415 if (rc)
416 return rc;
417
418 pm8x41_wled_reg_write(QPNP_WLED_IBB_BIAS_REG(wled->ibb_base), reg);
419
420 /* Configure ibb display type */
421 rc = qpnp_wled_set_display_type(wled, wled->ibb_base);
422 if (rc < 0)
423 return rc;
424
425 /* make IBB module ready */
426 rc = qpnp_wled_module_ready(wled, wled->ibb_base, true);
427 if (rc < 0)
428 return rc;
429
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800430 rc = qpnp_labibb_regulator_set_voltage(wled);
431 if (rc < 0)
432 return rc;
433
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530434 return 0;
435}
436
437/* Setup wled default parameters */
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800438static int qpnp_wled_setup(struct qpnp_wled *wled, struct qpnp_wled_config_data *config)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530439{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800440 int i;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530441
442 wled->sink_base = QPNP_WLED_SINK_BASE;
443 wled->ctrl_base = QPNP_WLED_CTRL_BASE;
444 wled->ibb_base = QPNP_WLED_IBB_BASE;
445 wled->lab_base = QPNP_WLED_LAB_BASE;
446 wled->fdbk_op = QPNP_WLED_FDBK_AUTO;
447 wled->vref_mv = QPNP_WLED_DFLT_VREF_MV;
448 wled->switch_freq_khz = QPNP_WLED_SWITCH_FREQ_800_KHZ;
449 wled->ovp_mv = QPNP_WLED_OVP_29500_MV;
450 wled->ilim_ma = QPNP_WLED_DFLT_ILIM_MA;
451 wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MIN_NS;
452 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_19200_KHZ;
453 wled->dim_mode = QPNP_WLED_DIM_HYBRID;
454 wled->dim_shape = QPNP_WLED_DIM_SHAPE_LINEAR;
455
456 if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) {
457 wled->hyb_thres = QPNP_WLED_DFLT_HYB_THRES;
458 }
459
460 wled->sync_dly_us = 800;
461 wled->fs_curr_ua = 16000;
462 wled->en_9b_dim_res = 0;
463 wled->en_phase_stag = true;
464 wled->en_cabc = 0;
465
466 wled->num_strings = QPNP_WLED_MAX_STRINGS;
467 for (i = 0; i < wled->num_strings; i++)
468 wled->strings[i] = i;
469
470 wled->ibb_bias_active = false;
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800471 wled->lab_fast_precharge = true;
472 wled->ibb_pwrup_dly_ms = config->pwr_up_delay;
473 wled->ibb_pwrdn_dly_ms = config->pwr_down_delay;
474 wled->ibb_discharge_en = config->ibb_discharge_en;
475 wled->disp_type_amoled = config->display_type;
476 wled->lab_min_volt = config->lab_min_volt;
477 wled->lab_max_volt = config->lab_max_volt;
478 wled->ibb_min_volt = config->ibb_min_volt;
479 wled->ibb_max_volt = config->ibb_max_volt;
480 wled->ibb_init_volt = config->ibb_init_volt;
481 wled->lab_init_volt = config->lab_init_volt;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530482
483 return 0;
484}
485
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800486int qpnp_wled_init(struct qpnp_wled_config_data *config)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530487{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800488 int rc;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530489 struct qpnp_wled *wled;
490
491 wled = malloc(sizeof(struct qpnp_wled));
492 if (!wled)
493 return ERR_NO_MEMORY;
494
495 memset(wled, 0, sizeof(struct qpnp_wled));
496
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800497 rc = qpnp_wled_setup(wled, config);
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530498 if (rc) {
499 dprintf(CRITICAL, "Setting WLED parameters failed\n");
500 return rc;
501 }
502
503 rc = qpnp_wled_config(wled);
504 if (rc) {
505 dprintf(CRITICAL, "wled config failed\n");
506 return rc;
507 }
508
509 gwled = wled;
510
511 return rc;
512}
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800513
514static int qpnp_labibb_regulator_set_voltage(struct qpnp_wled *wled)
515{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800516 int rc = -1;
517 uint32_t new_uV;
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800518 uint8_t val, mask=0;
519
520 if (wled->lab_min_volt < wled->lab_init_volt) {
521 dprintf(CRITICAL,"qpnp_lab_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
522 wled->lab_min_volt, wled->lab_init_volt);
523 return rc;
524 }
525
526 val = (((wled->lab_min_volt - wled->lab_init_volt) + (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
527 new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->lab_init_volt;
528
529 if (new_uV > wled->lab_max_volt) {
530 dprintf(CRITICAL,"qpnp_ibb_regulator_set_voltage unable to set voltage (%d %d)\n",
531 wled->lab_min_volt, wled->lab_max_volt);
532 return rc;
533 }
534 val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
535 mask = pm8x41_wled_reg_read(wled->lab_base + QPNP_LABIBB_OUTPUT_VOLTAGE);
536 mask &= ~(QPNP_LAB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
537 mask |= val & (QPNP_LAB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
538
539 pm8x41_wled_reg_write(wled->lab_base + QPNP_LABIBB_OUTPUT_VOLTAGE, mask);
540 udelay(2);
541
542 /* IBB Set Voltage */
543 if (wled->ibb_min_volt < wled->ibb_init_volt) {
544 dprintf(CRITICAL, "qpnp_ibb_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
545 wled->ibb_min_volt, wled->ibb_init_volt);
546 return rc;
547 }
548
549 val = (((wled->ibb_min_volt - wled->ibb_init_volt) + (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
550 new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->ibb_init_volt;
551 if (new_uV > wled->ibb_max_volt) {
552 dprintf(CRITICAL,"qpnp_ibb_regulator_set_voltage unable to set voltage %d %d\n",
553 wled->ibb_min_volt, wled->ibb_max_volt);
554 return rc;
555 }
556 val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
557 mask = pm8x41_wled_reg_read(wled->ibb_base + QPNP_LABIBB_OUTPUT_VOLTAGE);
558 udelay(2);
559 mask &= ~(QPNP_IBB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
560 mask |= (val & (QPNP_IBB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN));
561
562 pm8x41_wled_reg_write(wled->ibb_base + QPNP_LABIBB_OUTPUT_VOLTAGE,mask);
563
564 return 0;
565}