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