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