brcm63xx: Add profile and build image for Sagemcom F@ST2704V2 ADSL router
[openwrt/openwrt.git] / target / linux / brcm63xx / patches-3.10 / 049-spi-add-bcm63xx-HSSPI-driver.patch
1 From 8e051b79ae3f66dbad96312fe2976401c28d2148 Mon Sep 17 00:00:00 2001
2 From: Jonas Gorski <jogo@openwrt.org>
3 Date: Sat, 12 Nov 2011 12:19:55 +0100
4 Subject: [PATCH 5/5] spi: add bcm63xx HSSPI driver
5
6 Add a driver for the High Speed SPI controller found on newer BCM63XX SoCs.
7
8 It does feature some new modes like 3-wire or dual spi, but neither of it
9 is currently implemented.
10
11 Signed-off-by: Jonas Gorski <jogo@openwrt.org>
12 ---
13 drivers/spi/Kconfig | 7 +
14 drivers/spi/Makefile | 1 +
15 drivers/spi/spi-bcm63xx-hsspi.c | 484 ++++++++++++++++++++++++++++++++++++++++
16 3 files changed, 492 insertions(+)
17 create mode 100644 drivers/spi/spi-bcm63xx-hsspi.c
18
19 --- a/drivers/spi/Kconfig
20 +++ b/drivers/spi/Kconfig
21 @@ -112,6 +112,13 @@ config SPI_BCM63XX
22 help
23 Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
24
25 +config SPI_BCM63XX_HSSPI
26 + tristate "Broadcom BCM63XX HS SPI controller driver"
27 + depends on BCM63XX || COMPILE_TEST
28 + help
29 + This enables support for the High Speed SPI controller present on
30 + newer Broadcom BCM63XX SoCs.
31 +
32 config SPI_BITBANG
33 tristate "Utilities for Bitbanging SPI masters"
34 help
35 --- a/drivers/spi/Makefile
36 +++ b/drivers/spi/Makefile
37 @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
38 obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
39 obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
40 obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
41 +obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
42 obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
43 obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
44 obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
45 --- /dev/null
46 +++ b/drivers/spi/spi-bcm63xx-hsspi.c
47 @@ -0,0 +1,484 @@
48 +/*
49 + * Broadcom BCM63XX High Speed SPI Controller driver
50 + *
51 + * Copyright 2000-2010 Broadcom Corporation
52 + * Copyright 2012-2013 Jonas Gorski <jogo@openwrt.org>
53 + *
54 + * Licensed under the GNU/GPL. See COPYING for details.
55 + */
56 +
57 +#include <linux/kernel.h>
58 +#include <linux/init.h>
59 +#include <linux/io.h>
60 +#include <linux/clk.h>
61 +#include <linux/module.h>
62 +#include <linux/platform_device.h>
63 +#include <linux/delay.h>
64 +#include <linux/dma-mapping.h>
65 +#include <linux/err.h>
66 +#include <linux/interrupt.h>
67 +#include <linux/spi/spi.h>
68 +#include <linux/workqueue.h>
69 +#include <linux/mutex.h>
70 +
71 +#define HSSPI_GLOBAL_CTRL_REG 0x0
72 +#define GLOBAL_CTRL_CS_POLARITY_SHIFT 0
73 +#define GLOBAL_CTRL_CS_POLARITY_MASK 0x000000ff
74 +#define GLOBAL_CTRL_PLL_CLK_CTRL_SHIFT 8
75 +#define GLOBAL_CTRL_PLL_CLK_CTRL_MASK 0x0000ff00
76 +#define GLOBAL_CTRL_CLK_GATE_SSOFF BIT(16)
77 +#define GLOBAL_CTRL_CLK_POLARITY BIT(17)
78 +#define GLOBAL_CTRL_MOSI_IDLE BIT(18)
79 +
80 +#define HSSPI_GLOBAL_EXT_TRIGGER_REG 0x4
81 +
82 +#define HSSPI_INT_STATUS_REG 0x8
83 +#define HSSPI_INT_STATUS_MASKED_REG 0xc
84 +#define HSSPI_INT_MASK_REG 0x10
85 +
86 +#define HSSPI_PINGx_CMD_DONE(i) BIT((i * 8) + 0)
87 +#define HSSPI_PINGx_RX_OVER(i) BIT((i * 8) + 1)
88 +#define HSSPI_PINGx_TX_UNDER(i) BIT((i * 8) + 2)
89 +#define HSSPI_PINGx_POLL_TIMEOUT(i) BIT((i * 8) + 3)
90 +#define HSSPI_PINGx_CTRL_INVAL(i) BIT((i * 8) + 4)
91 +
92 +#define HSSPI_INT_CLEAR_ALL 0xff001f1f
93 +
94 +#define HSSPI_PINGPONG_COMMAND_REG(x) (0x80 + (x) * 0x40)
95 +#define PINGPONG_CMD_COMMAND_MASK 0xf
96 +#define PINGPONG_COMMAND_NOOP 0
97 +#define PINGPONG_COMMAND_START_NOW 1
98 +#define PINGPONG_COMMAND_START_TRIGGER 2
99 +#define PINGPONG_COMMAND_HALT 3
100 +#define PINGPONG_COMMAND_FLUSH 4
101 +#define PINGPONG_CMD_PROFILE_SHIFT 8
102 +#define PINGPONG_CMD_SS_SHIFT 12
103 +
104 +#define HSSPI_PINGPONG_STATUS_REG(x) (0x84 + (x) * 0x40)
105 +
106 +#define HSSPI_PROFILE_CLK_CTRL_REG(x) (0x100 + (x) * 0x20)
107 +#define CLK_CTRL_FREQ_CTRL_MASK 0x0000ffff
108 +#define CLK_CTRL_SPI_CLK_2X_SEL BIT(14)
109 +#define CLK_CTRL_ACCUM_RST_ON_LOOP BIT(15)
110 +
111 +#define HSSPI_PROFILE_SIGNAL_CTRL_REG(x) (0x104 + (x) * 0x20)
112 +#define SIGNAL_CTRL_LATCH_RISING BIT(12)
113 +#define SIGNAL_CTRL_LAUNCH_RISING BIT(13)
114 +#define SIGNAL_CTRL_ASYNC_INPUT_PATH BIT(16)
115 +
116 +#define HSSPI_PROFILE_MODE_CTRL_REG(x) (0x108 + (x) * 0x20)
117 +#define MODE_CTRL_MULTIDATA_RD_STRT_SHIFT 8
118 +#define MODE_CTRL_MULTIDATA_WR_STRT_SHIFT 12
119 +#define MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT 16
120 +#define MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT 18
121 +#define MODE_CTRL_MODE_3WIRE BIT(20)
122 +#define MODE_CTRL_PREPENDBYTE_CNT_SHIFT 24
123 +
124 +#define HSSPI_FIFO_REG(x) (0x200 + (x) * 0x200)
125 +
126 +
127 +#define HSSPI_OP_CODE_SHIFT 13
128 +#define HSSPI_OP_SLEEP (0 << HSSPI_OP_CODE_SHIFT)
129 +#define HSSPI_OP_READ_WRITE (1 << HSSPI_OP_CODE_SHIFT)
130 +#define HSSPI_OP_WRITE (2 << HSSPI_OP_CODE_SHIFT)
131 +#define HSSPI_OP_READ (3 << HSSPI_OP_CODE_SHIFT)
132 +#define HSSPI_OP_SETIRQ (4 << HSSPI_OP_CODE_SHIFT)
133 +
134 +#define HSSPI_BUFFER_LEN 512
135 +#define HSSPI_OPCODE_LEN 2
136 +
137 +#define HSSPI_MAX_PREPEND_LEN 15
138 +
139 +#define HSSPI_MAX_SYNC_CLOCK 30000000
140 +
141 +#define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
142 +
143 +struct bcm63xx_hsspi {
144 + struct completion done;
145 + struct mutex bus_mutex;
146 +
147 + struct platform_device *pdev;
148 + struct clk *clk;
149 + void __iomem *regs;
150 + u8 __iomem *fifo;
151 +
152 + u32 speed_hz;
153 + u8 cs_polarity;
154 +};
155 +
156 +static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned cs,
157 + bool active)
158 +{
159 + u32 reg;
160 +
161 + mutex_lock(&bs->bus_mutex);
162 + reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
163 +
164 + reg &= ~BIT(cs);
165 + if (active == !(bs->cs_polarity & BIT(cs)))
166 + reg |= BIT(cs);
167 +
168 + __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
169 + mutex_unlock(&bs->bus_mutex);
170 +}
171 +
172 +static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
173 + struct spi_device *spi, int hz)
174 +{
175 + unsigned profile = spi->chip_select;
176 + u32 reg;
177 +
178 + reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
179 + __raw_writel(CLK_CTRL_ACCUM_RST_ON_LOOP | reg,
180 + bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile));
181 +
182 + reg = __raw_readl(bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
183 + if (hz > HSSPI_MAX_SYNC_CLOCK)
184 + reg |= SIGNAL_CTRL_ASYNC_INPUT_PATH;
185 + else
186 + reg &= ~SIGNAL_CTRL_ASYNC_INPUT_PATH;
187 + __raw_writel(reg, bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
188 +
189 + mutex_lock(&bs->bus_mutex);
190 + /* setup clock polarity */
191 + reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
192 + reg &= ~GLOBAL_CTRL_CLK_POLARITY;
193 + if (spi->mode & SPI_CPOL)
194 + reg |= GLOBAL_CTRL_CLK_POLARITY;
195 + __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
196 + mutex_unlock(&bs->bus_mutex);
197 +}
198 +
199 +static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
200 +{
201 + struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
202 + unsigned chip_select = spi->chip_select;
203 + u16 opcode = 0;
204 + int pending = t->len;
205 + int step_size = HSSPI_BUFFER_LEN;
206 + const u8 *tx = t->tx_buf;
207 + u8 *rx = t->rx_buf;
208 +
209 + bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
210 + bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
211 +
212 + if (tx && rx)
213 + opcode = HSSPI_OP_READ_WRITE;
214 + else if (tx)
215 + opcode = HSSPI_OP_WRITE;
216 + else if (rx)
217 + opcode = HSSPI_OP_READ;
218 +
219 + if (opcode != HSSPI_OP_READ)
220 + step_size -= HSSPI_OPCODE_LEN;
221 +
222 + __raw_writel(0 << MODE_CTRL_PREPENDBYTE_CNT_SHIFT |
223 + 2 << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT |
224 + 2 << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT | 0xff,
225 + bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
226 +
227 + while (pending > 0) {
228 + int curr_step = min_t(int, step_size, pending);
229 +
230 + init_completion(&bs->done);
231 + if (tx) {
232 + memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
233 + tx += curr_step;
234 + }
235 +
236 + __raw_writew(opcode | curr_step, bs->fifo);
237 +
238 + /* enable interrupt */
239 + __raw_writel(HSSPI_PINGx_CMD_DONE(0),
240 + bs->regs + HSSPI_INT_MASK_REG);
241 +
242 + /* start the transfer */
243 + __raw_writel(!chip_select << PINGPONG_CMD_SS_SHIFT |
244 + chip_select << PINGPONG_CMD_PROFILE_SHIFT |
245 + PINGPONG_COMMAND_START_NOW,
246 + bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
247 +
248 + if (wait_for_completion_timeout(&bs->done, HZ) == 0) {
249 + dev_err(&bs->pdev->dev, "transfer timed out!\n");
250 + return -ETIMEDOUT;
251 + }
252 +
253 + if (rx) {
254 + memcpy_fromio(rx, bs->fifo, curr_step);
255 + rx += curr_step;
256 + }
257 +
258 + pending -= curr_step;
259 + }
260 +
261 + return 0;
262 +}
263 +
264 +static int bcm63xx_hsspi_setup(struct spi_device *spi)
265 +{
266 + struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
267 + u32 reg;
268 +
269 + reg = __raw_readl(bs->regs +
270 + HSSPI_PROFILE_SIGNAL_CTRL_REG(spi->chip_select));
271 + reg &= ~(SIGNAL_CTRL_LAUNCH_RISING | SIGNAL_CTRL_LATCH_RISING);
272 + if (spi->mode & SPI_CPHA)
273 + reg |= SIGNAL_CTRL_LAUNCH_RISING;
274 + else
275 + reg |= SIGNAL_CTRL_LATCH_RISING;
276 + __raw_writel(reg, bs->regs +
277 + HSSPI_PROFILE_SIGNAL_CTRL_REG(spi->chip_select));
278 +
279 + mutex_lock(&bs->bus_mutex);
280 + reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
281 +
282 + /* only change actual polarities if there is no transfer */
283 + if ((reg & GLOBAL_CTRL_CS_POLARITY_MASK) == bs->cs_polarity) {
284 + if (spi->mode & SPI_CS_HIGH)
285 + reg |= BIT(spi->chip_select);
286 + else
287 + reg &= ~BIT(spi->chip_select);
288 + __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
289 + }
290 +
291 + if (spi->mode & SPI_CS_HIGH)
292 + bs->cs_polarity |= BIT(spi->chip_select);
293 + else
294 + bs->cs_polarity &= ~BIT(spi->chip_select);
295 +
296 + mutex_unlock(&bs->bus_mutex);
297 +
298 + return 0;
299 +}
300 +
301 +static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
302 + struct spi_message *msg)
303 +{
304 + struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
305 + struct spi_transfer *t;
306 + struct spi_device *spi = msg->spi;
307 + int status = -EINVAL;
308 + int dummy_cs;
309 + u32 reg;
310 +
311 + /* This controller does not support keeping CS active during idle.
312 + * To work around this, we use the following ugly hack:
313 + *
314 + * a. Invert the target chip select's polarity so it will be active.
315 + * b. Select a "dummy" chip select to use as the hardware target.
316 + * c. Invert the dummy chip select's polarity so it will be inactive
317 + * during the actual transfers.
318 + * d. Tell the hardware to send to the dummy chip select. Thanks to
319 + * the multiplexed nature of SPI the actual target will receive
320 + * the transfer and we see its response.
321 + *
322 + * e. At the end restore the polarities again to their default values.
323 + */
324 +
325 + dummy_cs = !spi->chip_select;
326 + bcm63xx_hsspi_set_cs(bs, dummy_cs, true);
327 +
328 + list_for_each_entry(t, &msg->transfers, transfer_list) {
329 + status = bcm63xx_hsspi_do_txrx(spi, t);
330 + if (status)
331 + break;
332 +
333 + msg->actual_length += t->len;
334 +
335 + if (t->delay_usecs)
336 + udelay(t->delay_usecs);
337 +
338 + if (t->cs_change)
339 + bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
340 + }
341 +
342 + mutex_lock(&bs->bus_mutex);
343 + reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
344 + reg &= ~GLOBAL_CTRL_CS_POLARITY_MASK;
345 + reg |= bs->cs_polarity;
346 + __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
347 + mutex_unlock(&bs->bus_mutex);
348 +
349 + msg->status = status;
350 + spi_finalize_current_message(master);
351 +
352 + return 0;
353 +}
354 +
355 +static irqreturn_t bcm63xx_hsspi_interrupt(int irq, void *dev_id)
356 +{
357 + struct bcm63xx_hsspi *bs = (struct bcm63xx_hsspi *)dev_id;
358 +
359 + if (__raw_readl(bs->regs + HSSPI_INT_STATUS_MASKED_REG) == 0)
360 + return IRQ_NONE;
361 +
362 + __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
363 + __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
364 +
365 + complete(&bs->done);
366 +
367 + return IRQ_HANDLED;
368 +}
369 +
370 +static int bcm63xx_hsspi_probe(struct platform_device *pdev)
371 +{
372 + struct spi_master *master;
373 + struct bcm63xx_hsspi *bs;
374 + struct resource *res_mem;
375 + void __iomem *regs;
376 + struct device *dev = &pdev->dev;
377 + struct clk *clk;
378 + int irq, ret;
379 + u32 reg, rate;
380 +
381 + irq = platform_get_irq(pdev, 0);
382 + if (irq < 0) {
383 + dev_err(dev, "no irq\n");
384 + return -ENXIO;
385 + }
386 +
387 + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
388 + regs = devm_request_and_ioremap(dev, res_mem);
389 + if (IS_ERR(regs))
390 + return PTR_ERR(regs);
391 +
392 + clk = clk_get(dev, "hsspi");
393 +
394 + if (IS_ERR(clk))
395 + return PTR_ERR(clk);
396 +
397 + rate = clk_get_rate(clk);
398 + if (!rate) {
399 + ret = -EINVAL;
400 + goto out_put_clk;
401 + }
402 +
403 + clk_prepare_enable(clk);
404 +
405 + master = spi_alloc_master(&pdev->dev, sizeof(*bs));
406 + if (!master) {
407 + ret = -ENOMEM;
408 + goto out_disable_clk;
409 + }
410 +
411 + bs = spi_master_get_devdata(master);
412 + bs->pdev = pdev;
413 + bs->clk = clk;
414 + bs->regs = regs;
415 + bs->speed_hz = rate;
416 + bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
417 +
418 + mutex_init(&bs->bus_mutex);
419 +
420 + master->bus_num = HSSPI_BUS_NUM;
421 + master->num_chipselect = 8;
422 + master->setup = bcm63xx_hsspi_setup;
423 + master->transfer_one_message = bcm63xx_hsspi_transfer_one;
424 + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
425 + master->bits_per_word_mask = SPI_BPW_MASK(8);
426 + master->auto_runtime_pm = true;
427 +
428 + platform_set_drvdata(pdev, master);
429 +
430 + /* Initialize the hardware */
431 + __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
432 +
433 + /* clean up any pending interrupts */
434 + __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
435 +
436 + /* read out default CS polarities */
437 + reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
438 + bs->cs_polarity = reg & GLOBAL_CTRL_CS_POLARITY_MASK;
439 + __raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
440 + bs->regs + HSSPI_GLOBAL_CTRL_REG);
441 +
442 + ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
443 + pdev->name, bs);
444 +
445 + if (ret)
446 + goto out_put_master;
447 +
448 + /* register and we are done */
449 + ret = spi_register_master(master);
450 + if (ret)
451 + goto out_put_master;
452 +
453 + return 0;
454 +
455 +out_put_master:
456 + spi_master_put(master);
457 +out_disable_clk:
458 + clk_disable_unprepare(clk);
459 +out_put_clk:
460 + clk_put(clk);
461 +
462 + return ret;
463 +}
464 +
465 +
466 +static int bcm63xx_hsspi_remove(struct platform_device *pdev)
467 +{
468 + struct spi_master *master = platform_get_drvdata(pdev);
469 + struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
470 +
471 + spi_unregister_master(master);
472 +
473 + /* reset the hardware and block queue progress */
474 + __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
475 + clk_disable_unprepare(bs->clk);
476 + clk_put(bs->clk);
477 +
478 + return 0;
479 +}
480 +
481 +#ifdef CONFIG_PM
482 +static int bcm63xx_hsspi_suspend(struct device *dev)
483 +{
484 + struct spi_master *master = dev_get_drvdata(dev);
485 + struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
486 +
487 + spi_master_suspend(master);
488 + clk_disable(bs->clk);
489 +
490 + return 0;
491 +}
492 +
493 +static int bcm63xx_hsspi_resume(struct device *dev)
494 +{
495 + struct spi_master *master = dev_get_drvdata(dev);
496 + struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
497 +
498 + clk_enable(bs->clk);
499 + spi_master_resume(master);
500 +
501 + return 0;
502 +}
503 +
504 +static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = {
505 + .suspend = bcm63xx_hsspi_suspend,
506 + .resume = bcm63xx_hsspi_resume,
507 +};
508 +
509 +#define BCM63XX_HSSPI_PM_OPS (&bcm63xx_hsspi_pm_ops)
510 +#else
511 +#define BCM63XX_HSSPI_PM_OPS NULL
512 +#endif
513 +
514 +
515 +
516 +static struct platform_driver bcm63xx_hsspi_driver = {
517 + .driver = {
518 + .name = "bcm63xx-hsspi",
519 + .owner = THIS_MODULE,
520 + .pm = BCM63XX_HSSPI_PM_OPS,
521 + },
522 + .probe = bcm63xx_hsspi_probe,
523 + .remove = bcm63xx_hsspi_remove,
524 +};
525 +
526 +module_platform_driver(bcm63xx_hsspi_driver);
527 +
528 +MODULE_ALIAS("platform:bcm63xx_hsspi");
529 +MODULE_DESCRIPTION("Broadcom BCM63xx High Speed SPI Controller driver");
530 +MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
531 +MODULE_LICENSE("GPL");