reset-ti-sci.c 7.8 KB

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