1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-03-12     Vandoul      the first version
9  */
10 
11 #include <rtthread.h>
12 #include "fsl_i2s.h"
13 #include "fsl_i2s_dma.h"
14 #include "drv_i2s.h"
15 
16 #define DBG_TAG "DRVI2S"
17 #include "rtdbg.h"
18 
19 #ifdef BSP_USING_I2S
20 
21 #if !defined(BSP_USING_I2S0) && \
22     !defined(BSP_USING_I2S1) && \
23     !defined(BSP_USING_I2S2) && \
24     !defined(BSP_USING_I2S3) && \
25     !defined(BSP_USING_I2S4) && \
26     !defined(BSP_USING_I2S5) && \
27     !defined(BSP_USING_I2S6) && \
28     !defined(BSP_USING_I2S7)
29 #error "Please define at least one I2Sx"
30 #endif
31 
32 #include <rtdevice.h>
33 
34 enum {
35 #ifdef BSP_USING_I2S0
36     I2S0_INDEX,
37 #endif
38 #ifdef BSP_USING_I2S1
39     I2S1_INDEX,
40 #endif
41 #ifdef BSP_USING_I2S2
42     I2S2_INDEX,
43 #endif
44 #ifdef BSP_USING_I2S3
45     I2S3_INDEX,
46 #endif
47 #ifdef BSP_USING_I2S4
48     I2S4_INDEX,
49 #endif
50 #ifdef BSP_USING_I2S5
51     I2S5_INDEX,
52 #endif
53 #ifdef BSP_USING_I2S6
54     I2S6_INDEX,
55 #endif
56 #ifdef BSP_USING_I2S7
57     I2S7_INDEX,
58 #endif
59 };
60 
61 struct lpc_i2s_clock_and_irq_param
62 {
63     clock_attach_id_t i2s_clock;
64     reset_ip_name_t i2s_reset_bit;
65     IRQn_Type irq_type;
66 };
67 
68 struct lpc_i2s
69 {
70     struct rt_device device;
71     i2s_handle_t i2s_handle;
72     struct lpc_i2s_config config;
73     uint32_t index;
74     I2S_Type *i2s_base;
75     const char *device_name;
76 };
77 
78 #define LPC_I2S_CONFIG_MODE_IS_SLAVE(dev)           ((dev)->config.mode == LPC_I2S_CONFIG_MODE_SLAVE)
79 #define LPC_I2S_CONFIG_MODE_IS_MASTER(dev)          ((dev)->config.mode == LPC_I2S_CONFIG_MODE_MASTER)
80 
81 #define LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(index)         {.i2s_clock = kPLL0_DIV_to_FLEXCOMM##index, .i2s_reset_bit = kFC##index##_RST_SHIFT_RSTn, .irq_type = FLEXCOMM##index##_IRQn,}
82 const static struct lpc_i2s_clock_and_irq_param lpc_i2s_clock_and_irq_param_table[] =
83 {
84 #ifdef BSP_USING_I2S0
85 //    {.i2s_clock = kPLL0_DIV_to_FLEXCOMM0, .i2s_reset_bit = kFC0_RST_SHIFT_RSTn, .irq_type = FLEXCOMM0_IRQn,},
86     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(0),
87 #endif
88 #ifdef BSP_USING_I2S1
89     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(1),
90 #endif
91 #ifdef BSP_USING_I2S2
92     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(2),
93 #endif
94 #ifdef BSP_USING_I2S3
95     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(3),
96 #endif
97 #ifdef BSP_USING_I2S4
98     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(4),
99 #endif
100 #ifdef BSP_USING_I2S5
101     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(5),
102 #endif
103 #ifdef BSP_USING_I2S6
104     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(6),
105 #endif
106 #ifdef BSP_USING_I2S7
107     LPC_I2S_CLOCK_AND_IRQ_PARAM_INIT(7),
108 #endif
109 };
110 
111 static struct lpc_i2s lpc_i2s_table[] =
112 {
113 #ifdef BSP_USING_I2S0
114     {.index = I2S0_INDEX,.i2s_base = I2S0,.device_name = "i2s0"},
115 #endif
116 #ifdef BSP_USING_I2S1
117     {.index = I2S1_INDEX,.i2s_base = I2S1,.device_name = "i2s1"},
118 #endif
119 #ifdef BSP_USING_I2S2
120     {.index = I2S2_INDEX,.i2s_base = I2S2,.device_name = "i2s2"},
121 #endif
122 #ifdef BSP_USING_I2S3
123     {.index = I2S3_INDEX,.i2s_base = I2S3,.device_name = "i2s3"},
124 #endif
125 #ifdef BSP_USING_I2S4
126     {.index = I2S4_INDEX,.i2s_base = I2S4,.device_name = "i2s4"},
127 #endif
128 #ifdef BSP_USING_I2S5
129     {.index = I2S5_INDEX,.i2s_base = I2S5,.device_name = "i2s5"},
130 #endif
131 #ifdef BSP_USING_I2S6
132     {.index = I2S6_INDEX,.i2s_base = I2S6,.device_name = "i2s6"},
133 #endif
134 #ifdef BSP_USING_I2S7
135     {.index = I2S7_INDEX,.i2s_base = I2S7,.device_name = "i2s7"},
136 #endif
137 };
138 
transfer_callback(I2S_Type * base,i2s_handle_t * handle,status_t completionStatus,void * userData)139 static void transfer_callback(I2S_Type *base, i2s_handle_t *handle, status_t completionStatus, void *userData)
140 {
141     struct lpc_i2s *i2s_dev = rt_container_of(handle, struct lpc_i2s, i2s_handle);
142     if(LPC_I2S_CONFIG_MODE_IS_SLAVE(i2s_dev))
143     {
144         if(i2s_dev->device.rx_indicate != RT_NULL)
145         {
146             i2s_dev->device.rx_indicate(&i2s_dev->device, completionStatus);
147         }
148     }
149     else
150     {
151         if(i2s_dev->device.tx_complete != RT_NULL)
152         {
153             i2s_dev->device.tx_complete(&i2s_dev->device, RT_NULL);
154         }
155     }
156 }
157 
i2s_clock_and_irq_config(struct lpc_i2s * dev)158 static void i2s_clock_and_irq_config(struct lpc_i2s *dev)
159 {
160     const struct lpc_i2s_clock_and_irq_param *clock_and_irq_param = &lpc_i2s_clock_and_irq_param_table[dev->index];
161 //    CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 0U, true);
162 //    CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 1U, false);
163     CLOCK_AttachClk(clock_and_irq_param->i2s_clock);
164     RESET_PeripheralReset(clock_and_irq_param->i2s_reset_bit);
165     NVIC_ClearPendingIRQ(clock_and_irq_param->irq_type);
166     /* Enable interrupts for I2S */
167     EnableIRQ(clock_and_irq_param->irq_type);
168 }
rt_i2s_init(rt_device_t dev)169 rt_err_t rt_i2s_init(rt_device_t dev)
170 {
171     struct lpc_i2s *i2s_dev = rt_container_of(dev, struct lpc_i2s, device);
172     i2s_clock_and_irq_config(i2s_dev);
173     return RT_EOK;
174 }
rt_i2s_open(rt_device_t dev,rt_uint16_t oflag)175 rt_err_t rt_i2s_open(rt_device_t dev, rt_uint16_t oflag)
176 {
177     struct lpc_i2s *i2s_dev = rt_container_of(dev, struct lpc_i2s, device);
178     i2s_config_t config;
179     if(i2s_dev->config.mode == LPC_I2S_CONFIG_MODE_SLAVE)
180     {
181         RT_ASSERT(i2s_dev->config.is_blocking == 0);
182         I2S_RxGetDefaultConfig(&config);
183         config.divider = CLOCK_GetPll0OutFreq()/i2s_dev->config.sampling_rate/i2s_dev->config.data_bits/i2s_dev->config.channels;
184         config.masterSlave = kI2S_MasterSlaveNormalSlave;
185         I2S_RxInit(i2s_dev->i2s_base, &config);
186         I2S_RxTransferCreateHandle(i2s_dev->i2s_base, &i2s_dev->i2s_handle, transfer_callback, NULL);
187     }
188     else if(i2s_dev->config.mode == LPC_I2S_CONFIG_MODE_MASTER)
189     {
190         RT_ASSERT(i2s_dev->config.is_blocking == 0);
191         I2S_TxGetDefaultConfig(&config);
192         config.divider = CLOCK_GetPll0OutFreq()/i2s_dev->config.sampling_rate/i2s_dev->config.data_bits/i2s_dev->config.channels;
193         config.masterSlave = kI2S_MasterSlaveNormalMaster;
194         I2S_TxInit(i2s_dev->i2s_base, &config);
195         I2S_TxTransferCreateHandle(i2s_dev->i2s_base, &i2s_dev->i2s_handle, transfer_callback, NULL);
196     }
197     return RT_EOK;
198 }
rt_i2s_close(rt_device_t dev)199 rt_err_t rt_i2s_close(rt_device_t dev)
200 {
201     struct lpc_i2s *i2s_dev = rt_container_of(dev, struct lpc_i2s, device);
202     I2S_Deinit(i2s_dev->i2s_base);
203     return RT_EOK;
204 }
rt_i2s_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)205 rt_ssize_t rt_i2s_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
206 {
207     struct lpc_i2s *i2s_dev = rt_container_of(dev, struct lpc_i2s, device);
208     if(!LPC_I2S_CONFIG_MODE_IS_SLAVE(i2s_dev))
209     {
210         return -RT_ERROR;
211     }
212     i2s_transfer_t transfer;
213     transfer.data = buffer;
214     transfer.dataSize = size;
215     if(kStatus_Success == I2S_RxTransferNonBlocking(i2s_dev->i2s_base, &i2s_dev->i2s_handle, transfer))
216         return size;
217     else
218         return -RT_EBUSY;
219 }
rt_i2s_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)220 rt_ssize_t rt_i2s_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
221 {
222     struct lpc_i2s *i2s_dev = rt_container_of(dev, struct lpc_i2s, device);
223     if(!LPC_I2S_CONFIG_MODE_IS_MASTER(i2s_dev))
224     {
225         return -RT_ERROR;
226     }
227     i2s_transfer_t transfer;
228     transfer.data = (uint8_t *)buffer;
229     transfer.dataSize = size;
230     if(kStatus_Success == I2S_TxTransferNonBlocking(i2s_dev->i2s_base, &i2s_dev->i2s_handle, transfer))
231         return size;
232     else
233         return -RT_EBUSY;
234 }
rt_i2s_control(rt_device_t dev,int cmd,void * args)235 rt_err_t rt_i2s_control(rt_device_t dev, int cmd, void *args)
236 {
237     struct lpc_i2s *i2s_dev = rt_container_of(dev, struct lpc_i2s, device);
238     rt_err_t ret = RT_EOK;
239     RT_ASSERT(dev != RT_NULL);
240     RT_ASSERT(args != RT_NULL);
241     switch(cmd)
242     {
243         case RT_I2S_CTRL_RESET:
244             i2s_clock_and_irq_config(i2s_dev);
245             break;
246         case RT_I2S_CTRL_SET_CONFIG:
247         {
248             struct lpc_i2s_config *config = (struct lpc_i2s_config *)args;
249             i2s_dev->config = *config;
250         }
251             break;
252         default:
253             ret = -RT_ERROR;
254             break;
255     }
256     return ret;
257 }
258 
259 #ifdef RT_USING_DEVICE_OPS
260 const static struct rt_device_ops i2s_core_ops =
261 {
262     rt_i2s_init,
263     rt_i2s_open,
264     rt_i2s_close,
265     rt_i2s_read,
266     rt_i2s_write,
267     rt_i2s_control,
268 };
269 #endif /* RT_USING_DEVICE_OPS */
270 
rt_hw_i2s_init(void)271 int rt_hw_i2s_init(void)
272 {
273     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
274     int i;
275 
276     for (i = 0; i < sizeof(lpc_i2s_table) / sizeof(lpc_i2s_table[0]); i++)
277     {
278         #ifdef RT_USING_DEVICE_OPS
279         lpc_i2s_table[i].device.ops = &i2s_core_ops;
280         #else
281         lpc_i2s_table[i].device.init = rt_i2s_init;
282         lpc_i2s_table[i].device.open = rt_i2s_open;
283         lpc_i2s_table[i].device.close = rt_i2s_close;
284         lpc_i2s_table[i].device.read = rt_i2s_read;
285         lpc_i2s_table[i].device.write = rt_i2s_write;
286         lpc_i2s_table[i].device.control = rt_i2s_control;
287         #endif
288 
289         /* register UART device */
290         rt_device_register(&lpc_i2s_table[i].device,
291                               lpc_i2s_table[i].device_name,
292                               RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
293     }
294 
295     return 0;
296 }
297 
298 INIT_BOARD_EXPORT(rt_hw_i2s_init);
299 
300 #endif
301 
302