diff options
Diffstat (limited to 'drivers/spi/xilinx_spi.c')
-rw-r--r-- | drivers/spi/xilinx_spi.c | 131 |
1 files changed, 110 insertions, 21 deletions
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 80f2db5bcfd..4d2c75df886 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,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) | |||
350 | return IRQ_HANDLED; | 351 | return IRQ_HANDLED; |
351 | } | 352 | } |
352 | 353 | ||
354 | static const struct of_device_id xilinx_spi_of_match[] = { | ||
355 | { .compatible = "xlnx,xps-spi-2.00.a", }, | ||
356 | { .compatible = "xlnx,xps-spi-2.00.b", }, | ||
357 | {} | ||
358 | }; | ||
359 | MODULE_DEVICE_TABLE(of, xilinx_spi_of_match); | ||
360 | |||
353 | struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, | 361 | struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, |
354 | u32 irq, s16 bus_num) | 362 | u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word) |
355 | { | 363 | { |
356 | struct spi_master *master; | 364 | struct spi_master *master; |
357 | struct xilinx_spi *xspi; | 365 | struct xilinx_spi *xspi; |
358 | struct xspi_platform_data *pdata = dev->platform_data; | ||
359 | int ret; | 366 | int ret; |
360 | 367 | ||
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)); | 368 | master = spi_alloc_master(dev, sizeof(struct xilinx_spi)); |
367 | if (!master) | 369 | if (!master) |
368 | return NULL; | 370 | return NULL; |
@@ -389,21 +391,19 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, | |||
389 | } | 391 | } |
390 | 392 | ||
391 | master->bus_num = bus_num; | 393 | master->bus_num = bus_num; |
392 | master->num_chipselect = pdata->num_chipselect; | 394 | master->num_chipselect = num_cs; |
393 | #ifdef CONFIG_OF | ||
394 | master->dev.of_node = dev->of_node; | 395 | master->dev.of_node = dev->of_node; |
395 | #endif | ||
396 | 396 | ||
397 | xspi->mem = *mem; | 397 | xspi->mem = *mem; |
398 | xspi->irq = irq; | 398 | xspi->irq = irq; |
399 | if (pdata->little_endian) { | 399 | if (little_endian) { |
400 | xspi->read_fn = xspi_read32; | 400 | xspi->read_fn = xspi_read32; |
401 | xspi->write_fn = xspi_write32; | 401 | xspi->write_fn = xspi_write32; |
402 | } else { | 402 | } else { |
403 | xspi->read_fn = xspi_read32_be; | 403 | xspi->read_fn = xspi_read32_be; |
404 | xspi->write_fn = xspi_write32_be; | 404 | xspi->write_fn = xspi_write32_be; |
405 | } | 405 | } |
406 | xspi->bits_per_word = pdata->bits_per_word; | 406 | xspi->bits_per_word = bits_per_word; |
407 | if (xspi->bits_per_word == 8) { | 407 | if (xspi->bits_per_word == 8) { |
408 | xspi->tx_fn = xspi_tx8; | 408 | xspi->tx_fn = xspi_tx8; |
409 | xspi->rx_fn = xspi_rx8; | 409 | xspi->rx_fn = xspi_rx8; |
@@ -462,6 +462,95 @@ void xilinx_spi_deinit(struct spi_master *master) | |||
462 | } | 462 | } |
463 | EXPORT_SYMBOL(xilinx_spi_deinit); | 463 | EXPORT_SYMBOL(xilinx_spi_deinit); |
464 | 464 | ||
465 | static int __devinit xilinx_spi_probe(struct platform_device *dev) | ||
466 | { | ||
467 | struct xspi_platform_data *pdata; | ||
468 | struct resource *r; | ||
469 | int irq, num_cs = 0, little_endian = 0, bits_per_word = 8; | ||
470 | struct spi_master *master; | ||
471 | u8 i; | ||
472 | |||
473 | pdata = dev->dev.platform_data; | ||
474 | if (pdata) { | ||
475 | num_cs = pdata->num_chipselect; | ||
476 | little_endian = pdata->little_endian; | ||
477 | bits_per_word = pdata->bits_per_word; | ||
478 | } | ||
479 | |||
480 | #ifdef CONFIG_OF | ||
481 | if (dev->dev.of_node) { | ||
482 | const __be32 *prop; | ||
483 | int len; | ||
484 | |||
485 | /* number of slave select bits is required */ | ||
486 | prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits", | ||
487 | &len); | ||
488 | if (prop && len >= sizeof(*prop)) | ||
489 | num_cs = __be32_to_cpup(prop); | ||
490 | } | ||
491 | #endif | ||
492 | |||
493 | if (!num_cs) { | ||
494 | dev_err(&dev->dev, "Missing slave select configuration data\n"); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | |||
498 | |||
499 | r = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
500 | if (!r) | ||
501 | return -ENODEV; | ||
502 | |||
503 | irq = platform_get_irq(dev, 0); | ||
504 | if (irq < 0) | ||
505 | return -ENXIO; | ||
506 | |||
507 | master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs, | ||
508 | little_endian, bits_per_word); | ||
509 | if (!master) | ||
510 | return -ENODEV; | ||
511 | |||
512 | if (pdata) { | ||
513 | for (i = 0; i < pdata->num_devices; i++) | ||
514 | spi_new_device(master, pdata->devices + i); | ||
515 | } | ||
516 | |||
517 | platform_set_drvdata(dev, master); | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int __devexit xilinx_spi_remove(struct platform_device *dev) | ||
522 | { | ||
523 | xilinx_spi_deinit(platform_get_drvdata(dev)); | ||
524 | platform_set_drvdata(dev, 0); | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | /* work with hotplug and coldplug */ | ||
530 | MODULE_ALIAS("platform:" XILINX_SPI_NAME); | ||
531 | |||
532 | static struct platform_driver xilinx_spi_driver = { | ||
533 | .probe = xilinx_spi_probe, | ||
534 | .remove = __devexit_p(xilinx_spi_remove), | ||
535 | .driver = { | ||
536 | .name = XILINX_SPI_NAME, | ||
537 | .owner = THIS_MODULE, | ||
538 | .of_match_table = xilinx_spi_of_match, | ||
539 | }, | ||
540 | }; | ||
541 | |||
542 | static int __init xilinx_spi_pltfm_init(void) | ||
543 | { | ||
544 | return platform_driver_register(&xilinx_spi_driver); | ||
545 | } | ||
546 | module_init(xilinx_spi_pltfm_init); | ||
547 | |||
548 | static void __exit xilinx_spi_pltfm_exit(void) | ||
549 | { | ||
550 | platform_driver_unregister(&xilinx_spi_driver); | ||
551 | } | ||
552 | module_exit(xilinx_spi_pltfm_exit); | ||
553 | |||
465 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); | 554 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); |
466 | MODULE_DESCRIPTION("Xilinx SPI driver"); | 555 | MODULE_DESCRIPTION("Xilinx SPI driver"); |
467 | MODULE_LICENSE("GPL"); | 556 | MODULE_LICENSE("GPL"); |