1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-11-16 zylx first version.
9 */
10
11 #include "drivers/dev_spi.h"
12
13 extern rt_err_t spi_bus_register(struct rt_spi_bus *bus,
14 const char *name,
15 const struct rt_spi_ops *ops);
16
rt_qspi_configure(struct rt_qspi_device * device,struct rt_qspi_configuration * cfg)17 rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg)
18 {
19 RT_ASSERT(device != RT_NULL);
20 RT_ASSERT(cfg != RT_NULL);
21
22 /* reset the CS pin */
23 if (device->parent.cs_pin != PIN_NONE)
24 {
25 rt_err_t result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
26 if (result == RT_EOK)
27 {
28 if (cfg->parent.mode & RT_SPI_CS_HIGH)
29 {
30 rt_pin_write(device->parent.cs_pin, PIN_LOW);
31 }
32 else
33 {
34 rt_pin_write(device->parent.cs_pin, PIN_HIGH);
35 }
36 rt_mutex_release(&(device->parent.bus->lock));
37 }
38 else
39 {
40 return result;
41 }
42 }
43
44 /* If the configurations are the same, we don't need to set again. */
45 if (device->config.medium_size == cfg->medium_size &&
46 device->config.ddr_mode == cfg->ddr_mode &&
47 device->config.qspi_dl_width == cfg->qspi_dl_width &&
48 device->config.parent.data_width == cfg->parent.data_width &&
49 device->config.parent.mode == (cfg->parent.mode & RT_SPI_MODE_MASK) &&
50 device->config.parent.max_hz == cfg->parent.max_hz)
51 {
52 return RT_EOK;
53 }
54
55 /* copy configuration items */
56 device->config.parent.mode = cfg->parent.mode;
57 device->config.parent.max_hz = cfg->parent.max_hz;
58 device->config.parent.data_width = cfg->parent.data_width;
59 #ifdef RT_USING_DM
60 device->config.parent.data_width_tx = cfg->parent.data_width_tx;
61 device->config.parent.data_width_rx = cfg->parent.data_width_rx;
62 #else
63 device->config.parent.reserved = cfg->parent.reserved;
64 #endif
65 device->config.medium_size = cfg->medium_size;
66 device->config.ddr_mode = cfg->ddr_mode;
67 device->config.qspi_dl_width = cfg->qspi_dl_width;
68
69 return rt_spi_bus_configure(&device->parent);
70 }
71
rt_qspi_bus_register(struct rt_spi_bus * bus,const char * name,const struct rt_spi_ops * ops)72 rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops)
73 {
74 /* set SPI bus to qspi modes */
75 bus->mode = RT_SPI_BUS_MODE_QSPI;
76
77 return spi_bus_register(bus, name, ops);
78 }
79
rt_qspi_transfer_message(struct rt_qspi_device * device,struct rt_qspi_message * message)80 rt_ssize_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message)
81 {
82 rt_ssize_t result;
83
84 RT_ASSERT(device != RT_NULL);
85 RT_ASSERT(message != RT_NULL);
86
87 result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
88 if (result != RT_EOK)
89 {
90 rt_set_errno(-RT_EBUSY);
91
92 return 0;
93 }
94
95 /* reset errno */
96 rt_set_errno(RT_EOK);
97
98 /* configure SPI bus */
99 if (device->parent.bus->owner != &device->parent)
100 {
101 /* not the same owner as current, re-configure SPI bus */
102 result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
103 if (result == RT_EOK)
104 {
105 /* set SPI bus owner */
106 device->parent.bus->owner = &device->parent;
107 }
108 else
109 {
110 /* configure SPI bus failed */
111 rt_set_errno(-RT_EIO);
112 goto __exit;
113 }
114 }
115
116 /* transmit each SPI message */
117
118 result = device->parent.bus->ops->xfer(&device->parent, &message->parent);
119 if (result == 0)
120 {
121 rt_set_errno(-RT_EIO);
122 }
123
124 __exit:
125 /* release bus lock */
126 rt_mutex_release(&(device->parent.bus->lock));
127
128 return result;
129 }
130
rt_qspi_send_then_recv(struct rt_qspi_device * device,const void * send_buf,rt_size_t send_length,void * recv_buf,rt_size_t recv_length)131 rt_ssize_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length)
132 {
133 RT_ASSERT(send_buf);
134 RT_ASSERT(recv_buf);
135 RT_ASSERT(send_length != 0);
136
137 struct rt_qspi_message message;
138 unsigned char *ptr = (unsigned char *)send_buf;
139 rt_size_t count = 0;
140 rt_ssize_t result = 0;
141
142 message.instruction.content = ptr[0];
143 message.instruction.qspi_lines = 1;
144 count++;
145
146 /* get address */
147 if (send_length > 1)
148 {
149 if (device->config.medium_size > 0x1000000 && send_length >= 5)
150 {
151 /* medium size greater than 16Mb, address size is 4 Byte */
152 message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
153 message.address.size = 32;
154 count += 4;
155 }
156 else if (send_length >= 4)
157 {
158 /* address size is 3 Byte */
159 message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
160 message.address.size = 24;
161 count += 3;
162 }
163 else
164 {
165 return -RT_ERROR;
166 }
167 message.address.qspi_lines = 1;
168 }
169 else
170 {
171 /* no address stage */
172 message.address.content = 0 ;
173 message.address.qspi_lines = 0;
174 message.address.size = 0;
175 }
176
177 message.alternate_bytes.content = 0;
178 message.alternate_bytes.size = 0;
179 message.alternate_bytes.qspi_lines = 0;
180
181 /* set dummy cycles */
182 if (count != send_length)
183 {
184 message.dummy_cycles = (send_length - count) * 8;
185
186 }
187 else
188 {
189 message.dummy_cycles = 0;
190 }
191
192 /* set recv buf and recv size */
193 message.parent.recv_buf = recv_buf;
194 message.parent.send_buf = RT_NULL;
195 message.parent.length = recv_length;
196 message.parent.cs_take = 1;
197 message.parent.cs_release = 1;
198
199 message.qspi_data_lines = 1;
200 /* set next */
201 /* Ensure correct QSPI message chaining by setting next pointer to NULL, preventing unintended data transmission issues.*/
202 message.parent.next = RT_NULL;
203
204 result = rt_qspi_transfer_message(device, &message);
205 if (result == 0)
206 {
207 result = -RT_EIO;
208 }
209 else if (result > 0)
210 {
211 result = recv_length;
212 }
213
214 return result;
215 }
216
rt_qspi_send(struct rt_qspi_device * device,const void * send_buf,rt_size_t length)217 rt_ssize_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
218 {
219 RT_ASSERT(send_buf);
220 RT_ASSERT(length != 0);
221
222 struct rt_qspi_message message;
223 unsigned char *ptr = (unsigned char *)send_buf;
224 rt_size_t count = 0;
225 rt_ssize_t result = 0;
226
227 message.instruction.content = ptr[0];
228 message.instruction.qspi_lines = 1;
229 count++;
230
231 /* get address */
232 if (length > 1)
233 {
234 if (device->config.medium_size > 0x1000000 && length >= 5)
235 {
236 /* medium size greater than 16Mb, address size is 4 Byte */
237 message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
238 message.address.size = 32;
239 message.address.qspi_lines = 1;
240 count += 4;
241 }
242 else if (length >= 4)
243 {
244 /* address size is 3 Byte */
245 message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
246 message.address.size = 24;
247 message.address.qspi_lines = 1;
248 count += 3;
249 }
250 else
251 {
252 return -RT_ERROR;
253 }
254
255 }
256 else
257 {
258 /* no address stage */
259 message.address.content = 0 ;
260 message.address.qspi_lines = 0;
261 message.address.size = 0;
262 }
263
264 message.alternate_bytes.content = 0;
265 message.alternate_bytes.size = 0;
266 message.alternate_bytes.qspi_lines = 0;
267
268 message.dummy_cycles = 0;
269
270 /* determine if there is data to send */
271 if (length - count > 0)
272 {
273 message.qspi_data_lines = 1;
274 }
275 else
276 {
277 message.qspi_data_lines = 0;
278 }
279
280 /* set send buf and send size */
281 message.parent.send_buf = ptr + count;
282 message.parent.recv_buf = RT_NULL;
283 message.parent.length = length - count;
284 message.parent.cs_take = 1;
285 message.parent.cs_release = 1;
286 /* set next */
287 /* Ensure correct QSPI message chaining by setting next pointer to NULL, preventing unintended data transmission issues.*/
288 message.parent.next = RT_NULL;
289
290 result = rt_qspi_transfer_message(device, &message);
291 if (result == 0)
292 {
293 result = -RT_EIO;
294 }
295 else if (result > 0)
296 {
297 result = length;
298 }
299
300 return result;
301 }
302