diff options
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r-- | drivers/usb/otg/msm_otg.c | 380 |
1 files changed, 376 insertions, 4 deletions
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c index 7792fef0be5e..854b7e3413dd 100644 --- a/drivers/usb/otg/msm_otg.c +++ b/drivers/usb/otg/msm_otg.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. | 1 | /* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. |
2 | * | 2 | * |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License version 2 and | 4 | * it under the terms of the GNU General Public License version 2 and |
@@ -409,6 +409,33 @@ skip_phy_resume: | |||
409 | } | 409 | } |
410 | #endif | 410 | #endif |
411 | 411 | ||
412 | static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA) | ||
413 | { | ||
414 | if (motg->cur_power == mA) | ||
415 | return; | ||
416 | |||
417 | /* TODO: Notify PMIC about available current */ | ||
418 | dev_info(motg->otg.dev, "Avail curr from USB = %u\n", mA); | ||
419 | motg->cur_power = mA; | ||
420 | } | ||
421 | |||
422 | static int msm_otg_set_power(struct otg_transceiver *otg, unsigned mA) | ||
423 | { | ||
424 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
425 | |||
426 | /* | ||
427 | * Gadget driver uses set_power method to notify about the | ||
428 | * available current based on suspend/configured states. | ||
429 | * | ||
430 | * IDEV_CHG can be drawn irrespective of suspend/un-configured | ||
431 | * states when CDP/ACA is connected. | ||
432 | */ | ||
433 | if (motg->chg_type == USB_SDP_CHARGER) | ||
434 | msm_otg_notify_charger(motg, mA); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
412 | static void msm_otg_start_host(struct otg_transceiver *otg, int on) | 439 | static void msm_otg_start_host(struct otg_transceiver *otg, int on) |
413 | { | 440 | { |
414 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | 441 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); |
@@ -563,6 +590,306 @@ static int msm_otg_set_peripheral(struct otg_transceiver *otg, | |||
563 | return 0; | 590 | return 0; |
564 | } | 591 | } |
565 | 592 | ||
593 | static bool msm_chg_check_secondary_det(struct msm_otg *motg) | ||
594 | { | ||
595 | struct otg_transceiver *otg = &motg->otg; | ||
596 | u32 chg_det; | ||
597 | bool ret = false; | ||
598 | |||
599 | switch (motg->pdata->phy_type) { | ||
600 | case CI_45NM_INTEGRATED_PHY: | ||
601 | chg_det = ulpi_read(otg, 0x34); | ||
602 | ret = chg_det & (1 << 4); | ||
603 | break; | ||
604 | case SNPS_28NM_INTEGRATED_PHY: | ||
605 | chg_det = ulpi_read(otg, 0x87); | ||
606 | ret = chg_det & 1; | ||
607 | break; | ||
608 | default: | ||
609 | break; | ||
610 | } | ||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | static void msm_chg_enable_secondary_det(struct msm_otg *motg) | ||
615 | { | ||
616 | struct otg_transceiver *otg = &motg->otg; | ||
617 | u32 chg_det; | ||
618 | |||
619 | switch (motg->pdata->phy_type) { | ||
620 | case CI_45NM_INTEGRATED_PHY: | ||
621 | chg_det = ulpi_read(otg, 0x34); | ||
622 | /* Turn off charger block */ | ||
623 | chg_det |= ~(1 << 1); | ||
624 | ulpi_write(otg, chg_det, 0x34); | ||
625 | udelay(20); | ||
626 | /* control chg block via ULPI */ | ||
627 | chg_det &= ~(1 << 3); | ||
628 | ulpi_write(otg, chg_det, 0x34); | ||
629 | /* put it in host mode for enabling D- source */ | ||
630 | chg_det &= ~(1 << 2); | ||
631 | ulpi_write(otg, chg_det, 0x34); | ||
632 | /* Turn on chg detect block */ | ||
633 | chg_det &= ~(1 << 1); | ||
634 | ulpi_write(otg, chg_det, 0x34); | ||
635 | udelay(20); | ||
636 | /* enable chg detection */ | ||
637 | chg_det &= ~(1 << 0); | ||
638 | ulpi_write(otg, chg_det, 0x34); | ||
639 | break; | ||
640 | case SNPS_28NM_INTEGRATED_PHY: | ||
641 | /* | ||
642 | * Configure DM as current source, DP as current sink | ||
643 | * and enable battery charging comparators. | ||
644 | */ | ||
645 | ulpi_write(otg, 0x8, 0x85); | ||
646 | ulpi_write(otg, 0x2, 0x85); | ||
647 | ulpi_write(otg, 0x1, 0x85); | ||
648 | break; | ||
649 | default: | ||
650 | break; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | static bool msm_chg_check_primary_det(struct msm_otg *motg) | ||
655 | { | ||
656 | struct otg_transceiver *otg = &motg->otg; | ||
657 | u32 chg_det; | ||
658 | bool ret = false; | ||
659 | |||
660 | switch (motg->pdata->phy_type) { | ||
661 | case CI_45NM_INTEGRATED_PHY: | ||
662 | chg_det = ulpi_read(otg, 0x34); | ||
663 | ret = chg_det & (1 << 4); | ||
664 | break; | ||
665 | case SNPS_28NM_INTEGRATED_PHY: | ||
666 | chg_det = ulpi_read(otg, 0x87); | ||
667 | ret = chg_det & 1; | ||
668 | break; | ||
669 | default: | ||
670 | break; | ||
671 | } | ||
672 | return ret; | ||
673 | } | ||
674 | |||
675 | static void msm_chg_enable_primary_det(struct msm_otg *motg) | ||
676 | { | ||
677 | struct otg_transceiver *otg = &motg->otg; | ||
678 | u32 chg_det; | ||
679 | |||
680 | switch (motg->pdata->phy_type) { | ||
681 | case CI_45NM_INTEGRATED_PHY: | ||
682 | chg_det = ulpi_read(otg, 0x34); | ||
683 | /* enable chg detection */ | ||
684 | chg_det &= ~(1 << 0); | ||
685 | ulpi_write(otg, chg_det, 0x34); | ||
686 | break; | ||
687 | case SNPS_28NM_INTEGRATED_PHY: | ||
688 | /* | ||
689 | * Configure DP as current source, DM as current sink | ||
690 | * and enable battery charging comparators. | ||
691 | */ | ||
692 | ulpi_write(otg, 0x2, 0x85); | ||
693 | ulpi_write(otg, 0x1, 0x85); | ||
694 | break; | ||
695 | default: | ||
696 | break; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | static bool msm_chg_check_dcd(struct msm_otg *motg) | ||
701 | { | ||
702 | struct otg_transceiver *otg = &motg->otg; | ||
703 | u32 line_state; | ||
704 | bool ret = false; | ||
705 | |||
706 | switch (motg->pdata->phy_type) { | ||
707 | case CI_45NM_INTEGRATED_PHY: | ||
708 | line_state = ulpi_read(otg, 0x15); | ||
709 | ret = !(line_state & 1); | ||
710 | break; | ||
711 | case SNPS_28NM_INTEGRATED_PHY: | ||
712 | line_state = ulpi_read(otg, 0x87); | ||
713 | ret = line_state & 2; | ||
714 | break; | ||
715 | default: | ||
716 | break; | ||
717 | } | ||
718 | return ret; | ||
719 | } | ||
720 | |||
721 | static void msm_chg_disable_dcd(struct msm_otg *motg) | ||
722 | { | ||
723 | struct otg_transceiver *otg = &motg->otg; | ||
724 | u32 chg_det; | ||
725 | |||
726 | switch (motg->pdata->phy_type) { | ||
727 | case CI_45NM_INTEGRATED_PHY: | ||
728 | chg_det = ulpi_read(otg, 0x34); | ||
729 | chg_det &= ~(1 << 5); | ||
730 | ulpi_write(otg, chg_det, 0x34); | ||
731 | break; | ||
732 | case SNPS_28NM_INTEGRATED_PHY: | ||
733 | ulpi_write(otg, 0x10, 0x86); | ||
734 | break; | ||
735 | default: | ||
736 | break; | ||
737 | } | ||
738 | } | ||
739 | |||
740 | static void msm_chg_enable_dcd(struct msm_otg *motg) | ||
741 | { | ||
742 | struct otg_transceiver *otg = &motg->otg; | ||
743 | u32 chg_det; | ||
744 | |||
745 | switch (motg->pdata->phy_type) { | ||
746 | case CI_45NM_INTEGRATED_PHY: | ||
747 | chg_det = ulpi_read(otg, 0x34); | ||
748 | /* Turn on D+ current source */ | ||
749 | chg_det |= (1 << 5); | ||
750 | ulpi_write(otg, chg_det, 0x34); | ||
751 | break; | ||
752 | case SNPS_28NM_INTEGRATED_PHY: | ||
753 | /* Data contact detection enable */ | ||
754 | ulpi_write(otg, 0x10, 0x85); | ||
755 | break; | ||
756 | default: | ||
757 | break; | ||
758 | } | ||
759 | } | ||
760 | |||
761 | static void msm_chg_block_on(struct msm_otg *motg) | ||
762 | { | ||
763 | struct otg_transceiver *otg = &motg->otg; | ||
764 | u32 func_ctrl, chg_det; | ||
765 | |||
766 | /* put the controller in non-driving mode */ | ||
767 | func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL); | ||
768 | func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK; | ||
769 | func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; | ||
770 | ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL); | ||
771 | |||
772 | switch (motg->pdata->phy_type) { | ||
773 | case CI_45NM_INTEGRATED_PHY: | ||
774 | chg_det = ulpi_read(otg, 0x34); | ||
775 | /* control chg block via ULPI */ | ||
776 | chg_det &= ~(1 << 3); | ||
777 | ulpi_write(otg, chg_det, 0x34); | ||
778 | /* Turn on chg detect block */ | ||
779 | chg_det &= ~(1 << 1); | ||
780 | ulpi_write(otg, chg_det, 0x34); | ||
781 | udelay(20); | ||
782 | break; | ||
783 | case SNPS_28NM_INTEGRATED_PHY: | ||
784 | /* Clear charger detecting control bits */ | ||
785 | ulpi_write(otg, 0x3F, 0x86); | ||
786 | /* Clear alt interrupt latch and enable bits */ | ||
787 | ulpi_write(otg, 0x1F, 0x92); | ||
788 | ulpi_write(otg, 0x1F, 0x95); | ||
789 | udelay(100); | ||
790 | break; | ||
791 | default: | ||
792 | break; | ||
793 | } | ||
794 | } | ||
795 | |||
796 | static void msm_chg_block_off(struct msm_otg *motg) | ||
797 | { | ||
798 | struct otg_transceiver *otg = &motg->otg; | ||
799 | u32 func_ctrl, chg_det; | ||
800 | |||
801 | switch (motg->pdata->phy_type) { | ||
802 | case CI_45NM_INTEGRATED_PHY: | ||
803 | chg_det = ulpi_read(otg, 0x34); | ||
804 | /* Turn off charger block */ | ||
805 | chg_det |= ~(1 << 1); | ||
806 | ulpi_write(otg, chg_det, 0x34); | ||
807 | break; | ||
808 | case SNPS_28NM_INTEGRATED_PHY: | ||
809 | /* Clear charger detecting control bits */ | ||
810 | ulpi_write(otg, 0x3F, 0x86); | ||
811 | /* Clear alt interrupt latch and enable bits */ | ||
812 | ulpi_write(otg, 0x1F, 0x92); | ||
813 | ulpi_write(otg, 0x1F, 0x95); | ||
814 | break; | ||
815 | default: | ||
816 | break; | ||
817 | } | ||
818 | |||
819 | /* put the controller in normal mode */ | ||
820 | func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL); | ||
821 | func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK; | ||
822 | func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL; | ||
823 | ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL); | ||
824 | } | ||
825 | |||
826 | #define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */ | ||
827 | #define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */ | ||
828 | #define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */ | ||
829 | #define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */ | ||
830 | static void msm_chg_detect_work(struct work_struct *w) | ||
831 | { | ||
832 | struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work); | ||
833 | struct otg_transceiver *otg = &motg->otg; | ||
834 | bool is_dcd, tmout, vout; | ||
835 | unsigned long delay; | ||
836 | |||
837 | dev_dbg(otg->dev, "chg detection work\n"); | ||
838 | switch (motg->chg_state) { | ||
839 | case USB_CHG_STATE_UNDEFINED: | ||
840 | pm_runtime_get_sync(otg->dev); | ||
841 | msm_chg_block_on(motg); | ||
842 | msm_chg_enable_dcd(motg); | ||
843 | motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; | ||
844 | motg->dcd_retries = 0; | ||
845 | delay = MSM_CHG_DCD_POLL_TIME; | ||
846 | break; | ||
847 | case USB_CHG_STATE_WAIT_FOR_DCD: | ||
848 | is_dcd = msm_chg_check_dcd(motg); | ||
849 | tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES; | ||
850 | if (is_dcd || tmout) { | ||
851 | msm_chg_disable_dcd(motg); | ||
852 | msm_chg_enable_primary_det(motg); | ||
853 | delay = MSM_CHG_PRIMARY_DET_TIME; | ||
854 | motg->chg_state = USB_CHG_STATE_DCD_DONE; | ||
855 | } else { | ||
856 | delay = MSM_CHG_DCD_POLL_TIME; | ||
857 | } | ||
858 | break; | ||
859 | case USB_CHG_STATE_DCD_DONE: | ||
860 | vout = msm_chg_check_primary_det(motg); | ||
861 | if (vout) { | ||
862 | msm_chg_enable_secondary_det(motg); | ||
863 | delay = MSM_CHG_SECONDARY_DET_TIME; | ||
864 | motg->chg_state = USB_CHG_STATE_PRIMARY_DONE; | ||
865 | } else { | ||
866 | motg->chg_type = USB_SDP_CHARGER; | ||
867 | motg->chg_state = USB_CHG_STATE_DETECTED; | ||
868 | delay = 0; | ||
869 | } | ||
870 | break; | ||
871 | case USB_CHG_STATE_PRIMARY_DONE: | ||
872 | vout = msm_chg_check_secondary_det(motg); | ||
873 | if (vout) | ||
874 | motg->chg_type = USB_DCP_CHARGER; | ||
875 | else | ||
876 | motg->chg_type = USB_CDP_CHARGER; | ||
877 | motg->chg_state = USB_CHG_STATE_SECONDARY_DONE; | ||
878 | /* fall through */ | ||
879 | case USB_CHG_STATE_SECONDARY_DONE: | ||
880 | motg->chg_state = USB_CHG_STATE_DETECTED; | ||
881 | case USB_CHG_STATE_DETECTED: | ||
882 | msm_chg_block_off(motg); | ||
883 | dev_dbg(otg->dev, "charger = %d\n", motg->chg_type); | ||
884 | schedule_work(&motg->sm_work); | ||
885 | return; | ||
886 | default: | ||
887 | return; | ||
888 | } | ||
889 | |||
890 | schedule_delayed_work(&motg->chg_work, delay); | ||
891 | } | ||
892 | |||
566 | /* | 893 | /* |
567 | * We support OTG, Peripheral only and Host only configurations. In case | 894 | * We support OTG, Peripheral only and Host only configurations. In case |
568 | * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen | 895 | * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen |
@@ -633,9 +960,48 @@ static void msm_otg_sm_work(struct work_struct *w) | |||
633 | writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); | 960 | writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); |
634 | msm_otg_start_host(otg, 1); | 961 | msm_otg_start_host(otg, 1); |
635 | otg->state = OTG_STATE_A_HOST; | 962 | otg->state = OTG_STATE_A_HOST; |
636 | } else if (test_bit(B_SESS_VLD, &motg->inputs) && otg->gadget) { | 963 | } else if (test_bit(B_SESS_VLD, &motg->inputs)) { |
637 | msm_otg_start_peripheral(otg, 1); | 964 | switch (motg->chg_state) { |
638 | otg->state = OTG_STATE_B_PERIPHERAL; | 965 | case USB_CHG_STATE_UNDEFINED: |
966 | msm_chg_detect_work(&motg->chg_work.work); | ||
967 | break; | ||
968 | case USB_CHG_STATE_DETECTED: | ||
969 | switch (motg->chg_type) { | ||
970 | case USB_DCP_CHARGER: | ||
971 | msm_otg_notify_charger(motg, | ||
972 | IDEV_CHG_MAX); | ||
973 | break; | ||
974 | case USB_CDP_CHARGER: | ||
975 | msm_otg_notify_charger(motg, | ||
976 | IDEV_CHG_MAX); | ||
977 | msm_otg_start_peripheral(otg, 1); | ||
978 | otg->state = OTG_STATE_B_PERIPHERAL; | ||
979 | break; | ||
980 | case USB_SDP_CHARGER: | ||
981 | msm_otg_notify_charger(motg, IUNIT); | ||
982 | msm_otg_start_peripheral(otg, 1); | ||
983 | otg->state = OTG_STATE_B_PERIPHERAL; | ||
984 | break; | ||
985 | default: | ||
986 | break; | ||
987 | } | ||
988 | break; | ||
989 | default: | ||
990 | break; | ||
991 | } | ||
992 | } else { | ||
993 | /* | ||
994 | * If charger detection work is pending, decrement | ||
995 | * the pm usage counter to balance with the one that | ||
996 | * is incremented in charger detection work. | ||
997 | */ | ||
998 | if (cancel_delayed_work_sync(&motg->chg_work)) { | ||
999 | pm_runtime_put_sync(otg->dev); | ||
1000 | msm_otg_reset(otg); | ||
1001 | } | ||
1002 | msm_otg_notify_charger(motg, 0); | ||
1003 | motg->chg_state = USB_CHG_STATE_UNDEFINED; | ||
1004 | motg->chg_type = USB_INVALID_CHARGER; | ||
639 | } | 1005 | } |
640 | pm_runtime_put_sync(otg->dev); | 1006 | pm_runtime_put_sync(otg->dev); |
641 | break; | 1007 | break; |
@@ -643,7 +1009,10 @@ static void msm_otg_sm_work(struct work_struct *w) | |||
643 | dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n"); | 1009 | dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n"); |
644 | if (!test_bit(B_SESS_VLD, &motg->inputs) || | 1010 | if (!test_bit(B_SESS_VLD, &motg->inputs) || |
645 | !test_bit(ID, &motg->inputs)) { | 1011 | !test_bit(ID, &motg->inputs)) { |
1012 | msm_otg_notify_charger(motg, 0); | ||
646 | msm_otg_start_peripheral(otg, 0); | 1013 | msm_otg_start_peripheral(otg, 0); |
1014 | motg->chg_state = USB_CHG_STATE_UNDEFINED; | ||
1015 | motg->chg_type = USB_INVALID_CHARGER; | ||
647 | otg->state = OTG_STATE_B_IDLE; | 1016 | otg->state = OTG_STATE_B_IDLE; |
648 | msm_otg_reset(otg); | 1017 | msm_otg_reset(otg); |
649 | schedule_work(w); | 1018 | schedule_work(w); |
@@ -935,6 +1304,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) | |||
935 | writel(0, USB_OTGSC); | 1304 | writel(0, USB_OTGSC); |
936 | 1305 | ||
937 | INIT_WORK(&motg->sm_work, msm_otg_sm_work); | 1306 | INIT_WORK(&motg->sm_work, msm_otg_sm_work); |
1307 | INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work); | ||
938 | ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, | 1308 | ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, |
939 | "msm_otg", motg); | 1309 | "msm_otg", motg); |
940 | if (ret) { | 1310 | if (ret) { |
@@ -945,6 +1315,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) | |||
945 | otg->init = msm_otg_reset; | 1315 | otg->init = msm_otg_reset; |
946 | otg->set_host = msm_otg_set_host; | 1316 | otg->set_host = msm_otg_set_host; |
947 | otg->set_peripheral = msm_otg_set_peripheral; | 1317 | otg->set_peripheral = msm_otg_set_peripheral; |
1318 | otg->set_power = msm_otg_set_power; | ||
948 | 1319 | ||
949 | otg->io_ops = &msm_otg_io_ops; | 1320 | otg->io_ops = &msm_otg_io_ops; |
950 | 1321 | ||
@@ -1004,6 +1375,7 @@ static int __devexit msm_otg_remove(struct platform_device *pdev) | |||
1004 | return -EBUSY; | 1375 | return -EBUSY; |
1005 | 1376 | ||
1006 | msm_otg_debugfs_cleanup(); | 1377 | msm_otg_debugfs_cleanup(); |
1378 | cancel_delayed_work_sync(&motg->chg_work); | ||
1007 | cancel_work_sync(&motg->sm_work); | 1379 | cancel_work_sync(&motg->sm_work); |
1008 | 1380 | ||
1009 | pm_runtime_resume(&pdev->dev); | 1381 | pm_runtime_resume(&pdev->dev); |