Skip to content

Commit

Permalink
spi: atmel: Convert to use CS GPIO descriptors
Browse files Browse the repository at this point in the history
This converts the Atmel SPI master driver to use GPIO descriptors
for chip select handling.

The Atmel driver has duplicate code to look up and initialize CS
GPIOs from the device tree, so this is removed. It further has code
to retrieve a CS GPIO from .controller_data but this seems to be
completely unused in the kernel (legacy codepath?) so I deleted
this support. It keeps track of polarity when switching the CS, but
this is not needed anymore since we moved this over to the gpiolib.

The local handling of the "npcs_pin" (I guess this might mean
"negative polarity chip select pin") is preserved, but I strongly
suspect this can be switched over to handling by the core and
using the SPI_MASTER_GPIO_SS flag on the master to assure that
the additional CS handling in the driver is also done.

Cc: Eugen Hristev <eugen.hristev@microchip.com>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
Cc: Radu Pirea <radu.pirea@microchip.com>
Cc: Linuxarm <linuxarm@huawei.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Linus Walleij authored and Mark Brown committed Jan 9, 2019
1 parent 8db7954 commit efc92fb
Showing 1 changed file with 27 additions and 66 deletions.
93 changes: 27 additions & 66 deletions drivers/spi/spi-atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
#include <linux/of.h>

#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>

Expand Down Expand Up @@ -312,7 +311,7 @@ struct atmel_spi {

/* Controller-specific per-slave state */
struct atmel_spi_device {
unsigned int npcs_pin;
struct gpio_desc *npcs_pin;
u32 csr;
};

Expand Down Expand Up @@ -355,7 +354,6 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
{
struct atmel_spi_device *asd = spi->controller_state;
unsigned active = spi->mode & SPI_CS_HIGH;
u32 mr;

if (atmel_spi_is_v2(as)) {
Expand All @@ -379,7 +377,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)

mr = spi_readl(as, MR);
if (as->use_cs_gpios)
gpio_set_value(asd->npcs_pin, active);
gpiod_set_value(asd->npcs_pin, 1);
} else {
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
int i;
Expand All @@ -396,19 +394,16 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
mr = spi_readl(as, MR);
mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
if (as->use_cs_gpios && spi->chip_select != 0)
gpio_set_value(asd->npcs_pin, active);
gpiod_set_value(asd->npcs_pin, 1);
spi_writel(as, MR, mr);
}

dev_dbg(&spi->dev, "activate %u%s, mr %08x\n",
asd->npcs_pin, active ? " (high)" : "",
mr);
dev_dbg(&spi->dev, "activate NPCS, mr %08x\n", mr);
}

static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
{
struct atmel_spi_device *asd = spi->controller_state;
unsigned active = spi->mode & SPI_CS_HIGH;
u32 mr;

/* only deactivate *this* device; sometimes transfers to
Expand All @@ -420,14 +415,12 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
spi_writel(as, MR, mr);
}

dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n",
asd->npcs_pin, active ? " (low)" : "",
mr);
dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", mr);

if (!as->use_cs_gpios)
spi_writel(as, CR, SPI_BIT(LASTXFER));
else if (atmel_spi_is_v2(as) || spi->chip_select != 0)
gpio_set_value(asd->npcs_pin, !active);
gpiod_set_value(asd->npcs_pin, 0);
}

static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
Expand Down Expand Up @@ -1188,7 +1181,6 @@ static int atmel_spi_setup(struct spi_device *spi)
struct atmel_spi_device *asd;
u32 csr;
unsigned int bits = spi->bits_per_word;
unsigned int npcs_pin;

as = spi_master_get_devdata(spi->master);

Expand Down Expand Up @@ -1217,25 +1209,27 @@ static int atmel_spi_setup(struct spi_device *spi)
csr |= SPI_BF(DLYBS, 0);
csr |= SPI_BF(DLYBCT, 0);

/* chipselect must have been muxed as GPIO (e.g. in board setup) */
npcs_pin = (unsigned long)spi->controller_data;

if (!as->use_cs_gpios)
npcs_pin = spi->chip_select;
else if (gpio_is_valid(spi->cs_gpio))
npcs_pin = spi->cs_gpio;

asd = spi->controller_state;
if (!asd) {
asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
if (!asd)
return -ENOMEM;

if (as->use_cs_gpios)
gpio_direction_output(npcs_pin,
!(spi->mode & SPI_CS_HIGH));
/*
* If use_cs_gpios is true this means that we have "cs-gpios"
* defined in the device tree node so we should have
* gotten the GPIO lines from the device tree inside the
* SPI core. Warn if this is not the case but continue since
* CS GPIOs are after all optional.
*/
if (as->use_cs_gpios) {
if (!spi->cs_gpiod) {
dev_err(&spi->dev,
"host claims to use CS GPIOs but no CS found in DT by the SPI core\n");
}
asd->npcs_pin = spi->cs_gpiod;
}

asd->npcs_pin = npcs_pin;
spi->controller_state = asd;
}

Expand Down Expand Up @@ -1473,41 +1467,6 @@ static void atmel_get_caps(struct atmel_spi *as)
as->caps.has_pdc_support = version < 0x212;
}

/*-------------------------------------------------------------------------*/
static int atmel_spi_gpio_cs(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
struct device_node *np = master->dev.of_node;
int i;
int ret = 0;
int nb = 0;

if (!as->use_cs_gpios)
return 0;

if (!np)
return 0;

nb = of_gpio_named_count(np, "cs-gpios");
for (i = 0; i < nb; i++) {
int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
"cs-gpios", i);

if (cs_gpio == -EPROBE_DEFER)
return cs_gpio;

if (gpio_is_valid(cs_gpio)) {
ret = devm_gpio_request(&pdev->dev, cs_gpio,
dev_name(&pdev->dev));
if (ret)
return ret;
}
}

return 0;
}

static void atmel_spi_init(struct atmel_spi *as)
{
spi_writel(as, CR, SPI_BIT(SWRST));
Expand Down Expand Up @@ -1560,6 +1519,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
goto out_free;

/* the spi->mode bits understood by this driver: */
master->use_gpio_descriptors = true;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
master->dev.of_node = pdev->dev.of_node;
Expand Down Expand Up @@ -1592,6 +1552,11 @@ static int atmel_spi_probe(struct platform_device *pdev)

atmel_get_caps(as);

/*
* If there are chip selects in the device tree, those will be
* discovered by the SPI core when registering the SPI master
* and assigned to each SPI device.
*/
as->use_cs_gpios = true;
if (atmel_spi_is_v2(as) &&
pdev->dev.of_node &&
Expand All @@ -1600,10 +1565,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
master->num_chipselect = 4;
}

ret = atmel_spi_gpio_cs(pdev);
if (ret)
goto out_unmap_regs;

as->use_dma = false;
as->use_pdc = false;
if (as->caps.has_dma_support) {
Expand Down

0 comments on commit efc92fb

Please sign in to comment.