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/mmc/card.h>
24 #include <linux/mmc/host.h>
25 #include <linux/mmc/slot-gpio.h>
26 #include <linux/gpio/consumer.h>
28 #include "sdhci-pltfm.h"
30 /* Tegra SDHOST controller vendor register definitions */
31 #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
32 #define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8
33 #define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10
34 #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
35 #define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200
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)
40 #define NVQUIRK_DISABLE_SDR50 BIT(3)
41 #define NVQUIRK_DISABLE_SDR104 BIT(4)
42 #define NVQUIRK_DISABLE_DDR50 BIT(5)
44 struct sdhci_tegra_soc_data
{
45 const struct sdhci_pltfm_data
*pdata
;
50 const struct sdhci_tegra_soc_data
*soc_data
;
51 struct gpio_desc
*power_gpio
;
54 static u16
tegra_sdhci_readw(struct sdhci_host
*host
, int reg
)
56 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
57 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
58 const struct sdhci_tegra_soc_data
*soc_data
= tegra_host
->soc_data
;
60 if (unlikely((soc_data
->nvquirks
& NVQUIRK_FORCE_SDHCI_SPEC_200
) &&
61 (reg
== SDHCI_HOST_VERSION
))) {
62 /* Erratum: Version register is invalid in HW. */
63 return SDHCI_SPEC_200
;
66 return readw(host
->ioaddr
+ reg
);
69 static void tegra_sdhci_writew(struct sdhci_host
*host
, u16 val
, int reg
)
71 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
74 case SDHCI_TRANSFER_MODE
:
76 * Postpone this write, we must do it together with a
77 * command write that is down below.
79 pltfm_host
->xfer_mode_shadow
= val
;
82 writel((val
<< 16) | pltfm_host
->xfer_mode_shadow
,
83 host
->ioaddr
+ SDHCI_TRANSFER_MODE
);
87 writew(val
, host
->ioaddr
+ reg
);
90 static void tegra_sdhci_writel(struct sdhci_host
*host
, u32 val
, int reg
)
92 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
93 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
94 const struct sdhci_tegra_soc_data
*soc_data
= tegra_host
->soc_data
;
96 /* Seems like we're getting spurious timeout and crc errors, so
97 * disable signalling of them. In case of real errors software
98 * timers should take care of eventually detecting them.
100 if (unlikely(reg
== SDHCI_SIGNAL_ENABLE
))
101 val
&= ~(SDHCI_INT_TIMEOUT
|SDHCI_INT_CRC
);
103 writel(val
, host
->ioaddr
+ reg
);
105 if (unlikely((soc_data
->nvquirks
& NVQUIRK_ENABLE_BLOCK_GAP_DET
) &&
106 (reg
== SDHCI_INT_ENABLE
))) {
107 /* Erratum: Must enable block gap interrupt detection */
108 u8 gap_ctrl
= readb(host
->ioaddr
+ SDHCI_BLOCK_GAP_CONTROL
);
109 if (val
& SDHCI_INT_CARD_INT
)
113 writeb(gap_ctrl
, host
->ioaddr
+ SDHCI_BLOCK_GAP_CONTROL
);
117 static unsigned int tegra_sdhci_get_ro(struct sdhci_host
*host
)
119 return mmc_gpio_get_ro(host
->mmc
);
122 static void tegra_sdhci_reset(struct sdhci_host
*host
, u8 mask
)
124 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
125 struct sdhci_tegra
*tegra_host
= pltfm_host
->priv
;
126 const struct sdhci_tegra_soc_data
*soc_data
= tegra_host
->soc_data
;
129 sdhci_reset(host
, mask
);
131 if (!(mask
& SDHCI_RESET_ALL
))
134 misc_ctrl
= sdhci_readw(host
, SDHCI_TEGRA_VENDOR_MISC_CTRL
);
135 /* Erratum: Enable SDHCI spec v3.00 support */
136 if (soc_data
->nvquirks
& NVQUIRK_ENABLE_SDHCI_SPEC_300
)
137 misc_ctrl
|= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300
;
138 /* Don't advertise UHS modes which aren't supported yet */
139 if (soc_data
->nvquirks
& NVQUIRK_DISABLE_SDR50
)
140 misc_ctrl
&= ~SDHCI_MISC_CTRL_ENABLE_SDR50
;
141 if (soc_data
->nvquirks
& NVQUIRK_DISABLE_DDR50
)
142 misc_ctrl
&= ~SDHCI_MISC_CTRL_ENABLE_DDR50
;
143 if (soc_data
->nvquirks
& NVQUIRK_DISABLE_SDR104
)
144 misc_ctrl
&= ~SDHCI_MISC_CTRL_ENABLE_SDR104
;
145 sdhci_writew(host
, misc_ctrl
, SDHCI_TEGRA_VENDOR_MISC_CTRL
);
148 static void tegra_sdhci_set_bus_width(struct sdhci_host
*host
, int bus_width
)
152 ctrl
= sdhci_readb(host
, SDHCI_HOST_CONTROL
);
153 if ((host
->mmc
->caps
& MMC_CAP_8_BIT_DATA
) &&
154 (bus_width
== MMC_BUS_WIDTH_8
)) {
155 ctrl
&= ~SDHCI_CTRL_4BITBUS
;
156 ctrl
|= SDHCI_CTRL_8BITBUS
;
158 ctrl
&= ~SDHCI_CTRL_8BITBUS
;
159 if (bus_width
== MMC_BUS_WIDTH_4
)
160 ctrl
|= SDHCI_CTRL_4BITBUS
;
162 ctrl
&= ~SDHCI_CTRL_4BITBUS
;
164 sdhci_writeb(host
, ctrl
, SDHCI_HOST_CONTROL
);
167 static const struct sdhci_ops tegra_sdhci_ops
= {
168 .get_ro
= tegra_sdhci_get_ro
,
169 .read_w
= tegra_sdhci_readw
,
170 .write_l
= tegra_sdhci_writel
,
171 .set_clock
= sdhci_set_clock
,
172 .set_bus_width
= tegra_sdhci_set_bus_width
,
173 .reset
= tegra_sdhci_reset
,
174 .set_uhs_signaling
= sdhci_set_uhs_signaling
,
175 .get_max_clock
= sdhci_pltfm_clk_get_max_clock
,
178 static const struct sdhci_pltfm_data sdhci_tegra20_pdata
= {
179 .quirks
= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
|
180 SDHCI_QUIRK_SINGLE_POWER_WRITE
|
181 SDHCI_QUIRK_NO_HISPD_BIT
|
182 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
|
183 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN
,
184 .ops
= &tegra_sdhci_ops
,
187 static struct sdhci_tegra_soc_data soc_data_tegra20
= {
188 .pdata
= &sdhci_tegra20_pdata
,
189 .nvquirks
= NVQUIRK_FORCE_SDHCI_SPEC_200
|
190 NVQUIRK_ENABLE_BLOCK_GAP_DET
,
193 static const struct sdhci_pltfm_data sdhci_tegra30_pdata
= {
194 .quirks
= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
|
195 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
|
196 SDHCI_QUIRK_SINGLE_POWER_WRITE
|
197 SDHCI_QUIRK_NO_HISPD_BIT
|
198 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
|
199 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN
,
200 .ops
= &tegra_sdhci_ops
,
203 static struct sdhci_tegra_soc_data soc_data_tegra30
= {
204 .pdata
= &sdhci_tegra30_pdata
,
205 .nvquirks
= NVQUIRK_ENABLE_SDHCI_SPEC_300
|
206 NVQUIRK_DISABLE_SDR50
|
207 NVQUIRK_DISABLE_SDR104
,
210 static const struct sdhci_ops tegra114_sdhci_ops
= {
211 .get_ro
= tegra_sdhci_get_ro
,
212 .read_w
= tegra_sdhci_readw
,
213 .write_w
= tegra_sdhci_writew
,
214 .write_l
= tegra_sdhci_writel
,
215 .set_clock
= sdhci_set_clock
,
216 .set_bus_width
= tegra_sdhci_set_bus_width
,
217 .reset
= tegra_sdhci_reset
,
218 .set_uhs_signaling
= sdhci_set_uhs_signaling
,
219 .get_max_clock
= sdhci_pltfm_clk_get_max_clock
,
222 static const struct sdhci_pltfm_data sdhci_tegra114_pdata
= {
223 .quirks
= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
|
224 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
|
225 SDHCI_QUIRK_SINGLE_POWER_WRITE
|
226 SDHCI_QUIRK_NO_HISPD_BIT
|
227 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
|
228 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN
,
229 .ops
= &tegra114_sdhci_ops
,
232 static struct sdhci_tegra_soc_data soc_data_tegra114
= {
233 .pdata
= &sdhci_tegra114_pdata
,
234 .nvquirks
= NVQUIRK_DISABLE_SDR50
|
235 NVQUIRK_DISABLE_DDR50
|
236 NVQUIRK_DISABLE_SDR104
,
239 static const struct of_device_id sdhci_tegra_dt_match
[] = {
240 { .compatible
= "nvidia,tegra124-sdhci", .data
= &soc_data_tegra114
},
241 { .compatible
= "nvidia,tegra114-sdhci", .data
= &soc_data_tegra114
},
242 { .compatible
= "nvidia,tegra30-sdhci", .data
= &soc_data_tegra30
},
243 { .compatible
= "nvidia,tegra20-sdhci", .data
= &soc_data_tegra20
},
246 MODULE_DEVICE_TABLE(of
, sdhci_tegra_dt_match
);
248 static int sdhci_tegra_probe(struct platform_device
*pdev
)
250 const struct of_device_id
*match
;
251 const struct sdhci_tegra_soc_data
*soc_data
;
252 struct sdhci_host
*host
;
253 struct sdhci_pltfm_host
*pltfm_host
;
254 struct sdhci_tegra
*tegra_host
;
258 match
= of_match_device(sdhci_tegra_dt_match
, &pdev
->dev
);
261 soc_data
= match
->data
;
263 host
= sdhci_pltfm_init(pdev
, soc_data
->pdata
, 0);
265 return PTR_ERR(host
);
266 pltfm_host
= sdhci_priv(host
);
268 tegra_host
= devm_kzalloc(&pdev
->dev
, sizeof(*tegra_host
), GFP_KERNEL
);
270 dev_err(mmc_dev(host
->mmc
), "failed to allocate tegra_host\n");
272 goto err_alloc_tegra_host
;
274 tegra_host
->soc_data
= soc_data
;
275 pltfm_host
->priv
= tegra_host
;
277 rc
= mmc_of_parse(host
->mmc
);
281 tegra_host
->power_gpio
= devm_gpiod_get_optional(&pdev
->dev
, "power",
283 if (IS_ERR(tegra_host
->power_gpio
)) {
284 rc
= PTR_ERR(tegra_host
->power_gpio
);
288 clk
= devm_clk_get(mmc_dev(host
->mmc
), NULL
);
290 dev_err(mmc_dev(host
->mmc
), "clk err\n");
294 clk_prepare_enable(clk
);
295 pltfm_host
->clk
= clk
;
297 rc
= sdhci_add_host(host
);
304 clk_disable_unprepare(pltfm_host
->clk
);
308 err_alloc_tegra_host
:
309 sdhci_pltfm_free(pdev
);
313 static struct platform_driver sdhci_tegra_driver
= {
315 .name
= "sdhci-tegra",
316 .of_match_table
= sdhci_tegra_dt_match
,
317 .pm
= SDHCI_PLTFM_PMOPS
,
319 .probe
= sdhci_tegra_probe
,
320 .remove
= sdhci_pltfm_unregister
,
323 module_platform_driver(sdhci_tegra_driver
);
325 MODULE_DESCRIPTION("SDHCI driver for Tegra");
326 MODULE_AUTHOR("Google, Inc.");
327 MODULE_LICENSE("GPL v2");