1 /*
2  * Copyright (c) 2019 Winner Microelectronics Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018-11-12     fanwenl      1st version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "board.h"
14 #include "wm_hostspi.h"
15 #include "wm_spi_hal.h"
16 #include "wm_io.h"
17 #include "wm_gpio_afsel.h"
18 #include "pin_map.h"
19 #include "drv_spi.h"
20 
21 #ifdef BSP_USING_SPI
22 
23 #define BSP_SPI_MAX_HZ (20* 1000 *1000)
24 
25 struct wm_sw_spi_cs
26 {
27     rt_int16_t pin;
28 };
29 
30 struct wm_spi
31 {
32     struct rt_spi_configuration *cfg;
33 };
34 
wm_hostspi_init(struct rt_spi_configuration * cfg)35 static rt_err_t wm_hostspi_init(struct rt_spi_configuration *cfg)
36 {
37 
38     spi_clear_fifo();
39     spi_set_endian(1);
40     if (cfg->data_width == 8)
41     {
42         tls_spi_trans_type(SPI_BYTE_TRANSFER);
43     }
44     if (cfg->data_width == 16)
45     {
46         tls_spi_trans_type(SPI_WORD_TRANSFER);
47     }
48     spi_set_mode(cfg->mode);
49     spi_set_chipselect_mode(SPI_CS_INACTIVE_MODE);
50     spi_force_cs_out(1);
51     if(cfg->max_hz > BSP_SPI_MAX_HZ)
52     {
53         cfg->max_hz = BSP_SPI_MAX_HZ;
54     }
55     spi_set_sclk(cfg->max_hz);
56 
57     spi_set_tx_trigger_level(0);
58     spi_set_rx_trigger_level(7);
59 
60     spi_set_rx_channel(1);
61     spi_set_tx_channel(1);
62 
63     return RT_EOK;
64 }
65 
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * cfg)66 static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
67 {
68     RT_ASSERT(cfg != RT_NULL);
69     RT_ASSERT(device != RT_NULL);
70 
71     /*将cfg参数放到device中*/
72     struct wm_spi *hspi = (struct wm_spi *)device->bus->parent.user_data;
73     hspi->cfg = cfg;
74 
75     wm_hostspi_init(cfg);
76 
77     return RT_EOK;
78 }
79 
spixfer(struct rt_spi_device * device,struct rt_spi_message * message)80 static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
81 {
82     RT_ASSERT(device != RT_NULL);
83     RT_ASSERT(device->bus != RT_NULL);
84     RT_ASSERT(device->bus->parent.user_data != RT_NULL);
85 
86     struct wm_sw_spi_cs *cs = device->parent.user_data;
87 
88     struct tls_spi_transfer tls_transfer;
89 
90     tls_transfer.tx_buf = message->send_buf;
91     tls_transfer.rx_buf = message->recv_buf;
92     tls_transfer.len = message->length;
93 
94     rt_int32_t length = 0;
95     rt_int32_t remain_length = message->length;
96     rt_int32_t int_status;
97 
98     tls_irq_disable(SPI0_INT);
99 
100     length = spi_fill_txfifo(&tls_transfer, remain_length);
101     spi_set_sclk_length(length * 8, 0);
102     if (message->cs_take && cs)
103     {
104         tls_gpio_write((enum tls_io_name)cs->pin, 0);
105     }
106     spi_sclk_start();
107 
108     while (remain_length > 0)
109     {
110         while (spi_i2s_get_busy_status() == 1)
111             ;
112         length = spi_get_rxfifo(&tls_transfer, remain_length);
113         remain_length -= length;
114 
115         if (remain_length == 0)
116         {
117             while (spi_i2s_get_busy_status() == 1)
118                 ;
119             if (message->cs_release && cs)
120             {
121                 tls_gpio_write((enum tls_io_name)cs->pin, 1);
122             }
123         }
124         while (spi_i2s_get_busy_status() == 1)
125             ;
126         length = spi_fill_txfifo(&tls_transfer, remain_length);
127         if (length)
128         {
129             spi_set_sclk_length(length * 8, 0);
130             spi_sclk_start();
131         }
132     }
133 
134     while (spi_i2s_get_busy_status() == 1)
135         ;
136     if (message->cs_release && cs)
137     {
138         tls_gpio_write((enum tls_io_name)cs->pin, 1);
139     }
140 
141     int_status = spi_get_int_status();
142     spi_clear_int_status(int_status);
143     tls_irq_enable(SPI0_INT);
144 
145     return message->length - remain_length;
146 }
147 
wm_spi_bus_attach_device(const char * bus_name,const char * device_name,rt_uint32_t pin)148 rt_err_t wm_spi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint32_t pin)
149 {
150     rt_err_t ret;
151     rt_int16_t gpio_pin;
152     struct rt_spi_device *spi_device;
153     struct wm_sw_spi_cs *cs_pin;
154 
155     gpio_pin = wm_get_pin(pin);
156     if (gpio_pin == WM_PIN_DEFAULT)
157     {
158         return -RT_ERROR;
159     }
160     spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
161     RT_ASSERT(spi_device != RT_NULL);
162 
163     cs_pin = (struct wm_sw_spi_cs *)rt_malloc(sizeof(struct wm_sw_spi_cs));
164     RT_ASSERT(cs_pin != RT_NULL);
165 
166     cs_pin->pin = gpio_pin;
167     tls_gpio_cfg((enum tls_io_name)gpio_pin, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
168     tls_gpio_write((enum tls_io_name)gpio_pin, 1);
169 
170     ret = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
171 
172     return ret;
173 }
174 
175 static struct rt_spi_ops wm_spi_ops =
176 {
177     .configure = spi_configure,
178     .xfer = spixfer
179 };
180 
181 struct wm_spi spi;
182 struct rt_spi_bus wm_spi_bus;
183 
wm_hw_spi_bus_init(void)184 int wm_hw_spi_bus_init(void)
185 {
186     rt_int16_t gpio_pin;
187 
188     gpio_pin = wm_get_pin(WM_SPI_CK_PIN);
189     if (gpio_pin >= 0)
190     {
191         wm_spi_ck_config((enum tls_io_name)gpio_pin);
192     }
193     gpio_pin = wm_get_pin(WM_SPI_DI_PIN);
194     if (gpio_pin >= 0)
195     {
196         wm_spi_di_config((enum tls_io_name)gpio_pin);
197     }
198     gpio_pin = wm_get_pin(WM_SPI_DO_PIN);
199     if (gpio_pin >= 0)
200     {
201         wm_spi_do_config((enum tls_io_name)gpio_pin);
202     }
203 
204     wm_spi_bus.parent.user_data = &spi;
205 #ifdef WM_SPI_BUS_NAME
206     rt_spi_bus_register(&wm_spi_bus, WM_SPI_BUS_NAME, &wm_spi_ops);
207 #else
208     rt_spi_bus_register(&wm_spi_bus, "spi0", &wm_spi_ops);
209 #endif
210 
211     return RT_EOK;
212 }
213 INIT_PREV_EXPORT(wm_hw_spi_bus_init);
214 
215 #endif /* BSP_USING_SPI */
216