Re: [PATCH v1 1/1] spi: spi-mt65xx: add cs timing support
From: Leilk.Liu <hidden>
Date: 2021-01-05 07:59:52
Also in:
linux-arm-kernel
On Thu, 2020-12-31 at 17:57 +0800, Mason.Zhang@mediatek.com wrote:
quoted hunk
From: mtk22786 <redacted> spi user can set cs_setup, cs_hold, cs_inactive by call function: spi_set_cs_timing. If user have not call this, spi master will use default cs timing. Change-Id: I0189bab9a066d384e1f265846dac46816bf4561c Signed-off-by: Mason.Zhang --- drivers/spi/spi-mt65xx.c | 74 ++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 11 deletions(-)diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 5d643051bf3d..23d94eb9a465 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c@@ -284,11 +284,38 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable) } } +static int mtk_set_cs_timing(struct spi_device *spi, + struct spi_delay *setup, + struct spi_delay *hold, + struct spi_delay *inactive) +{ + u32 len = sizeof(struct spi_delay); + + if (setup) + memcpy(&spi->controller->cs_setup, setup, len); + else + memset(&spi->controller->cs_setup, 0, len); + + if (hold) + memcpy(&spi->controller->cs_hold, hold, len); + else + memset(&spi->controller->cs_hold, 0, len); + + if (inactive) + memcpy(&spi->controller->cs_inactive, inactive, len); + else + memset(&spi->controller->cs_inactive, 0, len); + + return 0; +} + static void mtk_spi_prepare_transfer(struct spi_master *master, - struct spi_transfer *xfer) + struct spi_transfer *xfer, struct spi_device *spi) { - u32 spi_clk_hz, div, sck_time, cs_time, reg_val; + u32 spi_clk_hz, div, sck_time, cs_time, reg_val, delay = 0; struct mtk_spi *mdata = spi_master_get_devdata(master); + u32 cs_setuptime, cs_holdtime, cs_idletime = 0; + u32 clk_period_ns = 0; spi_clk_hz = clk_get_rate(mdata->spi_clk); if (xfer->speed_hz < spi_clk_hz / 2)@@ -297,31 +324,55 @@ static void mtk_spi_prepare_transfer(struct spi_master *master, div = 1; sck_time = (div + 1) / 2; + /* set default cs timing */ cs_time = sck_time * 2; + clk_period_ns = 1000000000 / xfer->speed_hz; + + delay = spi_delay_to_ns(&master->cs_setup, xfer); + cs_setuptime = delay / clk_period_ns; + + delay = spi_delay_to_ns(&master->cs_hold, xfer); + cs_holdtime = delay / clk_period_ns; + + delay = spi_delay_to_ns(&master->cs_inactive, xfer); + cs_idletime = delay / clk_period_ns; + + if (cs_setuptime < cs_time) + cs_setuptime = cs_time; + + if (cs_holdtime < cs_time) + cs_holdtime = cs_time; + + if (cs_idletime < cs_time) + cs_idletime = cs_time; + if (mdata->dev_comp->enhance_timing) { reg_val = (((sck_time - 1) & 0xffff) << SPI_CFG2_SCK_HIGH_OFFSET); reg_val |= (((sck_time - 1) & 0xffff) << SPI_CFG2_SCK_LOW_OFFSET); writel(reg_val, mdata->base + SPI_CFG2_REG); - reg_val = (((cs_time - 1) & 0xffff) + reg_val = (((cs_holdtime - 1) & 0xffff) << SPI_ADJUST_CFG0_CS_HOLD_OFFSET); - reg_val |= (((cs_time - 1) & 0xffff) + reg_val |= (((cs_setuptime - 1) & 0xffff) << SPI_ADJUST_CFG0_CS_SETUP_OFFSET); writel(reg_val, mdata->base + SPI_CFG0_REG); } else { reg_val = (((sck_time - 1) & 0xff) - << SPI_CFG0_SCK_HIGH_OFFSET); - reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET); - reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET); - reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET); + << SPI_CFG0_SCK_HIGH_OFFSET); + reg_val |= (((sck_time - 1) & 0xff) + << SPI_CFG0_SCK_LOW_OFFSET); + reg_val |= (((cs_holdtime - 1) & 0xff) + << SPI_CFG0_CS_HOLD_OFFSET); + reg_val |= (((cs_setuptime - 1) & 0xff) + << SPI_CFG0_CS_SETUP_OFFSET); writel(reg_val, mdata->base + SPI_CFG0_REG); } reg_val = readl(mdata->base + SPI_CFG1_REG); reg_val &= ~SPI_CFG1_CS_IDLE_MASK; - reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET); + reg_val |= (((cs_idletime - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET); writel(reg_val, mdata->base + SPI_CFG1_REG); }@@ -430,7 +481,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, mdata->cur_transfer = xfer; mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len); mdata->num_xfered = 0; - mtk_spi_prepare_transfer(master, xfer); + mtk_spi_prepare_transfer(master, xfer, spi); mtk_spi_setup_packet(master); cnt = xfer->len / 4;@@ -462,7 +513,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master, mdata->cur_transfer = xfer; mdata->num_xfered = 0; - mtk_spi_prepare_transfer(master, xfer); + mtk_spi_prepare_transfer(master, xfer, spi); cmd = readl(mdata->base + SPI_CMD_REG); if (xfer->tx_buf)@@ -644,6 +695,7 @@ static int mtk_spi_probe(struct platform_device *pdev) master->transfer_one = mtk_spi_transfer_one; master->can_dma = mtk_spi_can_dma; master->setup = mtk_spi_setup; + master->set_cs_timing = mtk_set_cs_timing;
while add set_cs_timing callback, this driver can't support multiple devices on one bus(use "cs-gpios" property) with gpio cs timing.
of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
if (!of_id) {_______________________________________________ Linux-mediatek mailing list Linux-mediatek@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-mediatek