xref: /nrf52832-nimble/rt-thread/components/drivers/spi/spi_flash_sst25vfxx.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2011-12-16     aozima       the first version
9*10465441SEvalZero  */
10*10465441SEvalZero 
11*10465441SEvalZero #include <stdint.h>
12*10465441SEvalZero #include "spi_flash_sst25vfxx.h"
13*10465441SEvalZero 
14*10465441SEvalZero #define FLASH_DEBUG
15*10465441SEvalZero 
16*10465441SEvalZero #ifdef FLASH_DEBUG
17*10465441SEvalZero #define FLASH_TRACE         rt_kprintf
18*10465441SEvalZero #else
19*10465441SEvalZero #define FLASH_TRACE(...)
20*10465441SEvalZero #endif /* #ifdef FLASH_DEBUG */
21*10465441SEvalZero 
22*10465441SEvalZero /* JEDEC Manufacturer’s ID */
23*10465441SEvalZero #define MF_ID                       (0xBF)
24*10465441SEvalZero /* JEDEC Device ID : Memory Type */
25*10465441SEvalZero #define MT_ID                       (0x25)
26*10465441SEvalZero /* JEDEC Device ID: Memory Capacity */
27*10465441SEvalZero #define MC_ID_SST25VF020B            (0x8C) /* 2Mbit  */
28*10465441SEvalZero #define MC_ID_SST25VF040B            (0x8D) /* 4Mbit  */
29*10465441SEvalZero #define MC_ID_SST25VF080B            (0x8E) /* 8Mbit  */
30*10465441SEvalZero #define MC_ID_SST25VF016B            (0x41) /* 16Mbit */
31*10465441SEvalZero #define MC_ID_SST25VF032B            (0x4A) /* 32Mbit */
32*10465441SEvalZero #define MC_ID_SST25VF064C            (0x4B) /* 64Mbit */
33*10465441SEvalZero 
34*10465441SEvalZero /* command list */
35*10465441SEvalZero #define CMD_RDSR                    (0x05)
36*10465441SEvalZero #define CMD_WRSR                    (0x01)
37*10465441SEvalZero #define CMD_EWSR                    (0x50)
38*10465441SEvalZero #define CMD_WRDI                    (0x04)
39*10465441SEvalZero #define CMD_WREN                    (0x06)
40*10465441SEvalZero #define CMD_READ                    (0x03)
41*10465441SEvalZero #define CMD_FAST_READ               (0x0B)
42*10465441SEvalZero #define CMD_BP                      (0x02)
43*10465441SEvalZero #define CMD_AAIP                    (0xAD)
44*10465441SEvalZero #define CMD_ERASE_4K                (0x20)
45*10465441SEvalZero #define CMD_ERASE_32K               (0x52)
46*10465441SEvalZero #define CMD_ERASE_64K               (0xD8)
47*10465441SEvalZero #define CMD_ERASE_full              (0xC7)
48*10465441SEvalZero #define CMD_JEDEC_ID                (0x9F)
49*10465441SEvalZero #define CMD_EBSY                    (0x70)
50*10465441SEvalZero #define CMD_DBSY                    (0x80)
51*10465441SEvalZero 
52*10465441SEvalZero #define DUMMY                       (0xFF)
53*10465441SEvalZero 
54*10465441SEvalZero static struct spi_flash_sst25vfxx  spi_flash_sst25vfxx;
55*10465441SEvalZero 
sst25vfxx_read_status(struct spi_flash_sst25vfxx * spi_flash)56*10465441SEvalZero static uint8_t sst25vfxx_read_status(struct spi_flash_sst25vfxx * spi_flash)
57*10465441SEvalZero {
58*10465441SEvalZero     return rt_spi_sendrecv8(spi_flash->rt_spi_device, CMD_RDSR);
59*10465441SEvalZero }
60*10465441SEvalZero 
sst25vfxx_wait_busy(struct spi_flash_sst25vfxx * spi_flash)61*10465441SEvalZero static void sst25vfxx_wait_busy(struct spi_flash_sst25vfxx * spi_flash)
62*10465441SEvalZero {
63*10465441SEvalZero     while( sst25vfxx_read_status(spi_flash) & (0x01));
64*10465441SEvalZero }
65*10465441SEvalZero 
66*10465441SEvalZero /** \brief write N page on [page]
67*10465441SEvalZero  *
68*10465441SEvalZero  * \param page uint32_t unit : byte (4096 * N,1 page = 4096byte)
69*10465441SEvalZero  * \param buffer const uint8_t*
70*10465441SEvalZero  * \param size uint32_t unit : byte ( 4096*N )
71*10465441SEvalZero  * \return uint32_t
72*10465441SEvalZero  *
73*10465441SEvalZero  */
sst25vfxx_page_write(struct spi_flash_sst25vfxx * spi_flash,uint32_t page,const uint8_t * buffer,uint32_t size)74*10465441SEvalZero static uint32_t sst25vfxx_page_write(struct spi_flash_sst25vfxx * spi_flash, uint32_t page, const uint8_t * buffer, uint32_t size)
75*10465441SEvalZero {
76*10465441SEvalZero     uint32_t index;
77*10465441SEvalZero     uint32_t need_wirte = size;
78*10465441SEvalZero     uint8_t send_buffer[6];
79*10465441SEvalZero 
80*10465441SEvalZero     page &= ~0xFFF; // page size = 4096byte
81*10465441SEvalZero 
82*10465441SEvalZero     send_buffer[0] = CMD_WREN;
83*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
84*10465441SEvalZero 
85*10465441SEvalZero     send_buffer[0] = CMD_ERASE_4K;
86*10465441SEvalZero     send_buffer[1] = (page >> 16);
87*10465441SEvalZero     send_buffer[2] = (page >> 8);
88*10465441SEvalZero     send_buffer[3] = (page);
89*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 4);
90*10465441SEvalZero 
91*10465441SEvalZero     sst25vfxx_wait_busy(spi_flash); // wait erase done.
92*10465441SEvalZero 
93*10465441SEvalZero     send_buffer[0] = CMD_WREN;
94*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
95*10465441SEvalZero 
96*10465441SEvalZero     send_buffer[0] = CMD_AAIP;
97*10465441SEvalZero     send_buffer[1] = (uint8_t)(page >> 16);
98*10465441SEvalZero     send_buffer[2] = (uint8_t)(page >> 8);
99*10465441SEvalZero     send_buffer[3] = (uint8_t)(page);
100*10465441SEvalZero     send_buffer[4] = *buffer++;
101*10465441SEvalZero     send_buffer[5] = *buffer++;
102*10465441SEvalZero     need_wirte -= 2;
103*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 6);
104*10465441SEvalZero 
105*10465441SEvalZero     sst25vfxx_wait_busy(spi_flash);
106*10465441SEvalZero 
107*10465441SEvalZero     for(index=0; index < need_wirte/2; index++)
108*10465441SEvalZero     {
109*10465441SEvalZero         send_buffer[0] = CMD_AAIP;
110*10465441SEvalZero         send_buffer[1] = *buffer++;
111*10465441SEvalZero         send_buffer[2] = *buffer++;
112*10465441SEvalZero         rt_spi_send(spi_flash->rt_spi_device, send_buffer, 3);
113*10465441SEvalZero         sst25vfxx_wait_busy(spi_flash);
114*10465441SEvalZero     }
115*10465441SEvalZero 
116*10465441SEvalZero     send_buffer[0] = CMD_WRDI;
117*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
118*10465441SEvalZero 
119*10465441SEvalZero     return size;
120*10465441SEvalZero }
121*10465441SEvalZero 
122*10465441SEvalZero /* RT-Thread device interface */
sst25vfxx_flash_init(rt_device_t dev)123*10465441SEvalZero static rt_err_t sst25vfxx_flash_init(rt_device_t dev)
124*10465441SEvalZero {
125*10465441SEvalZero     return RT_EOK;
126*10465441SEvalZero }
127*10465441SEvalZero 
sst25vfxx_flash_open(rt_device_t dev,rt_uint16_t oflag)128*10465441SEvalZero static rt_err_t sst25vfxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
129*10465441SEvalZero {
130*10465441SEvalZero     rt_err_t result;
131*10465441SEvalZero     uint8_t send_buffer[2];
132*10465441SEvalZero     struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
133*10465441SEvalZero 
134*10465441SEvalZero     /* lock spi flash */
135*10465441SEvalZero     result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
136*10465441SEvalZero     if(result != RT_EOK)
137*10465441SEvalZero     {
138*10465441SEvalZero         return result;
139*10465441SEvalZero     }
140*10465441SEvalZero 
141*10465441SEvalZero     send_buffer[0] = CMD_DBSY;
142*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
143*10465441SEvalZero 
144*10465441SEvalZero     send_buffer[0] = CMD_EWSR;
145*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
146*10465441SEvalZero 
147*10465441SEvalZero     send_buffer[0] = CMD_WRSR;
148*10465441SEvalZero     send_buffer[1] = 0;
149*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 2);
150*10465441SEvalZero 
151*10465441SEvalZero     /* release lock */
152*10465441SEvalZero     rt_mutex_release(&(spi_flash->lock));
153*10465441SEvalZero 
154*10465441SEvalZero     return RT_EOK;
155*10465441SEvalZero }
156*10465441SEvalZero 
sst25vfxx_flash_close(rt_device_t dev)157*10465441SEvalZero static rt_err_t sst25vfxx_flash_close(rt_device_t dev)
158*10465441SEvalZero {
159*10465441SEvalZero     return RT_EOK;
160*10465441SEvalZero }
161*10465441SEvalZero 
sst25vfxx_flash_control(rt_device_t dev,int cmd,void * args)162*10465441SEvalZero static rt_err_t sst25vfxx_flash_control(rt_device_t dev, int cmd, void *args)
163*10465441SEvalZero {
164*10465441SEvalZero     struct spi_flash_sst25vfxx * spi_flash;
165*10465441SEvalZero 
166*10465441SEvalZero     spi_flash = (struct spi_flash_sst25vfxx *)dev;
167*10465441SEvalZero 
168*10465441SEvalZero     RT_ASSERT(dev != RT_NULL);
169*10465441SEvalZero 
170*10465441SEvalZero     if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
171*10465441SEvalZero     {
172*10465441SEvalZero         struct rt_device_blk_geometry *geometry;
173*10465441SEvalZero 
174*10465441SEvalZero         geometry = (struct rt_device_blk_geometry *)args;
175*10465441SEvalZero         if (geometry == RT_NULL) return -RT_ERROR;
176*10465441SEvalZero 
177*10465441SEvalZero         geometry->bytes_per_sector = spi_flash->geometry.bytes_per_sector;
178*10465441SEvalZero         geometry->sector_count = spi_flash->geometry.sector_count;
179*10465441SEvalZero         geometry->block_size = spi_flash->geometry.block_size;
180*10465441SEvalZero     }
181*10465441SEvalZero 
182*10465441SEvalZero     return RT_EOK;
183*10465441SEvalZero }
184*10465441SEvalZero 
sst25vfxx_flash_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)185*10465441SEvalZero static rt_size_t sst25vfxx_flash_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
186*10465441SEvalZero {
187*10465441SEvalZero     rt_err_t result;
188*10465441SEvalZero     uint8_t send_buffer[4];
189*10465441SEvalZero     struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
190*10465441SEvalZero     uint32_t offset = pos * spi_flash->geometry.bytes_per_sector;
191*10465441SEvalZero 
192*10465441SEvalZero     /* lock spi flash */
193*10465441SEvalZero     result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
194*10465441SEvalZero     if(result != RT_EOK)
195*10465441SEvalZero     {
196*10465441SEvalZero         return 0;
197*10465441SEvalZero     }
198*10465441SEvalZero 
199*10465441SEvalZero     send_buffer[0] = CMD_WRDI;
200*10465441SEvalZero     rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
201*10465441SEvalZero 
202*10465441SEvalZero     send_buffer[0] = CMD_READ;
203*10465441SEvalZero     send_buffer[1] = (uint8_t)(offset>>16);
204*10465441SEvalZero     send_buffer[2] = (uint8_t)(offset>>8);
205*10465441SEvalZero     send_buffer[3] = (uint8_t)(offset);
206*10465441SEvalZero     rt_spi_send_then_recv(spi_flash->rt_spi_device, send_buffer, 4, buffer, size * spi_flash->geometry.bytes_per_sector);
207*10465441SEvalZero 
208*10465441SEvalZero     /* release lock */
209*10465441SEvalZero     rt_mutex_release(&(spi_flash->lock));
210*10465441SEvalZero 
211*10465441SEvalZero     return size;
212*10465441SEvalZero }
213*10465441SEvalZero 
sst25vfxx_flash_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)214*10465441SEvalZero static rt_size_t sst25vfxx_flash_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
215*10465441SEvalZero {
216*10465441SEvalZero     uint32_t i;
217*10465441SEvalZero     rt_err_t result;
218*10465441SEvalZero     const uint8_t * write_buffer = buffer;
219*10465441SEvalZero     struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
220*10465441SEvalZero 
221*10465441SEvalZero     /* lock spi flash */
222*10465441SEvalZero     result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
223*10465441SEvalZero     if(result != RT_EOK)
224*10465441SEvalZero     {
225*10465441SEvalZero         return 0;
226*10465441SEvalZero     }
227*10465441SEvalZero 
228*10465441SEvalZero     for(i=0; i<size; i++)
229*10465441SEvalZero     {
230*10465441SEvalZero         sst25vfxx_page_write(spi_flash,
231*10465441SEvalZero                              (pos + i) * spi_flash->geometry.bytes_per_sector,
232*10465441SEvalZero                              write_buffer,
233*10465441SEvalZero                              spi_flash->geometry.bytes_per_sector);
234*10465441SEvalZero         write_buffer += spi_flash->geometry.bytes_per_sector;
235*10465441SEvalZero     }
236*10465441SEvalZero 
237*10465441SEvalZero     /* release lock */
238*10465441SEvalZero     rt_mutex_release(&(spi_flash->lock));
239*10465441SEvalZero 
240*10465441SEvalZero     return size;
241*10465441SEvalZero }
242*10465441SEvalZero 
243*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
244*10465441SEvalZero const static struct rt_device_ops sst25vfxx_device_ops =
245*10465441SEvalZero {
246*10465441SEvalZero     sst25vfxx_flash_init,
247*10465441SEvalZero     sst25vfxx_flash_open,
248*10465441SEvalZero     sst25vfxx_flash_close,
249*10465441SEvalZero     sst25vfxx_flash_read,
250*10465441SEvalZero     sst25vfxx_flash_write,
251*10465441SEvalZero     sst25vfxx_flash_control
252*10465441SEvalZero };
253*10465441SEvalZero #endif
254*10465441SEvalZero 
sst25vfxx_init(const char * flash_device_name,const char * spi_device_name)255*10465441SEvalZero rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name)
256*10465441SEvalZero {
257*10465441SEvalZero     struct rt_spi_device * rt_spi_device;
258*10465441SEvalZero     struct spi_flash_sst25vfxx * spi_flash = &spi_flash_sst25vfxx;
259*10465441SEvalZero 
260*10465441SEvalZero     rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
261*10465441SEvalZero     if(rt_spi_device == RT_NULL)
262*10465441SEvalZero     {
263*10465441SEvalZero         FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
264*10465441SEvalZero         return -RT_ENOSYS;
265*10465441SEvalZero     }
266*10465441SEvalZero     spi_flash->rt_spi_device = rt_spi_device;
267*10465441SEvalZero 
268*10465441SEvalZero     /* config spi */
269*10465441SEvalZero     {
270*10465441SEvalZero         struct rt_spi_configuration cfg;
271*10465441SEvalZero         cfg.data_width = 8;
272*10465441SEvalZero         cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
273*10465441SEvalZero         cfg.max_hz = 50000000; /* 50M */
274*10465441SEvalZero         rt_spi_configure(spi_flash->rt_spi_device, &cfg);
275*10465441SEvalZero     }
276*10465441SEvalZero 
277*10465441SEvalZero     /* init flash */
278*10465441SEvalZero     {
279*10465441SEvalZero         rt_uint8_t cmd;
280*10465441SEvalZero         rt_uint8_t id_recv[3];
281*10465441SEvalZero 
282*10465441SEvalZero         cmd = CMD_WRDI;
283*10465441SEvalZero         rt_spi_send(spi_flash->rt_spi_device, &cmd, 1);
284*10465441SEvalZero 
285*10465441SEvalZero         /* read flash id */
286*10465441SEvalZero         cmd = CMD_JEDEC_ID;
287*10465441SEvalZero         rt_spi_send_then_recv(spi_flash->rt_spi_device, &cmd, 1, id_recv, 3);
288*10465441SEvalZero 
289*10465441SEvalZero         if(id_recv[0] != MF_ID || id_recv[1] != MT_ID)
290*10465441SEvalZero         {
291*10465441SEvalZero             FLASH_TRACE("Manufacturer’s ID or Memory Type error!\r\n");
292*10465441SEvalZero             FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
293*10465441SEvalZero             return -RT_ENOSYS;
294*10465441SEvalZero         }
295*10465441SEvalZero 
296*10465441SEvalZero         spi_flash->geometry.bytes_per_sector = 4096;
297*10465441SEvalZero         spi_flash->geometry.block_size = 4096; /* block erase: 4k */
298*10465441SEvalZero 
299*10465441SEvalZero         if(id_recv[2] == MC_ID_SST25VF020B)
300*10465441SEvalZero         {
301*10465441SEvalZero             FLASH_TRACE("SST25VF020B detection\r\n");
302*10465441SEvalZero             spi_flash->geometry.sector_count = 64;
303*10465441SEvalZero         }
304*10465441SEvalZero         else if(id_recv[2] == MC_ID_SST25VF040B)
305*10465441SEvalZero         {
306*10465441SEvalZero             FLASH_TRACE("SST25VF040B detection\r\n");
307*10465441SEvalZero             spi_flash->geometry.sector_count = 128;
308*10465441SEvalZero         }
309*10465441SEvalZero         else if(id_recv[2] == MC_ID_SST25VF080B)
310*10465441SEvalZero         {
311*10465441SEvalZero             FLASH_TRACE("SST25VF080B detection\r\n");
312*10465441SEvalZero             spi_flash->geometry.sector_count = 256;
313*10465441SEvalZero         }
314*10465441SEvalZero         else if(id_recv[2] == MC_ID_SST25VF016B)
315*10465441SEvalZero         {
316*10465441SEvalZero             FLASH_TRACE("SST25VF016B detection\r\n");
317*10465441SEvalZero             spi_flash->geometry.sector_count = 512;
318*10465441SEvalZero         }
319*10465441SEvalZero         else if(id_recv[2] == MC_ID_SST25VF032B)
320*10465441SEvalZero         {
321*10465441SEvalZero             FLASH_TRACE("SST25VF032B detection\r\n");
322*10465441SEvalZero             spi_flash->geometry.sector_count = 1024;
323*10465441SEvalZero         }
324*10465441SEvalZero         else if(id_recv[2] == MC_ID_SST25VF064C)
325*10465441SEvalZero         {
326*10465441SEvalZero             FLASH_TRACE("SST25VF064C detection\r\n");
327*10465441SEvalZero             spi_flash->geometry.sector_count = 2048;
328*10465441SEvalZero         }
329*10465441SEvalZero         else
330*10465441SEvalZero         {
331*10465441SEvalZero             FLASH_TRACE("Memory Capacity error!\r\n");
332*10465441SEvalZero             return -RT_ENOSYS;
333*10465441SEvalZero         }
334*10465441SEvalZero     }
335*10465441SEvalZero 
336*10465441SEvalZero     /* initialize mutex lock */
337*10465441SEvalZero     rt_mutex_init(&spi_flash->lock, flash_device_name, RT_IPC_FLAG_PRIO);
338*10465441SEvalZero 
339*10465441SEvalZero     /* register device */
340*10465441SEvalZero     spi_flash->flash_device.type    = RT_Device_Class_Block;
341*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
342*10465441SEvalZero     spi_flash->flash_device.ops     = &sst25vfxx_device_ops;
343*10465441SEvalZero #else
344*10465441SEvalZero     spi_flash->flash_device.init    = sst25vfxx_flash_init;
345*10465441SEvalZero     spi_flash->flash_device.open    = sst25vfxx_flash_open;
346*10465441SEvalZero     spi_flash->flash_device.close   = sst25vfxx_flash_close;
347*10465441SEvalZero     spi_flash->flash_device.read    = sst25vfxx_flash_read;
348*10465441SEvalZero     spi_flash->flash_device.write   = sst25vfxx_flash_write;
349*10465441SEvalZero     spi_flash->flash_device.control = sst25vfxx_flash_control;
350*10465441SEvalZero #endif
351*10465441SEvalZero     /* no private */
352*10465441SEvalZero     spi_flash->flash_device.user_data = RT_NULL;
353*10465441SEvalZero 
354*10465441SEvalZero     rt_device_register(&spi_flash->flash_device, flash_device_name,
355*10465441SEvalZero                        RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
356*10465441SEvalZero 
357*10465441SEvalZero     return RT_EOK;
358*10465441SEvalZero }
359