1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-03-12     Wangyuqiang  the first version
9  */
10 #include <board.h>
11 #include <string.h>
12 #include "drv_soft_spi.h"
13 #include "drv_config.h"
14 
15 #if defined BSP_USING_SOFT_SPI
16 
17 //#define DRV_DEBUG
18 #define LOG_TAG             "drv.soft_spi"
19 #include <drv_log.h>
20 
21 static struct ra_soft_spi_config soft_spi_config[] =
22 {
23 #ifdef BSP_USING_SOFT_SPI1
24         SOFT_SPI1_BUS_CONFIG,
25 #endif
26 #ifdef BSP_USING_SOFT_SPI2
27         SOFT_SPI2_BUS_CONFIG,
28 #endif
29 };
30 
31 static struct ra_soft_spi spi_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])];
32 
33 /**
34   * Attach the spi device to soft SPI bus, this function must be used after initialization.
35   */
rt_soft_spi_device_attach(const char * bus_name,const char * device_name,rt_base_t cs_pin)36 rt_err_t rt_soft_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
37 {
38 
39     rt_err_t result;
40     struct rt_spi_device *spi_device;
41 
42     /* attach the device to soft spi bus*/
43     spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
44     RT_ASSERT(spi_device != RT_NULL);
45 
46     result = rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, cs_pin, RT_NULL);
47     return result;
48 }
49 
ra_spi_gpio_init(struct ra_soft_spi * spi)50 static void ra_spi_gpio_init(struct ra_soft_spi *spi)
51 {
52     struct ra_soft_spi_config *cfg = (struct ra_soft_spi_config *)spi->cfg;
53     rt_pin_mode(cfg->sck, PIN_MODE_OUTPUT);
54     rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
55     rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
56 
57     rt_pin_write(cfg->miso, PIN_HIGH);
58     rt_pin_write(cfg->sck, PIN_HIGH);
59     rt_pin_write(cfg->mosi, PIN_HIGH);
60 }
61 
ra_tog_sclk(void * data)62 static void ra_tog_sclk(void *data)
63 {
64     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
65     if(rt_pin_read(cfg->sck) == PIN_HIGH)
66     {
67         rt_pin_write(cfg->sck, PIN_LOW);
68     }
69     else
70     {
71         rt_pin_write(cfg->sck, PIN_HIGH);
72     }
73 }
74 
ra_set_sclk(void * data,rt_int32_t state)75 static void ra_set_sclk(void *data, rt_int32_t state)
76 {
77     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
78     if (state)
79     {
80         rt_pin_write(cfg->sck, PIN_HIGH);
81     }
82     else
83     {
84         rt_pin_write(cfg->sck, PIN_LOW);
85     }
86 }
87 
ra_set_mosi(void * data,rt_int32_t state)88 static void ra_set_mosi(void *data, rt_int32_t state)
89 {
90     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
91     if (state)
92     {
93         rt_pin_write(cfg->mosi, PIN_HIGH);
94     }
95     else
96     {
97         rt_pin_write(cfg->mosi, PIN_LOW);
98     }
99 }
100 
ra_set_miso(void * data,rt_int32_t state)101 static void ra_set_miso(void *data, rt_int32_t state)
102 {
103     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
104     if (state)
105     {
106         rt_pin_write(cfg->miso, PIN_HIGH);
107     }
108     else
109     {
110         rt_pin_write(cfg->miso, PIN_LOW);
111     }
112 }
113 
ra_get_sclk(void * data)114 static rt_int32_t ra_get_sclk(void *data)
115 {
116     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
117     return rt_pin_read(cfg->sck);
118 }
119 
ra_get_mosi(void * data)120 static rt_int32_t ra_get_mosi(void *data)
121 {
122     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
123     return rt_pin_read(cfg->mosi);
124 }
125 
ra_get_miso(void * data)126 static rt_int32_t ra_get_miso(void *data)
127 {
128     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
129     return rt_pin_read(cfg->miso);
130 }
131 
ra_dir_mosi(void * data,rt_int32_t state)132 static void ra_dir_mosi(void *data, rt_int32_t state)
133 {
134     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
135     if (state)
136     {
137         rt_pin_mode(cfg->mosi, PIN_MODE_INPUT);
138     }
139     else
140     {
141         rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
142     }
143 }
144 
ra_dir_miso(void * data,rt_int32_t state)145 static void ra_dir_miso(void *data, rt_int32_t state)
146 {
147     struct ra_soft_spi_config* cfg = (struct ra_soft_spi_config*)data;
148     if (state)
149     {
150         rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
151     }
152     else
153     {
154         rt_pin_mode(cfg->miso, PIN_MODE_OUTPUT);
155     }
156 }
157 
ra_udelay(rt_uint32_t us)158 static void ra_udelay(rt_uint32_t us)
159 {
160     rt_uint32_t ticks;
161     rt_uint32_t told, tnow, tcnt = 0;
162     rt_uint32_t reload = SysTick->LOAD;
163 
164     ticks = us * reload / (1000000UL / RT_TICK_PER_SECOND);
165     told = SysTick->VAL;
166     while (1)
167     {
168         tnow = SysTick->VAL;
169         if (tnow != told)
170         {
171             if (tnow < told)
172             {
173                 tcnt += told - tnow;
174             }
175             else
176             {
177                 tcnt += reload - tnow + told;
178             }
179             told = tnow;
180             if (tcnt >= ticks)
181             {
182                 break;
183             }
184         }
185     }
186 }
187 
ra_pin_init(void)188 static void ra_pin_init(void)
189 {
190     rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct ra_soft_spi);
191 
192     for(rt_size_t i = 0; i < obj_num; i++)
193     {
194         ra_spi_gpio_init(&spi_obj[i]);
195     }
196 }
197 
198 static struct rt_spi_bit_ops ra_soft_spi_ops =
199     {
200         .data = RT_NULL,
201         .pin_init = ra_pin_init,
202         .tog_sclk = ra_tog_sclk,
203         .set_sclk = ra_set_sclk,
204         .set_mosi = ra_set_mosi,
205         .set_miso = ra_set_miso,
206         .get_sclk = ra_get_sclk,
207         .get_mosi = ra_get_mosi,
208         .get_miso = ra_get_miso,
209         .dir_mosi = ra_dir_mosi,
210         .dir_miso = ra_dir_miso,
211         .udelay = ra_udelay,
212         .delay_us = 1,
213 };
214 
215 /* Soft SPI initialization function */
rt_hw_softspi_init(void)216 int rt_hw_softspi_init(void)
217 {
218     rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct ra_soft_spi);
219     rt_err_t result;
220 
221     for (rt_size_t i = 0; i < obj_num; i++)
222     {
223         memcpy(&spi_obj[i].ops, &ra_soft_spi_ops, sizeof(struct rt_spi_bit_ops));
224         spi_obj[i].ops.data = (void *)&soft_spi_config[i];
225         spi_obj[i].spi.ops = &ra_soft_spi_ops;
226         spi_obj[i].cfg = (void *)&soft_spi_config[i];
227         result = rt_spi_bit_add_bus(&spi_obj[i].spi, soft_spi_config[i].bus_name, &spi_obj[i].ops);
228         RT_ASSERT(result == RT_EOK);
229     }
230 
231     return RT_EOK;
232 }
233 INIT_BOARD_EXPORT(rt_hw_softspi_init);
234 
235 #endif /* BSP_USING_SOFT_SPI */
236