blob: 0a43bff3e7031a013fd3ac1b831093afa39815cb [file] [log] [blame]
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -08001/* Copyright (c) 2012-2015, 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.
Parth Dixitc2e6dfe2015-06-19 15:57:47 +053012 * * Neither the name of The Linux Foundation, 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>
Sridhar Parasuram92f87282015-02-05 09:58:18 -080036#include <rpm-ipc.h>
Channagoud Kadabi9089da62014-11-10 13:19:55 -080037#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 Kadabi1312b5d2015-01-28 23:28:47 -080080/* SPMI helper function which takes slave id as the i/p */
81void pm8xxx_reg_write(uint8_t slave_id, uint32_t addr, uint8_t val)
82{
83 struct pmic_arb_cmd cmd;
84 struct pmic_arb_param param;
85
86 cmd.address = PERIPH_ID(addr);
87 cmd.offset = REG_OFFSET(addr);
88 cmd.slave_id = slave_id;
89
90 cmd.priority = 0;
91
92 param.buffer = &val;
93 param.size = 1;
94
95 pmic_arb_write_cmd(&cmd, &param);
96}
97
Channagoud Kadabid091f702013-01-07 16:17:37 -080098void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -070099{
100 struct pmic_arb_cmd cmd;
101 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -0700102
Deepa Dinamani9a612932012-08-14 16:15:03 -0700103 cmd.address = PERIPH_ID(addr);
104 cmd.offset = REG_OFFSET(addr);
105 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -0700106 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -0700107
Deepa Dinamani9a612932012-08-14 16:15:03 -0700108 param.buffer = &val;
109 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -0700110
Deepa Dinamani9a612932012-08-14 16:15:03 -0700111 pmic_arb_write_cmd(&cmd, &param);
112}
Deepa Dinamani22799652012-07-21 12:26:22 -0700113
Deepa Dinamani9a612932012-08-14 16:15:03 -0700114/* Exported functions */
115
116/* Set the boot done flag */
117void pm8x41_set_boot_done()
118{
119 uint8_t val;
120
121 val = REG_READ(SMBB_MISC_BOOT_DONE);
122 val |= BIT(BOOT_DONE_BIT);
123 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
124}
125
126/* Configure GPIO */
127int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
128{
129 uint8_t val;
130 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
131
132 /* Disable the GPIO */
133 val = REG_READ(gpio_base + GPIO_EN_CTL);
134 val &= ~BIT(PERPH_EN_BIT);
135 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
136
137 /* Select the mode */
138 val = config->function | (config->direction << 4);
139 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
140
141 /* Set the right pull */
142 val = config->pull;
143 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
144
145 /* Select the VIN */
146 val = config->vin_sel;
147 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
148
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800149 if (config->direction == PM_GPIO_DIR_OUT) {
150 /* Set the right dig out control */
151 val = config->out_strength | (config->output_buffer << 4);
152 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
153 }
154
Deepa Dinamani9a612932012-08-14 16:15:03 -0700155 /* Enable the GPIO */
156 val = REG_READ(gpio_base + GPIO_EN_CTL);
157 val |= BIT(PERPH_EN_BIT);
158 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
159
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800160 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700161}
162
163/* Reads the status of requested gpio */
164int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
165{
166 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
167
168 *status = REG_READ(gpio_base + GPIO_STATUS);
169
170 /* Return the value of the GPIO pin */
171 *status &= BIT(GPIO_STATUS_VAL_BIT);
172
173 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
174
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800175 return 0;
176}
177
178/* Write the output value of the requested gpio */
179int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
180{
181 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
182 uint8_t val;
183
184 /* Set the output value of the gpio */
185 val = REG_READ(gpio_base + GPIO_MODE_CTL);
186 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
187 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
188
189 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700190}
191
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700192/* Configure PM and PMI GPIO with slave id */
193int pm8x41_gpio_config_sid(uint8_t sid, uint8_t gpio, struct pm8x41_gpio *config)
194{
195 uint8_t val;
196 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
197
198 gpio_base &= 0x0ffff; /* clear sid */
199 gpio_base |= (sid << 16); /* add sid */
200
201 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
202
203 /* Disable the GPIO */
204 val = REG_READ(gpio_base + GPIO_EN_CTL);
205 val &= ~BIT(PERPH_EN_BIT);
206 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
207
208 /* Select the mode */
209 val = config->function | (config->direction << 4);
210 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
211
212 /* Set the right pull */
213 val = config->pull;
214 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
215
216 /* Select the VIN */
217 val = config->vin_sel;
218 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
219
220 if (config->direction == PM_GPIO_DIR_OUT) {
221 /* Set the right dig out control */
222 val = config->out_strength | (config->output_buffer << 4);
223 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
224 }
225
226 /* Enable the GPIO */
227 val = REG_READ(gpio_base + GPIO_EN_CTL);
228 val |= BIT(PERPH_EN_BIT);
229 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
230
231 return 0;
232}
233
234/* Reads the status of requested gpio */
235int pm8x41_gpio_get_sid(uint8_t sid, uint8_t gpio, uint8_t *status)
236{
237 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
238
239 gpio_base &= 0x0ffff; /* clear sid */
240 gpio_base |= (sid << 16); /* add sid */
241
242 *status = REG_READ(gpio_base + GPIO_STATUS);
243
244 /* Return the value of the GPIO pin */
245 *status &= BIT(GPIO_STATUS_VAL_BIT);
246
247 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
248
249 return 0;
250}
251
252/* Write the output value of the requested gpio */
253int pm8x41_gpio_set_sid(uint8_t sid, uint8_t gpio, uint8_t value)
254{
255 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
256 uint8_t val;
257
258 gpio_base &= 0x0ffff; /* clear sid */
259 gpio_base |= (sid << 16); /* add sid */
260
261 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
262
263 /* Set the output value of the gpio */
264 val = REG_READ(gpio_base + GPIO_MODE_CTL);
265 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
266 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
267
268 return 0;
269}
270
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800271/* Prepare PON RESIN S2 reset (bite) */
272void pm8x41_resin_s2_reset_enable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700273{
274 uint8_t val;
275
276 /* disable s2 reset */
277 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
278
Amol Jadi7ec52b42012-08-16 14:12:45 -0700279 /* Delay needed for disable to kick in. */
280 udelay(300);
281
Deepa Dinamani9a612932012-08-14 16:15:03 -0700282 /* configure s1 timer to 0 */
283 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
284
285 /* configure s2 timer to 2s */
286 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
287
288 /* configure reset type */
289 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
290
291 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
292
293 /* enable s2 reset */
294 val |= BIT(S2_RESET_EN_BIT);
295 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
296}
297
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800298/* Disable PON RESIN S2 reset. (bite)*/
299void pm8x41_resin_s2_reset_disable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700300{
301 /* disable s2 reset */
302 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700303
304 /* Delay needed for disable to kick in. */
305 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700306}
307
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800308/* Resin irq status for faulty pmic*/
Channagoud Kadabi36c19ea2013-07-05 16:28:44 -0700309uint32_t pm8x41_v2_resin_status()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700310{
311 uint8_t rt_sts = 0;
312
313 /* Enable S2 reset so we can detect the volume down key press */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800314 pm8x41_resin_s2_reset_enable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700315
316 /* Delay before interrupt triggering.
317 * See PON_DEBOUNCE_CTL reg.
318 */
319 mdelay(100);
320
321 rt_sts = REG_READ(PON_INT_RT_STS);
322
323 /* Must disable S2 reset otherwise PMIC will reset if key
324 * is held longer than S2 timer.
325 */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800326 pm8x41_resin_s2_reset_disable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700327
328 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700329}
Neeti Desai120b55d2012-08-20 17:15:56 -0700330
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800331/* Resin pin status */
332uint32_t pm8x41_resin_status()
333{
334 uint8_t rt_sts = 0;
335
336 rt_sts = REG_READ(PON_INT_RT_STS);
337
338 return (rt_sts & BIT(RESIN_ON_INT_BIT));
339}
340
Matthew Qin3aa87052014-02-21 10:32:34 +0800341/* Return 1 if power key is pressed */
342uint32_t pm8x41_get_pwrkey_is_pressed()
343{
344 uint8_t pwr_sts = 0;
345
346 pwr_sts = REG_READ(PON_INT_RT_STS);
347
348 if (pwr_sts & BIT(KPDPWR_ON_INT_BIT))
349 return 1;
350 else
351 return 0;
352}
353
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800354void pm8994_reset_configure(uint8_t reset_type)
355{
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700356 /* Slave ID of pm8994 and pmi8994 */
357 uint8_t slave_id[] = {0, 2};
358 uint8_t i;
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800359
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700360 /* Reset sequence
361 1. Disable the ps hold for pm8994
362 2. set reset type for both pm8994 & pmi8994
363 3. Enable ps hold for pm8994 to trigger the reset
364 */
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800365 /* disable PS_HOLD_RESET */
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700366 pm8xxx_reg_write(slave_id[0], PON_PS_HOLD_RESET_CTL2, 0x0);
Channagoud Kadabi085ae312015-06-25 23:12:47 -0700367 pm8xxx_reg_write(slave_id[1], PON_PS_HOLD_RESET_CTL2, 0x0);
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800368
369 /* Delay needed for disable to kick in. */
370 udelay(300);
371
372 /* configure reset type */
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700373 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
374 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL, reset_type);
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800375
376 /* enable PS_HOLD_RESET */
Channagoud Kadabi085ae312015-06-25 23:12:47 -0700377 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
378 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800379}
380
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800381void pm8x41_v2_reset_configure(uint8_t reset_type)
Neeti Desai120b55d2012-08-20 17:15:56 -0700382{
383 uint8_t val;
384
385 /* disable PS_HOLD_RESET */
386 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
387
388 /* Delay needed for disable to kick in. */
389 udelay(300);
390
391 /* configure reset type */
392 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
393
394 val = REG_READ(PON_PS_HOLD_RESET_CTL);
395
396 /* enable PS_HOLD_RESET */
397 val |= BIT(S2_RESET_EN_BIT);
398 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
399}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530400
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800401void pm8x41_reset_configure(uint8_t reset_type)
402{
403 /* disable PS_HOLD_RESET */
404 REG_WRITE(PON_PS_HOLD_RESET_CTL2, 0x0);
405
406 /* Delay needed for disable to kick in. */
407 udelay(300);
408
409 /* configure reset type */
410 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
411
412 /* enable PS_HOLD_RESET */
413 REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
414}
415
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530416/*
417 * LDO set voltage, takes ldo name & voltage in UV as input
418 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700419int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530420{
421 uint32_t range = 0;
422 uint32_t step = 0;
423 uint32_t mult = 0;
424 uint32_t val = 0;
425 uint32_t vmin = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530426
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700427 if (!ldo)
428 {
429 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530430 return 1;
431 }
432
433 /* Program Normal power mode */
434 val = 0x0;
435 val = (1 << LDO_NORMAL_PWR_BIT);
436 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
437
438 /*
439 * Select range, step & vmin based on input voltage & type of LDO
440 * LDO can operate in low, mid, high power mode
441 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700442 if (ldo->type == PLDO_TYPE)
443 {
444 if (voltage < PLDO_UV_MIN)
445 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530446 range = 2;
447 step = PLDO_UV_STEP_LOW;
448 vmin = PLDO_UV_VMIN_LOW;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700449 }
450 else if (voltage < PDLO_UV_MID)
451 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530452 range = 3;
453 step = PLDO_UV_STEP_MID;
454 vmin = PLDO_UV_VMIN_MID;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700455 }
456 else
457 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530458 range = 4;
459 step = PLDO_UV_STEP_HIGH;
460 vmin = PLDO_UV_VMIN_HIGH;
461 }
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700462 }
463 else
464 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530465 range = 2;
466 step = NLDO_UV_STEP;
467 vmin = NLDO_UV_VMIN_LOW;
468 }
469
470 mult = (voltage - vmin) / step;
471
472 /* Set Range in voltage ctrl register */
473 val = 0x0;
474 val = range << LDO_RANGE_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700475 REG_WRITE((ldo->base + LDO_RANGE_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530476
477 /* Set multiplier in voltage ctrl register */
478 val = 0x0;
479 val = mult << LDO_VSET_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700480 REG_WRITE((ldo->base + LDO_STEP_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530481
482 return 0;
483}
484
485/*
486 * Enable or Disable LDO
487 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700488int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530489{
490 uint32_t val = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530491
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700492 if (!ldo)
493 {
494 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530495 return 1;
496 }
497
498 /* Enable LDO */
499 if (enable)
500 val = (1 << LDO_VREG_ENABLE_BIT);
501 else
502 val = (0 << LDO_VREG_ENABLE_BIT);
503
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700504 REG_WRITE((ldo->base + LDO_EN_CTL_REG), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530505
506 return 0;
507}
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800508
Kuogee Hsieh11835112013-10-04 15:50:36 -0700509/*
510 * lpg channel register write:
511 */
512void pm8x41_lpg_write(uint8_t chan, uint8_t off, uint8_t val)
513{
514 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
515
516 REG_WRITE(lpg_base + off, val);
517}
518
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700519/*
520 * pmi lpg channel register write with slave_id:
521 */
522void pm8x41_lpg_write_sid(uint8_t sid, uint8_t chan, uint8_t off, uint8_t val)
523{
524 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
525
526 lpg_base &= 0x0ffff; /* clear sid */
527 lpg_base |= (sid << 16); /* add sid */
528
529 dprintf(SPEW, "%s: lpg=%d base=%x\n", __func__, chan, lpg_base);
530
531 REG_WRITE(lpg_base + off, val);
532}
533
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800534uint8_t pm8x41_get_pmic_rev()
535{
536 return REG_READ(REVID_REVISION4);
537}
538
sundarajan srinivasand0f59e82013-02-12 19:17:02 -0800539uint8_t pm8x41_get_pon_reason()
540{
541 return REG_READ(PON_PON_REASON1);
542}
Deepa Dinamanic342f122013-06-12 15:41:31 -0700543
Parth Dixitc2e6dfe2015-06-19 15:57:47 +0530544uint8_t pm8950_get_pon_reason()
545{
546 uint8_t pon_reason = 0;
547
Parth Dixit746b6bb2015-07-09 19:29:44 +0530548 pon_reason = REG_READ(SMBCHGL_USB_ICL_STS_2|PMI8950_SLAVE_ID);
Parth Dixitc2e6dfe2015-06-19 15:57:47 +0530549 /* check usbin/dcin status on pmi and set the corresponding bits for pon */
550 pon_reason = (pon_reason & (USBIN_ACTIVE_PWR_SRC|DCIN_ACTIVE_PWR_SRC)) << 3 ;
551 pon_reason |= REG_READ(PON_PON_REASON1);
552
553 return pon_reason;
554}
555
Matthew Qin5e90d832014-07-11 11:15:22 +0800556uint8_t pm8x41_get_pon_poff_reason1()
557{
558 return REG_READ(PON_POFF_REASON1);
559}
560
561uint8_t pm8x41_get_pon_poff_reason2()
562{
563 return REG_READ(PON_POFF_REASON2);
564}
565
Ajay Singh Parmar502ed712014-07-23 22:58:43 -0700566void pm8x41_enable_mvs(struct pm8x41_mvs *mvs, enum mvs_en_ctl enable)
567{
568 ASSERT(mvs);
569
570 REG_WRITE(mvs->base + MVS_EN_CTL, enable << MVS_EN_CTL_ENABLE_SHIFT);
571}
572
Deepa Dinamanic342f122013-06-12 15:41:31 -0700573void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable)
574{
575 ASSERT(mpp);
576
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530577 REG_WRITE(((mpp->base + MPP_EN_CTL) + (mpp_slave_id << 16)), enable << MPP_EN_CTL_ENABLE_SHIFT);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700578}
579
580void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp)
581{
582 ASSERT(mpp);
583
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530584 REG_WRITE(((mpp->base + MPP_DIG_VIN_CTL) + (mpp_slave_id << 16)), mpp->vin);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700585
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530586 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 -0700587}
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700588
589uint8_t pm8x41_get_is_cold_boot()
590{
591 if (REG_READ(PON_WARMBOOT_STATUS1) || REG_READ(PON_WARMBOOT_STATUS2)) {
592 dprintf(INFO,"%s: Warm boot\n", __func__);
593 return 0;
594 }
595 dprintf(INFO,"%s: cold boot\n", __func__);
596 return 1;
597}
Amol Jadic3231ff2013-07-23 14:35:31 -0700598
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800599/* api to control lnbb clock */
600void pm8x41_lnbb_clock_ctrl(uint8_t enable)
601{
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800602 if (enable)
603 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800604 rpm_clk_enable(&ln_bb_clk[GENERIC_ENABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800605 }
606 else
607 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800608 rpm_clk_enable(&ln_bb_clk[GENERIC_DISABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800609 }
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800610}
611
Amol Jadic3231ff2013-07-23 14:35:31 -0700612/* api to control diff clock */
613void pm8x41_diff_clock_ctrl(uint8_t enable)
614{
615 uint8_t reg;
616
617 reg = REG_READ(DIFF_CLK1_EN_CTL);
618
619 if (enable)
620 {
621 reg |= BIT(DIFF_CLK1_EN_BIT);
622 }
623 else
624 {
625 reg &= ~BIT(DIFF_CLK1_EN_BIT);
626 }
627
628 REG_WRITE(DIFF_CLK1_EN_CTL, reg);
629}
Xiaocheng Li73c57122013-09-14 17:32:00 +0800630
631void pm8x41_clear_pmic_watchdog(void)
632{
633 pm8x41_reg_write(PMIC_WD_RESET_S2_CTL2, 0x0);
634}
Channagoud Kadabi1372b902013-10-28 16:20:51 -0700635
636/* API to check for borken battery */
637int pm8xxx_is_battery_broken()
638{
639 uint8_t trkl_default = 0;
640 uint8_t vbat_det_default = 0;
641 int batt_is_broken = 0;
642
643 /* Store original trickle charging current setting */
644 trkl_default = pm8x41_reg_read(PM8XXX_IBAT_ATC_A);
645 /* Store original VBAT_DET_LO setting */
646 vbat_det_default = pm8x41_reg_read(PM8XXX_VBAT_DET);
647
648 /*Set trickle charge current to 50mA (IBAT_ATC_A = 0x00) */
649 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, 0x00);
650 /* Set VBAT_DET_LO to 4.3V so that VBAT_DET_HI = 4.52V (VBAT_DET_LO = 0x35) */
651 pm8x41_reg_write(PM8XXX_VBAT_DET, VBAT_DET_LO_4_30V);
652 /* Unlock SMBBP Secured Register */
653 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
654 /* Disable VTRKL_FAULT comp (SMBBP_CHGR_COMP_OVR0 = 0x08) */
655 pm8x41_reg_write(PM8XXX_COMP_OVR0, OVR0_DIS_VTRKL_FAULT);
656 /* Disable VCP (SMBB_BAT_IF_VCP = 0x00) */
657 pm8x41_reg_write(PM8XXX_VCP, 0x00);
658 /* Unlock SMBBP Secured Register */
659 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
660 /* Force trickle charging (SMBB_CHGR_TRKL_CHG_TEST = 0x01) */
661 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, CHG_TRICKLE_FORCED_ON);
662 /* Wait for vbat to rise */
663 mdelay(12);
664
665 /* Check Above VBAT_DET_HIGH status */
666 if (pm8x41_reg_read(PM8XXX_VBAT_IN_TSTS) & VBAT_DET_HI_RT_STS)
667 batt_is_broken = 1;
668 else
669 batt_is_broken = 0;
670
671 /* Unlock SMBBP Secured Register */
672 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
673
674 /* Disable force trickle charging */
675 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, 0x00);
676 /* re-enable VCP */
677 pm8x41_reg_write(PM8XXX_VCP, VCP_ENABLE);
678 /* restore trickle charging default current */
679 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, trkl_default);
680 /* restore VBAT_DET_LO setting to original value */
681 pm8x41_reg_write(PM8XXX_VBAT_DET, vbat_det_default);
682
683 return batt_is_broken;
684}
Channagoud Kadabi8ceb7382014-11-14 11:25:35 -0800685
686/* Detect broken battery for pmi 8994*/
687bool pmi8994_is_battery_broken()
688{
689 bool batt_is_broken;
690 uint8_t fast_charge = 0;
691
692 /* Disable the input missing ppoller */
693 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) & ~INPUT_MISSING_POLLER_EN);
694 /* Disable current termination */
695 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) & ~CURRENT_TERM_EN);
696 /* Fast-charge current to 300 mA */
697 fast_charge = REG_READ(PMI8994_FCC_CFG);
698 REG_WRITE(PMI8994_FCC_CFG, 0x0);
699 /* Change the float voltage to 4.50V */
700 REG_WRITE(PMI8994_FV_CFG, 0x3F);
701
702 mdelay(5);
703
704 if (REG_READ(PMI8994_INT_RT_STS) & BAT_TAPER_MODE_CHARGING_RT_STS)
705 batt_is_broken = true;
706 else
707 batt_is_broken = false;
708
709 /* Set float voltage back to 4.35V */
710 REG_WRITE(PMI8994_FV_CFG, 0x2B);
711 /* Enable current termination */
712 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) | CURRENT_TERM_EN);
713 /* Fast-charge current back to default mA */
714 REG_WRITE(PMI8994_FCC_CFG, fast_charge);
715 /* Re-enable the input missing poller */
716 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) | INPUT_MISSING_POLLER_EN);
717
718 return batt_is_broken;
719}