aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBert Vermeulen <bert@biot.com>2015-04-15 11:43:52 -0400
committerMark Brown <broonie@kernel.org>2015-04-18 08:57:58 -0400
commit05aec357871f892eea91d8b808f96a6091dd5310 (patch)
treea51308d1be6148c3721b55425a89d612d9bc6e4d
parentc517d838eb7d07bbe9507871fab3931deccff539 (diff)
spi: Add SPI driver for Mikrotik RB4xx series boards
This driver mediates access between the connected CPLD and other devices on the bus. The m25p80-compatible boot flash and (some models) MMC use regular SPI, bitbanged as required by the SoC. However the SPI-connected CPLD has a two-wire mode, in which two bits are transferred per SPI clock cycle. The second bit is transmitted with the SoC's CS2 pin. Signed-off-by: Bert Vermeulen <bert@biot.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/Kconfig6
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-rb4xx.c210
3 files changed, 217 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index ab8dfbef6f1b..8b1beaf6c9e5 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -429,6 +429,12 @@ config SPI_ROCKCHIP
429 The main usecase of this controller is to use spi flash as boot 429 The main usecase of this controller is to use spi flash as boot
430 device. 430 device.
431 431
432config SPI_RB4XX
433 tristate "Mikrotik RB4XX SPI master"
434 depends on SPI_MASTER && ATH79
435 help
436 SPI controller driver for the Mikrotik RB4xx series boards.
437
432config SPI_RSPI 438config SPI_RSPI
433 tristate "Renesas RSPI/QSPI controller" 439 tristate "Renesas RSPI/QSPI controller"
434 depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST 440 depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d8cbf654976b..0218f39de7d2 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
66obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o 66obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
67obj-$(CONFIG_SPI_QUP) += spi-qup.o 67obj-$(CONFIG_SPI_QUP) += spi-qup.o
68obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o 68obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
69obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
69obj-$(CONFIG_SPI_RSPI) += spi-rspi.o 70obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
70obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o 71obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
71spi-s3c24xx-hw-y := spi-s3c24xx.o 72spi-s3c24xx-hw-y := spi-s3c24xx.o
diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c
new file mode 100644
index 000000000000..9b449d4f9871
--- /dev/null
+++ b/drivers/spi/spi-rb4xx.c
@@ -0,0 +1,210 @@
1/*
2 * SPI controller driver for the Mikrotik RB4xx boards
3 *
4 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2015 Bert Vermeulen <bert@biot.com>
6 *
7 * This file was based on the patches for Linux 2.6.27.39 published by
8 * MikroTik for their RouterBoard 4xx series devices.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/clk.h>
20#include <linux/spi/spi.h>
21
22#include <asm/mach-ath79/ar71xx_regs.h>
23
24struct rb4xx_spi {
25 void __iomem *base;
26 struct clk *clk;
27};
28
29static inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg)
30{
31 return __raw_readl(rbspi->base + reg);
32}
33
34static inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value)
35{
36 __raw_writel(value, rbspi->base + reg);
37}
38
39static inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value)
40{
41 u32 regval;
42
43 regval = spi_ioc;
44 if (value & BIT(0))
45 regval |= AR71XX_SPI_IOC_DO;
46
47 rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
48 rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
49}
50
51static void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
52{
53 int i;
54
55 for (i = 7; i >= 0; i--)
56 do_spi_clk(rbspi, spi_ioc, byte >> i);
57}
58
59/* The CS2 pin is used to clock in a second bit per clock cycle. */
60static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc,
61 u8 value)
62{
63 u32 regval;
64
65 regval = spi_ioc;
66 if (value & BIT(1))
67 regval |= AR71XX_SPI_IOC_DO;
68 if (value & BIT(0))
69 regval |= AR71XX_SPI_IOC_CS2;
70
71 rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
72 rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
73}
74
75/* Two bits at a time, msb first */
76static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
77{
78 do_spi_clk_two(rbspi, spi_ioc, byte >> 6);
79 do_spi_clk_two(rbspi, spi_ioc, byte >> 4);
80 do_spi_clk_two(rbspi, spi_ioc, byte >> 2);
81 do_spi_clk_two(rbspi, spi_ioc, byte >> 0);
82}
83
84static void rb4xx_set_cs(struct spi_device *spi, bool enable)
85{
86 struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
87
88 /*
89 * Setting CS is done along with bitbanging the actual values,
90 * since it's all on the same hardware register. However the
91 * CPLD needs CS deselected after every command.
92 */
93 if (!enable)
94 rb4xx_write(rbspi, AR71XX_SPI_REG_IOC,
95 AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1);
96}
97
98static int rb4xx_transfer_one(struct spi_master *master,
99 struct spi_device *spi, struct spi_transfer *t)
100{
101 struct rb4xx_spi *rbspi = spi_master_get_devdata(master);
102 int i;
103 u32 spi_ioc;
104 u8 *rx_buf;
105 const u8 *tx_buf;
106
107 /*
108 * Prime the SPI register with the SPI device selected. The m25p80 boot
109 * flash and CPLD share the CS0 pin. This works because the CPLD's
110 * command set was designed to almost not clash with that of the
111 * boot flash.
112 */
113 if (spi->chip_select == 2)
114 /* MMC */
115 spi_ioc = AR71XX_SPI_IOC_CS0;
116 else
117 /* Boot flash and CPLD */
118 spi_ioc = AR71XX_SPI_IOC_CS1;
119
120 tx_buf = t->tx_buf;
121 rx_buf = t->rx_buf;
122 for (i = 0; i < t->len; ++i) {
123 if (t->tx_nbits == SPI_NBITS_DUAL)
124 /* CPLD can use two-wire transfers */
125 do_spi_byte_two(rbspi, spi_ioc, tx_buf[i]);
126 else
127 do_spi_byte(rbspi, spi_ioc, tx_buf[i]);
128 if (!rx_buf)
129 continue;
130 rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS);
131 }
132 spi_finalize_current_transfer(master);
133
134 return 0;
135}
136
137static int rb4xx_spi_probe(struct platform_device *pdev)
138{
139 struct spi_master *master;
140 struct clk *ahb_clk;
141 struct rb4xx_spi *rbspi;
142 struct resource *r;
143 int err;
144 void __iomem *spi_base;
145
146 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
147 spi_base = devm_ioremap_resource(&pdev->dev, r);
148 if (!spi_base)
149 return PTR_ERR(spi_base);
150
151 master = spi_alloc_master(&pdev->dev, sizeof(*rbspi));
152 if (!master)
153 return -ENOMEM;
154
155 ahb_clk = devm_clk_get(&pdev->dev, "ahb");
156 if (IS_ERR(ahb_clk))
157 return PTR_ERR(ahb_clk);
158
159 master->bus_num = 0;
160 master->num_chipselect = 3;
161 master->mode_bits = SPI_TX_DUAL;
162 master->bits_per_word_mask = BIT(7);
163 master->flags = SPI_MASTER_MUST_TX;
164 master->transfer_one = rb4xx_transfer_one;
165 master->set_cs = rb4xx_set_cs;
166
167 err = devm_spi_register_master(&pdev->dev, master);
168 if (err) {
169 dev_err(&pdev->dev, "failed to register SPI master\n");
170 return err;
171 }
172
173 err = clk_prepare_enable(ahb_clk);
174 if (err)
175 return err;
176
177 rbspi = spi_master_get_devdata(master);
178 rbspi->base = spi_base;
179 rbspi->clk = ahb_clk;
180 platform_set_drvdata(pdev, rbspi);
181
182 /* Enable SPI */
183 rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
184
185 return 0;
186}
187
188static int rb4xx_spi_remove(struct platform_device *pdev)
189{
190 struct rb4xx_spi *rbspi = platform_get_drvdata(pdev);
191
192 clk_disable_unprepare(rbspi->clk);
193
194 return 0;
195}
196
197static struct platform_driver rb4xx_spi_drv = {
198 .probe = rb4xx_spi_probe,
199 .remove = rb4xx_spi_remove,
200 .driver = {
201 .name = "rb4xx-spi",
202 },
203};
204
205module_platform_driver(rb4xx_spi_drv);
206
207MODULE_DESCRIPTION("Mikrotik RB4xx SPI controller driver");
208MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
209MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>");
210MODULE_LICENSE("GPL v2");