blob: f28dd91d7478d92e4f022797532ae3e2f185f7bb [file] [log] [blame]
Channagoud Kadabid091f702013-01-07 16:17:37 -08001/* Copyright (c) 2012-2013, 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 Kadabi0e60b7d2012-11-01 22:56:08 +053038struct pm8x41_ldo ldo_data[] = {
39 LDO("LDO2", NLDO_TYPE, 0x14100, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
40 LDO("LDO12", PLDO_TYPE, 0x14B00, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
41 LDO("LDO22", PLDO_TYPE, 0x15500, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
42};
Deepa Dinamani9a612932012-08-14 16:15:03 -070043
Channagoud Kadabid091f702013-01-07 16:17:37 -080044/* SPMI helper functions */
45uint8_t pm8x41_reg_read(uint32_t addr)
Deepa Dinamani9a612932012-08-14 16:15:03 -070046{
47 uint8_t val = 0;
48 struct pmic_arb_cmd cmd;
49 struct pmic_arb_param param;
50
51 cmd.address = PERIPH_ID(addr);
52 cmd.offset = REG_OFFSET(addr);
53 cmd.slave_id = SLAVE_ID(addr);
54 cmd.priority = 0;
55
56 param.buffer = &val;
57 param.size = 1;
58
59 pmic_arb_read_cmd(&cmd, &param);
60
61 return val;
62}
63
Channagoud Kadabid091f702013-01-07 16:17:37 -080064void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -070065{
66 struct pmic_arb_cmd cmd;
67 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -070068
Deepa Dinamani9a612932012-08-14 16:15:03 -070069 cmd.address = PERIPH_ID(addr);
70 cmd.offset = REG_OFFSET(addr);
71 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -070072 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -070073
Deepa Dinamani9a612932012-08-14 16:15:03 -070074 param.buffer = &val;
75 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -070076
Deepa Dinamani9a612932012-08-14 16:15:03 -070077 pmic_arb_write_cmd(&cmd, &param);
78}
Deepa Dinamani22799652012-07-21 12:26:22 -070079
Deepa Dinamani9a612932012-08-14 16:15:03 -070080/* Exported functions */
81
82/* Set the boot done flag */
83void pm8x41_set_boot_done()
84{
85 uint8_t val;
86
87 val = REG_READ(SMBB_MISC_BOOT_DONE);
88 val |= BIT(BOOT_DONE_BIT);
89 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
90}
91
92/* Configure GPIO */
93int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
94{
95 uint8_t val;
96 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
97
98 /* Disable the GPIO */
99 val = REG_READ(gpio_base + GPIO_EN_CTL);
100 val &= ~BIT(PERPH_EN_BIT);
101 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
102
103 /* Select the mode */
104 val = config->function | (config->direction << 4);
105 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
106
107 /* Set the right pull */
108 val = config->pull;
109 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
110
111 /* Select the VIN */
112 val = config->vin_sel;
113 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
114
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800115 if (config->direction == PM_GPIO_DIR_OUT) {
116 /* Set the right dig out control */
117 val = config->out_strength | (config->output_buffer << 4);
118 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
119 }
120
Deepa Dinamani9a612932012-08-14 16:15:03 -0700121 /* Enable the GPIO */
122 val = REG_READ(gpio_base + GPIO_EN_CTL);
123 val |= BIT(PERPH_EN_BIT);
124 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
125
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800126 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700127}
128
129/* Reads the status of requested gpio */
130int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
131{
132 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
133
134 *status = REG_READ(gpio_base + GPIO_STATUS);
135
136 /* Return the value of the GPIO pin */
137 *status &= BIT(GPIO_STATUS_VAL_BIT);
138
139 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
140
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800141 return 0;
142}
143
144/* Write the output value of the requested gpio */
145int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
146{
147 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
148 uint8_t val;
149
150 /* Set the output value of the gpio */
151 val = REG_READ(gpio_base + GPIO_MODE_CTL);
152 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
153 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
154
155 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700156}
157
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800158/* Prepare PON RESIN S2 reset (bite) */
159void pm8x41_resin_s2_reset_enable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700160{
161 uint8_t val;
162
163 /* disable s2 reset */
164 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
165
Amol Jadi7ec52b42012-08-16 14:12:45 -0700166 /* Delay needed for disable to kick in. */
167 udelay(300);
168
Deepa Dinamani9a612932012-08-14 16:15:03 -0700169 /* configure s1 timer to 0 */
170 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
171
172 /* configure s2 timer to 2s */
173 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
174
175 /* configure reset type */
176 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
177
178 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
179
180 /* enable s2 reset */
181 val |= BIT(S2_RESET_EN_BIT);
182 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
183}
184
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800185/* Disable PON RESIN S2 reset. (bite)*/
186void pm8x41_resin_s2_reset_disable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700187{
188 /* disable s2 reset */
189 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700190
191 /* Delay needed for disable to kick in. */
192 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700193}
194
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800195/* Resin irq status for faulty pmic*/
196uint32_t pm8x41_resin_bark_workaround_status()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700197{
198 uint8_t rt_sts = 0;
199
200 /* Enable S2 reset so we can detect the volume down key press */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800201 pm8x41_resin_s2_reset_enable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700202
203 /* Delay before interrupt triggering.
204 * See PON_DEBOUNCE_CTL reg.
205 */
206 mdelay(100);
207
208 rt_sts = REG_READ(PON_INT_RT_STS);
209
210 /* Must disable S2 reset otherwise PMIC will reset if key
211 * is held longer than S2 timer.
212 */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800213 pm8x41_resin_s2_reset_disable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700214
215 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700216}
Neeti Desai120b55d2012-08-20 17:15:56 -0700217
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800218/* Resin pin status */
219uint32_t pm8x41_resin_status()
220{
221 uint8_t rt_sts = 0;
222
223 rt_sts = REG_READ(PON_INT_RT_STS);
224
225 return (rt_sts & BIT(RESIN_ON_INT_BIT));
226}
227
Neeti Desai120b55d2012-08-20 17:15:56 -0700228void pm8x41_reset_configure(uint8_t reset_type)
229{
230 uint8_t val;
231
232 /* disable PS_HOLD_RESET */
233 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
234
235 /* Delay needed for disable to kick in. */
236 udelay(300);
237
238 /* configure reset type */
239 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
240
241 val = REG_READ(PON_PS_HOLD_RESET_CTL);
242
243 /* enable PS_HOLD_RESET */
244 val |= BIT(S2_RESET_EN_BIT);
245 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
246}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530247
248static struct pm8x41_ldo *ldo_get(const char *ldo_name)
249{
250 uint8_t i;
251 struct pm8x41_ldo *ldo = NULL;
252
253 for (i = 0; i < ARRAY_SIZE(ldo_data); i++) {
254 ldo = &ldo_data[i];
255 if (!strncmp(ldo->name, ldo_name, strlen(ldo_name)))
256 break;
257 }
258 return ldo;
259}
260
261/*
262 * LDO set voltage, takes ldo name & voltage in UV as input
263 */
264int pm8x41_ldo_set_voltage(const char *name, uint32_t voltage)
265{
266 uint32_t range = 0;
267 uint32_t step = 0;
268 uint32_t mult = 0;
269 uint32_t val = 0;
270 uint32_t vmin = 0;
271 struct pm8x41_ldo *ldo;
272
273 ldo = ldo_get(name);
274 if (!ldo) {
275 dprintf(CRITICAL, "LDO requsted is not supported: %s\n", name);
276 return 1;
277 }
278
279 /* Program Normal power mode */
280 val = 0x0;
281 val = (1 << LDO_NORMAL_PWR_BIT);
282 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
283
284 /*
285 * Select range, step & vmin based on input voltage & type of LDO
286 * LDO can operate in low, mid, high power mode
287 */
288 if (ldo->type == PLDO_TYPE) {
289 if (voltage < PLDO_UV_MIN) {
290 range = 2;
291 step = PLDO_UV_STEP_LOW;
292 vmin = PLDO_UV_VMIN_LOW;
293 } else if (voltage < PDLO_UV_MID) {
294 range = 3;
295 step = PLDO_UV_STEP_MID;
296 vmin = PLDO_UV_VMIN_MID;
297 } else {
298 range = 4;
299 step = PLDO_UV_STEP_HIGH;
300 vmin = PLDO_UV_VMIN_HIGH;
301 }
302 } else {
303 range = 2;
304 step = NLDO_UV_STEP;
305 vmin = NLDO_UV_VMIN_LOW;
306 }
307
308 mult = (voltage - vmin) / step;
309
310 /* Set Range in voltage ctrl register */
311 val = 0x0;
312 val = range << LDO_RANGE_SEL_BIT;
313 REG_WRITE((ldo->base + ldo->range_reg), val);
314
315 /* Set multiplier in voltage ctrl register */
316 val = 0x0;
317 val = mult << LDO_VSET_SEL_BIT;
318 REG_WRITE((ldo->base + ldo->step_reg), val);
319
320 return 0;
321}
322
323/*
324 * Enable or Disable LDO
325 */
326int pm8x41_ldo_control(const char *name, uint8_t enable)
327{
328 uint32_t val = 0;
329 struct pm8x41_ldo *ldo;
330
331 ldo = ldo_get(name);
332 if (!ldo) {
333 dprintf(CRITICAL, "Requested LDO is not supported : %s\n", name);
334 return 1;
335 }
336
337 /* Enable LDO */
338 if (enable)
339 val = (1 << LDO_VREG_ENABLE_BIT);
340 else
341 val = (0 << LDO_VREG_ENABLE_BIT);
342
343 REG_WRITE((ldo->base + ldo->enable_reg), val);
344
345 return 0;
346}