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 }