diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-08-08 06:38:32 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-08-24 23:45:22 -0400 |
commit | bf287a90ceedf86e3313ba0dcff606ac5399b39a (patch) | |
tree | a3337495e68fde2270c406574774a283c0b4e002 /drivers/mmc | |
parent | 214fc309d1387e822d606a33a10e31cacfe83520 (diff) |
mmc: mmc_spi: Support CD/RO GPIOs
Add support for passing CD/RO GPIO numbers directly to the mmc_spi
driver instead of relying solely on board code callbacks to retrieve the
CD/RO signals values. The driver will enable debouncing on the card
detect GPIO if the cd_debounce field is set to a non-zero value.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/mmc_spi.c | 33 | ||||
-rw-r--r-- | drivers/mmc/host/of_mmc_spi.c | 46 |
2 files changed, 36 insertions, 43 deletions
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 74145d1d51f5..62fb82d7c942 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c | |||
@@ -36,6 +36,7 @@ | |||
36 | 36 | ||
37 | #include <linux/mmc/host.h> | 37 | #include <linux/mmc/host.h> |
38 | #include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */ | 38 | #include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */ |
39 | #include <linux/mmc/slot-gpio.h> | ||
39 | 40 | ||
40 | #include <linux/spi/spi.h> | 41 | #include <linux/spi/spi.h> |
41 | #include <linux/spi/mmc_spi.h> | 42 | #include <linux/spi/mmc_spi.h> |
@@ -1278,11 +1279,8 @@ static int mmc_spi_get_ro(struct mmc_host *mmc) | |||
1278 | 1279 | ||
1279 | if (host->pdata && host->pdata->get_ro) | 1280 | if (host->pdata && host->pdata->get_ro) |
1280 | return !!host->pdata->get_ro(mmc->parent); | 1281 | return !!host->pdata->get_ro(mmc->parent); |
1281 | /* | 1282 | else |
1282 | * Board doesn't support read only detection; let the mmc core | 1283 | return mmc_gpio_get_ro(mmc); |
1283 | * decide what to do. | ||
1284 | */ | ||
1285 | return -ENOSYS; | ||
1286 | } | 1284 | } |
1287 | 1285 | ||
1288 | static int mmc_spi_get_cd(struct mmc_host *mmc) | 1286 | static int mmc_spi_get_cd(struct mmc_host *mmc) |
@@ -1291,7 +1289,8 @@ static int mmc_spi_get_cd(struct mmc_host *mmc) | |||
1291 | 1289 | ||
1292 | if (host->pdata && host->pdata->get_cd) | 1290 | if (host->pdata && host->pdata->get_cd) |
1293 | return !!host->pdata->get_cd(mmc->parent); | 1291 | return !!host->pdata->get_cd(mmc->parent); |
1294 | return -ENOSYS; | 1292 | else |
1293 | return mmc_gpio_get_cd(mmc); | ||
1295 | } | 1294 | } |
1296 | 1295 | ||
1297 | static const struct mmc_host_ops mmc_spi_ops = { | 1296 | static const struct mmc_host_ops mmc_spi_ops = { |
@@ -1324,6 +1323,7 @@ static int mmc_spi_probe(struct spi_device *spi) | |||
1324 | struct mmc_host *mmc; | 1323 | struct mmc_host *mmc; |
1325 | struct mmc_spi_host *host; | 1324 | struct mmc_spi_host *host; |
1326 | int status; | 1325 | int status; |
1326 | bool has_ro = false; | ||
1327 | 1327 | ||
1328 | /* We rely on full duplex transfers, mostly to reduce | 1328 | /* We rely on full duplex transfers, mostly to reduce |
1329 | * per-transfer overheads (by making fewer transfers). | 1329 | * per-transfer overheads (by making fewer transfers). |
@@ -1448,18 +1448,33 @@ static int mmc_spi_probe(struct spi_device *spi) | |||
1448 | } | 1448 | } |
1449 | 1449 | ||
1450 | /* pass platform capabilities, if any */ | 1450 | /* pass platform capabilities, if any */ |
1451 | if (host->pdata) | 1451 | if (host->pdata) { |
1452 | mmc->caps |= host->pdata->caps; | 1452 | mmc->caps |= host->pdata->caps; |
1453 | mmc->caps2 |= host->pdata->caps2; | ||
1454 | } | ||
1453 | 1455 | ||
1454 | status = mmc_add_host(mmc); | 1456 | status = mmc_add_host(mmc); |
1455 | if (status != 0) | 1457 | if (status != 0) |
1456 | goto fail_add_host; | 1458 | goto fail_add_host; |
1457 | 1459 | ||
1460 | if (host->pdata && host->pdata->flags & MMC_SPI_USE_CD_GPIO) { | ||
1461 | status = mmc_gpio_request_cd(mmc, host->pdata->cd_gpio, | ||
1462 | host->pdata->cd_debounce); | ||
1463 | if (status != 0) | ||
1464 | goto fail_add_host; | ||
1465 | } | ||
1466 | |||
1467 | if (host->pdata && host->pdata->flags & MMC_SPI_USE_RO_GPIO) { | ||
1468 | has_ro = true; | ||
1469 | status = mmc_gpio_request_ro(mmc, host->pdata->ro_gpio); | ||
1470 | if (status != 0) | ||
1471 | goto fail_add_host; | ||
1472 | } | ||
1473 | |||
1458 | dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n", | 1474 | dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n", |
1459 | dev_name(&mmc->class_dev), | 1475 | dev_name(&mmc->class_dev), |
1460 | host->dma_dev ? "" : ", no DMA", | 1476 | host->dma_dev ? "" : ", no DMA", |
1461 | (host->pdata && host->pdata->get_ro) | 1477 | has_ro ? "" : ", no WP", |
1462 | ? "" : ", no WP", | ||
1463 | (host->pdata && host->pdata->setpower) | 1478 | (host->pdata && host->pdata->setpower) |
1464 | ? "" : ", no poweroff", | 1479 | ? "" : ", no poweroff", |
1465 | (mmc->caps & MMC_CAP_NEEDS_POLL) | 1480 | (mmc->caps & MMC_CAP_NEEDS_POLL) |
diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index d720b5e05b9c..6e218fb1a669 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c | |||
@@ -50,25 +50,6 @@ static struct of_mmc_spi *to_of_mmc_spi(struct device *dev) | |||
50 | return container_of(dev->platform_data, struct of_mmc_spi, pdata); | 50 | return container_of(dev->platform_data, struct of_mmc_spi, pdata); |
51 | } | 51 | } |
52 | 52 | ||
53 | static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num) | ||
54 | { | ||
55 | struct of_mmc_spi *oms = to_of_mmc_spi(dev); | ||
56 | bool active_low = oms->alow_gpios[gpio_num]; | ||
57 | bool value = gpio_get_value(oms->gpios[gpio_num]); | ||
58 | |||
59 | return active_low ^ value; | ||
60 | } | ||
61 | |||
62 | static int of_mmc_spi_get_cd(struct device *dev) | ||
63 | { | ||
64 | return of_mmc_spi_read_gpio(dev, CD_GPIO); | ||
65 | } | ||
66 | |||
67 | static int of_mmc_spi_get_ro(struct device *dev) | ||
68 | { | ||
69 | return of_mmc_spi_read_gpio(dev, WP_GPIO); | ||
70 | } | ||
71 | |||
72 | static int of_mmc_spi_init(struct device *dev, | 53 | static int of_mmc_spi_init(struct device *dev, |
73 | irqreturn_t (*irqhandler)(int, void *), void *mmc) | 54 | irqreturn_t (*irqhandler)(int, void *), void *mmc) |
74 | { | 55 | { |
@@ -130,20 +111,22 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) | |||
130 | if (!gpio_is_valid(oms->gpios[i])) | 111 | if (!gpio_is_valid(oms->gpios[i])) |
131 | continue; | 112 | continue; |
132 | 113 | ||
133 | ret = gpio_request(oms->gpios[i], dev_name(dev)); | ||
134 | if (ret < 0) { | ||
135 | oms->gpios[i] = -EINVAL; | ||
136 | continue; | ||
137 | } | ||
138 | |||
139 | if (gpio_flags & OF_GPIO_ACTIVE_LOW) | 114 | if (gpio_flags & OF_GPIO_ACTIVE_LOW) |
140 | oms->alow_gpios[i] = true; | 115 | oms->alow_gpios[i] = true; |
141 | } | 116 | } |
142 | 117 | ||
143 | if (gpio_is_valid(oms->gpios[CD_GPIO])) | 118 | if (gpio_is_valid(oms->gpios[CD_GPIO])) { |
144 | oms->pdata.get_cd = of_mmc_spi_get_cd; | 119 | oms->pdata.cd_gpio = oms->gpios[CD_GPIO]; |
145 | if (gpio_is_valid(oms->gpios[WP_GPIO])) | 120 | oms->pdata.flags |= MMC_SPI_USE_CD_GPIO; |
146 | oms->pdata.get_ro = of_mmc_spi_get_ro; | 121 | if (!oms->alow_gpios[CD_GPIO]) |
122 | oms->pdata.caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; | ||
123 | } | ||
124 | if (gpio_is_valid(oms->gpios[WP_GPIO])) { | ||
125 | oms->pdata.ro_gpio = oms->gpios[WP_GPIO]; | ||
126 | oms->pdata.flags |= MMC_SPI_USE_RO_GPIO; | ||
127 | if (!oms->alow_gpios[WP_GPIO]) | ||
128 | oms->pdata.caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; | ||
129 | } | ||
147 | 130 | ||
148 | oms->detect_irq = irq_of_parse_and_map(np, 0); | 131 | oms->detect_irq = irq_of_parse_and_map(np, 0); |
149 | if (oms->detect_irq != 0) { | 132 | if (oms->detect_irq != 0) { |
@@ -166,15 +149,10 @@ void mmc_spi_put_pdata(struct spi_device *spi) | |||
166 | struct device *dev = &spi->dev; | 149 | struct device *dev = &spi->dev; |
167 | struct device_node *np = dev->of_node; | 150 | struct device_node *np = dev->of_node; |
168 | struct of_mmc_spi *oms = to_of_mmc_spi(dev); | 151 | struct of_mmc_spi *oms = to_of_mmc_spi(dev); |
169 | int i; | ||
170 | 152 | ||
171 | if (!dev->platform_data || !np) | 153 | if (!dev->platform_data || !np) |
172 | return; | 154 | return; |
173 | 155 | ||
174 | for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) { | ||
175 | if (gpio_is_valid(oms->gpios[i])) | ||
176 | gpio_free(oms->gpios[i]); | ||
177 | } | ||
178 | kfree(oms); | 156 | kfree(oms); |
179 | dev->platform_data = NULL; | 157 | dev->platform_data = NULL; |
180 | } | 158 | } |