diff options
Diffstat (limited to 'drivers/memstick/host/jmb38x_ms.c')
-rw-r--r-- | drivers/memstick/host/jmb38x_ms.c | 120 |
1 files changed, 84 insertions, 36 deletions
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index f2b894cd8b0..d89d925caec 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c | |||
@@ -61,6 +61,7 @@ struct jmb38x_ms_host { | |||
61 | struct memstick_request *req; | 61 | struct memstick_request *req; |
62 | unsigned char cmd_flags; | 62 | unsigned char cmd_flags; |
63 | unsigned char io_pos; | 63 | unsigned char io_pos; |
64 | unsigned char ifmode; | ||
64 | unsigned int io_word[2]; | 65 | unsigned int io_word[2]; |
65 | }; | 66 | }; |
66 | 67 | ||
@@ -136,15 +137,14 @@ struct jmb38x_ms { | |||
136 | #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 | 137 | #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 |
137 | #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 | 138 | #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 |
138 | 139 | ||
140 | #define CLOCK_CONTROL_BY_MMIO 0x00000008 | ||
139 | #define CLOCK_CONTROL_40MHZ 0x00000001 | 141 | #define CLOCK_CONTROL_40MHZ 0x00000001 |
140 | #define CLOCK_CONTROL_50MHZ 0x0000000a | 142 | #define CLOCK_CONTROL_50MHZ 0x00000002 |
141 | #define CLOCK_CONTROL_60MHZ 0x00000008 | 143 | #define CLOCK_CONTROL_60MHZ 0x00000010 |
142 | #define CLOCK_CONTROL_62_5MHZ 0x0000000c | 144 | #define CLOCK_CONTROL_62_5MHZ 0x00000004 |
143 | #define CLOCK_CONTROL_OFF 0x00000000 | 145 | #define CLOCK_CONTROL_OFF 0x00000000 |
144 | 146 | ||
145 | #define PCI_CTL_CLOCK_DLY_ADDR 0x000000b0 | 147 | #define PCI_CTL_CLOCK_DLY_ADDR 0x000000b0 |
146 | #define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00 | ||
147 | #define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000 | ||
148 | 148 | ||
149 | enum { | 149 | enum { |
150 | CMD_READY = 0x01, | 150 | CMD_READY = 0x01, |
@@ -390,8 +390,13 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh) | |||
390 | 390 | ||
391 | if (host->req->data_dir == READ) | 391 | if (host->req->data_dir == READ) |
392 | cmd |= TPC_DIR; | 392 | cmd |= TPC_DIR; |
393 | if (host->req->need_card_int) | 393 | |
394 | cmd |= TPC_WAIT_INT; | 394 | if (host->req->need_card_int) { |
395 | if (host->ifmode == MEMSTICK_SERIAL) | ||
396 | cmd |= TPC_GET_INT; | ||
397 | else | ||
398 | cmd |= TPC_WAIT_INT; | ||
399 | } | ||
395 | 400 | ||
396 | data = host->req->data; | 401 | data = host->req->data; |
397 | 402 | ||
@@ -529,7 +534,10 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) | |||
529 | if (irq_status & INT_STATUS_ANY_ERR) { | 534 | if (irq_status & INT_STATUS_ANY_ERR) { |
530 | if (irq_status & INT_STATUS_CRC_ERR) | 535 | if (irq_status & INT_STATUS_CRC_ERR) |
531 | host->req->error = -EILSEQ; | 536 | host->req->error = -EILSEQ; |
532 | else | 537 | else if (irq_status & INT_STATUS_TPC_ERR) { |
538 | dev_dbg(&host->chip->pdev->dev, "TPC_ERR\n"); | ||
539 | jmb38x_ms_complete_cmd(msh, 0); | ||
540 | } else | ||
533 | host->req->error = -ETIME; | 541 | host->req->error = -ETIME; |
534 | } else { | 542 | } else { |
535 | if (host->cmd_flags & DMA_DATA) { | 543 | if (host->cmd_flags & DMA_DATA) { |
@@ -644,7 +652,6 @@ static int jmb38x_ms_reset(struct jmb38x_ms_host *host) | |||
644 | ndelay(20); | 652 | ndelay(20); |
645 | } | 653 | } |
646 | dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n"); | 654 | dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n"); |
647 | /* return -EIO; */ | ||
648 | 655 | ||
649 | reset_next: | 656 | reset_next: |
650 | writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN | 657 | writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN |
@@ -675,7 +682,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, | |||
675 | { | 682 | { |
676 | struct jmb38x_ms_host *host = memstick_priv(msh); | 683 | struct jmb38x_ms_host *host = memstick_priv(msh); |
677 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); | 684 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); |
678 | unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; | 685 | unsigned int clock_ctl = CLOCK_CONTROL_BY_MMIO, clock_delay = 0; |
679 | int rc = 0; | 686 | int rc = 0; |
680 | 687 | ||
681 | switch (param) { | 688 | switch (param) { |
@@ -687,9 +694,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, | |||
687 | 694 | ||
688 | host_ctl = 7; | 695 | host_ctl = 7; |
689 | host_ctl |= HOST_CONTROL_POWER_EN | 696 | host_ctl |= HOST_CONTROL_POWER_EN |
690 | | HOST_CONTROL_CLOCK_EN | 697 | | HOST_CONTROL_CLOCK_EN; |
691 | | HOST_CONTROL_HW_OC_P | ||
692 | | HOST_CONTROL_TDELAY_EN; | ||
693 | writel(host_ctl, host->addr + HOST_CONTROL); | 698 | writel(host_ctl, host->addr + HOST_CONTROL); |
694 | 699 | ||
695 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 | 700 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 |
@@ -712,46 +717,88 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, | |||
712 | return -EINVAL; | 717 | return -EINVAL; |
713 | break; | 718 | break; |
714 | case MEMSTICK_INTERFACE: | 719 | case MEMSTICK_INTERFACE: |
720 | dev_dbg(&host->chip->pdev->dev, | ||
721 | "Set Host Interface Mode to %d\n", value); | ||
722 | host_ctl &= ~(HOST_CONTROL_FAST_CLK | HOST_CONTROL_REI | | ||
723 | HOST_CONTROL_REO); | ||
724 | host_ctl |= HOST_CONTROL_TDELAY_EN | HOST_CONTROL_HW_OC_P; | ||
715 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); | 725 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); |
716 | pci_read_config_dword(host->chip->pdev, | ||
717 | PCI_CTL_CLOCK_DLY_ADDR, | ||
718 | &clock_delay); | ||
719 | clock_delay &= host->id ? ~PCI_CTL_CLOCK_DLY_MASK_B | ||
720 | : ~PCI_CTL_CLOCK_DLY_MASK_A; | ||
721 | 726 | ||
722 | if (value == MEMSTICK_SERIAL) { | 727 | if (value == MEMSTICK_SERIAL) { |
723 | host_ctl &= ~HOST_CONTROL_FAST_CLK; | ||
724 | host_ctl &= ~HOST_CONTROL_REO; | ||
725 | host_ctl |= HOST_CONTROL_IF_SERIAL | 728 | host_ctl |= HOST_CONTROL_IF_SERIAL |
726 | << HOST_CONTROL_IF_SHIFT; | 729 | << HOST_CONTROL_IF_SHIFT; |
727 | host_ctl |= HOST_CONTROL_REI; | 730 | host_ctl |= HOST_CONTROL_REI; |
728 | clock_ctl = CLOCK_CONTROL_40MHZ; | 731 | clock_ctl |= CLOCK_CONTROL_40MHZ; |
732 | clock_delay = 0; | ||
729 | } else if (value == MEMSTICK_PAR4) { | 733 | } else if (value == MEMSTICK_PAR4) { |
730 | host_ctl |= HOST_CONTROL_FAST_CLK | HOST_CONTROL_REO; | 734 | host_ctl |= HOST_CONTROL_FAST_CLK; |
731 | host_ctl |= HOST_CONTROL_IF_PAR4 | 735 | host_ctl |= HOST_CONTROL_IF_PAR4 |
732 | << HOST_CONTROL_IF_SHIFT; | 736 | << HOST_CONTROL_IF_SHIFT; |
733 | host_ctl &= ~HOST_CONTROL_REI; | 737 | host_ctl |= HOST_CONTROL_REO; |
734 | clock_ctl = CLOCK_CONTROL_40MHZ; | 738 | clock_ctl |= CLOCK_CONTROL_40MHZ; |
735 | clock_delay |= host->id ? (4 << 12) : (4 << 8); | 739 | clock_delay = 4; |
736 | } else if (value == MEMSTICK_PAR8) { | 740 | } else if (value == MEMSTICK_PAR8) { |
737 | host_ctl |= HOST_CONTROL_FAST_CLK; | 741 | host_ctl |= HOST_CONTROL_FAST_CLK; |
738 | host_ctl |= HOST_CONTROL_IF_PAR8 | 742 | host_ctl |= HOST_CONTROL_IF_PAR8 |
739 | << HOST_CONTROL_IF_SHIFT; | 743 | << HOST_CONTROL_IF_SHIFT; |
740 | host_ctl &= ~(HOST_CONTROL_REI | HOST_CONTROL_REO); | 744 | clock_ctl |= CLOCK_CONTROL_50MHZ; |
741 | clock_ctl = CLOCK_CONTROL_50MHZ; | 745 | clock_delay = 0; |
742 | } else | 746 | } else |
743 | return -EINVAL; | 747 | return -EINVAL; |
744 | 748 | ||
745 | writel(host_ctl, host->addr + HOST_CONTROL); | 749 | writel(host_ctl, host->addr + HOST_CONTROL); |
750 | writel(CLOCK_CONTROL_OFF, host->addr + CLOCK_CONTROL); | ||
746 | writel(clock_ctl, host->addr + CLOCK_CONTROL); | 751 | writel(clock_ctl, host->addr + CLOCK_CONTROL); |
747 | pci_write_config_dword(host->chip->pdev, | 752 | pci_write_config_byte(host->chip->pdev, |
748 | PCI_CTL_CLOCK_DLY_ADDR, | 753 | PCI_CTL_CLOCK_DLY_ADDR + 1, |
749 | clock_delay); | 754 | clock_delay); |
755 | host->ifmode = value; | ||
750 | break; | 756 | break; |
751 | }; | 757 | }; |
752 | return 0; | 758 | return 0; |
753 | } | 759 | } |
754 | 760 | ||
761 | #define PCI_PMOS0_CONTROL 0xae | ||
762 | #define PMOS0_ENABLE 0x01 | ||
763 | #define PMOS0_OVERCURRENT_LEVEL_2_4V 0x06 | ||
764 | #define PMOS0_EN_OVERCURRENT_DEBOUNCE 0x40 | ||
765 | #define PMOS0_SW_LED_POLARITY_ENABLE 0x80 | ||
766 | #define PMOS0_ACTIVE_BITS (PMOS0_ENABLE | PMOS0_EN_OVERCURRENT_DEBOUNCE | \ | ||
767 | PMOS0_OVERCURRENT_LEVEL_2_4V) | ||
768 | #define PCI_PMOS1_CONTROL 0xbd | ||
769 | #define PMOS1_ACTIVE_BITS 0x4a | ||
770 | #define PCI_CLOCK_CTL 0xb9 | ||
771 | |||
772 | static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag) | ||
773 | { | ||
774 | unsigned char val; | ||
775 | |||
776 | pci_read_config_byte(pdev, PCI_PMOS0_CONTROL, &val); | ||
777 | if (flag) | ||
778 | val |= PMOS0_ACTIVE_BITS; | ||
779 | else | ||
780 | val &= ~PMOS0_ACTIVE_BITS; | ||
781 | pci_write_config_byte(pdev, PCI_PMOS0_CONTROL, val); | ||
782 | dev_dbg(&pdev->dev, "JMB38x: set PMOS0 val 0x%x\n", val); | ||
783 | |||
784 | if (pci_resource_flags(pdev, 1)) { | ||
785 | pci_read_config_byte(pdev, PCI_PMOS1_CONTROL, &val); | ||
786 | if (flag) | ||
787 | val |= PMOS1_ACTIVE_BITS; | ||
788 | else | ||
789 | val &= ~PMOS1_ACTIVE_BITS; | ||
790 | pci_write_config_byte(pdev, PCI_PMOS1_CONTROL, val); | ||
791 | dev_dbg(&pdev->dev, "JMB38x: set PMOS1 val 0x%x\n", val); | ||
792 | } | ||
793 | |||
794 | pci_read_config_byte(pdev, PCI_CLOCK_CTL, &val); | ||
795 | pci_write_config_byte(pdev, PCI_CLOCK_CTL, val & ~0x0f); | ||
796 | pci_write_config_byte(pdev, PCI_CLOCK_CTL, val | 0x01); | ||
797 | dev_dbg(&pdev->dev, "Clock Control by PCI config is disabled!\n"); | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
755 | #ifdef CONFIG_PM | 802 | #ifdef CONFIG_PM |
756 | 803 | ||
757 | static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) | 804 | static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) |
@@ -784,8 +831,7 @@ static int jmb38x_ms_resume(struct pci_dev *dev) | |||
784 | return rc; | 831 | return rc; |
785 | pci_set_master(dev); | 832 | pci_set_master(dev); |
786 | 833 | ||
787 | pci_read_config_dword(dev, 0xac, &rc); | 834 | jmb38x_ms_pmos(dev, 1); |
788 | pci_write_config_dword(dev, 0xac, rc | 0x00470000); | ||
789 | 835 | ||
790 | for (rc = 0; rc < jm->host_cnt; ++rc) { | 836 | for (rc = 0; rc < jm->host_cnt; ++rc) { |
791 | if (!jm->hosts[rc]) | 837 | if (!jm->hosts[rc]) |
@@ -894,8 +940,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev, | |||
894 | goto err_out; | 940 | goto err_out; |
895 | } | 941 | } |
896 | 942 | ||
897 | pci_read_config_dword(pdev, 0xac, &rc); | 943 | jmb38x_ms_pmos(pdev, 1); |
898 | pci_write_config_dword(pdev, 0xac, rc | 0x00470000); | ||
899 | 944 | ||
900 | cnt = jmb38x_ms_count_slots(pdev); | 945 | cnt = jmb38x_ms_count_slots(pdev); |
901 | if (!cnt) { | 946 | if (!cnt) { |
@@ -976,6 +1021,8 @@ static void jmb38x_ms_remove(struct pci_dev *dev) | |||
976 | jmb38x_ms_free_host(jm->hosts[cnt]); | 1021 | jmb38x_ms_free_host(jm->hosts[cnt]); |
977 | } | 1022 | } |
978 | 1023 | ||
1024 | jmb38x_ms_pmos(dev, 0); | ||
1025 | |||
979 | pci_set_drvdata(dev, NULL); | 1026 | pci_set_drvdata(dev, NULL); |
980 | pci_release_regions(dev); | 1027 | pci_release_regions(dev); |
981 | pci_disable_device(dev); | 1028 | pci_disable_device(dev); |
@@ -983,8 +1030,9 @@ static void jmb38x_ms_remove(struct pci_dev *dev) | |||
983 | } | 1030 | } |
984 | 1031 | ||
985 | static struct pci_device_id jmb38x_ms_id_tbl [] = { | 1032 | static struct pci_device_id jmb38x_ms_id_tbl [] = { |
986 | { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID, | 1033 | { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS) }, |
987 | PCI_ANY_ID, 0, 0, 0 }, | 1034 | { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB385_MS) }, |
1035 | { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB390_MS) }, | ||
988 | { } | 1036 | { } |
989 | }; | 1037 | }; |
990 | 1038 | ||