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