aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2014-10-02 03:08:46 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2014-10-02 05:51:26 -0400
commit89168b48991537bec2573b3b6a8841df74465b12 (patch)
treef79f45a7a70b995da2fb0d7de39809dc8d2bd273
parent6a98f1e83a2874a189754ded5254ae687828739e (diff)
mmc: core: restore detect line inversion semantics
commit 98e90de99a0c43bd434da814c882c4332441871e "mmc: host: switch OF parser to use gpio descriptors" switched the semantic behaviour of card detect and read only flags such that the inversion capability flag would only be set if inversion was explicitly specified in the device tree, in the hopes that no-one was using double inversion. It turns out that the XOR:ing between the explicit inversion was indeed in use, so we need to restore the old semantics where both ways of inversion are checked and the end result XOR:ed. Reported-by: Javier Martinez Canillas <javier@dowhile0.org> Tested-by: Javier Martinez Canillas <javier@dowhile0.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/core/host.c32
-rw-r--r--drivers/mmc/core/slot-gpio.c14
-rw-r--r--drivers/mmc/host/mmci.c4
-rw-r--r--drivers/mmc/host/sdhci-acpi.c2
-rw-r--r--include/linux/mmc/slot-gpio.h4
5 files changed, 45 insertions, 11 deletions
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 31969436d77c..03c53b72a2d6 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -311,6 +311,7 @@ int mmc_of_parse(struct mmc_host *host)
311 struct device_node *np; 311 struct device_node *np;
312 u32 bus_width; 312 u32 bus_width;
313 int len, ret; 313 int len, ret;
314 bool cap_invert, gpio_invert;
314 315
315 if (!host->parent || !host->parent->of_node) 316 if (!host->parent || !host->parent->of_node)
316 return 0; 317 return 0;
@@ -359,12 +360,15 @@ int mmc_of_parse(struct mmc_host *host)
359 host->caps |= MMC_CAP_NONREMOVABLE; 360 host->caps |= MMC_CAP_NONREMOVABLE;
360 } else { 361 } else {
361 if (of_property_read_bool(np, "cd-inverted")) 362 if (of_property_read_bool(np, "cd-inverted"))
362 host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; 363 cap_invert = true;
364 else
365 cap_invert = false;
363 366
364 if (of_find_property(np, "broken-cd", &len)) 367 if (of_find_property(np, "broken-cd", &len))
365 host->caps |= MMC_CAP_NEEDS_POLL; 368 host->caps |= MMC_CAP_NEEDS_POLL;
366 369
367 ret = mmc_gpiod_request_cd(host, "cd", 0, false, 0); 370 ret = mmc_gpiod_request_cd(host, "cd", 0, true,
371 0, &gpio_invert);
368 if (ret) { 372 if (ret) {
369 if (ret == -EPROBE_DEFER) 373 if (ret == -EPROBE_DEFER)
370 return ret; 374 return ret;
@@ -375,13 +379,29 @@ int mmc_of_parse(struct mmc_host *host)
375 } 379 }
376 } else 380 } else
377 dev_info(host->parent, "Got CD GPIO\n"); 381 dev_info(host->parent, "Got CD GPIO\n");
382
383 /*
384 * There are two ways to flag that the CD line is inverted:
385 * through the cd-inverted flag and by the GPIO line itself
386 * being inverted from the GPIO subsystem. This is a leftover
387 * from the times when the GPIO subsystem did not make it
388 * possible to flag a line as inverted.
389 *
390 * If the capability on the host AND the GPIO line are
391 * both inverted, the end result is that the CD line is
392 * not inverted.
393 */
394 if (cap_invert ^ gpio_invert)
395 host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
378 } 396 }
379 397
380 /* Parse Write Protection */ 398 /* Parse Write Protection */
381 if (of_property_read_bool(np, "wp-inverted")) 399 if (of_property_read_bool(np, "wp-inverted"))
382 host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; 400 cap_invert = true;
401 else
402 cap_invert = false;
383 403
384 ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0); 404 ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &gpio_invert);
385 if (ret) { 405 if (ret) {
386 if (ret == -EPROBE_DEFER) 406 if (ret == -EPROBE_DEFER)
387 goto out; 407 goto out;
@@ -393,6 +413,10 @@ int mmc_of_parse(struct mmc_host *host)
393 } else 413 } else
394 dev_info(host->parent, "Got WP GPIO\n"); 414 dev_info(host->parent, "Got WP GPIO\n");
395 415
416 /* See the comment on CD inversion above */
417 if (cap_invert ^ gpio_invert)
418 host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
419
396 if (of_find_property(np, "cap-sd-highspeed", &len)) 420 if (of_find_property(np, "cap-sd-highspeed", &len))
397 host->caps |= MMC_CAP_SD_HIGHSPEED; 421 host->caps |= MMC_CAP_SD_HIGHSPEED;
398 if (of_find_property(np, "cap-mmc-highspeed", &len)) 422 if (of_find_property(np, "cap-mmc-highspeed", &len))
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 38f76555d4bf..69bbf2adb329 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -281,6 +281,8 @@ EXPORT_SYMBOL(mmc_gpio_free_cd);
281 * @idx: index of the GPIO to obtain in the consumer 281 * @idx: index of the GPIO to obtain in the consumer
282 * @override_active_level: ignore %GPIO_ACTIVE_LOW flag 282 * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
283 * @debounce: debounce time in microseconds 283 * @debounce: debounce time in microseconds
284 * @gpio_invert: will return whether the GPIO line is inverted or not, set
285 * to NULL to ignore
284 * 286 *
285 * Use this function in place of mmc_gpio_request_cd() to use the GPIO 287 * Use this function in place of mmc_gpio_request_cd() to use the GPIO
286 * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not 288 * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not
@@ -291,7 +293,7 @@ EXPORT_SYMBOL(mmc_gpio_free_cd);
291 */ 293 */
292int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, 294int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
293 unsigned int idx, bool override_active_level, 295 unsigned int idx, bool override_active_level,
294 unsigned int debounce) 296 unsigned int debounce, bool *gpio_invert)
295{ 297{
296 struct mmc_gpio *ctx; 298 struct mmc_gpio *ctx;
297 struct gpio_desc *desc; 299 struct gpio_desc *desc;
@@ -316,6 +318,9 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
316 return ret; 318 return ret;
317 } 319 }
318 320
321 if (gpio_invert)
322 *gpio_invert = !gpiod_is_active_low(desc);
323
319 ctx->override_cd_active_level = override_active_level; 324 ctx->override_cd_active_level = override_active_level;
320 ctx->cd_gpio = desc; 325 ctx->cd_gpio = desc;
321 326
@@ -330,6 +335,8 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd);
330 * @idx: index of the GPIO to obtain in the consumer 335 * @idx: index of the GPIO to obtain in the consumer
331 * @override_active_level: ignore %GPIO_ACTIVE_LOW flag 336 * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
332 * @debounce: debounce time in microseconds 337 * @debounce: debounce time in microseconds
338 * @gpio_invert: will return whether the GPIO line is inverted or not,
339 * set to NULL to ignore
333 * 340 *
334 * Use this function in place of mmc_gpio_request_ro() to use the GPIO 341 * Use this function in place of mmc_gpio_request_ro() to use the GPIO
335 * descriptor API. Note that it is paired with mmc_gpiod_free_ro() not 342 * descriptor API. Note that it is paired with mmc_gpiod_free_ro() not
@@ -339,7 +346,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd);
339 */ 346 */
340int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, 347int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
341 unsigned int idx, bool override_active_level, 348 unsigned int idx, bool override_active_level,
342 unsigned int debounce) 349 unsigned int debounce, bool *gpio_invert)
343{ 350{
344 struct mmc_gpio *ctx; 351 struct mmc_gpio *ctx;
345 struct gpio_desc *desc; 352 struct gpio_desc *desc;
@@ -364,6 +371,9 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
364 return ret; 371 return ret;
365 } 372 }
366 373
374 if (gpio_invert)
375 *gpio_invert = !gpiod_is_active_low(desc);
376
367 ctx->override_ro_active_level = override_active_level; 377 ctx->override_ro_active_level = override_active_level;
368 ctx->ro_gpio = desc; 378 ctx->ro_gpio = desc;
369 379
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index c9dafed550f2..43af791e2e45 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1682,7 +1682,7 @@ static int mmci_probe(struct amba_device *dev,
1682 * silently of these do not exist and proceed to try platform data 1682 * silently of these do not exist and proceed to try platform data
1683 */ 1683 */
1684 if (!np) { 1684 if (!np) {
1685 ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); 1685 ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
1686 if (ret < 0) { 1686 if (ret < 0) {
1687 if (ret == -EPROBE_DEFER) 1687 if (ret == -EPROBE_DEFER)
1688 goto clk_disable; 1688 goto clk_disable;
@@ -1693,7 +1693,7 @@ static int mmci_probe(struct amba_device *dev,
1693 } 1693 }
1694 } 1694 }
1695 1695
1696 ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0); 1696 ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
1697 if (ret < 0) { 1697 if (ret < 0) {
1698 if (ret == -EPROBE_DEFER) 1698 if (ret == -EPROBE_DEFER)
1699 goto clk_disable; 1699 goto clk_disable;
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 3483c089baa7..327bc24ec8ce 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -352,7 +352,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
352 if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) { 352 if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
353 bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL); 353 bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
354 354
355 if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0)) { 355 if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL)) {
356 dev_warn(dev, "failed to setup card detect gpio\n"); 356 dev_warn(dev, "failed to setup card detect gpio\n");
357 c->use_runtime_pm = false; 357 c->use_runtime_pm = false;
358 } 358 }
diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h
index a0d0442c15bf..e56fa24c9322 100644
--- a/include/linux/mmc/slot-gpio.h
+++ b/include/linux/mmc/slot-gpio.h
@@ -24,10 +24,10 @@ void mmc_gpio_free_cd(struct mmc_host *host);
24 24
25int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, 25int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
26 unsigned int idx, bool override_active_level, 26 unsigned int idx, bool override_active_level,
27 unsigned int debounce); 27 unsigned int debounce, bool *gpio_invert);
28int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, 28int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
29 unsigned int idx, bool override_active_level, 29 unsigned int idx, bool override_active_level,
30 unsigned int debounce); 30 unsigned int debounce, bool *gpio_invert);
31void mmc_gpiod_free_cd(struct mmc_host *host); 31void mmc_gpiod_free_cd(struct mmc_host *host);
32void mmc_gpiod_request_cd_irq(struct mmc_host *host); 32void mmc_gpiod_request_cd_irq(struct mmc_host *host);
33 33