diff options
Diffstat (limited to 'drivers/spi/xilinx_spi.c')
-rw-r--r-- | drivers/spi/xilinx_spi.c | 133 |
1 files changed, 114 insertions, 19 deletions
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 80f2db5bcfd6..7adaef62a991 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c | |||
@@ -1,26 +1,27 @@ | |||
1 | /* | 1 | /* |
2 | * xilinx_spi.c | ||
3 | * | ||
4 | * Xilinx SPI controller driver (master mode only) | 2 | * Xilinx SPI controller driver (master mode only) |
5 | * | 3 | * |
6 | * Author: MontaVista Software, Inc. | 4 | * Author: MontaVista Software, Inc. |
7 | * source@mvista.com | 5 | * source@mvista.com |
8 | * | 6 | * |
9 | * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the | 7 | * Copyright (c) 2010 Secret Lab Technologies, Ltd. |
10 | * terms of the GNU General Public License version 2. This program is licensed | 8 | * Copyright (c) 2009 Intel Corporation |
11 | * "as is" without any warranty of any kind, whether express or implied. | 9 | * 2002-2007 (c) MontaVista Software, Inc. |
10 | |||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
12 | */ | 14 | */ |
13 | 15 | ||
14 | #include <linux/module.h> | 16 | #include <linux/module.h> |
15 | #include <linux/init.h> | 17 | #include <linux/init.h> |
16 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
17 | 19 | #include <linux/of.h> | |
20 | #include <linux/platform_device.h> | ||
18 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
19 | #include <linux/spi/spi_bitbang.h> | 22 | #include <linux/spi/spi_bitbang.h> |
20 | #include <linux/io.h> | ||
21 | |||
22 | #include "xilinx_spi.h" | ||
23 | #include <linux/spi/xilinx_spi.h> | 23 | #include <linux/spi/xilinx_spi.h> |
24 | #include <linux/io.h> | ||
24 | 25 | ||
25 | #define XILINX_SPI_NAME "xilinx_spi" | 26 | #define XILINX_SPI_NAME "xilinx_spi" |
26 | 27 | ||
@@ -350,19 +351,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) | |||
350 | return IRQ_HANDLED; | 351 | return IRQ_HANDLED; |
351 | } | 352 | } |
352 | 353 | ||
354 | #ifdef CONFIG_OF | ||
355 | static const struct of_device_id xilinx_spi_of_match[] = { | ||
356 | { .compatible = "xlnx,xps-spi-2.00.a", }, | ||
357 | { .compatible = "xlnx,xps-spi-2.00.b", }, | ||
358 | {} | ||
359 | }; | ||
360 | MODULE_DEVICE_TABLE(of, xilinx_spi_of_match); | ||
361 | #endif | ||
362 | |||
353 | struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, | 363 | struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, |
354 | u32 irq, s16 bus_num) | 364 | u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word) |
355 | { | 365 | { |
356 | struct spi_master *master; | 366 | struct spi_master *master; |
357 | struct xilinx_spi *xspi; | 367 | struct xilinx_spi *xspi; |
358 | struct xspi_platform_data *pdata = dev->platform_data; | ||
359 | int ret; | 368 | int ret; |
360 | 369 | ||
361 | if (!pdata) { | ||
362 | dev_err(dev, "No platform data attached\n"); | ||
363 | return NULL; | ||
364 | } | ||
365 | |||
366 | master = spi_alloc_master(dev, sizeof(struct xilinx_spi)); | 370 | master = spi_alloc_master(dev, sizeof(struct xilinx_spi)); |
367 | if (!master) | 371 | if (!master) |
368 | return NULL; | 372 | return NULL; |
@@ -389,21 +393,21 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, | |||
389 | } | 393 | } |
390 | 394 | ||
391 | master->bus_num = bus_num; | 395 | master->bus_num = bus_num; |
392 | master->num_chipselect = pdata->num_chipselect; | 396 | master->num_chipselect = num_cs; |
393 | #ifdef CONFIG_OF | 397 | #ifdef CONFIG_OF |
394 | master->dev.of_node = dev->of_node; | 398 | master->dev.of_node = dev->of_node; |
395 | #endif | 399 | #endif |
396 | 400 | ||
397 | xspi->mem = *mem; | 401 | xspi->mem = *mem; |
398 | xspi->irq = irq; | 402 | xspi->irq = irq; |
399 | if (pdata->little_endian) { | 403 | if (little_endian) { |
400 | xspi->read_fn = xspi_read32; | 404 | xspi->read_fn = xspi_read32; |
401 | xspi->write_fn = xspi_write32; | 405 | xspi->write_fn = xspi_write32; |
402 | } else { | 406 | } else { |
403 | xspi->read_fn = xspi_read32_be; | 407 | xspi->read_fn = xspi_read32_be; |
404 | xspi->write_fn = xspi_write32_be; | 408 | xspi->write_fn = xspi_write32_be; |
405 | } | 409 | } |
406 | xspi->bits_per_word = pdata->bits_per_word; | 410 | xspi->bits_per_word = bits_per_word; |
407 | if (xspi->bits_per_word == 8) { | 411 | if (xspi->bits_per_word == 8) { |
408 | xspi->tx_fn = xspi_tx8; | 412 | xspi->tx_fn = xspi_tx8; |
409 | xspi->rx_fn = xspi_rx8; | 413 | xspi->rx_fn = xspi_rx8; |
@@ -462,6 +466,97 @@ void xilinx_spi_deinit(struct spi_master *master) | |||
462 | } | 466 | } |
463 | EXPORT_SYMBOL(xilinx_spi_deinit); | 467 | EXPORT_SYMBOL(xilinx_spi_deinit); |
464 | 468 | ||
469 | static int __devinit xilinx_spi_probe(struct platform_device *dev) | ||
470 | { | ||
471 | struct xspi_platform_data *pdata; | ||
472 | struct resource *r; | ||
473 | int irq, num_cs = 0, little_endian = 0, bits_per_word = 8; | ||
474 | struct spi_master *master; | ||
475 | u8 i; | ||
476 | |||
477 | pdata = dev->dev.platform_data; | ||
478 | if (pdata) { | ||
479 | num_cs = pdata->num_chipselect; | ||
480 | little_endian = pdata->little_endian; | ||
481 | bits_per_word = pdata->bits_per_word; | ||
482 | } | ||
483 | |||
484 | #ifdef CONFIG_OF | ||
485 | if (dev->dev.of_node) { | ||
486 | const __be32 *prop; | ||
487 | int len; | ||
488 | |||
489 | /* number of slave select bits is required */ | ||
490 | prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits", | ||
491 | &len); | ||
492 | if (prop && len >= sizeof(*prop)) | ||
493 | num_cs = __be32_to_cpup(prop); | ||
494 | } | ||
495 | #endif | ||
496 | |||
497 | if (!num_cs) { | ||
498 | dev_err(&dev->dev, "Missing slave select configuration data\n"); | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | |||
502 | |||
503 | r = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
504 | if (!r) | ||
505 | return -ENODEV; | ||
506 | |||
507 | irq = platform_get_irq(dev, 0); | ||
508 | if (irq < 0) | ||
509 | return -ENXIO; | ||
510 | |||
511 | master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs, | ||
512 | little_endian, bits_per_word); | ||
513 | if (!master) | ||
514 | return -ENODEV; | ||
515 | |||
516 | if (pdata) { | ||
517 | for (i = 0; i < pdata->num_devices; i++) | ||
518 | spi_new_device(master, pdata->devices + i); | ||
519 | } | ||
520 | |||
521 | platform_set_drvdata(dev, master); | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int __devexit xilinx_spi_remove(struct platform_device *dev) | ||
526 | { | ||
527 | xilinx_spi_deinit(platform_get_drvdata(dev)); | ||
528 | platform_set_drvdata(dev, 0); | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | /* work with hotplug and coldplug */ | ||
534 | MODULE_ALIAS("platform:" XILINX_SPI_NAME); | ||
535 | |||
536 | static struct platform_driver xilinx_spi_driver = { | ||
537 | .probe = xilinx_spi_probe, | ||
538 | .remove = __devexit_p(xilinx_spi_remove), | ||
539 | .driver = { | ||
540 | .name = XILINX_SPI_NAME, | ||
541 | .owner = THIS_MODULE, | ||
542 | #ifdef CONFIG_OF | ||
543 | .of_match_table = xilinx_spi_of_match, | ||
544 | #endif | ||
545 | }, | ||
546 | }; | ||
547 | |||
548 | static int __init xilinx_spi_pltfm_init(void) | ||
549 | { | ||
550 | return platform_driver_register(&xilinx_spi_driver); | ||
551 | } | ||
552 | module_init(xilinx_spi_pltfm_init); | ||
553 | |||
554 | static void __exit xilinx_spi_pltfm_exit(void) | ||
555 | { | ||
556 | platform_driver_unregister(&xilinx_spi_driver); | ||
557 | } | ||
558 | module_exit(xilinx_spi_pltfm_exit); | ||
559 | |||
465 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); | 560 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); |
466 | MODULE_DESCRIPTION("Xilinx SPI driver"); | 561 | MODULE_DESCRIPTION("Xilinx SPI driver"); |
467 | MODULE_LICENSE("GPL"); | 562 | MODULE_LICENSE("GPL"); |