diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/spi/spi-orion.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/spi/spi-orion.c')
-rw-r--r-- | drivers/spi/spi-orion.c | 290 |
1 files changed, 165 insertions, 125 deletions
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index b7e718254b1..9421a390a5e 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c | |||
@@ -16,9 +16,7 @@ | |||
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/spi/spi.h> | 18 | #include <linux/spi/spi.h> |
19 | #include <linux/module.h> | 19 | #include <linux/spi/orion_spi.h> |
20 | #include <linux/of.h> | ||
21 | #include <linux/clk.h> | ||
22 | #include <asm/unaligned.h> | 20 | #include <asm/unaligned.h> |
23 | 21 | ||
24 | #define DRIVER_NAME "orion_spi" | 22 | #define DRIVER_NAME "orion_spi" |
@@ -32,21 +30,25 @@ | |||
32 | #define ORION_SPI_DATA_IN_REG 0x0c | 30 | #define ORION_SPI_DATA_IN_REG 0x0c |
33 | #define ORION_SPI_INT_CAUSE_REG 0x10 | 31 | #define ORION_SPI_INT_CAUSE_REG 0x10 |
34 | 32 | ||
35 | #define ORION_SPI_MODE_CPOL (1 << 11) | ||
36 | #define ORION_SPI_MODE_CPHA (1 << 12) | ||
37 | #define ORION_SPI_IF_8_16_BIT_MODE (1 << 5) | 33 | #define ORION_SPI_IF_8_16_BIT_MODE (1 << 5) |
38 | #define ORION_SPI_CLK_PRESCALE_MASK 0x1F | 34 | #define ORION_SPI_CLK_PRESCALE_MASK 0x1F |
39 | #define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \ | ||
40 | ORION_SPI_MODE_CPHA) | ||
41 | 35 | ||
42 | struct orion_spi { | 36 | struct orion_spi { |
37 | struct work_struct work; | ||
38 | |||
39 | /* Lock access to transfer list. */ | ||
40 | spinlock_t lock; | ||
41 | |||
42 | struct list_head msg_queue; | ||
43 | struct spi_master *master; | 43 | struct spi_master *master; |
44 | void __iomem *base; | 44 | void __iomem *base; |
45 | unsigned int max_speed; | 45 | unsigned int max_speed; |
46 | unsigned int min_speed; | 46 | unsigned int min_speed; |
47 | struct clk *clk; | 47 | struct orion_spi_info *spi_info; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static struct workqueue_struct *orion_spi_wq; | ||
51 | |||
50 | static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) | 52 | static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) |
51 | { | 53 | { |
52 | return orion_spi->base + reg; | 54 | return orion_spi->base + reg; |
@@ -101,7 +103,7 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) | |||
101 | 103 | ||
102 | orion_spi = spi_master_get_devdata(spi->master); | 104 | orion_spi = spi_master_get_devdata(spi->master); |
103 | 105 | ||
104 | tclk_hz = clk_get_rate(orion_spi->clk); | 106 | tclk_hz = orion_spi->spi_info->tclk; |
105 | 107 | ||
106 | /* | 108 | /* |
107 | * the supported rates are: 4,6,8...30 | 109 | * the supported rates are: 4,6,8...30 |
@@ -127,23 +129,6 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) | |||
127 | return 0; | 129 | return 0; |
128 | } | 130 | } |
129 | 131 | ||
130 | static void | ||
131 | orion_spi_mode_set(struct spi_device *spi) | ||
132 | { | ||
133 | u32 reg; | ||
134 | struct orion_spi *orion_spi; | ||
135 | |||
136 | orion_spi = spi_master_get_devdata(spi->master); | ||
137 | |||
138 | reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); | ||
139 | reg &= ~ORION_SPI_MODE_MASK; | ||
140 | if (spi->mode & SPI_CPOL) | ||
141 | reg |= ORION_SPI_MODE_CPOL; | ||
142 | if (spi->mode & SPI_CPHA) | ||
143 | reg |= ORION_SPI_MODE_CPHA; | ||
144 | writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); | ||
145 | } | ||
146 | |||
147 | /* | 132 | /* |
148 | * called only when no transfer is active on the bus | 133 | * called only when no transfer is active on the bus |
149 | */ | 134 | */ |
@@ -163,8 +148,6 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) | |||
163 | if ((t != NULL) && t->bits_per_word) | 148 | if ((t != NULL) && t->bits_per_word) |
164 | bits_per_word = t->bits_per_word; | 149 | bits_per_word = t->bits_per_word; |
165 | 150 | ||
166 | orion_spi_mode_set(spi); | ||
167 | |||
168 | rc = orion_spi_baudrate_set(spi, speed); | 151 | rc = orion_spi_baudrate_set(spi, speed); |
169 | if (rc) | 152 | if (rc) |
170 | return rc; | 153 | return rc; |
@@ -292,78 +275,73 @@ out: | |||
292 | } | 275 | } |
293 | 276 | ||
294 | 277 | ||
295 | static int orion_spi_transfer_one_message(struct spi_master *master, | 278 | static void orion_spi_work(struct work_struct *work) |
296 | struct spi_message *m) | ||
297 | { | 279 | { |
298 | struct orion_spi *orion_spi = spi_master_get_devdata(master); | 280 | struct orion_spi *orion_spi = |
299 | struct spi_device *spi = m->spi; | 281 | container_of(work, struct orion_spi, work); |
300 | struct spi_transfer *t = NULL; | ||
301 | int par_override = 0; | ||
302 | int status = 0; | ||
303 | int cs_active = 0; | ||
304 | 282 | ||
305 | /* Load defaults */ | 283 | spin_lock_irq(&orion_spi->lock); |
306 | status = orion_spi_setup_transfer(spi, NULL); | 284 | while (!list_empty(&orion_spi->msg_queue)) { |
285 | struct spi_message *m; | ||
286 | struct spi_device *spi; | ||
287 | struct spi_transfer *t = NULL; | ||
288 | int par_override = 0; | ||
289 | int status = 0; | ||
290 | int cs_active = 0; | ||
307 | 291 | ||
308 | if (status < 0) | 292 | m = container_of(orion_spi->msg_queue.next, struct spi_message, |
309 | goto msg_done; | 293 | queue); |
310 | 294 | ||
311 | list_for_each_entry(t, &m->transfers, transfer_list) { | 295 | list_del_init(&m->queue); |
312 | /* make sure buffer length is even when working in 16 | 296 | spin_unlock_irq(&orion_spi->lock); |
313 | * bit mode*/ | ||
314 | if ((t->bits_per_word == 16) && (t->len & 1)) { | ||
315 | dev_err(&spi->dev, | ||
316 | "message rejected : " | ||
317 | "odd data length %d while in 16 bit mode\n", | ||
318 | t->len); | ||
319 | status = -EIO; | ||
320 | goto msg_done; | ||
321 | } | ||
322 | 297 | ||
323 | if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { | 298 | spi = m->spi; |
324 | dev_err(&spi->dev, | ||
325 | "message rejected : " | ||
326 | "device min speed (%d Hz) exceeds " | ||
327 | "required transfer speed (%d Hz)\n", | ||
328 | orion_spi->min_speed, t->speed_hz); | ||
329 | status = -EIO; | ||
330 | goto msg_done; | ||
331 | } | ||
332 | 299 | ||
333 | if (par_override || t->speed_hz || t->bits_per_word) { | 300 | /* Load defaults */ |
334 | par_override = 1; | 301 | status = orion_spi_setup_transfer(spi, NULL); |
335 | status = orion_spi_setup_transfer(spi, t); | ||
336 | if (status < 0) | ||
337 | break; | ||
338 | if (!t->speed_hz && !t->bits_per_word) | ||
339 | par_override = 0; | ||
340 | } | ||
341 | 302 | ||
342 | if (!cs_active) { | 303 | if (status < 0) |
343 | orion_spi_set_cs(orion_spi, 1); | 304 | goto msg_done; |
344 | cs_active = 1; | ||
345 | } | ||
346 | |||
347 | if (t->len) | ||
348 | m->actual_length += orion_spi_write_read(spi, t); | ||
349 | |||
350 | if (t->delay_usecs) | ||
351 | udelay(t->delay_usecs); | ||
352 | 305 | ||
353 | if (t->cs_change) { | 306 | list_for_each_entry(t, &m->transfers, transfer_list) { |
354 | orion_spi_set_cs(orion_spi, 0); | 307 | if (par_override || t->speed_hz || t->bits_per_word) { |
355 | cs_active = 0; | 308 | par_override = 1; |
309 | status = orion_spi_setup_transfer(spi, t); | ||
310 | if (status < 0) | ||
311 | break; | ||
312 | if (!t->speed_hz && !t->bits_per_word) | ||
313 | par_override = 0; | ||
314 | } | ||
315 | |||
316 | if (!cs_active) { | ||
317 | orion_spi_set_cs(orion_spi, 1); | ||
318 | cs_active = 1; | ||
319 | } | ||
320 | |||
321 | if (t->len) | ||
322 | m->actual_length += | ||
323 | orion_spi_write_read(spi, t); | ||
324 | |||
325 | if (t->delay_usecs) | ||
326 | udelay(t->delay_usecs); | ||
327 | |||
328 | if (t->cs_change) { | ||
329 | orion_spi_set_cs(orion_spi, 0); | ||
330 | cs_active = 0; | ||
331 | } | ||
356 | } | 332 | } |
357 | } | ||
358 | 333 | ||
359 | msg_done: | 334 | msg_done: |
360 | if (cs_active) | 335 | if (cs_active) |
361 | orion_spi_set_cs(orion_spi, 0); | 336 | orion_spi_set_cs(orion_spi, 0); |
362 | 337 | ||
363 | m->status = status; | 338 | m->status = status; |
364 | spi_finalize_current_message(master); | 339 | m->complete(m->context); |
365 | 340 | ||
366 | return 0; | 341 | spin_lock_irq(&orion_spi->lock); |
342 | } | ||
343 | |||
344 | spin_unlock_irq(&orion_spi->lock); | ||
367 | } | 345 | } |
368 | 346 | ||
369 | static int __init orion_spi_reset(struct orion_spi *orion_spi) | 347 | static int __init orion_spi_reset(struct orion_spi *orion_spi) |
@@ -380,6 +358,11 @@ static int orion_spi_setup(struct spi_device *spi) | |||
380 | 358 | ||
381 | orion_spi = spi_master_get_devdata(spi->master); | 359 | orion_spi = spi_master_get_devdata(spi->master); |
382 | 360 | ||
361 | /* Fix ac timing if required. */ | ||
362 | if (orion_spi->spi_info->enable_clock_fix) | ||
363 | orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, | ||
364 | (1 << 14)); | ||
365 | |||
383 | if ((spi->max_speed_hz == 0) | 366 | if ((spi->max_speed_hz == 0) |
384 | || (spi->max_speed_hz > orion_spi->max_speed)) | 367 | || (spi->max_speed_hz > orion_spi->max_speed)) |
385 | spi->max_speed_hz = orion_spi->max_speed; | 368 | spi->max_speed_hz = orion_spi->max_speed; |
@@ -396,15 +379,84 @@ static int orion_spi_setup(struct spi_device *spi) | |||
396 | return 0; | 379 | return 0; |
397 | } | 380 | } |
398 | 381 | ||
382 | static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m) | ||
383 | { | ||
384 | struct orion_spi *orion_spi; | ||
385 | struct spi_transfer *t = NULL; | ||
386 | unsigned long flags; | ||
387 | |||
388 | m->actual_length = 0; | ||
389 | m->status = 0; | ||
390 | |||
391 | /* reject invalid messages and transfers */ | ||
392 | if (list_empty(&m->transfers) || !m->complete) | ||
393 | return -EINVAL; | ||
394 | |||
395 | orion_spi = spi_master_get_devdata(spi->master); | ||
396 | |||
397 | list_for_each_entry(t, &m->transfers, transfer_list) { | ||
398 | unsigned int bits_per_word = spi->bits_per_word; | ||
399 | |||
400 | if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { | ||
401 | dev_err(&spi->dev, | ||
402 | "message rejected : " | ||
403 | "invalid transfer data buffers\n"); | ||
404 | goto msg_rejected; | ||
405 | } | ||
406 | |||
407 | if (t->bits_per_word) | ||
408 | bits_per_word = t->bits_per_word; | ||
409 | |||
410 | if ((bits_per_word != 8) && (bits_per_word != 16)) { | ||
411 | dev_err(&spi->dev, | ||
412 | "message rejected : " | ||
413 | "invalid transfer bits_per_word (%d bits)\n", | ||
414 | bits_per_word); | ||
415 | goto msg_rejected; | ||
416 | } | ||
417 | /*make sure buffer length is even when working in 16 bit mode*/ | ||
418 | if ((t->bits_per_word == 16) && (t->len & 1)) { | ||
419 | dev_err(&spi->dev, | ||
420 | "message rejected : " | ||
421 | "odd data length (%d) while in 16 bit mode\n", | ||
422 | t->len); | ||
423 | goto msg_rejected; | ||
424 | } | ||
425 | |||
426 | if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { | ||
427 | dev_err(&spi->dev, | ||
428 | "message rejected : " | ||
429 | "device min speed (%d Hz) exceeds " | ||
430 | "required transfer speed (%d Hz)\n", | ||
431 | orion_spi->min_speed, t->speed_hz); | ||
432 | goto msg_rejected; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | |||
437 | spin_lock_irqsave(&orion_spi->lock, flags); | ||
438 | list_add_tail(&m->queue, &orion_spi->msg_queue); | ||
439 | queue_work(orion_spi_wq, &orion_spi->work); | ||
440 | spin_unlock_irqrestore(&orion_spi->lock, flags); | ||
441 | |||
442 | return 0; | ||
443 | msg_rejected: | ||
444 | /* Message rejected and not queued */ | ||
445 | m->status = -EINVAL; | ||
446 | if (m->complete) | ||
447 | m->complete(m->context); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | |||
399 | static int __init orion_spi_probe(struct platform_device *pdev) | 451 | static int __init orion_spi_probe(struct platform_device *pdev) |
400 | { | 452 | { |
401 | struct spi_master *master; | 453 | struct spi_master *master; |
402 | struct orion_spi *spi; | 454 | struct orion_spi *spi; |
403 | struct resource *r; | 455 | struct resource *r; |
404 | unsigned long tclk_hz; | 456 | struct orion_spi_info *spi_info; |
405 | int status = 0; | 457 | int status = 0; |
406 | const u32 *iprop; | 458 | |
407 | int size; | 459 | spi_info = pdev->dev.platform_data; |
408 | 460 | ||
409 | master = spi_alloc_master(&pdev->dev, sizeof *spi); | 461 | master = spi_alloc_master(&pdev->dev, sizeof *spi); |
410 | if (master == NULL) { | 462 | if (master == NULL) { |
@@ -414,54 +466,44 @@ static int __init orion_spi_probe(struct platform_device *pdev) | |||
414 | 466 | ||
415 | if (pdev->id != -1) | 467 | if (pdev->id != -1) |
416 | master->bus_num = pdev->id; | 468 | master->bus_num = pdev->id; |
417 | if (pdev->dev.of_node) { | ||
418 | iprop = of_get_property(pdev->dev.of_node, "cell-index", | ||
419 | &size); | ||
420 | if (iprop && size == sizeof(*iprop)) | ||
421 | master->bus_num = *iprop; | ||
422 | } | ||
423 | 469 | ||
424 | /* we support only mode 0, and no options */ | 470 | /* we support only mode 0, and no options */ |
425 | master->mode_bits = SPI_CPHA | SPI_CPOL; | 471 | master->mode_bits = 0; |
426 | 472 | ||
427 | master->setup = orion_spi_setup; | 473 | master->setup = orion_spi_setup; |
428 | master->transfer_one_message = orion_spi_transfer_one_message; | 474 | master->transfer = orion_spi_transfer; |
429 | master->num_chipselect = ORION_NUM_CHIPSELECTS; | 475 | master->num_chipselect = ORION_NUM_CHIPSELECTS; |
430 | 476 | ||
431 | dev_set_drvdata(&pdev->dev, master); | 477 | dev_set_drvdata(&pdev->dev, master); |
432 | 478 | ||
433 | spi = spi_master_get_devdata(master); | 479 | spi = spi_master_get_devdata(master); |
434 | spi->master = master; | 480 | spi->master = master; |
481 | spi->spi_info = spi_info; | ||
435 | 482 | ||
436 | spi->clk = clk_get(&pdev->dev, NULL); | 483 | spi->max_speed = DIV_ROUND_UP(spi_info->tclk, 4); |
437 | if (IS_ERR(spi->clk)) { | 484 | spi->min_speed = DIV_ROUND_UP(spi_info->tclk, 30); |
438 | status = PTR_ERR(spi->clk); | ||
439 | goto out; | ||
440 | } | ||
441 | |||
442 | clk_prepare(spi->clk); | ||
443 | clk_enable(spi->clk); | ||
444 | tclk_hz = clk_get_rate(spi->clk); | ||
445 | spi->max_speed = DIV_ROUND_UP(tclk_hz, 4); | ||
446 | spi->min_speed = DIV_ROUND_UP(tclk_hz, 30); | ||
447 | 485 | ||
448 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 486 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
449 | if (r == NULL) { | 487 | if (r == NULL) { |
450 | status = -ENODEV; | 488 | status = -ENODEV; |
451 | goto out_rel_clk; | 489 | goto out; |
452 | } | 490 | } |
453 | 491 | ||
454 | if (!request_mem_region(r->start, resource_size(r), | 492 | if (!request_mem_region(r->start, resource_size(r), |
455 | dev_name(&pdev->dev))) { | 493 | dev_name(&pdev->dev))) { |
456 | status = -EBUSY; | 494 | status = -EBUSY; |
457 | goto out_rel_clk; | 495 | goto out; |
458 | } | 496 | } |
459 | spi->base = ioremap(r->start, SZ_1K); | 497 | spi->base = ioremap(r->start, SZ_1K); |
460 | 498 | ||
499 | INIT_WORK(&spi->work, orion_spi_work); | ||
500 | |||
501 | spin_lock_init(&spi->lock); | ||
502 | INIT_LIST_HEAD(&spi->msg_queue); | ||
503 | |||
461 | if (orion_spi_reset(spi) < 0) | 504 | if (orion_spi_reset(spi) < 0) |
462 | goto out_rel_mem; | 505 | goto out_rel_mem; |
463 | 506 | ||
464 | master->dev.of_node = pdev->dev.of_node; | ||
465 | status = spi_register_master(master); | 507 | status = spi_register_master(master); |
466 | if (status < 0) | 508 | if (status < 0) |
467 | goto out_rel_mem; | 509 | goto out_rel_mem; |
@@ -470,9 +512,7 @@ static int __init orion_spi_probe(struct platform_device *pdev) | |||
470 | 512 | ||
471 | out_rel_mem: | 513 | out_rel_mem: |
472 | release_mem_region(r->start, resource_size(r)); | 514 | release_mem_region(r->start, resource_size(r)); |
473 | out_rel_clk: | 515 | |
474 | clk_disable_unprepare(spi->clk); | ||
475 | clk_put(spi->clk); | ||
476 | out: | 516 | out: |
477 | spi_master_put(master); | 517 | spi_master_put(master); |
478 | return status; | 518 | return status; |
@@ -482,14 +522,13 @@ out: | |||
482 | static int __exit orion_spi_remove(struct platform_device *pdev) | 522 | static int __exit orion_spi_remove(struct platform_device *pdev) |
483 | { | 523 | { |
484 | struct spi_master *master; | 524 | struct spi_master *master; |
485 | struct resource *r; | ||
486 | struct orion_spi *spi; | 525 | struct orion_spi *spi; |
526 | struct resource *r; | ||
487 | 527 | ||
488 | master = dev_get_drvdata(&pdev->dev); | 528 | master = dev_get_drvdata(&pdev->dev); |
489 | spi = spi_master_get_devdata(master); | 529 | spi = spi_master_get_devdata(master); |
490 | 530 | ||
491 | clk_disable_unprepare(spi->clk); | 531 | cancel_work_sync(&spi->work); |
492 | clk_put(spi->clk); | ||
493 | 532 | ||
494 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 533 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
495 | release_mem_region(r->start, resource_size(r)); | 534 | release_mem_region(r->start, resource_size(r)); |
@@ -501,30 +540,31 @@ static int __exit orion_spi_remove(struct platform_device *pdev) | |||
501 | 540 | ||
502 | MODULE_ALIAS("platform:" DRIVER_NAME); | 541 | MODULE_ALIAS("platform:" DRIVER_NAME); |
503 | 542 | ||
504 | static const struct of_device_id orion_spi_of_match_table[] = { | ||
505 | { .compatible = "marvell,orion-spi", }, | ||
506 | {} | ||
507 | }; | ||
508 | MODULE_DEVICE_TABLE(of, orion_spi_of_match_table); | ||
509 | |||
510 | static struct platform_driver orion_spi_driver = { | 543 | static struct platform_driver orion_spi_driver = { |
511 | .driver = { | 544 | .driver = { |
512 | .name = DRIVER_NAME, | 545 | .name = DRIVER_NAME, |
513 | .owner = THIS_MODULE, | 546 | .owner = THIS_MODULE, |
514 | .of_match_table = of_match_ptr(orion_spi_of_match_table), | ||
515 | }, | 547 | }, |
516 | .remove = __exit_p(orion_spi_remove), | 548 | .remove = __exit_p(orion_spi_remove), |
517 | }; | 549 | }; |
518 | 550 | ||
519 | static int __init orion_spi_init(void) | 551 | static int __init orion_spi_init(void) |
520 | { | 552 | { |
553 | orion_spi_wq = create_singlethread_workqueue( | ||
554 | orion_spi_driver.driver.name); | ||
555 | if (orion_spi_wq == NULL) | ||
556 | return -ENOMEM; | ||
557 | |||
521 | return platform_driver_probe(&orion_spi_driver, orion_spi_probe); | 558 | return platform_driver_probe(&orion_spi_driver, orion_spi_probe); |
522 | } | 559 | } |
523 | module_init(orion_spi_init); | 560 | module_init(orion_spi_init); |
524 | 561 | ||
525 | static void __exit orion_spi_exit(void) | 562 | static void __exit orion_spi_exit(void) |
526 | { | 563 | { |
564 | flush_workqueue(orion_spi_wq); | ||
527 | platform_driver_unregister(&orion_spi_driver); | 565 | platform_driver_unregister(&orion_spi_driver); |
566 | |||
567 | destroy_workqueue(orion_spi_wq); | ||
528 | } | 568 | } |
529 | module_exit(orion_spi_exit); | 569 | module_exit(orion_spi_exit); |
530 | 570 | ||