summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRich Felker <dalias@libc.org>2016-08-04 00:30:37 -0400
committerMark Brown <broonie@kernel.org>2016-08-08 06:56:32 -0400
commit2cb1b3b3ac0ac86b70eb1ecd65585c0d024fe273 (patch)
tree6ff59ce2d624166ac780d695f299613fc6690592 /drivers
parent7ed66c6d8841f215c4371b72206fdecfbcd7a396 (diff)
spi: add driver for J-Core SPI controller
The J-Core "spi2" device is a PIO-based SPI master controller. It differs from "bitbang" devices in that that it's clocked in hardware rather than via soft clock modulation over gpio, and performs byte-at-a-time transfers between the cpu and SPI controller. This driver will be extended to support future versions of the J-Core SPI controller with DMA transfers when they become available. Signed-off-by: Rich Felker <dalias@libc.org> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/Kconfig7
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-jcore.c232
3 files changed, 240 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index d6fb8d4b7786..1abb3d767390 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -285,6 +285,13 @@ config SPI_IMX
285 This enables using the Freescale i.MX SPI controllers in master 285 This enables using the Freescale i.MX SPI controllers in master
286 mode. 286 mode.
287 287
288config SPI_JCORE
289 tristate "J-Core SPI Master"
290 depends on OF && (SUPERH || COMPILE_TEST)
291 help
292 This enables support for the SPI master controller in the J-Core
293 synthesizable, open source SoC.
294
288config SPI_LM70_LLP 295config SPI_LM70_LLP
289 tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" 296 tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
290 depends on PARPORT 297 depends on PARPORT
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 185367ef6576..8715fec8cffa 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
46obj-$(CONFIG_SPI_GPIO) += spi-gpio.o 46obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
47obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o 47obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
48obj-$(CONFIG_SPI_IMX) += spi-imx.o 48obj-$(CONFIG_SPI_IMX) += spi-imx.o
49obj-$(CONFIG_SPI_JCORE) += spi-jcore.o
49obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o 50obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
50obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o 51obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
51obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o 52obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c
new file mode 100644
index 000000000000..7d2044a106a2
--- /dev/null
+++ b/drivers/spi/spi-jcore.c
@@ -0,0 +1,232 @@
1/*
2 * J-Core SPI controller driver
3 *
4 * Copyright (C) 2012-2016 Smart Energy Instruments, Inc.
5 *
6 * Current version by Rich Felker
7 * Based loosely on initial version by Oleksandr G Zhadan
8 *
9 */
10#include <linux/init.h>
11#include <linux/interrupt.h>
12#include <linux/errno.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/spi/spi.h>
16#include <linux/clk.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/of.h>
20#include <linux/delay.h>
21
22#define DRV_NAME "jcore_spi"
23
24#define CTRL_REG 0x0
25#define DATA_REG 0x4
26
27#define JCORE_SPI_CTRL_XMIT 0x02
28#define JCORE_SPI_STAT_BUSY 0x02
29#define JCORE_SPI_CTRL_LOOP 0x08
30#define JCORE_SPI_CTRL_CS_BITS 0x15
31
32#define JCORE_SPI_WAIT_RDY_MAX_LOOP 2000000
33
34struct jcore_spi {
35 struct spi_master *master;
36 void __iomem *base;
37 unsigned int cs_reg;
38 unsigned int speed_reg;
39 unsigned int speed_hz;
40 unsigned int clock_freq;
41};
42
43static int jcore_spi_wait(void __iomem *ctrl_reg)
44{
45 unsigned timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP;
46
47 do {
48 if (!(readl(ctrl_reg) & JCORE_SPI_STAT_BUSY))
49 return 0;
50 cpu_relax();
51 } while (--timeout);
52
53 return -EBUSY;
54}
55
56static void jcore_spi_program(struct jcore_spi *hw)
57{
58 void __iomem *ctrl_reg = hw->base + CTRL_REG;
59
60 if (jcore_spi_wait(ctrl_reg))
61 dev_err(hw->master->dev.parent,
62 "timeout waiting to program ctrl reg.\n");
63
64 writel(hw->cs_reg | hw->speed_reg, ctrl_reg);
65}
66
67static void jcore_spi_chipsel(struct spi_device *spi, bool value)
68{
69 struct jcore_spi *hw = spi_master_get_devdata(spi->master);
70 u32 csbit = 1U << (2 * spi->chip_select);
71
72 dev_dbg(hw->master->dev.parent, "chipselect %d\n", spi->chip_select);
73
74 if (value)
75 hw->cs_reg |= csbit;
76 else
77 hw->cs_reg &= ~csbit;
78
79 jcore_spi_program(hw);
80}
81
82static void jcore_spi_baudrate(struct jcore_spi *hw, int speed)
83{
84 if (speed == hw->speed_hz) return;
85 hw->speed_hz = speed;
86 if (speed >= hw->clock_freq / 2)
87 hw->speed_reg = 0;
88 else
89 hw->speed_reg = ((hw->clock_freq / 2 / speed) - 1) << 27;
90 jcore_spi_program(hw);
91 dev_dbg(hw->master->dev.parent, "speed=%d reg=0x%x\n",
92 speed, hw->speed_reg);
93}
94
95static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
96 struct spi_transfer *t)
97{
98 struct jcore_spi *hw = spi_master_get_devdata(master);
99
100 void __iomem *ctrl_reg = hw->base + CTRL_REG;
101 void __iomem *data_reg = hw->base + DATA_REG;
102 u32 xmit;
103
104 /* data buffers */
105 const unsigned char *tx;
106 unsigned char *rx;
107 unsigned int len;
108 unsigned int count;
109
110 jcore_spi_baudrate(hw, t->speed_hz);
111
112 xmit = hw->cs_reg | hw->speed_reg | JCORE_SPI_CTRL_XMIT;
113 tx = t->tx_buf;
114 rx = t->rx_buf;
115 len = t->len;
116
117 for (count = 0; count < len; count++) {
118 if (jcore_spi_wait(ctrl_reg))
119 break;
120
121 writel(tx ? *tx++ : 0, data_reg);
122 writel(xmit, ctrl_reg);
123
124 if (jcore_spi_wait(ctrl_reg))
125 break;
126
127 if (rx)
128 *rx++ = readl(data_reg);
129 }
130
131 spi_finalize_current_transfer(master);
132
133 if (count < len)
134 return -EREMOTEIO;
135
136 return 0;
137}
138
139static int jcore_spi_probe(struct platform_device *pdev)
140{
141 struct device_node *node = pdev->dev.of_node;
142 struct jcore_spi *hw;
143 struct spi_master *master;
144 struct resource *res;
145 u32 clock_freq;
146 struct clk *clk;
147 int err = -ENODEV;
148
149 master = spi_alloc_master(&pdev->dev, sizeof(struct jcore_spi));
150 if (!master)
151 return err;
152
153 /* Setup the master state. */
154 master->num_chipselect = 3;
155 master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
156 master->transfer_one = jcore_spi_txrx;
157 master->set_cs = jcore_spi_chipsel;
158 master->dev.of_node = node;
159 master->bus_num = pdev->id;
160
161 hw = spi_master_get_devdata(master);
162 hw->master = master;
163 platform_set_drvdata(pdev, hw);
164
165 /* Find and map our resources */
166 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
167 if (!res)
168 goto exit_busy;
169 if (!devm_request_mem_region(&pdev->dev, res->start,
170 resource_size(res), pdev->name))
171 goto exit_busy;
172 hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
173 resource_size(res));
174 if (!hw->base)
175 goto exit_busy;
176
177 /*
178 * The SPI clock rate controlled via a configurable clock divider
179 * which is applied to the reference clock. A 50 MHz reference is
180 * most suitable for obtaining standard SPI clock rates, but some
181 * designs may have a different reference clock, and the DT must
182 * make the driver aware so that it can properly program the
183 * requested rate. If the clock is omitted, 50 MHz is assumed.
184 */
185 clock_freq = 50000000;
186 clk = devm_clk_get(&pdev->dev, "ref_clk");
187 if (!IS_ERR_OR_NULL(clk)) {
188 if (clk_enable(clk) == 0)
189 clock_freq = clk_get_rate(clk);
190 else
191 dev_warn(&pdev->dev, "could not enable ref_clk\n");
192 }
193 hw->clock_freq = clock_freq;
194
195 /* Initialize all CS bits to high. */
196 hw->cs_reg = JCORE_SPI_CTRL_CS_BITS;
197 jcore_spi_baudrate(hw, 400000);
198
199 /* Register our spi controller */
200 err = devm_spi_register_master(&pdev->dev, master);
201 if (err)
202 goto exit;
203
204 return 0;
205
206exit_busy:
207 err = -EBUSY;
208exit:
209 platform_set_drvdata(pdev, NULL);
210 spi_master_put(master);
211 return err;
212}
213
214static const struct of_device_id jcore_spi_of_match[] = {
215 { .compatible = "jcore,spi2" },
216 {},
217};
218
219static struct platform_driver jcore_spi_driver = {
220 .probe = jcore_spi_probe,
221 .driver = {
222 .name = DRV_NAME,
223 .of_match_table = jcore_spi_of_match,
224 },
225};
226
227module_platform_driver(jcore_spi_driver);
228
229MODULE_DESCRIPTION("J-Core SPI driver");
230MODULE_AUTHOR("Rich Felker <dalias@libc.org>");
231MODULE_LICENSE("GPL");
232MODULE_ALIAS("platform:" DRV_NAME);