1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-07-15 yandld The first version for MCXN
9 */
10 #include "rtdevice.h"
11
12 #include "fsl_common.h"
13 #include "fsl_lpspi.h"
14 #include "fsl_lpspi_edma.h"
15
16 #define DMA_MAX_TRANSFER_COUNT (32767)
17
18 enum
19 {
20 #ifdef BSP_USING_SPI1
21 SPI1_INDEX,
22 #endif
23 #ifdef BSP_USING_SPI3
24 SPI3_INDEX,
25 #endif
26
27 #ifdef BSP_USING_SPI6
28 SPI6_INDEX,
29 #endif
30
31 #ifdef BSP_USING_SPI7
32 SPI7_INDEX,
33 #endif
34 };
35
36 struct lpc_spi
37 {
38 struct rt_spi_bus parent;
39 LPSPI_Type *LPSPIx;
40 clock_attach_id_t clock_attach_id;
41 clock_div_name_t clock_div_name;
42 clock_name_t clock_name;
43
44 DMA_Type *DMAx;
45 uint8_t tx_dma_chl;
46 uint8_t rx_dma_chl;
47 edma_handle_t dma_tx_handle;
48 edma_handle_t dma_rx_handle;
49 dma_request_source_t tx_dma_request;
50 dma_request_source_t rx_dma_request;
51 lpspi_master_edma_handle_t spi_dma_handle;
52
53 rt_sem_t sem;
54 char *name;
55 };
56
57 static struct lpc_spi lpc_obj[] =
58 {
59 #ifdef BSP_USING_SPI1
60 {
61 .LPSPIx = LPSPI1,
62 .clock_attach_id = kFRO_HF_DIV_to_FLEXCOMM1,
63 .clock_div_name = kCLOCK_DivFlexcom1Clk,
64 .clock_name = kCLOCK_FroHf,
65 .tx_dma_request = kDma0RequestMuxLpFlexcomm1Tx,
66 .rx_dma_request = kDma0RequestMuxLpFlexcomm1Rx,
67 .DMAx = DMA0,
68 .tx_dma_chl = 0,
69 .rx_dma_chl = 1,
70 .name = "spi1",
71 },
72 #endif
73 #ifdef BSP_USING_SPI3
74 {
75 .LPSPIx = LPSPI3,
76 .clock_attach_id = kFRO_HF_DIV_to_FLEXCOMM3,
77 .clock_div_name = kCLOCK_DivFlexcom3Clk,
78 .clock_name = kCLOCK_FroHf,
79 .tx_dma_request = kDma0RequestMuxLpFlexcomm3Tx,
80 .rx_dma_request = kDma0RequestMuxLpFlexcomm3Rx,
81 .DMAx = DMA0,
82 .tx_dma_chl = 2,
83 .rx_dma_chl = 3,
84 .name = "spi3",
85 },
86 #endif /* BSP_USING_SPI3 */
87 #ifdef BSP_USING_SPI6
88 {
89 .LPSPIx = LPSPI6,
90 .clock_attach_id = kFRO_HF_DIV_to_FLEXCOMM6,
91 .clock_div_name = kCLOCK_DivFlexcom6Clk,
92 .clock_name = kCLOCK_FroHf,
93 .tx_dma_request = kDma0RequestMuxLpFlexcomm6Tx,
94 .rx_dma_request = kDma0RequestMuxLpFlexcomm6Rx,
95 .DMAx = DMA0,
96 .tx_dma_chl = 4,
97 .rx_dma_chl = 5,
98 .name = "spi6",
99 },
100 #endif /* BSP_USING_SPI6 */
101 #ifdef BSP_USING_SPI7
102 {
103 .LPSPIx = LPSPI7,
104 .clock_attach_id = kFRO_HF_DIV_to_FLEXCOMM7,
105 .clock_div_name = kCLOCK_DivFlexcom7Clk,
106 .clock_name = kCLOCK_FroHf,
107 .tx_dma_request = kDma0RequestMuxLpFlexcomm7Tx,
108 .rx_dma_request = kDma0RequestMuxLpFlexcomm7Rx,
109 .DMAx = DMA0,
110 .tx_dma_chl = 2,
111 .rx_dma_chl = 3,
112 .name = "spi7",
113 },
114 #endif /* BSP_USING_SPI7 */
115 };
116
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,rt_uint32_t pin)117 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_uint32_t pin)
118 {
119 struct rt_spi_device *spi_device = rt_malloc(sizeof(struct rt_spi_device));
120 if (!spi_device)
121 {
122 return -RT_ENOMEM;
123 }
124
125 return rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, pin, RT_NULL);
126 }
127
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * cfg)128 static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
129 {
130 rt_err_t ret = RT_EOK;
131 // struct lpc_spi *spi = RT_NULL;
132 // spi = (struct lpc_spi *)(device->bus->parent.user_data);
133 // ret = lpc_spi_init(spi->SPIx, cfg);
134 return ret;
135 }
136
LPSPI_MasterUserCallback(LPSPI_Type * base,lpspi_master_edma_handle_t * handle,status_t status,void * userData)137 static void LPSPI_MasterUserCallback(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, status_t status, void *userData)
138 {
139 struct lpc_spi *spi = (struct lpc_spi *)userData;
140 rt_sem_release(spi->sem);
141
142 }
143
spixfer(struct rt_spi_device * device,struct rt_spi_message * message)144 static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
145 {
146 int i;
147 lpspi_transfer_t transfer = {0};
148
149 RT_ASSERT(device != RT_NULL);
150 RT_ASSERT(device->bus != RT_NULL);
151 RT_ASSERT(device->bus->parent.user_data != RT_NULL);
152
153
154 struct lpc_spi *spi = device->bus->parent.user_data;
155
156 if (message->cs_take)
157 {
158 rt_pin_write(device->cs_pin, PIN_LOW);
159 }
160
161 transfer.dataSize = message->length;
162 transfer.rxData = (uint8_t *)(message->recv_buf);
163 transfer.txData = (uint8_t *)(message->send_buf);
164
165 // if(message->length < MAX_DMA_TRANSFER_SIZE)
166 if (0)
167 {
168 LPSPI_MasterTransferBlocking(spi->LPSPIx, &transfer);
169 }
170 else
171 {
172 uint32_t block, remain;
173 block = message->length / DMA_MAX_TRANSFER_COUNT;
174 remain = message->length % DMA_MAX_TRANSFER_COUNT;
175
176 for (i = 0; i < block; i++)
177 {
178 transfer.dataSize = DMA_MAX_TRANSFER_COUNT;
179 if (message->recv_buf) transfer.rxData = (uint8_t *)(message->recv_buf + i *DMA_MAX_TRANSFER_COUNT);
180 if (message->send_buf) transfer.txData = (uint8_t *)(message->send_buf + i *DMA_MAX_TRANSFER_COUNT);
181
182 LPSPI_MasterTransferEDMA(spi->LPSPIx, &spi->spi_dma_handle, &transfer);
183 rt_sem_take(spi->sem, RT_WAITING_FOREVER);
184 }
185
186 if (remain)
187 {
188 transfer.dataSize = remain;
189 if (message->recv_buf) transfer.rxData = (uint8_t *)(message->recv_buf + i *DMA_MAX_TRANSFER_COUNT);
190 if (message->send_buf) transfer.txData = (uint8_t *)(message->send_buf + i *DMA_MAX_TRANSFER_COUNT);
191
192 LPSPI_MasterTransferEDMA(spi->LPSPIx, &spi->spi_dma_handle, &transfer);
193 rt_sem_take(spi->sem, RT_WAITING_FOREVER);
194 }
195 }
196
197 if (message->cs_release)
198 {
199 rt_pin_write(device->cs_pin, PIN_HIGH);
200 }
201
202 return message->length;
203 }
204
205 static struct rt_spi_ops lpc_spi_ops =
206 {
207 .configure = spi_configure,
208 .xfer = spixfer
209 };
210
rt_hw_spi_init(void)211 int rt_hw_spi_init(void)
212 {
213 int i;
214
215 for (i = 0; i < ARRAY_SIZE(lpc_obj); i++)
216 {
217 CLOCK_SetClkDiv(lpc_obj[i].clock_div_name, 1u);
218 CLOCK_AttachClk(lpc_obj[i].clock_attach_id);
219
220 lpc_obj[i].parent.parent.user_data = &lpc_obj[i];
221 lpc_obj[i].sem = rt_sem_create("sem_spi", 0, RT_IPC_FLAG_FIFO);
222
223 lpspi_master_config_t masterConfig;
224 LPSPI_MasterGetDefaultConfig(&masterConfig);
225 masterConfig.baudRate = 24 * 1000 * 1000;
226 masterConfig.pcsToSckDelayInNanoSec = 1000000000U / masterConfig.baudRate * 1U;
227 masterConfig.lastSckToPcsDelayInNanoSec = 1000000000U / masterConfig.baudRate * 1U;
228 masterConfig.betweenTransferDelayInNanoSec = 1000000000U / masterConfig.baudRate * 1U;
229
230 LPSPI_MasterInit(lpc_obj[i].LPSPIx, &masterConfig, CLOCK_GetFreq(lpc_obj[i].clock_name));
231
232 EDMA_CreateHandle(&lpc_obj[i].dma_tx_handle, lpc_obj[i].DMAx, lpc_obj[i].tx_dma_chl);
233 EDMA_CreateHandle(&lpc_obj[i].dma_rx_handle, lpc_obj[i].DMAx, lpc_obj[i].rx_dma_chl);
234
235 EDMA_SetChannelMux(lpc_obj[i].DMAx, lpc_obj[i].tx_dma_chl, lpc_obj[i].tx_dma_request);
236 EDMA_SetChannelMux(lpc_obj[i].DMAx, lpc_obj[i].rx_dma_chl, lpc_obj[i].rx_dma_request);
237
238 LPSPI_MasterTransferCreateHandleEDMA(lpc_obj[i].LPSPIx, &lpc_obj[i].spi_dma_handle, LPSPI_MasterUserCallback, &lpc_obj[i], &lpc_obj[i].dma_rx_handle, &lpc_obj[i].dma_tx_handle);
239
240 rt_spi_bus_register(&lpc_obj[i].parent, lpc_obj[i].name, &lpc_spi_ops);
241 }
242 return RT_EOK;
243 }
244
245 INIT_DEVICE_EXPORT(rt_hw_spi_init);
246
247