1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-06-02     Chushicheng  the first version
9  */
10 #include "drv_soft_spi.h"
11 #include "board.h"
12 
13 #if defined BSP_USING_SOFT_SPI
14 #define LOG_TAG             "drv.soft_spi"
15 #include <rtdbg.h>
16 
17 static struct pico_soft_spi_config soft_spi_config[] =
18 {
19 #ifdef BSP_USING_SOFT_SPI0
20     SOFT_SPI0_BUS_CONFIG,
21 #endif
22 #ifdef BSP_USING_SOFT_SPI1
23     SOFT_SPI1_BUS_CONFIG,
24 #endif
25 };
26 
27 static struct pico_soft_spi spi_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])];
28 
29 /**
30   * Attach the spi device to soft SPI bus, this function must be used after initialization.
31   */
rt_hw_softspi_device_attach(const char * bus_name,const char * device_name,rt_base_t cs_pin)32 rt_err_t rt_hw_softspi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
33 {
34     rt_err_t result;
35     struct rt_spi_device *spi_device;
36 
37     /* attach the device to soft spi bus*/
38     spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
39     RT_ASSERT(spi_device != RT_NULL);
40 
41     result = rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, cs_pin, RT_NULL);
42     return result;
43 }
44 
pico_spi_gpio_init(struct pico_soft_spi * spi)45 static void pico_spi_gpio_init(struct pico_soft_spi *spi)
46 {
47     struct pico_soft_spi_config *cfg = (struct pico_soft_spi_config *)spi->cfg;
48     rt_pin_mode(cfg->sck, PIN_MODE_OUTPUT);
49     rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
50     rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
51 
52     rt_pin_write(cfg->miso, PIN_HIGH);
53     rt_pin_write(cfg->sck, PIN_HIGH);
54     rt_pin_write(cfg->mosi, PIN_HIGH);
55 }
56 
pico_tog_sclk(void * data)57 static void pico_tog_sclk(void *data)
58 {
59     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
60     if(rt_pin_read(cfg->sck) == PIN_HIGH)
61     {
62         rt_pin_write(cfg->sck, PIN_LOW);
63     }
64     else
65     {
66         rt_pin_write(cfg->sck, PIN_HIGH);
67     }
68 }
69 
pico_set_sclk(void * data,rt_int32_t state)70 static void pico_set_sclk(void *data, rt_int32_t state)
71 {
72     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
73     if (state)
74     {
75         rt_pin_write(cfg->sck, PIN_HIGH);
76     }
77     else
78     {
79         rt_pin_write(cfg->sck, PIN_LOW);
80     }
81 }
82 
pico_set_mosi(void * data,rt_int32_t state)83 static void pico_set_mosi(void *data, rt_int32_t state)
84 {
85     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
86     if (state)
87     {
88         rt_pin_write(cfg->mosi, PIN_HIGH);
89     }
90     else
91     {
92         rt_pin_write(cfg->mosi, PIN_LOW);
93     }
94 }
95 
pico_set_miso(void * data,rt_int32_t state)96 static void pico_set_miso(void *data, rt_int32_t state)
97 {
98     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
99     if (state)
100     {
101         rt_pin_write(cfg->miso, PIN_HIGH);
102     }
103     else
104     {
105         rt_pin_write(cfg->miso, PIN_LOW);
106     }
107 }
108 
pico_get_sclk(void * data)109 static rt_int32_t pico_get_sclk(void *data)
110 {
111     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
112     return rt_pin_read(cfg->sck);
113 }
114 
pico_get_mosi(void * data)115 static rt_int32_t pico_get_mosi(void *data)
116 {
117     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
118     return rt_pin_read(cfg->mosi);
119 }
120 
pico_get_miso(void * data)121 static rt_int32_t pico_get_miso(void *data)
122 {
123     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
124     return rt_pin_read(cfg->miso);
125 }
126 
pico_dir_mosi(void * data,rt_int32_t state)127 static void pico_dir_mosi(void *data, rt_int32_t state)
128 {
129     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
130     if (state)
131     {
132         rt_pin_mode(cfg->mosi, PIN_MODE_INPUT);
133     }
134     else
135     {
136         rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
137     }
138 }
139 
pico_dir_miso(void * data,rt_int32_t state)140 static void pico_dir_miso(void *data, rt_int32_t state)
141 {
142     struct pico_soft_spi_config* cfg = (struct pico_soft_spi_config*)data;
143     if (state)
144     {
145         rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
146     }
147     else
148     {
149         rt_pin_mode(cfg->miso, PIN_MODE_OUTPUT);
150     }
151 }
152 
pico_udelay(rt_uint32_t us)153 static void pico_udelay(rt_uint32_t us)
154 {
155     busy_wait_us_32(us);
156 }
157 
pico_pin_init(void)158 static void pico_pin_init(void)
159 {
160     rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct pico_soft_spi);
161 
162     for(rt_size_t i = 0; i < obj_num; i++)
163     {
164         pico_spi_gpio_init(&spi_obj[i]);
165     }
166 }
167 
168 static struct rt_spi_bit_ops pico_soft_spi_ops =
169 {
170     .data = RT_NULL,
171     .pin_init = pico_pin_init,
172     .tog_sclk = pico_tog_sclk,
173     .set_sclk = pico_set_sclk,
174     .set_mosi = pico_set_mosi,
175     .set_miso = pico_set_miso,
176     .get_sclk = pico_get_sclk,
177     .get_mosi = pico_get_mosi,
178     .get_miso = pico_get_miso,
179     .dir_mosi = pico_dir_mosi,
180     .dir_miso = pico_dir_miso,
181     .udelay = pico_udelay,
182     .delay_us = 1,
183 };
184 
185 /* Soft SPI initialization function */
rt_hw_softspi_init(void)186 int rt_hw_softspi_init(void)
187 {
188     rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct pico_soft_spi);
189     rt_err_t result;
190 
191     for (rt_size_t i = 0; i < obj_num; i++)
192     {
193         pico_soft_spi_ops.data = (void *)&soft_spi_config[i];
194         spi_obj[i].spi.ops = &pico_soft_spi_ops;
195         spi_obj[i].cfg = (void *)&soft_spi_config[i];
196 
197         result = rt_spi_bit_add_bus(&spi_obj[i].spi, soft_spi_config[i].bus_name, &pico_soft_spi_ops);
198         RT_ASSERT(result == RT_EOK);
199     }
200 
201     return RT_EOK;
202 }
203 INIT_DEVICE_EXPORT(rt_hw_softspi_init);
204 
205 #endif /* BSP_USING_SOFT_SPI */
206