diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/mmc/core/pwrseq.c | |
parent | Initial commit. (diff) | |
download | linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.tar.xz linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.zip |
Adding upstream version 6.1.76.upstream/6.1.76
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/mmc/core/pwrseq.c')
-rw-r--r-- | drivers/mmc/core/pwrseq.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c new file mode 100644 index 000000000..ef675f364 --- /dev/null +++ b/drivers/mmc/core/pwrseq.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * MMC power sequence management + */ +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> + +#include <linux/mmc/host.h> + +#include "pwrseq.h" + +static DEFINE_MUTEX(pwrseq_list_mutex); +static LIST_HEAD(pwrseq_list); + +int mmc_pwrseq_alloc(struct mmc_host *host) +{ + struct device_node *np; + struct mmc_pwrseq *p; + + np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); + if (!np) + return 0; + + mutex_lock(&pwrseq_list_mutex); + list_for_each_entry(p, &pwrseq_list, pwrseq_node) { + if (p->dev->of_node == np) { + if (!try_module_get(p->owner)) + dev_err(host->parent, + "increasing module refcount failed\n"); + else + host->pwrseq = p; + + break; + } + } + + of_node_put(np); + mutex_unlock(&pwrseq_list_mutex); + + if (!host->pwrseq) + return -EPROBE_DEFER; + + dev_info(host->parent, "allocated mmc-pwrseq\n"); + + return 0; +} + +void mmc_pwrseq_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops->pre_power_on) + pwrseq->ops->pre_power_on(host); +} + +void mmc_pwrseq_post_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops->post_power_on) + pwrseq->ops->post_power_on(host); +} + +void mmc_pwrseq_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops->power_off) + pwrseq->ops->power_off(host); +} + +void mmc_pwrseq_reset(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops->reset) + pwrseq->ops->reset(host); +} + +void mmc_pwrseq_free(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq) { + module_put(pwrseq->owner); + host->pwrseq = NULL; + } +} + +int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq) +{ + if (!pwrseq || !pwrseq->ops || !pwrseq->dev) + return -EINVAL; + + mutex_lock(&pwrseq_list_mutex); + list_add(&pwrseq->pwrseq_node, &pwrseq_list); + mutex_unlock(&pwrseq_list_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(mmc_pwrseq_register); + +void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) +{ + if (pwrseq) { + mutex_lock(&pwrseq_list_mutex); + list_del(&pwrseq->pwrseq_node); + mutex_unlock(&pwrseq_list_mutex); + } +} +EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister); |