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>
This commit is contained in:
parent
87c220d041
commit
2df286390a
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user