[PATCH v1 1/1] spi: spi-mt65xx: add cs timing support

Leilk.Liu leilk.liu at mediatek.com
Tue Jan 5 02:57:20 EST 2021


On Thu, 2020-12-31 at 17:57 +0800, Mason.Zhang at mediatek.com wrote:
> From: mtk22786 <Mason.Zhang at mediatek.com>
> 
> 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) {



More information about the linux-arm-kernel mailing list