From: Dharma Balasubiramani <dharma.b@microchip.com>
To: Mark Brown <broonie@kernel.org>, Rob Herring <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
"Nicolas Ferre" <nicolas.ferre@microchip.com>,
Alexandre Belloni <alexandre.belloni@bootlin.com>,
Claudiu Beznea <claudiu.beznea@tuxon.dev>,
Tudor Ambarus <tudor.ambarus@linaro.org>
Cc: <linux-spi@vger.kernel.org>, <devicetree@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>,
Dharma Balasubiramani <dharma.b@microchip.com>,
Varshini Rajendran <varshini.rajendran@microchip.com>
Subject: [PATCH 3/5] spi: atmel-quadspi: add padcalib, 2xgclk, and dllon capabilities
Date: Tue, 2 Sep 2025 11:22:20 +0530 [thread overview]
Message-ID: <20250902-microchip-qspi-v1-3-37af59a0406a@microchip.com> (raw)
In-Reply-To: <20250902-microchip-qspi-v1-0-37af59a0406a@microchip.com>
Introduce capability flags for SoC-specific variations of the QuadSPI
controller:
- has_padcalib: controller supports pad calibration
- has_2xgclk: requires GCLK at half the data rate (2x clocking)
- has_dllon: controller supports DLL clock
Set `has_padcalib` for Octal controllers that provide pad calibration
support. Use `has_2xgclk` for controllers that require the GCLK to run
at twice the data rate. Differentiate SoC integration variants with the
`has_dllon` flag and set it as needed.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
Signed-off-by: Dharma Balasubiramani <dharma.b@microchip.com>
---
drivers/spi/atmel-quadspi.c | 92 +++++++++++++++++++++++++++++----------------
1 file changed, 60 insertions(+), 32 deletions(-)
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 4e9bfd26aa80..83cea5faff78 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -262,6 +262,9 @@ struct atmel_qspi_caps {
bool has_ricr;
bool octal;
bool has_dma;
+ bool has_2xgclk;
+ bool has_padcalib;
+ bool has_dllon;
};
struct atmel_qspi_ops;
@@ -1027,13 +1030,25 @@ static int atmel_qspi_set_pad_calibration(struct atmel_qspi *aq)
aq, QSPI_PCALCFG);
/* DLL On + start calibration. */
- atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR);
+ if (aq->caps->has_dllon)
+ atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR);
+ /* If there is no DLL support only start calibration. */
+ else
+ atmel_qspi_write(QSPI_CR_STPCAL, aq, QSPI_CR);
- /* Check synchronization status before updating configuration. */
- ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
- (val & QSPI_SR2_DLOCK) &&
- !(val & QSPI_SR2_CALBSY), 40,
- ATMEL_QSPI_TIMEOUT);
+ /*
+ * Check DLL clock lock and synchronization status before updating
+ * configuration.
+ */
+ if (aq->caps->has_dllon)
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ (val & QSPI_SR2_DLOCK) &&
+ !(val & QSPI_SR2_CALBSY), 40,
+ ATMEL_QSPI_TIMEOUT);
+ else
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_CALBSY), 40,
+ ATMEL_QSPI_TIMEOUT);
/* Refresh analogic blocks every 1 ms.*/
atmel_qspi_write(FIELD_PREP(QSPI_REFRESH_DELAY_COUNTER,
@@ -1049,23 +1064,28 @@ static int atmel_qspi_set_gclk(struct atmel_qspi *aq)
int ret;
/* Disable DLL before setting GCLK */
- status = atmel_qspi_read(aq, QSPI_SR2);
- if (status & QSPI_SR2_DLOCK) {
- atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR);
+ if (aq->caps->has_dllon) {
+ status = atmel_qspi_read(aq, QSPI_SR2);
+ if (status & QSPI_SR2_DLOCK) {
+ 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 = readl_poll_timeout(aq->regs + QSPI_SR2, val,
- !(val & QSPI_SR2_DLOCK), 40,
- ATMEL_QSPI_TIMEOUT);
- if (ret)
- return ret;
+ if (aq->target_max_speed_hz > QSPI_DLLCFG_THRESHOLD_FREQ)
+ atmel_qspi_write(QSPI_DLLCFG_RANGE, aq, QSPI_DLLCFG);
+ else
+ atmel_qspi_write(0, aq, QSPI_DLLCFG);
}
- if (aq->target_max_speed_hz > QSPI_DLLCFG_THRESHOLD_FREQ)
- atmel_qspi_write(QSPI_DLLCFG_RANGE, aq, QSPI_DLLCFG);
+ if (aq->caps->has_2xgclk)
+ ret = clk_set_rate(aq->gclk, 2 * aq->target_max_speed_hz);
else
- atmel_qspi_write(0, aq, QSPI_DLLCFG);
+ ret = clk_set_rate(aq->gclk, aq->target_max_speed_hz);
- ret = clk_set_rate(aq->gclk, aq->target_max_speed_hz);
if (ret) {
dev_err(&aq->pdev->dev, "Failed to set generic clock rate.\n");
return ret;
@@ -1088,11 +1108,16 @@ static int atmel_qspi_sama7g5_init(struct atmel_qspi *aq)
if (ret)
return ret;
- if (aq->caps->octal) {
+ /*
+ * Check if the SoC supports pad calibration in Octal SPI mode.
+ * Proceed only if both the capabilities are true.
+ */
+ if (aq->caps->octal && aq->caps->has_padcalib) {
ret = atmel_qspi_set_pad_calibration(aq);
if (ret)
return ret;
- } else {
+ /* Start DLL on only if the SoC supports the same */
+ } else if (aq->caps->has_dllon) {
atmel_qspi_write(QSPI_CR_DLLON, aq, QSPI_CR);
ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
(val & QSPI_SR2_DLOCK), 40,
@@ -1458,19 +1483,19 @@ static int atmel_qspi_sama7g5_suspend(struct atmel_qspi *aq)
clk_disable_unprepare(aq->gclk);
- 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 = readl_poll_timeout(aq->regs + QSPI_SR2, val,
- !(val & QSPI_SR2_CALBSY), 40,
- ATMEL_QSPI_TIMEOUT);
- if (ret)
- return ret;
+ if (aq->caps->has_dllon) {
+ 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;
+ }
+ if (aq->caps->has_padcalib)
+ return readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_CALBSY), 40,
+ ATMEL_QSPI_TIMEOUT);
return 0;
}
@@ -1607,12 +1632,15 @@ static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = {
.has_gclk = true,
.octal = true,
.has_dma = true,
+ .has_padcalib = true,
+ .has_dllon = true,
};
static const struct atmel_qspi_caps atmel_sama7g5_qspi_caps = {
.max_speed_hz = SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ,
.has_gclk = true,
.has_dma = true,
+ .has_dllon = true,
};
static const struct of_device_id atmel_qspi_dt_ids[] = {
--
2.43.0
next prev parent reply other threads:[~2025-09-02 5:53 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-02 5:52 [PATCH 0/5] Add QSPI support for sam9x7 and sama7d65 SoCs Dharma Balasubiramani
2025-09-02 5:52 ` [PATCH 1/5] spi: atmel,quadspi: Document sam9x7 QSPI Dharma Balasubiramani
2025-09-02 9:21 ` Krzysztof Kozlowski
2025-09-02 9:22 ` Krzysztof Kozlowski
2025-09-02 5:52 ` [PATCH 2/5] spi: atmel,quadspi: Define sama7d65 QSPI Dharma Balasubiramani
2025-09-02 5:52 ` Dharma Balasubiramani [this message]
2025-09-02 5:52 ` [PATCH 4/5] spi: atmel-quadspi: add support for SAM9X7 QSPI controller Dharma Balasubiramani
2025-09-02 5:52 ` [PATCH 5/5] spi: atmel-quadspi: Add support for sama7d65 QSPI Dharma Balasubiramani
2025-09-02 11:08 ` [PATCH 0/5] Add QSPI support for sam9x7 and sama7d65 SoCs Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250902-microchip-qspi-v1-3-37af59a0406a@microchip.com \
--to=dharma.b@microchip.com \
--cc=alexandre.belloni@bootlin.com \
--cc=broonie@kernel.org \
--cc=claudiu.beznea@tuxon.dev \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-spi@vger.kernel.org \
--cc=nicolas.ferre@microchip.com \
--cc=robh@kernel.org \
--cc=tudor.ambarus@linaro.org \
--cc=varshini.rajendran@microchip.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).