sdhci-pxa.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /* linux/drivers/mmc/host/sdhci-pxa.c
  2. *
  3. * Copyright (C) 2010 Marvell International Ltd.
  4. * Zhangfei Gao <zhangfei.gao@marvell.com>
  5. * Kevin Wang <dwang4@marvell.com>
  6. * Mingwei Wang <mwwang@marvell.com>
  7. * Philip Rakity <prakity@marvell.com>
  8. * Mark Brown <markb@marvell.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. */
  14. /* Supports:
  15. * SDHCI support for MMP2/PXA910/PXA168
  16. *
  17. * Refer to sdhci-s3c.c.
  18. */
  19. #include <linux/delay.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/mmc/host.h>
  22. #include <linux/clk.h>
  23. #include <linux/io.h>
  24. #include <linux/err.h>
  25. #include <plat/sdhci.h>
  26. #include "sdhci.h"
  27. #define DRIVER_NAME "sdhci-pxa"
  28. #define SD_FIFO_PARAM 0x104
  29. #define DIS_PAD_SD_CLK_GATE 0x400
  30. struct sdhci_pxa {
  31. struct sdhci_host *host;
  32. struct sdhci_pxa_platdata *pdata;
  33. struct clk *clk;
  34. struct resource *res;
  35. u8 clk_enable;
  36. };
  37. /*****************************************************************************\
  38. * *
  39. * SDHCI core callbacks *
  40. * *
  41. \*****************************************************************************/
  42. static void set_clock(struct sdhci_host *host, unsigned int clock)
  43. {
  44. struct sdhci_pxa *pxa = sdhci_priv(host);
  45. u32 tmp = 0;
  46. if (clock == 0) {
  47. if (pxa->clk_enable) {
  48. clk_disable(pxa->clk);
  49. pxa->clk_enable = 0;
  50. }
  51. } else {
  52. if (0 == pxa->clk_enable) {
  53. if (pxa->pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) {
  54. tmp = readl(host->ioaddr + SD_FIFO_PARAM);
  55. tmp |= DIS_PAD_SD_CLK_GATE;
  56. writel(tmp, host->ioaddr + SD_FIFO_PARAM);
  57. }
  58. clk_enable(pxa->clk);
  59. pxa->clk_enable = 1;
  60. }
  61. }
  62. }
  63. static struct sdhci_ops sdhci_pxa_ops = {
  64. .set_clock = set_clock,
  65. };
  66. /*****************************************************************************\
  67. * *
  68. * Device probing/removal *
  69. * *
  70. \*****************************************************************************/
  71. static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
  72. {
  73. struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
  74. struct device *dev = &pdev->dev;
  75. struct sdhci_host *host = NULL;
  76. struct resource *iomem = NULL;
  77. struct sdhci_pxa *pxa = NULL;
  78. int ret, irq;
  79. irq = platform_get_irq(pdev, 0);
  80. if (irq < 0) {
  81. dev_err(dev, "no irq specified\n");
  82. return irq;
  83. }
  84. iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  85. if (!iomem) {
  86. dev_err(dev, "no memory specified\n");
  87. return -ENOENT;
  88. }
  89. host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pxa));
  90. if (IS_ERR(host)) {
  91. dev_err(dev, "failed to alloc host\n");
  92. return PTR_ERR(host);
  93. }
  94. pxa = sdhci_priv(host);
  95. pxa->host = host;
  96. pxa->pdata = pdata;
  97. pxa->clk_enable = 0;
  98. pxa->clk = clk_get(dev, "PXA-SDHCLK");
  99. if (IS_ERR(pxa->clk)) {
  100. dev_err(dev, "failed to get io clock\n");
  101. ret = PTR_ERR(pxa->clk);
  102. goto out;
  103. }
  104. pxa->res = request_mem_region(iomem->start, resource_size(iomem),
  105. mmc_hostname(host->mmc));
  106. if (!pxa->res) {
  107. dev_err(&pdev->dev, "cannot request region\n");
  108. ret = -EBUSY;
  109. goto out;
  110. }
  111. host->ioaddr = ioremap(iomem->start, resource_size(iomem));
  112. if (!host->ioaddr) {
  113. dev_err(&pdev->dev, "failed to remap registers\n");
  114. ret = -ENOMEM;
  115. goto out;
  116. }
  117. host->hw_name = "MMC";
  118. host->ops = &sdhci_pxa_ops;
  119. host->irq = irq;
  120. host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
  121. if (pdata->quirks)
  122. host->quirks |= pdata->quirks;
  123. ret = sdhci_add_host(host);
  124. if (ret) {
  125. dev_err(&pdev->dev, "failed to add host\n");
  126. goto out;
  127. }
  128. if (pxa->pdata->max_speed)
  129. host->mmc->f_max = pxa->pdata->max_speed;
  130. platform_set_drvdata(pdev, host);
  131. return 0;
  132. out:
  133. if (host) {
  134. clk_put(pxa->clk);
  135. if (host->ioaddr)
  136. iounmap(host->ioaddr);
  137. if (pxa->res)
  138. release_mem_region(pxa->res->start,
  139. resource_size(pxa->res));
  140. sdhci_free_host(host);
  141. }
  142. return ret;
  143. }
  144. static int __devexit sdhci_pxa_remove(struct platform_device *pdev)
  145. {
  146. struct sdhci_host *host = platform_get_drvdata(pdev);
  147. struct sdhci_pxa *pxa = sdhci_priv(host);
  148. int dead = 0;
  149. u32 scratch;
  150. if (host) {
  151. scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
  152. if (scratch == (u32)-1)
  153. dead = 1;
  154. sdhci_remove_host(host, dead);
  155. if (host->ioaddr)
  156. iounmap(host->ioaddr);
  157. if (pxa->res)
  158. release_mem_region(pxa->res->start,
  159. resource_size(pxa->res));
  160. if (pxa->clk_enable) {
  161. clk_disable(pxa->clk);
  162. pxa->clk_enable = 0;
  163. }
  164. clk_put(pxa->clk);
  165. sdhci_free_host(host);
  166. platform_set_drvdata(pdev, NULL);
  167. }
  168. return 0;
  169. }
  170. #ifdef CONFIG_PM
  171. static int sdhci_pxa_suspend(struct platform_device *dev, pm_message_t state)
  172. {
  173. struct sdhci_host *host = platform_get_drvdata(dev);
  174. return sdhci_suspend_host(host, state);
  175. }
  176. static int sdhci_pxa_resume(struct platform_device *dev)
  177. {
  178. struct sdhci_host *host = platform_get_drvdata(dev);
  179. return sdhci_resume_host(host);
  180. }
  181. #else
  182. #define sdhci_pxa_suspend NULL
  183. #define sdhci_pxa_resume NULL
  184. #endif
  185. static struct platform_driver sdhci_pxa_driver = {
  186. .probe = sdhci_pxa_probe,
  187. .remove = __devexit_p(sdhci_pxa_remove),
  188. .suspend = sdhci_pxa_suspend,
  189. .resume = sdhci_pxa_resume,
  190. .driver = {
  191. .name = DRIVER_NAME,
  192. .owner = THIS_MODULE,
  193. },
  194. };
  195. /*****************************************************************************\
  196. * *
  197. * Driver init/exit *
  198. * *
  199. \*****************************************************************************/
  200. static int __init sdhci_pxa_init(void)
  201. {
  202. return platform_driver_register(&sdhci_pxa_driver);
  203. }
  204. static void __exit sdhci_pxa_exit(void)
  205. {
  206. platform_driver_unregister(&sdhci_pxa_driver);
  207. }
  208. module_init(sdhci_pxa_init);
  209. module_exit(sdhci_pxa_exit);
  210. MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2");
  211. MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
  212. MODULE_LICENSE("GPL v2");