drv_adc.c 6.5 KB

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