bcm53xx: add SPI controller driver
[openwrt/staging/wigyori.git] / target / linux / bcm53xx / patches-3.14 / 180-spi-bcm53xx-driver-for-SPI-controller-on-Broadcom-bc.patch
1 From a59f3fa1dd4cb284171a53cb7a614ad947c544f6 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
3 Date: Wed, 13 Aug 2014 14:11:39 +0200
4 Subject: [PATCH V2] spi: bcm53xx: driver for SPI controller on Broadcom bcma
5 SoC
6 MIME-Version: 1.0
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
9
10 Broadcom 53xx ARM SoCs use bcma bus that contains various cores (AKA
11 devices). If board has a serial flash, it's connected over SPI and the
12 bcma bus includes a SPI controller. Example log from such a board:
13 bus0: Found chip with id 53010, rev 0x00 and package 0x02
14 (...)
15 bus0: Core 18 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)
16
17 This patch adds a bcma driver for SPI core, it registers SPI master
18 controller and "bcm53xxspiflash" SPI device.
19
20 Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
21 ---
22 Since RFC: Add Signed-off-by
23 Update to compile on top of for-next
24 V2: Use wait timeout
25 Describe bcm53xxspi_calc_timeout a bit
26 Use devm_spi_register_master
27
28 Thanks Mark for your comments!
29 ---
30 drivers/spi/Kconfig | 6 +
31 drivers/spi/Makefile | 1 +
32 drivers/spi/spi-bcm53xx.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++
33 drivers/spi/spi-bcm53xx.h | 72 +++++++++++
34 4 files changed, 374 insertions(+)
35 create mode 100644 drivers/spi/spi-bcm53xx.c
36 create mode 100644 drivers/spi/spi-bcm53xx.h
37
38 --- a/drivers/spi/Kconfig
39 +++ b/drivers/spi/Kconfig
40 @@ -112,6 +112,12 @@ config SPI_AU1550
41 If you say yes to this option, support will be included for the
42 PSC SPI controller found on Au1550, Au1200 and Au1300 series.
43
44 +config SPI_BCM53XX
45 + tristate "Broadcom BCM53xx SPI controller"
46 + depends on ARCH_BCM_5301X
47 + help
48 + Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs.
49 +
50 config SPI_BCM63XX
51 tristate "Broadcom BCM63xx SPI controller"
52 depends on BCM63XX
53 --- a/drivers/spi/Makefile
54 +++ b/drivers/spi/Makefile
55 @@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
56 obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
57 obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
58 obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
59 +obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o
60 obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
61 obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
62 obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
63 --- /dev/null
64 +++ b/drivers/spi/spi-bcm53xx.c
65 @@ -0,0 +1,295 @@
66 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
67 +
68 +#include <linux/kernel.h>
69 +#include <linux/module.h>
70 +#include <linux/slab.h>
71 +#include <linux/delay.h>
72 +#include <linux/bcma/bcma.h>
73 +#include <linux/spi/spi.h>
74 +
75 +#include "spi-bcm53xx.h"
76 +
77 +#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */
78 +
79 +/* The longest observed required wait was 19 ms */
80 +#define BCM53XXSPI_SPE_TIMEOUT_MS 80
81 +
82 +struct bcm53xxspi {
83 + struct bcma_device *core;
84 + struct spi_master *master;
85 +
86 + size_t read_offset;
87 +};
88 +
89 +static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
90 +{
91 + return bcma_read32(b53spi->core, offset);
92 +}
93 +
94 +static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset,
95 + u32 value)
96 +{
97 + bcma_write32(b53spi->core, offset, value);
98 +}
99 +
100 +static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
101 +{
102 + /* Do some magic calculation based on length and buad. Add 10% and 1. */
103 + return (len * 9000 / BCM53XXSPI_MAX_SPI_BAUD * 110 / 100) + 1;
104 +}
105 +
106 +static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms)
107 +{
108 + unsigned long deadline;
109 + u32 tmp;
110 +
111 + /* SPE bit has to be 0 before we read MSPI STATUS */
112 + deadline = jiffies + BCM53XXSPI_SPE_TIMEOUT_MS * HZ / 1000;
113 + do {
114 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
115 + if (!(tmp & B53SPI_MSPI_SPCR2_SPE))
116 + break;
117 + udelay(5);
118 + } while (!time_after_eq(jiffies, deadline));
119 +
120 + if (tmp & B53SPI_MSPI_SPCR2_SPE)
121 + goto spi_timeout;
122 +
123 + /* Check status */
124 + deadline = jiffies + timeout_ms * HZ / 1000;
125 + do {
126 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS);
127 + if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) {
128 + bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0);
129 + return 0;
130 + }
131 +
132 + cpu_relax();
133 + udelay(100);
134 + } while (!time_after_eq(jiffies, deadline));
135 +
136 +spi_timeout:
137 + bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0);
138 +
139 + pr_err("Timeout waiting for SPI to be ready!\n");
140 +
141 + return -EBUSY;
142 +}
143 +
144 +static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf,
145 + size_t len, bool cont)
146 +{
147 + u32 tmp;
148 + int i;
149 +
150 + for (i = 0; i < len; i++) {
151 + /* Transmit Register File MSB */
152 + bcm53xxspi_write(b53spi, B53SPI_MSPI_TXRAM + 4 * (i * 2),
153 + (unsigned int)w_buf[i]);
154 + }
155 +
156 + for (i = 0; i < len; i++) {
157 + tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL |
158 + B53SPI_CDRAM_PCS_DSCK;
159 + if (!cont && i == len - 1)
160 + tmp &= ~B53SPI_CDRAM_CONT;
161 + tmp &= ~0x1;
162 + /* Command Register File */
163 + bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp);
164 + }
165 +
166 + /* Set queue pointers */
167 + bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0);
168 + bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1);
169 +
170 + if (cont)
171 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1);
172 +
173 + /* Start SPI transfer */
174 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
175 + tmp |= B53SPI_MSPI_SPCR2_SPE;
176 + if (cont)
177 + tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD;
178 + bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp);
179 +
180 + /* Wait for SPI to finish */
181 + bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len));
182 +
183 + if (!cont)
184 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
185 +
186 + b53spi->read_offset = len;
187 +}
188 +
189 +static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf,
190 + size_t len, bool cont)
191 +{
192 + u32 tmp;
193 + int i;
194 +
195 + for (i = 0; i < b53spi->read_offset + len; i++) {
196 + tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL |
197 + B53SPI_CDRAM_PCS_DSCK;
198 + if (!cont && i == b53spi->read_offset + len - 1)
199 + tmp &= ~B53SPI_CDRAM_CONT;
200 + tmp &= ~0x1;
201 + /* Command Register File */
202 + bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp);
203 + }
204 +
205 + /* Set queue pointers */
206 + bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0);
207 + bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP,
208 + b53spi->read_offset + len - 1);
209 +
210 + if (cont)
211 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1);
212 +
213 + /* Start SPI transfer */
214 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
215 + tmp |= B53SPI_MSPI_SPCR2_SPE;
216 + if (cont)
217 + tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD;
218 + bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp);
219 +
220 + /* Wait for SPI to finish */
221 + bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len));
222 +
223 + if (!cont)
224 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
225 +
226 + for (i = 0; i < len; ++i) {
227 + int offset = b53spi->read_offset + i;
228 +
229 + /* Data stored in the transmit register file LSB */
230 + r_buf[i] = (u8)bcm53xxspi_read(b53spi, B53SPI_MSPI_RXRAM + 4 * (1 + offset * 2));
231 + }
232 +
233 + b53spi->read_offset = 0;
234 +}
235 +
236 +static int bcm53xxspi_transfer_one(struct spi_master *master,
237 + struct spi_device *spi,
238 + struct spi_transfer *t)
239 +{
240 + struct bcm53xxspi *b53spi = spi_master_get_devdata(master);
241 + u8 *buf;
242 + size_t left;
243 +
244 + if (t->tx_buf) {
245 + buf = (u8 *)t->tx_buf;
246 + left = t->len;
247 + while (left) {
248 + size_t to_write = min_t(size_t, 16, left);
249 + bool cont = left - to_write > 0;
250 +
251 + bcm53xxspi_buf_write(b53spi, buf, to_write, cont);
252 + left -= to_write;
253 + buf += to_write;
254 + }
255 + }
256 +
257 + if (t->rx_buf) {
258 + buf = (u8 *)t->rx_buf;
259 + left = t->len;
260 + while (left) {
261 + size_t to_read = min_t(size_t, 16 - b53spi->read_offset,
262 + left);
263 + bool cont = left - to_read > 0;
264 +
265 + bcm53xxspi_buf_read(b53spi, buf, to_read, cont);
266 + left -= to_read;
267 + buf += to_read;
268 + }
269 + }
270 +
271 + return 0;
272 +}
273 +
274 +/**************************************************
275 + * BCMA
276 + **************************************************/
277 +
278 +struct spi_board_info bcm53xx_info = {
279 + .modalias = "bcm53xxspiflash",
280 +};
281 +
282 +static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = {
283 + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS),
284 + BCMA_CORETABLE_END
285 +};
286 +MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl);
287 +
288 +static int bcm53xxspi_bcma_probe(struct bcma_device *core)
289 +{
290 + struct bcm53xxspi *b53spi;
291 + struct spi_master *master;
292 + int err;
293 +
294 + if (core->bus->drv_cc.core->id.rev != 42) {
295 + pr_err("SPI on SoC with unsupported ChipCommon rev\n");
296 + return -ENOTSUPP;
297 + }
298 +
299 + master = spi_alloc_master(&core->dev, sizeof(*b53spi));
300 + if (!master)
301 + return -ENOMEM;
302 +
303 + b53spi = spi_master_get_devdata(master);
304 + b53spi->master = master;
305 + b53spi->core = core;
306 +
307 + master->transfer_one = bcm53xxspi_transfer_one;
308 +
309 + bcma_set_drvdata(core, b53spi);
310 +
311 + err = devm_spi_register_master(&core->dev, master);
312 + if (err) {
313 + spi_master_put(master);
314 + bcma_set_drvdata(core, NULL);
315 + goto out;
316 + }
317 +
318 + /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
319 + spi_new_device(master, &bcm53xx_info);
320 +
321 +out:
322 + return err;
323 +}
324 +
325 +static void bcm53xxspi_bcma_remove(struct bcma_device *core)
326 +{
327 + struct bcm53xxspi *b53spi = bcma_get_drvdata(core);
328 +
329 + spi_unregister_master(b53spi->master);
330 +}
331 +
332 +static struct bcma_driver bcm53xxspi_bcma_driver = {
333 + .name = KBUILD_MODNAME,
334 + .id_table = bcm53xxspi_bcma_tbl,
335 + .probe = bcm53xxspi_bcma_probe,
336 + .remove = bcm53xxspi_bcma_remove,
337 +};
338 +
339 +/**************************************************
340 + * Init & exit
341 + **************************************************/
342 +
343 +static int __init bcm53xxspi_module_init(void)
344 +{
345 + int err = 0;
346 +
347 + err = bcma_driver_register(&bcm53xxspi_bcma_driver);
348 + if (err)
349 + pr_err("Failed to register bcma driver: %d\n", err);
350 +
351 + return err;
352 +}
353 +
354 +static void __exit bcm53xxspi_module_exit(void)
355 +{
356 + bcma_driver_unregister(&bcm53xxspi_bcma_driver);
357 +}
358 +
359 +module_init(bcm53xxspi_module_init);
360 +module_exit(bcm53xxspi_module_exit);
361 --- /dev/null
362 +++ b/drivers/spi/spi-bcm53xx.h
363 @@ -0,0 +1,72 @@
364 +#ifndef SPI_BCM53XX_H
365 +#define SPI_BCM53XX_H
366 +
367 +#define B53SPI_BSPI_REVISION_ID 0x000
368 +#define B53SPI_BSPI_SCRATCH 0x004
369 +#define B53SPI_BSPI_MAST_N_BOOT_CTRL 0x008
370 +#define B53SPI_BSPI_BUSY_STATUS 0x00c
371 +#define B53SPI_BSPI_INTR_STATUS 0x010
372 +#define B53SPI_BSPI_B0_STATUS 0x014
373 +#define B53SPI_BSPI_B0_CTRL 0x018
374 +#define B53SPI_BSPI_B1_STATUS 0x01c
375 +#define B53SPI_BSPI_B1_CTRL 0x020
376 +#define B53SPI_BSPI_STRAP_OVERRIDE_CTRL 0x024
377 +#define B53SPI_BSPI_FLEX_MODE_ENABLE 0x028
378 +#define B53SPI_BSPI_BITS_PER_CYCLE 0x02c
379 +#define B53SPI_BSPI_BITS_PER_PHASE 0x030
380 +#define B53SPI_BSPI_CMD_AND_MODE_BYTE 0x034
381 +#define B53SPI_BSPI_BSPI_FLASH_UPPER_ADDR_BYTE 0x038
382 +#define B53SPI_BSPI_BSPI_XOR_VALUE 0x03c
383 +#define B53SPI_BSPI_BSPI_XOR_ENABLE 0x040
384 +#define B53SPI_BSPI_BSPI_PIO_MODE_ENABLE 0x044
385 +#define B53SPI_BSPI_BSPI_PIO_IODIR 0x048
386 +#define B53SPI_BSPI_BSPI_PIO_DATA 0x04c
387 +
388 +/* RAF */
389 +#define B53SPI_RAF_START_ADDR 0x100
390 +#define B53SPI_RAF_NUM_WORDS 0x104
391 +#define B53SPI_RAF_CTRL 0x108
392 +#define B53SPI_RAF_FULLNESS 0x10c
393 +#define B53SPI_RAF_WATERMARK 0x110
394 +#define B53SPI_RAF_STATUS 0x114
395 +#define B53SPI_RAF_READ_DATA 0x118
396 +#define B53SPI_RAF_WORD_CNT 0x11c
397 +#define B53SPI_RAF_CURR_ADDR 0x120
398 +
399 +/* MSPI */
400 +#define B53SPI_MSPI_SPCR0_LSB 0x200
401 +#define B53SPI_MSPI_SPCR0_MSB 0x204
402 +#define B53SPI_MSPI_SPCR1_LSB 0x208
403 +#define B53SPI_MSPI_SPCR1_MSB 0x20c
404 +#define B53SPI_MSPI_NEWQP 0x210
405 +#define B53SPI_MSPI_ENDQP 0x214
406 +#define B53SPI_MSPI_SPCR2 0x218
407 +#define B53SPI_MSPI_SPCR2_SPE 0x00000040
408 +#define B53SPI_MSPI_SPCR2_CONT_AFTER_CMD 0x00000080
409 +#define B53SPI_MSPI_MSPI_STATUS 0x220
410 +#define B53SPI_MSPI_MSPI_STATUS_SPIF 0x00000001
411 +#define B53SPI_MSPI_CPTQP 0x224
412 +#define B53SPI_MSPI_TXRAM 0x240 /* 32 registers, up to 0x2b8 */
413 +#define B53SPI_MSPI_RXRAM 0x2c0 /* 32 registers, up to 0x33c */
414 +#define B53SPI_MSPI_CDRAM 0x340 /* 16 registers, up to 0x37c */
415 +#define B53SPI_CDRAM_PCS_PCS0 0x00000001
416 +#define B53SPI_CDRAM_PCS_PCS1 0x00000002
417 +#define B53SPI_CDRAM_PCS_PCS2 0x00000004
418 +#define B53SPI_CDRAM_PCS_PCS3 0x00000008
419 +#define B53SPI_CDRAM_PCS_DISABLE_ALL 0x0000000f
420 +#define B53SPI_CDRAM_PCS_DSCK 0x00000010
421 +#define B53SPI_CDRAM_BITSE 0x00000040
422 +#define B53SPI_CDRAM_CONT 0x00000080
423 +#define B53SPI_MSPI_WRITE_LOCK 0x380
424 +#define B53SPI_MSPI_DISABLE_FLUSH_GEN 0x384
425 +
426 +/* Interrupt */
427 +#define B53SPI_INTR_RAF_LR_FULLNESS_REACHED 0x3a0
428 +#define B53SPI_INTR_RAF_LR_TRUNCATED 0x3a4
429 +#define B53SPI_INTR_RAF_LR_IMPATIENT 0x3a8
430 +#define B53SPI_INTR_RAF_LR_SESSION_DONE 0x3ac
431 +#define B53SPI_INTR_RAF_LR_OVERREAD 0x3b0
432 +#define B53SPI_INTR_MSPI_DONE 0x3b4
433 +#define B53SPI_INTR_MSPI_HALT_SET_TRANSACTION_DONE 0x3b8
434 +
435 +#endif /* SPI_BCM53XX_H */