blob: ef0111ad9421b4c5b1de237cfe8c9cbca55cfd31 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, 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
13#include <linux/device.h>
Justin Paupored98328e2011-08-19 13:48:31 -070014#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/gpio.h>
16#include <mach/rpc_pmapp.h>
17#include <linux/err.h>
18#include <linux/qcomwlan7x27a_pwrif.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070019#include <linux/module.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020
21#define WLAN_GPIO_EXT_POR_N 134
22
23static const char *id = "WLAN";
24
25enum {
26 WLAN_VREG_L17 = 0,
27 WLAN_VREG_S3,
28 WLAN_VREG_TCXO_L11,
29 WLAN_VREG_L19,
30 WLAN_VREG_L5,
31 WLAN_VREG_L6
32};
33
34struct wlan_vreg_info {
35 const char *vreg_id;
Pankaj Kumar6ac59af2011-10-12 12:45:40 +053036 unsigned int level_min;
37 unsigned int level_max;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038 unsigned int pmapp_id;
39 unsigned int is_vreg_pin_controlled;
Justin Paupored98328e2011-08-19 13:48:31 -070040 struct regulator *reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041};
42
43
44static struct wlan_vreg_info vreg_info[] = {
Pankaj Kumar6ac59af2011-10-12 12:45:40 +053045 {"bt", 3050000, 3050000, 21, 1, NULL},
46 {"msme1", 1800000, 1800000, 2, 0, NULL},
47 {"wlan_tcx0", 1800000, 1800000, 53, 0, NULL},
48 {"wlan4", 1200000, 1200000, 23, 0, NULL},
49 {"wlan2", 1350000, 1350000, 9, 1, NULL},
50 {"wlan3", 1200000, 1200000, 10, 1, NULL},
Justin Paupored98328e2011-08-19 13:48:31 -070051};
Santosh Sajjan2370c642011-08-02 16:36:39 +053052
Justin Paupored98328e2011-08-19 13:48:31 -070053static int qrf6285_init_regs(void)
54{
55 struct regulator_bulk_data regs[ARRAY_SIZE(vreg_info)];
56 int i, rc;
57
58 for (i = 0; i < ARRAY_SIZE(regs); i++) {
59 regs[i].supply = vreg_info[i].vreg_id;
Pankaj Kumar6ac59af2011-10-12 12:45:40 +053060 regs[i].min_uV = vreg_info[i].level_min;
61 regs[i].max_uV = vreg_info[i].level_max;
Justin Paupored98328e2011-08-19 13:48:31 -070062 }
63
64 rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
65 if (rc) {
66 pr_err("%s: could not get regulators: %d\n", __func__, rc);
67 goto out;
68 }
69
Justin Paupored98328e2011-08-19 13:48:31 -070070 for (i = 0; i < ARRAY_SIZE(regs); i++)
71 vreg_info[i].reg = regs[i].consumer;
72
73 return 0;
74
Justin Paupored98328e2011-08-19 13:48:31 -070075out:
76 return rc;
77}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078
79int chip_power_qrf6285(bool on)
80{
Justin Paupored98328e2011-08-19 13:48:31 -070081 static bool init_done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082 int rc = 0, index = 0;
83
Justin Paupored98328e2011-08-19 13:48:31 -070084 if (unlikely(!init_done)) {
85 rc = qrf6285_init_regs();
86 if (rc)
87 return rc;
88 else
89 init_done = true;
90 }
91
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092 if (on) {
93 rc = gpio_request(WLAN_GPIO_EXT_POR_N, "WLAN_DEEP_SLEEP_N");
94
95 if (rc) {
96 pr_err("WLAN reset GPIO %d request failed %d\n",
97 WLAN_GPIO_EXT_POR_N, rc);
98 goto fail;
99 }
100 rc = gpio_direction_output(WLAN_GPIO_EXT_POR_N, 1);
101 if (rc < 0) {
102 pr_err("WLAN reset GPIO %d set direction failed %d\n",
103 WLAN_GPIO_EXT_POR_N, rc);
104 goto fail_gpio_dir_out;
105 }
Santosh Sajjanecce5612011-08-08 19:05:51 +0530106 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
107 PMAPP_CLOCK_VOTE_ON);
108 if (rc) {
109 pr_err("%s: Configuring A0 to always"
110 " on failed %d\n", __func__, rc);
111 goto clock_vote_fail;
112 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700113 } else {
114 gpio_set_value_cansleep(WLAN_GPIO_EXT_POR_N, 0);
Santosh Sajjanecce5612011-08-08 19:05:51 +0530115 rc = gpio_direction_input(WLAN_GPIO_EXT_POR_N);
116 if (rc) {
117 pr_err("WLAN reset GPIO %d set direction failed %d\n",
118 WLAN_GPIO_EXT_POR_N, rc);
119 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 gpio_free(WLAN_GPIO_EXT_POR_N);
Santosh Sajjanecce5612011-08-08 19:05:51 +0530121 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
122 PMAPP_CLOCK_VOTE_OFF);
123 if (rc) {
124 pr_err("%s: Configuring A0 to turn OFF"
125 " failed %d\n", __func__, rc);
126 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 }
128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 for (index = 0; index < ARRAY_SIZE(vreg_info); index++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130 if (on) {
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530131
132 rc = regulator_set_voltage(vreg_info[index].reg,
Pankaj Kumar6ac59af2011-10-12 12:45:40 +0530133 vreg_info[index].level_min,
134 vreg_info[index].level_max);
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530135 if (rc) {
136 pr_err("%s:%s set voltage failed %d\n",
137 __func__, vreg_info[index].vreg_id, rc);
138
139 goto vreg_fail;
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
147 goto vreg_fail;
148 }
149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 if (vreg_info[index].is_vreg_pin_controlled) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530151 rc = pmapp_vreg_lpm_pincntrl_vote(id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 vreg_info[index].pmapp_id,
153 PMAPP_CLOCK_ID_A0, 1);
154 if (rc) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530155 pr_err("%s:%s pmapp_vreg_lpm_pincntrl"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 " for enable failed %d\n",
157 __func__,
158 vreg_info[index].vreg_id, rc);
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530159 goto vreg_clock_vote_fail;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 }
161 }
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530162
Santosh Sajjan2370c642011-08-02 16:36:39 +0530163 /*At this point CLK_PWR_REQ is high*/
164 if (WLAN_VREG_L6 == index) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 /*
Santosh Sajjan2370c642011-08-02 16:36:39 +0530166 * Configure A0 clock to be slave to
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167 * WLAN_CLK_PWR_REQ
168` */
169 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
170 PMAPP_CLOCK_VOTE_PIN_CTRL);
171 if (rc) {
Santosh Sajjan2370c642011-08-02 16:36:39 +0530172 pr_err("%s: Configuring A0 to Pin"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173 " controllable failed %d\n",
174 __func__, rc);
175 goto vreg_clock_vote_fail;
176 }
177 }
178
179 } else {
180
181 if (vreg_info[index].is_vreg_pin_controlled) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530182 rc = pmapp_vreg_lpm_pincntrl_vote(id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183 vreg_info[index].pmapp_id,
184 PMAPP_CLOCK_ID_A0, 0);
185 if (rc) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530186 pr_err("%s:%s pmapp_vreg_lpm_pincntrl"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 " for disable failed %d\n",
188 __func__,
189 vreg_info[index].vreg_id, rc);
190 }
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530191 }
192 rc = regulator_disable(vreg_info[index].reg);
193 if (rc) {
194 pr_err("%s:%s vreg disable failed %d\n",
195 __func__, vreg_info[index].vreg_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 }
197 }
198 }
199 return 0;
200vreg_fail:
201 index--;
202vreg_clock_vote_fail:
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530203 while (index >= 0) {
Justin Paupored98328e2011-08-19 13:48:31 -0700204 rc = regulator_disable(vreg_info[index].reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 if (rc) {
206 pr_err("%s:%s vreg disable failed %d\n",
207 __func__, vreg_info[index].vreg_id, rc);
208 }
209 index--;
210 }
211 if (!on)
212 goto fail;
Santosh Sajjanecce5612011-08-08 19:05:51 +0530213clock_vote_fail:
214 gpio_set_value_cansleep(WLAN_GPIO_EXT_POR_N, 0);
215 rc = gpio_direction_input(WLAN_GPIO_EXT_POR_N);
216 if (rc) {
217 pr_err("WLAN reset GPIO %d set direction failed %d\n",
218 WLAN_GPIO_EXT_POR_N, rc);
219 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220fail_gpio_dir_out:
221 gpio_free(WLAN_GPIO_EXT_POR_N);
222fail:
223 return rc;
224}
225EXPORT_SYMBOL(chip_power_qrf6285);