aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci-tegra.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci-tegra.c')
-rw-r--r--drivers/mmc/host/sdhci-tegra.c105
1 files changed, 36 insertions, 69 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index f3778d58d1cd..ad28b49f0203 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -20,11 +20,10 @@
20#include <linux/io.h> 20#include <linux/io.h>
21#include <linux/of.h> 21#include <linux/of.h>
22#include <linux/of_device.h> 22#include <linux/of_device.h>
23#include <linux/of_gpio.h>
24#include <linux/gpio.h>
25#include <linux/mmc/card.h> 23#include <linux/mmc/card.h>
26#include <linux/mmc/host.h> 24#include <linux/mmc/host.h>
27#include <linux/mmc/slot-gpio.h> 25#include <linux/mmc/slot-gpio.h>
26#include <linux/gpio/consumer.h>
28 27
29#include "sdhci-pltfm.h" 28#include "sdhci-pltfm.h"
30 29
@@ -41,7 +40,6 @@
41#define NVQUIRK_DISABLE_SDR50 BIT(3) 40#define NVQUIRK_DISABLE_SDR50 BIT(3)
42#define NVQUIRK_DISABLE_SDR104 BIT(4) 41#define NVQUIRK_DISABLE_SDR104 BIT(4)
43#define NVQUIRK_DISABLE_DDR50 BIT(5) 42#define NVQUIRK_DISABLE_DDR50 BIT(5)
44#define NVQUIRK_SHADOW_XFER_MODE_REG BIT(6)
45 43
46struct sdhci_tegra_soc_data { 44struct sdhci_tegra_soc_data {
47 const struct sdhci_pltfm_data *pdata; 45 const struct sdhci_pltfm_data *pdata;
@@ -50,7 +48,7 @@ struct sdhci_tegra_soc_data {
50 48
51struct sdhci_tegra { 49struct sdhci_tegra {
52 const struct sdhci_tegra_soc_data *soc_data; 50 const struct sdhci_tegra_soc_data *soc_data;
53 int power_gpio; 51 struct gpio_desc *power_gpio;
54}; 52};
55 53
56static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) 54static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@@ -71,23 +69,19 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
71static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg) 69static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
72{ 70{
73 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 71 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
74 struct sdhci_tegra *tegra_host = pltfm_host->priv;
75 const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
76 72
77 if (soc_data->nvquirks & NVQUIRK_SHADOW_XFER_MODE_REG) { 73 switch (reg) {
78 switch (reg) { 74 case SDHCI_TRANSFER_MODE:
79 case SDHCI_TRANSFER_MODE: 75 /*
80 /* 76 * Postpone this write, we must do it together with a
81 * Postpone this write, we must do it together with a 77 * command write that is down below.
82 * command write that is down below. 78 */
83 */ 79 pltfm_host->xfer_mode_shadow = val;
84 pltfm_host->xfer_mode_shadow = val; 80 return;
85 return; 81 case SDHCI_COMMAND:
86 case SDHCI_COMMAND: 82 writel((val << 16) | pltfm_host->xfer_mode_shadow,
87 writel((val << 16) | pltfm_host->xfer_mode_shadow, 83 host->ioaddr + SDHCI_TRANSFER_MODE);
88 host->ioaddr + SDHCI_TRANSFER_MODE); 84 return;
89 return;
90 }
91 } 85 }
92 86
93 writew(val, host->ioaddr + reg); 87 writew(val, host->ioaddr + reg);
@@ -173,7 +167,6 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
173static const struct sdhci_ops tegra_sdhci_ops = { 167static const struct sdhci_ops tegra_sdhci_ops = {
174 .get_ro = tegra_sdhci_get_ro, 168 .get_ro = tegra_sdhci_get_ro,
175 .read_w = tegra_sdhci_readw, 169 .read_w = tegra_sdhci_readw,
176 .write_w = tegra_sdhci_writew,
177 .write_l = tegra_sdhci_writel, 170 .write_l = tegra_sdhci_writel,
178 .set_clock = sdhci_set_clock, 171 .set_clock = sdhci_set_clock,
179 .set_bus_width = tegra_sdhci_set_bus_width, 172 .set_bus_width = tegra_sdhci_set_bus_width,
@@ -214,6 +207,18 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = {
214 NVQUIRK_DISABLE_SDR104, 207 NVQUIRK_DISABLE_SDR104,
215}; 208};
216 209
210static 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,
220};
221
217static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { 222static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
218 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 223 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
219 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 224 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
@@ -221,15 +226,14 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
221 SDHCI_QUIRK_NO_HISPD_BIT | 226 SDHCI_QUIRK_NO_HISPD_BIT |
222 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 227 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
223 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 228 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
224 .ops = &tegra_sdhci_ops, 229 .ops = &tegra114_sdhci_ops,
225}; 230};
226 231
227static struct sdhci_tegra_soc_data soc_data_tegra114 = { 232static struct sdhci_tegra_soc_data soc_data_tegra114 = {
228 .pdata = &sdhci_tegra114_pdata, 233 .pdata = &sdhci_tegra114_pdata,
229 .nvquirks = NVQUIRK_DISABLE_SDR50 | 234 .nvquirks = NVQUIRK_DISABLE_SDR50 |
230 NVQUIRK_DISABLE_DDR50 | 235 NVQUIRK_DISABLE_DDR50 |
231 NVQUIRK_DISABLE_SDR104 | 236 NVQUIRK_DISABLE_SDR104,
232 NVQUIRK_SHADOW_XFER_MODE_REG,
233}; 237};
234 238
235static const struct of_device_id sdhci_tegra_dt_match[] = { 239static const struct of_device_id sdhci_tegra_dt_match[] = {
@@ -241,17 +245,6 @@ static const struct of_device_id sdhci_tegra_dt_match[] = {
241}; 245};
242MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); 246MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match);
243 247
244static int sdhci_tegra_parse_dt(struct device *dev)
245{
246 struct device_node *np = dev->of_node;
247 struct sdhci_host *host = dev_get_drvdata(dev);
248 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
249 struct sdhci_tegra *tegra_host = pltfm_host->priv;
250
251 tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
252 return mmc_of_parse(host->mmc);
253}
254
255static int sdhci_tegra_probe(struct platform_device *pdev) 248static int sdhci_tegra_probe(struct platform_device *pdev)
256{ 249{
257 const struct of_device_id *match; 250 const struct of_device_id *match;
@@ -281,21 +274,18 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
281 tegra_host->soc_data = soc_data; 274 tegra_host->soc_data = soc_data;
282 pltfm_host->priv = tegra_host; 275 pltfm_host->priv = tegra_host;
283 276
284 rc = sdhci_tegra_parse_dt(&pdev->dev); 277 rc = mmc_of_parse(host->mmc);
285 if (rc) 278 if (rc)
286 goto err_parse_dt; 279 goto err_parse_dt;
287 280
288 if (gpio_is_valid(tegra_host->power_gpio)) { 281 tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
289 rc = gpio_request(tegra_host->power_gpio, "sdhci_power"); 282 GPIOD_OUT_HIGH);
290 if (rc) { 283 if (IS_ERR(tegra_host->power_gpio)) {
291 dev_err(mmc_dev(host->mmc), 284 rc = PTR_ERR(tegra_host->power_gpio);
292 "failed to allocate power gpio\n"); 285 goto err_power_req;
293 goto err_power_req;
294 }
295 gpio_direction_output(tegra_host->power_gpio, 1);
296 } 286 }
297 287
298 clk = clk_get(mmc_dev(host->mmc), NULL); 288 clk = devm_clk_get(mmc_dev(host->mmc), NULL);
299 if (IS_ERR(clk)) { 289 if (IS_ERR(clk)) {
300 dev_err(mmc_dev(host->mmc), "clk err\n"); 290 dev_err(mmc_dev(host->mmc), "clk err\n");
301 rc = PTR_ERR(clk); 291 rc = PTR_ERR(clk);
@@ -312,10 +302,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
312 302
313err_add_host: 303err_add_host:
314 clk_disable_unprepare(pltfm_host->clk); 304 clk_disable_unprepare(pltfm_host->clk);
315 clk_put(pltfm_host->clk);
316err_clk_get: 305err_clk_get:
317 if (gpio_is_valid(tegra_host->power_gpio))
318 gpio_free(tegra_host->power_gpio);
319err_power_req: 306err_power_req:
320err_parse_dt: 307err_parse_dt:
321err_alloc_tegra_host: 308err_alloc_tegra_host:
@@ -323,26 +310,6 @@ err_alloc_tegra_host:
323 return rc; 310 return rc;
324} 311}
325 312
326static int sdhci_tegra_remove(struct platform_device *pdev)
327{
328 struct sdhci_host *host = platform_get_drvdata(pdev);
329 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
330 struct sdhci_tegra *tegra_host = pltfm_host->priv;
331 int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
332
333 sdhci_remove_host(host, dead);
334
335 if (gpio_is_valid(tegra_host->power_gpio))
336 gpio_free(tegra_host->power_gpio);
337
338 clk_disable_unprepare(pltfm_host->clk);
339 clk_put(pltfm_host->clk);
340
341 sdhci_pltfm_free(pdev);
342
343 return 0;
344}
345
346static struct platform_driver sdhci_tegra_driver = { 313static struct platform_driver sdhci_tegra_driver = {
347 .driver = { 314 .driver = {
348 .name = "sdhci-tegra", 315 .name = "sdhci-tegra",
@@ -350,7 +317,7 @@ static struct platform_driver sdhci_tegra_driver = {
350 .pm = SDHCI_PLTFM_PMOPS, 317 .pm = SDHCI_PLTFM_PMOPS,
351 }, 318 },
352 .probe = sdhci_tegra_probe, 319 .probe = sdhci_tegra_probe,
353 .remove = sdhci_tegra_remove, 320 .remove = sdhci_pltfm_unregister,
354}; 321};
355 322
356module_platform_driver(sdhci_tegra_driver); 323module_platform_driver(sdhci_tegra_driver);