summaryrefslogtreecommitdiff
path: root/drivers/spi/atmel-quadspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/atmel-quadspi.c')
-rw-r--r--drivers/spi/atmel-quadspi.c134
1 files changed, 102 insertions, 32 deletions
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 4e9bfd26aa80..d7a3d85d00c2 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -63,6 +63,7 @@
#define SAMA7G5_QSPI0_MAX_SPEED_HZ 200000000
#define SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ 133000000
+#define SAM9X7_QSPI_MAX_SPEED_HZ 100000000
/* Bitfields in QSPI_CR (Control Register) */
#define QSPI_CR_QSPIEN BIT(0)
@@ -262,6 +263,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 +1031,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 +1065,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 +1109,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 +1484,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;
}
@@ -1602,17 +1628,48 @@ static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = {
.has_ricr = true,
};
+static const struct atmel_qspi_caps atmel_sam9x7_ospi_caps = {
+ .max_speed_hz = SAM9X7_QSPI_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .octal = true,
+ .has_dma = true,
+ .has_2xgclk = true,
+ .has_padcalib = false,
+ .has_dllon = false,
+};
+
+static const struct atmel_qspi_caps atmel_sama7d65_ospi_caps = {
+ .max_speed_hz = SAMA7G5_QSPI0_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .octal = true,
+ .has_dma = true,
+ .has_2xgclk = true,
+ .has_padcalib = true,
+ .has_dllon = false,
+};
+
+static const struct atmel_qspi_caps atmel_sama7d65_qspi_caps = {
+ .max_speed_hz = SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .has_dma = true,
+ .has_2xgclk = true,
+ .has_dllon = false,
+};
+
static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = {
.max_speed_hz = SAMA7G5_QSPI0_MAX_SPEED_HZ,
.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[] = {
@@ -1632,6 +1689,19 @@ static const struct of_device_id atmel_qspi_dt_ids[] = {
.compatible = "microchip,sama7g5-qspi",
.data = &atmel_sama7g5_qspi_caps,
},
+ {
+ .compatible = "microchip,sam9x7-ospi",
+ .data = &atmel_sam9x7_ospi_caps,
+ },
+ {
+ .compatible = "microchip,sama7d65-ospi",
+ .data = &atmel_sama7d65_ospi_caps,
+ },
+ {
+ .compatible = "microchip,sama7d65-qspi",
+ .data = &atmel_sama7d65_qspi_caps,
+ },
+
{ /* sentinel */ }
};