From: Baruch Siach Date: Fri, 31 Jan 2014 10:07:47 +0000 (+0200) Subject: spi: dw: add support for gpio controlled chip select X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81;p=deliverable%2Flinux.git spi: dw: add support for gpio controlled chip select Also, use this opportunity to let spi_chip_sel() handle chip-select deactivation as well. Signed-off-by: Baruch Siach Signed-off-by: Mark Brown --- diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 1492f5ee9aaa..a5cba14ac3d2 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "spi-dw.h" @@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) dws->num_cs = 4; dws->max_freq = clk_get_rate(dwsmmio->clk); + if (pdev->dev.of_node) { + int i; + + for (i = 0; i < dws->num_cs; i++) { + int cs_gpio = of_get_named_gpio(pdev->dev.of_node, + "cs-gpios", i); + + if (cs_gpio == -EPROBE_DEFER) { + ret = cs_gpio; + goto out; + } + + if (gpio_is_valid(cs_gpio)) { + ret = devm_gpio_request(&pdev->dev, cs_gpio, + dev_name(&pdev->dev)); + if (ret) + goto out; + } + } + } + ret = dw_spi_add_host(&pdev->dev, dws); if (ret) goto out; diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 357869a704d6..9965e1b84832 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "spi-dw.h" @@ -36,9 +37,6 @@ #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) -#define MRST_SPI_DEASSERT 0 -#define MRST_SPI_ASSERT 1 - /* Slave spi_dev related */ struct chip_data { u16 cr0; @@ -272,8 +270,8 @@ static void giveback(struct dw_spi *dws) last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, transfer_list); - if (!last_transfer->cs_change && dws->cs_control) - dws->cs_control(MRST_SPI_DEASSERT); + if (!last_transfer->cs_change) + spi_chip_sel(dws, dws->cur_msg->spi, 0); spi_finalize_current_message(dws->master); } @@ -493,7 +491,7 @@ static void pump_transfers(unsigned long data) dw_writew(dws, DW_SPI_CTRL0, cr0); spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); - spi_chip_sel(dws, spi->chip_select); + spi_chip_sel(dws, spi, 1); /* Set the interrupt mask, for poll mode just disable all int */ spi_mask_intr(dws, 0xff); @@ -544,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi) { struct dw_spi_chip *chip_info = NULL; struct chip_data *chip; + int ret; /* Only alloc on first setup */ chip = spi_get_ctldata(spi); @@ -597,6 +596,13 @@ static int dw_spi_setup(struct spi_device *spi) | (spi->mode << SPI_MODE_OFFSET) | (chip->tmode << SPI_TMOD_OFFSET); + if (gpio_is_valid(spi->cs_gpio)) { + ret = gpio_direction_output(spi->cs_gpio, + !(spi->mode & SPI_CS_HIGH)); + if (ret) + return ret; + } + return 0; } diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 3fd7ab599ab4..6d2acad34f64 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -3,6 +3,7 @@ #include #include +#include /* Register offsets */ #define DW_SPI_CTRL0 0x00 @@ -178,15 +179,20 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div) dw_writel(dws, DW_SPI_BAUDR, div); } -static inline void spi_chip_sel(struct dw_spi *dws, u16 cs) +static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi, + int active) { - if (cs > dws->num_cs) - return; + u16 cs = spi->chip_select; + int gpio_val = active ? (spi->mode & SPI_CS_HIGH) : + !(spi->mode & SPI_CS_HIGH); if (dws->cs_control) - dws->cs_control(1); + dws->cs_control(active); + if (gpio_is_valid(spi->cs_gpio)) + gpio_set_value(spi->cs_gpio, gpio_val); - dw_writel(dws, DW_SPI_SER, 1 << cs); + if (active) + dw_writel(dws, DW_SPI_SER, 1 << cs); } /* Disable IRQ bits */