Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Baruch Siach and committed by
Mark Brown
d9c73bb8 20e5ea19

+45 -11
+22
drivers/spi/spi-dw-mmio.c
··· 16 16 #include <linux/spi/spi.h> 17 17 #include <linux/scatterlist.h> 18 18 #include <linux/module.h> 19 + #include <linux/of_gpio.h> 19 20 20 21 #include "spi-dw.h" 21 22 ··· 70 69 dws->bus_num = pdev->id; 71 70 dws->num_cs = 4; 72 71 dws->max_freq = clk_get_rate(dwsmmio->clk); 72 + 73 + if (pdev->dev.of_node) { 74 + int i; 75 + 76 + for (i = 0; i < dws->num_cs; i++) { 77 + int cs_gpio = of_get_named_gpio(pdev->dev.of_node, 78 + "cs-gpios", i); 79 + 80 + if (cs_gpio == -EPROBE_DEFER) { 81 + ret = cs_gpio; 82 + goto out; 83 + } 84 + 85 + if (gpio_is_valid(cs_gpio)) { 86 + ret = devm_gpio_request(&pdev->dev, cs_gpio, 87 + dev_name(&pdev->dev)); 88 + if (ret) 89 + goto out; 90 + } 91 + } 92 + } 73 93 74 94 ret = dw_spi_add_host(&pdev->dev, dws); 75 95 if (ret)
+12 -6
drivers/spi/spi-dw.c
··· 24 24 #include <linux/delay.h> 25 25 #include <linux/slab.h> 26 26 #include <linux/spi/spi.h> 27 + #include <linux/gpio.h> 27 28 28 29 #include "spi-dw.h" 29 30 ··· 36 35 #define RUNNING_STATE ((void *)1) 37 36 #define DONE_STATE ((void *)2) 38 37 #define ERROR_STATE ((void *)-1) 39 - 40 - #define MRST_SPI_DEASSERT 0 41 - #define MRST_SPI_ASSERT 1 42 38 43 39 /* Slave spi_dev related */ 44 40 struct chip_data { ··· 270 272 last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, 271 273 transfer_list); 272 274 273 - if (!last_transfer->cs_change && dws->cs_control) 274 - dws->cs_control(MRST_SPI_DEASSERT); 275 + if (!last_transfer->cs_change) 276 + spi_chip_sel(dws, dws->cur_msg->spi, 0); 275 277 276 278 spi_finalize_current_message(dws->master); 277 279 } ··· 491 493 dw_writew(dws, DW_SPI_CTRL0, cr0); 492 494 493 495 spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); 494 - spi_chip_sel(dws, spi->chip_select); 496 + spi_chip_sel(dws, spi, 1); 495 497 496 498 /* Set the interrupt mask, for poll mode just disable all int */ 497 499 spi_mask_intr(dws, 0xff); ··· 542 544 { 543 545 struct dw_spi_chip *chip_info = NULL; 544 546 struct chip_data *chip; 547 + int ret; 545 548 546 549 /* Only alloc on first setup */ 547 550 chip = spi_get_ctldata(spi); ··· 595 596 | (chip->type << SPI_FRF_OFFSET) 596 597 | (spi->mode << SPI_MODE_OFFSET) 597 598 | (chip->tmode << SPI_TMOD_OFFSET); 599 + 600 + if (gpio_is_valid(spi->cs_gpio)) { 601 + ret = gpio_direction_output(spi->cs_gpio, 602 + !(spi->mode & SPI_CS_HIGH)); 603 + if (ret) 604 + return ret; 605 + } 598 606 599 607 return 0; 600 608 }
+11 -5
drivers/spi/spi-dw.h
··· 3 3 4 4 #include <linux/io.h> 5 5 #include <linux/scatterlist.h> 6 + #include <linux/gpio.h> 6 7 7 8 /* Register offsets */ 8 9 #define DW_SPI_CTRL0 0x00 ··· 179 178 dw_writel(dws, DW_SPI_BAUDR, div); 180 179 } 181 180 182 - static inline void spi_chip_sel(struct dw_spi *dws, u16 cs) 181 + static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi, 182 + int active) 183 183 { 184 - if (cs > dws->num_cs) 185 - return; 184 + u16 cs = spi->chip_select; 185 + int gpio_val = active ? (spi->mode & SPI_CS_HIGH) : 186 + !(spi->mode & SPI_CS_HIGH); 186 187 187 188 if (dws->cs_control) 188 - dws->cs_control(1); 189 + dws->cs_control(active); 190 + if (gpio_is_valid(spi->cs_gpio)) 191 + gpio_set_value(spi->cs_gpio, gpio_val); 189 192 190 - dw_writel(dws, DW_SPI_SER, 1 << cs); 193 + if (active) 194 + dw_writel(dws, DW_SPI_SER, 1 << cs); 191 195 } 192 196 193 197 /* Disable IRQ bits */