Просмотр исходного кода

Merge tag 'spi-v3.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "A few driver specific fixes, the biggest one being a fix for the newly
  added Qualcomm SPI controller driver to make it not use its internal
  chip select due to hardware bugs, replacing it with GPIOs"

* tag 'spi-v3.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: qup: Remove chip select function
  spi: qup: Fix order of spi_register_master
  spi: sh-sci: fix use-after-free in sh_sci_spi_remove()
  spi/pxa2xx: fix incorrect SW mode chipselect setting for BayTrail LPSS SPI
Linus Torvalds 11 лет назад
Родитель
Сommit
24b414d5a7

+ 6 - 0
Documentation/devicetree/bindings/spi/qcom,spi-qup.txt

@@ -23,6 +23,12 @@ Optional properties:
 - spi-max-frequency: Specifies maximum SPI clock frequency,
 - spi-max-frequency: Specifies maximum SPI clock frequency,
                      Units - Hz. Definition as per
                      Units - Hz. Definition as per
                      Documentation/devicetree/bindings/spi/spi-bus.txt
                      Documentation/devicetree/bindings/spi/spi-bus.txt
+- num-cs:	total number of chipselects
+- cs-gpios:	should specify GPIOs used for chipselects.
+		The gpios will be referred to as reg = <index> in the SPI child
+		nodes.  If unspecified, a single SPI device without a chip
+		select can be used.
+
 
 
 SPI slave nodes must be children of the SPI master node and can contain
 SPI slave nodes must be children of the SPI master node and can contain
 properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
 properties described in Documentation/devicetree/bindings/spi/spi-bus.txt

+ 6 - 2
drivers/spi/spi-pxa2xx.c

@@ -118,6 +118,7 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
 	 */
 	 */
 	orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
 	orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
 
 
+	/* Test SPI_CS_CONTROL_SW_MODE bit enabling */
 	value = orig | SPI_CS_CONTROL_SW_MODE;
 	value = orig | SPI_CS_CONTROL_SW_MODE;
 	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
 	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
 	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
 	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
@@ -126,10 +127,13 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
 		goto detection_done;
 		goto detection_done;
 	}
 	}
 
 
-	value &= ~SPI_CS_CONTROL_SW_MODE;
+	orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
+
+	/* Test SPI_CS_CONTROL_SW_MODE bit disabling */
+	value = orig & ~SPI_CS_CONTROL_SW_MODE;
 	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
 	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
 	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
 	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
-	if (value != orig) {
+	if (value != (orig & ~SPI_CS_CONTROL_SW_MODE)) {
 		offset = 0x800;
 		offset = 0x800;
 		goto detection_done;
 		goto detection_done;
 	}
 	}

+ 13 - 31
drivers/spi/spi-qup.c

@@ -424,31 +424,6 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 	return 0;
 	return 0;
 }
 }
 
 
-static void spi_qup_set_cs(struct spi_device *spi, bool enable)
-{
-	struct spi_qup *controller = spi_master_get_devdata(spi->master);
-
-	u32 iocontol, mask;
-
-	iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL);
-
-	/* Disable auto CS toggle and use manual */
-	iocontol &= ~SPI_IO_C_MX_CS_MODE;
-	iocontol |= SPI_IO_C_FORCE_CS;
-
-	iocontol &= ~SPI_IO_C_CS_SELECT_MASK;
-	iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select);
-
-	mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
-
-	if (enable)
-		iocontol |= mask;
-	else
-		iocontol &= ~mask;
-
-	writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL);
-}
-
 static int spi_qup_transfer_one(struct spi_master *master,
 static int spi_qup_transfer_one(struct spi_master *master,
 			      struct spi_device *spi,
 			      struct spi_device *spi,
 			      struct spi_transfer *xfer)
 			      struct spi_transfer *xfer)
@@ -571,12 +546,16 @@ static int spi_qup_probe(struct platform_device *pdev)
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
+	/* use num-cs unless not present or out of range */
+	if (of_property_read_u16(dev->of_node, "num-cs",
+			&master->num_chipselect) ||
+			(master->num_chipselect > SPI_NUM_CHIPSELECTS))
+		master->num_chipselect = SPI_NUM_CHIPSELECTS;
+
 	master->bus_num = pdev->id;
 	master->bus_num = pdev->id;
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
-	master->num_chipselect = SPI_NUM_CHIPSELECTS;
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
 	master->max_speed_hz = max_freq;
 	master->max_speed_hz = max_freq;
-	master->set_cs = spi_qup_set_cs;
 	master->transfer_one = spi_qup_transfer_one;
 	master->transfer_one = spi_qup_transfer_one;
 	master->dev.of_node = pdev->dev.of_node;
 	master->dev.of_node = pdev->dev.of_node;
 	master->auto_runtime_pm = true;
 	master->auto_runtime_pm = true;
@@ -640,16 +619,19 @@ static int spi_qup_probe(struct platform_device *pdev)
 	if (ret)
 	if (ret)
 		goto error;
 		goto error;
 
 
-	ret = devm_spi_register_master(dev, master);
-	if (ret)
-		goto error;
-
 	pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
 	pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
 	pm_runtime_use_autosuspend(dev);
 	pm_runtime_use_autosuspend(dev);
 	pm_runtime_set_active(dev);
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
 	pm_runtime_enable(dev);
+
+	ret = devm_spi_register_master(dev, master);
+	if (ret)
+		goto disable_pm;
+
 	return 0;
 	return 0;
 
 
+disable_pm:
+	pm_runtime_disable(&pdev->dev);
 error:
 error:
 	clk_disable_unprepare(cclk);
 	clk_disable_unprepare(cclk);
 	clk_disable_unprepare(iclk);
 	clk_disable_unprepare(iclk);

+ 2 - 2
drivers/spi/spi-sh-sci.c

@@ -175,9 +175,9 @@ static int sh_sci_spi_remove(struct platform_device *dev)
 {
 {
 	struct sh_sci_spi *sp = platform_get_drvdata(dev);
 	struct sh_sci_spi *sp = platform_get_drvdata(dev);
 
 
-	iounmap(sp->membase);
-	setbits(sp, PIN_INIT, 0);
 	spi_bitbang_stop(&sp->bitbang);
 	spi_bitbang_stop(&sp->bitbang);
+	setbits(sp, PIN_INIT, 0);
+	iounmap(sp->membase);
 	spi_master_put(sp->bitbang.master);
 	spi_master_put(sp->bitbang.master);
 	return 0;
 	return 0;
 }
 }