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  * 2025-01-23     CYFS          first version
9  */
10 #include <rthw.h>
11 #include <rtdevice.h>
12 #include <dev_spi_bit_ops.h>
13 
14 #ifdef RT_USING_SOFT_SPI
15 #if !defined(RT_USING_SOFT_SPI0) &&\
16     !defined(RT_USING_SOFT_SPI1) && !defined(RT_USING_SOFT_SPI2) &&\
17     !defined(RT_USING_SOFT_SPI3) && !defined(RT_USING_SOFT_SPI4) &&\
18     !defined(RT_USING_SOFT_SPI5) && !defined(RT_USING_SOFT_SPI6)
19     #error "Please define at least one RT_USING_SOFT_SPIx"
20     /*
21     This driver can be disabled at:
22     menuconfig -> RT-Thread Components -> Device Drivers -> Using I2C device drivers
23     */
24 #endif
25 
26 #define DBG_ENABLE
27 #define DBG_TAG                         "SPI_S"
28 #ifdef RT_SPI_BITOPS_DEBUG
29     #define DBG_LEVEL                   DBG_LOG
30 #endif
31 #include <rtdbg.h>
32 
33 /* spi config class */
34 struct rt_soft_spi_config
35 {
36     rt_base_t       sck;
37     rt_base_t       miso;
38     rt_base_t       mosi;
39     rt_uint32_t     timing_delay;
40     const char      *bus_name;
41 };
42 
43 /* spi dirver class */
44 struct rt_soft_spi
45 {
46     struct rt_spi_bit_obj spi;
47     struct rt_spi_bit_ops ops;
48     struct rt_soft_spi_config *cfg;
49 };
50 
51 static struct rt_soft_spi_config soft_spi_config[] =
52 {
53 #ifdef RT_USING_SOFT_SPI0
54     {
55         .sck = RT_SOFT_SPI0_SCK_PIN,
56         .miso = RT_SOFT_SPI0_MISO_PIN,
57         .mosi = RT_SOFT_SPI0_MOSI_PIN,
58         .timing_delay = RT_SOFT_SPI0_TIMING_DELAY,
59         .bus_name = RT_SOFT_SPI0_BUS_NAME,
60     },
61 #endif  /*RT_USING_SOFT_SPI0*/
62 #ifdef RT_USING_SOFT_SPI1
63     {
64         .sck = RT_SOFT_SPI1_SCK_PIN,
65         .miso = RT_SOFT_SPI1_MISO_PIN,
66         .mosi = RT_SOFT_SPI1_MOSI_PIN,
67         .timing_delay = RT_SOFT_SPI1_TIMING_DELAY,
68         .bus_name = RT_SOFT_SPI1_BUS_NAME,
69     },
70 #endif  /*RT_USING_SOFT_SPI1*/
71 #ifdef RT_USING_SOFT_SPI2
72     {
73         .sck = RT_SOFT_SPI2_SCK_PIN,
74         .miso = RT_SOFT_SPI2_MISO_PIN,
75         .mosi = RT_SOFT_SPI2_MOSI_PIN,
76         .timing_delay = RT_SOFT_SPI2_TIMING_DELAY,
77         .bus_name = RT_SOFT_SPI2_BUS_NAME,
78     },
79 #endif  /*RT_USING_SOFT_SPI2*/
80 #ifdef RT_USING_SOFT_SPI3
81     {
82         .sck = RT_SOFT_SPI3_SCK_PIN,
83         .miso = RT_SOFT_SPI3_MISO_PIN,
84         .mosi = RT_SOFT_SPI3_MOSI_PIN,
85         .timing_delay = RT_SOFT_SPI3_TIMING_DELAY,
86         .bus_name = RT_SOFT_SPI3_BUS_NAME,
87     },
88 #endif  /*RT_USING_SOFT_SPI3*/
89 #ifdef RT_USING_SOFT_SPI4
90     {
91         .sck = RT_SOFT_SPI4_SCK_PIN,
92         .miso = RT_SOFT_SPI4_MISO_PIN,
93         .mosi = RT_SOFT_SPI4_MOSI_PIN,
94         .timing_delay = RT_SOFT_SPI4_TIMING_DELAY,
95         .bus_name = RT_SOFT_SPI4_BUS_NAME,
96     },
97 #endif  /*RT_USING_SOFT_SPI4*/
98 #ifdef RT_USING_SOFT_SPI5
99     {
100         .sck = RT_SOFT_SPI5_SCK_PIN,
101         .miso = RT_SOFT_SPI5_MISO_PIN,
102         .mosi = RT_SOFT_SPI5_MOSI_PIN,
103         .timing_delay = RT_SOFT_SPI5_TIMING_DELAY,
104         .bus_name = RT_SOFT_SPI5_BUS_NAME,
105     },
106 #endif  /*RT_USING_SOFT_SPI5*/
107 #ifdef RT_USING_SOFT_SPI6
108     {
109         .sck = RT_SOFT_SPI6_SCK_PIN,
110         .miso = RT_SOFT_SPI6_MISO_PIN,
111         .mosi = RT_SOFT_SPI6_MOSI_PIN,
112         .timing_delay = RT_SOFT_SPI6_TIMING_DELAY,
113         .bus_name = RT_SOFT_SPI6_BUS_NAME,
114     },
115 #endif  /*RT_USING_SOFT_SPI6*/
116 
117 };
118 
119 static struct rt_soft_spi spi_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])];
120 
spi_soft_pin_init(struct rt_soft_spi * soft_spi)121 static void spi_soft_pin_init(struct rt_soft_spi * soft_spi)
122 {
123     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)soft_spi->cfg;
124     rt_pin_mode(cfg->sck, PIN_MODE_OUTPUT);
125     rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
126     rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
127 
128     rt_pin_write(cfg->miso, PIN_HIGH);
129     rt_pin_write(cfg->sck, PIN_HIGH);
130     rt_pin_write(cfg->mosi, PIN_HIGH);
131 }
132 
133 
spi_soft_tog_sclk(void * data)134 static void spi_soft_tog_sclk(void *data)
135 {
136     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
137     if(rt_pin_read(cfg->sck) == PIN_HIGH)
138     {
139         rt_pin_write(cfg->sck, PIN_LOW);
140     }
141     else
142     {
143         rt_pin_write(cfg->sck, PIN_HIGH);
144     }
145 }
146 
spi_soft_set_sclk(void * data,rt_int32_t state)147 static void spi_soft_set_sclk(void *data, rt_int32_t state)
148 {
149     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
150     if (state)
151     {
152         rt_pin_write(cfg->sck, PIN_HIGH);
153     }
154     else
155     {
156         rt_pin_write(cfg->sck, PIN_LOW);
157     }
158 }
159 
spi_soft_set_mosi(void * data,rt_int32_t state)160 static void spi_soft_set_mosi(void *data, rt_int32_t state)
161 {
162     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
163     if (state)
164     {
165         rt_pin_write(cfg->mosi, PIN_HIGH);
166     }
167     else
168     {
169         rt_pin_write(cfg->mosi, PIN_LOW);
170     }
171 }
172 
spi_soft_set_miso(void * data,rt_int32_t state)173 static void spi_soft_set_miso(void *data, rt_int32_t state)
174 {
175     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
176     if (state)
177     {
178         rt_pin_write(cfg->miso, PIN_HIGH);
179     }
180     else
181     {
182         rt_pin_write(cfg->miso, PIN_LOW);
183     }
184 }
185 
spi_soft_get_sclk(void * data)186 static rt_int32_t spi_soft_get_sclk(void *data)
187 {
188     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
189     return rt_pin_read(cfg->sck);
190 }
191 
spi_soft_get_mosi(void * data)192 static rt_int32_t spi_soft_get_mosi(void *data)
193 {
194     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
195     return rt_pin_read(cfg->mosi);
196 }
197 
spi_soft_get_miso(void * data)198 static rt_int32_t spi_soft_get_miso(void *data)
199 {
200     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
201     return rt_pin_read(cfg->miso);
202 }
203 
spi_soft_dir_mosi(void * data,rt_int32_t state)204 static void spi_soft_dir_mosi(void *data, rt_int32_t state)
205 {
206     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
207     if (state)
208     {
209         rt_pin_mode(cfg->mosi, PIN_MODE_INPUT);
210     }
211     else
212     {
213         rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
214     }
215 }
216 
spi_soft_dir_miso(void * data,rt_int32_t state)217 static void spi_soft_dir_miso(void *data, rt_int32_t state)
218 {
219     struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
220     if (state)
221     {
222         rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
223     }
224     else
225     {
226         rt_pin_mode(cfg->miso, PIN_MODE_OUTPUT);
227     }
228 }
229 
230 static struct rt_spi_bit_ops soft_spi_ops=
231 {
232     .data = RT_NULL,
233     .pin_init = RT_NULL,
234     .tog_sclk = spi_soft_tog_sclk,
235     .set_sclk = spi_soft_set_sclk,
236     .set_mosi = spi_soft_set_mosi,
237     .set_miso = spi_soft_set_miso,
238     .get_sclk = spi_soft_get_sclk,
239     .get_mosi = spi_soft_get_mosi,
240     .get_miso = spi_soft_get_miso,
241     .dir_mosi = spi_soft_dir_mosi,
242     .dir_miso = spi_soft_dir_miso,
243     .udelay   = rt_hw_us_delay,
244 };
245 
246 /* Soft SPI initialization function */
rt_soft_spi_init(void)247 int rt_soft_spi_init(void)
248 {
249     rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct rt_soft_spi);
250     rt_err_t result;
251 
252     for (rt_size_t i = 0; i < obj_num; i++)
253     {
254         rt_memcpy(&spi_obj[i].ops, &soft_spi_ops, sizeof(struct rt_spi_bit_ops));
255         spi_obj[i].ops.data = (void *)&soft_spi_config[i];
256         spi_obj[i].spi.ops = &soft_spi_ops;
257         spi_obj[i].cfg = (void *)&soft_spi_config[i];
258         spi_soft_pin_init(&spi_obj[i]);
259         spi_obj[i].spi.ops->delay_us = soft_spi_config[i].timing_delay;
260         result = rt_spi_bit_add_bus(&spi_obj[i].spi, soft_spi_config[i].bus_name, &spi_obj[i].ops);
261         RT_ASSERT(result == RT_EOK);
262     }
263 
264     return RT_EOK;
265 }
266 INIT_PREV_EXPORT(rt_soft_spi_init);
267 
268 #endif /* RT_USING_SOFT_SPI */
269 
270