Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Alexander Dahl and committed by
Mark Brown
625de188 7a4b3ebf

+32 -4
+32 -4
drivers/spi/atmel-quadspi.c
··· 516 516 struct spi_controller *ctrl = spi->controller; 517 517 struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); 518 518 unsigned long clk_rate; 519 + u32 cs_inactive; 519 520 u32 cs_setup; 521 + u32 cs_hold; 520 522 int delay; 521 523 int ret; 522 - 523 - delay = spi_delay_to_ns(&spi->cs_setup, NULL); 524 - if (delay <= 0) 525 - return delay; 526 524 527 525 clk_rate = clk_get_rate(aq->pclk); 528 526 if (!clk_rate) 529 527 return -EINVAL; 530 528 529 + /* hold */ 530 + delay = spi_delay_to_ns(&spi->cs_hold, NULL); 531 + if (aq->mr & QSPI_MR_SMM) { 532 + if (delay > 0) 533 + dev_warn(&aq->pdev->dev, 534 + "Ignoring cs_hold, must be 0 in Serial Memory Mode.\n"); 535 + cs_hold = 0; 536 + } else { 537 + delay = spi_delay_to_ns(&spi->cs_hold, NULL); 538 + if (delay < 0) 539 + return delay; 540 + 541 + cs_hold = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 32000); 542 + } 543 + 544 + /* setup */ 545 + delay = spi_delay_to_ns(&spi->cs_setup, NULL); 546 + if (delay < 0) 547 + return delay; 548 + 531 549 cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 532 550 1000); 551 + 552 + /* inactive */ 553 + delay = spi_delay_to_ns(&spi->cs_inactive, NULL); 554 + if (delay < 0) 555 + return delay; 556 + cs_inactive = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 1000); 533 557 534 558 ret = pm_runtime_resume_and_get(ctrl->dev.parent); 535 559 if (ret < 0) ··· 562 538 aq->scr &= ~QSPI_SCR_DLYBS_MASK; 563 539 aq->scr |= QSPI_SCR_DLYBS(cs_setup); 564 540 atmel_qspi_write(aq->scr, aq, QSPI_SCR); 541 + 542 + aq->mr &= ~(QSPI_MR_DLYBCT_MASK | QSPI_MR_DLYCS_MASK); 543 + aq->mr |= QSPI_MR_DLYBCT(cs_hold) | QSPI_MR_DLYCS(cs_inactive); 544 + atmel_qspi_write(aq->mr, aq, QSPI_MR); 565 545 566 546 pm_runtime_mark_last_busy(ctrl->dev.parent); 567 547 pm_runtime_put_autosuspend(ctrl->dev.parent);