1 diff -urN linux-3.10/drivers/spi/Kconfig linux-rpi-3.10.y/drivers/spi/Kconfig
2 --- linux-3.10/drivers/spi/Kconfig 2013-06-30 23:13:29.000000000 +0100
3 +++ linux-rpi-3.10.y/drivers/spi/Kconfig 2013-07-06 15:25:50.000000000 +0100
5 is for the regular SPI controller. Slave mode operation is not also
9 + tristate "BCM2708 SPI controller driver (SPI0)"
10 + depends on MACH_BCM2708
12 + This selects a driver for the Broadcom BCM2708 SPI master (SPI0). This
13 + driver is not compatible with the "Universal SPI Master" or the SPI slave
17 tristate "SPI controller driver for ADI Blackfin5xx"
19 diff -urN linux-3.10/drivers/spi/Makefile linux-rpi-3.10.y/drivers/spi/Makefile
20 --- linux-3.10/drivers/spi/Makefile 2013-06-30 23:13:29.000000000 +0100
21 +++ linux-rpi-3.10.y/drivers/spi/Makefile 2013-07-06 15:25:50.000000000 +0100
23 obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
24 obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
25 obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
26 +obj-$(CONFIG_SPI_BCM2708) += spi-bcm2708.o
27 obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
28 obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
29 obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
30 diff -urN linux-3.10/drivers/spi/spi-bcm2708.c linux-rpi-3.10.y/drivers/spi/spi-bcm2708.c
31 --- linux-3.10/drivers/spi/spi-bcm2708.c 1970-01-01 01:00:00.000000000 +0100
32 +++ linux-rpi-3.10.y/drivers/spi/spi-bcm2708.c 2013-07-06 15:25:50.000000000 +0100
35 + * Driver for Broadcom BCM2708 SPI Controllers
37 + * Copyright (C) 2012 Chris Boot
39 + * This driver is inspired by:
40 + * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
41 + * spi-atmel.c, Copyright (C) 2006 Atmel Corporation
43 + * This program is free software; you can redistribute it and/or modify
44 + * it under the terms of the GNU General Public License as published by
45 + * the Free Software Foundation; either version 2 of the License, or
46 + * (at your option) any later version.
48 + * This program is distributed in the hope that it will be useful,
49 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
50 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51 + * GNU General Public License for more details.
53 + * You should have received a copy of the GNU General Public License
54 + * along with this program; if not, write to the Free Software
55 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
58 +#include <linux/kernel.h>
59 +#include <linux/module.h>
60 +#include <linux/spinlock.h>
61 +#include <linux/clk.h>
62 +#include <linux/err.h>
63 +#include <linux/platform_device.h>
64 +#include <linux/io.h>
65 +#include <linux/spi/spi.h>
66 +#include <linux/interrupt.h>
67 +#include <linux/delay.h>
68 +#include <linux/log2.h>
69 +#include <linux/sched.h>
70 +#include <linux/wait.h>
72 +/* SPI register offsets */
74 +#define SPI_FIFO 0x04
76 +#define SPI_DLEN 0x0c
77 +#define SPI_LTOH 0x10
80 +/* Bitfields in CS */
81 +#define SPI_CS_LEN_LONG 0x02000000
82 +#define SPI_CS_DMA_LEN 0x01000000
83 +#define SPI_CS_CSPOL2 0x00800000
84 +#define SPI_CS_CSPOL1 0x00400000
85 +#define SPI_CS_CSPOL0 0x00200000
86 +#define SPI_CS_RXF 0x00100000
87 +#define SPI_CS_RXR 0x00080000
88 +#define SPI_CS_TXD 0x00040000
89 +#define SPI_CS_RXD 0x00020000
90 +#define SPI_CS_DONE 0x00010000
91 +#define SPI_CS_LEN 0x00002000
92 +#define SPI_CS_REN 0x00001000
93 +#define SPI_CS_ADCS 0x00000800
94 +#define SPI_CS_INTR 0x00000400
95 +#define SPI_CS_INTD 0x00000200
96 +#define SPI_CS_DMAEN 0x00000100
97 +#define SPI_CS_TA 0x00000080
98 +#define SPI_CS_CSPOL 0x00000040
99 +#define SPI_CS_CLEAR_RX 0x00000020
100 +#define SPI_CS_CLEAR_TX 0x00000010
101 +#define SPI_CS_CPOL 0x00000008
102 +#define SPI_CS_CPHA 0x00000004
103 +#define SPI_CS_CS_10 0x00000002
104 +#define SPI_CS_CS_01 0x00000001
106 +#define SPI_TIMEOUT_MS 150
108 +#define DRV_NAME "bcm2708_spi"
110 +struct bcm2708_spi {
112 + void __iomem *base;
117 + struct list_head queue;
118 + struct workqueue_struct *workq;
119 + struct work_struct work;
120 + struct completion done;
127 +struct bcm2708_spi_state {
133 + * This function sets the ALT mode on the SPI pins so that we can use them with
134 + * the SPI hardware.
136 + * FIXME: This is a hack. Use pinmux / pinctrl.
138 +static void bcm2708_init_pinmode(void)
140 +#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
141 +#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
144 + u32 *gpio = ioremap(0x20200000, SZ_16K);
146 + /* SPI is on GPIO 7..11 */
147 + for (pin = 7; pin <= 11; pin++) {
148 + INP_GPIO(pin); /* set mode to GPIO input first */
149 + SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
158 +static inline u32 bcm2708_rd(struct bcm2708_spi *bs, unsigned reg)
160 + return readl(bs->base + reg);
163 +static inline void bcm2708_wr(struct bcm2708_spi *bs, unsigned reg, u32 val)
165 + writel(val, bs->base + reg);
168 +static inline void bcm2708_rd_fifo(struct bcm2708_spi *bs, int len)
173 + byte = bcm2708_rd(bs, SPI_FIFO);
175 + *bs->rx_buf++ = byte;
179 +static inline void bcm2708_wr_fifo(struct bcm2708_spi *bs, int len)
187 + if (unlikely(bcm2708_rd(bs, SPI_CS) & SPI_CS_LEN)) {
189 + if (unlikely(len % 2)) {
190 + printk(KERN_ERR"bcm2708_wr_fifo: length must be even, skipping.\n");
196 + val = *(const u16 *)bs->tx_buf;
200 + bcm2708_wr(bs, SPI_FIFO, val);
208 + byte = bs->tx_buf ? *bs->tx_buf++ : 0;
209 + bcm2708_wr(bs, SPI_FIFO, byte);
214 +static irqreturn_t bcm2708_spi_interrupt(int irq, void *dev_id)
216 + struct spi_master *master = dev_id;
217 + struct bcm2708_spi *bs = spi_master_get_devdata(master);
220 + spin_lock(&bs->lock);
222 + cs = bcm2708_rd(bs, SPI_CS);
224 + if (cs & SPI_CS_DONE) {
225 + if (bs->len) { /* first interrupt in a transfer */
226 + /* fill the TX fifo with up to 16 bytes */
227 + bcm2708_wr_fifo(bs, 16);
228 + } else { /* transfer complete */
229 + /* disable interrupts */
230 + cs &= ~(SPI_CS_INTR | SPI_CS_INTD);
231 + bcm2708_wr(bs, SPI_CS, cs);
233 + /* drain RX FIFO */
234 + while (cs & SPI_CS_RXD) {
235 + bcm2708_rd_fifo(bs, 1);
236 + cs = bcm2708_rd(bs, SPI_CS);
239 + /* wake up our bh */
240 + complete(&bs->done);
242 + } else if (cs & SPI_CS_RXR) {
243 + /* read 12 bytes of data */
244 + bcm2708_rd_fifo(bs, 12);
246 + /* write up to 12 bytes */
247 + bcm2708_wr_fifo(bs, 12);
250 + spin_unlock(&bs->lock);
252 + return IRQ_HANDLED;
255 +static int bcm2708_setup_state(struct spi_master *master,
256 + struct device *dev, struct bcm2708_spi_state *state,
257 + u32 hz, u8 csel, u8 mode, u8 bpw)
259 + struct bcm2708_spi *bs = spi_master_get_devdata(master);
261 + unsigned long bus_hz;
264 + bus_hz = clk_get_rate(bs->clk);
266 + if (hz >= bus_hz) {
267 + cdiv = 2; /* bus_hz / 2 is as fast as we can go */
269 + cdiv = DIV_ROUND_UP(bus_hz, hz);
271 + /* CDIV must be a power of 2, so round up */
272 + cdiv = roundup_pow_of_two(cdiv);
274 + if (cdiv > 65536) {
276 + "setup: %d Hz too slow, cdiv %u; min %ld Hz\n",
277 + hz, cdiv, bus_hz / 65536);
279 + } else if (cdiv == 65536) {
281 + } else if (cdiv == 1) {
282 + cdiv = 2; /* 1 gets rounded down to 0; == 65536 */
292 + /* Reading in LoSSI mode is a special case. See 'BCM2835 ARM Peripherals' datasheet */
296 + dev_dbg(dev, "setup: invalid bits_per_word %u (must be 8 or 9)\n",
301 + if (mode & SPI_CPOL)
303 + if (mode & SPI_CPHA)
306 + if (!(mode & SPI_NO_CS)) {
307 + if (mode & SPI_CS_HIGH) {
308 + cs |= SPI_CS_CSPOL;
309 + cs |= SPI_CS_CSPOL0 << csel;
314 + cs |= SPI_CS_CS_10 | SPI_CS_CS_01;
319 + state->cdiv = cdiv;
320 + dev_dbg(dev, "setup: want %d Hz; "
321 + "bus_hz=%lu / cdiv=%u == %lu Hz; "
322 + "mode %u: cs 0x%08X\n",
323 + hz, bus_hz, cdiv, bus_hz/cdiv, mode, cs);
329 +static int bcm2708_process_transfer(struct bcm2708_spi *bs,
330 + struct spi_message *msg, struct spi_transfer *xfer)
332 + struct spi_device *spi = msg->spi;
333 + struct bcm2708_spi_state state, *stp;
340 + if (xfer->bits_per_word || xfer->speed_hz) {
341 + ret = bcm2708_setup_state(spi->master, &spi->dev, &state,
342 + xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
343 + spi->chip_select, spi->mode,
344 + xfer->bits_per_word ? xfer->bits_per_word :
345 + spi->bits_per_word);
351 + stp = spi->controller_state;
354 + INIT_COMPLETION(bs->done);
355 + bs->tx_buf = xfer->tx_buf;
356 + bs->rx_buf = xfer->rx_buf;
357 + bs->len = xfer->len;
359 + cs = stp->cs | SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA;
361 + bcm2708_wr(bs, SPI_CLK, stp->cdiv);
362 + bcm2708_wr(bs, SPI_CS, cs);
364 + ret = wait_for_completion_timeout(&bs->done,
365 + msecs_to_jiffies(SPI_TIMEOUT_MS));
367 + dev_err(&spi->dev, "transfer timed out\n");
371 + if (xfer->delay_usecs)
372 + udelay(xfer->delay_usecs);
374 + if (list_is_last(&xfer->transfer_list, &msg->transfers) ||
376 + /* clear TA and interrupt flags */
377 + bcm2708_wr(bs, SPI_CS, stp->cs);
380 + msg->actual_length += (xfer->len - bs->len);
385 +static void bcm2708_work(struct work_struct *work)
387 + struct bcm2708_spi *bs = container_of(work, struct bcm2708_spi, work);
388 + unsigned long flags;
389 + struct spi_message *msg;
390 + struct spi_transfer *xfer;
393 + spin_lock_irqsave(&bs->lock, flags);
394 + while (!list_empty(&bs->queue)) {
395 + msg = list_first_entry(&bs->queue, struct spi_message, queue);
396 + list_del_init(&msg->queue);
397 + spin_unlock_irqrestore(&bs->lock, flags);
399 + list_for_each_entry(xfer, &msg->transfers, transfer_list) {
400 + status = bcm2708_process_transfer(bs, msg, xfer);
405 + msg->status = status;
406 + msg->complete(msg->context);
408 + spin_lock_irqsave(&bs->lock, flags);
410 + spin_unlock_irqrestore(&bs->lock, flags);
413 +static int bcm2708_spi_setup(struct spi_device *spi)
415 + struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
416 + struct bcm2708_spi_state *state;
422 + if (!(spi->mode & SPI_NO_CS) &&
423 + (spi->chip_select > spi->master->num_chipselect)) {
425 + "setup: invalid chipselect %u (%u defined)\n",
426 + spi->chip_select, spi->master->num_chipselect);
430 + state = spi->controller_state;
432 + state = kzalloc(sizeof(*state), GFP_KERNEL);
436 + spi->controller_state = state;
439 + ret = bcm2708_setup_state(spi->master, &spi->dev, state,
440 + spi->max_speed_hz, spi->chip_select, spi->mode,
441 + spi->bits_per_word);
444 + spi->controller_state = NULL;
449 + "setup: cd %d: %d Hz, bpw %u, mode 0x%x -> CS=%08x CDIV=%04x\n",
450 + spi->chip_select, spi->max_speed_hz, spi->bits_per_word,
451 + spi->mode, state->cs, state->cdiv);
456 +static int bcm2708_spi_transfer(struct spi_device *spi, struct spi_message *msg)
458 + struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
459 + struct spi_transfer *xfer;
461 + unsigned long flags;
463 + if (unlikely(list_empty(&msg->transfers)))
469 + list_for_each_entry(xfer, &msg->transfers, transfer_list) {
470 + if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
471 + dev_dbg(&spi->dev, "missing rx or tx buf\n");
475 + if (!xfer->bits_per_word || xfer->speed_hz)
478 + ret = bcm2708_setup_state(spi->master, &spi->dev, NULL,
479 + xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
480 + spi->chip_select, spi->mode,
481 + xfer->bits_per_word ? xfer->bits_per_word :
482 + spi->bits_per_word);
487 + msg->status = -EINPROGRESS;
488 + msg->actual_length = 0;
490 + spin_lock_irqsave(&bs->lock, flags);
491 + list_add_tail(&msg->queue, &bs->queue);
492 + queue_work(bs->workq, &bs->work);
493 + spin_unlock_irqrestore(&bs->lock, flags);
498 +static void bcm2708_spi_cleanup(struct spi_device *spi)
500 + if (spi->controller_state) {
501 + kfree(spi->controller_state);
502 + spi->controller_state = NULL;
506 +static int bcm2708_spi_probe(struct platform_device *pdev)
508 + struct resource *regs;
509 + int irq, err = -ENOMEM;
511 + struct spi_master *master;
512 + struct bcm2708_spi *bs;
514 + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
516 + dev_err(&pdev->dev, "could not get IO memory\n");
520 + irq = platform_get_irq(pdev, 0);
522 + dev_err(&pdev->dev, "could not get IRQ\n");
526 + clk = clk_get(&pdev->dev, NULL);
528 + dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
529 + return PTR_ERR(clk);
532 + bcm2708_init_pinmode();
534 + master = spi_alloc_master(&pdev->dev, sizeof(*bs));
536 + dev_err(&pdev->dev, "spi_alloc_master() failed\n");
540 + /* the spi->mode bits understood by this driver: */
541 + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS;
543 + master->bus_num = pdev->id;
544 + master->num_chipselect = 3;
545 + master->setup = bcm2708_spi_setup;
546 + master->transfer = bcm2708_spi_transfer;
547 + master->cleanup = bcm2708_spi_cleanup;
548 + platform_set_drvdata(pdev, master);
550 + bs = spi_master_get_devdata(master);
552 + spin_lock_init(&bs->lock);
553 + INIT_LIST_HEAD(&bs->queue);
554 + init_completion(&bs->done);
555 + INIT_WORK(&bs->work, bcm2708_work);
557 + bs->base = ioremap(regs->start, resource_size(regs));
559 + dev_err(&pdev->dev, "could not remap memory\n");
560 + goto out_master_put;
563 + bs->workq = create_singlethread_workqueue(dev_name(&pdev->dev));
565 + dev_err(&pdev->dev, "could not create workqueue\n");
571 + bs->stopping = false;
573 + err = request_irq(irq, bcm2708_spi_interrupt, 0, dev_name(&pdev->dev),
576 + dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
577 + goto out_workqueue;
580 + /* initialise the hardware */
582 + bcm2708_wr(bs, SPI_CS, SPI_CS_REN | SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
584 + err = spi_register_master(master);
586 + dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
590 + dev_info(&pdev->dev, "SPI Controller at 0x%08lx (irq %d)\n",
591 + (unsigned long)regs->start, irq);
596 + free_irq(bs->irq, master);
598 + destroy_workqueue(bs->workq);
602 + spi_master_put(master);
608 +static int bcm2708_spi_remove(struct platform_device *pdev)
610 + struct spi_master *master = platform_get_drvdata(pdev);
611 + struct bcm2708_spi *bs = spi_master_get_devdata(master);
613 + /* reset the hardware and block queue progress */
614 + spin_lock_irq(&bs->lock);
615 + bs->stopping = true;
616 + bcm2708_wr(bs, SPI_CS, SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
617 + spin_unlock_irq(&bs->lock);
619 + flush_work_sync(&bs->work);
621 + clk_disable(bs->clk);
623 + free_irq(bs->irq, master);
626 + spi_unregister_master(master);
631 +static struct platform_driver bcm2708_spi_driver = {
634 + .owner = THIS_MODULE,
636 + .probe = bcm2708_spi_probe,
637 + .remove = bcm2708_spi_remove,
641 +static int __init bcm2708_spi_init(void)
643 + return platform_driver_probe(&bcm2708_spi_driver, bcm2708_spi_probe);
645 +module_init(bcm2708_spi_init);
647 +static void __exit bcm2708_spi_exit(void)
649 + platform_driver_unregister(&bcm2708_spi_driver);
651 +module_exit(bcm2708_spi_exit);
654 +//module_platform_driver(bcm2708_spi_driver);
656 +MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2708");
657 +MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
658 +MODULE_LICENSE("GPL v2");
659 +MODULE_ALIAS("platform:" DRV_NAME);