brcm63xx: 3.10: backport multi-board support
[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");