aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi/spi-xilinx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-xilinx.c')
-rw-r--r--drivers/spi/spi-xilinx.c243
1 files changed, 92 insertions, 151 deletions
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 34d18dcfa0d..a3b0b9944bf 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -30,6 +29,7 @@
*/
#define XSPI_CR_OFFSET 0x60 /* Control Register */
+#define XSPI_CR_LOOP 0x01
#define XSPI_CR_ENABLE 0x02
#define XSPI_CR_MASTER_MODE 0x04
#define XSPI_CR_CPOL 0x08
@@ -79,19 +79,18 @@ struct xilinx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
- struct resource mem; /* phys mem */
void __iomem *regs; /* virt. address of the control registers */
- u32 irq;
+ int irq;
u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */
u8 bits_per_word;
- unsigned int (*read_fn) (void __iomem *);
- void (*write_fn) (u32, void __iomem *);
- void (*tx_fn) (struct xilinx_spi *);
- void (*rx_fn) (struct xilinx_spi *);
+ unsigned int (*read_fn)(void __iomem *);
+ void (*write_fn)(u32, void __iomem *);
+ void (*tx_fn)(struct xilinx_spi *);
+ void (*rx_fn)(struct xilinx_spi *);
};
static void xspi_write32(u32 val, void __iomem *addr)
@@ -209,41 +208,11 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
- * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
- * supports 8 or 16 bits per word which cannot be changed in software.
- * SPI clock can't be changed in software either.
- * Check for correct bits per word. Chip select delay calculations could be
- * added here as soon as bitbang_work() can be made aware of the delay value.
+ * custom txrx_bufs().
*/
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- u8 bits_per_word;
-
- bits_per_word = (t && t->bits_per_word)
- ? t->bits_per_word : spi->bits_per_word;
- if (bits_per_word != xspi->bits_per_word) {
- dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
- __func__, bits_per_word);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int xilinx_spi_setup(struct spi_device *spi)
-{
- /* always return 0, we can not check the number of bits.
- * There are cases when SPI setup is called before any driver is
- * there, in that case the SPI core defaults to 8 bits, which we
- * do not support in some cases. But if we return an error, the
- * SPI device would not be registered and no driver can get hold of it
- * When the driver is there, it will call SPI setup again with the
- * correct number of bits per transfer.
- * If a driver setups with the wrong bit number, it will fail when
- * it tries to do a transfer
- */
return 0;
}
@@ -273,7 +242,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf;
xspi->remaining_bytes = t->len;
- INIT_COMPLETION(xspi->done);
+ reinit_completion(&xspi->done);
/* Enable the transmit empty interrupt, which we use to determine
@@ -315,7 +284,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
}
/* See if there is more data to send */
- if (!xspi->remaining_bytes > 0)
+ if (xspi->remaining_bytes <= 0)
break;
}
@@ -354,51 +323,75 @@ static const struct of_device_id xilinx_spi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
- u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word)
+static int xilinx_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
struct xilinx_spi *xspi;
- int ret;
+ struct xspi_platform_data *pdata;
+ struct resource *res;
+ int ret, num_cs = 0, bits_per_word = 8;
+ struct spi_master *master;
+ u32 tmp;
+ u8 i;
- master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
+ pdata = dev_get_platdata(&pdev->dev);
+ if (pdata) {
+ num_cs = pdata->num_chipselect;
+ bits_per_word = pdata->bits_per_word;
+ } else {
+ of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
+ &num_cs);
+ }
+
+ if (!num_cs) {
+ dev_err(&pdev->dev,
+ "Missing slave select configuration data\n");
+ return -EINVAL;
+ }
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
if (!master)
- return NULL;
+ return -ENODEV;
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
xspi = spi_master_get_devdata(master);
- xspi->bitbang.master = spi_master_get(master);
+ xspi->bitbang.master = master;
xspi->bitbang.chipselect = xilinx_spi_chipselect;
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
- xspi->bitbang.master->setup = xilinx_spi_setup;
init_completion(&xspi->done);
- if (!request_mem_region(mem->start, resource_size(mem),
- XILINX_SPI_NAME))
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xspi->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(xspi->regs)) {
+ ret = PTR_ERR(xspi->regs);
goto put_master;
-
- xspi->regs = ioremap(mem->start, resource_size(mem));
- if (xspi->regs == NULL) {
- dev_warn(dev, "ioremap failure\n");
- goto map_failed;
}
- master->bus_num = bus_num;
+ master->bus_num = pdev->dev.id;
master->num_chipselect = num_cs;
- master->dev.of_node = dev->of_node;
+ master->dev.of_node = pdev->dev.of_node;
+
+ /*
+ * Detect endianess on the IP via loop bit in CR. Detection
+ * must be done before reset is sent because incorrect reset
+ * value generates error interrupt.
+ * Setup little endian helper functions first and try to use them
+ * and check if bit was correctly setup or not.
+ */
+ xspi->read_fn = xspi_read32;
+ xspi->write_fn = xspi_write32;
- xspi->mem = *mem;
- xspi->irq = irq;
- if (little_endian) {
- xspi->read_fn = xspi_read32;
- xspi->write_fn = xspi_write32;
- } else {
+ xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET);
+ tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
+ tmp &= XSPI_CR_LOOP;
+ if (tmp != XSPI_CR_LOOP) {
xspi->read_fn = xspi_read32_be;
xspi->write_fn = xspi_write32_be;
}
+
+ master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
xspi->bits_per_word = bits_per_word;
if (xspi->bits_per_word == 8) {
xspi->tx_fn = xspi_tx8;
@@ -409,115 +402,63 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
} else if (xspi->bits_per_word == 32) {
xspi->tx_fn = xspi_tx32;
xspi->rx_fn = xspi_rx32;
- } else
- goto unmap_io;
-
+ } else {
+ ret = -EINVAL;
+ goto put_master;
+ }
/* SPI controller initializations */
xspi_init_hw(xspi);
+ xspi->irq = platform_get_irq(pdev, 0);
+ if (xspi->irq < 0) {
+ ret = xspi->irq;
+ goto put_master;
+ }
+
/* Register for SPI Interrupt */
- ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+ ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
+ dev_name(&pdev->dev), xspi);
if (ret)
- goto unmap_io;
+ goto put_master;
ret = spi_bitbang_start(&xspi->bitbang);
if (ret) {
- dev_err(dev, "spi_bitbang_start FAILED\n");
- goto free_irq;
- }
-
- dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
- (unsigned long long)mem->start, xspi->regs, xspi->irq);
- return master;
-
-free_irq:
- free_irq(xspi->irq, xspi);
-unmap_io:
- iounmap(xspi->regs);
-map_failed:
- release_mem_region(mem->start, resource_size(mem));
-put_master:
- spi_master_put(master);
- return NULL;
-}
-EXPORT_SYMBOL(xilinx_spi_init);
-
-void xilinx_spi_deinit(struct spi_master *master)
-{
- struct xilinx_spi *xspi;
-
- xspi = spi_master_get_devdata(master);
-
- spi_bitbang_stop(&xspi->bitbang);
- free_irq(xspi->irq, xspi);
- iounmap(xspi->regs);
-
- release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
- spi_master_put(xspi->bitbang.master);
-}
-EXPORT_SYMBOL(xilinx_spi_deinit);
-
-static int xilinx_spi_probe(struct platform_device *dev)
-{
- struct xspi_platform_data *pdata;
- struct resource *r;
- int irq, num_cs = 0, little_endian = 0, bits_per_word = 8;
- struct spi_master *master;
- u8 i;
-
- pdata = dev->dev.platform_data;
- if (pdata) {
- num_cs = pdata->num_chipselect;
- little_endian = pdata->little_endian;
- bits_per_word = pdata->bits_per_word;
- }
-
-#ifdef CONFIG_OF
- if (dev->dev.of_node) {
- const __be32 *prop;
- int len;
-
- /* number of slave select bits is required */
- prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits",
- &len);
- if (prop && len >= sizeof(*prop))
- num_cs = __be32_to_cpup(prop);
- }
-#endif
-
- if (!num_cs) {
- dev_err(&dev->dev, "Missing slave select configuration data\n");
- return -EINVAL;
+ dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
+ goto put_master;
}
-
- r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!r)
- return -ENODEV;
-
- irq = platform_get_irq(dev, 0);
- if (irq < 0)
- return -ENXIO;
-
- master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
- little_endian, bits_per_word);
- if (!master)
- return -ENODEV;
+ dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
+ (unsigned long long)res->start, xspi->regs, xspi->irq);
if (pdata) {
for (i = 0; i < pdata->num_devices; i++)
spi_new_device(master, pdata->devices + i);
}
- platform_set_drvdata(dev, master);
+ platform_set_drvdata(pdev, master);
return 0;
+
+put_master:
+ spi_master_put(master);
+
+ return ret;
}
-static int xilinx_spi_remove(struct platform_device *dev)
+static int xilinx_spi_remove(struct platform_device *pdev)
{
- xilinx_spi_deinit(platform_get_drvdata(dev));
- platform_set_drvdata(dev, 0);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct xilinx_spi *xspi = spi_master_get_devdata(master);
+ void __iomem *regs_base = xspi->regs;
+
+ spi_bitbang_stop(&xspi->bitbang);
+
+ /* Disable all the interrupts just in case */
+ xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
+ /* Disable the global IPIF interrupt */
+ xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
+
+ spi_master_put(xspi->bitbang.master);
return 0;
}