Thread (1 message) 1 message, 1 author, 2021-01-05

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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help