aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2014-03-12 13:55:24 -0400
committerMark Brown <broonie@linaro.org>2014-03-13 05:12:44 -0400
commit6840cc29f2bcc9a06a7245d17e0e2f38fbc20df0 (patch)
tree29e8402ba03a62b794ed64727154d9d6d16f0f6a /drivers/spi
parent38dbfb59d1175ef458d006556061adeaa8751b72 (diff)
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 <jcmvbkbc@gmail.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig13
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c170
3 files changed, 184 insertions, 0 deletions
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
520 520
521 Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" 521 Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
522 522
523config SPI_XTENSA_XTFPGA
524 tristate "Xtensa SPI controller for xtfpga"
525 depends on XTENSA && XTENSA_PLATFORM_XTFPGA
526 select SPI_BITBANG
527 help
528 SPI driver for xtfpga SPI master controller.
529
530 This simple SPI master controller is built into xtfpga bitstreams
531 and is used to control daughterboard audio codec. It always transfers
532 16 bit words in SPI mode 0, automatically asserting CS on transfer
533 start and deasserting on end.
534
535
523config SPI_NUC900 536config SPI_NUC900
524 tristate "Nuvoton NUC900 series SPI" 537 tristate "Nuvoton NUC900 series SPI"
525 depends on ARCH_W90X900 538 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
79obj-$(CONFIG_SPI_TXX9) += spi-txx9.o 79obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
80obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o 80obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
81obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o 81obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
82obj-$(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 @@
1/*
2 * Xtensa xtfpga SPI controller driver
3 *
4 * Copyright (c) 2014 Cadence Design Systems Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/delay.h>
12#include <linux/io.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/platform_device.h>
16#include <linux/spi/spi.h>
17#include <linux/spi/spi_bitbang.h>
18
19#define XTFPGA_SPI_NAME "xtfpga_spi"
20
21#define XTFPGA_SPI_START 0x0
22#define XTFPGA_SPI_BUSY 0x4
23#define XTFPGA_SPI_DATA 0x8
24
25#define BUSY_WAIT_US 100
26
27struct xtfpga_spi {
28 struct spi_bitbang bitbang;
29 void __iomem *regs;
30 u32 data;
31 unsigned data_sz;
32};
33
34static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi,
35 unsigned addr, u32 val)
36{
37 iowrite32(val, spi->regs + addr);
38}
39
40static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi,
41 unsigned addr)
42{
43 return ioread32(spi->regs + addr);
44}
45
46static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
47{
48 unsigned i;
49 for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) &&
50 i < BUSY_WAIT_US; ++i)
51 udelay(1);
52 WARN_ON_ONCE(i == BUSY_WAIT_US);
53}
54
55static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
56 u32 v, u8 bits)
57{
58 struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
59
60 xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0));
61 xspi->data_sz += bits;
62 if (xspi->data_sz >= 16) {
63 xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA,
64 xspi->data >> (xspi->data_sz - 16));
65 xspi->data_sz -= 16;
66 xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1);
67 xtfpga_spi_wait_busy(xspi);
68 xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
69 }
70
71 return 0;
72}
73
74static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
75{
76 struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
77
78 WARN_ON(xspi->data_sz != 0);
79 xspi->data_sz = 0;
80}
81
82static int xtfpga_spi_probe(struct platform_device *pdev)
83{
84 struct xtfpga_spi *xspi;
85 struct resource *mem;
86 int ret;
87 struct spi_master *master;
88
89 master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
90 if (!master)
91 return -ENOMEM;
92
93 master->flags = SPI_MASTER_NO_RX;
94 master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
95 master->bus_num = pdev->dev.id;
96 master->dev.of_node = pdev->dev.of_node;
97
98 xspi = spi_master_get_devdata(master);
99 xspi->bitbang.master = master;
100 xspi->bitbang.chipselect = xtfpga_spi_chipselect;
101 xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
102
103 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
104 if (!mem) {
105 dev_err(&pdev->dev, "No memory resource\n");
106 ret = -ENODEV;
107 goto err;
108 }
109 xspi->regs = devm_ioremap_resource(&pdev->dev, mem);
110 if (IS_ERR(xspi->regs)) {
111 ret = PTR_ERR(xspi->regs);
112 goto err;
113 }
114
115 xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
116 usleep_range(1000, 2000);
117 if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) {
118 dev_err(&pdev->dev, "Device stuck in busy state\n");
119 ret = -EBUSY;
120 goto err;
121 }
122
123 ret = spi_bitbang_start(&xspi->bitbang);
124 if (ret < 0) {
125 dev_err(&pdev->dev, "spi_bitbang_start failed\n");
126 goto err;
127 }
128
129 platform_set_drvdata(pdev, master);
130 return 0;
131err:
132 spi_master_put(master);
133 return ret;
134}
135
136static int xtfpga_spi_remove(struct platform_device *pdev)
137{
138 struct spi_master *master = platform_get_drvdata(pdev);
139 struct xtfpga_spi *xspi = spi_master_get_devdata(master);
140
141 spi_bitbang_stop(&xspi->bitbang);
142 spi_master_put(master);
143
144 return 0;
145}
146
147MODULE_ALIAS("platform:" XTFPGA_SPI_NAME);
148
149#ifdef CONFIG_OF
150static const struct of_device_id xtfpga_spi_of_match[] = {
151 { .compatible = "cdns,xtfpga-spi", },
152 {}
153};
154MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match);
155#endif
156
157static struct platform_driver xtfpga_spi_driver = {
158 .probe = xtfpga_spi_probe,
159 .remove = xtfpga_spi_remove,
160 .driver = {
161 .name = XTFPGA_SPI_NAME,
162 .owner = THIS_MODULE,
163 .of_match_table = of_match_ptr(xtfpga_spi_of_match),
164 },
165};
166module_platform_driver(xtfpga_spi_driver);
167
168MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
169MODULE_DESCRIPTION("xtensa xtfpga SPI driver");
170MODULE_LICENSE("GPL");