diff options
-rw-r--r-- | drivers/spi/spi-omap-100k.c | 103 |
1 files changed, 17 insertions, 86 deletions
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 5999285f4cbd..d4fcca9dc8e5 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c | |||
@@ -83,11 +83,6 @@ | |||
83 | #define SPI_SHUTDOWN 1 | 83 | #define SPI_SHUTDOWN 1 |
84 | 84 | ||
85 | struct omap1_spi100k { | 85 | struct omap1_spi100k { |
86 | struct work_struct work; | ||
87 | |||
88 | /* lock protects queue and registers */ | ||
89 | spinlock_t lock; | ||
90 | struct list_head msg_queue; | ||
91 | struct spi_master *master; | 86 | struct spi_master *master; |
92 | struct clk *ick; | 87 | struct clk *ick; |
93 | struct clk *fck; | 88 | struct clk *fck; |
@@ -104,8 +99,6 @@ struct omap1_spi100k_cs { | |||
104 | int word_len; | 99 | int word_len; |
105 | }; | 100 | }; |
106 | 101 | ||
107 | static struct workqueue_struct *omap1_spi100k_wq; | ||
108 | |||
109 | #define MOD_REG_BIT(val, mask, set) do { \ | 102 | #define MOD_REG_BIT(val, mask, set) do { \ |
110 | if (set) \ | 103 | if (set) \ |
111 | val |= mask; \ | 104 | val |= mask; \ |
@@ -321,6 +314,16 @@ static int omap1_spi100k_setup(struct spi_device *spi) | |||
321 | return ret; | 314 | return ret; |
322 | } | 315 | } |
323 | 316 | ||
317 | static int omap1_spi100k_prepare_hardware(struct spi_master *master) | ||
318 | { | ||
319 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | ||
320 | |||
321 | clk_enable(spi100k->ick); | ||
322 | clk_enable(spi100k->fck); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
324 | static int omap1_spi100k_transfer_one_message(struct spi_master *master, | 327 | static int omap1_spi100k_transfer_one_message(struct spi_master *master, |
325 | struct spi_message *m) | 328 | struct spi_message *m) |
326 | { | 329 | { |
@@ -383,64 +386,18 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master, | |||
383 | omap1_spi100k_force_cs(spi100k, 0); | 386 | omap1_spi100k_force_cs(spi100k, 0); |
384 | 387 | ||
385 | m->status = status; | 388 | m->status = status; |
386 | m->complete(m->context); | 389 | |
390 | spi_finalize_current_message(master); | ||
387 | 391 | ||
388 | return status; | 392 | return status; |
389 | } | 393 | } |
390 | 394 | ||
391 | static void omap1_spi100k_work(struct work_struct *work) | 395 | static int omap1_spi100k_unprepare_hardware(struct spi_master *master) |
392 | { | 396 | { |
393 | struct omap1_spi100k *spi100k; | 397 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); |
394 | |||
395 | spi100k = container_of(work, struct omap1_spi100k, work); | ||
396 | spin_lock_irq(&spi100k->lock); | ||
397 | |||
398 | clk_enable(spi100k->ick); | ||
399 | clk_enable(spi100k->fck); | ||
400 | |||
401 | /* We only enable one channel at a time -- the one whose message is | ||
402 | * at the head of the queue -- although this controller would gladly | ||
403 | * arbitrate among multiple channels. This corresponds to "single | ||
404 | * channel" master mode. As a side effect, we need to manage the | ||
405 | * chipselect with the FORCE bit ... CS != channel enable. | ||
406 | */ | ||
407 | while (!list_empty(&spi100k->msg_queue)) { | ||
408 | struct spi_message *m; | ||
409 | |||
410 | m = container_of(spi100k->msg_queue.next, struct spi_message, | ||
411 | queue); | ||
412 | |||
413 | list_del_init(&m->queue); | ||
414 | spin_unlock_irq(&spi100k->lock); | ||
415 | |||
416 | omap1_spi100k_transfer_one_message(m->spi->master, m); | ||
417 | |||
418 | spin_lock_irq(&spi100k->lock); | ||
419 | } | ||
420 | 398 | ||
421 | clk_disable(spi100k->ick); | 399 | clk_disable(spi100k->ick); |
422 | clk_disable(spi100k->fck); | 400 | clk_disable(spi100k->fck); |
423 | spin_unlock_irq(&spi100k->lock); | ||
424 | } | ||
425 | |||
426 | static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m) | ||
427 | { | ||
428 | struct omap1_spi100k *spi100k; | ||
429 | unsigned long flags; | ||
430 | |||
431 | m->actual_length = 0; | ||
432 | m->status = -EINPROGRESS; | ||
433 | |||
434 | spi100k = spi_master_get_devdata(spi->master); | ||
435 | |||
436 | /* Don't accept new work if we're shutting down */ | ||
437 | if (spi100k->state == SPI_SHUTDOWN) | ||
438 | return -ESHUTDOWN; | ||
439 | |||
440 | spin_lock_irqsave(&spi100k->lock, flags); | ||
441 | list_add_tail(&m->queue, &spi100k->msg_queue); | ||
442 | queue_work(omap1_spi100k_wq, &spi100k->work); | ||
443 | spin_unlock_irqrestore(&spi100k->lock, flags); | ||
444 | 401 | ||
445 | return 0; | 402 | return 0; |
446 | } | 403 | } |
@@ -464,7 +421,9 @@ static int omap1_spi100k_probe(struct platform_device *pdev) | |||
464 | master->bus_num = pdev->id; | 421 | master->bus_num = pdev->id; |
465 | 422 | ||
466 | master->setup = omap1_spi100k_setup; | 423 | master->setup = omap1_spi100k_setup; |
467 | master->transfer = omap1_spi100k_transfer; | 424 | master->transfer_one_message = omap1_spi100k_transfer_one_message; |
425 | master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware; | ||
426 | master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware; | ||
468 | master->cleanup = NULL; | 427 | master->cleanup = NULL; |
469 | master->num_chipselect = 2; | 428 | master->num_chipselect = 2; |
470 | master->mode_bits = MODEBITS; | 429 | master->mode_bits = MODEBITS; |
@@ -484,10 +443,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev) | |||
484 | */ | 443 | */ |
485 | spi100k->base = (void __iomem *) pdev->dev.platform_data; | 444 | spi100k->base = (void __iomem *) pdev->dev.platform_data; |
486 | 445 | ||
487 | INIT_WORK(&spi100k->work, omap1_spi100k_work); | ||
488 | |||
489 | spin_lock_init(&spi100k->lock); | ||
490 | INIT_LIST_HEAD(&spi100k->msg_queue); | ||
491 | spi100k->ick = clk_get(&pdev->dev, "ick"); | 446 | spi100k->ick = clk_get(&pdev->dev, "ick"); |
492 | if (IS_ERR(spi100k->ick)) { | 447 | if (IS_ERR(spi100k->ick)) { |
493 | dev_dbg(&pdev->dev, "can't get spi100k_ick\n"); | 448 | dev_dbg(&pdev->dev, "can't get spi100k_ick\n"); |
@@ -524,27 +479,11 @@ static int omap1_spi100k_remove(struct platform_device *pdev) | |||
524 | struct spi_master *master; | 479 | struct spi_master *master; |
525 | struct omap1_spi100k *spi100k; | 480 | struct omap1_spi100k *spi100k; |
526 | struct resource *r; | 481 | struct resource *r; |
527 | unsigned limit = 500; | ||
528 | unsigned long flags; | ||
529 | int status = 0; | 482 | int status = 0; |
530 | 483 | ||
531 | master = platform_get_drvdata(pdev); | 484 | master = platform_get_drvdata(pdev); |
532 | spi100k = spi_master_get_devdata(master); | 485 | spi100k = spi_master_get_devdata(master); |
533 | 486 | ||
534 | spin_lock_irqsave(&spi100k->lock, flags); | ||
535 | |||
536 | spi100k->state = SPI_SHUTDOWN; | ||
537 | while (!list_empty(&spi100k->msg_queue) && limit--) { | ||
538 | spin_unlock_irqrestore(&spi100k->lock, flags); | ||
539 | msleep(10); | ||
540 | spin_lock_irqsave(&spi100k->lock, flags); | ||
541 | } | ||
542 | |||
543 | if (!list_empty(&spi100k->msg_queue)) | ||
544 | status = -EBUSY; | ||
545 | |||
546 | spin_unlock_irqrestore(&spi100k->lock, flags); | ||
547 | |||
548 | if (status != 0) | 487 | if (status != 0) |
549 | return status; | 488 | return status; |
550 | 489 | ||
@@ -569,20 +508,12 @@ static struct platform_driver omap1_spi100k_driver = { | |||
569 | 508 | ||
570 | static int __init omap1_spi100k_init(void) | 509 | static int __init omap1_spi100k_init(void) |
571 | { | 510 | { |
572 | omap1_spi100k_wq = create_singlethread_workqueue( | ||
573 | omap1_spi100k_driver.driver.name); | ||
574 | |||
575 | if (omap1_spi100k_wq == NULL) | ||
576 | return -1; | ||
577 | |||
578 | return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe); | 511 | return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe); |
579 | } | 512 | } |
580 | 513 | ||
581 | static void __exit omap1_spi100k_exit(void) | 514 | static void __exit omap1_spi100k_exit(void) |
582 | { | 515 | { |
583 | platform_driver_unregister(&omap1_spi100k_driver); | 516 | platform_driver_unregister(&omap1_spi100k_driver); |
584 | |||
585 | destroy_workqueue(omap1_spi100k_wq); | ||
586 | } | 517 | } |
587 | 518 | ||
588 | module_init(omap1_spi100k_init); | 519 | module_init(omap1_spi100k_init); |