pwrseq_simple.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. * Simple MMC power sequence management
  9. */
  10. #include <linux/clk.h>
  11. #include <linux/kernel.h>
  12. #include <linux/slab.h>
  13. #include <linux/device.h>
  14. #include <linux/err.h>
  15. #include <linux/of_gpio.h>
  16. #include <linux/gpio/consumer.h>
  17. #include <linux/mmc/host.h>
  18. #include "pwrseq.h"
  19. struct mmc_pwrseq_simple {
  20. struct mmc_pwrseq pwrseq;
  21. bool clk_enabled;
  22. struct clk *ext_clk;
  23. int nr_gpios;
  24. struct gpio_desc *reset_gpios[0];
  25. };
  26. static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
  27. int value)
  28. {
  29. int i;
  30. for (i = 0; i < pwrseq->nr_gpios; i++)
  31. if (!IS_ERR(pwrseq->reset_gpios[i]))
  32. gpiod_set_value_cansleep(pwrseq->reset_gpios[i], value);
  33. }
  34. static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
  35. {
  36. struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
  37. struct mmc_pwrseq_simple, pwrseq);
  38. if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
  39. clk_prepare_enable(pwrseq->ext_clk);
  40. pwrseq->clk_enabled = true;
  41. }
  42. mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
  43. }
  44. static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
  45. {
  46. struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
  47. struct mmc_pwrseq_simple, pwrseq);
  48. mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
  49. }
  50. static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
  51. {
  52. struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
  53. struct mmc_pwrseq_simple, pwrseq);
  54. mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
  55. if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) {
  56. clk_disable_unprepare(pwrseq->ext_clk);
  57. pwrseq->clk_enabled = false;
  58. }
  59. }
  60. static void mmc_pwrseq_simple_free(struct mmc_host *host)
  61. {
  62. struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
  63. struct mmc_pwrseq_simple, pwrseq);
  64. int i;
  65. for (i = 0; i < pwrseq->nr_gpios; i++)
  66. if (!IS_ERR(pwrseq->reset_gpios[i]))
  67. gpiod_put(pwrseq->reset_gpios[i]);
  68. if (!IS_ERR(pwrseq->ext_clk))
  69. clk_put(pwrseq->ext_clk);
  70. kfree(pwrseq);
  71. }
  72. static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
  73. .pre_power_on = mmc_pwrseq_simple_pre_power_on,
  74. .post_power_on = mmc_pwrseq_simple_post_power_on,
  75. .power_off = mmc_pwrseq_simple_power_off,
  76. .free = mmc_pwrseq_simple_free,
  77. };
  78. struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
  79. struct device *dev)
  80. {
  81. struct mmc_pwrseq_simple *pwrseq;
  82. int i, nr_gpios, ret = 0;
  83. nr_gpios = of_gpio_named_count(dev->of_node, "reset-gpios");
  84. if (nr_gpios < 0)
  85. nr_gpios = 0;
  86. pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios *
  87. sizeof(struct gpio_desc *), GFP_KERNEL);
  88. if (!pwrseq)
  89. return ERR_PTR(-ENOMEM);
  90. pwrseq->ext_clk = clk_get(dev, "ext_clock");
  91. if (IS_ERR(pwrseq->ext_clk) &&
  92. PTR_ERR(pwrseq->ext_clk) != -ENOENT) {
  93. ret = PTR_ERR(pwrseq->ext_clk);
  94. goto free;
  95. }
  96. for (i = 0; i < nr_gpios; i++) {
  97. pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i,
  98. GPIOD_OUT_HIGH);
  99. if (IS_ERR(pwrseq->reset_gpios[i]) &&
  100. PTR_ERR(pwrseq->reset_gpios[i]) != -ENOENT &&
  101. PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {
  102. ret = PTR_ERR(pwrseq->reset_gpios[i]);
  103. while (i--)
  104. gpiod_put(pwrseq->reset_gpios[i]);
  105. goto clk_put;
  106. }
  107. }
  108. pwrseq->nr_gpios = nr_gpios;
  109. pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
  110. return &pwrseq->pwrseq;
  111. clk_put:
  112. if (!IS_ERR(pwrseq->ext_clk))
  113. clk_put(pwrseq->ext_clk);
  114. free:
  115. kfree(pwrseq);
  116. return ERR_PTR(ret);
  117. }