aboutsummaryrefslogtreecommitdiff
path: root/nuttx/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/mtd')
-rw-r--r--nuttx/drivers/mtd/Kconfig133
-rw-r--r--nuttx/drivers/mtd/Make.defs65
-rw-r--r--nuttx/drivers/mtd/at24xx.c429
-rw-r--r--nuttx/drivers/mtd/at25.c710
-rw-r--r--nuttx/drivers/mtd/at45db.c899
-rw-r--r--nuttx/drivers/mtd/flash_eraseall.c117
-rw-r--r--nuttx/drivers/mtd/ftl.c601
-rw-r--r--nuttx/drivers/mtd/m25px.c798
-rw-r--r--nuttx/drivers/mtd/rammtd.c417
-rw-r--r--nuttx/drivers/mtd/ramtron.c686
-rw-r--r--nuttx/drivers/mtd/skeleton.c275
-rw-r--r--nuttx/drivers/mtd/sst25.c1250
-rw-r--r--nuttx/drivers/mtd/w25.c1179
13 files changed, 0 insertions, 7559 deletions
diff --git a/nuttx/drivers/mtd/Kconfig b/nuttx/drivers/mtd/Kconfig
deleted file mode 100644
index ae656c474..000000000
--- a/nuttx/drivers/mtd/Kconfig
+++ /dev/null
@@ -1,133 +0,0 @@
-#
-# For a description of the syntax of this configuration file,
-# see misc/tools/kconfig-language.txt.
-#
-config MTD_AT24XX
- bool "I2C-based AT24XX eeprom"
- default n
- select I2C
-
-config AT24XX_SIZE
- int "at24xx size(kByte)"
- default 64
- depends on MTD_AT24XX
-
-config AT24XX_ADDR
- hex "at24xx i2c address"
- default 0x50
- depends on MTD_AT24XX
-
-config MTD_AT45DB
- bool "SPI-based AT45DB flash"
- default n
- select SPI
-
-config AT45DB_FREQUENCY
- int "at45db frequency"
- default 1000000
- depends on MTD_AT45DB
-
-config AT45DB_PREWAIT
- bool "enables higher performance write logic"
- default y
- depends on MTD_AT45DB
-
-config AT45DB_PWRSAVE
- bool "enables power save"
- default n
- depends on MTD_AT45DB
-
-config MTD_MP25P
- bool "SPI-based M25P FLASH"
- default n
- select SPI
-
-config MP25P_SPIMODE
- int "MP25P SPI mode"
- default 0
- depends on MTD_MP25P
-
-config MP25P_MANUFACTURER
- hex "MP25P manufacturers ID"
- default 0x20
- depends on MTD_MP25P
- ---help---
- Various manufacturers may have produced the parts. 0x20 is the manufacturer ID
- for the STMicro MP25x serial FLASH. If, for example, you are using the a Macronix
- International MX25 serial FLASH, the correct manufacturer ID would be 0xc2.
-
-config MTD_RAMTRON
- bool "SPI-based RAMTRON NVRAM Devices FM25V10"
- default n
- select SPI
- ---help---
- SPI-based RAMTRON NVRAM Devices FM25V10
-
-config MTD_RAM
- bool "Memory bus ram"
- default n
-
-config MTD_SST25
- bool "SPI-based SST25 FLASH"
- default n
- select SPI
-
-config SST25_SPIMODE
- int "SST25 SPI Mode"
- default 0
- depends on MTD_SST25
-
-config SST25_SPIFREQUENCY
- int "SST25 SPI Frequency"
- default 20000000
- depends on MTD_SST25
-
-config SST25_READONLY
- bool "SST25 Read-Only FLASH"
- default n
- depends on MTD_SST25
-
-config SST25_SECTOR512
- bool "Simulate 512 byte Erase Blocks"
- default n
- depends on MTD_SST25
-
-config SST25_SLOWWRITE
- bool
- default y
- depends on MTD_SST25
-
-config SST25_SLOWREAD
- bool
- default n
- depends on MTD_SST25
-
-config MTD_W25
- bool "SPI-based W25 FLASH"
- default n
- select SPI
-
-config W25_SPIMODE
- int "W25 SPI Mode"
- default 0
- depends on MTD_W25
-
-config W25_SPIFREQUENCY
- int "W25 SPI Frequency"
- default 20000000
- depends on MTD_W25
-
-config W25_READONLY
- bool "W25 Read-Only FLASH"
- default n
- depends on MTD_W25
-
-config W25_SECTOR512
- bool "Simulate 512 byte Erase Blocks"
- default n
- depends on MTD_W25
-
-config W25_SLOWREAD
- bool
- default n
- depends on MTD_W25
diff --git a/nuttx/drivers/mtd/Make.defs b/nuttx/drivers/mtd/Make.defs
deleted file mode 100644
index 3102f1447..000000000
--- a/nuttx/drivers/mtd/Make.defs
+++ /dev/null
@@ -1,65 +0,0 @@
-############################################################################
-# drivers/mtd/Make.defs
-# These driver supports various Memory Technology Devices (MTD) using the
-# NuttX MTD interface.
-#
-# Copyright (C) 2009-2012 Gregory Nutt. All rights reserved.
-# Author: Gregory Nutt <gnutt@nuttx.org>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# 3. Neither the name NuttX nor the names of its contributors may be
-# used to endorse or promote products derived from this software
-# without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-############################################################################
-
-# Include MTD drivers
-
-ifeq ($(CONFIG_MTD),y)
-
-CSRCS += at45db.c flash_eraseall.c ftl.c m25px.c rammtd.c ramtron.c
-
-ifeq ($(CONFIG_MTD_AT24XX),y)
-CSRCS += at24xx.c
-endif
-
-ifeq ($(CONFIG_MTD_SST25),y)
-CSRCS += sst25.c
-endif
-
-ifeq ($(CONFIG_MTD_W25),y)
-CSRCS += w25.c
-endif
-
-ifeq ($(CONFIG_MTD_AT25),y)
-CSRCS += at25.c
-endif
-
-# Include MTD driver support
-
-DEPPATH += --dep-path mtd
-VPATH += :mtd
-
-endif
diff --git a/nuttx/drivers/mtd/at24xx.c b/nuttx/drivers/mtd/at24xx.c
deleted file mode 100644
index d157a9c47..000000000
--- a/nuttx/drivers/mtd/at24xx.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/************************************************************************************
- * drivers/mtd/at24xx.c
- * Driver for I2C-based at24cxx EEPROM(at24c32,at24c64,at24c128,at24c256)
- *
- * Copyright (C) 2011 Li Zhuoyi. All rights reserved.
- * Author: Li Zhuoyi <lzyy.cn@gmail.com>
- * History: 0.1 2011-08-20 initial version
- *
- * 2011-11-1 Added support for larger MTD block sizes: Hal Glenn <hglenn@2g-eng.com>
- *
- * Derived from drivers/mtd/m25px.c
- *
- * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ************************************************************************************/
-
-/************************************************************************************
- * Included Files
- ************************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/i2c.h>
-#include <nuttx/mtd.h>
-
-#ifdef CONFIG_MTD_AT24XX
-
-/************************************************************************************
- * Pre-processor Definitions
- ************************************************************************************/
-
-/* As a minimum, the size of the AT24 part and its 7-bit I2C address are required. */
-
-#ifndef CONFIG_AT24XX_SIZE
-# warning "Assuming AT24 size 64"
-# define CONFIG_AT24XX_SIZE 64
-#endif
-#ifndef CONFIG_AT24XX_ADDR
-# warning "Assuming AT24 address of 0x50"
-# define CONFIG_AT24XX_ADDR 0x50
-#endif
-
-/* Get the part configuration based on the size configuration */
-
-#if CONFIG_AT24XX_SIZE == 32
-# define AT24XX_NPAGES 128
-# define AT24XX_PAGESIZE 32
-#elif CONFIG_AT24XX_SIZE == 48
-# define AT24XX_NPAGES 192
-# define AT24XX_PAGESIZE 32
-#elif CONFIG_AT24XX_SIZE == 64
-# define AT24XX_NPAGES 256
-# define AT24XX_PAGESIZE 32
-#elif CONFIG_AT24XX_SIZE == 128
-# define AT24XX_NPAGES 256
-# define AT24XX_PAGESIZE 64
-#elif CONFIG_AT24XX_SIZE == 256
-# define AT24XX_NPAGES 512
-# define AT24XX_PAGESIZE 64
-#endif
-
-/* For applications where a file system is used on the AT24, the tiny page sizes
- * will result in very inefficient FLASH usage. In such cases, it is better if
- * blocks are comprised of "clusters" of pages so that the file system block
- * size is, say, 256 or 512 bytes. In any event, the block size *must* be an
- * even multiple of the pages.
- */
-
-#ifndef CONFIG_AT24XX_MTD_BLOCKSIZE
-# warning "Assuming driver block size is the same as the FLASH page size"
-# define CONFIG_AT24XX_MTD_BLOCKSIZE AT24XX_PAGESIZE
-#endif
-
-/************************************************************************************
- * Private Types
- ************************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s
- * must appear at the beginning of the definition so that you can freely
- * cast between pointers to struct mtd_dev_s and struct at24c_dev_s.
- */
-
-struct at24c_dev_s
-{
- struct mtd_dev_s mtd; /* MTD interface */
- FAR struct i2c_dev_s *dev; /* Saved I2C interface instance */
- uint8_t addr; /* I2C address */
- uint16_t pagesize; /* 32, 63 */
- uint16_t npages; /* 128, 256, 512, 1024 */
-};
-
-/************************************************************************************
- * Private Function Prototypes
- ************************************************************************************/
-
-/* MTD driver methods */
-
-static int at24c_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t at24c_bread(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR uint8_t *buf);
-static ssize_t at24c_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf);
-static ssize_t at24c_read(FAR struct mtd_dev_s *dev, off_t offset,
- size_t nbytes,FAR uint8_t *buffer);
-static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/************************************************************************************
- * Private Data
- ************************************************************************************/
-
-/* At present, only a signal AT24 part is supported. In this case, a statically
- * allocated state structure may be used.
- */
-
-static struct at24c_dev_s g_at24c;
-
-/************************************************************************************
- * Private Functions
- ************************************************************************************/
-
-static int at24c_eraseall(FAR struct at24c_dev_s *priv)
-{
- int startblock = 0;
- uint8_t buf[AT24XX_PAGESIZE + 2];
-
- memset(&buf[2],0xff,priv->pagesize);
- I2C_SETADDRESS(priv->dev,priv->addr,7);
- I2C_SETFREQUENCY(priv->dev,100000);
-
- for (startblock = 0; startblock < priv->npages; startblock++)
- {
- uint16_t offset = startblock * priv->pagesize;
- buf[1] = offset & 0xff;
- buf[0] = (offset >> 8) & 0xff;
-
- while (I2C_WRITE(priv->dev, buf, 2) < 0)
- {
- usleep(1000);
- }
- I2C_WRITE(priv->dev, buf, priv->pagesize + 2);
- }
-
- return OK;
-}
-
-/************************************************************************************
- * Name: at24c_erase
- ************************************************************************************/
-
-static int at24c_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
- /* EEprom need not erase */
-
- return (int)nblocks;
-}
-
-/************************************************************************************
- * Name: at24c_bread
- ************************************************************************************/
-
-static ssize_t at24c_bread(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR uint8_t *buffer)
-{
- FAR struct at24c_dev_s *priv = (FAR struct at24c_dev_s *)dev;
- size_t blocksleft;
-
-#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE
- startblock *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE);
- nblocks *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE);
-#endif
- blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- if (startblock >= priv->npages)
- {
- return 0;
- }
-
- if (startblock + nblocks > priv->npages)
- {
- nblocks = priv->npages - startblock;
- }
-
- I2C_SETADDRESS(priv->dev,priv->addr,7);
- I2C_SETFREQUENCY(priv->dev,100000);
-
- while (blocksleft-- > 0)
- {
- uint16_t offset = startblock * priv->pagesize;
- uint8_t buf[2];
- buf[1] = offset & 0xff;
- buf[0] = (offset >> 8) & 0xff;
-
- while (I2C_WRITE(priv->dev, buf, 2) < 0)
- {
- fvdbg("wait\n");
- usleep(1000);
- }
-
- I2C_READ(priv->dev, buffer, priv->pagesize);
- startblock++;
- buffer += priv->pagesize;
- }
-
-#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE
- return nblocks / (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE);
-#else
- return nblocks;
-#endif
-}
-
-/************************************************************************************
- * Name: at24c_bwrite
- *
- * Operates on MTD block's and translates to FLASH pages
- *
- ************************************************************************************/
-
-static ssize_t at24c_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
-{
- FAR struct at24c_dev_s *priv = (FAR struct at24c_dev_s *)dev;
- size_t blocksleft;
- uint8_t buf[AT24XX_PAGESIZE+2];
-
-#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE
- startblock *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE);
- nblocks *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE);
-#endif
- blocksleft = nblocks;
-
- if (startblock >= priv->npages)
- {
- return 0;
- }
-
- if (startblock + nblocks > priv->npages)
- {
- nblocks = priv->npages - startblock;
- }
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
- I2C_SETADDRESS(priv->dev, priv->addr, 7);
- I2C_SETFREQUENCY(priv->dev, 100000);
-
- while (blocksleft-- > 0)
- {
- uint16_t offset = startblock * priv->pagesize;
- while (I2C_WRITE(priv->dev, (uint8_t *)&offset, 2) < 0)
- {
- fvdbg("wait\n");
- usleep(1000);
- }
-
- buf[1] = offset & 0xff;
- buf[0] = (offset >> 8) & 0xff;
- memcpy(&buf[2], buffer, priv->pagesize);
-
- I2C_WRITE(priv->dev, buf, priv->pagesize + 2);
- startblock++;
- buffer += priv->pagesize;
- }
-
-#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE
- return nblocks / (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE);
-#else
- return nblocks;
-#endif
-}
-
-/************************************************************************************
- * Name: at24c_ioctl
- ************************************************************************************/
-
-static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct at24c_dev_s *priv = (FAR struct at24c_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- fvdbg("cmd: %d \n", cmd);
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- *
- * blocksize:
- * May be user defined. The block size for the at24XX devices may be
- * larger than the page size in order to better support file systems.
- * The read and write functions translate BLOCKS to pages for the
- * small flash devices
- * erasesize:
- * It has to be at least as big as the blocksize, bigger serves no
- * purpose.
- * neraseblocks
- * Note that the device size is in kilobits and must be scaled by
- * 1024 / 8
- */
-
-#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE
- geo->blocksize = CONFIG_AT24XX_MTD_BLOCKSIZE;
- geo->erasesize = CONFIG_AT24XX_MTD_BLOCKSIZE;
- geo->neraseblocks = (CONFIG_AT24XX_SIZE * 1024 / 8) / CONFIG_AT24XX_MTD_BLOCKSIZE;
-#else
- geo->blocksize = priv->pagesize;
- geo->erasesize = priv->pagesize;
- geo->neraseblocks = priv->npages;
-#endif
- ret = OK;
-
- fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
- geo->blocksize, geo->erasesize, geo->neraseblocks);
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- ret=at24c_eraseall(priv);
- break;
-
- case MTDIOC_XIPBASE:
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- return ret;
-}
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: at24c_initialize
- *
- * Description:
- * Create an initialize MTD device instance. MTD devices are not registered
- * in the file system, but are created as instances that can be bound to
- * other functions (such as a block or character driver front end).
- *
- ************************************************************************************/
-
-FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_dev_s *dev)
-{
- FAR struct at24c_dev_s *priv;
-
- fvdbg("dev: %p\n", dev);
-
- /* Allocate a state structure (we allocate the structure instead of using
- * a fixed, static allocation so that we can handle multiple FLASH devices.
- * The current implementation would handle only one FLASH part per I2C
- * device (only because of the SPIDEV_FLASH definition) and so would have
- * to be extended to handle multiple FLASH parts on the same I2C bus.
- */
-
- priv = &g_at24c;
- if (priv)
- {
- /* Initialize the allocated structure */
-
- priv->addr = CONFIG_AT24XX_ADDR;
- priv->pagesize = AT24XX_PAGESIZE;
- priv->npages = AT24XX_NPAGES;
-
- priv->mtd.erase = at24c_erase;
- priv->mtd.bread = at24c_bread;
- priv->mtd.bwrite = at24c_bwrite;
- priv->mtd.ioctl = at24c_ioctl;
- priv->dev = dev;
- }
-
- /* Return the implementation-specific state structure as the MTD device */
-
- fvdbg("Return %p\n", priv);
- return (FAR struct mtd_dev_s *)priv;
-}
-
-#endif
diff --git a/nuttx/drivers/mtd/at25.c b/nuttx/drivers/mtd/at25.c
deleted file mode 100644
index c58b16122..000000000
--- a/nuttx/drivers/mtd/at25.c
+++ /dev/null
@@ -1,710 +0,0 @@
-/************************************************************************************
- * drivers/mtd/at25.c
- * Driver for SPI-based AT25DF321 (32Mbit) flash.
- *
- * Copyright (C) 2009-2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- * Petteri Aimonen <jpa@nx.mail.kapsi.fi>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ************************************************************************************/
-
-/************************************************************************************
- * Included Files
- ************************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/spi.h>
-#include <nuttx/mtd.h>
-
-/************************************************************************************
- * Pre-processor Definitions
- ************************************************************************************/
-
-#ifndef CONFIG_AT25_SPIMODE
-# define CONFIG_AT25_SPIMODE SPIDEV_MODE0
-#endif
-
-/* AT25 Registers *******************************************************************/
-/* Indentification register values */
-
-#define AT25_MANUFACTURER 0x1F
-#define AT25_AT25DF321_TYPE 0x47 /* 32 M-bit */
-
-/* AT25DF321 capacity is 4,194,304 bytes:
- * (64 sectors) * (65,536 bytes per sector)
- * (16384 pages) * (256 bytes per page)
- */
-
-#define AT25_AT25DF321_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4096 */
-#define AT25_AT25DF321_NSECTORS 1024
-#define AT25_AT25DF321_PAGE_SHIFT 9 /* Page size 1 << 9 = 512 */
-#define AT25_AT25DF321_NPAGES 8192
-
-/* Instructions */
-/* Command Value N Description Addr Dummy Data */
-#define AT25_WREN 0x06 /* 1 Write Enable 0 0 0 */
-#define AT25_WRDI 0x04 /* 1 Write Disable 0 0 0 */
-#define AT25_RDID 0x9f /* 1 Read Identification 0 0 1-3 */
-#define AT25_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */
-#define AT25_WRSR 0x01 /* 1 Write Status Register 0 0 1 */
-#define AT25_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */
-#define AT25_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */
-#define AT25_PP 0x02 /* 1 Page Program 3 0 1-256 */
-#define AT25_SE 0x20 /* 1 Sector Erase 3 0 0 */
-#define AT25_BE 0xc7 /* 1 Bulk Erase 0 0 0 */
-#define AT25_DP 0xb9 /* 2 Deep power down 0 0 0 */
-#define AT25_RES 0xab /* 2 Read Electronic Signature 0 3 >=1 */
-
-/* Status register bit definitions */
-
-#define AT25_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */
-#define AT25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */
-#define AT25_SR_EPE (1 << 5) /* Bit 5: Erase/program error */
-#define AT25_SR_UNPROT 0x00 /* Global unprotect command */
-
-#define AT25_DUMMY 0xa5
-
-/************************************************************************************
- * Private Types
- ************************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s
- * must appear at the beginning of the definition so that you can freely
- * cast between pointers to struct mtd_dev_s and struct at25_dev_s.
- */
-
-struct at25_dev_s
-{
- struct mtd_dev_s mtd; /* MTD interface */
- FAR struct spi_dev_s *dev; /* Saved SPI interface instance */
- uint8_t sectorshift; /* 16 or 18 */
- uint8_t pageshift; /* 8 */
- uint16_t nsectors; /* 128 or 64 */
- uint32_t npages; /* 32,768 or 65,536 */
-};
-
-/************************************************************************************
- * Private Function Prototypes
- ************************************************************************************/
-
-/* Helpers */
-
-static void at25_lock(FAR struct spi_dev_s *dev);
-static inline void at25_unlock(FAR struct spi_dev_s *dev);
-static inline int at25_readid(struct at25_dev_s *priv);
-static void at25_waitwritecomplete(struct at25_dev_s *priv);
-static void at25_writeenable(struct at25_dev_s *priv);
-static inline void at25_sectorerase(struct at25_dev_s *priv, off_t offset);
-static inline int at25_bulkerase(struct at25_dev_s *priv);
-static inline void at25_pagewrite(struct at25_dev_s *priv, FAR const uint8_t *buffer,
- off_t offset);
-
-/* MTD driver methods */
-
-static int at25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t at25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR uint8_t *buf);
-static ssize_t at25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf);
-static ssize_t at25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer);
-static int at25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/************************************************************************************
- * Private Data
- ************************************************************************************/
-
-/************************************************************************************
- * Private Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: at25_lock
- ************************************************************************************/
-
-static void at25_lock(FAR struct spi_dev_s *dev)
-{
- /* On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
- * transfers. The bus should be locked before the chip is selected.
- *
- * This is a blocking call and will not return until we have exclusiv access to
- * the SPI buss. We will retain that exclusive access until the bus is unlocked.
- */
-
- (void)SPI_LOCK(dev, true);
-
- /* After locking the SPI bus, the we also need call the setfrequency, setbits, and
- * setmode methods to make sure that the SPI is properly configured for the device.
- * If the SPI buss is being shared, then it may have been left in an incompatible
- * state.
- */
-
- SPI_SETMODE(dev, CONFIG_AT25_SPIMODE);
- SPI_SETBITS(dev, 8);
- (void)SPI_SETFREQUENCY(dev, 20000000);
-}
-
-/************************************************************************************
- * Name: at25_unlock
- ************************************************************************************/
-
-static inline void at25_unlock(FAR struct spi_dev_s *dev)
-{
- (void)SPI_LOCK(dev, false);
-}
-
-/************************************************************************************
- * Name: at25_readid
- ************************************************************************************/
-
-static inline int at25_readid(struct at25_dev_s *priv)
-{
- uint16_t manufacturer;
- uint16_t memory;
- uint16_t version;
-
- fvdbg("priv: %p\n", priv);
-
- /* Lock the SPI bus, configure the bus, and select this FLASH part. */
-
- at25_lock(priv->dev);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Read ID (RDID)" command and read the first three ID bytes */
-
- (void)SPI_SEND(priv->dev, AT25_RDID);
- manufacturer = SPI_SEND(priv->dev, AT25_DUMMY);
- memory = SPI_SEND(priv->dev, AT25_DUMMY);
-
- /* Deselect the FLASH and unlock the bus */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- at25_unlock(priv->dev);
-
- fvdbg("manufacturer: %02x memory: %02x\n",
- manufacturer, memory);
-
- /* Check for a valid manufacturer and memory type */
-
- if (manufacturer == AT25_MANUFACTURER && memory == AT25_AT25DF321_TYPE)
- {
- priv->sectorshift = AT25_AT25DF321_SECTOR_SHIFT;
- priv->nsectors = AT25_AT25DF321_NSECTORS;
- priv->pageshift = AT25_AT25DF321_PAGE_SHIFT;
- priv->npages = AT25_AT25DF321_NPAGES;
- return OK;
- }
-
- return -ENODEV;
-}
-
-/************************************************************************************
- * Name: at25_waitwritecomplete
- ************************************************************************************/
-
-static void at25_waitwritecomplete(struct at25_dev_s *priv)
-{
- uint8_t status;
-
- /* Are we the only device on the bus? */
-
-#ifdef CONFIG_SPI_OWNBUS
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->dev, AT25_RDSR);
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->dev, AT25_DUMMY);
- }
- while ((status & AT25_SR_WIP) != 0);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
-#else
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->dev, AT25_RDSR);
-
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->dev, AT25_DUMMY);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
- /* Given that writing could take up to few tens of milliseconds, and erasing
- * could take more. The following short delay in the "busy" case will allow
- * other peripherals to access the SPI bus.
- */
-
- if ((status & AT25_SR_WIP) != 0)
- {
- at25_unlock(priv->dev);
- usleep(10000);
- at25_lock(priv->dev);
- }
- }
- while ((status & AT25_SR_WIP) != 0);
-#endif
-
- if (status & AT25_SR_EPE)
- {
- fdbg("Write error, status: 0x%02x\n", status);
- }
-
- fvdbg("Complete, status: 0x%02x\n", status);
-}
-
-/************************************************************************************
- * Name: at25_writeenable
- ************************************************************************************/
-
-static void at25_writeenable(struct at25_dev_s *priv)
-{
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
- (void)SPI_SEND(priv->dev, AT25_WREN);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Enabled\n");
-}
-
-/************************************************************************************
- * Name: at25_sectorerase
- ************************************************************************************/
-
-static inline void at25_sectorerase(struct at25_dev_s *priv, off_t sector)
-{
- off_t offset = sector << priv->sectorshift;
-
- fvdbg("sector: %08lx\n", (long)sector);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- at25_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- at25_writeenable(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Sector Erase (SE)" instruction */
-
- (void)SPI_SEND(priv->dev, AT25_SE);
-
- /* Send the sector offset high byte first. For all of the supported
- * parts, the sector number is completely contained in the first byte
- * and the values used in the following two bytes don't really matter.
- */
-
- (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, offset & 0xff);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Erased\n");
-}
-
-/************************************************************************************
- * Name: at25_bulkerase
- ************************************************************************************/
-
-static inline int at25_bulkerase(struct at25_dev_s *priv)
-{
- fvdbg("priv: %p\n", priv);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- at25_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- at25_writeenable(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Bulk Erase (BE)" instruction */
-
- (void)SPI_SEND(priv->dev, AT25_BE);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Return: OK\n");
- return OK;
-}
-
-/************************************************************************************
- * Name: at25_pagewrite
- ************************************************************************************/
-
-static inline void at25_pagewrite(struct at25_dev_s *priv, FAR const uint8_t *buffer,
- off_t page)
-{
- off_t offset = page << 8;
-
- fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- at25_waitwritecomplete(priv);
-
- /* Enable the write access to the FLASH */
-
- at25_writeenable(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Page Program (PP)" command */
-
- (void)SPI_SEND(priv->dev, AT25_PP);
-
- /* Send the page offset high byte first. */
-
- (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, offset & 0xff);
-
- /* Then write the specified number of bytes */
-
- SPI_SNDBLOCK(priv->dev, buffer, 256);
-
- /* Deselect the FLASH: Chip Select high */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Written\n");
-}
-
-/************************************************************************************
- * Name: at25_erase
- ************************************************************************************/
-
-static int at25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
- FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev;
- size_t blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock access to the SPI bus until we complete the erase */
-
- at25_lock(priv->dev);
- while (blocksleft-- > 0)
- {
- /* Erase each sector */
-
- at25_sectorerase(priv, startblock);
- startblock++;
- }
-
- at25_unlock(priv->dev);
- return (int)nblocks;
-}
-
-/************************************************************************************
- * Name: at25_bread
- ************************************************************************************/
-
-static ssize_t at25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buffer)
-{
- FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev;
- ssize_t nbytes;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* On this device, we can handle the block read just like the byte-oriented read */
-
- nbytes = at25_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer);
- if (nbytes > 0)
- {
- return nbytes >> priv->pageshift;
- }
-
- return (int)nbytes;
-}
-
-/************************************************************************************
- * Name: at25_bwrite
- ************************************************************************************/
-
-static ssize_t at25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
-{
- FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev;
- size_t blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock the SPI bus and write each page to FLASH */
-
- at25_lock(priv->dev);
- while (blocksleft-- > 0)
- {
- at25_pagewrite(priv, buffer, startblock * 2);
- at25_pagewrite(priv, buffer + 256, startblock * 2 + 1);
- buffer += 1 << priv->pageshift;
- startblock++;
- }
-
- at25_unlock(priv->dev);
- return nblocks;
-}
-
-/************************************************************************************
- * Name: at25_read
- ************************************************************************************/
-
-static ssize_t at25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
-{
- FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev;
-
- fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- at25_waitwritecomplete(priv);
-
- /* Lock the SPI bus and select this FLASH part */
-
- at25_lock(priv->dev);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read from Memory " instruction */
-
- (void)SPI_SEND(priv->dev, AT25_READ);
-
- /* Send the page offset high byte first. */
-
- (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, offset & 0xff);
-
- /* Then read all of the requested bytes */
-
- SPI_RECVBLOCK(priv->dev, buffer, nbytes);
-
- /* Deselect the FLASH and unlock the SPI bus */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- at25_unlock(priv->dev);
-
- fvdbg("return nbytes: %d\n", (int)nbytes);
- return nbytes;
-}
-
-/************************************************************************************
- * Name: at25_ioctl
- ************************************************************************************/
-
-static int at25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- fvdbg("cmd: %d \n", cmd);
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- */
-
- geo->blocksize = (1 << priv->pageshift);
- geo->erasesize = (1 << priv->sectorshift);
- geo->neraseblocks = priv->nsectors;
- ret = OK;
-
- fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
- geo->blocksize, geo->erasesize, geo->neraseblocks);
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- {
- /* Erase the entire device */
-
- at25_lock(priv->dev);
- ret = at25_bulkerase(priv);
- at25_unlock(priv->dev);
- }
- break;
-
- case MTDIOC_XIPBASE:
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- fvdbg("return %d\n", ret);
- return ret;
-}
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: at25_initialize
- *
- * Description:
- * Create an initialize MTD device instance. MTD devices are not registered
- * in the file system, but are created as instances that can be bound to
- * other functions (such as a block or character driver front end).
- *
- ************************************************************************************/
-
-FAR struct mtd_dev_s *at25_initialize(FAR struct spi_dev_s *dev)
-{
- FAR struct at25_dev_s *priv;
- int ret;
-
- fvdbg("dev: %p\n", dev);
-
- /* Allocate a state structure (we allocate the structure instead of using
- * a fixed, static allocation so that we can handle multiple FLASH devices.
- * The current implementation would handle only one FLASH part per SPI
- * device (only because of the SPIDEV_FLASH definition) and so would have
- * to be extended to handle multiple FLASH parts on the same SPI bus.
- */
-
- priv = (FAR struct at25_dev_s *)kmalloc(sizeof(struct at25_dev_s));
- if (priv)
- {
- /* Initialize the allocated structure */
-
- priv->mtd.erase = at25_erase;
- priv->mtd.bread = at25_bread;
- priv->mtd.bwrite = at25_bwrite;
- priv->mtd.read = at25_read;
- priv->mtd.ioctl = at25_ioctl;
- priv->dev = dev;
-
- /* Deselect the FLASH */
-
- SPI_SELECT(dev, SPIDEV_FLASH, false);
-
- /* Identify the FLASH chip and get its capacity */
-
- ret = at25_readid(priv);
- if (ret != OK)
- {
- /* Unrecognized! Discard all of that work we just did and return NULL */
-
- fdbg("Unrecognized\n");
- kfree(priv);
- priv = NULL;
- }
- else
- {
- /* Unprotect all sectors */
-
- at25_writeenable(priv);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
- (void)SPI_SEND(priv->dev, AT25_WRSR);
- (void)SPI_SEND(priv->dev, AT25_SR_UNPROT);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- }
- }
-
- /* Return the implementation-specific state structure as the MTD device */
-
- fvdbg("Return %p\n", priv);
- return (FAR struct mtd_dev_s *)priv;
-}
diff --git a/nuttx/drivers/mtd/at45db.c b/nuttx/drivers/mtd/at45db.c
deleted file mode 100644
index f3c0c72c1..000000000
--- a/nuttx/drivers/mtd/at45db.c
+++ /dev/null
@@ -1,899 +0,0 @@
-/************************************************************************************
- * drivers/mtd/at45db.c
- * Driver for SPI-based AT45DB161D (16Mbit)
- *
- * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ************************************************************************************/
-
-/* Ordering Code Detail:
- *
- * AT 45DB 16 1 D – SS U
- * | | | | | | `- Device grade
- * | | | | | `- Package Option
- * | | | | `- Device revision
- * | | | `- Interface: 1=serial
- * | | `- Capacity: 16=16Mbit
- * | `- Product family
- * `- Atmel designator
- */
-
-/************************************************************************************
- * Included Files
- ************************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/arch.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/spi.h>
-#include <nuttx/mtd.h>
-
-/************************************************************************************
- * Pre-processor Definitions
- ************************************************************************************/
-
-/* Configuration ********************************************************************/
-/* CONFIG_AT45DB_PREWAIT enables higher performance write logic: We leave the chip
- * busy after write and erase operations. This improves write and erase performance
- * because we do not have to wait as long between transactions (other processing can
- * occur while the chip is busy) but means that the chip must stay powered:
- */
-
-#if defined(CONFIG_AT45DB_PWRSAVE) && defined(CONFIG_AT45DB_PREWAIT)
-# error "Both CONFIG_AT45DB_PWRSAVE and CONFIG_AT45DB_PREWAIT are defined"
-#endif
-
-/* If the user has provided no frequency, use 1MHz */
-
-#ifndef CONFIG_AT45DB_FREQUENCY
-# define CONFIG_AT45DB_FREQUENCY 1000000
-#endif
-
-/* SPI Commands *********************************************************************/
-
-/* Read commands */
-
-#define AT45DB_RDMN 0xd2 /* Main Memory Page Read */
-#define AT45DB_RDARRY 0xe8 /* Continuous Array Read (Legacy Command) */
-#define AT45DB_RDARRAYLF 0x03 /* Continuous Array Read (Low Frequency) */
-#define AT45DB_RDARRAYHF 0x0b /* Continuous Array Read (High Frequency) */
-#define AT45DB_RDBF1LF 0xd1 /* Buffer 1 Read (Low Frequency) */
-#define AT45DB_RDBF2LF 0xd3 /* Buffer 2 Read (Low Frequency) */
-#define AT45DB_RDBF1 0xd4 /* Buffer 1 Read */
-#define AT45DB_RDBF2 0xd6 /* Buffer 2 Read */
-
-/* Program and Erase Commands */
-
-#define AT45DB_WRBF1 0x84 /* Buffer 1 Write */
-#define AT45DB_WRBF2 0x87 /* Buffer 2 Write */
-#define AT45DB_BF1TOMNE 0x83 /* Buffer 1 to Main Memory Page Program with Built-in Erase */
-#define AT45DB_BF2TOMNE 0x86 /* Buffer 2 to Main Memory Page Program with Built-in Erase */
-#define AT45DB_BF1TOMN 0x88 /* Buffer 1 to Main Memory Page Program without Built-in Erase */
-#define AT45DB_BF2TOMN 0x89 /* Buffer 2 to Main Memory Page Program without Built-in Erase */
-#define AT45DB_PGERASE 0x81 /* Page Erase */
-#define AT45DB_BLKERASE 0x50 /* Block Erase */
-#define AT45DB_SECTERASE 0x7c /* Sector Erase */
-#define AT45DB_CHIPERASE1 0xc7 /* Chip Erase - byte 1 */
-# define AT45DB_CHIPERASE2 0x94 /* Chip Erase - byte 2 */
-# define AT45DB_CHIPERASE3 0x80 /* Chip Erase - byte 3 */
-# define AT45DB_CHIPERASE4 0x9a /* Chip Erase - byte 4 */
-#define AT45DB_MNTHRUBF1 0x82 /* Main Memory Page Program Through Buffer 1 */
-#define AT45DB_MNTHRUBF2 0x85 /* Main Memory Page Program Through Buffer 2 */
-
-/* Protection and Security Commands */
-
-#define AT45DB_ENABPROT1 0x3d /* Enable Sector Protection - byte 1 */
-# define AT45DB_ENABPROT2 0x2a /* Enable Sector Protection - byte 2 */
-# define AT45DB_ENABPROT3 0x7f /* Enable Sector Protection - byte 3 */
-# define AT45DB_ENABPROT4 0xa9 /* Enable Sector Protection - byte 4 */
-#define AT45DB_DISABPROT1 0x3d /* Disable Sector Protection - byte 1 */
-# define AT45DB_DISABPROT2 0x2a /* Disable Sector Protection - byte 2 */
-# define AT45DB_DISABPROT3 0x7f /* Disable Sector Protection - byte 3 */
-# define AT45DB_DISABPROT4 0x9a /* Disable Sector Protection - byte 4 */
-#define AT45DB_ERASEPROT1 0x3d /* Erase Sector Protection Register - byte 1 */
-# define AT45DB_ERASEPROT2 0x2a /* Erase Sector Protection Register - byte 2 */
-# define AT45DB_ERASEPROT3 0x7f /* Erase Sector Protection Register - byte 3 */
-# define AT45DB_ERASEPROT4 0xcf /* Erase Sector Protection Register - byte 4 */
-#define AT45DB_PROGPROT1 0x3d /* Program Sector Protection Register - byte 1 */
-# define AT45DB_PROGPROT2 0x2a /* Program Sector Protection Register - byte 2 */
-# define AT45DB_PROGPROT3 0x7f /* Program Sector Protection Register - byte 3 */
-# define AT45DB_PROGPROT4 0xfc /* Program Sector Protection Register - byte 4 */
-#define AT45DB_RDPROT 0x32 /* Read Sector Protection Register */
-#define AT45DB_LOCKDOWN1 0x3d /* Sector Lockdown - byte 1 */
-# define AT45DB_LOCKDOWN2 0x2a /* Sector Lockdown - byte 2 */
-# define AT45DB_LOCKDOWN3 0x7f /* Sector Lockdown - byte 3 */
-# define AT45DB_LOCKDOWN4 0x30 /* Sector Lockdown - byte 4 */
-#define AT45DB_RDLOCKDOWN 0x35 /* Read Sector Lockdown Register */
-#define AT45DB_PROGSEC1 0x9b /* Program Security Register - byte 1 */
-# define AT45DB_PROGSEC2 0x00 /* Program Security Register - byte 2 */
-# define AT45DB_PROGSEC3 0x00 /* Program Security Register - byte 3 */
-# define AT45DB_PROGSEC4 0x00 /* Program Security Register - byte 4 */
-#define AT45DB_RDSEC 0x77 /* Read Security Register */
-
-/* Additional commands */
-
-#define AT45DB_MNTOBF1XFR 0x53 /* Main Memory Page to Buffer 1 Transfer */
-#define AT45DB_MNTOBF2XFR 0x55 /* Main Memory Page to Buffer 2 Transfer */
-#define AT45DB_MNBF1CMP 0x60 /* Main Memory Page to Buffer 1 Compare */
-#define AT45DB_MNBF2CMP 0x61 /* Main Memory Page to Buffer 2 Compare */
-#define AT45DB_AUTOWRBF1 0x58 /* Auto Page Rewrite through Buffer 1 */
-#define AT45DB_AUTOWRBF2 0x59 /* Auto Page Rewrite through Buffer 2 */
-#define AT45DB_PWRDOWN 0xb9 /* Deep Power-down */
-#define AT45DB_RESUME 0xab /* Resume from Deep Power-down */
-#define AT45DB_RDSR 0xd7 /* Status Register Read */
-#define AT45DB_RDDEVID 0x9f /* Manufacturer and Device ID Read */
-
-#define AT45DB_MANUFACTURER 0x1f /* Manufacturer ID: Atmel */
-#define AT45DB_DEVID1_CAPMSK 0x1f /* Bits 0-4: Capacity */
-#define AT45DB_DEVID1_1MBIT 0x02 /* xxx0 0010 = 1Mbit AT45DB011 */
-#define AT45DB_DEVID1_2MBIT 0x03 /* xxx0 0012 = 2Mbit AT45DB021 */
-#define AT45DB_DEVID1_4MBIT 0x04 /* xxx0 0100 = 4Mbit AT45DB041 */
-#define AT45DB_DEVID1_8MBIT 0x05 /* xxx0 0101 = 8Mbit AT45DB081 */
-#define AT45DB_DEVID1_16MBIT 0x06 /* xxx0 0110 = 16Mbit AT45DB161 */
-#define AT45DB_DEVID1_32MBIT 0x07 /* xxx0 0111 = 32Mbit AT45DB321 */
-#define AT45DB_DEVID1_64MBIT 0x08 /* xxx0 1000 = 32Mbit AT45DB641 */
-#define AT45DB_DEVID1_FAMMSK 0xe0 /* Bits 5-7: Family */
-#define AT45DB_DEVID1_DFLASH 0x20 /* 001x xxxx = Dataflash */
-#define AT45DB_DEVID1_AT26DF 0x40 /* 010x xxxx = AT26DFxxx series (Not supported) */
-#define AT45DB_DEVID2_VERMSK 0x1f /* Bits 0-4: MLC mask */
-#define AT45DB_DEVID2_MLCMSK 0xe0 /* Bits 5-7: MLC mask */
-
-/* Status register bit definitions */
-
-#define AT45DB_SR_RDY (1 << 7) /* Bit 7: RDY/ Not BUSY */
-#define AT45DB_SR_COMP (1 << 6) /* Bit 6: COMP */
-#define AT45DB_SR_PROTECT (1 << 1) /* Bit 1: PROTECT */
-#define AT45DB_SR_PGSIZE (1 << 0) /* Bit 0: PAGE_SIZE */
-
-/* 1 Block = 16 pages; 1 sector = 256 pages */
-
-#define PG_PER_BLOCK (16)
-#define PG_PER_SECTOR (256)
-
-/************************************************************************************
- * Private Types
- ************************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s
- * must appear at the beginning of the definition so that you can freely
- * cast between pointers to struct mtd_dev_s and struct at45db_dev_s.
- */
-
-struct at45db_dev_s
-{
- struct mtd_dev_s mtd; /* MTD interface */
- FAR struct spi_dev_s *spi; /* Saved SPI interface instance */
- uint8_t pageshift; /* log2 of the page size (eg. 1 << 9 = 512) */
- uint32_t npages; /* Number of pages in the device */
-};
-
-/************************************************************************************
- * Private Function Prototypes
- ************************************************************************************/
-
-/* Lock and per-transaction configuration */
-
-static void at45db_lock(struct at45db_dev_s *priv);
-static inline void at45db_unlock(struct at45db_dev_s *priv);
-
-/* Power management */
-
-#ifdef CONFIG_AT45DB_PWRSAVE
-static void at45db_pwrdown(struct at45db_dev_s *priv);
-static void at45db_resume(struct at45db_dev_s *priv);
-#else
-# define at45db_pwrdown(priv)
-# define at45db_resume(priv)
-#endif
-
-/* Low-level AT45DB Helpers */
-
-static inline int at45db_rdid(struct at45db_dev_s *priv);
-static inline uint8_t at45db_rdsr(struct at45db_dev_s *priv);
-static uint8_t at45db_waitbusy(struct at45db_dev_s *priv);
-static inline void at45db_pgerase(struct at45db_dev_s *priv, off_t offset);
-static inline int at32db_chiperase(struct at45db_dev_s *priv);
-static inline void at45db_pgwrite(struct at45db_dev_s *priv, FAR const uint8_t *buffer,
- off_t offset);
-
-/* MTD driver methods */
-
-static int at45db_erase(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks);
-static ssize_t at45db_bread(FAR struct mtd_dev_s *mtd, off_t startblock,
- size_t nblocks, FAR uint8_t *buf);
-static ssize_t at45db_bwrite(FAR struct mtd_dev_s *mtd, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf);
-static ssize_t at45db_read(FAR struct mtd_dev_s *mtd, off_t offset, size_t nbytes,
- FAR uint8_t *buffer);
-static int at45db_ioctl(FAR struct mtd_dev_s *mtd, int cmd, unsigned long arg);
-
-/************************************************************************************
- * Private Data
- ************************************************************************************/
-
-/* Chip erase sequence */
-
-#define CHIP_ERASE_SIZE 4
-static const uint8_t g_chiperase[CHIP_ERASE_SIZE] = {0xc7, 0x94, 0x80, 0x9a};
-
-/* Sequence to program the device to binary page sizes{256, 512, 1024} */
-
-#define BINPGSIZE_SIZE 4
-static const uint8_t g_binpgsize[BINPGSIZE_SIZE] = {0x3d, 0x2a, 0x80, 0xa6};
-
-/************************************************************************************
- * Private Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: at45db_lock
- ************************************************************************************/
-
-static void at45db_lock(struct at45db_dev_s *priv)
-{
- /* On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
- * transfers. The bus should be locked before the chip is selected.
- *
- * This is a blocking call and will not return until we have exclusiv access to
- * the SPI buss. We will retain that exclusive access until the bus is unlocked.
- */
-
- (void)SPI_LOCK(priv->spi, true);
-
- /* After locking the SPI bus, the we also need call the setfrequency, setbits, and
- * setmode methods to make sure that the SPI is properly configured for the device.
- * If the SPI buss is being shared, then it may have been left in an incompatible
- * state.
- */
-
- SPI_SETMODE(priv->spi, SPIDEV_MODE0);
- SPI_SETBITS(priv->spi, 8);
- (void)SPI_SETFREQUENCY(priv->spi, CONFIG_AT45DB_FREQUENCY);
-}
-
-/************************************************************************************
- * Name: at45db_unlock
- ************************************************************************************/
-
-static inline void at45db_unlock(struct at45db_dev_s *priv)
-{
- (void)SPI_LOCK(priv->spi, false);
-}
-
-/************************************************************************************
- * Name: at45db_pwrdown
- ************************************************************************************/
-
-#ifdef CONFIG_AT45DB_PWRSAVE
-static void at45db_pwrdown(struct at45db_dev_s *priv)
-{
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SEND(priv->spi, AT45DB_PWRDOWN);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-}
-#endif
-
-/************************************************************************************
- * Name: at45db_resume
- ************************************************************************************/
-
-#ifdef CONFIG_AT45DB_PWRSAVE
-static void at45db_resume(struct at45db_dev_s *priv)
-{
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SEND(priv->spi, AT45DB_RESUME);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
- up_udelay(50);
-}
-#endif
-
-/************************************************************************************
- * Name: at45db_rdid
- ************************************************************************************/
-
-static inline int at45db_rdid(struct at45db_dev_s *priv)
-{
- uint8_t capacity;
- uint8_t devid[3];
-
- fvdbg("priv: %p\n", priv);
-
- /* Configure the bus, and select this FLASH part. (The caller should alread have
- * loced the bus for exclusive access)
- */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send the " Manufacturer and Device ID Read" command and read the next three
- * ID bytes from the FLASH.
- */
-
- (void)SPI_SEND(priv->spi, AT45DB_RDDEVID);
- SPI_RECVBLOCK(priv->spi, devid, 3);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
- fvdbg("manufacturer: %02x devid1: %02x devid2: %02x\n",
- devid[0], devid[1], devid[2]);
-
- /* Check for a valid manufacturer and memory family */
-
- if (devid[0] == AT45DB_MANUFACTURER &&
- (devid[1] & AT45DB_DEVID1_FAMMSK) == AT45DB_DEVID1_DFLASH)
- {
- /* Okay.. is it a FLASH capacity that we understand? */
-
- capacity = devid[1] & AT45DB_DEVID1_CAPMSK;
- switch (capacity)
- {
- case AT45DB_DEVID1_1MBIT:
- /* Save the FLASH geometry for the 16Mbit AT45DB011 */
-
- priv->pageshift = 8; /* Page size = 256 bytes */
- priv->npages = 512; /* 512 pages */
- return OK;
-
- case AT45DB_DEVID1_2MBIT:
- /* Save the FLASH geometry for the 16Mbit AT45DB021 */
-
- priv->pageshift = 8; /* Page size = 256/264 bytes */
- priv->npages = 1024; /* 1024 pages */
- return OK;
-
- case AT45DB_DEVID1_4MBIT:
- /* Save the FLASH geometry for the 16Mbit AT45DB041 */
-
- priv->pageshift = 8; /* Page size = 256/264 bytes */
- priv->npages = 2048; /* 2048 pages */
- return OK;
-
- case AT45DB_DEVID1_8MBIT:
- /* Save the FLASH geometry for the 16Mbit AT45DB081 */
-
- priv->pageshift = 8; /* Page size = 256/264 bytes */
- priv->npages = 4096; /* 4096 pages */
- return OK;
-
- case AT45DB_DEVID1_16MBIT:
- /* Save the FLASH geometry for the 16Mbit AT45DB161 */
-
- priv->pageshift = 9; /* Page size = 512/528 bytes */
- priv->npages = 4096; /* 4096 pages */
- return OK;
-
- case AT45DB_DEVID1_32MBIT:
- /* Save the FLASH geometry for the 16Mbit AT45DB321 */
-
- priv->pageshift = 9; /* Page size = 512/528 bytes */
- priv->npages = 8192; /* 8192 pages */
- return OK;
-
- case AT45DB_DEVID1_64MBIT:
- /* Save the FLASH geometry for the 16Mbit AT45DB321 */
-
- priv->pageshift = 10; /* Page size = 1024/1056 bytes */
- priv->npages = 8192; /* 8192 pages */
- return OK;
-
- default:
- return -ENODEV;
- }
- }
-
- return -ENODEV;
-}
-
-/************************************************************************************
- * Name: at45db_rdsr
- ************************************************************************************/
-
-static inline uint8_t at45db_rdsr(struct at45db_dev_s *priv)
-{
- uint8_t retval;
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SEND(priv->spi, AT45DB_RDSR);
- retval = SPI_SEND(priv->spi, 0xff);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
- return retval;
-}
-
-/************************************************************************************
- * Name: at45db_waitbusy
- ************************************************************************************/
-
-static uint8_t at45db_waitbusy(struct at45db_dev_s *priv)
-{
- uint8_t sr;
-
- /* Poll the device, waiting for it to report that it is ready */
-
- do
- {
- up_udelay(10);
- sr = (uint8_t)at45db_rdsr(priv);
- }
- while ((sr & AT45DB_SR_RDY) == 0);
- return sr;
-}
-
-/************************************************************************************
- * Name: at45db_pgerase
- ************************************************************************************/
-
-static inline void at45db_pgerase(struct at45db_dev_s *priv, off_t sector)
-{
- uint8_t erasecmd[4];
- off_t offset = sector << priv->pageshift;
-
- fvdbg("sector: %08lx\n", (long)sector);
-
- /* Higher performance write logic: We leave the chip busy after write and erase
- * operations. This improves write and erase performance because we do not have
- * to wait as long between transactions (other processing can occur while the chip
- * is busy) but means that the chip must stay powered and that we must check if
- * the chip is still busy on each entry point.
- */
-
-#ifdef CONFIG_AT45DB_PREWAIT
- at45db_waitbusy(priv);
-#endif
-
- /* "The Page Erase command can be used to individually erase any page in the main
- * memory array allowing the Buffer to Main Memory Page Program to be utilized at a
- * later time. ... To perform a page erase in the binary page size ..., the
- * opcode 81H must be loaded into the device, followed by three address bytes
- * ... When a low-to-high transition occurs on the CS pin, the part will erase the
- * selected page (the erased state is a logical 1). ... the status register and the
- * RDY/BUSY pin will indicate that the part is busy."
- */
-
- erasecmd[0] = AT45DB_PGERASE; /* Page erase command */
- erasecmd[1] = (offset >> 16) & 0xff; /* 24-bit offset MS bytes */
- erasecmd[2] = (offset >> 8) & 0xff; /* 24-bit offset middle bytes */
- erasecmd[3] = offset & 0xff; /* 24-bit offset LS bytes */
-
- /* Erase the page */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SNDBLOCK(priv->spi, erasecmd, 4);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
- /* Wait for any erase to complete if we are not trying to improve write
- * performance. (see comments above).
- */
-
-#ifndef CONFIG_AT45DB_PREWAIT
- at45db_waitbusy(priv);
-#endif
- fvdbg("Erased\n");
-}
-
-/************************************************************************************
- * Name: at32db_chiperase
- ************************************************************************************/
-
-static inline int at32db_chiperase(struct at45db_dev_s *priv)
-{
- fvdbg("priv: %p\n", priv);
-
- /* Higher performance write logic: We leave the chip busy after write and erase
- * operations. This improves write and erase performance because we do not have
- * to wait as long between transactions (other processing can occur while the chip
- * is busy) but means that the chip must stay powered and that we must check if
- * the chip is still busy on each entry point.
- */
-
-#ifdef CONFIG_AT45DB_PREWAIT
- at45db_waitbusy(priv);
-#endif
-
- /* "The entire main memory can be erased at one time by using the Chip Erase
- * command. To execute the Chip Erase command, a 4-byte command sequence C7H, 94H,
- * 80H and 9AH must be clocked into the device. ... After the last bit of the opcode
- * sequence has been clocked in, the CS pin can be deasserted to start the erase
- * process. ... the Status Register will indicate that the device is busy. The Chip
- * Erase command will not affect sectors that are protected or locked down...
- */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SNDBLOCK(priv->spi, g_chiperase, CHIP_ERASE_SIZE);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
- /* Wait for any erase to complete if we are not trying to improve write
- * performance. (see comments above).
- */
-
-#ifndef CONFIG_AT45DB_PREWAIT
- at45db_waitbusy(priv);
-#endif
- return OK;
-}
-
-/************************************************************************************
- * Name: at45db_pgwrite
- ************************************************************************************/
-
-static inline void at45db_pgwrite(struct at45db_dev_s *priv, FAR const uint8_t *buffer,
- off_t page)
-{
- uint8_t wrcmd [4];
- off_t offset = page << priv->pageshift;
-
- fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset);
-
- /* We assume that sectors are not write protected */
-
- wrcmd[0] = AT45DB_MNTHRUBF1; /* To main memory through buffer 1 */
- wrcmd[1] = (offset >> 16) & 0xff; /* 24-bit address MS byte */
- wrcmd[2] = (offset >> 8) & 0xff; /* 24-bit address middle byte */
- wrcmd[3] = offset & 0xff; /* 24-bit address LS byte */
-
- /* Higher performance write logic: We leave the chip busy after write and erase
- * operations. This improves write and erase performance because we do not have
- * to wait as long between transactions (other processing can occur while the chip
- * is busy) but means that the chip must stay powered and that we must check if
- * the chip is still busy on each entry point.
- */
-
-#ifdef CONFIG_AT45DB_PREWAIT
- at45db_waitbusy(priv);
-#endif
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SNDBLOCK(priv->spi, wrcmd, 4);
- SPI_SNDBLOCK(priv->spi, buffer, 1 << priv->pageshift);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
- /* Wait for any erase to complete if we are not trying to improve write
- * performance. (see comments above).
- */
-
-#ifndef CONFIG_AT45DB_PREWAIT
- at45db_waitbusy(priv);
-#endif
- fvdbg("Written\n");
-}
-
-/************************************************************************************
- * Name: at45db_erase
- ************************************************************************************/
-
-static int at45db_erase(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks)
-{
- FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd;
- size_t pgsleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Take the lock so that we have exclusive access to the bus, then power up the
- * FLASH device.
- */
-
- at45db_lock(priv);
- at45db_resume(priv);
-
- /* Then erase each page */
-
- while (pgsleft-- > 0)
- {
- /* Erase each sector */
-
- at45db_pgerase(priv, startblock);
- startblock++;
- }
-
- at45db_pwrdown(priv);
- at45db_unlock(priv);
- return (int)nblocks;
-}
-
-/************************************************************************************
- * Name: at45db_bread
- ************************************************************************************/
-
-static ssize_t at45db_bread(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks,
- FAR uint8_t *buffer)
-{
- FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd;
- ssize_t nbytes;
-
- /* On this device, we can handle the block read just like the byte-oriented read */
-
- nbytes = at45db_read(mtd, startblock << priv->pageshift, nblocks << priv->pageshift, buffer);
- if (nbytes > 0)
- {
- return nbytes >> priv->pageshift;
- }
- return nbytes;
-}
-
-/************************************************************************************
- * Name: at45db_bwrite
- ************************************************************************************/
-
-static ssize_t at45db_bwrite(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
-{
- FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd;
- size_t pgsleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Take the lock so that we have exclusive access to the bus, then power up the
- * FLASH device.
- */
-
- at45db_lock(priv);
- at45db_resume(priv);
-
- /* Write each page to FLASH */
-
- while (pgsleft-- > 0)
- {
- at45db_pgwrite(priv, buffer, startblock);
- startblock++;
- }
-
- at45db_pwrdown(priv);
- at45db_unlock(priv);
-
- return nblocks;
-}
-
-/************************************************************************************
- * Name: at45db_read
- ************************************************************************************/
-
-static ssize_t at45db_read(FAR struct mtd_dev_s *mtd, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
-{
- FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd;
- uint8_t rdcmd [5];
-
- fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
-
- /* Set up for the read */
-
- rdcmd[0] = AT45DB_RDARRAYHF; /* FAST_READ is safe at all supported SPI speeds. */
- rdcmd[1] = (offset >> 16) & 0xff; /* 24-bit address upper byte */
- rdcmd[2] = (offset >> 8) & 0xff; /* 24-bit address middle byte */
- rdcmd[3] = offset & 0xff; /* 24-bit address least significant byte */
- rdcmd[4] = 0; /* Dummy byte */
-
- /* Take the lock so that we have exclusive access to the bus, then power up the
- * FLASH device.
- */
-
- at45db_lock(priv);
- at45db_resume(priv);
-
- /* Higher performance write logic: We leave the chip busy after write and erase
- * operations. This improves write and erase performance because we do not have
- * to wait as long between transactions (other processing can occur while the chip
- * is busy) but means that the chip must stay powered and that we must check if
- * the chip is still busy on each entry point.
- */
-
-#ifdef CONFIG_AT45DB_PREWAIT
- at45db_waitbusy(priv);
-#endif
-
- /* Perform the read */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SNDBLOCK(priv->spi, rdcmd, 5);
- SPI_RECVBLOCK(priv->spi, buffer, nbytes);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
- at45db_pwrdown(priv);
- at45db_unlock(priv);
-
- fvdbg("return nbytes: %d\n", (int)nbytes);
- return nbytes;
-}
-
-/************************************************************************************
- * Name: at45db_ioctl
- ************************************************************************************/
-
-static int at45db_ioctl(FAR struct mtd_dev_s *mtd, int cmd, unsigned long arg)
-{
- FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- fvdbg("cmd: %d \n", cmd);
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- */
-
- geo->blocksize = (1 << priv->pageshift);
- geo->erasesize = geo->blocksize;
- geo->neraseblocks = priv->npages;
- ret = OK;
-
- fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
- geo->blocksize, geo->erasesize, geo->neraseblocks);
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- {
- /* Take the lock so that we have exclusive access to the bus, then
- * power up the FLASH device.
- */
-
- at45db_lock(priv);
- at45db_resume(priv);
-
- /* Erase the entire device */
-
- ret = at32db_chiperase(priv);
- at45db_pwrdown(priv);
- at45db_unlock(priv);
- }
- break;
-
- case MTDIOC_XIPBASE:
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- fvdbg("return %d\n", ret);
- return ret;
-}
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: at45db_initialize
- *
- * Description:
- * Create an initialize MTD device instance. MTD devices are not registered
- * in the file system, but are created as instances that can be bound to
- * other functions (such as a block or character driver front end).
- *
- ************************************************************************************/
-
-FAR struct mtd_dev_s *at45db_initialize(FAR struct spi_dev_s *spi)
-{
- FAR struct at45db_dev_s *priv;
- uint8_t sr;
- int ret;
-
- fvdbg("spi: %p\n", spi);
-
- /* Allocate a state structure (we allocate the structure instead of using
- * a fixed, static allocation so that we can handle multiple FLASH devices.
- * The current implementation would handle only one FLASH part per SPI
- * device (only because of the SPIDEV_FLASH definition) and so would have
- * to be extended to handle multiple FLASH parts on the same SPI bus.
- */
-
- priv = (FAR struct at45db_dev_s *)kmalloc(sizeof(struct at45db_dev_s));
- if (priv)
- {
- /* Initialize the allocated structure */
-
- priv->mtd.erase = at45db_erase;
- priv->mtd.bread = at45db_bread;
- priv->mtd.bwrite = at45db_bwrite;
- priv->mtd.read = at45db_read;
- priv->mtd.ioctl = at45db_ioctl;
- priv->spi = spi;
-
- /* Deselect the FLASH */
-
- SPI_SELECT(spi, SPIDEV_FLASH, false);
-
- /* Lock and configure the SPI bus. */
-
- at45db_lock(priv);
- at45db_resume(priv);
-
- /* Identify the FLASH chip and get its capacity */
-
- ret = at45db_rdid(priv);
- if (ret != OK)
- {
- /* Unrecognized! Discard all of that work we just did and return NULL */
-
- fdbg("Unrecognized\n");
- goto errout;
- }
-
- /* Get the value of the status register (as soon as the device is ready) */
-
- sr = at45db_waitbusy(priv);
-
- /* Check if the device is configured as 256, 512 or 1024 bytes-per-page device */
-
- if ((sr & AT45DB_SR_PGSIZE) == 0)
- {
- /* No, re-program it for the binary page size. NOTE: A power cycle
- * is required after the device has be re-programmed.
- */
-
- fdbg("Reprogramming page size\n");
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
- SPI_SNDBLOCK(priv->spi, g_binpgsize, BINPGSIZE_SIZE);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
- goto errout;
- }
-
- /* Release the lock and power down the device */
-
- at45db_pwrdown(priv);
- at45db_unlock(priv);
- }
-
- fvdbg("Return %p\n", priv);
- return (FAR struct mtd_dev_s *)priv;
-
-/* On any failure, we need free memory allocations and release the lock that
- * we hold on the SPI bus. On failures, assume that we cannot talk to the
- * device to do any more.
- */
-
-errout:
- at45db_unlock(priv);
- kfree(priv);
- return NULL;
-}
diff --git a/nuttx/drivers/mtd/flash_eraseall.c b/nuttx/drivers/mtd/flash_eraseall.c
deleted file mode 100644
index ce0cfe649..000000000
--- a/nuttx/drivers/mtd/flash_eraseall.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
- * drivers/mtd/flash_eraseall.c
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/fs/fs.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/mtd.h>
-
-/****************************************************************************
- * Private Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: flash_eraseall
- *
- * Description:
- * Call a block driver with the MDIOC_BULKERASE ioctl command. This will
- * cause the MTD driver to erase all of the flash.
- *
- ****************************************************************************/
-
-int flash_eraseall(FAR const char *driver)
-{
- FAR struct inode *inode;
- FAR const struct block_operations *ops;
- int ret;
-
- /* Open the block driver */
-
- ret = open_blockdriver(driver ,0, &inode);
- if (ret < 0)
- {
- fdbg("ERROR: Failed to open '%s': %d\n", driver, ret);
- return ret;
- }
-
- /* Get the block operations */
-
- ops = inode->u.i_bops;
-
- /* Invoke the block driver ioctl method */
-
- ret = -EPERM;
- if (ops->ioctl)
- {
- ret = ops->ioctl(inode, MTDIOC_BULKERASE, 0);
- if (ret < 0)
- {
- fdbg("ERROR: MTD ioctl(%04x) failed: %d\n", MTDIOC_BULKERASE, ret);
- }
- }
-
- /* Close the block driver */
-
- close_blockdriver(inode);
- return ret;
-}
diff --git a/nuttx/drivers/mtd/ftl.c b/nuttx/drivers/mtd/ftl.c
deleted file mode 100644
index 6cf8f0317..000000000
--- a/nuttx/drivers/mtd/ftl.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/****************************************************************************
- * drivers/mtd/ftl.c
- *
- * Copyright (C) 2009, 2011-2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <debug.h>
-#include <errno.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/fs.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/mtd.h>
-#include <nuttx/rwbuffer.h>
-
-/****************************************************************************
- * Private Definitions
- ****************************************************************************/
-
-#if defined(CONFIG_FS_READAHEAD) || (defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER))
-# defined CONFIG_FTL_RWBUFFER 1
-#endif
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct ftl_struct_s
-{
- FAR struct mtd_dev_s *mtd; /* Contained MTD interface */
- struct mtd_geometry_s geo; /* Device geometry */
-#ifdef CONFIG_FTL_RWBUFFER
- struct rwbuffer_s rwb; /* Read-ahead/write buffer support */
-#endif
- uint16_t blkper; /* R/W blocks per erase block */
-#ifdef CONFIG_FS_WRITABLE
- FAR uint8_t *eblock; /* One, in-memory erase block */
-#endif
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int ftl_open(FAR struct inode *inode);
-static int ftl_close(FAR struct inode *inode);
-static ssize_t ftl_reload(FAR void *priv, FAR uint8_t *buffer,
- off_t startblock, size_t nblocks);
-static ssize_t ftl_read(FAR struct inode *inode, unsigned char *buffer,
- size_t start_sector, unsigned int nsectors);
-#ifdef CONFIG_FS_WRITABLE
-static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer,
- off_t startblock, size_t nblocks);
-static ssize_t ftl_write(FAR struct inode *inode, const unsigned char *buffer,
- size_t start_sector, unsigned int nsectors);
-#endif
-static int ftl_geometry(FAR struct inode *inode, struct geometry *geometry);
-static int ftl_ioctl(FAR struct inode *inode, int cmd, unsigned long arg);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-static const struct block_operations g_bops =
-{
- ftl_open, /* open */
- ftl_close, /* close */
- ftl_read, /* read */
-#ifdef CONFIG_FS_WRITABLE
- ftl_write, /* write */
-#else
- NULL, /* write */
-#endif
- ftl_geometry, /* geometry */
- ftl_ioctl /* ioctl */
-};
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: ftl_open
- *
- * Description: Open the block device
- *
- ****************************************************************************/
-
-static int ftl_open(FAR struct inode *inode)
-{
- fvdbg("Entry\n");
- return OK;
-}
-
-/****************************************************************************
- * Name: ftl_close
- *
- * Description: close the block device
- *
- ****************************************************************************/
-
-static int ftl_close(FAR struct inode *inode)
-{
- fvdbg("Entry\n");
- return OK;
-}
-
-/****************************************************************************
- * Name: ftl_reload
- *
- * Description: Read the specified numer of sectors
- *
- ****************************************************************************/
-
-static ssize_t ftl_reload(FAR void *priv, FAR uint8_t *buffer,
- off_t startblock, size_t nblocks)
-{
- struct ftl_struct_s *dev = (struct ftl_struct_s *)priv;
- ssize_t nread;
-
- /* Read the full erase block into the buffer */
-
- nread = MTD_BREAD(dev->mtd, startblock, nblocks, buffer);
- if (nread != nblocks)
- {
- fdbg("Read %d blocks starting at block %d failed: %d\n",
- nblocks, startblock, nread);
- }
- return nread;
-}
-
-/****************************************************************************
- * Name: ftl_read
- *
- * Description: Read the specified numer of sectors
- *
- ****************************************************************************/
-
-static ssize_t ftl_read(FAR struct inode *inode, unsigned char *buffer,
- size_t start_sector, unsigned int nsectors)
-{
- struct ftl_struct_s *dev;
-
- fvdbg("sector: %d nsectors: %d\n", start_sector, nsectors);
-
- DEBUGASSERT(inode && inode->i_private);
- dev = (struct ftl_struct_s *)inode->i_private;
-#ifdef CONFIG_FS_READAHEAD
- return rwb_read(&dev->rwb, start_sector, nsectors, buffer);
-#else
- return ftl_reload(dev, buffer, start_sector, nsectors);
-#endif
-}
-
-/****************************************************************************
- * Name: ftl_flush
- *
- * Description: Write the specified number of sectors
- *
- ****************************************************************************/
-
-#ifdef CONFIG_FS_WRITABLE
-static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer,
- off_t startblock, size_t nblocks)
-{
- struct ftl_struct_s *dev = (struct ftl_struct_s *)priv;
- off_t alignedblock;
- off_t mask;
- off_t rwblock;
- off_t eraseblock;
- off_t offset;
- size_t remaining;
- size_t nxfrd;
- int nbytes;
- int ret;
-
- /* Get the aligned block. Here is is assumed: (1) The number of R/W blocks
- * per erase block is a power of 2, and (2) the erase begins with that same
- * alignment.
- */
-
- mask = dev->blkper - 1;
- alignedblock = (startblock + mask) & ~mask;
-
- /* Handle partial erase blocks before the first unaligned block */
-
- remaining = nblocks;
- if (alignedblock > startblock)
- {
- /* Check if the write is shorter than to the end of the erase block */
-
- bool short_write = (remaining < (alignedblock - startblock));
-
- /* Read the full erase block into the buffer */
-
- rwblock = startblock & ~mask;
- nxfrd = MTD_BREAD(dev->mtd, rwblock, dev->blkper, dev->eblock);
- if (nxfrd != dev->blkper)
- {
- fdbg("Read erase block %d failed: %d\n", rwblock, nxfrd);
- return -EIO;
- }
-
- /* Then erase the erase block */
-
- eraseblock = rwblock / dev->blkper;
- ret = MTD_ERASE(dev->mtd, eraseblock, 1);
- if (ret < 0)
- {
- fdbg("Erase block=%d failed: %d\n", eraseblock, ret);
- return ret;
- }
-
- /* Copy the user data at the end of the buffered erase block */
-
- offset = (startblock & mask) * dev->geo.blocksize;
-
- if (short_write)
- {
- nbytes = remaining * dev->geo.blocksize;
- }
- else
- {
- nbytes = dev->geo.erasesize - offset;
- }
-
- fvdbg("Copy %d bytes into erase block=%d at offset=%d\n",
- nbytes, eraseblock, offset);
-
- memcpy(dev->eblock + offset, buffer, nbytes);
-
- /* And write the erase back to flash */
-
- nxfrd = MTD_BWRITE(dev->mtd, rwblock, dev->blkper, dev->eblock);
- if (nxfrd != dev->blkper)
- {
- fdbg("Write erase block %d failed: %d\n", rwblock, nxfrd);
- return -EIO;
- }
-
- /* Then update for amount written */
-
- if (short_write)
- {
- remaining = 0;
- }
- else
- {
- remaining -= dev->blkper - (startblock & mask);
- }
-
- buffer += nbytes;
- }
-
- /* How handle full erase pages in the middle */
-
- while (remaining >= dev->blkper)
- {
- /* Erase the erase block */
-
- eraseblock = alignedblock / dev->blkper;
- ret = MTD_ERASE(dev->mtd, eraseblock, 1);
- if (ret < 0)
- {
- fdbg("Erase block=%d failed: %d\n", eraseblock, ret);
- return ret;
- }
-
- /* Write a full erase back to flash */
-
- fvdbg("Write %d bytes into erase block=%d at offset=0\n",
- dev->geo.erasesize, alignedblock);
-
- nxfrd = MTD_BWRITE(dev->mtd, alignedblock, dev->blkper, buffer);
- if (nxfrd != dev->blkper)
- {
- fdbg("Write erase block %d failed: %d\n", alignedblock, nxfrd);
- return -EIO;
- }
-
- /* Then update for amount written */
-
- alignedblock += dev->blkper;
- remaining -= dev->blkper;
- buffer += dev->geo.erasesize;
- }
-
- /* Finally, handler any partial blocks after the last full erase block */
-
- if (remaining > 0)
- {
- /* Read the full erase block into the buffer */
-
- nxfrd = MTD_BREAD(dev->mtd, alignedblock, dev->blkper, dev->eblock);
- if (nxfrd != dev->blkper)
- {
- fdbg("Read erase block %d failed: %d\n", alignedblock, nxfrd);
- return -EIO;
- }
-
- /* Then erase the erase block */
-
- eraseblock = alignedblock / dev->blkper;
- ret = MTD_ERASE(dev->mtd, eraseblock, 1);
- if (ret < 0)
- {
- fdbg("Erase block=%d failed: %d\n", eraseblock, ret);
- return ret;
- }
-
- /* Copy the user data at the beginning the buffered erase block */
-
- nbytes = remaining * dev->geo.blocksize;
- fvdbg("Copy %d bytes into erase block=%d at offset=0\n",
- nbytes, alignedblock);
- memcpy(dev->eblock, buffer, nbytes);
-
- /* And write the erase back to flash */
-
- nxfrd = MTD_BWRITE(dev->mtd, alignedblock, dev->blkper, dev->eblock);
- if (nxfrd != dev->blkper)
- {
- fdbg("Write erase block %d failed: %d\n", alignedblock, nxfrd);
- return -EIO;
- }
- }
-
- return nblocks;
-}
-#endif
-
-/****************************************************************************
- * Name: ftl_write
- *
- * Description: Write (or buffer) the specified number of sectors
- *
- ****************************************************************************/
-
-#ifdef CONFIG_FS_WRITABLE
-static ssize_t ftl_write(FAR struct inode *inode, const unsigned char *buffer,
- size_t start_sector, unsigned int nsectors)
-{
- struct ftl_struct_s *dev;
-
- fvdbg("sector: %d nsectors: %d\n", start_sector, nsectors);
-
- DEBUGASSERT(inode && inode->i_private);
- dev = (struct ftl_struct_s *)inode->i_private;
-#ifdef CONFIG_FS_WRITEBUFFER
- return rwb_write(&dev->rwb, start_sector, nsectors, buffer);
-#else
- return ftl_flush(dev, buffer, start_sector, nsectors);
-#endif
-}
-#endif
-
-/****************************************************************************
- * Name: ftl_geometry
- *
- * Description: Return device geometry
- *
- ****************************************************************************/
-
-static int ftl_geometry(FAR struct inode *inode, struct geometry *geometry)
-{
- struct ftl_struct_s *dev;
-
- fvdbg("Entry\n");
-
- DEBUGASSERT(inode);
- if (geometry)
- {
- dev = (struct ftl_struct_s *)inode->i_private;
- geometry->geo_available = true;
- geometry->geo_mediachanged = false;
-#ifdef CONFIG_FS_WRITABLE
- geometry->geo_writeenabled = true;
-#else
- geometry->geo_writeenabled = false;
-#endif
- geometry->geo_nsectors = dev->geo.neraseblocks * dev->blkper;
- geometry->geo_sectorsize = dev->geo.blocksize;
-
- fvdbg("available: true mediachanged: false writeenabled: %s\n",
- geometry->geo_writeenabled ? "true" : "false");
- fvdbg("nsectors: %d sectorsize: %d\n",
- geometry->geo_nsectors, geometry->geo_sectorsize);
-
- return OK;
- }
- return -EINVAL;
-}
-
-/****************************************************************************
- * Name: ftl_ioctl
- *
- * Description: Return device geometry
- *
- ****************************************************************************/
-
-static int ftl_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
-{
- struct ftl_struct_s *dev ;
- int ret;
-
- fvdbg("Entry\n");
- DEBUGASSERT(inode && inode->i_private);
-
- /* Only one block driver ioctl command is supported by this driver (and
- * that command is just passed on to the MTD driver in a slightly
- * different form).
- */
-
- if (cmd == BIOC_XIPBASE)
- {
- /* The argument accompanying the BIOC_XIPBASE should be non-NULL. If
- * DEBUG is enabled, we will catch it here instead of in the MTD
- * driver.
- */
-
-#ifdef CONFIG_DEBUG
- if (arg == 0)
- {
- fdbg("ERROR: BIOC_XIPBASE argument is NULL\n");
- return -EINVAL;
- }
-#endif
-
- /* Just change the BIOC_XIPBASE command to the MTDIOC_XIPBASE command. */
-
- cmd = MTDIOC_XIPBASE;
- }
-
- /* No other block driver ioctl commmands are not recognized by this
- * driver. Other possible MTD driver ioctl commands are passed through
- * to the MTD driver (unchanged).
- */
-
- dev = (struct ftl_struct_s *)inode->i_private;
- ret = MTD_IOCTL(dev->mtd, cmd, arg);
- if (ret < 0)
- {
- fdbg("ERROR: MTD ioctl(%04x) failed: %d\n", cmd, ret);
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: ftl_initialize
- *
- * Description:
- * Initialize to provide a block driver wrapper around an MTD interface
- *
- * Input Parameters:
- * minor - The minor device number. The MTD block device will be
- * registered as as /dev/mtdblockN where N is the minor number.
- * mtd - The MTD device that supports the FLASH interface.
- *
- ****************************************************************************/
-
-int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd)
-{
- struct ftl_struct_s *dev;
- char devname[16];
- int ret = -ENOMEM;
-
- /* Sanity check */
-
-#ifdef CONFIG_DEBUG
- if (minor < 0 || minor > 255 || !mtd)
- {
- return -EINVAL;
- }
-#endif
-
- /* Allocate a FTL device structure */
-
- dev = (struct ftl_struct_s *)kmalloc(sizeof(struct ftl_struct_s));
- if (dev)
- {
- /* Initialize the FTL device structure */
-
- dev->mtd = mtd;
-
- /* Get the device geometry. (casting to uintptr_t first eliminates
- * complaints on some architectures where the sizeof long is different
- * from the size of a pointer).
- */
-
- ret = MTD_IOCTL(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&dev->geo));
- if (ret < 0)
- {
- fdbg("MTD ioctl(MTDIOC_GEOMETRY) failed: %d\n", ret);
- kfree(dev);
- return ret;
- }
-
- /* Allocate one, in-memory erase block buffer */
-
-#ifdef CONFIG_FS_WRITABLE
- dev->eblock = (FAR uint8_t *)kmalloc(dev->geo.erasesize);
- if (!dev->eblock)
- {
- fdbg("Failed to allocate an erase block buffer\n");
- kfree(dev);
- return -ENOMEM;
- }
-#endif
-
- /* Get the number of R/W blocks per erase block */
-
- dev->blkper = dev->geo.erasesize / dev->geo.blocksize;
- DEBUGASSERT(dev->blkper * dev->geo.blocksize == dev->geo.erasesize);
-
- /* Configure read-ahead/write buffering */
-
-#ifdef CONFIG_FTL_RWBUFFER
- dev->rwb.blocksize = dev->geo.blocksize;
- dev->rwb.nblocks = dev->geo.neraseblocks * dev->blkper;
- dev->rwb.dev = (FAR void *)dev;
-
-#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER)
- dev->rwb.wrmaxblocks = dev->blkper;
- dev->rwb.wrflush = ftl_flush;
-#endif
-
-#ifdef CONFIG_FS_READAHEAD
- dev->rwb.rhmaxblocks = dev->blkper;
- dev->rwb.rhreload = ftl_reload;
-#endif
- ret = rwb_initialize(&dev->rwb);
- if (ret < 0)
- {
- fdbg("rwb_initialize failed: %d\n", ret);
- kfree(dev);
- return ret;
- }
-#endif
-
- /* Create a MTD block device name */
-
- snprintf(devname, 16, "/dev/mtdblock%d", minor);
-
- /* Inode private data is a reference to the FTL device structure */
-
- ret = register_blockdriver(devname, &g_bops, 0, dev);
- if (ret < 0)
- {
- fdbg("register_blockdriver failed: %d\n", -ret);
- kfree(dev);
- }
- }
- return ret;
-}
diff --git a/nuttx/drivers/mtd/m25px.c b/nuttx/drivers/mtd/m25px.c
deleted file mode 100644
index 4f96c5a3b..000000000
--- a/nuttx/drivers/mtd/m25px.c
+++ /dev/null
@@ -1,798 +0,0 @@
-/************************************************************************************
- * drivers/mtd/m25px.c
- * Driver for SPI-based M25P1 (128Kbit), M25P64 (32Mbit), M25P64 (64Mbit), and
- * M25P128 (128Mbit) FLASH (and compatible).
- *
- * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ************************************************************************************/
-
-/************************************************************************************
- * Included Files
- ************************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/spi.h>
-#include <nuttx/mtd.h>
-
-/************************************************************************************
- * Pre-processor Definitions
- ************************************************************************************/
-/* Configuration ********************************************************************/
-/* Per the data sheet, MP25P10 parts can be driven with either SPI mode 0 (CPOL=0 and
- * CPHA=0) or mode 3 (CPOL=1 and CPHA=1). But I have heard that other devices can
- * operated in mode 0 or 1. So you may need to specify CONFIG_MP25P_SPIMODE to
- * select the best mode for your device. If CONFIG_MP25P_SPIMODE is not defined,
- * mode 0 will be used.
- */
-
-#ifndef CONFIG_MP25P_SPIMODE
-# define CONFIG_MP25P_SPIMODE SPIDEV_MODE0
-#endif
-
-/* Various manufacturers may have produced the parts. 0x20 is the manufacturer ID
- * for the STMicro MP25x serial FLASH. If, for example, you are using the a Macronix
- * International MX25 serial FLASH, the correct manufacturer ID would be 0xc2.
- */
-
-#ifndef CONFIG_MP25P_MANUFACTURER
-# define CONFIG_MP25P_MANUFACTURER 0x20
-#endif
-
-/* M25P Registers *******************************************************************/
-/* Indentification register values */
-
-#define M25P_MANUFACTURER CONFIG_MP25P_MANUFACTURER
-#define M25P_MEMORY_TYPE 0x20
-#define M25P_M25P1_CAPACITY 0x11 /* 1 M-bit */
-#define M25P_M25P32_CAPACITY 0x16 /* 32 M-bit */
-#define M25P_M25P64_CAPACITY 0x17 /* 64 M-bit */
-#define M25P_M25P128_CAPACITY 0x18 /* 128 M-bit */
-
-/* M25P1 capacity is 131,072 bytes:
- * (4 sectors) * (32,768 bytes per sector)
- * (512 pages) * (256 bytes per page)
- */
-
-#define M25P_M25P1_SECTOR_SHIFT 15 /* Sector size 1 << 15 = 65,536 */
-#define M25P_M25P1_NSECTORS 4
-#define M25P_M25P1_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
-#define M25P_M25P1_NPAGES 512
-
-/* M25P32 capacity is 4,194,304 bytes:
- * (64 sectors) * (65,536 bytes per sector)
- * (16384 pages) * (256 bytes per page)
- */
-
-#define M25P_M25P32_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */
-#define M25P_M25P32_NSECTORS 64
-#define M25P_M25P32_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
-#define M25P_M25P32_NPAGES 16384
-
-/* M25P64 capacity is 8,338,608 bytes:
- * (128 sectors) * (65,536 bytes per sector)
- * (32768 pages) * (256 bytes per page)
- */
-
-#define M25P_M25P64_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */
-#define M25P_M25P64_NSECTORS 128
-#define M25P_M25P64_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
-#define M25P_M25P64_NPAGES 32768
-
-/* M25P128 capacity is 16,777,216 bytes:
- * (64 sectors) * (262,144 bytes per sector)
- * (65536 pages) * (256 bytes per page)
- */
-
-#define M25P_M25P128_SECTOR_SHIFT 18 /* Sector size 1 << 18 = 262,144 */
-#define M25P_M25P128_NSECTORS 64
-#define M25P_M25P128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
-#define M25P_M25P128_NPAGES 65536
-
-/* Instructions */
-/* Command Value N Description Addr Dummy Data */
-#define M25P_WREN 0x06 /* 1 Write Enable 0 0 0 */
-#define M25P_WRDI 0x04 /* 1 Write Disable 0 0 0 */
-#define M25P_RDID 0x9f /* 1 Read Identification 0 0 1-3 */
-#define M25P_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */
-#define M25P_WRSR 0x01 /* 1 Write Status Register 0 0 1 */
-#define M25P_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */
-#define M25P_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */
-#define M25P_PP 0x02 /* 1 Page Program 3 0 1-256 */
-#define M25P_SE 0xd8 /* 1 Sector Erase 3 0 0 */
-#define M25P_BE 0xc7 /* 1 Bulk Erase 0 0 0 */
-#define M25P_DP 0xb9 /* 2 Deep power down 0 0 0 */
-#define M25P_RES 0xab /* 2 Read Electronic Signature 0 3 >=1 */
-
-/* NOTE 1: All parts, NOTE 2: M25P632/M25P64 */
-
-/* Status register bit definitions */
-
-#define M25P_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */
-#define M25P_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */
-#define M25P_SR_BP_SHIFT (2) /* Bits 2-4: Block protect bits */
-#define M25P_SR_BP_MASK (7 << M25P_SR_BP_SHIFT)
-# define M25P_SR_BP_NONE (0 << M25P_SR_BP_SHIFT) /* Unprotected */
-# define M25P_SR_BP_UPPER64th (1 << M25P_SR_BP_SHIFT) /* Upper 64th */
-# define M25P_SR_BP_UPPER32nd (2 << M25P_SR_BP_SHIFT) /* Upper 32nd */
-# define M25P_SR_BP_UPPER16th (3 << M25P_SR_BP_SHIFT) /* Upper 16th */
-# define M25P_SR_BP_UPPER8th (4 << M25P_SR_BP_SHIFT) /* Upper 8th */
-# define M25P_SR_BP_UPPERQTR (5 << M25P_SR_BP_SHIFT) /* Upper quarter */
-# define M25P_SR_BP_UPPERHALF (6 << M25P_SR_BP_SHIFT) /* Upper half */
-# define M25P_SR_BP_ALL (7 << M25P_SR_BP_SHIFT) /* All sectors */
- /* Bits 5-6: Unused, read zero */
-#define M25P_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */
-
-#define M25P_DUMMY 0xa5
-
-/************************************************************************************
- * Private Types
- ************************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s
- * must appear at the beginning of the definition so that you can freely
- * cast between pointers to struct mtd_dev_s and struct m25p_dev_s.
- */
-
-struct m25p_dev_s
-{
- struct mtd_dev_s mtd; /* MTD interface */
- FAR struct spi_dev_s *dev; /* Saved SPI interface instance */
- uint8_t sectorshift; /* 16 or 18 */
- uint8_t pageshift; /* 8 */
- uint16_t nsectors; /* 128 or 64 */
- uint32_t npages; /* 32,768 or 65,536 */
-};
-
-/************************************************************************************
- * Private Function Prototypes
- ************************************************************************************/
-
-/* Helpers */
-
-static void m25p_lock(FAR struct spi_dev_s *dev);
-static inline void m25p_unlock(FAR struct spi_dev_s *dev);
-static inline int m25p_readid(struct m25p_dev_s *priv);
-static void m25p_waitwritecomplete(struct m25p_dev_s *priv);
-static void m25p_writeenable(struct m25p_dev_s *priv);
-static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t offset);
-static inline int m25p_bulkerase(struct m25p_dev_s *priv);
-static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer,
- off_t offset);
-
-/* MTD driver methods */
-
-static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR uint8_t *buf);
-static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf);
-static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer);
-static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/************************************************************************************
- * Private Data
- ************************************************************************************/
-
-/************************************************************************************
- * Private Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: m25p_lock
- ************************************************************************************/
-
-static void m25p_lock(FAR struct spi_dev_s *dev)
-{
- /* On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
- * transfers. The bus should be locked before the chip is selected.
- *
- * This is a blocking call and will not return until we have exclusiv access to
- * the SPI buss. We will retain that exclusive access until the bus is unlocked.
- */
-
- (void)SPI_LOCK(dev, true);
-
- /* After locking the SPI bus, the we also need call the setfrequency, setbits, and
- * setmode methods to make sure that the SPI is properly configured for the device.
- * If the SPI buss is being shared, then it may have been left in an incompatible
- * state.
- */
-
- SPI_SETMODE(dev, CONFIG_MP25P_SPIMODE);
- SPI_SETBITS(dev, 8);
- (void)SPI_SETFREQUENCY(dev, 20000000);
-}
-
-/************************************************************************************
- * Name: m25p_unlock
- ************************************************************************************/
-
-static inline void m25p_unlock(FAR struct spi_dev_s *dev)
-{
- (void)SPI_LOCK(dev, false);
-}
-
-/************************************************************************************
- * Name: m25p_readid
- ************************************************************************************/
-
-static inline int m25p_readid(struct m25p_dev_s *priv)
-{
- uint16_t manufacturer;
- uint16_t memory;
- uint16_t capacity;
-
- fvdbg("priv: %p\n", priv);
-
- /* Lock the SPI bus, configure the bus, and select this FLASH part. */
-
- m25p_lock(priv->dev);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Read ID (RDID)" command and read the first three ID bytes */
-
- (void)SPI_SEND(priv->dev, M25P_RDID);
- manufacturer = SPI_SEND(priv->dev, M25P_DUMMY);
- memory = SPI_SEND(priv->dev, M25P_DUMMY);
- capacity = SPI_SEND(priv->dev, M25P_DUMMY);
-
- /* Deselect the FLASH and unlock the bus */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- m25p_unlock(priv->dev);
-
- fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n",
- manufacturer, memory, capacity);
-
- /* Check for a valid manufacturer and memory type */
-
- if (manufacturer == M25P_MANUFACTURER && memory == M25P_MEMORY_TYPE)
- {
- /* Okay.. is it a FLASH capacity that we understand? */
-
- if (capacity == M25P_M25P1_CAPACITY)
- {
- /* Save the FLASH geometry */
-
- priv->sectorshift = M25P_M25P1_SECTOR_SHIFT;
- priv->nsectors = M25P_M25P1_NSECTORS;
- priv->pageshift = M25P_M25P1_PAGE_SHIFT;
- priv->npages = M25P_M25P1_NPAGES;
- return OK;
- }
- else if (capacity == M25P_M25P32_CAPACITY)
- {
- /* Save the FLASH geometry */
-
- priv->sectorshift = M25P_M25P32_SECTOR_SHIFT;
- priv->nsectors = M25P_M25P32_NSECTORS;
- priv->pageshift = M25P_M25P32_PAGE_SHIFT;
- priv->npages = M25P_M25P32_NPAGES;
- return OK;
- }
- else if (capacity == M25P_M25P64_CAPACITY)
- {
- /* Save the FLASH geometry */
-
- priv->sectorshift = M25P_M25P64_SECTOR_SHIFT;
- priv->nsectors = M25P_M25P64_NSECTORS;
- priv->pageshift = M25P_M25P64_PAGE_SHIFT;
- priv->npages = M25P_M25P64_NPAGES;
- return OK;
- }
- else if (capacity == M25P_M25P128_CAPACITY)
- {
- /* Save the FLASH geometry */
-
- priv->sectorshift = M25P_M25P128_SECTOR_SHIFT;
- priv->nsectors = M25P_M25P128_NSECTORS;
- priv->pageshift = M25P_M25P128_PAGE_SHIFT;
- priv->npages = M25P_M25P128_NPAGES;
- return OK;
- }
- }
-
- return -ENODEV;
-}
-
-/************************************************************************************
- * Name: m25p_waitwritecomplete
- ************************************************************************************/
-
-static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
-{
- uint8_t status;
-
- /* Are we the only device on the bus? */
-
-#ifdef CONFIG_SPI_OWNBUS
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->dev, M25P_RDSR);
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->dev, M25P_DUMMY);
- }
- while ((status & M25P_SR_WIP) != 0);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
-#else
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->dev, M25P_RDSR);
-
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->dev, M25P_DUMMY);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
- /* Given that writing could take up to few tens of milliseconds, and erasing
- * could take more. The following short delay in the "busy" case will allow
- * other peripherals to access the SPI bus.
- */
-
- if ((status & M25P_SR_WIP) != 0)
- {
- m25p_unlock(priv->dev);
- usleep(1000);
- m25p_lock(priv->dev);
- }
- }
- while ((status & M25P_SR_WIP) != 0);
-#endif
-
- fvdbg("Complete\n");
-}
-
-/************************************************************************************
- * Name: m25p_writeenable
- ************************************************************************************/
-
-static void m25p_writeenable(struct m25p_dev_s *priv)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Write Enable (WREN)" command */
-
- (void)SPI_SEND(priv->dev, M25P_WREN);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Enabled\n");
-}
-
-/************************************************************************************
- * Name: m25p_sectorerase
- ************************************************************************************/
-
-static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector)
-{
- off_t offset = sector << priv->sectorshift;
-
- fvdbg("sector: %08lx\n", (long)sector);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- m25p_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- m25p_writeenable(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Sector Erase (SE)" instruction */
-
- (void)SPI_SEND(priv->dev, M25P_SE);
-
- /* Send the sector offset high byte first. For all of the supported
- * parts, the sector number is completely contained in the first byte
- * and the values used in the following two bytes don't really matter.
- */
-
- (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, offset & 0xff);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Erased\n");
-}
-
-/************************************************************************************
- * Name: m25p_bulkerase
- ************************************************************************************/
-
-static inline int m25p_bulkerase(struct m25p_dev_s *priv)
-{
- fvdbg("priv: %p\n", priv);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- m25p_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- m25p_writeenable(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Bulk Erase (BE)" instruction */
-
- (void)SPI_SEND(priv->dev, M25P_BE);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Return: OK\n");
- return OK;
-}
-
-/************************************************************************************
- * Name: m25p_pagewrite
- ************************************************************************************/
-
-static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer,
- off_t page)
-{
- off_t offset = page << priv->pageshift;
-
- fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- m25p_waitwritecomplete(priv);
-
- /* Enable the write access to the FLASH */
-
- m25p_writeenable(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Page Program (PP)" command */
-
- (void)SPI_SEND(priv->dev, M25P_PP);
-
- /* Send the page offset high byte first. */
-
- (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, offset & 0xff);
-
- /* Then write the specified number of bytes */
-
- SPI_SNDBLOCK(priv->dev, buffer, 1 << priv->pageshift);
-
- /* Deselect the FLASH: Chip Select high */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Written\n");
-}
-
-/************************************************************************************
- * Name: m25p_erase
- ************************************************************************************/
-
-static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
- FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev;
- size_t blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock access to the SPI bus until we complete the erase */
-
- m25p_lock(priv->dev);
- while (blocksleft-- > 0)
- {
- /* Erase each sector */
-
- m25p_sectorerase(priv, startblock);
- startblock++;
- }
- m25p_unlock(priv->dev);
- return (int)nblocks;
-}
-
-/************************************************************************************
- * Name: m25p_bread
- ************************************************************************************/
-
-static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buffer)
-{
- FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev;
- ssize_t nbytes;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* On this device, we can handle the block read just like the byte-oriented read */
-
- nbytes = m25p_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer);
- if (nbytes > 0)
- {
- return nbytes >> priv->pageshift;
- }
- return (int)nbytes;
-}
-
-/************************************************************************************
- * Name: m25p_bwrite
- ************************************************************************************/
-
-static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
-{
- FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev;
- size_t blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock the SPI bus and write each page to FLASH */
-
- m25p_lock(priv->dev);
- while (blocksleft-- > 0)
- {
- m25p_pagewrite(priv, buffer, startblock);
- startblock++;
- }
- m25p_unlock(priv->dev);
-
- return nblocks;
-}
-
-/************************************************************************************
- * Name: m25p_read
- ************************************************************************************/
-
-static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
-{
- FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev;
-
- fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- m25p_waitwritecomplete(priv);
-
- /* Lock the SPI bus and select this FLASH part */
-
- m25p_lock(priv->dev);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read from Memory " instruction */
-
- (void)SPI_SEND(priv->dev, M25P_READ);
-
- /* Send the page offset high byte first. */
-
- (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, offset & 0xff);
-
- /* Then read all of the requested bytes */
-
- SPI_RECVBLOCK(priv->dev, buffer, nbytes);
-
- /* Deselect the FLASH and unlock the SPI bus */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- m25p_unlock(priv->dev);
- fvdbg("return nbytes: %d\n", (int)nbytes);
- return nbytes;
-}
-
-/************************************************************************************
- * Name: m25p_ioctl
- ************************************************************************************/
-
-static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- fvdbg("cmd: %d \n", cmd);
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- */
-
- geo->blocksize = (1 << priv->pageshift);
- geo->erasesize = (1 << priv->sectorshift);
- geo->neraseblocks = priv->nsectors;
- ret = OK;
-
- fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
- geo->blocksize, geo->erasesize, geo->neraseblocks);
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- {
- /* Erase the entire device */
-
- m25p_lock(priv->dev);
- ret = m25p_bulkerase(priv);
- m25p_unlock(priv->dev);
- }
- break;
-
- case MTDIOC_XIPBASE:
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- fvdbg("return %d\n", ret);
- return ret;
-}
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: m25p_initialize
- *
- * Description:
- * Create an initialize MTD device instance. MTD devices are not registered
- * in the file system, but are created as instances that can be bound to
- * other functions (such as a block or character driver front end).
- *
- ************************************************************************************/
-
-FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev)
-{
- FAR struct m25p_dev_s *priv;
- int ret;
-
- fvdbg("dev: %p\n", dev);
-
- /* Allocate a state structure (we allocate the structure instead of using
- * a fixed, static allocation so that we can handle multiple FLASH devices.
- * The current implementation would handle only one FLASH part per SPI
- * device (only because of the SPIDEV_FLASH definition) and so would have
- * to be extended to handle multiple FLASH parts on the same SPI bus.
- */
-
- priv = (FAR struct m25p_dev_s *)kmalloc(sizeof(struct m25p_dev_s));
- if (priv)
- {
- /* Initialize the allocated structure */
-
- priv->mtd.erase = m25p_erase;
- priv->mtd.bread = m25p_bread;
- priv->mtd.bwrite = m25p_bwrite;
- priv->mtd.read = m25p_read;
- priv->mtd.ioctl = m25p_ioctl;
- priv->dev = dev;
-
- /* Deselect the FLASH */
-
- SPI_SELECT(dev, SPIDEV_FLASH, false);
-
- /* Identify the FLASH chip and get its capacity */
-
- ret = m25p_readid(priv);
- if (ret != OK)
- {
- /* Unrecognized! Discard all of that work we just did and return NULL */
-
- fdbg("Unrecognized\n");
- kfree(priv);
- priv = NULL;
- }
- }
-
- /* Return the implementation-specific state structure as the MTD device */
-
- fvdbg("Return %p\n", priv);
- return (FAR struct mtd_dev_s *)priv;
-}
diff --git a/nuttx/drivers/mtd/rammtd.c b/nuttx/drivers/mtd/rammtd.c
deleted file mode 100644
index 82a7191ea..000000000
--- a/nuttx/drivers/mtd/rammtd.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/****************************************************************************
- * drivers/mtd/rammtd.c
- *
- * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/mtd.h>
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-/* Configuration ************************************************************/
-
-#ifndef CONFIG_RAMMTD_BLOCKSIZE
-# define CONFIG_RAMMTD_BLOCKSIZE 512
-#endif
-
-#ifndef CONFIG_RAMMTD_ERASESIZE
-# define CONFIG_RAMMTD_ERASESIZE 4096
-#endif
-
-#ifndef CONFIG_RAMMTD_ERASESTATE
-# define CONFIG_RAMMTD_ERASESTATE 0xff
-#endif
-
-#if CONFIG_RAMMTD_ERASESTATE != 0xff && CONFIG_RAMMTD_ERASESTATE != 0x00
-# error "Unsupported value for CONFIG_RAMMTD_ERASESTATE"
-#endif
-
-#if CONFIG_RAMMTD_BLOCKSIZE > CONFIG_RAMMTD_ERASESIZE
-# error "Must have CONFIG_RAMMTD_BLOCKSIZE <= CONFIG_RAMMTD_ERASESIZE"
-#endif
-
-#undef CONFIG_RAMMTD_BLKPER
-#define CONFIG_RAMMTD_BLKPER (CONFIG_RAMMTD_ERASESIZE/CONFIG_RAMMTD_BLOCKSIZE)
-
-#if CONFIG_RAMMTD_BLKPER*CONFIG_RAMMTD_BLOCKSIZE != CONFIG_RAMMTD_ERASESIZE
-# error "CONFIG_RAMMTD_ERASESIZE must be an even multiple of CONFIG_RAMMTD_BLOCKSIZE"
-#endif
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s
- * must appear at the beginning of the definition so that you can freely
- * cast between pointers to struct mtd_dev_s and struct ram_dev_s.
- */
-
-struct ram_dev_s
-{
- struct mtd_dev_s mtd; /* MTD device */
- FAR uint8_t *start; /* Start of RAM */
- size_t nblocks; /* Number of erase blocks */
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-/* The RAM MTD driver may be useful just as it is, but another good use of
- * the RAM MTD driver is as a FLASH simulation -- to support testing of FLASH
- * based logic without having FLASH. CONFIG_RAMMTD_FLASHSIM will add some
- * extra logic to improve the level of FLASH simulation.
- */
-
-#define ram_read(dest, src, len) memcpy(dest, src, len)
-#ifdef CONFIG_RAMMTD_FLASHSIM
-static void *ram_write(FAR void *dest, FAR const void *src, size_t len);
-#else
-# define ram_write(dest, src, len) memcpy(dest, src, len)
-#endif
-
-/* MTD driver methods */
-
-static int ram_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t ram_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buf);
-static ssize_t ram_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buf);
-static int ram_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: ram_write
- ****************************************************************************/
-
-#ifdef CONFIG_RAMMTD_FLASHSIM
-static void *ram_write(FAR void *dest, FAR const void *src, size_t len)
-{
- FAR uint8_t *pout = (FAR uint8_t *)dest;
- FAR const uint8_t *pin = (FAR const uint8_t *)src;
-
- while (len-- > 0)
- {
- /* Get the source and destination values */
-
- uint8_t oldvalue = *pout;
- uint8_t srcvalue = *pin++;
- uint8_t newvalue;
-
- /* Get the new destination value, accounting for bits that cannot be
- * changes because they are not in the erased state.
- */
-
-#if CONFIG_RAMMTD_ERASESTATE == 0xff
- newvalue = oldvalue & srcvalue; /* We can only clear bits */
-#else /* CONFIG_RAMMTD_ERASESTATE == 0x00 */
- newvalue = oldvalue | srcvalue; /* We can only set bits */
-#endif
-
- /* Report any attempt to change the value of bits that are not in the
- * erased state.
- */
-
-#ifdef CONFIG_DEBUG
- if (newvalue != srcvalue)
- {
- dbg("ERROR: Bad write: source=%02x dest=%02x result=%02x\n",
- srcvalue, oldvalue, newvalue);
- }
-#endif
-
- /* Write the modified value to simulated FLASH */
-
- *pout++ = newvalue;
- }
-
- return dest;
-}
-#endif
-
-/****************************************************************************
- * Name: ram_erase
- ****************************************************************************/
-
-static int ram_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
- FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev;
- off_t offset;
- size_t nbytes;
-
- DEBUGASSERT(dev);
-
- /* Don't let the erase exceed the size of the ram buffer */
-
- if (startblock >= priv->nblocks)
- {
- return 0;
- }
-
- if (startblock + nblocks > priv->nblocks)
- {
- nblocks = priv->nblocks - startblock;
- }
-
- /* Convert the erase block to a logical block and the number of blocks
- * in logical block numbers
- */
-
- startblock *= CONFIG_RAMMTD_BLKPER;
- nblocks *= CONFIG_RAMMTD_BLKPER;
-
- /* Get the offset corresponding to the first block and the size
- * corresponding to the number of blocks.
- */
-
- offset = startblock * CONFIG_RAMMTD_BLOCKSIZE;
- nbytes = nblocks * CONFIG_RAMMTD_BLOCKSIZE;
-
- /* Then erase the data in RAM */
-
- memset(&priv->start[offset], CONFIG_RAMMTD_ERASESTATE, nbytes);
- return OK;
-}
-
-/****************************************************************************
- * Name: ram_bread
- ****************************************************************************/
-
-static ssize_t ram_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buf)
-{
- FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev;
- off_t offset;
- off_t maxblock;
- size_t nbytes;
-
- DEBUGASSERT(dev && buf);
-
- /* Don't let the read exceed the size of the ram buffer */
-
- maxblock = priv->nblocks * CONFIG_RAMMTD_BLKPER;
- if (startblock >= maxblock)
- {
- return 0;
- }
-
- if (startblock + nblocks > maxblock)
- {
- nblocks = maxblock - startblock;
- }
-
- /* Get the offset corresponding to the first block and the size
- * corresponding to the number of blocks.
- */
-
- offset = startblock * CONFIG_RAMMTD_BLOCKSIZE;
- nbytes = nblocks * CONFIG_RAMMTD_BLOCKSIZE;
-
- /* Then read the data frp, RAM */
-
- ram_read(buf, &priv->start[offset], nbytes);
- return nblocks;
-}
-
-/****************************************************************************
- * Name: ram_bwrite
- ****************************************************************************/
-
-static ssize_t ram_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf)
-{
- FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev;
- off_t offset;
- off_t maxblock;
- size_t nbytes;
-
- DEBUGASSERT(dev && buf);
-
- /* Don't let the write exceed the size of the ram buffer */
-
- maxblock = priv->nblocks * CONFIG_RAMMTD_BLKPER;
- if (startblock >= maxblock)
- {
- return 0;
- }
-
- if (startblock + nblocks > maxblock)
- {
- nblocks = maxblock - startblock;
- }
-
- /* Get the offset corresponding to the first block and the size
- * corresponding to the number of blocks.
- */
-
- offset = startblock * CONFIG_RAMMTD_BLOCKSIZE;
- nbytes = nblocks * CONFIG_RAMMTD_BLOCKSIZE;
-
- /* Then write the data to RAM */
-
- ram_write(&priv->start[offset], buf, nbytes);
- return nblocks;
-}
-
-/****************************************************************************
- * Name: ram_ioctl
- ****************************************************************************/
-
-static int ram_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- */
-
- geo->blocksize = CONFIG_RAMMTD_BLOCKSIZE;
- geo->erasesize = CONFIG_RAMMTD_ERASESIZE;
- geo->neraseblocks = priv->nblocks;
- ret = OK;
- }
- }
- break;
-
- case MTDIOC_XIPBASE:
- {
- FAR void **ppv = (FAR void**)((uintptr_t)arg);
- if (ppv)
- {
- /* Return (void*) base address of device memory */
-
- *ppv = (FAR void*)priv->start;
- ret = OK;
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- {
- size_t size = priv->nblocks * CONFIG_RAMMTD_ERASESIZE;
-
- /* Erase the entire device */
-
- memset(priv->start, CONFIG_RAMMTD_ERASESTATE, size);
- ret = OK;
- }
- break;
-
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: rammtd_initialize
- *
- * Description:
- * Create and initialize a RAM MTD device instance.
- *
- * Input Parameters:
- * start - Address of the beginning of the allocated RAM regions.
- * size - The size in bytes of the allocated RAM region.
- *
- ****************************************************************************/
-
-FAR struct mtd_dev_s *rammtd_initialize(FAR uint8_t *start, size_t size)
-{
- FAR struct ram_dev_s *priv;
- size_t nblocks;
-
- /* Create an instance of the RAM MTD device state structure */
-
- priv = (FAR struct ram_dev_s *)kmalloc(sizeof(struct ram_dev_s));
- if (!priv)
- {
- fdbg("Failed to allocate the RAM MTD state structure\n");
- return NULL;
- }
-
- /* Force the size to be an even number of the erase block size */
-
- nblocks = size / CONFIG_RAMMTD_ERASESIZE;
- if (nblocks <= 0)
- {
- fdbg("Need to provide at least one full erase block\n");
- return NULL;
- }
-
- /* Perform initialization as necessary */
-
- priv->mtd.erase = ram_erase;
- priv->mtd.bread = ram_bread;
- priv->mtd.bwrite = ram_bwrite;
- priv->mtd.ioctl = ram_ioctl;
- priv->mtd.erase = ram_erase;
-
- priv->start = start;
- priv->nblocks = nblocks;
- return &priv->mtd;
-}
diff --git a/nuttx/drivers/mtd/ramtron.c b/nuttx/drivers/mtd/ramtron.c
deleted file mode 100644
index 34273bccf..000000000
--- a/nuttx/drivers/mtd/ramtron.c
+++ /dev/null
@@ -1,686 +0,0 @@
-/************************************************************************************
- * drivers/mtd/ramtron.c
- * Driver for SPI-based RAMTRON NVRAM Devices FM25V10 and others (not tested)
- *
- * Copyright (C) 2011 Uros Platise. All rights reserved.
- * Copyright (C) 2009-2010, 2012 Gregory Nutt. All rights reserved.
- * Author: Uros Platise <uros.platise@isotel.eu>
- * Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ************************************************************************************/
-
-/* OPTIONS:
- * - additional non-jedec standard device: FM25H20
- * must be enabled with the CONFIG_RAMTRON_FRAM_NON_JEDEC=y
- *
- * NOTE:
- * - frequency is fixed to desired max by RAMTRON_INIT_CLK_MAX
- * if new devices with different speed arrive, then SETFREQUENCY()
- * needs to handle freq changes and INIT_CLK_MAX must be reduced
- * to fit all devices. Note that STM32_SPI driver is prone to
- * too high freq. parameters and limit it within physical constraints.
- *
- * TODO:
- * - add support for sleep
- * - add support for faster read FSTRD command
- */
-
-/************************************************************************************
- * Included Files
- ************************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <debug.h>
-#include <assert.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/spi.h>
-#include <nuttx/mtd.h>
-
-/************************************************************************************
- * Pre-processor Definitions
- ************************************************************************************/
-
-/* RAMTRON devices are flat!
- * For purpose of the VFAT file system we emulate the following configuration:
- */
-
-#define RAMTRON_EMULATE_SECTOR_SHIFT 9
-#define RAMTRON_EMULATE_PAGE_SHIFT 9
-
-/* RAMTRON Indentification register values */
-
-#define RAMTRON_MANUFACTURER 0x7F
-#define RAMTRON_MEMORY_TYPE 0xC2
-
-/* Instructions:
- * Command Value N Description Addr Dummy Data */
-#define RAMTRON_WREN 0x06 /* 1 Write Enable 0 0 0 */
-#define RAMTRON_WRDI 0x04 /* 1 Write Disable 0 0 0 */
-#define RAMTRON_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */
-#define RAMTRON_WRSR 0x01 /* 1 Write Status Register 0 0 1 */
-#define RAMTRON_READ 0x03 /* 1 Read Data Bytes A 0 >=1 */
-#define RAMTRON_FSTRD 0x0b /* 1 Higher speed read A 1 >=1 */
-#define RAMTRON_WRITE 0x02 /* 1 Write A 0 1-256 */
-#define RAMTRON_SLEEP 0xb9 // TODO:
-#define RAMTRON_RDID 0x9f /* 1 Read Identification 0 0 1-3 */
-#define RAMTRON_SN 0xc3 // TODO:
-
-
-/* Status register bit definitions */
-
-#define RAMTRON_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */
-#define RAMTRON_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */
-#define RAMTRON_SR_BP_SHIFT (2) /* Bits 2-4: Block protect bits */
-#define RAMTRON_SR_BP_MASK (7 << RAMTRON_SR_BP_SHIFT)
-# define RAMTRON_SR_BP_NONE (0 << RAMTRON_SR_BP_SHIFT) /* Unprotected */
-# define RAMTRON_SR_BP_UPPER64th (1 << RAMTRON_SR_BP_SHIFT) /* Upper 64th */
-# define RAMTRON_SR_BP_UPPER32nd (2 << RAMTRON_SR_BP_SHIFT) /* Upper 32nd */
-# define RAMTRON_SR_BP_UPPER16th (3 << RAMTRON_SR_BP_SHIFT) /* Upper 16th */
-# define RAMTRON_SR_BP_UPPER8th (4 << RAMTRON_SR_BP_SHIFT) /* Upper 8th */
-# define RAMTRON_SR_BP_UPPERQTR (5 << RAMTRON_SR_BP_SHIFT) /* Upper quarter */
-# define RAMTRON_SR_BP_UPPERHALF (6 << RAMTRON_SR_BP_SHIFT) /* Upper half */
-# define RAMTRON_SR_BP_ALL (7 << RAMTRON_SR_BP_SHIFT) /* All sectors */
-#define RAMTRON_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */
-
-#define RAMTRON_DUMMY 0xa5
-
-/************************************************************************************
- * Private Types
- ************************************************************************************/
-
-struct ramtron_parts_s
-{
- const char *name;
- uint8_t id1;
- uint8_t id2;
- uint32_t size;
- uint8_t addr_len;
- uint32_t speed;
-};
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s
- * must appear at the beginning of the definition so that you can freely
- * cast between pointers to struct mtd_dev_s and struct ramtron_dev_s.
- */
-
-struct ramtron_dev_s
-{
- struct mtd_dev_s mtd; /* MTD interface */
- FAR struct spi_dev_s *dev; /* Saved SPI interface instance */
- uint8_t sectorshift;
- uint8_t pageshift;
- uint16_t nsectors;
- uint32_t npages;
- const struct ramtron_parts_s *part; /* part instance */
-};
-
-/************************************************************************************
- * Supported Part Lists
- ************************************************************************************/
-
-/* Defines the initial speed compatible with all devices. In case of RAMTRON
- * the defined devices within the part list have all the same speed.
- */
-
-#define RAMTRON_INIT_CLK_MAX 40000000UL
-
-static struct ramtron_parts_s ramtron_parts[] =
-{
- {
- "FM25V02", /* name */
- 0x22, /* id1 */
- 0x00, /* id2 */
- 32L*1024L, /* size */
- 2, /* addr_len */
- 40000000 /* speed */
- },
- {
- "FM25VN02", /* name */
- 0x22, /* id1 */
- 0x01, /* id2 */
- 32L*1024L, /* size */
- 2, /* addr_len */
- 40000000 /* speed */
- },
- {
- "FM25V05", /* name */
- 0x23, /* id1 */
- 0x00, /* id2 */
- 64L*1024L, /* size */
- 2, /* addr_len */
- 40000000 /* speed */
- },
- {
- "FM25VN05", /* name */
- 0x23, /* id1 */
- 0x01, /* id2 */
- 64L*1024L, /* size */
- 2, /* addr_len */
- 40000000 /* speed */
- },
- {
- "FM25V10", /* name */
- 0x24, /* id1 */
- 0x00, /* id2 */
- 128L*1024L, /* size */
- 3, /* addr_len */
- 40000000 /* speed */
- },
- {
- "FM25VN10", /* name */
- 0x24, /* id1 */
- 0x01, /* id2 */
- 128L*1024L, /* size */
- 3, /* addr_len */
- 40000000 /* speed */
- },
-#ifdef CONFIG_RAMTRON_FRAM_NON_JEDEC
- {
- "FM25H20", /* name */
- 0xff, /* id1 */
- 0xff, /* id2 */
- 256L*1024L, /* size */
- 3, /* addr_len */
- 40000000 /* speed */
- },
- {
- NULL, /* name */
- 0, /* id1 */
- 0, /* id2 */
- 0, /* size */
- 0, /* addr_len */
- 0 /* speed */
- }
-#endif
-};
-
-
-/************************************************************************************
- * Private Function Prototypes
- ************************************************************************************/
-
-/* Helpers */
-
-static void ramtron_lock(FAR struct spi_dev_s *dev);
-static inline void ramtron_unlock(FAR struct spi_dev_s *dev);
-static inline int ramtron_readid(struct ramtron_dev_s *priv);
-static void ramtron_waitwritecomplete(struct ramtron_dev_s *priv);
-static void ramtron_writeenable(struct ramtron_dev_s *priv);
-static inline void ramtron_pagewrite(struct ramtron_dev_s *priv, FAR const uint8_t *buffer,
- off_t offset);
-
-/* MTD driver methods */
-
-static int ramtron_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t ramtron_bread(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR uint8_t *buf);
-static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf);
-static ssize_t ramtron_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer);
-static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/************************************************************************************
- * Private Data
- ************************************************************************************/
-
-/************************************************************************************
- * Private Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: ramtron_lock
- ************************************************************************************/
-
-static void ramtron_lock(FAR struct spi_dev_s *dev)
-{
- /* On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
- * transfers. The bus should be locked before the chip is selected.
- *
- * This is a blocking call and will not return until we have exclusiv access to
- * the SPI buss. We will retain that exclusive access until the bus is unlocked.
- */
-
- (void)SPI_LOCK(dev, true);
-
- /* After locking the SPI bus, the we also need call the setfrequency, setbits, and
- * setmode methods to make sure that the SPI is properly configured for the device.
- * If the SPI buss is being shared, then it may have been left in an incompatible
- * state.
- */
-
- SPI_SETMODE(dev, SPIDEV_MODE3);
- SPI_SETBITS(dev, 8);
-
- (void)SPI_SETFREQUENCY(dev, RAMTRON_INIT_CLK_MAX);
-}
-
-/************************************************************************************
- * Name: ramtron_unlock
- ************************************************************************************/
-
-static inline void ramtron_unlock(FAR struct spi_dev_s *dev)
-{
- (void)SPI_LOCK(dev, false);
-}
-
-/************************************************************************************
- * Name: ramtron_readid
- ************************************************************************************/
-
-static inline int ramtron_readid(struct ramtron_dev_s *priv)
-{
- uint16_t manufacturer, memory, capacity, part;
- int i;
-
- fvdbg("priv: %p\n", priv);
-
- /* Lock the SPI bus, configure the bus, and select this FLASH part. */
-
- ramtron_lock(priv->dev);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Read ID (RDID)" command and read the first three ID bytes */
-
- (void)SPI_SEND(priv->dev, RAMTRON_RDID);
- for (i = 0; i < 6; i++)
- {
- manufacturer = SPI_SEND(priv->dev, RAMTRON_DUMMY);
- }
-
- memory = SPI_SEND(priv->dev, RAMTRON_DUMMY);
- capacity = SPI_SEND(priv->dev, RAMTRON_DUMMY); // fram.id1
- part = SPI_SEND(priv->dev, RAMTRON_DUMMY); // fram.id2
-
- /* Deselect the FLASH and unlock the bus */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- ramtron_unlock(priv->dev);
-
- /* Select part from the part list */
-
- for (priv->part = ramtron_parts;
- priv->part->name != NULL && !(priv->part->id1 == capacity && priv->part->id2 == part);
- priv->part++);
-
- if (priv->part->name)
- {
- fvdbg("RAMTRON %s of size %d bytes (mf:%02x mem:%02x cap:%02x part:%02x)\n",
- priv->part->name, priv->part->size, manufacturer, memory, capacity, part);
-
- priv->sectorshift = RAMTRON_EMULATE_SECTOR_SHIFT;
- priv->nsectors = priv->part->size / (1 << RAMTRON_EMULATE_SECTOR_SHIFT);
- priv->pageshift = RAMTRON_EMULATE_PAGE_SHIFT;
- priv->npages = priv->part->size / (1 << RAMTRON_EMULATE_PAGE_SHIFT);
- return OK;
- }
-
- fvdbg("RAMTRON device not found\n");
- return -ENODEV;
-}
-
-/************************************************************************************
- * Name: ramtron_waitwritecomplete
- ************************************************************************************/
-
-static void ramtron_waitwritecomplete(struct ramtron_dev_s *priv)
-{
- uint8_t status;
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->dev, RAMTRON_RDSR);
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->dev, RAMTRON_DUMMY);
- }
- while ((status & RAMTRON_SR_WIP) != 0);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Complete\n");
-}
-
-/************************************************************************************
- * Name: ramtron_writeenable
- ************************************************************************************/
-
-static void ramtron_writeenable(struct ramtron_dev_s *priv)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Write Enable (WREN)" command */
-
- (void)SPI_SEND(priv->dev, RAMTRON_WREN);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Enabled\n");
-}
-
-/************************************************************************************
- * Name: ramtron_sendaddr
- ************************************************************************************/
-
-static inline void ramtron_sendaddr(const struct ramtron_dev_s *priv, uint32_t addr)
-{
- DEBUGASSERT(priv->part->addr_len == 3 || priv->part->addr_len == 2);
-
- if (priv->part->addr_len == 3)
- {
- (void)SPI_SEND(priv->dev, (addr >> 16) & 0xff);
- }
-
- (void)SPI_SEND(priv->dev, (addr >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, addr & 0xff);
-}
-
-/************************************************************************************
- * Name: ramtron_pagewrite
- ************************************************************************************/
-
-static inline void ramtron_pagewrite(struct ramtron_dev_s *priv, FAR const uint8_t *buffer,
- off_t page)
-{
- off_t offset = page << priv->pageshift;
-
- fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- ramtron_waitwritecomplete(priv);
-
- /* Enable the write access to the FLASH */
-
- ramtron_writeenable(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Page Program (PP)" command */
-
- (void)SPI_SEND(priv->dev, RAMTRON_WRITE);
-
- /* Send the page offset high byte first. */
-
- ramtron_sendaddr(priv, offset);
-
- /* Then write the specified number of bytes */
-
- SPI_SNDBLOCK(priv->dev, buffer, 1 << priv->pageshift);
-
- /* Deselect the FLASH: Chip Select high */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Written\n");
-}
-
-/************************************************************************************
- * Name: ramtron_erase
- ************************************************************************************/
-
-static int ramtron_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
- fvdbg("On RAMTRON devices erasing makes no sense, returning as OK\n");
- return (int)nblocks;
-}
-
-/************************************************************************************
- * Name: ramtron_bread
- ************************************************************************************/
-
-static ssize_t ramtron_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buffer)
-{
- FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev;
- ssize_t nbytes;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* On this device, we can handle the block read just like the byte-oriented read */
-
- nbytes = ramtron_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer);
- if (nbytes > 0)
- {
- return nbytes >> priv->pageshift;
- }
-
- return (int)nbytes;
-}
-
-/************************************************************************************
- * Name: ramtron_bwrite
- ************************************************************************************/
-
-static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
-{
- FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev;
- size_t blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock the SPI bus and write each page to FLASH */
-
- ramtron_lock(priv->dev);
- while (blocksleft-- > 0)
- {
- ramtron_pagewrite(priv, buffer, startblock);
- startblock++;
- }
-
- ramtron_unlock(priv->dev);
- return nblocks;
-}
-
-/************************************************************************************
- * Name: ramtron_read
- ************************************************************************************/
-
-static ssize_t ramtron_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
-{
- FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev;
-
- fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
-
- /* Wait for any preceding write to complete. We could simplify things by
- * perform this wait at the end of each write operation (rather than at
- * the beginning of ALL operations), but have the wait first will slightly
- * improve performance.
- */
-
- ramtron_waitwritecomplete(priv);
-
- /* Lock the SPI bus and select this FLASH part */
-
- ramtron_lock(priv->dev);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read from Memory " instruction */
-
- (void)SPI_SEND(priv->dev, RAMTRON_READ);
-
- /* Send the page offset high byte first. */
-
- ramtron_sendaddr(priv, offset);
-
- /* Then read all of the requested bytes */
-
- SPI_RECVBLOCK(priv->dev, buffer, nbytes);
-
- /* Deselect the FLASH and unlock the SPI bus */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- ramtron_unlock(priv->dev);
- fvdbg("return nbytes: %d\n", (int)nbytes);
- return nbytes;
-}
-
-/************************************************************************************
- * Name: ramtron_ioctl
- ************************************************************************************/
-
-static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- fvdbg("cmd: %d \n", cmd);
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- */
-
- geo->blocksize = (1 << priv->pageshift);
- geo->erasesize = (1 << priv->sectorshift);
- geo->neraseblocks = priv->nsectors;
- ret = OK;
-
- fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
- geo->blocksize, geo->erasesize, geo->neraseblocks);
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- fvdbg("BULDERASE: Makes no sense in ramtron. Let's confirm operation as OK\n");
- ret = OK;
- break;
-
- case MTDIOC_XIPBASE:
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- fvdbg("return %d\n", ret);
- return ret;
-}
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: ramtron_initialize
- *
- * Description:
- * Create an initialize MTD device instance. MTD devices are not registered
- * in the file system, but are created as instances that can be bound to
- * other functions (such as a block or character driver front end).
- *
- ************************************************************************************/
-
-FAR struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *dev)
-{
- FAR struct ramtron_dev_s *priv;
-
- fvdbg("dev: %p\n", dev);
-
- /* Allocate a state structure (we allocate the structure instead of using
- * a fixed, static allocation so that we can handle multiple FLASH devices.
- * The current implementation would handle only one FLASH part per SPI
- * device (only because of the SPIDEV_FLASH definition) and so would have
- * to be extended to handle multiple FLASH parts on the same SPI bus.
- */
-
- priv = (FAR struct ramtron_dev_s *)kmalloc(sizeof(struct ramtron_dev_s));
- if (priv)
- {
- /* Initialize the allocated structure */
-
- priv->mtd.erase = ramtron_erase;
- priv->mtd.bread = ramtron_bread;
- priv->mtd.bwrite = ramtron_bwrite;
- priv->mtd.read = ramtron_read;
- priv->mtd.ioctl = ramtron_ioctl;
- priv->dev = dev;
-
- /* Deselect the FLASH */
-
- SPI_SELECT(dev, SPIDEV_FLASH, false);
-
- /* Identify the FLASH chip and get its capacity */
-
- if (ramtron_readid(priv) != OK)
- {
- /* Unrecognized! Discard all of that work we just did and return NULL */
-
- kfree(priv);
- priv = NULL;
- }
- }
-
- /* Return the implementation-specific state structure as the MTD device */
-
- fvdbg("Return %p\n", priv);
- return (FAR struct mtd_dev_s *)priv;
-}
diff --git a/nuttx/drivers/mtd/skeleton.c b/nuttx/drivers/mtd/skeleton.c
deleted file mode 100644
index a2fb98238..000000000
--- a/nuttx/drivers/mtd/skeleton.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/****************************************************************************
- * drivers/mtd/skeleton.c
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <errno.h>
-
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/mtd.h>
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s
- * must appear at the beginning of the definition so that you can freely
- * cast between pointers to struct mtd_dev_s and struct skel_dev_s.
- */
-
-struct skel_dev_s
-{
- struct mtd_dev_s mtd;
-
- /* Other implementation specific data may follow here */
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/* MTD driver methods */
-
-static int skel_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t skel_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buf);
-static ssize_t skel_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buf);
-static ssize_t skel_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer);
-static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-static struct skel_dev_s g_skeldev =
-{
- { skel_erase, skel_rbead, skel_bwrite, skel_read, skel_ioctl },
- /* Initialization of any other implemenation specific data goes here */
-};
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: skel_erase
- ****************************************************************************/
-
-static int skel_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
- FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
-
- /* The interface definition assumes that all erase blocks ar the same size.
- * If that is not true for this particular device, then transform the
- * start block and nblocks as necessary.
- */
-
- /* Erase the specified blocks and return status (OK or a negated errno) */
-
- return OK;
-}
-
-/****************************************************************************
- * Name: skel_bread
- ****************************************************************************/
-
-static ssize_t skel_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buf)
-{
- FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
-
- /* The interface definition assumes that all read/write blocks ar the same size.
- * If that is not true for this particular device, then transform the
- * start block and nblocks as necessary.
- */
-
- /* Read the specified blocks into the provided user buffer and return status
- * (The positive, number of blocks actually read or a negated errno).
- */
-
- return 0;
-}
-
-/****************************************************************************
- * Name: skel_bwrite
- ****************************************************************************/
-
-static ssize_t skel_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buf)
-{
- FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
-
- /* The interface definition assumes that all read/write blocks ar the same size.
- * If that is not true for this particular device, then transform the
- * start block and nblocks as necessary.
- */
-
- /* Write the specified blocks from the provided user buffer and return status
- * (The positive, number of blocks actually written or a negated errno)
- */
-
- return 0;
-}
-
-/****************************************************************************
- * Name: skel_read
- ****************************************************************************/
-
-static ssize_t skel_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
-{
- FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
-
- /* Some devices may support byte oriented read (optional). Byte-oriented
- * writing is inherently block oriented on most MTD devices and is not supported.
- * It is recommended that low-level drivers not support read() if it requires
- * buffering -- let the higher level logic handle that. If the read method is
- * not implemented, just set the method pointer to NULL in the struct mtd_dev_s
- * instance.
- */
-
- /* The interface definition assumes that all read/write blocks ar the same size.
- * If that is not true for this particular device, then transform the
- * start block and nblocks as necessary.
- */
-
- /* Read the specified blocks into the provided user buffer and return status
- * (The positive, number of blocks actually read or a negated errno)
- */
-
- return 0;
-}
-
-/****************************************************************************
- * Name: skel_ioctl
- ****************************************************************************/
-
-static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FARstruct mtd_geometry_s *)arg;
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- */
-
- geo->blocksize = 512; /* Size of one read/write block */
- geo->erasesize = 4096; /* Size of one erase block */
- geo->neraseblocks = 1024; /* Number of erase blocks */
- ret = OK;
- }
- }
- break;
-
- case MTDIOC_XIPBASE:
- {
- FAR void **ppv = (FAR void**)arg;
-
- if (ppv)
- {
- /* If media is directly acccesible, return (void*) base address
- * of device memory. NULL otherwise. It is acceptable to omit
- * this case altogether and simply return -ENOTTY.
- */
-
- *ppv = NULL;
- ret = OK;
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- {
- /* Erase the entire device */
-
- ret = OK;
- }
- break;
-
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: skel_initialize
- *
- * Description:
- * Create and initialize an MTD device instance. MTD devices are not
- * registered in the file system, but are created as instances that can
- * be bound to other functions (such as a block or character driver front
- * end).
- *
- ****************************************************************************/
-
-void skel_initialize(void)
-{
- /* Perform initialization as necessary */
-
- /* Return the implementation-specific state structure as the MTD device */
-
- return (FAR struct mtd_dev_s *)&g_skeldev;
-}
diff --git a/nuttx/drivers/mtd/sst25.c b/nuttx/drivers/mtd/sst25.c
deleted file mode 100644
index 66d201add..000000000
--- a/nuttx/drivers/mtd/sst25.c
+++ /dev/null
@@ -1,1250 +0,0 @@
-/************************************************************************************
- * drivers/mtd/sst25.c
- * Driver for SPI-based SST25 FLASH.
- *
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ************************************************************************************/
-
-/************************************************************************************
- * Included Files
- ************************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/spi.h>
-#include <nuttx/mtd.h>
-
-/************************************************************************************
- * Pre-processor Definitions
- ************************************************************************************/
-/* Configuration ********************************************************************/
-/* Per the data sheet, the SST25 parts can be driven with either SPI mode 0 (CPOL=0
- * and CPHA=0) or mode 3 (CPOL=1 and CPHA=1). But I have heard that other devices
- * can operate in mode 0 or 1. So you may need to specify CONFIG_SST25_SPIMODE to
- * select the best mode for your device. If CONFIG_SST25_SPIMODE is not defined,
- * mode 0 will be used.
- */
-
-#ifndef CONFIG_SST25_SPIMODE
-# define CONFIG_SST25_SPIMODE SPIDEV_MODE0
-#endif
-
-/* SPI Frequency. May be up to 25MHz. */
-
-#ifndef CONFIG_SST25_SPIFREQUENCY
-# define CONFIG_SST25_SPIFREQUENCY 20000000
-#endif
-
-/* There is a bug in the current code when using the higher speed AAI write sequence.
- * The nature of the bug is that the WRDI instruction is not working. At the end
- * of the AAI sequence, the status register continues to report that the SST25 is
- * write enabled (WEL bit) and in AAI mode (AAI bit). This *must* be fixed in any
- * production code if you want to have proper write performance.
- */
-
-#warning "REVISIT"
-#undef CONFIG_SST25_SLOWWRITE
-#define CONFIG_SST25_SLOWWRITE 1
-
-/* SST25 Instructions ***************************************************************/
-/* Command Value Description Addr Data */
-/* Dummy */
-#define SST25_READ 0x03 /* Read data bytes 3 0 >=1 */
-#define SST25_FAST_READ 0x0b /* Higher speed read 3 1 >=1 */
-#define SST25_SE 0x20 /* 4Kb Sector erase 3 0 0 */
-#define SST25_BE32 0x52 /* 32Kbit block Erase 3 0 0 */
-#define SST25_BE64 0xd8 /* 64Kbit block Erase 3 0 0 */
-#define SST25_CE 0xc7 /* Chip erase 0 0 0 */
-#define SST25_CE_ALT 0x60 /* Chip erase (alternate) 0 0 0 */
-#define SST25_BP 0x02 /* Byte program 3 0 1 */
-#define SST25_AAI 0xad /* Auto address increment 3 0 >=2 */
-#define SST25_RDSR 0x05 /* Read status register 0 0 >=1 */
-#define SST25_EWSR 0x50 /* Write enable status 0 0 0 */
-#define SST25_WRSR 0x01 /* Write Status Register 0 0 1 */
-#define SST25_WREN 0x06 /* Write Enable 0 0 0 */
-#define SST25_WRDI 0x04 /* Write Disable 0 0 0 */
-#define SST25_RDID 0xab /* Read Identification 0 0 >=1 */
-#define SST25_RDID_ALT 0x90 /* Read Identification (alt) 0 0 >=1 */
-#define SST25_JEDEC_ID 0x9f /* JEDEC ID read 0 0 >=3 */
-#define SST25_EBSY 0x70 /* Enable SO RY/BY# status 0 0 0 */
-#define SST25_DBSY 0x80 /* Disable SO RY/BY# status 0 0 0 */
-
-/* SST25 Registers ******************************************************************/
-/* Read ID (RDID) register values */
-
-#define SST25_MANUFACTURER 0xbf /* SST manufacturer ID */
-#define SST25_VF032_DEVID 0x20 /* SSTVF032B device ID */
-
-/* JEDEC Read ID register values */
-
-#define SST25_JEDEC_MANUFACTURER 0xbf /* SST manufacturer ID */
-#define SST25_JEDEC_MEMORY_TYPE 0x25 /* SST25 memory type */
-#define SST25_JEDEC_MEMORY_CAPACITY 0x4a /* SST25VF032B memory capacity */
-
-/* Status register bit definitions */
-
-#define SST25_SR_BUSY (1 << 0) /* Bit 0: Write in progress */
-#define SST25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */
-#define SST25_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */
-#define SST25_SR_BP_MASK (15 << SST25_SR_BP_SHIFT)
-# define SST25_SR_BP_NONE (0 << SST25_SR_BP_SHIFT) /* Unprotected */
-# define SST25_SR_BP_UPPER64th (1 << SST25_SR_BP_SHIFT) /* Upper 64th */
-# define SST25_SR_BP_UPPER32nd (2 << SST25_SR_BP_SHIFT) /* Upper 32nd */
-# define SST25_SR_BP_UPPER16th (3 << SST25_SR_BP_SHIFT) /* Upper 16th */
-# define SST25_SR_BP_UPPER8th (4 << SST25_SR_BP_SHIFT) /* Upper 8th */
-# define SST25_SR_BP_UPPERQTR (5 << SST25_SR_BP_SHIFT) /* Upper quarter */
-# define SST25_SR_BP_UPPERHALF (6 << SST25_SR_BP_SHIFT) /* Upper half */
-# define SST25_SR_BP_ALL (7 << SST25_SR_BP_SHIFT) /* All sectors */
-#define SST25_SR_AAI (1 << 6) /* Bit 6: Auto Address increment programming */
-#define SST25_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */
-
-#define SST25_DUMMY 0xa5
-
-/* Chip Geometries ******************************************************************/
-/* SST25VF512 capacity is 512Kbit (64Kbit x 8) = 64Kb (8Kb x 8)*/
-/* SST25VF010 capacity is 1Mbit (128Kbit x 8) = 128Kb (16Kb x 8*/
-/* SST25VF520 capacity is 2Mbit (256Kbit x 8) = 256Kb (32Kb x 8) */
-/* SST25VF540 capacity is 4Mbit (512Kbit x 8) = 512Kb (64Kb x 8) */
-/* SST25VF080 capacity is 8Mbit (1024Kbit x 8) = 1Mb (128Kb x 8) */
-/* SST25VF016 capacity is 16Mbit (2048Kbit x 8) = 2Mb (256Kb x 8) */
-/* Not yet supported */
-
-/* SST25VF032 capacity is 32Mbit (4096Kbit x 8) = 4Mb (512kb x 8) */
-
-#define SST25_VF032_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4Kb */
-#define SST25_VF032_NSECTORS 1024 /* 1024 sectors x 4096 bytes/sector = 4Mb */
-
-#ifdef CONFIG_SST25_SECTOR512 /* Simulate a 512 byte sector */
-# define SST25_SECTOR_SHIFT 9 /* Sector size 1 << 9 = 512 bytes */
-# define SST25_SECTOR_SIZE 512 /* Sector size = 512 bytes */
-#endif
-
-#define SST25_ERASED_STATE 0xff /* State of FLASH when erased */
-
-/* Cache flags */
-
-#define SST25_CACHE_VALID (1 << 0) /* 1=Cache has valid data */
-#define SST25_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */
-#define SST25_CACHE_ERASED (1 << 2) /* 1=Backing FLASH is erased */
-
-#define IS_VALID(p) ((((p)->flags) & SST25_CACHE_VALID) != 0)
-#define IS_DIRTY(p) ((((p)->flags) & SST25_CACHE_DIRTY) != 0)
-#define IS_ERASED(p) ((((p)->flags) & SST25_CACHE_DIRTY) != 0)
-
-#define SET_VALID(p) do { (p)->flags |= SST25_CACHE_VALID; } while (0)
-#define SET_DIRTY(p) do { (p)->flags |= SST25_CACHE_DIRTY; } while (0)
-#define SET_ERASED(p) do { (p)->flags |= SST25_CACHE_DIRTY; } while (0)
-
-#define CLR_VALID(p) do { (p)->flags &= ~SST25_CACHE_VALID; } while (0)
-#define CLR_DIRTY(p) do { (p)->flags &= ~SST25_CACHE_DIRTY; } while (0)
-#define CLR_ERASED(p) do { (p)->flags &= ~SST25_CACHE_DIRTY; } while (0)
-
-/************************************************************************************
- * Private Types
- ************************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s must
- * appear at the beginning of the definition so that you can freely cast between
- * pointers to struct mtd_dev_s and struct sst25_dev_s.
- */
-
-struct sst25_dev_s
-{
- struct mtd_dev_s mtd; /* MTD interface */
- FAR struct spi_dev_s *dev; /* Saved SPI interface instance */
- uint16_t nsectors; /* Number of erase sectors */
- uint8_t sectorshift; /* Log2 of erase sector size */
-
-#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY)
- uint8_t flags; /* Buffered sector flags */
- uint16_t esectno; /* Erase sector number in the cache*/
- FAR uint8_t *sector; /* Allocated sector data */
-#endif
-};
-
-/************************************************************************************
- * Private Function Prototypes
- ************************************************************************************/
-
-/* Helpers */
-
-static void sst25_lock(FAR struct spi_dev_s *dev);
-static inline void sst25_unlock(FAR struct spi_dev_s *dev);
-static inline int sst25_readid(FAR struct sst25_dev_s *priv);
-#ifndef CONFIG_SST25_READONLY
-static void sst25_unprotect(FAR struct spi_dev_s *dev);
-#endif
-static uint8_t sst25_waitwritecomplete(FAR struct sst25_dev_s *priv);
-static inline void sst25_wren(FAR struct sst25_dev_s *priv);
-static inline void sst25_wrdi(FAR struct sst25_dev_s *priv);
-static void sst25_sectorerase(FAR struct sst25_dev_s *priv, off_t offset);
-static inline int sst25_chiperase(FAR struct sst25_dev_s *priv);
-static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer,
- off_t address, size_t nbytes);
-#ifndef CONFIG_SST25_READONLY
-#ifdef CONFIG_SST25_SLOWWRITE
-static void sst25_bytewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
- off_t address, size_t nbytes);
-#else
-static void sst25_wordwrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
- off_t address, size_t nbytes);
-#endif
-#ifdef CONFIG_SST25_SECTOR512
-static void sst25_cacheflush(struct sst25_dev_s *priv);
-static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector);
-static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector);
-static void sst25_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
- off_t sector, size_t nsectors);
-#endif
-#endif
-
-/* MTD driver methods */
-
-static int sst25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR uint8_t *buf);
-static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf);
-static ssize_t sst25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer);
-static int sst25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/************************************************************************************
- * Private Data
- ************************************************************************************/
-
-/************************************************************************************
- * Private Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: sst25_lock
- ************************************************************************************/
-
-static void sst25_lock(FAR struct spi_dev_s *dev)
-{
- /* On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
- * transfers. The bus should be locked before the chip is selected.
- *
- * This is a blocking call and will not return until we have exclusiv access to
- * the SPI buss. We will retain that exclusive access until the bus is unlocked.
- */
-
- (void)SPI_LOCK(dev, true);
-
- /* After locking the SPI bus, the we also need call the setfrequency, setbits, and
- * setmode methods to make sure that the SPI is properly configured for the device.
- * If the SPI buss is being shared, then it may have been left in an incompatible
- * state.
- */
-
- SPI_SETMODE(dev, CONFIG_SST25_SPIMODE);
- SPI_SETBITS(dev, 8);
- (void)SPI_SETFREQUENCY(dev, CONFIG_SST25_SPIFREQUENCY);
-}
-
-/************************************************************************************
- * Name: sst25_unlock
- ************************************************************************************/
-
-static inline void sst25_unlock(FAR struct spi_dev_s *dev)
-{
- (void)SPI_LOCK(dev, false);
-}
-
-/************************************************************************************
- * Name: sst25_readid
- ************************************************************************************/
-
-static inline int sst25_readid(struct sst25_dev_s *priv)
-{
- uint16_t manufacturer;
- uint16_t memory;
- uint16_t capacity;
-
- fvdbg("priv: %p\n", priv);
-
- /* Lock the SPI bus, configure the bus, and select this FLASH part. */
-
- sst25_lock(priv->dev);
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Read ID (RDID)" command and read the first three ID bytes */
-
- (void)SPI_SEND(priv->dev, SST25_JEDEC_ID);
- manufacturer = SPI_SEND(priv->dev, SST25_DUMMY);
- memory = SPI_SEND(priv->dev, SST25_DUMMY);
- capacity = SPI_SEND(priv->dev, SST25_DUMMY);
-
- /* Deselect the FLASH and unlock the bus */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- sst25_unlock(priv->dev);
-
- fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n",
- manufacturer, memory, capacity);
-
- /* Check for a valid manufacturer and memory type */
-
- if (manufacturer == SST25_JEDEC_MANUFACTURER && memory == SST25_JEDEC_MEMORY_TYPE)
- {
- /* Okay.. is it a FLASH capacity that we understand? This should be extended
- * support other members of the SST25 family.
- */
-
- if (capacity == SST25_JEDEC_MEMORY_CAPACITY)
- {
- /* Save the FLASH geometry */
-
- priv->sectorshift = SST25_VF032_SECTOR_SHIFT;
- priv->nsectors = SST25_VF032_NSECTORS;
- return OK;
- }
- }
-
- return -ENODEV;
-}
-
-/************************************************************************************
- * Name: sst25_unprotect
- ************************************************************************************/
-
-#ifndef CONFIG_SST25_READONLY
-static void sst25_unprotect(FAR struct spi_dev_s *dev)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(dev, SPIDEV_FLASH, true);
-
- /* Send "Write enable status (EWSR)" */
-
- SPI_SEND(dev, SST25_EWSR);
-
- /* Re-select this FLASH part (This might not be necessary... but is it shown in
- * the timing diagrams)
- */
-
- SPI_SELECT(dev, SPIDEV_FLASH, false);
- SPI_SELECT(dev, SPIDEV_FLASH, true);
-
- /* Send "Write enable status (EWSR)" */
-
- SPI_SEND(dev, SST25_WRSR);
-
- /* Following by the new status value */
-
- SPI_SEND(dev, 0);
-}
-#endif
-
-/************************************************************************************
- * Name: sst25_waitwritecomplete
- ************************************************************************************/
-
-static uint8_t sst25_waitwritecomplete(struct sst25_dev_s *priv)
-{
- uint8_t status;
-
- /* Are we the only device on the bus? */
-
-#ifdef CONFIG_SPI_OWNBUS
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->dev, SST25_RDSR);
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->dev, SST25_DUMMY);
- }
- while ((status & SST25_SR_BUSY) != 0);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
-#else
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->dev, SST25_RDSR);
-
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->dev, SST25_DUMMY);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
- /* Given that writing could take up to few tens of milliseconds, and erasing
- * could take more. The following short delay in the "busy" case will allow
- * other peripherals to access the SPI bus.
- */
-
-#if 0 /* Makes writes too slow */
- if ((status & SST25_SR_BUSY) != 0)
- {
- sst25_unlock(priv->dev);
- usleep(1000);
- sst25_lock(priv->dev);
- }
-#endif
- }
- while ((status & SST25_SR_BUSY) != 0);
-#endif
-
- return status;
-}
-
-/************************************************************************************
- * Name: sst25_wren
- ************************************************************************************/
-
-static inline void sst25_wren(struct sst25_dev_s *priv)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Write Enable (WREN)" command */
-
- (void)SPI_SEND(priv->dev, SST25_WREN);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: sst25_wrdi
- ************************************************************************************/
-
-static inline void sst25_wrdi(struct sst25_dev_s *priv)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Write Disable (WRDI)" command */
-
- (void)SPI_SEND(priv->dev, SST25_WRDI);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: sst25_sectorerase
- ************************************************************************************/
-
-static void sst25_sectorerase(struct sst25_dev_s *priv, off_t sector)
-{
- off_t address = sector << priv->sectorshift;
-
- fvdbg("sector: %08lx\n", (long)sector);
-
- /* Wait for any preceding write or erase operation to complete. */
-
- (void)sst25_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- sst25_wren(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Sector Erase (SE)" instruction */
-
- (void)SPI_SEND(priv->dev, SST25_SE);
-
- /* Send the sector address high byte first. Only the most significant bits (those
- * corresponding to the sector) have any meaning.
- */
-
- (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, address & 0xff);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: sst25_chiperase
- ************************************************************************************/
-
-static inline int sst25_chiperase(struct sst25_dev_s *priv)
-{
- fvdbg("priv: %p\n", priv);
-
- /* Wait for any preceding write or erase operation to complete. */
-
- (void)sst25_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- sst25_wren(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send the "Chip Erase (CE)" instruction */
-
- (void)SPI_SEND(priv->dev, SST25_CE);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Return: OK\n");
- return OK;
-}
-
-/************************************************************************************
- * Name: sst25_byteread
- ************************************************************************************/
-
-static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer,
- off_t address, size_t nbytes)
-{
- uint8_t status;
-
- fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes);
-
- /* Wait for any preceding write or erase operation to complete. */
-
- status = sst25_waitwritecomplete(priv);
- DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Read from Memory " instruction */
-
-#ifdef CONFIG_SST25_SLOWREAD
- (void)SPI_SEND(priv->dev, SST25_READ);
-#else
- (void)SPI_SEND(priv->dev, SST25_FAST_READ);
-#endif
-
- /* Send the address high byte first. */
-
- (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, address & 0xff);
-
- /* Send a dummy byte */
-
-#ifndef CONFIG_SST25_SLOWREAD
- (void)SPI_SEND(priv->dev, SST25_DUMMY);
-#endif
-
- /* Then read all of the requested bytes */
-
- SPI_RECVBLOCK(priv->dev, buffer, nbytes);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: sst25_bytewrite
- ************************************************************************************/
-
-#if defined(CONFIG_SST25_SLOWWRITE) && !defined(CONFIG_SST25_READONLY)
-static void sst25_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
- off_t address, size_t nbytes)
-{
- uint8_t status;
-
- fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nbytes);
- DEBUGASSERT(priv && buffer);
-
- /* Write each byte individually */
-
- for (; nbytes > 0; nbytes--)
- {
- /* Skip over bytes that are begin written to the erased state */
-
- if (*buffer != SST25_ERASED_STATE)
- {
- /* Wait for any preceding write or erase operation to complete. */
-
- status = sst25_waitwritecomplete(priv);
- DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0);
-
- /* Enable write access to the FLASH */
-
- sst25_wren(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Byte Program (BP)" command */
-
- (void)SPI_SEND(priv->dev, SST25_BP);
-
- /* Send the byte address high byte first. */
-
- (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, address & 0xff);
-
- /* Then write the single byte */
-
- (void)SPI_SEND(priv->dev, *buffer);
-
- /* Deselect the FLASH and setup for the next pass through the loop */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- }
-
- /* Advance to the next byte */
-
- buffer++;
- address++;
- }
-}
-#endif
-
-/************************************************************************************
- * Name: sst25_wordwrite
- ************************************************************************************/
-
-#if !defined(CONFIG_SST25_SLOWWRITE) && !defined(CONFIG_SST25_READONLY)
-static void sst25_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
- off_t address, size_t nbytes)
-{
- size_t nwords = (nbytes + 1) >> 1;
- uint8_t status;
-
- fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nwords);
- DEBUGASSERT(priv && buffer);
-
- /* Loop until all of the bytes have been written */
-
- while (nwords > 0)
- {
- /* Skip over any data that is being written to the erased state */
-
- while (nwords > 0 &&
- buffer[0] == SST25_ERASED_STATE &&
- buffer[1] == SST25_ERASED_STATE)
- {
- /* Decrement the word count and advance the write position */
-
- nwords--;
- buffer += 2;
- address += 2;
- }
-
- /* If there are no further non-erased bytes in the user buffer, then
- * we are finished.
- */
-
- if (nwords <= 0)
- {
- return;
- }
-
- /* Wait for any preceding write or erase operation to complete. */
-
- status = sst25_waitwritecomplete(priv);
- DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0);
-
- /* Enable write access to the FLASH */
-
- sst25_wren(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Auto Address Increment (AAI)" command */
-
- (void)SPI_SEND(priv->dev, SST25_AAI);
-
- /* Send the word address high byte first. */
-
- (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, address & 0xff);
-
- /* Then write one 16-bit word */
-
- SPI_SNDBLOCK(priv->dev, buffer, 2);
-
- /* Deselect the FLASH: Chip Select high */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
- /* Decrement the word count and advance the write position */
-
- nwords--;
- buffer += 2;
- address += 2;
-
- /* Now loop, writing 16-bits of data on each pass through the loop
- * until all of the words have been transferred or until we encounter
- * data to be written to the erased state.
- */
-
- while (nwords > 0 &&
- (buffer[0] != SST25_ERASED_STATE ||
- buffer[1] != SST25_ERASED_STATE))
- {
- /* Wait for the preceding write to complete. */
-
- status = sst25_waitwritecomplete(priv);
- DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == (SST25_SR_WEL|SST25_SR_AAI));
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
-
- /* Send "Auto Address Increment (AAI)" command with no address */
-
- (void)SPI_SEND(priv->dev, SST25_AAI);
-
- /* Then write one 16-bit word */
-
- SPI_SNDBLOCK(priv->dev, buffer, 2);
-
- /* Deselect the FLASH: Chip Select high */
-
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
-
- /* Decrement the word count and advance the write position */
-
- nwords--;
- buffer += 2;
- address += 2;
- }
-
- /* Disable writing */
-
- sst25_wrdi(priv);
- }
-}
-#endif
-
-/************************************************************************************
- * Name: sst25_cacheflush
- ************************************************************************************/
-
-#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY)
-static void sst25_cacheflush(struct sst25_dev_s *priv)
-{
- /* If the cached is dirty (meaning that it no longer matches the old FLASH contents)
- * or was erased (with the cache containing the correct FLASH contents), then write
- * the cached erase block to FLASH.
- */
-
- if (IS_DIRTY(priv) || IS_ERASED(priv))
- {
- /* Write entire erase block to FLASH */
-
-#ifdef CONFIG_SST25_SLOWWRITE
- sst25_bytewrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift,
- (1 << priv->sectorshift));
-#else
- sst25_wordwrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift,
- (1 << priv->sectorshift));
-#endif
-
- /* The case is no long dirty and the FLASH is no longer erased */
-
- CLR_DIRTY(priv);
- CLR_ERASED(priv);
- }
-}
-#endif
-
-/************************************************************************************
- * Name: sst25_cacheread
- ************************************************************************************/
-
-#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY)
-static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector)
-{
- off_t esectno;
- int shift;
- int index;
-
- /* Convert from the 512 byte sector to the erase sector size of the device. For
- * exmample, if the actual erase sector size if 4Kb (1 << 12), then we first
- * shift to the right by 3 to get the sector number in 4096 increments.
- */
-
- shift = priv->sectorshift - SST25_SECTOR_SHIFT;
- esectno = sector >> shift;
- fvdbg("sector: %ld esectno: %d shift=%d\n", sector, esectno, shift);
-
- /* Check if the requested erase block is already in the cache */
-
- if (!IS_VALID(priv) || esectno != priv->esectno)
- {
- /* No.. Flush any dirty erase block currently in the cache */
-
- sst25_cacheflush(priv);
-
- /* Read the erase block into the cache */
-
- sst25_byteread(priv, priv->sector, (esectno << priv->sectorshift), 1 << priv->sectorshift);
-
- /* Mark the sector as cached */
-
- priv->esectno = esectno;
-
- SET_VALID(priv); /* The data in the cache is valid */
- CLR_DIRTY(priv); /* It should match the FLASH contents */
- CLR_ERASED(priv); /* The underlying FLASH has not been erased */
- }
-
- /* Get the index to the 512 sector in the erase block that holds the argument */
-
- index = sector & ((1 << shift) - 1);
-
- /* Return the address in the cache that holds this sector */
-
- return &priv->sector[index << SST25_SECTOR_SHIFT];
-}
-#endif
-
-/************************************************************************************
- * Name: sst25_cacheerase
- ************************************************************************************/
-
-#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY)
-static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector)
-{
- FAR uint8_t *dest;
-
- /* First, make sure that the erase block containing the 512 byte sector is in
- * the cache.
- */
-
- dest = sst25_cacheread(priv, sector);
-
- /* Erase the block containing this sector if it is not already erased.
- * The erased indicated will be cleared when the data from the erase sector
- * is read into the cache and set here when we erase the block.
- */
-
- if (!IS_ERASED(priv))
- {
- off_t esectno = sector >> (priv->sectorshift - SST25_SECTOR_SHIFT);
- fvdbg("sector: %ld esectno: %d\n", sector, esectno);
-
- sst25_sectorerase(priv, esectno);
- SET_ERASED(priv);
- }
-
- /* Put the cached sector data into the erase state and mart the cache as dirty
- * (but don't update the FLASH yet. The caller will do that at a more optimal
- * time).
- */
-
- memset(dest, SST25_ERASED_STATE, SST25_SECTOR_SIZE);
- SET_DIRTY(priv);
-}
-#endif
-
-/************************************************************************************
- * Name: sst25_cachewrite
- ************************************************************************************/
-
-#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY)
-static void sst25_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
- off_t sector, size_t nsectors)
-{
- FAR uint8_t *dest;
-
- for (; nsectors > 0; nsectors--)
- {
- /* First, make sure that the erase block containing 512 byte sector is in
- * memory.
- */
-
- dest = sst25_cacheread(priv, sector);
-
- /* Erase the block containing this sector if it is not already erased.
- * The erased indicated will be cleared when the data from the erase sector
- * is read into the cache and set here when we erase the sector.
- */
-
- if (!IS_ERASED(priv))
- {
- off_t esectno = sector >> (priv->sectorshift - SST25_SECTOR_SHIFT);
- fvdbg("sector: %ld esectno: %d\n", sector, esectno);
-
- sst25_sectorerase(priv, esectno);
- SET_ERASED(priv);
- }
-
- /* Copy the new sector data into cached erase block */
-
- memcpy(dest, buffer, SST25_SECTOR_SIZE);
- SET_DIRTY(priv);
-
- /* Set up for the next 512 byte sector */
-
- buffer += SST25_SECTOR_SIZE;
- sector++;
- }
-
- /* Flush the last erase block left in the cache */
-
- sst25_cacheflush(priv);
-}
-#endif
-
-/************************************************************************************
- * Name: sst25_erase
- ************************************************************************************/
-
-static int sst25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
-#ifdef CONFIG_SST25_READONLY
- return -EACESS
-#else
- FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev;
- size_t blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock access to the SPI bus until we complete the erase */
-
- sst25_lock(priv->dev);
-
- while (blocksleft-- > 0)
- {
- /* Erase each sector */
-
-#ifdef CONFIG_SST25_SECTOR512
- sst25_cacheerase(priv, startblock);
-#else
- sst25_sectorerase(priv, startblock);
-#endif
- startblock++;
- }
-
-#ifdef CONFIG_SST25_SECTOR512
- /* Flush the last erase block left in the cache */
-
- sst25_cacheflush(priv);
-#endif
-
- sst25_unlock(priv->dev);
- return (int)nblocks;
-#endif
-}
-
-/************************************************************************************
- * Name: sst25_bread
- ************************************************************************************/
-
-static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buffer)
-{
-#ifdef CONFIG_SST25_SECTOR512
- ssize_t nbytes;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* On this device, we can handle the block read just like the byte-oriented read */
-
- nbytes = sst25_read(dev, startblock << SST25_SECTOR_SHIFT, nblocks << SST25_SECTOR_SHIFT, buffer);
- if (nbytes > 0)
- {
- return nbytes >> SST25_SECTOR_SHIFT;
- }
-
- return (int)nbytes;
-#else
- FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev;
- ssize_t nbytes;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* On this device, we can handle the block read just like the byte-oriented read */
-
- nbytes = sst25_read(dev, startblock << priv->sectorshift, nblocks << priv->sectorshift, buffer);
- if (nbytes > 0)
- {
- return nbytes >> priv->sectorshift;
- }
-
- return (int)nbytes;
-#endif
-}
-
-/************************************************************************************
- * Name: sst25_bwrite
- ************************************************************************************/
-
-static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
-{
-#ifdef CONFIG_SST25_READONLY
- return -EACCESS;
-#else
- FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock the SPI bus and write all of the pages to FLASH */
-
- sst25_lock(priv->dev);
-
-#if defined(CONFIG_SST25_SECTOR512)
- sst25_cachewrite(priv, buffer, startblock, nblocks);
-#elif defined(CONFIG_SST25_SLOWWRITE)
- sst25_bytewrite(priv, buffer, startblock << priv->sectorshift,
- nblocks << priv->sectorshift);
-#else
- sst25_wordwrite(priv, buffer, startblock << priv->sectorshift,
- nblocks << priv->sectorshift);
-#endif
- sst25_unlock(priv->dev);
-
- return nblocks;
-#endif
-}
-
-/************************************************************************************
- * Name: sst25_read
- ************************************************************************************/
-
-static ssize_t sst25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
-{
- FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev;
-
- fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
-
- /* Lock the SPI bus and select this FLASH part */
-
- sst25_lock(priv->dev);
- sst25_byteread(priv, buffer, offset, nbytes);
- sst25_unlock(priv->dev);
-
- fvdbg("return nbytes: %d\n", (int)nbytes);
- return nbytes;
-}
-
-/************************************************************************************
- * Name: sst25_ioctl
- ************************************************************************************/
-
-static int sst25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- fvdbg("cmd: %d \n", cmd);
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- */
-
-#ifdef CONFIG_SST25_SECTOR512
- geo->blocksize = (1 << SST25_SECTOR_SHIFT);
- geo->erasesize = (1 << SST25_SECTOR_SHIFT);
- geo->neraseblocks = priv->nsectors << (priv->sectorshift - );
-#else
- geo->blocksize = (1 << priv->sectorshift);
- geo->erasesize = (1 << priv->sectorshift);
- geo->neraseblocks = priv->nsectors;
-#endif
- ret = OK;
-
- fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
- geo->blocksize, geo->erasesize, geo->neraseblocks);
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- {
- /* Erase the entire device */
-
- sst25_lock(priv->dev);
- ret = sst25_chiperase(priv);
- sst25_unlock(priv->dev);
- }
- break;
-
- case MTDIOC_XIPBASE:
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- fvdbg("return %d\n", ret);
- return ret;
-}
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: sst25_initialize
- *
- * Description:
- * Create an initialize MTD device instance. MTD devices are not registered
- * in the file system, but are created as instances that can be bound to
- * other functions (such as a block or character driver front end).
- *
- ************************************************************************************/
-
-FAR struct mtd_dev_s *sst25_initialize(FAR struct spi_dev_s *dev)
-{
- FAR struct sst25_dev_s *priv;
- int ret;
-
- fvdbg("dev: %p\n", dev);
-
- /* Allocate a state structure (we allocate the structure instead of using
- * a fixed, static allocation so that we can handle multiple FLASH devices.
- * The current implementation would handle only one FLASH part per SPI
- * device (only because of the SPIDEV_FLASH definition) and so would have
- * to be extended to handle multiple FLASH parts on the same SPI bus.
- */
-
- priv = (FAR struct sst25_dev_s *)kzalloc(sizeof(struct sst25_dev_s));
- if (priv)
- {
- /* Initialize the allocated structure */
-
- priv->mtd.erase = sst25_erase;
- priv->mtd.bread = sst25_bread;
- priv->mtd.bwrite = sst25_bwrite;
- priv->mtd.read = sst25_read;
- priv->mtd.ioctl = sst25_ioctl;
- priv->dev = dev;
-
- /* Deselect the FLASH */
-
- SPI_SELECT(dev, SPIDEV_FLASH, false);
-
- /* Identify the FLASH chip and get its capacity */
-
- ret = sst25_readid(priv);
- if (ret != OK)
- {
- /* Unrecognized! Discard all of that work we just did and return NULL */
-
- fdbg("Unrecognized\n");
- kfree(priv);
- priv = NULL;
- }
- else
- {
- /* Make sure the the FLASH is unprotected so that we can write into it */
-
-#ifndef CONFIG_SST25_READONLY
- sst25_unprotect(priv->dev);
-#endif
-
-#ifdef CONFIG_SST25_SECTOR512 /* Simulate a 512 byte sector */
- /* Allocate a buffer for the erase block cache */
-
- priv->sector = (FAR uint8_t *)kmalloc(1 << priv->sectorshift);
- if (!priv->sector)
- {
- /* Allocation failed! Discard all of that work we just did and return NULL */
-
- fdbg("Allocation failed\n");
- kfree(priv);
- priv = NULL;
- }
-#endif
- }
- }
-
- /* Return the implementation-specific state structure as the MTD device */
-
- fvdbg("Return %p\n", priv);
- return (FAR struct mtd_dev_s *)priv;
-}
diff --git a/nuttx/drivers/mtd/w25.c b/nuttx/drivers/mtd/w25.c
deleted file mode 100644
index bd6680fdf..000000000
--- a/nuttx/drivers/mtd/w25.c
+++ /dev/null
@@ -1,1179 +0,0 @@
-/************************************************************************************
- * drivers/mtd/w25.c
- * Driver for SPI-based W25x16, x32, and x64 and W25q16, q32, q64, and q128 FLASH
- *
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ************************************************************************************/
-
-/************************************************************************************
- * Included Files
- ************************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/ioctl.h>
-#include <nuttx/spi.h>
-#include <nuttx/mtd.h>
-
-/************************************************************************************
- * Pre-processor Definitions
- ************************************************************************************/
-/* Configuration ********************************************************************/
-/* Per the data sheet, the W25 parts can be driven with either SPI mode 0 (CPOL=0
- * and CPHA=0) or mode 3 (CPOL=1 and CPHA=1). But I have heard that other devices
- * can operate in mode 0 or 1. So you may need to specify CONFIG_W25_SPIMODE to
- * select the best mode for your device. If CONFIG_W25_SPIMODE is not defined,
- * mode 0 will be used.
- */
-
-#ifndef CONFIG_W25_SPIMODE
-# define CONFIG_W25_SPIMODE SPIDEV_MODE0
-#endif
-
-/* SPI Frequency. May be up to 25MHz. */
-
-#ifndef CONFIG_W25_SPIFREQUENCY
-# define CONFIG_W25_SPIFREQUENCY 20000000
-#endif
-
-/* W25 Instructions *****************************************************************/
-/* Command Value Description */
-/* */
-#define W25_WREN 0x06 /* Write enable */
-#define W25_WRDI 0x04 /* Write Disable */
-#define W25_RDSR 0x05 /* Read status register */
-#define W25_WRSR 0x01 /* Write Status Register */
-#define W25_RDDATA 0x03 /* Read data bytes */
-#define W25_FRD 0x0b /* Higher speed read */
-#define W25_FRDD 0x3b /* Fast read, dual output */
-#define W25_PP 0x02 /* Program page */
-#define W25_BE 0xd8 /* Block Erase (64KB) */
-#define W25_SE 0x20 /* Sector erase (4KB) */
-#define W25_CE 0xc7 /* Chip erase */
-#define W25_PD 0xb9 /* Power down */
-#define W25_PURDID 0xab /* Release PD, Device ID */
-#define W25_RDMFID 0x90 /* Read Manufacturer / Device */
-#define W25_JEDEC_ID 0x9f /* JEDEC ID read */
-
-/* W25 Registers ********************************************************************/
-/* Read ID (RDID) register values */
-
-#define W25_MANUFACTURER 0xef /* Winbond Serial Flash */
-#define W25X16_DEVID 0x14 /* W25X16 device ID (0xab, 0x90) */
-#define W25X32_DEVID 0x15 /* W25X16 device ID (0xab, 0x90) */
-#define W25X64_DEVID 0x16 /* W25X16 device ID (0xab, 0x90) */
-
-/* JEDEC Read ID register values */
-
-#define W25_JEDEC_MANUFACTURER 0xef /* SST manufacturer ID */
-#define W25X_JEDEC_MEMORY_TYPE 0x30 /* W25X memory type */
-#define W25Q_JEDEC_MEMORY_TYPE_A 0x40 /* W25Q memory type */
-#define W25Q_JEDEC_MEMORY_TYPE_B 0x60 /* W25Q memory type */
-
-#define W25_JEDEC_CAPACITY_16MBIT 0x15 /* 512x4096 = 16Mbit memory capacity */
-#define W25_JEDEC_CAPACITY_32MBIT 0x16 /* 1024x4096 = 32Mbit memory capacity */
-#define W25_JEDEC_CAPACITY_64MBIT 0x17 /* 2048x4096 = 64Mbit memory capacity */
-#define W25_JEDEC_CAPACITY_128MBIT 0x18 /* 4096x4096 = 128Mbit memory capacity */
-
-#define NSECTORS_16MBIT 512 /* 512 sectors x 4096 bytes/sector = 2Mb */
-#define NSECTORS_32MBIT 1024 /* 1024 sectors x 4096 bytes/sector = 4Mb */
-#define NSECTORS_64MBIT 2048 /* 2048 sectors x 4096 bytes/sector = 8Mb */
-#define NSECTORS_128MBIT 4096 /* 4096 sectors x 4096 bytes/sector = 16Mb */
-
-/* Status register bit definitions */
-
-#define W25_SR_BUSY (1 << 0) /* Bit 0: Write in progress */
-#define W25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */
-#define W25_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */
-#define W25_SR_BP_MASK (15 << W25_SR_BP_SHIFT)
-# define W25X16_SR_BP_NONE (0 << W25_SR_BP_SHIFT) /* Unprotected */
-# define W25X16_SR_BP_UPPER32nd (1 << W25_SR_BP_SHIFT) /* Upper 32nd */
-# define W25X16_SR_BP_UPPER16th (2 << W25_SR_BP_SHIFT) /* Upper 16th */
-# define W25X16_SR_BP_UPPER8th (3 << W25_SR_BP_SHIFT) /* Upper 8th */
-# define W25X16_SR_BP_UPPERQTR (4 << W25_SR_BP_SHIFT) /* Upper quarter */
-# define W25X16_SR_BP_UPPERHALF (5 << W25_SR_BP_SHIFT) /* Upper half */
-# define W25X16_SR_BP_ALL (6 << W25_SR_BP_SHIFT) /* All sectors */
-# define W25X16_SR_BP_LOWER32nd (9 << W25_SR_BP_SHIFT) /* Lower 32nd */
-# define W25X16_SR_BP_LOWER16th (10 << W25_SR_BP_SHIFT) /* Lower 16th */
-# define W25X16_SR_BP_LOWER8th (11 << W25_SR_BP_SHIFT) /* Lower 8th */
-# define W25X16_SR_BP_LOWERQTR (12 << W25_SR_BP_SHIFT) /* Lower quarter */
-# define W25X16_SR_BP_LOWERHALF (13 << W25_SR_BP_SHIFT) /* Lower half */
-
-# define W25X32_SR_BP_NONE (0 << W25_SR_BP_SHIFT) /* Unprotected */
-# define W25X32_SR_BP_UPPER64th (1 << W25_SR_BP_SHIFT) /* Upper 64th */
-# define W25X32_SR_BP_UPPER32nd (2 << W25_SR_BP_SHIFT) /* Upper 32nd */
-# define W25X32_SR_BP_UPPER16th (3 << W25_SR_BP_SHIFT) /* Upper 16th */
-# define W25X32_SR_BP_UPPER8th (4 << W25_SR_BP_SHIFT) /* Upper 8th */
-# define W25X32_SR_BP_UPPERQTR (5 << W25_SR_BP_SHIFT) /* Upper quarter */
-# define W25X32_SR_BP_UPPERHALF (6 << W25_SR_BP_SHIFT) /* Upper half */
-# define W25X32_SR_BP_ALL (7 << W25_SR_BP_SHIFT) /* All sectors */
-# define W25X32_SR_BP_LOWER64th (9 << W25_SR_BP_SHIFT) /* Lower 64th */
-# define W25X32_SR_BP_LOWER32nd (10 << W25_SR_BP_SHIFT) /* Lower 32nd */
-# define W25X32_SR_BP_LOWER16th (11 << W25_SR_BP_SHIFT) /* Lower 16th */
-# define W25X32_SR_BP_LOWER8th (12 << W25_SR_BP_SHIFT) /* Lower 8th */
-# define W25X32_SR_BP_LOWERQTR (13 << W25_SR_BP_SHIFT) /* Lower quarter */
-# define W25X32_SR_BP_LOWERHALF (14 << W25_SR_BP_SHIFT) /* Lower half */
-
-# define W25X64_SR_BP_NONE (0 << W25_SR_BP_SHIFT) /* Unprotected */
-# define W25X64_SR_BP_UPPER64th (1 << W25_SR_BP_SHIFT) /* Upper 64th */
-# define W25X64_SR_BP_UPPER32nd (2 << W25_SR_BP_SHIFT) /* Upper 32nd */
-# define W25X64_SR_BP_UPPER16th (3 << W25_SR_BP_SHIFT) /* Upper 16th */
-# define W25X64_SR_BP_UPPER8th (4 << W25_SR_BP_SHIFT) /* Upper 8th */
-# define W25X64_SR_BP_UPPERQTR (5 << W25_SR_BP_SHIFT) /* Upper quarter */
-# define W25X64_SR_BP_UPPERHALF (6 << W25_SR_BP_SHIFT) /* Upper half */
-# define W25X46_SR_BP_ALL (7 << W25_SR_BP_SHIFT) /* All sectors */
-# define W25X64_SR_BP_LOWER64th (9 << W25_SR_BP_SHIFT) /* Lower 64th */
-# define W25X64_SR_BP_LOWER32nd (10 << W25_SR_BP_SHIFT) /* Lower 32nd */
-# define W25X64_SR_BP_LOWER16th (11 << W25_SR_BP_SHIFT) /* Lower 16th */
-# define W25X64_SR_BP_LOWER8th (12 << W25_SR_BP_SHIFT) /* Lower 8th */
-# define W25X64_SR_BP_LOWERQTR (13 << W25_SR_BP_SHIFT) /* Lower quarter */
-# define W25X64_SR_BP_LOWERHALF (14 << W25_SR_BP_SHIFT) /* Lower half */
- /* Bit 6: Reserved */
-#define W25_SR_SRP (1 << 7) /* Bit 7: Status register write protect */
-
-#define W25_DUMMY 0xa5
-
-/* Chip Geometries ******************************************************************/
-/* All members of the family support uniform 4K-byte sectors and 256 byte pages */
-
-#define W25_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4Kb */
-#define W25_SECTOR_SIZE (1 << 12) /* Sector size 1 << 12 = 4Kb */
-#define W25_PAGE_SHIFT 8 /* Sector size 1 << 8 = 256b */
-#define W25_PAGE_SIZE (1 << 8) /* Sector size 1 << 8 = 256b */
-
-#ifdef CONFIG_W25_SECTOR512 /* Simulate a 512 byte sector */
-# define W25_SECTOR512_SHIFT 9 /* Sector size 1 << 9 = 512 bytes */
-# define W25_SECTOR512_SIZE (1 << 9) /* Sector size 1 << 9 = 512 bytes */
-#endif
-
-#define W25_ERASED_STATE 0xff /* State of FLASH when erased */
-
-/* Cache flags */
-
-#define W25_CACHE_VALID (1 << 0) /* 1=Cache has valid data */
-#define W25_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */
-#define W25_CACHE_ERASED (1 << 2) /* 1=Backing FLASH is erased */
-
-#define IS_VALID(p) ((((p)->flags) & W25_CACHE_VALID) != 0)
-#define IS_DIRTY(p) ((((p)->flags) & W25_CACHE_DIRTY) != 0)
-#define IS_ERASED(p) ((((p)->flags) & W25_CACHE_DIRTY) != 0)
-
-#define SET_VALID(p) do { (p)->flags |= W25_CACHE_VALID; } while (0)
-#define SET_DIRTY(p) do { (p)->flags |= W25_CACHE_DIRTY; } while (0)
-#define SET_ERASED(p) do { (p)->flags |= W25_CACHE_DIRTY; } while (0)
-
-#define CLR_VALID(p) do { (p)->flags &= ~W25_CACHE_VALID; } while (0)
-#define CLR_DIRTY(p) do { (p)->flags &= ~W25_CACHE_DIRTY; } while (0)
-#define CLR_ERASED(p) do { (p)->flags &= ~W25_CACHE_DIRTY; } while (0)
-
-/************************************************************************************
- * Private Types
- ************************************************************************************/
-
-/* This type represents the state of the MTD device. The struct mtd_dev_s must
- * appear at the beginning of the definition so that you can freely cast between
- * pointers to struct mtd_dev_s and struct w25_dev_s.
- */
-
-struct w25_dev_s
-{
- struct mtd_dev_s mtd; /* MTD interface */
- FAR struct spi_dev_s *spi; /* Saved SPI interface instance */
- uint16_t nsectors; /* Number of erase sectors */
-
-#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY)
- uint8_t flags; /* Buffered sector flags */
- uint16_t esectno; /* Erase sector number in the cache*/
- FAR uint8_t *sector; /* Allocated sector data */
-#endif
-};
-
-/************************************************************************************
- * Private Function Prototypes
- ************************************************************************************/
-
-/* Helpers */
-
-static void w25_lock(FAR struct spi_dev_s *spi);
-static inline void w25_unlock(FAR struct spi_dev_s *spi);
-static inline int w25_readid(FAR struct w25_dev_s *priv);
-#ifndef CONFIG_W25_READONLY
-static void w25_unprotect(FAR struct w25_dev_s *priv);
-#endif
-static uint8_t w25_waitwritecomplete(FAR struct w25_dev_s *priv);
-static inline void w25_wren(FAR struct w25_dev_s *priv);
-static inline void w25_wrdi(FAR struct w25_dev_s *priv);
-static void w25_sectorerase(FAR struct w25_dev_s *priv, off_t offset);
-static inline int w25_chiperase(FAR struct w25_dev_s *priv);
-static void w25_byteread(FAR struct w25_dev_s *priv, FAR uint8_t *buffer,
- off_t address, size_t nbytes);
-#ifndef CONFIG_W25_READONLY
-static void w25_pagewrite(FAR struct w25_dev_s *priv, FAR const uint8_t *buffer,
- off_t address, size_t nbytes);
-#endif
-#ifdef CONFIG_W25_SECTOR512
-static void w25_cacheflush(struct w25_dev_s *priv);
-static FAR uint8_t *w25_cacheread(struct w25_dev_s *priv, off_t sector);
-static void w25_cacheerase(struct w25_dev_s *priv, off_t sector);
-static void w25_cachewrite(FAR struct w25_dev_s *priv, FAR const uint8_t *buffer,
- off_t sector, size_t nsectors);
-#endif
-
-/* MTD driver methods */
-
-static int w25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
-static ssize_t w25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR uint8_t *buf);
-static ssize_t w25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
- size_t nblocks, FAR const uint8_t *buf);
-static ssize_t w25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer);
-static int w25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
-
-/************************************************************************************
- * Private Data
- ************************************************************************************/
-
-/************************************************************************************
- * Private Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: w25_lock
- ************************************************************************************/
-
-static void w25_lock(FAR struct spi_dev_s *spi)
-{
- /* On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
- * transfers. The bus should be locked before the chip is selected.
- *
- * This is a blocking call and will not return until we have exclusiv access to
- * the SPI buss. We will retain that exclusive access until the bus is unlocked.
- */
-
- (void)SPI_LOCK(spi, true);
-
- /* After locking the SPI bus, the we also need call the setfrequency, setbits, and
- * setmode methods to make sure that the SPI is properly configured for the device.
- * If the SPI buss is being shared, then it may have been left in an incompatible
- * state.
- */
-
- SPI_SETMODE(spi, CONFIG_W25_SPIMODE);
- SPI_SETBITS(spi, 8);
- (void)SPI_SETFREQUENCY(spi, CONFIG_W25_SPIFREQUENCY);
-}
-
-/************************************************************************************
- * Name: w25_unlock
- ************************************************************************************/
-
-static inline void w25_unlock(FAR struct spi_dev_s *spi)
-{
- (void)SPI_LOCK(spi, false);
-}
-
-/************************************************************************************
- * Name: w25_readid
- ************************************************************************************/
-
-static inline int w25_readid(struct w25_dev_s *priv)
-{
- uint16_t manufacturer;
- uint16_t memory;
- uint16_t capacity;
-
- fvdbg("priv: %p\n", priv);
-
- /* Lock the SPI bus, configure the bus, and select this FLASH part. */
-
- w25_lock(priv->spi);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send the "Read ID (RDID)" command and read the first three ID bytes */
-
- (void)SPI_SEND(priv->spi, W25_JEDEC_ID);
- manufacturer = SPI_SEND(priv->spi, W25_DUMMY);
- memory = SPI_SEND(priv->spi, W25_DUMMY);
- capacity = SPI_SEND(priv->spi, W25_DUMMY);
-
- /* Deselect the FLASH and unlock the bus */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
- w25_unlock(priv->spi);
-
- fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n",
- manufacturer, memory, capacity);
-
- /* Check for a valid manufacturer and memory type */
-
- if (manufacturer == W25_JEDEC_MANUFACTURER &&
- (memory == W25X_JEDEC_MEMORY_TYPE ||
- memory == W25Q_JEDEC_MEMORY_TYPE_A ||
- memory == W25Q_JEDEC_MEMORY_TYPE_B))
- {
- /* Okay.. is it a FLASH capacity that we understand? If so, save
- * the FLASH capacity.
- */
-
- /* 16M-bit / 2M-byte (2,097,152)
- *
- * W24X16, W25Q16BV, W25Q16CL, W25Q16CV, W25Q16DW
- */
-
- if (capacity == W25_JEDEC_CAPACITY_16MBIT)
- {
- priv->nsectors = NSECTORS_16MBIT;
- }
-
- /* 32M-bit / M-byte (4,194,304)
- *
- * W25X32, W25Q32BV, W25Q32DW
- */
-
- else if (capacity == W25_JEDEC_CAPACITY_32MBIT)
- {
- priv->nsectors = NSECTORS_32MBIT;
- }
-
- /* 64M-bit / 8M-byte (8,388,608)
- *
- * W25X64, W25Q64BV, W25Q64CV, W25Q64DW
- */
-
- else if (capacity == W25_JEDEC_CAPACITY_64MBIT)
- {
- priv->nsectors = NSECTORS_64MBIT;
- }
-
- /* 128M-bit / 16M-byte (16,777,216)
- *
- * W25Q128BV
- */
-
- else if (capacity == W25_JEDEC_CAPACITY_128MBIT)
- {
- priv->nsectors = NSECTORS_128MBIT;
- }
- else
- {
- /* Nope.. we don't understand this capacity. */
-
- return -ENODEV;
- }
-
- return OK;
- }
-
- /* We don't understand the manufacturer or the memory type */
-
- return -ENODEV;
-}
-
-/************************************************************************************
- * Name: w25_unprotect
- ************************************************************************************/
-
-#ifndef CONFIG_W25_READONLY
-static void w25_unprotect(FAR struct w25_dev_s *priv)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send "Write enable (WREN)" */
-
- w25_wren(priv);
-
- /* Re-select this FLASH part (This might not be necessary... but is it shown in
- * the SST25 timing diagrams from which this code was leveraged.)
- */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send "Write enable status (EWSR)" */
-
- SPI_SEND(priv->spi, W25_WRSR);
-
- /* Following by the new status value */
-
- SPI_SEND(priv->spi, 0);
- SPI_SEND(priv->spi, 0);
-}
-#endif
-
-/************************************************************************************
- * Name: w25_waitwritecomplete
- ************************************************************************************/
-
-static uint8_t w25_waitwritecomplete(struct w25_dev_s *priv)
-{
- uint8_t status;
-
- /* Are we the only device on the bus? */
-
-#ifdef CONFIG_SPI_OWNBUS
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->spi, W25_RDSR);
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->spi, W25_DUMMY);
- }
- while ((status & W25_SR_BUSY) != 0);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
-#else
-
- /* Loop as long as the memory is busy with a write cycle */
-
- do
- {
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send "Read Status Register (RDSR)" command */
-
- (void)SPI_SEND(priv->spi, W25_RDSR);
-
- /* Send a dummy byte to generate the clock needed to shift out the status */
-
- status = SPI_SEND(priv->spi, W25_DUMMY);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
- /* Given that writing could take up to few tens of milliseconds, and erasing
- * could take more. The following short delay in the "busy" case will allow
- * other peripherals to access the SPI bus.
- */
-
-#if 0 /* Makes writes too slow */
- if ((status & W25_SR_BUSY) != 0)
- {
- w25_unlock(priv->spi);
- usleep(1000);
- w25_lock(priv->spi);
- }
-#endif
- }
- while ((status & W25_SR_BUSY) != 0);
-#endif
-
- return status;
-}
-
-/************************************************************************************
- * Name: w25_wren
- ************************************************************************************/
-
-static inline void w25_wren(struct w25_dev_s *priv)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send "Write Enable (WREN)" command */
-
- (void)SPI_SEND(priv->spi, W25_WREN);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: w25_wrdi
- ************************************************************************************/
-
-static inline void w25_wrdi(struct w25_dev_s *priv)
-{
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send "Write Disable (WRDI)" command */
-
- (void)SPI_SEND(priv->spi, W25_WRDI);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: w25_sectorerase
- ************************************************************************************/
-
-static void w25_sectorerase(struct w25_dev_s *priv, off_t sector)
-{
- off_t address = sector << W25_SECTOR_SHIFT;
-
- fvdbg("sector: %08lx\n", (long)sector);
-
- /* Wait for any preceding write or erase operation to complete. */
-
- (void)w25_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- w25_wren(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send the "Sector Erase (SE)" instruction */
-
- (void)SPI_SEND(priv->spi, W25_SE);
-
- /* Send the sector address high byte first. Only the most significant bits (those
- * corresponding to the sector) have any meaning.
- */
-
- (void)SPI_SEND(priv->spi, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->spi, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->spi, address & 0xff);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: w25_chiperase
- ************************************************************************************/
-
-static inline int w25_chiperase(struct w25_dev_s *priv)
-{
- fvdbg("priv: %p\n", priv);
-
- /* Wait for any preceding write or erase operation to complete. */
-
- (void)w25_waitwritecomplete(priv);
-
- /* Send write enable instruction */
-
- w25_wren(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send the "Chip Erase (CE)" instruction */
-
- (void)SPI_SEND(priv->spi, W25_CE);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
- fvdbg("Return: OK\n");
- return OK;
-}
-
-/************************************************************************************
- * Name: w25_byteread
- ************************************************************************************/
-
-static void w25_byteread(FAR struct w25_dev_s *priv, FAR uint8_t *buffer,
- off_t address, size_t nbytes)
-{
- uint8_t status;
-
- fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes);
-
- /* Wait for any preceding write or erase operation to complete. */
-
- status = w25_waitwritecomplete(priv);
- DEBUGASSERT((status & (W25_SR_WEL|W25_SR_BP_MASK)) == 0);
-
- /* Make sure that writing is disabled */
-
- w25_wrdi(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send "Read from Memory " instruction */
-
-#ifdef CONFIG_W25_SLOWREAD
- (void)SPI_SEND(priv->spi, W25_RDDATA);
-#else
- (void)SPI_SEND(priv->spi, W25_FRD);
-#endif
-
- /* Send the address high byte first. */
-
- (void)SPI_SEND(priv->spi, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->spi, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->spi, address & 0xff);
-
- /* Send a dummy byte */
-
-#ifndef CONFIG_W25_SLOWREAD
- (void)SPI_SEND(priv->spi, W25_DUMMY);
-#endif
-
- /* Then read all of the requested bytes */
-
- SPI_RECVBLOCK(priv->spi, buffer, nbytes);
-
- /* Deselect the FLASH */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-}
-
-/************************************************************************************
- * Name: w25_pagewrite
- ************************************************************************************/
-
-#ifndef CONFIG_W25_READONLY
-static void w25_pagewrite(struct w25_dev_s *priv, FAR const uint8_t *buffer,
- off_t address, size_t nbytes)
-{
- uint8_t status;
-
- fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nbytes);
- DEBUGASSERT(priv && buffer && (address & 0xff) == 0 &&
- (nbytes & 0xff) == 0);
-
- for (; nbytes > 0; nbytes -= W25_PAGE_SIZE)
- {
- /* Wait for any preceding write or erase operation to complete. */
-
- status = w25_waitwritecomplete(priv);
- DEBUGASSERT((status & (W25_SR_WEL|W25_SR_BP_MASK)) == 0);
-
- /* Enable write access to the FLASH */
-
- w25_wren(priv);
-
- /* Select this FLASH part */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, true);
-
- /* Send the "Page Program (W25_PP)" Command */
-
- SPI_SEND(priv->spi, W25_PP);
-
- /* Send the address high byte first. */
-
- (void)SPI_SEND(priv->spi, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->spi, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->spi, address & 0xff);
-
- /* Then send the page of data */
-
- SPI_SNDBLOCK(priv->spi, buffer, W25_PAGE_SIZE);
-
- /* Deselect the FLASH and setup for the next pass through the loop */
-
- SPI_SELECT(priv->spi, SPIDEV_FLASH, false);
-
- /* Update addresses */
-
- address += W25_PAGE_SIZE;
- buffer += W25_PAGE_SIZE;
- }
-
- /* Disable writing */
-
- w25_wrdi(priv);
-}
-#endif
-
-/************************************************************************************
- * Name: w25_cacheflush
- ************************************************************************************/
-
-#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY)
-static void w25_cacheflush(struct w25_dev_s *priv)
-{
- /* If the cached is dirty (meaning that it no longer matches the old FLASH contents)
- * or was erased (with the cache containing the correct FLASH contents), then write
- * the cached erase block to FLASH.
- */
-
- if (IS_DIRTY(priv) || IS_ERASED(priv))
- {
- /* Write entire erase block to FLASH */
-
- w25_pagewrite(priv, priv->sector, (off_t)priv->esectno << W25_SECTOR_SHIFT,
- W25_SECTOR_SIZE);
-
- /* The case is no long dirty and the FLASH is no longer erased */
-
- CLR_DIRTY(priv);
- CLR_ERASED(priv);
- }
-}
-#endif
-
-/************************************************************************************
- * Name: w25_cacheread
- ************************************************************************************/
-
-#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY)
-static FAR uint8_t *w25_cacheread(struct w25_dev_s *priv, off_t sector)
-{
- off_t esectno;
- int shift;
- int index;
-
- /* Convert from the 512 byte sector to the erase sector size of the device. For
- * exmample, if the actual erase sector size if 4Kb (1 << 12), then we first
- * shift to the right by 3 to get the sector number in 4096 increments.
- */
-
- shift = W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT;
- esectno = sector >> shift;
- fvdbg("sector: %ld esectno: %d shift=%d\n", sector, esectno, shift);
-
- /* Check if the requested erase block is already in the cache */
-
- if (!IS_VALID(priv) || esectno != priv->esectno)
- {
- /* No.. Flush any dirty erase block currently in the cache */
-
- w25_cacheflush(priv);
-
- /* Read the erase block into the cache */
-
- w25_byteread(priv, priv->sector, (esectno << W25_SECTOR_SHIFT), W25_SECTOR_SIZE);
-
- /* Mark the sector as cached */
-
- priv->esectno = esectno;
-
- SET_VALID(priv); /* The data in the cache is valid */
- CLR_DIRTY(priv); /* It should match the FLASH contents */
- CLR_ERASED(priv); /* The underlying FLASH has not been erased */
- }
-
- /* Get the index to the 512 sector in the erase block that holds the argument */
-
- index = sector & ((1 << shift) - 1);
-
- /* Return the address in the cache that holds this sector */
-
- return &priv->sector[index << W25_SECTOR512_SHIFT];
-}
-#endif
-
-/************************************************************************************
- * Name: w25_cacheerase
- ************************************************************************************/
-
-#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY)
-static void w25_cacheerase(struct w25_dev_s *priv, off_t sector)
-{
- FAR uint8_t *dest;
-
- /* First, make sure that the erase block containing the 512 byte sector is in
- * the cache.
- */
-
- dest = w25_cacheread(priv, sector);
-
- /* Erase the block containing this sector if it is not already erased.
- * The erased indicated will be cleared when the data from the erase sector
- * is read into the cache and set here when we erase the block.
- */
-
- if (!IS_ERASED(priv))
- {
- off_t esectno = sector >> (W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT);
- fvdbg("sector: %ld esectno: %d\n", sector, esectno);
-
- w25_sectorerase(priv, esectno);
- SET_ERASED(priv);
- }
-
- /* Put the cached sector data into the erase state and mart the cache as dirty
- * (but don't update the FLASH yet. The caller will do that at a more optimal
- * time).
- */
-
- memset(dest, W25_ERASED_STATE, W25_SECTOR512_SIZE);
- SET_DIRTY(priv);
-}
-#endif
-
-/************************************************************************************
- * Name: w25_cachewrite
- ************************************************************************************/
-
-#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY)
-static void w25_cachewrite(FAR struct w25_dev_s *priv, FAR const uint8_t *buffer,
- off_t sector, size_t nsectors)
-{
- FAR uint8_t *dest;
-
- for (; nsectors > 0; nsectors--)
- {
- /* First, make sure that the erase block containing 512 byte sector is in
- * memory.
- */
-
- dest = w25_cacheread(priv, sector);
-
- /* Erase the block containing this sector if it is not already erased.
- * The erased indicated will be cleared when the data from the erase sector
- * is read into the cache and set here when we erase the sector.
- */
-
- if (!IS_ERASED(priv))
- {
- off_t esectno = sector >> (W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT);
- fvdbg("sector: %ld esectno: %d\n", sector, esectno);
-
- w25_sectorerase(priv, esectno);
- SET_ERASED(priv);
- }
-
- /* Copy the new sector data into cached erase block */
-
- memcpy(dest, buffer, W25_SECTOR512_SIZE);
- SET_DIRTY(priv);
-
- /* Set up for the next 512 byte sector */
-
- buffer += W25_SECTOR512_SIZE;
- sector++;
- }
-
- /* Flush the last erase block left in the cache */
-
- w25_cacheflush(priv);
-}
-#endif
-
-/************************************************************************************
- * Name: w25_erase
- ************************************************************************************/
-
-static int w25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
-{
-#ifdef CONFIG_W25_READONLY
- return -EACESS
-#else
- FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev;
- size_t blocksleft = nblocks;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock access to the SPI bus until we complete the erase */
-
- w25_lock(priv->spi);
-
- while (blocksleft-- > 0)
- {
- /* Erase each sector */
-
-#ifdef CONFIG_W25_SECTOR512
- w25_cacheerase(priv, startblock);
-#else
- w25_sectorerase(priv, startblock);
-#endif
- startblock++;
- }
-
-#ifdef CONFIG_W25_SECTOR512
- /* Flush the last erase block left in the cache */
-
- w25_cacheflush(priv);
-#endif
-
- w25_unlock(priv->spi);
- return (int)nblocks;
-#endif
-}
-
-/************************************************************************************
- * Name: w25_bread
- ************************************************************************************/
-
-static ssize_t w25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buffer)
-{
- ssize_t nbytes;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* On this device, we can handle the block read just like the byte-oriented read */
-
-#ifdef CONFIG_W25_SECTOR512
- nbytes = w25_read(dev, startblock << W25_SECTOR512_SHIFT, nblocks << W25_SECTOR512_SHIFT, buffer);
- if (nbytes > 0)
- {
- nbytes >>= W25_SECTOR512_SHIFT;
- }
-#else
- nbytes = w25_read(dev, startblock << W25_SECTOR_SHIFT, nblocks << W25_SECTOR_SHIFT, buffer);
- if (nbytes > 0)
- {
- nbytes >>= W25_SECTOR_SHIFT;
- }
-#endif
-
- return nbytes;
-}
-
-/************************************************************************************
- * Name: w25_bwrite
- ************************************************************************************/
-
-static ssize_t w25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
-{
-#ifdef CONFIG_W25_READONLY
- return -EACCESS;
-#else
- FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev;
-
- fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
-
- /* Lock the SPI bus and write all of the pages to FLASH */
-
- w25_lock(priv->spi);
-
-#if defined(CONFIG_W25_SECTOR512)
- w25_cachewrite(priv, buffer, startblock, nblocks);
-#else
- w25_pagewrite(priv, buffer, startblock << W25_SECTOR_SHIFT,
- nblocks << W25_SECTOR_SHIFT);
-#endif
- w25_unlock(priv->spi);
-
- return nblocks;
-#endif
-}
-
-/************************************************************************************
- * Name: w25_read
- ************************************************************************************/
-
-static ssize_t w25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
-{
- FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev;
-
- fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
-
- /* Lock the SPI bus and select this FLASH part */
-
- w25_lock(priv->spi);
- w25_byteread(priv, buffer, offset, nbytes);
- w25_unlock(priv->spi);
-
- fvdbg("return nbytes: %d\n", (int)nbytes);
- return nbytes;
-}
-
-/************************************************************************************
- * Name: w25_ioctl
- ************************************************************************************/
-
-static int w25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
-{
- FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev;
- int ret = -EINVAL; /* Assume good command with bad parameters */
-
- fvdbg("cmd: %d \n", cmd);
-
- switch (cmd)
- {
- case MTDIOC_GEOMETRY:
- {
- FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
- if (geo)
- {
- /* Populate the geometry structure with information need to know
- * the capacity and how to access the device.
- *
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
- */
-
-#ifdef CONFIG_W25_SECTOR512
- geo->blocksize = (1 << W25_SECTOR512_SHIFT);
- geo->erasesize = (1 << W25_SECTOR512_SHIFT);
- geo->neraseblocks = priv->nsectors << (W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT);
-#else
- geo->blocksize = W25_SECTOR_SIZE;
- geo->erasesize = W25_SECTOR_SIZE;
- geo->neraseblocks = priv->nsectors;
-#endif
- ret = OK;
-
- fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
- geo->blocksize, geo->erasesize, geo->neraseblocks);
- }
- }
- break;
-
- case MTDIOC_BULKERASE:
- {
- /* Erase the entire device */
-
- w25_lock(priv->spi);
- ret = w25_chiperase(priv);
- w25_unlock(priv->spi);
- }
- break;
-
- case MTDIOC_XIPBASE:
- default:
- ret = -ENOTTY; /* Bad command */
- break;
- }
-
- fvdbg("return %d\n", ret);
- return ret;
-}
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: w25_initialize
- *
- * Description:
- * Create an initialize MTD device instance. MTD devices are not registered
- * in the file system, but are created as instances that can be bound to
- * other functions (such as a block or character driver front end).
- *
- ************************************************************************************/
-
-FAR struct mtd_dev_s *w25_initialize(FAR struct spi_dev_s *spi)
-{
- FAR struct w25_dev_s *priv;
- int ret;
-
- fvdbg("spi: %p\n", spi);
-
- /* Allocate a state structure (we allocate the structure instead of using
- * a fixed, static allocation so that we can handle multiple FLASH devices.
- * The current implementation would handle only one FLASH part per SPI
- * device (only because of the SPIDEV_FLASH definition) and so would have
- * to be extended to handle multiple FLASH parts on the same SPI bus.
- */
-
- priv = (FAR struct w25_dev_s *)kzalloc(sizeof(struct w25_dev_s));
- if (priv)
- {
- /* Initialize the allocated structure */
-
- priv->mtd.erase = w25_erase;
- priv->mtd.bread = w25_bread;
- priv->mtd.bwrite = w25_bwrite;
- priv->mtd.read = w25_read;
- priv->mtd.ioctl = w25_ioctl;
- priv->spi = spi;
-
- /* Deselect the FLASH */
-
- SPI_SELECT(spi, SPIDEV_FLASH, false);
-
- /* Identify the FLASH chip and get its capacity */
-
- ret = w25_readid(priv);
- if (ret != OK)
- {
- /* Unrecognized! Discard all of that work we just did and return NULL */
-
- fdbg("Unrecognized\n");
- kfree(priv);
- priv = NULL;
- }
- else
- {
- /* Make sure the the FLASH is unprotected so that we can write into it */
-
-#ifndef CONFIG_W25_READONLY
- w25_unprotect(priv);
-#endif
-
-#ifdef CONFIG_W25_SECTOR512 /* Simulate a 512 byte sector */
- /* Allocate a buffer for the erase block cache */
-
- priv->sector = (FAR uint8_t *)kmalloc(W25_SECTOR_SIZE);
- if (!priv->sector)
- {
- /* Allocation failed! Discard all of that work we just did and return NULL */
-
- fdbg("Allocation failed\n");
- kfree(priv);
- priv = NULL;
- }
-#endif
- }
- }
-
- /* Return the implementation-specific state structure as the MTD device */
-
- fvdbg("Return %p\n", priv);
- return (FAR struct mtd_dev_s *)priv;
-}