blob: 5886161b52a1165c06300a70ae2037820b90281f [file] [log] [blame]
Matthew Qin3aa87052014-02-21 10:32:34 +08001/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Deepa Dinamani22799652012-07-21 12:26:22 -07002
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.
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +053012 * * Neither the name of The Linux Foundation, Inc. nor the names of its
Deepa Dinamani22799652012-07-21 12:26:22 -070013 * 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
Deepa Dinamani9a612932012-08-14 16:15:03 -070029#include <bits.h>
Deepa Dinamani22799652012-07-21 12:26:22 -070030#include <debug.h>
31#include <reg.h>
32#include <spmi.h>
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +053033#include <string.h>
Deepa Dinamani22799652012-07-21 12:26:22 -070034#include <pm8x41_hw.h>
Deepa Dinamani9a612932012-08-14 16:15:03 -070035#include <pm8x41.h>
Channagoud Kadabi9089da62014-11-10 13:19:55 -080036#include <rpm-smd.h>
37#include <regulator.h>
Deepa Dinamani9a612932012-08-14 16:15:03 -070038#include <platform/timer.h>
Deepa Dinamani22799652012-07-21 12:26:22 -070039
Channagoud Kadabi9089da62014-11-10 13:19:55 -080040/* Enable LN BB CLK */
41static uint32_t ln_bb_clk[][8] = {
42 {
43 RPM_CLK_BUFFER_A_REQ, LNBB_CLK_ID,
44 KEY_SOFTWARE_ENABLE, 4, GENERIC_DISABLE,
45 RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, 4, RPM_CLK_BUFFER_PIN_CONTROL_ENABLE_NONE,
46 },
47 {
48 RPM_CLK_BUFFER_A_REQ, LNBB_CLK_ID,
49 KEY_SOFTWARE_ENABLE, 4, GENERIC_ENABLE,
50 RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, 4, RPM_CLK_BUFFER_PIN_CONTROL_ENABLE_NONE,
51 },
52};
53
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053054static uint8_t mpp_slave_id;
55
vijay kumar9ec33942014-08-08 17:25:46 +053056void pmi8994_config_mpp_slave_id(uint8_t slave_id)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053057{
58 mpp_slave_id = slave_id;
59}
Channagoud Kadabid091f702013-01-07 16:17:37 -080060/* SPMI helper functions */
61uint8_t pm8x41_reg_read(uint32_t addr)
Deepa Dinamani9a612932012-08-14 16:15:03 -070062{
63 uint8_t val = 0;
64 struct pmic_arb_cmd cmd;
65 struct pmic_arb_param param;
66
67 cmd.address = PERIPH_ID(addr);
68 cmd.offset = REG_OFFSET(addr);
69 cmd.slave_id = SLAVE_ID(addr);
70 cmd.priority = 0;
71
72 param.buffer = &val;
73 param.size = 1;
74
75 pmic_arb_read_cmd(&cmd, &param);
76
77 return val;
78}
79
Channagoud Kadabid091f702013-01-07 16:17:37 -080080void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -070081{
82 struct pmic_arb_cmd cmd;
83 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -070084
Deepa Dinamani9a612932012-08-14 16:15:03 -070085 cmd.address = PERIPH_ID(addr);
86 cmd.offset = REG_OFFSET(addr);
87 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -070088 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -070089
Deepa Dinamani9a612932012-08-14 16:15:03 -070090 param.buffer = &val;
91 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -070092
Deepa Dinamani9a612932012-08-14 16:15:03 -070093 pmic_arb_write_cmd(&cmd, &param);
94}
Deepa Dinamani22799652012-07-21 12:26:22 -070095
Deepa Dinamani9a612932012-08-14 16:15:03 -070096/* Exported functions */
97
98/* Set the boot done flag */
99void pm8x41_set_boot_done()
100{
101 uint8_t val;
102
103 val = REG_READ(SMBB_MISC_BOOT_DONE);
104 val |= BIT(BOOT_DONE_BIT);
105 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
106}
107
108/* Configure GPIO */
109int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
110{
111 uint8_t val;
112 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
113
114 /* Disable the GPIO */
115 val = REG_READ(gpio_base + GPIO_EN_CTL);
116 val &= ~BIT(PERPH_EN_BIT);
117 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
118
119 /* Select the mode */
120 val = config->function | (config->direction << 4);
121 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
122
123 /* Set the right pull */
124 val = config->pull;
125 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
126
127 /* Select the VIN */
128 val = config->vin_sel;
129 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
130
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800131 if (config->direction == PM_GPIO_DIR_OUT) {
132 /* Set the right dig out control */
133 val = config->out_strength | (config->output_buffer << 4);
134 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
135 }
136
Deepa Dinamani9a612932012-08-14 16:15:03 -0700137 /* Enable the GPIO */
138 val = REG_READ(gpio_base + GPIO_EN_CTL);
139 val |= BIT(PERPH_EN_BIT);
140 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
141
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800142 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700143}
144
145/* Reads the status of requested gpio */
146int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
147{
148 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
149
150 *status = REG_READ(gpio_base + GPIO_STATUS);
151
152 /* Return the value of the GPIO pin */
153 *status &= BIT(GPIO_STATUS_VAL_BIT);
154
155 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
156
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800157 return 0;
158}
159
160/* Write the output value of the requested gpio */
161int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
162{
163 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
164 uint8_t val;
165
166 /* Set the output value of the gpio */
167 val = REG_READ(gpio_base + GPIO_MODE_CTL);
168 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
169 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
170
171 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700172}
173
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700174/* Configure PM and PMI GPIO with slave id */
175int pm8x41_gpio_config_sid(uint8_t sid, uint8_t gpio, struct pm8x41_gpio *config)
176{
177 uint8_t val;
178 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
179
180 gpio_base &= 0x0ffff; /* clear sid */
181 gpio_base |= (sid << 16); /* add sid */
182
183 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
184
185 /* Disable the GPIO */
186 val = REG_READ(gpio_base + GPIO_EN_CTL);
187 val &= ~BIT(PERPH_EN_BIT);
188 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
189
190 /* Select the mode */
191 val = config->function | (config->direction << 4);
192 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
193
194 /* Set the right pull */
195 val = config->pull;
196 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
197
198 /* Select the VIN */
199 val = config->vin_sel;
200 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
201
202 if (config->direction == PM_GPIO_DIR_OUT) {
203 /* Set the right dig out control */
204 val = config->out_strength | (config->output_buffer << 4);
205 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
206 }
207
208 /* Enable the GPIO */
209 val = REG_READ(gpio_base + GPIO_EN_CTL);
210 val |= BIT(PERPH_EN_BIT);
211 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
212
213 return 0;
214}
215
216/* Reads the status of requested gpio */
217int pm8x41_gpio_get_sid(uint8_t sid, uint8_t gpio, uint8_t *status)
218{
219 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
220
221 gpio_base &= 0x0ffff; /* clear sid */
222 gpio_base |= (sid << 16); /* add sid */
223
224 *status = REG_READ(gpio_base + GPIO_STATUS);
225
226 /* Return the value of the GPIO pin */
227 *status &= BIT(GPIO_STATUS_VAL_BIT);
228
229 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
230
231 return 0;
232}
233
234/* Write the output value of the requested gpio */
235int pm8x41_gpio_set_sid(uint8_t sid, uint8_t gpio, uint8_t value)
236{
237 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
238 uint8_t val;
239
240 gpio_base &= 0x0ffff; /* clear sid */
241 gpio_base |= (sid << 16); /* add sid */
242
243 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
244
245 /* Set the output value of the gpio */
246 val = REG_READ(gpio_base + GPIO_MODE_CTL);
247 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
248 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
249
250 return 0;
251}
252
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800253/* Prepare PON RESIN S2 reset (bite) */
254void pm8x41_resin_s2_reset_enable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700255{
256 uint8_t val;
257
258 /* disable s2 reset */
259 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
260
Amol Jadi7ec52b42012-08-16 14:12:45 -0700261 /* Delay needed for disable to kick in. */
262 udelay(300);
263
Deepa Dinamani9a612932012-08-14 16:15:03 -0700264 /* configure s1 timer to 0 */
265 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
266
267 /* configure s2 timer to 2s */
268 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
269
270 /* configure reset type */
271 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
272
273 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
274
275 /* enable s2 reset */
276 val |= BIT(S2_RESET_EN_BIT);
277 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
278}
279
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800280/* Disable PON RESIN S2 reset. (bite)*/
281void pm8x41_resin_s2_reset_disable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700282{
283 /* disable s2 reset */
284 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700285
286 /* Delay needed for disable to kick in. */
287 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700288}
289
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800290/* Resin irq status for faulty pmic*/
Channagoud Kadabi36c19ea2013-07-05 16:28:44 -0700291uint32_t pm8x41_v2_resin_status()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700292{
293 uint8_t rt_sts = 0;
294
295 /* Enable S2 reset so we can detect the volume down key press */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800296 pm8x41_resin_s2_reset_enable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700297
298 /* Delay before interrupt triggering.
299 * See PON_DEBOUNCE_CTL reg.
300 */
301 mdelay(100);
302
303 rt_sts = REG_READ(PON_INT_RT_STS);
304
305 /* Must disable S2 reset otherwise PMIC will reset if key
306 * is held longer than S2 timer.
307 */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800308 pm8x41_resin_s2_reset_disable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700309
310 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700311}
Neeti Desai120b55d2012-08-20 17:15:56 -0700312
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800313/* Resin pin status */
314uint32_t pm8x41_resin_status()
315{
316 uint8_t rt_sts = 0;
317
318 rt_sts = REG_READ(PON_INT_RT_STS);
319
320 return (rt_sts & BIT(RESIN_ON_INT_BIT));
321}
322
Matthew Qin3aa87052014-02-21 10:32:34 +0800323/* Return 1 if power key is pressed */
324uint32_t pm8x41_get_pwrkey_is_pressed()
325{
326 uint8_t pwr_sts = 0;
327
328 pwr_sts = REG_READ(PON_INT_RT_STS);
329
330 if (pwr_sts & BIT(KPDPWR_ON_INT_BIT))
331 return 1;
332 else
333 return 0;
334}
335
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800336void pm8x41_v2_reset_configure(uint8_t reset_type)
Neeti Desai120b55d2012-08-20 17:15:56 -0700337{
338 uint8_t val;
339
340 /* disable PS_HOLD_RESET */
341 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
342
343 /* Delay needed for disable to kick in. */
344 udelay(300);
345
346 /* configure reset type */
347 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
348
349 val = REG_READ(PON_PS_HOLD_RESET_CTL);
350
351 /* enable PS_HOLD_RESET */
352 val |= BIT(S2_RESET_EN_BIT);
353 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
354}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530355
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800356void pm8x41_reset_configure(uint8_t reset_type)
357{
358 /* disable PS_HOLD_RESET */
359 REG_WRITE(PON_PS_HOLD_RESET_CTL2, 0x0);
360
361 /* Delay needed for disable to kick in. */
362 udelay(300);
363
364 /* configure reset type */
365 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
366
367 /* enable PS_HOLD_RESET */
368 REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
369}
370
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530371/*
372 * LDO set voltage, takes ldo name & voltage in UV as input
373 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700374int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530375{
376 uint32_t range = 0;
377 uint32_t step = 0;
378 uint32_t mult = 0;
379 uint32_t val = 0;
380 uint32_t vmin = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530381
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700382 if (!ldo)
383 {
384 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530385 return 1;
386 }
387
388 /* Program Normal power mode */
389 val = 0x0;
390 val = (1 << LDO_NORMAL_PWR_BIT);
391 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
392
393 /*
394 * Select range, step & vmin based on input voltage & type of LDO
395 * LDO can operate in low, mid, high power mode
396 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700397 if (ldo->type == PLDO_TYPE)
398 {
399 if (voltage < PLDO_UV_MIN)
400 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530401 range = 2;
402 step = PLDO_UV_STEP_LOW;
403 vmin = PLDO_UV_VMIN_LOW;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700404 }
405 else if (voltage < PDLO_UV_MID)
406 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530407 range = 3;
408 step = PLDO_UV_STEP_MID;
409 vmin = PLDO_UV_VMIN_MID;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700410 }
411 else
412 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530413 range = 4;
414 step = PLDO_UV_STEP_HIGH;
415 vmin = PLDO_UV_VMIN_HIGH;
416 }
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700417 }
418 else
419 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530420 range = 2;
421 step = NLDO_UV_STEP;
422 vmin = NLDO_UV_VMIN_LOW;
423 }
424
425 mult = (voltage - vmin) / step;
426
427 /* Set Range in voltage ctrl register */
428 val = 0x0;
429 val = range << LDO_RANGE_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700430 REG_WRITE((ldo->base + LDO_RANGE_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530431
432 /* Set multiplier in voltage ctrl register */
433 val = 0x0;
434 val = mult << LDO_VSET_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700435 REG_WRITE((ldo->base + LDO_STEP_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530436
437 return 0;
438}
439
440/*
441 * Enable or Disable LDO
442 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700443int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530444{
445 uint32_t val = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530446
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700447 if (!ldo)
448 {
449 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530450 return 1;
451 }
452
453 /* Enable LDO */
454 if (enable)
455 val = (1 << LDO_VREG_ENABLE_BIT);
456 else
457 val = (0 << LDO_VREG_ENABLE_BIT);
458
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700459 REG_WRITE((ldo->base + LDO_EN_CTL_REG), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530460
461 return 0;
462}
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800463
Kuogee Hsieh11835112013-10-04 15:50:36 -0700464/*
465 * lpg channel register write:
466 */
467void pm8x41_lpg_write(uint8_t chan, uint8_t off, uint8_t val)
468{
469 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
470
471 REG_WRITE(lpg_base + off, val);
472}
473
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700474/*
475 * pmi lpg channel register write with slave_id:
476 */
477void pm8x41_lpg_write_sid(uint8_t sid, uint8_t chan, uint8_t off, uint8_t val)
478{
479 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
480
481 lpg_base &= 0x0ffff; /* clear sid */
482 lpg_base |= (sid << 16); /* add sid */
483
484 dprintf(SPEW, "%s: lpg=%d base=%x\n", __func__, chan, lpg_base);
485
486 REG_WRITE(lpg_base + off, val);
487}
488
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800489uint8_t pm8x41_get_pmic_rev()
490{
491 return REG_READ(REVID_REVISION4);
492}
493
sundarajan srinivasand0f59e82013-02-12 19:17:02 -0800494uint8_t pm8x41_get_pon_reason()
495{
496 return REG_READ(PON_PON_REASON1);
497}
Deepa Dinamanic342f122013-06-12 15:41:31 -0700498
Matthew Qin5e90d832014-07-11 11:15:22 +0800499uint8_t pm8x41_get_pon_poff_reason1()
500{
501 return REG_READ(PON_POFF_REASON1);
502}
503
504uint8_t pm8x41_get_pon_poff_reason2()
505{
506 return REG_READ(PON_POFF_REASON2);
507}
508
Ajay Singh Parmar502ed712014-07-23 22:58:43 -0700509void pm8x41_enable_mvs(struct pm8x41_mvs *mvs, enum mvs_en_ctl enable)
510{
511 ASSERT(mvs);
512
513 REG_WRITE(mvs->base + MVS_EN_CTL, enable << MVS_EN_CTL_ENABLE_SHIFT);
514}
515
Deepa Dinamanic342f122013-06-12 15:41:31 -0700516void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable)
517{
518 ASSERT(mpp);
519
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530520 REG_WRITE(((mpp->base + MPP_EN_CTL) + (mpp_slave_id << 16)), enable << MPP_EN_CTL_ENABLE_SHIFT);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700521}
522
523void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp)
524{
525 ASSERT(mpp);
526
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530527 REG_WRITE(((mpp->base + MPP_DIG_VIN_CTL) + (mpp_slave_id << 16)), mpp->vin);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700528
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530529 REG_WRITE(((mpp->base + MPP_MODE_CTL) + (mpp_slave_id << 16)), mpp->mode | (MPP_DIGITAL_OUTPUT << MPP_MODE_CTL_MODE_SHIFT));
Deepa Dinamanic342f122013-06-12 15:41:31 -0700530}
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700531
532uint8_t pm8x41_get_is_cold_boot()
533{
534 if (REG_READ(PON_WARMBOOT_STATUS1) || REG_READ(PON_WARMBOOT_STATUS2)) {
535 dprintf(INFO,"%s: Warm boot\n", __func__);
536 return 0;
537 }
538 dprintf(INFO,"%s: cold boot\n", __func__);
539 return 1;
540}
Amol Jadic3231ff2013-07-23 14:35:31 -0700541
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800542/* api to control lnbb clock */
543void pm8x41_lnbb_clock_ctrl(uint8_t enable)
544{
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800545 if (enable)
546 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800547 rpm_clk_enable(&ln_bb_clk[GENERIC_ENABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800548 }
549 else
550 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800551 rpm_clk_enable(&ln_bb_clk[GENERIC_DISABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800552 }
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800553}
554
Amol Jadic3231ff2013-07-23 14:35:31 -0700555/* api to control diff clock */
556void pm8x41_diff_clock_ctrl(uint8_t enable)
557{
558 uint8_t reg;
559
560 reg = REG_READ(DIFF_CLK1_EN_CTL);
561
562 if (enable)
563 {
564 reg |= BIT(DIFF_CLK1_EN_BIT);
565 }
566 else
567 {
568 reg &= ~BIT(DIFF_CLK1_EN_BIT);
569 }
570
571 REG_WRITE(DIFF_CLK1_EN_CTL, reg);
572}
Xiaocheng Li73c57122013-09-14 17:32:00 +0800573
574void pm8x41_clear_pmic_watchdog(void)
575{
576 pm8x41_reg_write(PMIC_WD_RESET_S2_CTL2, 0x0);
577}
Channagoud Kadabi1372b902013-10-28 16:20:51 -0700578
579/* API to check for borken battery */
580int pm8xxx_is_battery_broken()
581{
582 uint8_t trkl_default = 0;
583 uint8_t vbat_det_default = 0;
584 int batt_is_broken = 0;
585
586 /* Store original trickle charging current setting */
587 trkl_default = pm8x41_reg_read(PM8XXX_IBAT_ATC_A);
588 /* Store original VBAT_DET_LO setting */
589 vbat_det_default = pm8x41_reg_read(PM8XXX_VBAT_DET);
590
591 /*Set trickle charge current to 50mA (IBAT_ATC_A = 0x00) */
592 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, 0x00);
593 /* Set VBAT_DET_LO to 4.3V so that VBAT_DET_HI = 4.52V (VBAT_DET_LO = 0x35) */
594 pm8x41_reg_write(PM8XXX_VBAT_DET, VBAT_DET_LO_4_30V);
595 /* Unlock SMBBP Secured Register */
596 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
597 /* Disable VTRKL_FAULT comp (SMBBP_CHGR_COMP_OVR0 = 0x08) */
598 pm8x41_reg_write(PM8XXX_COMP_OVR0, OVR0_DIS_VTRKL_FAULT);
599 /* Disable VCP (SMBB_BAT_IF_VCP = 0x00) */
600 pm8x41_reg_write(PM8XXX_VCP, 0x00);
601 /* Unlock SMBBP Secured Register */
602 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
603 /* Force trickle charging (SMBB_CHGR_TRKL_CHG_TEST = 0x01) */
604 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, CHG_TRICKLE_FORCED_ON);
605 /* Wait for vbat to rise */
606 mdelay(12);
607
608 /* Check Above VBAT_DET_HIGH status */
609 if (pm8x41_reg_read(PM8XXX_VBAT_IN_TSTS) & VBAT_DET_HI_RT_STS)
610 batt_is_broken = 1;
611 else
612 batt_is_broken = 0;
613
614 /* Unlock SMBBP Secured Register */
615 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
616
617 /* Disable force trickle charging */
618 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, 0x00);
619 /* re-enable VCP */
620 pm8x41_reg_write(PM8XXX_VCP, VCP_ENABLE);
621 /* restore trickle charging default current */
622 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, trkl_default);
623 /* restore VBAT_DET_LO setting to original value */
624 pm8x41_reg_write(PM8XXX_VBAT_DET, vbat_det_default);
625
626 return batt_is_broken;
627}
Channagoud Kadabi8ceb7382014-11-14 11:25:35 -0800628
629/* Detect broken battery for pmi 8994*/
630bool pmi8994_is_battery_broken()
631{
632 bool batt_is_broken;
633 uint8_t fast_charge = 0;
634
635 /* Disable the input missing ppoller */
636 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) & ~INPUT_MISSING_POLLER_EN);
637 /* Disable current termination */
638 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) & ~CURRENT_TERM_EN);
639 /* Fast-charge current to 300 mA */
640 fast_charge = REG_READ(PMI8994_FCC_CFG);
641 REG_WRITE(PMI8994_FCC_CFG, 0x0);
642 /* Change the float voltage to 4.50V */
643 REG_WRITE(PMI8994_FV_CFG, 0x3F);
644
645 mdelay(5);
646
647 if (REG_READ(PMI8994_INT_RT_STS) & BAT_TAPER_MODE_CHARGING_RT_STS)
648 batt_is_broken = true;
649 else
650 batt_is_broken = false;
651
652 /* Set float voltage back to 4.35V */
653 REG_WRITE(PMI8994_FV_CFG, 0x2B);
654 /* Enable current termination */
655 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) | CURRENT_TERM_EN);
656 /* Fast-charge current back to default mA */
657 REG_WRITE(PMI8994_FCC_CFG, fast_charge);
658 /* Re-enable the input missing poller */
659 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) | INPUT_MISSING_POLLER_EN);
660
661 return batt_is_broken;
662}