board-swordfish-mmc.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /* linux/arch/arm/mach-msm/board-swordfish-mmc.c
  2. *
  3. * Copyright (C) 2008 Google, Inc.
  4. *
  5. * This software is licensed under the terms of the GNU General Public
  6. * License version 2, as published by the Free Software Foundation, and
  7. * may be copied, distributed, and modified under those terms.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. *
  15. */
  16. #include <linux/delay.h>
  17. #include <linux/device.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/mmc.h>
  27. #include <mach/vreg.h>
  28. #include <mach/proc_comm.h>
  29. #include "devices.h"
  30. #define FPGA_BASE 0x70000000
  31. #define FPGA_SDIO_STATUS 0x280
  32. static void __iomem *fpga_base;
  33. #define DEBUG_SWORDFISH_MMC 1
  34. extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
  35. unsigned int stat_irq, unsigned long stat_irq_flags);
  36. static int config_gpio_table(unsigned *table, int len, int enable)
  37. {
  38. int n;
  39. int rc = 0;
  40. for (n = 0; n < len; n++) {
  41. unsigned dis = !enable;
  42. unsigned id = table[n];
  43. if (msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, &dis)) {
  44. pr_err("%s: id=0x%08x dis=%d\n", __func__, table[n],
  45. dis);
  46. rc = -1;
  47. }
  48. }
  49. return rc;
  50. }
  51. static unsigned sdc1_gpio_table[] = {
  52. PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  53. PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  54. PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  55. PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  56. PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  57. PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
  58. };
  59. static unsigned sdc2_gpio_table[] = {
  60. PCOM_GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
  61. PCOM_GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  62. PCOM_GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  63. PCOM_GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  64. PCOM_GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  65. PCOM_GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA),
  66. };
  67. static unsigned sdc3_gpio_table[] = {
  68. PCOM_GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
  69. PCOM_GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  70. PCOM_GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  71. PCOM_GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  72. PCOM_GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  73. PCOM_GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  74. };
  75. static unsigned sdc4_gpio_table[] = {
  76. PCOM_GPIO_CFG(142, 3, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
  77. PCOM_GPIO_CFG(143, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  78. PCOM_GPIO_CFG(144, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  79. PCOM_GPIO_CFG(145, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  80. PCOM_GPIO_CFG(146, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  81. PCOM_GPIO_CFG(147, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
  82. };
  83. struct sdc_info {
  84. unsigned *table;
  85. unsigned len;
  86. };
  87. static struct sdc_info sdcc_gpio_tables[] = {
  88. [0] = {
  89. .table = sdc1_gpio_table,
  90. .len = ARRAY_SIZE(sdc1_gpio_table),
  91. },
  92. [1] = {
  93. .table = sdc2_gpio_table,
  94. .len = ARRAY_SIZE(sdc2_gpio_table),
  95. },
  96. [2] = {
  97. .table = sdc3_gpio_table,
  98. .len = ARRAY_SIZE(sdc3_gpio_table),
  99. },
  100. [3] = {
  101. .table = sdc4_gpio_table,
  102. .len = ARRAY_SIZE(sdc4_gpio_table),
  103. },
  104. };
  105. static int swordfish_sdcc_setup_gpio(int dev_id, unsigned enable)
  106. {
  107. struct sdc_info *info;
  108. if (dev_id < 1 || dev_id > 4)
  109. return -1;
  110. info = &sdcc_gpio_tables[dev_id - 1];
  111. return config_gpio_table(info->table, info->len, enable);
  112. }
  113. struct mmc_vdd_xlat {
  114. int mask;
  115. int level;
  116. };
  117. static struct mmc_vdd_xlat mmc_vdd_table[] = {
  118. { MMC_VDD_165_195, 1800 },
  119. { MMC_VDD_20_21, 2050 },
  120. { MMC_VDD_21_22, 2150 },
  121. { MMC_VDD_22_23, 2250 },
  122. { MMC_VDD_23_24, 2350 },
  123. { MMC_VDD_24_25, 2450 },
  124. { MMC_VDD_25_26, 2550 },
  125. { MMC_VDD_26_27, 2650 },
  126. { MMC_VDD_27_28, 2750 },
  127. { MMC_VDD_28_29, 2850 },
  128. { MMC_VDD_29_30, 2950 },
  129. };
  130. static struct vreg *vreg_sdcc;
  131. static unsigned int vreg_sdcc_enabled;
  132. static unsigned int sdcc_vdd = 0xffffffff;
  133. static uint32_t sdcc_translate_vdd(struct device *dev, unsigned int vdd)
  134. {
  135. int i;
  136. int rc = 0;
  137. struct platform_device *pdev;
  138. pdev = container_of(dev, struct platform_device, dev);
  139. BUG_ON(!vreg_sdcc);
  140. if (vdd == sdcc_vdd)
  141. return 0;
  142. sdcc_vdd = vdd;
  143. /* enable/disable the signals to the slot */
  144. swordfish_sdcc_setup_gpio(pdev->id, !!vdd);
  145. /* power down */
  146. if (vdd == 0) {
  147. #if DEBUG_SWORDFISH_MMC
  148. pr_info("%s: disable sdcc power\n", __func__);
  149. #endif
  150. vreg_disable(vreg_sdcc);
  151. vreg_sdcc_enabled = 0;
  152. return 0;
  153. }
  154. if (!vreg_sdcc_enabled) {
  155. rc = vreg_enable(vreg_sdcc);
  156. if (rc)
  157. pr_err("%s: Error enabling vreg (%d)\n", __func__, rc);
  158. vreg_sdcc_enabled = 1;
  159. }
  160. for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
  161. if (mmc_vdd_table[i].mask != (1 << vdd))
  162. continue;
  163. #if DEBUG_SWORDFISH_MMC
  164. pr_info("%s: Setting level to %u\n", __func__,
  165. mmc_vdd_table[i].level);
  166. #endif
  167. rc = vreg_set_level(vreg_sdcc, mmc_vdd_table[i].level);
  168. if (rc)
  169. pr_err("%s: Error setting vreg level (%d)\n", __func__, rc);
  170. return 0;
  171. }
  172. pr_err("%s: Invalid VDD %d specified\n", __func__, vdd);
  173. return 0;
  174. }
  175. static unsigned int swordfish_sdcc_slot_status (struct device *dev)
  176. {
  177. struct platform_device *pdev;
  178. uint32_t sdcc_stat;
  179. pdev = container_of(dev, struct platform_device, dev);
  180. sdcc_stat = readl(fpga_base + FPGA_SDIO_STATUS);
  181. /* bit 0 - sdcc1 crd_det
  182. * bit 1 - sdcc1 wr_prt
  183. * bit 2 - sdcc2 crd_det
  184. * bit 3 - sdcc2 wr_prt
  185. * etc...
  186. */
  187. /* crd_det is active low */
  188. return !(sdcc_stat & (1 << ((pdev->id - 1) << 1)));
  189. }
  190. #define SWORDFISH_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
  191. | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
  192. | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
  193. | MMC_VDD_28_29 | MMC_VDD_29_30)
  194. static struct mmc_platform_data swordfish_sdcc_data = {
  195. .ocr_mask = SWORDFISH_MMC_VDD/*MMC_VDD_27_28 | MMC_VDD_28_29*/,
  196. .status = swordfish_sdcc_slot_status,
  197. .translate_vdd = sdcc_translate_vdd,
  198. };
  199. int __init swordfish_init_mmc(void)
  200. {
  201. vreg_sdcc_enabled = 0;
  202. vreg_sdcc = vreg_get(NULL, "gp5");
  203. if (IS_ERR(vreg_sdcc)) {
  204. pr_err("%s: vreg get failed (%ld)\n",
  205. __func__, PTR_ERR(vreg_sdcc));
  206. return PTR_ERR(vreg_sdcc);
  207. }
  208. fpga_base = ioremap(FPGA_BASE, SZ_4K);
  209. if (!fpga_base) {
  210. pr_err("%s: Can't ioremap FPGA base address (0x%08x)\n",
  211. __func__, FPGA_BASE);
  212. vreg_put(vreg_sdcc);
  213. return -EIO;
  214. }
  215. msm_add_sdcc(1, &swordfish_sdcc_data, 0, 0);
  216. msm_add_sdcc(4, &swordfish_sdcc_data, 0, 0);
  217. return 0;
  218. }