blob: 2f4b196a1c72b4307bdb344b4921d9ea71cd9b3c [file] [log] [blame]
Channagoud Kadabif5f0ded2015-02-25 13:42:18 -08001 /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
Aparna Mallavarapu083766b2014-07-21 21:04:48 +05302
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);
Channagoud Kadabif5f0ded2015-02-25 13:42:18 -0800411 /* Power down delay bits could already be set, clear them before
412 * or'ing new values
413 */
414 reg &= ~(PWRDN_DLY2_MASK);
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800415 reg |= wled->ibb_pwrdn_dly_ms;
416 reg |= (wled->ibb_discharge_en << 2);
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530417
418 rc = qpnp_wled_sec_access(wled, wled->ibb_base);
419 if (rc)
420 return rc;
421
422 pm8x41_wled_reg_write(QPNP_WLED_IBB_BIAS_REG(wled->ibb_base), reg);
423
424 /* Configure ibb display type */
425 rc = qpnp_wled_set_display_type(wled, wled->ibb_base);
426 if (rc < 0)
427 return rc;
428
429 /* make IBB module ready */
430 rc = qpnp_wled_module_ready(wled, wled->ibb_base, true);
431 if (rc < 0)
432 return rc;
433
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800434 rc = qpnp_labibb_regulator_set_voltage(wled);
435 if (rc < 0)
436 return rc;
437
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530438 return 0;
439}
440
441/* Setup wled default parameters */
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800442static int qpnp_wled_setup(struct qpnp_wled *wled, struct qpnp_wled_config_data *config)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530443{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800444 int i;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530445
446 wled->sink_base = QPNP_WLED_SINK_BASE;
447 wled->ctrl_base = QPNP_WLED_CTRL_BASE;
448 wled->ibb_base = QPNP_WLED_IBB_BASE;
449 wled->lab_base = QPNP_WLED_LAB_BASE;
450 wled->fdbk_op = QPNP_WLED_FDBK_AUTO;
451 wled->vref_mv = QPNP_WLED_DFLT_VREF_MV;
452 wled->switch_freq_khz = QPNP_WLED_SWITCH_FREQ_800_KHZ;
453 wled->ovp_mv = QPNP_WLED_OVP_29500_MV;
454 wled->ilim_ma = QPNP_WLED_DFLT_ILIM_MA;
455 wled->boost_duty_ns = QPNP_WLED_BOOST_DUTY_MIN_NS;
456 wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_19200_KHZ;
457 wled->dim_mode = QPNP_WLED_DIM_HYBRID;
458 wled->dim_shape = QPNP_WLED_DIM_SHAPE_LINEAR;
459
460 if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) {
461 wled->hyb_thres = QPNP_WLED_DFLT_HYB_THRES;
462 }
463
464 wled->sync_dly_us = 800;
465 wled->fs_curr_ua = 16000;
466 wled->en_9b_dim_res = 0;
467 wled->en_phase_stag = true;
468 wled->en_cabc = 0;
469
470 wled->num_strings = QPNP_WLED_MAX_STRINGS;
471 for (i = 0; i < wled->num_strings; i++)
472 wled->strings[i] = i;
473
474 wled->ibb_bias_active = false;
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800475 wled->lab_fast_precharge = true;
476 wled->ibb_pwrup_dly_ms = config->pwr_up_delay;
477 wled->ibb_pwrdn_dly_ms = config->pwr_down_delay;
478 wled->ibb_discharge_en = config->ibb_discharge_en;
479 wled->disp_type_amoled = config->display_type;
480 wled->lab_min_volt = config->lab_min_volt;
481 wled->lab_max_volt = config->lab_max_volt;
482 wled->ibb_min_volt = config->ibb_min_volt;
483 wled->ibb_max_volt = config->ibb_max_volt;
484 wled->ibb_init_volt = config->ibb_init_volt;
485 wled->lab_init_volt = config->lab_init_volt;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530486
487 return 0;
488}
489
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800490int qpnp_wled_init(struct qpnp_wled_config_data *config)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530491{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800492 int rc;
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530493 struct qpnp_wled *wled;
494
495 wled = malloc(sizeof(struct qpnp_wled));
496 if (!wled)
497 return ERR_NO_MEMORY;
498
499 memset(wled, 0, sizeof(struct qpnp_wled));
500
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800501 rc = qpnp_wled_setup(wled, config);
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530502 if (rc) {
503 dprintf(CRITICAL, "Setting WLED parameters failed\n");
504 return rc;
505 }
506
507 rc = qpnp_wled_config(wled);
508 if (rc) {
509 dprintf(CRITICAL, "wled config failed\n");
510 return rc;
511 }
512
513 gwled = wled;
514
515 return rc;
516}
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800517
518static int qpnp_labibb_regulator_set_voltage(struct qpnp_wled *wled)
519{
Veera Sundaram Sankaran4e23fab2014-12-09 13:54:32 -0800520 int rc = -1;
521 uint32_t new_uV;
Aparna Mallavarapua42de902014-12-08 17:25:44 -0800522 uint8_t val, mask=0;
523
524 if (wled->lab_min_volt < wled->lab_init_volt) {
525 dprintf(CRITICAL,"qpnp_lab_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
526 wled->lab_min_volt, wled->lab_init_volt);
527 return rc;
528 }
529
530 val = (((wled->lab_min_volt - wled->lab_init_volt) + (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
531 new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->lab_init_volt;
532
533 if (new_uV > wled->lab_max_volt) {
534 dprintf(CRITICAL,"qpnp_ibb_regulator_set_voltage unable to set voltage (%d %d)\n",
535 wled->lab_min_volt, wled->lab_max_volt);
536 return rc;
537 }
538 val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
539 mask = pm8x41_wled_reg_read(wled->lab_base + QPNP_LABIBB_OUTPUT_VOLTAGE);
540 mask &= ~(QPNP_LAB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
541 mask |= val & (QPNP_LAB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
542
543 pm8x41_wled_reg_write(wled->lab_base + QPNP_LABIBB_OUTPUT_VOLTAGE, mask);
544 udelay(2);
545
546 /* IBB Set Voltage */
547 if (wled->ibb_min_volt < wled->ibb_init_volt) {
548 dprintf(CRITICAL, "qpnp_ibb_regulator_set_voltage failed, min_uV %d is less than init volt %d\n",
549 wled->ibb_min_volt, wled->ibb_init_volt);
550 return rc;
551 }
552
553 val = (((wled->ibb_min_volt - wled->ibb_init_volt) + (IBB_LAB_VREG_STEP_SIZE - 1)) / IBB_LAB_VREG_STEP_SIZE);
554 new_uV = val * IBB_LAB_VREG_STEP_SIZE + wled->ibb_init_volt;
555 if (new_uV > wled->ibb_max_volt) {
556 dprintf(CRITICAL,"qpnp_ibb_regulator_set_voltage unable to set voltage %d %d\n",
557 wled->ibb_min_volt, wled->ibb_max_volt);
558 return rc;
559 }
560 val |= QPNP_LAB_OUTPUT_OVERRIDE_EN;
561 mask = pm8x41_wled_reg_read(wled->ibb_base + QPNP_LABIBB_OUTPUT_VOLTAGE);
562 udelay(2);
563 mask &= ~(QPNP_IBB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN);
564 mask |= (val & (QPNP_IBB_SET_VOLTAGE_MASK | QPNP_LAB_OUTPUT_OVERRIDE_EN));
565
566 pm8x41_wled_reg_write(wled->ibb_base + QPNP_LABIBB_OUTPUT_VOLTAGE,mask);
567
568 return 0;
569}