pwrseq.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. #include <linux/mmc/host.h>
  15. #include "pwrseq.h"
  16. static DEFINE_MUTEX(pwrseq_list_mutex);
  17. static LIST_HEAD(pwrseq_list);
  18. int mmc_pwrseq_alloc(struct mmc_host *host)
  19. {
  20. struct device_node *np;
  21. struct mmc_pwrseq *p;
  22. np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
  23. if (!np)
  24. return 0;
  25. mutex_lock(&pwrseq_list_mutex);
  26. list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
  27. if (p->dev->of_node == np) {
  28. if (!try_module_get(p->owner))
  29. dev_err(host->parent,
  30. "increasing module refcount failed\n");
  31. else
  32. host->pwrseq = p;
  33. break;
  34. }
  35. }
  36. of_node_put(np);
  37. mutex_unlock(&pwrseq_list_mutex);
  38. if (!host->pwrseq)
  39. return -EPROBE_DEFER;
  40. dev_info(host->parent, "allocated mmc-pwrseq\n");
  41. return 0;
  42. }
  43. void mmc_pwrseq_pre_power_on(struct mmc_host *host)
  44. {
  45. struct mmc_pwrseq *pwrseq = host->pwrseq;
  46. if (pwrseq && pwrseq->ops->pre_power_on)
  47. pwrseq->ops->pre_power_on(host);
  48. }
  49. void mmc_pwrseq_post_power_on(struct mmc_host *host)
  50. {
  51. struct mmc_pwrseq *pwrseq = host->pwrseq;
  52. if (pwrseq && pwrseq->ops->post_power_on)
  53. pwrseq->ops->post_power_on(host);
  54. }
  55. void mmc_pwrseq_power_off(struct mmc_host *host)
  56. {
  57. struct mmc_pwrseq *pwrseq = host->pwrseq;
  58. if (pwrseq && pwrseq->ops->power_off)
  59. pwrseq->ops->power_off(host);
  60. }
  61. void mmc_pwrseq_reset(struct mmc_host *host)
  62. {
  63. struct mmc_pwrseq *pwrseq = host->pwrseq;
  64. if (pwrseq && pwrseq->ops->reset)
  65. pwrseq->ops->reset(host);
  66. }
  67. void mmc_pwrseq_free(struct mmc_host *host)
  68. {
  69. struct mmc_pwrseq *pwrseq = host->pwrseq;
  70. if (pwrseq) {
  71. module_put(pwrseq->owner);
  72. host->pwrseq = NULL;
  73. }
  74. }
  75. int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
  76. {
  77. if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
  78. return -EINVAL;
  79. mutex_lock(&pwrseq_list_mutex);
  80. list_add(&pwrseq->pwrseq_node, &pwrseq_list);
  81. mutex_unlock(&pwrseq_list_mutex);
  82. return 0;
  83. }
  84. EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
  85. void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
  86. {
  87. if (pwrseq) {
  88. mutex_lock(&pwrseq_list_mutex);
  89. list_del(&pwrseq->pwrseq_node);
  90. mutex_unlock(&pwrseq_list_mutex);
  91. }
  92. }
  93. EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);