diff options
author | Baruch Siach <baruch@tkos.co.il> | 2014-01-31 05:07:47 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-04-24 13:09:05 -0400 |
commit | d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81 (patch) | |
tree | f711caf00b7025672dc919e5896a597535588111 | |
parent | 20e5ea191524b482e1b4aa12b5ff4684717f44b8 (diff) |
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 <baruch@tkos.co.il>
Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r-- | drivers/spi/spi-dw-mmio.c | 22 | ||||
-rw-r--r-- | drivers/spi/spi-dw.c | 18 | ||||
-rw-r--r-- | drivers/spi/spi-dw.h | 16 |
3 files changed, 45 insertions, 11 deletions
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 @@ | |||
16 | #include <linux/spi/spi.h> | 16 | #include <linux/spi/spi.h> |
17 | #include <linux/scatterlist.h> | 17 | #include <linux/scatterlist.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/of_gpio.h> | ||
19 | 20 | ||
20 | #include "spi-dw.h" | 21 | #include "spi-dw.h" |
21 | 22 | ||
@@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) | |||
70 | dws->num_cs = 4; | 71 | dws->num_cs = 4; |
71 | dws->max_freq = clk_get_rate(dwsmmio->clk); | 72 | dws->max_freq = clk_get_rate(dwsmmio->clk); |
72 | 73 | ||
74 | if (pdev->dev.of_node) { | ||
75 | int i; | ||
76 | |||
77 | for (i = 0; i < dws->num_cs; i++) { | ||
78 | int cs_gpio = of_get_named_gpio(pdev->dev.of_node, | ||
79 | "cs-gpios", i); | ||
80 | |||
81 | if (cs_gpio == -EPROBE_DEFER) { | ||
82 | ret = cs_gpio; | ||
83 | goto out; | ||
84 | } | ||
85 | |||
86 | if (gpio_is_valid(cs_gpio)) { | ||
87 | ret = devm_gpio_request(&pdev->dev, cs_gpio, | ||
88 | dev_name(&pdev->dev)); | ||
89 | if (ret) | ||
90 | goto out; | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
73 | ret = dw_spi_add_host(&pdev->dev, dws); | 95 | ret = dw_spi_add_host(&pdev->dev, dws); |
74 | if (ret) | 96 | if (ret) |
75 | goto out; | 97 | 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 @@ | |||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/spi/spi.h> | 26 | #include <linux/spi/spi.h> |
27 | #include <linux/gpio.h> | ||
27 | 28 | ||
28 | #include "spi-dw.h" | 29 | #include "spi-dw.h" |
29 | 30 | ||
@@ -36,9 +37,6 @@ | |||
36 | #define DONE_STATE ((void *)2) | 37 | #define DONE_STATE ((void *)2) |
37 | #define ERROR_STATE ((void *)-1) | 38 | #define ERROR_STATE ((void *)-1) |
38 | 39 | ||
39 | #define MRST_SPI_DEASSERT 0 | ||
40 | #define MRST_SPI_ASSERT 1 | ||
41 | |||
42 | /* Slave spi_dev related */ | 40 | /* Slave spi_dev related */ |
43 | struct chip_data { | 41 | struct chip_data { |
44 | u16 cr0; | 42 | u16 cr0; |
@@ -272,8 +270,8 @@ static void giveback(struct dw_spi *dws) | |||
272 | last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, | 270 | last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, |
273 | transfer_list); | 271 | transfer_list); |
274 | 272 | ||
275 | if (!last_transfer->cs_change && dws->cs_control) | 273 | if (!last_transfer->cs_change) |
276 | dws->cs_control(MRST_SPI_DEASSERT); | 274 | spi_chip_sel(dws, dws->cur_msg->spi, 0); |
277 | 275 | ||
278 | spi_finalize_current_message(dws->master); | 276 | spi_finalize_current_message(dws->master); |
279 | } | 277 | } |
@@ -493,7 +491,7 @@ static void pump_transfers(unsigned long data) | |||
493 | dw_writew(dws, DW_SPI_CTRL0, cr0); | 491 | dw_writew(dws, DW_SPI_CTRL0, cr0); |
494 | 492 | ||
495 | spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); | 493 | spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); |
496 | spi_chip_sel(dws, spi->chip_select); | 494 | spi_chip_sel(dws, spi, 1); |
497 | 495 | ||
498 | /* Set the interrupt mask, for poll mode just disable all int */ | 496 | /* Set the interrupt mask, for poll mode just disable all int */ |
499 | spi_mask_intr(dws, 0xff); | 497 | spi_mask_intr(dws, 0xff); |
@@ -544,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi) | |||
544 | { | 542 | { |
545 | struct dw_spi_chip *chip_info = NULL; | 543 | struct dw_spi_chip *chip_info = NULL; |
546 | struct chip_data *chip; | 544 | struct chip_data *chip; |
545 | int ret; | ||
547 | 546 | ||
548 | /* Only alloc on first setup */ | 547 | /* Only alloc on first setup */ |
549 | chip = spi_get_ctldata(spi); | 548 | chip = spi_get_ctldata(spi); |
@@ -597,6 +596,13 @@ static int dw_spi_setup(struct spi_device *spi) | |||
597 | | (spi->mode << SPI_MODE_OFFSET) | 596 | | (spi->mode << SPI_MODE_OFFSET) |
598 | | (chip->tmode << SPI_TMOD_OFFSET); | 597 | | (chip->tmode << SPI_TMOD_OFFSET); |
599 | 598 | ||
599 | if (gpio_is_valid(spi->cs_gpio)) { | ||
600 | ret = gpio_direction_output(spi->cs_gpio, | ||
601 | !(spi->mode & SPI_CS_HIGH)); | ||
602 | if (ret) | ||
603 | return ret; | ||
604 | } | ||
605 | |||
600 | return 0; | 606 | return 0; |
601 | } | 607 | } |
602 | 608 | ||
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 @@ | |||
3 | 3 | ||
4 | #include <linux/io.h> | 4 | #include <linux/io.h> |
5 | #include <linux/scatterlist.h> | 5 | #include <linux/scatterlist.h> |
6 | #include <linux/gpio.h> | ||
6 | 7 | ||
7 | /* Register offsets */ | 8 | /* Register offsets */ |
8 | #define DW_SPI_CTRL0 0x00 | 9 | #define DW_SPI_CTRL0 0x00 |
@@ -178,15 +179,20 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div) | |||
178 | dw_writel(dws, DW_SPI_BAUDR, div); | 179 | dw_writel(dws, DW_SPI_BAUDR, div); |
179 | } | 180 | } |
180 | 181 | ||
181 | static inline void spi_chip_sel(struct dw_spi *dws, u16 cs) | 182 | static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi, |
183 | int active) | ||
182 | { | 184 | { |
183 | if (cs > dws->num_cs) | 185 | u16 cs = spi->chip_select; |
184 | return; | 186 | int gpio_val = active ? (spi->mode & SPI_CS_HIGH) : |
187 | !(spi->mode & SPI_CS_HIGH); | ||
185 | 188 | ||
186 | if (dws->cs_control) | 189 | if (dws->cs_control) |
187 | dws->cs_control(1); | 190 | dws->cs_control(active); |
191 | if (gpio_is_valid(spi->cs_gpio)) | ||
192 | gpio_set_value(spi->cs_gpio, gpio_val); | ||
188 | 193 | ||
189 | dw_writel(dws, DW_SPI_SER, 1 << cs); | 194 | if (active) |
195 | dw_writel(dws, DW_SPI_SER, 1 << cs); | ||
190 | } | 196 | } |
191 | 197 | ||
192 | /* Disable IRQ bits */ | 198 | /* Disable IRQ bits */ |