[PATCH v3] spi: mvebu_a3700_spi: add support for cs-gpios

The device tree has a way to specify GPIO lines as chip selects. From the binding docs:
So if for example the controller has 2 CS lines, and the cs-gpios property looks like this:
cs-gpios = <&gpio1 0 0> <0> <&gpio1 1 0> <&gpio1 2 0>;
Then it should be configured so that num_chipselect = 4 with the following mapping:
cs0 : &gpio1 0 0 cs1 : native cs2 : &gpio1 1 0 cs3 : &gpio1 2 0
Add support for this, while retaining backward-compatibility with existing device trees; the driver will preserve existing behavior if a cs-gpios list is not given, or if a particular line is specified as <0> (native).
This implementation is inspired by similar implementations in neighboring drivers for other platforms: atmega, mxc, etc.
Signed-off-by: George Hilliard ghilliar@amazon.com Reviewed-by: Stefan Roese sr@denx.de --- drivers/spi/mvebu_a3700_spi.c | 41 ++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/mvebu_a3700_spi.c b/drivers/spi/mvebu_a3700_spi.c index e860b9ec64..eb13cf349e 100644 --- a/drivers/spi/mvebu_a3700_spi.c +++ b/drivers/spi/mvebu_a3700_spi.c @@ -15,6 +15,7 @@ #include <asm/io.h> #include <dm/device_compat.h> #include <linux/bitops.h> +#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -27,6 +28,7 @@ DECLARE_GLOBAL_DATA_PTR; #define MVEBU_SPI_A3700_SPI_EN_0 BIT(16) #define MVEBU_SPI_A3700_CLK_PRESCALE_MASK 0x1f
+#define MAX_CS_COUNT 4
/* SPI registers */ struct spi_reg { @@ -39,16 +41,23 @@ struct spi_reg { struct mvebu_spi_platdata { struct spi_reg *spireg; struct clk clk; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; };
-static void spi_cs_activate(struct spi_reg *reg, int cs) +static void spi_cs_activate(struct mvebu_spi_platdata *plat, int cs) { - setbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); + if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs])) + dm_gpio_set_value(&plat->cs_gpios[cs], 1); + else + setbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); }
-static void spi_cs_deactivate(struct spi_reg *reg, int cs) +static void spi_cs_deactivate(struct mvebu_spi_platdata *plat, int cs) { - clrbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); + if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs])) + dm_gpio_set_value(&plat->cs_gpios[cs], 0); + else + clrbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); }
/** @@ -150,7 +159,7 @@ static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Activate CS */ if (flags & SPI_XFER_BEGIN) { debug("SPI: activate cs.\n"); - spi_cs_activate(reg, spi_chip_select(dev)); + spi_cs_activate(plat, spi_chip_select(dev)); }
/* Send and/or receive */ @@ -169,7 +178,7 @@ static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, return ret;
debug("SPI: deactivate cs.\n"); - spi_cs_deactivate(reg, spi_chip_select(dev)); + spi_cs_deactivate(plat, spi_chip_select(dev)); }
return 0; @@ -247,6 +256,26 @@ static int mvebu_spi_probe(struct udevice *bus)
writel(data, ®->cfg);
+ /* Set up CS GPIOs in device tree, if any */ + if (CONFIG_IS_ENABLED(DM_GPIO) && gpio_get_list_count(bus, "cs-gpios") > 0) { + int i; + + for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) { + ret = gpio_request_by_name(bus, "cs-gpios", i, &plat->cs_gpios[i], 0); + if (ret < 0 || !dm_gpio_is_valid(&plat->cs_gpios[i])) { + /* Use the native CS function for this line */ + continue; + } + + ret = dm_gpio_set_dir_flags(&plat->cs_gpios[i], + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); + if (ret) { + dev_err(bus, "Setting cs %d error\n", i); + return ret; + } + } + } + return 0; }

On 30.09.20 16:28, George Hilliard wrote:
The device tree has a way to specify GPIO lines as chip selects. From the binding docs:
So if for example the controller has 2 CS lines, and the cs-gpios property looks like this: cs-gpios = <&gpio1 0 0> <0> <&gpio1 1 0> <&gpio1 2 0>; Then it should be configured so that num_chipselect = 4 with the following mapping: cs0 : &gpio1 0 0 cs1 : native cs2 : &gpio1 1 0 cs3 : &gpio1 2 0
Add support for this, while retaining backward-compatibility with existing device trees; the driver will preserve existing behavior if a cs-gpios list is not given, or if a particular line is specified as <0> (native).
This implementation is inspired by similar implementations in neighboring drivers for other platforms: atmega, mxc, etc.
Signed-off-by: George Hilliard ghilliar@amazon.com Reviewed-by: Stefan Roese sr@denx.de
Applied to u-boot-marvell/master
Thanks, Stefan
drivers/spi/mvebu_a3700_spi.c | 41 ++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/mvebu_a3700_spi.c b/drivers/spi/mvebu_a3700_spi.c index e860b9ec64..eb13cf349e 100644 --- a/drivers/spi/mvebu_a3700_spi.c +++ b/drivers/spi/mvebu_a3700_spi.c @@ -15,6 +15,7 @@ #include <asm/io.h> #include <dm/device_compat.h> #include <linux/bitops.h> +#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -27,6 +28,7 @@ DECLARE_GLOBAL_DATA_PTR; #define MVEBU_SPI_A3700_SPI_EN_0 BIT(16) #define MVEBU_SPI_A3700_CLK_PRESCALE_MASK 0x1f
+#define MAX_CS_COUNT 4
/* SPI registers */ struct spi_reg { @@ -39,16 +41,23 @@ struct spi_reg { struct mvebu_spi_platdata { struct spi_reg *spireg; struct clk clk;
- struct gpio_desc cs_gpios[MAX_CS_COUNT]; };
-static void spi_cs_activate(struct spi_reg *reg, int cs) +static void spi_cs_activate(struct mvebu_spi_platdata *plat, int cs) {
- setbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
- if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs]))
dm_gpio_set_value(&plat->cs_gpios[cs], 1);
- else
}setbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
-static void spi_cs_deactivate(struct spi_reg *reg, int cs) +static void spi_cs_deactivate(struct mvebu_spi_platdata *plat, int cs) {
- clrbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs]))
dm_gpio_set_value(&plat->cs_gpios[cs], 0);
else
clrbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
}
/**
@@ -150,7 +159,7 @@ static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Activate CS */ if (flags & SPI_XFER_BEGIN) { debug("SPI: activate cs.\n");
spi_cs_activate(reg, spi_chip_select(dev));
spi_cs_activate(plat, spi_chip_select(dev));
}
/* Send and/or receive */
@@ -169,7 +178,7 @@ static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, return ret;
debug("SPI: deactivate cs.\n");
spi_cs_deactivate(reg, spi_chip_select(dev));
spi_cs_deactivate(plat, spi_chip_select(dev));
}
return 0;
@@ -247,6 +256,26 @@ static int mvebu_spi_probe(struct udevice *bus)
writel(data, ®->cfg);
- /* Set up CS GPIOs in device tree, if any */
- if (CONFIG_IS_ENABLED(DM_GPIO) && gpio_get_list_count(bus, "cs-gpios") > 0) {
int i;
for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) {
ret = gpio_request_by_name(bus, "cs-gpios", i, &plat->cs_gpios[i], 0);
if (ret < 0 || !dm_gpio_is_valid(&plat->cs_gpios[i])) {
/* Use the native CS function for this line */
continue;
}
ret = dm_gpio_set_dir_flags(&plat->cs_gpios[i],
GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
if (ret) {
dev_err(bus, "Setting cs %d error\n", i);
return ret;
}
}
- }
- return 0; }
Viele Grüße, Stefan
participants (2)
-
George Hilliard
-
Stefan Roese