xref: /nrf52832-nimble/rt-thread/components/drivers/spi/spi_flash_w25qxx_mtd.c (revision 104654410c56c573564690304ae786df310c91fc)
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  */
9 #include <rtthread.h>
10 #include <rtdevice.h>
11 
12 #include "spi_flash.h"
13 #include "spi_flash_w25qxx_mtd.h"
14 
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 
20 #define FLASH_DEBUG
21 
22 #ifdef FLASH_DEBUG
23 #define FLASH_TRACE         printf
24 #else
25 #define FLASH_TRACE(...)
26 #endif /* #ifdef FLASH_DEBUG */
27 
28 /* JEDEC Manufacturer’s ID */
29 #define MF_ID           (0xEF)
30 /* JEDEC Device ID: Memory type and Capacity */
31 #define MTC_W25Q80_BV         (0x4014) /* W25Q80BV */
32 #define MTC_W25Q16_BV_CL_CV   (0x4015) /* W25Q16BV W25Q16CL W25Q16CV  */
33 #define MTC_W25Q16_DW         (0x6015) /* W25Q16DW  */
34 #define MTC_W25Q32_BV         (0x4016) /* W25Q32BV */
35 #define MTC_W25Q32_DW         (0x6016) /* W25Q32DW */
36 #define MTC_W25Q64_BV_CV      (0x4017) /* W25Q64BV W25Q64CV */
37 #define MTC_W25Q64_DW         (0x4017) /* W25Q64DW */
38 #define MTC_W25Q128_BV        (0x4018) /* W25Q128BV */
39 #define MTC_W25Q256_FV        (TBD)    /* W25Q256FV */
40 
41 #define MTC_W25X80            (0x3014)
42 
43 /* command list */
44 #define CMD_WRSR                    (0x01)  /* Write Status Register */
45 #define CMD_PP                      (0x02)  /* Page Program */
46 #define CMD_READ                    (0x03)  /* Read Data */
47 #define CMD_WRDI                    (0x04)  /* Write Disable */
48 #define CMD_RDSR1                   (0x05)  /* Read Status Register-1 */
49 #define CMD_WREN                    (0x06)  /* Write Enable */
50 #define CMD_FAST_READ               (0x0B)  /* Fast Read */
51 #define CMD_ERASE_4K                (0x20)  /* Sector Erase:4K */
52 #define CMD_RDSR2                   (0x35)  /* Read Status Register-2 */
53 #define CMD_ERASE_32K               (0x52)  /* 32KB Block Erase */
54 #define CMD_JEDEC_ID                (0x9F)  /* Read JEDEC ID */
55 #define CMD_ERASE_full              (0xC7)  /* Chip Erase */
56 #define CMD_ERASE_64K               (0xD8)  /* 64KB Block Erase */
57 #define CMD_MANU_ID                 (0x90)
58 
59 #define DUMMY                       (0xFF)
60 
61 #define FLASH_ERASE_CMD             CMD_ERASE_4K
62 #define FLASH_BLOCK_SIZE            4096
63 #define FLASH_PAGE_SIZE             256
64 
w25qxx_lock(struct rt_mtd_nor_device * device)65 static void w25qxx_lock(struct rt_mtd_nor_device *device)
66 {
67     struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
68     rt_mutex_take(&mtd->lock, RT_WAITING_FOREVER);
69 }
70 
w25qxx_unlock(struct rt_mtd_nor_device * device)71 static void w25qxx_unlock(struct rt_mtd_nor_device *device)
72 {
73     struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
74     rt_mutex_release(&mtd->lock);
75 }
76 
w25qxx_read_status(struct rt_mtd_nor_device * device)77 static rt_uint8_t w25qxx_read_status(struct rt_mtd_nor_device *device)
78 {
79     struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
80     return rt_spi_sendrecv8(mtd->rt_spi_device, CMD_RDSR1);
81 }
82 
w25qxx_wait_busy(struct rt_mtd_nor_device * device)83 static void w25qxx_wait_busy(struct rt_mtd_nor_device *device)
84 {
85     while( w25qxx_read_status(device) & (0x01));
86 }
87 
w25qxx_read_id(struct rt_mtd_nor_device * device)88 static rt_err_t w25qxx_read_id(struct rt_mtd_nor_device *device)
89 {
90     rt_uint8_t cmd;
91     rt_uint8_t id_recv[3];
92 
93     struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
94 
95     w25qxx_lock(device);
96 
97     cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
98     rt_spi_send(mtd->rt_spi_device, &cmd, 1);
99 
100     cmd = CMD_WRDI;
101     rt_spi_send(mtd->rt_spi_device, &cmd, 1);
102 
103     /* read flash id */
104     cmd = CMD_JEDEC_ID;
105     rt_spi_send_then_recv(mtd->rt_spi_device, &cmd, 1, id_recv, 3);
106 
107     w25qxx_unlock(device);
108 
109     return (rt_uint32_t)(id_recv[0] << 16) | (id_recv[1] << 8) | id_recv[2];
110 }
111 
w25qxx_read(struct rt_mtd_nor_device * device,rt_off_t offset,rt_uint8_t * buffer,rt_size_t length)112 static rt_size_t w25qxx_read(struct rt_mtd_nor_device *device, rt_off_t offset, rt_uint8_t *buffer, rt_size_t length)
113 {
114     struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
115     rt_uint8_t send_buffer[4];
116 
117     if((offset + length) > device->block_end * FLASH_BLOCK_SIZE)
118         return 0;
119 
120 
121     w25qxx_lock(device);
122 
123     send_buffer[0] = CMD_WRDI;
124     rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
125 
126     send_buffer[0] = CMD_READ;
127     send_buffer[1] = (rt_uint8_t)(offset>>16);
128     send_buffer[2] = (rt_uint8_t)(offset>>8);
129     send_buffer[3] = (rt_uint8_t)(offset);
130     rt_spi_send_then_recv(mtd->rt_spi_device,
131                           send_buffer, 4,
132                           buffer, length);
133 
134     w25qxx_unlock(device);
135     return length;
136 }
137 
w25qxx_write(struct rt_mtd_nor_device * device,rt_off_t offset,const rt_uint8_t * buffer,rt_size_t length)138 static rt_size_t w25qxx_write(struct rt_mtd_nor_device *device, rt_off_t offset, const rt_uint8_t *buffer, rt_size_t length)
139 {
140     struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
141     rt_uint8_t send_buffer[4];
142     rt_uint8_t *write_ptr ;
143     rt_size_t   write_size,write_total;
144 
145     if((offset + length) > device->block_end * FLASH_BLOCK_SIZE)
146         return 0;
147 
148     w25qxx_lock(device);
149 
150     send_buffer[0] = CMD_WREN;
151     rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
152     w25qxx_wait_busy(device); // wait erase done.
153 
154     write_size  = 0;
155     write_total = 0;
156     write_ptr   = (rt_uint8_t *)buffer;
157     while(write_total < length)
158     {
159         send_buffer[0] = CMD_WREN;
160         rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
161 
162         //write first page...
163         send_buffer[0] = CMD_PP;
164         send_buffer[1] = (rt_uint8_t)(offset >> 16);
165         send_buffer[2] = (rt_uint8_t)(offset >> 8);
166         send_buffer[3] = (rt_uint8_t)(offset);
167 
168         //address % FLASH_PAGE_SIZE + length
169         if(((offset & (FLASH_PAGE_SIZE - 1)) + (length - write_total)) > FLASH_PAGE_SIZE)
170         {
171             write_size = FLASH_PAGE_SIZE - (offset & (FLASH_PAGE_SIZE - 1));
172         }
173         else
174         {
175             write_size = (length - write_total);
176         }
177 
178         rt_spi_send_then_send(mtd->rt_spi_device,
179                               send_buffer, 4,
180                               write_ptr + write_total, write_size);
181         w25qxx_wait_busy(device);
182 
183 
184         offset      += write_size;
185         write_total += write_size;
186     }
187 
188     send_buffer[0] = CMD_WRDI;
189     rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
190 
191     w25qxx_unlock(device);
192 
193     return length;
194 }
195 
w25qxx_erase_block(struct rt_mtd_nor_device * device,rt_off_t offset,rt_uint32_t length)196 static rt_err_t w25qxx_erase_block(struct rt_mtd_nor_device *device, rt_off_t offset, rt_uint32_t length)
197 {
198     struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
199     rt_uint8_t  send_buffer[4];
200     rt_uint32_t erase_size = 0;
201 
202     //offset must be ALIGN_DOWN to BLOCKSIZE
203     if(offset != RT_ALIGN_DOWN(offset,FLASH_BLOCK_SIZE))
204         return 0;
205 
206     if((offset + length) > device->block_end * FLASH_BLOCK_SIZE)
207         return 0;
208 
209     /* check length must align to block size */
210     if(length %  device->block_size != 0)
211     {
212         rt_kprintf("param length = %d ,error\n",length);
213         return 0;
214     }
215 
216     w25qxx_lock(device);
217 
218     send_buffer[0] = CMD_WREN;
219     rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
220     w25qxx_wait_busy(device); // wait erase done.
221     while (erase_size < length)
222     {
223         send_buffer[0] = CMD_ERASE_4K;
224         send_buffer[1] = (rt_uint8_t) (offset >> 16);
225         send_buffer[2] = (rt_uint8_t) (offset >> 8);
226         send_buffer[3] = (rt_uint8_t) (offset);
227         rt_spi_send(mtd->rt_spi_device, send_buffer, 4);
228         w25qxx_wait_busy(device);    // wait erase done.
229 
230         erase_size += 4096;
231         offset += 4096;
232     }
233     send_buffer[0] = CMD_WRDI;
234     rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
235 
236     w25qxx_unlock(device);
237     return RT_EOK;
238 }
239 
240 const static struct rt_mtd_nor_driver_ops w25qxx_mtd_ops =
241 {
242     w25qxx_read_id,
243     w25qxx_read,
244     w25qxx_write,
245     w25qxx_erase_block,
246 };
247 
w25qxx_mtd_init(const char * mtd_name,const char * spi_device_name)248 rt_err_t w25qxx_mtd_init(const char *mtd_name,const char * spi_device_name)
249 {
250     rt_err_t    result = RT_EOK;
251     rt_uint32_t id;
252     rt_uint8_t  send_buffer[3];
253 
254     struct rt_spi_device*   rt_spi_device;
255     struct spi_flash_mtd*   mtd = (struct spi_flash_mtd *)rt_malloc(sizeof(struct spi_flash_mtd));
256 
257     RT_ASSERT(mtd != RT_NULL);
258 
259     /* initialize mutex */
260     if (rt_mutex_init(&mtd->lock, mtd_name, RT_IPC_FLAG_FIFO) != RT_EOK)
261     {
262         FLASH_TRACE("init mtd lock mutex failed\n");
263         result = -RT_ENOSYS;
264 
265         goto _error_exit;
266     }
267 
268     rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
269     if(rt_spi_device == RT_NULL)
270     {
271         FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
272         result = -RT_ENOSYS;
273 
274         goto _error_exit;
275     }
276     mtd->rt_spi_device = rt_spi_device;
277     /* config spi */
278     {
279         struct rt_spi_configuration cfg;
280         cfg.data_width = 8;
281         cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
282         cfg.max_hz = 20 * 1000 * 1000; /* 20 */
283         rt_spi_configure(rt_spi_device, &cfg);
284     }
285 
286     /* Init Flash device */
287     {
288         w25qxx_lock(&mtd->mtd_device);
289 
290         send_buffer[0] = CMD_WREN;
291         rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
292         w25qxx_wait_busy(&mtd->mtd_device);
293 
294         send_buffer[0] = CMD_WRSR;
295         send_buffer[1] = 0;
296         send_buffer[2] = 0;
297         rt_spi_send(mtd->rt_spi_device, send_buffer, 3);
298         w25qxx_wait_busy(&mtd->mtd_device);
299 
300         w25qxx_unlock(&mtd->mtd_device);
301     }
302 
303     id = w25qxx_read_id(&mtd->mtd_device);
304 
305     mtd->mtd_device.block_size  = 4096;
306     mtd->mtd_device.block_start = 0;
307     switch(id & 0xFFFF)
308     {
309         case MTC_W25Q80_BV: /* W25Q80BV */
310             mtd->mtd_device.block_end = 256;
311             break;
312         case MTC_W25Q16_BV_CL_CV: /* W25Q16BV W25Q16CL W25Q16CV  */
313         case MTC_W25Q16_DW: /* W25Q16DW  */
314             mtd->mtd_device.block_end = 512;
315             break;
316         case MTC_W25Q32_BV: /* W25Q32BV */
317         case MTC_W25Q32_DW: /* W25Q32DW */
318             mtd->mtd_device.block_end = 1024;
319             break;
320         case MTC_W25Q64_BV_CV: /* W25Q64BV W25Q64CV */
321             mtd->mtd_device.block_end = 2048;
322             break;
323         case MTC_W25Q128_BV: /* W25Q128BV */
324             mtd->mtd_device.block_end = 4086;
325             break;
326     }
327     mtd->mtd_device.ops = &w25qxx_mtd_ops;
328     rt_mtd_nor_register_device(mtd_name,&mtd->mtd_device);
329 
330     return RT_EOK;
331 
332 _error_exit:
333     if(mtd != RT_NULL)
334         rt_free(mtd);
335     return result;
336 }
337