linux/drivers/mmc/core/pwrseq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Copyright (C) 2014 Linaro Ltd
   4 *
   5 * Author: Ulf Hansson <ulf.hansson@linaro.org>
   6 *
   7 *  MMC power sequence management
   8 */
   9#include <linux/kernel.h>
  10#include <linux/err.h>
  11#include <linux/module.h>
  12#include <linux/of.h>
  13
  14#include <linux/mmc/host.h>
  15
  16#include "pwrseq.h"
  17
  18static DEFINE_MUTEX(pwrseq_list_mutex);
  19static LIST_HEAD(pwrseq_list);
  20
  21int mmc_pwrseq_alloc(struct mmc_host *host)
  22{
  23        struct device_node *np;
  24        struct mmc_pwrseq *p;
  25
  26        np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
  27        if (!np)
  28                return 0;
  29
  30        mutex_lock(&pwrseq_list_mutex);
  31        list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
  32                if (p->dev->of_node == np) {
  33                        if (!try_module_get(p->owner))
  34                                dev_err(host->parent,
  35                                        "increasing module refcount failed\n");
  36                        else
  37                                host->pwrseq = p;
  38
  39                        break;
  40                }
  41        }
  42
  43        of_node_put(np);
  44        mutex_unlock(&pwrseq_list_mutex);
  45
  46        if (!host->pwrseq)
  47                return -EPROBE_DEFER;
  48
  49        dev_info(host->parent, "allocated mmc-pwrseq\n");
  50
  51        return 0;
  52}
  53
  54void mmc_pwrseq_pre_power_on(struct mmc_host *host)
  55{
  56        struct mmc_pwrseq *pwrseq = host->pwrseq;
  57
  58        if (pwrseq && pwrseq->ops->pre_power_on)
  59                pwrseq->ops->pre_power_on(host);
  60}
  61
  62void mmc_pwrseq_post_power_on(struct mmc_host *host)
  63{
  64        struct mmc_pwrseq *pwrseq = host->pwrseq;
  65
  66        if (pwrseq && pwrseq->ops->post_power_on)
  67                pwrseq->ops->post_power_on(host);
  68}
  69
  70void mmc_pwrseq_power_off(struct mmc_host *host)
  71{
  72        struct mmc_pwrseq *pwrseq = host->pwrseq;
  73
  74        if (pwrseq && pwrseq->ops->power_off)
  75                pwrseq->ops->power_off(host);
  76}
  77
  78void mmc_pwrseq_reset(struct mmc_host *host)
  79{
  80        struct mmc_pwrseq *pwrseq = host->pwrseq;
  81
  82        if (pwrseq && pwrseq->ops->reset)
  83                pwrseq->ops->reset(host);
  84}
  85
  86void mmc_pwrseq_free(struct mmc_host *host)
  87{
  88        struct mmc_pwrseq *pwrseq = host->pwrseq;
  89
  90        if (pwrseq) {
  91                module_put(pwrseq->owner);
  92                host->pwrseq = NULL;
  93        }
  94}
  95
  96int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
  97{
  98        if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
  99                return -EINVAL;
 100
 101        mutex_lock(&pwrseq_list_mutex);
 102        list_add(&pwrseq->pwrseq_node, &pwrseq_list);
 103        mutex_unlock(&pwrseq_list_mutex);
 104
 105        return 0;
 106}
 107EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
 108
 109void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
 110{
 111        if (pwrseq) {
 112                mutex_lock(&pwrseq_list_mutex);
 113                list_del(&pwrseq->pwrseq_node);
 114                mutex_unlock(&pwrseq_list_mutex);
 115        }
 116}
 117EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);
 118