cns21xx: add initial support for the Cavium CNS21xx SoC
[openwrt.git] / target / linux / cns21xx / patches-2.6.36 / 105-cns21xx-spi-driver.patch
1 --- a/include/linux/spi/spi.h
2 +++ b/include/linux/spi/spi.h
3 @@ -442,6 +442,8 @@ struct spi_transfer {
4         u16             delay_usecs;
5         u32             speed_hz;
6  
7 +       unsigned        last_in_message_list;
8 +
9         struct list_head transfer_list;
10  };
11  
12 --- a/drivers/spi/Kconfig
13 +++ b/drivers/spi/Kconfig
14 @@ -152,6 +152,14 @@ config SPI_GPIO_OLD
15  
16           If unsure, say N.
17  
18 +config SPI_CNS21XX
19 +       tristate "Cavium Netowrks CNS21xx SPI master"
20 +       depends on ARCH_CNS21XX && EXPERIMENTAL
21 +       select SPI_BITBANG
22 +       help
23 +         This driver supports the buil-in SPI controller of the Cavium Networks
24 +         CNS21xx SoCs.
25 +
26  config SPI_IMX
27         tristate "Freescale i.MX SPI controllers"
28         depends on ARCH_MXC
29 --- a/drivers/spi/Makefile
30 +++ b/drivers/spi/Makefile
31 @@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_SH_SCI)              += spi_sh_sci.
32  obj-$(CONFIG_SPI_SH_MSIOF)             += spi_sh_msiof.o
33  obj-$(CONFIG_SPI_STMP3XXX)             += spi_stmp.o
34  obj-$(CONFIG_SPI_NUC900)               += spi_nuc900.o
35 +obj-$(CONFIG_SPI_CNS21XX)              += spi_cns21xx.o
36  
37  # special build for s3c24xx spi driver with fiq support
38  spi_s3c24xx_hw-y                       := spi_s3c24xx.o
39 --- a/drivers/spi/spi_bitbang.c
40 +++ b/drivers/spi/spi_bitbang.c
41 @@ -337,6 +337,13 @@ static void bitbang_work(struct work_str
42                                  */
43                                 if (!m->is_dma_mapped)
44                                         t->rx_dma = t->tx_dma = 0;
45 +
46 +                               if (t->transfer_list.next == &m->transfers) {
47 +                                       t->last_in_message_list = 1;
48 +                               } else {
49 +                                       t->last_in_message_list = 0;
50 +                               }
51 +
52                                 status = bitbang->txrx_bufs(spi, t);
53                         }
54                         if (status > 0)
55 --- /dev/null
56 +++ b/drivers/spi/spi_cns21xx.c
57 @@ -0,0 +1,520 @@
58 +/*
59 + *  Copyright (c) 2008 Cavium Networks
60 + *  Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
61 + *
62 + *  This file is free software; you can redistribute it and/or modify
63 + *  it under the terms of the GNU General Public License, Version 2, as
64 + *  published by the Free Software Foundation.
65 + */
66 +
67 +#include <linux/init.h>
68 +#include <linux/spinlock.h>
69 +#include <linux/workqueue.h>
70 +#include <linux/interrupt.h>
71 +#include <linux/delay.h>
72 +#include <linux/errno.h>
73 +#include <linux/platform_device.h>
74 +#include <linux/io.h>
75 +#include <linux/spi/spi.h>
76 +#include <linux/spi/spi_bitbang.h>
77 +
78 +#include <mach/hardware.h>
79 +#include <mach/cns21xx.h>
80 +
81 +#define DRIVER_NAME    "cns21xx-spi"
82 +
83 +#ifdef CONFIG_CNS21XX_SPI_DEBUG
84 +#define DBG(fmt, args...)      pr_info("[CNS21XX_SPI_DEBUG]" fmt, ## args)
85 +#else
86 +#define DBG(fmt, args...)      do {} while (0)
87 +#endif /*  CNS21XX_SPI_DEBUG */
88 +
89 +#define SPI_REG_CFG                    0x40
90 +#define SPI_REG_STAT                   0x44
91 +#define SPI_REG_BIT_RATE               0x48
92 +#define SPI_REG_TX_CTRL                        0x4c
93 +#define SPI_REG_TX_DATA                        0x50
94 +#define SPI_REG_RX_CTRL                        0x54
95 +#define SPI_REG_RX_DATA                        0x58
96 +#define SPI_REG_FIFO_TX_CFG            0x5c
97 +#define SPI_REG_FIFO_TX_CTRL           0x60
98 +#define SPI_REG_FIFO_RX_CFG            0x64
99 +#define SPI_REG_INTR_STAT              0x68
100 +#define SPI_REG_INTR_ENA               0x6c
101 +
102 +#define CFG_SPI_EN                     BIT(31)
103 +#define CFG_SPI_CLKPOL                 BIT(14)
104 +#define CFG_SPI_CLKPHA                 BIT(13)
105 +#define CFG_SPI_MASTER_EN              BIT(11)
106 +#define CFG_SPI_CHAR_LEN_M             0x3
107 +#define CFG_SPI_CHAR_LEN_8BITS         0
108 +#define CFG_SPI_CHAR_LEN_16BITS                1
109 +#define CFG_SPI_CHAR_LEN_24BITS                2
110 +#define CFG_SPI_CHAR_LEN_32BITS                3
111 +
112 +#define STAT_SPI_BUSY_STA              BIT(1)
113 +
114 +#define BIT_RATE_DIV_1                 0
115 +#define BIT_RATE_DIV_2                 1
116 +#define BIT_RATE_DIV_4                 2
117 +#define BIT_RATE_DIV_8                 3
118 +#define BIT_RATE_DIV_16                        4
119 +#define BIT_RATE_DIV_32                        5
120 +#define BIT_RATE_DIV_64                        6
121 +#define BIT_RATE_DIV_128               7
122 +
123 +#define TX_CTRL_SPI_TXDAT_EOF          BIT(2)
124 +#define TX_CTRL_SPI_TXCH_NUM_M         0x3
125 +#define TX_CTRL_CLEAR_MASK             (TX_CTRL_SPI_TXDAT_EOF | \
126 +                                        TX_CTRL_SPI_TXCH_NUM_M)
127 +
128 +#define RX_CTRL_SPI_RXDAT_EOF          BIT(2)
129 +#define RX_CTRL_SPI_RXCH_NUM_M         0x3
130 +
131 +#define INTR_STAT_SPI_TXBF_UNRN_FG     BIT(7)
132 +#define INTR_STAT_SPI_RXBF_OVRN_FG     BIT(6)
133 +#define INTR_STAT_SPI_TXFF_UNRN_FG     BIT(5)
134 +#define INTR_STAT_SPI_RXFF_OVRN_FG     BIT(4)
135 +#define INTR_STAT_SPI_TXBUF_FG         BIT(3)
136 +#define INTR_STAT_SPI_RXBUF_FG         BIT(2)
137 +#define INTR_STAT_SPI_TXFF_FG          BIT(1)
138 +#define INTR_STAT_SPI_RXFF_FG          BIT(0)
139 +
140 +#define INTR_STAT_CLEAR_MASK           (INTR_STAT_SPI_TXBF_UNRN_FG | \
141 +                                        INTR_STAT_SPI_RXBF_OVRN_FG | \
142 +                                        INTR_STAT_SPI_TXFF_UNRN_FG | \
143 +                                        INTR_STAT_SPI_RXFF_OVRN_FG)
144 +
145 +#define FIFO_TX_CFG_SPI_TXFF_THRED_M   0x3
146 +#define FIFO_TX_CFG_SPI_TXFF_THRED_S   4
147 +#define FIFO_TX_CFG_SPI_TXFF_THRED_2   0
148 +#define FIFO_TX_CFG_SPI_TXFF_THRED_4   1
149 +#define FIFO_TX_CFG_SPI_TXFF_THRED_6   0
150 +#define FIFO_TX_CFG_SPI_TXFF_STATUS_M  0xf
151 +
152 +#define FIFO_RX_CFG_SPI_RXFF_THRED_M   0x3
153 +#define FIFO_RX_CFG_SPI_RXFF_THRED_S   4
154 +#define FIFO_RX_CFG_SPI_RXFF_THRED_2   0
155 +#define FIFO_RX_CFG_SPI_RXFF_THRED_4   1
156 +#define FIFO_RX_CFG_SPI_RXFF_THRED_6   0
157 +#define FIFO_RX_CFG_SPI_RXFF_STATUS_M  0xf
158 +
159 +#define CNS21XX_SPI_NUM_BIT_RATES      8
160 +
161 +struct cns21xx_spi {
162 +       struct spi_bitbang      bitbang;
163 +
164 +       struct spi_master       *master;
165 +       struct device           *dev;
166 +       void __iomem            *base;
167 +       struct resource         *region;
168 +
169 +       unsigned                freq_max;
170 +       unsigned                freq_min;
171 +
172 +};
173 +
174 +static inline struct cns21xx_spi *to_hw(struct spi_device *spi)
175 +{
176 +       return spi_master_get_devdata(spi->master);
177 +}
178 +
179 +static inline u32 cns21xx_spi_rr(struct cns21xx_spi *hw, unsigned int reg)
180 +{
181 +       return __raw_readl(hw->base + reg);
182 +}
183 +
184 +static inline void cns21xx_spi_wr(struct cns21xx_spi *hw, u32 val,
185 +                                 unsigned int reg)
186 +{
187 +       __raw_writel(val, hw->base + reg);
188 +}
189 +
190 +#define CNS21XX_SPI_RETRY_COUNT                100
191 +static inline int cns21xx_spi_wait(struct cns21xx_spi *hw, unsigned int reg,
192 +                                  u32 mask, u32 val)
193 +{
194 +       int retry_cnt = 0;
195 +
196 +       do {
197 +               if ((cns21xx_spi_rr(hw, reg) & mask) == val)
198 +                       break;
199 +
200 +               if (++retry_cnt > CNS21XX_SPI_RETRY_COUNT) {
201 +                       dev_err(hw->dev, "timeout waiting on register %02x\n",
202 +                               reg);
203 +                       return -EIO;
204 +               }
205 +       } while (1);
206 +
207 +       return 0;
208 +}
209 +
210 +static int cns21xx_spi_txrx_word(struct cns21xx_spi *hw, u8 tx_channel,
211 +                                u8 tx_eof_flag, u32 tx_data, u32 *rx_data)
212 +{
213 +       unsigned int tx_ctrl;
214 +       u8 rx_channel;
215 +       u8 rx_eof_flag;
216 +       int err = 0;
217 +
218 +       err = cns21xx_spi_wait(hw, SPI_REG_STAT, STAT_SPI_BUSY_STA, 0);
219 +       if (err)
220 +               return err;
221 +
222 +       err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_TXBUF_FG,
223 +                              INTR_STAT_SPI_TXBUF_FG);
224 +       if (err)
225 +               return err;
226 +
227 +       tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
228 +       tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
229 +       tx_ctrl |= (tx_channel & TX_CTRL_SPI_TXCH_NUM_M);
230 +       tx_ctrl |= (tx_eof_flag) ? TX_CTRL_SPI_TXDAT_EOF : 0;
231 +       cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
232 +
233 +       cns21xx_spi_wr(hw, tx_data, SPI_REG_TX_DATA);
234 +
235 +       err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_RXBUF_FG,
236 +                              INTR_STAT_SPI_RXBUF_FG);
237 +       if (err)
238 +               return err;
239 +
240 +       rx_channel = cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
241 +                                       RX_CTRL_SPI_RXCH_NUM_M;
242 +
243 +       rx_eof_flag = (cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
244 +                                       RX_CTRL_SPI_RXDAT_EOF) ? 1 : 0;
245 +
246 +       *rx_data = cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
247 +
248 +       if ((tx_channel != rx_channel) || (tx_eof_flag != rx_eof_flag))
249 +               return -EPROTO;
250 +
251 +       return 0;
252 +}
253 +
254 +static void cns21xx_spi_chipselect(struct spi_device *spi, int value)
255 +{
256 +       struct cns21xx_spi *hw = to_hw(spi);
257 +       unsigned int spi_config;
258 +       unsigned int tx_ctrl;
259 +
260 +       switch (value) {
261 +       case BITBANG_CS_INACTIVE:
262 +               break;
263 +
264 +       case BITBANG_CS_ACTIVE:
265 +               spi_config = cns21xx_spi_rr(hw, SPI_REG_CFG);
266 +
267 +               if (spi->mode & SPI_CPHA)
268 +                       spi_config |= CFG_SPI_CLKPHA;
269 +               else
270 +                       spi_config &= ~CFG_SPI_CLKPHA;
271 +
272 +               if (spi->mode & SPI_CPOL)
273 +                       spi_config |= CFG_SPI_CLKPOL;
274 +               else
275 +                       spi_config &= ~CFG_SPI_CLKPOL;
276 +
277 +               cns21xx_spi_wr(hw, spi_config, SPI_REG_CFG);
278 +
279 +               tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
280 +               tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
281 +               tx_ctrl |= (spi->chip_select & TX_CTRL_SPI_TXCH_NUM_M);
282 +               cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
283 +
284 +               break;
285 +       }
286 +}
287 +
288 +static int cns21xx_spi_setup(struct spi_device *spi)
289 +{
290 +       struct cns21xx_spi *hw = to_hw(spi);
291 +
292 +       if (spi->bits_per_word != 8) {
293 +               dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
294 +                       __func__, spi->bits_per_word);
295 +               return -EINVAL;
296 +       }
297 +
298 +       if (spi->max_speed_hz == 0)
299 +               spi->max_speed_hz = hw->freq_max;
300 +
301 +       if (spi->max_speed_hz > hw->freq_max ||
302 +           spi->max_speed_hz < hw->freq_min) {
303 +               dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
304 +                       __func__, spi->max_speed_hz);
305 +               return -EINVAL;
306 +       }
307 +
308 +       return 0;
309 +}
310 +
311 +static int cns21xx_spi_setup_transfer(struct spi_device *spi,
312 +                                     struct spi_transfer *t)
313 +{
314 +       struct cns21xx_spi *hw = to_hw(spi);
315 +       u8      bits_per_word;
316 +       u32     hz;
317 +       int     i;
318 +
319 +       bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
320 +       hz = t ? t->speed_hz : spi->max_speed_hz;
321 +
322 +       if (!bits_per_word)
323 +               bits_per_word = spi->bits_per_word;
324 +
325 +       if (!hz)
326 +               hz = spi->max_speed_hz;
327 +
328 +       if (bits_per_word != 8) {
329 +               dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
330 +                       __func__, bits_per_word);
331 +               return -EINVAL;
332 +       }
333 +
334 +       if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
335 +               dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
336 +                       __func__, hz);
337 +               return -EINVAL;
338 +       }
339 +
340 +       for (i = 0; i < CNS21XX_SPI_NUM_BIT_RATES; i++)
341 +               if (spi->max_speed_hz > (cns21xx_get_apb_freq() >> i))
342 +                       break;
343 +
344 +       DBG("max_speed:%uHz, curr_speed:%luHz, rate_index=%d\n",
345 +           spi->max_speed_hz, cns21xx_get_apb_freq() / (1 << i), i);
346 +
347 +       cns21xx_spi_wr(hw, i, SPI_REG_BIT_RATE);
348 +
349 +       return 0;
350 +}
351 +
352 +static int cns21xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
353 +{
354 +       struct cns21xx_spi *hw = to_hw(spi);
355 +       const unsigned char *tx_buf;
356 +       unsigned char *rx_buf;
357 +       u32 rx_data;
358 +       int tx_eof;
359 +       int err = 0;
360 +       int i;
361 +
362 +       tx_buf = t->tx_buf;
363 +       rx_buf = t->rx_buf;
364 +       tx_eof = t->last_in_message_list;
365 +
366 +       DBG("txrx: tx %p, rx %p, len %d\n", tx_buf, rx_buf, t->len);
367 +
368 +       if (tx_buf) {
369 +               for (i = 0; i < t->len; i++)
370 +                       DBG("tx_buf[%02d]: 0x%02x\n", i, tx_buf[i]);
371 +
372 +               for (i = 0; i < (t->len - 1); i++) {
373 +                       err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
374 +                                                   tx_buf[i], &rx_data);
375 +                       if (err)
376 +                               goto done;
377 +
378 +                       if (rx_buf) {
379 +                               rx_buf[i] = rx_data;
380 +                               DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
381 +                       }
382 +               }
383 +
384 +               err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
385 +                                           tx_buf[i], &rx_data);
386 +               if (err)
387 +                       goto done;
388 +
389 +               if ((tx_eof) && rx_buf) {
390 +                       rx_buf[i] = rx_data;
391 +                       DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
392 +               }
393 +       } else if (rx_buf) {
394 +               for (i = 0; i < (t->len - 1); i++) {
395 +                       err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
396 +                                                   0xff, &rx_data);
397 +                       if (err)
398 +                               goto done;
399 +
400 +                       rx_buf[i] = rx_data;
401 +                       DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
402 +               }
403 +
404 +               err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
405 +                                           0xff, &rx_data);
406 +               if (err)
407 +                       goto done;
408 +
409 +               rx_buf[i] = rx_data;
410 +               DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
411 +       }
412 +
413 + done:
414 +       return (err) ? err : t->len;
415 +}
416 +
417 +static void __init cns21xx_spi_hw_init(struct cns21xx_spi *hw)
418 +{
419 +       u32 t;
420 +       u32 pclk;
421 +
422 +       /* Setup configuration register */
423 +       cns21xx_spi_wr(hw, CFG_SPI_MASTER_EN, SPI_REG_CFG);
424 +
425 +       /* Set default clock to PCLK/2 */
426 +       cns21xx_spi_wr(hw, BIT_RATE_DIV_2, SPI_REG_BIT_RATE);
427 +
428 +       /* Configure SPI's Tx channel */
429 +       cns21xx_spi_wr(hw, 0, SPI_REG_TX_CTRL);
430 +
431 +       /* Configure Tx FIFO Threshold */
432 +       t = cns21xx_spi_rr(hw, SPI_REG_FIFO_TX_CFG);
433 +       t &= ~(FIFO_TX_CFG_SPI_TXFF_THRED_M << FIFO_TX_CFG_SPI_TXFF_THRED_S);
434 +       t |= (FIFO_TX_CFG_SPI_TXFF_THRED_2 << FIFO_TX_CFG_SPI_TXFF_THRED_S);
435 +       cns21xx_spi_wr(hw, t, SPI_REG_FIFO_TX_CFG);
436 +
437 +       /* Configure Rx FIFO Threshold */
438 +       t = cns21xx_spi_rr(hw, SPI_REG_FIFO_RX_CFG);
439 +       t &= ~(FIFO_RX_CFG_SPI_RXFF_THRED_M << FIFO_RX_CFG_SPI_RXFF_THRED_S);
440 +       t |= (FIFO_RX_CFG_SPI_RXFF_THRED_2 << FIFO_RX_CFG_SPI_RXFF_THRED_S);
441 +       cns21xx_spi_wr(hw, t, SPI_REG_FIFO_RX_CFG);
442 +
443 +       /* Disable interrupts, and clear interrupt status */
444 +       cns21xx_spi_wr(hw, 0, SPI_REG_INTR_ENA);
445 +       cns21xx_spi_wr(hw, INTR_STAT_CLEAR_MASK, SPI_REG_INTR_STAT);
446 +
447 +       (void) cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
448 +
449 +       /* Enable SPI */
450 +       t = cns21xx_spi_rr(hw, SPI_REG_CFG);
451 +       t |= CFG_SPI_EN;
452 +       cns21xx_spi_wr(hw, t, SPI_REG_CFG);
453 +
454 +       pclk = cns21xx_get_apb_freq();
455 +       hw->freq_max = pclk;
456 +       hw->freq_min = pclk / (1 << BIT_RATE_DIV_128);
457 +}
458 +
459 +static int __init cns21xx_spi_probe(struct platform_device *pdev)
460 +{
461 +       struct cns21xx_spi *hw;
462 +       struct spi_master *master;
463 +       struct resource *res;
464 +       int err = 0;
465 +
466 +       master = spi_alloc_master(&pdev->dev, sizeof(struct cns21xx_spi));
467 +       if (!master) {
468 +               dev_err(&pdev->dev, "No memory for spi_master\n");
469 +               return -ENOMEM;
470 +       }
471 +
472 +       hw = spi_master_get_devdata(master);
473 +
474 +       platform_set_drvdata(pdev, hw);
475 +       hw->master = spi_master_get(master);
476 +       hw->dev = &pdev->dev;
477 +
478 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
479 +       if (!res) {
480 +               dev_dbg(&pdev->dev, "no MEM resource found\n");
481 +               err = -ENOENT;
482 +               goto err_put_master;
483 +       }
484 +
485 +       hw->region = request_mem_region(res->start, resource_size(res),
486 +                                       dev_name(&pdev->dev));
487 +       if (!hw->region) {
488 +               dev_err(&pdev->dev, "unable to reserve iomem region\n");
489 +               err = -ENXIO;
490 +               goto err_put_master;
491 +       }
492 +
493 +       hw->base = ioremap(res->start, resource_size(res));
494 +       if (!hw->base) {
495 +               dev_err(&pdev->dev, "ioremap failed\n");
496 +               err = -ENOENT;
497 +               goto err_release_region;
498 +       }
499 +
500 +       cns21xx_spi_hw_init(hw);
501 +
502 +       master->bus_num = pdev->id;
503 +       if (master->bus_num == -1)
504 +               master->bus_num = 0;
505 +
506 +       master->num_chipselect = 4;
507 +       master->setup = cns21xx_spi_setup;
508 +
509 +       hw->bitbang.master = hw->master;
510 +       hw->bitbang.chipselect = cns21xx_spi_chipselect;
511 +       hw->bitbang.txrx_bufs = cns21xx_spi_txrx;
512 +       hw->bitbang.setup_transfer = cns21xx_spi_setup_transfer;
513 +
514 +       err = spi_bitbang_start(&hw->bitbang);
515 +       if (err) {
516 +               dev_err(hw->dev, "unable to register SPI master\n");
517 +               goto err_unmap;
518 +       }
519 +
520 +       dev_info(hw->dev, "iomem at %08x\n", res->start);
521 +
522 +       return 0;
523 +
524 + err_unmap:
525 +       iounmap(hw->base);
526 +
527 + err_release_region:
528 +       release_resource(hw->region);
529 +       kfree(hw->region);
530 +
531 + err_put_master:
532 +       spi_master_put(hw->bitbang.master);
533 +       platform_set_drvdata(pdev, NULL);
534 +
535 +       return err;
536 +}
537 +
538 +static int __devexit cns21xx_spi_remove(struct platform_device *pdev)
539 +{
540 +       struct cns21xx_spi *hw = platform_get_drvdata(pdev);
541 +
542 +       spi_bitbang_stop(&hw->bitbang);
543 +       iounmap(hw->base);
544 +       release_resource(hw->region);
545 +       kfree(hw->region);
546 +       spi_master_put(hw->bitbang.master);
547 +       platform_set_drvdata(pdev, NULL);
548 +
549 +       return 0;
550 +}
551 +
552 +static struct platform_driver cns21xx_spi_driver = {
553 +       .remove         = __devexit_p(cns21xx_spi_remove),
554 +       .driver         = {
555 +               .name   = DRIVER_NAME,
556 +               .owner  = THIS_MODULE,
557 +       },
558 +};
559 +
560 +static int __init cns21xx_spi_init(void)
561 +{
562 +       return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe);
563 +}
564 +
565 +static void __exit cns21xx_spi_exit(void)
566 +{
567 +       platform_driver_unregister(&cns21xx_spi_driver);
568 +}
569 +
570 +module_init(cns21xx_spi_init);
571 +module_exit(cns21xx_spi_exit);
572 +
573 +MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver");
574 +MODULE_AUTHOR("STAR Semi Corp.");
575 +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
576 +MODULE_LICENSE("GPL v2");
577 +MODULE_ALIAS("platform:" DRIVER_NAME);