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 }