aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Griffin <peter.griffin@linaro.org>2014-07-09 11:07:32 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2014-07-10 03:11:18 -0400
commitf52d9c4f459bdab128b1b033f26fb52d3418e0f5 (patch)
treec5eeab6b193aefbcdf196693f785661eb398da49
parentbf7978483c0c119e0d650710ee713f0ed95939ca (diff)
mmc: sdhci-st: Intial support for ST SDHCI controller
This platform driver adds initial support for the SDHCI host controller found on STMicroelectronics SoCs. It has been tested on STiH41x b2020 platforms currently. Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: Peter Griffin <peter.griffin@linaro.org> Acked-by: Lee Jones <lee.jones@linaro.org> Acked-by: Maxime Coquelin <maxime.coquelin@st.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/host/Kconfig12
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/sdhci-st.c176
3 files changed, 189 insertions, 0 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9682ad1e94b5..d95e75d915d4 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -290,6 +290,18 @@ config MMC_MOXART
290 be found on some embedded hardware such as UC-7112-LX. 290 be found on some embedded hardware such as UC-7112-LX.
291 If you have a controller with this interface, say Y here. 291 If you have a controller with this interface, say Y here.
292 292
293config MMC_SDHCI_ST
294 tristate "SDHCI support on STMicroelectronics SoC"
295 depends on ARCH_STI
296 depends on MMC_SDHCI_PLTFM
297 select MMC_SDHCI_IO_ACCESSORS
298 help
299 This selects the Secure Digital Host Controller Interface in
300 STMicroelectronics SoCs.
301
302 If you have a controller with this interface, say Y or M here.
303 If unsure, say N.
304
293config MMC_OMAP 305config MMC_OMAP
294 tristate "TI OMAP Multimedia Card Interface support" 306 tristate "TI OMAP Multimedia Card Interface support"
295 depends on ARCH_OMAP 307 depends on ARCH_OMAP
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 7f81ddf1dd2c..f211eede8db5 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
68obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o 68obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
69obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o 69obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
70obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o 70obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
71obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
71 72
72ifeq ($(CONFIG_CB710_DEBUG),y) 73ifeq ($(CONFIG_CB710_DEBUG),y)
73 CFLAGS-cb710-mmc += -DDEBUG 74 CFLAGS-cb710-mmc += -DDEBUG
diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c
new file mode 100644
index 000000000000..328f348c7243
--- /dev/null
+++ b/drivers/mmc/host/sdhci-st.c
@@ -0,0 +1,176 @@
1/*
2 * Support for SDHCI on STMicroelectronics SoCs
3 *
4 * Copyright (C) 2014 STMicroelectronics Ltd
5 * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
6 * Contributors: Peter Griffin <peter.griffin@linaro.org>
7 *
8 * Based on sdhci-cns3xxx.c
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 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 */
20
21#include <linux/io.h>
22#include <linux/of.h>
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/mmc/host.h>
26
27#include "sdhci-pltfm.h"
28
29static u32 sdhci_st_readl(struct sdhci_host *host, int reg)
30{
31 u32 ret;
32
33 switch (reg) {
34 case SDHCI_CAPABILITIES:
35 ret = readl_relaxed(host->ioaddr + reg);
36 /* Support 3.3V and 1.8V */
37 ret &= ~SDHCI_CAN_VDD_300;
38 break;
39 default:
40 ret = readl_relaxed(host->ioaddr + reg);
41 }
42 return ret;
43}
44
45static const struct sdhci_ops sdhci_st_ops = {
46 .get_max_clock = sdhci_pltfm_clk_get_max_clock,
47 .set_clock = sdhci_set_clock,
48 .set_bus_width = sdhci_set_bus_width,
49 .read_l = sdhci_st_readl,
50 .reset = sdhci_reset,
51};
52
53static const struct sdhci_pltfm_data sdhci_st_pdata = {
54 .ops = &sdhci_st_ops,
55 .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
56 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
57};
58
59
60static int sdhci_st_probe(struct platform_device *pdev)
61{
62 struct sdhci_host *host;
63 struct sdhci_pltfm_host *pltfm_host;
64 struct clk *clk;
65 int ret = 0;
66 u16 host_version;
67
68 clk = devm_clk_get(&pdev->dev, "mmc");
69 if (IS_ERR(clk)) {
70 dev_err(&pdev->dev, "Peripheral clk not found\n");
71 return PTR_ERR(clk);
72 }
73
74 host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0);
75 if (IS_ERR(host)) {
76 dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n");
77 return PTR_ERR(host);
78 }
79
80 ret = mmc_of_parse(host->mmc);
81
82 if (ret) {
83 dev_err(&pdev->dev, "Failed mmc_of_parse\n");
84 return ret;
85 }
86
87 clk_prepare_enable(clk);
88
89 pltfm_host = sdhci_priv(host);
90 pltfm_host->clk = clk;
91
92 ret = sdhci_add_host(host);
93 if (ret) {
94 dev_err(&pdev->dev, "Failed sdhci_add_host\n");
95 goto err_out;
96 }
97
98 platform_set_drvdata(pdev, host);
99
100 host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
101
102 dev_info(&pdev->dev, "SDHCI ST Initialised: Host Version: 0x%x Vendor Version 0x%x\n",
103 ((host_version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT),
104 ((host_version & SDHCI_VENDOR_VER_MASK) >>
105 SDHCI_VENDOR_VER_SHIFT));
106
107 return 0;
108
109err_out:
110 clk_disable_unprepare(clk);
111 sdhci_pltfm_free(pdev);
112
113 return ret;
114}
115
116static int sdhci_st_remove(struct platform_device *pdev)
117{
118 struct sdhci_host *host = platform_get_drvdata(pdev);
119 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
120
121 clk_disable_unprepare(pltfm_host->clk);
122
123 return sdhci_pltfm_unregister(pdev);
124}
125
126#ifdef CONFIG_PM_SLEEP
127static int sdhci_st_suspend(struct device *dev)
128{
129 struct sdhci_host *host = dev_get_drvdata(dev);
130 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
131 int ret = sdhci_suspend_host(host);
132
133 if (ret)
134 goto out;
135
136 clk_disable_unprepare(pltfm_host->clk);
137out:
138 return ret;
139}
140
141static int sdhci_st_resume(struct device *dev)
142{
143 struct sdhci_host *host = dev_get_drvdata(dev);
144 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
145
146 clk_prepare_enable(pltfm_host->clk);
147
148 return sdhci_resume_host(host);
149}
150#endif
151
152static SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume);
153
154static const struct of_device_id st_sdhci_match[] = {
155 { .compatible = "st,sdhci" },
156 {},
157};
158
159MODULE_DEVICE_TABLE(of, st_sdhci_match);
160
161static struct platform_driver sdhci_st_driver = {
162 .probe = sdhci_st_probe,
163 .remove = sdhci_st_remove,
164 .driver = {
165 .name = "sdhci-st",
166 .pm = &sdhci_st_pmops,
167 .of_match_table = of_match_ptr(st_sdhci_match),
168 },
169};
170
171module_platform_driver(sdhci_st_driver);
172
173MODULE_DESCRIPTION("SDHCI driver for STMicroelectronics SoCs");
174MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
175MODULE_LICENSE("GPL v2");
176MODULE_ALIAS("platform:st-sdhci");