0047-mmc-sdhci-msm-Initial-support-for-Qualcomm-chipsets.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. From 5a8f026acb4a7a6c6d0c868cc1790363640b9b8f Mon Sep 17 00:00:00 2001
  2. From: Georgi Djakov <[email protected]>
  3. Date: Mon, 10 Mar 2014 17:37:12 +0200
  4. Subject: [PATCH 047/182] mmc: sdhci-msm: Initial support for Qualcomm
  5. chipsets
  6. This platform driver adds the initial support of Secure Digital Host
  7. Controller Interface compliant controller found in Qualcomm chipsets.
  8. Signed-off-by: Asutosh Das <[email protected]>
  9. Signed-off-by: Venkat Gopalakrishnan <[email protected]>
  10. Tested-by: Ivan T. Ivanov <[email protected]>
  11. Signed-off-by: Georgi Djakov <[email protected]>
  12. Acked-by: Ulf Hansson <[email protected]>
  13. Signed-off-by: Chris Ball <[email protected]>
  14. ---
  15. drivers/mmc/host/Kconfig | 13 +++
  16. drivers/mmc/host/Makefile | 1 +
  17. drivers/mmc/host/sdhci-msm.c | 208 ++++++++++++++++++++++++++++++++++++++++++
  18. 3 files changed, 222 insertions(+)
  19. create mode 100644 drivers/mmc/host/sdhci-msm.c
  20. --- a/drivers/mmc/host/Kconfig
  21. +++ b/drivers/mmc/host/Kconfig
  22. @@ -334,6 +334,19 @@ config MMC_ATMELMCI
  23. If unsure, say N.
  24. +config MMC_SDHCI_MSM
  25. + tristate "Qualcomm SDHCI Controller Support"
  26. + depends on ARCH_QCOM
  27. + depends on MMC_SDHCI_PLTFM
  28. + help
  29. + This selects the Secure Digital Host Controller Interface (SDHCI)
  30. + support present in Qualcomm SOCs. The controller supports
  31. + SD/MMC/SDIO devices.
  32. +
  33. + If you have a controller with this interface, say Y or M here.
  34. +
  35. + If unsure, say N.
  36. +
  37. config MMC_MSM
  38. tristate "Qualcomm SDCC Controller Support"
  39. depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
  40. --- a/drivers/mmc/host/Makefile
  41. +++ b/drivers/mmc/host/Makefile
  42. @@ -65,6 +65,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhc
  43. obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
  44. obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
  45. obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
  46. +obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
  47. ifeq ($(CONFIG_CB710_DEBUG),y)
  48. CFLAGS-cb710-mmc += -DDEBUG
  49. --- /dev/null
  50. +++ b/drivers/mmc/host/sdhci-msm.c
  51. @@ -0,0 +1,208 @@
  52. +/*
  53. + * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
  54. + *
  55. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  56. + *
  57. + * This program is free software; you can redistribute it and/or modify
  58. + * it under the terms of the GNU General Public License version 2 and
  59. + * only version 2 as published by the Free Software Foundation.
  60. + *
  61. + * This program is distributed in the hope that it will be useful,
  62. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  63. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  64. + * GNU General Public License for more details.
  65. + *
  66. + */
  67. +
  68. +#include <linux/module.h>
  69. +#include <linux/of_device.h>
  70. +#include <linux/regulator/consumer.h>
  71. +#include <linux/delay.h>
  72. +
  73. +#include "sdhci-pltfm.h"
  74. +
  75. +#define CORE_HC_MODE 0x78
  76. +#define HC_MODE_EN 0x1
  77. +#define CORE_POWER 0x0
  78. +#define CORE_SW_RST BIT(7)
  79. +
  80. +
  81. +struct sdhci_msm_host {
  82. + struct platform_device *pdev;
  83. + void __iomem *core_mem; /* MSM SDCC mapped address */
  84. + struct clk *clk; /* main SD/MMC bus clock */
  85. + struct clk *pclk; /* SDHC peripheral bus clock */
  86. + struct clk *bus_clk; /* SDHC bus voter clock */
  87. + struct mmc_host *mmc;
  88. + struct sdhci_pltfm_data sdhci_msm_pdata;
  89. +};
  90. +
  91. +/* Platform specific tuning */
  92. +static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
  93. +{
  94. + /*
  95. + * Tuning is required for SDR104, HS200 and HS400 cards and if the clock
  96. + * frequency greater than 100MHz in those modes. The standard tuning
  97. + * procedure should not be executed, but a custom implementation will be
  98. + * added here instead.
  99. + */
  100. + return 0;
  101. +}
  102. +
  103. +static const struct of_device_id sdhci_msm_dt_match[] = {
  104. + { .compatible = "qcom,sdhci-msm-v4" },
  105. + {},
  106. +};
  107. +
  108. +MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
  109. +
  110. +static struct sdhci_ops sdhci_msm_ops = {
  111. + .platform_execute_tuning = sdhci_msm_execute_tuning,
  112. +};
  113. +
  114. +static int sdhci_msm_probe(struct platform_device *pdev)
  115. +{
  116. + struct sdhci_host *host;
  117. + struct sdhci_pltfm_host *pltfm_host;
  118. + struct sdhci_msm_host *msm_host;
  119. + struct resource *core_memres;
  120. + int ret;
  121. + u16 host_version;
  122. +
  123. + msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
  124. + if (!msm_host)
  125. + return -ENOMEM;
  126. +
  127. + msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
  128. + host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
  129. + if (IS_ERR(host))
  130. + return PTR_ERR(host);
  131. +
  132. + pltfm_host = sdhci_priv(host);
  133. + pltfm_host->priv = msm_host;
  134. + msm_host->mmc = host->mmc;
  135. + msm_host->pdev = pdev;
  136. +
  137. + ret = mmc_of_parse(host->mmc);
  138. + if (ret)
  139. + goto pltfm_free;
  140. +
  141. + sdhci_get_of_property(pdev);
  142. +
  143. + /* Setup SDCC bus voter clock. */
  144. + msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
  145. + if (!IS_ERR(msm_host->bus_clk)) {
  146. + /* Vote for max. clk rate for max. performance */
  147. + ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
  148. + if (ret)
  149. + goto pltfm_free;
  150. + ret = clk_prepare_enable(msm_host->bus_clk);
  151. + if (ret)
  152. + goto pltfm_free;
  153. + }
  154. +
  155. + /* Setup main peripheral bus clock */
  156. + msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
  157. + if (IS_ERR(msm_host->pclk)) {
  158. + ret = PTR_ERR(msm_host->pclk);
  159. + dev_err(&pdev->dev, "Perpheral clk setup failed (%d)\n", ret);
  160. + goto bus_clk_disable;
  161. + }
  162. +
  163. + ret = clk_prepare_enable(msm_host->pclk);
  164. + if (ret)
  165. + goto bus_clk_disable;
  166. +
  167. + /* Setup SDC MMC clock */
  168. + msm_host->clk = devm_clk_get(&pdev->dev, "core");
  169. + if (IS_ERR(msm_host->clk)) {
  170. + ret = PTR_ERR(msm_host->clk);
  171. + dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
  172. + goto pclk_disable;
  173. + }
  174. +
  175. + ret = clk_prepare_enable(msm_host->clk);
  176. + if (ret)
  177. + goto pclk_disable;
  178. +
  179. + core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  180. + msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
  181. +
  182. + if (IS_ERR(msm_host->core_mem)) {
  183. + dev_err(&pdev->dev, "Failed to remap registers\n");
  184. + ret = PTR_ERR(msm_host->core_mem);
  185. + goto clk_disable;
  186. + }
  187. +
  188. + /* Reset the core and Enable SDHC mode */
  189. + writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
  190. + CORE_SW_RST, msm_host->core_mem + CORE_POWER);
  191. +
  192. + /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
  193. + usleep_range(1000, 5000);
  194. + if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
  195. + dev_err(&pdev->dev, "Stuck in reset\n");
  196. + ret = -ETIMEDOUT;
  197. + goto clk_disable;
  198. + }
  199. +
  200. + /* Set HC_MODE_EN bit in HC_MODE register */
  201. + writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
  202. +
  203. + host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
  204. + host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
  205. +
  206. + host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
  207. + dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
  208. + host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
  209. + SDHCI_VENDOR_VER_SHIFT));
  210. +
  211. + ret = sdhci_add_host(host);
  212. + if (ret)
  213. + goto clk_disable;
  214. +
  215. + return 0;
  216. +
  217. +clk_disable:
  218. + clk_disable_unprepare(msm_host->clk);
  219. +pclk_disable:
  220. + clk_disable_unprepare(msm_host->pclk);
  221. +bus_clk_disable:
  222. + if (!IS_ERR(msm_host->bus_clk))
  223. + clk_disable_unprepare(msm_host->bus_clk);
  224. +pltfm_free:
  225. + sdhci_pltfm_free(pdev);
  226. + return ret;
  227. +}
  228. +
  229. +static int sdhci_msm_remove(struct platform_device *pdev)
  230. +{
  231. + struct sdhci_host *host = platform_get_drvdata(pdev);
  232. + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
  233. + struct sdhci_msm_host *msm_host = pltfm_host->priv;
  234. + int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
  235. + 0xffffffff);
  236. +
  237. + sdhci_remove_host(host, dead);
  238. + sdhci_pltfm_free(pdev);
  239. + clk_disable_unprepare(msm_host->clk);
  240. + clk_disable_unprepare(msm_host->pclk);
  241. + if (!IS_ERR(msm_host->bus_clk))
  242. + clk_disable_unprepare(msm_host->bus_clk);
  243. + return 0;
  244. +}
  245. +
  246. +static struct platform_driver sdhci_msm_driver = {
  247. + .probe = sdhci_msm_probe,
  248. + .remove = sdhci_msm_remove,
  249. + .driver = {
  250. + .name = "sdhci_msm",
  251. + .owner = THIS_MODULE,
  252. + .of_match_table = sdhci_msm_dt_match,
  253. + },
  254. +};
  255. +
  256. +module_platform_driver(sdhci_msm_driver);
  257. +
  258. +MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
  259. +MODULE_LICENSE("GPL v2");