pwrseq.c 2.3 KB

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