Commit d9c73bb8 authored by Baruch Siach's avatar Baruch Siach Committed by Mark Brown

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: default avatarBaruch Siach <baruch@tkos.co.il>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent 20e5ea19
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_gpio.h>
#include "spi-dw.h" #include "spi-dw.h"
...@@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) ...@@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
dws->num_cs = 4; dws->num_cs = 4;
dws->max_freq = clk_get_rate(dwsmmio->clk); 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); ret = dw_spi_add_host(&pdev->dev, dws);
if (ret) if (ret)
goto out; goto out;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/gpio.h>
#include "spi-dw.h" #include "spi-dw.h"
...@@ -36,9 +37,6 @@ ...@@ -36,9 +37,6 @@
#define DONE_STATE ((void *)2) #define DONE_STATE ((void *)2)
#define ERROR_STATE ((void *)-1) #define ERROR_STATE ((void *)-1)
#define MRST_SPI_DEASSERT 0
#define MRST_SPI_ASSERT 1
/* Slave spi_dev related */ /* Slave spi_dev related */
struct chip_data { struct chip_data {
u16 cr0; u16 cr0;
...@@ -272,8 +270,8 @@ static void giveback(struct dw_spi *dws) ...@@ -272,8 +270,8 @@ static void giveback(struct dw_spi *dws)
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list); transfer_list);
if (!last_transfer->cs_change && dws->cs_control) if (!last_transfer->cs_change)
dws->cs_control(MRST_SPI_DEASSERT); spi_chip_sel(dws, dws->cur_msg->spi, 0);
spi_finalize_current_message(dws->master); spi_finalize_current_message(dws->master);
} }
...@@ -493,7 +491,7 @@ static void pump_transfers(unsigned long data) ...@@ -493,7 +491,7 @@ static void pump_transfers(unsigned long data)
dw_writew(dws, DW_SPI_CTRL0, cr0); dw_writew(dws, DW_SPI_CTRL0, cr0);
spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); 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 */ /* Set the interrupt mask, for poll mode just disable all int */
spi_mask_intr(dws, 0xff); spi_mask_intr(dws, 0xff);
...@@ -544,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi) ...@@ -544,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi)
{ {
struct dw_spi_chip *chip_info = NULL; struct dw_spi_chip *chip_info = NULL;
struct chip_data *chip; struct chip_data *chip;
int ret;
/* Only alloc on first setup */ /* Only alloc on first setup */
chip = spi_get_ctldata(spi); chip = spi_get_ctldata(spi);
...@@ -597,6 +596,13 @@ static int dw_spi_setup(struct spi_device *spi) ...@@ -597,6 +596,13 @@ static int dw_spi_setup(struct spi_device *spi)
| (spi->mode << SPI_MODE_OFFSET) | (spi->mode << SPI_MODE_OFFSET)
| (chip->tmode << SPI_TMOD_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; return 0;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/gpio.h>
/* Register offsets */ /* Register offsets */
#define DW_SPI_CTRL0 0x00 #define DW_SPI_CTRL0 0x00
...@@ -178,14 +179,19 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div) ...@@ -178,14 +179,19 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)
dw_writel(dws, DW_SPI_BAUDR, 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) u16 cs = spi->chip_select;
return; int gpio_val = active ? (spi->mode & SPI_CS_HIGH) :
!(spi->mode & SPI_CS_HIGH);
if (dws->cs_control) 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);
if (active)
dw_writel(dws, DW_SPI_SER, 1 << cs); dw_writel(dws, DW_SPI_SER, 1 << cs);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment