TimJTi commented on code in PR #11423:
URL: https://github.com/apache/nuttx/pull/11423#discussion_r1433917123


##########
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);

Review Comment:
   Missing, accidentally deleted, memcpy. I recall, now, that I added a second 
buf to read back the erased memory to do a memcmp - like a verify - while I was 
developing this, so when removing that I must have deleted the memcpy oo. Doh!!



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to