apache / apache/nuttx

drivers: mtd: align spi and qspi

Open
#1,356 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
4k
Forks
1.7k
Avg merge
1d 17h
Merged PRs (30d)
237

Description

**Issue:**

Currently there's a misalignment in MTD drivers, where some drivers are written exclusively for QSPI interfaces, while others are using standard SPI. As you know, (nearly?) all QuadSPI controller implementations allows you to use QSPI in a standard SPI way, and opposite, all QSPI devices that I have seen (I've seen things you people wouldn't believe (C)) are able to operate in a standard SPI mode.

**Example:**

1. [n25qxxx driver](https://github.com/apache/incubator-nuttx/blob/master/drivers/mtd/n25qxxx.c) is using QSPI_* functions, which means currently it is impossible to use this particular driver with standard SPI interface, even though this NOR chip supports operation via standard SPI.

```c
static int n25qxxx_command_write(FAR struct qspi_dev_s *qspi, uint8_t cmd,
FAR const void *buffer, size_t buflen)
{
struct qspi_cmdinfo_s cmdinfo;

finfo("CMD: %02x buflen: %lu\n", cmd, (unsigned long)buflen);

cmdinfo.flags = QSPICMD_WRITEDATA;
cmdinfo.addrlen = 0;
cmdinfo.cmd = cmd;
cmdinfo.buflen = buflen;
cmdinfo.addr = 0;
cmdinfo.buffer = (FAR void *)buffer;

return QSPI_COMMAND(qspi, &cmdinfo);
}
```

2. [gd5f driver](https://github.com/apache/incubator-nuttx/blob/master/drivers/mtd/gd5f.c) is using SPI_* functions, which means currently it is impossible to use this particular driver with QSPI interface, even though this NAND chip supports QSPI.

```c
static bool gd5f_execute_write(FAR struct gd5f_dev_s *priv, uint32_t pageaddress)
{
const uint32_t row = pageaddress >> priv->pageshift;

/* Select this FLASH part */

SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->spi_devid), true);

/* Send the Program Execute instruction */

SPI_SEND(priv->dev, GD5F_PROGRAM_EXECUTE);
SPI_SEND(priv->dev, (row >> 16) & 0xff);
SPI_SEND(priv->dev, (row >> 8) & 0xff);
SPI_SEND(priv->dev, row & 0xff);

/* De-select the FLASH */

SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->spi_devid), false);

return gd5f_waitstatus(priv, GD5F_SR_P_FAIL, false);
}
```

**Solution:**

Ideally having some sort of a common `ops` structure that is initialized by SPI/QSPI/other_transport drivers, which then is used in MTD (and other) device drivers, by simply calling appropriate callbacks without caring what transport is being used. That's pretty much the same way how these kind of things are implemented in Linux kernel.

```c
struct spi_nor_controller_ops {
int (*prepare)(struct spi_nor *nor);
void (*unprepare)(struct spi_nor *nor);
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len);
int (*write_reg)(struct spi_nor *nor, u8 opcode, const u8 *buf,
size_t len);

ssize_t (*read)(struct spi_nor *nor, loff_t from, size_t len, u8 *buf);
ssize_t (*write)(struct spi_nor *nor, loff_t to, size_t len,
const u8 *buf);
int (*erase)(struct spi_nor *nor, loff_t offs);
};
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.