diff options
Diffstat (limited to 'drivers/spi/spi-stm32.c')
| -rw-r--r-- | drivers/spi/spi-stm32.c | 119 | 
1 files changed, 72 insertions, 47 deletions
| diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 4c643dfc7fbb..2cc850eb8922 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -13,6 +13,7 @@  #include <linux/iopoll.h>  #include <linux/module.h>  #include <linux/of_platform.h> +#include <linux/pinctrl/consumer.h>  #include <linux/pm_runtime.h>  #include <linux/reset.h>  #include <linux/spi/spi.h> @@ -441,7 +442,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,  {  	u32 div, mbrdiv; -	div = DIV_ROUND_UP(spi->clk_rate, speed_hz); +	/* Ensure spi->clk_rate is even */ +	div = DIV_ROUND_UP(spi->clk_rate & ~0x1, speed_hz);  	/*  	 * SPI framework set xfer->speed_hz to master->max_speed_hz if @@ -467,20 +469,27 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,  /**   * stm32h7_spi_prepare_fthlv - Determine FIFO threshold level   * @spi: pointer to the spi controller data structure + * @xfer_len: length of the message to be transferred   */ -static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) +static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len)  { -	u32 fthlv, half_fifo; +	u32 fthlv, half_fifo, packet;  	/* data packet should not exceed 1/2 of fifo space */  	half_fifo = (spi->fifo_size / 2); +	/* data_packet should not exceed transfer length */ +	if (half_fifo > xfer_len) +		packet = xfer_len; +	else +		packet = half_fifo; +  	if (spi->cur_bpw <= 8) -		fthlv = half_fifo; +		fthlv = packet;  	else if (spi->cur_bpw <= 16) -		fthlv = half_fifo / 2; +		fthlv = packet / 2;  	else -		fthlv = half_fifo / 4; +		fthlv = packet / 4;  	/* align packet size with data registers access */  	if (spi->cur_bpw > 8) @@ -488,6 +497,9 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi)  	else  		fthlv -= (fthlv % 4); /* multiple of 4 */ +	if (!fthlv) +		fthlv = 1; +  	return fthlv;  } @@ -792,10 +804,9 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)  	struct spi_master *master = dev_id;  	struct stm32_spi *spi = spi_master_get_devdata(master);  	u32 sr, mask = 0; -	unsigned long flags;  	bool end = false; -	spin_lock_irqsave(&spi->lock, flags); +	spin_lock(&spi->lock);  	sr = readl_relaxed(spi->base + STM32F4_SPI_SR);  	/* @@ -821,7 +832,7 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)  	if (!(sr & mask)) {  		dev_dbg(spi->dev, "spurious IT (sr=0x%08x)\n", sr); -		spin_unlock_irqrestore(&spi->lock, flags); +		spin_unlock(&spi->lock);  		return IRQ_NONE;  	} @@ -863,11 +874,11 @@ end_irq:  					STM32F4_SPI_CR2_TXEIE |  					STM32F4_SPI_CR2_RXNEIE |  					STM32F4_SPI_CR2_ERRIE); -		spin_unlock_irqrestore(&spi->lock, flags); +		spin_unlock(&spi->lock);  		return IRQ_WAKE_THREAD;  	} -	spin_unlock_irqrestore(&spi->lock, flags); +	spin_unlock(&spi->lock);  	return IRQ_HANDLED;  } @@ -924,7 +935,11 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)  	}  	if (sr & STM32H7_SPI_SR_SUSP) { -		dev_warn(spi->dev, "Communication suspended\n"); +		static DEFINE_RATELIMIT_STATE(rs, +					      DEFAULT_RATELIMIT_INTERVAL * 10, +					      1); +		if (__ratelimit(&rs)) +			dev_dbg_ratelimited(spi->dev, "Communication suspended\n");  		if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))  			stm32h7_spi_read_rxfifo(spi, false);  		/* @@ -966,13 +981,13 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)  		if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))  			stm32h7_spi_read_rxfifo(spi, false); -	writel_relaxed(mask, spi->base + STM32H7_SPI_IFCR); +	writel_relaxed(sr & mask, spi->base + STM32H7_SPI_IFCR);  	spin_unlock_irqrestore(&spi->lock, flags);  	if (end) { -		spi_finalize_current_transfer(master);  		stm32h7_spi_disable(spi); +		spi_finalize_current_transfer(master);  	}  	return IRQ_HANDLED; @@ -1393,7 +1408,7 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi)  	cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) &  		     STM32H7_SPI_CFG1_DSIZE; -	spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi); +	spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen);  	fthlv = spi->cur_fthlv - 1;  	cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; @@ -1585,39 +1600,33 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,  	unsigned long flags;  	unsigned int comm_type;  	int nb_words, ret = 0; +	int mbr;  	spin_lock_irqsave(&spi->lock, flags); -	if (spi->cur_bpw != transfer->bits_per_word) { -		spi->cur_bpw = transfer->bits_per_word; -		spi->cfg->set_bpw(spi); -	} - -	if (spi->cur_speed != transfer->speed_hz) { -		int mbr; +	spi->cur_xferlen = transfer->len; -		/* Update spi->cur_speed with real clock speed */ -		mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, -					    spi->cfg->baud_rate_div_min, -					    spi->cfg->baud_rate_div_max); -		if (mbr < 0) { -			ret = mbr; -			goto out; -		} +	spi->cur_bpw = transfer->bits_per_word; +	spi->cfg->set_bpw(spi); -		transfer->speed_hz = spi->cur_speed; -		stm32_spi_set_mbr(spi, mbr); +	/* Update spi->cur_speed with real clock speed */ +	mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, +				    spi->cfg->baud_rate_div_min, +				    spi->cfg->baud_rate_div_max); +	if (mbr < 0) { +		ret = mbr; +		goto out;  	} -	comm_type = stm32_spi_communication_type(spi_dev, transfer); -	if (spi->cur_comm != comm_type) { -		ret = spi->cfg->set_mode(spi, comm_type); +	transfer->speed_hz = spi->cur_speed; +	stm32_spi_set_mbr(spi, mbr); -		if (ret < 0) -			goto out; +	comm_type = stm32_spi_communication_type(spi_dev, transfer); +	ret = spi->cfg->set_mode(spi, comm_type); +	if (ret < 0) +		goto out; -		spi->cur_comm = comm_type; -	} +	spi->cur_comm = comm_type;  	if (spi->cfg->set_data_idleness)  		spi->cfg->set_data_idleness(spi, transfer->len); @@ -1635,8 +1644,6 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,  			goto out;  	} -	spi->cur_xferlen = transfer->len; -  	dev_dbg(spi->dev, "transfer communication mode set to %d\n",  		spi->cur_comm);  	dev_dbg(spi->dev, @@ -1853,9 +1860,7 @@ static int stm32_spi_probe(struct platform_device *pdev)  	spi->irq = platform_get_irq(pdev, 0);  	if (spi->irq <= 0) { -		ret = spi->irq; -		if (ret != -EPROBE_DEFER) -			dev_err(&pdev->dev, "failed to get irq: %d\n", ret); +		ret = dev_err_probe(&pdev->dev, spi->irq, "failed to get irq\n");  		goto err_master_put;  	}  	ret = devm_request_threaded_irq(&pdev->dev, spi->irq, @@ -1996,6 +2001,8 @@ static int stm32_spi_remove(struct platform_device *pdev)  	pm_runtime_disable(&pdev->dev); +	pinctrl_pm_select_sleep_state(&pdev->dev); +  	return 0;  } @@ -2007,13 +2014,18 @@ static int stm32_spi_runtime_suspend(struct device *dev)  	clk_disable_unprepare(spi->clk); -	return 0; +	return pinctrl_pm_select_sleep_state(dev);  }  static int stm32_spi_runtime_resume(struct device *dev)  {  	struct spi_master *master = dev_get_drvdata(dev);  	struct stm32_spi *spi = spi_master_get_devdata(master); +	int ret; + +	ret = pinctrl_pm_select_default_state(dev); +	if (ret) +		return ret;  	return clk_prepare_enable(spi->clk);  } @@ -2043,10 +2055,23 @@ static int stm32_spi_resume(struct device *dev)  		return ret;  	ret = spi_master_resume(master); -	if (ret) +	if (ret) {  		clk_disable_unprepare(spi->clk); +		return ret; +	} -	return ret; +	ret = pm_runtime_get_sync(dev); +	if (ret < 0) { +		dev_err(dev, "Unable to power device:%d\n", ret); +		return ret; +	} + +	spi->cfg->config(spi); + +	pm_runtime_mark_last_busy(dev); +	pm_runtime_put_autosuspend(dev); + +	return 0;  }  #endif |