blob: 43314094699f47b54e936e08037e7aed302ed604 [file] [log] [blame]
Barry Songb3b665b2013-03-21 16:27:19 +08001/*
2 * SDHCI support for SiRF primaII and marco SoCs
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/delay.h>
10#include <linux/device.h>
11#include <linux/mmc/host.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/of_gpio.h>
15#include <linux/mmc/slot-gpio.h>
Barry Songb3b665b2013-03-21 16:27:19 +080016#include "sdhci-pltfm.h"
17
Minda Chenfc0b6382014-12-04 20:09:20 +080018#define SDHCI_CLK_DELAY_SETTING 0x4C
Minda Chen1ba4c322014-08-26 10:50:42 +080019#define SDHCI_SIRF_8BITBUS BIT(3)
Minda Chenfc0b6382014-12-04 20:09:20 +080020#define SIRF_TUNING_COUNT 128
Minda Chen1ba4c322014-08-26 10:50:42 +080021
Barry Songb3b665b2013-03-21 16:27:19 +080022struct sdhci_sirf_priv {
23 struct clk *clk;
24 int gpio_cd;
25};
26
27static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
28{
29 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -040030 struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
Barry Songb3b665b2013-03-21 16:27:19 +080031 return clk_get_rate(priv->clk);
32}
33
Minda Chen1ba4c322014-08-26 10:50:42 +080034static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
35{
36 u8 ctrl;
37
38 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
39 ctrl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_SIRF_8BITBUS);
40
41 /*
42 * CSR atlas7 and prima2 SD host version is not 3.0
43 * 8bit-width enable bit of CSR SD hosts is 3,
44 * while stardard hosts use bit 5
45 */
46 if (width == MMC_BUS_WIDTH_8)
47 ctrl |= SDHCI_SIRF_8BITBUS;
48 else if (width == MMC_BUS_WIDTH_4)
49 ctrl |= SDHCI_CTRL_4BITBUS;
50
51 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
52}
53
Minda Chenfc0b6382014-12-04 20:09:20 +080054static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
55{
56 int tuning_seq_cnt = 3;
57 u8 phase, tuned_phases[SIRF_TUNING_COUNT];
58 u8 tuned_phase_cnt = 0;
weijun yangb36ac1b2015-02-15 23:43:51 +080059 int rc = 0, longest_range = 0;
Minda Chenfc0b6382014-12-04 20:09:20 +080060 int start = -1, end = 0, tuning_value = -1, range = 0;
61 u16 clock_setting;
62 struct mmc_host *mmc = host->mmc;
63
64 clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING);
65 clock_setting &= ~0x3fff;
66
67retry:
68 phase = 0;
69 do {
70 sdhci_writel(host,
weijun yangb36ac1b2015-02-15 23:43:51 +080071 clock_setting | phase,
Minda Chenfc0b6382014-12-04 20:09:20 +080072 SDHCI_CLK_DELAY_SETTING);
73
74 if (!mmc_send_tuning(mmc)) {
75 /* Tuning is successful at this tuning point */
76 tuned_phases[tuned_phase_cnt++] = phase;
77 dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
78 mmc_hostname(mmc), phase);
79 if (start == -1)
80 start = phase;
81 end = phase;
82 range++;
83 if (phase == (SIRF_TUNING_COUNT - 1)
84 && range > longest_range)
85 tuning_value = (start + end) / 2;
86 } else {
87 dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n",
88 mmc_hostname(mmc), phase);
89 if (range > longest_range) {
90 tuning_value = (start + end) / 2;
91 longest_range = range;
92 }
93 start = -1;
94 end = range = 0;
95 }
96 } while (++phase < ARRAY_SIZE(tuned_phases));
97
98 if (tuned_phase_cnt && tuning_value > 0) {
99 /*
100 * Finally set the selected phase in delay
101 * line hw block.
102 */
103 phase = tuning_value;
104 sdhci_writel(host,
weijun yangb36ac1b2015-02-15 23:43:51 +0800105 clock_setting | phase,
Minda Chenfc0b6382014-12-04 20:09:20 +0800106 SDHCI_CLK_DELAY_SETTING);
107
108 dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
109 mmc_hostname(mmc), phase);
110 } else {
111 if (--tuning_seq_cnt)
112 goto retry;
113 /* Tuning failed */
114 dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
115 mmc_hostname(mmc));
116 rc = -EIO;
117 }
118
119 return rc;
120}
121
Barry Songb3b665b2013-03-21 16:27:19 +0800122static struct sdhci_ops sdhci_sirf_ops = {
Minda Chenfc0b6382014-12-04 20:09:20 +0800123 .platform_execute_tuning = sdhci_sirf_execute_tuning,
Russell King17710592014-04-25 12:58:55 +0100124 .set_clock = sdhci_set_clock,
Barry Songb3b665b2013-03-21 16:27:19 +0800125 .get_max_clock = sdhci_sirf_get_max_clk,
Minda Chen1ba4c322014-08-26 10:50:42 +0800126 .set_bus_width = sdhci_sirf_set_bus_width,
Russell King03231f92014-04-25 12:57:12 +0100127 .reset = sdhci_reset,
Russell King96d7b782014-04-25 12:59:26 +0100128 .set_uhs_signaling = sdhci_set_uhs_signaling,
Barry Songb3b665b2013-03-21 16:27:19 +0800129};
130
131static struct sdhci_pltfm_data sdhci_sirf_pdata = {
132 .ops = &sdhci_sirf_ops,
133 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
134 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
135 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
136 SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
137 SDHCI_QUIRK_DELAY_AFTER_POWER,
138};
139
140static int sdhci_sirf_probe(struct platform_device *pdev)
141{
142 struct sdhci_host *host;
143 struct sdhci_pltfm_host *pltfm_host;
144 struct sdhci_sirf_priv *priv;
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400145 struct clk *clk;
146 int gpio_cd;
Barry Songb3b665b2013-03-21 16:27:19 +0800147 int ret;
148
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400149 clk = devm_clk_get(&pdev->dev, NULL);
150 if (IS_ERR(clk)) {
Barry Songb3b665b2013-03-21 16:27:19 +0800151 dev_err(&pdev->dev, "unable to get clock");
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400152 return PTR_ERR(clk);
Barry Songb3b665b2013-03-21 16:27:19 +0800153 }
154
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400155 if (pdev->dev.of_node)
156 gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
157 else
158 gpio_cd = -EINVAL;
Barry Songb3b665b2013-03-21 16:27:19 +0800159
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400160 host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
161 if (IS_ERR(host))
162 return PTR_ERR(host);
Barry Songb3b665b2013-03-21 16:27:19 +0800163
164 pltfm_host = sdhci_priv(host);
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400165 priv = sdhci_pltfm_priv(pltfm_host);
166 priv->clk = clk;
167 priv->gpio_cd = gpio_cd;
Barry Songb3b665b2013-03-21 16:27:19 +0800168
169 sdhci_get_of_property(pdev);
170
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400171 ret = clk_prepare_enable(priv->clk);
172 if (ret)
173 goto err_clk_prepare;
Barry Songb3b665b2013-03-21 16:27:19 +0800174
175 ret = sdhci_add_host(host);
176 if (ret)
177 goto err_sdhci_add;
178
179 /*
180 * We must request the IRQ after sdhci_add_host(), as the tasklet only
181 * gets setup in sdhci_add_host() and we oops.
182 */
183 if (gpio_is_valid(priv->gpio_cd)) {
Laurent Pinchart214fc302013-08-08 12:38:31 +0200184 ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0);
Barry Songb3b665b2013-03-21 16:27:19 +0800185 if (ret) {
186 dev_err(&pdev->dev, "card detect irq request failed: %d\n",
187 ret);
188 goto err_request_cd;
189 }
Stephen Warrend4d11442014-09-22 09:57:42 -0600190 mmc_gpiod_request_cd_irq(host->mmc);
Barry Songb3b665b2013-03-21 16:27:19 +0800191 }
192
193 return 0;
194
195err_request_cd:
196 sdhci_remove_host(host, 0);
197err_sdhci_add:
198 clk_disable_unprepare(priv->clk);
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400199err_clk_prepare:
Barry Songb3b665b2013-03-21 16:27:19 +0800200 sdhci_pltfm_free(pdev);
Barry Songb3b665b2013-03-21 16:27:19 +0800201 return ret;
202}
203
204static int sdhci_sirf_remove(struct platform_device *pdev)
205{
206 struct sdhci_host *host = platform_get_drvdata(pdev);
207 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400208 struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
Barry Songb3b665b2013-03-21 16:27:19 +0800209
210 sdhci_pltfm_unregister(pdev);
211
Barry Songb3b665b2013-03-21 16:27:19 +0800212 clk_disable_unprepare(priv->clk);
213 return 0;
214}
215
216#ifdef CONFIG_PM_SLEEP
217static int sdhci_sirf_suspend(struct device *dev)
218{
219 struct sdhci_host *host = dev_get_drvdata(dev);
220 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400221 struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
Barry Songb3b665b2013-03-21 16:27:19 +0800222 int ret;
223
224 ret = sdhci_suspend_host(host);
225 if (ret)
226 return ret;
227
228 clk_disable(priv->clk);
229
230 return 0;
231}
232
233static int sdhci_sirf_resume(struct device *dev)
234{
235 struct sdhci_host *host = dev_get_drvdata(dev);
236 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
Arnd Bergmanne2f6aac2013-06-27 11:17:25 -0400237 struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
Barry Songb3b665b2013-03-21 16:27:19 +0800238 int ret;
239
240 ret = clk_enable(priv->clk);
241 if (ret) {
242 dev_dbg(dev, "Resume: Error enabling clock\n");
243 return ret;
244 }
245
246 return sdhci_resume_host(host);
247}
248
249static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
250#endif
251
252static const struct of_device_id sdhci_sirf_of_match[] = {
253 { .compatible = "sirf,prima2-sdhc" },
254 { }
255};
256MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
257
258static struct platform_driver sdhci_sirf_driver = {
259 .driver = {
260 .name = "sdhci-sirf",
Barry Songb3b665b2013-03-21 16:27:19 +0800261 .of_match_table = sdhci_sirf_of_match,
262#ifdef CONFIG_PM_SLEEP
263 .pm = &sdhci_sirf_pm_ops,
264#endif
265 },
266 .probe = sdhci_sirf_probe,
267 .remove = sdhci_sirf_remove,
268};
269
270module_platform_driver(sdhci_sirf_driver);
271
272MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco");
273MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
274MODULE_LICENSE("GPL v2");