xiaoxiang781216 commented on code in PR #11423: URL: https://github.com/apache/nuttx/pull/11423#discussion_r1433352237
########## drivers/mtd/at25ee.c: ########## @@ -0,0 +1,1033 @@ +/**************************************************************************** + * drivers/mtd/at25ee.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/kmalloc.h> +#include <nuttx/signal.h> +#include <nuttx/fs/ioctl.h> +#include <nuttx/spi/spi.h> +#include <nuttx/mtd/mtd.h> + +#ifdef CONFIG_MTD_AT25EE + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_AT25EE_SPIMODE +# define CONFIG_AT25EE_SPIMODE 0 +#endif + +/* EEPROM commands + * High bit of low nibble used for A8 in 25xx040/at25040 products + */ + +#define AT25EE_CMD_WRSR 0x01 +#define AT25EE_CMD_WRITE 0x02 +#define AT25EE_CMD_READ 0x03 +#define AT25EE_CMD_WRDIS 0x04 +#define AT25EE_CMD_RDSR 0x05 +#define AT25EE_CMD_WREN 0x06 + +/* Following commands will be available some day via IOCTLs + * PE 0x42 Page erase (25xx512/1024) + * SE 0xD8 Sector erase (25xx512/1024) + * CE 0xC7 Chip erase (25xx512/1024) + * RDID 0xAB Wake up and read electronic signature (25xx512/1024) + * DPD 0xB9 Sleep (25xx512/1024) + * + * Identification page access for ST devices + * RDID/RDLS 0x83 Read identification page / Read ID page lock status + * WRID/LID 0x82 Write identification page / Lock ID page + */ + +/* SR bits definitions */ + +#define AT25EE_SR_WIP 0x01 /* Write in Progress */ +#define AT25EE_SR_WEL 0x02 /* Write Enable Latch */ +#define AT25EE_SR_BP0 0x04 /* First Block Protect bit */ +#define AT25EE_SR_BP1 0x08 /* Second Block Protect bit */ +#define AT25EE_SR_WPEN 0x80 /* Write Protect Enable */ + +#define AT25EE_DUMMY 0xFF + +/* For applications where a file system is used on the AT25EE, the tiny page + * sizes will result in very inefficient EEPROM 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. + */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Device geometry description, compact form (2 bytes per entry) */ + +struct at25ee_geom_s +{ + uint8_t bytes : 4; /* Power of 2 of 128 bytes (0:128 1:256 2:512 etc) */ + uint8_t pagesize : 4; /* Power of 2 of 8 bytes (0:8 1:16 2:32 3:64 etc) */ + uint8_t addrlen : 4; /* Number of bytes in command address field */ + uint8_t flags : 4; /* Addr. management for 25xx040, 1=A8 in inst */ +}; + +/* 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 at25ee_dev_s. + */ + +struct at25ee_dev_s +{ + struct mtd_dev_s mtd; /* MTD interface */ + struct spi_dev_s *spi; /* SPI device where the EEPROM is attached */ + uint32_t size; /* in bytes, expanded from geometry */ + uint16_t pgsize; /* write block size, in bytes, expanded from + * geometry + */ + uint16_t npages; /* numpages, derived from geometry */ + uint16_t addrlen; /* number of BITS in data addresses */ + uint16_t blocksize; /* Block sized to report */ + mutex_t lock; /* file access serialization */ + uint8_t readonly; /* Flags */ + bool initd; /* True: The device has been initialize */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void at25ee_lock(FAR struct spi_dev_s *dev); + +/* MTD driver methods */ + +static int at25ee_erase(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks); +static ssize_t at25ee_bread(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, FAR uint8_t *buf); +static ssize_t at25ee_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR const uint8_t *buf); +static ssize_t at25ee_read(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR uint8_t *buf); +static ssize_t at25ee_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buf); +static int at25ee_ioctl(FAR struct mtd_dev_s *dev, int cmd, + unsigned long arg); +static void at25ee_writepage(FAR struct at25ee_dev_s *priv, uint32_t devaddr, + FAR const uint8_t *data, size_t len); +static void at25ee_writeenable(FAR struct at25ee_dev_s *priv, int enable); +static void at25ee_waitwritecomplete(struct at25ee_dev_s *priv); +static void at25ee_sendcmd(FAR struct spi_dev_s *spi, uint8_t cmd, + uint8_t addrlen, uint32_t addr); +static inline void at25ee_unlock(FAR struct spi_dev_s *dev); +static void at25ee_lock(FAR struct spi_dev_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Supported device geometries. + * One geometry can fit more than one device. + * The user will use an enum'd index from include/eeprom/spi_xx25xx.h + */ + +static const struct at25ee_geom_s g_at25ee_devices[] = +{ + /* Microchip devices */ + + { + 0, 1, 1, 0 + }, /* 25xx010A 128 16 1 */ + { + 1, 1, 1, 0 + }, /* 25xx020A 256 16 1 */ + { + 2, 1, 1, 1 + }, /* 25xx040 512 16 1+bit */ + { + 3, 1, 1, 0 + }, /* 25xx080 1024 16 1 */ + { + 3, 2, 2, 0 + }, /* 25xx080B 1024 32 2 */ + { + 4, 1, 2, 0 + }, /* 25xx160 2048 16 2 */ + { + 4, 2, 2, 0 + }, /* 25xx160B/D 2048 32 2 */ + { + 5, 2, 2, 0 + }, /* 25xx320 4096 32 2 */ + { + 6, 2, 2, 0 + }, /* 25xx640 8192 32 2 */ + { + 7, 3, 2, 0 + }, /* 25xx128 16384 64 2 */ + { + 8, 3, 2, 0 + }, /* 25xx256 32768 64 2 */ + { + 9, 4, 2, 0 + }, /* 25xx512 65536 128 2 */ + { + 10, 5, 3, 0 + }, /* 25xx1024 131072 256 3 */ + + /* Atmel devices */ + + { + 0, 0, 1, 0 + }, /* AT25010B 128 8 1 */ + { + 1, 0, 1, 0 + }, /* AT25020B 256 8 1 */ + { + 2, 0, 1, 1 + }, /* AT25040B 512 8 1+bit */ + + /* STM devices */ + + { + 11, 5, 3, 0 + }, /* M95M02 262144 256 3 */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at25ee_lock + * + * Description: + * 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. + * + * 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. + * + * Input Parameters: + * dev - pointer to device structure + * Returned Value: + * none + * + ****************************************************************************/ + +static void at25ee_lock(FAR struct spi_dev_s *dev) +{ + SPI_LOCK(dev, true); + SPI_SETMODE(dev, CONFIG_AT25EE_SPIMODE); + SPI_SETBITS(dev, 8); + SPI_HWFEATURES(dev, 0); + SPI_SETFREQUENCY(dev, CONFIG_AT25EE_SPIFREQUENCY); +#ifdef CONFIG_SPI_DELAY_CONTROL + SPI_SETDELAY(dev, CONFIG_AT25EE_START_DELAY, CONFIG_AT25EE_STOP_DELAY, + CONFIG_AT25EE_CS_DELAY, CONFIG_AT25EE_IFDELAY); +#endif +} + +/**************************************************************************** + * Name: at25ee_unlock + * + * Description: + * Unlocks the SPI bus + * + * Input Parameters: + * dev - pointer to device structure + * Returned Value: + * none + * + ****************************************************************************/ + +static inline void at25ee_unlock(FAR struct spi_dev_s *dev) +{ + SPI_LOCK(dev, false); +} + +/**************************************************************************** + * Name: at25ee_sendcmd + * + * Description: + * Send command and address as one transaction to take advantage + * of possible faster DMA transfers. + * Sending byte per byte is MUCH slower. + * + * Input Parameters: + * spi - a reference to the spi device + * cmd - SPI command to send + * addrlen - length of the address, in bits + * addr - address to write to + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void at25ee_sendcmd(FAR struct spi_dev_s *spi, uint8_t cmd, + uint8_t addrlen, uint32_t addr) +{ + uint8_t buf[4]; + int cmdlen = 1; + + /* Store command */ + + buf[0] = cmd; + + /* Store address according to its length */ + + if (addrlen == 9) + { + buf[0] |= (((addr >> 8) & 1) << 3); + } + + if (addrlen > 16) + { + buf[cmdlen++] = (addr >> 16) & 0xff; + } + + if (addrlen > 9) + { + buf[cmdlen++] = (addr >> 8) & 0xff; + } + + buf[cmdlen++] = addr & 0xff; + + SPI_SNDBLOCK(spi, buf, cmdlen); +} + +/**************************************************************************** + * Name: at25ee_waitwritecomplete + * + * Description: + * loop until the write operation is done. + * + * Input Parameters: + * priv - a reference to the device structure + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void at25ee_waitwritecomplete(struct at25ee_dev_s *priv) +{ + uint8_t status; + + /* Loop as long as the memory is busy with a write cycle */ + + do + { + /* Select this FLASH part */ + + at25ee_lock(priv->spi); + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), true); + + /* Send "Read Status Register (RDSR)" command */ + + SPI_SEND(priv->spi, AT25EE_CMD_RDSR); + + /* Send a dummy byte to generate the clock needed to shift out the + * status + */ + + status = SPI_SEND(priv->spi, AT25EE_DUMMY); + + /* Deselect the FLASH */ + + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), false); + at25ee_unlock(priv->spi); + + /* Given that writing could take up to a few milliseconds, + * the following short delay in the "busy" case will allow + * other peripherals to access the SPI bus. + */ + + if ((status & AT25EE_SR_WIP) != 0) + { + nxsig_usleep(1000); + } + } + while ((status & AT25EE_SR_WIP) != 0); +} + +/**************************************************************************** + * Name: at25ee_writeenable + * + * Description: + * Enable or disable write operations. + * This is required before any write, since a lot of operations + * automatically disable the write latch. + * + * Input Parameters: + * priv - a reference to the device structure + * enable - enable (true) or disable(false) write operations + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void at25ee_writeenable(FAR struct at25ee_dev_s *priv, int enable) +{ + at25ee_lock(priv->spi); + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), true); + + SPI_SEND(priv->spi, enable ? AT25EE_CMD_WREN : AT25EE_CMD_WRDIS); + + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), false); + at25ee_unlock(priv->spi); +} + +/**************************************************************************** + * Name: at25ee_writepage + * + * Description: + * Write data to the EEPROM, NOT crossing page boundaries. + * + * Input Parameters: + * priv - a reference to the device structure + * devaddr - the address to start the write + * data - pointer to data buffer to write + * len - length of the data to write + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void at25ee_writepage(FAR struct at25ee_dev_s *priv, uint32_t devaddr, + FAR const uint8_t *data, size_t len) +{ + at25ee_lock(priv->spi); + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), true); + + at25ee_sendcmd(priv->spi, AT25EE_CMD_WRITE, priv->addrlen, devaddr); + SPI_SNDBLOCK(priv->spi, data, len); + + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), false); + at25ee_unlock(priv->spi); +} + +/**************************************************************************** + * Name: at25ee_eraseall + * + * Description: + * Erase all data in the device + * + * Input Parameters: + * priv - a reference to the device structure + * devaddr - the address to start the write + * data - pointer to data buffer to write + * len - length of the data to write + * + * Returned Value: + * none + * + ****************************************************************************/ + +static int at25ee_eraseall(FAR struct at25ee_dev_s *priv) +{ + uint8_t *buf; + int startblock = 0; + + DEBUGASSERT(priv); + + buf = kmm_malloc(priv->pgsize); + if (!buf) + { + ferr("ERROR: Failed to alloc memory for at25ee eraseall!\n"); + return -ENOMEM; + } + + for (startblock = 0; startblock < priv->npages; startblock++) + { + uint16_t offset = startblock * priv->pgsize; + at25ee_write(&priv->mtd, offset, priv->pgsize, buf); + } + + kmm_free(buf); + return OK; +} + +/**************************************************************************** + * Name: at25ee_erase + * + * Description: + * Erase a number of blocks of data. + * NB - It is not necessary to erase data before writing with EEPROMs + * + * Input Parameters: + * dev - a reference to the device structure + * startblock - start block of the erase + * nblocks - nblocks to erase + * + * Returned Value: + * Success (OK) or fail (negated error code) + ****************************************************************************/ + +static int at25ee_erase(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks) +{ + return (int)nblocks; +} + +/**************************************************************************** + * Name: at25ee_read + * + * Description: + * Read a number of bytes of data. + * + * Input Parameters: + * dev - a reference to the device structure + * offset - start of the memory to read + * nbytes - number of bytes to read + * buffer - pointer to variable to store the read data + * + * Returned Value: + * Size of the data read + ****************************************************************************/ + +static ssize_t at25ee_read(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR uint8_t *buf) +{ + int ret; + FAR struct at25ee_dev_s *priv = (FAR struct at25ee_dev_s *)dev; + + DEBUGASSERT(buf); + DEBUGASSERT(dev); + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + if ((offset + nbytes) > priv->size) + { + return 0; /* end-of-file */ + } + + at25ee_lock(priv->spi); + + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), true); + + /* STM32F4Disco: There is a 25 us delay here */ + + at25ee_sendcmd(priv->spi, AT25EE_CMD_READ, priv->addrlen, offset); + + SPI_RECVBLOCK(priv->spi, buf, nbytes); + + SPI_SELECT(priv->spi, SPIDEV_EEPROM(0), false); + + at25ee_unlock(priv->spi); + + nxmutex_unlock(&priv->lock); + return nbytes; +} + +/**************************************************************************** + * Name: at25ee_write + * + * Description: + * Write a number of bytes of data. + * + * Input Parameters: + * dev - a reference to the device structure + * offset - start of the memory to write + * nbytes - number of bytes to write + * buf - pointer to buffer of data to write + * + * Returned Value: + * Size of the data written + ****************************************************************************/ + +static ssize_t at25ee_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buf) +{ + int ret = -EACCES; + FAR struct at25ee_dev_s *priv = (FAR struct at25ee_dev_s *)dev; + int pageoff; + size_t cnt; + + DEBUGASSERT(buf); + DEBUGASSERT(dev); + + if (priv->readonly) + { + return 0; + } + + /* Forbid writes past the end of the device */ + + if (nbytes + offset >= priv->size) + { + return 0; + } + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return 0; + } + + /* From this point no failure cannot be detected anymore. + * The user should verify the write by rereading memory. + */ + + ret = nbytes; /* save number of bytes written */ + + /* Writes can't happen in a row like the read does. + * The EEPROM is made of pages, and write sequences + * cannot cross page boundaries. So every time the last + * byte of a page is programmed, the SPI transaction is + * stopped, and the status register is read until the + * write operation has completed. + */ + + /* First, write some page-unaligned data */ + + pageoff = offset & (priv->pgsize - 1); + cnt = priv->pgsize - pageoff; + if (cnt > nbytes) + { + cnt = nbytes; + } + + if (pageoff > 0) + { + at25ee_writeenable(priv, true); + at25ee_writepage(priv, offset, buf, cnt); + at25ee_waitwritecomplete(priv); + nbytes -= cnt; + buf += cnt; + offset += cnt; + } + + /* Then, write remaining bytes at page-aligned addresses */ + + while (nbytes > 0) + { + cnt = nbytes; + if (cnt > priv->pgsize) + { + cnt = priv->pgsize; + } + + at25ee_writeenable(priv, true); + at25ee_writepage(priv, offset, buf, cnt); + at25ee_waitwritecomplete(priv); + nbytes -= cnt; + buf += cnt; + offset += cnt; + } + + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Name: at25ee_bread + * + * Description: + * Read a number of blocks of data. + * + * Input Parameters: + * dev - a reference to the device structure + * startblock - start block of the read + * nblocks - nblocks to read + * buf - pointer to variable to store the read data + * + * Returned Value: + * Number of blocks written + ****************************************************************************/ + +static ssize_t at25ee_bread(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, FAR uint8_t *buf) +{ + FAR struct at25ee_dev_s *priv = (FAR struct at25ee_dev_s *)dev; + off_t offset; + ssize_t nread; + size_t i; + + DEBUGASSERT(dev); + DEBUGASSERT(buf); + + if (priv->blocksize > priv->pgsize) + { + startblock *= (priv->blocksize / priv->pgsize); + nblocks *= (priv->blocksize / priv->pgsize); + } + + finfo("startblock: %08lx nblocks: %lu\n", + (unsigned long)startblock, (unsigned long)nblocks); + + if (startblock >= priv->npages) + { + return 0; + } + + if (startblock + nblocks > priv->npages) + { + nblocks = priv->npages - startblock; + } + + /* Convert the access from startblock and number of blocks to a byte + * offset and number of bytes. + */ + + offset = startblock * priv->pgsize; + + /* Then perform the byte-oriented read for each block separately */ + + for (i = 0; i < nblocks; i++) + { + nread = at25ee_read(dev, offset, priv->pgsize, buf); + if (nread < 0) + { + return nread; + } + + offset += priv->pgsize; + buf += priv->pgsize; + } + + if (priv->blocksize > priv->pgsize) + { + return nblocks / (priv->blocksize / priv->pgsize); + } + else + { + return nblocks; + } +} + +/**************************************************************************** + * Name: at25ee_bwrite + * + * Description: + * Write a number of blocks of data. + * + * Input Parameters: + * dev - a reference to the device structure + * startblock - starting block to write to + * nblocks - nblocks to write + * buf - pointer to data buffer to write + * + * Returned Value: + * Size of the data written + ****************************************************************************/ + +static ssize_t at25ee_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR const uint8_t *buf) +{ + FAR struct at25ee_dev_s *priv = (FAR struct at25ee_dev_s *)dev; + size_t blocksleft; + + DEBUGASSERT(dev); + DEBUGASSERT(buf); + +#if 1 + if (priv->blocksize > priv->pgsize) + { + startblock *= (priv->blocksize / priv->pgsize); + nblocks *= (priv->blocksize / priv->pgsize); + } +#endif + + blocksleft = nblocks; + + if (startblock >= priv->npages) + { + return 0; + } + + if (startblock + nblocks > priv->npages) + { + nblocks = priv->npages - startblock; + } + + finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + while (blocksleft-- > 0) + { + uint16_t offset = startblock * priv->pgsize; + + finfo("startblock: %08lx offset: %d\n", (long)startblock, offset); + at25ee_write(dev, offset, priv->pgsize, buf); + startblock++; + buf += priv->pgsize; + } + + if (priv->blocksize > priv->pgsize) + { + return nblocks / (priv->blocksize / priv->pgsize); + } + else + { + return nblocks; + } +} + +/**************************************************************************** + * Name: at25ee_ioctl + * * Description: + * IOCTLS relating to the EEPROM mtd device + * + * Input Parameters: + * dev - a reference to the device structure + * cmd - ioctl command + * arg - ioctl argument + * + * Returned Value: + * Success (OK) or fail (negated error code) + ****************************************************************************/ + +static int at25ee_ioctl(FAR struct mtd_dev_s *dev, + int cmd, + unsigned long arg) +{ + FAR struct at25ee_dev_s *priv = (FAR struct at25ee_dev_s *)dev; + int ret = -EINVAL; /* Assume good command with bad parameters */ + + DEBUGASSERT(dev); + + finfo("cmd: %d\n", cmd); + + switch (cmd) + { + case MTDIOC_GEOMETRY: + { + FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *) + ((uintptr_t)arg); + if (geo) + { + memset(geo, 0, sizeof(*geo)); + + /* Populate the geometry structure with information need to + * know the capacity and how to access the device. + * + * NOTE: + * that the device is treated as though it where just an array + * of fixed size blocks. + * That is most likely not true, but the client will expect the + * device logic to do whatever is necessary to make it appear + * so. + * + * blocksize: + * May be user defined. + * The block size for the at24XX devices may be larger than + * the page size in order to better support file systems. + * The read and write functions translate BLOCKS to pages + * for the small flash devices + * erasesize: + * It has to be at least as big as the blocksize, bigger + * serves no purpose. + * neraseblocks + * Note that the device size is in kilobits and must be + * scaled by 1024 / 8 + */ + + if (priv->blocksize > priv->pgsize) + { + geo->blocksize = priv->blocksize; + geo->erasesize = priv->blocksize; + geo->neraseblocks = priv->size / priv->blocksize; + } + else + { + geo->blocksize = priv->pgsize; + geo->erasesize = priv->pgsize; + geo->neraseblocks = priv->npages; + } + + ret = OK; + + finfo("blocksize: %" PRId32 " erasesize: %" PRId32 + " neraseblocks: %" PRId32 "\n", + geo->blocksize, geo->erasesize, geo->neraseblocks); + } + } + break; + + case BIOC_PARTINFO: + { + FAR struct partition_info_s *info = + (FAR struct partition_info_s *)arg; + if (info != NULL) + { + if (priv->blocksize > priv->pgsize) + { + info->numsectors = priv->size / priv->blocksize; + info->sectorsize = priv->blocksize; + } + else + { + info->numsectors = priv->npages; + info->sectorsize = priv->pgsize; + } + + info->startsector = 0; + info->parent[0] = '\0'; + ret = OK; + } + } + break; + + case MTDIOC_BULKERASE: + ret = at25ee_eraseall(priv); + break; + + default: + ret = -ENOTTY; /* Bad command */ + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at25ee_initialize + * + * Description: + * Create an initialized MTD device instance for an AT25 SPI EEPROM + * 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). + * + * Input Parameters: + * dev - a reference to the spi device structure + * devtype - device type, from include/nuttx/eeprom/spi_xx25xx.h + * readonly - sets block driver to be readonly + * + * Returned Value: + * Initialised device instance (success) or NULL (fail) + * + ****************************************************************************/ + +FAR struct mtd_dev_s *at25ee_initialize(FAR struct spi_dev_s *dev, + int devtype, int readonly) +{ + FAR struct at25ee_dev_s *priv; + + DEBUGASSERT(dev); + + /* Check device type early */ + + if ((devtype < 0) || + (devtype >= sizeof(g_at25ee_devices) / sizeof(g_at25ee_devices[0]))) + { + return NULL; + } + + priv = kmm_zalloc(sizeof(struct at25ee_dev_s)); + if (priv == NULL) + { + ferr("ERROR: Failed to allocate device structure\n"); + return NULL; + } + + if (!priv->initd) Review Comment: I mean initd is always zero at this check point. initd is redundant variable -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org