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 * 2021-12-15 JasonHu first version
9 */
10
11 #include <rtthread.h>
12 #include <rthw.h>
13 #include <rtdevice.h>
14
15 #include "drv_spi.h"
16
17 #define DBG_TAG "DRV.SPI"
18 #define DBG_LVL DBG_LOG
19 #include <rtdbg.h>
20 #include <sunxi_hal_spi.h>
21
22 #ifdef BSP_USING_SPI
23
24 struct hw_spi_bus
25 {
26 struct rt_spi_bus parent;
27 hal_spi_master_port_t port;
28 };
29
30 #define BSP_SPI_MAX_HZ SPI_MAX_FREQUENCY
31
32 #if defined (BSP_USING_SPI0)
33 #define SPI0_BUS_NAME "spi0"
34 #define SPI0_BUS_DEVICE0_NAME "spi01"
35
36 struct hw_spi_bus spi0_bus;
37
38 #endif /* BSP_USING_SPI0 */
39
40 #if defined (BSP_USING_SPI1)
41 #define SPI1_BUS_NAME "spi1"
42 #define SPI1_BUS_DEVICE0_NAME "spi11"
43
44 struct hw_spi_bus spi1_bus;
45
46 #endif /* BSP_USING_SPI1 */
47
hw_spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * cfg)48 static rt_err_t hw_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
49 {
50 RT_ASSERT(cfg != RT_NULL);
51 RT_ASSERT(device != RT_NULL);
52
53 struct hw_spi_bus *spi_dev = RT_NULL;
54 hal_spi_master_config_t hal_cfg;
55
56 LOG_D("configure mode:%x, clk:%d\n", cfg->mode, cfg->max_hz);
57
58 /* trans cfg to hal cfg */
59 spi_dev = (struct hw_spi_bus *)(device->parent.user_data);
60
61 if (cfg->max_hz > BSP_SPI_MAX_HZ)
62 cfg->max_hz = BSP_SPI_MAX_HZ;
63
64 /* set default frequency */
65 hal_cfg.clock_frequency = cfg->max_hz;
66 hal_cfg.slave_port = HAL_SPI_MASTER_SLAVE_0; /* only support slave 0 */
67
68 /* byte order */
69 if (cfg->mode & RT_SPI_MSB)
70 {
71 hal_cfg.bit_order = HAL_SPI_MASTER_MSB_FIRST;
72 }
73 else
74 {
75 hal_cfg.bit_order = HAL_SPI_MASTER_LSB_FIRST;
76 }
77
78 if(cfg->mode & RT_SPI_CPOL)
79 {
80 hal_cfg.cpol = HAL_SPI_MASTER_CLOCK_POLARITY1;
81 }
82 else
83 {
84 hal_cfg.cpol = HAL_SPI_MASTER_CLOCK_POLARITY0;
85 }
86
87 if(cfg->mode & RT_SPI_CPHA)
88 {
89 hal_cfg.cpha = HAL_SPI_MASTER_CLOCK_PHASE1;
90 }
91 else
92 {
93 hal_cfg.cpha = HAL_SPI_MASTER_CLOCK_PHASE0;
94 }
95
96 if (cfg->mode & RT_SPI_NO_CS)
97 {
98 hal_cfg.csmode = HAL_SPI_MASTER_CS_AUTO;
99 }
100 else
101 {
102 hal_cfg.csmode = HAL_SPI_MASTER_CS_SOFT;
103 }
104
105 if (hal_spi_hw_config(spi_dev->port, &hal_cfg) != SPI_MASTER_OK)
106 {
107 return -RT_EIO;
108 }
109
110 return RT_EOK;
111 }
112
hw_spi_xfer(struct rt_spi_device * device,struct rt_spi_message * message)113 static rt_uint32_t hw_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
114 {
115 spi_master_status_t ret = SPI_MASTER_OK;
116 hal_spi_master_transfer_t tr;
117 struct hw_spi_bus *spi_dev = RT_NULL;
118
119 RT_ASSERT(device != RT_NULL);
120 RT_ASSERT(device->bus != RT_NULL);
121 RT_ASSERT(device->parent.user_data != RT_NULL);
122
123 spi_dev = (struct hw_spi_bus *)(device->parent.user_data);
124
125 tr.rx_buf = message->recv_buf;
126 tr.rx_len = message->recv_buf == RT_NULL ? 0 : message->length;
127 tr.tx_buf = message->send_buf;
128 tr.tx_len = message->send_buf == RT_NULL ? 0 : message->length;
129 tr.dummy_byte = 0;
130 tr.tx_single_len = message->send_buf == RT_NULL ? 0 : message->length;
131 tr.rx_nbits = SPI_NBITS_SINGLE;
132 tr.tx_nbits = SPI_NBITS_SINGLE;
133
134 if (message->cs_take && !(device->config.mode & RT_SPI_NO_CS))
135 {
136 if (device->config.mode & RT_SPI_CS_HIGH)
137 {
138 hal_spi_cs(spi_dev->port, 1);
139 }
140 else
141 {
142 hal_spi_cs(spi_dev->port, 0);
143 }
144 }
145
146 if (message->length > 0)
147 {
148 ret = hal_spi_xfer(spi_dev->port, &tr);
149 }
150
151 // FIXME: GCC O3 maybe not execute.
152 if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS))
153 {
154 if (device->config.mode & RT_SPI_CS_HIGH)
155 {
156 hal_spi_cs(spi_dev->port, 0);
157 }
158 else
159 {
160 hal_spi_cs(spi_dev->port, 1);
161 }
162 }
163
164 if (ret != SPI_MASTER_OK)
165 {
166 LOG_E("xfer err ret:%ld", ret);
167 return -RT_EIO;
168 }
169
170 return message->length;
171 }
172
173 /**
174 * attach a spi device on bus
175 */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name)176 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name)
177 {
178 rt_err_t ret = RT_EOK;
179 struct hw_spi_bus *hw_spi = RT_NULL;
180
181 struct rt_spi_device *spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
182 RT_ASSERT(spi_device != RT_NULL);
183 #ifdef BSP_USING_SPI0
184 if (!rt_strcmp(bus_name, SPI0_BUS_NAME))
185 {
186 hw_spi = &spi0_bus;
187 }
188 else
189 #endif
190 #ifdef BSP_USING_SPI1
191 if (!rt_strcmp(bus_name, SPI0_BUS_NAME))
192 {
193 hw_spi = &spi1_bus;
194 }
195 else
196 #endif
197 {
198 return -RT_EIO;
199 }
200 /* TODO: attach device */
201 ret = rt_spi_bus_attach_device(spi_device, device_name, bus_name, hw_spi);
202 return ret;
203 }
204
205 static struct rt_spi_ops hw_spi_ops =
206 {
207 .configure = hw_spi_configure,
208 .xfer = hw_spi_xfer
209 };
210
211 #endif /* BSP_USING_SPI */
212
213 /* used to init spi bus */
214 static hal_spi_master_config_t default_hal_cfg = {
215 .bit_order = HAL_SPI_MASTER_MSB_FIRST,
216 .clock_frequency = 5000000,//SPI_MOD_CLK,
217 .cpha = HAL_SPI_MASTER_CLOCK_PHASE0,
218 .cpol = HAL_SPI_MASTER_CLOCK_POLARITY0,
219 .slave_port = HAL_SPI_MASTER_SLAVE_0,
220 .csmode = HAL_SPI_MASTER_CS_SOFT,
221 };
222
rt_hw_spi_init(void)223 int rt_hw_spi_init(void)
224 {
225 #if defined (BSP_USING_SPI0)
226 spi0_bus.port = HAL_SPI_MASTER_0;
227 if (hal_spi_init(spi0_bus.port, &default_hal_cfg) != SPI_MASTER_OK)
228 {
229 LOG_E("hal init %s bus failed!", SPI0_BUS_NAME);
230 return -1;
231 }
232 rt_spi_bus_register(&spi0_bus.parent, SPI0_BUS_NAME, &hw_spi_ops);
233
234 rt_hw_spi_device_attach(SPI0_BUS_NAME, SPI0_BUS_DEVICE0_NAME);
235 #endif /* BSP_USING_SPI0 */
236
237 #if defined (BSP_USING_SPI1)
238 spi1_bus.port = HAL_SPI_MASTER_1;
239 if (hal_spi_init(spi1_bus.port, &default_hal_cfg) != SPI_MASTER_OK)
240 {
241 LOG_E("hal init %s bus failed!", SPI1_BUS_NAME);
242 return -1;
243 }
244 rt_spi_bus_register(&spi1_bus.parent, SPI1_BUS_NAME, &hw_spi_ops);
245 rt_hw_spi_device_attach(SPI1_BUS_NAME, SPI1_BUS_DEVICE0_NAME);
246
247 #endif /* BSP_USING_SPI1 */
248 return RT_EOK;
249 }
250 INIT_DEVICE_EXPORT(rt_hw_spi_init);
251
252 #define CFG_GPIO_PORT(p) ((p) - 'A' + 1)
253
hal_spi_gpio_cfg_count(const char * secname)254 int32_t hal_spi_gpio_cfg_count(const char *secname)
255 {
256 return 4;
257 }
258
259 static const user_gpio_set_t _spi_gpio_cfg[][4] = {
260 {// spi0
261 {
262 .gpio_name = "spi0_sclk",
263 .port = CFG_GPIO_PORT('C'),
264 .port_num = 2, // PC02
265 .mul_sel = 2,
266 .pull = 0, // no pull
267 .drv_level = 3,
268 .data = 0,
269 },
270 {
271 .gpio_name = "spi0_cs",
272 .port = CFG_GPIO_PORT('C'),
273 .port_num = 3, // PC03
274 .mul_sel = 2,
275 .pull = 1, // pull up
276 .drv_level = 3,
277 .data = 0,
278 },
279 {
280 .gpio_name = "spi0_mosi",
281 .port = CFG_GPIO_PORT('C'),
282 .port_num = 4, // PC04
283 .mul_sel = 2,
284 .pull = 0, // no pull
285 .drv_level = 3,
286 .data = 0,
287 },
288 {
289 .gpio_name = "spi0_miso",
290 .port = CFG_GPIO_PORT('C'),
291 .port_num = 5, // PC05
292 .mul_sel = 2,
293 .pull = 0, // no pull
294 .drv_level = 3,
295 .data = 0,
296 }
297 },
298 };
299
hal_spi_gpio_cfg_load(user_gpio_set_t * gpio_cfg,int32_t GPIONum,int id)300 int hal_spi_gpio_cfg_load(user_gpio_set_t *gpio_cfg, int32_t GPIONum, int id)
301 {
302 int i;
303
304 if (id > sizeof(_spi_gpio_cfg) / sizeof(_spi_gpio_cfg[0]))
305 {
306 rt_kprintf("spi id %d>%d\n", id, sizeof(_spi_gpio_cfg) / sizeof(_spi_gpio_cfg[0]));
307 return -1;
308 }
309
310 /* twi0 */
311 for (i = 0; i < GPIONum; i++)
312 {
313 memcpy(gpio_cfg, &_spi_gpio_cfg[id][i], sizeof(user_gpio_set_t));
314 gpio_cfg++;
315 }
316
317 return 0;
318 }
319
320 /*
321 * 程序清单:这是一个 SPI 设备使用例程
322 * 例程导出了 spi_w25q_sample 命令到控制终端
323 * 命令调用格式:spi_w25q_sample spi10
324 * 命令解释:命令第二个参数是要使用的SPI设备名称,为空则使用默认的SPI设备
325 * 程序功能:通过SPI设备读取 w25q 的 ID 数据
326 */
327
328 #include <rtthread.h>
329 #include <rtdevice.h>
330
331 #define SPI_DEVICE_NAME "spi01"
332
spi_sample(int argc,char * argv[])333 static void spi_sample(int argc, char *argv[])
334 {
335 struct rt_spi_device *spi_dev;
336 static char cmd[200];
337 static char recv_data[200];
338 rt_uint8_t id[5] = {0};
339 int i;
340 rt_err_t err;
341 int type;
342
343 type = atoi(argv[1]);
344
345 for (i = 0; i < sizeof(cmd); i++)
346 {
347 cmd[i] = i + 1;
348 }
349
350 /* 查找 spi 设备获取设备句柄 */
351 spi_dev = (struct rt_spi_device *)rt_device_find(SPI_DEVICE_NAME);
352 if (!spi_dev)
353 {
354 rt_kprintf("spi sample run failed! can't find %s device!\n", SPI_DEVICE_NAME);
355 }
356 else
357 {
358 struct rt_spi_configuration spi_cfg;
359 spi_cfg.max_hz = 5000000;
360 spi_cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB;
361 spi_cfg.data_width = 8;
362
363 rt_spi_configure(spi_dev, &spi_cfg);
364 if (type == 1)
365 {
366 err = rt_spi_transfer(spi_dev, cmd, recv_data, sizeof(recv_data));
367 }
368 else if (type == 2)
369 {
370 err = rt_spi_send_then_recv(spi_dev, cmd, sizeof(cmd), recv_data, sizeof(recv_data));
371 }
372 else if (type == 3)
373 {
374 err = rt_spi_send(spi_dev, cmd, sizeof(cmd));
375 }
376 else if (type == 4)
377 {
378 err = rt_spi_send_then_send(spi_dev, cmd, sizeof(cmd), cmd, sizeof(cmd));
379 }
380 else if (type == 5)
381 {
382 err = rt_spi_recv(spi_dev, recv_data, sizeof(recv_data));
383 }
384 // err = rt_spi_send(spi_dev, cmd, sizeof(cmd));
385 if (err != sizeof(cmd))
386 {
387 rt_kprintf("spi send error:%d\n", err);
388 }
389 }
390 }
391 /* 导出到 msh 命令列表中 */
392 MSH_CMD_EXPORT(spi_sample, spi w25q sample);
393