1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2017-06-05 tanek first implementation.
9 * 2018-04-19 misonyo Porting for v85xxf30x
10 * 2019-03-31 xuzhuoyi Porting for v85xxe230
11 * 2021-09-21 zhuxw Porting for v85xx
12 */
13
14 #include "drv_spi.h"
15 #include "board.h"
16 #include <rtthread.h>
17
18 #if defined(RT_USING_SPI) && defined(RT_USING_PIN)
19 #include <rtdevice.h>
20
21 #if !defined(RT_USING_SPI1) && !defined(RT_USING_SPI2)
22 #error "Please define at least one SPIx"
23 #endif
24
25 /* private rt-thread spi ops function */
26 static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration);
27 static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message);
28
29 static struct rt_spi_ops v85xx_spi_ops =
30 {
31 configure,
32 xfer
33 };
34
configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)35 static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration)
36 {
37 SPI_InitType spi_init_struct;
38
39 rt_uint32_t spi_periph = (rt_uint32_t)device->bus->parent.user_data;
40
41 RT_ASSERT(device != RT_NULL);
42 RT_ASSERT(configuration != RT_NULL);
43
44 if(configuration->data_width > 8)
45 {
46 return -RT_EIO;
47 }
48
49 {
50 rt_uint32_t spi_apb_clock;
51 rt_uint32_t max_hz;
52
53 max_hz = configuration->max_hz;
54
55 spi_apb_clock = CLK_GetPCLKFreq();
56
57 if(max_hz >= spi_apb_clock/2)
58 {
59 spi_init_struct.ClockDivision = SPI_CLKDIV_2;
60 }
61 else if (max_hz >= spi_apb_clock/4)
62 {
63 spi_init_struct.ClockDivision = SPI_CLKDIV_4;
64 }
65 else if (max_hz >= spi_apb_clock/8)
66 {
67 spi_init_struct.ClockDivision = SPI_CLKDIV_8;
68 }
69 else if (max_hz >= spi_apb_clock/16)
70 {
71 spi_init_struct.ClockDivision = SPI_CLKDIV_16;
72 }
73 else if (max_hz >= spi_apb_clock/32)
74 {
75 spi_init_struct.ClockDivision = SPI_CLKDIV_32;
76 }
77 else if (max_hz >= spi_apb_clock/64)
78 {
79 spi_init_struct.ClockDivision = SPI_CLKDIV_64;
80 }
81 else
82 {
83 /* min prescaler 128 */
84 spi_init_struct.ClockDivision = SPI_CLKDIV_128;
85 }
86 } /* baudrate */
87
88 switch(configuration->mode & RT_SPI_MODE_3)
89 {
90 case RT_SPI_MODE_0:
91 spi_init_struct.SPH = SPI_SPH_0;
92 spi_init_struct.SPO = SPI_SPO_0;
93 break;
94 case RT_SPI_MODE_1:
95 spi_init_struct.SPH = SPI_SPH_1;
96 spi_init_struct.SPO = SPI_SPO_0;
97 break;
98 case RT_SPI_MODE_2:
99 spi_init_struct.SPH = SPI_SPH_0;
100 spi_init_struct.SPO = SPI_SPO_1;
101 break;
102 case RT_SPI_MODE_3:
103 spi_init_struct.SPH = SPI_SPH_1;
104 spi_init_struct.SPO = SPI_SPO_1;
105 break;
106 }
107
108 if(!(configuration->mode & RT_SPI_MSB))
109 {
110 return -RT_EIO;
111 }
112
113 spi_init_struct.Mode = SPI_MODE_MASTER;
114 spi_init_struct.CSNSoft = SPI_CSNSOFT_ENABLE;
115
116 SPI_Init((SPI_TypeDef*)spi_periph, &spi_init_struct);
117
118 SPI_Cmd((SPI_TypeDef*)spi_periph, ENABLE);
119
120 return RT_EOK;
121 };
122
xfer(struct rt_spi_device * device,struct rt_spi_message * message)123 static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message)
124 {
125 rt_base_t v85xx_cs_pin = (rt_base_t)device->parent.user_data;
126 rt_uint32_t spi_periph = (rt_uint32_t)device->bus->parent.user_data;
127 struct rt_spi_configuration * config = &device->config;
128
129 RT_ASSERT(device != RT_NULL);
130 RT_ASSERT(message != RT_NULL);
131
132 /* take CS */
133 if(message->cs_take)
134 {
135 rt_pin_write(v85xx_cs_pin, PIN_LOW);
136 DEBUG_PRINTF("spi take cs\n");
137 }
138
139 {
140 if(config->data_width <= 8)
141 {
142 const rt_uint8_t * send_ptr = message->send_buf;
143 rt_uint8_t * recv_ptr = message->recv_buf;
144 rt_uint32_t size = message->length;
145
146 DEBUG_PRINTF("spi poll transfer start: %d\n", size);
147
148 while(size--)
149 {
150 rt_uint8_t data = 0xFF;
151
152 if(send_ptr != RT_NULL)
153 {
154 data = *send_ptr++;
155 }
156
157 //Wait until the transmit buffer is empty
158 while(RESET == SPI_GetStatus((SPI_TypeDef*)spi_periph, SPI_STS_TXEMPTY));
159 // Send the byte
160 SPI_SendData((SPI_TypeDef*)spi_periph, data);
161
162 //Wait until a data is received
163 while(RESET == SPI_GetStatus((SPI_TypeDef*)spi_periph, SPI_STS_RNE));
164 // Get the received data
165 data = SPI_ReceiveData((SPI_TypeDef*)spi_periph);
166
167 if(recv_ptr != RT_NULL)
168 {
169 *recv_ptr++ = data;
170 }
171 }
172 DEBUG_PRINTF("spi poll transfer finsh\n");
173 }
174 }
175
176 /* release CS */
177 if(message->cs_release)
178 {
179 rt_pin_write(v85xx_cs_pin, PIN_HIGH);
180 DEBUG_PRINTF("spi release cs\n");
181 }
182
183 return message->length;
184 };
185
v85xx_hw_spi_init(void)186 int v85xx_hw_spi_init(void)
187 {
188 int result = 0;
189 #ifdef RT_USING_SPI1
190 static struct rt_spi_bus spi_bus0;
191 spi_bus0.parent.user_data = (void *)SPI1;
192
193 result = rt_spi_bus_register(&spi_bus0, "spi1", &v85xx_spi_ops);
194
195 #endif
196
197 #ifdef RT_USING_SPI2
198 static struct rt_spi_bus spi_bus1;
199 spi_bus1.parent.user_data = (void *)SPI2;
200
201 result = rt_spi_bus_register(&spi_bus1, "spi2", &v85xx_spi_ops);
202
203 #endif
204 return result;
205 }
206 INIT_BOARD_EXPORT(v85xx_hw_spi_init);
207 #endif
208