+ spi-pxa2xx_spi-introduces-chipselect-gpio-to-simplify-the-common-cases.patch added to -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch titled
     spi: pxa2xx_spi: introduce chipselect GPIO to simplify the common cases
has been added to the -mm tree.  Its filename is
     spi-pxa2xx_spi-introduces-chipselect-gpio-to-simplify-the-common-cases.patch

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/SubmitChecklist when testing your code ***

See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find
out what to do about this

The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/

------------------------------------------------------
Subject: spi: pxa2xx_spi: introduce chipselect GPIO to simplify the common cases
From: Eric Miao <eric.miao@xxxxxxxxxxx>

Most SPI peripherals use GPIOs as their chip selects, introduce .gpio_cs
for this.

Signed-off-by: Eric Miao <eric.miao@xxxxxxxxxxx>
Cc: David Brownell <david-b@xxxxxxxxxxx>
Cc: Russell King <rmk@xxxxxxxxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
---

 arch/arm/mach-pxa/include/mach/pxa2xx_spi.h |    1 
 drivers/spi/pxa2xx_spi.c                    |   96 ++++++++++++++----
 2 files changed, 79 insertions(+), 18 deletions(-)

diff -puN arch/arm/mach-pxa/include/mach/pxa2xx_spi.h~spi-pxa2xx_spi-introduces-chipselect-gpio-to-simplify-the-common-cases arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
--- a/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h~spi-pxa2xx_spi-introduces-chipselect-gpio-to-simplify-the-common-cases
+++ a/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
@@ -38,6 +38,7 @@ struct pxa2xx_spi_chip {
 	u8 dma_burst_size;
 	u32 timeout;
 	u8 enable_loopback;
+	int gpio_cs;
 	void (*cs_control)(u32 command);
 };
 
diff -puN drivers/spi/pxa2xx_spi.c~spi-pxa2xx_spi-introduces-chipselect-gpio-to-simplify-the-common-cases drivers/spi/pxa2xx_spi.c
--- a/drivers/spi/pxa2xx_spi.c~spi-pxa2xx_spi-introduces-chipselect-gpio-to-simplify-the-common-cases
+++ a/drivers/spi/pxa2xx_spi.c
@@ -28,6 +28,7 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -166,6 +167,8 @@ struct chip_data {
 	u8 enable_dma;
 	u8 bits_per_word;
 	u32 speed_hz;
+	int gpio_cs;
+	int gpio_cs_inverted;
 	int (*write)(struct driver_data *drv_data);
 	int (*read)(struct driver_data *drv_data);
 	void (*cs_control)(u32 command);
@@ -173,6 +176,32 @@ struct chip_data {
 
 static void pump_messages(struct work_struct *work);
 
+static void cs_assert(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	if (chip->cs_control) {
+		chip->cs_control(PXA2XX_CS_ASSERT);
+		return;
+	}
+
+	if (gpio_is_valid(chip->gpio_cs))
+		gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted);
+}
+
+static void cs_deassert(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	if (chip->cs_control) {
+		chip->cs_control(PXA2XX_CS_ASSERT);
+		return;
+	}
+
+	if (gpio_is_valid(chip->gpio_cs))
+		gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
+}
+
 static int flush(struct driver_data *drv_data)
 {
 	unsigned long limit = loops_per_jiffy << 1;
@@ -189,10 +218,6 @@ static int flush(struct driver_data *drv
 	return limit;
 }
 
-static void null_cs_control(u32 command)
-{
-}
-
 static int null_writer(struct driver_data *drv_data)
 {
 	void __iomem *reg = drv_data->ioaddr;
@@ -400,7 +425,6 @@ static void giveback(struct driver_data 
 	msg = drv_data->cur_msg;
 	drv_data->cur_msg = NULL;
 	drv_data->cur_transfer = NULL;
-	drv_data->cur_chip = NULL;
 	queue_work(drv_data->workqueue, &drv_data->pump_messages);
 	spin_unlock_irqrestore(&drv_data->lock, flags);
 
@@ -416,7 +440,7 @@ static void giveback(struct driver_data 
 	 * a message with an error, or next message is for another chip
 	 */
 	if (!last_transfer->cs_change)
-		drv_data->cs_control(PXA2XX_CS_DEASSERT);
+		cs_deassert(drv_data);
 	else {
 		struct spi_message *next_msg;
 
@@ -445,12 +469,14 @@ static void giveback(struct driver_data 
 		if (next_msg && next_msg->spi != msg->spi)
 			next_msg = NULL;
 		if (!next_msg || msg->state == ERROR_STATE)
-			drv_data->cs_control(PXA2XX_CS_DEASSERT);
+			cs_deassert(drv_data);
 	}
 
 	msg->state = NULL;
 	if (msg->complete)
 		msg->complete(msg->context);
+
+	drv_data->cur_chip = NULL;
 }
 
 static int wait_ssp_rx_stall(void const __iomem *ioaddr)
@@ -887,7 +913,7 @@ static void pump_transfers(unsigned long
 
 		/* Drop chip select only if cs_change is requested */
 		if (previous->cs_change)
-			drv_data->cs_control(PXA2XX_CS_DEASSERT);
+			cs_deassert(drv_data);
 	}
 
 	/* Check for transfers that need multiple DMA segments */
@@ -922,7 +948,6 @@ static void pump_transfers(unsigned long
 	}
 	drv_data->n_bytes = chip->n_bytes;
 	drv_data->dma_width = chip->dma_width;
-	drv_data->cs_control = chip->cs_control;
 	drv_data->tx = (void *)transfer->tx_buf;
 	drv_data->tx_end = drv_data->tx + transfer->len;
 	drv_data->rx = transfer->rx_buf;
@@ -1084,11 +1109,7 @@ static void pump_transfers(unsigned long
 			write_SSTO(chip->timeout, reg);
 	}
 
-	/* FIXME, need to handle cs polarity,
-	 * this driver uses struct pxa2xx_spi_chip.cs_control to
-	 * specify a CS handling function, and it ignores most
-	 * struct spi_device.mode[s], including SPI_CS_HIGH */
-	drv_data->cs_control(PXA2XX_CS_ASSERT);
+	cs_assert(drv_data);
 
 	/* after chip select, release the data by enabling service
 	 * requests and interrupts, without changing any mode bits */
@@ -1166,6 +1187,44 @@ static int transfer(struct spi_device *s
 /* the spi->mode bits understood by this driver: */
 #define MODEBITS (SPI_CPOL | SPI_CPHA)
 
+static int setup_cs(struct spi_device *spi, struct chip_data *chip,
+		    struct pxa2xx_spi_chip *chip_info)
+{
+	int err = 0;
+
+	if (chip == NULL || chip_info == NULL)
+		return 0;
+
+	/* NOTE: setup() can be called multiple times, possibly with
+	 * different chip_info, release previously requested GPIO
+	 */
+	if (gpio_is_valid(chip->gpio_cs))
+		gpio_free(chip->gpio_cs);
+
+	/* If (*cs_control) is provided, ignore GPIO chip select */
+	if (chip_info->cs_control) {
+		chip->cs_control = chip_info->cs_control;
+		return 0;
+	}
+
+	if (gpio_is_valid(chip_info->gpio_cs)) {
+		err = gpio_request(chip_info->gpio_cs, "SPI_CS");
+		if (err) {
+			dev_err(&spi->dev, "failed to request chip select "
+					"GPIO%d\n", chip_info->gpio_cs);
+			return err;
+		}
+
+		chip->gpio_cs = chip_info->gpio_cs;
+		chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
+
+		err = gpio_direction_output(chip->gpio_cs,
+					!chip->gpio_cs_inverted);
+	}
+
+	return err;
+}
+
 static int setup(struct spi_device *spi)
 {
 	struct pxa2xx_spi_chip *chip_info = NULL;
@@ -1211,7 +1270,7 @@ static int setup(struct spi_device *spi)
 			return -ENOMEM;
 		}
 
-		chip->cs_control = null_cs_control;
+		chip->gpio_cs = -1;
 		chip->enable_dma = 0;
 		chip->timeout = TIMOUT_DFLT;
 		chip->dma_burst_size = drv_data->master_info->enable_dma ?
@@ -1225,8 +1284,6 @@ static int setup(struct spi_device *spi)
 	/* chip_info isn't always needed */
 	chip->cr1 = 0;
 	if (chip_info) {
-		if (chip_info->cs_control)
-			chip->cs_control = chip_info->cs_control;
 		if (chip_info->timeout)
 			chip->timeout = chip_info->timeout;
 		if (chip_info->tx_threshold)
@@ -1308,13 +1365,16 @@ static int setup(struct spi_device *spi)
 
 	spi_set_ctldata(spi, chip);
 
-	return 0;
+	return setup_cs(spi, chip, chip_info);
 }
 
 static void cleanup(struct spi_device *spi)
 {
 	struct chip_data *chip = spi_get_ctldata(spi);
 
+	if (gpio_is_valid(chip->gpio_cs))
+		gpio_free(chip->gpio_cs);
+
 	kfree(chip);
 }
 
_

Patches currently in -mm which might be from eric.miao@xxxxxxxxxxx are

linux-next.patch
spi-pxa2xx_spi-introduces-chipselect-gpio-to-simplify-the-common-cases.patch

--
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux