mirror of
https://github.com/apache/nuttx.git
synced 2026-08-09 22:45:08 +00:00
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:
parent
95adb15824
commit
2d8b193df4
24 changed files with 3804 additions and 2972 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue