[PATCH 3/4] spi: atmel-quadspi: add LAN969x QSPI support

From: Robert Marko

Date: Wed Jul 08 2026 - 12:52:59 EST


Microchip LAN969x has two QSPI controllers based on SAMA7G5 QSPI.

It requires pad calibration, supports DMA, and supports 100 MHz operation.

Signed-off-by: Robert Marko <robert.marko@xxxxxxxxxx>
---
drivers/spi/Kconfig | 2 +-
drivers/spi/atmel-quadspi.c | 66 ++++++++++++++++++++++++++++++++++++-
2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8782514bb89b..bb3773f99ad9 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -189,7 +189,7 @@ config SPI_AT91_USART

config SPI_ATMEL_QUADSPI
tristate "Atmel Quad SPI Controller"
- depends on ARCH_AT91 || COMPILE_TEST
+ depends on ARCH_MICROCHIP || COMPILE_TEST
depends on OF && HAS_IOMEM
help
This enables support for the Quad SPI controller in master mode.
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index d1aec14e3978..f05e2617fa89 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -1152,6 +1152,58 @@ static int atmel_qspi_sama7g5_init(struct atmel_qspi *aq)
return ret;
}

+static int atmel_qspi_lan969x_init(struct atmel_qspi *aq)
+{
+ u32 val;
+ int ret;
+
+ atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_DLOCK), 40,
+ ATMEL_QSPI_TIMEOUT);
+ if (ret)
+ return ret;
+
+ ret = atmel_qspi_set_gclk(aq);
+ if (ret)
+ return ret;
+
+ /* Start the DLL before resetting the controller. */
+ atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ (val & QSPI_SR2_DLOCK) &&
+ !(val & QSPI_SR2_CALBSY), 40,
+ ATMEL_QSPI_TIMEOUT);
+ if (ret)
+ return ret;
+
+ atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+
+ atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+
+ ret = atmel_qspi_set_pad_calibration(aq);
+ if (ret)
+ return ret;
+
+ aq->mr = 0;
+ aq->scr = 0;
+
+ ret = atmel_qspi_set_serial_memory_mode(aq);
+ if (ret)
+ return ret;
+
+ atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+ return readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ (val & QSPI_SR2_QSPIENS), 40,
+ ATMEL_QSPI_TIMEOUT);
+}
+
static int atmel_qspi_sama7g5_setup(struct spi_device *spi)
{
struct atmel_qspi *aq = spi_controller_get_devdata(spi->controller);
@@ -1679,6 +1731,15 @@ static const struct atmel_qspi_caps atmel_sama7g5_qspi_caps = {
.has_dllon = true,
};

+static const struct atmel_qspi_caps atmel_lan969x_qspi_caps = {
+ .max_speed_hz = SAM9X7_QSPI_MAX_SPEED_HZ,
+ .init = atmel_qspi_lan969x_init,
+ .has_gclk = true,
+ .has_dma = true,
+ .has_padcalib = true,
+ .has_dllon = true,
+};
+
static const struct of_device_id atmel_qspi_dt_ids[] = {
{
.compatible = "atmel,sama5d2-qspi",
@@ -1708,7 +1769,10 @@ static const struct of_device_id atmel_qspi_dt_ids[] = {
.compatible = "microchip,sama7d65-qspi",
.data = &atmel_sama7d65_qspi_caps,
},
-
+ {
+ .compatible = "microchip,lan9691-qspi",
+ .data = &atmel_lan969x_qspi_caps,
+ },

{ /* sentinel */ }
};
--
2.55.0