diff options
Diffstat (limited to 'drivers/spi/spi-mpc52xx-psc.c')
-rw-r--r-- | drivers/spi/spi-mpc52xx-psc.c | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c new file mode 100644 index 000000000000..e30baf0852ac --- /dev/null +++ b/drivers/spi/spi-mpc52xx-psc.c | |||
@@ -0,0 +1,529 @@ | |||
1 | /* | ||
2 | * MPC52xx PSC in SPI mode driver. | ||
3 | * | ||
4 | * Maintainer: Dragos Carp | ||
5 | * | ||
6 | * Copyright (C) 2006 TOPTICA Photonics AG. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | #include <linux/workqueue.h> | ||
22 | #include <linux/completion.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/spi/spi.h> | ||
26 | #include <linux/fsl_devices.h> | ||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include <asm/mpc52xx.h> | ||
30 | #include <asm/mpc52xx_psc.h> | ||
31 | |||
32 | #define MCLK 20000000 /* PSC port MClk in hz */ | ||
33 | |||
34 | struct mpc52xx_psc_spi { | ||
35 | /* fsl_spi_platform data */ | ||
36 | void (*cs_control)(struct spi_device *spi, bool on); | ||
37 | u32 sysclk; | ||
38 | |||
39 | /* driver internal data */ | ||
40 | struct mpc52xx_psc __iomem *psc; | ||
41 | struct mpc52xx_psc_fifo __iomem *fifo; | ||
42 | unsigned int irq; | ||
43 | u8 bits_per_word; | ||
44 | u8 busy; | ||
45 | |||
46 | struct workqueue_struct *workqueue; | ||
47 | struct work_struct work; | ||
48 | |||
49 | struct list_head queue; | ||
50 | spinlock_t lock; | ||
51 | |||
52 | struct completion done; | ||
53 | }; | ||
54 | |||
55 | /* controller state */ | ||
56 | struct mpc52xx_psc_spi_cs { | ||
57 | int bits_per_word; | ||
58 | int speed_hz; | ||
59 | }; | ||
60 | |||
61 | /* set clock freq, clock ramp, bits per work | ||
62 | * if t is NULL then reset the values to the default values | ||
63 | */ | ||
64 | static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi, | ||
65 | struct spi_transfer *t) | ||
66 | { | ||
67 | struct mpc52xx_psc_spi_cs *cs = spi->controller_state; | ||
68 | |||
69 | cs->speed_hz = (t && t->speed_hz) | ||
70 | ? t->speed_hz : spi->max_speed_hz; | ||
71 | cs->bits_per_word = (t && t->bits_per_word) | ||
72 | ? t->bits_per_word : spi->bits_per_word; | ||
73 | cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8; | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi) | ||
78 | { | ||
79 | struct mpc52xx_psc_spi_cs *cs = spi->controller_state; | ||
80 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
81 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
82 | u32 sicr; | ||
83 | u16 ccr; | ||
84 | |||
85 | sicr = in_be32(&psc->sicr); | ||
86 | |||
87 | /* Set clock phase and polarity */ | ||
88 | if (spi->mode & SPI_CPHA) | ||
89 | sicr |= 0x00001000; | ||
90 | else | ||
91 | sicr &= ~0x00001000; | ||
92 | if (spi->mode & SPI_CPOL) | ||
93 | sicr |= 0x00002000; | ||
94 | else | ||
95 | sicr &= ~0x00002000; | ||
96 | |||
97 | if (spi->mode & SPI_LSB_FIRST) | ||
98 | sicr |= 0x10000000; | ||
99 | else | ||
100 | sicr &= ~0x10000000; | ||
101 | out_be32(&psc->sicr, sicr); | ||
102 | |||
103 | /* Set clock frequency and bits per word | ||
104 | * Because psc->ccr is defined as 16bit register instead of 32bit | ||
105 | * just set the lower byte of BitClkDiv | ||
106 | */ | ||
107 | ccr = in_be16((u16 __iomem *)&psc->ccr); | ||
108 | ccr &= 0xFF00; | ||
109 | if (cs->speed_hz) | ||
110 | ccr |= (MCLK / cs->speed_hz - 1) & 0xFF; | ||
111 | else /* by default SPI Clk 1MHz */ | ||
112 | ccr |= (MCLK / 1000000 - 1) & 0xFF; | ||
113 | out_be16((u16 __iomem *)&psc->ccr, ccr); | ||
114 | mps->bits_per_word = cs->bits_per_word; | ||
115 | |||
116 | if (mps->cs_control) | ||
117 | mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); | ||
118 | } | ||
119 | |||
120 | static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi) | ||
121 | { | ||
122 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
123 | |||
124 | if (mps->cs_control) | ||
125 | mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); | ||
126 | } | ||
127 | |||
128 | #define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1) | ||
129 | /* wake up when 80% fifo full */ | ||
130 | #define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100) | ||
131 | |||
132 | static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, | ||
133 | struct spi_transfer *t) | ||
134 | { | ||
135 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
136 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
137 | struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; | ||
138 | unsigned rb = 0; /* number of bytes receieved */ | ||
139 | unsigned sb = 0; /* number of bytes sent */ | ||
140 | unsigned char *rx_buf = (unsigned char *)t->rx_buf; | ||
141 | unsigned char *tx_buf = (unsigned char *)t->tx_buf; | ||
142 | unsigned rfalarm; | ||
143 | unsigned send_at_once = MPC52xx_PSC_BUFSIZE; | ||
144 | unsigned recv_at_once; | ||
145 | int last_block = 0; | ||
146 | |||
147 | if (!t->tx_buf && !t->rx_buf && t->len) | ||
148 | return -EINVAL; | ||
149 | |||
150 | /* enable transmiter/receiver */ | ||
151 | out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); | ||
152 | while (rb < t->len) { | ||
153 | if (t->len - rb > MPC52xx_PSC_BUFSIZE) { | ||
154 | rfalarm = MPC52xx_PSC_RFALARM; | ||
155 | last_block = 0; | ||
156 | } else { | ||
157 | send_at_once = t->len - sb; | ||
158 | rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb); | ||
159 | last_block = 1; | ||
160 | } | ||
161 | |||
162 | dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); | ||
163 | for (; send_at_once; sb++, send_at_once--) { | ||
164 | /* set EOF flag before the last word is sent */ | ||
165 | if (send_at_once == 1 && last_block) | ||
166 | out_8(&psc->ircr2, 0x01); | ||
167 | |||
168 | if (tx_buf) | ||
169 | out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); | ||
170 | else | ||
171 | out_8(&psc->mpc52xx_psc_buffer_8, 0); | ||
172 | } | ||
173 | |||
174 | |||
175 | /* enable interrupts and wait for wake up | ||
176 | * if just one byte is expected the Rx FIFO genererates no | ||
177 | * FFULL interrupt, so activate the RxRDY interrupt | ||
178 | */ | ||
179 | out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); | ||
180 | if (t->len - rb == 1) { | ||
181 | out_8(&psc->mode, 0); | ||
182 | } else { | ||
183 | out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); | ||
184 | out_be16(&fifo->rfalarm, rfalarm); | ||
185 | } | ||
186 | out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY); | ||
187 | wait_for_completion(&mps->done); | ||
188 | recv_at_once = in_be16(&fifo->rfnum); | ||
189 | dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once); | ||
190 | |||
191 | send_at_once = recv_at_once; | ||
192 | if (rx_buf) { | ||
193 | for (; recv_at_once; rb++, recv_at_once--) | ||
194 | rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8); | ||
195 | } else { | ||
196 | for (; recv_at_once; rb++, recv_at_once--) | ||
197 | in_8(&psc->mpc52xx_psc_buffer_8); | ||
198 | } | ||
199 | } | ||
200 | /* disable transmiter/receiver */ | ||
201 | out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static void mpc52xx_psc_spi_work(struct work_struct *work) | ||
207 | { | ||
208 | struct mpc52xx_psc_spi *mps = | ||
209 | container_of(work, struct mpc52xx_psc_spi, work); | ||
210 | |||
211 | spin_lock_irq(&mps->lock); | ||
212 | mps->busy = 1; | ||
213 | while (!list_empty(&mps->queue)) { | ||
214 | struct spi_message *m; | ||
215 | struct spi_device *spi; | ||
216 | struct spi_transfer *t = NULL; | ||
217 | unsigned cs_change; | ||
218 | int status; | ||
219 | |||
220 | m = container_of(mps->queue.next, struct spi_message, queue); | ||
221 | list_del_init(&m->queue); | ||
222 | spin_unlock_irq(&mps->lock); | ||
223 | |||
224 | spi = m->spi; | ||
225 | cs_change = 1; | ||
226 | status = 0; | ||
227 | list_for_each_entry (t, &m->transfers, transfer_list) { | ||
228 | if (t->bits_per_word || t->speed_hz) { | ||
229 | status = mpc52xx_psc_spi_transfer_setup(spi, t); | ||
230 | if (status < 0) | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | if (cs_change) | ||
235 | mpc52xx_psc_spi_activate_cs(spi); | ||
236 | cs_change = t->cs_change; | ||
237 | |||
238 | status = mpc52xx_psc_spi_transfer_rxtx(spi, t); | ||
239 | if (status) | ||
240 | break; | ||
241 | m->actual_length += t->len; | ||
242 | |||
243 | if (t->delay_usecs) | ||
244 | udelay(t->delay_usecs); | ||
245 | |||
246 | if (cs_change) | ||
247 | mpc52xx_psc_spi_deactivate_cs(spi); | ||
248 | } | ||
249 | |||
250 | m->status = status; | ||
251 | m->complete(m->context); | ||
252 | |||
253 | if (status || !cs_change) | ||
254 | mpc52xx_psc_spi_deactivate_cs(spi); | ||
255 | |||
256 | mpc52xx_psc_spi_transfer_setup(spi, NULL); | ||
257 | |||
258 | spin_lock_irq(&mps->lock); | ||
259 | } | ||
260 | mps->busy = 0; | ||
261 | spin_unlock_irq(&mps->lock); | ||
262 | } | ||
263 | |||
264 | static int mpc52xx_psc_spi_setup(struct spi_device *spi) | ||
265 | { | ||
266 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
267 | struct mpc52xx_psc_spi_cs *cs = spi->controller_state; | ||
268 | unsigned long flags; | ||
269 | |||
270 | if (spi->bits_per_word%8) | ||
271 | return -EINVAL; | ||
272 | |||
273 | if (!cs) { | ||
274 | cs = kzalloc(sizeof *cs, GFP_KERNEL); | ||
275 | if (!cs) | ||
276 | return -ENOMEM; | ||
277 | spi->controller_state = cs; | ||
278 | } | ||
279 | |||
280 | cs->bits_per_word = spi->bits_per_word; | ||
281 | cs->speed_hz = spi->max_speed_hz; | ||
282 | |||
283 | spin_lock_irqsave(&mps->lock, flags); | ||
284 | if (!mps->busy) | ||
285 | mpc52xx_psc_spi_deactivate_cs(spi); | ||
286 | spin_unlock_irqrestore(&mps->lock, flags); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int mpc52xx_psc_spi_transfer(struct spi_device *spi, | ||
292 | struct spi_message *m) | ||
293 | { | ||
294 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
295 | unsigned long flags; | ||
296 | |||
297 | m->actual_length = 0; | ||
298 | m->status = -EINPROGRESS; | ||
299 | |||
300 | spin_lock_irqsave(&mps->lock, flags); | ||
301 | list_add_tail(&m->queue, &mps->queue); | ||
302 | queue_work(mps->workqueue, &mps->work); | ||
303 | spin_unlock_irqrestore(&mps->lock, flags); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static void mpc52xx_psc_spi_cleanup(struct spi_device *spi) | ||
309 | { | ||
310 | kfree(spi->controller_state); | ||
311 | } | ||
312 | |||
313 | static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) | ||
314 | { | ||
315 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
316 | struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; | ||
317 | u32 mclken_div; | ||
318 | int ret; | ||
319 | |||
320 | /* default sysclk is 512MHz */ | ||
321 | mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK; | ||
322 | ret = mpc52xx_set_psc_clkdiv(psc_id, mclken_div); | ||
323 | if (ret) | ||
324 | return ret; | ||
325 | |||
326 | /* Reset the PSC into a known state */ | ||
327 | out_8(&psc->command, MPC52xx_PSC_RST_RX); | ||
328 | out_8(&psc->command, MPC52xx_PSC_RST_TX); | ||
329 | out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); | ||
330 | |||
331 | /* Disable interrupts, interrupts are based on alarm level */ | ||
332 | out_be16(&psc->mpc52xx_psc_imr, 0); | ||
333 | out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); | ||
334 | out_8(&fifo->rfcntl, 0); | ||
335 | out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); | ||
336 | |||
337 | /* Configure 8bit codec mode as a SPI master and use EOF flags */ | ||
338 | /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */ | ||
339 | out_be32(&psc->sicr, 0x0180C800); | ||
340 | out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */ | ||
341 | |||
342 | /* Set 2ms DTL delay */ | ||
343 | out_8(&psc->ctur, 0x00); | ||
344 | out_8(&psc->ctlr, 0x84); | ||
345 | |||
346 | mps->bits_per_word = 8; | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id) | ||
352 | { | ||
353 | struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id; | ||
354 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
355 | |||
356 | /* disable interrupt and wake up the work queue */ | ||
357 | if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) { | ||
358 | out_be16(&psc->mpc52xx_psc_imr, 0); | ||
359 | complete(&mps->done); | ||
360 | return IRQ_HANDLED; | ||
361 | } | ||
362 | return IRQ_NONE; | ||
363 | } | ||
364 | |||
365 | /* bus_num is used only for the case dev->platform_data == NULL */ | ||
366 | static int __devinit mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, | ||
367 | u32 size, unsigned int irq, s16 bus_num) | ||
368 | { | ||
369 | struct fsl_spi_platform_data *pdata = dev->platform_data; | ||
370 | struct mpc52xx_psc_spi *mps; | ||
371 | struct spi_master *master; | ||
372 | int ret; | ||
373 | |||
374 | master = spi_alloc_master(dev, sizeof *mps); | ||
375 | if (master == NULL) | ||
376 | return -ENOMEM; | ||
377 | |||
378 | dev_set_drvdata(dev, master); | ||
379 | mps = spi_master_get_devdata(master); | ||
380 | |||
381 | /* the spi->mode bits understood by this driver: */ | ||
382 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; | ||
383 | |||
384 | mps->irq = irq; | ||
385 | if (pdata == NULL) { | ||
386 | dev_warn(dev, "probe called without platform data, no " | ||
387 | "cs_control function will be called\n"); | ||
388 | mps->cs_control = NULL; | ||
389 | mps->sysclk = 0; | ||
390 | master->bus_num = bus_num; | ||
391 | master->num_chipselect = 255; | ||
392 | } else { | ||
393 | mps->cs_control = pdata->cs_control; | ||
394 | mps->sysclk = pdata->sysclk; | ||
395 | master->bus_num = pdata->bus_num; | ||
396 | master->num_chipselect = pdata->max_chipselect; | ||
397 | } | ||
398 | master->setup = mpc52xx_psc_spi_setup; | ||
399 | master->transfer = mpc52xx_psc_spi_transfer; | ||
400 | master->cleanup = mpc52xx_psc_spi_cleanup; | ||
401 | master->dev.of_node = dev->of_node; | ||
402 | |||
403 | mps->psc = ioremap(regaddr, size); | ||
404 | if (!mps->psc) { | ||
405 | dev_err(dev, "could not ioremap I/O port range\n"); | ||
406 | ret = -EFAULT; | ||
407 | goto free_master; | ||
408 | } | ||
409 | /* On the 5200, fifo regs are immediately ajacent to the psc regs */ | ||
410 | mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc); | ||
411 | |||
412 | ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi", | ||
413 | mps); | ||
414 | if (ret) | ||
415 | goto free_master; | ||
416 | |||
417 | ret = mpc52xx_psc_spi_port_config(master->bus_num, mps); | ||
418 | if (ret < 0) { | ||
419 | dev_err(dev, "can't configure PSC! Is it capable of SPI?\n"); | ||
420 | goto free_irq; | ||
421 | } | ||
422 | |||
423 | spin_lock_init(&mps->lock); | ||
424 | init_completion(&mps->done); | ||
425 | INIT_WORK(&mps->work, mpc52xx_psc_spi_work); | ||
426 | INIT_LIST_HEAD(&mps->queue); | ||
427 | |||
428 | mps->workqueue = create_singlethread_workqueue( | ||
429 | dev_name(master->dev.parent)); | ||
430 | if (mps->workqueue == NULL) { | ||
431 | ret = -EBUSY; | ||
432 | goto free_irq; | ||
433 | } | ||
434 | |||
435 | ret = spi_register_master(master); | ||
436 | if (ret < 0) | ||
437 | goto unreg_master; | ||
438 | |||
439 | return ret; | ||
440 | |||
441 | unreg_master: | ||
442 | destroy_workqueue(mps->workqueue); | ||
443 | free_irq: | ||
444 | free_irq(mps->irq, mps); | ||
445 | free_master: | ||
446 | if (mps->psc) | ||
447 | iounmap(mps->psc); | ||
448 | spi_master_put(master); | ||
449 | |||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op) | ||
454 | { | ||
455 | const u32 *regaddr_p; | ||
456 | u64 regaddr64, size64; | ||
457 | s16 id = -1; | ||
458 | |||
459 | regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); | ||
460 | if (!regaddr_p) { | ||
461 | dev_err(&op->dev, "Invalid PSC address\n"); | ||
462 | return -EINVAL; | ||
463 | } | ||
464 | regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); | ||
465 | |||
466 | /* get PSC id (1..6, used by port_config) */ | ||
467 | if (op->dev.platform_data == NULL) { | ||
468 | const u32 *psc_nump; | ||
469 | |||
470 | psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL); | ||
471 | if (!psc_nump || *psc_nump > 5) { | ||
472 | dev_err(&op->dev, "Invalid cell-index property\n"); | ||
473 | return -EINVAL; | ||
474 | } | ||
475 | id = *psc_nump + 1; | ||
476 | } | ||
477 | |||
478 | return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64, | ||
479 | irq_of_parse_and_map(op->dev.of_node, 0), id); | ||
480 | } | ||
481 | |||
482 | static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op) | ||
483 | { | ||
484 | struct spi_master *master = dev_get_drvdata(&op->dev); | ||
485 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master); | ||
486 | |||
487 | flush_workqueue(mps->workqueue); | ||
488 | destroy_workqueue(mps->workqueue); | ||
489 | spi_unregister_master(master); | ||
490 | free_irq(mps->irq, mps); | ||
491 | if (mps->psc) | ||
492 | iounmap(mps->psc); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static const struct of_device_id mpc52xx_psc_spi_of_match[] = { | ||
498 | { .compatible = "fsl,mpc5200-psc-spi", }, | ||
499 | { .compatible = "mpc5200-psc-spi", }, /* old */ | ||
500 | {} | ||
501 | }; | ||
502 | |||
503 | MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match); | ||
504 | |||
505 | static struct platform_driver mpc52xx_psc_spi_of_driver = { | ||
506 | .probe = mpc52xx_psc_spi_of_probe, | ||
507 | .remove = __devexit_p(mpc52xx_psc_spi_of_remove), | ||
508 | .driver = { | ||
509 | .name = "mpc52xx-psc-spi", | ||
510 | .owner = THIS_MODULE, | ||
511 | .of_match_table = mpc52xx_psc_spi_of_match, | ||
512 | }, | ||
513 | }; | ||
514 | |||
515 | static int __init mpc52xx_psc_spi_init(void) | ||
516 | { | ||
517 | return platform_driver_register(&mpc52xx_psc_spi_of_driver); | ||
518 | } | ||
519 | module_init(mpc52xx_psc_spi_init); | ||
520 | |||
521 | static void __exit mpc52xx_psc_spi_exit(void) | ||
522 | { | ||
523 | platform_driver_unregister(&mpc52xx_psc_spi_of_driver); | ||
524 | } | ||
525 | module_exit(mpc52xx_psc_spi_exit); | ||
526 | |||
527 | MODULE_AUTHOR("Dragos Carp"); | ||
528 | MODULE_DESCRIPTION("MPC52xx PSC SPI Driver"); | ||
529 | MODULE_LICENSE("GPL"); | ||