blob: c30c6b6d561d99b89c29c7bcdc6ee736341976f9 [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
56uint8_t pmi8994_config_mpp_slave_id(uint8_t slave_id)
57{
58 mpp_slave_id = slave_id;
59}
60
Channagoud Kadabid091f702013-01-07 16:17:37 -080061/* SPMI helper functions */
62uint8_t pm8x41_reg_read(uint32_t addr)
Deepa Dinamani9a612932012-08-14 16:15:03 -070063{
64 uint8_t val = 0;
65 struct pmic_arb_cmd cmd;
66 struct pmic_arb_param param;
67
68 cmd.address = PERIPH_ID(addr);
69 cmd.offset = REG_OFFSET(addr);
70 cmd.slave_id = SLAVE_ID(addr);
71 cmd.priority = 0;
72
73 param.buffer = &val;
74 param.size = 1;
75
76 pmic_arb_read_cmd(&cmd, &param);
77
78 return val;
79}
80
Channagoud Kadabid091f702013-01-07 16:17:37 -080081void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -070082{
83 struct pmic_arb_cmd cmd;
84 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -070085
Deepa Dinamani9a612932012-08-14 16:15:03 -070086 cmd.address = PERIPH_ID(addr);
87 cmd.offset = REG_OFFSET(addr);
88 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -070089 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -070090
Deepa Dinamani9a612932012-08-14 16:15:03 -070091 param.buffer = &val;
92 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -070093
Deepa Dinamani9a612932012-08-14 16:15:03 -070094 pmic_arb_write_cmd(&cmd, &param);
95}
Deepa Dinamani22799652012-07-21 12:26:22 -070096
Deepa Dinamani9a612932012-08-14 16:15:03 -070097/* Exported functions */
98
99/* Set the boot done flag */
100void pm8x41_set_boot_done()
101{
102 uint8_t val;
103
104 val = REG_READ(SMBB_MISC_BOOT_DONE);
105 val |= BIT(BOOT_DONE_BIT);
106 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
107}
108
109/* Configure GPIO */
110int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
111{
112 uint8_t val;
113 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
114
115 /* Disable the GPIO */
116 val = REG_READ(gpio_base + GPIO_EN_CTL);
117 val &= ~BIT(PERPH_EN_BIT);
118 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
119
120 /* Select the mode */
121 val = config->function | (config->direction << 4);
122 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
123
124 /* Set the right pull */
125 val = config->pull;
126 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
127
128 /* Select the VIN */
129 val = config->vin_sel;
130 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
131
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800132 if (config->direction == PM_GPIO_DIR_OUT) {
133 /* Set the right dig out control */
134 val = config->out_strength | (config->output_buffer << 4);
135 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
136 }
137
Deepa Dinamani9a612932012-08-14 16:15:03 -0700138 /* Enable the GPIO */
139 val = REG_READ(gpio_base + GPIO_EN_CTL);
140 val |= BIT(PERPH_EN_BIT);
141 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
142
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800143 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700144}
145
146/* Reads the status of requested gpio */
147int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
148{
149 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
150
151 *status = REG_READ(gpio_base + GPIO_STATUS);
152
153 /* Return the value of the GPIO pin */
154 *status &= BIT(GPIO_STATUS_VAL_BIT);
155
156 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
157
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800158 return 0;
159}
160
161/* Write the output value of the requested gpio */
162int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
163{
164 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
165 uint8_t val;
166
167 /* Set the output value of the gpio */
168 val = REG_READ(gpio_base + GPIO_MODE_CTL);
169 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
170 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
171
172 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700173}
174
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700175/* Configure PM and PMI GPIO with slave id */
176int pm8x41_gpio_config_sid(uint8_t sid, uint8_t gpio, struct pm8x41_gpio *config)
177{
178 uint8_t val;
179 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
180
181 gpio_base &= 0x0ffff; /* clear sid */
182 gpio_base |= (sid << 16); /* add sid */
183
184 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
185
186 /* Disable the GPIO */
187 val = REG_READ(gpio_base + GPIO_EN_CTL);
188 val &= ~BIT(PERPH_EN_BIT);
189 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
190
191 /* Select the mode */
192 val = config->function | (config->direction << 4);
193 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
194
195 /* Set the right pull */
196 val = config->pull;
197 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
198
199 /* Select the VIN */
200 val = config->vin_sel;
201 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
202
203 if (config->direction == PM_GPIO_DIR_OUT) {
204 /* Set the right dig out control */
205 val = config->out_strength | (config->output_buffer << 4);
206 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
207 }
208
209 /* Enable the GPIO */
210 val = REG_READ(gpio_base + GPIO_EN_CTL);
211 val |= BIT(PERPH_EN_BIT);
212 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
213
214 return 0;
215}
216
217/* Reads the status of requested gpio */
218int pm8x41_gpio_get_sid(uint8_t sid, uint8_t gpio, uint8_t *status)
219{
220 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
221
222 gpio_base &= 0x0ffff; /* clear sid */
223 gpio_base |= (sid << 16); /* add sid */
224
225 *status = REG_READ(gpio_base + GPIO_STATUS);
226
227 /* Return the value of the GPIO pin */
228 *status &= BIT(GPIO_STATUS_VAL_BIT);
229
230 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
231
232 return 0;
233}
234
235/* Write the output value of the requested gpio */
236int pm8x41_gpio_set_sid(uint8_t sid, uint8_t gpio, uint8_t value)
237{
238 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
239 uint8_t val;
240
241 gpio_base &= 0x0ffff; /* clear sid */
242 gpio_base |= (sid << 16); /* add sid */
243
244 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
245
246 /* Set the output value of the gpio */
247 val = REG_READ(gpio_base + GPIO_MODE_CTL);
248 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
249 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
250
251 return 0;
252}
253
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800254/* Prepare PON RESIN S2 reset (bite) */
255void pm8x41_resin_s2_reset_enable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700256{
257 uint8_t val;
258
259 /* disable s2 reset */
260 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
261
Amol Jadi7ec52b42012-08-16 14:12:45 -0700262 /* Delay needed for disable to kick in. */
263 udelay(300);
264
Deepa Dinamani9a612932012-08-14 16:15:03 -0700265 /* configure s1 timer to 0 */
266 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
267
268 /* configure s2 timer to 2s */
269 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
270
271 /* configure reset type */
272 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
273
274 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
275
276 /* enable s2 reset */
277 val |= BIT(S2_RESET_EN_BIT);
278 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
279}
280
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800281/* Disable PON RESIN S2 reset. (bite)*/
282void pm8x41_resin_s2_reset_disable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700283{
284 /* disable s2 reset */
285 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700286
287 /* Delay needed for disable to kick in. */
288 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700289}
290
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800291/* Resin irq status for faulty pmic*/
Channagoud Kadabi36c19ea2013-07-05 16:28:44 -0700292uint32_t pm8x41_v2_resin_status()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700293{
294 uint8_t rt_sts = 0;
295
296 /* Enable S2 reset so we can detect the volume down key press */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800297 pm8x41_resin_s2_reset_enable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700298
299 /* Delay before interrupt triggering.
300 * See PON_DEBOUNCE_CTL reg.
301 */
302 mdelay(100);
303
304 rt_sts = REG_READ(PON_INT_RT_STS);
305
306 /* Must disable S2 reset otherwise PMIC will reset if key
307 * is held longer than S2 timer.
308 */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800309 pm8x41_resin_s2_reset_disable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700310
311 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700312}
Neeti Desai120b55d2012-08-20 17:15:56 -0700313
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800314/* Resin pin status */
315uint32_t pm8x41_resin_status()
316{
317 uint8_t rt_sts = 0;
318
319 rt_sts = REG_READ(PON_INT_RT_STS);
320
321 return (rt_sts & BIT(RESIN_ON_INT_BIT));
322}
323
Matthew Qin3aa87052014-02-21 10:32:34 +0800324/* Return 1 if power key is pressed */
325uint32_t pm8x41_get_pwrkey_is_pressed()
326{
327 uint8_t pwr_sts = 0;
328
329 pwr_sts = REG_READ(PON_INT_RT_STS);
330
331 if (pwr_sts & BIT(KPDPWR_ON_INT_BIT))
332 return 1;
333 else
334 return 0;
335}
336
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800337void pm8x41_v2_reset_configure(uint8_t reset_type)
Neeti Desai120b55d2012-08-20 17:15:56 -0700338{
339 uint8_t val;
340
341 /* disable PS_HOLD_RESET */
342 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
343
344 /* Delay needed for disable to kick in. */
345 udelay(300);
346
347 /* configure reset type */
348 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
349
350 val = REG_READ(PON_PS_HOLD_RESET_CTL);
351
352 /* enable PS_HOLD_RESET */
353 val |= BIT(S2_RESET_EN_BIT);
354 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
355}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530356
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800357void pm8x41_reset_configure(uint8_t reset_type)
358{
359 /* disable PS_HOLD_RESET */
360 REG_WRITE(PON_PS_HOLD_RESET_CTL2, 0x0);
361
362 /* Delay needed for disable to kick in. */
363 udelay(300);
364
365 /* configure reset type */
366 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
367
368 /* enable PS_HOLD_RESET */
369 REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
370}
371
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530372/*
373 * LDO set voltage, takes ldo name & voltage in UV as input
374 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700375int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530376{
377 uint32_t range = 0;
378 uint32_t step = 0;
379 uint32_t mult = 0;
380 uint32_t val = 0;
381 uint32_t vmin = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530382
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700383 if (!ldo)
384 {
385 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530386 return 1;
387 }
388
389 /* Program Normal power mode */
390 val = 0x0;
391 val = (1 << LDO_NORMAL_PWR_BIT);
392 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
393
394 /*
395 * Select range, step & vmin based on input voltage & type of LDO
396 * LDO can operate in low, mid, high power mode
397 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700398 if (ldo->type == PLDO_TYPE)
399 {
400 if (voltage < PLDO_UV_MIN)
401 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530402 range = 2;
403 step = PLDO_UV_STEP_LOW;
404 vmin = PLDO_UV_VMIN_LOW;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700405 }
406 else if (voltage < PDLO_UV_MID)
407 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530408 range = 3;
409 step = PLDO_UV_STEP_MID;
410 vmin = PLDO_UV_VMIN_MID;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700411 }
412 else
413 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530414 range = 4;
415 step = PLDO_UV_STEP_HIGH;
416 vmin = PLDO_UV_VMIN_HIGH;
417 }
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700418 }
419 else
420 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530421 range = 2;
422 step = NLDO_UV_STEP;
423 vmin = NLDO_UV_VMIN_LOW;
424 }
425
426 mult = (voltage - vmin) / step;
427
428 /* Set Range in voltage ctrl register */
429 val = 0x0;
430 val = range << LDO_RANGE_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700431 REG_WRITE((ldo->base + LDO_RANGE_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530432
433 /* Set multiplier in voltage ctrl register */
434 val = 0x0;
435 val = mult << LDO_VSET_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700436 REG_WRITE((ldo->base + LDO_STEP_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530437
438 return 0;
439}
440
441/*
442 * Enable or Disable LDO
443 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700444int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530445{
446 uint32_t val = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530447
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700448 if (!ldo)
449 {
450 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530451 return 1;
452 }
453
454 /* Enable LDO */
455 if (enable)
456 val = (1 << LDO_VREG_ENABLE_BIT);
457 else
458 val = (0 << LDO_VREG_ENABLE_BIT);
459
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700460 REG_WRITE((ldo->base + LDO_EN_CTL_REG), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530461
462 return 0;
463}
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800464
Kuogee Hsieh11835112013-10-04 15:50:36 -0700465/*
466 * lpg channel register write:
467 */
468void pm8x41_lpg_write(uint8_t chan, uint8_t off, uint8_t val)
469{
470 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
471
472 REG_WRITE(lpg_base + off, val);
473}
474
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700475/*
476 * pmi lpg channel register write with slave_id:
477 */
478void pm8x41_lpg_write_sid(uint8_t sid, uint8_t chan, uint8_t off, uint8_t val)
479{
480 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
481
482 lpg_base &= 0x0ffff; /* clear sid */
483 lpg_base |= (sid << 16); /* add sid */
484
485 dprintf(SPEW, "%s: lpg=%d base=%x\n", __func__, chan, lpg_base);
486
487 REG_WRITE(lpg_base + off, val);
488}
489
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800490uint8_t pm8x41_get_pmic_rev()
491{
492 return REG_READ(REVID_REVISION4);
493}
494
sundarajan srinivasand0f59e82013-02-12 19:17:02 -0800495uint8_t pm8x41_get_pon_reason()
496{
497 return REG_READ(PON_PON_REASON1);
498}
Deepa Dinamanic342f122013-06-12 15:41:31 -0700499
Matthew Qin5e90d832014-07-11 11:15:22 +0800500uint8_t pm8x41_get_pon_poff_reason1()
501{
502 return REG_READ(PON_POFF_REASON1);
503}
504
505uint8_t pm8x41_get_pon_poff_reason2()
506{
507 return REG_READ(PON_POFF_REASON2);
508}
509
Ajay Singh Parmar502ed712014-07-23 22:58:43 -0700510void pm8x41_enable_mvs(struct pm8x41_mvs *mvs, enum mvs_en_ctl enable)
511{
512 ASSERT(mvs);
513
514 REG_WRITE(mvs->base + MVS_EN_CTL, enable << MVS_EN_CTL_ENABLE_SHIFT);
515}
516
Deepa Dinamanic342f122013-06-12 15:41:31 -0700517void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable)
518{
519 ASSERT(mpp);
520
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530521 REG_WRITE(((mpp->base + MPP_EN_CTL) + (mpp_slave_id << 16)), enable << MPP_EN_CTL_ENABLE_SHIFT);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700522}
523
524void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp)
525{
526 ASSERT(mpp);
527
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530528 REG_WRITE(((mpp->base + MPP_DIG_VIN_CTL) + (mpp_slave_id << 16)), mpp->vin);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700529
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530530 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 -0700531}
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700532
533uint8_t pm8x41_get_is_cold_boot()
534{
535 if (REG_READ(PON_WARMBOOT_STATUS1) || REG_READ(PON_WARMBOOT_STATUS2)) {
536 dprintf(INFO,"%s: Warm boot\n", __func__);
537 return 0;
538 }
539 dprintf(INFO,"%s: cold boot\n", __func__);
540 return 1;
541}
Amol Jadic3231ff2013-07-23 14:35:31 -0700542
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800543/* api to control lnbb clock */
544void pm8x41_lnbb_clock_ctrl(uint8_t enable)
545{
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800546 if (enable)
547 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800548 rpm_clk_enable(&ln_bb_clk[GENERIC_ENABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800549 }
550 else
551 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800552 rpm_clk_enable(&ln_bb_clk[GENERIC_DISABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800553 }
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800554}
555
Amol Jadic3231ff2013-07-23 14:35:31 -0700556/* api to control diff clock */
557void pm8x41_diff_clock_ctrl(uint8_t enable)
558{
559 uint8_t reg;
560
561 reg = REG_READ(DIFF_CLK1_EN_CTL);
562
563 if (enable)
564 {
565 reg |= BIT(DIFF_CLK1_EN_BIT);
566 }
567 else
568 {
569 reg &= ~BIT(DIFF_CLK1_EN_BIT);
570 }
571
572 REG_WRITE(DIFF_CLK1_EN_CTL, reg);
573}
Xiaocheng Li73c57122013-09-14 17:32:00 +0800574
575void pm8x41_clear_pmic_watchdog(void)
576{
577 pm8x41_reg_write(PMIC_WD_RESET_S2_CTL2, 0x0);
578}
Channagoud Kadabi1372b902013-10-28 16:20:51 -0700579
580/* API to check for borken battery */
581int pm8xxx_is_battery_broken()
582{
583 uint8_t trkl_default = 0;
584 uint8_t vbat_det_default = 0;
585 int batt_is_broken = 0;
586
587 /* Store original trickle charging current setting */
588 trkl_default = pm8x41_reg_read(PM8XXX_IBAT_ATC_A);
589 /* Store original VBAT_DET_LO setting */
590 vbat_det_default = pm8x41_reg_read(PM8XXX_VBAT_DET);
591
592 /*Set trickle charge current to 50mA (IBAT_ATC_A = 0x00) */
593 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, 0x00);
594 /* Set VBAT_DET_LO to 4.3V so that VBAT_DET_HI = 4.52V (VBAT_DET_LO = 0x35) */
595 pm8x41_reg_write(PM8XXX_VBAT_DET, VBAT_DET_LO_4_30V);
596 /* Unlock SMBBP Secured Register */
597 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
598 /* Disable VTRKL_FAULT comp (SMBBP_CHGR_COMP_OVR0 = 0x08) */
599 pm8x41_reg_write(PM8XXX_COMP_OVR0, OVR0_DIS_VTRKL_FAULT);
600 /* Disable VCP (SMBB_BAT_IF_VCP = 0x00) */
601 pm8x41_reg_write(PM8XXX_VCP, 0x00);
602 /* Unlock SMBBP Secured Register */
603 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
604 /* Force trickle charging (SMBB_CHGR_TRKL_CHG_TEST = 0x01) */
605 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, CHG_TRICKLE_FORCED_ON);
606 /* Wait for vbat to rise */
607 mdelay(12);
608
609 /* Check Above VBAT_DET_HIGH status */
610 if (pm8x41_reg_read(PM8XXX_VBAT_IN_TSTS) & VBAT_DET_HI_RT_STS)
611 batt_is_broken = 1;
612 else
613 batt_is_broken = 0;
614
615 /* Unlock SMBBP Secured Register */
616 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
617
618 /* Disable force trickle charging */
619 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, 0x00);
620 /* re-enable VCP */
621 pm8x41_reg_write(PM8XXX_VCP, VCP_ENABLE);
622 /* restore trickle charging default current */
623 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, trkl_default);
624 /* restore VBAT_DET_LO setting to original value */
625 pm8x41_reg_write(PM8XXX_VBAT_DET, vbat_det_default);
626
627 return batt_is_broken;
628}