mfd-syscon.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <ioremap.h>
  13. #include <drivers/ofw_io.h>
  14. #include <drivers/syscon.h>
  15. #include <drivers/core/dm.h>
  16. #include <drivers/platform.h>
  17. static RT_DEFINE_SPINLOCK(_syscon_nodes_lock);
  18. static rt_list_t _syscon_nodes = RT_LIST_OBJECT_INIT(_syscon_nodes);
  19. rt_err_t rt_syscon_read(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t *out_val)
  20. {
  21. if (offset < syscon->iomem_size)
  22. {
  23. rt_ubase_t level = rt_spin_lock_irqsave(&syscon->rw_lock);
  24. *out_val = HWREG32(syscon->iomem_base + offset);
  25. rt_spin_unlock_irqrestore(&syscon->rw_lock, level);
  26. return RT_EOK;
  27. }
  28. else
  29. {
  30. return -RT_EINVAL;
  31. }
  32. }
  33. rt_err_t rt_syscon_write(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t val)
  34. {
  35. if (offset < syscon->iomem_size)
  36. {
  37. rt_ubase_t level = rt_spin_lock_irqsave(&syscon->rw_lock);
  38. HWREG32(syscon->iomem_base + offset) = val;
  39. rt_spin_unlock_irqrestore(&syscon->rw_lock, level);
  40. return RT_EOK;
  41. }
  42. else
  43. {
  44. return -RT_EINVAL;
  45. }
  46. }
  47. rt_err_t rt_syscon_update_bits(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t mask, rt_uint32_t val)
  48. {
  49. rt_err_t err;
  50. rt_ubase_t level = rt_spin_lock_irqsave(&syscon->rw_lock);
  51. if (offset < syscon->iomem_size)
  52. {
  53. rt_uint32_t old_val = HWREG32(syscon->iomem_base + offset);
  54. old_val &= ~mask;
  55. HWREG32(syscon->iomem_base + offset) = old_val | val;
  56. err = RT_EOK;
  57. }
  58. else
  59. {
  60. err = -RT_EINVAL;
  61. }
  62. rt_spin_unlock_irqrestore(&syscon->rw_lock, level);
  63. return err;
  64. }
  65. static rt_err_t syscon_probe(struct rt_platform_device *pdev);
  66. struct rt_syscon *rt_syscon_find_by_ofw_node(struct rt_ofw_node *np)
  67. {
  68. rt_ubase_t level;
  69. struct rt_syscon *syscon = RT_NULL, *syscon_tmp;
  70. struct rt_platform_device syscon_pdev;
  71. if (!np)
  72. {
  73. goto _exit;
  74. }
  75. level = rt_spin_lock_irqsave(&_syscon_nodes_lock);
  76. /* ofw_data is not safety */
  77. rt_list_for_each_entry(syscon_tmp, &_syscon_nodes, list)
  78. {
  79. if (syscon_tmp->np == np)
  80. {
  81. syscon = syscon_tmp;
  82. break;
  83. }
  84. }
  85. rt_spin_unlock_irqrestore(&_syscon_nodes_lock, level);
  86. if (syscon)
  87. {
  88. goto _exit;
  89. }
  90. /* Not found, try probe this node */
  91. if (!rt_ofw_node_is_compatible(np, "syscon") &&
  92. !rt_ofw_node_is_compatible(np, "simple-mfd"))
  93. {
  94. goto _exit;
  95. }
  96. syscon_pdev.parent.ofw_node = np;
  97. if (!syscon_probe(&syscon_pdev))
  98. {
  99. syscon = rt_ofw_data(np);
  100. }
  101. _exit:
  102. return syscon;
  103. }
  104. struct rt_syscon *rt_syscon_find_by_ofw_compatible(const char *compatible)
  105. {
  106. struct rt_syscon *syscon = RT_NULL;
  107. struct rt_ofw_node *syscon_np = rt_ofw_find_node_by_compatible(RT_NULL, compatible);
  108. if (syscon_np)
  109. {
  110. syscon = rt_syscon_find_by_ofw_node(syscon_np);
  111. rt_ofw_node_put(syscon_np);
  112. }
  113. return syscon;
  114. }
  115. struct rt_syscon *rt_syscon_find_by_ofw_phandle(struct rt_ofw_node *np, const char *propname)
  116. {
  117. struct rt_syscon *syscon = RT_NULL;
  118. struct rt_ofw_node *syscon_np = rt_ofw_parse_phandle(np, propname, 0);
  119. if (syscon_np)
  120. {
  121. syscon = rt_syscon_find_by_ofw_node(syscon_np);
  122. rt_ofw_node_put(syscon_np);
  123. }
  124. return syscon;
  125. }
  126. static rt_err_t syscon_probe(struct rt_platform_device *pdev)
  127. {
  128. rt_err_t err;
  129. rt_ubase_t level;
  130. struct rt_ofw_node *np;
  131. rt_uint64_t iomem_range[2];
  132. struct rt_syscon *syscon = rt_calloc(1, sizeof(*syscon));
  133. if (!syscon)
  134. {
  135. return -RT_ENOMEM;
  136. }
  137. np = pdev->parent.ofw_node;
  138. if ((err = rt_ofw_get_address(np, 0, &iomem_range[0], &iomem_range[1])))
  139. {
  140. goto _fail;
  141. }
  142. syscon->iomem_size = (rt_size_t)iomem_range[1];
  143. syscon->iomem_base = rt_ioremap((void *)iomem_range[0], syscon->iomem_size);
  144. if (!syscon->iomem_base)
  145. {
  146. goto _fail;
  147. }
  148. rt_list_init(&syscon->list);
  149. level = rt_spin_lock_irqsave(&_syscon_nodes_lock);
  150. rt_list_insert_after(&_syscon_nodes, &syscon->list);
  151. rt_spin_unlock_irqrestore(&_syscon_nodes_lock, level);
  152. rt_spin_lock_init(&syscon->rw_lock);
  153. pdev->parent.user_data = syscon;
  154. syscon->np = pdev->parent.ofw_node;
  155. rt_ofw_data(np) = syscon;
  156. return RT_EOK;
  157. _fail:
  158. rt_free(syscon);
  159. return err;
  160. }
  161. static rt_err_t syscon_remove(struct rt_platform_device *pdev)
  162. {
  163. struct rt_syscon *syscon = pdev->parent.user_data;
  164. rt_iounmap(syscon->iomem_base);
  165. rt_free(syscon);
  166. return RT_EOK;
  167. }
  168. static const struct rt_ofw_node_id syscon_ofw_ids[] =
  169. {
  170. { .compatible = "syscon" },
  171. { /* sentinel */ }
  172. };
  173. static struct rt_platform_driver syscon_driver =
  174. {
  175. .name = "mfd-syscon",
  176. .ids = syscon_ofw_ids,
  177. .probe = syscon_probe,
  178. .remove = syscon_remove,
  179. };
  180. static int syscon_drv_register(void)
  181. {
  182. rt_platform_driver_register(&syscon_driver);
  183. return 0;
  184. }
  185. INIT_SUBSYS_EXPORT(syscon_drv_register);