reset-ti-sci.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Texas Instrument's System Control Interface (TI-SCI) reset driver
  3. *
  4. * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
  5. * Andrew F. Davis <afd@ti.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  12. * kind, whether express or implied; without even the implied warranty
  13. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/idr.h>
  17. #include <linux/module.h>
  18. #include <linux/mutex.h>
  19. #include <linux/of.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/reset-controller.h>
  22. #include <linux/soc/ti/ti_sci_protocol.h>
  23. /**
  24. * struct ti_sci_reset_control - reset control structure
  25. * @dev_id: SoC-specific device identifier
  26. * @reset_mask: reset mask to use for toggling reset
  27. * @lock: synchronize reset_mask read-modify-writes
  28. */
  29. struct ti_sci_reset_control {
  30. u32 dev_id;
  31. u32 reset_mask;
  32. struct mutex lock;
  33. };
  34. /**
  35. * struct ti_sci_reset_data - reset controller information structure
  36. * @rcdev: reset controller entity
  37. * @dev: reset controller device pointer
  38. * @sci: TI SCI handle used for communication with system controller
  39. * @idr: idr structure for mapping ids to reset control structures
  40. */
  41. struct ti_sci_reset_data {
  42. struct reset_controller_dev rcdev;
  43. struct device *dev;
  44. const struct ti_sci_handle *sci;
  45. struct idr idr;
  46. };
  47. #define to_ti_sci_reset_data(p) \
  48. container_of((p), struct ti_sci_reset_data, rcdev)
  49. /**
  50. * ti_sci_reset_set() - program a device's reset
  51. * @rcdev: reset controller entity
  52. * @id: ID of the reset to toggle
  53. * @assert: boolean flag to indicate assert or deassert
  54. *
  55. * This is a common internal function used to assert or deassert a device's
  56. * reset using the TI SCI protocol. The device's reset is asserted if the
  57. * @assert argument is true, or deasserted if @assert argument is false.
  58. * The mechanism itself is a read-modify-write procedure, the current device
  59. * reset register is read using a TI SCI device operation, the new value is
  60. * set or un-set using the reset's mask, and the new reset value written by
  61. * using another TI SCI device operation.
  62. *
  63. * Return: 0 for successful request, else a corresponding error value
  64. */
  65. static int ti_sci_reset_set(struct reset_controller_dev *rcdev,
  66. unsigned long id, bool assert)
  67. {
  68. struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
  69. const struct ti_sci_handle *sci = data->sci;
  70. const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
  71. struct ti_sci_reset_control *control;
  72. u32 reset_state;
  73. int ret;
  74. control = idr_find(&data->idr, id);
  75. if (!control)
  76. return -EINVAL;
  77. mutex_lock(&control->lock);
  78. ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
  79. if (ret)
  80. goto out;
  81. if (assert)
  82. reset_state |= control->reset_mask;
  83. else
  84. reset_state &= ~control->reset_mask;
  85. ret = dev_ops->set_device_resets(sci, control->dev_id, reset_state);
  86. out:
  87. mutex_unlock(&control->lock);
  88. return ret;
  89. }
  90. /**
  91. * ti_sci_reset_assert() - assert device reset
  92. * @rcdev: reset controller entity
  93. * @id: ID of the reset to be asserted
  94. *
  95. * This function implements the reset driver op to assert a device's reset
  96. * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
  97. * with the corresponding parameters as passed in, but with the @assert
  98. * argument set to true for asserting the reset.
  99. *
  100. * Return: 0 for successful request, else a corresponding error value
  101. */
  102. static int ti_sci_reset_assert(struct reset_controller_dev *rcdev,
  103. unsigned long id)
  104. {
  105. return ti_sci_reset_set(rcdev, id, true);
  106. }
  107. /**
  108. * ti_sci_reset_deassert() - deassert device reset
  109. * @rcdev: reset controller entity
  110. * @id: ID of the reset to be deasserted
  111. *
  112. * This function implements the reset driver op to deassert a device's reset
  113. * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
  114. * with the corresponding parameters as passed in, but with the @assert
  115. * argument set to false for deasserting the reset.
  116. *
  117. * Return: 0 for successful request, else a corresponding error value
  118. */
  119. static int ti_sci_reset_deassert(struct reset_controller_dev *rcdev,
  120. unsigned long id)
  121. {
  122. return ti_sci_reset_set(rcdev, id, false);
  123. }
  124. /**
  125. * ti_sci_reset_status() - check device reset status
  126. * @rcdev: reset controller entity
  127. * @id: ID of reset to be checked
  128. *
  129. * This function implements the reset driver op to return the status of a
  130. * device's reset using the TI SCI protocol. The reset register value is read
  131. * by invoking the TI SCI device operation .get_device_resets(), and the
  132. * status of the specific reset is extracted and returned using this reset's
  133. * reset mask.
  134. *
  135. * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted
  136. */
  137. static int ti_sci_reset_status(struct reset_controller_dev *rcdev,
  138. unsigned long id)
  139. {
  140. struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
  141. const struct ti_sci_handle *sci = data->sci;
  142. const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
  143. struct ti_sci_reset_control *control;
  144. u32 reset_state;
  145. int ret;
  146. control = idr_find(&data->idr, id);
  147. if (!control)
  148. return -EINVAL;
  149. ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
  150. if (ret)
  151. return ret;
  152. return reset_state & control->reset_mask;
  153. }
  154. static const struct reset_control_ops ti_sci_reset_ops = {
  155. .assert = ti_sci_reset_assert,
  156. .deassert = ti_sci_reset_deassert,
  157. .status = ti_sci_reset_status,
  158. };
  159. /**
  160. * ti_sci_reset_of_xlate() - translate a set of OF arguments to a reset ID
  161. * @rcdev: reset controller entity
  162. * @reset_spec: OF reset argument specifier
  163. *
  164. * This function performs the translation of the reset argument specifier
  165. * values defined in a reset consumer device node. The function allocates a
  166. * reset control structure for that device reset, and will be used by the
  167. * driver for performing any reset functions on that reset. An idr structure
  168. * is allocated and used to map to the reset control structure. This idr
  169. * is used by the driver to do reset lookups.
  170. *
  171. * Return: 0 for successful request, else a corresponding error value
  172. */
  173. static int ti_sci_reset_of_xlate(struct reset_controller_dev *rcdev,
  174. const struct of_phandle_args *reset_spec)
  175. {
  176. struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
  177. struct ti_sci_reset_control *control;
  178. if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
  179. return -EINVAL;
  180. control = devm_kzalloc(data->dev, sizeof(*control), GFP_KERNEL);
  181. if (!control)
  182. return -ENOMEM;
  183. control->dev_id = reset_spec->args[0];
  184. control->reset_mask = reset_spec->args[1];
  185. mutex_init(&control->lock);
  186. return idr_alloc(&data->idr, control, 0, 0, GFP_KERNEL);
  187. }
  188. static const struct of_device_id ti_sci_reset_of_match[] = {
  189. { .compatible = "ti,sci-reset", },
  190. { /* sentinel */ },
  191. };
  192. MODULE_DEVICE_TABLE(of, ti_sci_reset_of_match);
  193. static int ti_sci_reset_probe(struct platform_device *pdev)
  194. {
  195. struct ti_sci_reset_data *data;
  196. if (!pdev->dev.of_node)
  197. return -ENODEV;
  198. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  199. if (!data)
  200. return -ENOMEM;
  201. data->sci = devm_ti_sci_get_handle(&pdev->dev);
  202. if (IS_ERR(data->sci))
  203. return PTR_ERR(data->sci);
  204. data->rcdev.ops = &ti_sci_reset_ops;
  205. data->rcdev.owner = THIS_MODULE;
  206. data->rcdev.of_node = pdev->dev.of_node;
  207. data->rcdev.of_reset_n_cells = 2;
  208. data->rcdev.of_xlate = ti_sci_reset_of_xlate;
  209. data->dev = &pdev->dev;
  210. idr_init(&data->idr);
  211. platform_set_drvdata(pdev, data);
  212. return reset_controller_register(&data->rcdev);
  213. }
  214. static int ti_sci_reset_remove(struct platform_device *pdev)
  215. {
  216. struct ti_sci_reset_data *data = platform_get_drvdata(pdev);
  217. reset_controller_unregister(&data->rcdev);
  218. idr_destroy(&data->idr);
  219. return 0;
  220. }
  221. static struct platform_driver ti_sci_reset_driver = {
  222. .probe = ti_sci_reset_probe,
  223. .remove = ti_sci_reset_remove,
  224. .driver = {
  225. .name = "ti-sci-reset",
  226. .of_match_table = ti_sci_reset_of_match,
  227. },
  228. };
  229. module_platform_driver(ti_sci_reset_driver);
  230. MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
  231. MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver");
  232. MODULE_LICENSE("GPL v2");