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