提交 a88e34ea 编写于 作者: M Murali Karicheri 提交者: Mark Brown

spi: davinci: add support to configure gpio cs through dt

Currently driver supports only configuration of GPIO CS through
platform data. This patch enhances the driver to configure GPIO
CS through DT. Also update the DT binding documentation to
reflect the availability of cs-gpios.
Signed-off-by: NMurali Karicheri <m-karicheri2@ti.com>
Signed-off-by: NGrygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: NMark Brown <broonie@linaro.org>
上级 7480e755
...@@ -8,7 +8,8 @@ Required properties: ...@@ -8,7 +8,8 @@ Required properties:
- "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family - "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family
- "ti,da830-spi" for SPI used similar to that on DA8xx SoC family - "ti,da830-spi" for SPI used similar to that on DA8xx SoC family
- reg: Offset and length of SPI controller register space - reg: Offset and length of SPI controller register space
- num-cs: Number of chip selects - num-cs: Number of chip selects. This includes internal as well as
GPIO chip selects.
- ti,davinci-spi-intr-line: interrupt line used to connect the SPI - ti,davinci-spi-intr-line: interrupt line used to connect the SPI
IP to the interrupt controller within the SoC. Possible values IP to the interrupt controller within the SoC. Possible values
are 0 and 1. Manual says one of the two possible interrupt are 0 and 1. Manual says one of the two possible interrupt
...@@ -17,6 +18,12 @@ Required properties: ...@@ -17,6 +18,12 @@ Required properties:
- interrupts: interrupt number mapped to CPU. - interrupts: interrupt number mapped to CPU.
- clocks: spi clk phandle - clocks: spi clk phandle
Optional:
- cs-gpios: gpio chip selects
For example to have 3 internal CS and 2 GPIO CS, user could define
cs-gpios = <0>, <0>, <0>, <&gpio1 30 0>, <&gpio1 31 0>;
where first three are internal CS and last two are GPIO CS.
Example of a NOR flash slave device (n25q032) connected to DaVinci Example of a NOR flash slave device (n25q032) connected to DaVinci
SPI controller device over the SPI bus. SPI controller device over the SPI bus.
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/edma.h> #include <linux/edma.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -207,17 +208,28 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits) ...@@ -207,17 +208,28 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits)
static void davinci_spi_chipselect(struct spi_device *spi, int value) static void davinci_spi_chipselect(struct spi_device *spi, int value)
{ {
struct davinci_spi *dspi; struct davinci_spi *dspi;
struct device_node *np = spi->dev.of_node;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
struct spi_master *master = spi->master;
u8 chip_sel = spi->chip_select; u8 chip_sel = spi->chip_select;
u16 spidat1 = CS_DEFAULT; u16 spidat1 = CS_DEFAULT;
bool gpio_chipsel = false; bool gpio_chipsel = false;
int gpio;
dspi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
pdata = &dspi->pdata; pdata = &dspi->pdata;
if (pdata->chip_sel && chip_sel < pdata->num_chipselect && if (np && master->cs_gpios != NULL && spi->cs_gpio >= 0) {
pdata->chip_sel[chip_sel] != SPI_INTERN_CS) /* SPI core parse and update master->cs_gpio */
gpio_chipsel = true; gpio_chipsel = true;
gpio = spi->cs_gpio;
} else if (pdata->chip_sel &&
chip_sel < pdata->num_chipselect &&
pdata->chip_sel[chip_sel] != SPI_INTERN_CS) {
/* platform data defines chip_sel */
gpio_chipsel = true;
gpio = pdata->chip_sel[chip_sel];
}
/* /*
* Board specific chip select logic decides the polarity and cs * Board specific chip select logic decides the polarity and cs
...@@ -225,9 +237,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) ...@@ -225,9 +237,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
*/ */
if (gpio_chipsel) { if (gpio_chipsel) {
if (value == BITBANG_CS_ACTIVE) if (value == BITBANG_CS_ACTIVE)
gpio_set_value(pdata->chip_sel[chip_sel], 0); gpio_set_value(gpio, 0);
else else
gpio_set_value(pdata->chip_sel[chip_sel], 1); gpio_set_value(gpio, 1);
} else { } else {
if (value == BITBANG_CS_ACTIVE) { if (value == BITBANG_CS_ACTIVE) {
spidat1 |= SPIDAT1_CSHOLD_MASK; spidat1 |= SPIDAT1_CSHOLD_MASK;
...@@ -390,17 +402,41 @@ static int davinci_spi_setup(struct spi_device *spi) ...@@ -390,17 +402,41 @@ static int davinci_spi_setup(struct spi_device *spi)
int retval = 0; int retval = 0;
struct davinci_spi *dspi; struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
struct spi_master *master = spi->master;
struct device_node *np = spi->dev.of_node;
bool internal_cs = true;
dspi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
pdata = &dspi->pdata; pdata = &dspi->pdata;
if (!(spi->mode & SPI_NO_CS)) { if (!(spi->mode & SPI_NO_CS)) {
if ((pdata->chip_sel == NULL) || if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) {
(pdata->chip_sel[spi->chip_select] == SPI_INTERN_CS)) unsigned long flags;
set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
flags = GPIOF_DIR_OUT;
if (spi->mode & SPI_CS_HIGH)
flags |= GPIOF_INIT_LOW;
else
flags |= GPIOF_INIT_HIGH;
retval = gpio_request_one(spi->cs_gpio,
flags, dev_name(&spi->dev));
if (retval) {
dev_err(&spi->dev,
"GPIO %d request failed (%d)\n",
spi->cs_gpio, retval);
return retval;
}
internal_cs = false;
} else if (pdata->chip_sel &&
spi->chip_select < pdata->num_chipselect &&
pdata->chip_sel[spi->chip_select] != SPI_INTERN_CS) {
internal_cs = false;
}
} }
if (internal_cs)
set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
if (spi->mode & SPI_READY) if (spi->mode & SPI_READY)
set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK); set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK);
...@@ -412,6 +448,15 @@ static int davinci_spi_setup(struct spi_device *spi) ...@@ -412,6 +448,15 @@ static int davinci_spi_setup(struct spi_device *spi)
return retval; return retval;
} }
static void davinci_spi_cleanup(struct spi_device *spi)
{
struct spi_master *master = spi->master;
struct device_node *np = spi->dev.of_node;
if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0))
gpio_free(spi->cs_gpio);
}
static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
{ {
struct device *sdev = dspi->bitbang.master->dev.parent; struct device *sdev = dspi->bitbang.master->dev.parent;
...@@ -810,6 +855,8 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, ...@@ -810,6 +855,8 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
/* /*
* default num_cs is 1 and all chipsel are internal to the chip * default num_cs is 1 and all chipsel are internal to the chip
* indicated by chip_sel being NULL or cs_gpios being NULL or
* set to -ENOENT. num-cs includes internal as well as gpios.
* indicated by chip_sel being NULL. GPIO based CS is not * indicated by chip_sel being NULL. GPIO based CS is not
* supported yet in DT bindings. * supported yet in DT bindings.
*/ */
...@@ -921,6 +968,7 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -921,6 +968,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
master->num_chipselect = pdata->num_chipselect; master->num_chipselect = pdata->num_chipselect;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
master->setup = davinci_spi_setup; master->setup = davinci_spi_setup;
master->cleanup = davinci_spi_cleanup;
dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.chipselect = davinci_spi_chipselect;
dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册