drv_adc.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024/02/22 flyingcys first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include "drv_adc.h"
  13. #include "drv_pinmux.h"
  14. #include "drv_ioremap.h"
  15. #define DBG_LEVEL DBG_LOG
  16. #include <rtdbg.h>
  17. #define LOG_TAG "DRV.ADC"
  18. rt_inline void cvi_set_saradc_ctrl(unsigned long reg_base, rt_uint32_t value)
  19. {
  20. value |= mmio_read_32(reg_base + SARADC_CTRL_OFFSET);
  21. mmio_write_32(reg_base + SARADC_CTRL_OFFSET, value);
  22. }
  23. rt_inline void cvi_reset_saradc_ctrl(unsigned long reg_base, rt_uint32_t value)
  24. {
  25. value = mmio_read_32(reg_base + SARADC_CTRL_OFFSET) & ~value;
  26. mmio_write_32(reg_base + SARADC_CTRL_OFFSET, value);
  27. }
  28. rt_inline rt_uint32_t cvi_get_saradc_status(unsigned long reg_base)
  29. {
  30. return((rt_uint32_t)mmio_read_32(reg_base + SARADC_STATUS_OFFSET));
  31. }
  32. rt_inline void cvi_set_cyc(unsigned long reg_base)
  33. {
  34. rt_uint32_t value;
  35. value = mmio_read_32(reg_base + SARADC_CYC_SET_OFFSET);
  36. value &= ~SARADC_CYC_CLKDIV_DIV_16;
  37. mmio_write_32(reg_base + SARADC_CYC_SET_OFFSET, value);
  38. value |= SARADC_CYC_CLKDIV_DIV_16; //set saradc clock cycle=840ns
  39. mmio_write_32(reg_base + SARADC_CYC_SET_OFFSET, value);
  40. }
  41. rt_inline void cvi_do_calibration(unsigned long reg_base)
  42. {
  43. rt_uint32_t val;
  44. val = mmio_read_32(reg_base + SARADC_TEST_OFFSET);
  45. val |= 1 << SARADC_TEST_VREFSEL_BIT;
  46. mmio_write_32(reg_base + SARADC_TEST_OFFSET, val);
  47. val = mmio_read_32(reg_base + SARADC_TRIM_OFFSET);
  48. val |= 0x4;
  49. mmio_write_32(reg_base + SARADC_TRIM_OFFSET, val);
  50. }
  51. struct cvi_adc_dev
  52. {
  53. struct rt_adc_device device;
  54. const char *name;
  55. rt_ubase_t base;
  56. };
  57. static struct cvi_adc_dev adc_dev_config[] =
  58. {
  59. #ifdef BSP_USING_ADC_ACTIVE
  60. {
  61. .name = "adc1",
  62. .base = SARADC_BASE
  63. },
  64. #endif /* BSP_USING_ADC_ACTIVE */
  65. #ifdef BSP_USING_ADC_NODIE
  66. {
  67. .name = "adc2",
  68. .base = RTC_ADC_BASE
  69. },
  70. #endif /* BSP_USING_ADC_NODIE */
  71. };
  72. static rt_err_t _adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled)
  73. {
  74. struct cvi_adc_dev *adc_dev = (struct cvi_adc_dev *)device->parent.user_data;
  75. uint32_t value;
  76. RT_ASSERT(adc_dev != RT_NULL);
  77. if (channel > SARADC_CH_MAX)
  78. return -RT_EINVAL;
  79. if (enabled)
  80. {
  81. //set channel
  82. cvi_set_saradc_ctrl(adc_dev->base, (rt_uint32_t)channel << (SARADC_CTRL_SEL_POS + 1));
  83. //set saradc clock cycle
  84. cvi_set_cyc(adc_dev->base);
  85. //start
  86. cvi_set_saradc_ctrl(adc_dev->base, SARADC_CTRL_START);
  87. LOG_D("enable saradc...");
  88. }
  89. else
  90. {
  91. cvi_reset_saradc_ctrl(adc_dev->base, (rt_uint32_t)channel << (SARADC_CTRL_SEL_POS + 1));
  92. LOG_D("disable saradc...");
  93. }
  94. return RT_EOK;
  95. }
  96. static rt_err_t _adc_convert(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value)
  97. {
  98. struct cvi_adc_dev *adc_dev = (struct cvi_adc_dev *)device->parent.user_data;
  99. rt_uint32_t result;
  100. rt_uint32_t cnt = 0;
  101. RT_ASSERT(adc_dev != RT_NULL);
  102. if (channel > SARADC_CH_MAX)
  103. return -RT_EINVAL;
  104. while (cvi_get_saradc_status(adc_dev->base) & SARADC_STATUS_BUSY)
  105. {
  106. rt_thread_delay(10);
  107. LOG_D("wait saradc ready");
  108. cnt ++;
  109. if (cnt > 100)
  110. return -RT_ETIMEOUT;
  111. }
  112. result = mmio_read_32(adc_dev->base + SARADC_RESULT(channel - 1));
  113. if (result & SARADC_RESULT_VALID)
  114. {
  115. *value = result & SARADC_RESULT_MASK;
  116. LOG_D("saradc channel %d value: %04x", channel, *value);
  117. }
  118. else
  119. {
  120. LOG_E("saradc channel %d read failed. result:0x%04x", channel, result);
  121. return -RT_ERROR;
  122. }
  123. return RT_EOK;
  124. }
  125. static const struct rt_adc_ops _adc_ops =
  126. {
  127. .enabled = _adc_enabled,
  128. .convert = _adc_convert,
  129. };
  130. #if defined(BOARD_TYPE_MILKV_DUO)
  131. /*
  132. * cv180xb supports
  133. * - adc1 & adc2 for active domain
  134. * - adc3 for no-die domain
  135. */
  136. #ifdef BSP_USING_ADC_ACTIVE
  137. static const char *pinname_whitelist_adc1_active[] = {
  138. "ADC1",
  139. NULL,
  140. };
  141. static const char *pinname_whitelist_adc2_active[] = {
  142. NULL,
  143. };
  144. static const char *pinname_whitelist_adc3_active[] = {
  145. NULL,
  146. };
  147. #endif
  148. #ifdef BSP_USING_ADC_NODIE
  149. static const char *pinname_whitelist_adc1_nodie[] = {
  150. "PWR_GPIO2",
  151. NULL,
  152. };
  153. static const char *pinname_whitelist_adc2_nodie[] = {
  154. "PWR_GPIO1",
  155. NULL,
  156. };
  157. static const char *pinname_whitelist_adc3_nodie[] = {
  158. "PWR_VBAT_DET",
  159. NULL,
  160. };
  161. #endif
  162. #elif defined(BOARD_TYPE_MILKV_DUO256M)
  163. /*
  164. * sg2002 supports
  165. * - adc1 for active domain
  166. * - adc1/adc2/adc3 for no-die domain
  167. */
  168. #ifdef BSP_USING_ADC_ACTIVE
  169. static const char *pinname_whitelist_adc1_active[] = {
  170. "ADC1",
  171. NULL,
  172. };
  173. static const char *pinname_whitelist_adc2_active[] = {
  174. NULL,
  175. };
  176. static const char *pinname_whitelist_adc3_active[] = {
  177. NULL,
  178. };
  179. #endif
  180. #ifdef BSP_USING_ADC_NODIE
  181. static const char *pinname_whitelist_adc1_nodie[] = {
  182. "PWR_GPIO2",
  183. NULL,
  184. };
  185. static const char *pinname_whitelist_adc2_nodie[] = {
  186. "PWR_GPIO1",
  187. NULL,
  188. };
  189. static const char *pinname_whitelist_adc3_nodie[] = {
  190. "PWR_VBAT_DET",
  191. NULL,
  192. };
  193. #endif
  194. #else
  195. #error "Unsupported board type!"
  196. #endif
  197. static void rt_hw_adc_pinmux_config()
  198. {
  199. #ifdef BSP_USING_ADC_ACTIVE
  200. pinmux_config(BSP_ACTIVE_ADC1_PINNAME, XGPIOB_3, pinname_whitelist_adc1_active);
  201. pinmux_config(BSP_ACTIVE_ADC2_PINNAME, XGPIOB_6, pinname_whitelist_adc2_active);
  202. /* cv1800b & sg2002 don't support ADC3 either in active domain */
  203. #endif
  204. #ifdef BSP_USING_ADC_NODIE
  205. pinmux_config(BSP_NODIE_ADC1_PINNAME, PWR_GPIO_2, pinname_whitelist_adc1_nodie);
  206. pinmux_config(BSP_NODIE_ADC2_PINNAME, PWR_GPIO_1, pinname_whitelist_adc2_nodie);
  207. pinmux_config(BSP_NODIE_ADC3_PINNAME, PWR_VBAT_DET, pinname_whitelist_adc3_nodie);
  208. #endif
  209. }
  210. int rt_hw_adc_init(void)
  211. {
  212. rt_uint8_t i;
  213. for (i = 0; i < sizeof(adc_dev_config) / sizeof(adc_dev_config[0]); i++)
  214. {
  215. if (!rt_strcmp(adc_dev_config[i].name, "adc1"))
  216. {
  217. adc_dev_config[i].base = (rt_ubase_t)DRV_IOREMAP(SARADC_BASE, 0x10000);
  218. }
  219. else if (!rt_strcmp(adc_dev_config[i].name, "adc2"))
  220. {
  221. adc_dev_config[i].base = (rt_ubase_t)DRV_IOREMAP(RTC_ADC_BASE, 0x1000);
  222. }
  223. }
  224. rt_hw_adc_pinmux_config();
  225. for (i = 0; i < sizeof(adc_dev_config) / sizeof(adc_dev_config[0]); i++)
  226. {
  227. cvi_do_calibration(adc_dev_config[i].base);
  228. if (rt_hw_adc_register(&adc_dev_config[i].device, adc_dev_config[i].name, &_adc_ops, &adc_dev_config[i]) != RT_EOK)
  229. {
  230. LOG_E("%s register failed!", adc_dev_config[i].name);
  231. return -RT_ERROR;
  232. }
  233. }
  234. return RT_EOK;
  235. }
  236. INIT_DEVICE_EXPORT(rt_hw_adc_init);