1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020-06-27     AHTYDHD      the first version
9  */
10 
11 #include "drv_spi.h"
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include "inc/hw_memmap.h"
15 #include "driverlib/ssi.h"
16 #include "driverlib/gpio.h"
17 #include "driverlib/sysctl.h"
18 
19 #ifdef RT_USING_SPI
20 
21 #if defined(BSP_USING_SPI0) || defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3)
22 /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
23 #include "tm4c123_config.h"
24 #include "spi_config.h"
25 #include <string.h>
26 
27 //#define DRV_DEBUG
28 #define LOG_TAG              "drv.spi"
29 #include <drv_log.h>
30 
31 enum
32 {
33 #ifdef BSP_USING_SPI0
34     SPI0_INDEX,
35 #endif
36 #ifdef BSP_USING_SPI1
37     SPI1_INDEX,
38 #endif
39 #ifdef BSP_USING_SPI2
40     SPI2_INDEX,
41 #endif
42 #ifdef BSP_USING_SPI3
43     SPI3_INDEX,
44 #endif
45 };
46 
47 static struct tm4c123_spi_config spi_config[] =
48 {
49 #ifdef BSP_USING_SPI0
50     SPI0_BUS_CONFIG,
51 #endif
52 
53 #ifdef BSP_USING_SPI1
54     SPI1_BUS_CONFIG,
55 #endif
56 
57 #ifdef BSP_USING_SPI2
58     SPI2_BUS_CONFIG,
59 #endif
60 
61 #ifdef BSP_USING_SPI3
62     SPI3_BUS_CONFIG,
63 #endif
64 
65 };
66 
67 static struct tm4c123_spi spi_bus_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0};
68 
tm4c123_spi_configure(struct tm4c123_spi * spi_drv,struct rt_spi_configuration * cfg)69 static rt_err_t tm4c123_spi_configure(struct tm4c123_spi *spi_drv, struct rt_spi_configuration *cfg)
70 {
71     RT_ASSERT(spi_drv != RT_NULL);
72     RT_ASSERT(cfg != RT_NULL);
73 
74     uint32_t ui32Protocol, ui32Mode;
75     uint32_t ui32BitRate = (uint32_t)cfg->max_hz;
76     uint32_t ui32DataWidth = (uint32_t)cfg->data_width;
77     uint32_t pui32DataRx[1];
78     rt_uint8_t   ui8Protocol = 0;
79 
80     if (cfg->mode & RT_SPI_SLAVE)
81     {
82         ui32Mode = SSI_MODE_SLAVE;
83     }
84     else
85     {
86         ui32Mode = SSI_MODE_MASTER;
87     }
88 
89     if (cfg->mode & RT_SPI_CPHA)
90     {
91         ui8Protocol += 1;
92     }
93     else
94     {
95         ui8Protocol += 0;
96     }
97 
98     if (cfg->mode & RT_SPI_CPOL)
99     {
100         ui8Protocol += 2;
101     }
102     else
103     {
104         ui8Protocol += 0;
105     }
106 
107     switch (ui8Protocol)
108     {
109     case 0:
110         ui32Protocol =  SSI_FRF_MOTO_MODE_0;
111         break;
112     case 1:
113         ui32Protocol =  SSI_FRF_MOTO_MODE_1;
114         break;
115     case 2:
116         ui32Protocol =  SSI_FRF_MOTO_MODE_2;
117         break;
118     case 3:
119         ui32Protocol =  SSI_FRF_MOTO_MODE_3;
120         break;
121     default:
122         ui32Protocol =  SSI_FRF_MOTO_MODE_0;
123         break;
124     }
125 
126     SSIConfigSetExpClk(spi_drv->config->base, SysCtlClockGet(), ui32Protocol,
127                        ui32Mode, ui32BitRate, ui32DataWidth);
128 
129     LOG_D("ssiclk freq: %d, SPI limiting freq: %d", SysCtlClockGet(), cfg->max_hz);
130 
131     SSIEnable(spi_drv->config->base);
132 
133     while (SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
134     {
135     }
136 
137     LOG_D("%s init done", spi_drv->config->bus_name);
138 
139     return RT_EOK;
140 }
141 
spixfer(struct rt_spi_device * device,struct rt_spi_message * message)142 static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
143 {
144 
145     rt_size_t message_length;
146     rt_uint8_t *recv_buf;
147     const rt_uint8_t *send_buf;
148     uint32_t  ReadData = 0;
149     int    i = 0;
150 
151     RT_ASSERT(device != RT_NULL);
152     RT_ASSERT(device->bus != RT_NULL);
153     RT_ASSERT(device->bus->parent.user_data != RT_NULL);
154     RT_ASSERT(message != RT_NULL);
155 
156     struct tm4c123_spi *spi_drv =  rt_container_of(device->bus, struct tm4c123_spi, spi_bus);
157     struct tm4c123_hw_spi_cs *cs = device->parent.user_data;
158 
159     if (message->cs_take)
160     {
161         GPIOPinWrite(cs->portbase, cs->GPIO_Pin, 0);
162     }
163 
164     LOG_D("%s transfer prepare and start", spi_drv->config->bus_name);
165     LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
166           spi_drv->config->bus_name,
167           (uint32_t)message->send_buf,
168           (uint32_t)message->recv_buf, message->length);
169 
170     message_length = message->length;
171     recv_buf = message->recv_buf;
172     send_buf = message->send_buf;
173 
174     if (message->send_buf && message->recv_buf)
175     {
176         for (i = 0; i < message_length; i++)
177         {
178             SSIDataPut(spi_drv->config->base, (uint32_t)send_buf[i]);
179             while (SSIBusy(spi_drv->config->base))
180             {
181             }
182             SSIDataGet(spi_drv->config->base, &ReadData);
183             recv_buf[i] = (unsigned char)ReadData;
184         }
185 
186     }
187     else if (message->send_buf)
188     {
189         for (i = 0; i < message_length; i++)
190         {
191             SSIDataPut(spi_drv->config->base, (uint32_t)send_buf[i]);
192             while (SSIBusy(spi_drv->config->base))
193             {
194             }
195             SSIDataGet(spi_drv->config->base, &ReadData);
196         }
197     }
198     else
199     {
200         for (i = 0; i < message_length; i++)
201         {
202             SSIDataPut(spi_drv->config->base, (uint32_t)0xff);
203             while (SSIBusy(spi_drv->config->base))
204             {
205             }
206             SSIDataGet(spi_drv->config->base, &ReadData);
207             recv_buf[i] = (unsigned char)ReadData;
208         }
209     }
210 
211     LOG_D("%s transfer done", spi_drv->config->bus_name);
212 
213     if (message->cs_release)
214     {
215         GPIOPinWrite(cs->portbase, cs->GPIO_Pin, cs->GPIO_Pin);
216     }
217 
218     return message->length;
219 }
220 
221 
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)222 static rt_err_t spi_configure(struct rt_spi_device *device,
223                               struct rt_spi_configuration *configuration)
224 {
225     RT_ASSERT(device != RT_NULL);
226     RT_ASSERT(configuration != RT_NULL);
227 
228     struct tm4c123_spi *spi_drv =  rt_container_of(device->bus, struct tm4c123_spi, spi_bus);
229     spi_drv->cfg = configuration;
230 
231     return tm4c123_spi_configure(spi_drv, configuration);
232 }
233 
234 static const struct rt_spi_ops tm4c123_spi_ops =
235 {
236     .configure = spi_configure,
237     .xfer = spixfer,
238 };
239 
240 
rt_hw_spi_bus_init(void)241 static int rt_hw_spi_bus_init(void)
242 {
243     rt_err_t result;
244     for (int i = 0; i < sizeof(spi_config) / sizeof(spi_config[0]); i++)
245     {
246         spi_bus_obj[i].config = &spi_config[i];
247         spi_bus_obj[i].spi_bus.parent.user_data = &spi_config[i];
248 
249 
250         result = rt_spi_bus_register(&spi_bus_obj[i].spi_bus, spi_config[i].bus_name, &tm4c123_spi_ops);
251         RT_ASSERT(result == RT_EOK);
252 
253         LOG_D("%s bus init done", spi_config[i].bus_name);
254     }
255 
256     return result;
257 }
258 
259 /**
260   * Attach the spi device to SPI bus, this function must be used after initialization.
261   */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,uint32_t portindex,uint32_t cs_gpiobase,uint32_t cs_gpio_pin)262 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, uint32_t portindex, uint32_t cs_gpiobase, uint32_t cs_gpio_pin)
263 {
264     RT_ASSERT(bus_name != RT_NULL);
265     RT_ASSERT(device_name != RT_NULL);
266 
267     rt_err_t result;
268     struct rt_spi_device *spi_device;
269     struct tm4c123_hw_spi_cs *cs_pin;
270 
271     /* initialize the cs pin && select the slave*/
272     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA + portindex);
273     GPIOPinTypeGPIOOutput(cs_gpiobase, cs_gpio_pin);
274     GPIOPinWrite(cs_gpiobase, cs_gpio_pin, cs_gpio_pin);
275 
276     /* attach the device to spi bus*/
277     spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
278     RT_ASSERT(spi_device != RT_NULL);
279     cs_pin = (struct tm4c123_hw_spi_cs *)rt_malloc(sizeof(struct tm4c123_hw_spi_cs));
280     RT_ASSERT(cs_pin != RT_NULL);
281     cs_pin->portbase = cs_gpiobase;
282     cs_pin->GPIO_Pin = cs_gpio_pin;
283     result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
284 
285     if (result != RT_EOK)
286     {
287         LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
288     }
289 
290     RT_ASSERT(result == RT_EOK);
291 
292     LOG_D("%s attach to %s done", device_name, bus_name);
293 
294     return result;
295 }
296 
297 
rt_hw_spi_init(void)298 int rt_hw_spi_init(void)
299 {
300     spi_hw_config();
301 
302     return rt_hw_spi_bus_init();
303 }
304 INIT_BOARD_EXPORT(rt_hw_spi_init);
305 
306 #endif /* defined(BSP_USING_SPI0) || defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3)  */
307 #endif  /*RT_USING_SPI*/
308 
309 /************************** end of file ******************/
310