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