spi: oc-tiny: Use GPIO descriptors

Switch the OC Tiny driver over to handling CS GPIOs using
GPIO descriptors in the core.

This driver is entirely relying on GPIOs to be used for
chipselect, so let the core pick these out using either
device tree or machine descriptors.

There are no in-tree users of this driver so no board files
need to be patched, out-of-tree boardfiles can use machine
descriptor tables, c.f. commit 1dfbf334f1.

Cc: Thomas Chou <thomas@wytron.com.tw>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20191205092411.64341-1-linus.walleij@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Linus Walleij 2019-12-05 10:24:11 +01:00 committed by Mark Brown
parent 28d1dddc59
commit f03ee2042b
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 1 additions and 53 deletions

View File

@ -20,7 +20,6 @@
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
#include <linux/spi/spi_oc_tiny.h> #include <linux/spi/spi_oc_tiny.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of.h> #include <linux/of.h>
#define DRV_NAME "spi_oc_tiny" #define DRV_NAME "spi_oc_tiny"
@ -50,8 +49,6 @@ struct tiny_spi {
unsigned int txc, rxc; unsigned int txc, rxc;
const u8 *txp; const u8 *txp;
u8 *rxp; u8 *rxp;
int gpio_cs_count;
int *gpio_cs;
}; };
static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev) static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev)
@ -66,16 +63,6 @@ static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz)
return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1; return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1;
} }
static void tiny_spi_chipselect(struct spi_device *spi, int is_active)
{
struct tiny_spi *hw = tiny_spi_to_hw(spi);
if (hw->gpio_cs_count > 0) {
gpio_set_value(hw->gpio_cs[spi->chip_select],
(spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
}
}
static int tiny_spi_setup_transfer(struct spi_device *spi, static int tiny_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
@ -203,24 +190,10 @@ static int tiny_spi_of_probe(struct platform_device *pdev)
{ {
struct tiny_spi *hw = platform_get_drvdata(pdev); struct tiny_spi *hw = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
unsigned int i;
u32 val; u32 val;
if (!np) if (!np)
return 0; return 0;
hw->gpio_cs_count = of_gpio_count(np);
if (hw->gpio_cs_count > 0) {
hw->gpio_cs = devm_kcalloc(&pdev->dev,
hw->gpio_cs_count, sizeof(unsigned int),
GFP_KERNEL);
if (!hw->gpio_cs)
return -ENOMEM;
}
for (i = 0; i < hw->gpio_cs_count; i++) {
hw->gpio_cs[i] = of_get_gpio_flags(np, i, NULL);
if (hw->gpio_cs[i] < 0)
return -ENODEV;
}
hw->bitbang.master->dev.of_node = pdev->dev.of_node; hw->bitbang.master->dev.of_node = pdev->dev.of_node;
if (!of_property_read_u32(np, "clock-frequency", &val)) if (!of_property_read_u32(np, "clock-frequency", &val))
hw->freq = val; hw->freq = val;
@ -240,7 +213,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev); struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct tiny_spi *hw; struct tiny_spi *hw;
struct spi_master *master; struct spi_master *master;
unsigned int i;
int err = -ENODEV; int err = -ENODEV;
master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi)); master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi));
@ -249,9 +221,9 @@ static int tiny_spi_probe(struct platform_device *pdev)
/* setup the master state. */ /* setup the master state. */
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->num_chipselect = 255;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = tiny_spi_setup; master->setup = tiny_spi_setup;
master->use_gpio_descriptors = true;
hw = spi_master_get_devdata(master); hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw); platform_set_drvdata(pdev, hw);
@ -259,7 +231,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
/* setup the state for the bitbang driver */ /* setup the state for the bitbang driver */
hw->bitbang.master = master; hw->bitbang.master = master;
hw->bitbang.setup_transfer = tiny_spi_setup_transfer; hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
hw->bitbang.chipselect = tiny_spi_chipselect;
hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs; hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
/* find and map our resources */ /* find and map our resources */
@ -279,12 +250,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
} }
/* find platform data */ /* find platform data */
if (platp) { if (platp) {
hw->gpio_cs_count = platp->gpio_cs_count;
hw->gpio_cs = platp->gpio_cs;
if (platp->gpio_cs_count && !platp->gpio_cs) {
err = -EBUSY;
goto exit;
}
hw->freq = platp->freq; hw->freq = platp->freq;
hw->baudwidth = platp->baudwidth; hw->baudwidth = platp->baudwidth;
} else { } else {
@ -292,13 +257,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
if (err) if (err)
goto exit; goto exit;
} }
for (i = 0; i < hw->gpio_cs_count; i++) {
err = gpio_request(hw->gpio_cs[i], dev_name(&pdev->dev));
if (err)
goto exit_gpio;
gpio_direction_output(hw->gpio_cs[i], 1);
}
hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count);
/* register our spi controller */ /* register our spi controller */
err = spi_bitbang_start(&hw->bitbang); err = spi_bitbang_start(&hw->bitbang);
@ -308,9 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
return 0; return 0;
exit_gpio:
while (i-- > 0)
gpio_free(hw->gpio_cs[i]);
exit: exit:
spi_master_put(master); spi_master_put(master);
return err; return err;
@ -320,11 +275,8 @@ static int tiny_spi_remove(struct platform_device *pdev)
{ {
struct tiny_spi *hw = platform_get_drvdata(pdev); struct tiny_spi *hw = platform_get_drvdata(pdev);
struct spi_master *master = hw->bitbang.master; struct spi_master *master = hw->bitbang.master;
unsigned int i;
spi_bitbang_stop(&hw->bitbang); spi_bitbang_stop(&hw->bitbang);
for (i = 0; i < hw->gpio_cs_count; i++)
gpio_free(hw->gpio_cs[i]);
spi_master_put(master); spi_master_put(master);
return 0; return 0;
} }

View File

@ -6,16 +6,12 @@
* struct tiny_spi_platform_data - platform data of the OpenCores tiny SPI * struct tiny_spi_platform_data - platform data of the OpenCores tiny SPI
* @freq: input clock freq to the core. * @freq: input clock freq to the core.
* @baudwidth: baud rate divider width of the core. * @baudwidth: baud rate divider width of the core.
* @gpio_cs_count: number of gpio pins used for chipselect.
* @gpio_cs: array of gpio pins used for chipselect.
* *
* freq and baudwidth are used only if the divider is programmable. * freq and baudwidth are used only if the divider is programmable.
*/ */
struct tiny_spi_platform_data { struct tiny_spi_platform_data {
unsigned int freq; unsigned int freq;
unsigned int baudwidth; unsigned int baudwidth;
unsigned int gpio_cs_count;
int *gpio_cs;
}; };
#endif /* _LINUX_SPI_SPI_OC_TINY_H */ #endif /* _LINUX_SPI_SPI_OC_TINY_H */