blob: 5684082116cc9071b8618a86f6435bc997f5fe54 [file] [log] [blame]
Maheshkumar Sivasubramanian4ac23762011-11-02 10:03:06 -06001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/io.h>
19#include <linux/slab.h>
20#include <mach/msm_iomap.h>
21
22#include "spm_driver.h"
23
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -060024#define MSM_SPM_PMIC_STATE_IDLE 0
25
26#define SAW2_V1_VER_REG 0x04
27#define SAW2_V2_VER_REG 0xfd0
28
29#define SAW2_MAJOR_2 2
30
31
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032enum {
33 MSM_SPM_DEBUG_SHADOW = 1U << 0,
34 MSM_SPM_DEBUG_VCTL = 1U << 1,
35};
36
37static int msm_spm_debug_mask;
38module_param_named(
39 debug_mask, msm_spm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
40);
41
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -060043static uint32_t msm_spm_reg_offsets_v1[MSM_SPM_REG_NR] = {
44 [MSM_SPM_REG_SAW2_SECURE] = 0x00,
45 [MSM_SPM_REG_SAW2_ID] = 0x04,
46 [MSM_SPM_REG_SAW2_CFG] = 0x08,
47 [MSM_SPM_REG_SAW2_STS0] = 0x0C,
48 [MSM_SPM_REG_SAW2_STS1] = 0x10,
49 [MSM_SPM_REG_SAW2_VCTL] = 0x14,
50 [MSM_SPM_REG_SAW2_AVS_CTL] = 0x18,
51 [MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x1C,
52 [MSM_SPM_REG_SAW2_SPM_CTL] = 0x20,
53 [MSM_SPM_REG_SAW2_PMIC_DLY] = 0x24,
54 [MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x28,
55 [MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x2C,
56 [MSM_SPM_REG_SAW2_RST] = 0x30,
57 [MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
58};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -060060static uint32_t msm_spm_reg_offsets_v2[MSM_SPM_REG_NR] = {
61 [MSM_SPM_REG_SAW2_SECURE] = 0x00,
62 [MSM_SPM_REG_SAW2_ID] = 0x04,
63 [MSM_SPM_REG_SAW2_CFG] = 0x08,
64 [MSM_SPM_REG_SAW2_SPM_STS] = 0x0C,
65 [MSM_SPM_REG_SAW2_AVS_STS] = 0x10,
66 [MSM_SPM_REG_SAW2_PMIC_STS] = 0x14,
67 [MSM_SPM_REG_SAW2_RST] = 0x18,
68 [MSM_SPM_REG_SAW2_VCTL] = 0x1C,
69 [MSM_SPM_REG_SAW2_AVS_CTL] = 0x20,
70 [MSM_SPM_REG_SAW2_AVS_LIMIT] = 0x24,
71 [MSM_SPM_REG_SAW2_AVS_DLY] = 0x28,
72 [MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x2C,
73 [MSM_SPM_REG_SAW2_SPM_CTL] = 0x30,
74 [MSM_SPM_REG_SAW2_SPM_DLY] = 0x34,
75 [MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x40,
76 [MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x44,
77 [MSM_SPM_REG_SAW2_PMIC_DATA_2] = 0x48,
78 [MSM_SPM_REG_SAW2_PMIC_DATA_3] = 0x4C,
79 [MSM_SPM_REG_SAW2_PMIC_DATA_4] = 0x50,
80 [MSM_SPM_REG_SAW2_PMIC_DATA_5] = 0x54,
81 [MSM_SPM_REG_SAW2_PMIC_DATA_6] = 0x58,
82 [MSM_SPM_REG_SAW2_PMIC_DATA_7] = 0x5C,
83 [MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
84 [MSM_SPM_REG_SAW2_VERSION] = 0xFD0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085};
86
87/******************************************************************************
88 * Internal helper functions
89 *****************************************************************************/
90
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -060091static inline uint32_t msm_spm_drv_get_num_spm_entry(
92 struct msm_spm_driver_data *dev)
93{
94 return 32;
95}
96
97static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
98 unsigned int reg_index)
99{
100 __raw_writel(dev->reg_shadow[reg_index],
101 dev->reg_base_addr + dev->reg_offsets[reg_index]);
102}
103
104static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
105 unsigned int reg_index)
106{
107 dev->reg_shadow[reg_index] =
108 __raw_readl(dev->reg_base_addr +
109 dev->reg_offsets[reg_index]);
110}
111
112static inline void msm_spm_drv_set_start_addr(
113 struct msm_spm_driver_data *dev, uint32_t addr)
114{
115 addr &= 0x7F;
116 addr <<= 4;
117 dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
118 dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
119}
120
121static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
122{
123 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_ID);
124
125 if (dev->major == SAW2_MAJOR_2)
126 return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 2) & 0x1;
127 else
128 return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 18) & 0x1;
129}
130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131static inline void msm_spm_drv_set_vctl(struct msm_spm_driver_data *dev,
132 uint32_t vlevel)
133{
134 dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0xFF;
135 dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= vlevel;
136
137 dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0xFF;
138 dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= vlevel;
Praveen Chidambaramf3f2b3e2012-03-21 20:13:38 -0600139
140 dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F;
141 dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
Girish Mahadevan63b87262012-08-15 09:21:23 -0600142
143 dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F0000;
144 dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |=
145 ((vlevel & 0x3F) << 16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146}
147
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600148static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
149 uint32_t vlevel)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150{
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600151 unsigned int pmic_data = 0;
152
153 pmic_data |= vlevel;
154 pmic_data |= (dev->vctl_port & 0x7) << 16;
155
156 dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
157 dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158}
159
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600160static inline void msm_spm_drv_apcs_set_vctl(struct msm_spm_driver_data *dev,
161 unsigned int vlevel)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162{
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600163 if (dev->major == SAW2_MAJOR_2)
164 return msm_spm_drv_set_vctl2(dev, vlevel);
165 else
166 return msm_spm_drv_set_vctl(dev, vlevel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167}
168
169static inline uint32_t msm_spm_drv_get_sts_pmic_state(
170 struct msm_spm_driver_data *dev)
171{
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600172 if (dev->major == SAW2_MAJOR_2) {
173 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
174 return (dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] >> 16) &
175 0x03;
176 } else {
177 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
178 return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
179 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180}
181
Praveen Chidambaramebbf2122012-09-29 22:27:03 -0600182uint32_t msm_spm_drv_get_sts_curr_pmic_data(
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183 struct msm_spm_driver_data *dev)
184{
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600185 if (dev->major == SAW2_MAJOR_2) {
186 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
187 return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] & 0xFF;
188 } else {
189 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
190 return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
191 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192}
193
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600194static inline uint32_t msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
195 uint32_t *major, uint32_t *minor)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196{
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600197 int ret = -ENODEV;
198 uint32_t val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600200 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_VERSION);
201 val = dev->reg_shadow[MSM_SPM_REG_SAW2_VERSION];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600203 if (dev->ver_reg == SAW2_V2_VER_REG) {
204 *major = (val >> 28) & 0xF;
205 *minor = (val >> 16) & 0xFFF;
206 ret = 0;
207 } else if (dev->ver_reg == SAW2_V1_VER_REG) {
208 *major = (val >> 4) & 0xF;
209 *minor = val & 0xF;
210 ret = 0;
211 }
212
213 return ret;
214}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215
216/******************************************************************************
217 * Public functions
218 *****************************************************************************/
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220inline int msm_spm_drv_set_spm_enable(
221 struct msm_spm_driver_data *dev, bool enable)
222{
223 uint32_t value = enable ? 0x01 : 0x00;
224
225 if (!dev)
226 return -EINVAL;
227
228 if ((dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] & 0x01) ^ value) {
229
230 dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= ~0x1;
231 dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= value;
232
233 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
234 wmb();
235 }
236 return 0;
237}
238void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev)
239{
240 int i;
241 int num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
242
243 if (!dev) {
244 __WARN();
245 return;
246 }
247
248 for (i = 0; i < num_spm_entry; i++) {
249 __raw_writel(dev->reg_seq_entry_shadow[i],
250 dev->reg_base_addr
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600251 + dev->reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 + 4 * i);
253 }
254 mb();
255}
256
257int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600258 uint8_t *cmd, uint32_t *offset)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259{
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600260 uint32_t cmd_w;
261 uint32_t offset_w = *offset / 4;
262 uint8_t last_cmd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600264 if (!cmd)
265 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266
267 while (1) {
268 int i;
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600269 cmd_w = 0;
270 last_cmd = 0;
271 cmd_w = dev->reg_seq_entry_shadow[offset_w];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600273 for (i = (*offset % 4) ; i < 4; i++) {
274 last_cmd = *(cmd++);
275 cmd_w |= last_cmd << (i * 8);
276 (*offset)++;
277 if (last_cmd == 0x0f)
278 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 }
280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
282 if (last_cmd == 0x0f)
283 break;
284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600286 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287}
288
289int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
290 uint32_t addr)
291{
292
293 /* SPM is configured to reset start address to zero after end of Program
294 */
295 if (!dev)
296 return -EINVAL;
297
298 msm_spm_drv_set_start_addr(dev, addr);
299
Maheshkumar Sivasubramaniandaa23bb2011-07-01 17:24:51 -0600300 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
301 wmb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302
303 if (msm_spm_debug_mask & MSM_SPM_DEBUG_SHADOW) {
304 int i;
305 for (i = 0; i < MSM_SPM_REG_NR; i++)
306 pr_info("%s: reg %02x = 0x%08x\n", __func__,
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600307 dev->reg_offsets[i], dev->reg_shadow[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 }
309
310 return 0;
311}
312
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600313#ifdef CONFIG_MSM_AVS_HW
Anji Jonnaladfede052013-01-16 22:33:54 +0530314static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
315{
316 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
317 if (dev->major == SAW2_MAJOR_2)
318 return dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] & BIT(0);
319 else
320 return dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] & BIT(27);
321}
322
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600323static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev)
324{
325 msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
326 dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~BIT(27);
327 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
328}
329
330static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev)
331{
332 dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= BIT(27);
333 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
334}
335
336static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
337 unsigned int vlevel)
338{
339 vlevel &= 0x3f;
340 dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~0x7efc00;
341 dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= ((vlevel - 4) << 10);
342 dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= (vlevel << 17);
343 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
344}
345
346#else
Anji Jonnaladfede052013-01-16 22:33:54 +0530347static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
348{
349 return false;
350}
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600351
352static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev) { }
353
354static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev) { }
355
356static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
357 unsigned int vlevel) { }
358#endif
359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
361{
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600362 uint32_t timeout_us, new_level;
Anji Jonnaladfede052013-01-16 22:33:54 +0530363 bool avs_enabled = msm_spm_drv_is_avs_enabled(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364
365 if (!dev)
366 return -EINVAL;
367
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600368 if (!msm_spm_pmic_arb_present(dev))
369 return -ENOSYS;
370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600372 pr_info("%s: requesting vlevel %#x\n", __func__, vlevel);
373
Anji Jonnaladfede052013-01-16 22:33:54 +0530374 if (avs_enabled)
375 msm_spm_drv_disable_avs(dev);
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600376
377 /* Kick the state machine back to idle */
378 dev->reg_shadow[MSM_SPM_REG_SAW2_RST] = 1;
379 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_RST);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600381 msm_spm_drv_apcs_set_vctl(dev, vlevel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
383 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
Praveen Chidambaramf3f2b3e2012-03-21 20:13:38 -0600384 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 timeout_us = dev->vctl_timeout_us;
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600387 /* Confirm the voltage we set was what hardware sent */
388 do {
389 new_level = msm_spm_drv_get_sts_curr_pmic_data(dev);
390 if (new_level == vlevel)
391 break;
392 udelay(1);
393 } while (--timeout_us);
394 if (!timeout_us) {
395 pr_info("Wrong level %#x\n", new_level);
396 goto set_vdd_bail;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 }
398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
400 pr_info("%s: done, remaining timeout %uus\n",
401 __func__, timeout_us);
402
Anji Jonnaladfede052013-01-16 22:33:54 +0530403 /* Set AVS min/max */
404 if (avs_enabled) {
405 msm_spm_drv_set_avs_vlevel(dev, vlevel);
406 msm_spm_drv_enable_avs(dev);
407 }
408
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 return 0;
410
411set_vdd_bail:
Anji Jonnaladfede052013-01-16 22:33:54 +0530412 if (avs_enabled)
413 msm_spm_drv_enable_avs(dev);
414
Praveen Chidambaramd3c5eaf2012-03-16 12:08:42 -0600415 pr_err("%s: failed %#x, remaining timeout %uus, vlevel %#x\n",
416 __func__, vlevel, timeout_us, new_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 return -EIO;
418}
419
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600420int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
421 unsigned int phase_cnt)
422{
423 unsigned int pmic_data = 0;
424 unsigned int timeout_us = 0;
425
426 if (dev->major != SAW2_MAJOR_2)
427 return -ENODEV;
428
429 pmic_data |= phase_cnt & 0xFF;
430 pmic_data |= (dev->phase_port & 0x7) << 16;
431
432 dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
433 dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
434 msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
435 mb();
436
437 /* Wait for PMIC state to return to idle or until timeout */
438 timeout_us = dev->vctl_timeout_us;
439 while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
440 if (!timeout_us)
441 goto set_phase_bail;
442
443 if (timeout_us > 10) {
444 udelay(10);
445 timeout_us -= 10;
446 } else {
447 udelay(timeout_us);
448 timeout_us = 0;
449 }
450 }
451
452 if (msm_spm_drv_get_sts_curr_pmic_data(dev) != phase_cnt)
453 goto set_phase_bail;
454
455 if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
456 pr_info("%s: done, remaining timeout %uus\n",
457 __func__, timeout_us);
458
459 return 0;
460
461set_phase_bail:
462 pr_err("%s: failed, remaining timeout %uus, phase count %d\n",
463 __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
464 return -EIO;
465
466}
467
Maheshkumar Sivasubramanian4ac23762011-11-02 10:03:06 -0600468void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
469{
470 int i;
471
472 for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
473 msm_spm_drv_flush_shadow(dev, i);
474
475 msm_spm_drv_flush_seq_entry(dev);
476 mb();
477}
478
Stephen Boyddb354112012-05-09 14:24:58 -0700479int __devinit msm_spm_drv_init(struct msm_spm_driver_data *dev,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 struct msm_spm_platform_data *data)
481{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 int i;
483 int num_spm_entry;
484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 BUG_ON(!dev || !data);
486
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600487 if (dev->ver_reg == SAW2_V2_VER_REG)
488 dev->reg_offsets = msm_spm_reg_offsets_v2;
489 else
490 dev->reg_offsets = msm_spm_reg_offsets_v1;
491
492 dev->vctl_port = data->vctl_port;
493 dev->phase_port = data->phase_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 dev->reg_base_addr = data->reg_base_addr;
495 memcpy(dev->reg_shadow, data->reg_init_values,
496 sizeof(data->reg_init_values));
497
498 dev->vctl_timeout_us = data->vctl_timeout_us;
499
500 for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
501 msm_spm_drv_flush_shadow(dev, i);
502 /* barrier to ensure write completes before we update shadow
503 * registers
504 */
505 mb();
506
507 for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
508 msm_spm_drv_load_shadow(dev, i);
509
510 /* barrier to ensure read completes before we proceed further*/
511 mb();
512
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600513 msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
516
517 dev->reg_seq_entry_shadow =
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600518 kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519 GFP_KERNEL);
520
521 if (!dev->reg_seq_entry_shadow)
522 return -ENOMEM;
523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700524 return 0;
525}