1 #include "bflb_auadc.h"
2 #include "hardware/auadc_reg.h"
3
bflb_auadc_init(struct bflb_device_s * dev,const struct bflb_auadc_init_config_s * config)4 int bflb_auadc_init(struct bflb_device_s *dev, const struct bflb_auadc_init_config_s *config)
5 {
6 uint32_t reg_base;
7 uint32_t regval;
8
9 reg_base = dev->reg_base;
10
11 regval = getreg32(reg_base + AUADC_AUDPDM_TOP_OFFSET);
12 /* enable clk */
13 regval |= AUADC_AUDIO_CKG_EN;
14 /* sampling rate */
15 regval &= ~AUADC_ADC_RATE_MASK;
16 regval |= config->sampling_rate << AUADC_ADC_RATE_SHIFT;
17 putreg32(regval, reg_base + AUADC_AUDPDM_TOP_OFFSET);
18
19 /* disable ch0 and enable dma interface */
20 regval = getreg32(reg_base + AUADC_AUDPDM_ITF_OFFSET);
21 regval &= ~AUADC_ADC_0_EN;
22 regval |= AUADC_ADC_ITF_EN;
23 putreg32(regval, reg_base + AUADC_AUDPDM_ITF_OFFSET);
24
25 /* pdm or adc input */
26 regval = getreg32(reg_base + AUADC_PDM_DAC_0_OFFSET);
27 if (config->input_mode == AUADC_INPUT_MODE_ADC) {
28 regval &= ~AUADC_ADC_0_SRC;
29 } else {
30 regval |= AUADC_ADC_0_SRC;
31 }
32 putreg32(regval, reg_base + AUADC_PDM_DAC_0_OFFSET);
33
34 /* pdm cfg */
35 regval = getreg32(reg_base + AUADC_PDM_PDM_0_OFFSET);
36 if (config->input_mode == AUADC_INPUT_MODE_PDM_L || config->input_mode == AUADC_INPUT_MODE_PDM_R) {
37 /* enable pdm */
38 regval |= AUADC_PDM_0_EN;
39 /* pdm_l or pdm_r input */
40 regval &= ~AUADC_ADC_0_PDM_SEL_MASK;
41 if (config->input_mode == AUADC_INPUT_MODE_PDM_L) {
42 regval |= 0 << AUADC_ADC_0_PDM_SEL_SHIFT;
43 } else if (config->input_mode == AUADC_INPUT_MODE_PDM_R) {
44 regval |= 1 << AUADC_ADC_0_PDM_SEL_SHIFT;
45 }
46 } else {
47 /* disable pdm */
48 regval &= ~AUADC_PDM_0_EN;
49 }
50 putreg32(regval, reg_base + AUADC_PDM_PDM_0_OFFSET);
51
52 regval = getreg32(reg_base + AUADC_AUDADC_CMD_OFFSET);
53 /* audio osr configuration */
54 if (config->input_mode != AUADC_INPUT_MODE_ADC && (config->sampling_rate == AUADC_SAMPLING_RATE_32K || config->sampling_rate == AUADC_SAMPLING_RATE_48K)) {
55 /* osr 64 */
56 regval |= AUADC_AUDADC_AUDIO_OSR_SEL;
57 } else {
58 /* osr 128 */
59 regval &= ~AUADC_AUDADC_AUDIO_OSR_SEL;
60 }
61 putreg32(regval, reg_base + AUADC_AUDADC_CMD_OFFSET);
62
63 /* fifo configuration */
64 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
65 /* data format */
66 regval &= ~AUADC_RX_DATA_MODE_MASK;
67 regval |= config->data_format << AUADC_RX_DATA_MODE_SHIFT;
68
69 /* fifo threshold */
70 regval &= ~AUADC_RX_TRG_LEVEL_MASK;
71 regval |= config->fifo_threshold << AUADC_RX_TRG_LEVEL_SHIFT;
72 regval &= ~AUADC_RX_DRQ_CNT_MASK;
73
74 /* disable record */
75 regval &= ~AUADC_RX_CH_EN;
76
77 /* 24bit sample */
78 regval &= ~AUADC_RX_DATA_RES_MASK;
79 regval |= 2 << AUADC_RX_DATA_RES_SHIFT;
80
81 /* disable fifo dma and int */
82 regval &= ~AUADC_RX_DRQ_EN;
83 regval &= ~AUADC_RXA_INT_EN;
84 regval &= ~AUADC_RXU_INT_EN;
85 regval &= ~AUADC_RXO_INT_EN;
86
87 /* clear fifo */
88 regval |= AUADC_RX_FIFO_FLUSH;
89 putreg32(regval, reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
90
91 /* enable ch0 */
92 regval = getreg32(reg_base + AUADC_AUDPDM_ITF_OFFSET);
93 regval |= AUADC_ADC_0_EN;
94 putreg32(regval, reg_base + AUADC_AUDPDM_ITF_OFFSET);
95
96 return 0;
97 }
98
bflb_auadc_adc_init(struct bflb_device_s * dev,const struct bflb_auadc_adc_init_config_s * adc_analog_cfg)99 int bflb_auadc_adc_init(struct bflb_device_s *dev, const struct bflb_auadc_adc_init_config_s *adc_analog_cfg)
100 {
101 uint32_t reg_base;
102 uint32_t regval;
103
104 reg_base = dev->reg_base;
105
106 if (adc_analog_cfg->auadc_analog_en == false) {
107 /* disable analog and channel */
108 regval = getreg32(reg_base + AUADC_AUDADC_CMD_OFFSET);
109 regval &= ~AUADC_AUDADC_PGA_PU;
110 regval &= ~AUADC_AUDADC_SDM_PU;
111 regval &= ~AUADC_AUDADC_CHANNEL_EN_MASK;
112 putreg32(regval, reg_base + AUADC_AUDADC_CMD_OFFSET);
113 return 0;
114 }
115
116 /* power up, and SDM reset */
117 regval = getreg32(reg_base + AUADC_AUDADC_CMD_OFFSET);
118 regval |= AUADC_AUDADC_PGA_PU;
119 regval |= AUADC_AUDADC_SDM_PU;
120 regval &= ~AUADC_AUDADC_CONV;
121 putreg32(regval, reg_base + AUADC_AUDADC_CMD_OFFSET);
122
123 /* select analog channel */
124 regval &= ~AUADC_AUDADC_CHANNEL_SELP_MASK;
125 regval &= ~AUADC_AUDADC_CHANNEL_SELN_MASK;
126 regval |= adc_analog_cfg->adc_pga_posi_ch << AUADC_AUDADC_CHANNEL_SELP_SHIFT;
127 regval |= adc_analog_cfg->adc_pga_nega_ch << AUADC_AUDADC_CHANNEL_SELN_SHIFT;
128
129 /* PGA mode */
130 regval &= ~AUADC_AUDADC_PGA_MODE_MASK;
131 regval |= adc_analog_cfg->adc_pga_mode << AUADC_AUDADC_PGA_MODE_SHIFT;
132
133 /* PGA gain */
134 regval &= ~AUADC_AUDADC_PGA_GAIN_MASK;
135 regval |= (adc_analog_cfg->adc_pga_gain / 3) << AUADC_AUDADC_PGA_GAIN_SHIFT;
136
137 /* adc mode */
138 if (adc_analog_cfg->adc_mode == AUADC_ADC_MODE_AUDIO) {
139 regval &= ~AUADC_AUDADC_MEAS_FILTER_EN;
140 } else {
141 regval |= AUADC_AUDADC_MEAS_FILTER_EN;
142 }
143
144 /* measuring mode rate */
145 regval &= ~AUADC_AUDADC_MEAS_ODR_SEL_MASK;
146 regval |= adc_analog_cfg->adc_measure_rate << AUADC_AUDADC_MEAS_ODR_SEL_SHIFT;
147
148 /* enable analog channel */
149 regval &= ~AUADC_AUDADC_CHANNEL_EN_MASK;
150 if (adc_analog_cfg->adc_pga_mode == AUADC_ADC_PGA_MODE_AC_DIFFER || adc_analog_cfg->adc_pga_mode == AUADC_ADC_PGA_MODE_DC_DIFFER) {
151 regval |= 0x03 << AUADC_AUDADC_CHANNEL_EN_SHIFT;
152 } else {
153 regval |= 0x02 << AUADC_AUDADC_CHANNEL_EN_SHIFT;
154 }
155 putreg32(regval, reg_base + AUADC_AUDADC_CMD_OFFSET);
156
157 /* SDM conversion start */
158 regval |= AUADC_AUDADC_CONV;
159 putreg32(regval, reg_base + AUADC_AUDADC_CMD_OFFSET);
160
161 return 0;
162 }
163
bflb_auadc_link_rxdma(struct bflb_device_s * dev,bool enable)164 int bflb_auadc_link_rxdma(struct bflb_device_s *dev, bool enable)
165 {
166 uint32_t reg_base;
167 uint32_t regval;
168
169 reg_base = dev->reg_base;
170
171 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
172 if (enable) {
173 regval |= AUADC_RX_DRQ_EN;
174 } else {
175 regval &= ~AUADC_RX_DRQ_EN;
176 }
177 putreg32(regval, reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
178
179 return 0;
180 }
181
bflb_auadc_int_mask(struct bflb_device_s * dev,uint32_t int_sts)182 int bflb_auadc_int_mask(struct bflb_device_s *dev, uint32_t int_sts)
183 {
184 uint32_t reg_base;
185 uint32_t regval;
186
187 reg_base = dev->reg_base;
188
189 /* fifo int */
190 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
191 regval &= ~int_sts;
192 putreg32(regval, reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
193
194 return 0;
195 }
196
bflb_auadc_int_unmask(struct bflb_device_s * dev,uint32_t int_sts)197 int bflb_auadc_int_unmask(struct bflb_device_s *dev, uint32_t int_sts)
198 {
199 uint32_t reg_base;
200 uint32_t regval;
201
202 reg_base = dev->reg_base;
203
204 /* fifo int */
205 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
206 regval |= int_sts;
207 putreg32(regval, reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
208
209 return 0;
210 }
211
bflb_auadc_get_intstatus(struct bflb_device_s * dev)212 int bflb_auadc_get_intstatus(struct bflb_device_s *dev)
213 {
214 uint32_t reg_base;
215 uint32_t regval;
216 int32_t int_sts;
217
218 reg_base = dev->reg_base;
219 int_sts = 0;
220
221 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_STATUS_OFFSET);
222 if (regval & AUADC_RXO_INT) {
223 int_sts |= AUADC_INTSTS_FIFO_OVER;
224 }
225 if (regval & AUADC_RXU_INT) {
226 int_sts |= AUADC_INTSTS_FIFO_UNDER;
227 }
228 if (regval & AUADC_RXA_INT) {
229 int_sts |= AUADC_INTSTS_FIFO_AVAILABLE;
230 }
231
232 return int_sts;
233 }
234
bflb_auadc_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)235 int bflb_auadc_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
236 {
237 int ret = 0;
238 uint32_t reg_base;
239 uint32_t regval;
240 int16_t volume_val;
241
242 reg_base = dev->reg_base;
243
244 switch (cmd) {
245 case AUADC_CMD_RECORD_START:
246 /* record start */
247 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
248 regval |= AUADC_RX_CH_EN;
249 putreg32(regval, reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
250 break;
251
252 case AUADC_CMD_RECORD_STOP:
253 /* record stop */
254 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
255 regval &= ~AUADC_RX_CH_EN;
256 putreg32(regval, reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
257 break;
258
259 case AUADC_CMD_SET_VOLUME_VAL:
260 /* set volume value dB, arg range -191 to + 36, 0.5dB step, range -95.5dB to +18dB*/
261 volume_val = (uint16_t)((int16_t)arg * 2);
262 regval = getreg32(reg_base + AUADC_PDM_ADC_S0_OFFSET);
263 regval &= ~AUADC_ADC_S0_VOLUME_MASK;
264 regval |= (volume_val << AUADC_ADC_S0_VOLUME_SHIFT) & AUADC_ADC_S0_VOLUME_MASK;
265 putreg32(regval, reg_base + AUADC_PDM_ADC_S0_OFFSET);
266 break;
267
268 case AUADC_CMD_SET_PGA_GAIN_VAL:
269 /* set adc pga gain, range 6dB ~ 42dB, step by 3db */
270 volume_val = arg / 3;
271 regval = getreg32(reg_base + AUADC_AUDADC_CMD_OFFSET);
272 regval &= ~AUADC_AUDADC_PGA_GAIN_MASK;
273 regval |= (volume_val << AUADC_AUDADC_PGA_GAIN_SHIFT) & AUADC_AUDADC_PGA_GAIN_MASK;
274 putreg32(regval, reg_base + AUADC_AUDADC_CMD_OFFSET);
275 break;
276
277 case AUADC_CMD_CLEAR_RX_FIFO:
278 /* get rx fifo cnt */
279 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
280 regval |= AUADC_RX_FIFO_FLUSH;
281 putreg32(regval, reg_base + AUADC_AUDADC_RX_FIFO_CTRL_OFFSET);
282 break;
283
284 case AUADC_CMD_GET_RX_FIFO_CNT:
285 /* get rx fifo cnt */
286 regval = getreg32(reg_base + AUADC_AUDADC_RX_FIFO_STATUS_OFFSET);
287 ret = (regval & AUADC_RXA_CNT_MASK) >> AUADC_RXA_CNT_SHIFT;
288 }
289
290 return ret;
291 }