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  * 2024-03-28     qiujingbao   first version
9  * 2024/06/08     flyingcys    fix transmission failure
10  */
11 
12 #include <rtthread.h>
13 #include <rthw.h>
14 #include <rtdevice.h>
15 
16 #include "board.h"
17 #include "drv_spi.h"
18 
19 #include "drv_pinmux.h"
20 #include "drv_ioremap.h"
21 
22 #define DBG_LEVEL   DBG_LOG
23 #include <rtdbg.h>
24 #define LOG_TAG "drv.spi"
25 
26 struct _device_spi
27 {
28     struct rt_spi_bus spi_bus;
29     struct dw_spi dws;
30     char *device_name;
31 };
32 
33 static struct _device_spi _spi_obj[] =
34 {
35 #ifdef BSP_USING_SPI0
36     {
37         .dws.regs = (void *)DW_SPI0_BASE,
38         .dws.irq = DW_SPI0_IRQn,
39         .dws.index = 0,
40         .device_name = "spi0",
41     },
42 #endif /* BSP_USING_SPI0 */
43 #ifdef BSP_USING_SPI1
44     {
45         .dws.regs = (void *)DW_SPI1_BASE,
46         .dws.irq = DW_SPI1_IRQn,
47         .dws.index = 0,
48         .device_name = "spi1",
49     },
50 #endif /* BSP_USING_SPI1 */
51 #ifdef BSP_USING_SPI2
52     {
53         .dws.regs = (void *)DW_SPI2_BASE,
54         .dws.irq = DW_SPI2_IRQn,
55         .dws.index = 0,
56         .device_name = "spi2",
57     },
58 #endif /* BSP_USING_SPI2 */
59 #ifdef BSP_USING_SPI3
60     {
61         .dws.regs = (void *)DW_SPI3_BASE,
62         .dws.irq = DW_SPI3_IRQn,
63         .dws.index = 0,
64         .device_name = "spi3",
65     },
66 #endif /* BSP_USING_SPI3 */
67 };
68 
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * cfg)69 static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
70 {
71     RT_ASSERT(device != RT_NULL);
72     RT_ASSERT(device->bus != RT_NULL);
73     RT_ASSERT(device->bus->parent.user_data != RT_NULL);
74     RT_ASSERT(cfg != RT_NULL);
75 
76     struct _device_spi *spi = (struct _device_spi *)device->bus->parent.user_data;
77     struct dw_spi *dws = &spi->dws;
78 
79     rt_uint8_t mode;
80 
81     LOG_D("spi_configure input");
82 
83     if (cfg->mode & RT_SPI_SLAVE)
84     {
85         LOG_E("invalid mode: %d", cfg->mode);
86         return -RT_EINVAL;
87     }
88 
89     spi_reset_chip(dws);
90     spi_hw_init(dws);
91     spi_enable_chip(dws, 0);
92 
93     LOG_D("cfg->max_hz: %d", cfg->max_hz);
94     dw_spi_set_clock(dws, SPI_REF_CLK, cfg->max_hz);
95 
96     LOG_D("cfg->data_width: %d", cfg->data_width);
97     if (dw_spi_set_data_frame_len(dws, (uint32_t)cfg->data_width) < 0)
98     {
99         LOG_E("dw_spi_set_data_frame_len failed...\n");
100         return -RT_ERROR;
101     }
102 
103     LOG_D("cfg->mode: %08x", cfg->mode);
104     switch (cfg->mode & RT_SPI_MODE_3)
105     {
106         case RT_SPI_MODE_0:
107             mode = SPI_FORMAT_CPOL0_CPHA0;
108             break;
109 
110         case RT_SPI_MODE_1:
111             mode = SPI_FORMAT_CPOL0_CPHA1;
112             break;
113 
114         case RT_SPI_MODE_2:
115             mode = SPI_FORMAT_CPOL1_CPHA0;
116             break;
117 
118         case RT_SPI_MODE_3:
119             mode = SPI_FORMAT_CPOL1_CPHA1;
120             break;
121 
122         default:
123             LOG_E("spi configure mode error %x\n", cfg->mode);
124             break;
125     }
126 
127     dw_spi_set_polarity_and_phase(dws, mode);
128 
129     dw_spi_set_cs(dws, 1, 0);
130 
131     spi_enable_chip(dws, 1);
132 
133     return RT_EOK;
134 }
135 
dw_spi_transfer_one(struct dw_spi * dws,const void * tx_buf,void * rx_buf,uint32_t len,enum transfer_type tran_type)136 static rt_err_t dw_spi_transfer_one(struct dw_spi *dws, const void *tx_buf, void *rx_buf, uint32_t len, enum transfer_type  tran_type)
137 {
138     dws->tx = NULL;
139     dws->tx_end = NULL;
140     dws->rx = NULL;
141     dws->rx_end = NULL;
142 
143     if (tx_buf != NULL) {
144         dws->tx = tx_buf;
145         dws->tx_end = dws->tx + len;
146     }
147 
148     if (rx_buf != NULL) {
149         dws->rx = rx_buf;
150         dws->rx_end = dws->rx + len;
151     }
152 
153     dws->rx_len = len / dws->n_bytes;
154     dws->tx_len = len / dws->n_bytes;
155 
156     spi_enable_chip(dws, 0);
157 
158     /* For poll mode just disable all interrupts */
159     spi_mask_intr(dws, 0xff);
160 
161     /* set tran mode */
162     set_tran_mode(dws);
163 
164     /* cs0 */
165     dw_spi_set_cs(dws, true, 0);
166 
167     /* enable spi */
168     spi_enable_chip(dws, 1);
169 
170     rt_hw_us_delay(10);
171 
172     if (tran_type == POLL_TRAN)
173     {
174         if (poll_transfer(dws) < 0)
175             return -RT_ERROR;
176     }
177     else
178     {
179         return -RT_ENOSYS;
180     }
181 
182     return RT_EOK;
183 }
184 
spi_xfer(struct rt_spi_device * device,struct rt_spi_message * message)185 static rt_ssize_t spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
186 {
187     RT_ASSERT(device != RT_NULL);
188     RT_ASSERT(device->bus != RT_NULL);
189     RT_ASSERT(device->bus->parent.user_data != RT_NULL);
190     RT_ASSERT(message != RT_NULL);
191 
192     struct _device_spi *spi = (struct _device_spi *)device->bus->parent.user_data;
193     struct dw_spi *dws = &spi->dws;
194     int32_t ret = RT_EOK;
195 
196     if (message->send_buf && message->recv_buf)
197     {
198         ret = dw_spi_transfer_one(dws, message->send_buf, message->recv_buf, message->length, POLL_TRAN);
199 
200     }
201     else if (message->send_buf)
202     {
203         ret = dw_spi_transfer_one(dws, message->send_buf, RT_NULL, message->length, POLL_TRAN);
204 
205     }
206     else if (message->recv_buf)
207     {
208         ret = dw_spi_transfer_one(dws, RT_NULL, message->recv_buf, message->length, POLL_TRAN);
209 
210     } else {
211         return 0;
212     }
213 
214     if (ret != RT_EOK)
215     {
216         LOG_E("spi transfer error : %d", ret);
217         return 0;
218     }
219 
220     return message->length;
221 }
222 
223 static const struct rt_spi_ops _spi_ops =
224 {
225     .configure = spi_configure,
226     .xfer = spi_xfer,
227 };
228 
229 #if defined(BOARD_TYPE_MILKV_DUO) || defined(BOARD_TYPE_MILKV_DUO256M)
230 // For Duo / Duo 256m, only SPI2 are exported on board.
231 #ifdef BSP_USING_SPI0
232 static const char *pinname_whitelist_spi0_sck[] = {
233     NULL,
234 };
235 static const char *pinname_whitelist_spi0_sdo[] = {
236     NULL,
237 };
238 static const char *pinname_whitelist_spi0_sdi[] = {
239     NULL,
240 };
241 static const char *pinname_whitelist_spi0_cs[] = {
242     NULL,
243 };
244 #endif
245 
246 #ifdef BSP_USING_SPI1
247 static const char *pinname_whitelist_spi1_sck[] = {
248     NULL,
249 };
250 static const char *pinname_whitelist_spi1_sdo[] = {
251     NULL,
252 };
253 static const char *pinname_whitelist_spi1_sdi[] = {
254     NULL,
255 };
256 static const char *pinname_whitelist_spi1_cs[] = {
257     NULL,
258 };
259 #endif
260 
261 #ifdef BSP_USING_SPI2
262 static const char *pinname_whitelist_spi2_sck[] = {
263     "SD1_CLK",
264     NULL,
265 };
266 static const char *pinname_whitelist_spi2_sdo[] = {
267     "SD1_CMD",
268     NULL,
269 };
270 static const char *pinname_whitelist_spi2_sdi[] = {
271     "SD1_D0",
272     NULL,
273 };
274 static const char *pinname_whitelist_spi2_cs[] = {
275     "SD1_D3",
276     NULL,
277 };
278 #endif
279 
280 #ifdef BSP_USING_SPI3
281 static const char *pinname_whitelist_spi3_sck[] = {
282     NULL,
283 };
284 static const char *pinname_whitelist_spi3_sdo[] = {
285     NULL,
286 };
287 static const char *pinname_whitelist_spi3_sdi[] = {
288     NULL,
289 };
290 static const char *pinname_whitelist_spi3_cs[] = {
291     NULL,
292 };
293 #endif
294 
295 #else
296     #error "Unsupported board type!"
297 #endif
298 
rt_hw_spi_pinmux_config()299 static void rt_hw_spi_pinmux_config()
300 {
301 #ifdef BSP_USING_SPI0
302     pinmux_config(BSP_SPI0_SCK_PINNAME, SPI0_SCK, pinname_whitelist_spi0_sck);
303     pinmux_config(BSP_SPI0_SDO_PINNAME, SPI0_SDO, pinname_whitelist_spi0_sdo);
304     pinmux_config(BSP_SPI0_SDI_PINNAME, SPI0_SDI, pinname_whitelist_spi0_sdi);
305     pinmux_config(BSP_SPI0_CS_PINNAME, SPI0_CS_X, pinname_whitelist_spi0_cs);
306 #endif /* BSP_USING_SPI0 */
307 
308 #ifdef BSP_USING_SPI1
309     pinmux_config(BSP_SPI1_SCK_PINNAME, SPI1_SCK, pinname_whitelist_spi1_sck);
310     pinmux_config(BSP_SPI1_SDO_PINNAME, SPI1_SDO, pinname_whitelist_spi1_sdo);
311     pinmux_config(BSP_SPI1_SDI_PINNAME, SPI1_SDI, pinname_whitelist_spi1_sdi);
312     pinmux_config(BSP_SPI1_CS_PINNAME, SPI1_CS_X, pinname_whitelist_spi1_cs);
313 #endif /* BSP_USING_SPI1 */
314 
315 #ifdef BSP_USING_SPI2
316     pinmux_config(BSP_SPI2_SCK_PINNAME, SPI2_SCK, pinname_whitelist_spi2_sck);
317     pinmux_config(BSP_SPI2_SDO_PINNAME, SPI2_SDO, pinname_whitelist_spi2_sdo);
318     pinmux_config(BSP_SPI2_SDI_PINNAME, SPI2_SDI, pinname_whitelist_spi2_sdi);
319     pinmux_config(BSP_SPI2_CS_PINNAME, SPI2_CS_X, pinname_whitelist_spi2_cs);
320 #endif /* BSP_USING_SPI2 */
321 
322 #ifdef BSP_USING_SPI3
323     pinmux_config(BSP_SPI3_SCK_PINNAME, SPI3_SCK, pinname_whitelist_spi3_sck);
324     pinmux_config(BSP_SPI3_SDO_PINNAME, SPI3_SDO, pinname_whitelist_spi3_sdo);
325     pinmux_config(BSP_SPI3_SDI_PINNAME, SPI3_SDI, pinname_whitelist_spi3_sdi);
326     pinmux_config(BSP_SPI3_CS_PINNAME, SPI3_CS_X, pinname_whitelist_spi3_cs);
327 #endif /* BSP_USING_SPI3 */
328 }
329 
rt_hw_spi_init(void)330 int rt_hw_spi_init(void)
331 {
332     rt_err_t ret = RT_EOK;
333 
334     rt_hw_spi_pinmux_config();
335 
336     for (rt_size_t i = 0; i < sizeof(_spi_obj) / sizeof(struct _device_spi); i++)
337     {
338         _spi_obj[i].dws.regs = (void *)DRV_IOREMAP((void *)_spi_obj[i].dws.regs, 0x1000);
339 
340         _spi_obj[i].spi_bus.parent.user_data = (void *)&_spi_obj[i];
341         ret = rt_spi_bus_register(&_spi_obj[i].spi_bus, _spi_obj[i].device_name, &_spi_ops);
342     }
343 
344     RT_ASSERT(ret == RT_EOK);
345 
346     return ret;
347 }
348 INIT_DEVICE_EXPORT(rt_hw_spi_init);
349