Skip to content

Commit 0822f02

Browse files
Vandoulmysterywolf
authored andcommitted
[bsp][lpc55sxx] add i2s and wm8904 driver
1 parent d6e40f2 commit 0822f02

File tree

5 files changed

+1687
-0
lines changed

5 files changed

+1687
-0
lines changed

bsp/lpc55sxx/Libraries/drivers/SConscript

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ if GetDepend('BSP_USING_WDT'):
4343
if GetDepend('BSP_USING_PWM'):
4444
src += ['drv_pwm.c']
4545

46+
if GetDepend('BSP_USING_I2S'):
47+
src += ['drv_i2s.c']
48+
49+
if GetDepend('BSP_USING_WM8904'):
50+
src += ['drv_sound_wm8904.c']
51+
4652
path = [cwd,cwd + '/config']
4753

4854
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path)
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
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+
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+
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+
}
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+
}
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+
}
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+
}
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+
}
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+
}
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+
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+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2006-2022, 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+
#ifndef __DRV_I2S_H__
12+
#define __DRV_I2S_H__
13+
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
#include <rtthread.h>
19+
20+
#pragma pack(push,1)
21+
struct lpc_i2s_config
22+
{
23+
uint32_t sampling_rate;
24+
uint8_t mode;
25+
uint8_t data_bits;
26+
uint8_t channels;
27+
uint8_t is_blocking;
28+
};
29+
#pragma pack(pop)
30+
31+
#define LPC_I2S_CONFIG_MODE_NULL 0
32+
#define LPC_I2S_CONFIG_MODE_SLAVE 1
33+
#define LPC_I2S_CONFIG_MODE_MASTER 2
34+
35+
#define RT_I2S_CTRL_RESET (RT_DEVICE_CTRL_BASE(Bus) + 1)
36+
#define RT_I2S_CTRL_SET_CONFIG (RT_DEVICE_CTRL_BASE(Bus) + 2)
37+
38+
#ifdef __cplusplus
39+
}
40+
#endif
41+
42+
#endif
43+

0 commit comments

Comments
 (0)