2 * Copyright (C) 2010 Google, Inc.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <linux/err.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/platform_device.h>
19 #include <linux/clk.h>
22 #include <linux/of_device.h>
23 #include <linux/of_gpio.h>
24 #include <linux/gpio.h>
25 #include <linux/mmc/card.h>
26 #include <linux/mmc/host.h>
27 #include <linux/mmc/slot-gpio.h>
31 #include "sdhci-pltfm.h"
33 /* Tegra SDHOST controller vendor register definitions */
34 #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
35 #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
37 #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
38 #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
39 #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
41 struct sdhci_tegra_soc_data
{
42 const struct sdhci_pltfm_data
*pdata
;
47 const struct sdhci_tegra_soc_data
*soc_data
;
51 static u32
tegra_sdhci_readl(struct sdhci_host
*host
, int reg
)
55 if (unlikely(reg
== SDHCI_PRESENT_STATE
)) {
56 /* Use wp_gpio here instead? */
57 val
= readl(host
->ioaddr
+ reg
);
58 return val
| SDHCI_WRITE_PROTECT
;
61 return readl(host
->ioaddr
+ reg
);
64 static u16
tegra_sdhci_readw(struct sdhci_host
*host
, int reg
)
66 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
67 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
68 const struct sdhci_tegra_soc_data
*soc_data
= tegra_host
->soc_data
;
70 if (unlikely((soc_data
->nvquirks
& NVQUIRK_FORCE_SDHCI_SPEC_200
) &&
71 (reg
== SDHCI_HOST_VERSION
))) {
72 /* Erratum: Version register is invalid in HW. */
73 return SDHCI_SPEC_200
;
76 return readw(host
->ioaddr
+ reg
);
79 static void tegra_sdhci_writel(struct sdhci_host
*host
, u32 val
, int reg
)
81 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
82 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
83 const struct sdhci_tegra_soc_data
*soc_data
= tegra_host
->soc_data
;
85 /* Seems like we're getting spurious timeout and crc errors, so
86 * disable signalling of them. In case of real errors software
87 * timers should take care of eventually detecting them.
89 if (unlikely(reg
== SDHCI_SIGNAL_ENABLE
))
90 val
&= ~(SDHCI_INT_TIMEOUT
|SDHCI_INT_CRC
);
92 writel(val
, host
->ioaddr
+ reg
);
94 if (unlikely((soc_data
->nvquirks
& NVQUIRK_ENABLE_BLOCK_GAP_DET
) &&
95 (reg
== SDHCI_INT_ENABLE
))) {
96 /* Erratum: Must enable block gap interrupt detection */
97 u8 gap_ctrl
= readb(host
->ioaddr
+ SDHCI_BLOCK_GAP_CONTROL
);
98 if (val
& SDHCI_INT_CARD_INT
)
102 writeb(gap_ctrl
, host
->ioaddr
+ SDHCI_BLOCK_GAP_CONTROL
);
106 static unsigned int tegra_sdhci_get_ro(struct sdhci_host
*host
)
108 return mmc_gpio_get_ro(host
->mmc
);
111 static void tegra_sdhci_reset_exit(struct sdhci_host
*host
, u8 mask
)
113 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
114 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
115 const struct sdhci_tegra_soc_data
*soc_data
= tegra_host
->soc_data
;
117 if (!(mask
& SDHCI_RESET_ALL
))
120 /* Erratum: Enable SDHCI spec v3.00 support */
121 if (soc_data
->nvquirks
& NVQUIRK_ENABLE_SDHCI_SPEC_300
) {
124 misc_ctrl
= sdhci_readb(host
, SDHCI_TEGRA_VENDOR_MISC_CTRL
);
125 misc_ctrl
|= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300
;
126 sdhci_writeb(host
, misc_ctrl
, SDHCI_TEGRA_VENDOR_MISC_CTRL
);
130 static int tegra_sdhci_buswidth(struct sdhci_host
*host
, int bus_width
)
134 ctrl
= sdhci_readb(host
, SDHCI_HOST_CONTROL
);
135 if ((host
->mmc
->caps
& MMC_CAP_8_BIT_DATA
) &&
136 (bus_width
== MMC_BUS_WIDTH_8
)) {
137 ctrl
&= ~SDHCI_CTRL_4BITBUS
;
138 ctrl
|= SDHCI_CTRL_8BITBUS
;
140 ctrl
&= ~SDHCI_CTRL_8BITBUS
;
141 if (bus_width
== MMC_BUS_WIDTH_4
)
142 ctrl
|= SDHCI_CTRL_4BITBUS
;
144 ctrl
&= ~SDHCI_CTRL_4BITBUS
;
146 sdhci_writeb(host
, ctrl
, SDHCI_HOST_CONTROL
);
150 static const struct sdhci_ops tegra_sdhci_ops
= {
151 .get_ro
= tegra_sdhci_get_ro
,
152 .read_l
= tegra_sdhci_readl
,
153 .read_w
= tegra_sdhci_readw
,
154 .write_l
= tegra_sdhci_writel
,
155 .platform_bus_width
= tegra_sdhci_buswidth
,
156 .platform_reset_exit
= tegra_sdhci_reset_exit
,
159 static const struct sdhci_pltfm_data sdhci_tegra20_pdata
= {
160 .quirks
= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
|
161 SDHCI_QUIRK_SINGLE_POWER_WRITE
|
162 SDHCI_QUIRK_NO_HISPD_BIT
|
163 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
,
164 .ops
= &tegra_sdhci_ops
,
167 static struct sdhci_tegra_soc_data soc_data_tegra20
= {
168 .pdata
= &sdhci_tegra20_pdata
,
169 .nvquirks
= NVQUIRK_FORCE_SDHCI_SPEC_200
|
170 NVQUIRK_ENABLE_BLOCK_GAP_DET
,
173 static const struct sdhci_pltfm_data sdhci_tegra30_pdata
= {
174 .quirks
= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
|
175 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
|
176 SDHCI_QUIRK_SINGLE_POWER_WRITE
|
177 SDHCI_QUIRK_NO_HISPD_BIT
|
178 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
,
179 .ops
= &tegra_sdhci_ops
,
182 static struct sdhci_tegra_soc_data soc_data_tegra30
= {
183 .pdata
= &sdhci_tegra30_pdata
,
184 .nvquirks
= NVQUIRK_ENABLE_SDHCI_SPEC_300
,
187 static const struct sdhci_pltfm_data sdhci_tegra114_pdata
= {
188 .quirks
= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
|
189 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
|
190 SDHCI_QUIRK_SINGLE_POWER_WRITE
|
191 SDHCI_QUIRK_NO_HISPD_BIT
|
192 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
,
193 .ops
= &tegra_sdhci_ops
,
196 static struct sdhci_tegra_soc_data soc_data_tegra114
= {
197 .pdata
= &sdhci_tegra114_pdata
,
200 static const struct of_device_id sdhci_tegra_dt_match
[] = {
201 { .compatible
= "nvidia,tegra114-sdhci", .data
= &soc_data_tegra114
},
202 { .compatible
= "nvidia,tegra30-sdhci", .data
= &soc_data_tegra30
},
203 { .compatible
= "nvidia,tegra20-sdhci", .data
= &soc_data_tegra20
},
206 MODULE_DEVICE_TABLE(of
, sdhci_tegra_dt_match
);
208 static int sdhci_tegra_parse_dt(struct device
*dev
)
210 struct device_node
*np
= dev
->of_node
;
211 struct sdhci_host
*host
= dev_get_drvdata(dev
);
212 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
213 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
215 tegra_host
->power_gpio
= of_get_named_gpio(np
, "power-gpios", 0);
216 return mmc_of_parse(host
->mmc
);
219 static int sdhci_tegra_probe(struct platform_device
*pdev
)
221 const struct of_device_id
*match
;
222 const struct sdhci_tegra_soc_data
*soc_data
;
223 struct sdhci_host
*host
;
224 struct sdhci_pltfm_host
*pltfm_host
;
225 struct sdhci_tegra
*tegra_host
;
229 match
= of_match_device(sdhci_tegra_dt_match
, &pdev
->dev
);
232 soc_data
= match
->data
;
234 host
= sdhci_pltfm_init(pdev
, soc_data
->pdata
, 0);
236 return PTR_ERR(host
);
237 pltfm_host
= sdhci_priv(host
);
239 tegra_host
= devm_kzalloc(&pdev
->dev
, sizeof(*tegra_host
), GFP_KERNEL
);
241 dev_err(mmc_dev(host
->mmc
), "failed to allocate tegra_host\n");
243 goto err_alloc_tegra_host
;
245 tegra_host
->soc_data
= soc_data
;
246 pltfm_host
->priv
= tegra_host
;
248 rc
= sdhci_tegra_parse_dt(&pdev
->dev
);
252 if (gpio_is_valid(tegra_host
->power_gpio
)) {
253 rc
= gpio_request(tegra_host
->power_gpio
, "sdhci_power");
255 dev_err(mmc_dev(host
->mmc
),
256 "failed to allocate power gpio\n");
259 gpio_direction_output(tegra_host
->power_gpio
, 1);
262 clk
= clk_get(mmc_dev(host
->mmc
), NULL
);
264 dev_err(mmc_dev(host
->mmc
), "clk err\n");
268 clk_prepare_enable(clk
);
269 pltfm_host
->clk
= clk
;
271 rc
= sdhci_add_host(host
);
278 clk_disable_unprepare(pltfm_host
->clk
);
279 clk_put(pltfm_host
->clk
);
281 if (gpio_is_valid(tegra_host
->power_gpio
))
282 gpio_free(tegra_host
->power_gpio
);
285 err_alloc_tegra_host
:
286 sdhci_pltfm_free(pdev
);
290 static int sdhci_tegra_remove(struct platform_device
*pdev
)
292 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
293 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
294 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
295 int dead
= (readl(host
->ioaddr
+ SDHCI_INT_STATUS
) == 0xffffffff);
297 sdhci_remove_host(host
, dead
);
299 if (gpio_is_valid(tegra_host
->power_gpio
))
300 gpio_free(tegra_host
->power_gpio
);
302 clk_disable_unprepare(pltfm_host
->clk
);
303 clk_put(pltfm_host
->clk
);
305 sdhci_pltfm_free(pdev
);
310 static struct platform_driver sdhci_tegra_driver
= {
312 .name
= "sdhci-tegra",
313 .owner
= THIS_MODULE
,
314 .of_match_table
= sdhci_tegra_dt_match
,
315 .pm
= SDHCI_PLTFM_PMOPS
,
317 .probe
= sdhci_tegra_probe
,
318 .remove
= sdhci_tegra_remove
,
321 module_platform_driver(sdhci_tegra_driver
);
323 MODULE_DESCRIPTION("SDHCI driver for Tegra");
324 MODULE_AUTHOR("Google, Inc.");
325 MODULE_LICENSE("GPL v2");