board-msm7627a-wlan.c 9.8 KB

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