mmc: pwrseq_simple: add support for one reset control

Reset controls being refcounted, they allow to share gpios across
drivers. Right now, reset framework and reset-gpio driver supports only
one reset gpio, so add support for one single reset control. If more
than one reset gpio is configured in the device tree, then fallback to
classic gpio control.

Signed-off-by: Catalin Popescu <catalin.popescu@leica-geosystems.com>
Message-ID: <20241017131957.1171323-1-catalin.popescu@leica-geosystems.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
Catalin Popescu 2024-10-17 15:19:57 +02:00 committed by Ulf Hansson
parent de6840095f
commit 73bf4b7381

View File

@ -17,6 +17,8 @@
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/property.h>
#include <linux/of.h>
#include <linux/reset.h>
#include <linux/mmc/host.h>
@ -29,6 +31,8 @@ struct mmc_pwrseq_simple {
u32 power_off_delay_us;
struct clk *ext_clk;
struct gpio_descs *reset_gpios;
struct reset_control *reset_ctrl;
bool use_reset;
};
#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
@ -67,14 +71,21 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
pwrseq->clk_enabled = true;
}
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
if (pwrseq->use_reset) {
reset_control_deassert(pwrseq->reset_ctrl);
reset_control_assert(pwrseq->reset_ctrl);
} else
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
}
static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
{
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
if (pwrseq->use_reset)
reset_control_deassert(pwrseq->reset_ctrl);
else
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
if (pwrseq->post_power_on_delay_ms)
msleep(pwrseq->post_power_on_delay_ms);
@ -84,7 +95,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
{
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
if (pwrseq->use_reset)
reset_control_assert(pwrseq->reset_ctrl);
else
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
if (pwrseq->power_off_delay_us)
usleep_range(pwrseq->power_off_delay_us,
@ -112,6 +126,7 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
{
struct mmc_pwrseq_simple *pwrseq;
struct device *dev = &pdev->dev;
int ngpio;
pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
if (!pwrseq)
@ -121,12 +136,23 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n");
pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(pwrseq->reset_gpios) &&
PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), "reset GPIOs not ready\n");
ngpio = of_count_phandle_with_args(dev->of_node, "reset-gpios", "#gpio-cells");
if (ngpio == 1)
pwrseq->use_reset = true;
if (pwrseq->use_reset) {
pwrseq->reset_ctrl = devm_reset_control_get_optional_shared(dev, NULL);
if (IS_ERR(pwrseq->reset_ctrl))
return dev_err_probe(dev, PTR_ERR(pwrseq->reset_ctrl),
"reset control not ready\n");
} else {
pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(pwrseq->reset_gpios) &&
PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios),
"reset GPIOs not ready\n");
}
}
device_property_read_u32(dev, "post-power-on-delay-ms",