From 9bf46f6df5d1e9db8b4b786d22e88d8b6edd949e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Feb 2014 21:06:43 +0800 Subject: [PATCH 1/6] spi: xilinx: Convert to let spi core validate bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. spi_bitbang requires custom setup_transfer() to be defined if there is a custom txrx_bufs(). Thus keep the empty xilinx_spi_setup_transfer() function in the code. Signed-off-by: Axel Lin Acked-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 6d4ce4615163..4eb1ed9ab6da 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -209,26 +209,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; } @@ -407,6 +392,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) 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; From 6ff8672a96a01ec0861784b23be48a32443269f7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:24:47 +0900 Subject: [PATCH 2/6] spi: xilinx: remove unnecessary spaces Remove unnecessary space in order to fix the following checkpatch issues. WARNING: Unnecessary space after function pointer name Signed-off-by: Jingoo Han Reviewed-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 4eb1ed9ab6da..85082a85ee37 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -88,10 +88,10 @@ struct xilinx_spi { 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) From 6840cc29f2bcc9a06a7245d17e0e2f38fbc20df0 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 12 Mar 2014 21:55:24 +0400 Subject: [PATCH 3/6] spi: add xtfpga SPI controller driver This simple SPI master controller is built into xtfpga bitstreams. It always transfers 16 bit words in SPI mode 0, automatically asserting CS on transfer start and deasserting on end. Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 13 +++ drivers/spi/Makefile | 1 + drivers/spi/spi-xtensa-xtfpga.c | 170 ++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 drivers/spi/spi-xtensa-xtfpga.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..c87475db0f79 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -520,6 +520,19 @@ config SPI_XILINX Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" +config SPI_XTENSA_XTFPGA + tristate "Xtensa SPI controller for xtfpga" + depends on XTENSA && XTENSA_PLATFORM_XTFPGA + select SPI_BITBANG + help + SPI driver for xtfpga SPI master controller. + + This simple SPI master controller is built into xtfpga bitstreams + and is used to control daughterboard audio codec. It always transfers + 16 bit words in SPI mode 0, automatically asserting CS on transfer + start and deasserting on end. + + config SPI_NUC900 tristate "Nuvoton NUC900 series SPI" depends on ARCH_W90X900 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 95af48d2d360..5379adee0a77 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -79,3 +79,4 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o +obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c new file mode 100644 index 000000000000..41e158187f9d --- /dev/null +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -0,0 +1,170 @@ +/* + * Xtensa xtfpga SPI controller driver + * + * Copyright (c) 2014 Cadence Design Systems Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define XTFPGA_SPI_NAME "xtfpga_spi" + +#define XTFPGA_SPI_START 0x0 +#define XTFPGA_SPI_BUSY 0x4 +#define XTFPGA_SPI_DATA 0x8 + +#define BUSY_WAIT_US 100 + +struct xtfpga_spi { + struct spi_bitbang bitbang; + void __iomem *regs; + u32 data; + unsigned data_sz; +}; + +static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi, + unsigned addr, u32 val) +{ + iowrite32(val, spi->regs + addr); +} + +static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi, + unsigned addr) +{ + return ioread32(spi->regs + addr); +} + +static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi) +{ + unsigned i; + for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) && + i < BUSY_WAIT_US; ++i) + udelay(1); + WARN_ON_ONCE(i == BUSY_WAIT_US); +} + +static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs, + u32 v, u8 bits) +{ + struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master); + + xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0)); + xspi->data_sz += bits; + if (xspi->data_sz >= 16) { + xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA, + xspi->data >> (xspi->data_sz - 16)); + xspi->data_sz -= 16; + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1); + xtfpga_spi_wait_busy(xspi); + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0); + } + + return 0; +} + +static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on) +{ + struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master); + + WARN_ON(xspi->data_sz != 0); + xspi->data_sz = 0; +} + +static int xtfpga_spi_probe(struct platform_device *pdev) +{ + struct xtfpga_spi *xspi; + struct resource *mem; + int ret; + struct spi_master *master; + + master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi)); + if (!master) + return -ENOMEM; + + master->flags = SPI_MASTER_NO_RX; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + master->bus_num = pdev->dev.id; + master->dev.of_node = pdev->dev.of_node; + + xspi = spi_master_get_devdata(master); + xspi->bitbang.master = master; + xspi->bitbang.chipselect = xtfpga_spi_chipselect; + xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err; + } + xspi->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(xspi->regs)) { + ret = PTR_ERR(xspi->regs); + goto err; + } + + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0); + usleep_range(1000, 2000); + if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) { + dev_err(&pdev->dev, "Device stuck in busy state\n"); + ret = -EBUSY; + goto err; + } + + ret = spi_bitbang_start(&xspi->bitbang); + if (ret < 0) { + dev_err(&pdev->dev, "spi_bitbang_start failed\n"); + goto err; + } + + platform_set_drvdata(pdev, master); + return 0; +err: + spi_master_put(master); + return ret; +} + +static int xtfpga_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct xtfpga_spi *xspi = spi_master_get_devdata(master); + + spi_bitbang_stop(&xspi->bitbang); + spi_master_put(master); + + return 0; +} + +MODULE_ALIAS("platform:" XTFPGA_SPI_NAME); + +#ifdef CONFIG_OF +static const struct of_device_id xtfpga_spi_of_match[] = { + { .compatible = "cdns,xtfpga-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match); +#endif + +static struct platform_driver xtfpga_spi_driver = { + .probe = xtfpga_spi_probe, + .remove = xtfpga_spi_remove, + .driver = { + .name = XTFPGA_SPI_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(xtfpga_spi_of_match), + }, +}; +module_platform_driver(xtfpga_spi_driver); + +MODULE_AUTHOR("Max Filippov "); +MODULE_DESCRIPTION("xtensa xtfpga SPI driver"); +MODULE_LICENSE("GPL"); From 27a89b9f0dc7c98b5c28882656d1044434ba28f1 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 12 Mar 2014 21:55:25 +0400 Subject: [PATCH 4/6] spi/xtensa-xtfpga: add DT binding documentation Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-xtensa-xtfpga.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt diff --git a/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt new file mode 100644 index 000000000000..b6ebe2bc7041 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt @@ -0,0 +1,9 @@ +Cadence Xtensa XTFPGA platform SPI controller. + +This simple SPI master controller is built into xtfpga bitstreams and is used +to control daughterboard audio codec. + +Required properties: +- compatible: should be "cdns,xtfpga-spi". +- reg: physical base address of the controller and length of memory mapped + region. From f620e4b81685e95b43894e85f443dfe252fb17b6 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 12 Mar 2014 21:55:26 +0400 Subject: [PATCH 5/6] MAINTAINERS: add xtfpga platform section This section will list xtfpga platform-specific drivers. Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..f34b325cfd77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9740,6 +9740,12 @@ L: linux-serial@vger.kernel.org S: Maintained F: drivers/tty/serial/uartlite.c +XTENSA XTFPGA PLATFORM SUPPORT +M: Max Filippov +L: linux-xtensa@linux-xtensa.org +S: Maintained +F: drivers/spi/spi-xtensa-xtfpga.c + YAM DRIVER FOR AX.25 M: Jean-Paul Roubelat L: linux-hams@vger.kernel.org From be8dde46750be49fbf161dccd568b5cd14d3f004 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 20 Mar 2014 18:08:04 +0800 Subject: [PATCH 6/6] spi: xtensa-xtfpga: Enable driver compilation with COMPILE_TEST This helps increasing build testing coverage. Signed-off-by: Axel Lin Reviewed-by: Max Filippov Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index c87475db0f79..d36045f4fc24 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -522,7 +522,7 @@ config SPI_XILINX config SPI_XTENSA_XTFPGA tristate "Xtensa SPI controller for xtfpga" - depends on XTENSA && XTENSA_PLATFORM_XTFPGA + depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST select SPI_BITBANG help SPI driver for xtfpga SPI master controller.