1 /*
2 * Copyright (c) 2006-2018, 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/spi.h>
12
rt_qspi_configure(struct rt_qspi_device * device,struct rt_qspi_configuration * cfg)13 rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg)
14 {
15 RT_ASSERT(device != RT_NULL);
16 RT_ASSERT(cfg != RT_NULL);
17
18 struct rt_qspi_device *qspi_device = (struct rt_qspi_device *)device;
19 rt_err_t result = RT_EOK;
20
21 /* copy configuration items */
22 qspi_device->config.parent.mode = cfg->parent.mode;
23 qspi_device->config.parent.max_hz = cfg->parent.max_hz;
24 qspi_device->config.parent.data_width = cfg->parent.data_width;
25 qspi_device->config.parent.reserved = cfg->parent.reserved;
26 qspi_device->config.medium_size = cfg->medium_size;
27 qspi_device->config.ddr_mode = cfg->ddr_mode;
28 qspi_device->config.qspi_dl_width = cfg->qspi_dl_width;
29
30 result = rt_spi_configure(&device->parent, &cfg->parent);
31
32 return result;
33 }
34
rt_qspi_bus_register(struct rt_spi_bus * bus,const char * name,const struct rt_spi_ops * ops)35 rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops)
36 {
37 rt_err_t result = RT_EOK;
38
39 result = rt_spi_bus_register(bus, name, ops);
40 if(result == RT_EOK)
41 {
42 /* set SPI bus to qspi modes */
43 bus->mode = RT_SPI_BUS_MODE_QSPI;
44 }
45
46 return result;
47 }
48
rt_qspi_transfer_message(struct rt_qspi_device * device,struct rt_qspi_message * message)49 rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message)
50 {
51 rt_err_t result;
52
53 RT_ASSERT(device != RT_NULL);
54 RT_ASSERT(message != RT_NULL);
55
56 result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
57 if (result != RT_EOK)
58 {
59 rt_set_errno(-RT_EBUSY);
60
61 return 0;
62 }
63
64 /* reset errno */
65 rt_set_errno(RT_EOK);
66
67 /* configure SPI bus */
68 if (device->parent.bus->owner != &device->parent)
69 {
70 /* not the same owner as current, re-configure SPI bus */
71 result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
72 if (result == RT_EOK)
73 {
74 /* set SPI bus owner */
75 device->parent.bus->owner = &device->parent;
76 }
77 else
78 {
79 /* configure SPI bus failed */
80 rt_set_errno(-RT_EIO);
81 goto __exit;
82 }
83 }
84
85 /* transmit each SPI message */
86
87 result = device->parent.bus->ops->xfer(&device->parent, &message->parent);
88 if (result == 0)
89 {
90 rt_set_errno(-RT_EIO);
91 }
92
93 __exit:
94 /* release bus lock */
95 rt_mutex_release(&(device->parent.bus->lock));
96
97 return result;
98 }
99
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)100 rt_err_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)
101 {
102 RT_ASSERT(send_buf);
103 RT_ASSERT(recv_buf);
104 RT_ASSERT(send_length != 0);
105
106 struct rt_qspi_message message;
107 unsigned char *ptr = (unsigned char *)send_buf;
108 rt_size_t count = 0;
109 rt_err_t result = 0;
110
111 message.instruction.content = ptr[0];
112 message.instruction.qspi_lines = 1;
113 count++;
114
115 /* get address */
116 if (send_length > 1)
117 {
118 if (device->config.medium_size > 0x1000000 && send_length >= 5)
119 {
120 /* medium size greater than 16Mb, address size is 4 Byte */
121 message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
122 message.address.size = 32;
123 count += 4;
124 }
125 else if (send_length >= 4)
126 {
127 /* address size is 3 Byte */
128 message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
129 message.address.size = 24;
130 count += 3;
131 }
132 else
133 {
134 return -RT_ERROR;
135 }
136 message.address.qspi_lines = 1;
137 }
138 else
139 {
140 /* no address stage */
141 message.address.content = 0 ;
142 message.address.qspi_lines = 0;
143 message.address.size = 0;
144 }
145
146 message.alternate_bytes.content = 0;
147 message.alternate_bytes.size = 0;
148 message.alternate_bytes.qspi_lines = 0;
149
150 /* set dummy cycles */
151 if (count != send_length)
152 {
153 message.dummy_cycles = (send_length - count) * 8;
154
155 }
156 else
157 {
158 message.dummy_cycles = 0;
159 }
160
161 /* set recv buf and recv size */
162 message.parent.recv_buf = recv_buf;
163 message.parent.send_buf = RT_NULL;
164 message.parent.length = recv_length;
165 message.parent.cs_take = 1;
166 message.parent.cs_release = 1;
167
168 message.qspi_data_lines = 1;
169
170 result = rt_qspi_transfer_message(device, &message);
171 if (result == 0)
172 {
173 result = -RT_EIO;
174 }
175 else
176 {
177 result = recv_length;
178 }
179
180 return result;
181 }
182
rt_qspi_send(struct rt_qspi_device * device,const void * send_buf,rt_size_t length)183 rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
184 {
185 RT_ASSERT(send_buf);
186 RT_ASSERT(length != 0);
187
188 struct rt_qspi_message message;
189 char *ptr = (char *)send_buf;
190 rt_size_t count = 0;
191 rt_err_t result = 0;
192
193 message.instruction.content = ptr[0];
194 message.instruction.qspi_lines = 1;
195 count++;
196
197 /* get address */
198 if (length > 1)
199 {
200 if (device->config.medium_size > 0x1000000 && length >= 5)
201 {
202 /* medium size greater than 16Mb, address size is 4 Byte */
203 message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
204 message.address.size = 32;
205 message.address.qspi_lines = 1;
206 count += 4;
207 }
208 else if (length >= 4)
209 {
210 /* address size is 3 Byte */
211 message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
212 message.address.size = 24;
213 message.address.qspi_lines = 1;
214 count += 3;
215 }
216 else
217 {
218 return -RT_ERROR;
219 }
220
221 }
222 else
223 {
224 /* no address stage */
225 message.address.content = 0 ;
226 message.address.qspi_lines = 0;
227 message.address.size = 0;
228 }
229
230 message.alternate_bytes.content = 0;
231 message.alternate_bytes.size = 0;
232 message.alternate_bytes.qspi_lines = 0;
233
234 message.dummy_cycles = 0;
235
236 /* determine if there is data to send */
237 if (length - count > 0)
238 {
239 message.qspi_data_lines = 1;
240 }
241 else
242 {
243 message.qspi_data_lines = 0;
244
245 }
246
247 /* set send buf and send size */
248 message.parent.send_buf = ptr + count;
249 message.parent.recv_buf = RT_NULL;
250 message.parent.length = length - count;
251 message.parent.cs_take = 1;
252 message.parent.cs_release = 1;
253
254 result = rt_qspi_transfer_message(device, &message);
255 if (result == 0)
256 {
257 result = -RT_EIO;
258 }
259 else
260 {
261 result = length;
262 }
263
264 return result;
265 }
266