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 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 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 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 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 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