diff options
Diffstat (limited to 'drivers/spi/xilinx_spi.c')
| -rw-r--r-- | drivers/spi/xilinx_spi.c | 137 |
1 files changed, 81 insertions, 56 deletions
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 68d6f4988fb5..fe7e5f35e5d0 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c | |||
| @@ -15,12 +15,15 @@ | |||
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
| 17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 18 | |||
| 19 | #include <linux/of_platform.h> | ||
| 20 | #include <linux/of_device.h> | ||
| 21 | #include <linux/of_spi.h> | ||
| 22 | |||
| 18 | #include <linux/spi/spi.h> | 23 | #include <linux/spi/spi.h> |
| 19 | #include <linux/spi/spi_bitbang.h> | 24 | #include <linux/spi/spi_bitbang.h> |
| 20 | #include <linux/io.h> | 25 | #include <linux/io.h> |
| 21 | 26 | ||
| 22 | #include <syslib/virtex_devices.h> | ||
| 23 | |||
| 24 | #define XILINX_SPI_NAME "xilinx_spi" | 27 | #define XILINX_SPI_NAME "xilinx_spi" |
| 25 | 28 | ||
| 26 | /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) | 29 | /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) |
| @@ -144,23 +147,14 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, | |||
| 144 | struct spi_transfer *t) | 147 | struct spi_transfer *t) |
| 145 | { | 148 | { |
| 146 | u8 bits_per_word; | 149 | u8 bits_per_word; |
| 147 | u32 hz; | ||
| 148 | struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); | ||
| 149 | 150 | ||
| 150 | bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; | 151 | bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; |
| 151 | hz = (t) ? t->speed_hz : spi->max_speed_hz; | ||
| 152 | if (bits_per_word != 8) { | 152 | if (bits_per_word != 8) { |
| 153 | dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", | 153 | dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", |
| 154 | __func__, bits_per_word); | 154 | __func__, bits_per_word); |
| 155 | return -EINVAL; | 155 | return -EINVAL; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | if (hz && xspi->speed_hz > hz) { | ||
| 159 | dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n", | ||
| 160 | __func__, hz); | ||
| 161 | return -EINVAL; | ||
| 162 | } | ||
| 163 | |||
| 164 | return 0; | 158 | return 0; |
| 165 | } | 159 | } |
| 166 | 160 | ||
| @@ -304,32 +298,38 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) | |||
| 304 | return IRQ_HANDLED; | 298 | return IRQ_HANDLED; |
| 305 | } | 299 | } |
| 306 | 300 | ||
| 307 | static int __init xilinx_spi_probe(struct platform_device *dev) | 301 | static int __init xilinx_spi_of_probe(struct of_device *ofdev, |
| 302 | const struct of_device_id *match) | ||
| 308 | { | 303 | { |
| 309 | int ret = 0; | ||
| 310 | struct spi_master *master; | 304 | struct spi_master *master; |
| 311 | struct xilinx_spi *xspi; | 305 | struct xilinx_spi *xspi; |
| 312 | struct xspi_platform_data *pdata; | 306 | struct resource r_irq_struct; |
| 313 | struct resource *r; | 307 | struct resource r_mem_struct; |
| 308 | |||
| 309 | struct resource *r_irq = &r_irq_struct; | ||
| 310 | struct resource *r_mem = &r_mem_struct; | ||
| 311 | int rc = 0; | ||
| 312 | const u32 *prop; | ||
| 313 | int len; | ||
| 314 | 314 | ||
| 315 | /* Get resources(memory, IRQ) associated with the device */ | 315 | /* Get resources(memory, IRQ) associated with the device */ |
| 316 | master = spi_alloc_master(&dev->dev, sizeof(struct xilinx_spi)); | 316 | master = spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi)); |
| 317 | 317 | ||
| 318 | if (master == NULL) { | 318 | if (master == NULL) { |
| 319 | return -ENOMEM; | 319 | return -ENOMEM; |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | platform_set_drvdata(dev, master); | 322 | dev_set_drvdata(&ofdev->dev, master); |
| 323 | pdata = dev->dev.platform_data; | ||
| 324 | 323 | ||
| 325 | if (pdata == NULL) { | 324 | rc = of_address_to_resource(ofdev->node, 0, r_mem); |
| 326 | ret = -ENODEV; | 325 | if (rc) { |
| 326 | dev_warn(&ofdev->dev, "invalid address\n"); | ||
| 327 | goto put_master; | 327 | goto put_master; |
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | r = platform_get_resource(dev, IORESOURCE_MEM, 0); | 330 | rc = of_irq_to_resource(ofdev->node, 0, r_irq); |
| 331 | if (r == NULL) { | 331 | if (rc == NO_IRQ) { |
| 332 | ret = -ENODEV; | 332 | dev_warn(&ofdev->dev, "no IRQ found\n"); |
| 333 | goto put_master; | 333 | goto put_master; |
| 334 | } | 334 | } |
| 335 | 335 | ||
| @@ -341,47 +341,57 @@ static int __init xilinx_spi_probe(struct platform_device *dev) | |||
| 341 | xspi->bitbang.master->setup = xilinx_spi_setup; | 341 | xspi->bitbang.master->setup = xilinx_spi_setup; |
| 342 | init_completion(&xspi->done); | 342 | init_completion(&xspi->done); |
| 343 | 343 | ||
| 344 | if (!request_mem_region(r->start, | 344 | xspi->irq = r_irq->start; |
| 345 | r->end - r->start + 1, XILINX_SPI_NAME)) { | 345 | |
| 346 | ret = -ENXIO; | 346 | if (!request_mem_region(r_mem->start, |
| 347 | r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) { | ||
| 348 | rc = -ENXIO; | ||
| 349 | dev_warn(&ofdev->dev, "memory request failure\n"); | ||
| 347 | goto put_master; | 350 | goto put_master; |
| 348 | } | 351 | } |
| 349 | 352 | ||
| 350 | xspi->regs = ioremap(r->start, r->end - r->start + 1); | 353 | xspi->regs = ioremap(r_mem->start, r_mem->end - r_mem->start + 1); |
| 351 | if (xspi->regs == NULL) { | 354 | if (xspi->regs == NULL) { |
| 352 | ret = -ENOMEM; | 355 | rc = -ENOMEM; |
| 356 | dev_warn(&ofdev->dev, "ioremap failure\n"); | ||
| 353 | goto put_master; | 357 | goto put_master; |
| 354 | } | 358 | } |
| 359 | xspi->irq = r_irq->start; | ||
| 355 | 360 | ||
| 356 | ret = platform_get_irq(dev, 0); | 361 | /* dynamic bus assignment */ |
| 357 | if (ret < 0) { | 362 | master->bus_num = -1; |
| 358 | ret = -ENXIO; | ||
| 359 | goto unmap_io; | ||
| 360 | } | ||
| 361 | xspi->irq = ret; | ||
| 362 | 363 | ||
| 363 | master->bus_num = pdata->bus_num; | 364 | /* number of slave select bits is required */ |
| 364 | master->num_chipselect = pdata->num_chipselect; | 365 | prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len); |
| 365 | xspi->speed_hz = pdata->speed_hz; | 366 | if (!prop || len < sizeof(*prop)) { |
| 367 | dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n"); | ||
| 368 | goto put_master; | ||
| 369 | } | ||
| 370 | master->num_chipselect = *prop; | ||
| 366 | 371 | ||
| 367 | /* SPI controller initializations */ | 372 | /* SPI controller initializations */ |
| 368 | xspi_init_hw(xspi->regs); | 373 | xspi_init_hw(xspi->regs); |
| 369 | 374 | ||
| 370 | /* Register for SPI Interrupt */ | 375 | /* Register for SPI Interrupt */ |
| 371 | ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi); | 376 | rc = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi); |
| 372 | if (ret != 0) | 377 | if (rc != 0) { |
| 378 | dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq); | ||
| 373 | goto unmap_io; | 379 | goto unmap_io; |
| 380 | } | ||
| 374 | 381 | ||
| 375 | ret = spi_bitbang_start(&xspi->bitbang); | 382 | rc = spi_bitbang_start(&xspi->bitbang); |
| 376 | if (ret != 0) { | 383 | if (rc != 0) { |
| 377 | dev_err(&dev->dev, "spi_bitbang_start FAILED\n"); | 384 | dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n"); |
| 378 | goto free_irq; | 385 | goto free_irq; |
| 379 | } | 386 | } |
| 380 | 387 | ||
| 381 | dev_info(&dev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n", | 388 | dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n", |
| 382 | r->start, (u32)xspi->regs, xspi->irq); | 389 | (unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq); |
| 383 | 390 | ||
| 384 | return ret; | 391 | /* Add any subnodes on the SPI bus */ |
| 392 | of_register_spi_devices(master, ofdev->node); | ||
| 393 | |||
| 394 | return rc; | ||
| 385 | 395 | ||
| 386 | free_irq: | 396 | free_irq: |
| 387 | free_irq(xspi->irq, xspi); | 397 | free_irq(xspi->irq, xspi); |
| @@ -389,21 +399,21 @@ unmap_io: | |||
| 389 | iounmap(xspi->regs); | 399 | iounmap(xspi->regs); |
| 390 | put_master: | 400 | put_master: |
| 391 | spi_master_put(master); | 401 | spi_master_put(master); |
| 392 | return ret; | 402 | return rc; |
| 393 | } | 403 | } |
| 394 | 404 | ||
| 395 | static int __devexit xilinx_spi_remove(struct platform_device *dev) | 405 | static int __devexit xilinx_spi_remove(struct of_device *ofdev) |
| 396 | { | 406 | { |
| 397 | struct xilinx_spi *xspi; | 407 | struct xilinx_spi *xspi; |
| 398 | struct spi_master *master; | 408 | struct spi_master *master; |
| 399 | 409 | ||
| 400 | master = platform_get_drvdata(dev); | 410 | master = platform_get_drvdata(ofdev); |
| 401 | xspi = spi_master_get_devdata(master); | 411 | xspi = spi_master_get_devdata(master); |
| 402 | 412 | ||
| 403 | spi_bitbang_stop(&xspi->bitbang); | 413 | spi_bitbang_stop(&xspi->bitbang); |
| 404 | free_irq(xspi->irq, xspi); | 414 | free_irq(xspi->irq, xspi); |
| 405 | iounmap(xspi->regs); | 415 | iounmap(xspi->regs); |
| 406 | platform_set_drvdata(dev, 0); | 416 | dev_set_drvdata(&ofdev->dev, 0); |
| 407 | spi_master_put(xspi->bitbang.master); | 417 | spi_master_put(xspi->bitbang.master); |
| 408 | 418 | ||
| 409 | return 0; | 419 | return 0; |
| @@ -412,27 +422,42 @@ static int __devexit xilinx_spi_remove(struct platform_device *dev) | |||
| 412 | /* work with hotplug and coldplug */ | 422 | /* work with hotplug and coldplug */ |
| 413 | MODULE_ALIAS("platform:" XILINX_SPI_NAME); | 423 | MODULE_ALIAS("platform:" XILINX_SPI_NAME); |
| 414 | 424 | ||
| 415 | static struct platform_driver xilinx_spi_driver = { | 425 | static int __exit xilinx_spi_of_remove(struct of_device *op) |
| 416 | .probe = xilinx_spi_probe, | 426 | { |
| 417 | .remove = __devexit_p(xilinx_spi_remove), | 427 | return xilinx_spi_remove(op); |
| 428 | } | ||
| 429 | |||
| 430 | static struct of_device_id xilinx_spi_of_match[] = { | ||
| 431 | { .compatible = "xlnx,xps-spi-2.00.a", }, | ||
| 432 | { .compatible = "xlnx,xps-spi-2.00.b", }, | ||
| 433 | {} | ||
| 434 | }; | ||
| 435 | |||
| 436 | MODULE_DEVICE_TABLE(of, xilinx_spi_of_match); | ||
| 437 | |||
| 438 | static struct of_platform_driver xilinx_spi_of_driver = { | ||
| 439 | .owner = THIS_MODULE, | ||
| 440 | .name = "xilinx-xps-spi", | ||
| 441 | .match_table = xilinx_spi_of_match, | ||
| 442 | .probe = xilinx_spi_of_probe, | ||
| 443 | .remove = __exit_p(xilinx_spi_of_remove), | ||
| 418 | .driver = { | 444 | .driver = { |
| 419 | .name = XILINX_SPI_NAME, | 445 | .name = "xilinx-xps-spi", |
| 420 | .owner = THIS_MODULE, | 446 | .owner = THIS_MODULE, |
| 421 | }, | 447 | }, |
| 422 | }; | 448 | }; |
| 423 | 449 | ||
| 424 | static int __init xilinx_spi_init(void) | 450 | static int __init xilinx_spi_init(void) |
| 425 | { | 451 | { |
| 426 | return platform_driver_register(&xilinx_spi_driver); | 452 | return of_register_platform_driver(&xilinx_spi_of_driver); |
| 427 | } | 453 | } |
| 428 | module_init(xilinx_spi_init); | 454 | module_init(xilinx_spi_init); |
| 429 | 455 | ||
| 430 | static void __exit xilinx_spi_exit(void) | 456 | static void __exit xilinx_spi_exit(void) |
| 431 | { | 457 | { |
| 432 | platform_driver_unregister(&xilinx_spi_driver); | 458 | of_unregister_platform_driver(&xilinx_spi_of_driver); |
| 433 | } | 459 | } |
| 434 | module_exit(xilinx_spi_exit); | 460 | module_exit(xilinx_spi_exit); |
| 435 | |||
| 436 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); | 461 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); |
| 437 | MODULE_DESCRIPTION("Xilinx SPI driver"); | 462 | MODULE_DESCRIPTION("Xilinx SPI driver"); |
| 438 | MODULE_LICENSE("GPL"); | 463 | MODULE_LICENSE("GPL"); |
