diff --git a/Documentation/os/drivers/special/mtd/index.rst b/Documentation/os/drivers/special/mtd/index.rst index 138a97e8634..e08beac8d78 100644 --- a/Documentation/os/drivers/special/mtd/index.rst +++ b/Documentation/os/drivers/special/mtd/index.rst @@ -312,3 +312,18 @@ NuttX provides support for the following MTD devices. :glob: devices/* + +RAMTRON SPI FRAM byte writes +=========================== + +With ``CONFIG_MTD_RAMTRON`` and ``CONFIG_MTD_BYTE_WRITE`` enabled, the +RAMTRON driver implements ``MTD_WRITE()`` for arbitrary byte offsets and +lengths. Writes need not align to the emulated block or erase geometry. +The callback returns the number of bytes written; requests outside the +physical device return ``-EINVAL``. A zero-length request within the +device, including its end offset, returns zero without SPI traffic. + +When ``CONFIG_RAMTRON_CHUNKING`` is enabled, writes to parts marked as +chunk-limited are split at their write-buffer boundaries. Each transfer +has its own write-enable and write-command sequence. Existing block-write +operations are unchanged. diff --git a/drivers/mtd/ramtron.c b/drivers/mtd/ramtron.c index 7045c561fab..4d26fd7ead9 100644 --- a/drivers/mtd/ramtron.c +++ b/drivers/mtd/ramtron.c @@ -431,6 +431,10 @@ static ssize_t ramtron_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 ramtron_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buffer); +#endif static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); @@ -844,6 +848,71 @@ static ssize_t ramtron_read(FAR struct mtd_dev_s *dev, return nbytes; } +/**************************************************************************** + * Name: ramtron_write + ****************************************************************************/ + +#ifdef CONFIG_MTD_BYTE_WRITE +static ssize_t ramtron_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buffer) +{ + FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev; + size_t remaining = nbytes; + size_t count; +#ifdef CONFIG_RAMTRON_CHUNKING + size_t available; +#endif + + /* Reject requests that could wrap around the physical device. */ + + if (offset < 0 || offset > priv->part->size || + nbytes > priv->part->size - (uint32_t)offset) + { + return -EINVAL; + } + + if (nbytes == 0) + { + return 0; + } + + DEBUGASSERT(buffer != NULL); + ramtron_lock(priv); + + while (remaining > 0) + { + count = remaining; +#ifdef CONFIG_RAMTRON_CHUNKING + if (priv->part->chunked) + { + /* Do not cross a write-buffer boundary on chunk-limited parts. */ + + available = priv->part->chunksize - + offset % priv->part->chunksize; + if (count > available) + { + count = available; + } + } +#endif + + ramtron_writeenable(priv); + SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->devid), true); + SPI_SEND(priv->dev, RAMTRON_WRITE); + ramtron_sendaddr(priv, offset); + SPI_SNDBLOCK(priv->dev, buffer, count); + SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->devid), false); + + offset += count; + buffer += count; + remaining -= count; + } + + ramtron_unlock(priv->dev); + return nbytes; +} +#endif + /**************************************************************************** * Name: ramtron_ioctl ****************************************************************************/ @@ -863,6 +932,7 @@ static int ramtron_ioctl(FAR struct mtd_dev_s *dev, { FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); + if (geo) { memset(geo, 0, sizeof(*geo)); @@ -892,6 +962,7 @@ static int ramtron_ioctl(FAR struct mtd_dev_s *dev, { FAR struct partition_info_s *info = (FAR struct partition_info_s *)arg; + if (info != NULL) { info->numsectors = priv->nsectors * @@ -975,6 +1046,9 @@ FAR struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *dev, priv->mtd.bread = ramtron_bread; priv->mtd.bwrite = ramtron_bwrite; priv->mtd.read = ramtron_read; +#ifdef CONFIG_MTD_BYTE_WRITE + priv->mtd.write = ramtron_write; +#endif priv->mtd.ioctl = ramtron_ioctl; priv->mtd.name = "ramtron"; priv->dev = dev;