ffddc140cdd9b22931b4da8d2932fa04a82a4ed2
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 009-bcm2708-spi-driver.patch
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
4 @@ -86,6 +86,14 @@
5 is for the regular SPI controller. Slave mode operation is not also
6 not supported.
7
8 +config SPI_BCM2708
9 + tristate "BCM2708 SPI controller driver (SPI0)"
10 + depends on MACH_BCM2708
11 + help
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
14 + device.
15 +
16 config SPI_BFIN5XX
17 tristate "SPI controller driver for ADI Blackfin5xx"
18 depends on BLACKFIN
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
22 @@ -17,6 +17,7 @@
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
33 @@ -0,0 +1,626 @@
34 +/*
35 + * Driver for Broadcom BCM2708 SPI Controllers
36 + *
37 + * Copyright (C) 2012 Chris Boot
38 + *
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
42 + *
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.
47 + *
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.
52 + *
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.
56 + */
57 +
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>
71 +
72 +/* SPI register offsets */
73 +#define SPI_CS 0x00
74 +#define SPI_FIFO 0x04
75 +#define SPI_CLK 0x08
76 +#define SPI_DLEN 0x0c
77 +#define SPI_LTOH 0x10
78 +#define SPI_DC 0x14
79 +
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
105 +
106 +#define SPI_TIMEOUT_MS 150
107 +
108 +#define DRV_NAME "bcm2708_spi"
109 +
110 +struct bcm2708_spi {
111 + spinlock_t lock;
112 + void __iomem *base;
113 + int irq;
114 + struct clk *clk;
115 + bool stopping;
116 +
117 + struct list_head queue;
118 + struct workqueue_struct *workq;
119 + struct work_struct work;
120 + struct completion done;
121 +
122 + const u8 *tx_buf;
123 + u8 *rx_buf;
124 + int len;
125 +};
126 +
127 +struct bcm2708_spi_state {
128 + u32 cs;
129 + u16 cdiv;
130 +};
131 +
132 +/*
133 + * This function sets the ALT mode on the SPI pins so that we can use them with
134 + * the SPI hardware.
135 + *
136 + * FIXME: This is a hack. Use pinmux / pinctrl.
137 + */
138 +static void bcm2708_init_pinmode(void)
139 +{
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))
142 +
143 + int pin;
144 + u32 *gpio = ioremap(0x20200000, SZ_16K);
145 +
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 */
150 + }
151 +
152 + iounmap(gpio);
153 +
154 +#undef INP_GPIO
155 +#undef SET_GPIO_ALT
156 +}
157 +
158 +static inline u32 bcm2708_rd(struct bcm2708_spi *bs, unsigned reg)
159 +{
160 + return readl(bs->base + reg);
161 +}
162 +
163 +static inline void bcm2708_wr(struct bcm2708_spi *bs, unsigned reg, u32 val)
164 +{
165 + writel(val, bs->base + reg);
166 +}
167 +
168 +static inline void bcm2708_rd_fifo(struct bcm2708_spi *bs, int len)
169 +{
170 + u8 byte;
171 +
172 + while (len--) {
173 + byte = bcm2708_rd(bs, SPI_FIFO);
174 + if (bs->rx_buf)
175 + *bs->rx_buf++ = byte;
176 + }
177 +}
178 +
179 +static inline void bcm2708_wr_fifo(struct bcm2708_spi *bs, int len)
180 +{
181 + u8 byte;
182 + u16 val;
183 +
184 + if (len > bs->len)
185 + len = bs->len;
186 +
187 + if (unlikely(bcm2708_rd(bs, SPI_CS) & SPI_CS_LEN)) {
188 + /* LoSSI mode */
189 + if (unlikely(len % 2)) {
190 + printk(KERN_ERR"bcm2708_wr_fifo: length must be even, skipping.\n");
191 + bs->len = 0;
192 + return;
193 + }
194 + while (len) {
195 + if (bs->tx_buf) {
196 + val = *(const u16 *)bs->tx_buf;
197 + bs->tx_buf += 2;
198 + } else
199 + val = 0;
200 + bcm2708_wr(bs, SPI_FIFO, val);
201 + bs->len -= 2;
202 + len -= 2;
203 + }
204 + return;
205 + }
206 +
207 + while (len--) {
208 + byte = bs->tx_buf ? *bs->tx_buf++ : 0;
209 + bcm2708_wr(bs, SPI_FIFO, byte);
210 + bs->len--;
211 + }
212 +}
213 +
214 +static irqreturn_t bcm2708_spi_interrupt(int irq, void *dev_id)
215 +{
216 + struct spi_master *master = dev_id;
217 + struct bcm2708_spi *bs = spi_master_get_devdata(master);
218 + u32 cs;
219 +
220 + spin_lock(&bs->lock);
221 +
222 + cs = bcm2708_rd(bs, SPI_CS);
223 +
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);
232 +
233 + /* drain RX FIFO */
234 + while (cs & SPI_CS_RXD) {
235 + bcm2708_rd_fifo(bs, 1);
236 + cs = bcm2708_rd(bs, SPI_CS);
237 + }
238 +
239 + /* wake up our bh */
240 + complete(&bs->done);
241 + }
242 + } else if (cs & SPI_CS_RXR) {
243 + /* read 12 bytes of data */
244 + bcm2708_rd_fifo(bs, 12);
245 +
246 + /* write up to 12 bytes */
247 + bcm2708_wr_fifo(bs, 12);
248 + }
249 +
250 + spin_unlock(&bs->lock);
251 +
252 + return IRQ_HANDLED;
253 +}
254 +
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)
258 +{
259 + struct bcm2708_spi *bs = spi_master_get_devdata(master);
260 + int cdiv;
261 + unsigned long bus_hz;
262 + u32 cs = 0;
263 +
264 + bus_hz = clk_get_rate(bs->clk);
265 +
266 + if (hz >= bus_hz) {
267 + cdiv = 2; /* bus_hz / 2 is as fast as we can go */
268 + } else if (hz) {
269 + cdiv = DIV_ROUND_UP(bus_hz, hz);
270 +
271 + /* CDIV must be a power of 2, so round up */
272 + cdiv = roundup_pow_of_two(cdiv);
273 +
274 + if (cdiv > 65536) {
275 + dev_dbg(dev,
276 + "setup: %d Hz too slow, cdiv %u; min %ld Hz\n",
277 + hz, cdiv, bus_hz / 65536);
278 + return -EINVAL;
279 + } else if (cdiv == 65536) {
280 + cdiv = 0;
281 + } else if (cdiv == 1) {
282 + cdiv = 2; /* 1 gets rounded down to 0; == 65536 */
283 + }
284 + } else {
285 + cdiv = 0;
286 + }
287 +
288 + switch (bpw) {
289 + case 8:
290 + break;
291 + case 9:
292 + /* Reading in LoSSI mode is a special case. See 'BCM2835 ARM Peripherals' datasheet */
293 + cs |= SPI_CS_LEN;
294 + break;
295 + default:
296 + dev_dbg(dev, "setup: invalid bits_per_word %u (must be 8 or 9)\n",
297 + bpw);
298 + return -EINVAL;
299 + }
300 +
301 + if (mode & SPI_CPOL)
302 + cs |= SPI_CS_CPOL;
303 + if (mode & SPI_CPHA)
304 + cs |= SPI_CS_CPHA;
305 +
306 + if (!(mode & SPI_NO_CS)) {
307 + if (mode & SPI_CS_HIGH) {
308 + cs |= SPI_CS_CSPOL;
309 + cs |= SPI_CS_CSPOL0 << csel;
310 + }
311 +
312 + cs |= csel;
313 + } else {
314 + cs |= SPI_CS_CS_10 | SPI_CS_CS_01;
315 + }
316 +
317 + if (state) {
318 + state->cs = cs;
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);
324 + }
325 +
326 + return 0;
327 +}
328 +
329 +static int bcm2708_process_transfer(struct bcm2708_spi *bs,
330 + struct spi_message *msg, struct spi_transfer *xfer)
331 +{
332 + struct spi_device *spi = msg->spi;
333 + struct bcm2708_spi_state state, *stp;
334 + int ret;
335 + u32 cs;
336 +
337 + if (bs->stopping)
338 + return -ESHUTDOWN;
339 +
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);
346 + if (ret)
347 + return ret;
348 +
349 + stp = &state;
350 + } else {
351 + stp = spi->controller_state;
352 + }
353 +
354 + INIT_COMPLETION(bs->done);
355 + bs->tx_buf = xfer->tx_buf;
356 + bs->rx_buf = xfer->rx_buf;
357 + bs->len = xfer->len;
358 +
359 + cs = stp->cs | SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA;
360 +
361 + bcm2708_wr(bs, SPI_CLK, stp->cdiv);
362 + bcm2708_wr(bs, SPI_CS, cs);
363 +
364 + ret = wait_for_completion_timeout(&bs->done,
365 + msecs_to_jiffies(SPI_TIMEOUT_MS));
366 + if (ret == 0) {
367 + dev_err(&spi->dev, "transfer timed out\n");
368 + return -ETIMEDOUT;
369 + }
370 +
371 + if (xfer->delay_usecs)
372 + udelay(xfer->delay_usecs);
373 +
374 + if (list_is_last(&xfer->transfer_list, &msg->transfers) ||
375 + xfer->cs_change) {
376 + /* clear TA and interrupt flags */
377 + bcm2708_wr(bs, SPI_CS, stp->cs);
378 + }
379 +
380 + msg->actual_length += (xfer->len - bs->len);
381 +
382 + return 0;
383 +}
384 +
385 +static void bcm2708_work(struct work_struct *work)
386 +{
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;
391 + int status = 0;
392 +
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);
398 +
399 + list_for_each_entry(xfer, &msg->transfers, transfer_list) {
400 + status = bcm2708_process_transfer(bs, msg, xfer);
401 + if (status)
402 + break;
403 + }
404 +
405 + msg->status = status;
406 + msg->complete(msg->context);
407 +
408 + spin_lock_irqsave(&bs->lock, flags);
409 + }
410 + spin_unlock_irqrestore(&bs->lock, flags);
411 +}
412 +
413 +static int bcm2708_spi_setup(struct spi_device *spi)
414 +{
415 + struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
416 + struct bcm2708_spi_state *state;
417 + int ret;
418 +
419 + if (bs->stopping)
420 + return -ESHUTDOWN;
421 +
422 + if (!(spi->mode & SPI_NO_CS) &&
423 + (spi->chip_select > spi->master->num_chipselect)) {
424 + dev_dbg(&spi->dev,
425 + "setup: invalid chipselect %u (%u defined)\n",
426 + spi->chip_select, spi->master->num_chipselect);
427 + return -EINVAL;
428 + }
429 +
430 + state = spi->controller_state;
431 + if (!state) {
432 + state = kzalloc(sizeof(*state), GFP_KERNEL);
433 + if (!state)
434 + return -ENOMEM;
435 +
436 + spi->controller_state = state;
437 + }
438 +
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);
442 + if (ret < 0) {
443 + kfree(state);
444 + spi->controller_state = NULL;
445 + return ret;
446 + }
447 +
448 + dev_dbg(&spi->dev,
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);
452 +
453 + return 0;
454 +}
455 +
456 +static int bcm2708_spi_transfer(struct spi_device *spi, struct spi_message *msg)
457 +{
458 + struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
459 + struct spi_transfer *xfer;
460 + int ret;
461 + unsigned long flags;
462 +
463 + if (unlikely(list_empty(&msg->transfers)))
464 + return -EINVAL;
465 +
466 + if (bs->stopping)
467 + return -ESHUTDOWN;
468 +
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");
472 + return -EINVAL;
473 + }
474 +
475 + if (!xfer->bits_per_word || xfer->speed_hz)
476 + continue;
477 +
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);
483 + if (ret)
484 + return ret;
485 + }
486 +
487 + msg->status = -EINPROGRESS;
488 + msg->actual_length = 0;
489 +
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);
494 +
495 + return 0;
496 +}
497 +
498 +static void bcm2708_spi_cleanup(struct spi_device *spi)
499 +{
500 + if (spi->controller_state) {
501 + kfree(spi->controller_state);
502 + spi->controller_state = NULL;
503 + }
504 +}
505 +
506 +static int bcm2708_spi_probe(struct platform_device *pdev)
507 +{
508 + struct resource *regs;
509 + int irq, err = -ENOMEM;
510 + struct clk *clk;
511 + struct spi_master *master;
512 + struct bcm2708_spi *bs;
513 +
514 + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
515 + if (!regs) {
516 + dev_err(&pdev->dev, "could not get IO memory\n");
517 + return -ENXIO;
518 + }
519 +
520 + irq = platform_get_irq(pdev, 0);
521 + if (irq < 0) {
522 + dev_err(&pdev->dev, "could not get IRQ\n");
523 + return irq;
524 + }
525 +
526 + clk = clk_get(&pdev->dev, NULL);
527 + if (IS_ERR(clk)) {
528 + dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
529 + return PTR_ERR(clk);
530 + }
531 +
532 + bcm2708_init_pinmode();
533 +
534 + master = spi_alloc_master(&pdev->dev, sizeof(*bs));
535 + if (!master) {
536 + dev_err(&pdev->dev, "spi_alloc_master() failed\n");
537 + goto out_clk_put;
538 + }
539 +
540 + /* the spi->mode bits understood by this driver: */
541 + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS;
542 +
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);
549 +
550 + bs = spi_master_get_devdata(master);
551 +
552 + spin_lock_init(&bs->lock);
553 + INIT_LIST_HEAD(&bs->queue);
554 + init_completion(&bs->done);
555 + INIT_WORK(&bs->work, bcm2708_work);
556 +
557 + bs->base = ioremap(regs->start, resource_size(regs));
558 + if (!bs->base) {
559 + dev_err(&pdev->dev, "could not remap memory\n");
560 + goto out_master_put;
561 + }
562 +
563 + bs->workq = create_singlethread_workqueue(dev_name(&pdev->dev));
564 + if (!bs->workq) {
565 + dev_err(&pdev->dev, "could not create workqueue\n");
566 + goto out_iounmap;
567 + }
568 +
569 + bs->irq = irq;
570 + bs->clk = clk;
571 + bs->stopping = false;
572 +
573 + err = request_irq(irq, bcm2708_spi_interrupt, 0, dev_name(&pdev->dev),
574 + master);
575 + if (err) {
576 + dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
577 + goto out_workqueue;
578 + }
579 +
580 + /* initialise the hardware */
581 + clk_enable(clk);
582 + bcm2708_wr(bs, SPI_CS, SPI_CS_REN | SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
583 +
584 + err = spi_register_master(master);
585 + if (err) {
586 + dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
587 + goto out_free_irq;
588 + }
589 +
590 + dev_info(&pdev->dev, "SPI Controller at 0x%08lx (irq %d)\n",
591 + (unsigned long)regs->start, irq);
592 +
593 + return 0;
594 +
595 +out_free_irq:
596 + free_irq(bs->irq, master);
597 +out_workqueue:
598 + destroy_workqueue(bs->workq);
599 +out_iounmap:
600 + iounmap(bs->base);
601 +out_master_put:
602 + spi_master_put(master);
603 +out_clk_put:
604 + clk_put(clk);
605 + return err;
606 +}
607 +
608 +static int bcm2708_spi_remove(struct platform_device *pdev)
609 +{
610 + struct spi_master *master = platform_get_drvdata(pdev);
611 + struct bcm2708_spi *bs = spi_master_get_devdata(master);
612 +
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);
618 +
619 + flush_work_sync(&bs->work);
620 +
621 + clk_disable(bs->clk);
622 + clk_put(bs->clk);
623 + free_irq(bs->irq, master);
624 + iounmap(bs->base);
625 +
626 + spi_unregister_master(master);
627 +
628 + return 0;
629 +}
630 +
631 +static struct platform_driver bcm2708_spi_driver = {
632 + .driver = {
633 + .name = DRV_NAME,
634 + .owner = THIS_MODULE,
635 + },
636 + .probe = bcm2708_spi_probe,
637 + .remove = bcm2708_spi_remove,
638 +};
639 +
640 +
641 +static int __init bcm2708_spi_init(void)
642 +{
643 + return platform_driver_probe(&bcm2708_spi_driver, bcm2708_spi_probe);
644 +}
645 +module_init(bcm2708_spi_init);
646 +
647 +static void __exit bcm2708_spi_exit(void)
648 +{
649 + platform_driver_unregister(&bcm2708_spi_driver);
650 +}
651 +module_exit(bcm2708_spi_exit);
652 +
653 +
654 +//module_platform_driver(bcm2708_spi_driver);
655 +
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);