Commit c8b348dd authored by Linus Walleij's avatar Linus Walleij Committed by Mark Brown

spi: txx9: Convert to use GPIO descriptors

This converts the TXX9 SPI driver to use GPIO descriptors
to control the GPIO chip selects.

As the driver was clearly (ab)using the device tree "reg"
property to offset into the global GPIO chip we have to
add a hack to counter the hack: add a 1-to-1 chip select
to GPIO offset mapping for all 16 lines on the TXX9 GPIO
chip. The details are described in a largeish comment
in the patch.

We do not need to set up the GPIO as output any more since
the core will take care of this, as well as it will handle
the polarity inversion semantics.

Cc: Atsushi Nemoto <atsushi.nemoto@sord.co.jp>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20191030073832.24038-1-linus.walleij@linaro.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 76f0030f
...@@ -26,7 +26,8 @@ ...@@ -26,7 +26,8 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio/machine.h>
#include <linux/gpio/consumer.h>
#define SPI_FIFO_SIZE 4 #define SPI_FIFO_SIZE 4
...@@ -79,7 +80,7 @@ struct txx9spi { ...@@ -79,7 +80,7 @@ struct txx9spi {
void __iomem *membase; void __iomem *membase;
int baseclk; int baseclk;
struct clk *clk; struct clk *clk;
int last_chipselect; struct gpio_desc *last_chipselect;
int last_chipselect_val; int last_chipselect_val;
}; };
...@@ -95,20 +96,22 @@ static void txx9spi_wr(struct txx9spi *c, u32 val, int reg) ...@@ -95,20 +96,22 @@ static void txx9spi_wr(struct txx9spi *c, u32 val, int reg)
static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c, static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
int on, unsigned int cs_delay) int on, unsigned int cs_delay)
{ {
int val = (spi->mode & SPI_CS_HIGH) ? on : !on; /*
* The GPIO descriptor will track polarity inversion inside
* gpiolib.
*/
if (on) { if (on) {
/* deselect the chip with cs_change hint in last transfer */ /* deselect the chip with cs_change hint in last transfer */
if (c->last_chipselect >= 0) if (c->last_chipselect)
gpio_set_value(c->last_chipselect, gpiod_set_value(c->last_chipselect,
!c->last_chipselect_val); !c->last_chipselect_val);
c->last_chipselect = spi->chip_select; c->last_chipselect = spi->cs_gpiod;
c->last_chipselect_val = val; c->last_chipselect_val = on;
} else { } else {
c->last_chipselect = -1; c->last_chipselect = NULL;
ndelay(cs_delay); /* CS Hold Time */ ndelay(cs_delay); /* CS Hold Time */
} }
gpio_set_value(spi->chip_select, val); gpiod_set_value(spi->cs_gpiod, on);
ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */ ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */
} }
...@@ -119,12 +122,6 @@ static int txx9spi_setup(struct spi_device *spi) ...@@ -119,12 +122,6 @@ static int txx9spi_setup(struct spi_device *spi)
if (!spi->max_speed_hz) if (!spi->max_speed_hz)
return -EINVAL; return -EINVAL;
if (gpio_direction_output(spi->chip_select,
!(spi->mode & SPI_CS_HIGH))) {
dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
return -EINVAL;
}
/* deselect chip */ /* deselect chip */
spin_lock(&c->lock); spin_lock(&c->lock);
txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz); txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz);
...@@ -319,6 +316,47 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) ...@@ -319,6 +316,47 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
return 0; return 0;
} }
/*
* Chip select uses GPIO only, further the driver is using the chip select
* numer (from the device tree "reg" property, and this can only come from
* device tree since this i MIPS and there is no way to pass platform data) as
* the GPIO number. As the platform has only one GPIO controller (the txx9 GPIO
* chip) it is thus using the chip select number as an offset into that chip.
* This chip has a maximum of 16 GPIOs 0..15 and this is what all platforms
* register.
*
* We modernized this behaviour by explicitly converting that offset to an
* offset on the GPIO chip using a GPIO descriptor machine table of the same
* size as the txx9 GPIO chip with a 1-to-1 mapping of chip select to GPIO
* offset.
*
* This is admittedly a hack, but it is countering the hack of using "reg" to
* contain a GPIO offset when it should be using "cs-gpios" as the SPI bindings
* state.
*/
static struct gpiod_lookup_table txx9spi_cs_gpio_table = {
.dev_id = "spi0",
.table = {
GPIO_LOOKUP_IDX("TXx9", 0, "cs", 0, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 1, "cs", 1, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 2, "cs", 2, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 3, "cs", 3, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 4, "cs", 4, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 5, "cs", 5, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 6, "cs", 6, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 7, "cs", 7, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 8, "cs", 8, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 9, "cs", 9, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 10, "cs", 10, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 11, "cs", 11, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 12, "cs", 12, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 13, "cs", 13, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 14, "cs", 14, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("TXx9", 15, "cs", 15, GPIO_ACTIVE_LOW),
{ },
},
};
static int txx9spi_probe(struct platform_device *dev) static int txx9spi_probe(struct platform_device *dev)
{ {
struct spi_master *master; struct spi_master *master;
...@@ -372,12 +410,14 @@ static int txx9spi_probe(struct platform_device *dev) ...@@ -372,12 +410,14 @@ static int txx9spi_probe(struct platform_device *dev)
if (ret) if (ret)
goto exit; goto exit;
c->last_chipselect = -1; c->last_chipselect = NULL;
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n", dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
(unsigned long long)res->start, irq, (unsigned long long)res->start, irq,
(c->baseclk + 500000) / 1000000); (c->baseclk + 500000) / 1000000);
gpiod_add_lookup_table(&txx9spi_cs_gpio_table);
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
...@@ -386,6 +426,7 @@ static int txx9spi_probe(struct platform_device *dev) ...@@ -386,6 +426,7 @@ static int txx9spi_probe(struct platform_device *dev)
master->transfer = txx9spi_transfer; master->transfer = txx9spi_transfer;
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */ master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->use_gpio_descriptors = true;
ret = devm_spi_register_master(&dev->dev, master); ret = devm_spi_register_master(&dev->dev, master);
if (ret) if (ret)
......
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