drivers: mtd: fix nxstyle errors

Fix nxstyle errors to pass the CI errors.

Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>
This commit is contained in:
Alin Jerpelea 2021-01-27 16:48:40 +01:00 committed by Xiang Xiao
parent 95adb15824
commit 2d8b193df4
24 changed files with 3804 additions and 2972 deletions

View file

@ -1,6 +1,7 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/at24xx.c
* Driver for I2C-based at24cxx EEPROM(at24c32,at24c64,at24c128,at24c256,at24c512)
* Driver for I2C-based at24cxx EEPROM
* (at24c32,at24c64,at24c128,at24c256,at24c512)
*
* Copyright (C) 2011 Li Zhuoyi. All rights reserved.
* Author: Li Zhuoyi <lzyy.cn@gmail.com>
@ -40,11 +41,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -66,11 +67,13 @@
#ifdef CONFIG_MTD_AT24XX
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* As a minimum, the size of the AT24 part and its 7-bit I2C address are required. */
/* 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"
@ -129,11 +132,11 @@
# define AT24XX_ADDRSIZE 2
#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.
/* 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
@ -145,9 +148,9 @@
# define CONFIG_AT24XX_TIMEOUT_MS 10
#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
@ -167,24 +170,33 @@ struct at24c_dev_s
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,
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,
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);
static int at24c_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Data
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AT24XX_MULTI
/* If only a signal AT24 part is supported then a statically allocated state
@ -194,17 +206,17 @@ static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static struct at24c_dev_s g_at24c;
#endif
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: at24c_i2c_write
*
* Description:
* Write to the I2C device.
*
************************************************************************************/
****************************************************************************/
static int at24c_i2c_write(FAR struct at24c_dev_s *priv, uint16_t at24addr,
FAR const uint8_t *buffer, int buflen)
@ -224,13 +236,13 @@ static int at24c_i2c_write(FAR struct at24c_dev_s *priv, uint16_t at24addr,
return I2C_TRANSFER(priv->dev, &msg, 1);
}
/************************************************************************************
/****************************************************************************
* Name: at24c_i2c_read
*
* Description:
* Read from the I2C device.
*
************************************************************************************/
****************************************************************************/
static int at24c_i2c_read(FAR struct at24c_dev_s *priv, uint16_t at24addr,
FAR uint8_t *buffer, int buflen)
@ -250,9 +262,9 @@ static int at24c_i2c_read(FAR struct at24c_dev_s *priv, uint16_t at24addr,
return I2C_TRANSFER(priv->dev, &msg, 1);
}
/************************************************************************************
/****************************************************************************
* Name: at24c_eraseall
************************************************************************************/
****************************************************************************/
static int at24c_eraseall(FAR struct at24c_dev_s *priv)
{
@ -277,7 +289,10 @@ static int at24c_eraseall(FAR struct at24c_dev_s *priv)
#endif
wait = CONFIG_AT24XX_TIMEOUT_MS;
while (at24c_i2c_write(priv, at24addr, buf, AT24XX_ADDRSIZE) < 0)
while (at24c_i2c_write(priv,
at24addr,
buf,
AT24XX_ADDRSIZE) < 0)
{
finfo("wait\n");
if (!wait--)
@ -288,29 +303,36 @@ static int at24c_eraseall(FAR struct at24c_dev_s *priv)
nxsig_usleep(1000);
}
at24c_i2c_write(priv, at24addr, buf, AT24XX_PAGESIZE + AT24XX_ADDRSIZE);
at24c_i2c_write(priv,
at24addr,
buf,
AT24XX_PAGESIZE + AT24XX_ADDRSIZE);
}
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: at24c_erase
************************************************************************************/
****************************************************************************/
static int at24c_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
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_read_internal
************************************************************************************/
****************************************************************************/
static ssize_t at24c_read_internal(FAR struct at24c_dev_s *priv, off_t offset,
size_t nbytes, FAR uint8_t *buffer,
static ssize_t at24c_read_internal(FAR struct at24c_dev_s *priv,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer,
uint8_t address)
{
uint8_t buf[AT24XX_ADDRSIZE];
@ -363,9 +385,9 @@ static ssize_t at24c_read_internal(FAR struct at24c_dev_s *priv, off_t offset,
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: at24c_bread
************************************************************************************/
****************************************************************************/
static ssize_t at24c_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buffer)
@ -421,12 +443,12 @@ static ssize_t at24c_bread(FAR struct mtd_dev_s *dev, off_t startblock,
#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,
@ -495,18 +517,22 @@ static ssize_t at24c_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
#endif
}
/************************************************************************************
/****************************************************************************
* Name: at24c_read
************************************************************************************/
****************************************************************************/
static ssize_t at24c_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t at24c_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct at24c_dev_s *priv = (FAR struct at24c_dev_s *)dev;
size_t memsize;
uint8_t addr;
finfo("offset: %lu nbytes: %lu\n", (unsigned long)offset, (unsigned long)nbytes);
finfo("offset: %lu nbytes: %lu\n",
(unsigned long)offset,
(unsigned long)nbytes);
/* Don't permit reads beyond the end of the memory region */
@ -543,9 +569,9 @@ static ssize_t at24c_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
return at24c_read_internal(priv, offset, nbytes, buffer, addr);
}
/************************************************************************************
/****************************************************************************
* Name: at24c_ioctl
************************************************************************************/
****************************************************************************/
static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -562,25 +588,28 @@ static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
((uintptr_t)arg);
if (geo)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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
* 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.
* 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
* Note that the device size is in kilobits and must be
* scaled by 1024 / 8
*/
#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE
@ -622,22 +651,24 @@ static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: at24c_initialize
*
* Description:
* Create an initialized 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).
* Create an initialized 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).
*
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_AT24XX_MULTI
FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_master_s *dev, uint8_t address)
FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_master_s *dev,
uint8_t address)
#else
FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_master_s *dev)
#endif
@ -650,8 +681,8 @@ FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_master_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same I2C bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same I2C bus.
*/
priv = (FAR struct at24c_dev_s *)kmm_zalloc(sizeof(struct at24c_dev_s));
@ -664,8 +695,8 @@ FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_master_s *dev)
#else
finfo("dev: %p\n", dev);
/* If only a signal AT24 part is supported then a statically allocated state
* structure is used.
/* If only a signal AT24 part is supported then a statically allocated
* state structure is used.
*/
priv = &g_at24c;
@ -703,14 +734,15 @@ FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_master_s *dev)
return (FAR struct mtd_dev_s *)priv;
}
/************************************************************************************
/****************************************************************************
* Name: at24c_uninitialize
*
* Description:
* Release resources held by an allocated MTD device instance. Resources are only
* allocated for the case where multiple AT24xx devices are support.
* Release resources held by an allocated MTD device instance.
* Resources are only allocated for the case where multiple AT24xx
* devices are support.
*
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_AT24XX_MULTI
void at24c_uninitialize(FAR struct mtd_dev_s *mtd)

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/at25.c
* Driver for SPI-based AT25DF321 (32Mbit) flash.
*
@ -33,11 +33,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -56,11 +56,11 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* Configuration ************************************************************/
#ifndef CONFIG_AT25_SPIMODE
# define CONFIG_AT25_SPIMODE SPIDEV_MODE0
@ -70,7 +70,7 @@
# define CONFIG_AT25_SPIFREQUENCY 20000000
#endif
/* AT25 Registers *******************************************************************/
/* AT25 Registers ***********************************************************/
/* Identification register values */
@ -129,9 +129,9 @@
#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
@ -148,9 +148,9 @@ struct at25_dev_s
uint32_t npages; /* 32,768 or 65,536 */
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -159,29 +159,41 @@ 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 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,
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,
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);
static int at25_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: at25_lock
************************************************************************************/
****************************************************************************/
static void at25_lock(FAR struct spi_dev_s *dev)
{
@ -189,16 +201,18 @@ static void at25_lock(FAR struct spi_dev_s *dev)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus.
* We will retain that exclusive access until the bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(dev, CONFIG_AT25_SPIMODE);
@ -207,18 +221,18 @@ static void at25_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_AT25_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: at25_unlock
************************************************************************************/
****************************************************************************/
static inline void at25_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: at25_readid
************************************************************************************/
****************************************************************************/
static inline int at25_readid(struct at25_dev_s *priv)
{
@ -248,7 +262,8 @@ static inline int at25_readid(struct at25_dev_s *priv)
/* Check for a valid manufacturer and memory type */
if (manufacturer == AT25_MANUFACTURER && memory == AT25_AT25DF081A_TYPE)
if (manufacturer == AT25_MANUFACTURER &&
memory == AT25_AT25DF081A_TYPE)
{
priv->sectorshift = AT25_AT25DF081A_SECTOR_SHIFT;
priv->nsectors = AT25_AT25DF081A_NSECTORS;
@ -256,7 +271,8 @@ static inline int at25_readid(struct at25_dev_s *priv)
priv->npages = AT25_AT25DF081A_NPAGES;
return OK;
}
else if (manufacturer == AT25_MANUFACTURER && memory == AT25_AT25DF321_TYPE)
else if (manufacturer == AT25_MANUFACTURER &&
memory == AT25_AT25DF321_TYPE)
{
priv->sectorshift = AT25_AT25DF321_SECTOR_SHIFT;
priv->nsectors = AT25_AT25DF321_NSECTORS;
@ -268,9 +284,9 @@ static inline int at25_readid(struct at25_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: at25_waitwritecomplete
************************************************************************************/
****************************************************************************/
static void at25_waitwritecomplete(struct at25_dev_s *priv)
{
@ -288,7 +304,9 @@ static void at25_waitwritecomplete(struct at25_dev_s *priv)
SPI_SEND(priv->dev, AT25_RDSR);
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out
* the status
*/
status = SPI_SEND(priv->dev, AT25_DUMMY);
@ -296,9 +314,10 @@ static void at25_waitwritecomplete(struct at25_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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.
/* 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_BUSY) != 0)
@ -318,9 +337,9 @@ static void at25_waitwritecomplete(struct at25_dev_s *priv)
finfo("Complete, status: 0x%02x\n", status);
}
/************************************************************************************
/****************************************************************************
* Name: at25_writeenable
************************************************************************************/
****************************************************************************/
static void at25_writeenable(struct at25_dev_s *priv)
{
@ -330,9 +349,9 @@ static void at25_writeenable(struct at25_dev_s *priv)
finfo("Enabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: at25_sectorerase
************************************************************************************/
****************************************************************************/
static inline void at25_sectorerase(struct at25_dev_s *priv, off_t sector)
{
@ -375,9 +394,9 @@ static inline void at25_sectorerase(struct at25_dev_s *priv, off_t sector)
finfo("Erased\n");
}
/************************************************************************************
/****************************************************************************
* Name: at25_bulkerase
************************************************************************************/
****************************************************************************/
static inline int at25_bulkerase(struct at25_dev_s *priv)
{
@ -410,11 +429,12 @@ static inline int at25_bulkerase(struct at25_dev_s *priv)
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: at25_pagewrite
************************************************************************************/
****************************************************************************/
static inline void at25_pagewrite(struct at25_dev_s *priv, FAR const uint8_t *buffer,
static inline void at25_pagewrite(struct at25_dev_s *priv,
FAR const uint8_t *buffer,
off_t page)
{
off_t offset = page << 8;
@ -457,11 +477,13 @@ static inline void at25_pagewrite(struct at25_dev_s *priv, FAR const uint8_t *bu
finfo("Written\n");
}
/************************************************************************************
/****************************************************************************
* Name: at25_erase
************************************************************************************/
****************************************************************************/
static int at25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
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;
@ -483,9 +505,9 @@ static int at25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock
return (int)nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: at25_bread
************************************************************************************/
****************************************************************************/
static ssize_t at25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks,
@ -496,7 +518,9 @@ static ssize_t at25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* 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);
@ -508,9 +532,9 @@ static ssize_t at25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
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)
@ -535,11 +559,13 @@ static ssize_t at25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
return nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: at25_read
************************************************************************************/
****************************************************************************/
static ssize_t at25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
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;
@ -587,9 +613,9 @@ static ssize_t at25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: at25_ioctl
************************************************************************************/
****************************************************************************/
static int at25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -607,13 +633,15 @@ static int at25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
if (geo != NULL)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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);
@ -648,19 +676,19 @@ static int at25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: at25_initialize
*
* Description:
* Create an initialize MTD device instance. MTD devices are not registered
* 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)
{
@ -672,8 +700,8 @@ FAR struct mtd_dev_s *at25_initialize(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct at25_dev_s *)kmm_zalloc(sizeof(struct at25_dev_s));
@ -700,7 +728,9 @@ FAR struct mtd_dev_s *at25_initialize(FAR struct spi_dev_s *dev)
ret = at25_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized!
* Discard all of that work we just did and return NULL
*/
ferr("ERROR: Unrecognized\n");
kmm_free(priv);

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/at45db.c
* Driver for SPI-based AT45DB161D (16Mbit)
*
@ -32,7 +32,7 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/* Ordering Code Detail:
*
@ -46,9 +46,9 @@
* `- Atmel designator
*/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -65,15 +65,17 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/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:
/* 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)
@ -86,7 +88,7 @@
# define CONFIG_AT45DB_FREQUENCY 1000000
#endif
/* SPI Commands *********************************************************************/
/* SPI Commands *************************************************************/
/* Read commands */
@ -187,9 +189,9 @@
#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
@ -204,9 +206,9 @@ struct at45db_dev_s
uint32_t npages; /* Number of pages in the device */
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Lock and per-transaction configuration */
@ -228,25 +230,37 @@ static void at45db_resume(FAR struct at45db_dev_s *priv);
static inline int at45db_rdid(FAR struct at45db_dev_s *priv);
static inline uint8_t at45db_rdsr(FAR struct at45db_dev_s *priv);
static uint8_t at45db_waitbusy(FAR struct at45db_dev_s *priv);
static inline void at45db_pgerase(FAR struct at45db_dev_s *priv, off_t offset);
static inline void at45db_pgerase(FAR struct at45db_dev_s *priv,
off_t offset);
static inline int at45db_chiperase(FAR struct at45db_dev_s *priv);
static inline void at45db_pgwrite(FAR struct at45db_dev_s *priv,
FAR const uint8_t *buffer, off_t offset);
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,
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);
static int at45db_ioctl(FAR struct mtd_dev_s *mtd,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Data
************************************************************************************/
****************************************************************************/
/* Chip erase sequence */
@ -264,30 +278,32 @@ static const uint8_t g_binpgsize[BINPGSIZE_SIZE] =
0x3d, 0x2a, 0x80, 0xa6
};
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: at45db_lock
************************************************************************************/
****************************************************************************/
static void at45db_lock(FAR struct at45db_dev_s *priv)
{
/* On SPI buses where there are multiple devices, it will be necessary to lock SPI
* to have exclusive access to the buses for a sequence of transfers. The bus
* should be locked before the chip is selected.
/* On SPI buses where there are multiple devices, it will be necessary to
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus. We will retain that exclusive access until the
* bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(priv->spi, SPIDEV_MODE0);
@ -296,18 +312,18 @@ static void at45db_lock(FAR struct at45db_dev_s *priv)
SPI_SETFREQUENCY(priv->spi, CONFIG_AT45DB_FREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: at45db_unlock
************************************************************************************/
****************************************************************************/
static inline void at45db_unlock(FAR struct at45db_dev_s *priv)
{
SPI_LOCK(priv->spi, false);
}
/************************************************************************************
/****************************************************************************
* Name: at45db_pwrdown
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_AT45DB_PWRSAVE
static void at45db_pwrdown(FAR struct at45db_dev_s *priv)
@ -318,9 +334,9 @@ static void at45db_pwrdown(FAR struct at45db_dev_s *priv)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: at45db_resume
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_AT45DB_PWRSAVE
static void at45db_resume(FAR struct at45db_dev_s *priv)
@ -332,9 +348,9 @@ static void at45db_resume(FAR struct at45db_dev_s *priv)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: at45db_rdid
************************************************************************************/
****************************************************************************/
static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
{
@ -343,14 +359,14 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
finfo("priv: %p\n", priv);
/* Configure the bus, and select this FLASH part. (The caller should already have
* locked the bus for exclusive access)
/* Configure the bus, and select this FLASH part. (The caller should
* already have locked the bus for exclusive access)
*/
SPI_SELECT(priv->spi, SPIDEV_FLASH(0), true);
/* Send the " Manufacturer and Device ID Read" command and read the next three
* ID bytes from the FLASH.
/* Send the "Manufacturer and Device ID Read" command and read the
* next three ID bytes from the FLASH.
*/
SPI_SEND(priv->spi, AT45DB_RDDEVID);
@ -374,6 +390,7 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
switch (capacity)
{
case AT45DB_DEVID1_1MBIT:
/* Save the FLASH geometry for the 16Mbit AT45DB011 */
priv->pageshift = 8; /* Page size = 256 bytes */
@ -381,6 +398,7 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
return OK;
case AT45DB_DEVID1_2MBIT:
/* Save the FLASH geometry for the 16Mbit AT45DB021 */
priv->pageshift = 8; /* Page size = 256/264 bytes */
@ -388,6 +406,7 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
return OK;
case AT45DB_DEVID1_4MBIT:
/* Save the FLASH geometry for the 16Mbit AT45DB041 */
priv->pageshift = 8; /* Page size = 256/264 bytes */
@ -395,6 +414,7 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
return OK;
case AT45DB_DEVID1_8MBIT:
/* Save the FLASH geometry for the 16Mbit AT45DB081 */
priv->pageshift = 8; /* Page size = 256/264 bytes */
@ -402,6 +422,7 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
return OK;
case AT45DB_DEVID1_16MBIT:
/* Save the FLASH geometry for the 16Mbit AT45DB161 */
priv->pageshift = 9; /* Page size = 512/528 bytes */
@ -409,6 +430,7 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
return OK;
case AT45DB_DEVID1_32MBIT:
/* Save the FLASH geometry for the 16Mbit AT45DB321 */
priv->pageshift = 9; /* Page size = 512/528 bytes */
@ -416,6 +438,7 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
return OK;
case AT45DB_DEVID1_64MBIT:
/* Save the FLASH geometry for the 16Mbit AT45DB321 */
priv->pageshift = 10; /* Page size = 1024/1056 bytes */
@ -430,9 +453,9 @@ static inline int at45db_rdid(FAR struct at45db_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: at45db_rdsr
************************************************************************************/
****************************************************************************/
static inline uint8_t at45db_rdsr(FAR struct at45db_dev_s *priv)
{
@ -445,9 +468,9 @@ static inline uint8_t at45db_rdsr(FAR struct at45db_dev_s *priv)
return retval;
}
/************************************************************************************
/****************************************************************************
* Name: at45db_waitbusy
************************************************************************************/
****************************************************************************/
static uint8_t at45db_waitbusy(FAR struct at45db_dev_s *priv)
{
@ -465,35 +488,37 @@ static uint8_t at45db_waitbusy(FAR struct at45db_dev_s *priv)
return sr;
}
/************************************************************************************
/****************************************************************************
* Name: at45db_pgerase
************************************************************************************/
****************************************************************************/
static inline void at45db_pgerase(FAR struct at45db_dev_s *priv, off_t sector)
static inline void at45db_pgerase(FAR struct at45db_dev_s *priv,
off_t sector)
{
uint8_t erasecmd[4];
off_t offset = sector << priv->pageshift;
finfo("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.
/* 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."
/* "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 */
@ -517,32 +542,33 @@ static inline void at45db_pgerase(FAR struct at45db_dev_s *priv, off_t sector)
finfo("Erased\n");
}
/************************************************************************************
/****************************************************************************
* Name: at45db_chiperase
************************************************************************************/
****************************************************************************/
static inline int at45db_chiperase(FAR struct at45db_dev_s *priv)
{
finfo("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.
/* 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...
/* "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 theerase 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(0), true);
@ -559,9 +585,9 @@ static inline int at45db_chiperase(FAR struct at45db_dev_s *priv)
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: at45db_pgwrite
************************************************************************************/
****************************************************************************/
static inline void at45db_pgwrite(FAR struct at45db_dev_s *priv,
FAR const uint8_t *buffer, off_t page)
@ -578,11 +604,11 @@ static inline void at45db_pgwrite(FAR struct at45db_dev_s *priv,
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.
/* 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
@ -604,19 +630,20 @@ static inline void at45db_pgwrite(FAR struct at45db_dev_s *priv,
finfo("Written\n");
}
/************************************************************************************
/****************************************************************************
* Name: at45db_erase
************************************************************************************/
****************************************************************************/
static int at45db_erase(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks)
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;
finfo("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.
/* Take the lock so that we have exclusive access to the bus, then power
* up the FLASH device.
*/
at45db_lock(priv);
@ -637,9 +664,9 @@ static int at45db_erase(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblo
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)
@ -647,7 +674,9 @@ static ssize_t at45db_bread(FAR struct mtd_dev_s *mtd, off_t startblock,
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 */
/* 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);
@ -659,9 +688,9 @@ static ssize_t at45db_bread(FAR struct mtd_dev_s *mtd, off_t startblock,
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)
@ -671,8 +700,8 @@ static ssize_t at45db_bwrite(FAR struct mtd_dev_s *mtd, off_t startblock,
finfo("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.
/* Take the lock so that we have exclusive access to the bus, then power
* up the FLASH device.
*/
at45db_lock(priv);
@ -685,7 +714,7 @@ static ssize_t at45db_bwrite(FAR struct mtd_dev_s *mtd, off_t startblock,
at45db_pgwrite(priv, buffer, startblock);
startblock++;
buffer += (1 << priv->pageshift);
}
}
at45db_pwrdown(priv);
at45db_unlock(priv);
@ -693,11 +722,13 @@ static ssize_t at45db_bwrite(FAR struct mtd_dev_s *mtd, off_t startblock,
return nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: at45db_read
************************************************************************************/
****************************************************************************/
static ssize_t at45db_read(FAR struct mtd_dev_s *mtd, off_t offset, size_t nbytes,
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;
@ -713,18 +744,18 @@ static ssize_t at45db_read(FAR struct mtd_dev_s *mtd, off_t offset, size_t nbyte
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.
/* 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.
/* 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
@ -745,11 +776,13 @@ static ssize_t at45db_read(FAR struct mtd_dev_s *mtd, off_t offset, size_t nbyte
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: at45db_ioctl
************************************************************************************/
****************************************************************************/
static int at45db_ioctl(FAR struct mtd_dev_s *mtd, int cmd, unsigned long arg)
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 */
@ -760,16 +793,19 @@ static int at45db_ioctl(FAR struct mtd_dev_s *mtd, int cmd, unsigned long arg)
{
case MTDIOC_GEOMETRY:
{
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
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.
/* 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.
* 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 clientwill expect the
* device logic to do whatever is necessary to make it appear
* so.
*/
geo->blocksize = (1 << priv->pageshift);
@ -810,19 +846,19 @@ static int at45db_ioctl(FAR struct mtd_dev_s *mtd, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: at45db_initialize
*
* Description:
* Create an initialize MTD device instance. MTD devices are not registered
* 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)
{
@ -832,11 +868,11 @@ FAR struct mtd_dev_s *at45db_initialize(FAR struct spi_dev_s *spi)
finfo("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(0) definition) and so would have to be extended to handle
* multiple FLASH parts on the same SPI bus.
/* 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(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct at45db_dev_s *)kmm_zalloc(sizeof(struct at45db_dev_s));
@ -868,24 +904,29 @@ FAR struct mtd_dev_s *at45db_initialize(FAR struct spi_dev_s *spi)
ret = at45db_rdid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized!
* Discard all of that work we just did and return NULL
*/
ferr("ERROR: Unrecognized\n");
goto errout;
}
/* Get the value of the status register (as soon as the device is ready) */
/* 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.
/* 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.
/* No, re-program it for the binary page size.
* NOTE:
* A power cycle is required after the device has be re-programmed.
*/
fwarn("WARNING: Reprogramming page size\n");
@ -905,9 +946,9 @@ FAR struct mtd_dev_s *at45db_initialize(FAR struct spi_dev_s *spi)
finfo("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.
/* 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:

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/gd5f.c
* Driver for GigaDevice SPI nand flash.
*
@ -32,11 +32,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -54,11 +54,11 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* Configuration ************************************************************/
#ifndef CONFIG_GD5F_SPIMODE
# define CONFIG_GD5F_SPIMODE SPIDEV_MODE0
@ -68,33 +68,33 @@
# define CONFIG_GD5F_SPIFREQUENCY 20000000
#endif
/* GD5F Instructions ****************************************************************/
/* GD5F Instructions ********************************************************/
/* Command Value Description Addr Data */
/* Dummy */
/* Command Value Description Addr Data */
#define GD5F_GET_FEATURE 0x0f /* Get features 1 0 1 */
#define GD5F_SET_FEATURE 0x1f /* Set features 1 0 1 */
#define GD5F_PAGE_READ 0x13 /* Array read 3 0 0 */
#define GD5F_READ_FROM_CACHE 0x03 /* Output cache data
* on SO 2 1 1-2112 */
#define GD5F_READ_ID 0x9f /* Read device ID 0 1 2 */
#define GD5F_ECC_STATUS_READ 0x7c /* Internal ECC status
* output 0 1 1 */
#define GD5F_BLOCK_ERASE 0xd8 /* Block erase 3 0 0 */
#define GD5F_PROGRAM_EXECUTE 0x10 /* Enter block/page
* address, execute 3 0 0 */
#define GD5F_PROGRAM_LOAD 0x02 /* Load program data with
* cache reset first 2 0 1-2112 */
#define GD5F_PROGRAM_LOAD_RANDOM 0x84 /* Load program data
* without cache reset 2 0 1-2112 */
#define GD5F_WRITE_ENABLE 0x06 /* 0 0 0 */
#define GD5F_WRITE_DISABLE 0x04 /* 0 0 0 */
#define GD5F_RESET 0xff /* Reset the device 0 0 0 */
/* Dummy */
#define GD5F_DUMMY 0x00 /* No Operation 0 0 0 */
#define GD5F_GET_FEATURE 0x0f /* Get features 1 0 1 */
#define GD5F_SET_FEATURE 0x1f /* Set features 1 0 1 */
#define GD5F_PAGE_READ 0x13 /* Array read 3 0 0 */
#define GD5F_READ_FROM_CACHE 0x03 /* Output cache data
* on SO 2 1 1-2112 */
#define GD5F_READ_ID 0x9f /* Read device ID 0 1 2 */
#define GD5F_ECC_STATUS_READ 0x7c /* Internal ECC status
* output 0 1 1 */
#define GD5F_BLOCK_ERASE 0xd8 /* Block erase 3 0 0 */
#define GD5F_PROGRAM_EXECUTE 0x10 /* Enter block/page
* address, execute 3 0 0 */
#define GD5F_PROGRAM_LOAD 0x02 /* Load program data with
* cache reset first 2 0 1-2112 */
#define GD5F_PROGRAM_LOAD_RANDOM 0x84 /* Load program data
* without cache reset 2 0 1-2112 */
#define GD5F_WRITE_ENABLE 0x06 /* 0 0 0 */
#define GD5F_WRITE_DISABLE 0x04 /* 0 0 0 */
#define GD5F_RESET 0xff /* Reset the device 0 0 0 */
#define GD5F_DUMMY 0x00 /* No Operation 0 0 0 */
/* Feature register *****************************************************************/
/* Feature register *********************************************************/
/* JEDEC Read ID register values */
@ -153,9 +153,9 @@
#define GD5F_FEATURE_ECC_OFFSET 4
#define GD5F_ECC_STATUS_MASK 0x0f
/************************************************************************************
/****************************************************************************
* 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
@ -173,9 +173,9 @@ struct gd5f_dev_s
uint8_t eccstatus; /* Internal ECC status */
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -183,18 +183,26 @@ static inline void gd5f_lock(FAR struct spi_dev_s *dev);
static inline void gd5f_unlock(FAR struct spi_dev_s *dev);
static int gd5f_readid(FAR struct gd5f_dev_s *priv);
static bool gd5f_waitstatus(FAR struct gd5f_dev_s *priv, uint8_t mask,
static bool gd5f_waitstatus(FAR struct gd5f_dev_s *priv,
uint8_t mask,
bool successif);
static inline void gd5f_writeenable(FAR struct gd5f_dev_s *priv);
static inline void gd5f_writedisable(FAR struct gd5f_dev_s *priv);
static bool gd5f_sectorerase(FAR struct gd5f_dev_s *priv, off_t startsector);
static void gd5f_readbuffer(FAR struct gd5f_dev_s *priv, uint32_t address,
uint8_t *buffer, size_t length);
static bool gd5f_read_page(FAR struct gd5f_dev_s *priv, uint32_t position);
static bool gd5f_sectorerase(FAR struct gd5f_dev_s *priv,
off_t startsector);
static void gd5f_readbuffer(FAR struct gd5f_dev_s *priv,
uint32_t address,
uint8_t *buffer,
size_t length);
static bool gd5f_read_page(FAR struct gd5f_dev_s *priv,
uint32_t position);
static void gd5f_write_to_cache(FAR struct gd5f_dev_s *priv, uint32_t address,
const uint8_t *buffer, size_t length);
static bool gd5f_execute_write(FAR struct gd5f_dev_s *priv, uint32_t position);
static void gd5f_write_to_cache(FAR struct gd5f_dev_s *priv,
uint32_t address,
const uint8_t *buffer,
size_t length);
static bool gd5f_execute_write(FAR struct gd5f_dev_s *priv,
uint32_t position);
static inline void gd5f_eccstatusread(FAR struct gd5f_dev_s *priv);
static inline void gd5f_enable_ecc(FAR struct gd5f_dev_s *priv);
@ -202,24 +210,36 @@ static inline void gd5f_unlockblocks(FAR struct gd5f_dev_s *priv);
/* MTD driver methods */
static ssize_t gd5f_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buffer);
static ssize_t gd5f_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t gd5f_bread(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR uint8_t *buffer);
static ssize_t gd5f_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer);
static ssize_t gd5f_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer);
static ssize_t gd5f_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR const uint8_t *buffer);
static int gd5f_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int gd5f_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
static ssize_t gd5f_bwrite(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buffer);
static ssize_t gd5f_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer);
static int gd5f_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
static int gd5f_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks);
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: gd5f_lock
************************************************************************************/
****************************************************************************/
static inline void gd5f_lock(FAR struct spi_dev_s *dev)
{
@ -231,18 +251,18 @@ static inline void gd5f_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_GD5F_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_unlock
************************************************************************************/
****************************************************************************/
static inline void gd5f_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_readid
************************************************************************************/
****************************************************************************/
static int gd5f_readid(FAR struct gd5f_dev_s *priv)
{
@ -303,11 +323,13 @@ static int gd5f_readid(FAR struct gd5f_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_waitstatus
************************************************************************************/
****************************************************************************/
static bool gd5f_waitstatus(FAR struct gd5f_dev_s *priv, uint8_t mask, bool successif)
static bool gd5f_waitstatus(FAR struct gd5f_dev_s *priv,
uint8_t mask,
bool successif)
{
uint8_t status;
@ -337,9 +359,9 @@ static bool gd5f_waitstatus(FAR struct gd5f_dev_s *priv, uint8_t mask, bool succ
return successif ? ((status & mask) != 0) : ((status & mask) == 0);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_writeenable
************************************************************************************/
****************************************************************************/
static inline void gd5f_writeenable(FAR struct gd5f_dev_s *priv)
{
@ -356,9 +378,9 @@ static inline void gd5f_writeenable(FAR struct gd5f_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->spi_devid), false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_writedisable
************************************************************************************/
****************************************************************************/
static inline void gd5f_writedisable(FAR struct gd5f_dev_s *priv)
{
@ -375,13 +397,15 @@ static inline void gd5f_writedisable(FAR struct gd5f_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->spi_devid), false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_sectorerase (128K)
************************************************************************************/
****************************************************************************/
static bool gd5f_sectorerase(FAR struct gd5f_dev_s *priv, off_t startsector)
static bool gd5f_sectorerase(FAR struct gd5f_dev_s *priv,
off_t startsector)
{
const uint32_t block = startsector << (priv->sectorshift - priv->pageshift);
const uint32_t block = startsector << (priv->sectorshift -
priv->pageshift);
finfo("block sector: %08lx\n", (long)block);
@ -408,16 +432,20 @@ static bool gd5f_sectorerase(FAR struct gd5f_dev_s *priv, off_t startsector)
return gd5f_waitstatus(priv, GD5F_SR_E_FAIL, false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_erase
************************************************************************************/
****************************************************************************/
static int gd5f_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int gd5f_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
FAR struct gd5f_dev_s *priv = (FAR struct gd5f_dev_s *)dev;
size_t blocksleft = nblocks;
finfo("Erase: startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
finfo("Erase: startblock: %08lx nblocks: %d\n",
(long)startblock,
(int)nblocks);
/* Lock access to the SPI bus until we complete the erase */
@ -442,12 +470,14 @@ static int gd5f_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock
return nblocks - blocksleft;
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_readbuffer
************************************************************************************/
****************************************************************************/
static void gd5f_readbuffer(FAR struct gd5f_dev_s *priv, uint32_t address,
uint8_t *buffer, size_t length)
static void gd5f_readbuffer(FAR struct gd5f_dev_s *priv,
uint32_t address,
uint8_t *buffer,
size_t length)
{
const uint16_t offset = address & ((1 << priv->pageshift) - 1);
@ -475,9 +505,9 @@ static void gd5f_readbuffer(FAR struct gd5f_dev_s *priv, uint32_t address,
SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->spi_devid), false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_read_page
************************************************************************************/
****************************************************************************/
static bool gd5f_read_page(FAR struct gd5f_dev_s *priv, uint32_t pageaddress)
{
@ -515,11 +545,13 @@ static bool gd5f_read_page(FAR struct gd5f_dev_s *priv, uint32_t pageaddress)
return true;
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_read
************************************************************************************/
****************************************************************************/
static ssize_t gd5f_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t gd5f_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct gd5f_dev_s *priv = (FAR struct gd5f_dev_s *)dev;
@ -538,9 +570,12 @@ static ssize_t gd5f_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
while (bytesleft)
{
const uint32_t pageaddress = (position >> priv->pageshift) << priv->pageshift;
const uint32_t spaceleft = pageaddress + (1 << priv->pageshift) - position;
const size_t chunklength = bytesleft < spaceleft ? bytesleft : spaceleft;
const uint32_t pageaddress =
(position >> priv->pageshift) << priv->pageshift;
const uint32_t spaceleft =
pageaddress + (1 << priv->pageshift) - position;
const size_t chunklength =
bytesleft < spaceleft ? bytesleft : spaceleft;
if (!gd5f_read_page(priv, pageaddress))
{
@ -560,9 +595,9 @@ static ssize_t gd5f_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
return nbytes - bytesleft;
}
/**************************************************************************
/****************************************************************************
* Name: gd5f_bread
**************************************************************************/
****************************************************************************/
static ssize_t gd5f_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buffer)
@ -583,12 +618,14 @@ static ssize_t gd5f_bread(FAR struct mtd_dev_s *dev, off_t startblock,
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_write_to_cache
************************************************************************************/
****************************************************************************/
static void gd5f_write_to_cache(FAR struct gd5f_dev_s *priv, uint32_t address,
const uint8_t *buffer, size_t length)
static void gd5f_write_to_cache(FAR struct gd5f_dev_s *priv,
uint32_t address,
const uint8_t *buffer,
size_t length)
{
const uint16_t offset = address & ((1 << priv->pageshift) - 1);
@ -614,11 +651,12 @@ static void gd5f_write_to_cache(FAR struct gd5f_dev_s *priv, uint32_t address,
SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->spi_devid), false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_execute_write
************************************************************************************/
****************************************************************************/
static bool gd5f_execute_write(FAR struct gd5f_dev_s *priv, uint32_t pageaddress)
static bool gd5f_execute_write(FAR struct gd5f_dev_s *priv,
uint32_t pageaddress)
{
const uint32_t row = pageaddress >> priv->pageshift;
@ -640,11 +678,13 @@ static bool gd5f_execute_write(FAR struct gd5f_dev_s *priv, uint32_t pageaddress
return gd5f_waitstatus(priv, GD5F_SR_P_FAIL, false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_write
************************************************************************************/
****************************************************************************/
static ssize_t gd5f_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t gd5f_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer)
{
FAR struct gd5f_dev_s *priv = (FAR struct gd5f_dev_s *)dev;
@ -660,9 +700,12 @@ static ssize_t gd5f_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
while (bytesleft)
{
const uint32_t pageaddress = (position >> priv->pageshift) << priv->pageshift;
const uint32_t spaceleft = pageaddress + (1 << priv->pageshift) - position;
const size_t chunklength = bytesleft < spaceleft ? bytesleft : spaceleft;
const uint32_t pageaddress =
(position >> priv->pageshift) << priv->pageshift;
const uint32_t spaceleft =
pageaddress + (1 << priv->pageshift) - position;
const size_t chunklength =
bytesleft < spaceleft ? bytesleft : spaceleft;
gd5f_write_to_cache(priv, position, buffer, chunklength);
gd5f_writeenable(priv);
@ -681,9 +724,9 @@ static ssize_t gd5f_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
return nbytes - bytesleft;
}
/**************************************************************************
/****************************************************************************
* Name: gd5f_bwrite
**************************************************************************/
****************************************************************************/
static ssize_t gd5f_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer)
@ -707,9 +750,9 @@ static ssize_t gd5f_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_ioctl
************************************************************************************/
****************************************************************************/
static int gd5f_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -750,7 +793,8 @@ static int gd5f_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
uint8_t *result = (uint8_t *)arg;
*result =
(priv->eccstatus & GD5F_FEATURE_ECC_MASK) >> GD5F_FEATURE_ECC_OFFSET;
(priv->eccstatus & GD5F_FEATURE_ECC_MASK)
>> GD5F_FEATURE_ECC_OFFSET;
ret = OK;
}
@ -765,9 +809,9 @@ static int gd5f_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_eccstatusread
************************************************************************************/
****************************************************************************/
static inline void gd5f_eccstatusread(FAR struct gd5f_dev_s *priv)
{
@ -778,9 +822,9 @@ static inline void gd5f_eccstatusread(FAR struct gd5f_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->spi_devid), false);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_enable_ecc
************************************************************************************/
****************************************************************************/
static inline void gd5f_enable_ecc(FAR struct gd5f_dev_s *priv)
{
@ -799,9 +843,9 @@ static inline void gd5f_enable_ecc(FAR struct gd5f_dev_s *priv)
gd5f_unlock(priv->dev);
}
/************************************************************************************
/****************************************************************************
* Name: gd5f_unlockblocks
************************************************************************************/
****************************************************************************/
static inline void gd5f_unlockblocks(FAR struct gd5f_dev_s *priv)
{
@ -820,19 +864,20 @@ static inline void gd5f_unlockblocks(FAR struct gd5f_dev_s *priv)
gd5f_unlock(priv->dev);
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: gd5f_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).
* 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 *gd5f_initialize(FAR struct spi_dev_s *dev,
uint32_t spi_devid)
@ -876,7 +921,9 @@ FAR struct mtd_dev_s *gd5f_initialize(FAR struct spi_dev_s *dev,
ret = gd5f_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
ferr("ERROR: Unrecognized\n");
kmm_free(priv);

View file

@ -80,6 +80,7 @@ static unsigned int hamming_bitsinbyte(uint8_t byte)
{
count++;
}
byte >>= 1;
}
@ -194,7 +195,8 @@ static void hamming_compute256(FAR const uint8_t *data, FAR uint8_t *code)
colsum >>= 1;
}
/* Now, we must interleave the parity values, to obtain the following layout:
/* Now, we must interleave the parity values,
* to obtain the following layout:
* Code[0] = Line1
* Code[1] = Line2
* Code[2] = Column
@ -415,7 +417,9 @@ void hamming_compute256x(FAR const uint8_t *data, size_t size, uint8_t *code)
*
****************************************************************************/
int hamming_verify256x(FAR uint8_t *data, size_t size, FAR const uint8_t *code)
int hamming_verify256x(FAR uint8_t *data,
size_t size,
FAR const uint8_t *code)
{
ssize_t remaining = (ssize_t)size;
int result = HAMMING_SUCCESS;

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/is25xp.c
* Driver for SPI-based IS25LPxx parts 32MBit and larger.
*
@ -37,11 +37,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -59,28 +59,30 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* Per the data sheet, IS25xP parts can be driven with either SPI mode 0 (CPOL=0 and
* CPHA=0) or mode 3 (CPOL=1 and CPHA=1). So you may need to specify
* CONFIG_IS25XP_SPIMODE to select the best mode for your device. If
* CONFIG_IS25XP_SPIMODE is not defined, mode 0 will be used.
/* Configuration ************************************************************/
/* Per the data sheet, IS25xP parts can be driven with either SPI mode 0
* (CPOL=0 and CPHA=0) or mode 3 (CPOL=1 and CPHA=1). So you may need to
* specify CONFIG_IS25XP_SPIMODE to select the best mode for your device.
* If CONFIG_IS25XP_SPIMODE is not defined, mode 0 will be used.
*/
#ifndef CONFIG_IS25XP_SPIMODE
# define CONFIG_IS25XP_SPIMODE SPIDEV_MODE0
#define CONFIG_IS25XP_SPIMODE SPIDEV_MODE0
#endif
/* SPI Frequency. May be up to 50MHz. */
#ifndef CONFIG_IS25XP_SPIFREQUENCY
# define CONFIG_IS25XP_SPIFREQUENCY 20000000
#define CONFIG_IS25XP_SPIFREQUENCY 20000000
#endif
/* IS25 Registers *******************************************************************/
/* IS25 Registers ***********************************************************/
/* Identification register values */
#define IS25_MANUFACTURER 0x9d
@ -108,22 +110,24 @@
#define IS25_IS25LP128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
#define IS25_IS25LP128_NPAGES 65536
/* Instructions */
/* Command Value N Description Addr Dummy Data */
#define IS25_WREN 0x06 /* 1 Write Enable 0 0 0 */
#define IS25_WRDI 0x04 /* 1 Write Disable 0 0 0 */
#define IS25_RDID 0x9f /* 1 Read Identification 0 0 1-3 */
#define IS25_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */
//#define IS25_EWSR 0x50 /* 1 Write enable status 0 0 0 */
#define IS25_WRSR 0x01 /* 1 Write Status Register 0 0 1 */
#define IS25_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */
#define IS25_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */
#define IS25_PP 0x02 /* 1 Page Program 3 0 1-256 */
#define IS25_SE 0x20 /* 1 Sector Erase 3 0 0 */
#define IS25_BE32 0x52 /* 2 32K Block Erase 3 0 0 */
#define IS25_BE64 0xD8 /* 2 64K Block Erase 3 0 0 */
#define IS25_CER 0xC7 /* 1 Chip Erase 0 0 0 */
/* Command Value N Description Addr Dummy Data */
#define IS25_WREN 0x06 /* 1 Write Enable 0 0 0 */
#define IS25_WRDI 0x04 /* 1 Write Disable 0 0 0 */
#define IS25_RDID 0x9f /* 1 Read Identification 0 0 1-3 */
#define IS25_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */
/* #define IS25_EWSR 0x50 1 Write enable status 0 0 0 */
#define IS25_WRSR 0x01 /* 1 Write Status Register 0 0 1 */
#define IS25_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */
#define IS25_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */
#define IS25_PP 0x02 /* 1 Page Program 3 0 1-256 */
#define IS25_SE 0x20 /* 1 Sector Erase 3 0 0 */
#define IS25_BE32 0x52 /* 2 32K Block Erase 3 0 0 */
#define IS25_BE64 0xD8 /* 2 64K Block Erase 3 0 0 */
#define IS25_CER 0xC7 /* 1 Chip Erase 0 0 0 */
/* NOTE 1: All parts.
* NOTE 2: In IS25XP terminology, 0x52 and 0xd8 are block erase and 0x20
@ -133,27 +137,27 @@
/* Status register bit definitions */
#define IS25_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */
#define IS25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */
#define IS25_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */
#define IS25_SR_BP_MASK (15 << IS25_SR_BP_SHIFT)
# define IS25_SR_BP_NONE (0 << IS25_SR_BP_SHIFT) /* Unprotected */
# define IS25_SR_BP_UPPER128th (1 << IS25_SR_BP_SHIFT) /* Upper 128th */
# define IS25_SR_BP_UPPER64th (2 << IS25_SR_BP_SHIFT) /* Upper 64th */
# define IS25_SR_BP_UPPER32nd (3 << IS25_SR_BP_SHIFT) /* Upper 32nd */
# define IS25_SR_BP_UPPER16th (4 << IS25_SR_BP_SHIFT) /* Upper 16th */
# define IS25_SR_BP_UPPER8th (5 << IS25_SR_BP_SHIFT) /* Upper 8th */
# define IS25_SR_BP_UPPERQTR (6 << IS25_SR_BP_SHIFT) /* Upper quarter */
# define IS25_SR_BP_UPPERHALF (7 << IS25_SR_BP_SHIFT) /* Upper half */
# define IS25_SR_BP_ALL (8 << IS25_SR_BP_SHIFT) /* All sectors */
#define IS25_SR_QE (1 << 6) /* Bit 6: Quad (QSPI) enable bit */
#define IS25_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */
#define IS25_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */
#define IS25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */
#define IS25_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */
#define IS25_SR_BP_MASK (15 << IS25_SR_BP_SHIFT)
#define IS25_SR_BP_NONE (0 << IS25_SR_BP_SHIFT) /* Unprotected */
#define IS25_SR_BP_UPPER128th (1 << IS25_SR_BP_SHIFT) /* Upper 128th */
#define IS25_SR_BP_UPPER64th (2 << IS25_SR_BP_SHIFT) /* Upper 64th */
#define IS25_SR_BP_UPPER32nd (3 << IS25_SR_BP_SHIFT) /* Upper 32nd */
#define IS25_SR_BP_UPPER16th (4 << IS25_SR_BP_SHIFT) /* Upper 16th */
#define IS25_SR_BP_UPPER8th (5 << IS25_SR_BP_SHIFT) /* Upper 8th */
#define IS25_SR_BP_UPPERQTR (6 << IS25_SR_BP_SHIFT) /* Upper quarter */
#define IS25_SR_BP_UPPERHALF (7 << IS25_SR_BP_SHIFT) /* Upper half */
#define IS25_SR_BP_ALL (8 << IS25_SR_BP_SHIFT) /* All sectors */
#define IS25_SR_QE (1 << 6) /* Bit 6: Quad (QSPI) enable bit */
#define IS25_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */
#define IS25_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
@ -171,9 +175,9 @@ struct is25xp_dev_s
uint8_t lastwaswrite; /* Indicates if last operation was write */
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -182,29 +186,42 @@ static inline void is25xp_unlock(FAR struct spi_dev_s *dev);
static inline int is25xp_readid(struct is25xp_dev_s *priv);
static void is25xp_waitwritecomplete(struct is25xp_dev_s *priv);
static void is25xp_writeenable(struct is25xp_dev_s *priv);
static inline void is25xp_sectorerase(struct is25xp_dev_s *priv, off_t offset, uint8_t type);
static inline void is25xp_sectorerase(struct is25xp_dev_s *priv,
off_t offset,
uint8_t type);
static inline int is25xp_bulkerase(struct is25xp_dev_s *priv);
static inline void is25xp_pagewrite(struct is25xp_dev_s *priv, FAR const uint8_t *buffer,
off_t offset);
static inline void is25xp_pagewrite(struct is25xp_dev_s *priv,
FAR const uint8_t *buffer,
off_t offset);
/* MTD driver methods */
static int is25xp_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
static ssize_t is25xp_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buf);
static ssize_t is25xp_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buf);
static ssize_t is25xp_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR uint8_t *buffer);
static int is25xp_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks);
static ssize_t is25xp_bread(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks, FAR uint8_t *buf);
static ssize_t is25xp_bwrite(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks, FAR const uint8_t *buf);
static ssize_t is25xp_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer);
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t is25xp_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR const uint8_t *buffer);
static ssize_t is25xp_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer);
#endif
static int is25xp_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int is25xp_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Name: is25xp_lock
************************************************************************************/
****************************************************************************/
static void is25xp_lock(FAR struct spi_dev_s *dev)
{
@ -212,16 +229,18 @@ static void is25xp_lock(FAR struct spi_dev_s *dev)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus. We will retain that exclusive access until the
* bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(dev, CONFIG_IS25XP_SPIMODE);
@ -230,18 +249,18 @@ static void is25xp_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_IS25XP_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_unlock
************************************************************************************/
****************************************************************************/
static inline void is25xp_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_readid
************************************************************************************/
****************************************************************************/
static inline int is25xp_readid(struct is25xp_dev_s *priv)
{
@ -302,9 +321,9 @@ static inline int is25xp_readid(struct is25xp_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_waitwritecomplete
************************************************************************************/
****************************************************************************/
static void is25xp_waitwritecomplete(struct is25xp_dev_s *priv)
{
@ -335,7 +354,9 @@ static void is25xp_waitwritecomplete(struct is25xp_dev_s *priv)
do
{
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out
* the status
*/
status = SPI_SEND(priv->dev, IS25_DUMMY);
}
@ -359,7 +380,9 @@ static void is25xp_waitwritecomplete(struct is25xp_dev_s *priv)
SPI_SEND(priv->dev, IS25_RDSR);
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out
* the status
*/
status = SPI_SEND(priv->dev, IS25_DUMMY);
@ -367,9 +390,9 @@ static void is25xp_waitwritecomplete(struct is25xp_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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.
/* 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 & IS25_SR_WIP) != 0)
@ -387,9 +410,9 @@ static void is25xp_waitwritecomplete(struct is25xp_dev_s *priv)
finfo("Complete\n");
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_writeenable
************************************************************************************/
****************************************************************************/
static void is25xp_writeenable(struct is25xp_dev_s *priv)
{
@ -407,9 +430,9 @@ static void is25xp_writeenable(struct is25xp_dev_s *priv)
finfo("Enabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_unprotect
************************************************************************************/
****************************************************************************/
static void is25xp_unprotect(struct is25xp_dev_s *priv)
{
@ -429,11 +452,13 @@ static void is25xp_unprotect(struct is25xp_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_sectorerase
************************************************************************************/
****************************************************************************/
static void is25xp_sectorerase(struct is25xp_dev_s *priv, off_t sector, uint8_t type)
static void is25xp_sectorerase(struct is25xp_dev_s *priv,
off_t sector,
uint8_t type)
{
off_t offset;
@ -479,9 +504,9 @@ static void is25xp_sectorerase(struct is25xp_dev_s *priv, off_t sector, uint8_t
finfo("Erased\n");
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_bulkerase
************************************************************************************/
****************************************************************************/
static inline int is25xp_bulkerase(struct is25xp_dev_s *priv)
{
@ -516,12 +541,13 @@ static inline int is25xp_bulkerase(struct is25xp_dev_s *priv)
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_pagewrite
************************************************************************************/
****************************************************************************/
static inline void is25xp_pagewrite(struct is25xp_dev_s *priv, FAR const uint8_t *buffer,
off_t page)
static inline void is25xp_pagewrite(struct is25xp_dev_s *priv,
FAR const uint8_t *buffer,
off_t page)
{
off_t offset = page << priv->pageshift;
@ -564,9 +590,9 @@ static inline void is25xp_pagewrite(struct is25xp_dev_s *priv, FAR const uint8_t
finfo("Written\n");
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_bytewrite
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MTD_BYTE_WRITE
static inline void is25xp_bytewrite(struct is25xp_dev_s *priv,
@ -613,11 +639,13 @@ static inline void is25xp_bytewrite(struct is25xp_dev_s *priv,
}
#endif
/************************************************************************************
/****************************************************************************
* Name: is25xp_erase
************************************************************************************/
****************************************************************************/
static int is25xp_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int is25xp_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
FAR struct is25xp_dev_s *priv = (FAR struct is25xp_dev_s *)dev;
size_t blocksleft = nblocks;
@ -689,21 +717,28 @@ static int is25xp_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblo
return (int)nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_bread
************************************************************************************/
****************************************************************************/
static ssize_t is25xp_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
FAR uint8_t *buffer)
static ssize_t is25xp_bread(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR uint8_t *buffer)
{
FAR struct is25xp_dev_s *priv = (FAR struct is25xp_dev_s *)dev;
ssize_t nbytes;
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* On this device, we can handle the block read just like the byte-oriented
* read
*/
nbytes = is25xp_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer);
nbytes = is25xp_read(dev,
startblock << priv->pageshift,
nblocks << priv->pageshift,
buffer);
if (nbytes > 0)
{
return nbytes >> priv->pageshift;
@ -712,12 +747,14 @@ static ssize_t is25xp_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t
return (int)nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_bwrite
************************************************************************************/
****************************************************************************/
static ssize_t is25xp_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
FAR const uint8_t *buffer)
static ssize_t is25xp_bwrite(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buffer)
{
FAR struct is25xp_dev_s *priv = (FAR struct is25xp_dev_s *)dev;
size_t blocksleft = nblocks;
@ -733,18 +770,20 @@ static ssize_t is25xp_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t
is25xp_pagewrite(priv, buffer, startblock);
buffer += pagesize;
startblock++;
}
}
is25xp_unlock(priv->dev);
return nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_read
************************************************************************************/
****************************************************************************/
static ssize_t is25xp_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR uint8_t *buffer)
static ssize_t is25xp_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct is25xp_dev_s *priv = (FAR struct is25xp_dev_s *)dev;
@ -794,13 +833,15 @@ static ssize_t is25xp_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbyte
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: is25xp_write
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t is25xp_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR const uint8_t *buffer)
static ssize_t is25xp_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer)
{
FAR struct is25xp_dev_s *priv = (FAR struct is25xp_dev_s *)dev;
int startpage;
@ -833,7 +874,7 @@ static ssize_t is25xp_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbyt
count = nbytes;
pagesize = (1 << priv->pageshift);
bytestowrite = pagesize - (offset & (pagesize-1));
bytestowrite = pagesize - (offset & (pagesize - 1));
is25xp_bytewrite(priv, buffer, offset, bytestowrite);
/* Update offset and count */
@ -870,11 +911,13 @@ static ssize_t is25xp_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbyt
}
#endif /* CONFIG_MTD_BYTE_WRITE */
/************************************************************************************
/****************************************************************************
* Name: is25xp_ioctl
************************************************************************************/
****************************************************************************/
static int is25xp_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
static int is25xp_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg)
{
FAR struct is25xp_dev_s *priv = (FAR struct is25xp_dev_s *)dev;
int ret = -EINVAL; /* Assume good command with bad parameters */
@ -885,16 +928,18 @@ static int is25xp_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
case MTDIOC_GEOMETRY:
{
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
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.
/* 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.
* 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);
@ -929,19 +974,19 @@ static int is25xp_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: is25xp_initialize
*
* Description:
* Create an initialize MTD device instance. MTD devices are not registered
* 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 *is25xp_initialize(FAR struct spi_dev_s *dev)
{
@ -953,8 +998,8 @@ FAR struct mtd_dev_s *is25xp_initialize(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct is25xp_dev_s *)kmm_zalloc(sizeof(struct is25xp_dev_s));
@ -985,7 +1030,9 @@ FAR struct mtd_dev_s *is25xp_initialize(FAR struct spi_dev_s *dev)
ret = is25xp_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
ferr("ERROR: Unrecognized\n");
kmm_free(priv);
@ -993,7 +1040,9 @@ FAR struct mtd_dev_s *is25xp_initialize(FAR struct spi_dev_s *dev)
}
else
{
/* Make sure that the FLASH is unprotected so that we can write into it */
/* Make sure that the FLASH is unprotected so that we can
* write into it
*/
is25xp_unprotect(priv);
}

View file

@ -1,7 +1,7 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/m25px.c
* Driver for SPI-based M25P1 (128Kbit), M25P64 (32Mbit), M25P64 (64Mbit), and
* M25P128 (128Mbit) FLASH (and compatible).
* Driver for SPI-based M25P1 (128Kbit), M25P64 (32Mbit), M25P64 (64Mbit),
* and M25P128 (128Mbit) FLASH (and compatible).
*
* Copyright (C) 2009-2011, 2013, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@ -33,11 +33,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -56,17 +56,18 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* Configuration ************************************************************/
/* Per the data sheet, M25P10 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_M25P_SPIMODE to
* select the best mode for your device. If CONFIG_M25P_SPIMODE is not defined,
* mode 0 will be used.
/* Per the data sheet, M25P10 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_M25P_SPIMODE to
* select the best mode for your device.
* If CONFIG_M25P_SPIMODE is not defined, mode 0 will be used.
*/
#ifndef CONFIG_M25P_SPIMODE
@ -77,9 +78,10 @@
# define CONFIG_M25P_SPIFREQUENCY 20000000
#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.
/* 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_M25P_MANUFACTURER
@ -94,7 +96,7 @@
# define CONFIG_MT25Q_MEMORY_TYPE 0xBA
#endif
/* M25P Registers *******************************************************************/
/* M25P Registers ***********************************************************/
/* Identification register values */
@ -187,20 +189,20 @@
/* 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 */
#define M25P_SSE 0x20 /* 3 Sub-Sector Erase 0 0 0 */
/* 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 */
#define M25P_SSE 0x20 /* 3 Sub-Sector Erase 0 0 0 */
/* NOTE 1: All parts.
* NOTE 2: M25P632/M25P64
@ -227,9 +229,9 @@
#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
@ -249,9 +251,9 @@ struct m25p_dev_s
#endif
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -260,38 +262,51 @@ 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 void m25p_sectorerase(struct m25p_dev_s *priv,
off_t offset,
uint8_t type);
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,
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,
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);
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t m25p_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR const uint8_t *buffer);
static ssize_t m25p_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer);
#endif
static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
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)
{
@ -299,16 +314,18 @@ static void m25p_lock(FAR struct spi_dev_s *dev)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus. We will retain that exclusive access until the
* bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(dev, CONFIG_M25P_SPIMODE);
@ -317,18 +334,18 @@ static void m25p_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_M25P_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: m25p_unlock
************************************************************************************/
****************************************************************************/
static inline void m25p_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: m25p_readid
************************************************************************************/
****************************************************************************/
static inline int m25p_readid(struct m25p_dev_s *priv)
{
@ -463,9 +480,9 @@ static inline int m25p_readid(struct m25p_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: m25p_waitwritecomplete
************************************************************************************/
****************************************************************************/
static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
{
@ -483,7 +500,9 @@ static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
SPI_SEND(priv->dev, M25P_RDSR);
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out the
* status
*/
status = SPI_SEND(priv->dev, M25P_DUMMY);
@ -491,9 +510,10 @@ static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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.
/* 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)
@ -508,9 +528,9 @@ static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
finfo("Complete\n");
}
/************************************************************************************
/****************************************************************************
* Name: m25p_writeenable
************************************************************************************/
****************************************************************************/
static void m25p_writeenable(struct m25p_dev_s *priv)
{
@ -528,11 +548,13 @@ static void m25p_writeenable(struct m25p_dev_s *priv)
finfo("Enabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: m25p_sectorerase
************************************************************************************/
****************************************************************************/
static void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector, uint8_t type)
static void m25p_sectorerase(struct m25p_dev_s *priv,
off_t sector,
uint8_t type)
{
off_t offset;
@ -549,7 +571,7 @@ static void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector, uint8_t type
finfo("sector: %08lx\n", (long)sector);
/* Wait for any preceding write to complete. We could simplify things by
/* 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.
@ -586,9 +608,9 @@ static void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector, uint8_t type
finfo("Erased\n");
}
/************************************************************************************
/****************************************************************************
* Name: m25p_bulkerase
************************************************************************************/
****************************************************************************/
static inline int m25p_bulkerase(struct m25p_dev_s *priv)
{
@ -621,11 +643,12 @@ static inline int m25p_bulkerase(struct m25p_dev_s *priv)
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: m25p_pagewrite
************************************************************************************/
****************************************************************************/
static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer,
static inline void m25p_pagewrite(struct m25p_dev_s *priv,
FAR const uint8_t *buffer,
off_t page)
{
off_t offset = page << priv->pageshift;
@ -668,13 +691,15 @@ static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *bu
finfo("Written\n");
}
/************************************************************************************
/****************************************************************************
* Name: m25p_bytewrite
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MTD_BYTE_WRITE
static inline void m25p_bytewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer,
off_t offset, uint16_t count)
static inline void m25p_bytewrite(struct m25p_dev_s *priv,
FAR const uint8_t *buffer,
off_t offset,
uint16_t count)
{
finfo("offset: %08lx count:%d\n", (long)offset, count);
@ -715,11 +740,13 @@ static inline void m25p_bytewrite(struct m25p_dev_s *priv, FAR const uint8_t *bu
}
#endif
/************************************************************************************
/****************************************************************************
* Name: m25p_erase
************************************************************************************/
****************************************************************************/
static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
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;
@ -782,9 +809,9 @@ static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock
return (int)nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: m25p_bread
************************************************************************************/
****************************************************************************/
static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks,
@ -809,9 +836,9 @@ static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock,
return (int)nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: m25p_bwrite
************************************************************************************/
****************************************************************************/
static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks,
@ -837,11 +864,13 @@ static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
return nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: m25p_read
************************************************************************************/
****************************************************************************/
static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
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;
@ -889,13 +918,15 @@ static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: m25p_write
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t m25p_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR const uint8_t *buffer)
static ssize_t m25p_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer)
{
FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev;
int startpage;
@ -963,9 +994,9 @@ static ssize_t m25p_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
}
#endif /* CONFIG_MTD_BYTE_WRITE */
/************************************************************************************
/****************************************************************************
* Name: m25p_ioctl
************************************************************************************/
****************************************************************************/
static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -982,13 +1013,15 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
((uintptr_t)arg);
if (geo)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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);
@ -996,8 +1029,9 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
if (priv->subsectorshift > 0)
{
geo->erasesize = (1 << priv->subsectorshift);
geo->neraseblocks = priv->nsectors * (1 << (priv->sectorshift -
priv->subsectorshift));
geo->neraseblocks = priv->nsectors *
(1 << (priv->sectorshift -
priv->subsectorshift));
}
else
#endif
@ -1035,19 +1069,20 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
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).
* 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)
{
@ -1059,8 +1094,8 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct m25p_dev_s *)kmm_zalloc(sizeof(struct m25p_dev_s));
@ -1090,7 +1125,9 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev)
ret = m25p_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized!
* Discard all of that work we just did and return NULL
*/
ferr("ERROR: Unrecognized\n");
kmm_free(priv);

View file

@ -1,4 +1,4 @@
/**************************************************************************************************
/****************************************************************************
* drivers/mtd/mtd_modeltab.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
@ -37,11 +37,11 @@
* 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 <nuttx/mtd/nand_config.h>
@ -49,122 +49,109 @@
#include <nuttx/mtd/nand_scheme.h>
#include <nuttx/mtd/nand_model.h>
/**************************************************************************************************
/****************************************************************************
* Public Data
**************************************************************************************************/
****************************************************************************/
/* List of NandFlash models which can be recognized by the software */
/****************************************************************************
* ID OPTIONS PAGE SPARE DEV BLOCK | SCHEME
* SIZE SIZE SIZE SIZE |
****************************************************************************/
const struct nand_model_s g_nandmodels[NAND_NMODELS] =
{
/*----------|------------------------------+------+-------+------+-------+------------------------
* | ID | OPTIONS | PAGE | SPARE | DEV | BLOCK | SCHEME
* | | | SIZE | SIZE | SIZE | SIZE |
*----------|------------------------------+------+-------+------+-------+------------------------*/
{0x6e, NANDMODEL_DATAWIDTH8, 256, 0, 1, 4, &g_nand_sparescheme256},
{0x64, NANDMODEL_DATAWIDTH8, 256, 0, 2, 4, &g_nand_sparescheme256},
{0x68, NANDMODEL_DATAWIDTH8, 4096, 0, 224, 1024, &g_nand_sparescheme4096},
{0x6b, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xe8, NANDMODEL_DATAWIDTH8, 256, 0, 1, 4, &g_nand_sparescheme256},
{0xec, NANDMODEL_DATAWIDTH8, 256, 0, 1, 4, &g_nand_sparescheme256},
{0xea, NANDMODEL_DATAWIDTH8, 256, 0, 2, 4, &g_nand_sparescheme256},
{0xd5, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xe3, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xe5, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xd6, NANDMODEL_DATAWIDTH8, 512, 0, 8, 8, &g_nand_sparescheme512},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0x39, NANDMODEL_DATAWIDTH8, 512, 0, 8, 8, &g_nand_sparescheme512},
{0xe6, NANDMODEL_DATAWIDTH8, 512, 0, 8, 8, &g_nand_sparescheme512},
{0x49, NANDMODEL_DATAWIDTH16, 512, 0, 8, 8, &g_nand_sparescheme512},
{0x59, NANDMODEL_DATAWIDTH16, 512, 0, 8, 8, &g_nand_sparescheme512},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0x33, NANDMODEL_DATAWIDTH8, 512, 0, 16, 16, &g_nand_sparescheme512},
{0x73, NANDMODEL_DATAWIDTH8, 512, 0, 16, 16, &g_nand_sparescheme512},
{0x43, NANDMODEL_DATAWIDTH16, 512, 0, 16, 16, &g_nand_sparescheme512},
{0x53, NANDMODEL_DATAWIDTH16, 512, 0, 16, 16, &g_nand_sparescheme512},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0x35, NANDMODEL_DATAWIDTH8, 512, 0, 32, 16, &g_nand_sparescheme512},
{0x75, NANDMODEL_DATAWIDTH8, 512, 0, 32, 16, &g_nand_sparescheme512},
{0x45, NANDMODEL_DATAWIDTH16, 512, 0, 32, 16, &g_nand_sparescheme512},
{0x55, NANDMODEL_DATAWIDTH16, 512, 0, 32, 16, &g_nand_sparescheme512},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0x36, NANDMODEL_DATAWIDTH8, 512, 0, 64, 16, &g_nand_sparescheme512},
{0x76, NANDMODEL_DATAWIDTH8, 512, 0, 64, 16, &g_nand_sparescheme512},
{0x46, NANDMODEL_DATAWIDTH16, 512, 0, 64, 16, &g_nand_sparescheme512},
{0x56, NANDMODEL_DATAWIDTH16, 512, 0, 64, 16, &g_nand_sparescheme512},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0x78, NANDMODEL_DATAWIDTH8, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x39, NANDMODEL_DATAWIDTH8, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x79, NANDMODEL_DATAWIDTH8, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x72, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x49, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x74, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x59, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0x71, NANDMODEL_DATAWIDTH8, 512, 0, 256, 16, &g_nand_sparescheme512},
/* Large blocks devices. Parameters must be fetched from the extended I */
{0x6e, NANDMODEL_DATAWIDTH8, 256, 0, 1, 4, &g_nand_sparescheme256},
{0x64, NANDMODEL_DATAWIDTH8, 256, 0, 2, 4, &g_nand_sparescheme256},
{0x68, NANDMODEL_DATAWIDTH8, 4096, 0, 224, 1024, &g_nand_sparescheme4096},
{0x6b, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xe8, NANDMODEL_DATAWIDTH8, 256, 0, 1, 4, &g_nand_sparescheme256},
{0xec, NANDMODEL_DATAWIDTH8, 256, 0, 1, 4, &g_nand_sparescheme256},
{0xea, NANDMODEL_DATAWIDTH8, 256, 0, 2, 4, &g_nand_sparescheme256},
{0xd5, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xe3, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xe5, NANDMODEL_DATAWIDTH8, 512, 0, 4, 8, &g_nand_sparescheme512},
{0xd6, NANDMODEL_DATAWIDTH8, 512, 0, 8, 8, &g_nand_sparescheme512},
{0x39, NANDMODEL_DATAWIDTH8, 512, 0, 8, 8, &g_nand_sparescheme512},
{0xe6, NANDMODEL_DATAWIDTH8, 512, 0, 8, 8, &g_nand_sparescheme512},
{0x49, NANDMODEL_DATAWIDTH16, 512, 0, 8, 8, &g_nand_sparescheme512},
{0x59, NANDMODEL_DATAWIDTH16, 512, 0, 8, 8, &g_nand_sparescheme512},
{0x33, NANDMODEL_DATAWIDTH8, 512, 0, 16, 16, &g_nand_sparescheme512},
{0x73, NANDMODEL_DATAWIDTH8, 512, 0, 16, 16, &g_nand_sparescheme512},
{0x43, NANDMODEL_DATAWIDTH16, 512, 0, 16, 16, &g_nand_sparescheme512},
{0x53, NANDMODEL_DATAWIDTH16, 512, 0, 16, 16, &g_nand_sparescheme512},
{0x35, NANDMODEL_DATAWIDTH8, 512, 0, 32, 16, &g_nand_sparescheme512},
{0x75, NANDMODEL_DATAWIDTH8, 512, 0, 32, 16, &g_nand_sparescheme512},
{0x45, NANDMODEL_DATAWIDTH16, 512, 0, 32, 16, &g_nand_sparescheme512},
{0x55, NANDMODEL_DATAWIDTH16, 512, 0, 32, 16, &g_nand_sparescheme512},
{0x36, NANDMODEL_DATAWIDTH8, 512, 0, 64, 16, &g_nand_sparescheme512},
{0x76, NANDMODEL_DATAWIDTH8, 512, 0, 64, 16, &g_nand_sparescheme512},
{0x46, NANDMODEL_DATAWIDTH16, 512, 0, 64, 16, &g_nand_sparescheme512},
{0x56, NANDMODEL_DATAWIDTH16, 512, 0, 64, 16, &g_nand_sparescheme512},
{0x78, NANDMODEL_DATAWIDTH8, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x39, NANDMODEL_DATAWIDTH8, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x79, NANDMODEL_DATAWIDTH8, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x72, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x49, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x74, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x59, NANDMODEL_DATAWIDTH16, 512, 0, 128, 16, &g_nand_sparescheme512},
{0x71, NANDMODEL_DATAWIDTH8, 512, 0, 256, 16, &g_nand_sparescheme512},
/* Large blocks devices. Parameters must be fetched from the extended I */
#define OPTIONS NANDMODEL_COPYBACK
/*----------|------------------------------+------+-------+------+-------+------------------------
* | ID | OPTIONS | PAGE | SPARE | DEV | BLOCK | SCHEME
* | | | SIZE | SIZE | SIZE | SIZE |
*----------|------------------------------+------+-------+------+-------+------------------------*/
{0xA2, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 64, 0, &g_nand_sparescheme2048},
{0xF2, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 64, 0, &g_nand_sparescheme2048},
{0xB2, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 64, 0, &g_nand_sparescheme2048},
{0xC2, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 64, 0, &g_nand_sparescheme2048},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0xA1, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 128, 0, &g_nand_sparescheme2048},
{0xF1, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 128, 0, &g_nand_sparescheme2048},
{0xB1, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 128, 0, &g_nand_sparescheme2048},
{0xC1, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 128, 0, &g_nand_sparescheme2048},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0xAA, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 256, 0, &g_nand_sparescheme2048},
{0xDA, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 256, 0, &g_nand_sparescheme2048},
{0xBA, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 256, 0, &g_nand_sparescheme2048},
{0xCA, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 256, 0, &g_nand_sparescheme2048},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0xAC, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 512, 0, &g_nand_sparescheme2048},
{0xDC, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 512, 0, &g_nand_sparescheme2048},
{0xBC, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 512, 0, &g_nand_sparescheme2048},
{0xCC, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 512, 0, &g_nand_sparescheme2048},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0xA3, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 1024, 0, &g_nand_sparescheme2048},
{0xD3, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 1024, 0, &g_nand_sparescheme2048},
{0xB3, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 1024, 0, &g_nand_sparescheme2048},
{0xC3, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 1024, 0, &g_nand_sparescheme2048},
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0xA5, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 2048, 0, &g_nand_sparescheme2048},
{0xD5, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 2048, 0, &g_nand_sparescheme2048},
{0xB5, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 2048, 0, &g_nand_sparescheme2048},
{0xC5, NANDMODEL_DATAWIDTH16 | OPTIONS, 0, 0, 2048, 0, &g_nand_sparescheme2048},
{0x38, NANDMODEL_DATAWIDTH8 | OPTIONS, 0, 0, 1024, 0, &g_nand_sparescheme4096}
/*----------|------------------------------+------+-------+------+-------+------------------------*/
{0xa2, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 64, 0, &g_nand_sparescheme2048},
{0xf2, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 64, 0, &g_nand_sparescheme2048},
{0xb2, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 64, 0, &g_nand_sparescheme2048},
{0xc2, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 64, 0, &g_nand_sparescheme2048},
{0xa1, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 128, 0, &g_nand_sparescheme2048},
{0xf1, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 128, 0, &g_nand_sparescheme2048},
{0xb1, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 128, 0, &g_nand_sparescheme2048},
{0xc1, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 128, 0, &g_nand_sparescheme2048},
{0xaa, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 256, 0, &g_nand_sparescheme2048},
{0xda, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 256, 0, &g_nand_sparescheme2048},
{0xba, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 256, 0, &g_nand_sparescheme2048},
{0xca, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 256, 0, &g_nand_sparescheme2048},
{0xac, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 512, 0, &g_nand_sparescheme2048},
{0xdc, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 512, 0, &g_nand_sparescheme2048},
{0xbc, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 512, 0, &g_nand_sparescheme2048},
{0xcc, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 512, 0, &g_nand_sparescheme2048},
{0xa3, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 1024, 0, &g_nand_sparescheme2048},
{0xd3, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 1024, 0, &g_nand_sparescheme2048},
{0xb3, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 1024, 0, &g_nand_sparescheme2048},
{0xd3, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 1024, 0, &g_nand_sparescheme2048},
{0xa5, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 2048, 0, &g_nand_sparescheme2048},
{0xd5, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 2048, 0, &g_nand_sparescheme2048},
{0xb5, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 2048, 0, &g_nand_sparescheme2048},
{0xc5, NANDMODEL_DATAWIDTH16 | OPTIONS,
0, 0, 2048, 0, &g_nand_sparescheme2048},
{0x38, NANDMODEL_DATAWIDTH8 | OPTIONS,
0, 0, 1024, 0, &g_nand_sparescheme4096}
};
/****************************************************************************
* Public Functions
****************************************************************************/

View file

@ -97,7 +97,11 @@ int nandecc_readpage(FAR struct nand_dev_s *nand, off_t block,
unsigned int sparesize;
int ret;
finfo("block=%d page=%d data=%p spare=%d\n", (int)block, page, data, spare);
finfo("block=%d page=%d data=%p spare=%d\n",
(int)block,
page,
data,
spare);
/* Get convenience pointers */
@ -189,7 +193,11 @@ int nandecc_writepage(FAR struct nand_dev_s *nand, off_t block,
unsigned int sparesize;
int ret;
finfo("block=%d page=%d data=%p spare=%d\n", (int)block, page, data, spare);
finfo("block=%d page=%d data=%p spare=%d\n",
(int)block,
page,
data,
spare);
/* Get convenience pointers */

View file

@ -73,7 +73,8 @@
* Input Parameters:
* modeltab List of nand_model_s instances.
* size Number of models in list.
* chipid Identifier returned by the Nand(id1|(id2<<8)|(id3<<16)|(id4<<24)).
* chipid Identifier returned by the Nand
* (id1|(id2<<8)|(id3<<16)|(id4<<24)).
* model nand_model_s instance to update with the model parameters.
*
* Returned Value:

View file

@ -1,7 +1,7 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/mtd_rwbuffer.c
* MTD driver that contains another MTD driver and provides read-ahead and/or write
* buffering.
* MTD driver that contains another MTD driver and provides read-ahead
* and/or write buffering.
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@ -33,11 +33,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -59,9 +59,9 @@
#if defined(CONFIG_DRVR_WRITEBUFFER) || defined(CONFIG_DRVR_READAHEAD)
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_DRVR_INVALIDATE
# error This driver requires CONFIG_DRVR_INVALIDATE
@ -79,62 +79,79 @@
# define CONFIG_MTD_NRDBLOCKS 4
#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 mtd_rwbuffer_s.
/* 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
* mtd_rwbuffer_s.
*/
struct mtd_rwbuffer_s
{
struct mtd_dev_s mtd; /* Our exported MTD interface */
FAR struct mtd_dev_s *dev; /* Saved lower level MTD interface instance */
struct rwbuffer_s rwb; /* The rwbuffer state structure */
uint16_t spb; /* Number of sectors per block */
struct mtd_dev_s mtd; /* Our exported MTD interface */
FAR struct mtd_dev_s *dev; /* Saved lower level MTD interface instance */
struct rwbuffer_s rwb; /* The rwbuffer state structure */
uint16_t spb; /* Number of sectors per block */
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* rwbuffer callouts */
static ssize_t mtd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock,
static ssize_t mtd_reload(FAR void *dev,
FAR uint8_t *buffer,
off_t startblock,
size_t nblocks);
static ssize_t mtd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock,
static ssize_t mtd_flush(FAR void *dev,
FAR const uint8_t *buffer,
off_t startblock,
size_t nblocks);
/* MTD driver methods */
static int mtd_erase(FAR struct mtd_dev_s *dev, off_t block, size_t nsectors);
static ssize_t mtd_bread(FAR struct mtd_dev_s *dev, off_t block,
size_t nsectors, FAR uint8_t *buf);
static ssize_t mtd_bwrite(FAR struct mtd_dev_s *dev, off_t block,
size_t nsectors, FAR const uint8_t *buf);
static ssize_t mtd_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static int mtd_erase(FAR struct mtd_dev_s *dev,
off_t block,
size_t nsectors);
static ssize_t mtd_bread(FAR struct mtd_dev_s *dev,
off_t block,
size_t nsectors,
FAR uint8_t *buf);
static ssize_t mtd_bwrite(FAR struct mtd_dev_s *dev,
off_t block,
size_t nsectors,
FAR const uint8_t *buf);
static ssize_t mtd_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer);
static int mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int mtd_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Data
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: mtd_reload
*
* Description:
* Reload the read-ahead buffer
*
************************************************************************************/
****************************************************************************/
static ssize_t mtd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock,
static ssize_t mtd_reload(FAR void *dev,
FAR uint8_t *buffer,
off_t startblock,
size_t nblocks)
{
FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev;
@ -145,15 +162,17 @@ static ssize_t mtd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock,
return priv->dev->bread(priv->dev, startblock, nblocks, buffer);
}
/************************************************************************************
/****************************************************************************
* Name: mtd_flush
*
* Description:
* Flush the write buffer to hardware
*
************************************************************************************/
****************************************************************************/
static ssize_t mtd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock,
static ssize_t mtd_flush(FAR void *dev,
FAR const uint8_t *buffer,
off_t startblock,
size_t nblocks)
{
FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev;
@ -164,11 +183,13 @@ static ssize_t mtd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startbl
return priv->dev->bwrite(priv->dev, startblock, nblocks, buffer);
}
/************************************************************************************
/****************************************************************************
* Name: mtd_erase
************************************************************************************/
****************************************************************************/
static int mtd_erase(FAR struct mtd_dev_s *dev, off_t block, size_t nblocks)
static int mtd_erase(FAR struct mtd_dev_s *dev,
off_t block,
size_t nblocks)
{
FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev;
off_t sector;
@ -197,57 +218,60 @@ static int mtd_erase(FAR struct mtd_dev_s *dev, off_t block, size_t nblocks)
return priv->dev->erase(priv->dev, block, nblocks);
}
/************************************************************************************
/****************************************************************************
* Name: mtd_bread
************************************************************************************/
****************************************************************************/
static ssize_t mtd_bread(FAR struct mtd_dev_s *dev, off_t sector,
size_t nsectors, FAR uint8_t *buffer)
{
FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev;
/* Let the rwbuffer logic do it real work. It will call out to mtd_reload if is
* needs to read any data.
/* Let the rwbuffer logic do it real work.
* It will call out to mtd_reload if is needs to read any data.
*/
return rwb_read(&priv->rwb, sector, nsectors, buffer);
}
/************************************************************************************
/****************************************************************************
* Name: mtd_bwrite
************************************************************************************/
****************************************************************************/
static ssize_t mtd_bwrite(FAR struct mtd_dev_s *dev, off_t block, size_t nsectors,
FAR const uint8_t *buffer)
static ssize_t mtd_bwrite(FAR struct mtd_dev_s *dev, off_t block,
size_t nsectors,
FAR const uint8_t *buffer)
{
FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev;
/* Let the rwbuffer logic do it real work. It will call out to wrb_reload it is
* needs to read any data.
/* Let the rwbuffer logic do it real work.
* It will call out to wrb_reload it is needs to read any data.
*/
return rwb_write(&priv->rwb, block, nsectors, buffer);
}
/************************************************************************************
/****************************************************************************
* Name: mtd_read
************************************************************************************/
****************************************************************************/
static ssize_t mtd_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR uint8_t *buffer)
static ssize_t mtd_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev;
/* Let the rwbuffer logic do it real work. It will call out to mtd_reload it is
* needs to read any data.
/* Let the rwbuffer logic do it real work.
* It will call out to mtd_reload it is needs to read any data.
*/
return rwb_readbytes(&priv->rwb, offset, nbytes, buffer);
}
/************************************************************************************
/****************************************************************************
* Name: mtd_ioctl
************************************************************************************/
****************************************************************************/
static int mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -264,13 +288,14 @@ static int mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
((uintptr_t)arg);
if (geo)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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 = priv->rwb.blocksize;
@ -315,23 +340,23 @@ static int mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: mtd_rwb_initialize
*
* Description:
* Create an initialized MTD device instance. This MTD driver contains another
* MTD driver and converts a larger sector size to a standard 512 byte sector
* size.
* Create an initialized MTD device instance.
* This MTD driver contains another MTD driver and converts a larger
* sector size to a standard 512 byte sector size.
*
* 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).
* 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 *mtd_rwb_initialize(FAR struct mtd_dev_s *mtd)
{
@ -354,11 +379,12 @@ FAR struct mtd_dev_s *mtd_rwb_initialize(FAR struct mtd_dev_s *mtd)
/* 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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct mtd_rwbuffer_s *)kmm_zalloc(sizeof(struct mtd_rwbuffer_s));
priv = (FAR struct mtd_rwbuffer_s *)
kmm_zalloc(sizeof(struct mtd_rwbuffer_s));
if (!priv)
{
ferr("ERROR: Failed to allocate mtd_rwbuffer\n");

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/mx25lx.c
* Driver for SPI-based or QSPI-based MX25Lxx33L parts of 32 or 64MBit.
*
@ -36,11 +36,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -59,16 +59,17 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* Configuration ************************************************************/
/* Per the data sheet, MX25L parts can be driven with either SPI mode 0 (CPOL=0 and
* CPHA=0) or mode 3 (CPOL=1 and CPHA=1). So you may need to specify
* CONFIG_MX25L_SPIMODE to select the best mode for your device. If
* CONFIG_MX25L_SPIMODE is not defined, mode 0 will be used.
/* Per the data sheet, MX25L parts can be driven with either SPI mode 0
* (CPOL=0 and CPHA=0) or mode 3 (CPOL=1 and CPHA=1).
* So you may need to specify:
* CONFIG_MX25L_SPIMODE to select the best mode for your device.
* If CONFIG_MX25L_SPIMODE is not defined, mode 0 will be used.
*/
#ifndef CONFIG_MX25L_SPIMODE
@ -81,7 +82,7 @@
# define CONFIG_MX25L_SPIFREQUENCY 20000000
#endif
/* Chip Geometries ******************************************************************/
/* Chip Geometries **********************************************************/
/* MX25L3233F capacity is 32Mbit (4096Kbit x 8) = 4Mb (512kb x 8) */
@ -110,80 +111,82 @@
# define MX25L_SECTOR512_SHIFT 9 /* Sector size 1 << 9 = 512 bytes */
#endif
#define MX25L_ERASED_STATE 0xff /* State of FLASH when erased */
#define MX25L_ERASED_STATE 0xff /* State of FLASH when erased */
#define MX25L_CACHE_VALID (1 << 0) /* 1=Cache has valid data */
#define MX25L_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */
#define MX25L_CACHE_ERASED (1 << 2) /* 1=Backing FLASH is erased */
#define MX25L_CACHE_VALID (1 << 0) /* 1=Cache has valid data */
#define MX25L_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */
#define MX25L_CACHE_ERASED (1 << 2) /* 1=Backing FLASH is erased */
#define IS_VALID(p) ((((p)->flags) & MX25L_CACHE_VALID) != 0)
#define IS_DIRTY(p) ((((p)->flags) & MX25L_CACHE_DIRTY) != 0)
#define IS_ERASED(p) ((((p)->flags) & MX25L_CACHE_ERASED) != 0)
#define IS_VALID(p) ((((p)->flags) & MX25L_CACHE_VALID) != 0)
#define IS_DIRTY(p) ((((p)->flags) & MX25L_CACHE_DIRTY) != 0)
#define IS_ERASED(p) ((((p)->flags) & MX25L_CACHE_ERASED) != 0)
#define SET_VALID(p) do { (p)->flags |= MX25L_CACHE_VALID; } while (0)
#define SET_DIRTY(p) do { (p)->flags |= MX25L_CACHE_DIRTY; } while (0)
#define SET_ERASED(p) do { (p)->flags |= MX25L_CACHE_ERASED; } while (0)
#define SET_VALID(p) do { (p)->flags |= MX25L_CACHE_VALID; } while (0)
#define SET_DIRTY(p) do { (p)->flags |= MX25L_CACHE_DIRTY; } while (0)
#define SET_ERASED(p) do { (p)->flags |= MX25L_CACHE_ERASED; } while (0)
#define CLR_VALID(p) do { (p)->flags &= ~MX25L_CACHE_VALID; } while (0)
#define CLR_DIRTY(p) do { (p)->flags &= ~MX25L_CACHE_DIRTY; } while (0)
#define CLR_ERASED(p) do { (p)->flags &= ~MX25L_CACHE_ERASED; } while (0)
#define CLR_VALID(p) do { (p)->flags &= ~MX25L_CACHE_VALID; } while (0)
#define CLR_DIRTY(p) do { (p)->flags &= ~MX25L_CACHE_DIRTY; } while (0)
#define CLR_ERASED(p) do { (p)->flags &= ~MX25L_CACHE_ERASED; } while (0)
/* MX25L Instructions *******************************************************************/
/* MX25L Instructions *******************************************************/
/* Command Value Description Addr Data */
/* Dummy */
#define MX25L_READ 0x03 /* Read data bytes 3/4 0 >=1 */
#define MX25L_FAST_READ 0x0b /* Higher speed read 3/4 1 >=1 */
#define MX25L_2READ 0xbb /* 2 x I/O read command */
#define MX25L_DREAD 0x3b /* 1I / 2O read command 3/4 1 >=1 */
#define MX25L_4READ 0xeb /* 4 x I/O read command */
#define MX25L_QREAD 0x6b /* 1I / 4O read command 3/4 1 >=1 */
#define MX25L_WREN 0x06 /* Write Enable 0 0 0 */
#define MX25L_WRDI 0x04 /* Write Disable 0 0 0 */
#define MX25L_RDSR 0x05 /* Read status register 0 0 >=1 */
#define MX25L_RDCR 0x15 /* Read config register 0 0 >=1 */
#define MX25L_WRSR 0x01 /* Write stat/conf register 0 0 2 */
#define MX25L_4PP 0x38 /* Quad page program 3/4 0 1-256 */
#define MX25L_SE 0x20 /* 4Kb Sector erase 3/4 0 0 */
#define MX25L_BE32 0x52 /* 32Kbit block Erase 3/4 0 0 */
#define MX25L_BE64 0xd8 /* 64Kbit block Erase 3/4 0 0 */
#define MX25L_CE 0xc7 /* Chip erase 0 0 0 */
#define MX25L_CE_ALT 0x60 /* Chip erase (alternate) 0 0 0 */
#define MX25L_PP 0x02 /* Page program 3 0 1-256 */
#define MX25L_DP 0xb9 /* Deep power down 0 0 0 */
#define MX25L_RDP 0xab /* Release deep power down 0 0 0 */
#define MX25L_PGM_SUSPEND 0x75 /* Suspends program 0 0 0 */
#define MX25L_ERS_SUSPEND 0xb0 /* Suspends erase 0 0 0 */
#define MX25L_PGM_RESUME 0x7A /* Resume program 0 0 0 */
#define MX25L_ERS_RESUME 0x30 /* Resume erase 0 0 0 */
#define MX25L_RDID 0x9f /* Read identification 0 0 3 */
#define MX25L_RES 0xab /* Read electronic ID 0 3 1 */
#define MX25L_REMS 0x90 /* Read manufacture and ID 1 2 >=2 */
#define MX25L_ENSO 0xb1 /* Enter secured OTP 0 0 0 */
#define MX25L_EXSO 0xc1 /* Exit secured OTP 0 0 0 */
#define MX25L_RDSCUR 0x2b /* Read security register 0 0 0 */
#define MX25L_WRSCUR 0x2f /* Write security register 0 0 0 */
#define MX25L_RSTEN 0x66 /* Reset Enable 0 0 0 */
#define MX25L_RST 0x99 /* Reset Memory 0 0 0 */
#define MX25L_EN4B 0xb7 /* Enter 4-byte mode 0 0 0 */
#define MX25L_EX4B 0xe9 /* Exit 4-byte mode 0 0 0 */
#define MX25L_READ4B 0x13 /* Read data (4 Byte mode) 4 0 >=1 */
#define MX25L_FAST_READ4B 0x0c /* Higher speed read (4B) 4 1 >=1 */
#define MX25L_2READ4B 0xbc /* 2 x I/O read command (4B) */
#define MX25L_DREAD4B 0x3c /* 1I / 2O read command (4B) 4 1 >=1 */
#define MX25L_4READ4B 0xec /* 4 x I/O read command (4B) */
#define MX25L_QREAD4B 0x6c /* 1I / 4O read command (4B) 4 1 >=1 */
#define MX25L_4PP4B 0x3e /* Quad page program (4B) 4 0 1-256 */
#define MX25L_SE4B 0x21 /* 4Kb Sector erase (4B) 4 0 0 */
#define MX25L_BE32K4B 0x5c /* 32Kbit block Erase (4B) 4 0 0 */
#define MX25L_BE64K4B 0xdc /* 64Kbit block Erase (4B) 4 0 0 */
#define MX25L_PP4B 0x12 /* Page program (4B) 4 0 1-256 */
#define MX25L_RDSFDP 0x5a /* read out until CS# high */
#define MX25L_SBL 0xc0 /* Set Burst Length */
#define MX25L_SBL_ALT 0x77 /* Set Burst Length */
#define MX25L_NOP 0x00 /* No Operation 0 0 0 */
/* Command Value Description Addr Data */
/* MX25L Registers ******************************************************************/
/* Dummy */
#define MX25L_READ 0x03 /* Read data bytes 3/4 0 >=1 */
#define MX25L_FAST_READ 0x0b /* Higher speed read 3/4 1 >=1 */
#define MX25L_2READ 0xbb /* 2 x I/O read command */
#define MX25L_DREAD 0x3b /* 1I / 2O read command 3/4 1 >=1 */
#define MX25L_4READ 0xeb /* 4 x I/O read command */
#define MX25L_QREAD 0x6b /* 1I / 4O read command 3/4 1 >=1 */
#define MX25L_WREN 0x06 /* Write Enable 0 0 0 */
#define MX25L_WRDI 0x04 /* Write Disable 0 0 0 */
#define MX25L_RDSR 0x05 /* Read status register 0 0 >=1 */
#define MX25L_RDCR 0x15 /* Read config register 0 0 >=1 */
#define MX25L_WRSR 0x01 /* Write stat/conf registe 0 0 2 */
#define MX25L_4PP 0x38 /* Quad page program 3/4 0 1-256 */
#define MX25L_SE 0x20 /* 4Kb Sector erase 3/4 0 0 */
#define MX25L_BE32 0x52 /* 32Kbit block Erase 3/4 0 0 */
#define MX25L_BE64 0xd8 /* 64Kbit block Erase 3/4 0 0 */
#define MX25L_CE 0xc7 /* Chip erase 0 0 0 */
#define MX25L_CE_ALT 0x60 /* Chip erase (alternate) 0 0 0 */
#define MX25L_PP 0x02 /* Page program 3 0 1-256 */
#define MX25L_DP 0xb9 /* Deep power down 0 0 0 */
#define MX25L_RDP 0xab /* Release deep power down 0 0 0 */
#define MX25L_PGM_SUSPEND 0x75 /* Suspends program 0 0 0 */
#define MX25L_ERS_SUSPEND 0xb0 /* Suspends erase 0 0 0 */
#define MX25L_PGM_RESUME 0x7a /* Resume program 0 0 0 */
#define MX25L_ERS_RESUME 0x30 /* Resume erase 0 0 0 */
#define MX25L_RDID 0x9f /* Read identification 0 0 3 */
#define MX25L_RES 0xab /* Read electronic ID 0 3 1 */
#define MX25L_REMS 0x90 /* Read manufacture and ID 1 2 >=2 */
#define MX25L_ENSO 0xb1 /* Enter secured OTP 0 0 0 */
#define MX25L_EXSO 0xc1 /* Exit secured OTP 0 0 0 */
#define MX25L_RDSCUR 0x2b /* Read security register 0 0 0 */
#define MX25L_WRSCUR 0x2f /* Write security register 0 0 0 */
#define MX25L_RSTEN 0x66 /* Reset Enable 0 0 0 */
#define MX25L_RST 0x99 /* Reset Memory 0 0 0 */
#define MX25L_EN4B 0xb7 /* Enter 4-byte mode 0 0 0 */
#define MX25L_EX4B 0xe9 /* Exit 4-byte mode 0 0 0 */
#define MX25L_READ4B 0x13 /* Read data (4 Byte mode) 4 0 >=1 */
#define MX25L_FAST_READ4B 0x0c /* Higher speed read (4B) 4 1 >=1 */
#define MX25L_2READ4B 0xbc /* 2 x I/O read command (4B) */
#define MX25L_DREAD4B 0x3c /* 1I / 2O read command (4B) 4 1 >=1 */
#define MX25L_4READ4B 0xec /* 4 x I/O read command (4B) */
#define MX25L_QREAD4B 0x6c /* 1I / 4O read command (4B) 4 1 >=1 */
#define MX25L_4PP4B 0x3e /* Quad page program (4B) 4 0 1-256 */
#define MX25L_SE4B 0x21 /* 4Kb Sector erase (4B) 4 0 0 */
#define MX25L_BE32K4B 0x5c /* 32Kbit block Erase (4B) 4 0 0 */
#define MX25L_BE64K4B 0xdc /* 64Kbit block Erase (4B) 4 0 0 */
#define MX25L_PP4B 0x12 /* Page program (4B) 4 0 1-256 */
#define MX25L_RDSFDP 0x5a /* read out until CS# high */
#define MX25L_SBL 0xc0 /* Set Burst Length */
#define MX25L_SBL_ALT 0x77 /* Set Burst Length */
#define MX25L_NOP 0x00 /* No Operation 0 0 0 */
/* MX25L Registers **********************************************************/
/* Read ID (RDID) register values */
@ -200,22 +203,22 @@
/* Status register bit definitions */
#define MX25L_SR_WIP (1 << 0) /* Bit 0: Write in progress */
#define MX25L_SR_WEL (1 << 1) /* Bit 1: Write enable latch */
#define MX25L_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */
#define MX25L_SR_BP_MASK (15 << MX25L_SR_BP_SHIFT)
#define MX25L_SR_QE (1 << 6) /* Bit 6: Quad enable */
#define MX25L_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */
#define MX25L_SR_WIP (1 << 0) /* Bit 0: Write in progress */
#define MX25L_SR_WEL (1 << 1) /* Bit 1: Write enable latch */
#define MX25L_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */
#define MX25L_SR_BP_MASK (15 << MX25L_SR_BP_SHIFT)
#define MX25L_SR_QE (1 << 6) /* Bit 6: Quad enable */
#define MX25L_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */
/* Configuration register bit definitions */
#define MX25L_CR_ODS (1 << 0) /* Bit 0: Output driver strength */
#define MX25L_CR_TB (1 << 3) /* Bit 3: Top/bottom selected */
#define MX25L_CR_DC (1 << 6) /* Bit 6: Dummy cycle */
#define MX25L_CR_ODS (1 << 0) /* Bit 0: Output driver strength */
#define MX25L_CR_TB (1 << 3) /* Bit 3: Top/bottom selected */
#define MX25L_CR_DC (1 << 6) /* Bit 6: Dummy cycle */
#define MX25L_DUMMY MX25L_NOP
#define MX25L_DUMMY MX25L_NOP
/* Debug ****************************************************************************/
/* Debug ********************************************************************/
#ifdef CONFIG_MX25L_DEBUG
# define mxlerr(format, ...) _err(format, ##__VA_ARGS__)
@ -225,9 +228,9 @@
# define mxlinfo(x...)
#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
@ -249,9 +252,9 @@ struct mx25l_dev_s
#endif
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -261,17 +264,22 @@ static inline int mx25l_readid(FAR struct mx25l_dev_s *priv);
static void mx25l_waitwritecomplete(FAR struct mx25l_dev_s *priv);
static void mx25l_writeenable(FAR struct mx25l_dev_s *priv);
static void mx25l_writedisable(FAR struct mx25l_dev_s *priv);
static inline void mx25l_sectorerase(FAR struct mx25l_dev_s *priv, off_t offset);
static inline void mx25l_sectorerase(FAR struct mx25l_dev_s *priv,
off_t offset);
static inline int mx25l_chiperase(FAR struct mx25l_dev_s *priv);
static void mx25l_byteread(FAR struct mx25l_dev_s *priv, FAR uint8_t *buffer,
off_t address, size_t nbytes);
static void mx25l_byteread(FAR struct mx25l_dev_s *priv,
FAR uint8_t *buffer,
off_t address,
size_t nbytes);
static inline void mx25l_pagewrite(FAR struct mx25l_dev_s *priv,
FAR const uint8_t *buffer,
off_t address, size_t nbytes);
#if defined(CONFIG_MX25L_SECTOR512)
static void mx25l_cacheflush(FAR struct mx25l_dev_s *priv);
static FAR uint8_t *mx25l_cacheread(FAR struct mx25l_dev_s *priv, off_t sector);
static void mx25l_cacheerase(FAR struct mx25l_dev_s *priv, off_t sector);
static FAR uint8_t *mx25l_cacheread(FAR struct mx25l_dev_s *priv,
off_t sector);
static void mx25l_cacheerase(FAR struct mx25l_dev_s *priv,
off_t sector);
static void mx25l_cachewrite(FAR struct mx25l_dev_s *priv,
FAR const uint8_t *buffer,
off_t sector, size_t nsectors);
@ -279,22 +287,32 @@ static void mx25l_cachewrite(FAR struct mx25l_dev_s *priv,
/* MTD driver methods */
static int mx25l_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
static ssize_t mx25l_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buf);
static ssize_t mx25l_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buf);
static ssize_t mx25l_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static int mx25l_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks);
static ssize_t mx25l_bread(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR uint8_t *buf);
static ssize_t mx25l_bwrite(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buf);
static ssize_t mx25l_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer);
static int mx25l_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int mx25l_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: mx25l_lock
************************************************************************************/
****************************************************************************/
static void mx25l_lock(FAR struct spi_dev_s *dev)
{
@ -302,16 +320,18 @@ static void mx25l_lock(FAR struct spi_dev_s *dev)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus.
* We will retain that exclusive access until the bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(dev, CONFIG_MX25L_SPIMODE);
@ -320,18 +340,18 @@ static void mx25l_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_MX25L_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_unlock
************************************************************************************/
****************************************************************************/
static inline void mx25l_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_readid
************************************************************************************/
****************************************************************************/
static inline int mx25l_readid(FAR struct mx25l_dev_s *priv)
{
@ -363,7 +383,8 @@ static inline int mx25l_readid(FAR struct mx25l_dev_s *priv)
/* Check for a valid manufacturer and memory type */
if (manufacturer == MX25L_JEDEC_MANUFACTURER && memory == MX25L_JEDEC_MEMORY_TYPE)
if (manufacturer == MX25L_JEDEC_MANUFACTURER &&
memory == MX25L_JEDEC_MEMORY_TYPE)
{
/* Okay.. is it a FLASH capacity that we understand? */
@ -402,9 +423,9 @@ static inline int mx25l_readid(FAR struct mx25l_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_waitwritecomplete
************************************************************************************/
****************************************************************************/
static void mx25l_waitwritecomplete(FAR struct mx25l_dev_s *priv)
{
@ -422,7 +443,9 @@ static void mx25l_waitwritecomplete(FAR struct mx25l_dev_s *priv)
SPI_SEND(priv->dev, MX25L_RDSR);
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out
* the status
*/
status = SPI_SEND(priv->dev, MX25L_DUMMY);
@ -430,9 +453,10 @@ static void mx25l_waitwritecomplete(FAR struct mx25l_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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.
/* 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 & MX25L_SR_WIP) != 0)
@ -447,9 +471,9 @@ static void mx25l_waitwritecomplete(FAR struct mx25l_dev_s *priv)
mxlinfo("Complete\n");
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_writeenable
************************************************************************************/
****************************************************************************/
static void mx25l_writeenable(FAR struct mx25l_dev_s *priv)
{
@ -468,9 +492,9 @@ static void mx25l_writeenable(FAR struct mx25l_dev_s *priv)
mxlinfo("Enabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_writedisable
************************************************************************************/
****************************************************************************/
static void mx25l_writedisable(FAR struct mx25l_dev_s *priv)
{
@ -489,9 +513,9 @@ static void mx25l_writedisable(FAR struct mx25l_dev_s *priv)
mxlinfo("Disabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_sectorerase (4k)
************************************************************************************/
****************************************************************************/
static void mx25l_sectorerase(FAR struct mx25l_dev_s *priv, off_t sector)
{
@ -513,7 +537,9 @@ static void mx25l_sectorerase(FAR struct mx25l_dev_s *priv, off_t sector)
* that was passed in as the erase type.
*/
/* The command we send varies depending on if we need 3 or 4 address bytes */
/* The command we send varies depending on if we need 3 or 4 address
* bytes
*/
if (priv->addressbytes == MX25L_ADDRESSBYTES_4)
{
@ -549,9 +575,9 @@ static void mx25l_sectorerase(FAR struct mx25l_dev_s *priv, off_t sector)
mxlinfo("Erased\n");
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_chiperase
************************************************************************************/
****************************************************************************/
static inline int mx25l_chiperase(FAR struct mx25l_dev_s *priv)
{
@ -579,9 +605,9 @@ static inline int mx25l_chiperase(FAR struct mx25l_dev_s *priv)
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_byteread
************************************************************************************/
****************************************************************************/
static void mx25l_byteread(FAR struct mx25l_dev_s *priv, FAR uint8_t *buffer,
off_t address, size_t nbytes)
@ -600,7 +626,9 @@ static void mx25l_byteread(FAR struct mx25l_dev_s *priv, FAR uint8_t *buffer,
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), true);
/* The command we send varies depending on if we need 3 or 4 address bytes */
/* The command we send varies depending on if we need 3 or 4 address
* bytes
*/
if (priv->addressbytes == MX25L_ADDRESSBYTES_4)
{
@ -641,9 +669,9 @@ static void mx25l_byteread(FAR struct mx25l_dev_s *priv, FAR uint8_t *buffer,
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_pagewrite
************************************************************************************/
****************************************************************************/
static inline void mx25l_pagewrite(FAR struct mx25l_dev_s *priv,
FAR const uint8_t *buffer,
@ -708,24 +736,25 @@ static inline void mx25l_pagewrite(FAR struct mx25l_dev_s *priv,
mxlinfo("Written\n");
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_cacheflush
************************************************************************************/
****************************************************************************/
#if defined(CONFIG_MX25L_SECTOR512)
static void mx25l_cacheflush(FAR struct mx25l_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 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 */
mx25l_pagewrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift,
(1 << priv->sectorshift));
mx25l_pagewrite(priv, priv->sector,
(off_t)priv->esectno << priv->sectorshift,
(1 << priv->sectorshift));
/* The case is no long dirty and the FLASH is no longer erased */
@ -735,20 +764,22 @@ static void mx25l_cacheflush(FAR struct mx25l_dev_s *priv)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: mx25l_cacheread
************************************************************************************/
****************************************************************************/
#if defined(CONFIG_MX25L_SECTOR512)
static FAR uint8_t *mx25l_cacheread(FAR struct mx25l_dev_s *priv, off_t sector)
static FAR uint8_t *mx25l_cacheread(FAR struct mx25l_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.
/* 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 - MX25L_SECTOR512_SHIFT;
@ -777,7 +808,9 @@ static FAR uint8_t *mx25l_cacheread(FAR struct mx25l_dev_s *priv, off_t sector)
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 */
/* Get the index to the 512 sector in the erase block that holds the
* argument
*/
index = sector & ((1 << shift) - 1);
@ -787,17 +820,17 @@ static FAR uint8_t *mx25l_cacheread(FAR struct mx25l_dev_s *priv, off_t sector)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: mx25l_cacheerase
************************************************************************************/
****************************************************************************/
#if defined(CONFIG_MX25L_SECTOR512)
static void mx25l_cacheerase(FAR struct mx25l_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.
/* First, make sure that the erase block containing the 512 byte sector is
* in the cache.
*/
dest = mx25l_cacheread(priv, sector);
@ -816,9 +849,9 @@ static void mx25l_cacheerase(FAR struct mx25l_dev_s *priv, off_t sector)
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).
/* 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, MX25L_ERASED_STATE, 1 << MX25L_SECTOR512_SHIFT);
@ -826,32 +859,34 @@ static void mx25l_cacheerase(FAR struct mx25l_dev_s *priv, off_t sector)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: mx25l_cachewrite
************************************************************************************/
****************************************************************************/
#if defined(CONFIG_MX25L_SECTOR512)
static void mx25l_cachewrite(FAR struct mx25l_dev_s *priv, FAR const uint8_t *buffer,
off_t sector, size_t nsectors)
static void mx25l_cachewrite(FAR struct mx25l_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.
/* First, make sure that the erase block containing 512 byte sector is
* in memory.
*/
dest = mx25l_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.
* 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 - MX25L_SECTOR512_SHIFT);
off_t esectno =
sector >> (priv->sectorshift - MX25L_SECTOR512_SHIFT);
mxlinfo("sector: %ld esectno: %d\n", sector, esectno);
mx25l_sectorerase(priv, esectno);
@ -875,11 +910,13 @@ static void mx25l_cachewrite(FAR struct mx25l_dev_s *priv, FAR const uint8_t *bu
}
#endif
/************************************************************************************
/****************************************************************************
* Name: mx25l_erase
************************************************************************************/
****************************************************************************/
static int mx25l_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int mx25l_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
FAR struct mx25l_dev_s *priv = (FAR struct mx25l_dev_s *)dev;
size_t blocksleft = nblocks;
@ -914,9 +951,9 @@ static int mx25l_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nbloc
return (int)nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_bread
************************************************************************************/
****************************************************************************/
static ssize_t mx25l_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buffer)
@ -926,7 +963,9 @@ static ssize_t mx25l_bread(FAR struct mtd_dev_s *dev, off_t startblock,
mxlinfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* On this device, we can handle the block read just like the byte-oriented
* read
*/
#ifdef CONFIG_MX25L_SECTOR512
nbytes = mx25l_read(dev, startblock << MX25L_SECTOR512_SHIFT,
@ -936,7 +975,9 @@ static ssize_t mx25l_bread(FAR struct mtd_dev_s *dev, off_t startblock,
return nbytes >> MX25L_SECTOR512_SHIFT;
}
#else
nbytes = mx25l_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift,
nbytes = mx25l_read(dev,
startblock << priv->pageshift,
nblocks << priv->pageshift,
buffer);
if (nbytes > 0)
{
@ -947,9 +988,9 @@ static ssize_t mx25l_bread(FAR struct mtd_dev_s *dev, off_t startblock,
return (int)nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_bwrite
************************************************************************************/
****************************************************************************/
static ssize_t mx25l_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer)
@ -973,11 +1014,13 @@ static ssize_t mx25l_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
return nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_read
************************************************************************************/
****************************************************************************/
static ssize_t mx25l_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t mx25l_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct mx25l_dev_s *priv = (FAR struct mx25l_dev_s *)dev;
@ -993,9 +1036,9 @@ static ssize_t mx25l_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_ioctl
************************************************************************************/
****************************************************************************/
static int mx25l_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -1012,20 +1055,21 @@ static int mx25l_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
(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.
/* 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.
* 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_MX25L_SECTOR512
geo->blocksize = (1 << MX25L_SECTOR512_SHIFT);
geo->erasesize = (1 << MX25L_SECTOR512_SHIFT);
geo->neraseblocks = priv->nsectors <<
(priv->sectorshift - MX25L_SECTOR512_SHIFT);
(priv->sectorshift - MX25L_SECTOR512_SHIFT);
#else
geo->blocksize = (1 << priv->pageshift);
geo->erasesize = (1 << priv->sectorshift);
@ -1059,19 +1103,19 @@ static int mx25l_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: mx25l_initialize_spi
*
* Description:
* Create an initialize MTD device instance. MTD devices are not registered
* 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 *mx25l_initialize_spi(FAR struct spi_dev_s *dev)
{
@ -1083,8 +1127,8 @@ FAR struct mtd_dev_s *mx25l_initialize_spi(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct mx25l_dev_s *)kmm_zalloc(sizeof(struct mx25l_dev_s));
@ -1111,7 +1155,9 @@ FAR struct mtd_dev_s *mx25l_initialize_spi(FAR struct spi_dev_s *dev)
ret = mx25l_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
mxlerr("ERROR: Unrecognized\n");
kmm_free(priv);
@ -1125,7 +1171,9 @@ FAR struct mtd_dev_s *mx25l_initialize_spi(FAR struct spi_dev_s *dev)
priv->sector = (FAR uint8_t *)kmm_malloc(1 << priv->sectorshift);
if (!priv->sector)
{
/* Allocation failed! Discard all of that work we just did and return NULL */
/* Allocation failed! Discard all of that work we just did and
* return NULL
*/
ferr("ERROR: Allocation failed\n");
kmm_free(priv);

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/mx25rxx.c
*
* Copyright (C) 201, 2019 Gregory Nutt. All rights reserved.
@ -34,11 +34,11 @@
* 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>
@ -59,9 +59,9 @@
#include <nuttx/spi/qspi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* MX25RXX Commands */
@ -146,7 +146,7 @@
#define MX25R_CR_TB (1 << 3) /* Bit 3: Top/bottom selected */
#define MX25R_CR_DC (1 << 6) /* Bit 6: Dummy cycle */
/* Cache flags **********************************************************************/
/* Cache flags **************************************************************/
#define MX25RXX_CACHE_VALID (1 << 0) /* 1=Cache has valid data */
#define MX25RXX_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */
@ -164,15 +164,15 @@
#define CLR_DIRTY(p) do { (p)->flags &= ~MX25RXX_CACHE_DIRTY; } while (0)
#define CLR_ERASED(p) do { (p)->flags &= ~MX25RXX_CACHE_ERASED; } while (0)
/* 512 byte sector support **********************************************************/
/* 512 byte sector support **************************************************/
#define MX25RXX_SECTOR512_SHIFT 9
#define MX25RXX_SECTOR512_SIZE (1 << 9)
#define MX25RXX_ERASED_STATE 0xff
/************************************************************************************
/****************************************************************************
* Private Types
************************************************************************************/
****************************************************************************/
/* Internal state of the MTD device */
@ -194,9 +194,9 @@ struct mx25rxx_dev_s
#endif
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* MTD driver methods */
@ -234,7 +234,9 @@ static void mx25rxx_write_status_config(FAR struct mx25rxx_dev_s *dev,
static void mx25rxx_write_enable(FAR struct mx25rxx_dev_s *dev, bool enable);
static int mx25rxx_write_page(struct mx25rxx_dev_s *priv,
FAR const uint8_t *buffer, off_t address, size_t buflen);
FAR const uint8_t *buffer,
off_t address,
size_t buflen);
static int mx25rxx_erase_sector(struct mx25rxx_dev_s *priv, off_t sector);
#if 0 /* FIXME: Not used */
static int mx25rxx_erase_block(struct mx25rxx_dev_s *priv, off_t block);
@ -243,15 +245,16 @@ static int mx25rxx_erase_chip(struct mx25rxx_dev_s *priv);
#ifdef CONFIG_MX25RXX_SECTOR512
static int mx25rxx_flush_cache(struct mx25rxx_dev_s *priv);
static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv, off_t sector);
static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv,
off_t sector);
static void mx25rxx_erase_cache(struct mx25rxx_dev_s *priv, off_t sector);
static int mx25rxx_write_cache(FAR struct mx25rxx_dev_s *priv,
FAR const uint8_t *buffer, off_t sector, size_t nsectors);
#endif
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
void mx25rxx_lock(FAR struct qspi_dev_s *qspi, bool read)
{
@ -259,23 +262,24 @@ void mx25rxx_lock(FAR struct qspi_dev_s *qspi, bool read)
* lock SPI to have exclusive access to the buses 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 exclusive access
* to the SPI bus. We will retain that exclusive access until the bus is
* unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus. We will retain that exclusive access until the
* bus is unlocked.
*/
QSPI_LOCK(qspi, 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 bus is being shared, then it may have been left
* in an incompatible state.
/* 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 bus is being shared, then it
* may have been left in an incompatible state.
*/
QSPI_SETMODE(qspi, CONFIG_MX25RXX_QSPIMODE);
QSPI_SETBITS(qspi, 8);
QSPI_SETFREQUENCY(qspi,
read ? CONFIG_MX25RXX_QSPI_READ_FREQUENCY : CONFIG_MX25RXX_QSPI_FREQUENCY);
read ? CONFIG_MX25RXX_QSPI_READ_FREQUENCY :
CONFIG_MX25RXX_QSPI_FREQUENCY);
}
void mx25rxx_unlock(FAR struct qspi_dev_s *qspi)
@ -538,7 +542,8 @@ int mx25rxx_read_configuration(FAR struct mx25rxx_dev_s *dev)
return mx25rxx_command_read(dev->qspi, MX25R_RDCR, dev->cmdbuf, 4);
}
void mx25rxx_write_status_config(FAR struct mx25rxx_dev_s *dev, uint8_t status,
void mx25rxx_write_status_config(FAR struct mx25rxx_dev_s *dev,
uint8_t status,
uint16_t config)
{
mx25rxx_write_enable(dev, true);
@ -555,7 +560,9 @@ void mx25rxx_write_status_config(FAR struct mx25rxx_dev_s *dev, uint8_t status,
mx25rxx_write_enable(dev, false);
}
int mx25rxx_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
int mx25rxx_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
FAR struct mx25rxx_dev_s *priv = (FAR struct mx25rxx_dev_s *)dev;
size_t blocksleft = nblocks;
@ -636,7 +643,9 @@ ssize_t mx25rxx_bread(FAR struct mtd_dev_s *dev, off_t startblock,
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* On this device, we can handle the block read just like the
* byte-oriented read
*/
#ifdef CONFIG_MX25RXX_SECTOR512
nbytes = mx25rxx_read(dev, startblock << MX25RXX_SECTOR512_SHIFT,
@ -730,20 +739,22 @@ int mx25rxx_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
if (geo)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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_MX25RXX_SECTOR512
geo->blocksize = (1 << MX25RXX_SECTOR512_SHIFT);
geo->erasesize = (1 << MX25RXX_SECTOR512_SHIFT);
geo->neraseblocks = priv->nsectors <<
(priv->sectorshift - MX25RXX_SECTOR512_SHIFT);
(priv->sectorshift -
MX25RXX_SECTOR512_SHIFT);
#else
geo->blocksize = (1 << priv->pageshift);
geo->erasesize = (1 << priv->sectorshift);
@ -823,18 +834,18 @@ int mx25rxx_readid(struct mx25rxx_dev_s *dev)
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: mx25rxx_flush_cache
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MX25RXX_SECTOR512
static int mx25rxx_flush_cache(struct mx25rxx_dev_s *priv)
{
int ret = OK;
/* If the cache 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 the cache 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))
@ -847,7 +858,10 @@ static int mx25rxx_flush_cache(struct mx25rxx_dev_s *priv)
/* Write entire erase block to FLASH */
ret = mx25rxx_write_page(priv, priv->sector, address, 1 << priv->sectorshift);
ret = mx25rxx_write_page(priv,
priv->sector,
address,
1 << priv->sectorshift);
if (ret < 0)
{
ferr("ERROR: mx25rxx_write_page failed: %d\n", ret);
@ -863,21 +877,23 @@ static int mx25rxx_flush_cache(struct mx25rxx_dev_s *priv)
}
#endif /* CONFIG_MX25RXX_SECTOR512 */
/************************************************************************************
/****************************************************************************
* Name: mx25rxx_read_cache
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MX25RXX_SECTOR512
static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv, off_t sector)
static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv,
off_t sector)
{
off_t esectno;
int shift;
int index;
int ret;
/* Convert from the 512 byte sector to the erase sector size of the device. For
* example, if the actual erase sector size is 4Kb (1 << 12), then we first
* shift to the right by 3 to get the sector number in 4096 increments.
/* Convert from the 512 byte sector to the erase sector size of the device.
* For example, if the actual erase sector size is 4Kb (1 << 12), then we
* first shift to the right by 3 to get the sector number in 4096
* increments.
*/
shift = priv->sectorshift - MX25RXX_SECTOR512_SHIFT;
@ -918,7 +934,9 @@ static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv, off_t sector)
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 */
/* Get the index to the 512 sector in the erase block that holds the
* argument
*/
index = sector & ((1 << shift) - 1);
@ -928,17 +946,17 @@ static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv, off_t sector)
}
#endif /* CONFIG_MX25RXX_SECTOR512 */
/************************************************************************************
/****************************************************************************
* Name: mx25rxx_erase_cache
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MX25RXX_SECTOR512
static void mx25rxx_erase_cache(struct mx25rxx_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.
/* First, make sure that the erase block containing the 512 byte sector is
* in the cache.
*/
dest = mx25rxx_read_cache(priv, sector);
@ -950,7 +968,8 @@ static void mx25rxx_erase_cache(struct mx25rxx_dev_s *priv, off_t sector)
if (!IS_ERASED(priv))
{
off_t esectno = sector >> (priv->sectorshift - MX25RXX_SECTOR512_SHIFT);
off_t esectno = sector >>
(priv->sectorshift - MX25RXX_SECTOR512_SHIFT);
finfo("sector: %jd esectno: %jd\n",
(intmax_t)sector, (intmax_t)esectno);
@ -958,9 +977,9 @@ static void mx25rxx_erase_cache(struct mx25rxx_dev_s *priv, off_t sector)
SET_ERASED(priv);
}
/* Put the cached sector data into the erase state and mark the cache as dirty
* (but don't update the FLASH yet. The caller will do that at a more optimal
* time).
/* Put the cached sector data into the erase state and mark the cache as
* dirty (but don't update the FLASH yet. The caller will do that at a
* more optimal time).
*/
memset(dest, MX25RXX_ERASED_STATE, MX25RXX_SECTOR512_SIZE);
@ -968,9 +987,9 @@ static void mx25rxx_erase_cache(struct mx25rxx_dev_s *priv, off_t sector)
}
#endif /* CONFIG_MX25RXX_SECTOR512 */
/************************************************************************************
/****************************************************************************
* Name: mx25rxx_write_cache
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MX25RXX_SECTOR512
static int mx25rxx_write_cache(FAR struct mx25rxx_dev_s *priv,
@ -982,20 +1001,21 @@ static int mx25rxx_write_cache(FAR struct mx25rxx_dev_s *priv,
for (; nsectors > 0; nsectors--)
{
/* First, make sure that the erase block containing 512 byte sector is in
* memory.
/* First, make sure that the erase block containing 512 byte sector is
* in memory.
*/
dest = mx25rxx_read_cache(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.
* 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 - MX25RXX_SECTOR512_SHIFT);
off_t esectno = sector >>
(priv->sectorshift - MX25RXX_SECTOR512_SHIFT);
finfo("sector: %jd esectno: %jd\n",
(intmax_t)sector, (intmax_t)esectno);
@ -1030,11 +1050,11 @@ static int mx25rxx_write_cache(FAR struct mx25rxx_dev_s *priv,
}
#endif /* CONFIG_MX25RXX_SECTOR512 */
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: mx25rxx_initialize
*
* Description:
@ -1044,9 +1064,10 @@ static int mx25rxx_write_cache(FAR struct mx25rxx_dev_s *priv,
* instances that can be bound to other functions (such as a block or
* character driver front end).
*
************************************************************************************/
****************************************************************************/
FAR struct mtd_dev_s *mx25rxx_initialize(FAR struct qspi_dev_s *qspi, bool unprotect)
FAR struct mtd_dev_s *mx25rxx_initialize(FAR struct qspi_dev_s *qspi,
bool unprotect)
{
FAR struct mx25rxx_dev_s *dev;
int ret;
@ -1058,8 +1079,9 @@ FAR struct mtd_dev_s *mx25rxx_initialize(FAR struct qspi_dev_s *qspi, bool unpro
/* 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 QuadSPI
* device (only because of the QSPIDEV_FLASH(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same QuadSPI bus.
* device (only because of the QSPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same QuadSPI
* bus.
*/
dev = (FAR struct mx25rxx_dev_s *)kmm_zalloc(sizeof(*dev));
@ -1104,7 +1126,9 @@ FAR struct mtd_dev_s *mx25rxx_initialize(FAR struct qspi_dev_s *qspi, bool unpro
dev->sector = (FAR uint8_t *)QSPI_ALLOC(qspi, 1 << dev->sectorshift);
if (dev->sector == NULL)
{
/* Allocation failed! Discard all of that work we just did and return NULL */
/* Allocation failed! Discard all of that work we just did and
* return NULL
*/
ferr("ERROR: Sector allocation failed\n");
goto exit_free_cmdbuf;

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/mx35.c
* Driver for SPI-based MX35LFxGE4AB parts of 1 or 2GBit.
*
@ -35,11 +35,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -57,15 +57,15 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* Configuration ************************************************************/
/* Per the data sheet, MX35 parts can be driven with either SPI mode 0 (CPOL=0 and
* CPHA=0) or mode 3 (CPOL=1 and CPHA=1). If CONFIG_MX35_SPIMODE is not defined,
* mode 0 will be used.
/* Per the data sheet, MX35 parts can be driven with either SPI mode 0
* (CPOL=0 and CPHA=0) or mode 3 (CPOL=1 and CPHA=1). If CONFIG_MX35_SPIMODE
* is not defined, mode 0 will be used.
*/
#ifndef CONFIG_MX35_SPIMODE
@ -80,7 +80,7 @@
# define CONFIG_MX35_MANUFACTURER 0xC2
#endif
/* Debug ****************************************************************************/
/* Debug ********************************************************************/
#ifdef CONFIG_MX35_DEBUG
# define mx35err(format, ...) _err(format, ##__VA_ARGS__)
@ -90,61 +90,62 @@
# define mx35info(x...)
#endif
/* Identification register values **************************************************/
/* Identification register values *******************************************/
#define MX35_MANUFACTURER CONFIG_MX35_MANUFACTURER
#define MX35_MX35LF1GE4AB_CAPACITY 0x12 /* 1 Gb */
#define MX35_MX35LF2GE4AB_CAPACITY 0x22 /* 2 Gb */
/* Chip Geometries ******************************************************************/
/* Chip Geometries **********************************************************/
/* MX35LF1GE4AB capacity is 1 G-bit */
#define MX35_MX35LF1GE4AB_SECTOR_SHIFT 17 /* Sector size 1 << 17 = 128 Kb */
#define MX35_MX35LF1GE4AB_SECTOR_SHIFT 17 /* Sector size 1 << 17 = 128 Kb */
#define MX35_MX35LF1GE4AB_NSECTORS 1024
#define MX35_MX35LF1GE4AB_PAGE_SHIFT 11 /* Page size 1 << 11 = 2 Kb */
#define MX35_MX35LF1GE4AB_PAGE_SHIFT 11 /* Page size 1 << 11 = 2 Kb */
/* MX35LF2GE4AB capacity is 2 G-bit */
#define MX35_MX35LF2GE4AB_SECTOR_SHIFT 17 /* Sector size 1 << 17 = 128 Kb */
#define MX35_MX35LF2GE4AB_SECTOR_SHIFT 17 /* Sector size 1 << 17 = 128 Kb */
#define MX35_MX35LF2GE4AB_NSECTORS 2048
#define MX35_MX35LF2GE4AB_PAGE_SHIFT 11 /* Page size 1 << 11 = 2 Kb */
#define MX35_MX35LF2GE4AB_PAGE_SHIFT 11 /* Page size 1 << 11 = 2 Kb */
/* MX35 Instructions ****************************************************************/
/* Command Value Description Addr Data */
/* Dummy */
#define MX35_GET_FEATURE 0x0F /* Get features 1 0 1 */
#define MX35_SET_FEATURE 0x1F /* Set features 1 0 1 */
#define MX35_PAGE_READ 0x13 /* Array read 3 0 0 */
/* MX35 Instructions ********************************************************/
/* Command Value Description Addr Data */
/* Dummy */
#define MX35_GET_FEATURE 0x0F /* Get features 1 0 1 */
#define MX35_SET_FEATURE 0x1F /* Set features 1 0 1 */
#define MX35_PAGE_READ 0x13 /* Array read 3 0 0 */
#define MX35_READ_FROM_CACHE 0x03 /* Output cache data
on SO 2 1 1-2112 */
* on SO 2 1 1-2112 */
#define MX35_READ_FROM_CACHE_X1 0x0B /* Output cache data
on SO 2 1 1-2112 */
* on SO 2 1 1-2112 */
#define MX35_READ_FROM_CACHE_X2 0x3B /* Output cache data
on SI and SO 2 1 1-2112 */
* on SI and SO 2 1 1-2112 */
#define MX35_READ_FROM_CACHE_X4 0x6B /* Output cache data
on SI, SO, WP, HOLD 2 1 1-2112 */
#define MX35_READ_ID 0x9F /* Read device ID 0 1 2 */
* on SI, SO, WP, HOLD 2 1 1-2112 */
#define MX35_READ_ID 0x9F /* Read device ID 0 1 2 */
#define MX35_ECC_STATUS_READ 0x7C /* Internal ECC status
output 0 1 1 */
#define MX35_BLOCK_ERASE 0xD8 /* Block erase 3 0 0 */
* output 0 1 1 */
#define MX35_BLOCK_ERASE 0xD8 /* Block erase 3 0 0 */
#define MX35_PROGRAM_EXECUTE 0x10 /* Enter block/page
address, execute 3 0 0 */
* address, execute 3 0 0 */
#define MX35_PROGRAM_LOAD 0x02 /* Load program data with
cache reset first 2 0 1-2112 */
* cache reset first 2 0 1-2112 */
#define MX35_PROGRAM_LOAD_RANDOM 0x84 /* Load program data
without cache reset 2 0 1-2112 */
* without cache reset 2 0 1-2112 */
#define MX35_PROGRAM_LOAD_X4 0x32 /* Program load operation
with x4 data input 2 0 1-2112 */
* with x4 data input 2 0 1-2112 */
#define MX35_PROGRAM_LOAD_RANDOM_X4 0x34 /* Load random operation
with x4 data input 2 0 1-2112 */
#define MX35_WRITE_ENABLE 0x06 /* 0 0 0 */
#define MX35_WRITE_DISABLE 0x04 /* 0 0 0 */
#define MX35_RESET 0xFF /* Reset the device 0 0 0 */
* with x4 data input 2 0 1-2112 */
#define MX35_WRITE_ENABLE 0x06 /* 0 0 0 */
#define MX35_WRITE_DISABLE 0x04 /* 0 0 0 */
#define MX35_RESET 0xFF /* Reset the device 0 0 0 */
#define MX35_DUMMY 0x00 /* No Operation 0 0 0 */
#define MX35_DUMMY 0x00 /* No Operation 0 0 0 */
/* Feature register *****************************************************************/
/* Feature register *********************************************************/
/* Register address */
@ -154,7 +155,7 @@
/* Bit definitions */
/* Secure OTP (On-Time-Programmable) register*/
/* Secure OTP (On-Time-Programmable) register */
#define MX35_SOTP_QE (1 << 0) /* Bit 0: Quad Enable */
#define MX35_SOTP_ECC (1 << 4) /* Bit 4: ECC enabled */
@ -170,7 +171,7 @@
#define MX35_SR_ECC_S0 (1 << 4) /* Bit 4-5: ECC Status */
#define MX35_SR_ECC_S1 (1 << 5)
/* Block Protection register*/
/* Block Protection register */
#define MX35_BP_SP (1 << 0) /* Bit 0: Solid-protection (1Gb only) */
#define MX35_BP_COMPL (1 << 1) /* Bit 1: Complementary (1Gb only) */
@ -189,9 +190,9 @@
#define MX35_ECC_STATUS_MASK 0x0F
#define MX35_ECC_INCORRECTABLE 0x0F
/************************************************************************************
/****************************************************************************
* 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
@ -209,9 +210,9 @@ struct mx35_dev_s
uint8_t eccstatus; /* Internal ECC status */
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
static inline void mx35_lock(FAR struct spi_dev_s *dev);
static inline void mx35_unlock(FAR struct spi_dev_s *dev);
@ -226,33 +227,47 @@ static inline uint32_t mx35_addresstorow(FAR struct mx35_dev_s *priv,
static inline uint32_t mx35_addresstocolumn(FAR struct mx35_dev_s *priv,
uint32_t address);
static bool mx35_sectorerase(FAR struct mx35_dev_s *priv, off_t startsector);
static int mx35_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
static bool mx35_sectorerase(FAR struct mx35_dev_s *priv,
off_t startsector);
static int mx35_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks);
static void mx35_readbuffer(FAR struct mx35_dev_s *priv, uint32_t address,
static void mx35_readbuffer(FAR struct mx35_dev_s *priv,
uint32_t address,
uint8_t *buffer, size_t length);
static bool mx35_read_page(FAR struct mx35_dev_s *priv, uint32_t position);
static ssize_t mx35_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static bool mx35_read_page(FAR struct mx35_dev_s *priv,
uint32_t position);
static ssize_t mx35_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer);
static void mx35_write_to_cache(FAR struct mx35_dev_s *priv, uint32_t address,
const uint8_t *buffer, size_t length);
static bool mx35_execute_write(FAR struct mx35_dev_s *priv, uint32_t position);
static ssize_t mx35_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static void mx35_write_to_cache(FAR struct mx35_dev_s *priv,
uint32_t address,
const uint8_t *buffer,
size_t length);
static bool mx35_execute_write(FAR struct mx35_dev_s *priv,
uint32_t position);
static ssize_t mx35_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer);
static int mx35_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int mx35_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
static inline void mx35_eccstatusread(struct mx35_dev_s *priv);
static inline void mx35_enableECC(struct mx35_dev_s *priv);
static inline void mx35_unlockblocks(struct mx35_dev_s *priv);
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: mx35_lock
************************************************************************************/
****************************************************************************/
static inline void mx35_lock(FAR struct spi_dev_s *dev)
{
@ -260,16 +275,18 @@ static inline void mx35_lock(FAR struct spi_dev_s *dev)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus.
* We will retain that exclusive access until the bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(dev, CONFIG_MX35_SPIMODE);
@ -278,18 +295,18 @@ static inline void mx35_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_MX35_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_unlock
************************************************************************************/
****************************************************************************/
static inline void mx35_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: m25p_readid
************************************************************************************/
****************************************************************************/
static int mx35_readid(struct mx35_dev_s *priv)
{
@ -349,11 +366,13 @@ static int mx35_readid(struct mx35_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: mx35_waitstatus
************************************************************************************/
****************************************************************************/
static bool mx35_waitstatus(FAR struct mx35_dev_s *priv, uint8_t mask, bool successif)
static bool mx35_waitstatus(FAR struct mx35_dev_s *priv,
uint8_t mask,
bool successif)
{
uint8_t status;
@ -375,9 +394,9 @@ static bool mx35_waitstatus(FAR struct mx35_dev_s *priv, uint8_t mask, bool succ
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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.
/* 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.
*/
}
while (((status & MX35_SR_OIP) != 0) && (!nxsig_usleep(1000)));
@ -386,9 +405,9 @@ static bool mx35_waitstatus(FAR struct mx35_dev_s *priv, uint8_t mask, bool succ
return successif ? ((status & mask) != 0) : ((status & mask) == 0);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_writeenable
************************************************************************************/
****************************************************************************/
static inline void mx35_writeenable(struct mx35_dev_s *priv)
{
@ -405,9 +424,9 @@ static inline void mx35_writeenable(struct mx35_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_writedisable
************************************************************************************/
****************************************************************************/
static inline void mx35_writedisable(struct mx35_dev_s *priv)
{
@ -424,9 +443,9 @@ static inline void mx35_writedisable(struct mx35_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_addresstorow
************************************************************************************/
****************************************************************************/
static inline uint32_t mx35_addresstorow(FAR struct mx35_dev_s *priv,
uint32_t address)
@ -441,7 +460,7 @@ static inline uint32_t mx35_addresstorow(FAR struct mx35_dev_s *priv,
/* Shift block address */
row = ((row & ~0x3F) << 1) | (row & 0x3F);
row = ((row & ~0x3f) << 1) | (row & 0x3f);
/* Insert plane select bit */
@ -451,9 +470,9 @@ static inline uint32_t mx35_addresstorow(FAR struct mx35_dev_s *priv,
return row;
}
/************************************************************************************
/****************************************************************************
* Name: mx35_addresstocolumn
************************************************************************************/
****************************************************************************/
static inline uint32_t mx35_addresstocolumn(FAR struct mx35_dev_s *priv,
uint32_t address)
@ -474,15 +493,15 @@ static inline uint32_t mx35_addresstocolumn(FAR struct mx35_dev_s *priv,
else
{
uint16_t wraplength = 0x00;
column |= (wraplength & 0xC000);
column |= (wraplength & 0xc000);
}
return column;
}
/************************************************************************************
/****************************************************************************
* Name: mx35_sectorerase (128K)
************************************************************************************/
****************************************************************************/
static bool mx35_sectorerase(FAR struct mx35_dev_s *priv, off_t startsector)
{
@ -514,16 +533,20 @@ static bool mx35_sectorerase(FAR struct mx35_dev_s *priv, off_t startsector)
return mx35_waitstatus(priv, MX35_SR_E_FAIL, false);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_erase
************************************************************************************/
****************************************************************************/
static int mx35_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int mx35_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
FAR struct mx35_dev_s *priv = (FAR struct mx35_dev_s *)dev;
size_t blocksleft = nblocks;
mx35info("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
mx35info("startblock: %08lx nblocks: %d\n",
(long)startblock,
(int)nblocks);
/* Lock access to the SPI bus until we complete the erase */
@ -543,9 +566,9 @@ static int mx35_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock
return (int)nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: mx35_readbuffer
************************************************************************************/
****************************************************************************/
static void mx35_readbuffer(FAR struct mx35_dev_s *priv, uint32_t address,
uint8_t *buffer, size_t length)
@ -576,9 +599,9 @@ static void mx35_readbuffer(FAR struct mx35_dev_s *priv, uint32_t address,
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_read_page
************************************************************************************/
****************************************************************************/
static bool mx35_read_page(FAR struct mx35_dev_s *priv, uint32_t pageaddress)
{
@ -602,7 +625,8 @@ static bool mx35_read_page(FAR struct mx35_dev_s *priv, uint32_t pageaddress)
mx35_waitstatus(priv, MX35_SR_OIP, false);
mx35_eccstatusread(priv);
if ((priv->eccstatus & MX35_FEATURE_ECC_MASK) == MX35_FEATURE_ECC_INCORRECTABLE)
if ((priv->eccstatus & MX35_FEATURE_ECC_MASK) ==
MX35_FEATURE_ECC_INCORRECTABLE)
{
return false;
}
@ -610,11 +634,13 @@ static bool mx35_read_page(FAR struct mx35_dev_s *priv, uint32_t pageaddress)
return true;
}
/************************************************************************************
/****************************************************************************
* Name: mx35_read
************************************************************************************/
****************************************************************************/
static ssize_t mx35_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t mx35_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct mx35_dev_s *priv = (FAR struct mx35_dev_s *)dev;
@ -633,9 +659,12 @@ static ssize_t mx35_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
while (bytesleft)
{
const uint32_t pageaddress = (position >> priv->pageshift) << priv->pageshift;
const uint32_t spaceleft = pageaddress + (1 << priv->pageshift) - position;
const size_t chunklength = bytesleft < spaceleft ? bytesleft : spaceleft;
const uint32_t pageaddress = (position >> priv->pageshift) <<
priv->pageshift;
const uint32_t spaceleft = pageaddress + (1 << priv->pageshift) -
position;
const size_t chunklength = bytesleft < spaceleft ?
bytesleft : spaceleft;
if (!mx35_read_page(priv, pageaddress))
{
@ -655,12 +684,14 @@ static ssize_t mx35_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
return nbytes - bytesleft;
}
/************************************************************************************
/****************************************************************************
* Name: mx35_write_to_cache
************************************************************************************/
****************************************************************************/
static void mx35_write_to_cache(FAR struct mx35_dev_s *priv, uint32_t address,
const uint8_t *buffer, size_t length)
static void mx35_write_to_cache(FAR struct mx35_dev_s *priv,
uint32_t address,
const uint8_t *buffer,
size_t length)
{
const uint16_t offset = mx35_addresstocolumn(priv, address);
@ -686,11 +717,12 @@ static void mx35_write_to_cache(FAR struct mx35_dev_s *priv, uint32_t address,
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_write_to_cache
************************************************************************************/
****************************************************************************/
static bool mx35_execute_write(FAR struct mx35_dev_s *priv, uint32_t pageaddress)
static bool mx35_execute_write(FAR struct mx35_dev_s *priv,
uint32_t pageaddress)
{
const uint32_t row = mx35_addresstorow(priv, pageaddress);
@ -712,11 +744,13 @@ static bool mx35_execute_write(FAR struct mx35_dev_s *priv, uint32_t pageaddress
return mx35_waitstatus(priv, MX35_SR_P_FAIL, false);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_write
************************************************************************************/
****************************************************************************/
static ssize_t mx35_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t mx35_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer)
{
FAR struct mx35_dev_s *priv = (FAR struct mx35_dev_s *)dev;
@ -731,9 +765,12 @@ static ssize_t mx35_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
while (bytesleft)
{
const uint32_t pageaddress = (position >> priv->pageshift) << priv->pageshift;
const uint32_t spaceleft = pageaddress + (1 << priv->pageshift) - position;
const size_t chunklength = bytesleft < spaceleft ? bytesleft : spaceleft;
const uint32_t pageaddress = (position >> priv->pageshift) <<
priv->pageshift;
const uint32_t spaceleft = pageaddress + (1 << priv->pageshift) -
position;
const size_t chunklength = bytesleft < spaceleft ?
bytesleft : spaceleft;
mx35_writeenable(priv);
mx35_write_to_cache(priv, position, buffer, chunklength);
@ -752,9 +789,9 @@ static ssize_t mx35_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
return nbytes - bytesleft;
}
/************************************************************************************
/****************************************************************************
* Name: mx25l_ioctl
************************************************************************************/
****************************************************************************/
static int mx35_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -771,13 +808,14 @@ static int mx35_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
(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.
/* 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.
* 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);
@ -804,7 +842,8 @@ static int mx35_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
uint8_t *result = (uint8_t *)arg;
*result =
(priv->eccstatus & MX35_FEATURE_ECC_MASK) >> MX35_FEATURE_ECC_OFFSET;
(priv->eccstatus & MX35_FEATURE_ECC_MASK) >>
MX35_FEATURE_ECC_OFFSET;
ret = OK;
}
@ -819,9 +858,9 @@ static int mx35_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Name: mx35_eccstatusread
************************************************************************************/
****************************************************************************/
static inline void mx35_eccstatusread(struct mx35_dev_s *priv)
{
@ -832,9 +871,9 @@ static inline void mx35_eccstatusread(struct mx35_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_enableECC
************************************************************************************/
****************************************************************************/
static inline void mx35_enableECC(struct mx35_dev_s *priv)
{
@ -853,9 +892,9 @@ static inline void mx35_enableECC(struct mx35_dev_s *priv)
mx35_unlock(priv->dev);
}
/************************************************************************************
/****************************************************************************
* Name: mx35_unlockblocks
************************************************************************************/
****************************************************************************/
static inline void mx35_unlockblocks(struct mx35_dev_s *priv)
{
@ -874,19 +913,20 @@ static inline void mx35_unlockblocks(struct mx35_dev_s *priv)
mx35_unlock(priv->dev);
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: mx35_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).
* 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 *mx35_initialize(FAR struct spi_dev_s *dev)
{
@ -898,8 +938,8 @@ FAR struct mtd_dev_s *mx35_initialize(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct mx35_dev_s *)kmm_zalloc(sizeof(struct mx35_dev_s));
@ -935,7 +975,9 @@ FAR struct mtd_dev_s *mx35_initialize(FAR struct spi_dev_s *dev)
ret = mx35_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
mx35err("ERROR: Unrecognized\n");
kmm_free(priv);

File diff suppressed because it is too large Load diff

View file

@ -53,6 +53,7 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
#ifndef CONFIG_RAMMTD_BLOCKSIZE
@ -117,18 +118,29 @@ static void *ram_write(FAR void *dest, FAR const void *src, size_t len);
/* 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 ssize_t ram_byteread(FAR struct mtd_dev_s *dev, off_t offset,
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 ssize_t ram_byteread(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes, FAR uint8_t *buf);
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t ram_bytewrite(FAR struct mtd_dev_s *dev, off_t offset,
size_t nbytes, FAR const uint8_t *buf);
static ssize_t ram_bytewrite(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buf);
#endif
static int ram_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int ram_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/****************************************************************************
* Private Functions
@ -232,8 +244,10 @@ static int ram_erase(FAR struct mtd_dev_s *dev, off_t startblock,
* Name: ram_bread
****************************************************************************/
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_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;
@ -322,9 +336,9 @@ static ssize_t ram_byteread(FAR struct mtd_dev_s *dev, off_t offset,
/* Don't let read read past end of buffer */
if (offset + nbytes > priv->nblocks * CONFIG_RAMMTD_ERASESIZE)
{
return 0;
}
{
return 0;
}
ram_read(buf, &priv->start[offset], nbytes);
return nbytes;
@ -371,11 +385,12 @@ static int ram_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
case MTDIOC_GEOMETRY:
{
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
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.
/* Populate the geometry structure with information need to
* know the capacity and how to access the device.
*/
geo->blocksize = CONFIG_RAMMTD_BLOCKSIZE;

View file

@ -1,9 +1,11 @@
/************************************************************************************
/****************************************************************************
* 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-2013, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2009-2010, 2012-2013, 2017 Gregory Nutt.
* All rights reserved.
*
* Author: Uros Platise <uros.platise@isotel.eu>
* Gregory Nutt <gnutt@nuttx.org>
*
@ -34,27 +36,27 @@
* 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, use the table to handle freq change and to fit all
* devices. Note that STM32_SPI driver is prone to too high freq. parameters and
* limit it within physical constraints. The speed may be changed through ioctl
* MTDIOC_SETSPEED
* - frequency is fixed to desired max by RAMTRON_INIT_CLK_MAX if new
* devices with different speed arrive, use the table to handle freq
* change and to fit all devices. Note that STM32_SPI driver is prone
* to too high freq. parameters and limit it within physical constraints.
* The speed may be changed through ioctl MTDIOC_SETSPEED
*
* TODO:
* - add support for sleep
* - add support for faster read FSTRD command
*/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -71,9 +73,9 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Used to abort the write wait */
@ -82,7 +84,8 @@
#endif
/* RAMTRON devices are flat!
* For purpose of the VFAT file system we emulate the following configuration:
* For purpose of the VFAT file system we emulate the following
* configuration:
*/
#define RAMTRON_EMULATE_SECTOR_SHIFT 9
@ -95,34 +98,35 @@
#define RAMTRON_MEMORY_TYPE 0xc2
/* Instructions:
* Command Value N Description Addr Dummy Data */
* 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_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_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_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
@ -132,9 +136,9 @@
#define RAMTRON_INIT_CLK_MAX 40000000UL
/************************************************************************************
/****************************************************************************
* Private Types
************************************************************************************/
****************************************************************************/
struct ramtron_parts_s
{
@ -167,9 +171,9 @@ struct ramtron_dev_s
FAR const struct ramtron_parts_s *part; /* Part instance */
};
/************************************************************************************
/****************************************************************************
* Supported Part Lists
************************************************************************************/
****************************************************************************/
static const struct ramtron_parts_s g_ramtron_parts[] =
{
@ -177,7 +181,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25V01", /* name */
0x21, /* id1 */
0x00, /* id2 */
16L*1024L, /* size */
16L * 1024L, /* size */
2, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -189,7 +193,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25V01A", /* name */
0x21, /* id1 */
0x08, /* id2 */
16L*1024L, /* size */
16L * 1024L, /* size */
2, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -201,7 +205,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25V02", /* name */
0x22, /* id1 */
0x00, /* id2 */
32L*1024L, /* size */
32L * 1024L, /* size */
2, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -213,7 +217,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25V02A", /* name */
0x22, /* id1 */
0x08, /* id2 */
32L*1024L, /* size */
32L * 1024L, /* size */
2, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -225,7 +229,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25VN02", /* name */
0x22, /* id1 */
0x01, /* id2 */
32L*1024L, /* size */
32L * 1024L, /* size */
2, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -237,7 +241,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25V05", /* name */
0x23, /* id1 */
0x00, /* id2 */
64L*1024L, /* size */
64L * 1024L, /* size */
2, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -249,7 +253,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25VN05", /* name */
0x23, /* id1 */
0x01, /* id2 */
64L*1024L, /* size */
64L * 1024L, /* size */
2, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -261,7 +265,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25V10", /* name */
0x24, /* id1 */
0x00, /* id2 */
128L*1024L, /* size */
128L * 1024L, /* size */
3, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -273,7 +277,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25VN10", /* name */
0x24, /* id1 */
0x01, /* id2 */
128L*1024L, /* size */
128L * 1024L, /* size */
3, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -285,7 +289,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25V20A", /* name */
0x25, /* id1 */
0x08, /* id2 */
256L*1024L, /* size */
256L * 1024L, /* size */
3, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -297,7 +301,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"CY15B104Q", /* name */
0x26, /* id1 */
0x08, /* id2 */
512L*1024L, /* size */
512L * 1024L, /* size */
3, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -309,7 +313,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"MB85RS1MT", /* name */
0x27, /* id1 */
0x03, /* id2 */
128L*1024L, /* size */
128L * 1024L, /* size */
3, /* addr_len */
25000000 /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -321,7 +325,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"MB85RS256B", /* name */
0x05, /* id1 */
0x09, /* id2 */
32L*1024L, /* size */
32L * 1024L, /* size */
3, /* addr_len */
25000000 /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -334,7 +338,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"MB85AS4MT", /* name */
0xc9, /* id1 */
0x03, /* id2 */
512L*1024L, /* size */
512L * 1024L, /* size */
3, /* addr_len */
RAMTRON_INIT_CLK_MAX, /* speed */
true, /* chunked */
@ -346,7 +350,7 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
"FM25H20", /* name */
0xff, /* id1 */
0xff, /* id2 */
256L*1024L, /* size */
256L * 1024L, /* size */
3, /* addr_len */
RAMTRON_INIT_CLK_MAX /* speed */
#ifdef CONFIG_RAMTRON_CHUNKING
@ -369,9 +373,9 @@ static const struct ramtron_parts_s g_ramtron_parts[] =
}
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -381,33 +385,47 @@ static inline int ramtron_readid(struct ramtron_dev_s *priv);
static int ramtron_waitwritecomplete(struct ramtron_dev_s *priv);
static void ramtron_writeenable(struct ramtron_dev_s *priv);
static inline int ramtron_pagewrite(struct ramtron_dev_s *priv,
FAR const uint8_t *buffer, off_t offset,
FAR const uint8_t *buffer,
off_t offset,
size_t pagesize);
/* 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,
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);
#ifdef CONFIG_RAMTRON_CHUNKING
static ssize_t ramtron_bwrite_nonchunked(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer);
static ssize_t ramtron_bwrite_chunked(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buf);
static ssize_t ramtron_bwrite_nonchunked(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buffer);
static ssize_t ramtron_bwrite_chunked(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buf);
#endif
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,
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);
static int ramtron_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: ramtron_lock
************************************************************************************/
****************************************************************************/
static void ramtron_lock(FAR struct ramtron_dev_s *priv)
{
@ -417,16 +435,18 @@ static void ramtron_lock(FAR struct ramtron_dev_s *priv)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus.
* We will retain that exclusive access until the bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(dev, SPIDEV_MODE3);
@ -435,18 +455,18 @@ static void ramtron_lock(FAR struct ramtron_dev_s *priv)
SPI_SETFREQUENCY(dev, priv->speed);
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_unlock
************************************************************************************/
****************************************************************************/
static inline void ramtron_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_readid
************************************************************************************/
****************************************************************************/
static inline int ramtron_readid(struct ramtron_dev_s *priv)
{
@ -475,8 +495,8 @@ static inline int ramtron_readid(struct ramtron_dev_s *priv)
manufacturer = SPI_SEND(priv->dev, RAMTRON_DUMMY);
/* Fujitsu parts such as MB85RS1MT only have 1-byte for the manufacturer
* ID. The manufacturer code is "0x4".
/* Fujitsu parts such as MB85RS1MT only have 1-byte for the
* manufacturer ID. The manufacturer code is "0x4".
*/
if (i == 0 && manufacturer == 0x04)
@ -506,13 +526,17 @@ static inline int ramtron_readid(struct ramtron_dev_s *priv)
UNUSED(manufacturer); /* Eliminate warnings when debug is off */
UNUSED(memory); /* Eliminate warnings when debug is off */
finfo("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);
finfo(
"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->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);
priv->npages = priv->part->size /
(1 << RAMTRON_EMULATE_PAGE_SHIFT);
priv->speed = priv->part->speed;
return OK;
}
@ -521,9 +545,9 @@ static inline int ramtron_readid(struct ramtron_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_waitwritecomplete
************************************************************************************/
****************************************************************************/
static int ramtron_waitwritecomplete(struct ramtron_dev_s *priv)
{
@ -547,7 +571,9 @@ static int ramtron_waitwritecomplete(struct ramtron_dev_s *priv)
do
{
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out the
* status
*/
status = SPI_SEND(priv->dev, RAMTRON_DUMMY);
}
@ -571,9 +597,9 @@ static int ramtron_waitwritecomplete(struct ramtron_dev_s *priv)
return retries;
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_writeenable
************************************************************************************/
****************************************************************************/
static void ramtron_writeenable(struct ramtron_dev_s *priv)
{
@ -591,11 +617,12 @@ static void ramtron_writeenable(struct ramtron_dev_s *priv)
finfo("Enabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_sendaddr
************************************************************************************/
****************************************************************************/
static inline void ramtron_sendaddr(const struct ramtron_dev_s *priv, uint32_t addr)
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);
@ -608,9 +635,9 @@ static inline void ramtron_sendaddr(const struct ramtron_dev_s *priv, uint32_t a
SPI_SEND(priv->dev, addr & 0xff);
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_pagewrite
************************************************************************************/
****************************************************************************/
static inline int ramtron_pagewrite(struct ramtron_dev_s *priv,
FAR const uint8_t *buffer, off_t page,
@ -656,8 +683,9 @@ static inline int ramtron_pagewrite(struct ramtron_dev_s *priv,
finfo("Written\n");
#ifdef CONFIG_RAMTRON_WRITEWAIT
/* Wait for write completion now so we can report any errors to the caller. Thus
* the caller will know whether or not if the data is on stable storage
/* Wait for write completion now so we can report any errors to the caller.
* Thus the caller will know whether or not if the data is on stable
* storage
*/
return ramtron_waitwritecomplete(priv);
@ -666,20 +694,24 @@ static inline int ramtron_pagewrite(struct ramtron_dev_s *priv,
#endif
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_erase
************************************************************************************/
****************************************************************************/
static int ramtron_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int ramtron_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
finfo("startblock: %08lx nblocks: %d\n", (unsigned long)startblock, (int)nblocks);
finfo("startblock: %08lx nblocks: %d\n",
(unsigned long)startblock,
(int)nblocks);
finfo("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)
@ -689,28 +721,34 @@ static ssize_t ramtron_bread(FAR struct mtd_dev_s *dev, off_t startblock,
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* 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 nbytes >> priv->pageshift;
}
return (int)nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_bwrite/ramtron_bwrite_nonchunked
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_RAMTRON_CHUNKING
static ssize_t ramtron_bwrite_nonchunked(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer)
static ssize_t ramtron_bwrite_nonchunked(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buffer)
#else
static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer)
static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buffer)
#endif
{
FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev;
@ -737,18 +775,21 @@ static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
return nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_bwrite_chunked
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_RAMTRON_CHUNKING
static ssize_t ramtron_bwrite_chunked(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer)
static ssize_t ramtron_bwrite_chunked(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;
FAR const struct ramtron_parts_s *part;
size_t blocksleft = nblocks;
uint32_t p, writesplits;
uint32_t p;
uint32_t writesplits;
off_t newstartblock;
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
@ -767,16 +808,18 @@ static ssize_t ramtron_bwrite_chunked(FAR struct mtd_dev_s *dev, off_t startbloc
/* Split writes in chunksize chunks */
for (p = 0; p < writesplits; p++)
{
if (ramtron_pagewrite(priv, buffer + p * part->chunksize, newstartblock,
part->chunksize))
{
nblocks = 0;
goto out;
}
{
if (ramtron_pagewrite(priv,
buffer + p * part->chunksize,
newstartblock,
part->chunksize))
{
nblocks = 0;
goto out;
}
newstartblock++;
}
newstartblock++;
}
}
out:
@ -785,9 +828,9 @@ out:
}
#endif
/************************************************************************************
/****************************************************************************
* Name: ramtron_bwrite
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_RAMTRON_CHUNKING
static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
@ -812,11 +855,13 @@ static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
}
#endif
/************************************************************************************
/****************************************************************************
* Name: ramtron_read
************************************************************************************/
****************************************************************************/
static ssize_t ramtron_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
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;
@ -884,11 +929,13 @@ static ssize_t ramtron_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbyt
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: ramtron_ioctl
************************************************************************************/
****************************************************************************/
static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
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 */
@ -899,16 +946,18 @@ static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
case MTDIOC_GEOMETRY:
{
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
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.
/* 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.
* 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);
@ -923,7 +972,8 @@ static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
break;
case MTDIOC_BULKERASE:
finfo("BULDERASE: Makes no sense in ramtron. Let's confirm operation as OK\n");
finfo("BULDERASE: Makes no sense in ramtron.\n");
finfo("BULDERASE: Let's confirm operation as OK\n");
ret = OK;
break;
@ -950,19 +1000,20 @@ static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
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).
* 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)
{
@ -973,11 +1024,12 @@ FAR struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct ramtron_dev_s *)kmm_zalloc(sizeof(struct ramtron_dev_s));
priv = (FAR struct ramtron_dev_s *)
kmm_zalloc(sizeof(struct ramtron_dev_s));
if (priv)
{
/* Initialize the allocated structure. (unsupported methods were
@ -1000,7 +1052,9 @@ FAR struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *dev)
if (ramtron_readid(priv) != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
kmm_free(priv);
return NULL;

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/sector512.c
* MTD driver that contains another MTD driver and converts a larger sector size
* to a standard 512 byte sector size.
* MTD driver that contains another MTD driver and converts a larger sector
* size to a standard 512 byte sector size.
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@ -33,11 +33,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -57,9 +57,9 @@
#include <nuttx/fs/ioctl.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration */
@ -69,35 +69,35 @@
/* 512-byte sector constants */
#define SECTOR_512 512
#define SHIFT_512 9
#define MASK_512 511
#define SECTOR_512 512
#define SHIFT_512 9
#define MASK_512 511
/* 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 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 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 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)
#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 s512_dev_s.
/* 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 s512_dev_s.
*/
struct s512_dev_s
@ -113,9 +113,9 @@ struct s512_dev_s
FAR uint8_t *eblock; /* Allocated erase block */
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -126,26 +126,36 @@ static void s512_cacheflush(struct s512_dev_s *priv);
/* MTD driver methods */
static int s512_erase(FAR struct mtd_dev_s *dev, off_t sector512, size_t nsectors);
static ssize_t s512_bread(FAR struct mtd_dev_s *dev, off_t sector512,
size_t nsectors, FAR uint8_t *buf);
static ssize_t s512_bwrite(FAR struct mtd_dev_s *dev, off_t sector512,
size_t nsectors, FAR const uint8_t *buf);
static ssize_t s512_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR uint8_t *buffer);
static int s512_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int s512_erase(FAR struct mtd_dev_s *dev,
off_t sector512,
size_t nsectors);
static ssize_t s512_bread(FAR struct mtd_dev_s *dev,
off_t sector512,
size_t nsectors,
FAR uint8_t *buf);
static ssize_t s512_bwrite(FAR struct mtd_dev_s *dev,
off_t sector512,
size_t nsectors,
FAR const uint8_t *buf);
static ssize_t s512_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer);
static int s512_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Data
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: s512_cacheread
************************************************************************************/
****************************************************************************/
static FAR uint8_t *s512_cacheread(struct s512_dev_s *priv, off_t sector512)
{
@ -191,7 +201,9 @@ static FAR uint8_t *s512_cacheread(struct s512_dev_s *priv, off_t sector512)
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 */
/* Get the index to the 512 sector in the erase block that holds the
* argument
*/
index = sector512 % priv->stdperblock;
@ -200,9 +212,9 @@ static FAR uint8_t *s512_cacheread(struct s512_dev_s *priv, off_t sector512)
return &priv->eblock[index << SHIFT_512];
}
/************************************************************************************
/****************************************************************************
* Name: s512_cacheflush
************************************************************************************/
****************************************************************************/
#if !defined(CONFIG_MTD_SECT512_READONLY)
static void s512_cacheflush(struct s512_dev_s *priv)
@ -239,11 +251,13 @@ static void s512_cacheflush(struct s512_dev_s *priv)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: s512_erase
************************************************************************************/
****************************************************************************/
static int s512_erase(FAR struct mtd_dev_s *dev, off_t sector512, size_t nsectors)
static int s512_erase(FAR struct mtd_dev_s *dev,
off_t sector512,
size_t nsectors)
{
#ifdef CONFIG_MTD_SECT512_READONLY
return -EACESS
@ -258,21 +272,22 @@ static int s512_erase(FAR struct mtd_dev_s *dev, off_t sector512, size_t nsector
while (sectorsleft-- > 0)
{
/* Erase each sector. First, make sure that the erase block containing the
* 512 byte sector is in the cache.
/* Erase each sector. First, make sure that the erase block containing
* the 512 byte sector is in the cache.
*/
dest = s512_cacheread(priv, sector512);
if (!dest)
{
ferr("ERROR: s512_cacheread(%lu) failed\n", (unsigned long)sector512);
ferr("ERROR: s512_cacheread(%lu) failed\n",
(unsigned long)sector512);
DEBUGPANIC();
return -EIO;
}
/* Erase the block containing this sector if it is not already erased.
* The erased indicator will be cleared when the data from the erase sector
* is read into the cache and set here when we erase the block.
* The erased indicator 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))
@ -310,9 +325,9 @@ static int s512_erase(FAR struct mtd_dev_s *dev, off_t sector512, size_t nsector
#endif
}
/************************************************************************************
/****************************************************************************
* Name: s512_bread
************************************************************************************/
****************************************************************************/
static ssize_t s512_bread(FAR struct mtd_dev_s *dev, off_t sector512,
size_t nsectors, FAR uint8_t *buffer)
@ -333,7 +348,8 @@ static ssize_t s512_bread(FAR struct mtd_dev_s *dev, off_t sector512,
src = s512_cacheread(priv, sector512);
if (!src)
{
ferr("ERROR: s512_cacheread(%lu) failed\n", (unsigned long)sector512);
ferr("ERROR: s512_cacheread(%lu) failed\n",
(unsigned long)sector512);
DEBUGPANIC();
result = (ssize_t)nsectors - remaining;
@ -345,7 +361,9 @@ static ssize_t s512_bread(FAR struct mtd_dev_s *dev, off_t sector512,
break;
}
/* Copy the sector data from the erase block cache into the user buffer */
/* Copy the sector data from the erase block cache into the user
* buffer
*/
memcpy(buffer, src, SECTOR_512);
@ -356,9 +374,9 @@ static ssize_t s512_bread(FAR struct mtd_dev_s *dev, off_t sector512,
return result;
}
/************************************************************************************
/****************************************************************************
* Name: s512_bwrite
************************************************************************************/
****************************************************************************/
static ssize_t s512_bwrite(FAR struct mtd_dev_s *dev, off_t sector512,
size_t nsectors,
@ -378,8 +396,8 @@ static ssize_t s512_bwrite(FAR struct mtd_dev_s *dev, off_t sector512,
for (remaining = nsectors; remaining > 0; remaining--)
{
/* First, make sure that the erase block containing 512 byte sector is in
* memory.
/* First, make sure that the erase block containing 512 byte sector is
* in memory.
*/
dest = s512_cacheread(priv, sector512);
@ -395,8 +413,8 @@ static ssize_t s512_bwrite(FAR struct mtd_dev_s *dev, off_t sector512,
}
/* 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.
* 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))
@ -434,11 +452,13 @@ static ssize_t s512_bwrite(FAR struct mtd_dev_s *dev, off_t sector512,
#endif
}
/************************************************************************************
/****************************************************************************
* Name: s512_read
************************************************************************************/
****************************************************************************/
static ssize_t s512_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t s512_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct s512_dev_s *priv = (FAR struct s512_dev_s *)dev;
@ -495,9 +515,9 @@ static ssize_t s512_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: s512_ioctl
************************************************************************************/
****************************************************************************/
static int s512_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -514,13 +534,14 @@ static int s512_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
((uintptr_t)arg);
if (geo)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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 = SECTOR_512;
@ -559,23 +580,23 @@ static int s512_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: s512_initialize
*
* Description:
* Create an initialized MTD device instance. This MTD driver contains another
* MTD driver and converts a larger sector size to a standard 512 byte sector
* size.
* Create an initialized MTD device instance. This MTD driver contains
* another MTD driver and converts a larger sector size to a standard 512
* byte sector size.
*
* 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).
* 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 *s512_initialize(FAR struct mtd_dev_s *mtd)
{
@ -595,7 +616,8 @@ FAR struct mtd_dev_s *s512_initialize(FAR struct mtd_dev_s *mtd)
if (ret < 0 || geo.erasesize <= SECTOR_512 ||
(geo.erasesize & ~MASK_512) != geo.erasesize)
{
ferr("ERROR: MTDIOC_GEOMETRY ioctl returned %d, eraseize=%" PRId32 "\n",
ferr(
"ERROR: MTDIOC_GEOMETRY ioctl returned %d, eraseize=%" PRId32 "\n",
ret, geo.erasesize);
DEBUGPANIC();
return NULL;
@ -604,8 +626,8 @@ FAR struct mtd_dev_s *s512_initialize(FAR struct mtd_dev_s *mtd)
/* 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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct s512_dev_s *)kmm_zalloc(sizeof(struct s512_dev_s));

View file

@ -90,6 +90,7 @@ static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd,
/****************************************************************************
* Private Data
****************************************************************************/
/* This structure holds the state of the MTD driver */
static struct skel_dev_s g_skeldev =
@ -255,13 +256,14 @@ static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)arg;
if (geo)
{
/* Populate the geometry structure with information needed to know
* the capacity and how to access the device.
/* Populate the geometry structure with information needed 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.
* 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 */

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/sst25.c
* Driver for SPI-based SST25 FLASH.
*
@ -37,11 +37,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -63,56 +63,57 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* 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.
/* 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
#define CONFIG_SST25_SPIMODE SPIDEV_MODE0
#endif
/* SPI Frequency. May be up to 25MHz. */
#ifndef CONFIG_SST25_SPIFREQUENCY
# define CONFIG_SST25_SPIFREQUENCY 20000000
#define CONFIG_SST25_SPIFREQUENCY 20000000
#endif
/* SST25 Instructions ***************************************************************/
/* SST25 Instructions *******************************************************/
/* Command Value Description Addr Data */
/* Command Value Description Addr Data */
/* Dummy */
/* 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 */
#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 ******************************************************************/
/* SST25 Registers **********************************************************/
/* Read ID (RDID) register values */
@ -129,25 +130,25 @@
/* 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_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_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
#define SST25_DUMMY 0xa5
/* Chip Geometries ******************************************************************/
/* Chip Geometries **********************************************************/
/* SST25VF512 capacity is 512Kbit (64Kbit x 8) = 64Kb (8Kb x 8) */
@ -172,8 +173,8 @@
#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 */
#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 */
@ -196,13 +197,14 @@
#define CLR_DIRTY(p) do { (p)->flags &= ~SST25_CACHE_DIRTY; } while (0)
#define CLR_ERASED(p) do { (p)->flags &= ~SST25_CACHE_ERASED; } 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.
/* 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
@ -219,9 +221,9 @@ struct sst25_dev_s
#endif
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -239,47 +241,67 @@ static inline void sst25_wrdi(FAR struct sst25_dev_s *priv);
#endif
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);
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);
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);
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);
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,
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);
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)
{
@ -287,16 +309,18 @@ static void sst25_lock(FAR struct spi_dev_s *dev)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus.
* We will retain that exclusive access until the bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(dev, CONFIG_SST25_SPIMODE);
@ -305,18 +329,18 @@ static void sst25_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_SST25_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: sst25_unlock
************************************************************************************/
****************************************************************************/
static inline void sst25_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: sst25_readid
************************************************************************************/
****************************************************************************/
static inline int sst25_readid(struct sst25_dev_s *priv)
{
@ -378,9 +402,9 @@ static inline int sst25_readid(struct sst25_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: sst25_unprotect
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_SST25_READONLY
static void sst25_unprotect(struct sst25_dev_s *priv)
@ -403,9 +427,9 @@ static void sst25_unprotect(struct sst25_dev_s *priv)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: sst25_waitwritecomplete
************************************************************************************/
****************************************************************************/
static uint8_t sst25_waitwritecomplete(struct sst25_dev_s *priv)
{
@ -423,7 +447,9 @@ static uint8_t sst25_waitwritecomplete(struct sst25_dev_s *priv)
SPI_SEND(priv->dev, SST25_RDSR);
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out the
* status
*/
status = SPI_SEND(priv->dev, SST25_DUMMY);
@ -431,9 +457,9 @@ static uint8_t sst25_waitwritecomplete(struct sst25_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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.
/* 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 */
@ -450,9 +476,9 @@ static uint8_t sst25_waitwritecomplete(struct sst25_dev_s *priv)
return status;
}
/************************************************************************************
/****************************************************************************
* Name: sst25_cmd
************************************************************************************/
****************************************************************************/
static inline void sst25_cmd(struct sst25_dev_s *priv, uint8_t cmd)
{
@ -469,9 +495,9 @@ static inline void sst25_cmd(struct sst25_dev_s *priv, uint8_t cmd)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: sst25_wren
************************************************************************************/
****************************************************************************/
static inline void sst25_wren(struct sst25_dev_s *priv)
{
@ -480,9 +506,9 @@ static inline void sst25_wren(struct sst25_dev_s *priv)
sst25_cmd(priv, SST25_WREN);
}
/************************************************************************************
/****************************************************************************
* Name: sst25_wrdi
************************************************************************************/
****************************************************************************/
#if !defined(CONFIG_SST25_SLOWWRITE) && !defined(CONFIG_SST25_READONLY)
static inline void sst25_wrdi(struct sst25_dev_s *priv)
@ -493,9 +519,9 @@ static inline void sst25_wrdi(struct sst25_dev_s *priv)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: sst25_sectorerase
************************************************************************************/
****************************************************************************/
static void sst25_sectorerase(struct sst25_dev_s *priv, off_t sector)
{
@ -519,8 +545,8 @@ static void sst25_sectorerase(struct sst25_dev_s *priv, off_t sector)
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.
/* Send the sector address high byte first. Only the most significant bits
* (those corresponding to the sector) have any meaning.
*/
SPI_SEND(priv->dev, (address >> 16) & 0xff);
@ -532,9 +558,9 @@ static void sst25_sectorerase(struct sst25_dev_s *priv, off_t sector)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: sst25_chiperase
************************************************************************************/
****************************************************************************/
static inline int sst25_chiperase(struct sst25_dev_s *priv)
{
@ -556,12 +582,14 @@ static inline int sst25_chiperase(struct sst25_dev_s *priv)
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)
static void sst25_byteread(FAR struct sst25_dev_s *priv,
FAR uint8_t *buffer,
off_t address,
size_t nbytes)
{
uint8_t status;
@ -570,7 +598,9 @@ static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer,
/* 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);
DEBUGASSERT((status & (SST25_SR_WEL |
SST25_SR_BP_MASK |
SST25_SR_AAI)) == 0);
UNUSED(status);
/* Select this FLASH part */
@ -606,13 +636,15 @@ static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer,
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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)
static void sst25_bytewrite(struct sst25_dev_s *priv,
FAR const uint8_t *buffer,
off_t address,
size_t nbytes)
{
uint8_t status;
@ -655,7 +687,9 @@ static void sst25_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
SPI_SEND(priv->dev, *buffer);
/* Deselect the FLASH and setup for the next pass through the loop */
/* Deselect the FLASH and setup for the next pass through the
* loop
*/
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false);
}
@ -668,13 +702,15 @@ static void sst25_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
}
#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)
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;
@ -711,7 +747,9 @@ static void sst25_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
/* 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);
DEBUGASSERT((status & (SST25_SR_WEL |
SST25_SR_BP_MASK |
SST25_SR_AAI)) == 0);
UNUSED(status);
/* Enable write access to the FLASH */
@ -743,8 +781,11 @@ static void sst25_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
/* 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));
DEBUGASSERT((status & (SST25_SR_WEL |
SST25_SR_BP_MASK |
SST25_SR_AAI)) ==
(SST25_SR_WEL |
SST25_SR_AAI));
UNUSED(status);
/* Decrement the word count and advance the write position */
@ -781,8 +822,11 @@ static void sst25_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
/* 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));
DEBUGASSERT((status & (SST25_SR_WEL |
SST25_SR_BP_MASK |
SST25_SR_AAI)) ==
(SST25_SR_WEL |
SST25_SR_AAI));
UNUSED(status);
/* Decrement the word count and advance the write position */
@ -799,9 +843,9 @@ static void sst25_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
}
#endif
/************************************************************************************
/****************************************************************************
* Name: sst25_cacheflush
************************************************************************************/
****************************************************************************/
#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY)
static void sst25_cacheflush(struct sst25_dev_s *priv)
@ -816,11 +860,13 @@ static void sst25_cacheflush(struct sst25_dev_s *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));
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));
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 */
@ -831,9 +877,9 @@ static void sst25_cacheflush(struct sst25_dev_s *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)
@ -842,9 +888,10 @@ static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector)
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.
/* 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;
@ -873,7 +920,9 @@ static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector)
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 */
/* Get the index to the 512 sector in the erase block that holds the
* argument
*/
index = sector & ((1 << shift) - 1);
@ -883,17 +932,17 @@ static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector)
}
#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.
/* First, make sure that the erase block containing the 512 byte sector is
* in the cache.
*/
dest = sst25_cacheread(priv, sector);
@ -912,9 +961,9 @@ static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector)
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).
/* 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);
@ -922,32 +971,35 @@ static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector)
}
#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)
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.
/* 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.
* 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);
off_t esectno = sector >>
(priv->sectorshift - SST25_SECTOR_SHIFT);
finfo("sector: %ld esectno: %d\n", sector, esectno);
sst25_sectorerase(priv, esectno);
@ -971,11 +1023,13 @@ static void sst25_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *bu
}
#endif
/************************************************************************************
/****************************************************************************
* Name: sst25_erase
************************************************************************************/
****************************************************************************/
static int sst25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int sst25_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
#ifdef CONFIG_SST25_READONLY
return -EACESS
@ -1012,9 +1066,9 @@ static int sst25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nbloc
#endif
}
/************************************************************************************
/****************************************************************************
* Name: sst25_bread
************************************************************************************/
****************************************************************************/
static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks,
@ -1025,7 +1079,9 @@ static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* 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);
@ -1041,7 +1097,9 @@ static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* 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);
@ -1054,9 +1112,9 @@ static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock,
#endif
}
/************************************************************************************
/****************************************************************************
* Name: sst25_bwrite
************************************************************************************/
****************************************************************************/
static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks,
@ -1088,11 +1146,13 @@ static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
#endif
}
/************************************************************************************
/****************************************************************************
* Name: sst25_read
************************************************************************************/
****************************************************************************/
static ssize_t sst25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
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;
@ -1109,9 +1169,9 @@ static ssize_t sst25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: sst25_ioctl
************************************************************************************/
****************************************************************************/
static int sst25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -1128,13 +1188,14 @@ static int sst25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
((uintptr_t)arg);
if (geo)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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
@ -1175,19 +1236,19 @@ static int sst25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
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).
* 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)
{
@ -1199,8 +1260,8 @@ FAR struct mtd_dev_s *sst25_initialize(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct sst25_dev_s *)kmm_zalloc(sizeof(struct sst25_dev_s));
@ -1227,7 +1288,9 @@ FAR struct mtd_dev_s *sst25_initialize(FAR struct spi_dev_s *dev)
ret = sst25_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
ferr("ERROR: Unrecognized\n");
kmm_free(priv);
@ -1235,7 +1298,9 @@ FAR struct mtd_dev_s *sst25_initialize(FAR struct spi_dev_s *dev)
}
else
{
/* Make sure that the FLASH is unprotected so that we can write into it */
/* Make sure that the FLASH is unprotected so that we can
* write into it
*/
#ifndef CONFIG_SST25_READONLY
sst25_unprotect(priv);

View file

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/sst26.c
* Driver for SPI-based or QSPI-based SST26VF parts of 32 or 64MBit.
*
@ -44,11 +44,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -66,41 +66,42 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* Configuration ************************************************************/
/* Per the data sheet, SST26 parts can be driven with either SPI mode 0 (CPOL=0 and
* CPHA=0) or mode 3 (CPOL=1 and CPHA=1). So you may need to specify
* CONFIG_SST26_SPIMODE to select the best mode for your device. If
* CONFIG_SST26_SPIMODE is not defined, mode 0 will be used.
/* Per the data sheet, SST26 parts can be driven with either SPI mode 0
* (CPOL=0 and CPHA=0) or mode 3 (CPOL=1 and CPHA=1).
* So you may need to specify CONFIG_SST26_SPIMODE to select the best mode
* for your device. If CONFIG_SST26_SPIMODE is not defined, mode 0 will be
* used.
*/
#ifndef CONFIG_SST26_SPIMODE
# define CONFIG_SST26_SPIMODE SPIDEV_MODE0
#define CONFIG_SST26_SPIMODE SPIDEV_MODE0
#endif
/* SPI Frequency. May be up to 104 MHz. */
#ifndef CONFIG_SST26_SPIFREQUENCY
# define CONFIG_SST26_SPIFREQUENCY 20000000
#define CONFIG_SST26_SPIFREQUENCY 20000000
#endif
/* Various manufacturers may have produced the parts. 0xBF is the manufacturer ID
* for the SST serial FLASH.
/* Various manufacturers may have produced the parts.
* 0xBF is the manufacturer ID for the SST serial FLASH.
*/
#ifndef CONFIG_SST26_MANUFACTURER
# define CONFIG_SST26_MANUFACTURER 0xBF
#define CONFIG_SST26_MANUFACTURER 0xBF
#endif
#ifndef CONFIG_SST26_MEMORY_TYPE
# define CONFIG_SST26_MEMORY_TYPE 0x26
#define CONFIG_SST26_MEMORY_TYPE 0x26
#endif
/* SST26 Registers *******************************************************************/
/* SST26 Registers **********************************************************/
/* Identification register values */
@ -142,53 +143,51 @@
#define SST26_SST26VF064_NPAGES 32768
/* Instructions */
/* Command Value NN Description Addr Dummy Data */
#define SST26_NOP 0x00 /* 14 No Operation 0 0 0 */
#define SST26_RSTEN 0x66 /* 14 Reset Enable 0 0 0 */
#define SST26_RST 0x99 /* 14 Reset Memory 0 0 0 */
#define SST26_EQIO 0x38 /* 1 Enable Quad I/O 0 0 0 */
#define SST26_RSTQIO 0xFF /* 4 Reset Quad I/O 0 0 0 */
#define SST26_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */
/* 4 Read Status Register 0 1 >=1 */
#define SST26_WRSR 0x01 /* 14 Write Status Register 0 0 2 */
#define SST26_RDCR 0x35 /* 1 Read Config Register 0 0 >=1 */
/* 4 Read Config Register 0 1 >=1 */
#define SST26_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */
#define SST26_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */
/* 4 Higher speed read 3 3 >=1 */
#define SST26_SQOR 0x6b /* 1 SQI Output Read 3 1 >=1 */
#define SST26_SQIOR 0xeb /* 1 SQI I/O Read 3 3 >=1 */
#define SST26_SDOR 0x3b /* 1 SDI Output Read 3 1 >=1 */
#define SST26_SDIOR 0xbb /* 1 SDI I/O Read 3 1 >=1 */
#define SST26_SB 0xc0 /* 14 Set Burst Length 0 0 1 */
#define SST26_RBSQI 0x0c /* 4 SQI Read Burst w/ Wrap 3 3 >=1 */
#define SST26_RBSPI 0xec /* 1 SPI Read Burst w/ Wrap 3 3 >=1 */
/* Command Value NN Description Addr Dummy Data */
#define SST26_RDID 0x9f /* 1 Read Identification 0 0 >=3 */
#define SST26_QRDID 0xaf /* 4 Quad Read Identification 0 1 >=3 */
#define SST26_SFDP 0x5a /* 1 Serial Flash Discov. Par. 3 1 >=1 */
#define SST26_WREN 0x06 /* 14 Write Enable 0 0 0 */
#define SST26_WRDI 0x04 /* 14 Write Disable 0 0 0 */
#define SST26_SE 0x20 /* 14 Sector Erase 3 0 0 */
#define SST26_BE 0xd8 /* 14 8/32/64K Block Erase 3 0 0 */
#define SST26_CE 0xc7 /* 14 Chip Erase 0 0 0 */
#define SST26_PP 0x02 /* 1 Page Program 3 0 1-256 */
#define SST26_QPP 0x32 /* 1 Quad Page Program 3 0 1-256 */
#define SST26_WRSU 0xb0 /* 14 Suspend Program/Erase 0 0 0 */
#define SST26_WRRE 0x30 /* 14 Resume Program/Erase 0 0 0 */
#define SST26_RBPR 0x72 /* 1 Read Block-Protection reg 0 0 1-18 */
/* 4 Read Block-Protection reg 0 1 1-18 */
#define SST26_WBPR 0x42 /* 14 Write Block-Protection reg 0 0 1-18 */
#define SST26_LBPR 0x8d /* 14 Lock down Block-Prot. reg 0 0 0 */
#define SST26_NVWLDR 0xe8 /* 14 non-Volatile Write L-D reg 0 0 1-18 */
#define SST26_ULBPR 0x98 /* 14 Global Block Protection unlock 0 0 0 */
#define SST26_RSID 0x88 /* 14 Read Security ID 2 1 1-2048*/
/* 4 Read Security ID 2 3 1-2048*/
#define SST26_PSID 0xa5 /* 14 Program User Security ID area 2 0 1-256 */
#define SST26_LSID 0x85 /* 14 Lockout Security ID programming 0 0 0 */
#define SST26_NOP 0x00 /* 14 No Operation 0 0 0 */
#define SST26_RSTEN 0x66 /* 14 Reset Enable 0 0 0 */
#define SST26_RST 0x99 /* 14 Reset Memory 0 0 0 */
#define SST26_EQIO 0x38 /* 1 Enable Quad I/O 0 0 0 */
#define SST26_RSTQIO 0xFF /* 4 Reset Quad I/O 0 0 0 */
#define SST26_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */
/* 4 Read Status Register 0 1 >=1 */
#define SST26_WRSR 0x01 /* 14 Write Status Register 0 0 2 */
#define SST26_RDCR 0x35 /* 1 Read Config Register 0 0 >=1 */
/* 4 Read Config Register 0 1 >=1 */
#define SST26_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */
#define SST26_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */
/* 4 Higher speed read 3 3 >=1 */
#define SST26_SQOR 0x6b /* 1 SQI Output Read 3 1 >=1 */
#define SST26_SQIOR 0xeb /* 1 SQI I/O Read 3 3 >=1 */
#define SST26_SDOR 0x3b /* 1 SDI Output Read 3 1 >=1 */
#define SST26_SDIOR 0xbb /* 1 SDI I/O Read 3 1 >=1 */
#define SST26_SB 0xc0 /* 14 Set Burst Length 0 0 1 */
#define SST26_RBSQI 0x0c /* 4 SQI Read Burst w/ Wrap 3 3 >=1 */
#define SST26_RBSPI 0xec /* 1 SPI Read Burst w/ Wrap 3 3 >=1 */
#define SST26_RDID 0x9f /* 1 Read Identification 0 0 >=3 */
#define SST26_QRDID 0xaf /* 4 Quad Read Identification 0 1 >=3 */
#define SST26_SFDP 0x5a /* 1 Serial Flash Discov. Par.3 1 >=1 */
#define SST26_WREN 0x06 /* 14 Write Enable 0 0 0 */
#define SST26_WRDI 0x04 /* 14 Write Disable 0 0 0 */
#define SST26_SE 0x20 /* 14 Sector Erase 3 0 0 */
#define SST26_BE 0xd8 /* 14 8/32/64K Block Erase 3 0 0 */
#define SST26_CE 0xc7 /* 14 Chip Erase 0 0 0 */
#define SST26_PP 0x02 /* 1 Page Program 3 0 1-256 */
#define SST26_QPP 0x32 /* 1 Quad Page Program 3 0 1-256 */
#define SST26_WRSU 0xb0 /* 14 Suspend Program/Erase 0 0 0 */
#define SST26_WRRE 0x30 /* 14 Resume Program/Erase 0 0 0 */
#define SST26_RBPR 0x72 /* 1 Read Block-Protection reg 0 0 1-18 */
/* 4 Read Block-Protection reg 0 1 1-18 */
#define SST26_WBPR 0x42 /* 14 Write Block-Protection reg 0 0 1-18 */
#define SST26_LBPR 0x8d /* 14 Lock down Block-Prot. reg 0 0 0 */
#define SST26_NVWLDR 0xe8 /* 14 non-Volatile Write L-D reg 0 0 1-18 */
#define SST26_ULBPR 0x98 /* 14 Global Block Protection unlock 0 0 0 */
#define SST26_RSID 0x88 /* 14 Read Security ID 2 1 1-2048 */
/* 4 Read Security ID 2 3 1-2048 */
#define SST26_PSID 0xa5 /* 14 Program User Security ID area 2 0 1-256 */
#define SST26_LSID 0x85 /* 14 Lockout Security ID programming 0 0 0 */
/* NOTE 1: All parts.
* NOTE 2: In SST26VF064 terminology, 0xd8 is block erase and 0x20
@ -198,18 +197,18 @@
/* Status register bit definitions */
#define SST26_SR_WIP (1 << 0) /* Bit 0: Write in progress */
#define SST26_SR_WEL (1 << 1) /* Bit 1: Write enable latch */
#define SST26_SR_WSE (1 << 2) /* Bit 2: Write Suspend-Erase Status */
#define SST26_SR_WSP (1 << 3) /* Bit 3: Write Suspend-Program Status */
#define SST26_SR_WPLD (1 << 4) /* Bit 4: Write Protection Lock-Down Status */
#define SST26_SR_SEC (1 << 5) /* Bit 5: Security ID status */
#define SST26_SR_RES (1 << 6) /* Bit 6: RFU */
#define SST26_SR_WIP2 (1 << 7) /* Bit 7: Write in progress */
#define SST26_SR_WIP (1 << 0) /* Bit 0: Write in progress */
#define SST26_SR_WEL (1 << 1) /* Bit 1: Write enable latch */
#define SST26_SR_WSE (1 << 2) /* Bit 2: Write Suspend-Erase Status */
#define SST26_SR_WSP (1 << 3) /* Bit 3: Write Suspend-Program Status */
#define SST26_SR_WPLD (1 << 4) /* Bit 4: Write Protection Lock-Down Status */
#define SST26_SR_SEC (1 << 5) /* Bit 5: Security ID status */
#define SST26_SR_RES (1 << 6) /* Bit 6: RFU */
#define SST26_SR_WIP2 (1 << 7) /* Bit 7: Write in progress */
#define SST26_DUMMY 0xa5
/* Debug ****************************************************************************/
/* Debug ********************************************************************/
#ifdef CONFIG_SST26_DEBUG
# define ssterr(format, ...) _err(format, ##__VA_ARGS__)
@ -219,9 +218,9 @@
# define sstinfo(x...)
#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
@ -239,9 +238,9 @@ struct sst26_dev_s
uint32_t npages;
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -252,34 +251,48 @@ static void sst26_waitwritecomplete(struct sst26_dev_s *priv);
static void sst26_writeenable(struct sst26_dev_s *priv);
static void sst26_writedisable(struct sst26_dev_s *priv);
static void sst26_globalunlock(struct sst26_dev_s *priv);
static inline void sst26_sectorerase(struct sst26_dev_s *priv, off_t offset,
static inline void sst26_sectorerase(struct sst26_dev_s *priv,
off_t offset,
uint8_t type);
static inline int sst26_chiperase(struct sst26_dev_s *priv);
static inline void sst26_pagewrite(struct sst26_dev_s *priv,
FAR const uint8_t *buffer, off_t offset);
FAR const uint8_t *buffer,
off_t offset);
/* MTD driver methods */
static int sst26_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
static ssize_t sst26_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buf);
static ssize_t sst26_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buf);
static ssize_t sst26_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static int sst26_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks);
static ssize_t sst26_bread(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR uint8_t *buf);
static ssize_t sst26_bwrite(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR const uint8_t *buf);
static ssize_t sst26_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer);
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t sst26_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t sst26_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer);
#endif
static int sst26_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
static int sst26_ioctl(FAR struct mtd_dev_s *dev,
int cmd,
unsigned long arg);
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: sst26_lock
************************************************************************************/
****************************************************************************/
static void sst26_lock(FAR struct spi_dev_s *dev)
{
@ -287,16 +300,17 @@ static void sst26_lock(FAR struct spi_dev_s *dev)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus. We will retain that exclusive access until the
* bus is unlocked.
*/
SPI_LOCK(dev, true);
/* After locking the SPI bus, then we also need to call the setfrequency, setbits,
* and setmode methods to make sure that the SPI is properly configured for the
* device. If the SPI bus is being shared, then it may have been left in an
* incompatible state.
/* After locking the SPI bus, then we also need to call the setfrequency,
* setbits, and setmode methods to make sure that the SPI is properly
* configured for the device. If the SPI bus is being shared, then it
* may have been left in an incompatible state.
*/
SPI_SETMODE(dev, CONFIG_SST26_SPIMODE);
@ -305,18 +319,18 @@ static void sst26_lock(FAR struct spi_dev_s *dev)
SPI_SETFREQUENCY(dev, CONFIG_SST26_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: sst26_unlock
************************************************************************************/
****************************************************************************/
static inline void sst26_unlock(FAR struct spi_dev_s *dev)
{
SPI_LOCK(dev, false);
}
/************************************************************************************
/****************************************************************************
* Name: sst26_readid
************************************************************************************/
****************************************************************************/
static inline int sst26_readid(struct sst26_dev_s *priv)
{
@ -387,9 +401,9 @@ static inline int sst26_readid(struct sst26_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: sst26_waitwritecomplete
************************************************************************************/
****************************************************************************/
static void sst26_waitwritecomplete(struct sst26_dev_s *priv)
{
@ -407,7 +421,9 @@ static void sst26_waitwritecomplete(struct sst26_dev_s *priv)
SPI_SEND(priv->dev, SST26_RDSR);
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out the
* status
*/
status = SPI_SEND(priv->dev, SST26_DUMMY);
@ -415,9 +431,9 @@ static void sst26_waitwritecomplete(struct sst26_dev_s *priv)
SPI_SELECT(priv->dev, SPIDEV_FLASH(0), 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.
/* 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 & SST26_SR_WIP) != 0)
@ -432,11 +448,11 @@ static void sst26_waitwritecomplete(struct sst26_dev_s *priv)
sstinfo("Complete\n");
}
/************************************************************************************
/****************************************************************************
* Name: sst26_globalunlock
* Description: SST26 flashes are globally locked after startup. To allow writing,
* this command must be sent once.
************************************************************************************/
* Description: SST26 flashes are globally locked after startup.
* To allow writing, this command must be sent once.
****************************************************************************/
static void sst26_globalunlock(struct sst26_dev_s *priv)
{
@ -455,9 +471,9 @@ static void sst26_globalunlock(struct sst26_dev_s *priv)
sstinfo("Device unlocked.\n");
}
/************************************************************************************
/****************************************************************************
* Name: sst26_writeenable
************************************************************************************/
****************************************************************************/
static void sst26_writeenable(struct sst26_dev_s *priv)
{
@ -476,9 +492,9 @@ static void sst26_writeenable(struct sst26_dev_s *priv)
sstinfo("Enabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: sst26_writedisable
************************************************************************************/
****************************************************************************/
static void sst26_writedisable(struct sst26_dev_s *priv)
{
@ -497,11 +513,13 @@ static void sst26_writedisable(struct sst26_dev_s *priv)
sstinfo("Disabled\n");
}
/************************************************************************************
/****************************************************************************
* Name: sst26_sectorerase (4k)
************************************************************************************/
****************************************************************************/
static void sst26_sectorerase(struct sst26_dev_s *priv, off_t sector, uint8_t type)
static void sst26_sectorerase(struct sst26_dev_s *priv,
off_t sector,
uint8_t type)
{
off_t offset;
@ -541,9 +559,9 @@ static void sst26_sectorerase(struct sst26_dev_s *priv, off_t sector, uint8_t ty
sstinfo("Erased\n");
}
/************************************************************************************
/****************************************************************************
* Name: sst26_chiperase
************************************************************************************/
****************************************************************************/
static inline int sst26_chiperase(struct sst26_dev_s *priv)
{
@ -571,9 +589,9 @@ static inline int sst26_chiperase(struct sst26_dev_s *priv)
return OK;
}
/************************************************************************************
/****************************************************************************
* Name: sst26_pagewrite
************************************************************************************/
****************************************************************************/
static inline void sst26_pagewrite(struct sst26_dev_s *priv,
FAR const uint8_t *buffer, off_t page)
@ -613,9 +631,9 @@ static inline void sst26_pagewrite(struct sst26_dev_s *priv,
sstinfo("Written\n");
}
/************************************************************************************
/****************************************************************************
* Name: sst26_bytewrite
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MTD_BYTE_WRITE
static inline void sst26_bytewrite(struct sst26_dev_s *priv,
@ -659,11 +677,13 @@ static inline void sst26_bytewrite(struct sst26_dev_s *priv,
/* Driver routines */
/************************************************************************************
/****************************************************************************
* Name: sst26_erase
************************************************************************************/
****************************************************************************/
static int sst26_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int sst26_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
FAR struct sst26_dev_s *priv = (FAR struct sst26_dev_s *)dev;
size_t blocksleft = nblocks;
@ -688,9 +708,9 @@ static int sst26_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nbloc
return (int)nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: sst26_bread
************************************************************************************/
****************************************************************************/
static ssize_t sst26_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buffer)
@ -700,9 +720,13 @@ static ssize_t sst26_bread(FAR struct mtd_dev_s *dev, off_t startblock,
sstinfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* On this device, we can handle the block read just like the byte-oriented
* read
*/
nbytes = sst26_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift,
nbytes = sst26_read(dev,
startblock << priv->pageshift,
nblocks << priv->pageshift,
buffer);
if (nbytes > 0)
{
@ -712,9 +736,9 @@ static ssize_t sst26_bread(FAR struct mtd_dev_s *dev, off_t startblock,
return (int)nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: sst26_bwrite
************************************************************************************/
****************************************************************************/
static ssize_t sst26_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer)
@ -739,12 +763,14 @@ static ssize_t sst26_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
return nblocks;
}
/************************************************************************************
/****************************************************************************
* Name: sst26_read
************************************************************************************/
****************************************************************************/
static ssize_t sst26_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR uint8_t *buffer)
static ssize_t sst26_read(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR uint8_t *buffer)
{
FAR struct sst26_dev_s *priv = (FAR struct sst26_dev_s *)dev;
@ -781,13 +807,15 @@ static ssize_t sst26_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: sst26_write
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t sst26_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
FAR const uint8_t *buffer)
static ssize_t sst26_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer)
{
FAR struct sst26_dev_s *priv = (FAR struct sst26_dev_s *)dev;
int startpage;
@ -857,9 +885,9 @@ static ssize_t sst26_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbyte
}
#endif /* CONFIG_MTD_BYTE_WRITE */
/************************************************************************************
/****************************************************************************
* Name: sst26_ioctl
************************************************************************************/
****************************************************************************/
static int sst26_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -876,13 +904,14 @@ static int sst26_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
(FAR struct mtd_geometry_s *)((uintptr_t)arg);
if (geo != NULL)
{
/* Populate the geometry structure with information need to know
* the capacity and how to access the device.
/* 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.
* 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);
@ -917,19 +946,19 @@ static int sst26_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: sst26_initialize
*
* Description:
* Create an initialize MTD device instance. MTD devices are not registered
* 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 *sst26_initialize_spi(FAR struct spi_dev_s *dev)
{
@ -941,8 +970,8 @@ FAR struct mtd_dev_s *sst26_initialize_spi(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct sst26_dev_s *)kmm_zalloc(sizeof(struct sst26_dev_s));
@ -972,7 +1001,9 @@ FAR struct mtd_dev_s *sst26_initialize_spi(FAR struct spi_dev_s *dev)
ret = sst26_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
ssterr("ERROR: Unrecognized\n");
kmm_free(priv);
@ -980,7 +1011,9 @@ FAR struct mtd_dev_s *sst26_initialize_spi(FAR struct spi_dev_s *dev)
}
else
{
/* Make sure that the FLASH is unprotected so that we can write into it */
/* Make sure that the FLASH is unprotected so that we can
* write into it
*/
sst26_writeenable(priv);
sst26_globalunlock(priv);

View file

@ -1,7 +1,7 @@
/************************************************************************************
/****************************************************************************
* drivers/mtd/w25.c
* Driver for SPI-based W25x16, x32, and x64 and W25q16, q32, q64, and q128 FLASH
* from Winbond (and work-alike parts from AMIC)
* Driver for SPI-based W25x16, x32, and x64 and W25q16, q32, q64, and q128
* FLASH from Winbond (and work-alike parts from AMIC)
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -18,11 +18,11 @@
* License for the specific language governing permissions and limitations
* under the License.
*
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -43,17 +43,18 @@
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/* Configuration ********************************************************************/
/* 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.
/* 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
@ -66,25 +67,25 @@
# define CONFIG_W25_SPIFREQUENCY 20000000
#endif
/* W25 Instructions *****************************************************************/
/* W25 Instructions *********************************************************/
#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 */
#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 ********************************************************************/
/* W25 Registers ************************************************************/
/* Read ID (RDID) register values */
@ -169,9 +170,11 @@
#define W25_DUMMY 0xa5
/* Chip Geometries ******************************************************************/
/* Chip Geometries **********************************************************/
/* All members of the family support uniform 4K-byte sectors and 256 byte pages */
/* 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 */
@ -203,13 +206,14 @@
#define CLR_DIRTY(p) do { (p)->flags &= ~W25_CACHE_DIRTY; } while (0)
#define CLR_ERASED(p) do { (p)->flags &= ~W25_CACHE_ERASED; } 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.
/* 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
@ -226,9 +230,9 @@ struct w25_dev_s
#endif
};
/************************************************************************************
/****************************************************************************
* Private Function Prototypes
************************************************************************************/
****************************************************************************/
/* Helpers */
@ -241,49 +245,71 @@ static void w25_unprotect(FAR struct w25_dev_s *priv);
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 bool w25_is_erased(struct w25_dev_s *priv, off_t address, off_t size);
static void w25_sectorerase(FAR struct w25_dev_s *priv, off_t offset);
static bool w25_is_erased(struct w25_dev_s *priv,
off_t address,
off_t size);
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);
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);
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);
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);
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);
#if defined(CONFIG_MTD_BYTE_WRITE) && !defined(CONFIG_W25_READONLY)
static ssize_t w25_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t w25_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer);
#endif
/************************************************************************************
/****************************************************************************
* Private Data
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: w25_lock
************************************************************************************/
****************************************************************************/
static void w25_lock(FAR struct spi_dev_s *spi)
{
@ -291,16 +317,18 @@ static void w25_lock(FAR struct spi_dev_s *spi)
* lock SPI to have exclusive access to the buses 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 exclusive access to
* the SPI bus. We will retain that exclusive access until the bus is unlocked.
* This is a blocking call and will not return until we have exclusive
* access to the SPI bus.
* We will retain that exclusive access until the bus is unlocked.
*/
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 bus is being shared, then it may have been left in an incompatible
* state.
/* 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 bus is being shared, then it may have been left in an
* incompatible state.
*/
SPI_SETMODE(spi, CONFIG_W25_SPIMODE);
@ -309,18 +337,18 @@ static void w25_lock(FAR struct spi_dev_s *spi)
SPI_SETFREQUENCY(spi, CONFIG_W25_SPIFREQUENCY);
}
/************************************************************************************
/****************************************************************************
* Name: w25_unlock
************************************************************************************/
****************************************************************************/
static inline void w25_unlock(FAR struct spi_dev_s *spi)
{
SPI_LOCK(spi, false);
}
/************************************************************************************
/****************************************************************************
* Name: w25_readid
************************************************************************************/
****************************************************************************/
static inline int w25_readid(struct w25_dev_s *priv)
{
@ -437,9 +465,9 @@ static inline int w25_readid(struct w25_dev_s *priv)
return -ENODEV;
}
/************************************************************************************
/****************************************************************************
* Name: w25_unprotect
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_W25_READONLY
static void w25_unprotect(FAR struct w25_dev_s *priv)
@ -476,18 +504,19 @@ static void w25_unprotect(FAR struct w25_dev_s *priv)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: w25_waitwritecomplete
************************************************************************************/
****************************************************************************/
static uint8_t w25_waitwritecomplete(struct w25_dev_s *priv)
{
uint8_t status;
/* Loop as long as the memory is busy with a write cycle. Device sets BUSY
* flag to a 1 state whhen previous write or erase command is still executing
* and during this time, device will ignore further instructions except for
* "Read Status Register" and "Erase/Program Suspend" instructions.
* flag to a 1 state whhen previous write or erase command is still
* executing and during this time, device will ignore further instructions
* except for "Read Status Register" and "Erase/Program Suspend"
* instructions.
*/
do
@ -500,7 +529,9 @@ static uint8_t w25_waitwritecomplete(struct w25_dev_s *priv)
SPI_SEND(priv->spi, W25_RDSR);
/* Send a dummy byte to generate the clock needed to shift out the status */
/* Send a dummy byte to generate the clock needed to shift out the
* status
*/
status = SPI_SEND(priv->spi, W25_DUMMY);
@ -508,11 +539,11 @@ static uint8_t w25_waitwritecomplete(struct w25_dev_s *priv)
SPI_SELECT(priv->spi, SPIDEV_FLASH(0), 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. Delay would slow down writing
* too much, so go to sleep only if previous operation was not a page program
* operation.
/* 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.
* Delay would slow down writing too much, so go to sleep only if
* previous operation was not a page program operation.
*/
if (priv->prev_instr != W25_PP && (status & W25_SR_BUSY) != 0)
@ -527,9 +558,9 @@ static uint8_t w25_waitwritecomplete(struct w25_dev_s *priv)
return status;
}
/************************************************************************************
/****************************************************************************
* Name: w25_wren
************************************************************************************/
****************************************************************************/
static inline void w25_wren(struct w25_dev_s *priv)
{
@ -546,9 +577,9 @@ static inline void w25_wren(struct w25_dev_s *priv)
SPI_SELECT(priv->spi, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: w25_wrdi
************************************************************************************/
****************************************************************************/
static inline void w25_wrdi(struct w25_dev_s *priv)
{
@ -565,9 +596,9 @@ static inline void w25_wrdi(struct w25_dev_s *priv)
SPI_SELECT(priv->spi, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: w25_is_erased
************************************************************************************/
****************************************************************************/
static bool w25_is_erased(struct w25_dev_s *priv, off_t address, off_t size)
{
@ -614,9 +645,9 @@ static bool w25_is_erased(struct w25_dev_s *priv, off_t address, off_t size)
return true;
}
/************************************************************************************
/****************************************************************************
* Name: w25_sectorerase
************************************************************************************/
****************************************************************************/
static void w25_sectorerase(struct w25_dev_s *priv, off_t sector)
{
@ -650,8 +681,8 @@ static void w25_sectorerase(struct w25_dev_s *priv, off_t sector)
SPI_SEND(priv->spi, W25_SE);
priv->prev_instr = W25_SE;
/* Send the sector address high byte first. Only the most significant bits (those
* corresponding to the sector) have any meaning.
/* Send the sector address high byte first. Only the most significant bits
* (those corresponding to the sector) have any meaning.
*/
SPI_SEND(priv->spi, (address >> 16) & 0xff);
@ -663,9 +694,9 @@ static void w25_sectorerase(struct w25_dev_s *priv, off_t sector)
SPI_SELECT(priv->spi, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: w25_chiperase
************************************************************************************/
****************************************************************************/
static inline int w25_chiperase(struct w25_dev_s *priv)
{
@ -695,9 +726,9 @@ static inline int w25_chiperase(struct w25_dev_s *priv)
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)
@ -750,9 +781,9 @@ static void w25_byteread(FAR struct w25_dev_s *priv, FAR uint8_t *buffer,
SPI_SELECT(priv->spi, SPIDEV_FLASH(0), false);
}
/************************************************************************************
/****************************************************************************
* Name: w25_pagewrite
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_W25_READONLY
static void w25_pagewrite(struct w25_dev_s *priv, FAR const uint8_t *buffer,
@ -810,13 +841,15 @@ static void w25_pagewrite(struct w25_dev_s *priv, FAR const uint8_t *buffer,
}
#endif
/************************************************************************************
/****************************************************************************
* Name: w25_bytewrite
************************************************************************************/
****************************************************************************/
#if defined(CONFIG_MTD_BYTE_WRITE) && !defined(CONFIG_W25_READONLY)
static inline void w25_bytewrite(struct w25_dev_s *priv, FAR const uint8_t *buffer,
off_t offset, uint16_t count)
static inline void w25_bytewrite(struct w25_dev_s *priv,
FAR const uint8_t *buffer,
off_t offset,
uint16_t count)
{
finfo("offset: %08lx count:%d\n", (long)offset, count);
@ -858,23 +891,24 @@ static inline void w25_bytewrite(struct w25_dev_s *priv, FAR const uint8_t *buff
}
#endif /* defined(CONFIG_MTD_BYTE_WRITE) && !defined(CONFIG_W25_READONLY) */
/************************************************************************************
/****************************************************************************
* 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.
* 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_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 */
@ -885,9 +919,9 @@ static void w25_cacheflush(struct w25_dev_s *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)
@ -896,9 +930,10 @@ static FAR uint8_t *w25_cacheread(struct w25_dev_s *priv, off_t sector)
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.
/* 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;
@ -927,7 +962,9 @@ static FAR uint8_t *w25_cacheread(struct w25_dev_s *priv, off_t sector)
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 */
/* Get the index to the 512 sector in the erase block that holds the
* argument
*/
index = sector & ((1 << shift) - 1);
@ -937,24 +974,24 @@ static FAR uint8_t *w25_cacheread(struct w25_dev_s *priv, off_t sector)
}
#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.
/* 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.
* 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))
@ -966,9 +1003,9 @@ static void w25_cacheerase(struct w25_dev_s *priv, off_t sector)
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).
/* 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);
@ -976,32 +1013,35 @@ static void w25_cacheerase(struct w25_dev_s *priv, off_t sector)
}
#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)
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.
/* 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.
* 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);
off_t esectno = sector >>
(W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT);
finfo("sector: %ld esectno: %d\n", sector, esectno);
w25_sectorerase(priv, esectno);
@ -1025,11 +1065,13 @@ static void w25_cachewrite(FAR struct w25_dev_s *priv, FAR const uint8_t *buffer
}
#endif
/************************************************************************************
/****************************************************************************
* Name: w25_erase
************************************************************************************/
****************************************************************************/
static int w25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
static int w25_erase(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks)
{
#ifdef CONFIG_W25_READONLY
return -EACESS
@ -1066,18 +1108,23 @@ static int w25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t 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)
static ssize_t w25_bread(FAR struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
FAR uint8_t *buffer)
{
ssize_t nbytes;
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
finfo("startblock: %08lx nblocks: %d\n",
(long)startblock, (int)nblocks);
/* On this device, we can handle the block read just like the byte-oriented read */
/* 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,
@ -1099,9 +1146,9 @@ static ssize_t w25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nbl
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)
@ -1129,12 +1176,14 @@ static ssize_t w25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
#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)
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;
@ -1150,12 +1199,14 @@ static ssize_t w25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
return nbytes;
}
/************************************************************************************
/****************************************************************************
* Name: w25_write
************************************************************************************/
****************************************************************************/
#if defined(CONFIG_MTD_BYTE_WRITE) && !defined(CONFIG_W25_READONLY)
static ssize_t w25_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
static ssize_t w25_write(FAR struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
FAR const uint8_t *buffer)
{
FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev;
@ -1222,9 +1273,9 @@ static ssize_t w25_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
}
#endif /* defined(CONFIG_MTD_BYTE_WRITE) && !defined(CONFIG_W25_READONLY) */
/************************************************************************************
/****************************************************************************
* Name: w25_ioctl
************************************************************************************/
****************************************************************************/
static int w25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
@ -1241,13 +1292,14 @@ static int w25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
(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.
/* 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.
* 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
@ -1289,19 +1341,19 @@ static int w25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
return ret;
}
/************************************************************************************
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Name: w25_initialize
*
* Description:
* Create an initialize MTD device instance. MTD devices are not registered
* 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)
{
@ -1313,8 +1365,8 @@ FAR struct mtd_dev_s *w25_initialize(FAR struct spi_dev_s *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(0) definition) and so would have
* to be extended to handle multiple FLASH parts on the same SPI bus.
* device (only because of the SPIDEV_FLASH(0) definition) and so would
* have to be extended to handle multiple FLASH parts on the same SPI bus.
*/
priv = (FAR struct w25_dev_s *)kmm_zalloc(sizeof(struct w25_dev_s));
@ -1344,7 +1396,9 @@ FAR struct mtd_dev_s *w25_initialize(FAR struct spi_dev_s *spi)
ret = w25_readid(priv);
if (ret != OK)
{
/* Unrecognized! Discard all of that work we just did and return NULL */
/* Unrecognized! Discard all of that work we just did and
* return NULL
*/
ferr("ERROR: Unrecognized\n");
kmm_free(priv);

File diff suppressed because it is too large Load diff