aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaruch Siach <baruch@tkos.co.il>2014-01-31 05:07:47 -0500
committerMark Brown <broonie@linaro.org>2014-04-24 13:09:05 -0400
commitd9c73bb8a3a5e4b76d2ad55da00d9ea776475c81 (patch)
treef711caf00b7025672dc919e5896a597535588111
parent20e5ea191524b482e1b4aa12b5ff4684717f44b8 (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.c22
-rw-r--r--drivers/spi/spi-dw.c18
-rw-r--r--drivers/spi/spi-dw.h16
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 */
43struct chip_data { 41struct 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
181static inline void spi_chip_sel(struct dw_spi *dws, u16 cs) 182static 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 */