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