blob: 82625b5c16bc3e977d287bc171424c03fc9b8ce6 [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>
19
20#define WLAN_GPIO_EXT_POR_N 134
21
22static const char *id = "WLAN";
23
24enum {
25 WLAN_VREG_L17 = 0,
26 WLAN_VREG_S3,
27 WLAN_VREG_TCXO_L11,
28 WLAN_VREG_L19,
29 WLAN_VREG_L5,
30 WLAN_VREG_L6
31};
32
33struct wlan_vreg_info {
34 const char *vreg_id;
Pankaj Kumar6ac59af2011-10-12 12:45:40 +053035 unsigned int level_min;
36 unsigned int level_max;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037 unsigned int pmapp_id;
38 unsigned int is_vreg_pin_controlled;
Justin Paupored98328e2011-08-19 13:48:31 -070039 struct regulator *reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040};
41
42
43static struct wlan_vreg_info vreg_info[] = {
Pankaj Kumar6ac59af2011-10-12 12:45:40 +053044 {"bt", 3050000, 3050000, 21, 1, NULL},
45 {"msme1", 1800000, 1800000, 2, 0, NULL},
46 {"wlan_tcx0", 1800000, 1800000, 53, 0, NULL},
47 {"wlan4", 1200000, 1200000, 23, 0, NULL},
48 {"wlan2", 1350000, 1350000, 9, 1, NULL},
49 {"wlan3", 1200000, 1200000, 10, 1, NULL},
Justin Paupored98328e2011-08-19 13:48:31 -070050};
Santosh Sajjan2370c642011-08-02 16:36:39 +053051
Justin Paupored98328e2011-08-19 13:48:31 -070052static int qrf6285_init_regs(void)
53{
54 struct regulator_bulk_data regs[ARRAY_SIZE(vreg_info)];
55 int i, rc;
56
57 for (i = 0; i < ARRAY_SIZE(regs); i++) {
58 regs[i].supply = vreg_info[i].vreg_id;
Pankaj Kumar6ac59af2011-10-12 12:45:40 +053059 regs[i].min_uV = vreg_info[i].level_min;
60 regs[i].max_uV = vreg_info[i].level_max;
Justin Paupored98328e2011-08-19 13:48:31 -070061 }
62
63 rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
64 if (rc) {
65 pr_err("%s: could not get regulators: %d\n", __func__, rc);
66 goto out;
67 }
68
Justin Paupored98328e2011-08-19 13:48:31 -070069 for (i = 0; i < ARRAY_SIZE(regs); i++)
70 vreg_info[i].reg = regs[i].consumer;
71
72 return 0;
73
Justin Paupored98328e2011-08-19 13:48:31 -070074out:
75 return rc;
76}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070077
78int chip_power_qrf6285(bool on)
79{
Justin Paupored98328e2011-08-19 13:48:31 -070080 static bool init_done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081 int rc = 0, index = 0;
82
Justin Paupored98328e2011-08-19 13:48:31 -070083 if (unlikely(!init_done)) {
84 rc = qrf6285_init_regs();
85 if (rc)
86 return rc;
87 else
88 init_done = true;
89 }
90
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 if (on) {
92 rc = gpio_request(WLAN_GPIO_EXT_POR_N, "WLAN_DEEP_SLEEP_N");
93
94 if (rc) {
95 pr_err("WLAN reset GPIO %d request failed %d\n",
96 WLAN_GPIO_EXT_POR_N, rc);
97 goto fail;
98 }
99 rc = gpio_direction_output(WLAN_GPIO_EXT_POR_N, 1);
100 if (rc < 0) {
101 pr_err("WLAN reset GPIO %d set direction failed %d\n",
102 WLAN_GPIO_EXT_POR_N, rc);
103 goto fail_gpio_dir_out;
104 }
Santosh Sajjanecce5612011-08-08 19:05:51 +0530105 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
106 PMAPP_CLOCK_VOTE_ON);
107 if (rc) {
108 pr_err("%s: Configuring A0 to always"
109 " on failed %d\n", __func__, rc);
110 goto clock_vote_fail;
111 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112 } else {
113 gpio_set_value_cansleep(WLAN_GPIO_EXT_POR_N, 0);
Santosh Sajjanecce5612011-08-08 19:05:51 +0530114 rc = gpio_direction_input(WLAN_GPIO_EXT_POR_N);
115 if (rc) {
116 pr_err("WLAN reset GPIO %d set direction failed %d\n",
117 WLAN_GPIO_EXT_POR_N, rc);
118 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119 gpio_free(WLAN_GPIO_EXT_POR_N);
Santosh Sajjanecce5612011-08-08 19:05:51 +0530120 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
121 PMAPP_CLOCK_VOTE_OFF);
122 if (rc) {
123 pr_err("%s: Configuring A0 to turn OFF"
124 " failed %d\n", __func__, rc);
125 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 }
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 for (index = 0; index < ARRAY_SIZE(vreg_info); index++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 if (on) {
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530130
131 rc = regulator_set_voltage(vreg_info[index].reg,
Pankaj Kumar6ac59af2011-10-12 12:45:40 +0530132 vreg_info[index].level_min,
133 vreg_info[index].level_max);
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530134 if (rc) {
135 pr_err("%s:%s set voltage failed %d\n",
136 __func__, vreg_info[index].vreg_id, rc);
137
138 goto vreg_fail;
139 }
140
141 rc = regulator_enable(vreg_info[index].reg);
142 if (rc) {
143 pr_err("%s:%s vreg enable failed %d\n",
144 __func__, vreg_info[index].vreg_id, rc);
145
146 goto vreg_fail;
147 }
148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 if (vreg_info[index].is_vreg_pin_controlled) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530150 rc = pmapp_vreg_lpm_pincntrl_vote(id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 vreg_info[index].pmapp_id,
152 PMAPP_CLOCK_ID_A0, 1);
153 if (rc) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530154 pr_err("%s:%s pmapp_vreg_lpm_pincntrl"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155 " for enable failed %d\n",
156 __func__,
157 vreg_info[index].vreg_id, rc);
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530158 goto vreg_clock_vote_fail;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 }
160 }
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530161
Santosh Sajjan2370c642011-08-02 16:36:39 +0530162 /*At this point CLK_PWR_REQ is high*/
163 if (WLAN_VREG_L6 == index) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164 /*
Santosh Sajjan2370c642011-08-02 16:36:39 +0530165 * Configure A0 clock to be slave to
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166 * WLAN_CLK_PWR_REQ
167` */
168 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
169 PMAPP_CLOCK_VOTE_PIN_CTRL);
170 if (rc) {
Santosh Sajjan2370c642011-08-02 16:36:39 +0530171 pr_err("%s: Configuring A0 to Pin"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172 " controllable failed %d\n",
173 __func__, rc);
174 goto vreg_clock_vote_fail;
175 }
176 }
177
178 } else {
179
180 if (vreg_info[index].is_vreg_pin_controlled) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530181 rc = pmapp_vreg_lpm_pincntrl_vote(id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182 vreg_info[index].pmapp_id,
183 PMAPP_CLOCK_ID_A0, 0);
184 if (rc) {
Santosh Sajjan0e506ab2011-08-30 12:30:50 +0530185 pr_err("%s:%s pmapp_vreg_lpm_pincntrl"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 " for disable failed %d\n",
187 __func__,
188 vreg_info[index].vreg_id, rc);
189 }
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530190 }
191 rc = regulator_disable(vreg_info[index].reg);
192 if (rc) {
193 pr_err("%s:%s vreg disable failed %d\n",
194 __func__, vreg_info[index].vreg_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 }
196 }
197 }
198 return 0;
199vreg_fail:
200 index--;
201vreg_clock_vote_fail:
Pankaj Kumara9d576c2011-09-29 10:56:53 +0530202 while (index >= 0) {
Justin Paupored98328e2011-08-19 13:48:31 -0700203 rc = regulator_disable(vreg_info[index].reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 if (rc) {
205 pr_err("%s:%s vreg disable failed %d\n",
206 __func__, vreg_info[index].vreg_id, rc);
207 }
208 index--;
209 }
210 if (!on)
211 goto fail;
Santosh Sajjanecce5612011-08-08 19:05:51 +0530212clock_vote_fail:
213 gpio_set_value_cansleep(WLAN_GPIO_EXT_POR_N, 0);
214 rc = gpio_direction_input(WLAN_GPIO_EXT_POR_N);
215 if (rc) {
216 pr_err("WLAN reset GPIO %d set direction failed %d\n",
217 WLAN_GPIO_EXT_POR_N, rc);
218 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219fail_gpio_dir_out:
220 gpio_free(WLAN_GPIO_EXT_POR_N);
221fail:
222 return rc;
223}
224EXPORT_SYMBOL(chip_power_qrf6285);