blob: 035c442434808421225e4892248004232d37a65e [file] [log] [blame]
Matthew Qindc1e9672014-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>
36#include <platform/timer.h>
Deepa Dinamani22799652012-07-21 12:26:22 -070037
Channagoud Kadabid091f702013-01-07 16:17:37 -080038/* SPMI helper functions */
39uint8_t pm8x41_reg_read(uint32_t addr)
Deepa Dinamani9a612932012-08-14 16:15:03 -070040{
41 uint8_t val = 0;
42 struct pmic_arb_cmd cmd;
43 struct pmic_arb_param param;
44
45 cmd.address = PERIPH_ID(addr);
46 cmd.offset = REG_OFFSET(addr);
47 cmd.slave_id = SLAVE_ID(addr);
48 cmd.priority = 0;
49
50 param.buffer = &val;
51 param.size = 1;
52
53 pmic_arb_read_cmd(&cmd, &param);
54
55 return val;
56}
57
Channagoud Kadabid091f702013-01-07 16:17:37 -080058void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -070059{
60 struct pmic_arb_cmd cmd;
61 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -070062
Deepa Dinamani9a612932012-08-14 16:15:03 -070063 cmd.address = PERIPH_ID(addr);
64 cmd.offset = REG_OFFSET(addr);
65 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -070066 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -070067
Deepa Dinamani9a612932012-08-14 16:15:03 -070068 param.buffer = &val;
69 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -070070
Deepa Dinamani9a612932012-08-14 16:15:03 -070071 pmic_arb_write_cmd(&cmd, &param);
72}
Deepa Dinamani22799652012-07-21 12:26:22 -070073
Deepa Dinamani9a612932012-08-14 16:15:03 -070074/* Exported functions */
75
76/* Set the boot done flag */
77void pm8x41_set_boot_done()
78{
79 uint8_t val;
80
81 val = REG_READ(SMBB_MISC_BOOT_DONE);
82 val |= BIT(BOOT_DONE_BIT);
83 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
84}
85
86/* Configure GPIO */
87int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
88{
89 uint8_t val;
90 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
91
92 /* Disable the GPIO */
93 val = REG_READ(gpio_base + GPIO_EN_CTL);
94 val &= ~BIT(PERPH_EN_BIT);
95 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
96
97 /* Select the mode */
98 val = config->function | (config->direction << 4);
99 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
100
101 /* Set the right pull */
102 val = config->pull;
103 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
104
105 /* Select the VIN */
106 val = config->vin_sel;
107 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
108
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800109 if (config->direction == PM_GPIO_DIR_OUT) {
110 /* Set the right dig out control */
111 val = config->out_strength | (config->output_buffer << 4);
112 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
113 }
114
Deepa Dinamani9a612932012-08-14 16:15:03 -0700115 /* Enable 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
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800120 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700121}
122
123/* Reads the status of requested gpio */
124int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
125{
126 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
127
128 *status = REG_READ(gpio_base + GPIO_STATUS);
129
130 /* Return the value of the GPIO pin */
131 *status &= BIT(GPIO_STATUS_VAL_BIT);
132
133 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
134
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800135 return 0;
136}
137
138/* Write the output value of the requested gpio */
139int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
140{
141 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
142 uint8_t val;
143
144 /* Set the output value of the gpio */
145 val = REG_READ(gpio_base + GPIO_MODE_CTL);
146 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
147 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
148
149 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700150}
151
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800152/* Prepare PON RESIN S2 reset (bite) */
153void pm8x41_resin_s2_reset_enable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700154{
155 uint8_t val;
156
157 /* disable s2 reset */
158 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
159
Amol Jadi7ec52b42012-08-16 14:12:45 -0700160 /* Delay needed for disable to kick in. */
161 udelay(300);
162
Deepa Dinamani9a612932012-08-14 16:15:03 -0700163 /* configure s1 timer to 0 */
164 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
165
166 /* configure s2 timer to 2s */
167 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
168
169 /* configure reset type */
170 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
171
172 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
173
174 /* enable s2 reset */
175 val |= BIT(S2_RESET_EN_BIT);
176 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
177}
178
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800179/* Disable PON RESIN S2 reset. (bite)*/
180void pm8x41_resin_s2_reset_disable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700181{
182 /* disable s2 reset */
183 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700184
185 /* Delay needed for disable to kick in. */
186 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700187}
188
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800189/* Resin irq status for faulty pmic*/
Channagoud Kadabi36c19ea2013-07-05 16:28:44 -0700190uint32_t pm8x41_v2_resin_status()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700191{
192 uint8_t rt_sts = 0;
193
194 /* Enable S2 reset so we can detect the volume down key press */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800195 pm8x41_resin_s2_reset_enable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700196
197 /* Delay before interrupt triggering.
198 * See PON_DEBOUNCE_CTL reg.
199 */
200 mdelay(100);
201
202 rt_sts = REG_READ(PON_INT_RT_STS);
203
204 /* Must disable S2 reset otherwise PMIC will reset if key
205 * is held longer than S2 timer.
206 */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800207 pm8x41_resin_s2_reset_disable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700208
209 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700210}
Neeti Desai120b55d2012-08-20 17:15:56 -0700211
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800212/* Resin pin status */
213uint32_t pm8x41_resin_status()
214{
215 uint8_t rt_sts = 0;
216
217 rt_sts = REG_READ(PON_INT_RT_STS);
218
219 return (rt_sts & BIT(RESIN_ON_INT_BIT));
220}
221
Matthew Qindc1e9672014-02-21 10:32:34 +0800222/* Return 1 if power key is pressed */
223uint32_t pm8x41_get_pwrkey_is_pressed()
224{
225 uint8_t pwr_sts = 0;
226
227 pwr_sts = REG_READ(PON_INT_RT_STS);
228
229 if (pwr_sts & BIT(KPDPWR_ON_INT_BIT))
230 return 1;
231 else
232 return 0;
233}
234
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800235void pm8x41_v2_reset_configure(uint8_t reset_type)
Neeti Desai120b55d2012-08-20 17:15:56 -0700236{
237 uint8_t val;
238
239 /* disable PS_HOLD_RESET */
240 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
241
242 /* Delay needed for disable to kick in. */
243 udelay(300);
244
245 /* configure reset type */
246 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
247
248 val = REG_READ(PON_PS_HOLD_RESET_CTL);
249
250 /* enable PS_HOLD_RESET */
251 val |= BIT(S2_RESET_EN_BIT);
252 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
253}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530254
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800255void pm8x41_reset_configure(uint8_t reset_type)
256{
257 /* disable PS_HOLD_RESET */
258 REG_WRITE(PON_PS_HOLD_RESET_CTL2, 0x0);
259
260 /* Delay needed for disable to kick in. */
261 udelay(300);
262
263 /* configure reset type */
264 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
265
266 /* enable PS_HOLD_RESET */
267 REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
268}
269
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530270/*
271 * LDO set voltage, takes ldo name & voltage in UV as input
272 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700273int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530274{
275 uint32_t range = 0;
276 uint32_t step = 0;
277 uint32_t mult = 0;
278 uint32_t val = 0;
279 uint32_t vmin = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530280
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700281 if (!ldo)
282 {
283 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530284 return 1;
285 }
286
287 /* Program Normal power mode */
288 val = 0x0;
289 val = (1 << LDO_NORMAL_PWR_BIT);
290 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
291
292 /*
293 * Select range, step & vmin based on input voltage & type of LDO
294 * LDO can operate in low, mid, high power mode
295 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700296 if (ldo->type == PLDO_TYPE)
297 {
298 if (voltage < PLDO_UV_MIN)
299 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530300 range = 2;
301 step = PLDO_UV_STEP_LOW;
302 vmin = PLDO_UV_VMIN_LOW;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700303 }
304 else if (voltage < PDLO_UV_MID)
305 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530306 range = 3;
307 step = PLDO_UV_STEP_MID;
308 vmin = PLDO_UV_VMIN_MID;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700309 }
310 else
311 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530312 range = 4;
313 step = PLDO_UV_STEP_HIGH;
314 vmin = PLDO_UV_VMIN_HIGH;
315 }
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700316 }
317 else
318 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530319 range = 2;
320 step = NLDO_UV_STEP;
321 vmin = NLDO_UV_VMIN_LOW;
322 }
323
324 mult = (voltage - vmin) / step;
325
326 /* Set Range in voltage ctrl register */
327 val = 0x0;
328 val = range << LDO_RANGE_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700329 REG_WRITE((ldo->base + LDO_RANGE_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530330
331 /* Set multiplier in voltage ctrl register */
332 val = 0x0;
333 val = mult << LDO_VSET_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700334 REG_WRITE((ldo->base + LDO_STEP_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530335
336 return 0;
337}
338
339/*
340 * Enable or Disable LDO
341 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700342int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530343{
344 uint32_t val = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530345
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700346 if (!ldo)
347 {
348 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530349 return 1;
350 }
351
352 /* Enable LDO */
353 if (enable)
354 val = (1 << LDO_VREG_ENABLE_BIT);
355 else
356 val = (0 << LDO_VREG_ENABLE_BIT);
357
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700358 REG_WRITE((ldo->base + LDO_EN_CTL_REG), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530359
360 return 0;
361}
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800362
Kuogee Hsieh0392b672013-10-04 15:50:36 -0700363/*
364 * lpg channel register write:
365 */
366void pm8x41_lpg_write(uint8_t chan, uint8_t off, uint8_t val)
367{
368 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
369
370 REG_WRITE(lpg_base + off, val);
371}
372
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800373uint8_t pm8x41_get_pmic_rev()
374{
375 return REG_READ(REVID_REVISION4);
376}
377
sundarajan srinivasand0f59e82013-02-12 19:17:02 -0800378uint8_t pm8x41_get_pon_reason()
379{
380 return REG_READ(PON_PON_REASON1);
381}
Deepa Dinamanic342f122013-06-12 15:41:31 -0700382
383void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable)
384{
385 ASSERT(mpp);
386
387 REG_WRITE(mpp->base + MPP_EN_CTL, enable << MPP_EN_CTL_ENABLE_SHIFT);
388}
389
390void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp)
391{
392 ASSERT(mpp);
393
394 REG_WRITE(mpp->base + MPP_DIG_VIN_CTL, mpp->vin);
395
396 REG_WRITE(mpp->base + MPP_MODE_CTL, mpp->mode | (MPP_DIGITAL_OUTPUT << MPP_MODE_CTL_MODE_SHIFT));
397}
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700398
399uint8_t pm8x41_get_is_cold_boot()
400{
401 if (REG_READ(PON_WARMBOOT_STATUS1) || REG_READ(PON_WARMBOOT_STATUS2)) {
402 dprintf(INFO,"%s: Warm boot\n", __func__);
403 return 0;
404 }
405 dprintf(INFO,"%s: cold boot\n", __func__);
406 return 1;
407}
Amol Jadic3231ff2013-07-23 14:35:31 -0700408
409/* api to control diff clock */
410void pm8x41_diff_clock_ctrl(uint8_t enable)
411{
412 uint8_t reg;
413
414 reg = REG_READ(DIFF_CLK1_EN_CTL);
415
416 if (enable)
417 {
418 reg |= BIT(DIFF_CLK1_EN_BIT);
419 }
420 else
421 {
422 reg &= ~BIT(DIFF_CLK1_EN_BIT);
423 }
424
425 REG_WRITE(DIFF_CLK1_EN_CTL, reg);
426}
Channagoud Kadabifbfa2a92013-10-28 16:20:51 -0700427
428/* API to check for borken battery */
429int pm8xxx_is_battery_broken()
430{
431 uint8_t trkl_default = 0;
432 uint8_t vbat_det_default = 0;
433 int batt_is_broken = 0;
434
435 /* Store original trickle charging current setting */
436 trkl_default = pm8x41_reg_read(PM8XXX_IBAT_ATC_A);
437 /* Store original VBAT_DET_LO setting */
438 vbat_det_default = pm8x41_reg_read(PM8XXX_VBAT_DET);
439
440 /*Set trickle charge current to 50mA (IBAT_ATC_A = 0x00) */
441 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, 0x00);
442 /* Set VBAT_DET_LO to 4.3V so that VBAT_DET_HI = 4.52V (VBAT_DET_LO = 0x35) */
443 pm8x41_reg_write(PM8XXX_VBAT_DET, VBAT_DET_LO_4_30V);
444 /* Unlock SMBBP Secured Register */
445 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
446 /* Disable VTRKL_FAULT comp (SMBBP_CHGR_COMP_OVR0 = 0x08) */
447 pm8x41_reg_write(PM8XXX_COMP_OVR0, OVR0_DIS_VTRKL_FAULT);
448 /* Disable VCP (SMBB_BAT_IF_VCP = 0x00) */
449 pm8x41_reg_write(PM8XXX_VCP, 0x00);
450 /* Unlock SMBBP Secured Register */
451 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
452 /* Force trickle charging (SMBB_CHGR_TRKL_CHG_TEST = 0x01) */
453 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, CHG_TRICKLE_FORCED_ON);
454 /* Wait for vbat to rise */
455 mdelay(12);
456
457 /* Check Above VBAT_DET_HIGH status */
458 if (pm8x41_reg_read(PM8XXX_VBAT_IN_TSTS) & VBAT_DET_HI_RT_STS)
459 batt_is_broken = 1;
460 else
461 batt_is_broken = 0;
462
463 /* Unlock SMBBP Secured Register */
464 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
465
466 /* Disable force trickle charging */
467 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, 0x00);
468 /* re-enable VCP */
469 pm8x41_reg_write(PM8XXX_VCP, VCP_ENABLE);
470 /* restore trickle charging default current */
471 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, trkl_default);
472 /* restore VBAT_DET_LO setting to original value */
473 pm8x41_reg_write(PM8XXX_VBAT_DET, vbat_det_default);
474
475 return batt_is_broken;
476}
Xiaocheng Li9ddc84a2013-09-14 17:32:00 +0800477
478void pm8x41_clear_pmic_watchdog(void)
479{
480 pm8x41_reg_write(PMIC_WD_RESET_S2_CTL2, 0x0);
481}