ti_sci_pm_domains.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * TI SCI Generic Power Domain Driver
  3. *
  4. * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
  5. * J Keerthy <j-keerthy@ti.com>
  6. * Dave Gerlach <d-gerlach@ti.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * version 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include <linux/err.h>
  18. #include <linux/module.h>
  19. #include <linux/mutex.h>
  20. #include <linux/of.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/pm_domain.h>
  23. #include <linux/slab.h>
  24. #include <linux/soc/ti/ti_sci_protocol.h>
  25. /**
  26. * struct ti_sci_genpd_dev_data: holds data needed for every device attached
  27. * to this genpd
  28. * @idx: index of the device that identifies it with the system
  29. * control processor.
  30. */
  31. struct ti_sci_genpd_dev_data {
  32. int idx;
  33. };
  34. /**
  35. * struct ti_sci_pm_domain: TI specific data needed for power domain
  36. * @ti_sci: handle to TI SCI protocol driver that provides ops to
  37. * communicate with system control processor.
  38. * @dev: pointer to dev for the driver for devm allocs
  39. * @pd: generic_pm_domain for use with the genpd framework
  40. */
  41. struct ti_sci_pm_domain {
  42. const struct ti_sci_handle *ti_sci;
  43. struct device *dev;
  44. struct generic_pm_domain pd;
  45. };
  46. #define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
  47. /**
  48. * ti_sci_dev_id(): get prepopulated ti_sci id from struct dev
  49. * @dev: pointer to device associated with this genpd
  50. *
  51. * Returns device_id stored from ti,sci_id property
  52. */
  53. static int ti_sci_dev_id(struct device *dev)
  54. {
  55. struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
  56. struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
  57. return sci_dev_data->idx;
  58. }
  59. /**
  60. * ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle
  61. * @dev: pointer to device associated with this genpd
  62. *
  63. * Returns ti_sci_handle to be used to communicate with system
  64. * control processor.
  65. */
  66. static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev)
  67. {
  68. struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain);
  69. struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd);
  70. return ti_sci_genpd->ti_sci;
  71. }
  72. /**
  73. * ti_sci_dev_start(): genpd device start hook called to turn device on
  74. * @dev: pointer to device associated with this genpd to be powered on
  75. */
  76. static int ti_sci_dev_start(struct device *dev)
  77. {
  78. const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
  79. int idx = ti_sci_dev_id(dev);
  80. return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
  81. }
  82. /**
  83. * ti_sci_dev_stop(): genpd device stop hook called to turn device off
  84. * @dev: pointer to device associated with this genpd to be powered off
  85. */
  86. static int ti_sci_dev_stop(struct device *dev)
  87. {
  88. const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
  89. int idx = ti_sci_dev_id(dev);
  90. return ti_sci->ops.dev_ops.put_device(ti_sci, idx);
  91. }
  92. static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
  93. struct device *dev)
  94. {
  95. struct device_node *np = dev->of_node;
  96. struct of_phandle_args pd_args;
  97. struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain);
  98. const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
  99. struct ti_sci_genpd_dev_data *sci_dev_data;
  100. struct generic_pm_domain_data *genpd_data;
  101. int idx, ret = 0;
  102. ret = of_parse_phandle_with_args(np, "power-domains",
  103. "#power-domain-cells", 0, &pd_args);
  104. if (ret < 0)
  105. return ret;
  106. if (pd_args.args_count != 1)
  107. return -EINVAL;
  108. idx = pd_args.args[0];
  109. /*
  110. * Check the validity of the requested idx, if the index is not valid
  111. * the PMMC will return a NAK here and we will not allocate it.
  112. */
  113. ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
  114. if (ret)
  115. return -EINVAL;
  116. sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL);
  117. if (!sci_dev_data)
  118. return -ENOMEM;
  119. sci_dev_data->idx = idx;
  120. genpd_data = dev_gpd_data(dev);
  121. genpd_data->data = sci_dev_data;
  122. return 0;
  123. }
  124. static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain,
  125. struct device *dev)
  126. {
  127. struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
  128. struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
  129. kfree(sci_dev_data);
  130. genpd_data->data = NULL;
  131. }
  132. static const struct of_device_id ti_sci_pm_domain_matches[] = {
  133. { .compatible = "ti,sci-pm-domain", },
  134. { },
  135. };
  136. MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
  137. static int ti_sci_pm_domain_probe(struct platform_device *pdev)
  138. {
  139. struct device *dev = &pdev->dev;
  140. struct device_node *np = dev->of_node;
  141. struct ti_sci_pm_domain *ti_sci_pd;
  142. int ret;
  143. ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL);
  144. if (!ti_sci_pd)
  145. return -ENOMEM;
  146. ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev);
  147. if (IS_ERR(ti_sci_pd->ti_sci))
  148. return PTR_ERR(ti_sci_pd->ti_sci);
  149. ti_sci_pd->dev = dev;
  150. ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev;
  151. ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev;
  152. ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start;
  153. ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop;
  154. pm_genpd_init(&ti_sci_pd->pd, NULL, true);
  155. ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd);
  156. return ret;
  157. }
  158. static struct platform_driver ti_sci_pm_domains_driver = {
  159. .probe = ti_sci_pm_domain_probe,
  160. .driver = {
  161. .name = "ti_sci_pm_domains",
  162. .of_match_table = ti_sci_pm_domain_matches,
  163. },
  164. };
  165. module_platform_driver(ti_sci_pm_domains_driver);
  166. MODULE_LICENSE("GPL v2");
  167. MODULE_DESCRIPTION("TI System Control Interface (SCI) Power Domain driver");
  168. MODULE_AUTHOR("Dave Gerlach");