reset-sunplus.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /*
  3. * SP7021 reset driver
  4. *
  5. * Copyright (C) Sunplus Technology Co., Ltd.
  6. * All rights reserved.
  7. */
  8. #include <linux/io.h>
  9. #include <linux/init.h>
  10. #include <linux/mod_devicetable.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/reset-controller.h>
  13. #include <linux/reboot.h>
  14. /* HIWORD_MASK_REG BITS */
  15. #define BITS_PER_HWM_REG 16
  16. /* resets HW info: reg_index_shift */
  17. static const u32 sp_resets[] = {
  18. /* SP7021: mo_reset0 ~ mo_reset9 */
  19. 0x00,
  20. 0x02,
  21. 0x03,
  22. 0x04,
  23. 0x05,
  24. 0x06,
  25. 0x07,
  26. 0x08,
  27. 0x09,
  28. 0x0a,
  29. 0x0b,
  30. 0x0d,
  31. 0x0e,
  32. 0x0f,
  33. 0x10,
  34. 0x12,
  35. 0x14,
  36. 0x15,
  37. 0x16,
  38. 0x17,
  39. 0x18,
  40. 0x19,
  41. 0x1a,
  42. 0x1b,
  43. 0x1c,
  44. 0x1d,
  45. 0x1e,
  46. 0x1f,
  47. 0x20,
  48. 0x21,
  49. 0x22,
  50. 0x23,
  51. 0x24,
  52. 0x25,
  53. 0x26,
  54. 0x2a,
  55. 0x2b,
  56. 0x2d,
  57. 0x2e,
  58. 0x30,
  59. 0x31,
  60. 0x32,
  61. 0x33,
  62. 0x3d,
  63. 0x3e,
  64. 0x3f,
  65. 0x42,
  66. 0x44,
  67. 0x4b,
  68. 0x4c,
  69. 0x4d,
  70. 0x4e,
  71. 0x4f,
  72. 0x50,
  73. 0x55,
  74. 0x60,
  75. 0x61,
  76. 0x6a,
  77. 0x6f,
  78. 0x70,
  79. 0x73,
  80. 0x74,
  81. 0x86,
  82. 0x8a,
  83. 0x8b,
  84. 0x8d,
  85. 0x8e,
  86. 0x8f,
  87. 0x90,
  88. 0x92,
  89. 0x93,
  90. 0x94,
  91. 0x95,
  92. 0x96,
  93. 0x97,
  94. 0x98,
  95. 0x99,
  96. };
  97. struct sp_reset {
  98. struct reset_controller_dev rcdev;
  99. struct notifier_block notifier;
  100. void __iomem *base;
  101. };
  102. static inline struct sp_reset *to_sp_reset(struct reset_controller_dev *rcdev)
  103. {
  104. return container_of(rcdev, struct sp_reset, rcdev);
  105. }
  106. static int sp_reset_update(struct reset_controller_dev *rcdev,
  107. unsigned long id, bool assert)
  108. {
  109. struct sp_reset *reset = to_sp_reset(rcdev);
  110. int index = sp_resets[id] / BITS_PER_HWM_REG;
  111. int shift = sp_resets[id] % BITS_PER_HWM_REG;
  112. u32 val;
  113. val = (1 << (16 + shift)) | (assert << shift);
  114. writel(val, reset->base + (index * 4));
  115. return 0;
  116. }
  117. static int sp_reset_assert(struct reset_controller_dev *rcdev,
  118. unsigned long id)
  119. {
  120. return sp_reset_update(rcdev, id, true);
  121. }
  122. static int sp_reset_deassert(struct reset_controller_dev *rcdev,
  123. unsigned long id)
  124. {
  125. return sp_reset_update(rcdev, id, false);
  126. }
  127. static int sp_reset_status(struct reset_controller_dev *rcdev,
  128. unsigned long id)
  129. {
  130. struct sp_reset *reset = to_sp_reset(rcdev);
  131. int index = sp_resets[id] / BITS_PER_HWM_REG;
  132. int shift = sp_resets[id] % BITS_PER_HWM_REG;
  133. u32 reg;
  134. reg = readl(reset->base + (index * 4));
  135. return !!(reg & BIT(shift));
  136. }
  137. static const struct reset_control_ops sp_reset_ops = {
  138. .assert = sp_reset_assert,
  139. .deassert = sp_reset_deassert,
  140. .status = sp_reset_status,
  141. };
  142. static int sp_restart(struct notifier_block *nb, unsigned long mode,
  143. void *cmd)
  144. {
  145. struct sp_reset *reset = container_of(nb, struct sp_reset, notifier);
  146. sp_reset_assert(&reset->rcdev, 0);
  147. sp_reset_deassert(&reset->rcdev, 0);
  148. return NOTIFY_DONE;
  149. }
  150. static int sp_reset_probe(struct platform_device *pdev)
  151. {
  152. struct device *dev = &pdev->dev;
  153. struct sp_reset *reset;
  154. struct resource *res;
  155. int ret;
  156. reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
  157. if (!reset)
  158. return -ENOMEM;
  159. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  160. reset->base = devm_ioremap_resource(dev, res);
  161. if (IS_ERR(reset->base))
  162. return PTR_ERR(reset->base);
  163. reset->rcdev.ops = &sp_reset_ops;
  164. reset->rcdev.owner = THIS_MODULE;
  165. reset->rcdev.of_node = dev->of_node;
  166. reset->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_HWM_REG;
  167. ret = devm_reset_controller_register(dev, &reset->rcdev);
  168. if (ret)
  169. return ret;
  170. reset->notifier.notifier_call = sp_restart;
  171. reset->notifier.priority = 192;
  172. return register_restart_handler(&reset->notifier);
  173. }
  174. static const struct of_device_id sp_reset_dt_ids[] = {
  175. {.compatible = "sunplus,sp7021-reset",},
  176. { /* sentinel */ },
  177. };
  178. static struct platform_driver sp_reset_driver = {
  179. .probe = sp_reset_probe,
  180. .driver = {
  181. .name = "sunplus-reset",
  182. .of_match_table = sp_reset_dt_ids,
  183. .suppress_bind_attrs = true,
  184. },
  185. };
  186. builtin_platform_driver(sp_reset_driver);