blob: 6df7626ab8e8dc0da07555966b030b87494ea224 [file] [log] [blame]
Santosh Sajjan374d6592012-01-19 23:16:46 +05301/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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#include <linux/delay.h>
13#include <linux/device.h>
14#include <linux/err.h>
15#include <linux/gpio.h>
16#include <linux/platform_device.h>
17#include <linux/regulator/consumer.h>
18#include <asm/mach-types.h>
19#include <mach/rpc_pmapp.h>
20#include "board-msm7627a.h"
21#include "devices-msm7x2xa.h"
22#include "timer.h"
23
24#define GPIO_WLAN_3V3_EN 119
25static const char *id = "WLAN";
26
27enum {
28 WLAN_VREG_S3 = 0,
29 WLAN_VREG_L17,
30 WLAN_VREG_L19
31};
32
33struct wlan_vreg_info {
34 const char *vreg_id;
35 unsigned int level_min;
36 unsigned int level_max;
37 unsigned int pmapp_id;
38 unsigned int is_vreg_pin_controlled;
39 struct regulator *reg;
40};
41
42static struct wlan_vreg_info vreg_info[] = {
43 {"msme1", 1800000, 1800000, 2, 0, NULL},
44 {"bt", 3300000, 3300000, 21, 1, NULL},
45 {"wlan4", 1800000, 1800000, 23, 1, NULL}
46};
47
48int gpio_wlan_sys_rest_en = 134;
49static void gpio_wlan_config(void)
50{
51 if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb())
52 gpio_wlan_sys_rest_en = 124;
53}
54
55static unsigned int qrf6285_init_regs(void)
56{
57 struct regulator_bulk_data regs[ARRAY_SIZE(vreg_info)];
58 int i = 0, rc = 0;
59
60 for (i = 0; i < ARRAY_SIZE(regs); i++) {
61 regs[i].supply = vreg_info[i].vreg_id;
62 regs[i].min_uV = vreg_info[i].level_min;
63 regs[i].max_uV = vreg_info[i].level_max;
64 }
65
66 rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
67 if (rc) {
68 pr_err("%s: could not get regulators: %d\n", __func__, rc);
69 goto out;
70 }
71
72 for (i = 0; i < ARRAY_SIZE(regs); i++)
73 vreg_info[i].reg = regs[i].consumer;
74
75out:
76 return rc;
77}
78
79static unsigned int setup_wlan_gpio(bool on)
80{
81 int rc = 0;
82
83 if (on) {
84 rc = gpio_direction_output(gpio_wlan_sys_rest_en, 1);
85 msleep(100);
86 } else {
87 gpio_set_value_cansleep(gpio_wlan_sys_rest_en, 0);
88 rc = gpio_direction_input(gpio_wlan_sys_rest_en);
89 msleep(100);
90 }
91
92 if (rc)
93 pr_err("%s: WLAN sys_reset_en GPIO: Error", __func__);
94
95 return rc;
96}
97
98static unsigned int setup_wlan_clock(bool on)
99{
100 int rc = 0;
101
102 if (on) {
103 /* Vote for A0 clock */
104 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
105 PMAPP_CLOCK_VOTE_ON);
106 } else {
107 /* Vote against A0 clock */
108 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
109 PMAPP_CLOCK_VOTE_OFF);
110 }
111
112 if (rc)
113 pr_err("%s: Configuring A0 clock for WLAN: Error", __func__);
114
115 return rc;
116}
117
118static unsigned int wlan_switch_regulators(int on)
119{
120 int rc = 0, index = 0;
121
122 if (machine_is_msm7627a_qrd1())
123 index = 2;
124
125 for ( ; index < ARRAY_SIZE(vreg_info); index++) {
126 if (on) {
127 rc = regulator_set_voltage(vreg_info[index].reg,
128 vreg_info[index].level_min,
129 vreg_info[index].level_max);
130 if (rc) {
131 pr_err("%s:%s set voltage failed %d\n",
132 __func__, vreg_info[index].vreg_id, rc);
133 goto reg_disable;
134 }
135
136 rc = regulator_enable(vreg_info[index].reg);
137 if (rc) {
138 pr_err("%s:%s vreg enable failed %d\n",
139 __func__, vreg_info[index].vreg_id, rc);
140 goto reg_disable;
141 }
142
143 if (vreg_info[index].is_vreg_pin_controlled) {
144 rc = pmapp_vreg_lpm_pincntrl_vote(id,
145 vreg_info[index].pmapp_id,
146 PMAPP_CLOCK_ID_A0, 1);
147 if (rc) {
148 pr_err("%s:%s pincntrl failed %d\n",
149 __func__,
150 vreg_info[index].vreg_id, rc);
151 goto pin_cnt_fail;
152 }
153 }
154 } else {
155 if (vreg_info[index].is_vreg_pin_controlled) {
156 rc = pmapp_vreg_lpm_pincntrl_vote(id,
157 vreg_info[index].pmapp_id,
158 PMAPP_CLOCK_ID_A0, 0);
159 if (rc) {
160 pr_err("%s:%s pincntrl failed %d\n",
161 __func__,
162 vreg_info[index].vreg_id, rc);
163 goto pin_cnt_fail;
164 }
165 }
166
167 rc = regulator_disable(vreg_info[index].reg);
168 if (rc) {
169 pr_err("%s:%s vreg disable failed %d\n",
170 __func__,
171 vreg_info[index].vreg_id, rc);
172 goto reg_disable;
173 }
174 }
175 }
176 return 0;
177pin_cnt_fail:
178 if (on)
179 regulator_disable(vreg_info[index].reg);
180reg_disable:
181 if (!machine_is_msm7627a_qrd1()) {
182 while (index) {
183 if (on) {
184 index--;
185 regulator_disable(vreg_info[index].reg);
186 regulator_put(vreg_info[index].reg);
187 }
188 }
189 }
190 return rc;
191}
192
193static unsigned int msm_AR600X_setup_power(bool on)
194{
195 int rc = 0;
196 static bool init_done;
197
198 if (unlikely(!init_done)) {
199 gpio_wlan_config();
200 rc = qrf6285_init_regs();
201 if (rc) {
202 pr_err("%s: qrf6285 init failed = %d\n", __func__, rc);
203 return rc;
204 } else {
205 init_done = true;
206 }
207 }
208
209 rc = wlan_switch_regulators(on);
210 if (rc) {
211 pr_err("%s: wlan_switch_regulators error = %d\n", __func__, rc);
212 goto out;
213 }
214
215 /* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
216 if (machine_is_msm7627a_qrd1()) {
217 rc = gpio_tlmm_config(GPIO_CFG(GPIO_WLAN_3V3_EN, 0,
218 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
219 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
220 if (rc) {
221 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
222 __func__, rc);
223 goto reg_disable;
224 }
225 gpio_set_value(GPIO_WLAN_3V3_EN, 1);
226 }
227
228 /*
229 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
230 * EVB1.0 and QRD8625,so the below step is required for those devices.
231 */
232 if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()) {
233 rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
234 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
235 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
236 if (rc) {
237 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
238 __func__, rc);
239 goto qrd_gpio_fail;
240 }
241 gpio_set_value(gpio_wlan_sys_rest_en, 1);
242 } else {
243 rc = gpio_request(gpio_wlan_sys_rest_en, "WLAN_DEEP_SLEEP_N");
244 if (rc) {
245 pr_err("%s: WLAN sys_rest_en GPIO %d request failed %d\n",
246 __func__,
247 gpio_wlan_sys_rest_en, rc);
248 goto qrd_gpio_fail;
249 }
250 rc = setup_wlan_gpio(on);
251 if (rc) {
252 pr_err("%s: wlan_set_gpio = %d\n", __func__, rc);
253 goto gpio_fail;
254 }
255 }
256
257 /* Enable the A0 clock */
258 rc = setup_wlan_clock(on);
259 if (rc) {
260 pr_err("%s: setup_wlan_clock = %d\n", __func__, rc);
261 goto set_gpio_fail;
262 }
263
264 /* Configure A0 clock to be slave to WLAN_CLK_PWR_REQ */
265 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
266 PMAPP_CLOCK_VOTE_PIN_CTRL);
267 if (rc) {
268 pr_err("%s: Configuring A0 to Pin controllable failed %d\n",
269 __func__, rc);
270 goto set_clock_fail;
271 }
272
273 pr_info("WLAN power-up success\n");
274 return 0;
275set_clock_fail:
276 setup_wlan_clock(0);
277set_gpio_fail:
278 setup_wlan_gpio(0);
279gpio_fail:
280 gpio_free(gpio_wlan_sys_rest_en);
281qrd_gpio_fail:
282 gpio_free(GPIO_WLAN_3V3_EN);
283reg_disable:
284 wlan_switch_regulators(0);
285out:
286 pr_info("WLAN power-up failed\n");
287 return rc;
288}
289
290static unsigned int msm_AR600X_shutdown_power(bool on)
291{
292 int rc = 0;
293
294 /* Disable the A0 clock */
295 rc = setup_wlan_clock(on);
296 if (rc) {
297 pr_err("%s: setup_wlan_clock = %d\n", __func__, rc);
298 goto set_clock_fail;
299 }
300
301 /*
302 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
303 * EVB1.0 and QRD8625,so the below step is required for those devices.
304 */
305 if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()) {
306 rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
307 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
308 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
309 if (rc) {
310 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
311 __func__, rc);
312 goto gpio_fail;
313 }
314 gpio_set_value(gpio_wlan_sys_rest_en, 0);
315 } else {
316 rc = setup_wlan_gpio(on);
317 if (rc) {
318 pr_err("%s: wlan_set_gpio = %d\n", __func__, rc);
319 goto set_gpio_fail;
320 }
321 gpio_free(gpio_wlan_sys_rest_en);
322 }
323
324 /* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
325 if (machine_is_msm7627a_qrd1()) {
326 rc = gpio_tlmm_config(GPIO_CFG(GPIO_WLAN_3V3_EN, 0,
327 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
328 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
329 if (rc) {
330 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
331 __func__, rc);
332 goto qrd_gpio_fail;
333 }
334 gpio_set_value(GPIO_WLAN_3V3_EN, 0);
335 }
336
337 rc = wlan_switch_regulators(on);
338 if (rc) {
339 pr_err("%s: wlan_switch_regulators error = %d\n",
340 __func__, rc);
341 goto reg_disable;
342 }
343
344 pr_info("WLAN power-down success\n");
345 return 0;
346set_clock_fail:
347 setup_wlan_clock(0);
348set_gpio_fail:
349 setup_wlan_gpio(0);
350gpio_fail:
351 gpio_free(gpio_wlan_sys_rest_en);
352qrd_gpio_fail:
353 gpio_free(GPIO_WLAN_3V3_EN);
354reg_disable:
355 wlan_switch_regulators(0);
356 pr_info("WLAN power-down failed\n");
357 return rc;
358}
359
360int ar600x_wlan_power(bool on)
361{
362 if (on)
363 msm_AR600X_setup_power(on);
364 else
365 msm_AR600X_shutdown_power(on);
366
367 return 0;
368}