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

spi: ppc4xx: Convert to use GPIO descriptors

This converts the PPC4xx SPI driver to use GPIO descriptors.

The driver is already just picking some GPIOs from the device
tree so the conversion is pretty straight forward. However
this driver is looking form a pure "gpios" property rather
than the standard binding "cs-gpios" so we need to add a new
exception to the gpiolib OF parser to allow this for this
driver's compatibles.
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Cc: linuxppc-dev@lists.ozlabs.org
Link: https://lore.kernel.org/r/20200714072226.26071-1-linus.walleij@linaro.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent ce8e60fe
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
/** /**
* of_gpio_spi_cs_get_count() - special GPIO counting for SPI * of_gpio_spi_cs_get_count() - special GPIO counting for SPI
* Some elder GPIO controllers need special quirks. Currently we handle * Some elder GPIO controllers need special quirks. Currently we handle
* the Freescale GPIO controller with bindings that doesn't use the * the Freescale and PPC GPIO controller with bindings that doesn't use the
* established "cs-gpios" for chip selects but instead rely on * established "cs-gpios" for chip selects but instead rely on
* "gpios" for the chip select lines. If we detect this, we redirect * "gpios" for the chip select lines. If we detect this, we redirect
* the counting of "cs-gpios" to count "gpios" transparent to the * the counting of "cs-gpios" to count "gpios" transparent to the
...@@ -41,7 +41,8 @@ static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id) ...@@ -41,7 +41,8 @@ static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
if (!con_id || strcmp(con_id, "cs")) if (!con_id || strcmp(con_id, "cs"))
return 0; return 0;
if (!of_device_is_compatible(np, "fsl,spi") && if (!of_device_is_compatible(np, "fsl,spi") &&
!of_device_is_compatible(np, "aeroflexgaisler,spictrl")) !of_device_is_compatible(np, "aeroflexgaisler,spictrl") &&
!of_device_is_compatible(np, "ibm,ppc4xx-spi"))
return 0; return 0;
return of_gpio_named_count(np, "gpios"); return of_gpio_named_count(np, "gpios");
} }
...@@ -405,9 +406,10 @@ static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev, ...@@ -405,9 +406,10 @@ static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
if (!IS_ENABLED(CONFIG_SPI_MASTER)) if (!IS_ENABLED(CONFIG_SPI_MASTER))
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
/* Allow this specifically for Freescale devices */ /* Allow this specifically for Freescale and PPC devices */
if (!of_device_is_compatible(np, "fsl,spi") && if (!of_device_is_compatible(np, "fsl,spi") &&
!of_device_is_compatible(np, "aeroflexgaisler,spictrl")) !of_device_is_compatible(np, "aeroflexgaisler,spictrl") &&
!of_device_is_compatible(np, "ibm,ppc4xx-spi"))
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
/* Allow only if asking for "cs-gpios" */ /* Allow only if asking for "cs-gpios" */
if (!con_id || strcmp(con_id, "cs")) if (!con_id || strcmp(con_id, "cs"))
......
...@@ -28,11 +28,9 @@ ...@@ -28,11 +28,9 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
...@@ -127,8 +125,6 @@ struct ppc4xx_spi { ...@@ -127,8 +125,6 @@ struct ppc4xx_spi {
const unsigned char *tx; const unsigned char *tx;
unsigned char *rx; unsigned char *rx;
int *gpios;
struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */ struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
struct spi_master *master; struct spi_master *master;
struct device *dev; struct device *dev;
...@@ -260,27 +256,6 @@ static int spi_ppc4xx_setup(struct spi_device *spi) ...@@ -260,27 +256,6 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
return 0; return 0;
} }
static void spi_ppc4xx_chipsel(struct spi_device *spi, int value)
{
struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
unsigned int cs = spi->chip_select;
unsigned int cspol;
/*
* If there are no chip selects at all, or if this is the special
* case of a non-existent (dummy) chip select, do nothing.
*/
if (!hw->master->num_chipselect || hw->gpios[cs] == -EEXIST)
return;
cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
if (value == BITBANG_CS_INACTIVE)
cspol = !cspol;
gpio_set_value(hw->gpios[cs], cspol);
}
static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id) static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
{ {
struct ppc4xx_spi *hw; struct ppc4xx_spi *hw;
...@@ -359,19 +334,6 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw) ...@@ -359,19 +334,6 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0); dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0);
} }
static void free_gpios(struct ppc4xx_spi *hw)
{
if (hw->master->num_chipselect) {
int i;
for (i = 0; i < hw->master->num_chipselect; i++)
if (gpio_is_valid(hw->gpios[i]))
gpio_free(hw->gpios[i]);
kfree(hw->gpios);
hw->gpios = NULL;
}
}
/* /*
* platform_device layer stuff... * platform_device layer stuff...
*/ */
...@@ -385,7 +347,6 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ...@@ -385,7 +347,6 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
struct device *dev = &op->dev; struct device *dev = &op->dev;
struct device_node *opbnp; struct device_node *opbnp;
int ret; int ret;
int num_gpios;
const unsigned int *clk; const unsigned int *clk;
master = spi_alloc_master(dev, sizeof *hw); master = spi_alloc_master(dev, sizeof *hw);
...@@ -399,74 +360,32 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ...@@ -399,74 +360,32 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
init_completion(&hw->done); init_completion(&hw->done);
/*
* A count of zero implies a single SPI device without any chip-select.
* Note that of_gpio_count counts all gpios assigned to this spi master.
* This includes both "null" gpio's and real ones.
*/
num_gpios = of_gpio_count(np);
if (num_gpios > 0) {
int i;
hw->gpios = kcalloc(num_gpios, sizeof(*hw->gpios), GFP_KERNEL);
if (!hw->gpios) {
ret = -ENOMEM;
goto free_master;
}
for (i = 0; i < num_gpios; i++) {
int gpio;
enum of_gpio_flags flags;
gpio = of_get_gpio_flags(np, i, &flags);
hw->gpios[i] = gpio;
if (gpio_is_valid(gpio)) {
/* Real CS - set the initial state. */
ret = gpio_request(gpio, np->name);
if (ret < 0) {
dev_err(dev,
"can't request gpio #%d: %d\n",
i, ret);
goto free_gpios;
}
gpio_direction_output(gpio,
!!(flags & OF_GPIO_ACTIVE_LOW));
} else if (gpio == -EEXIST) {
; /* No CS, but that's OK. */
} else {
dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
ret = -EINVAL;
goto free_gpios;
}
}
}
/* Setup the state for the bitbang driver */ /* Setup the state for the bitbang driver */
bbp = &hw->bitbang; bbp = &hw->bitbang;
bbp->master = hw->master; bbp->master = hw->master;
bbp->setup_transfer = spi_ppc4xx_setupxfer; bbp->setup_transfer = spi_ppc4xx_setupxfer;
bbp->chipselect = spi_ppc4xx_chipsel;
bbp->txrx_bufs = spi_ppc4xx_txrx; bbp->txrx_bufs = spi_ppc4xx_txrx;
bbp->use_dma = 0; bbp->use_dma = 0;
bbp->master->setup = spi_ppc4xx_setup; bbp->master->setup = spi_ppc4xx_setup;
bbp->master->cleanup = spi_ppc4xx_cleanup; bbp->master->cleanup = spi_ppc4xx_cleanup;
bbp->master->bits_per_word_mask = SPI_BPW_MASK(8); bbp->master->bits_per_word_mask = SPI_BPW_MASK(8);
bbp->master->use_gpio_descriptors = true;
/*
* The SPI core will count the number of GPIO descriptors to figure
* out the number of chip selects available on the platform.
*/
bbp->master->num_chipselect = 0;
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
bbp->master->mode_bits = bbp->master->mode_bits =
SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST; SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
/* this many pins in all GPIO controllers */
bbp->master->num_chipselect = num_gpios > 0 ? num_gpios : 0;
/* Get the clock for the OPB */ /* Get the clock for the OPB */
opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb"); opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
if (opbnp == NULL) { if (opbnp == NULL) {
dev_err(dev, "OPB: cannot find node\n"); dev_err(dev, "OPB: cannot find node\n");
ret = -ENODEV; ret = -ENODEV;
goto free_gpios; goto free_master;
} }
/* Get the clock (Hz) for the OPB */ /* Get the clock (Hz) for the OPB */
clk = of_get_property(opbnp, "clock-frequency", NULL); clk = of_get_property(opbnp, "clock-frequency", NULL);
...@@ -474,7 +393,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ...@@ -474,7 +393,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
dev_err(dev, "OPB: no clock-frequency property set\n"); dev_err(dev, "OPB: no clock-frequency property set\n");
of_node_put(opbnp); of_node_put(opbnp);
ret = -ENODEV; ret = -ENODEV;
goto free_gpios; goto free_master;
} }
hw->opb_freq = *clk; hw->opb_freq = *clk;
hw->opb_freq >>= 2; hw->opb_freq >>= 2;
...@@ -483,7 +402,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ...@@ -483,7 +402,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
ret = of_address_to_resource(np, 0, &resource); ret = of_address_to_resource(np, 0, &resource);
if (ret) { if (ret) {
dev_err(dev, "error while parsing device node resource\n"); dev_err(dev, "error while parsing device node resource\n");
goto free_gpios; goto free_master;
} }
hw->mapbase = resource.start; hw->mapbase = resource.start;
hw->mapsize = resource_size(&resource); hw->mapsize = resource_size(&resource);
...@@ -492,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ...@@ -492,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) { if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
dev_err(dev, "too small to map registers\n"); dev_err(dev, "too small to map registers\n");
ret = -EINVAL; ret = -EINVAL;
goto free_gpios; goto free_master;
} }
/* Request IRQ */ /* Request IRQ */
...@@ -501,7 +420,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ...@@ -501,7 +420,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
0, "spi_ppc4xx_of", (void *)hw); 0, "spi_ppc4xx_of", (void *)hw);
if (ret) { if (ret) {
dev_err(dev, "unable to allocate interrupt\n"); dev_err(dev, "unable to allocate interrupt\n");
goto free_gpios; goto free_master;
} }
if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) { if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
...@@ -538,8 +457,6 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) ...@@ -538,8 +457,6 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
release_mem_region(hw->mapbase, hw->mapsize); release_mem_region(hw->mapbase, hw->mapsize);
request_mem_error: request_mem_error:
free_irq(hw->irqnum, hw); free_irq(hw->irqnum, hw);
free_gpios:
free_gpios(hw);
free_master: free_master:
spi_master_put(master); spi_master_put(master);
...@@ -556,7 +473,6 @@ static int spi_ppc4xx_of_remove(struct platform_device *op) ...@@ -556,7 +473,6 @@ static int spi_ppc4xx_of_remove(struct platform_device *op)
release_mem_region(hw->mapbase, hw->mapsize); release_mem_region(hw->mapbase, hw->mapsize);
free_irq(hw->irqnum, hw); free_irq(hw->irqnum, hw);
iounmap(hw->regs); iounmap(hw->regs);
free_gpios(hw);
spi_master_put(master); spi_master_put(master);
return 0; return 0;
} }
......
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