pwrseq.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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_free(struct mmc_host *host)
  62. {
  63. struct mmc_pwrseq *pwrseq = host->pwrseq;
  64. if (pwrseq) {
  65. module_put(pwrseq->owner);
  66. host->pwrseq = NULL;
  67. }
  68. }
  69. int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
  70. {
  71. if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
  72. return -EINVAL;
  73. mutex_lock(&pwrseq_list_mutex);
  74. list_add(&pwrseq->pwrseq_node, &pwrseq_list);
  75. mutex_unlock(&pwrseq_list_mutex);
  76. return 0;
  77. }
  78. EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
  79. void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
  80. {
  81. if (pwrseq) {
  82. mutex_lock(&pwrseq_list_mutex);
  83. list_del(&pwrseq->pwrseq_node);
  84. mutex_unlock(&pwrseq_list_mutex);
  85. }
  86. }
  87. EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);