kernel: update 3.10 to 3.10.2
[openwrt.git] / target / linux / brcm2708 / patches-3.10 / 009-bcm2708-spi-driver.patch
1 --- a/drivers/spi/Kconfig
2 +++ b/drivers/spi/Kconfig
3 @@ -86,6 +86,14 @@ config SPI_BCM2835
4           is for the regular SPI controller. Slave mode operation is not also
5           not supported.
6  
7 +config SPI_BCM2708
8 +       tristate "BCM2708 SPI controller driver (SPI0)"
9 +       depends on MACH_BCM2708
10 +       help
11 +         This selects a driver for the Broadcom BCM2708 SPI master (SPI0). This
12 +         driver is not compatible with the "Universal SPI Master" or the SPI slave
13 +         device.
14 +
15  config SPI_BFIN5XX
16         tristate "SPI controller driver for ADI Blackfin5xx"
17         depends on BLACKFIN
18 --- a/drivers/spi/Makefile
19 +++ b/drivers/spi/Makefile
20 @@ -17,6 +17,7 @@ obj-$(CONFIG_SPI_AU1550)              += spi-au1550.
21  obj-$(CONFIG_SPI_BCM2835)              += spi-bcm2835.o
22  obj-$(CONFIG_SPI_BCM63XX)              += spi-bcm63xx.o
23  obj-$(CONFIG_SPI_BFIN5XX)              += spi-bfin5xx.o
24 +obj-$(CONFIG_SPI_BCM2708)              += spi-bcm2708.o
25  obj-$(CONFIG_SPI_BFIN_SPORT)           += spi-bfin-sport.o
26  obj-$(CONFIG_SPI_BITBANG)              += spi-bitbang.o
27  obj-$(CONFIG_SPI_BUTTERFLY)            += spi-butterfly.o
28 --- /dev/null
29 +++ b/drivers/spi/spi-bcm2708.c
30 @@ -0,0 +1,626 @@
31 +/*
32 + * Driver for Broadcom BCM2708 SPI Controllers
33 + *
34 + * Copyright (C) 2012 Chris Boot
35 + *
36 + * This driver is inspired by:
37 + * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
38 + * spi-atmel.c, Copyright (C) 2006 Atmel Corporation
39 + *
40 + * This program is free software; you can redistribute it and/or modify
41 + * it under the terms of the GNU General Public License as published by
42 + * the Free Software Foundation; either version 2 of the License, or
43 + * (at your option) any later version.
44 + *
45 + * This program is distributed in the hope that it will be useful,
46 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
47 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
48 + * GNU General Public License for more details.
49 + *
50 + * You should have received a copy of the GNU General Public License
51 + * along with this program; if not, write to the Free Software
52 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
53 + */
54 +
55 +#include <linux/kernel.h>
56 +#include <linux/module.h>
57 +#include <linux/spinlock.h>
58 +#include <linux/clk.h>
59 +#include <linux/err.h>
60 +#include <linux/platform_device.h>
61 +#include <linux/io.h>
62 +#include <linux/spi/spi.h>
63 +#include <linux/interrupt.h>
64 +#include <linux/delay.h>
65 +#include <linux/log2.h>
66 +#include <linux/sched.h>
67 +#include <linux/wait.h>
68 +
69 +/* SPI register offsets */
70 +#define SPI_CS                 0x00
71 +#define SPI_FIFO               0x04
72 +#define SPI_CLK                        0x08
73 +#define SPI_DLEN               0x0c
74 +#define SPI_LTOH               0x10
75 +#define SPI_DC                 0x14
76 +
77 +/* Bitfields in CS */
78 +#define SPI_CS_LEN_LONG                0x02000000
79 +#define SPI_CS_DMA_LEN         0x01000000
80 +#define SPI_CS_CSPOL2          0x00800000
81 +#define SPI_CS_CSPOL1          0x00400000
82 +#define SPI_CS_CSPOL0          0x00200000
83 +#define SPI_CS_RXF             0x00100000
84 +#define SPI_CS_RXR             0x00080000
85 +#define SPI_CS_TXD             0x00040000
86 +#define SPI_CS_RXD             0x00020000
87 +#define SPI_CS_DONE            0x00010000
88 +#define SPI_CS_LEN             0x00002000
89 +#define SPI_CS_REN             0x00001000
90 +#define SPI_CS_ADCS            0x00000800
91 +#define SPI_CS_INTR            0x00000400
92 +#define SPI_CS_INTD            0x00000200
93 +#define SPI_CS_DMAEN           0x00000100
94 +#define SPI_CS_TA              0x00000080
95 +#define SPI_CS_CSPOL           0x00000040
96 +#define SPI_CS_CLEAR_RX                0x00000020
97 +#define SPI_CS_CLEAR_TX                0x00000010
98 +#define SPI_CS_CPOL            0x00000008
99 +#define SPI_CS_CPHA            0x00000004
100 +#define SPI_CS_CS_10           0x00000002
101 +#define SPI_CS_CS_01           0x00000001
102 +
103 +#define SPI_TIMEOUT_MS 150
104 +
105 +#define DRV_NAME       "bcm2708_spi"
106 +
107 +struct bcm2708_spi {
108 +       spinlock_t lock;
109 +       void __iomem *base;
110 +       int irq;
111 +       struct clk *clk;
112 +       bool stopping;
113 +
114 +       struct list_head queue;
115 +       struct workqueue_struct *workq;
116 +       struct work_struct work;
117 +       struct completion done;
118 +
119 +       const u8 *tx_buf;
120 +       u8 *rx_buf;
121 +       int len;
122 +};
123 +
124 +struct bcm2708_spi_state {
125 +       u32 cs;
126 +       u16 cdiv;
127 +};
128 +
129 +/*
130 + * This function sets the ALT mode on the SPI pins so that we can use them with
131 + * the SPI hardware.
132 + *
133 + * FIXME: This is a hack. Use pinmux / pinctrl.
134 + */
135 +static void bcm2708_init_pinmode(void)
136 +{
137 +#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
138 +#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
139 +
140 +       int pin;
141 +       u32 *gpio = ioremap(0x20200000, SZ_16K);
142 +
143 +       /* SPI is on GPIO 7..11 */
144 +       for (pin = 7; pin <= 11; pin++) {
145 +               INP_GPIO(pin);          /* set mode to GPIO input first */
146 +               SET_GPIO_ALT(pin, 0);   /* set mode to ALT 0 */
147 +       }
148 +
149 +       iounmap(gpio);
150 +
151 +#undef INP_GPIO
152 +#undef SET_GPIO_ALT
153 +}
154 +
155 +static inline u32 bcm2708_rd(struct bcm2708_spi *bs, unsigned reg)
156 +{
157 +       return readl(bs->base + reg);
158 +}
159 +
160 +static inline void bcm2708_wr(struct bcm2708_spi *bs, unsigned reg, u32 val)
161 +{
162 +       writel(val, bs->base + reg);
163 +}
164 +
165 +static inline void bcm2708_rd_fifo(struct bcm2708_spi *bs, int len)
166 +{
167 +       u8 byte;
168 +
169 +       while (len--) {
170 +               byte = bcm2708_rd(bs, SPI_FIFO);
171 +               if (bs->rx_buf)
172 +                       *bs->rx_buf++ = byte;
173 +       }
174 +}
175 +
176 +static inline void bcm2708_wr_fifo(struct bcm2708_spi *bs, int len)
177 +{
178 +       u8 byte;
179 +       u16 val;
180 +
181 +       if (len > bs->len)
182 +               len = bs->len;
183 +
184 +       if (unlikely(bcm2708_rd(bs, SPI_CS) & SPI_CS_LEN)) {
185 +               /* LoSSI mode */
186 +               if (unlikely(len % 2)) {
187 +                       printk(KERN_ERR"bcm2708_wr_fifo: length must be even, skipping.\n");
188 +                       bs->len = 0;
189 +                       return;
190 +               }
191 +               while (len) {
192 +                       if (bs->tx_buf) {
193 +                               val = *(const u16 *)bs->tx_buf;
194 +                               bs->tx_buf += 2;
195 +                       } else
196 +                               val = 0;
197 +                       bcm2708_wr(bs, SPI_FIFO, val);
198 +                       bs->len -= 2;
199 +                       len -= 2;
200 +               }
201 +               return;
202 +       }
203 +
204 +       while (len--) {
205 +               byte = bs->tx_buf ? *bs->tx_buf++ : 0;
206 +               bcm2708_wr(bs, SPI_FIFO, byte);
207 +               bs->len--;
208 +       }
209 +}
210 +
211 +static irqreturn_t bcm2708_spi_interrupt(int irq, void *dev_id)
212 +{
213 +       struct spi_master *master = dev_id;
214 +       struct bcm2708_spi *bs = spi_master_get_devdata(master);
215 +       u32 cs;
216 +
217 +       spin_lock(&bs->lock);
218 +
219 +       cs = bcm2708_rd(bs, SPI_CS);
220 +
221 +       if (cs & SPI_CS_DONE) {
222 +               if (bs->len) { /* first interrupt in a transfer */
223 +                       /* fill the TX fifo with up to 16 bytes */
224 +                       bcm2708_wr_fifo(bs, 16);
225 +               } else { /* transfer complete */
226 +                       /* disable interrupts */
227 +                       cs &= ~(SPI_CS_INTR | SPI_CS_INTD);
228 +                       bcm2708_wr(bs, SPI_CS, cs);
229 +
230 +                       /* drain RX FIFO */
231 +                       while (cs & SPI_CS_RXD) {
232 +                               bcm2708_rd_fifo(bs, 1);
233 +                               cs = bcm2708_rd(bs, SPI_CS);
234 +                       }
235 +
236 +                       /* wake up our bh */
237 +                       complete(&bs->done);
238 +               }
239 +       } else if (cs & SPI_CS_RXR) {
240 +               /* read 12 bytes of data */
241 +               bcm2708_rd_fifo(bs, 12);
242 +
243 +               /* write up to 12 bytes */
244 +               bcm2708_wr_fifo(bs, 12);
245 +       }
246 +
247 +       spin_unlock(&bs->lock);
248 +
249 +       return IRQ_HANDLED;
250 +}
251 +
252 +static int bcm2708_setup_state(struct spi_master *master,
253 +               struct device *dev, struct bcm2708_spi_state *state,
254 +               u32 hz, u8 csel, u8 mode, u8 bpw)
255 +{
256 +       struct bcm2708_spi *bs = spi_master_get_devdata(master);
257 +       int cdiv;
258 +       unsigned long bus_hz;
259 +       u32 cs = 0;
260 +
261 +       bus_hz = clk_get_rate(bs->clk);
262 +
263 +       if (hz >= bus_hz) {
264 +               cdiv = 2; /* bus_hz / 2 is as fast as we can go */
265 +       } else if (hz) {
266 +               cdiv = DIV_ROUND_UP(bus_hz, hz);
267 +
268 +               /* CDIV must be a power of 2, so round up */
269 +               cdiv = roundup_pow_of_two(cdiv);
270 +
271 +               if (cdiv > 65536) {
272 +                       dev_dbg(dev,
273 +                               "setup: %d Hz too slow, cdiv %u; min %ld Hz\n",
274 +                               hz, cdiv, bus_hz / 65536);
275 +                       return -EINVAL;
276 +               } else if (cdiv == 65536) {
277 +                       cdiv = 0;
278 +               } else if (cdiv == 1) {
279 +                       cdiv = 2; /* 1 gets rounded down to 0; == 65536 */
280 +               }
281 +       } else {
282 +               cdiv = 0;
283 +       }
284 +
285 +       switch (bpw) {
286 +       case 8:
287 +               break;
288 +       case 9:
289 +               /* Reading in LoSSI mode is a special case. See 'BCM2835 ARM Peripherals' datasheet */
290 +               cs |= SPI_CS_LEN;
291 +               break;
292 +       default:
293 +               dev_dbg(dev, "setup: invalid bits_per_word %u (must be 8 or 9)\n",
294 +                       bpw);
295 +               return -EINVAL;
296 +       }
297 +
298 +       if (mode & SPI_CPOL)
299 +               cs |= SPI_CS_CPOL;
300 +       if (mode & SPI_CPHA)
301 +               cs |= SPI_CS_CPHA;
302 +
303 +       if (!(mode & SPI_NO_CS)) {
304 +               if (mode & SPI_CS_HIGH) {
305 +                       cs |= SPI_CS_CSPOL;
306 +                       cs |= SPI_CS_CSPOL0 << csel;
307 +               }
308 +
309 +               cs |= csel;
310 +       } else {
311 +               cs |= SPI_CS_CS_10 | SPI_CS_CS_01;
312 +       }
313 +
314 +       if (state) {
315 +               state->cs = cs;
316 +               state->cdiv = cdiv;
317 +               dev_dbg(dev, "setup: want %d Hz; "
318 +                       "bus_hz=%lu / cdiv=%u == %lu Hz; "
319 +                       "mode %u: cs 0x%08X\n",
320 +                       hz, bus_hz, cdiv, bus_hz/cdiv, mode, cs);
321 +       }
322 +
323 +       return 0;
324 +}
325 +
326 +static int bcm2708_process_transfer(struct bcm2708_spi *bs,
327 +               struct spi_message *msg, struct spi_transfer *xfer)
328 +{
329 +       struct spi_device *spi = msg->spi;
330 +       struct bcm2708_spi_state state, *stp;
331 +       int ret;
332 +       u32 cs;
333 +
334 +       if (bs->stopping)
335 +               return -ESHUTDOWN;
336 +
337 +       if (xfer->bits_per_word || xfer->speed_hz) {
338 +               ret = bcm2708_setup_state(spi->master, &spi->dev, &state,
339 +                       xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
340 +                       spi->chip_select, spi->mode,
341 +                       xfer->bits_per_word ? xfer->bits_per_word :
342 +                               spi->bits_per_word);
343 +               if (ret)
344 +                       return ret;
345 +
346 +               stp = &state;
347 +       } else {
348 +               stp = spi->controller_state;
349 +       }
350 +
351 +       INIT_COMPLETION(bs->done);
352 +       bs->tx_buf = xfer->tx_buf;
353 +       bs->rx_buf = xfer->rx_buf;
354 +       bs->len = xfer->len;
355 +
356 +       cs = stp->cs | SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA;
357 +
358 +       bcm2708_wr(bs, SPI_CLK, stp->cdiv);
359 +       bcm2708_wr(bs, SPI_CS, cs);
360 +
361 +       ret = wait_for_completion_timeout(&bs->done,
362 +                       msecs_to_jiffies(SPI_TIMEOUT_MS));
363 +       if (ret == 0) {
364 +               dev_err(&spi->dev, "transfer timed out\n");
365 +               return -ETIMEDOUT;
366 +       }
367 +
368 +       if (xfer->delay_usecs)
369 +               udelay(xfer->delay_usecs);
370 +
371 +       if (list_is_last(&xfer->transfer_list, &msg->transfers) ||
372 +                       xfer->cs_change) {
373 +               /* clear TA and interrupt flags */
374 +               bcm2708_wr(bs, SPI_CS, stp->cs);
375 +       }
376 +
377 +       msg->actual_length += (xfer->len - bs->len);
378 +
379 +       return 0;
380 +}
381 +
382 +static void bcm2708_work(struct work_struct *work)
383 +{
384 +       struct bcm2708_spi *bs = container_of(work, struct bcm2708_spi, work);
385 +       unsigned long flags;
386 +       struct spi_message *msg;
387 +       struct spi_transfer *xfer;
388 +       int status = 0;
389 +
390 +       spin_lock_irqsave(&bs->lock, flags);
391 +       while (!list_empty(&bs->queue)) {
392 +               msg = list_first_entry(&bs->queue, struct spi_message, queue);
393 +               list_del_init(&msg->queue);
394 +               spin_unlock_irqrestore(&bs->lock, flags);
395 +
396 +               list_for_each_entry(xfer, &msg->transfers, transfer_list) {
397 +                       status = bcm2708_process_transfer(bs, msg, xfer);
398 +                       if (status)
399 +                               break;
400 +               }
401 +
402 +               msg->status = status;
403 +               msg->complete(msg->context);
404 +
405 +               spin_lock_irqsave(&bs->lock, flags);
406 +       }
407 +       spin_unlock_irqrestore(&bs->lock, flags);
408 +}
409 +
410 +static int bcm2708_spi_setup(struct spi_device *spi)
411 +{
412 +       struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
413 +       struct bcm2708_spi_state *state;
414 +       int ret;
415 +
416 +       if (bs->stopping)
417 +               return -ESHUTDOWN;
418 +
419 +       if (!(spi->mode & SPI_NO_CS) &&
420 +                       (spi->chip_select > spi->master->num_chipselect)) {
421 +               dev_dbg(&spi->dev,
422 +                       "setup: invalid chipselect %u (%u defined)\n",
423 +                       spi->chip_select, spi->master->num_chipselect);
424 +               return -EINVAL;
425 +       }
426 +
427 +       state = spi->controller_state;
428 +       if (!state) {
429 +               state = kzalloc(sizeof(*state), GFP_KERNEL);
430 +               if (!state)
431 +                       return -ENOMEM;
432 +
433 +               spi->controller_state = state;
434 +       }
435 +
436 +       ret = bcm2708_setup_state(spi->master, &spi->dev, state,
437 +               spi->max_speed_hz, spi->chip_select, spi->mode,
438 +               spi->bits_per_word);
439 +       if (ret < 0) {
440 +               kfree(state);
441 +               spi->controller_state = NULL;
442 +                return ret;
443 +       }
444 +
445 +       dev_dbg(&spi->dev,
446 +               "setup: cd %d: %d Hz, bpw %u, mode 0x%x -> CS=%08x CDIV=%04x\n",
447 +               spi->chip_select, spi->max_speed_hz, spi->bits_per_word,
448 +               spi->mode, state->cs, state->cdiv);
449 +
450 +       return 0;
451 +}
452 +
453 +static int bcm2708_spi_transfer(struct spi_device *spi, struct spi_message *msg)
454 +{
455 +       struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
456 +       struct spi_transfer *xfer;
457 +       int ret;
458 +       unsigned long flags;
459 +
460 +       if (unlikely(list_empty(&msg->transfers)))
461 +               return -EINVAL;
462 +
463 +       if (bs->stopping)
464 +               return -ESHUTDOWN;
465 +
466 +       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
467 +               if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
468 +                       dev_dbg(&spi->dev, "missing rx or tx buf\n");
469 +                       return -EINVAL;
470 +               }
471 +
472 +               if (!xfer->bits_per_word || xfer->speed_hz)
473 +                       continue;
474 +
475 +               ret = bcm2708_setup_state(spi->master, &spi->dev, NULL,
476 +                       xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
477 +                       spi->chip_select, spi->mode,
478 +                       xfer->bits_per_word ? xfer->bits_per_word :
479 +                               spi->bits_per_word);
480 +               if (ret)
481 +                       return ret;
482 +       }
483 +
484 +       msg->status = -EINPROGRESS;
485 +       msg->actual_length = 0;
486 +
487 +       spin_lock_irqsave(&bs->lock, flags);
488 +       list_add_tail(&msg->queue, &bs->queue);
489 +       queue_work(bs->workq, &bs->work);
490 +       spin_unlock_irqrestore(&bs->lock, flags);
491 +
492 +       return 0;
493 +}
494 +
495 +static void bcm2708_spi_cleanup(struct spi_device *spi)
496 +{
497 +       if (spi->controller_state) {
498 +               kfree(spi->controller_state);
499 +               spi->controller_state = NULL;
500 +       }
501 +}
502 +
503 +static int bcm2708_spi_probe(struct platform_device *pdev)
504 +{
505 +       struct resource *regs;
506 +       int irq, err = -ENOMEM;
507 +       struct clk *clk;
508 +       struct spi_master *master;
509 +       struct bcm2708_spi *bs;
510 +
511 +       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
512 +       if (!regs) {
513 +               dev_err(&pdev->dev, "could not get IO memory\n");
514 +               return -ENXIO;
515 +       }
516 +
517 +       irq = platform_get_irq(pdev, 0);
518 +       if (irq < 0) {
519 +               dev_err(&pdev->dev, "could not get IRQ\n");
520 +               return irq;
521 +       }
522 +
523 +       clk = clk_get(&pdev->dev, NULL);
524 +       if (IS_ERR(clk)) {
525 +               dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
526 +               return PTR_ERR(clk);
527 +       }
528 +
529 +       bcm2708_init_pinmode();
530 +
531 +       master = spi_alloc_master(&pdev->dev, sizeof(*bs));
532 +       if (!master) {
533 +               dev_err(&pdev->dev, "spi_alloc_master() failed\n");
534 +               goto out_clk_put;
535 +       }
536 +
537 +       /* the spi->mode bits understood by this driver: */
538 +       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS;
539 +
540 +       master->bus_num = pdev->id;
541 +       master->num_chipselect = 3;
542 +       master->setup = bcm2708_spi_setup;
543 +       master->transfer = bcm2708_spi_transfer;
544 +       master->cleanup = bcm2708_spi_cleanup;
545 +       platform_set_drvdata(pdev, master);
546 +
547 +       bs = spi_master_get_devdata(master);
548 +
549 +       spin_lock_init(&bs->lock);
550 +       INIT_LIST_HEAD(&bs->queue);
551 +       init_completion(&bs->done);
552 +       INIT_WORK(&bs->work, bcm2708_work);
553 +
554 +       bs->base = ioremap(regs->start, resource_size(regs));
555 +       if (!bs->base) {
556 +               dev_err(&pdev->dev, "could not remap memory\n");
557 +               goto out_master_put;
558 +       }
559 +
560 +       bs->workq = create_singlethread_workqueue(dev_name(&pdev->dev));
561 +       if (!bs->workq) {
562 +               dev_err(&pdev->dev, "could not create workqueue\n");
563 +               goto out_iounmap;
564 +       }
565 +
566 +       bs->irq = irq;
567 +       bs->clk = clk;
568 +       bs->stopping = false;
569 +
570 +       err = request_irq(irq, bcm2708_spi_interrupt, 0, dev_name(&pdev->dev),
571 +                       master);
572 +       if (err) {
573 +               dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
574 +               goto out_workqueue;
575 +       }
576 +
577 +       /* initialise the hardware */
578 +       clk_enable(clk);
579 +       bcm2708_wr(bs, SPI_CS, SPI_CS_REN | SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
580 +
581 +       err = spi_register_master(master);
582 +       if (err) {
583 +               dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
584 +               goto out_free_irq;
585 +       }
586 +
587 +       dev_info(&pdev->dev, "SPI Controller at 0x%08lx (irq %d)\n",
588 +               (unsigned long)regs->start, irq);
589 +
590 +       return 0;
591 +
592 +out_free_irq:
593 +       free_irq(bs->irq, master);
594 +out_workqueue:
595 +       destroy_workqueue(bs->workq);
596 +out_iounmap:
597 +       iounmap(bs->base);
598 +out_master_put:
599 +       spi_master_put(master);
600 +out_clk_put:
601 +       clk_put(clk);
602 +       return err;
603 +}
604 +
605 +static int bcm2708_spi_remove(struct platform_device *pdev)
606 +{
607 +       struct spi_master *master = platform_get_drvdata(pdev);
608 +       struct bcm2708_spi *bs = spi_master_get_devdata(master);
609 +
610 +       /* reset the hardware and block queue progress */
611 +       spin_lock_irq(&bs->lock);
612 +       bs->stopping = true;
613 +       bcm2708_wr(bs, SPI_CS, SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
614 +       spin_unlock_irq(&bs->lock);
615 +
616 +       flush_work_sync(&bs->work);
617 +
618 +       clk_disable(bs->clk);
619 +       clk_put(bs->clk);
620 +       free_irq(bs->irq, master);
621 +       iounmap(bs->base);
622 +
623 +       spi_unregister_master(master);
624 +
625 +       return 0;
626 +}
627 +
628 +static struct platform_driver bcm2708_spi_driver = {
629 +       .driver         = {
630 +               .name   = DRV_NAME,
631 +               .owner  = THIS_MODULE,
632 +       },
633 +       .probe          = bcm2708_spi_probe,
634 +       .remove         = bcm2708_spi_remove,
635 +};
636 +
637 +
638 +static int __init bcm2708_spi_init(void)
639 +{
640 +       return platform_driver_probe(&bcm2708_spi_driver, bcm2708_spi_probe);
641 +}
642 +module_init(bcm2708_spi_init);
643 +
644 +static void __exit bcm2708_spi_exit(void)
645 +{
646 +       platform_driver_unregister(&bcm2708_spi_driver);
647 +}
648 +module_exit(bcm2708_spi_exit);
649 +
650 +
651 +//module_platform_driver(bcm2708_spi_driver);
652 +
653 +MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2708");
654 +MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
655 +MODULE_LICENSE("GPL v2");
656 +MODULE_ALIAS("platform:" DRV_NAME);