1 /*
2 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0.
5 *
6 * @Date: 2021-04-25 14:01:29
7 * @LastEditTime: 2021-05-26 15:42:52
8 * @Description: This files is for
9 *
10 * @Modify History:
11 * Ver Who Date Changes
12 * ----- ------ -------- --------------------------------------
13 */
14
15 #include "drv_spi.h"
16 #include <rtthread.h>
17 #include <rtdevice.h>
18 #include <string.h>
19 #include "ft_spi.h"
20 #include "ft_mux.h"
21 #include "ft_trace.h"
22 #include "ft_generic_timer.h"
23
24 #ifdef BSP_USE_SPI
25
26 #define DRV_DEBUG
27 #define LOG_TAG "drv.spi"
28 #include <drv_log.h>
29
30 typedef void (*spi_cs_handler_t)(const rt_bool_t select);
31 typedef struct
32 {
33 FSpi_Ctrl_t spi_ctrl;
34 struct rt_spi_bus spi_bus;
35 rt_uint16_t spi_cs_pin;
36 spi_cs_handler_t spi_cs_handler;
37 } ft2004_spi_class;
38
39 void ft2004_spi_cs(const rt_bool_t select);
40 static ft2004_spi_class spi_obj = {
41 .spi_cs_handler = ft2004_spi_cs,
42 .spi_ctrl = {
43 .CtrlId = SPI_CTRL_ID_0,
44 .DevId = SPI_DEV_ID_0,
45 .IsReady = FALSE,
46 .CsPin = 5, /* use pin 5 in gpio group a as cs signal pin */
47 },
48 };
49 static const FSpi_Conf_t spi_conf[NUM_OF_SPI_CTRL] =
50 {
51 {
52 .DevAddr = {0x00, 0x00, 0x00, 0x00},
53 .DevAddrLen = SPI_4_BYTE_ADDR,
54 .WorkMode = SPI_CTRL_MASTER_MODE,
55 /* mode 2 CPOL = 1, CPHA = 0 */
56 .Cpol = SPI_CTRL_CPOL_HIGH,
57 .Cpha = SPI_CTRL_CPHA_1EDGE,
58 .BaudRDiv = SPI_SCKDV_4,
59 },
60 {
61 .DevAddr = {0x00, 0x00, 0x00, 0x00},
62 .DevAddrLen = SPI_4_BYTE_ADDR,
63 .WorkMode = SPI_CTRL_MASTER_MODE,
64 .Cpol = SPI_CTRL_CPOL_HIGH,
65 .Cpha = SPI_CTRL_CPHA_1EDGE,
66 .BaudRDiv = SPI_SCKDV_MAX,
67 }};
68
ft2004_spi_get_class()69 inline static ft2004_spi_class *ft2004_spi_get_class()
70 {
71 return &spi_obj;
72 }
73
ft2004_spi_get_ctrl()74 inline static FSpi_Ctrl_t *ft2004_spi_get_ctrl()
75 {
76 return &(ft2004_spi_get_class()->spi_ctrl);
77 }
78
ft2004_lookup_conf(FT_IN FSpi_CtrlId_t CtrlId)79 static const FSpi_Conf_t *ft2004_lookup_conf(FT_IN FSpi_CtrlId_t CtrlId)
80 {
81 return &spi_conf[CtrlId];
82 }
83
ft2004_spi_cs(const rt_bool_t select)84 void ft2004_spi_cs(const rt_bool_t select)
85 {
86 FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
87 FSpi_SelectSlave(ctrl_p, ctrl_p->DevId, (bool_t)select);
88 }
89
90 /**spi flash operations***/
ft2004_spi_transcation(const u8 tx_data,u8 * rx_data_p)91 u32 ft2004_spi_transcation(const u8 tx_data, u8 *rx_data_p)
92 {
93 FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
94 u32 ret = ERR_SPI_OK;
95
96 ret = FSpi_ReadWriteByte(ctrl_p, tx_data, rx_data_p);
97 return ret;
98 }
99 /**spi flash operations***/
100
ft2004_spi_init(struct rt_spi_configuration * cfg)101 static rt_err_t ft2004_spi_init(struct rt_spi_configuration *cfg)
102 {
103 FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
104 FSpi_DevId_t dev_id;
105 u32 ret = ERR_SPI_OK;
106
107 //RT_ASSERT(cfg != RT_NULL);
108 RT_ASSERT(ctrl_p != RT_NULL);
109 dev_id = ctrl_p->DevId;
110
111 /* get spi flash default config */
112 ctrl_p->Config = *(ft2004_lookup_conf(dev_id));
113
114 /* change config according to inputs, cfg could be RT_NULL */
115
116 /* reset ctrl block */
117 ctrl_p->IsReady = FALSE;
118
119 /* set spi pin mux */
120 Ft_setSpiMux(ctrl_p->CtrlId);
121
122 /* init spi ctrl */
123 ret = FSpi_Init(ctrl_p);
124
125 if (ERR_SPI_OK == ret)
126 {
127 return RT_EOK;
128 }
129 else
130 {
131 return -RT_ERROR;
132 }
133 }
134
spi_xfer(struct rt_spi_device * device,struct rt_spi_message * message)135 static rt_uint32_t spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
136 {
137 rt_size_t message_length, loop;
138 rt_uint8_t *recv_buf;
139 const rt_uint8_t *send_buf;
140 u32 tx_rx_result = ERR_SPI_OK;
141 spi_cs_handler_t cs_handler = ft2004_spi_get_class()->spi_cs_handler;
142
143 RT_ASSERT(device != RT_NULL);
144 RT_ASSERT(device->bus != RT_NULL);
145 RT_ASSERT(device->bus->parent.user_data != RT_NULL);
146 RT_ASSERT(message != RT_NULL);
147
148 if (message->cs_take && cs_handler)
149 {
150 cs_handler(TRUE);
151 }
152
153 message_length = message->length;
154 recv_buf = message->recv_buf;
155 send_buf = message->send_buf;
156
157 /* handle msg */
158 for (loop = 0; loop < message_length; loop++)
159 {
160 /* start data exchange */
161 if ((message->recv_buf) && (message->send_buf))
162 {
163 /* need tx and rx */
164 tx_rx_result |= ft2004_spi_transcation(*send_buf, recv_buf);
165 send_buf++;
166 recv_buf++;
167 }
168 else if (message->send_buf)
169 {
170 /* tx only */
171 tx_rx_result |= ft2004_spi_transcation(*send_buf, RT_NULL);
172 send_buf++;
173 }
174 else
175 {
176 /* rx only */
177 tx_rx_result |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, recv_buf);
178 recv_buf++;
179 }
180 }
181
182 if (ERR_SPI_OK != tx_rx_result)
183 {
184 LOG_E("spi transfer error : 0x%x", tx_rx_result);
185 message->length = 0;
186 }
187 else
188 {
189 }
190
191 if (message->cs_release && cs_handler)
192 {
193 cs_handler(FALSE);
194 }
195
196 return message->length;
197 }
198
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)199 static rt_err_t spi_configure(struct rt_spi_device *device,
200 struct rt_spi_configuration *configuration)
201 {
202 RT_ASSERT(device != RT_NULL);
203 RT_ASSERT(configuration != RT_NULL);
204
205 return ft2004_spi_init(configuration);
206 }
207
208 static const struct rt_spi_ops ft2004_spi_ops =
209 {
210 .configure = spi_configure,
211 .xfer = spi_xfer,
212 };
213
214 /**
215 * Attach the spi device to SPI bus, this function must be used after initialization.
216 */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,rt_uint16_t cs_gpio_pin)217 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_uint16_t cs_gpio_pin)
218 {
219 rt_err_t result;
220 struct rt_spi_device *spi_device;
221 ft2004_spi_class *spi_class = ft2004_spi_get_class();
222
223 RT_ASSERT(spi_class != RT_NULL);
224
225 spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
226 RT_ASSERT(spi_device != RT_NULL);
227
228 result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, RT_NULL);
229
230 LOG_I("attach result 0x%x", result);
231
232 if (result != RT_EOK)
233 {
234 if (spi_device)
235 {
236 rt_free(spi_device);
237 }
238 }
239 return result;
240 }
241
rt_hw_spi_bus_init(void)242 static int rt_hw_spi_bus_init(void)
243 {
244 rt_err_t result;
245 ft2004_spi_class *spi_class = ft2004_spi_get_class();
246
247 LOG_I("init spi ctrl");
248 spi_class->spi_bus.parent.user_data = &spi_class->spi_bus;
249 result = rt_spi_bus_register(&spi_class->spi_bus, SPI_BUS_NAME, &ft2004_spi_ops);
250 return result;
251 }
252
rt_hw_spi_init(void)253 int rt_hw_spi_init(void)
254 {
255 return rt_hw_spi_bus_init();
256 }
257 INIT_BOARD_EXPORT(rt_hw_spi_init);
258
rthw_spi_delay(u32 delayCnt)259 static void rthw_spi_delay(u32 delayCnt)
260 {
261 Ft_GenericTimer_UsDelay(delayCnt);
262 }
263
264 /************spi flash operatiosn implemented for sample test****************/
265 /* definition of s25fs maunfactor id */
266 typedef struct
267 {
268 u8 Mid;
269 u8 MemoryType;
270 u8 Density;
271 u8 RemainBytes;
272 u8 PhySectArch;
273 u8 FamilyID;
274 } ft2004_manuid_t;
275
276 /* definition of cmd for s25fs */
277 #define S25FS_ENABLE_WR 0x06
278 #define S25FS_DISABLE_WR 0x04
279 #define S25FS_READ_ID 0x9F
280 #define S25FS_READ_4BYTE_ADD 0x13
281 #define S25FS_ERASE_4BYTE_ADD 0x21
282 #define S25FS_READ_STATUS_1 0x05
283 #define S25FS_READ_FLASH_PARAM 0x5A
284
ft2004_dump_manuid(const ft2004_manuid_t * pId)285 static void ft2004_dump_manuid(const ft2004_manuid_t *pId)
286 {
287 rt_kprintf("0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\r\n",
288 pId->Mid, pId->MemoryType, pId->Density, pId->RemainBytes,
289 pId->PhySectArch, pId->FamilyID);
290 }
291
ft2004_read_in_4byte_addr(const u32 ReadAddr,const u32 BytesToRead,u8 * pBuf)292 static u32 ft2004_read_in_4byte_addr(const u32 ReadAddr, const u32 BytesToRead, u8 *pBuf)
293 {
294 u32 ret = ERR_SPI_OK;
295 u32 loop;
296
297 RT_ASSERT(RT_NULL != pBuf);
298
299 ft2004_spi_cs(TRUE);
300 ret |= ft2004_spi_transcation(S25FS_READ_4BYTE_ADD, RT_NULL);
301 /* only 4-bytes address, MSB first */
302 ret |= ft2004_spi_transcation((u8)(ReadAddr >> 24), RT_NULL);
303 ret |= ft2004_spi_transcation((u8)(ReadAddr >> 16), RT_NULL);
304 ret |= ft2004_spi_transcation((u8)(ReadAddr >> 8), RT_NULL);
305 ret |= ft2004_spi_transcation((u8)ReadAddr, RT_NULL);
306 /* read out data */
307 for (loop = 0; loop < BytesToRead; loop++)
308 {
309 ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, pBuf + loop);
310 if (ERR_SPI_OK != ret)
311 {
312 break;
313 }
314 }
315 ft2004_spi_cs(FALSE);
316 return ret;
317 }
318
ft2004_spi_enable_wr(const bool_t enable)319 u32 ft2004_spi_enable_wr(const bool_t enable)
320 {
321 u32 ret = ERR_SPI_OK;
322 ft2004_spi_cs(TRUE);
323 if (enable)
324 {
325 ret |= ft2004_spi_transcation(S25FS_ENABLE_WR, RT_NULL);
326 }
327 else
328 {
329 ret |= ft2004_spi_transcation(S25FS_DISABLE_WR, RT_NULL);
330 }
331 ft2004_spi_cs(FALSE);
332 return ret;
333 }
334
ft2004_erase_sector_in_4byte_addr(const u32 sector_addr)335 u32 ft2004_erase_sector_in_4byte_addr(const u32 sector_addr)
336 {
337 u32 Ret = ERR_SPI_OK;
338
339 ft2004_spi_enable_wr(TRUE);
340 LOG_I("erase sector 0x%x", Ret);
341 if (ERR_SPI_OK != Ret)
342 {
343 return Ret;
344 }
345
346 ft2004_spi_cs(TRUE);
347 Ret |= ft2004_spi_transcation(S25FS_ERASE_4BYTE_ADD, RT_NULL);
348 Ret |= ft2004_spi_transcation((u8)(sector_addr >> 24), RT_NULL);
349 Ret |= ft2004_spi_transcation((u8)(sector_addr >> 16), RT_NULL);
350 Ret |= ft2004_spi_transcation((u8)(sector_addr >> 8), RT_NULL);
351 Ret |= ft2004_spi_transcation((u8)(sector_addr), RT_NULL);
352 ft2004_spi_cs(FALSE);
353
354 return Ret;
355 }
356
ft2004_spi_read_params(const u32 Addr)357 u32 ft2004_spi_read_params(const u32 Addr)
358 {
359 u32 Ret = ERR_SPI_OK;
360 u8 dat[8] = {0};
361 u32 loop;
362
363 ft2004_spi_cs(TRUE);
364 Ret |= ft2004_spi_transcation(S25FS_READ_FLASH_PARAM, RT_NULL);
365 Ret |= ft2004_spi_transcation((u8)(Addr >> 16), RT_NULL);
366 Ret |= ft2004_spi_transcation((u8)(Addr >> 8), RT_NULL);
367 Ret |= ft2004_spi_transcation((u8)(Addr), RT_NULL);
368 for (loop = 0; loop < 8; loop++)
369 {
370 Ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, dat + loop);
371 rt_kprintf("%d: 0x%x", loop, *(dat + loop));
372 }
373
374 ft2004_spi_cs(FALSE);
375 return Ret;
376 }
377
ft2004_spi_readid_for_test(ft2004_manuid_t * pId)378 static u32 ft2004_spi_readid_for_test(ft2004_manuid_t *pId)
379 {
380 FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
381 u32 ret = ERR_SPI_OK;
382
383 if (!ctrl_p->IsReady)
384 {
385 return ERR_SPI_NOT_READY;
386 }
387
388 RT_ASSERT(RT_NULL != pId);
389
390 ft2004_spi_cs(TRUE);
391
392 /* shifting the command code “90H” followed by a 24-bit address */
393 ret |= ft2004_spi_transcation(S25FS_READ_ID, RT_NULL);
394
395 /* Manufacturer ID and the Device ID are shifted out */
396 ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->Mid);
397 ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->MemoryType);
398 ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->Density);
399 ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->RemainBytes);
400 ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->PhySectArch);
401 ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->FamilyID);
402 ft2004_spi_cs(FALSE);
403
404 if (ERR_SPI_OK == ret)
405 {
406 ft2004_dump_manuid(pId);
407 }
408
409 return ret;
410 }
411
spi_9f_s25fs_sample(int argc,char * argv[])412 static void spi_9f_s25fs_sample(int argc, char *argv[])
413 {
414 ft2004_manuid_t dev_id;
415 u32 ret = ERR_SPI_OK;
416 u32 delay = SPI_TIMEOUT * 10;
417
418 rt_kprintf("test s25fs spi flash\r\n");
419 ret |= ft2004_spi_init(RT_NULL);
420 ret |= ft2004_spi_readid_for_test(&dev_id);
421
422 rt_kprintf("result is: 0x%x \r\n", ret);
423 while (--delay)
424 {
425 rthw_spi_delay(10);
426 }
427 }
428 MSH_CMD_EXPORT(spi_9f_s25fs_sample, "spi s25fs cmd 9fH sample");
429
430 static u8 read_buf[256];
spi_5a_s25fs_sample(int argc,char * argv[])431 static void spi_5a_s25fs_sample(int argc, char *argv[])
432 {
433 u32 ret = ERR_SPI_OK;
434 u32 delay = SPI_TIMEOUT * 10;
435 u32 read_addr = 0x0000;
436
437 rt_kprintf("test s25fs spi flash\r\n");
438 ret |= ft2004_spi_init(RT_NULL);
439 ret |= ft2004_spi_read_params(read_addr);
440 ret |= ft2004_read_in_4byte_addr(read_addr, 256, read_buf);
441 rt_kprintf("result is: 0x%x \r\n", ret);
442 while (--delay)
443 {
444 rthw_spi_delay(10);
445 }
446 }
447 MSH_CMD_EXPORT(spi_5a_s25fs_sample, "spi s25fs cmd 5aH sample");
448
449 #endif
450