The 23K256 and the 23LCV1024 are a 32 KiB and a 128 KiB serial SRAM on
an SPI bus, the larger one with battery backup, used as non volatile
scratch storage. Register them as an MTD device of type MTD_RAM, so the
mtd command reaches them. A command carries a two byte address on the
smaller part and a three byte one on the larger, which is what the per
compatible data holds.

Sequential operation, where a command transfers as many bytes as the
master clocks, is the mode the devices power up in. Select it during
probe, as nothing says which mode the device was left in by whoever
talked to it before, and in byte operation a command would carry a
single byte. The Linux driver does the same.

Erasing is not required for writing, so the driver sets mtd->_erase to
NULL and says MTD_NO_ERASE through MTD_CAP_RAM in the MTD flags.

Signed-off-by: Stefan Bigler <[email protected]>
Signed-off-by: Heiko Schocher <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---

Changes in v3:
- Named after the Linux driver and moved to
  drivers/mtd/devices/mchp23k256.c, with CONFIG_MTD_MCHP23K256 and the
  driver name mchp23k256. drivers/mtd/devices/ is new in U-Boot, it is
  where the related parts of the family would go (Simon)
- Added the microchip,mchp23k256 compatible, 32 KiB with a two byte
  address, so that the name covers what the driver does. The address
  width comes from the per compatible data
- spi_ram_xfer() dropped, the driver calls spi_write_then_read(), which
  does the same two transfers (Simon)
- The message and the comment in the probe claimed the device powers up
  in byte operation. The data sheet (DS25156A, section 2.5) gives
  sequential as the default, and the Linux driver writes the MODE
  register all the same (Simon)
- Removed two comments in probe. The reason for selecting sequential
  operation is in the commit message, and mtd->_erase is set to NULL
  explicitly (even if that is redundant), so it is obvious that there
  is no erase function
- did not add Simons comment about the single 128k comment in this
  patch, instead moved that to a new patch:
  mtd: mchp23k256: move the transfers to spi-mem
- Added Reviewed-by from Simon

Changes in v2:
Added comments from Simon:
- Moved from UCLASS_SPI_FLASH to UCLASS_MTD, the way the SPI NAND
  driver sits. The struct spi_nor shim and the dm_spi_flash_ops are
  gone with it, and the device is reached through the mtd command
  rather than sf.
- Moved from drivers/mtd/spi/ to drivers/mtd/, where the other
  standalone MTD drivers live.
- Dropped the erase operation. v1 filled the range with 0xff from a
  malloc'd buffer and claimed the bus once per 1 KB chunk. A RAM needs
  no erase, and patch 1 makes mtd_erase() answer -EOPNOTSUPP.
- Dropped the linux/mtd/spi-nor.h include, spi_flash.h pulled it in
  anyway and it advertised a NOR driver.
- sprintf() into a fixed field replaced by snprintf() into a buffer the
  driver owns.
- Copyright: dropped the trailing full stop and added Stefan Bigler's
  address.
fixed checkpatch warning:
- Added a MAINTAINERS entry, as the move out of drivers/mtd/spi/
  dropped a checkpatch warning.

 MAINTAINERS                      |   5 +
 configs/sandbox_defconfig        |   1 +
 drivers/mtd/Kconfig              |   2 +
 drivers/mtd/Makefile             |   1 +
 drivers/mtd/devices/Kconfig      |  17 +++
 drivers/mtd/devices/Makefile     |   3 +
 drivers/mtd/devices/mchp23k256.c | 200 +++++++++++++++++++++++++++++++
 7 files changed, 229 insertions(+)
 create mode 100644 drivers/mtd/devices/Kconfig
 create mode 100644 drivers/mtd/devices/Makefile
 create mode 100644 drivers/mtd/devices/mchp23k256.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 95b1f3b5ab3..5dc2067d1f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1663,6 +1663,11 @@ S:       Maintained
 T:     git 
https://git.u-boot-project.org/u-boot/custodians/u-boot-nand-flash.git
 F:     drivers/mtd/nand/spi/
 
+MICROCHIP 23K256/23LCV1024 SPI SRAM
+M:     Heiko Schocher <[email protected]>
+S:     Maintained
+F:     drivers/mtd/devices/mchp23k256.c
+
 SPI-NOR
 M:     Vignesh R <[email protected]>
 R:     Takahiro Kuwano <[email protected]>
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index a3fa5246082..728470bb0d2 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -265,6 +265,7 @@ CONFIG_MMC_SANDBOX=y
 CONFIG_MMC_SDHCI=y
 CONFIG_DM_MTD=y
 CONFIG_MTD_BLOCK=y
+CONFIG_MTD_MCHP23K256=y
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_MAX_NAND_DEVICE=8
 CONFIG_SYS_NAND_USE_FLASH_BBT=y
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index f6bd9f6f2e9..f4f0c58f2fe 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -248,6 +248,8 @@ config SYS_MAX_FLASH_BANKS_DETECT
          to reduce the effective number of flash bank, between 0 and
          CONFIG_SYS_MAX_FLASH_BANKS
 
+source "drivers/mtd/devices/Kconfig"
+
 source "drivers/mtd/nand/Kconfig"
 
 config SYS_NAND_MAX_OOBFREE
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index ce05e206073..80435729ad6 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -21,6 +21,7 @@ ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
 ifneq ($(mtd-y),)
 obj-y += mtd.o
 endif
+obj-$(CONFIG_MTD_MCHP23K256) += devices/
 obj-y += nand/
 obj-y += onenand/
 obj-y += spi/
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
new file mode 100644
index 00000000000..1b39382bcb9
--- /dev/null
+++ b/drivers/mtd/devices/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+config MTD_MCHP23K256
+       bool "Microchip 23K256 and 23LCV1024 SPI SRAM"
+       depends on DM_SPI && DM_MTD
+       help
+         Enable support for the Microchip 23K256 and 23LCV1024 serial SRAMs,
+         a 32 KiB and a 128 KiB SRAM on an SPI bus, the latter with battery
+         backup. The device is registered as an MTD device of type MTD_RAM,
+         so the mtd command reaches it.
+
+         Writing needs no erase, so the driver implements none and the MTD
+         flags say MTD_NO_ERASE. An erase request is answered with
+         -EOPNOTSUPP rather than silently doing nothing.
+
+         If unsure, say N
+
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
new file mode 100644
index 00000000000..e8404019cb6
--- /dev/null
+++ b/drivers/mtd/devices/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o
diff --git a/drivers/mtd/devices/mchp23k256.c b/drivers/mtd/devices/mchp23k256.c
new file mode 100644
index 00000000000..624fb9e65e1
--- /dev/null
+++ b/drivers/mtd/devices/mchp23k256.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip 23K256 and 23LCV1024 SPI SRAM
+ *
+ * Copyright (C) 2019 Stefan Bigler <[email protected]>
+ * Copyright (C) 2023 Heiko Schocher, DENX Software Engineering, [email protected]
+ * Copyright (C) 2026 Heiko Schocher, Nabla Software Engineering 
<[email protected]>
+ */
+
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <spi.h>
+#include <vsprintf.h>
+#include <linux/bitops.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sizes.h>
+
+/* Instruction set of the 23x series serial SRAMs */
+#define MCHP23K256_CMD_WRITE_STATUS    0x01
+#define MCHP23K256_CMD_WRITE           0x02
+#define MCHP23K256_CMD_READ            0x03
+
+/* MODE register, bits 7:6 select byte, page or sequential operation */
+#define MCHP23K256_MODE_SEQ            BIT(6)
+
+/* The widest address of the supported parts, in bytes */
+#define MCHP23K256_ADDR_MAX            3
+
+/**
+ * struct mchp23_caps - what one supported device looks like
+ *
+ * @size:      usable size of the array in bytes
+ * @addr_width:        width of the address a command carries, in bytes
+ */
+struct mchp23_caps {
+       u32 size;
+       u8 addr_width;
+};
+
+/**
+ * struct mchp23k256_priv - per device state
+ *
+ * @name:      MTD name, built from the technology and the sequence number
+ *             so that several of these can coexist
+ */
+struct mchp23k256_priv {
+       char name[16];
+};
+
+/**
+ * mchp23k256_command() - run one read or write command over the whole length
+ *
+ * Sequential operation was selected during probe, so the device serves a
+ * transfer of any length from a single command and the bus is claimed once.
+ *
+ * @dev:       the SRAM device
+ * @opcode:    MCHP23K256_CMD_READ or MCHP23K256_CMD_WRITE
+ * @offset:    byte offset into the array
+ * @data_out:  data to write, NULL when reading
+ * @data_in:   where to put data read, NULL when writing
+ * @len:       number of bytes to transfer
+ * Return: 0 on success, negative on error
+ */
+static int mchp23k256_command(struct udevice *dev, u8 opcode, u32 offset,
+                             const void *data_out, void *data_in, size_t len)
+{
+       const struct mchp23_caps *caps =
+               (const struct mchp23_caps *)dev_get_driver_data(dev);
+       struct spi_slave *spi = dev_get_parent_priv(dev);
+       u8 cmd[1 + MCHP23K256_ADDR_MAX];
+       uint i;
+       int ret;
+
+       cmd[0] = opcode;
+       for (i = 0; i < caps->addr_width; i++)
+               cmd[1 + i] = offset >> (8 * (caps->addr_width - i - 1));
+
+       ret = spi_claim_bus(spi);
+       if (ret) {
+               dev_dbg(dev, "failed to claim SPI bus: %d\n", ret);
+               return ret;
+       }
+
+       ret = spi_write_then_read(spi, cmd, 1 + caps->addr_width, data_out,
+                                 data_in, len);
+
+       spi_release_bus(spi);
+
+       return ret;
+}
+
+static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len,
+                          size_t *retlen, u_char *buf)
+{
+       int ret;
+
+       ret = mchp23k256_command(mtd->dev, MCHP23K256_CMD_READ, from, NULL,
+                                buf, len);
+       if (ret)
+               return ret;
+
+       *retlen = len;
+
+       return 0;
+}
+
+static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len,
+                           size_t *retlen, const u_char *buf)
+{
+       int ret;
+
+       ret = mchp23k256_command(mtd->dev, MCHP23K256_CMD_WRITE, to, buf,
+                                NULL, len);
+       if (ret)
+               return ret;
+
+       *retlen = len;
+
+       return 0;
+}
+
+static int mchp23k256_probe(struct udevice *dev)
+{
+       const struct mchp23_caps *caps =
+               (const struct mchp23_caps *)dev_get_driver_data(dev);
+       struct mtd_info *mtd = dev_get_uclass_priv(dev);
+       struct mchp23k256_priv *priv = dev_get_priv(dev);
+       struct spi_slave *spi = dev_get_parent_priv(dev);
+       u8 cmd[2];
+       int ret;
+
+       ret = spi_claim_bus(spi);
+       if (ret) {
+               dev_dbg(dev, "failed to claim SPI bus: %d\n", ret);
+               return ret;
+       }
+
+       cmd[0] = MCHP23K256_CMD_WRITE_STATUS;
+       cmd[1] = MCHP23K256_MODE_SEQ;
+       ret = spi_write_then_read(spi, cmd, sizeof(cmd), NULL, NULL, 0);
+
+       spi_release_bus(spi);
+
+       if (ret) {
+               dev_dbg(dev, "failed to select sequential operation: %d\n",
+                       ret);
+               return ret;
+       }
+
+       /*
+        * Name the MTD device after the technology, the way nand0 and
+        * spi-nor0 are named, not after the part.
+        */
+       snprintf(priv->name, sizeof(priv->name), "spi-ram%d", dev_seq(dev));
+       mtd->name = priv->name;
+       mtd->dev = dev;
+       mtd->type = MTD_RAM;
+       mtd->flags = MTD_CAP_RAM;
+       mtd->size = caps->size;
+       mtd->writesize = 1;
+       mtd->writebufsize = 1;
+
+       mtd->_read = mchp23k256_read;
+       mtd->_write = mchp23k256_write;
+       mtd->_erase = NULL;
+
+       return add_mtd_device(mtd);
+}
+
+static int mchp23k256_remove(struct udevice *dev)
+{
+       return del_mtd_device(dev_get_uclass_priv(dev));
+}
+
+static const struct mchp23_caps mchp23k256_caps = {
+       .size = SZ_32K,
+       .addr_width = 2,
+};
+
+static const struct mchp23_caps mchp23lcv1024_caps = {
+       .size = SZ_128K,
+       .addr_width = 3,
+};
+
+static const struct udevice_id mchp23k256_ids[] = {
+       { .compatible = "microchip,mchp23k256",
+         .data = (ulong)&mchp23k256_caps },
+       { .compatible = "microchip,mchp23lcv1024",
+         .data = (ulong)&mchp23lcv1024_caps },
+       { }
+};
+
+U_BOOT_DRIVER(mchp23k256) = {
+       .name           = "mchp23k256",
+       .id             = UCLASS_MTD,
+       .of_match       = mchp23k256_ids,
+       .probe          = mchp23k256_probe,
+       .remove         = mchp23k256_remove,
+       .priv_auto      = sizeof(struct mchp23k256_priv),
+};
-- 
2.55.0

Reply via email to