mmc: core: restore detect line inversion semantics
commit 98e90de99a
"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>
This commit is contained in:
parent
6a98f1e83a
commit
89168b4899
5 changed files with 45 additions and 11 deletions
|
@ -311,6 +311,7 @@ int mmc_of_parse(struct mmc_host *host)
|
|||
struct device_node *np;
|
||||
u32 bus_width;
|
||||
int len, ret;
|
||||
bool cap_invert, gpio_invert;
|
||||
|
||||
if (!host->parent || !host->parent->of_node)
|
||||
return 0;
|
||||
|
@ -359,12 +360,15 @@ int mmc_of_parse(struct mmc_host *host)
|
|||
host->caps |= MMC_CAP_NONREMOVABLE;
|
||||
} else {
|
||||
if (of_property_read_bool(np, "cd-inverted"))
|
||||
host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
|
||||
cap_invert = true;
|
||||
else
|
||||
cap_invert = false;
|
||||
|
||||
if (of_find_property(np, "broken-cd", &len))
|
||||
host->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
ret = mmc_gpiod_request_cd(host, "cd", 0, false, 0);
|
||||
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
|
||||
0, &gpio_invert);
|
||||
if (ret) {
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
|
@ -375,13 +379,29 @@ int mmc_of_parse(struct mmc_host *host)
|
|||
}
|
||||
} else
|
||||
dev_info(host->parent, "Got CD GPIO\n");
|
||||
|
||||
/*
|
||||
* There are two ways to flag that the CD line is inverted:
|
||||
* through the cd-inverted flag and by the GPIO line itself
|
||||
* being inverted from the GPIO subsystem. This is a leftover
|
||||
* from the times when the GPIO subsystem did not make it
|
||||
* possible to flag a line as inverted.
|
||||
*
|
||||
* If the capability on the host AND the GPIO line are
|
||||
* both inverted, the end result is that the CD line is
|
||||
* not inverted.
|
||||
*/
|
||||
if (cap_invert ^ gpio_invert)
|
||||
host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
|
||||
}
|
||||
|
||||
/* Parse Write Protection */
|
||||
if (of_property_read_bool(np, "wp-inverted"))
|
||||
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
cap_invert = true;
|
||||
else
|
||||
cap_invert = false;
|
||||
|
||||
ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0);
|
||||
ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &gpio_invert);
|
||||
if (ret) {
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto out;
|
||||
|
@ -393,6 +413,10 @@ int mmc_of_parse(struct mmc_host *host)
|
|||
} else
|
||||
dev_info(host->parent, "Got WP GPIO\n");
|
||||
|
||||
/* See the comment on CD inversion above */
|
||||
if (cap_invert ^ gpio_invert)
|
||||
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
|
||||
if (of_find_property(np, "cap-sd-highspeed", &len))
|
||||
host->caps |= MMC_CAP_SD_HIGHSPEED;
|
||||
if (of_find_property(np, "cap-mmc-highspeed", &len))
|
||||
|
|
|
@ -281,6 +281,8 @@ EXPORT_SYMBOL(mmc_gpio_free_cd);
|
|||
* @idx: index of the GPIO to obtain in the consumer
|
||||
* @override_active_level: ignore %GPIO_ACTIVE_LOW flag
|
||||
* @debounce: debounce time in microseconds
|
||||
* @gpio_invert: will return whether the GPIO line is inverted or not, set
|
||||
* to NULL to ignore
|
||||
*
|
||||
* Use this function in place of mmc_gpio_request_cd() to use the GPIO
|
||||
* descriptor API. Note that it is paired with mmc_gpiod_free_cd() not
|
||||
|
@ -291,7 +293,7 @@ EXPORT_SYMBOL(mmc_gpio_free_cd);
|
|||
*/
|
||||
int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
|
||||
unsigned int idx, bool override_active_level,
|
||||
unsigned int debounce)
|
||||
unsigned int debounce, bool *gpio_invert)
|
||||
{
|
||||
struct mmc_gpio *ctx;
|
||||
struct gpio_desc *desc;
|
||||
|
@ -316,6 +318,9 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_invert)
|
||||
*gpio_invert = !gpiod_is_active_low(desc);
|
||||
|
||||
ctx->override_cd_active_level = override_active_level;
|
||||
ctx->cd_gpio = desc;
|
||||
|
||||
|
@ -330,6 +335,8 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd);
|
|||
* @idx: index of the GPIO to obtain in the consumer
|
||||
* @override_active_level: ignore %GPIO_ACTIVE_LOW flag
|
||||
* @debounce: debounce time in microseconds
|
||||
* @gpio_invert: will return whether the GPIO line is inverted or not,
|
||||
* set to NULL to ignore
|
||||
*
|
||||
* Use this function in place of mmc_gpio_request_ro() to use the GPIO
|
||||
* descriptor API. Note that it is paired with mmc_gpiod_free_ro() not
|
||||
|
@ -339,7 +346,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd);
|
|||
*/
|
||||
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
|
||||
unsigned int idx, bool override_active_level,
|
||||
unsigned int debounce)
|
||||
unsigned int debounce, bool *gpio_invert)
|
||||
{
|
||||
struct mmc_gpio *ctx;
|
||||
struct gpio_desc *desc;
|
||||
|
@ -364,6 +371,9 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_invert)
|
||||
*gpio_invert = !gpiod_is_active_low(desc);
|
||||
|
||||
ctx->override_ro_active_level = override_active_level;
|
||||
ctx->ro_gpio = desc;
|
||||
|
||||
|
|
|
@ -1682,7 +1682,7 @@ static int mmci_probe(struct amba_device *dev,
|
|||
* silently of these do not exist and proceed to try platform data
|
||||
*/
|
||||
if (!np) {
|
||||
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0);
|
||||
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto clk_disable;
|
||||
|
@ -1693,7 +1693,7 @@ static int mmci_probe(struct amba_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0);
|
||||
ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto clk_disable;
|
||||
|
|
|
@ -352,7 +352,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
|
|||
if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
|
||||
bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
|
||||
|
||||
if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0)) {
|
||||
if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL)) {
|
||||
dev_warn(dev, "failed to setup card detect gpio\n");
|
||||
c->use_runtime_pm = false;
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@ void mmc_gpio_free_cd(struct mmc_host *host);
|
|||
|
||||
int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
|
||||
unsigned int idx, bool override_active_level,
|
||||
unsigned int debounce);
|
||||
unsigned int debounce, bool *gpio_invert);
|
||||
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
|
||||
unsigned int idx, bool override_active_level,
|
||||
unsigned int debounce);
|
||||
unsigned int debounce, bool *gpio_invert);
|
||||
void mmc_gpiod_free_cd(struct mmc_host *host);
|
||||
void mmc_gpiod_request_cd_irq(struct mmc_host *host);
|
||||
|
||||
|
|
Loading…
Reference in a new issue