diff options
Diffstat (limited to 'drivers/spi')
-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"); |