board-mahimahi-mmc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /* linux/arch/arm/mach-msm/board-mahimahi-mmc.c
  2. *
  3. * Copyright (C) 2009 Google, Inc.
  4. * Copyright (C) 2009 HTC Corporation
  5. *
  6. * This software is licensed under the terms of the GNU General Public
  7. * License version 2, as published by the Free Software Foundation, and
  8. * may be copied, distributed, and modified under those terms.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. */
  16. #include <linux/delay.h>
  17. #include <linux/debugfs.h>
  18. #include <linux/err.h>
  19. #include <linux/init.h>
  20. #include <linux/kernel.h>
  21. #include <linux/mmc/host.h>
  22. #include <linux/mmc/sdio_ids.h>
  23. #include <linux/platform_device.h>
  24. #include <asm/gpio.h>
  25. #include <asm/io.h>
  26. #include <asm/mach-types.h>
  27. #include <asm/mach/mmc.h>
  28. #include <mach/vreg.h>
  29. #include <mach/proc_comm.h>
  30. #include "board-mahimahi.h"
  31. #include "devices.h"
  32. #undef MAHIMAHI_DEBUG_MMC
  33. static bool opt_disable_sdcard;
  34. static int __init mahimahi_disablesdcard_setup(char *str)
  35. {
  36. opt_disable_sdcard = (bool)simple_strtol(str, NULL, 0);
  37. return 1;
  38. }
  39. __setup("board_mahimahi.disable_sdcard=", mahimahi_disablesdcard_setup);
  40. static void config_gpio_table(uint32_t *table, int len)
  41. {
  42. int n;
  43. unsigned id;
  44. for(n = 0; n < len; n++) {
  45. id = table[n];
  46. msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
  47. }
  48. }
  49. static uint32_t sdcard_on_gpio_table[] = {
  50. PCOM_GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
  51. PCOM_GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
  52. PCOM_GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
  53. PCOM_GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
  54. PCOM_GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
  55. PCOM_GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
  56. };
  57. static uint32_t sdcard_off_gpio_table[] = {
  58. PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
  59. PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
  60. PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
  61. PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
  62. PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
  63. PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
  64. };
  65. static struct vreg *sdslot_vreg;
  66. static uint32_t sdslot_vdd = 0xffffffff;
  67. static uint32_t sdslot_vreg_enabled;
  68. static struct {
  69. int mask;
  70. int level;
  71. } mmc_vdd_table[] = {
  72. { MMC_VDD_165_195, 1800 },
  73. { MMC_VDD_20_21, 2050 },
  74. { MMC_VDD_21_22, 2150 },
  75. { MMC_VDD_22_23, 2250 },
  76. { MMC_VDD_23_24, 2350 },
  77. { MMC_VDD_24_25, 2450 },
  78. { MMC_VDD_25_26, 2550 },
  79. { MMC_VDD_26_27, 2650 },
  80. { MMC_VDD_27_28, 2750 },
  81. { MMC_VDD_28_29, 2850 },
  82. { MMC_VDD_29_30, 2950 },
  83. };
  84. static uint32_t mahimahi_sdslot_switchvdd(struct device *dev, unsigned int vdd)
  85. {
  86. int i;
  87. int ret;
  88. if (vdd == sdslot_vdd)
  89. return 0;
  90. sdslot_vdd = vdd;
  91. if (vdd == 0) {
  92. config_gpio_table(sdcard_off_gpio_table,
  93. ARRAY_SIZE(sdcard_off_gpio_table));
  94. vreg_disable(sdslot_vreg);
  95. sdslot_vreg_enabled = 0;
  96. return 0;
  97. }
  98. if (!sdslot_vreg_enabled) {
  99. ret = vreg_enable(sdslot_vreg);
  100. if (ret)
  101. pr_err("%s: Error enabling vreg (%d)\n", __func__, ret);
  102. config_gpio_table(sdcard_on_gpio_table,
  103. ARRAY_SIZE(sdcard_on_gpio_table));
  104. sdslot_vreg_enabled = 1;
  105. }
  106. for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
  107. if (mmc_vdd_table[i].mask != (1 << vdd))
  108. continue;
  109. ret = vreg_set_level(sdslot_vreg, mmc_vdd_table[i].level);
  110. if (ret)
  111. pr_err("%s: Error setting level (%d)\n", __func__, ret);
  112. return 0;
  113. }
  114. pr_err("%s: Invalid VDD (%d) specified\n", __func__, vdd);
  115. return 0;
  116. }
  117. static uint32_t mahimahi_cdma_sdslot_switchvdd(struct device *dev, unsigned int vdd)
  118. {
  119. if (!vdd == !sdslot_vdd)
  120. return 0;
  121. /* In CDMA version, the vdd of sdslot is not configurable, and it is
  122. * fixed in 2.85V by hardware design.
  123. */
  124. sdslot_vdd = vdd ? MMC_VDD_28_29 : 0;
  125. if (vdd) {
  126. gpio_set_value(MAHIMAHI_CDMA_SD_2V85_EN, 1);
  127. config_gpio_table(sdcard_on_gpio_table,
  128. ARRAY_SIZE(sdcard_on_gpio_table));
  129. } else {
  130. config_gpio_table(sdcard_off_gpio_table,
  131. ARRAY_SIZE(sdcard_off_gpio_table));
  132. gpio_set_value(MAHIMAHI_CDMA_SD_2V85_EN, 0);
  133. }
  134. sdslot_vreg_enabled = !!vdd;
  135. return 0;
  136. }
  137. static unsigned int mahimahi_sdslot_status_rev0(struct device *dev)
  138. {
  139. return !gpio_get_value(MAHIMAHI_GPIO_SDMC_CD_REV0_N);
  140. }
  141. #define MAHIMAHI_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | \
  142. MMC_VDD_21_22 | MMC_VDD_22_23 | \
  143. MMC_VDD_23_24 | MMC_VDD_24_25 | \
  144. MMC_VDD_25_26 | MMC_VDD_26_27 | \
  145. MMC_VDD_27_28 | MMC_VDD_28_29 | \
  146. MMC_VDD_29_30)
  147. int mahimahi_microp_sdslot_status_register(void (*cb)(int, void *), void *);
  148. unsigned int mahimahi_microp_sdslot_status(struct device *);
  149. static struct mmc_platform_data mahimahi_sdslot_data = {
  150. .ocr_mask = MAHIMAHI_MMC_VDD,
  151. .status = mahimahi_microp_sdslot_status,
  152. .register_status_notify = mahimahi_microp_sdslot_status_register,
  153. .translate_vdd = mahimahi_sdslot_switchvdd,
  154. };
  155. static uint32_t wifi_on_gpio_table[] = {
  156. PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
  157. PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
  158. PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
  159. PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
  160. PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
  161. PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
  162. PCOM_GPIO_CFG(152, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
  163. };
  164. static uint32_t wifi_off_gpio_table[] = {
  165. PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
  166. PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
  167. PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
  168. PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
  169. PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
  170. PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
  171. PCOM_GPIO_CFG(152, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
  172. };
  173. /* BCM4329 returns wrong sdio_vsn(1) when we read cccr,
  174. * we use predefined value (sdio_vsn=2) here to initial sdio driver well
  175. */
  176. static struct embedded_sdio_data mahimahi_wifi_emb_data = {
  177. .cccr = {
  178. .sdio_vsn = 2,
  179. .multi_block = 1,
  180. .low_speed = 0,
  181. .wide_bus = 0,
  182. .high_power = 1,
  183. .high_speed = 1,
  184. },
  185. };
  186. static int mahimahi_wifi_cd = 0; /* WIFI virtual 'card detect' status */
  187. static void (*wifi_status_cb)(int card_present, void *dev_id);
  188. static void *wifi_status_cb_devid;
  189. static int mahimahi_wifi_status_register(
  190. void (*callback)(int card_present, void *dev_id),
  191. void *dev_id)
  192. {
  193. if (wifi_status_cb)
  194. return -EAGAIN;
  195. wifi_status_cb = callback;
  196. wifi_status_cb_devid = dev_id;
  197. return 0;
  198. }
  199. static unsigned int mahimahi_wifi_status(struct device *dev)
  200. {
  201. return mahimahi_wifi_cd;
  202. }
  203. static struct mmc_platform_data mahimahi_wifi_data = {
  204. .ocr_mask = MMC_VDD_28_29,
  205. .built_in = 1,
  206. .status = mahimahi_wifi_status,
  207. .register_status_notify = mahimahi_wifi_status_register,
  208. .embedded_sdio = &mahimahi_wifi_emb_data,
  209. };
  210. int mahimahi_wifi_set_carddetect(int val)
  211. {
  212. pr_info("%s: %d\n", __func__, val);
  213. mahimahi_wifi_cd = val;
  214. if (wifi_status_cb) {
  215. wifi_status_cb(val, wifi_status_cb_devid);
  216. } else
  217. pr_warning("%s: Nobody to notify\n", __func__);
  218. return 0;
  219. }
  220. static int mahimahi_wifi_power_state;
  221. int mahimahi_wifi_power(int on)
  222. {
  223. printk("%s: %d\n", __func__, on);
  224. if (on) {
  225. config_gpio_table(wifi_on_gpio_table,
  226. ARRAY_SIZE(wifi_on_gpio_table));
  227. mdelay(50);
  228. } else {
  229. config_gpio_table(wifi_off_gpio_table,
  230. ARRAY_SIZE(wifi_off_gpio_table));
  231. }
  232. mdelay(100);
  233. gpio_set_value(MAHIMAHI_GPIO_WIFI_SHUTDOWN_N, on); /* WIFI_SHUTDOWN */
  234. mdelay(200);
  235. mahimahi_wifi_power_state = on;
  236. return 0;
  237. }
  238. static int mahimahi_wifi_reset_state;
  239. int mahimahi_wifi_reset(int on)
  240. {
  241. printk("%s: do nothing\n", __func__);
  242. mahimahi_wifi_reset_state = on;
  243. return 0;
  244. }
  245. int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
  246. unsigned int stat_irq, unsigned long stat_irq_flags);
  247. int __init mahimahi_init_mmc(unsigned int sys_rev, unsigned debug_uart)
  248. {
  249. uint32_t id;
  250. printk("%s()+\n", __func__);
  251. /* initial WIFI_SHUTDOWN# */
  252. id = PCOM_GPIO_CFG(MAHIMAHI_GPIO_WIFI_SHUTDOWN_N, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
  253. msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
  254. msm_add_sdcc(1, &mahimahi_wifi_data, 0, 0);
  255. if (debug_uart) {
  256. pr_info("%s: sdcard disabled due to debug uart\n", __func__);
  257. goto done;
  258. }
  259. if (opt_disable_sdcard) {
  260. pr_info("%s: sdcard disabled on cmdline\n", __func__);
  261. goto done;
  262. }
  263. sdslot_vreg_enabled = 0;
  264. if (is_cdma_version(sys_rev)) {
  265. /* In the CDMA version, sdslot is supplied by a gpio. */
  266. int rc = gpio_request(MAHIMAHI_CDMA_SD_2V85_EN, "sdslot_en");
  267. if (rc < 0) {
  268. pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
  269. MAHIMAHI_CDMA_SD_2V85_EN, rc);
  270. return rc;
  271. }
  272. mahimahi_sdslot_data.translate_vdd = mahimahi_cdma_sdslot_switchvdd;
  273. } else {
  274. /* in UMTS version, sdslot is supplied by pmic */
  275. sdslot_vreg = vreg_get(0, "gp6");
  276. if (IS_ERR(sdslot_vreg))
  277. return PTR_ERR(sdslot_vreg);
  278. }
  279. if (system_rev > 0)
  280. msm_add_sdcc(2, &mahimahi_sdslot_data, 0, 0);
  281. else {
  282. mahimahi_sdslot_data.status = mahimahi_sdslot_status_rev0;
  283. mahimahi_sdslot_data.register_status_notify = NULL;
  284. set_irq_wake(MSM_GPIO_TO_INT(MAHIMAHI_GPIO_SDMC_CD_REV0_N), 1);
  285. msm_add_sdcc(2, &mahimahi_sdslot_data,
  286. MSM_GPIO_TO_INT(MAHIMAHI_GPIO_SDMC_CD_REV0_N),
  287. IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE);
  288. }
  289. done:
  290. printk("%s()-\n", __func__);
  291. return 0;
  292. }
  293. #if defined(MAHIMAHI_DEBUG_MMC) && defined(CONFIG_DEBUG_FS)
  294. static int mahimahimmc_dbg_wifi_reset_set(void *data, u64 val)
  295. {
  296. mahimahi_wifi_reset((int) val);
  297. return 0;
  298. }
  299. static int mahimahimmc_dbg_wifi_reset_get(void *data, u64 *val)
  300. {
  301. *val = mahimahi_wifi_reset_state;
  302. return 0;
  303. }
  304. static int mahimahimmc_dbg_wifi_cd_set(void *data, u64 val)
  305. {
  306. mahimahi_wifi_set_carddetect((int) val);
  307. return 0;
  308. }
  309. static int mahimahimmc_dbg_wifi_cd_get(void *data, u64 *val)
  310. {
  311. *val = mahimahi_wifi_cd;
  312. return 0;
  313. }
  314. static int mahimahimmc_dbg_wifi_pwr_set(void *data, u64 val)
  315. {
  316. mahimahi_wifi_power((int) val);
  317. return 0;
  318. }
  319. static int mahimahimmc_dbg_wifi_pwr_get(void *data, u64 *val)
  320. {
  321. *val = mahimahi_wifi_power_state;
  322. return 0;
  323. }
  324. static int mahimahimmc_dbg_sd_pwr_set(void *data, u64 val)
  325. {
  326. mahimahi_sdslot_switchvdd(NULL, (unsigned int) val);
  327. return 0;
  328. }
  329. static int mahimahimmc_dbg_sd_pwr_get(void *data, u64 *val)
  330. {
  331. *val = sdslot_vdd;
  332. return 0;
  333. }
  334. static int mahimahimmc_dbg_sd_cd_set(void *data, u64 val)
  335. {
  336. return -ENOSYS;
  337. }
  338. static int mahimahimmc_dbg_sd_cd_get(void *data, u64 *val)
  339. {
  340. *val = mahimahi_sdslot_data.status(NULL);
  341. return 0;
  342. }
  343. DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_reset_fops,
  344. mahimahimmc_dbg_wifi_reset_get,
  345. mahimahimmc_dbg_wifi_reset_set, "%llu\n");
  346. DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_cd_fops,
  347. mahimahimmc_dbg_wifi_cd_get,
  348. mahimahimmc_dbg_wifi_cd_set, "%llu\n");
  349. DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_pwr_fops,
  350. mahimahimmc_dbg_wifi_pwr_get,
  351. mahimahimmc_dbg_wifi_pwr_set, "%llu\n");
  352. DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_sd_pwr_fops,
  353. mahimahimmc_dbg_sd_pwr_get,
  354. mahimahimmc_dbg_sd_pwr_set, "%llu\n");
  355. DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_sd_cd_fops,
  356. mahimahimmc_dbg_sd_cd_get,
  357. mahimahimmc_dbg_sd_cd_set, "%llu\n");
  358. static int __init mahimahimmc_dbg_init(void)
  359. {
  360. struct dentry *dent;
  361. if (!machine_is_mahimahi())
  362. return 0;
  363. dent = debugfs_create_dir("mahimahi_mmc_dbg", 0);
  364. if (IS_ERR(dent))
  365. return PTR_ERR(dent);
  366. debugfs_create_file("wifi_reset", 0644, dent, NULL,
  367. &mahimahimmc_dbg_wifi_reset_fops);
  368. debugfs_create_file("wifi_cd", 0644, dent, NULL,
  369. &mahimahimmc_dbg_wifi_cd_fops);
  370. debugfs_create_file("wifi_pwr", 0644, dent, NULL,
  371. &mahimahimmc_dbg_wifi_pwr_fops);
  372. debugfs_create_file("sd_pwr", 0644, dent, NULL,
  373. &mahimahimmc_dbg_sd_pwr_fops);
  374. debugfs_create_file("sd_cd", 0644, dent, NULL,
  375. &mahimahimmc_dbg_sd_cd_fops);
  376. return 0;
  377. }
  378. device_initcall(mahimahimmc_dbg_init);
  379. #endif