1 #include "bflb_i2s.h"
2 #include "bflb_clock.h"
3 #include "hardware/i2s_reg.h"
4 
bflb_i2s_init(struct bflb_device_s * dev,const struct bflb_i2s_config_s * config)5 void bflb_i2s_init(struct bflb_device_s *dev, const struct bflb_i2s_config_s *config)
6 {
7     uint32_t reg_base;
8     uint32_t regval;
9     uint32_t div;
10 
11     reg_base = dev->reg_base;
12 
13     regval = getreg32(reg_base + I2S_CONFIG_OFFSET);
14     /* disable I2S */
15     regval &= ~I2S_CR_I2S_M_EN;
16     regval &= ~I2S_CR_I2S_S_EN;
17     regval &= ~I2S_CR_I2S_TXD_EN;
18     regval &= ~I2S_CR_I2S_TXD_EN;
19     putreg32(regval, reg_base + I2S_CONFIG_OFFSET);
20 
21     if (config->channel_mode == I2S_CHANNEL_MODE_NUM_1) {
22         /* Mono mode */
23         regval |= I2S_CR_MONO_MODE;
24         regval &= ~I2S_CR_FS_CH_CNT_MASK;
25     } else {
26         regval &= ~I2S_CR_MONO_MODE;
27         regval &= ~I2S_CR_FS_CH_CNT_MASK;
28         regval |= (config->channel_mode - 1) << I2S_CR_FS_CH_CNT_SHIFT;
29     }
30 
31     /* disable mute */
32     regval &= ~I2S_CR_MUTE_MODE;
33 
34     if (config->format_mode == I2S_MODE_DSP_SHORT_FRAME_SYNC) {
35         /* dsp modeA/B short frame sync, there is only one bclk cycle */
36         regval |= I2S_CR_FS_1T_MODE;
37     } else {
38         regval &= ~I2S_CR_FS_1T_MODE;
39     }
40 
41     /* frame/data width */
42     regval &= ~I2S_CR_FRAME_SIZE_MASK;
43     regval &= ~I2S_CR_DATA_SIZE_MASK;
44     regval |= config->frame_width << I2S_CR_FRAME_SIZE_SHIFT;
45     regval |= config->data_width << I2S_CR_DATA_SIZE_SHIFT;
46 
47     if (config->format_mode == I2S_MODE_LEFT_JUSTIFIED) {
48         /* left justified*/
49         regval &= ~I2S_CR_I2S_MODE_MASK;
50     } else if (config->format_mode == I2S_MODE_RIGHT_JUSTIFIED) {
51         /* right justified*/
52         regval &= ~I2S_CR_I2S_MODE_MASK;
53         regval |= 1 << I2S_CR_I2S_MODE_SHIFT;
54     } else {
55         /* dsp mode */
56         regval &= ~I2S_CR_I2S_MODE_MASK;
57         regval |= 2 << I2S_CR_I2S_MODE_SHIFT;
58     }
59 
60     /* fs_offset_cycle */
61     if (config->fs_offset_cycle) {
62         regval |= I2S_CR_OFS_EN;
63         regval &= ~I2S_CR_OFS_CNT_MASK;
64         regval |= ((config->fs_offset_cycle - 1) << I2S_CR_OFS_CNT_SHIFT) & I2S_CR_OFS_CNT_MASK;
65     } else {
66         regval &= ~I2S_CR_OFS_EN;
67     }
68 
69     /* rx mono mode L-channel */
70     regval &= ~I2S_CR_MONO_RX_CH;
71     /* MSB */
72     regval &= ~I2S_CR_ENDIAN;
73 
74     putreg32(regval, reg_base + I2S_CONFIG_OFFSET);
75 
76     /* integer frequency segmentation by rounding */
77     div = (bflb_clk_get_peripheral_clock(BFLB_DEVICE_TYPE_I2S, dev->idx) / 2 * 10 / config->bclk_freq_hz + 5) / 10;
78     div = (div) ? (div - 1) : 0;
79     div = (div > 0xfff) ? 0xfff : div;
80 
81     /* bclk timing config */
82     regval = getreg32(reg_base + I2S_BCLK_CONFIG_OFFSET);
83     regval &= ~I2S_CR_BCLK_DIV_L_MASK;
84     regval &= ~I2S_CR_BCLK_DIV_H_MASK;
85     regval |= div << I2S_CR_BCLK_DIV_L_SHIFT;
86     regval |= div << I2S_CR_BCLK_DIV_H_SHIFT;
87     putreg32(regval, reg_base + I2S_BCLK_CONFIG_OFFSET);
88 
89     /* fifo threshold config */
90     regval = getreg32(reg_base + I2S_FIFO_CONFIG_1_OFFSET);
91     regval &= ~I2S_TX_FIFO_TH_MASK;
92     regval &= ~I2S_RX_FIFO_TH_MASK;
93     regval |= (config->tx_fifo_threshold << I2S_TX_FIFO_TH_SHIFT) & I2S_TX_FIFO_TH_MASK;
94     regval |= (config->tx_fifo_threshold << I2S_RX_FIFO_TH_SHIFT) & I2S_RX_FIFO_TH_MASK;
95     putreg32(regval, reg_base + I2S_FIFO_CONFIG_1_OFFSET);
96 
97     regval = getreg32(reg_base + I2S_FIFO_CONFIG_0_OFFSET);
98     /* 32bit to 24bit */
99     regval &= ~I2S_CR_FIFO_24B_LJ;
100     /* Exchange L/R channel data */
101     regval &= ~I2S_CR_FIFO_LR_EXCHG;
102     /* Each FIFO entry contains both L/R channel data */
103     regval &= ~I2S_CR_FIFO_LR_MERGE;
104     /* disable dma */
105     regval &= ~I2S_DMA_TX_EN;
106     regval &= ~I2S_DMA_RX_EN;
107     /* clean fifo */
108     regval |= I2S_TX_FIFO_CLR;
109     regval |= I2S_RX_FIFO_CLR;
110     putreg32(regval, reg_base + I2S_FIFO_CONFIG_0_OFFSET);
111 
112     regval = getreg32(reg_base + I2S_IO_CONFIG_OFFSET);
113     /* disable deglitch */
114     regval &= ~I2S_CR_DEG_EN;
115     /* disable inverse signal */
116     regval &= ~I2S_CR_I2S_BCLK_INV;
117     regval &= ~I2S_CR_I2S_FS_INV;
118     regval &= ~I2S_CR_I2S_RXD_INV;
119     regval &= ~I2S_CR_I2S_TXD_INV;
120     putreg32(regval, reg_base + I2S_IO_CONFIG_OFFSET);
121 
122     /* enable I2S, but disable tx and rx */
123     regval = getreg32(reg_base + I2S_CONFIG_OFFSET);
124     if (config->role == I2S_ROLE_MASTER) {
125         regval |= I2S_CR_I2S_M_EN;
126     } else {
127         regval |= I2S_CR_I2S_S_EN;
128     }
129     putreg32(regval, reg_base + I2S_CONFIG_OFFSET);
130 }
131 
bflb_i2s_deinit(struct bflb_device_s * dev)132 void bflb_i2s_deinit(struct bflb_device_s *dev)
133 {
134     uint32_t regval;
135     uint32_t reg_base;
136 
137     reg_base = dev->reg_base;
138 
139     /* disable I2S */
140     regval = getreg32(reg_base + I2S_CONFIG_OFFSET);
141     regval &= ~I2S_CR_I2S_S_EN;
142     regval &= ~I2S_CR_I2S_M_EN;
143     putreg32(regval, reg_base + I2S_CONFIG_OFFSET);
144 }
145 
bflb_i2s_link_txdma(struct bflb_device_s * dev,bool enable)146 void bflb_i2s_link_txdma(struct bflb_device_s *dev, bool enable)
147 {
148     uint32_t reg_base;
149     uint32_t regval;
150 
151     reg_base = dev->reg_base;
152     regval = getreg32(reg_base + I2S_FIFO_CONFIG_0_OFFSET);
153     if (enable) {
154         regval |= I2S_DMA_TX_EN;
155     } else {
156         regval &= ~I2S_DMA_TX_EN;
157     }
158     putreg32(regval, reg_base + I2S_FIFO_CONFIG_0_OFFSET);
159 }
160 
bflb_i2s_link_rxdma(struct bflb_device_s * dev,bool enable)161 void bflb_i2s_link_rxdma(struct bflb_device_s *dev, bool enable)
162 {
163     uint32_t reg_base;
164     uint32_t regval;
165 
166     reg_base = dev->reg_base;
167     regval = getreg32(reg_base + I2S_FIFO_CONFIG_0_OFFSET);
168     if (enable) {
169         regval |= I2S_DMA_RX_EN;
170     } else {
171         regval &= ~I2S_DMA_RX_EN;
172     }
173     putreg32(regval, reg_base + I2S_FIFO_CONFIG_0_OFFSET);
174 }
175 
bflb_i2s_txint_mask(struct bflb_device_s * dev,bool mask)176 void bflb_i2s_txint_mask(struct bflb_device_s *dev, bool mask)
177 {
178     uint32_t regval;
179     uint32_t reg_base = dev->reg_base;
180 
181     regval = getreg32(reg_base + I2S_INT_STS_OFFSET);
182     if (mask) {
183         regval |= I2S_CR_I2S_TXF_MASK;
184     } else {
185         regval &= ~I2S_CR_I2S_TXF_MASK;
186     }
187     putreg32(regval, reg_base + I2S_INT_STS_OFFSET);
188 }
189 
bflb_i2s_rxint_mask(struct bflb_device_s * dev,bool mask)190 void bflb_i2s_rxint_mask(struct bflb_device_s *dev, bool mask)
191 {
192     uint32_t regval;
193     uint32_t reg_base = dev->reg_base;
194 
195     regval = getreg32(reg_base + I2S_INT_STS_OFFSET);
196     if (mask) {
197         regval |= I2S_CR_I2S_RXF_MASK;
198     } else {
199         regval &= ~I2S_CR_I2S_RXF_MASK;
200     }
201     putreg32(regval, reg_base + I2S_INT_STS_OFFSET);
202 }
203 
bflb_i2s_errint_mask(struct bflb_device_s * dev,bool mask)204 void bflb_i2s_errint_mask(struct bflb_device_s *dev, bool mask)
205 {
206     uint32_t regval;
207     uint32_t reg_base = dev->reg_base;
208 
209     regval = getreg32(reg_base + I2S_INT_STS_OFFSET);
210     if (mask) {
211         regval |= I2S_CR_I2S_FER_MASK;
212     } else {
213         regval &= ~I2S_CR_I2S_FER_MASK;
214     }
215     putreg32(regval, reg_base + I2S_INT_STS_OFFSET);
216 }
217 
bflb_i2s_get_intstatus(struct bflb_device_s * dev)218 uint32_t bflb_i2s_get_intstatus(struct bflb_device_s *dev)
219 {
220     uint32_t reg_base;
221     uint32_t int_status;
222     uint32_t int_mask;
223 
224     reg_base = dev->reg_base;
225 
226     int_status = getreg32(reg_base + I2S_INT_STS_OFFSET) & 0x1f;
227 
228     int_mask = (getreg32(reg_base + I2S_INT_STS_OFFSET) >> 8) & 0x1f;
229 
230     return (int_status & ~int_mask);
231 }
232 
bflb_i2s_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)233 int bflb_i2s_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
234 {
235     int ret = 0;
236     uint32_t reg_base;
237     uint32_t regval;
238 
239     reg_base = dev->reg_base;
240 
241     switch (cmd) {
242         case I2S_CMD_CLEAR_TX_FIFO:
243             /* clear tx fifo */
244             regval = getreg32(reg_base + I2S_FIFO_CONFIG_0_OFFSET);
245             regval |= I2S_TX_FIFO_CLR;
246             putreg32(regval, reg_base + I2S_FIFO_CONFIG_0_OFFSET);
247             break;
248 
249         case I2S_CMD_CLEAR_RX_FIFO:
250             /* clear rx fifo */
251             regval = getreg32(reg_base + I2S_FIFO_CONFIG_0_OFFSET);
252             regval |= I2S_RX_FIFO_CLR;
253             putreg32(regval, reg_base + I2S_FIFO_CONFIG_0_OFFSET);
254             break;
255 
256         case I2S_CMD_RX_DEGLITCH:
257             /* set rx deglitch, arg: deglitch cycle count (unit: cycle of I2S kernel clock) */
258             regval = getreg32(reg_base + I2S_IO_CONFIG_OFFSET);
259             if (arg) {
260                 regval |= I2S_CR_DEG_EN;
261                 regval &= ~I2S_CR_DEG_CNT_MASK;
262                 regval |= (arg << I2S_CR_DEG_CNT_SHIFT) & I2S_CR_DEG_CNT_MASK;
263             } else {
264                 regval &= ~I2S_CR_DEG_EN;
265             }
266             putreg32(regval, reg_base + I2S_IO_CONFIG_OFFSET);
267             break;
268 
269         case I2S_CMD_DATA_ENABLE:
270             /* data enable, arg: use @ref I2S_CMD_DATA_ENABLE_TYPE */
271             regval = getreg32(reg_base + I2S_CONFIG_OFFSET);
272             /* enable tx data signal */
273             if (arg & I2S_CMD_DATA_ENABLE_TX) {
274                 regval |= I2S_CR_I2S_TXD_EN;
275             } else {
276                 regval &= ~I2S_CR_I2S_TXD_EN;
277             }
278             /* enable rx data signal */
279             if (arg & I2S_CMD_DATA_ENABLE_RX) {
280                 regval |= I2S_CR_I2S_RXD_EN;
281             } else {
282                 regval &= ~I2S_CR_I2S_RXD_EN;
283             }
284             putreg32(regval, reg_base + I2S_CONFIG_OFFSET);
285             break;
286 
287         case I2S_CMD_CHANNEL_LR_MERGE:
288             /* Each FIFO entry contains both L/R channel data ,
289             can only be enabled if data size is 8 or 16 bits,
290             arg use true or false */
291             regval = getreg32(reg_base + I2S_FIFO_CONFIG_0_OFFSET);
292             if (arg) {
293                 regval |= I2S_CR_FIFO_LR_MERGE;
294             } else {
295                 regval &= ~I2S_CR_FIFO_LR_MERGE;
296             }
297             putreg32(regval, reg_base + I2S_FIFO_CONFIG_0_OFFSET);
298             break;
299 
300         case I2S_CMD_CHANNEL_LR_EXCHG:
301             /* The position of L/R channel data within each entry is exchanged,
302             can only be enabled if data size is 8 or 16 bits and I2S_CMD_CHANNEL_LR_MERGE is enabled,
303             arg use true or false */
304             regval = getreg32(reg_base + I2S_FIFO_CONFIG_0_OFFSET);
305             if (arg) {
306                 regval |= I2S_CR_FIFO_LR_EXCHG;
307             } else {
308                 regval &= ~I2S_CR_FIFO_LR_EXCHG;
309             }
310             putreg32(regval, reg_base + I2S_FIFO_CONFIG_0_OFFSET);
311             break;
312 
313         case I2S_CMD_MUTE:
314             /* Enable mute, arg use true or false */
315             regval = getreg32(reg_base + I2S_CONFIG_OFFSET);
316             if (arg) {
317                 regval |= I2S_CR_MUTE_MODE;
318             } else {
319                 regval &= ~I2S_CR_MUTE_MODE;
320             }
321             putreg32(regval, reg_base + I2S_CONFIG_OFFSET);
322             break;
323 
324         case I2S_CMD_BIT_REVERSE:
325             /* Data endian (bit reverse), arg use true or false, true: MSB goes out first, false: LSB goes out first*/
326             regval = getreg32(reg_base + I2S_CONFIG_OFFSET);
327             if (arg) {
328                 regval |= I2S_CR_MUTE_MODE;
329             } else {
330                 regval &= ~I2S_CR_MUTE_MODE;
331             }
332             putreg32(regval, reg_base + I2S_CONFIG_OFFSET);
333             break;
334 
335         default:
336             ret = -EPERM;
337             break;
338     }
339 
340     return ret;
341 }