blob: 31b13cbc3f6a8a042a252c290662a312949e049b [file] [log] [blame]
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +05301/* Copyright (c) 2012, 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
Deepa Dinamani9a612932012-08-14 16:15:03 -070038/* Local Macros */
39#define REG_READ(_a) pm8x41_reg_read(_a)
40#define REG_WRITE(_a, _v) pm8x41_reg_write(_a, _v)
41
42#define REG_OFFSET(_addr) ((_addr) & 0xFF)
43#define PERIPH_ID(_addr) (((_addr) & 0xFF00) >> 8)
44#define SLAVE_ID(_addr) ((_addr) >> 16)
45
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +053046struct pm8x41_ldo ldo_data[] = {
47 LDO("LDO2", NLDO_TYPE, 0x14100, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
48 LDO("LDO12", PLDO_TYPE, 0x14B00, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
49 LDO("LDO22", PLDO_TYPE, 0x15500, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
50};
Deepa Dinamani9a612932012-08-14 16:15:03 -070051
52/* Local functions */
53static uint8_t pm8x41_reg_read(uint32_t addr)
54{
55 uint8_t val = 0;
56 struct pmic_arb_cmd cmd;
57 struct pmic_arb_param param;
58
59 cmd.address = PERIPH_ID(addr);
60 cmd.offset = REG_OFFSET(addr);
61 cmd.slave_id = SLAVE_ID(addr);
62 cmd.priority = 0;
63
64 param.buffer = &val;
65 param.size = 1;
66
67 pmic_arb_read_cmd(&cmd, &param);
68
69 return val;
70}
71
72static void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -070073{
74 struct pmic_arb_cmd cmd;
75 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -070076
Deepa Dinamani9a612932012-08-14 16:15:03 -070077 cmd.address = PERIPH_ID(addr);
78 cmd.offset = REG_OFFSET(addr);
79 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -070080 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -070081
Deepa Dinamani9a612932012-08-14 16:15:03 -070082 param.buffer = &val;
83 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -070084
Deepa Dinamani9a612932012-08-14 16:15:03 -070085 pmic_arb_write_cmd(&cmd, &param);
86}
Deepa Dinamani22799652012-07-21 12:26:22 -070087
Deepa Dinamani9a612932012-08-14 16:15:03 -070088/* Exported functions */
89
90/* Set the boot done flag */
91void pm8x41_set_boot_done()
92{
93 uint8_t val;
94
95 val = REG_READ(SMBB_MISC_BOOT_DONE);
96 val |= BIT(BOOT_DONE_BIT);
97 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
98}
99
100/* Configure GPIO */
101int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
102{
103 uint8_t val;
104 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
105
Amol Jadi7ec52b42012-08-16 14:12:45 -0700106 /* Only input configuration is implemented at this time. */
107 ASSERT(config->direction == PM_GPIO_DIR_IN);
108
Deepa Dinamani9a612932012-08-14 16:15:03 -0700109 /* Disable the GPIO */
110 val = REG_READ(gpio_base + GPIO_EN_CTL);
111 val &= ~BIT(PERPH_EN_BIT);
112 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
113
114 /* Select the mode */
115 val = config->function | (config->direction << 4);
116 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
117
118 /* Set the right pull */
119 val = config->pull;
120 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
121
122 /* Select the VIN */
123 val = config->vin_sel;
124 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
125
126 /* Enable the GPIO */
127 val = REG_READ(gpio_base + GPIO_EN_CTL);
128 val |= BIT(PERPH_EN_BIT);
129 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
130
131 return 1;
132}
133
134/* Reads the status of requested gpio */
135int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
136{
137 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
138
139 *status = REG_READ(gpio_base + GPIO_STATUS);
140
141 /* Return the value of the GPIO pin */
142 *status &= BIT(GPIO_STATUS_VAL_BIT);
143
144 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
145
146 return 1;
147}
148
149/* Prepare PON RESIN S2 reset */
150void pm8x41_vol_down_key_prepare()
151{
152 uint8_t val;
153
154 /* disable s2 reset */
155 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
156
Amol Jadi7ec52b42012-08-16 14:12:45 -0700157 /* Delay needed for disable to kick in. */
158 udelay(300);
159
Deepa Dinamani9a612932012-08-14 16:15:03 -0700160 /* configure s1 timer to 0 */
161 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
162
163 /* configure s2 timer to 2s */
164 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
165
166 /* configure reset type */
167 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
168
169 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
170
171 /* enable s2 reset */
172 val |= BIT(S2_RESET_EN_BIT);
173 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
174}
175
176/* Volume_Down key detect cleanup */
177void pm8x41_vol_down_key_done()
178{
179 /* disable s2 reset */
180 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700181
182 /* Delay needed for disable to kick in. */
183 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700184}
185
186/* Volume_Down key status */
187int pm8x41_vol_down_key_status()
188{
189 uint8_t rt_sts = 0;
190
191 /* Enable S2 reset so we can detect the volume down key press */
192 pm8x41_vol_down_key_prepare();
193
194 /* Delay before interrupt triggering.
195 * See PON_DEBOUNCE_CTL reg.
196 */
197 mdelay(100);
198
199 rt_sts = REG_READ(PON_INT_RT_STS);
200
201 /* Must disable S2 reset otherwise PMIC will reset if key
202 * is held longer than S2 timer.
203 */
204 pm8x41_vol_down_key_done();
205
206 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700207}
Neeti Desai120b55d2012-08-20 17:15:56 -0700208
209void pm8x41_reset_configure(uint8_t reset_type)
210{
211 uint8_t val;
212
213 /* disable PS_HOLD_RESET */
214 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
215
216 /* Delay needed for disable to kick in. */
217 udelay(300);
218
219 /* configure reset type */
220 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
221
222 val = REG_READ(PON_PS_HOLD_RESET_CTL);
223
224 /* enable PS_HOLD_RESET */
225 val |= BIT(S2_RESET_EN_BIT);
226 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
227}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530228
229static struct pm8x41_ldo *ldo_get(const char *ldo_name)
230{
231 uint8_t i;
232 struct pm8x41_ldo *ldo = NULL;
233
234 for (i = 0; i < ARRAY_SIZE(ldo_data); i++) {
235 ldo = &ldo_data[i];
236 if (!strncmp(ldo->name, ldo_name, strlen(ldo_name)))
237 break;
238 }
239 return ldo;
240}
241
242/*
243 * LDO set voltage, takes ldo name & voltage in UV as input
244 */
245int pm8x41_ldo_set_voltage(const char *name, uint32_t voltage)
246{
247 uint32_t range = 0;
248 uint32_t step = 0;
249 uint32_t mult = 0;
250 uint32_t val = 0;
251 uint32_t vmin = 0;
252 struct pm8x41_ldo *ldo;
253
254 ldo = ldo_get(name);
255 if (!ldo) {
256 dprintf(CRITICAL, "LDO requsted is not supported: %s\n", name);
257 return 1;
258 }
259
260 /* Program Normal power mode */
261 val = 0x0;
262 val = (1 << LDO_NORMAL_PWR_BIT);
263 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
264
265 /*
266 * Select range, step & vmin based on input voltage & type of LDO
267 * LDO can operate in low, mid, high power mode
268 */
269 if (ldo->type == PLDO_TYPE) {
270 if (voltage < PLDO_UV_MIN) {
271 range = 2;
272 step = PLDO_UV_STEP_LOW;
273 vmin = PLDO_UV_VMIN_LOW;
274 } else if (voltage < PDLO_UV_MID) {
275 range = 3;
276 step = PLDO_UV_STEP_MID;
277 vmin = PLDO_UV_VMIN_MID;
278 } else {
279 range = 4;
280 step = PLDO_UV_STEP_HIGH;
281 vmin = PLDO_UV_VMIN_HIGH;
282 }
283 } else {
284 range = 2;
285 step = NLDO_UV_STEP;
286 vmin = NLDO_UV_VMIN_LOW;
287 }
288
289 mult = (voltage - vmin) / step;
290
291 /* Set Range in voltage ctrl register */
292 val = 0x0;
293 val = range << LDO_RANGE_SEL_BIT;
294 REG_WRITE((ldo->base + ldo->range_reg), val);
295
296 /* Set multiplier in voltage ctrl register */
297 val = 0x0;
298 val = mult << LDO_VSET_SEL_BIT;
299 REG_WRITE((ldo->base + ldo->step_reg), val);
300
301 return 0;
302}
303
304/*
305 * Enable or Disable LDO
306 */
307int pm8x41_ldo_control(const char *name, uint8_t enable)
308{
309 uint32_t val = 0;
310 struct pm8x41_ldo *ldo;
311
312 ldo = ldo_get(name);
313 if (!ldo) {
314 dprintf(CRITICAL, "Requested LDO is not supported : %s\n", name);
315 return 1;
316 }
317
318 /* Enable LDO */
319 if (enable)
320 val = (1 << LDO_VREG_ENABLE_BIT);
321 else
322 val = (0 << LDO_VREG_ENABLE_BIT);
323
324 REG_WRITE((ldo->base + ldo->enable_reg), val);
325
326 return 0;
327}