diff options
Diffstat (limited to 'drivers/mmc/tifm_sd.c')
-rw-r--r-- | drivers/mmc/tifm_sd.c | 205 |
1 files changed, 110 insertions, 95 deletions
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 5817a138a1e4..85a5974318b4 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c | |||
@@ -79,7 +79,6 @@ typedef enum { | |||
79 | 79 | ||
80 | enum { | 80 | enum { |
81 | FIFO_RDY = 0x0001, /* hardware dependent value */ | 81 | FIFO_RDY = 0x0001, /* hardware dependent value */ |
82 | HOST_REG = 0x0002, | ||
83 | EJECT = 0x0004, | 82 | EJECT = 0x0004, |
84 | EJECT_DONE = 0x0008, | 83 | EJECT_DONE = 0x0008, |
85 | CARD_BUSY = 0x0010, | 84 | CARD_BUSY = 0x0010, |
@@ -97,10 +96,10 @@ struct tifm_sd { | |||
97 | unsigned int clk_div; | 96 | unsigned int clk_div; |
98 | unsigned long timeout_jiffies; | 97 | unsigned long timeout_jiffies; |
99 | 98 | ||
99 | struct tasklet_struct finish_tasklet; | ||
100 | struct timer_list timer; | 100 | struct timer_list timer; |
101 | struct mmc_request *req; | 101 | struct mmc_request *req; |
102 | struct work_struct cmd_handler; | 102 | wait_queue_head_t notify; |
103 | wait_queue_head_t can_eject; | ||
104 | 103 | ||
105 | size_t written_blocks; | 104 | size_t written_blocks; |
106 | size_t buffer_size; | 105 | size_t buffer_size; |
@@ -317,7 +316,7 @@ change_state: | |||
317 | } | 316 | } |
318 | break; | 317 | break; |
319 | case READY: | 318 | case READY: |
320 | queue_work(sock->wq, &host->cmd_handler); | 319 | tasklet_schedule(&host->finish_tasklet); |
321 | return; | 320 | return; |
322 | } | 321 | } |
323 | 322 | ||
@@ -345,8 +344,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, | |||
345 | host_status = readl(sock->addr + SOCK_MMCSD_STATUS); | 344 | host_status = readl(sock->addr + SOCK_MMCSD_STATUS); |
346 | writel(host_status, sock->addr + SOCK_MMCSD_STATUS); | 345 | writel(host_status, sock->addr + SOCK_MMCSD_STATUS); |
347 | 346 | ||
348 | if (!(host->flags & HOST_REG)) | ||
349 | queue_work(sock->wq, &host->cmd_handler); | ||
350 | if (!host->req) | 347 | if (!host->req) |
351 | goto done; | 348 | goto done; |
352 | 349 | ||
@@ -517,9 +514,9 @@ err_out: | |||
517 | mmc_request_done(mmc, mrq); | 514 | mmc_request_done(mmc, mrq); |
518 | } | 515 | } |
519 | 516 | ||
520 | static void tifm_sd_end_cmd(struct work_struct *work) | 517 | static void tifm_sd_end_cmd(unsigned long data) |
521 | { | 518 | { |
522 | struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); | 519 | struct tifm_sd *host = (struct tifm_sd*)data; |
523 | struct tifm_dev *sock = host->dev; | 520 | struct tifm_dev *sock = host->dev; |
524 | struct mmc_host *mmc = tifm_get_drvdata(sock); | 521 | struct mmc_host *mmc = tifm_get_drvdata(sock); |
525 | struct mmc_request *mrq; | 522 | struct mmc_request *mrq; |
@@ -616,9 +613,9 @@ err_out: | |||
616 | mmc_request_done(mmc, mrq); | 613 | mmc_request_done(mmc, mrq); |
617 | } | 614 | } |
618 | 615 | ||
619 | static void tifm_sd_end_cmd_nodma(struct work_struct *work) | 616 | static void tifm_sd_end_cmd_nodma(unsigned long data) |
620 | { | 617 | { |
621 | struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); | 618 | struct tifm_sd *host = (struct tifm_sd*)data; |
622 | struct tifm_dev *sock = host->dev; | 619 | struct tifm_dev *sock = host->dev; |
623 | struct mmc_host *mmc = tifm_get_drvdata(sock); | 620 | struct mmc_host *mmc = tifm_get_drvdata(sock); |
624 | struct mmc_request *mrq; | 621 | struct mmc_request *mrq; |
@@ -666,11 +663,33 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) | |||
666 | mmc_request_done(mmc, mrq); | 663 | mmc_request_done(mmc, mrq); |
667 | } | 664 | } |
668 | 665 | ||
666 | static void tifm_sd_terminate(struct tifm_sd *host) | ||
667 | { | ||
668 | struct tifm_dev *sock = host->dev; | ||
669 | unsigned long flags; | ||
670 | |||
671 | writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); | ||
672 | mmiowb(); | ||
673 | spin_lock_irqsave(&sock->lock, flags); | ||
674 | host->flags |= EJECT; | ||
675 | if (host->req) { | ||
676 | writel(TIFM_FIFO_INT_SETALL, | ||
677 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); | ||
678 | writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); | ||
679 | tasklet_schedule(&host->finish_tasklet); | ||
680 | } | ||
681 | spin_unlock_irqrestore(&sock->lock, flags); | ||
682 | } | ||
683 | |||
669 | static void tifm_sd_abort(unsigned long data) | 684 | static void tifm_sd_abort(unsigned long data) |
670 | { | 685 | { |
686 | struct tifm_sd *host = (struct tifm_sd*)data; | ||
687 | |||
671 | printk(KERN_ERR DRIVER_NAME | 688 | printk(KERN_ERR DRIVER_NAME |
672 | ": card failed to respond for a long period of time"); | 689 | ": card failed to respond for a long period of time"); |
673 | tifm_eject(((struct tifm_sd*)data)->dev); | 690 | |
691 | tifm_sd_terminate(host); | ||
692 | tifm_eject(host->dev); | ||
674 | } | 693 | } |
675 | 694 | ||
676 | static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 695 | static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
@@ -739,7 +758,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
739 | // allow removal. | 758 | // allow removal. |
740 | if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { | 759 | if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { |
741 | host->flags |= EJECT_DONE; | 760 | host->flags |= EJECT_DONE; |
742 | wake_up_all(&host->can_eject); | 761 | wake_up_all(&host->notify); |
743 | } | 762 | } |
744 | 763 | ||
745 | spin_unlock_irqrestore(&sock->lock, flags); | 764 | spin_unlock_irqrestore(&sock->lock, flags); |
@@ -767,21 +786,67 @@ static struct mmc_host_ops tifm_sd_ops = { | |||
767 | .get_ro = tifm_sd_ro | 786 | .get_ro = tifm_sd_ro |
768 | }; | 787 | }; |
769 | 788 | ||
770 | static void tifm_sd_register_host(struct work_struct *work) | 789 | static int tifm_sd_initialize_host(struct tifm_sd *host) |
771 | { | 790 | { |
772 | struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); | 791 | int rc; |
792 | unsigned int host_status = 0; | ||
773 | struct tifm_dev *sock = host->dev; | 793 | struct tifm_dev *sock = host->dev; |
774 | struct mmc_host *mmc = tifm_get_drvdata(sock); | ||
775 | unsigned long flags; | ||
776 | 794 | ||
777 | spin_lock_irqsave(&sock->lock, flags); | 795 | writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); |
778 | del_timer(&host->timer); | 796 | mmiowb(); |
779 | host->flags |= HOST_REG; | 797 | host->clk_div = 61; |
780 | PREPARE_WORK(&host->cmd_handler, | 798 | host->clk_freq = 20000000; |
781 | no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd); | 799 | writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); |
782 | spin_unlock_irqrestore(&sock->lock, flags); | 800 | writel(host->clk_div | TIFM_MMCSD_POWER, |
783 | dev_dbg(&sock->dev, "adding host\n"); | 801 | sock->addr + SOCK_MMCSD_CONFIG); |
784 | mmc_add_host(mmc); | 802 | |
803 | /* wait up to 0.51 sec for reset */ | ||
804 | for (rc = 2; rc <= 256; rc <<= 1) { | ||
805 | if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { | ||
806 | rc = 0; | ||
807 | break; | ||
808 | } | ||
809 | msleep(rc); | ||
810 | } | ||
811 | |||
812 | if (rc) { | ||
813 | printk(KERN_ERR DRIVER_NAME | ||
814 | ": controller failed to reset\n"); | ||
815 | return -ENODEV; | ||
816 | } | ||
817 | |||
818 | writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); | ||
819 | writel(host->clk_div | TIFM_MMCSD_POWER, | ||
820 | sock->addr + SOCK_MMCSD_CONFIG); | ||
821 | writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); | ||
822 | |||
823 | // command timeout fixed to 64 clocks for now | ||
824 | writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); | ||
825 | writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); | ||
826 | |||
827 | /* INAB should take much less than reset */ | ||
828 | for (rc = 1; rc <= 16; rc <<= 1) { | ||
829 | host_status = readl(sock->addr + SOCK_MMCSD_STATUS); | ||
830 | writel(host_status, sock->addr + SOCK_MMCSD_STATUS); | ||
831 | if (!(host_status & TIFM_MMCSD_ERRMASK) | ||
832 | && (host_status & TIFM_MMCSD_EOC)) { | ||
833 | rc = 0; | ||
834 | break; | ||
835 | } | ||
836 | msleep(rc); | ||
837 | } | ||
838 | |||
839 | if (rc) { | ||
840 | printk(KERN_ERR DRIVER_NAME | ||
841 | ": card not ready - probe failed on initialization\n"); | ||
842 | return -ENODEV; | ||
843 | } | ||
844 | |||
845 | writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, | ||
846 | sock->addr + SOCK_MMCSD_INT_ENABLE); | ||
847 | mmiowb(); | ||
848 | |||
849 | return 0; | ||
785 | } | 850 | } |
786 | 851 | ||
787 | static int tifm_sd_probe(struct tifm_dev *sock) | 852 | static int tifm_sd_probe(struct tifm_dev *sock) |
@@ -801,77 +866,37 @@ static int tifm_sd_probe(struct tifm_dev *sock) | |||
801 | return -ENOMEM; | 866 | return -ENOMEM; |
802 | 867 | ||
803 | host = mmc_priv(mmc); | 868 | host = mmc_priv(mmc); |
804 | host->dev = sock; | ||
805 | host->clk_div = 61; | ||
806 | init_waitqueue_head(&host->can_eject); | ||
807 | INIT_WORK(&host->cmd_handler, tifm_sd_register_host); | ||
808 | setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); | ||
809 | |||
810 | tifm_set_drvdata(sock, mmc); | 869 | tifm_set_drvdata(sock, mmc); |
811 | sock->signal_irq = tifm_sd_signal_irq; | 870 | host->dev = sock; |
812 | |||
813 | host->clk_freq = 20000000; | ||
814 | host->timeout_jiffies = msecs_to_jiffies(1000); | 871 | host->timeout_jiffies = msecs_to_jiffies(1000); |
815 | 872 | ||
873 | init_waitqueue_head(&host->notify); | ||
874 | tasklet_init(&host->finish_tasklet, | ||
875 | no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, | ||
876 | (unsigned long)host); | ||
877 | setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); | ||
878 | |||
816 | tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; | 879 | tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; |
817 | mmc->ops = &tifm_sd_ops; | 880 | mmc->ops = &tifm_sd_ops; |
818 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | 881 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; |
819 | mmc->caps = MMC_CAP_4_BIT_DATA; | 882 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; |
820 | mmc->f_min = 20000000 / 60; | 883 | mmc->f_min = 20000000 / 60; |
821 | mmc->f_max = 24000000; | 884 | mmc->f_max = 24000000; |
822 | mmc->max_hw_segs = 1; | 885 | mmc->max_hw_segs = 1; |
823 | mmc->max_phys_segs = 1; | 886 | mmc->max_phys_segs = 1; |
824 | mmc->max_sectors = 127; | 887 | mmc->max_sectors = 127; |
825 | mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length | 888 | mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length |
889 | sock->signal_irq = tifm_sd_signal_irq; | ||
890 | rc = tifm_sd_initialize_host(host); | ||
826 | 891 | ||
827 | writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); | 892 | if (!rc) |
828 | writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); | 893 | rc = mmc_add_host(mmc); |
829 | writel(host->clk_div | TIFM_MMCSD_POWER, | 894 | if (rc) |
830 | sock->addr + SOCK_MMCSD_CONFIG); | 895 | goto out_free_mmc; |
831 | |||
832 | for (rc = 0; rc < 50; rc++) { | ||
833 | /* Wait for reset ack */ | ||
834 | if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { | ||
835 | rc = 0; | ||
836 | break; | ||
837 | } | ||
838 | msleep(10); | ||
839 | } | ||
840 | |||
841 | if (rc) { | ||
842 | printk(KERN_ERR DRIVER_NAME | ||
843 | ": card not ready - probe failed\n"); | ||
844 | mmc_free_host(mmc); | ||
845 | return -ENODEV; | ||
846 | } | ||
847 | |||
848 | writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); | ||
849 | writel(host->clk_div | TIFM_MMCSD_POWER, | ||
850 | sock->addr + SOCK_MMCSD_CONFIG); | ||
851 | writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); | ||
852 | writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, | ||
853 | sock->addr + SOCK_MMCSD_INT_ENABLE); | ||
854 | |||
855 | writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now | ||
856 | writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); | ||
857 | writel(host->clk_div | TIFM_MMCSD_POWER, | ||
858 | sock->addr + SOCK_MMCSD_CONFIG); | ||
859 | |||
860 | mod_timer(&host->timer, jiffies + host->timeout_jiffies); | ||
861 | 896 | ||
862 | return 0; | 897 | return 0; |
863 | } | 898 | out_free_mmc: |
864 | 899 | mmc_free_host(mmc); | |
865 | static int tifm_sd_host_is_down(struct tifm_dev *sock) | ||
866 | { | ||
867 | struct mmc_host *mmc = tifm_get_drvdata(sock); | ||
868 | struct tifm_sd *host = mmc_priv(mmc); | ||
869 | unsigned long flags; | ||
870 | int rc = 0; | ||
871 | |||
872 | spin_lock_irqsave(&sock->lock, flags); | ||
873 | rc = (host->flags & EJECT_DONE); | ||
874 | spin_unlock_irqrestore(&sock->lock, flags); | ||
875 | return rc; | 900 | return rc; |
876 | } | 901 | } |
877 | 902 | ||
@@ -879,27 +904,17 @@ static void tifm_sd_remove(struct tifm_dev *sock) | |||
879 | { | 904 | { |
880 | struct mmc_host *mmc = tifm_get_drvdata(sock); | 905 | struct mmc_host *mmc = tifm_get_drvdata(sock); |
881 | struct tifm_sd *host = mmc_priv(mmc); | 906 | struct tifm_sd *host = mmc_priv(mmc); |
882 | unsigned long flags; | ||
883 | 907 | ||
884 | del_timer_sync(&host->timer); | 908 | del_timer_sync(&host->timer); |
885 | spin_lock_irqsave(&sock->lock, flags); | 909 | tifm_sd_terminate(host); |
886 | host->flags |= EJECT; | 910 | wait_event_timeout(host->notify, host->flags & EJECT_DONE, |
887 | if (host->req) | 911 | host->timeout_jiffies); |
888 | queue_work(sock->wq, &host->cmd_handler); | 912 | tasklet_kill(&host->finish_tasklet); |
889 | spin_unlock_irqrestore(&sock->lock, flags); | 913 | mmc_remove_host(mmc); |
890 | wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock), | ||
891 | host->timeout_jiffies); | ||
892 | |||
893 | if (host->flags & HOST_REG) | ||
894 | mmc_remove_host(mmc); | ||
895 | 914 | ||
896 | /* The meaning of the bit majority in this constant is unknown. */ | 915 | /* The meaning of the bit majority in this constant is unknown. */ |
897 | writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), | 916 | writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), |
898 | sock->addr + SOCK_CONTROL); | 917 | sock->addr + SOCK_CONTROL); |
899 | writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); | ||
900 | writel(TIFM_FIFO_INT_SETALL, | ||
901 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); | ||
902 | writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); | ||
903 | 918 | ||
904 | tifm_set_drvdata(sock, NULL); | 919 | tifm_set_drvdata(sock, NULL); |
905 | mmc_free_host(mmc); | 920 | mmc_free_host(mmc); |