1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-11-17 LiWeiHao First implementation
9 */
10
11 #include "drv_sound.h"
12 #include "fsl_common.h"
13 #include "fsl_iocon.h"
14 #include "fsl_dma.h"
15 #include "fsl_i2s.h"
16 #include "fsl_i2s_dma.h"
17 #include "fsl_wm8904.h"
18 #include "fsl_i2c.h"
19
20 #define TX_FIFO_SIZE (4096)
21
22 #define I2S_TX I2S1
23 #define I2S_RX I2S0
24
25 #define I2S_DMA_TX 15
26 #define I2S_DMA_RX 12
27
28 #ifndef CODEC_I2C_NAME
29 #define CODEC_I2C_NAME "i2c4"
30 #endif
31
32 struct sound_device
33 {
34 wm8904_handle_t wm8904_handle;
35 dma_handle_t tx_dma_handle;
36 i2s_dma_handle_t tx_i2s_dma_handle;
37 struct rt_audio_device audio;
38 struct rt_audio_configure replay_config;
39 rt_uint8_t volume;
40 rt_uint8_t *tx_fifo;
41 };
42
43 const pll_setup_t pll_setup =
44 {
45 .syspllctrl = SYSCON_SYSPLLCTRL_BANDSEL_MASK | SYSCON_SYSPLLCTRL_SELP(0x1FU) | SYSCON_SYSPLLCTRL_SELI(0x8U),
46 .syspllndec = SYSCON_SYSPLLNDEC_NDEC(0x2DU),
47 .syspllpdec = SYSCON_SYSPLLPDEC_PDEC(0x42U),
48 .syspllssctrl = {SYSCON_SYSPLLSSCTRL0_MDEC(0x34D3U) | SYSCON_SYSPLLSSCTRL0_SEL_EXT_MASK, 0x00000000U},
49 .pllRate = 24576000U, /* 16 bits * 2 channels * 44.1 kHz * 16 */
50 .flags = PLL_SETUPFLAG_WAITLOCK
51 };
52
53 static struct sound_device snd_dev;
54
i2s_tx_transfer_callback(I2S_Type * base,i2s_dma_handle_t * handle,status_t completionStatus,void * userData)55 void i2s_tx_transfer_callback(I2S_Type *base,
56 i2s_dma_handle_t *handle,
57 status_t completionStatus,
58 void *userData)
59 {
60 struct sound_device *snd_dev = (struct sound_device *)userData;
61 rt_audio_tx_complete(&snd_dev->audio);
62 }
63
lpc_audio_init(struct rt_audio_device * audio)64 static rt_err_t lpc_audio_init(struct rt_audio_device *audio)
65 {
66 i2s_config_t tx_i2s_config;
67 wm8904_config_t wm8904_config;
68
69 CLOCK_EnableClock(kCLOCK_Iocon);
70 CLOCK_EnableClock(kCLOCK_InputMux);
71 CLOCK_EnableClock(kCLOCK_Gpio0);
72 CLOCK_EnableClock(kCLOCK_Gpio1);
73
74 CLOCK_AttachClk(kFRO12M_to_SYS_PLL);
75 CLOCK_AttachClk(kSYS_PLL_to_FLEXCOMM7);
76
77 RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);
78
79 CLOCK_SetPLLFreq(&pll_setup);
80 CLOCK_AttachClk(kSYS_PLL_to_MCLK);
81 SYSCON->MCLKDIV = SYSCON_MCLKDIV_DIV(0U);
82
83 // Flexcomm 7 I2S Tx
84 IOCON_PinMuxSet(IOCON, 1, 12, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / SCK */
85 IOCON_PinMuxSet(IOCON, 1, 13, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / SDA */
86 IOCON_PinMuxSet(IOCON, 1, 14, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / WS */
87
88 /* MCLK output for I2S */
89 IOCON_PinMuxSet(IOCON, 1, 17, IOCON_FUNC4 | IOCON_MODE_INACT | IOCON_DIGITAL_EN);
90 SYSCON->MCLKIO = 1U;
91
92 WM8904_GetDefaultConfig(&wm8904_config);
93 snd_dev.wm8904_handle.i2c = (struct rt_i2c_bus_device *)rt_device_find(CODEC_I2C_NAME);
94 if (WM8904_Init(&snd_dev.wm8904_handle, &wm8904_config) != kStatus_Success)
95 {
96 rt_kprintf("wm8904 init failed\n");
97 return -RT_ERROR;
98 }
99
100 WM8904_SetMute(&snd_dev.wm8904_handle, RT_TRUE, RT_TRUE);
101
102 I2S_TxGetDefaultConfig(&tx_i2s_config);
103 tx_i2s_config.divider = CLOCK_GetPllOutFreq() / 48000U / 16 / 2;
104 I2S_TxInit(I2S_TX, &tx_i2s_config);
105
106 DMA_Init(DMA0);
107
108 DMA_EnableChannel(DMA0, I2S_DMA_TX);
109 DMA_SetChannelPriority(DMA0, I2S_DMA_TX, kDMA_ChannelPriority3);
110 DMA_CreateHandle(&snd_dev.tx_dma_handle, DMA0, I2S_DMA_TX);
111
112 I2S_TxTransferCreateHandleDMA(I2S_TX,
113 &snd_dev.tx_i2s_dma_handle,
114 &snd_dev.tx_dma_handle,
115 i2s_tx_transfer_callback,
116 (void *)&snd_dev);
117
118 return RT_EOK;
119 }
120
lpc_audio_start(struct rt_audio_device * audio,int stream)121 static rt_err_t lpc_audio_start(struct rt_audio_device *audio, int stream)
122 {
123 RT_ASSERT(audio != RT_NULL);
124
125 if (stream == AUDIO_STREAM_REPLAY)
126 {
127 struct rt_audio_caps caps;
128 caps.main_type = AUDIO_TYPE_MIXER;
129 caps.sub_type = AUDIO_MIXER_VOLUME;
130 audio->ops->getcaps(audio, &caps);
131 audio->ops->configure(audio, &caps);
132 rt_audio_tx_complete(audio);
133 }
134 return RT_EOK;
135 }
136
lpc_audio_stop(struct rt_audio_device * audio,int stream)137 static rt_err_t lpc_audio_stop(struct rt_audio_device *audio, int stream)
138 {
139 if (stream == AUDIO_STREAM_REPLAY)
140 {
141 WM8904_SetMute(&snd_dev.wm8904_handle, RT_TRUE, RT_TRUE);
142 I2S_TransferAbortDMA(I2S_TX, &snd_dev.tx_i2s_dma_handle);
143 }
144 return RT_EOK;
145 }
146
lpc_audio_getcaps(struct rt_audio_device * audio,struct rt_audio_caps * caps)147 static rt_err_t lpc_audio_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
148 {
149 rt_err_t result = RT_EOK;
150 struct sound_device *snd_dev;
151
152 RT_ASSERT(audio != RT_NULL);
153 snd_dev = (struct sound_device *)audio->parent.user_data;
154
155 switch (caps->main_type)
156 {
157 case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */
158 {
159 switch (caps->sub_type)
160 {
161 case AUDIO_TYPE_QUERY:
162 caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER;
163 break;
164
165 default:
166 result = -RT_ERROR;
167 break;
168 }
169
170 break;
171 }
172
173 case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */
174 {
175 switch (caps->sub_type)
176 {
177 case AUDIO_DSP_PARAM:
178 caps->udata.config.samplerate = snd_dev->replay_config.samplerate;
179 caps->udata.config.channels = snd_dev->replay_config.channels;
180 caps->udata.config.samplebits = snd_dev->replay_config.samplebits;
181 break;
182
183 case AUDIO_DSP_SAMPLERATE:
184 caps->udata.config.samplerate = snd_dev->replay_config.samplerate;
185 break;
186
187 case AUDIO_DSP_CHANNELS:
188 caps->udata.config.channels = snd_dev->replay_config.channels;
189 break;
190
191 case AUDIO_DSP_SAMPLEBITS:
192 caps->udata.config.samplebits = snd_dev->replay_config.samplebits;
193 break;
194
195 default:
196 result = -RT_ERROR;
197 break;
198 }
199
200 break;
201 }
202
203 case AUDIO_TYPE_MIXER: /* report the Mixer Units */
204 {
205 switch (caps->sub_type)
206 {
207 case AUDIO_MIXER_QUERY:
208 caps->udata.mask = AUDIO_MIXER_VOLUME;
209 break;
210
211 case AUDIO_MIXER_VOLUME:
212 caps->udata.value = snd_dev->volume;
213 break;
214
215 default:
216 result = -RT_ERROR;
217 break;
218 }
219
220 break;
221 }
222
223 default:
224 result = -RT_ERROR;
225 break;
226 }
227
228 return result;
229 }
230
lpc_audio_configure(struct rt_audio_device * audio,struct rt_audio_caps * caps)231 static rt_err_t lpc_audio_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
232 {
233 rt_err_t result = RT_EOK;
234 struct sound_device *snd_dev = audio->parent.user_data;
235
236 switch (caps->main_type)
237 {
238 case AUDIO_TYPE_MIXER:
239 {
240 switch (caps->sub_type)
241 {
242 case AUDIO_MIXER_MUTE:
243 {
244 WM8904_SetMute(&snd_dev->wm8904_handle, RT_TRUE, RT_TRUE);
245 snd_dev->volume = 0;
246 break;
247 }
248
249 case AUDIO_MIXER_VOLUME:
250 {
251 int volume = caps->udata.value / 2;
252 WM8904_SetMute(&snd_dev->wm8904_handle, RT_FALSE, RT_FALSE);
253 WM8904_SetVolume(&snd_dev->wm8904_handle, volume, volume);
254 snd_dev->volume = volume;
255 break;
256 }
257 }
258
259 break;
260 }
261 case AUDIO_TYPE_OUTPUT:
262 {
263 switch (caps->sub_type)
264 {
265 case AUDIO_DSP_PARAM:
266 {
267 struct rt_audio_configure config = caps->udata.config;
268 i2s_config_t tx_i2s_config;
269 snd_dev->replay_config.channels = config.channels;
270 snd_dev->replay_config.samplebits = config.samplebits;
271 snd_dev->replay_config.samplerate = config.samplerate;
272 I2S_TxGetDefaultConfig(&tx_i2s_config);
273 tx_i2s_config.divider = CLOCK_GetPllOutFreq() / config.samplerate / 16 / 2;
274 I2S_TxInit(I2S_TX, &tx_i2s_config);
275 break;
276 }
277
278 case AUDIO_DSP_SAMPLERATE:
279 {
280 struct rt_audio_configure config = caps->udata.config;
281 i2s_config_t tx_i2s_config;
282 snd_dev->replay_config.samplerate = config.samplerate;
283 I2S_TxGetDefaultConfig(&tx_i2s_config);
284 tx_i2s_config.divider = CLOCK_GetPllOutFreq() / config.samplerate / 16 / 2;
285 I2S_TxInit(I2S_TX, &tx_i2s_config);
286 break;
287 }
288
289 default:
290 result = -RT_ERROR;
291 break;
292 }
293 break;
294 }
295 }
296
297 return result;
298 }
299
lpc_audio_transmit(struct rt_audio_device * audio,const void * writeBuf,void * readBuf,rt_size_t size)300 static rt_ssize_t lpc_audio_transmit(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size)
301 {
302 RT_ASSERT(audio != RT_NULL);
303 i2s_transfer_t transfer;
304 transfer.data = (uint8_t *)writeBuf;
305 transfer.dataSize = size;
306 I2S_TxTransferSendDMA(I2S_TX, &snd_dev.tx_i2s_dma_handle, transfer);
307
308 return RT_EOK;
309 }
310
lpc_audio_buffer_info(struct rt_audio_device * audio,struct rt_audio_buf_info * info)311 static void lpc_audio_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info)
312 {
313 RT_ASSERT(audio != RT_NULL);
314 /**
315 * TX_FIFO
316 * +----------------+----------------+
317 * | block1 | block2 |
318 * +----------------+----------------+
319 * \ block_size /
320 */
321 info->buffer = snd_dev.tx_fifo;
322 info->total_size = TX_FIFO_SIZE;
323 info->block_size = TX_FIFO_SIZE / 2;
324 info->block_count = 2;
325 }
326
327 static struct rt_audio_ops audio_ops =
328 {
329 .getcaps = lpc_audio_getcaps,
330 .configure = lpc_audio_configure,
331 .init = lpc_audio_init,
332 .start = lpc_audio_start,
333 .stop = lpc_audio_stop,
334 .transmit = lpc_audio_transmit,
335 .buffer_info = lpc_audio_buffer_info,
336 };
337
rt_hw_sound_init(void)338 int rt_hw_sound_init(void)
339 {
340 rt_uint8_t *tx_fifo = RT_NULL;
341
342 tx_fifo = rt_malloc(TX_FIFO_SIZE);
343 if (tx_fifo == NULL)
344 {
345 return -RT_ENOMEM;
346 }
347 snd_dev.tx_fifo = tx_fifo;
348
349 /* init default configuration */
350 {
351 snd_dev.replay_config.samplerate = 44100;
352 snd_dev.replay_config.channels = 2;
353 snd_dev.replay_config.samplebits = 16;
354 snd_dev.volume = 30;
355 }
356
357 snd_dev.audio.ops = &audio_ops;
358 rt_audio_register(&snd_dev.audio, "sound0", RT_DEVICE_FLAG_WRONLY, &snd_dev);
359 return RT_EOK;
360 }
361 INIT_DEVICE_EXPORT(rt_hw_sound_init);
362