diff options
author | Tudor Ambarus <tudor.ambarus@microchip.com> | 2022-11-17 12:52:45 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2022-11-18 11:57:11 +0000 |
commit | f732646d0ccd22f42ed7de5e59c0abb7a848e034 (patch) | |
tree | ee35f0fa0ad4c5fad6d02fa780f78f1e596b39ec /drivers/spi | |
parent | 684a47847ae639689e7b823251975348a8e5434f (diff) | |
download | lwn-f732646d0ccd22f42ed7de5e59c0abb7a848e034.tar.gz lwn-f732646d0ccd22f42ed7de5e59c0abb7a848e034.zip |
spi: atmel-quadspi: Add support for configuring CS timing
The at91 QSPI IP uses a default value of half of the period of the QSPI
clock period for the cs-setup time, which is not always enough, an example
being the sst26vf064b SPI NOR flash which requires a minimum cs-setup time
of 5 ns. It was observed that none of the at91 SoCs can fulfill the
minimum CS setup time for the aforementioned flash, as they operate at
high frequencies and half a period does not suffice for the required CS
setup time. Add support for configuring the CS timing in the controller.
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Link: https://lore.kernel.org/r/20221117105249.115649-5-tudor.ambarus@microchip.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/atmel-quadspi.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 976a217e356d..70637e46290a 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -510,6 +510,39 @@ static int atmel_qspi_setup(struct spi_device *spi) return 0; } +static int atmel_qspi_set_cs_timing(struct spi_device *spi) +{ + struct spi_controller *ctrl = spi->master; + struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); + unsigned long clk_rate; + u32 cs_setup; + int delay; + int ret; + + delay = spi_delay_to_ns(&spi->cs_setup, NULL); + if (delay <= 0) + return delay; + + clk_rate = clk_get_rate(aq->pclk); + if (!clk_rate) + return -EINVAL; + + cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), + 1000); + + ret = pm_runtime_resume_and_get(ctrl->dev.parent); + if (ret < 0) + return ret; + + aq->scr |= QSPI_SCR_DLYBS(cs_setup); + atmel_qspi_write(aq->scr, aq, QSPI_SCR); + + pm_runtime_mark_last_busy(ctrl->dev.parent); + pm_runtime_put_autosuspend(ctrl->dev.parent); + + return 0; +} + static void atmel_qspi_init(struct atmel_qspi *aq) { /* Reset the QSPI controller */ @@ -555,6 +588,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; ctrl->setup = atmel_qspi_setup; + ctrl->set_cs_timing = atmel_qspi_set_cs_timing; ctrl->bus_num = -1; ctrl->mem_ops = &atmel_qspi_mem_ops; ctrl->num_chipselect = 1; |