mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 18:56:24 +00:00
spi: atmel-quadspi: Add cs_hold and cs_inactive setting support
spi-cs-inactive-delay-ns in dts is cs_inactive in spi core, and it maps to DLYCS (Minimum Inactive QCS Delay) in QSPI Mode Register (QSPI_MR). spi-cs-hold-delay-ns in dts is cs_hold in spi core, and it maps to DLYBCT (Delay Between Consecutive Transfers) in QSPI_MR. That one can be set to other values than 0 only if the chip is not in Serial Memory Mode (SMM), it must be written to '0' however when in SMM. Tested on SAM9X60 based board with FPGA implementing custom SPI Memory protocol. Signed-off-by: Alexander Dahl <ada@thorsis.com> Link: https://patch.msgid.link/20240918082744.379610-3-ada@thorsis.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
7a4b3ebf1d
commit
625de1881b
@ -516,21 +516,45 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi)
|
||||
struct spi_controller *ctrl = spi->controller;
|
||||
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
|
||||
unsigned long clk_rate;
|
||||
u32 cs_inactive;
|
||||
u32 cs_setup;
|
||||
u32 cs_hold;
|
||||
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;
|
||||
|
||||
/* hold */
|
||||
delay = spi_delay_to_ns(&spi->cs_hold, NULL);
|
||||
if (aq->mr & QSPI_MR_SMM) {
|
||||
if (delay > 0)
|
||||
dev_warn(&aq->pdev->dev,
|
||||
"Ignoring cs_hold, must be 0 in Serial Memory Mode.\n");
|
||||
cs_hold = 0;
|
||||
} else {
|
||||
delay = spi_delay_to_ns(&spi->cs_hold, NULL);
|
||||
if (delay < 0)
|
||||
return delay;
|
||||
|
||||
cs_hold = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 32000);
|
||||
}
|
||||
|
||||
/* setup */
|
||||
delay = spi_delay_to_ns(&spi->cs_setup, NULL);
|
||||
if (delay < 0)
|
||||
return delay;
|
||||
|
||||
cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)),
|
||||
1000);
|
||||
|
||||
/* inactive */
|
||||
delay = spi_delay_to_ns(&spi->cs_inactive, NULL);
|
||||
if (delay < 0)
|
||||
return delay;
|
||||
cs_inactive = 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;
|
||||
@ -539,6 +563,10 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi)
|
||||
aq->scr |= QSPI_SCR_DLYBS(cs_setup);
|
||||
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
|
||||
|
||||
aq->mr &= ~(QSPI_MR_DLYBCT_MASK | QSPI_MR_DLYCS_MASK);
|
||||
aq->mr |= QSPI_MR_DLYBCT(cs_hold) | QSPI_MR_DLYCS(cs_inactive);
|
||||
atmel_qspi_write(aq->mr, aq, QSPI_MR);
|
||||
|
||||
pm_runtime_mark_last_busy(ctrl->dev.parent);
|
||||
pm_runtime_put_autosuspend(ctrl->dev.parent);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user