This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new bac870123f2 drivers/mtd: add MX66UW1G45G support
bac870123f2 is described below

commit bac870123f20226140602a3fa5ff0ddfe811f2a5
Author: Peter Barada <[email protected]>
AuthorDate: Fri Oct 9 14:49:49 2026 -0400

    drivers/mtd: add MX66UW1G45G support
    
    add an MTD driver for the Macronix MX66UW1G45G Octal SPI NOR flash.
    
    Signed-off-by: Peter Barada <[email protected]>
---
 .../os/drivers/special/mtd/devices/mx66uw1g45g.rst |  25 +
 drivers/mtd/CMakeLists.txt                         |   4 +
 drivers/mtd/Kconfig                                |  23 +
 drivers/mtd/Make.defs                              |   4 +
 drivers/mtd/mx66uw1g45g.c                          | 834 +++++++++++++++++++++
 include/nuttx/mtd/mtd.h                            |  12 +
 6 files changed, 902 insertions(+)

diff --git a/Documentation/os/drivers/special/mtd/devices/mx66uw1g45g.rst 
b/Documentation/os/drivers/special/mtd/devices/mx66uw1g45g.rst
new file mode 100644
index 00000000000..294ce95815e
--- /dev/null
+++ b/Documentation/os/drivers/special/mtd/devices/mx66uw1g45g.rst
@@ -0,0 +1,25 @@
+=====================
+MX66UW1G45G NOR Flash
+=====================
+
+NuttX provides support for the Octal SPI NOR flash MX66UW1G45G using QSPI
+and OPI transactions.
+
+Supported capacity is up to 1 Gbit (128 MB).
+
+The driver can be enabled by ``CONFIG_MTD_MX65UW1G45G`` option. It is possible
+to select the SPI mode with ``CONFIG_MX66UW1G45G_SPIMODE`` option and
+communication frequency with ``CONFIG_MMX66UW1G45G_QSPI_FREQUENCY`` option.
+
+As this is the first supported chip in the MX66UW family the size of
+flash is fixed at 1 Gbit.
+
+The flash memory has to be initialized before used. This is typically done
+from board support package layer during the board's bringup phase. This
+operation is performed by following function.
+
+.. code-block:: C
+
+   #include <nuttx/mtd/mtd.h>
+
+   FAR struct mtd_dev_s *mx66uw1g456_initialize_spi(FAR struct qspi_dev_s *dev)
diff --git a/drivers/mtd/CMakeLists.txt b/drivers/mtd/CMakeLists.txt
index 9c78ce21f91..116c53e3b5d 100644
--- a/drivers/mtd/CMakeLists.txt
+++ b/drivers/mtd/CMakeLists.txt
@@ -162,6 +162,10 @@ if(CONFIG_MTD)
     list(APPEND SRCS mx35.c)
   endif()
 
+  if(CONFIG_MTD_MX66UW1G45G)
+    list(APPEND SRCS mx66uw1g45g.c)
+  endif()
+
   if(CONFIG_MTD_S25FL1)
     list(APPEND SRCS s25fl1.c)
   endif()
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index dd74be9d005..bd45c7ef9b5 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -936,6 +936,29 @@ config MX25RXX_LXX
 
 endif # MTD_MX25RXX
 
+config MTD_MX66UW1G45G
+       bool "Macronix MX66UW1G45G XSPI flash"
+       default n
+       ---help---
+               Enable the MTD driver for the 1-Gbit Macronix MX66UW1G45G
+               OctaBus flash memory.  The driver uses the QSPI interface.
+
+if MTD_MX66UW1G45G
+
+config MX66UW1G45G_QSPIMODE
+       int "MX66UW1G45G QSPI mode"
+       default 0
+       ---help---
+               The MX66UW1G45G supports QSPI mode 0 or 3.
+
+config MX66UW1G45G_QSPI_FREQUENCY
+       int "MX66UW1G45G QSPI frequency"
+       default 75000000
+       ---help---
+               Clock frequency used for MX66UW1G45G transfers.
+
+endif # MTD_MX66UW1G45G
+
 config MTD_GD55
        bool "QuadSPI-based GigaDevices GD55 family FLASH"
        default n
diff --git a/drivers/mtd/Make.defs b/drivers/mtd/Make.defs
index ef41ed84c94..528210aa6eb 100644
--- a/drivers/mtd/Make.defs
+++ b/drivers/mtd/Make.defs
@@ -165,6 +165,10 @@ ifeq ($(CONFIG_MTD_MX35),y)
 CSRCS += mx35.c
 endif
 
+ifeq ($(CONFIG_MTD_MX66UW1G45G),y)
+CSRCS += mx66uw1g45g.c
+endif
+
 ifeq ($(CONFIG_MTD_S25FL1),y)
 CSRCS += s25fl1.c
 endif
diff --git a/drivers/mtd/mx66uw1g45g.c b/drivers/mtd/mx66uw1g45g.c
new file mode 100644
index 00000000000..d916bdb63d5
--- /dev/null
+++ b/drivers/mtd/mx66uw1g45g.c
@@ -0,0 +1,834 @@
+/****************************************************************************
+ * drivers/mtd/mx66uw1g45g.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 <nuttx/debug.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/fs/ioctl.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mtd/mtd.h>
+#include <nuttx/spi/qspi.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* SPI commands *************************************************************/
+
+#define MX66UW_RDID             0x9f
+#define MX66UW_RDSR             0x05
+#define MX66UW_WREN             0x06
+#define MX66UW_RDCR2            0x71
+#define MX66UW_WRCR2            0x72
+#define MX66UW_RSTEN            0x66
+#define MX66UW_RST              0x99
+
+/* Octal commands ***********************************************************/
+
+#define MX66UW_OCTA_READ        0xec13
+#define MX66UW_OCTA_PP          0x12ed
+#define MX66UW_OCTA_SE          0x21de
+#define MX66UW_OCTA_CE          0x609f
+#define MX66UW_OCTA_RDSR        0x05fa
+#define MX66UW_OCTA_WREN        0x06f9
+#define MX66UW_OCTA_RDCR2       0x718e
+#define MX66UW_OCTA_RSTEN       0x6699
+#define MX66UW_OCTA_RST         0x9966
+
+/* Registers ****************************************************************/
+
+#define MX66UW_SR_WIP           (1 << 0)
+#define MX66UW_SR_WEL           (1 << 1)
+
+#define MX66UW_CR2_MODE         0x00000000
+#define MX66UW_CR2_DUMMY        0x00000300
+#define MX66UW_CR2_SOPI         0x01
+#define MX66UW_CR2_DUMMY_6      0x07
+
+/* Geometry *****************************************************************/
+
+#define MX66UW_PAGE_SHIFT       8
+#define MX66UW_PAGE_SIZE        (1 << MX66UW_PAGE_SHIFT)
+#define MX66UW_SECTOR_SHIFT     12
+#define MX66UW_SECTOR_SIZE      (1 << MX66UW_SECTOR_SHIFT)
+#define MX66UW_NSECTORS         32768
+#define MX66UW_FLASH_SIZE       (MX66UW_SECTOR_SIZE * MX66UW_NSECTORS)
+#define MX66UW_ERASED_STATE     0xff
+
+/* Timing *******************************************************************/
+
+#define MX66UW_RESET_TIME_MS    100
+#define MX66UW_PAGE_TIME_MS     1000
+#define MX66UW_SUBSECTOR_TIME_MS 400
+#define MX66UW_BULK_TIME_MS     460000
+#define MX66UW_REGISTER_TIME_MS 40
+#define MX66UW_REG_DUMMY        4
+#define MX66UW_READ_DUMMY       6
+
+/* Identification ***********************************************************/
+
+#define MX66UW_MANUFACTURER     0xc2
+#define MX66UW_MEMORY_TYPE      0x81
+#define MX66UW_MEMORY_DENSITY   0x3b
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct mx66uw_dev_s
+{
+  struct mtd_dev_s mtd;
+  FAR struct qspi_dev_s *qspi;
+  bool sopi;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int mx66uw_erase(FAR struct mtd_dev_s *dev, off_t startblock,
+                        size_t nblocks);
+static ssize_t mx66uw_bread(FAR struct mtd_dev_s *dev, off_t startblock,
+                            size_t nblocks, FAR uint8_t *buffer);
+static ssize_t mx66uw_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
+                             size_t nblocks, FAR const uint8_t *buffer);
+static ssize_t mx66uw_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 mx66uw_write(FAR struct mtd_dev_s *dev, off_t offset,
+                            size_t nbytes, FAR const uint8_t *buffer);
+#endif
+static int mx66uw_ioctl(FAR struct mtd_dev_s *dev, int cmd,
+                        unsigned long arg);
+
+static int mx66uw_lock(FAR struct mx66uw_dev_s *priv);
+static void mx66uw_unlock(FAR struct mx66uw_dev_s *priv);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mx66uw_command
+ ****************************************************************************/
+
+static int mx66uw_command(FAR struct mx66uw_dev_s *priv,
+                          uint32_t instruction, bool octal, bool dtr)
+{
+  struct qspi_cmdinfo_s cmd;
+
+  cmd.flags   = (octal ? QSPICMD_IOCTAL : 0) |
+                (dtr ? QSPICMD_DTR : 0);
+  cmd.addrlen = 0;
+  cmd.cmd     = instruction;
+  cmd.buflen  = 0;
+  cmd.addr    = 0;
+  cmd.buffer  = NULL;
+
+  return QSPI_COMMAND(priv->qspi, &cmd);
+}
+
+/****************************************************************************
+ * Name: mx66uw_read_status
+ ****************************************************************************/
+
+static int mx66uw_read_status(FAR struct mx66uw_dev_s *priv,
+                              FAR uint8_t *status)
+{
+  struct qspi_meminfo_s mem;
+
+  mem.flags   = priv->sopi ? QSPIMEM_IOCTAL | QSPIMEM_OCTALIO : 0;
+  mem.addrlen = priv->sopi ? 4 : 0;
+  mem.dummies = priv->sopi ? MX66UW_REG_DUMMY : 0;
+  mem.cmd     = priv->sopi ? MX66UW_OCTA_RDSR : MX66UW_RDSR;
+  mem.buflen  = 1;
+  mem.addr    = 0;
+  mem.buffer  = status;
+
+  return QSPI_MEMORY(priv->qspi, &mem);
+}
+
+/****************************************************************************
+ * Name: mx66uw_wait_ready
+ ****************************************************************************/
+
+static int mx66uw_wait_ready(FAR struct mx66uw_dev_s *priv,
+                             unsigned int timeout)
+{
+  uint8_t status;
+  int retry;
+  int ret;
+
+  for (retry = 0; retry < timeout; retry++)
+    {
+      ret = mx66uw_read_status(priv, &status);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      if ((status & MX66UW_SR_WIP) == 0)
+        {
+          return OK;
+        }
+
+      up_mdelay(1);
+    }
+
+  return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: mx66uw_write_enable
+ ****************************************************************************/
+
+static int mx66uw_write_enable(FAR struct mx66uw_dev_s *priv)
+{
+  uint8_t status;
+  int ret;
+
+  ret = mx66uw_wait_ready(priv, MX66UW_PAGE_TIME_MS);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = mx66uw_command(priv,
+                       priv->sopi ? MX66UW_OCTA_WREN : MX66UW_WREN,
+                       priv->sopi, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = mx66uw_read_status(priv, &status);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return (status & MX66UW_SR_WEL) != 0 ? OK : -EACCES;
+}
+
+/****************************************************************************
+ * Name: mx66uw_reset
+ ****************************************************************************/
+
+static int mx66uw_reset(FAR struct mx66uw_dev_s *priv)
+{
+  int ret;
+
+  priv->sopi = false;
+  ret = mx66uw_command(priv, MX66UW_RSTEN, false, false);
+  if (ret == OK)
+    {
+      ret = mx66uw_command(priv, MX66UW_RST, false, false);
+    }
+
+  if (ret == OK)
+    {
+      ret = mx66uw_command(priv, MX66UW_OCTA_RSTEN, true, false);
+    }
+
+  if (ret == OK)
+    {
+      ret = mx66uw_command(priv, MX66UW_OCTA_RST, true, false);
+    }
+
+  if (ret == OK)
+    {
+      ret = mx66uw_command(priv, MX66UW_OCTA_RSTEN, true, true);
+    }
+
+  if (ret == OK)
+    {
+      ret = mx66uw_command(priv, MX66UW_OCTA_RST, true, true);
+    }
+
+  if (ret == OK)
+    {
+      up_mdelay(MX66UW_RESET_TIME_MS);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mx66uw_read_id
+ ****************************************************************************/
+
+static int mx66uw_read_id(FAR struct mx66uw_dev_s *priv)
+{
+  uint8_t id[3];
+  struct qspi_cmdinfo_s cmd;
+  int ret;
+
+  cmd.flags   = QSPICMD_READDATA;
+  cmd.addrlen = 0;
+  cmd.cmd     = MX66UW_RDID;
+  cmd.buflen  = sizeof(id);
+  cmd.addr    = 0;
+  cmd.buffer  = id;
+
+  ret = QSPI_COMMAND(priv->qspi, &cmd);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (id[0] != MX66UW_MANUFACTURER || id[1] != MX66UW_MEMORY_TYPE ||
+      id[2] != MX66UW_MEMORY_DENSITY)
+    {
+      return -ENODEV;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: mx66uw_write_cr2
+ ****************************************************************************/
+
+static int mx66uw_write_cr2(FAR struct mx66uw_dev_s *priv,
+                            uint32_t address, uint8_t value)
+{
+  struct qspi_cmdinfo_s cmd;
+  int ret;
+
+  cmd.flags   = QSPICMD_ADDRESS | QSPICMD_WRITEDATA;
+  cmd.addrlen = 4;
+  cmd.cmd     = MX66UW_WRCR2;
+  cmd.buflen  = 1;
+  cmd.addr    = address;
+  cmd.buffer  = &value;
+
+  ret = mx66uw_write_enable(priv);
+  return ret < 0 ? ret : QSPI_COMMAND(priv->qspi, &cmd);
+}
+
+/****************************************************************************
+ * Name: mx66uw_read_cr2
+ ****************************************************************************/
+
+static int mx66uw_read_cr2(FAR struct mx66uw_dev_s *priv,
+                           uint32_t address, FAR uint8_t *value)
+{
+  struct qspi_meminfo_s mem;
+
+  mem.flags   = priv->sopi ? QSPIMEM_IOCTAL | QSPIMEM_OCTALIO : 0;
+  mem.addrlen = 4;
+  mem.dummies = priv->sopi ? MX66UW_REG_DUMMY : 0;
+  mem.cmd     = priv->sopi ? MX66UW_OCTA_RDCR2 : MX66UW_RDCR2;
+  mem.buflen  = 1;
+  mem.addr    = address;
+  mem.buffer  = value;
+
+  return QSPI_MEMORY(priv->qspi, &mem);
+}
+
+/****************************************************************************
+ * Name: mx66uw_enter_sopi
+ ****************************************************************************/
+
+static int mx66uw_enter_sopi(FAR struct mx66uw_dev_s *priv)
+{
+  uint8_t value;
+  int ret;
+
+  ret = mx66uw_write_cr2(priv, MX66UW_CR2_DUMMY,
+                         MX66UW_CR2_DUMMY_6);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = mx66uw_wait_ready(priv, MX66UW_REGISTER_TIME_MS);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = mx66uw_write_cr2(priv, MX66UW_CR2_MODE, MX66UW_CR2_SOPI);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  up_mdelay(MX66UW_REGISTER_TIME_MS);
+  priv->sopi = true;
+
+  ret = mx66uw_wait_ready(priv, MX66UW_REGISTER_TIME_MS);
+  if (ret == OK)
+    {
+      ret = mx66uw_read_cr2(priv, MX66UW_CR2_MODE, &value);
+    }
+
+  if (ret == OK && value != MX66UW_CR2_SOPI)
+    {
+      ret = -EIO;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mx66uw_lock
+ ****************************************************************************/
+
+static int mx66uw_lock(FAR struct mx66uw_dev_s *priv)
+{
+  int ret;
+
+  ret = QSPI_LOCK(priv->qspi, true);
+  if (ret >= 0)
+    {
+      QSPI_SETMODE(priv->qspi, CONFIG_MX66UW1G45G_QSPIMODE);
+      QSPI_SETBITS(priv->qspi, 8);
+      QSPI_SETFREQUENCY(priv->qspi,
+                        CONFIG_MX66UW1G45G_QSPI_FREQUENCY);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mx66uw_unlock
+ ****************************************************************************/
+
+static void mx66uw_unlock(FAR struct mx66uw_dev_s *priv)
+{
+  QSPI_LOCK(priv->qspi, false);
+}
+
+/****************************************************************************
+ * Name: mx66uw_read_data
+ ****************************************************************************/
+
+static int mx66uw_read_data(FAR struct mx66uw_dev_s *priv,
+                            uint32_t address, FAR uint8_t *buffer,
+                            size_t buflen)
+{
+  struct qspi_meminfo_s mem;
+
+  mem.flags   = QSPIMEM_IOCTAL | QSPIMEM_OCTALIO;
+  mem.addrlen = 4;
+  mem.dummies = MX66UW_READ_DUMMY;
+  mem.cmd     = MX66UW_OCTA_READ;
+  mem.buflen  = buflen;
+  mem.addr    = address;
+  mem.buffer  = buffer;
+
+  return QSPI_MEMORY(priv->qspi, &mem);
+}
+
+/****************************************************************************
+ * Name: mx66uw_page_program
+ ****************************************************************************/
+
+static int mx66uw_page_program(FAR struct mx66uw_dev_s *priv,
+                               uint32_t address,
+                               FAR const uint8_t *buffer, size_t buflen)
+{
+  struct qspi_meminfo_s mem;
+  int ret;
+
+  mem.flags   = QSPIMEM_WRITE | QSPIMEM_IOCTAL | QSPIMEM_OCTALIO;
+  mem.addrlen = 4;
+  mem.dummies = 0;
+  mem.cmd     = MX66UW_OCTA_PP;
+  mem.buflen  = buflen;
+  mem.addr    = address;
+  mem.buffer  = (FAR void *)buffer;
+
+  ret = mx66uw_write_enable(priv);
+  if (ret == OK)
+    {
+      ret = QSPI_MEMORY(priv->qspi, &mem);
+    }
+
+  return ret < 0 ? ret : mx66uw_wait_ready(priv, MX66UW_PAGE_TIME_MS);
+}
+
+/****************************************************************************
+ * Name: mx66uw_sector_erase
+ ****************************************************************************/
+
+static int mx66uw_sector_erase(FAR struct mx66uw_dev_s *priv,
+                               uint32_t address)
+{
+  struct qspi_cmdinfo_s cmd;
+  int ret;
+
+  cmd.flags   = QSPICMD_ADDRESS | QSPICMD_IOCTAL | QSPICMD_OCTALIO;
+  cmd.addrlen = 4;
+  cmd.cmd     = MX66UW_OCTA_SE;
+  cmd.buflen  = 0;
+  cmd.addr    = address;
+  cmd.buffer  = NULL;
+
+  ret = mx66uw_write_enable(priv);
+  if (ret == OK)
+    {
+      ret = QSPI_COMMAND(priv->qspi, &cmd);
+    }
+
+  return ret < 0 ? ret :
+         mx66uw_wait_ready(priv, MX66UW_SUBSECTOR_TIME_MS);
+}
+
+/****************************************************************************
+ * Name: mx66uw_chip_erase
+ ****************************************************************************/
+
+static int mx66uw_chip_erase(FAR struct mx66uw_dev_s *priv)
+{
+  int ret;
+
+  ret = mx66uw_write_enable(priv);
+  if (ret == OK)
+    {
+      ret = mx66uw_command(priv, MX66UW_OCTA_CE, true, false);
+    }
+
+  return ret < 0 ? ret : mx66uw_wait_ready(priv, MX66UW_BULK_TIME_MS);
+}
+
+/****************************************************************************
+ * Name: mx66uw_erase
+ ****************************************************************************/
+
+static int mx66uw_erase(FAR struct mtd_dev_s *dev, off_t startblock,
+                        size_t nblocks)
+{
+  FAR struct mx66uw_dev_s *priv = (FAR struct mx66uw_dev_s *)dev;
+  size_t erased;
+  int ret;
+
+  if (startblock < 0 || startblock >= MX66UW_NSECTORS ||
+      nblocks > MX66UW_NSECTORS - startblock)
+    {
+      return -EINVAL;
+    }
+
+  ret = mx66uw_lock(priv);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (erased = 0; ret == OK && erased < nblocks; erased++)
+    {
+      ret = mx66uw_sector_erase(priv,
+                                (startblock + erased) <<
+                                MX66UW_SECTOR_SHIFT);
+    }
+
+  mx66uw_unlock(priv);
+  return ret < 0 ? ret : (int)erased;
+}
+
+/****************************************************************************
+ * Name: mx66uw_bread
+ ****************************************************************************/
+
+static ssize_t mx66uw_bread(FAR struct mtd_dev_s *dev, off_t startblock,
+                            size_t nblocks, FAR uint8_t *buffer)
+{
+  ssize_t ret;
+
+  ret = mx66uw_read(dev, startblock << MX66UW_PAGE_SHIFT,
+                    nblocks << MX66UW_PAGE_SHIFT, buffer);
+  return ret < 0 ? ret : (ssize_t)nblocks;
+}
+
+/****************************************************************************
+ * Name: mx66uw_bwrite
+ ****************************************************************************/
+
+static ssize_t mx66uw_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
+                             size_t nblocks, FAR const uint8_t *buffer)
+{
+  FAR struct mx66uw_dev_s *priv = (FAR struct mx66uw_dev_s *)dev;
+  size_t written;
+  int ret;
+
+  if (startblock < 0 || startblock >=
+      (MX66UW_FLASH_SIZE >> MX66UW_PAGE_SHIFT) ||
+      nblocks > (MX66UW_FLASH_SIZE >> MX66UW_PAGE_SHIFT) - startblock)
+    {
+      return -EINVAL;
+    }
+
+  ret = mx66uw_lock(priv);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (written = 0; ret == OK && written < nblocks; written++)
+    {
+      ret = mx66uw_page_program(priv,
+                                (startblock + written) <<
+                                MX66UW_PAGE_SHIFT,
+                                buffer + (written << MX66UW_PAGE_SHIFT),
+                                MX66UW_PAGE_SIZE);
+    }
+
+  mx66uw_unlock(priv);
+  return ret < 0 ? ret : (ssize_t)written;
+}
+
+/****************************************************************************
+ * Name: mx66uw_read
+ ****************************************************************************/
+
+static ssize_t mx66uw_read(FAR struct mtd_dev_s *dev, off_t offset,
+                           size_t nbytes, FAR uint8_t *buffer)
+{
+  FAR struct mx66uw_dev_s *priv = (FAR struct mx66uw_dev_s *)dev;
+  int ret;
+
+  if (offset < 0 || offset >= MX66UW_FLASH_SIZE ||
+      nbytes > MX66UW_FLASH_SIZE - offset)
+    {
+      return -EINVAL;
+    }
+
+  ret = mx66uw_lock(priv);
+  if (ret == OK)
+    {
+      ret = mx66uw_read_data(priv, offset, buffer, nbytes);
+      mx66uw_unlock(priv);
+    }
+
+  return ret < 0 ? ret : (ssize_t)nbytes;
+}
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+/****************************************************************************
+ * Name: mx66uw_write
+ ****************************************************************************/
+
+static ssize_t mx66uw_write(FAR struct mtd_dev_s *dev, off_t offset,
+                            size_t nbytes, FAR const uint8_t *buffer)
+{
+  FAR struct mx66uw_dev_s *priv = (FAR struct mx66uw_dev_s *)dev;
+  size_t pagesize;
+  size_t written;
+  int ret;
+
+  if (offset < 0 || offset >= MX66UW_FLASH_SIZE ||
+      nbytes > MX66UW_FLASH_SIZE - offset)
+    {
+      return -EINVAL;
+    }
+
+  ret = mx66uw_lock(priv);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (written = 0; ret == OK && written < nbytes; written += pagesize)
+    {
+      pagesize = MX66UW_PAGE_SIZE - ((offset + written) &
+                                     (MX66UW_PAGE_SIZE - 1));
+      if (pagesize > nbytes - written)
+        {
+          pagesize = nbytes - written;
+        }
+
+      ret = mx66uw_page_program(priv, offset + written,
+                                buffer + written, pagesize);
+    }
+
+  mx66uw_unlock(priv);
+  return ret < 0 ? ret : (ssize_t)written;
+}
+#endif
+
+/****************************************************************************
+ * Name: mx66uw_ioctl
+ ****************************************************************************/
+
+static int mx66uw_ioctl(FAR struct mtd_dev_s *dev, int cmd,
+                        unsigned long arg)
+{
+  FAR struct mx66uw_dev_s *priv = (FAR struct mx66uw_dev_s *)dev;
+  int ret = -ENOTTY;
+
+  switch (cmd)
+    {
+      case MTDIOC_GEOMETRY:
+        {
+          FAR struct mtd_geometry_s *geo =
+            (FAR struct mtd_geometry_s *)(uintptr_t)arg;
+
+          if (geo == NULL)
+            {
+              ret = -EINVAL;
+            }
+          else
+            {
+              geo->blocksize    = MX66UW_PAGE_SIZE;
+              geo->erasesize    = MX66UW_SECTOR_SIZE;
+              geo->neraseblocks = MX66UW_NSECTORS;
+              strlcpy(geo->model, "MX66UW1G45G", sizeof(geo->model));
+              ret = OK;
+            }
+        }
+        break;
+
+      case BIOC_PARTINFO:
+        {
+          FAR struct partition_info_s *info =
+            (FAR struct partition_info_s *)(uintptr_t)arg;
+
+          if (info == NULL)
+            {
+              ret = -EINVAL;
+            }
+          else
+            {
+              info->numsectors  = MX66UW_FLASH_SIZE / MX66UW_PAGE_SIZE;
+              info->sectorsize  = MX66UW_PAGE_SIZE;
+              info->startsector = 0;
+              info->parent[0]   = '\0';
+              ret = OK;
+            }
+        }
+        break;
+
+      case MTDIOC_BULKERASE:
+        ret = mx66uw_lock(priv);
+        if (ret == OK)
+          {
+            ret = mx66uw_chip_erase(priv);
+            mx66uw_unlock(priv);
+          }
+        break;
+
+      case MTDIOC_ERASESTATE:
+        {
+          FAR uint8_t *state = (FAR uint8_t *)(uintptr_t)arg;
+
+          if (state == NULL)
+            {
+              ret = -EINVAL;
+            }
+          else
+            {
+              *state = MX66UW_ERASED_STATE;
+              ret = OK;
+            }
+        }
+        break;
+
+      default:
+        break;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mx66uw1g45g_initialize
+ *
+ * Description:
+ *   Bind an MX66UW1G45G flash memory to an XSPI interface.
+ *
+ * Input Parameters:
+ *   qspi - QSPI interface
+ *
+ * Returned Value:
+ *   An MTD device on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+FAR struct mtd_dev_s *
+mx66uw1g45g_initialize(FAR struct qspi_dev_s *qspi)
+{
+  FAR struct mx66uw_dev_s *priv;
+  int ret;
+
+  if (qspi == NULL)
+    {
+      return NULL;
+    }
+
+  priv = kmm_zalloc(sizeof(*priv));
+  if (priv == NULL)
+    {
+      return NULL;
+    }
+
+  priv->mtd.erase  = mx66uw_erase;
+  priv->mtd.bread  = mx66uw_bread;
+  priv->mtd.bwrite = mx66uw_bwrite;
+  priv->mtd.read   = mx66uw_read;
+#ifdef CONFIG_MTD_BYTE_WRITE
+  priv->mtd.write  = mx66uw_write;
+#endif
+  priv->mtd.ioctl  = mx66uw_ioctl;
+  priv->mtd.name   = "mx66uw1g45g";
+  priv->qspi       = qspi;
+
+  ret = mx66uw_lock(priv);
+  if (ret < 0)
+    {
+      kmm_free(priv);
+      return NULL;
+    }
+
+  ret = mx66uw_reset(priv);
+  if (ret == OK)
+    {
+      ret = mx66uw_read_id(priv);
+    }
+
+  if (ret == OK)
+    {
+      ret = mx66uw_enter_sopi(priv);
+    }
+
+  mx66uw_unlock(priv);
+
+  if (ret < 0)
+    {
+      kmm_free(priv);
+      return NULL;
+    }
+
+  return &priv->mtd;
+}
diff --git a/include/nuttx/mtd/mtd.h b/include/nuttx/mtd/mtd.h
index e597f4c402d..e67b00a36ac 100644
--- a/include/nuttx/mtd/mtd.h
+++ b/include/nuttx/mtd/mtd.h
@@ -749,6 +749,18 @@ mx25uw25645g_initialize(FAR struct qspi_dev_s *qspi);
 FAR struct mtd_dev_s *n25qxxx_initialize(FAR struct qspi_dev_s *qspi,
                                          bool unprotect);
 
+/****************************************************************************
+ * Name: mx66uw1g45g_initialize
+ *
+ * Description:
+ *   Create an initialized MTD device instance for the QSPI-based
+ *   MX66U21G45G FLASH part.
+ *
+ ****************************************************************************/
+
+FAR struct mtd_dev_s *
+mx66uw1g45g_initialize(FAR struct qspi_dev_s *qspi);
+
 /****************************************************************************
  * Name: w25qxxxjv_initialize
  *

Reply via email to