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