1 /*
2  * Copyright (c) 2006-2020, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020-05-28     hqfang       first implementation.
9  */
10 
11 #include "drv_spi.h"
12 
13 #ifdef RT_USING_SPI
14 
15 #if !defined(BSP_USING_SPI0) && !defined(BSP_USING_SPI1) && !defined(BSP_USING_SPI2)
16     #error "Please define at least one BSP_USING_SPIx"
17     /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable SPI */
18 #endif
19 
20 static struct gd32_spi_config spi_config[] =
21 {
22 #ifdef BSP_USING_SPI0
23     {
24         "spi0",
25         SPI0,
26     },
27 #endif
28 #ifdef BSP_USING_SPI1
29     {
30         "spi1",
31         SPI1,
32     },
33 #endif
34 #ifdef BSP_USING_SPI2
35     {
36         "spi2",
37         SPI2,
38     },
39 #endif
40 };
41 
42 static struct gd32_spi spi_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0};
43 
gd32_spi_init(rt_uint32_t spi_periph,struct rt_spi_configuration * cfg)44 static rt_err_t gd32_spi_init(rt_uint32_t spi_periph, struct rt_spi_configuration *cfg)
45 {
46     spi_parameter_struct spicfg;
47     uint32_t apbfreq;
48     uint32_t scale;
49 
50     RT_ASSERT(cfg != RT_NULL);
51 
52     spi_struct_para_init(&spicfg);
53 
54     if (cfg->data_width != 8 && cfg->data_width != 16)
55     {
56         return (-RT_EINVAL);
57     }
58 
59     switch (spi_periph)
60     {
61     case SPI0:
62         apbfreq = rcu_clock_freq_get(CK_APB2);
63         break;
64     default:
65         apbfreq = rcu_clock_freq_get(CK_APB1);
66         break;
67     }
68 
69     scale = apbfreq / cfg->max_hz;
70     if (scale <= 2)
71     {
72         spicfg.prescale = SPI_PSC_2;
73     }
74     else if (scale <= 4)
75     {
76         spicfg.prescale = SPI_PSC_4;
77     }
78     else if (scale <= 8)
79     {
80         spicfg.prescale = SPI_PSC_8;
81     }
82     else if (scale <= 16)
83     {
84         spicfg.prescale = SPI_PSC_16;
85     }
86     else if (scale <= 32)
87     {
88         spicfg.prescale = SPI_PSC_32;
89     }
90     else if (scale <= 64)
91     {
92         spicfg.prescale = SPI_PSC_64;
93     }
94     else if (scale <= 128)
95     {
96         spicfg.prescale = SPI_PSC_128;
97     }
98     else if (scale <= 256)
99     {
100         spicfg.prescale = SPI_PSC_256;
101     }
102     else
103     {
104         spicfg.prescale = SPI_PSC_256;
105     }
106 
107     if (cfg->data_width == 8)
108     {
109         spicfg.frame_size = SPI_FRAMESIZE_8BIT;
110     }
111     else
112     {
113         spicfg.frame_size = SPI_FRAMESIZE_16BIT;
114     }
115 
116     if (cfg->mode & RT_SPI_MSB)
117     {
118         spicfg.endian = SPI_ENDIAN_MSB;
119     }
120     else
121     {
122         spicfg.endian = SPI_ENDIAN_LSB;
123     }
124 
125     spicfg.clock_polarity_phase = 0;
126     if (cfg->mode & RT_SPI_CPHA)
127     {
128         spicfg.clock_polarity_phase |= SPI_CTL0_CKPH;
129     }
130     if (cfg->mode & RT_SPI_CPOL)
131     {
132         spicfg.clock_polarity_phase |= SPI_CTL0_CKPL;
133     }
134 
135     if (cfg->mode & RT_SPI_SLAVE)
136     {
137         spicfg.device_mode = SPI_SLAVE;
138     }
139     else
140     {
141         spicfg.device_mode = SPI_MASTER;
142     }
143     spicfg.nss = SPI_NSS_SOFT;
144     spicfg.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
145 
146     spi_init(spi_periph, &spicfg);
147     /* set crc polynomial */
148     spi_crc_polynomial_set(spi_periph, 7);
149 
150     return RT_EOK;
151 }
152 
gd32_spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * cfg)153 static rt_err_t gd32_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
154 {
155     rt_err_t ret = RT_EOK;
156     RT_ASSERT(device != RT_NULL);
157 
158     struct gd32_spi *spi_obj = (struct gd32_spi *)(device->bus->parent.user_data);
159     struct gd32_spi_config *spi_cfg = (struct gd32_spi_config *)(spi_obj->config);
160 
161     ret = gd32_spi_init(spi_cfg->spi_periph, cfg);
162     /* enable SPI */
163     spi_enable(spi_cfg->spi_periph);
164 
165     return ret;
166 }
167 
168 /**
169   * Attach the spi device to SPI bus, this function must be used after initialization.
170   */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,rt_uint32_t pin)171 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_uint32_t pin)
172 {
173     rt_err_t ret = RT_EOK;
174 
175     struct rt_spi_device *spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
176     RT_ASSERT(spi_device != RT_NULL);
177 
178     struct gd32_spi_cs *cs_pin = (struct gd32_spi_cs *)rt_malloc(sizeof(struct gd32_spi_cs));
179     RT_ASSERT(cs_pin != RT_NULL);
180 
181     cs_pin->pin = pin;
182     rt_pin_mode(pin, PIN_MODE_OUTPUT);
183     rt_pin_write(pin, PIN_HIGH);
184 
185     ret = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
186 
187     return ret;
188 }
189 
gd32_spi_transmit(rt_uint32_t spi_periph,const void * send_buf,void * recv_buf,rt_size_t length)190 rt_size_t gd32_spi_transmit(rt_uint32_t spi_periph, const void *send_buf, void *recv_buf, rt_size_t length)
191 {
192     uint8_t *send_buf_8b = (uint8_t *)send_buf;
193     uint8_t *recv_buf_8b = (uint8_t *)recv_buf;
194     uint8_t sndbyte = 0xFF, rcvbyte;
195     rt_size_t idx = 0;
196 
197     while (idx < length)
198     {
199         while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));
200         if (send_buf_8b)
201         {
202             sndbyte = send_buf_8b[idx];
203         }
204         spi_i2s_data_transmit(spi_periph, sndbyte);
205         while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));
206         rcvbyte = spi_i2s_data_receive(spi_periph);
207         if (recv_buf_8b)
208         {
209             recv_buf_8b[idx] = rcvbyte;
210         }
211         idx ++;
212     }
213 
214     return length;
215 }
216 
gd32_spi_xfer(struct rt_spi_device * device,struct rt_spi_message * message)217 static rt_uint32_t gd32_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
218 {
219     rt_uint32_t total_length = 0;
220     rt_err_t ret = RT_EOK;
221 
222     RT_ASSERT(device != RT_NULL);
223 
224     struct gd32_spi *spi_obj = (struct gd32_spi *)(device->bus->parent.user_data);
225     struct gd32_spi_config *spi_cfg = (struct gd32_spi_config *)(spi_obj->config);
226     RT_ASSERT(spi_cfg != RT_NULL);
227     struct gd32_spi_cs *cs = (struct gd32_spi_cs *)(device->parent.user_data);
228 
229     if (message && message->cs_take)
230     {
231         rt_pin_write(cs->pin, PIN_LOW);
232     }
233     if (message && message->length)
234     {
235 
236         total_length += gd32_spi_transmit(spi_cfg->spi_periph, message->send_buf, \
237                                           message->recv_buf, message->length);
238     }
239     if (message && message->cs_release)
240     {
241         rt_pin_write(cs->pin, PIN_HIGH);
242     }
243     return total_length;
244 }
245 
246 static const struct rt_spi_ops spi_ops =
247 {
248     gd32_spi_configure,
249     gd32_spi_xfer
250 };
251 
rt_hw_spi_init(void)252 int rt_hw_spi_init(void)
253 {
254     rt_size_t obj_num;
255     int index;
256     rt_err_t result = 0;
257 
258 #ifdef BSP_USING_SPI0
259     rcu_periph_clock_enable(RCU_SPI0);
260 #endif
261 #ifdef BSP_USING_SPI1
262     rcu_periph_clock_enable(RCU_SPI1);
263 #endif
264 #ifdef BSP_USING_SPI2
265     rcu_periph_clock_enable(RCU_SPI2);
266 #endif
267 
268     obj_num = sizeof(spi_obj) / sizeof(struct gd32_spi);
269     for (index = 0; index < obj_num; index++)
270     {
271         /* init spi object */
272         spi_obj[index].config = &spi_config[index];
273         spi_obj[index].bus.parent.user_data = &spi_obj[index];
274 
275         /* register spi device */
276         result = rt_spi_bus_register(&spi_obj[index].bus,
277                                      spi_obj[index].config->name,
278                                      &spi_ops);
279         RT_ASSERT(result == RT_EOK);
280     }
281 
282     return 0;
283 }
284 INIT_DEVICE_EXPORT(rt_hw_spi_init);
285 
286 #endif
287 /* end of spi driver */
288