1 #include "bflb_audac.h"
2 #include "hardware/audac_reg.h"
3 #include "hardware/dac_reg.h"
4 
5 #if defined(BL616) || defined(BL606P) || defined(BL808) || defined(BL628)
6 #define GLB_BASE ((uint32_t)0x20000000)
7 #endif
8 
9 static volatile uint32_t g_audac_channel_mode = 0;
10 
bflb_audac_init(struct bflb_device_s * dev,const struct bflb_audac_init_config_s * config)11 int bflb_audac_init(struct bflb_device_s *dev, const struct bflb_audac_init_config_s *config)
12 {
13     uint32_t reg_base;
14     uint32_t regval;
15 
16     reg_base = dev->reg_base;
17 
18     /* enable clk, enable dma interface, disable ch0 */
19     regval = getreg32(reg_base + AUDAC_0_OFFSET);
20     regval |= AUDAC_CKG_ENA;
21     regval |= AUDAC_DAC_ITF_EN;
22     regval |= AUDAC_DAC_0_EN;
23 
24     /* set output mode and sampling rate */
25     regval &= ~AUDAC_AU_PWM_MODE_MASK;
26     if (config->output_mode != AUDAC_OUTPUT_MODE_PWM) {
27         regval |= (config->sampling_rate + 8) << AUDAC_AU_PWM_MODE_SHIFT;
28     } else {
29         regval |= config->sampling_rate << AUDAC_AU_PWM_MODE_SHIFT;
30     }
31     putreg32(regval, reg_base + AUDAC_0_OFFSET);
32 
33     regval = getreg32(reg_base + AUDAC_1_OFFSET);
34     /* set dsm dither, scaling, and order */
35     regval &= ~AUDAC_DAC_DSM_SCALING_MODE_MASK;
36     regval |= 3 << AUDAC_DAC_DSM_SCALING_MODE_SHIFT;
37     regval &= ~AUDAC_DAC_DSM_ORDER_MASK;
38     regval |= 1 << AUDAC_DAC_DSM_ORDER_SHIFT;
39 
40     /* set mixer */
41     regval &= ~AUDAC_DAC_MIX_SEL_MASK;
42     if (config->source_channels_num == AUDAC_SOURCE_CHANNEL_DUAL) {
43         regval |= config->mixer_mode << AUDAC_DAC_MIX_SEL_SHIFT;
44     }
45     putreg32(regval, reg_base + AUDAC_1_OFFSET);
46 
47     regval = getreg32(reg_base + AUDAC_FIFO_CTRL_OFFSET);
48     /* data format */
49     regval &= ~AUDAC_TX_DATA_MODE_MASK;
50     regval |= config->data_format;
51 
52     /* fifo threshold */
53     regval &= ~AUDAC_TX_TRG_LEVEL_MASK;
54     regval |= (config->fifo_threshold << AUDAC_TX_TRG_LEVEL_SHIFT) & AUDAC_TX_TRG_LEVEL_MASK;
55     regval &= ~AUDAC_TX_DRQ_CNT_MASK;
56 
57     /* dma disable */
58     regval &= ~AUDAC_TX_DRQ_EN;
59 
60     /* source channels num */
61     regval &= ~AUDAC_TX_CH_EN_MASK;
62     g_audac_channel_mode = config->source_channels_num;
63 
64     /* disable fifo int */
65     regval &= ~AUDAC_TXO_INT_EN;
66     regval &= ~AUDAC_TXU_INT_EN;
67     regval &= ~AUDAC_TXA_INT_EN;
68 
69     /* clear fifo */
70     regval &= ~AUDAC_TX_FIFO_FLUSH;
71     putreg32(regval, reg_base + AUDAC_FIFO_CTRL_OFFSET);
72 
73     /* enable zero delete */
74     regval = getreg32(reg_base + AUDAC_ZD_0_OFFSET);
75     regval |= AUDAC_ZD_EN;
76     regval &= ~AUDAC_ZD_TIME_MASK;
77     regval |= 512 << AUDAC_ZD_TIME_SHIFT;
78     putreg32(regval, reg_base + AUDAC_ZD_0_OFFSET);
79 
80     /* disable volume interrupt */
81     regval = getreg32(reg_base + AUDAC_STATUS_OFFSET);
82     regval |= AUDAC_DAC_S0_INT_CLR;
83     putreg32(regval, reg_base + AUDAC_STATUS_OFFSET);
84 
85     /* gpdac config */
86     reg_base = GLB_BASE;
87     if (config->output_mode != AUDAC_OUTPUT_MODE_PWM) {
88         /* Select Internal reference */
89         regval = getreg32(reg_base + GLB_GPDAC_CTRL_OFFSET);
90         regval |= (GLB_GPDACA_RSTN_ANA | GLB_GPDACB_RSTN_ANA);
91         regval = getreg32(reg_base + GLB_GPDAC_CTRL_OFFSET);
92         regval &= ~GLB_GPDAC_REF_SEL;
93 
94         /* Select the clock and data from aupdac */
95         regval |= GLB_GPDAC_ANA_CLK_SEL;
96         if (config->output_mode & AUDAC_OUTPUT_MODE_GPDAC_CH_A) {
97             regval |= GLB_GPDAC_DAT_CHA_SEL;
98         }
99         if (config->output_mode & AUDAC_OUTPUT_MODE_GPDAC_CH_B) {
100             regval |= GLB_GPDAC_DAT_CHB_SEL;
101         }
102         putreg32(regval, reg_base + GLB_GPDAC_CTRL_OFFSET);
103 
104         if (config->output_mode & AUDAC_OUTPUT_MODE_GPDAC_CH_A) {
105             /* gpdac enable ch-A */
106             regval = getreg32(reg_base + GLB_GPDAC_ACTRL_OFFSET);
107             regval |= (GLB_GPDAC_A_EN | GLB_GPDAC_IOA_EN);
108             putreg32(regval, reg_base + GLB_GPDAC_ACTRL_OFFSET);
109         }
110 
111         if (config->output_mode & AUDAC_OUTPUT_MODE_GPDAC_CH_B) {
112             /* gpdac enable ch-A */
113             regval = getreg32(reg_base + GLB_GPDAC_BCTRL_OFFSET);
114             regval |= (GLB_GPDAC_B_EN | GLB_GPDAC_IOB_EN);
115             putreg32(regval, reg_base + GLB_GPDAC_BCTRL_OFFSET);
116         }
117     }
118 
119     return 0;
120 }
121 
bflb_audac_volume_init(struct bflb_device_s * dev,const struct bflb_audac_volume_config_s * vol_cfg)122 int bflb_audac_volume_init(struct bflb_device_s *dev, const struct bflb_audac_volume_config_s *vol_cfg)
123 {
124     uint32_t reg_base;
125     uint32_t regval;
126 
127     reg_base = dev->reg_base;
128 
129     /* enable volume update */
130     regval = getreg32(reg_base + AUDAC_S0_OFFSET);
131     regval |= AUDAC_DAC_S0_VOLUME_UPDATE;
132 
133     if (vol_cfg->mute_ramp_en) {
134         /* mute ramp mode */
135         regval |= AUDAC_DAC_S0_MUTE_SOFTMODE;
136         regval &= ~AUDAC_DAC_S0_MUTE_RMPDN_RATE_MASK;
137         regval |= vol_cfg->mute_down_ramp_rate << AUDAC_DAC_S0_MUTE_RMPDN_RATE_SHIFT;
138         regval &= ~AUDAC_DAC_S0_MUTE_RMPUP_RATE_MASK;
139         regval |= vol_cfg->mute_up_ramp_rate << AUDAC_DAC_S0_MUTE_RMPUP_RATE_SHIFT;
140 
141     } else {
142         /* mute directly mode */
143         regval &= ~AUDAC_DAC_S0_MUTE_SOFTMODE;
144     }
145 
146     regval &= ~AUDAC_DAC_S0_CTRL_MODE_MASK;
147     if (vol_cfg->volume_update_mode == AUDAC_VOLUME_UPDATE_MODE_RAMP) {
148         /* ramp mode */
149         regval |= 2 << AUDAC_DAC_S0_CTRL_MODE_SHIFT;
150         regval &= ~AUDAC_DAC_S0_CTRL_RMP_RATE_MASK;
151         regval |= vol_cfg->volume_ramp_rate << AUDAC_DAC_S0_CTRL_RMP_RATE_SHIFT;
152     } else if (vol_cfg->volume_update_mode == AUDAC_VOLUME_UPDATE_MODE_RAMP_ZERO_CROSSING) {
153         /* ramp and zero crossing mode */
154         regval |= 1 << AUDAC_DAC_S0_CTRL_MODE_SHIFT;
155         regval &= ~AUDAC_DAC_S0_CTRL_ZCD_RATE_MASK;
156         regval |= vol_cfg->volume_ramp_rate << AUDAC_DAC_S0_CTRL_ZCD_RATE_SHIFT;
157     }
158     putreg32(regval, reg_base + AUDAC_S0_OFFSET);
159 
160     return 0;
161 }
162 
bflb_audac_link_rxdma(struct bflb_device_s * dev,bool enable)163 int bflb_audac_link_rxdma(struct bflb_device_s *dev, bool enable)
164 {
165     uint32_t reg_base;
166     uint32_t regval;
167 
168     reg_base = dev->reg_base;
169 
170     regval = getreg32(reg_base + AUDAC_FIFO_CTRL_OFFSET);
171     if (enable) {
172         regval |= AUDAC_TX_DRQ_EN;
173     } else {
174         regval &= ~AUDAC_TX_DRQ_EN;
175     }
176     putreg32(regval, reg_base + AUDAC_FIFO_CTRL_OFFSET);
177 
178     return 0;
179 }
180 
bflb_audac_int_mask(struct bflb_device_s * dev,uint32_t int_sts)181 int bflb_audac_int_mask(struct bflb_device_s *dev, uint32_t int_sts)
182 {
183     uint32_t reg_base;
184     uint32_t regval;
185 
186     reg_base = dev->reg_base;
187 
188     if (int_sts & AUDAC_INTSTS_VOLUME_RAMP) {
189         /* volume ramp done int */
190         regval = getreg32(reg_base + AUDAC_0_OFFSET);
191         regval &= ~(0x01 << 17);
192         putreg32(regval, reg_base + AUDAC_0_OFFSET);
193 
194         int_sts &= ~AUDAC_INTSTS_VOLUME_RAMP;
195     }
196 
197     if (int_sts) {
198         /* fifo int */
199         regval = getreg32(reg_base + AUDAC_FIFO_CTRL_OFFSET);
200         regval &= ~int_sts;
201         putreg32(regval, reg_base + AUDAC_FIFO_CTRL_OFFSET);
202     }
203 
204     return 0;
205 }
206 
bflb_audac_int_unmask(struct bflb_device_s * dev,uint32_t int_sts)207 int bflb_audac_int_unmask(struct bflb_device_s *dev, uint32_t int_sts)
208 {
209     uint32_t reg_base;
210     uint32_t regval;
211 
212     reg_base = dev->reg_base;
213 
214     if (int_sts & AUDAC_INTSTS_VOLUME_RAMP) {
215         /* volume ramp done int */
216         regval = getreg32(reg_base + AUDAC_0_OFFSET);
217         regval |= (0x01 << 17);
218         putreg32(regval, reg_base + AUDAC_0_OFFSET);
219 
220         int_sts &= ~AUDAC_INTSTS_VOLUME_RAMP;
221     }
222 
223     if (int_sts) {
224         /* fifo int */
225         regval = getreg32(reg_base + AUDAC_FIFO_CTRL_OFFSET);
226         regval |= int_sts;
227         putreg32(regval, reg_base + AUDAC_FIFO_CTRL_OFFSET);
228     }
229 
230     return 0;
231 }
232 
bflb_audac_get_intstatus(struct bflb_device_s * dev)233 int bflb_audac_get_intstatus(struct bflb_device_s *dev)
234 {
235     uint32_t reg_base;
236     uint32_t regval;
237     int32_t int_sts;
238 
239     reg_base = dev->reg_base;
240     int_sts = 0;
241 
242     /* volume ramp done int */
243     regval = getreg32(reg_base + AUDAC_0_OFFSET);
244     if (regval & (0x01 << 17)) {
245         int_sts |= AUDAC_INTSTS_VOLUME_RAMP;
246     }
247 
248     /* fifo int */
249     regval = getreg32(reg_base + AUDAC_FIFO_STATUS_OFFSET);
250     if (regval & AUDAC_TXO_INT) {
251         int_sts |= AUDAC_INTSTS_FIFO_OVER;
252     }
253     if (regval & AUDAC_TXU_INT) {
254         int_sts |= AUDAC_INTSTS_FIFO_UNDER;
255     }
256     if (regval & AUDAC_TXA_INT) {
257         int_sts |= AUDAC_INTSTS_FIFO_AVAILABLE;
258     }
259 
260     return int_sts;
261 }
262 
bflb_audac_int_clear(struct bflb_device_s * dev,uint32_t int_clear)263 int bflb_audac_int_clear(struct bflb_device_s *dev, uint32_t int_clear)
264 {
265     uint32_t reg_base;
266     uint32_t regval;
267     uint8_t ramp_int_en;
268 
269     reg_base = dev->reg_base;
270 
271     if (int_clear & AUDAC_INTSTS_VOLUME_RAMP) {
272         /* volume ramp done int */
273         regval = getreg32(reg_base + AUDAC_0_OFFSET);
274 
275         if (regval & (0x01 << 17)) {
276             ramp_int_en = 0;
277         } else {
278             ramp_int_en = 1;
279         }
280 
281         regval |= (0x01 << 17);
282         putreg32(regval, reg_base + AUDAC_0_OFFSET);
283 
284         if (ramp_int_en) {
285             regval &= ~(0x01 << 17);
286         }
287         putreg32(regval, reg_base + AUDAC_0_OFFSET);
288     }
289 
290     return 0;
291 }
292 
bflb_audac_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)293 int bflb_audac_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
294 {
295     int ret = 0;
296     uint32_t reg_base;
297     uint32_t regval;
298     int16_t volume_val;
299 
300     reg_base = dev->reg_base;
301 
302     switch (cmd) {
303         case AUDAC_CMD_PLAY_START:
304             /* play start */
305             regval = getreg32(reg_base + AUDAC_FIFO_CTRL_OFFSET);
306             regval &= ~AUDAC_TX_CH_EN_MASK;
307             regval |= g_audac_channel_mode << AUDAC_TX_CH_EN_SHIFT;
308             putreg32(regval, reg_base + AUDAC_FIFO_CTRL_OFFSET);
309             g_audac_channel_mode = 0;
310             break;
311 
312         case AUDAC_CMD_PLAY_STOP:
313             /* play stop */
314             regval = getreg32(reg_base + AUDAC_FIFO_CTRL_OFFSET);
315             if (g_audac_channel_mode == 0) {
316                 g_audac_channel_mode = (regval & AUDAC_TX_CH_EN_MASK) >> AUDAC_TX_CH_EN_SHIFT;
317             }
318             regval &= ~AUDAC_TX_CH_EN_MASK;
319             putreg32(regval, reg_base + AUDAC_FIFO_CTRL_OFFSET);
320             break;
321 
322         case AUDAC_CMD_SET_MUTE:
323             /* set mute, arg use true or false */
324             regval = getreg32(reg_base + AUDAC_S0_OFFSET);
325             if (arg) {
326                 regval |= AUDAC_DAC_S0_MUTE;
327             } else {
328                 regval &= ~AUDAC_DAC_S0_MUTE;
329             }
330             putreg32(regval, reg_base + AUDAC_S0_OFFSET);
331             break;
332 
333         case AUDAC_CMD_SET_VOLUME_VAL:
334             /* set volume value dB, arg range -191 to + 36, 0.5dB step, range -95.5dB to +18dB*/
335             volume_val = (uint16_t)((int16_t)arg * 2);
336             regval = getreg32(reg_base + AUDAC_S0_OFFSET);
337             regval &= ~AUDAC_DAC_S0_VOLUME_MASK;
338             regval |= (volume_val << AUDAC_DAC_S0_VOLUME_SHIFT) & AUDAC_DAC_S0_VOLUME_MASK;
339             putreg32(regval, reg_base + AUDAC_S0_OFFSET);
340             break;
341 
342         case AUDAC_CMD_CLEAR_TX_FIFO:
343             /* get tx fifo cnt */
344             regval = getreg32(reg_base + AUDAC_FIFO_CTRL_OFFSET);
345             regval |= AUDAC_TX_FIFO_FLUSH;
346             putreg32(regval, reg_base + AUDAC_FIFO_CTRL_OFFSET);
347             break;
348 
349         case AUDAC_CMD_GET_TX_FIFO_CNT:
350             /* get tx fifo cnt */
351             regval = getreg32(reg_base + AUDAC_FIFO_STATUS_OFFSET);
352             ret = (regval & AUDAC_TXA_CNT_MASK) >> AUDAC_TXA_CNT_SHIFT;
353             break;
354 
355         default:
356             break;
357     }
358 
359     return ret;
360 }