Commit 18445bf4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull spi fixes from Mark Brown:
 "A bunch of fixes that came in for SPI during the merge window.

  Some from ST and others for their controller, one from Lukas for a
  race between device addition and controller unregistration and one
  from fix from Geert for the DT bindings which unbreaks validation"

* tag 'spi-fix-v5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  dt-bindings: lpspi: Add missing boolean type for fsl,spi-only-use-cs1-sel
  spi: stm32: always perform registers configuration prior to transfer
  spi: stm32: fixes suspend/resume management
  spi: stm32: fix stm32_spi_prepare_mbr in case of odd clk_rate
  spi: stm32: fix fifo threshold level in case of short transfer
  spi: stm32h7: fix race condition at end of transfer
  spi: stm32: clear only asserted irq flags on interrupt
  spi: Prevent adding devices below an unregistering controller
parents 9899b587 8cb61d65
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ properties:
      spi common code does not support use of CS signals discontinuously.
      i.MX8DXL-EVK board only uses CS1 without using CS0. Therefore, add
      this property to re-config the chipselect value in the LPSPI driver.
    type: boolean

required:
  - compatible
+3 −0
Original line number Diff line number Diff line
@@ -1017,4 +1017,7 @@ config SPI_SLAVE_SYSTEM_CONTROL

endif # SPI_SLAVE

config SPI_DYNAMIC
	def_bool ACPI || OF_DYNAMIC || SPI_SLAVE

endif # SPI
+62 −38
Original line number Diff line number Diff line
@@ -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;
}

@@ -966,13 +978,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 +1405,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,16 +1597,14 @@ 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_xferlen = transfer->len;

	spi->cur_bpw = transfer->bits_per_word;
	spi->cfg->set_bpw(spi);
	}

	if (spi->cur_speed != transfer->speed_hz) {
		int mbr;

	/* Update spi->cur_speed with real clock speed */
	mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
@@ -1607,17 +1617,13 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,

	transfer->speed_hz = spi->cur_speed;
	stm32_spi_set_mbr(spi, mbr);
	}

	comm_type = stm32_spi_communication_type(spi_dev, transfer);
	if (spi->cur_comm != comm_type) {
	ret = spi->cfg->set_mode(spi, comm_type);

	if (ret < 0)
		goto out;

	spi->cur_comm = comm_type;
	}

	if (spi->cfg->set_data_idleness)
		spi->cfg->set_data_idleness(spi, transfer->len);
@@ -1635,8 +1641,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,
@@ -1996,6 +2000,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 +2013,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,11 +2054,24 @@ 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;
	}

	ret = pm_runtime_get_sync(dev);
	if (ret) {
		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

static const struct dev_pm_ops stm32_spi_pm_ops = {
+20 −1
Original line number Diff line number Diff line
@@ -475,6 +475,12 @@ static LIST_HEAD(spi_controller_list);
 */
static DEFINE_MUTEX(board_lock);

/*
 * Prevents addition of devices with same chip select and
 * addition of devices below an unregistering controller.
 */
static DEFINE_MUTEX(spi_add_lock);

/**
 * spi_alloc_device - Allocate a new SPI device
 * @ctlr: Controller to which device is connected
@@ -554,7 +560,6 @@ static int spi_dev_check(struct device *dev, void *data)
 */
int spi_add_device(struct spi_device *spi)
{
	static DEFINE_MUTEX(spi_add_lock);
	struct spi_controller *ctlr = spi->controller;
	struct device *dev = ctlr->dev.parent;
	int status;
@@ -582,6 +587,13 @@ int spi_add_device(struct spi_device *spi)
		goto done;
	}

	/* Controller may unregister concurrently */
	if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
	    !device_is_registered(&ctlr->dev)) {
		status = -ENODEV;
		goto done;
	}

	/* Descriptors take precedence */
	if (ctlr->cs_gpiods)
		spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select];
@@ -2795,6 +2807,10 @@ void spi_unregister_controller(struct spi_controller *ctlr)
	struct spi_controller *found;
	int id = ctlr->bus_num;

	/* Prevent addition of new devices, unregister existing ones */
	if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
		mutex_lock(&spi_add_lock);

	device_for_each_child(&ctlr->dev, NULL, __unregister);

	/* First make sure that this controller was ever added */
@@ -2815,6 +2831,9 @@ void spi_unregister_controller(struct spi_controller *ctlr)
	if (found == ctlr)
		idr_remove(&spi_master_idr, id);
	mutex_unlock(&board_lock);

	if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
		mutex_unlock(&spi_add_lock);
}
EXPORT_SYMBOL_GPL(spi_unregister_controller);