[brcm63xx] the SPI_CMD register is 16-bits wide
[openwrt.git] / target / linux / brcm63xx / patches-2.6.32 / 240-spi.patch
1 Index: linux-2.6.32.10/arch/mips/bcm63xx/cpu.c
2 ===================================================================
3 --- linux-2.6.32.10.orig/arch/mips/bcm63xx/cpu.c        2010-03-15 16:52:04.000000000 +0100
4 +++ linux-2.6.32.10/arch/mips/bcm63xx/cpu.c     2010-04-22 17:35:21.000000000 +0200
5 @@ -55,6 +55,7 @@
6  
7  static const int bcm96338_irqs[] = {
8         [IRQ_TIMER]             = BCM_6338_TIMER_IRQ,
9 +       [IRQ_SPI]               = BCM_6338_SPI_IRQ,
10         [IRQ_UART0]             = BCM_6338_UART0_IRQ,
11         [IRQ_DSL]               = BCM_6338_DSL_IRQ,
12         [IRQ_ENET0]             = BCM_6338_ENET0_IRQ,
13 @@ -127,6 +128,7 @@
14  
15  static const int bcm96348_irqs[] = {
16         [IRQ_TIMER]             = BCM_6348_TIMER_IRQ,
17 +       [IRQ_SPI]               = BCM_6348_SPI_IRQ,
18         [IRQ_UART0]             = BCM_6348_UART0_IRQ,
19         [IRQ_DSL]               = BCM_6348_DSL_IRQ,
20         [IRQ_ENET0]             = BCM_6348_ENET0_IRQ,
21 @@ -169,6 +171,7 @@
22  
23  static const int bcm96358_irqs[] = {
24         [IRQ_TIMER]             = BCM_6358_TIMER_IRQ,
25 +       [IRQ_SPI]               = BCM_6358_SPI_IRQ,
26         [IRQ_UART0]             = BCM_6358_UART0_IRQ,
27         [IRQ_DSL]               = BCM_6358_DSL_IRQ,
28         [IRQ_ENET0]             = BCM_6358_ENET0_IRQ,
29 Index: linux-2.6.32.10/arch/mips/bcm63xx/dev-spi.c
30 ===================================================================
31 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
32 +++ linux-2.6.32.10/arch/mips/bcm63xx/dev-spi.c 2010-04-22 17:35:21.000000000 +0200
33 @@ -0,0 +1,60 @@
34 +/*
35 + * This file is subject to the terms and conditions of the GNU General Public
36 + * License.  See the file "COPYING" in the main directory of this archive
37 + * for more details.
38 + *
39 + * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
40 + */
41 +
42 +#include <linux/init.h>
43 +#include <linux/kernel.h>
44 +#include <linux/platform_device.h>
45 +
46 +#include <bcm63xx_cpu.h>
47 +#include <bcm63xx_dev_spi.h>
48 +#include <bcm63xx_regs.h>
49 +
50 +static struct resource spi_resources[] = {
51 +       {
52 +               .start          = -1, /* filled at runtime */
53 +               .end            = -1, /* filled at runtime */
54 +               .flags          = IORESOURCE_MEM,
55 +       },
56 +       {
57 +               .start          = -1, /* filled at runtime */
58 +               .flags          = IORESOURCE_IRQ,
59 +       },
60 +};
61 +
62 +static struct bcm63xx_spi_pdata spi_pdata = {
63 +       .bus_num                = 0,
64 +       .num_chipselect         = 4,
65 +       .speed_hz               = 50000000,     /* Fclk */
66 +};
67 +
68 +static struct platform_device bcm63xx_spi_device = {
69 +       .name           = "bcm63xx-spi",
70 +       .id             = 0,
71 +       .num_resources  = ARRAY_SIZE(spi_resources),
72 +       .resource       = spi_resources,
73 +       .dev            = {
74 +               .platform_data = &spi_pdata,
75 +       },
76 +};
77 +
78 +int __init bcm63xx_spi_register(void)
79 +{
80 +       spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
81 +       spi_resources[0].end = spi_resources[0].start;
82 +       spi_resources[0].end += RSET_SPI_SIZE - 1;
83 +       spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
84 +
85 +       /* Fill in platform data */
86 +       if (BCMCPU_IS_6338() || BCMCPU_IS_6348())
87 +               spi_pdata.fifo_size = SPI_BCM_6338_SPI_MSG_DATA_SIZE;
88 +
89 +       if (BCMCPU_IS_6358())
90 +               spi_pdata.fifo_size = SPI_BCM_6358_SPI_MSG_DATA_SIZE;
91 +
92 +       return platform_device_register(&bcm63xx_spi_device);
93 +}
94 Index: linux-2.6.32.10/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
95 ===================================================================
96 --- linux-2.6.32.10.orig/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h       2010-04-22 17:35:21.000000000 +0200
97 +++ linux-2.6.32.10/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h    2010-04-22 17:43:33.000000000 +0200
98 @@ -108,6 +108,7 @@
99  #define RSET_WDT_SIZE                  12
100  #define RSET_ENET_SIZE                 2048
101  #define RSET_ENETDMA_SIZE              2048
102 +#define RSET_SPI_SIZE                  256
103  #define RSET_UART_SIZE                 24
104  #define RSET_UDC_SIZE                  256
105  #define RSET_OHCI_SIZE                 256
106 @@ -428,6 +429,7 @@
107   */
108  enum bcm63xx_irq {
109         IRQ_TIMER = 0,
110 +       IRQ_SPI,
111         IRQ_UART0,
112         IRQ_DSL,
113         IRQ_UDC0,
114 @@ -493,6 +495,7 @@
115   * 6348 irqs
116   */
117  #define BCM_6348_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
118 +#define BCM_6348_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
119  #define BCM_6348_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
120  #define BCM_6348_DSL_IRQ               (IRQ_INTERNAL_BASE + 4)
121  #define BCM_6348_UDC0_IRQ              (IRQ_INTERNAL_BASE + 6)
122 @@ -517,6 +520,7 @@
123   * 6358 irqs
124   */
125  #define BCM_6358_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
126 +#define BCM_6358_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
127  #define BCM_6358_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
128  #define BCM_6358_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 5)
129  #define BCM_6358_ENET1_IRQ             (IRQ_INTERNAL_BASE + 6)
130 Index: linux-2.6.32.10/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
131 ===================================================================
132 --- linux-2.6.32.10.orig/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h      2010-03-15 16:52:04.000000000 +0100
133 +++ linux-2.6.32.10/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h   2010-04-22 17:35:21.000000000 +0200
134 @@ -769,5 +769,117 @@
135  #define DMIPSPLLCFG_N2_SHIFT           29
136  #define DMIPSPLLCFG_N2_MASK            (0x7 << DMIPSPLLCFG_N2_SHIFT)
137  
138 +/*************************************************************************
139 + * _REG relative to RSET_SPI
140 + *************************************************************************/
141 +
142 +/* BCM 6338 SPI core */
143 +#define SPI_BCM_6338_SPI_CMD           0x00    /* 16-bits register */
144 +#define SPI_BCM_6338_SPI_INT_STATUS    0x02
145 +#define SPI_BCM_6338_SPI_MASK_INT_ST   0x03
146 +#define SPI_BCM_6338_SPI_INT_MASK      0x04
147 +#define SPI_BCM_6338_SPI_ST            0x05
148 +#define SPI_BCM_6338_SPI_CLK_CFG       0x06
149 +#define SPI_BCM_6338_SPI_FILL_BYTE     0x07
150 +#define SPI_BCM_6338_SPI_MSG_TAIL      0x09
151 +#define SPI_BCM_6338_SPI_RX_TAIL       0x0b
152 +#define SPI_BCM_6338_SPI_MSG_CTL       0x40
153 +#define SPI_BCM_6338_SPI_MSG_DATA      0x41
154 +#define SPI_BCM_6338_SPI_MSG_DATA_SIZE 0x3f
155 +#define SPI_BCM_6338_SPI_RX_DATA       0x80
156 +#define SPI_BCM_6338_SPI_RX_DATA_SIZE  0x3f
157 +
158 +/* BCM 6348 SPI core */
159 +#define SPI_BCM_6348_SPI_MASK_INT_ST   0x00
160 +#define SPI_BCM_6348_SPI_INT_STATUS    0x01
161 +#define SPI_BCM_6348_SPI_CMD           0x02    /* 16-bits register */
162 +#define SPI_BCM_6348_SPI_FILL_BYTE     0x04
163 +#define SPI_BCM_6348_SPI_CLK_CFG       0x05
164 +#define SPI_BCM_6348_SPI_ST            0x06
165 +#define SPI_BCM_6348_SPI_INT_MASK      0x07
166 +#define SPI_BCM_6348_SPI_RX_TAIL       0x08
167 +#define SPI_BCM_6348_SPI_MSG_TAIL      0x10
168 +#define SPI_BCM_6348_SPI_MSG_DATA      0x40
169 +#define SPI_BCM_6348_SPI_MSG_CTL       0x42
170 +#define SPI_BCM_6348_SPI_MSG_DATA_SIZE 0x3f
171 +#define SPI_BCM_6348_SPI_RX_DATA       0x80
172 +#define SPI_BCM_6348_SPI_RX_DATA_SIZE  0x3f
173 +
174 +/* BCM 6358 SPI core */
175 +#define SPI_BCM_6358_MSG_CTL           0x00    /* 16-bits register */
176 +
177 +#define SPI_BCM_6358_SPI_MSG_DATA      0x02
178 +#define SPI_BCM_6358_SPI_MSG_DATA_SIZE 0x21e
179 +
180 +#define SPI_BCM_6358_SPI_RX_DATA       0x400
181 +#define SPI_BCM_6358_SPI_RX_DATA_SIZE  0x220
182 +
183 +#define SPI_BCM_6358_SPI_CMD           0x700   /* 16-bits register */
184 +
185 +#define SPI_BCM_6358_SPI_INT_STATUS    0x702
186 +#define SPI_BCM_6358_SPI_MASK_INT_ST   0x703
187 +
188 +#define SPI_BCM_6358_SPI_INT_MASK      0x704
189 +
190 +#define SPI_BCM_6358_SPI_STATUS                0x705
191 +
192 +#define SPI_BCM_6358_SPI_CLK_CFG       0x706
193 +
194 +#define SPI_BCM_6358_SPI_FILL_BYTE     0x707
195 +#define SPI_BCM_6358_SPI_MSG_TAIL      0x709
196 +#define SPI_BCM_6358_SPI_RX_TAIL       0x70B
197 +
198 +/* Shared SPI definitions */
199 +
200 +/* Message configuration */
201 +#define SPI_FD_RW                      0x00
202 +#define SPI_HD_W                       0x01
203 +#define SPI_HD_R                       0x02
204 +#define SPI_BYTE_CNT_SHIFT             0
205 +#define SPI_MSG_TYPE_SHIFT             14
206 +
207 +/* Command */
208 +#define SPI_CMD_NOOP                   0x01
209 +#define SPI_CMD_SOFT_RESET             0x02
210 +#define SPI_CMD_HARD_RESET             0x04
211 +#define SPI_CMD_START_IMMEDIATE                0x08
212 +#define SPI_CMD_COMMAND_SHIFT          0
213 +#define SPI_CMD_COMMAND_MASK           0x000f
214 +#define SPI_CMD_DEVICE_ID_SHIFT                4
215 +#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT 8
216 +#define SPI_CMD_ONE_BYTE_SHIFT         11
217 +#define SPI_CMD_ONE_WIRE_SHIFT         12
218 +#define SPI_DEV_ID_0                   0
219 +#define SPI_DEV_ID_1                   1
220 +#define SPI_DEV_ID_2                   2
221 +#define SPI_DEV_ID_3                   3
222 +
223 +/* Interrupt mask */
224 +#define SPI_INTR_CMD_DONE              0x01
225 +#define SPI_INTR_RX_OVERFLOW           0x02
226 +#define SPI_INTR_TX_UNDERFLOW          0x04
227 +#define SPI_INTR_TX_OVERFLOW           0x08
228 +#define SPI_INTR_RX_UNDERFLOW          0x10
229 +#define SPI_INTR_CLEAR_ALL             0x1f
230 +
231 +/* Status */
232 +#define SPI_RX_EMPTY                   0x02
233 +#define SPI_CMD_BUSY                   0x04
234 +#define SPI_SERIAL_BUSY                        0x08
235 +
236 +/* Clock configuration */
237 +#define SPI_CLK_20MHZ                  0x00
238 +#define SPI_CLK_0_391MHZ               0x01
239 +#define SPI_CLK_0_781MHZ               0x02 /* default */
240 +#define SPI_CLK_1_563MHZ               0x03
241 +#define SPI_CLK_3_125MHZ               0x04
242 +#define SPI_CLK_6_250MHZ               0x05
243 +#define SPI_CLK_12_50MHZ               0x06
244 +#define SPI_CLK_25MHZ                  0x07
245 +#define SPI_CLK_MASK                   0x07
246 +#define SPI_SSOFFTIME_MASK             0x38
247 +#define SPI_SSOFFTIME_SHIFT            3
248 +#define SPI_BYTE_SWAP                  0x80
249 +
250  #endif /* BCM63XX_REGS_H_ */
251  
252 Index: linux-2.6.32.10/drivers/spi/bcm63xx_spi.c
253 ===================================================================
254 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
255 +++ linux-2.6.32.10/drivers/spi/bcm63xx_spi.c   2010-04-22 17:35:21.000000000 +0200
256 @@ -0,0 +1,628 @@
257 +/*
258 + * Broadcom BCM63xx SPI controller support
259 + *
260 + * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
261 + *
262 + * This program is free software; you can redistribute it and/or
263 + * modify it under the terms of the GNU General Public License
264 + * as published by the Free Software Foundation; either version 2
265 + * of the License, or (at your option) any later version.
266 + *
267 + * This program is distributed in the hope that it will be useful,
268 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
269 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
270 + * GNU General Public License for more details.
271 + *
272 + * You should have received a copy of the GNU General Public License
273 + * along with this program; if not, write to the
274 + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
275 + */
276 +
277 +#include <linux/kernel.h>
278 +#include <linux/init.h>
279 +#include <linux/clk.h>
280 +#include <linux/module.h>
281 +#include <linux/platform_device.h>
282 +#include <linux/delay.h>
283 +#include <linux/interrupt.h>
284 +#include <linux/spi/spi.h>
285 +#include <linux/spi/spi_bitbang.h>
286 +#include <linux/gpio.h>
287 +#include <linux/completion.h>
288 +#include <linux/err.h>
289 +
290 +#include <bcm63xx_io.h>
291 +#include <bcm63xx_regs.h>
292 +#include <bcm63xx_dev_spi.h>
293 +
294 +#define PFX            KBUILD_MODNAME
295 +#define DRV_VER                "0.1.2"
296 +
297 +enum bcm63xx_regs_spi {
298 +        SPI_CMD,
299 +        SPI_INT_STATUS,
300 +        SPI_INT_MASK_ST,
301 +        SPI_INT_MASK,
302 +        SPI_ST,
303 +        SPI_CLK_CFG,
304 +        SPI_FILL_BYTE,
305 +        SPI_MSG_TAIL,
306 +        SPI_RX_TAIL,
307 +        SPI_MSG_CTL,
308 +        SPI_MSG_DATA,
309 +        SPI_RX_DATA,
310 +};
311 +
312 +/*
313 + * register offsets
314 + */
315 +static const unsigned long bcm96338_regs_spi[] = {
316 +       [SPI_CMD]               = SPI_BCM_6338_SPI_CMD,
317 +       [SPI_INT_STATUS]        = SPI_BCM_6338_SPI_INT_STATUS,
318 +       [SPI_INT_MASK_ST]       = SPI_BCM_6338_SPI_MASK_INT_ST,
319 +       [SPI_INT_MASK]          = SPI_BCM_6338_SPI_INT_MASK,
320 +       [SPI_ST]                = SPI_BCM_6338_SPI_ST,
321 +       [SPI_CLK_CFG]           = SPI_BCM_6338_SPI_CLK_CFG,
322 +       [SPI_FILL_BYTE]         = SPI_BCM_6338_SPI_FILL_BYTE,
323 +       [SPI_MSG_TAIL]          = SPI_BCM_6338_SPI_MSG_TAIL,
324 +       [SPI_RX_TAIL]           = SPI_BCM_6338_SPI_RX_TAIL,
325 +       [SPI_MSG_CTL]           = SPI_BCM_6338_SPI_MSG_CTL,
326 +       [SPI_MSG_DATA]          = SPI_BCM_6338_SPI_MSG_DATA,
327 +       [SPI_RX_DATA]           = SPI_BCM_6338_SPI_RX_DATA,
328 +};
329 +
330 +static const unsigned long bcm96348_regs_spi[] = {
331 +       [SPI_CMD]               = SPI_BCM_6348_SPI_CMD,
332 +       [SPI_INT_STATUS]        = SPI_BCM_6348_SPI_INT_STATUS,
333 +       [SPI_INT_MASK_ST]       = SPI_BCM_6348_SPI_MASK_INT_ST,
334 +       [SPI_INT_MASK]          = SPI_BCM_6348_SPI_INT_MASK,
335 +       [SPI_ST]                = SPI_BCM_6348_SPI_ST,
336 +       [SPI_CLK_CFG]           = SPI_BCM_6348_SPI_CLK_CFG,
337 +       [SPI_FILL_BYTE]         = SPI_BCM_6348_SPI_FILL_BYTE,
338 +       [SPI_MSG_TAIL]          = SPI_BCM_6348_SPI_MSG_TAIL,
339 +       [SPI_RX_TAIL]           = SPI_BCM_6348_SPI_RX_TAIL,
340 +       [SPI_MSG_CTL]           = SPI_BCM_6348_SPI_MSG_CTL,
341 +       [SPI_MSG_DATA]          = SPI_BCM_6348_SPI_MSG_DATA,
342 +       [SPI_RX_DATA]           = SPI_BCM_6348_SPI_RX_DATA,
343 +};
344 +
345 +static const unsigned long bcm96358_regs_spi[] = {
346 +       [SPI_CMD]               = SPI_BCM_6358_SPI_CMD,
347 +       [SPI_INT_STATUS]        = SPI_BCM_6358_SPI_INT_STATUS,
348 +       [SPI_INT_MASK_ST]       = SPI_BCM_6358_SPI_MASK_INT_ST,
349 +       [SPI_INT_MASK]          = SPI_BCM_6358_SPI_INT_MASK,
350 +       [SPI_ST]                = SPI_BCM_6358_SPI_STATUS,
351 +       [SPI_CLK_CFG]           = SPI_BCM_6358_SPI_CLK_CFG,
352 +       [SPI_FILL_BYTE]         = SPI_BCM_6358_SPI_FILL_BYTE,
353 +       [SPI_MSG_TAIL]          = SPI_BCM_6358_SPI_MSG_TAIL,
354 +       [SPI_RX_TAIL]           = SPI_BCM_6358_SPI_RX_TAIL,
355 +       [SPI_MSG_CTL]           = SPI_BCM_6358_MSG_CTL,
356 +       [SPI_MSG_DATA]          = SPI_BCM_6358_SPI_MSG_DATA,
357 +       [SPI_RX_DATA]           = SPI_BCM_6358_SPI_RX_DATA,
358 +};
359 +
360 +
361 +#ifdef BCMCPU_RUNTIME_DETECT
362 +static const unsigned long *bcm63xx_regs_spi;
363 +
364 +static __init void bcm63xx_spi_regs_init(void)
365 +{
366 +       if (BCMCPU_IS_6338())
367 +               bcm63xx_regs_spi = bcm96338_regs_spi;
368 +       if (BCMCPU_IS_6348())
369 +               bcm63xx_regs_spi = bcm96348_regs_spi;
370 +       if (BCMCPU_IS_6358())
371 +               bcm63xx_regs_spi = bcm96358_regs_spi;
372 +}
373 +#else
374 +static __init void bcm63xx_spi_regs_init(void) { }
375 +#endif
376 +
377 +static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg)
378 +{
379 +#ifdef BCMCPU_RUNTIME_DETECT
380 +        return bcm63xx_regs_spi[reg];
381 +#else
382 +#ifdef CONFIG_BCM63XX_CPU_6338
383 +switch (reg) {
384 +       case SPI_CMD:
385 +               return SPI_BCM_6338_SPI_CMD;
386 +       case SPI_INT_STATUS:
387 +               return SPI_BCM_6338_SPI_INT_STATUS;
388 +       case SPI_INT_MASK_ST:
389 +               return SPI_BCM_6338_SPI_MASK_INT_ST;
390 +       case SPI_INT_MASK:
391 +               return SPI_BCM_6338_SPI_INT_MASK;
392 +       case SPI_ST:
393 +               return SPI_BCM_6338_SPI_ST;
394 +       case SPI_CLK_CFG:
395 +               return SPI_BCM_6338_SPI_CLK_CFG;
396 +       case SPI_FILL_BYTE:
397 +               return SPI_BCM_6338_SPI_FILL_BYTE;
398 +       case SPI_MSG_TAIL:
399 +               return SPI_BCM_6338_SPI_MSG_TAIL;
400 +       case SPI_RX_TAIL:
401 +               return SPI_BCM_6338_SPI_RX_TAIL;
402 +       case SPI_MSG_CTL:
403 +               return SPI_BCM_6338_SPI_MSG_CTL;
404 +       case SPI_MSG_DATA:
405 +               return SPI_BCM_6338_SPI_MSG_DATA;
406 +       case SPI_RX_DATA:
407 +               return SPI_BCM_6338_SPI_RX_DATA;
408 +}
409 +#endif
410 +#ifdef CONFIG_BCM63XX_CPU_6348
411 +switch (reg) {
412 +       case SPI_CMD:
413 +               return SPI_BCM_6348_SPI_CMD;
414 +       case SPI_INT_MASK_ST:
415 +               return SPI_BCM_6348_SPI_MASK_INT_ST;
416 +       case SPI_INT_MASK:
417 +               return SPI_BCM_6348_SPI_INT_MASK;
418 +       case SPI_INT_STATUS:
419 +               return SPI_BCM_6348_SPI_INT_STATUS;
420 +       case SPI_ST:
421 +               return SPI_BCM_6348_SPI_ST;
422 +       case SPI_CLK_CFG:
423 +               return SPI_BCM_6348_SPI_CLK_CFG;
424 +       case SPI_FILL_BYTE:
425 +               return SPI_BCM_6348_SPI_FILL_BYTE;
426 +       case SPI_MSG_TAIL:
427 +               return SPI_BCM_6348_SPI_MSG_TAIL;
428 +       case SPI_RX_TAIL:
429 +               return SPI_BCM_6348_SPI_RX_TAIL;
430 +       case SPI_MSG_CTL:
431 +               return SPI_BCM_6348_SPI_MSG_CTL;
432 +       case SPI_MSG_DATA:
433 +               return SPI_BCM_6348_SPI_MSG_DATA;
434 +       case SPI_RX_DATA:
435 +               return SPI_BCM_6348_SPI_RX_DATA;
436 +}
437 +#endif
438 +#ifdef CONFIG_BCM63XX_CPU_6358
439 +switch (reg) {
440 +       case SPI_CMD:
441 +               return SPI_BCM_6358_SPI_CMD;
442 +       case SPI_INT_STATUS:
443 +               return SPI_BCM_6358_SPI_INT_STATUS;
444 +       case SPI_INT_MASK_ST:
445 +               return SPI_BCM_6358_SPI_MASK_INT_ST;
446 +       case SPI_INT_MASK:
447 +               return SPI_BCM_6358_SPI_INT_MASK;
448 +       case SPI_ST:
449 +               return SPI_BCM_6358_SPI_STATUS;
450 +       case SPI_CLK_CFG:
451 +               return SPI_BCM_6358_SPI_CLK_CFG;
452 +       case SPI_FILL_BYTE:
453 +               return SPI_BCM_6358_SPI_FILL_BYTE;
454 +       case SPI_MSG_TAIL:
455 +               return SPI_BCM_6358_SPI_MSG_TAIL;
456 +       case SPI_RX_TAIL:
457 +               return SPI_BCM_6358_SPI_RX_TAIL;
458 +       case SPI_MSG_CTL:
459 +               return SPI_BCM_6358_MSG_CTL;
460 +       case SPI_MSG_DATA:
461 +               return SPI_BCM_6358_SPI_MSG_DATA;
462 +       case SPI_RX_DATA:
463 +               return SPI_BCM_6358_SPI_RX_DATA;
464 +}
465 +#endif
466 +#endif
467 +       return 0;
468 +}
469 +
470 +/*
471 + * helpers for the SPI register sets
472 + */
473 +#define bcm_spi_readb(b,o)      bcm_readb((b) + bcm63xx_spireg(o))
474 +#define bcm_spi_readw(b,o)      bcm_readw((b) + bcm63xx_spireg(o))
475 +#define bcm_spi_writeb(v,b,o)   bcm_writeb((v), (b) + bcm63xx_spireg(o))
476 +#define bcm_spi_writew(v,b,o)   bcm_writew((v), (b) + bcm63xx_spireg(o))
477 +
478 +struct bcm63xx_spi {
479 +       /* bitbang has to be first */
480 +        struct spi_bitbang     bitbang;
481 +        struct completion      done;
482 +
483 +        void __iomem           *regs;
484 +        int                    irq;
485 +
486 +       /* Platform data */
487 +        u32                    speed_hz;
488 +       unsigned                fifo_size;
489 +
490 +       /* Data buffers */
491 +       const unsigned char     *tx_ptr;
492 +       unsigned char           *rx_ptr;
493 +       int                     remaining_bytes;
494 +
495 +       struct clk              *clk;
496 +       struct resource         *ioarea;
497 +       struct platform_device  *pdev;
498 +};
499 +
500 +static void bcm63xx_spi_chipselect(struct spi_device *spi, int is_on)
501 +{
502 +       struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
503 +       u16 val;
504 +
505 +       val = bcm_spi_readw(bs->regs, SPI_CMD);
506 +       if (is_on == BITBANG_CS_INACTIVE)
507 +               val |= SPI_CMD_NOOP;
508 +       else if (is_on == BITBANG_CS_ACTIVE)
509 +               val |= (1 << spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
510 +
511 +       bcm_spi_writew(val, bs->regs, SPI_CMD);
512 +}
513 +
514 +static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
515 +                                       struct spi_transfer *t)
516 +{
517 +       u8 bits_per_word;
518 +       u8 clk_cfg;
519 +       u32 hz;
520 +       unsigned int div;
521 +
522 +       struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
523 +
524 +       bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
525 +       hz = (t) ? t->speed_hz : spi->max_speed_hz;
526 +       if (bits_per_word != 8) {
527 +               dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
528 +                       __func__, bits_per_word);
529 +               return -EINVAL;
530 +        }
531 +
532 +       if (spi->chip_select > spi->master->num_chipselect) {
533 +               dev_err(&spi->dev, "%s, unsupported slave %d\n",
534 +                       __func__, spi->chip_select);
535 +               return -EINVAL;
536 +       }
537 +
538 +       /* Check clock setting */
539 +       div = (bs->speed_hz / hz);
540 +       switch (div) {
541 +       case 2:
542 +               clk_cfg = SPI_CLK_25MHZ;
543 +               break;
544 +       case 4:
545 +               clk_cfg = SPI_CLK_12_50MHZ;
546 +               break;
547 +       case 8:
548 +               clk_cfg = SPI_CLK_6_250MHZ;
549 +               break;
550 +       case 16:
551 +               clk_cfg = SPI_CLK_3_125MHZ;
552 +               break;
553 +       case 32:
554 +               clk_cfg = SPI_CLK_1_563MHZ;
555 +               break;
556 +       case 128:
557 +               clk_cfg = SPI_CLK_0_781MHZ;
558 +               break;
559 +       case 64:
560 +       default:
561 +               /* Set to slowest mode for compatibility */
562 +               clk_cfg = SPI_CLK_0_781MHZ;
563 +               break;
564 +       }
565 +
566 +       bcm_spi_writeb(clk_cfg, bs->regs, SPI_CLK_CFG);
567 +       dev_dbg(&spi->dev, "Setting clock register to %d (hz %d, cmd %02x)\n",
568 +                                                               div, hz, clk_cfg);
569 +
570 +       return 0;
571 +}
572 +
573 +/* the spi->mode bits understood by this driver: */
574 +#define MODEBITS (SPI_CPOL | SPI_CPHA)
575 +
576 +static int bcm63xx_spi_setup(struct spi_device *spi)
577 +{
578 +       struct spi_bitbang *bitbang;
579 +       struct bcm63xx_spi *bs;
580 +       int retval;
581 +
582 +       bs = spi_master_get_devdata(spi->master);
583 +       bitbang = &bs->bitbang;
584 +
585 +       if (!spi->bits_per_word)
586 +               spi->bits_per_word = 8;
587 +
588 +       if (spi->mode & ~MODEBITS) {
589 +               dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
590 +                       __func__, spi->mode & ~MODEBITS);
591 +               return -EINVAL;
592 +       }
593 +
594 +       retval = bcm63xx_spi_setup_transfer(spi, NULL);
595 +       if (retval < 0) {
596 +               dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
597 +                       spi->mode & ~MODEBITS);
598 +               return retval;
599 +       }
600 +
601 +       dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
602 +               __func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
603 +
604 +       return 0;
605 +}
606 +
607 +/* Fill the TX FIFO with as many bytes as possible */
608 +static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
609 +{
610 +        u8 tail;
611 +
612 +        /* Fill the Tx FIFO with as many bytes as possible */
613 +       tail = bcm_spi_readb(bs->regs, SPI_MSG_TAIL);
614 +        while ((tail < bs->fifo_size) && (bs->remaining_bytes > 0)) {
615 +                if (bs->tx_ptr)
616 +                        bcm_spi_writeb(*bs->tx_ptr++, bs->regs, SPI_MSG_DATA);
617 +               else
618 +                       bcm_spi_writeb(0, bs->regs, SPI_MSG_DATA);
619 +                bs->remaining_bytes--;
620 +               tail = bcm_spi_readb(bs->regs, SPI_MSG_TAIL);
621 +        }
622 +}
623 +
624 +static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
625 +{
626 +       struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
627 +       u8 msg_ctl;
628 +       u16 cmd;
629 +
630 +       dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
631 +                               t->tx_buf, t->rx_buf, t->len);
632 +
633 +       /* Transmitter is inhibited */
634 +       bs->tx_ptr = t->tx_buf;
635 +       bs->rx_ptr = t->rx_buf;
636 +       bs->remaining_bytes = t->len;
637 +       init_completion(&bs->done);
638 +
639 +       bcm63xx_spi_fill_tx_fifo(bs);
640 +
641 +       /* Enable the command done interrupt which
642 +        * we use to determine completion of a command */
643 +       bcm_spi_writeb(SPI_INTR_CMD_DONE, bs->regs, SPI_INT_MASK);
644 +
645 +       /* Fill in the Message control register */
646 +       msg_ctl = bcm_spi_readb(bs->regs, SPI_MSG_CTL);
647 +       msg_ctl |= (t->len << SPI_BYTE_CNT_SHIFT);
648 +       msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT);
649 +       bcm_spi_writeb(msg_ctl, bs->regs, SPI_MSG_CTL);
650 +
651 +       /* Issue the transfer */
652 +       cmd = bcm_spi_readw(bs->regs, SPI_CMD);
653 +       cmd |= SPI_CMD_START_IMMEDIATE;
654 +       cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
655 +       bcm_spi_writew(cmd, bs->regs, SPI_CMD);
656 +
657 +       wait_for_completion(&bs->done);
658 +
659 +       /* Disable the CMD_DONE interrupt */
660 +       bcm_spi_writeb(~(SPI_INTR_CMD_DONE), bs->regs, SPI_INT_MASK);
661 +
662 +       return t->len - bs->remaining_bytes;
663 +}
664 +
665 +/* This driver supports single master mode only. Hence
666 + * CMD_DONE is the only interrupt we care about
667 + */
668 +static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
669 +{
670 +       struct spi_master *master = (struct spi_master *)dev_id;
671 +       struct bcm63xx_spi *bs = spi_master_get_devdata(master);
672 +       u8 intr;
673 +       u16 cmd;
674 +
675 +       /* Read interupts and clear them immediately */
676 +       intr = bcm_spi_readb(bs->regs, SPI_INT_STATUS);
677 +       bcm_spi_writeb(SPI_INTR_CLEAR_ALL, bs->regs, SPI_INT_MASK);
678 +
679 +       /* A tansfer completed */
680 +       if (intr & SPI_INTR_CMD_DONE) {
681 +               u8 rx_empty;
682 +
683 +               rx_empty = bcm_spi_readb(bs->regs, SPI_ST);
684 +               /* Read out all the data */
685 +               while ((rx_empty & SPI_RX_EMPTY) == 0) {
686 +                       u8 data;
687 +
688 +                       data = bcm_spi_readb(bs->regs, SPI_RX_DATA);
689 +                       if (bs->rx_ptr)
690 +                               *bs->rx_ptr++ = data;
691 +
692 +                       rx_empty = bcm_spi_readb(bs->regs, SPI_RX_EMPTY);
693 +               }
694 +
695 +               /* See if there is more data to send */
696 +               if (bs->remaining_bytes > 0) {
697 +                       bcm63xx_spi_fill_tx_fifo(bs);
698 +
699 +                       /* Start the transfer */
700 +                       cmd = bcm_spi_readw(bs->regs, SPI_CMD);
701 +                       cmd |= SPI_CMD_START_IMMEDIATE;
702 +                       cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
703 +                       bcm_spi_writew(cmd, bs->regs, SPI_CMD);
704 +               } else
705 +                       complete(&bs->done);
706 +       }
707 +
708 +       return IRQ_HANDLED;
709 +}
710 +
711 +
712 +static int __init bcm63xx_spi_probe(struct platform_device *pdev)
713 +{
714 +       struct resource *r;
715 +       struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data;
716 +       int irq;
717 +       struct spi_master *master;
718 +       struct clk *clk;
719 +       struct bcm63xx_spi *bs;
720 +       int ret;
721 +
722 +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
723 +       if (!r) {
724 +               ret = -ENXIO;
725 +               goto out;
726 +       }
727 +
728 +       irq = platform_get_irq(pdev, 0);
729 +       if (irq < 0) {
730 +               ret = -ENXIO;
731 +               goto out;
732 +       }
733 +
734 +       bcm63xx_spi_regs_init();
735 +
736 +       clk = clk_get(&pdev->dev, "spi");
737 +       if (IS_ERR(clk)) {
738 +               dev_err(&pdev->dev, "No clock for device\n");
739 +               ret = -ENODEV;
740 +               goto out;
741 +       }
742 +
743 +       master = spi_alloc_master(&pdev->dev, sizeof(struct bcm63xx_spi));
744 +       if (!master) {
745 +               ret = -ENOMEM;
746 +               goto out_free;
747 +       }
748 +
749 +       bs = spi_master_get_devdata(master);
750 +       bs->bitbang.master = spi_master_get(master);
751 +       bs->bitbang.chipselect = bcm63xx_spi_chipselect;
752 +       bs->bitbang.setup_transfer = bcm63xx_spi_setup_transfer;
753 +       bs->bitbang.txrx_bufs = bcm63xx_txrx_bufs;
754 +       bs->bitbang.master->setup = bcm63xx_spi_setup;
755 +       init_completion(&bs->done);
756 +
757 +       platform_set_drvdata(pdev, master);
758 +        bs->pdev = pdev;
759 +
760 +       if (!request_mem_region(r->start,
761 +                       r->end - r->start, PFX)) {
762 +               ret = -ENXIO;
763 +               goto out_free;
764 +       }
765 +
766 +        bs->regs = ioremap_nocache(r->start, r->end - r->start);
767 +       if (!bs->regs) {
768 +               printk(KERN_ERR PFX " unable to ioremap regs\n");
769 +               ret = -ENOMEM;
770 +               goto out_free;
771 +       }
772 +       bs->irq = irq;
773 +       bs->clk = clk;
774 +       bs->fifo_size = pdata->fifo_size;
775 +
776 +       ret = request_irq(irq, bcm63xx_spi_interrupt, 0,
777 +                               pdev->name, master);
778 +       if (ret) {
779 +               printk(KERN_ERR PFX " unable to request irq\n");
780 +               goto out_unmap;
781 +       }
782 +
783 +       master->bus_num = pdata->bus_num;
784 +       master->num_chipselect = pdata->num_chipselect;
785 +       bs->speed_hz = pdata->speed_hz;
786 +
787 +       /* Initialize hardware */
788 +       clk_enable(bs->clk);
789 +       bcm_spi_writeb(SPI_INTR_CLEAR_ALL, bs->regs, SPI_INT_MASK);
790 +
791 +       dev_info(&pdev->dev, " at 0x%08x (irq %d, FIFOs size %d) v%s\n",
792 +                               r->start, irq, bs->fifo_size, DRV_VER);
793 +
794 +       ret = spi_bitbang_start(&bs->bitbang);
795 +       if (ret) {
796 +               dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
797 +               goto out_reset_hw;
798 +       }
799 +
800 +       return ret;
801 +
802 +out_reset_hw:
803 +       clk_disable(clk);
804 +       free_irq(irq, master);
805 +out_unmap:
806 +       iounmap(bs->regs);
807 +out_free:
808 +       clk_put(clk);
809 +       spi_master_put(master);
810 +out:
811 +       return ret;
812 +}
813 +
814 +static int __exit bcm63xx_spi_remove(struct platform_device *pdev)
815 +{
816 +       struct spi_master       *master = platform_get_drvdata(pdev);
817 +       struct bcm63xx_spi      *bs = spi_master_get_devdata(master);
818 +
819 +       spi_bitbang_stop(&bs->bitbang);
820 +       clk_disable(bs->clk);
821 +       clk_put(bs->clk);
822 +       free_irq(bs->irq, master);
823 +       iounmap(bs->regs);
824 +       platform_set_drvdata(pdev, 0);
825 +       spi_master_put(bs->bitbang.master);
826 +
827 +       return 0;
828 +}
829 +
830 +#ifdef CONFIG_PM
831 +static int bcm63xx_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
832 +{
833 +       struct spi_master       *master = platform_get_drvdata(pdev);
834 +       struct bcm63xx_spi      *bs = spi_master_get_devdata(master);
835 +
836 +        clk_disable(bs->clk);
837 +
838 +       return 0;
839 +}
840 +
841 +static int bcm63xx_spi_resume(struct platform_device *pdev)
842 +{
843 +       struct bcm63xx_spi      *bs = spi_master_get_devdata(master);
844 +       struct bcm63xx_spi      *bs = spi_master_get_devdata(master);
845 +
846 +       clk_enable(bs->clk);
847 +
848 +       return 0;
849 +}
850 +#else
851 +#define bcm63xx_spi_suspend    NULL
852 +#define bcm63xx_spi_resume     NULL
853 +#endif
854 +
855 +static struct platform_driver bcm63xx_spi_driver = {
856 +       .driver = {
857 +               .name   = "bcm63xx-spi",
858 +               .owner  = THIS_MODULE,
859 +       },
860 +       .probe          = bcm63xx_spi_probe,
861 +       .remove         = bcm63xx_spi_remove,
862 +       .suspend        = bcm63xx_spi_suspend,
863 +       .resume         = bcm63xx_spi_resume,
864 +};
865 +
866 +
867 +static int __init bcm63xx_spi_init(void)
868 +{
869 +       return platform_driver_register(&bcm63xx_spi_driver);
870 +}
871 +
872 +static void __exit bcm63xx_spi_exit(void)
873 +{
874 +       platform_driver_unregister(&bcm63xx_spi_driver);
875 +}
876 +
877 +module_init(bcm63xx_spi_init);
878 +module_exit(bcm63xx_spi_exit);
879 +
880 +MODULE_ALIAS("platform:bcm63xx_spi");
881 +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
882 +MODULE_DESCRIPTION("Broadcom BCM63xx SPI Controller driver");
883 +MODULE_LICENSE("GPL");
884 +MODULE_VERSION(DRV_VER);
885 Index: linux-2.6.32.10/drivers/spi/Kconfig
886 ===================================================================
887 --- linux-2.6.32.10.orig/drivers/spi/Kconfig    2010-04-22 17:35:20.000000000 +0200
888 +++ linux-2.6.32.10/drivers/spi/Kconfig 2010-04-22 17:35:21.000000000 +0200
889 @@ -60,6 +60,13 @@
890           This selects a driver for the Atmel SPI Controller, present on
891           many AT32 (AVR32) and AT91 (ARM) chips.
892  
893 +config SPI_BCM63XX
894 +       tristate "Broadcom BCM63xx SPI controller"
895 +       depends on BCM63XX
896 +       select SPI_BITBANG
897 +       help
898 +         This is the SPI controller master driver for Broadcom BCM63xx SoC.
899 +
900  config SPI_BFIN
901         tristate "SPI controller driver for ADI Blackfin5xx"
902         depends on BLACKFIN
903 Index: linux-2.6.32.10/drivers/spi/Makefile
904 ===================================================================
905 --- linux-2.6.32.10.orig/drivers/spi/Makefile   2010-04-22 17:35:20.000000000 +0200
906 +++ linux-2.6.32.10/drivers/spi/Makefile        2010-04-22 17:35:21.000000000 +0200
907 @@ -34,6 +34,7 @@
908  obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
909  obj-$(CONFIG_SPI_SH_SCI)               += spi_sh_sci.o
910  obj-$(CONFIG_SPI_STMP3XXX)             += spi_stmp.o
911 +obj-$(CONFIG_SPI_BCM63XX)              += bcm63xx_spi.o
912  #      ... add above this line ...
913  
914  # SPI protocol drivers (device/link on bus)
915 Index: linux-2.6.32.10/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
916 ===================================================================
917 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
918 +++ linux-2.6.32.10/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h        2010-04-22 17:35:21.000000000 +0200
919 @@ -0,0 +1,15 @@
920 +#ifndef BCM63XX_DEV_SPI_H
921 +#define BCM63XX_DEV_SPI_H
922 +
923 +#include <linux/types.h>
924 +
925 +int __init bcm63xx_spi_register(void);
926 +
927 +struct bcm63xx_spi_pdata {
928 +       unsigned int    fifo_size;
929 +       int             bus_num;
930 +       int             num_chipselect;
931 +       u32             speed_hz;
932 +};
933 +
934 +#endif /* BCM63XX_DEV_SPI_H */
935 Index: linux-2.6.32.10/arch/mips/bcm63xx/Makefile
936 ===================================================================
937 --- linux-2.6.32.10.orig/arch/mips/bcm63xx/Makefile     2010-04-22 17:35:21.000000000 +0200
938 +++ linux-2.6.32.10/arch/mips/bcm63xx/Makefile  2010-04-22 17:35:21.000000000 +0200
939 @@ -1,6 +1,6 @@
940  obj-y          += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
941                    dev-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o dev-wdt.o \
942 -                  dev-usb-ohci.o dev-usb-ehci.o dev-usb-udc.o
943 +                  dev-usb-ohci.o dev-usb-ehci.o dev-usb-udc.o dev-spi.o
944  obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
945  
946  obj-y          += boards/
947 Index: linux-2.6.32.10/arch/mips/bcm63xx/boards/board_bcm963xx.c
948 ===================================================================
949 --- linux-2.6.32.10.orig/arch/mips/bcm63xx/boards/board_bcm963xx.c      2010-04-22 17:35:21.000000000 +0200
950 +++ linux-2.6.32.10/arch/mips/bcm63xx/boards/board_bcm963xx.c   2010-04-22 17:35:21.000000000 +0200
951 @@ -29,6 +29,7 @@
952  #include <bcm63xx_dev_usb_ohci.h>
953  #include <bcm63xx_dev_usb_ehci.h>
954  #include <bcm63xx_dev_usb_udc.h>
955 +#include <bcm63xx_dev_spi.h>
956  #include <board_bcm963xx.h>
957  
958  #define PFX    "board_bcm963xx: "
959 @@ -998,6 +999,9 @@
960         if (board.has_udc0)
961                 bcm63xx_udc_register();
962  
963 +       if (!BCMCPU_IS_6345())
964 +               bcm63xx_spi_register();
965 +
966         /* Generate MAC address for WLAN and
967          * register our SPROM */
968  #ifdef CONFIG_SSB_PCIHOST