blob: a84b43b1027d56137da1d7467c20eda48ea8024a [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Santosh Sajjan374d6592012-01-19 23:16:46 +05302 *
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";
Antony Thomas20c171d2012-10-05 15:52:04 +053026static bool wlan_powered_up;
Santosh Sajjan374d6592012-01-19 23:16:46 +053027
28enum {
29 WLAN_VREG_S3 = 0,
30 WLAN_VREG_L17,
31 WLAN_VREG_L19
32};
33
34struct wlan_vreg_info {
35 const char *vreg_id;
36 unsigned int level_min;
37 unsigned int level_max;
38 unsigned int pmapp_id;
39 unsigned int is_vreg_pin_controlled;
40 struct regulator *reg;
41};
42
43static struct wlan_vreg_info vreg_info[] = {
44 {"msme1", 1800000, 1800000, 2, 0, NULL},
45 {"bt", 3300000, 3300000, 21, 1, NULL},
46 {"wlan4", 1800000, 1800000, 23, 1, NULL}
47};
48
49int gpio_wlan_sys_rest_en = 134;
50static void gpio_wlan_config(void)
51{
Chintan Pandyaf4ad4002012-02-28 19:49:03 +053052 if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
Aparna Mallavarapu093e7fd2012-04-05 13:08:50 +053053 || machine_is_msm8625_evb()
Aparna Mallavarapu5a326242012-05-09 19:49:02 +053054 || machine_is_msm8625_evt()
Aparna Mallavarapu093e7fd2012-04-05 13:08:50 +053055 || machine_is_msm7627a_qrd3()
Channagoud Kadabi2bd65c82012-10-12 15:14:23 +053056 || machine_is_msm8625_qrd7()
57 || machine_is_qrd_skud_prime())
Santosh Sajjan374d6592012-01-19 23:16:46 +053058 gpio_wlan_sys_rest_en = 124;
59}
60
61static unsigned int qrf6285_init_regs(void)
62{
63 struct regulator_bulk_data regs[ARRAY_SIZE(vreg_info)];
64 int i = 0, rc = 0;
65
66 for (i = 0; i < ARRAY_SIZE(regs); i++) {
67 regs[i].supply = vreg_info[i].vreg_id;
68 regs[i].min_uV = vreg_info[i].level_min;
69 regs[i].max_uV = vreg_info[i].level_max;
70 }
71
72 rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
73 if (rc) {
74 pr_err("%s: could not get regulators: %d\n", __func__, rc);
75 goto out;
76 }
77
78 for (i = 0; i < ARRAY_SIZE(regs); i++)
79 vreg_info[i].reg = regs[i].consumer;
80
81out:
82 return rc;
83}
84
85static unsigned int setup_wlan_gpio(bool on)
86{
87 int rc = 0;
88
89 if (on) {
90 rc = gpio_direction_output(gpio_wlan_sys_rest_en, 1);
91 msleep(100);
92 } else {
93 gpio_set_value_cansleep(gpio_wlan_sys_rest_en, 0);
94 rc = gpio_direction_input(gpio_wlan_sys_rest_en);
95 msleep(100);
96 }
97
98 if (rc)
99 pr_err("%s: WLAN sys_reset_en GPIO: Error", __func__);
100
101 return rc;
102}
103
104static unsigned int setup_wlan_clock(bool on)
105{
106 int rc = 0;
107
108 if (on) {
109 /* Vote for A0 clock */
110 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
111 PMAPP_CLOCK_VOTE_ON);
112 } else {
113 /* Vote against A0 clock */
114 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
115 PMAPP_CLOCK_VOTE_OFF);
116 }
117
118 if (rc)
119 pr_err("%s: Configuring A0 clock for WLAN: Error", __func__);
120
121 return rc;
122}
123
124static unsigned int wlan_switch_regulators(int on)
125{
126 int rc = 0, index = 0;
127
128 if (machine_is_msm7627a_qrd1())
129 index = 2;
130
131 for ( ; index < ARRAY_SIZE(vreg_info); index++) {
132 if (on) {
133 rc = regulator_set_voltage(vreg_info[index].reg,
134 vreg_info[index].level_min,
135 vreg_info[index].level_max);
136 if (rc) {
137 pr_err("%s:%s set voltage failed %d\n",
138 __func__, vreg_info[index].vreg_id, rc);
139 goto reg_disable;
140 }
141
142 rc = regulator_enable(vreg_info[index].reg);
143 if (rc) {
144 pr_err("%s:%s vreg enable failed %d\n",
145 __func__, vreg_info[index].vreg_id, rc);
146 goto reg_disable;
147 }
148
149 if (vreg_info[index].is_vreg_pin_controlled) {
150 rc = pmapp_vreg_lpm_pincntrl_vote(id,
151 vreg_info[index].pmapp_id,
152 PMAPP_CLOCK_ID_A0, 1);
153 if (rc) {
154 pr_err("%s:%s pincntrl failed %d\n",
155 __func__,
156 vreg_info[index].vreg_id, rc);
157 goto pin_cnt_fail;
158 }
159 }
160 } else {
161 if (vreg_info[index].is_vreg_pin_controlled) {
162 rc = pmapp_vreg_lpm_pincntrl_vote(id,
163 vreg_info[index].pmapp_id,
164 PMAPP_CLOCK_ID_A0, 0);
165 if (rc) {
166 pr_err("%s:%s pincntrl failed %d\n",
167 __func__,
168 vreg_info[index].vreg_id, rc);
169 goto pin_cnt_fail;
170 }
171 }
172
173 rc = regulator_disable(vreg_info[index].reg);
174 if (rc) {
175 pr_err("%s:%s vreg disable failed %d\n",
176 __func__,
177 vreg_info[index].vreg_id, rc);
178 goto reg_disable;
179 }
180 }
181 }
182 return 0;
183pin_cnt_fail:
184 if (on)
185 regulator_disable(vreg_info[index].reg);
186reg_disable:
187 if (!machine_is_msm7627a_qrd1()) {
188 while (index) {
189 if (on) {
190 index--;
191 regulator_disable(vreg_info[index].reg);
192 regulator_put(vreg_info[index].reg);
193 }
194 }
195 }
196 return rc;
197}
198
199static unsigned int msm_AR600X_setup_power(bool on)
200{
201 int rc = 0;
202 static bool init_done;
203
Antony Thomas20c171d2012-10-05 15:52:04 +0530204 if (wlan_powered_up) {
205 pr_info("WLAN already powered up\n");
206 return 0;
207 }
208
Santosh Sajjan374d6592012-01-19 23:16:46 +0530209 if (unlikely(!init_done)) {
210 gpio_wlan_config();
211 rc = qrf6285_init_regs();
212 if (rc) {
213 pr_err("%s: qrf6285 init failed = %d\n", __func__, rc);
214 return rc;
215 } else {
216 init_done = true;
217 }
218 }
219
220 rc = wlan_switch_regulators(on);
221 if (rc) {
222 pr_err("%s: wlan_switch_regulators error = %d\n", __func__, rc);
223 goto out;
224 }
225
226 /* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
227 if (machine_is_msm7627a_qrd1()) {
228 rc = gpio_tlmm_config(GPIO_CFG(GPIO_WLAN_3V3_EN, 0,
229 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
230 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
231 if (rc) {
232 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
233 __func__, rc);
234 goto reg_disable;
235 }
236 gpio_set_value(GPIO_WLAN_3V3_EN, 1);
237 }
238
239 /*
240 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
241 * EVB1.0 and QRD8625,so the below step is required for those devices.
242 */
Chintan Pandyaf4ad4002012-02-28 19:49:03 +0530243 if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
Aparna Mallavarapu093e7fd2012-04-05 13:08:50 +0530244 || machine_is_msm8625_evb()
Aparna Mallavarapu5a326242012-05-09 19:49:02 +0530245 || machine_is_msm8625_evt()
Aparna Mallavarapu093e7fd2012-04-05 13:08:50 +0530246 || machine_is_msm7627a_qrd3()
Channagoud Kadabi2bd65c82012-10-12 15:14:23 +0530247 || machine_is_msm8625_qrd7()
248 || machine_is_qrd_skud_prime()) {
Santosh Sajjan374d6592012-01-19 23:16:46 +0530249 rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
250 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
251 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
252 if (rc) {
253 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
254 __func__, rc);
255 goto qrd_gpio_fail;
256 }
257 gpio_set_value(gpio_wlan_sys_rest_en, 1);
258 } else {
259 rc = gpio_request(gpio_wlan_sys_rest_en, "WLAN_DEEP_SLEEP_N");
260 if (rc) {
261 pr_err("%s: WLAN sys_rest_en GPIO %d request failed %d\n",
262 __func__,
263 gpio_wlan_sys_rest_en, rc);
264 goto qrd_gpio_fail;
265 }
266 rc = setup_wlan_gpio(on);
267 if (rc) {
268 pr_err("%s: wlan_set_gpio = %d\n", __func__, rc);
269 goto gpio_fail;
270 }
271 }
272
273 /* Enable the A0 clock */
274 rc = setup_wlan_clock(on);
275 if (rc) {
276 pr_err("%s: setup_wlan_clock = %d\n", __func__, rc);
277 goto set_gpio_fail;
278 }
279
280 /* Configure A0 clock to be slave to WLAN_CLK_PWR_REQ */
281 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
282 PMAPP_CLOCK_VOTE_PIN_CTRL);
283 if (rc) {
284 pr_err("%s: Configuring A0 to Pin controllable failed %d\n",
285 __func__, rc);
286 goto set_clock_fail;
287 }
288
289 pr_info("WLAN power-up success\n");
Antony Thomas20c171d2012-10-05 15:52:04 +0530290 wlan_powered_up = true;
Santosh Sajjan374d6592012-01-19 23:16:46 +0530291 return 0;
292set_clock_fail:
293 setup_wlan_clock(0);
294set_gpio_fail:
295 setup_wlan_gpio(0);
296gpio_fail:
Antony Thomas20c171d2012-10-05 15:52:04 +0530297 if (!(machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb() ||
298 machine_is_msm8625_evb() || machine_is_msm8625_evt() ||
299 machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()))
300 gpio_free(gpio_wlan_sys_rest_en);
Santosh Sajjan374d6592012-01-19 23:16:46 +0530301qrd_gpio_fail:
Santosh Sajjan7a435d32012-04-23 18:34:38 +0530302 /* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
303 if (machine_is_msm7627a_qrd1())
304 gpio_free(GPIO_WLAN_3V3_EN);
Santosh Sajjan374d6592012-01-19 23:16:46 +0530305reg_disable:
306 wlan_switch_regulators(0);
307out:
308 pr_info("WLAN power-up failed\n");
Antony Thomas20c171d2012-10-05 15:52:04 +0530309 wlan_powered_up = false;
Santosh Sajjan374d6592012-01-19 23:16:46 +0530310 return rc;
311}
312
313static unsigned int msm_AR600X_shutdown_power(bool on)
314{
315 int rc = 0;
316
Antony Thomas20c171d2012-10-05 15:52:04 +0530317 if (!wlan_powered_up) {
318 pr_info("WLAN is not powered up, returning success\n");
319 return 0;
320 }
321
Santosh Sajjan374d6592012-01-19 23:16:46 +0530322 /* Disable the A0 clock */
323 rc = setup_wlan_clock(on);
324 if (rc) {
325 pr_err("%s: setup_wlan_clock = %d\n", __func__, rc);
326 goto set_clock_fail;
327 }
328
329 /*
330 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
331 * EVB1.0 and QRD8625,so the below step is required for those devices.
332 */
Chintan Pandyaf4ad4002012-02-28 19:49:03 +0530333 if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
Aparna Mallavarapu093e7fd2012-04-05 13:08:50 +0530334 || machine_is_msm8625_evb()
Aparna Mallavarapu5a326242012-05-09 19:49:02 +0530335 || machine_is_msm8625_evt()
Aparna Mallavarapu093e7fd2012-04-05 13:08:50 +0530336 || machine_is_msm7627a_qrd3()
Channagoud Kadabi2bd65c82012-10-12 15:14:23 +0530337 || machine_is_msm8625_qrd7()
338 || machine_is_qrd_skud_prime()) {
Santosh Sajjan374d6592012-01-19 23:16:46 +0530339 rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
340 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
341 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
342 if (rc) {
343 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
344 __func__, rc);
345 goto gpio_fail;
346 }
347 gpio_set_value(gpio_wlan_sys_rest_en, 0);
348 } else {
Antony Thomas20c171d2012-10-05 15:52:04 +0530349 rc = setup_wlan_gpio(on);
350 if (rc) {
351 pr_err("%s: setup_wlan_gpio = %d\n", __func__, rc);
352 goto set_gpio_fail;
Santosh Sajjan374d6592012-01-19 23:16:46 +0530353 }
Antony Thomas20c171d2012-10-05 15:52:04 +0530354 gpio_free(gpio_wlan_sys_rest_en);
Santosh Sajjan374d6592012-01-19 23:16:46 +0530355 }
356
357 /* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
358 if (machine_is_msm7627a_qrd1()) {
359 rc = gpio_tlmm_config(GPIO_CFG(GPIO_WLAN_3V3_EN, 0,
360 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
361 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
362 if (rc) {
363 pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
364 __func__, rc);
365 goto qrd_gpio_fail;
366 }
367 gpio_set_value(GPIO_WLAN_3V3_EN, 0);
368 }
369
370 rc = wlan_switch_regulators(on);
371 if (rc) {
372 pr_err("%s: wlan_switch_regulators error = %d\n",
373 __func__, rc);
374 goto reg_disable;
375 }
Antony Thomas20c171d2012-10-05 15:52:04 +0530376 wlan_powered_up = false;
Santosh Sajjan374d6592012-01-19 23:16:46 +0530377 pr_info("WLAN power-down success\n");
378 return 0;
379set_clock_fail:
380 setup_wlan_clock(0);
381set_gpio_fail:
382 setup_wlan_gpio(0);
383gpio_fail:
Antony Thomas20c171d2012-10-05 15:52:04 +0530384 if (!(machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb() ||
385 machine_is_msm8625_evb() || machine_is_msm8625_evt() ||
386 machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()))
387 gpio_free(gpio_wlan_sys_rest_en);
Santosh Sajjan374d6592012-01-19 23:16:46 +0530388qrd_gpio_fail:
Santosh Sajjan7a435d32012-04-23 18:34:38 +0530389 /* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
390 if (machine_is_msm7627a_qrd1())
391 gpio_free(GPIO_WLAN_3V3_EN);
Santosh Sajjan374d6592012-01-19 23:16:46 +0530392reg_disable:
393 wlan_switch_regulators(0);
Santosh Sajjan374d6592012-01-19 23:16:46 +0530394 pr_info("WLAN power-down failed\n");
395 return rc;
396}
397
398int ar600x_wlan_power(bool on)
399{
400 if (on)
401 msm_AR600X_setup_power(on);
402 else
403 msm_AR600X_shutdown_power(on);
404
405 return 0;
406}