diff options
author | Alex Dubov <oakad@yahoo.com> | 2008-07-25 22:45:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-26 15:00:04 -0400 |
commit | b77899985bdfd85a8e5a6e485033a9b4713d2471 (patch) | |
tree | 5cf53074b73de6fc27d8d8b0ac78fc8d32c0b9df | |
parent | 0147600172b4a5d261165d1aa5ef818d84da1557 (diff) |
memstick: allow "set_param" method to return an error code
Some controllers (Jmicron, for instance) can report temporal failure
condition during power-on. It is desirable to account for this using a
return value of "set_param" device method. The return value can also be
handy to distinguish between supported and unsupported device parameters
in run time.
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/memstick/core/memstick.c | 18 | ||||
-rw-r--r-- | drivers/memstick/host/jmb38x_ms.c | 67 | ||||
-rw-r--r-- | drivers/memstick/host/tifm_ms.c | 17 | ||||
-rw-r--r-- | include/linux/memstick.h | 2 |
4 files changed, 71 insertions, 33 deletions
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 61b98c333cb..3c7d9a79c1e 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c | |||
@@ -415,10 +415,14 @@ err_out: | |||
415 | return NULL; | 415 | return NULL; |
416 | } | 416 | } |
417 | 417 | ||
418 | static void memstick_power_on(struct memstick_host *host) | 418 | static int memstick_power_on(struct memstick_host *host) |
419 | { | 419 | { |
420 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); | 420 | int rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); |
421 | host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); | 421 | |
422 | if (!rc) | ||
423 | rc = host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); | ||
424 | |||
425 | return rc; | ||
422 | } | 426 | } |
423 | 427 | ||
424 | static void memstick_check(struct work_struct *work) | 428 | static void memstick_check(struct work_struct *work) |
@@ -573,11 +577,15 @@ EXPORT_SYMBOL(memstick_suspend_host); | |||
573 | */ | 577 | */ |
574 | void memstick_resume_host(struct memstick_host *host) | 578 | void memstick_resume_host(struct memstick_host *host) |
575 | { | 579 | { |
580 | int rc = 0; | ||
581 | |||
576 | mutex_lock(&host->lock); | 582 | mutex_lock(&host->lock); |
577 | if (host->card) | 583 | if (host->card) |
578 | memstick_power_on(host); | 584 | rc = memstick_power_on(host); |
579 | mutex_unlock(&host->lock); | 585 | mutex_unlock(&host->lock); |
580 | memstick_detect_change(host); | 586 | |
587 | if (!rc) | ||
588 | memstick_detect_change(host); | ||
581 | } | 589 | } |
582 | EXPORT_SYMBOL(memstick_resume_host); | 590 | EXPORT_SYMBOL(memstick_resume_host); |
583 | 591 | ||
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 4e3bfbcdf15..9d82e67737d 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c | |||
@@ -609,36 +609,68 @@ static void jmb38x_ms_request(struct memstick_host *msh) | |||
609 | spin_unlock_irqrestore(&host->lock, flags); | 609 | spin_unlock_irqrestore(&host->lock, flags); |
610 | } | 610 | } |
611 | 611 | ||
612 | static void jmb38x_ms_reset(struct jmb38x_ms_host *host) | 612 | static int jmb38x_ms_reset(struct jmb38x_ms_host *host) |
613 | { | 613 | { |
614 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); | 614 | int cnt; |
615 | 615 | ||
616 | writel(HOST_CONTROL_RESET_REQ, host->addr + HOST_CONTROL); | 616 | writel(HOST_CONTROL_RESET_REQ | HOST_CONTROL_CLOCK_EN |
617 | | readl(host->addr + HOST_CONTROL), | ||
618 | host->addr + HOST_CONTROL); | ||
619 | mmiowb(); | ||
620 | |||
621 | for (cnt = 0; cnt < 20; ++cnt) { | ||
622 | if (!(HOST_CONTROL_RESET_REQ | ||
623 | & readl(host->addr + HOST_CONTROL))) | ||
624 | goto reset_next; | ||
617 | 625 | ||
618 | while (HOST_CONTROL_RESET_REQ | ||
619 | & (host_ctl = readl(host->addr + HOST_CONTROL))) { | ||
620 | ndelay(20); | 626 | ndelay(20); |
621 | dev_dbg(&host->chip->pdev->dev, "reset %08x\n", host_ctl); | ||
622 | } | 627 | } |
628 | dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n"); | ||
629 | return -EIO; | ||
623 | 630 | ||
624 | writel(HOST_CONTROL_RESET, host->addr + HOST_CONTROL); | 631 | reset_next: |
632 | writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN | ||
633 | | readl(host->addr + HOST_CONTROL), | ||
634 | host->addr + HOST_CONTROL); | ||
635 | mmiowb(); | ||
636 | |||
637 | for (cnt = 0; cnt < 20; ++cnt) { | ||
638 | if (!(HOST_CONTROL_RESET | ||
639 | & readl(host->addr + HOST_CONTROL))) | ||
640 | goto reset_ok; | ||
641 | |||
642 | ndelay(20); | ||
643 | } | ||
644 | dev_dbg(&host->chip->pdev->dev, "reset timeout\n"); | ||
645 | return -EIO; | ||
646 | |||
647 | reset_ok: | ||
625 | mmiowb(); | 648 | mmiowb(); |
626 | writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); | 649 | writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); |
627 | writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); | 650 | writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); |
651 | return 0; | ||
628 | } | 652 | } |
629 | 653 | ||
630 | static void jmb38x_ms_set_param(struct memstick_host *msh, | 654 | static int jmb38x_ms_set_param(struct memstick_host *msh, |
631 | enum memstick_param param, | 655 | enum memstick_param param, |
632 | int value) | 656 | int value) |
633 | { | 657 | { |
634 | struct jmb38x_ms_host *host = memstick_priv(msh); | 658 | struct jmb38x_ms_host *host = memstick_priv(msh); |
635 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); | 659 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); |
636 | unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; | 660 | unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; |
661 | int rc = 0; | ||
637 | 662 | ||
638 | switch (param) { | 663 | switch (param) { |
639 | case MEMSTICK_POWER: | 664 | case MEMSTICK_POWER: |
640 | if (value == MEMSTICK_POWER_ON) { | 665 | if (value == MEMSTICK_POWER_ON) { |
641 | jmb38x_ms_reset(host); | 666 | rc = jmb38x_ms_reset(host); |
667 | if (rc) | ||
668 | return rc; | ||
669 | |||
670 | host_ctl = 7; | ||
671 | host_ctl |= HOST_CONTROL_POWER_EN | ||
672 | | HOST_CONTROL_CLOCK_EN; | ||
673 | writel(host_ctl, host->addr + HOST_CONTROL); | ||
642 | 674 | ||
643 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 | 675 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 |
644 | : PAD_PU_PD_ON_MS_SOCK0, | 676 | : PAD_PU_PD_ON_MS_SOCK0, |
@@ -647,11 +679,7 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
647 | writel(PAD_OUTPUT_ENABLE_MS, | 679 | writel(PAD_OUTPUT_ENABLE_MS, |
648 | host->addr + PAD_OUTPUT_ENABLE); | 680 | host->addr + PAD_OUTPUT_ENABLE); |
649 | 681 | ||
650 | host_ctl = 7; | 682 | msleep(10); |
651 | host_ctl |= HOST_CONTROL_POWER_EN | ||
652 | | HOST_CONTROL_CLOCK_EN; | ||
653 | writel(host_ctl, host->addr + HOST_CONTROL); | ||
654 | |||
655 | dev_dbg(&host->chip->pdev->dev, "power on\n"); | 683 | dev_dbg(&host->chip->pdev->dev, "power on\n"); |
656 | } else if (value == MEMSTICK_POWER_OFF) { | 684 | } else if (value == MEMSTICK_POWER_OFF) { |
657 | host_ctl &= ~(HOST_CONTROL_POWER_EN | 685 | host_ctl &= ~(HOST_CONTROL_POWER_EN |
@@ -660,7 +688,8 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
660 | writel(0, host->addr + PAD_OUTPUT_ENABLE); | 688 | writel(0, host->addr + PAD_OUTPUT_ENABLE); |
661 | writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); | 689 | writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); |
662 | dev_dbg(&host->chip->pdev->dev, "power off\n"); | 690 | dev_dbg(&host->chip->pdev->dev, "power off\n"); |
663 | } | 691 | } else |
692 | return -EINVAL; | ||
664 | break; | 693 | break; |
665 | case MEMSTICK_INTERFACE: | 694 | case MEMSTICK_INTERFACE: |
666 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); | 695 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); |
@@ -686,12 +715,14 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
686 | host_ctl &= ~HOST_CONTROL_REI; | 715 | host_ctl &= ~HOST_CONTROL_REI; |
687 | clock_ctl = CLOCK_CONTROL_60MHZ; | 716 | clock_ctl = CLOCK_CONTROL_60MHZ; |
688 | clock_delay = 0; | 717 | clock_delay = 0; |
689 | } | 718 | } else |
719 | return -EINVAL; | ||
690 | writel(host_ctl, host->addr + HOST_CONTROL); | 720 | writel(host_ctl, host->addr + HOST_CONTROL); |
691 | writel(clock_ctl, host->addr + CLOCK_CONTROL); | 721 | writel(clock_ctl, host->addr + CLOCK_CONTROL); |
692 | writel(clock_delay, host->addr + CLOCK_DELAY); | 722 | writel(clock_delay, host->addr + CLOCK_DELAY); |
693 | break; | 723 | break; |
694 | }; | 724 | }; |
725 | return 0; | ||
695 | } | 726 | } |
696 | 727 | ||
697 | #ifdef CONFIG_PM | 728 | #ifdef CONFIG_PM |
diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 8577de4ebb0..14458764588 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c | |||
@@ -489,15 +489,12 @@ static void tifm_ms_request(struct memstick_host *msh) | |||
489 | return; | 489 | return; |
490 | } | 490 | } |
491 | 491 | ||
492 | static void tifm_ms_set_param(struct memstick_host *msh, | 492 | static int tifm_ms_set_param(struct memstick_host *msh, |
493 | enum memstick_param param, | 493 | enum memstick_param param, |
494 | int value) | 494 | int value) |
495 | { | 495 | { |
496 | struct tifm_ms *host = memstick_priv(msh); | 496 | struct tifm_ms *host = memstick_priv(msh); |
497 | struct tifm_dev *sock = host->dev; | 497 | struct tifm_dev *sock = host->dev; |
498 | unsigned long flags; | ||
499 | |||
500 | spin_lock_irqsave(&sock->lock, flags); | ||
501 | 498 | ||
502 | switch (param) { | 499 | switch (param) { |
503 | case MEMSTICK_POWER: | 500 | case MEMSTICK_POWER: |
@@ -512,7 +509,8 @@ static void tifm_ms_set_param(struct memstick_host *msh, | |||
512 | writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, | 509 | writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, |
513 | sock->addr + SOCK_MS_SYSTEM); | 510 | sock->addr + SOCK_MS_SYSTEM); |
514 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); | 511 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); |
515 | } | 512 | } else |
513 | return -EINVAL; | ||
516 | break; | 514 | break; |
517 | case MEMSTICK_INTERFACE: | 515 | case MEMSTICK_INTERFACE: |
518 | if (value == MEMSTICK_SERIAL) { | 516 | if (value == MEMSTICK_SERIAL) { |
@@ -525,11 +523,12 @@ static void tifm_ms_set_param(struct memstick_host *msh, | |||
525 | writel(TIFM_CTRL_FAST_CLK | 523 | writel(TIFM_CTRL_FAST_CLK |
526 | | readl(sock->addr + SOCK_CONTROL), | 524 | | readl(sock->addr + SOCK_CONTROL), |
527 | sock->addr + SOCK_CONTROL); | 525 | sock->addr + SOCK_CONTROL); |
528 | } | 526 | } else |
527 | return -EINVAL; | ||
529 | break; | 528 | break; |
530 | }; | 529 | }; |
531 | 530 | ||
532 | spin_unlock_irqrestore(&sock->lock, flags); | 531 | return 0; |
533 | } | 532 | } |
534 | 533 | ||
535 | static void tifm_ms_abort(unsigned long data) | 534 | static void tifm_ms_abort(unsigned long data) |
diff --git a/include/linux/memstick.h b/include/linux/memstick.h index 37a5cdb0391..2fe599c66d5 100644 --- a/include/linux/memstick.h +++ b/include/linux/memstick.h | |||
@@ -284,7 +284,7 @@ struct memstick_host { | |||
284 | /* Notify the host that some requests are pending. */ | 284 | /* Notify the host that some requests are pending. */ |
285 | void (*request)(struct memstick_host *host); | 285 | void (*request)(struct memstick_host *host); |
286 | /* Set host IO parameters (power, clock, etc). */ | 286 | /* Set host IO parameters (power, clock, etc). */ |
287 | void (*set_param)(struct memstick_host *host, | 287 | int (*set_param)(struct memstick_host *host, |
288 | enum memstick_param param, | 288 | enum memstick_param param, |
289 | int value); | 289 | int value); |
290 | unsigned long private[0] ____cacheline_aligned; | 290 | unsigned long private[0] ____cacheline_aligned; |