aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorPavankumar Kondeti <pkondeti@codeaurora.org>2011-05-04 00:49:47 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-06 21:27:48 -0400
commitd860852e087eed7eadbea64f1a8db9a231c5e9b3 (patch)
tree792b7c6d3cfe769983929699bbd385e8985b668e /drivers/usb
parent0f73cac8e41723d600c91a0f5b481dc3202f4f82 (diff)
USB: OTG: msm: Implement charger detection
Implement good battery algorithm defined in the battery charging V1.2 spec for detecting different charging ports. USB hardware is put into low power mode when connected to a dedicated charging port. vbus_draw and set_power methods are implemented for determining the allowed current from Host in different states (un-configured/suspend/configured). The charger block is implemented using vendor specific registers and the PHY used in MSM8960(28nm PHY) different from older targets like MSM8x60 and MSM7x30(45nm PHY). The PHY vendor and product id registers are not implemented in the above chipsets. Hence PHY type is passed via platform data. Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c10
-rw-r--r--drivers/usb/otg/msm_otg.c380
2 files changed, 386 insertions, 4 deletions
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 68123ee01392..baaf87ed7685 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2506,6 +2506,15 @@ out:
2506 return ret; 2506 return ret;
2507} 2507}
2508 2508
2509static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
2510{
2511 struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
2512
2513 if (udc->transceiver)
2514 return otg_set_power(udc->transceiver, mA);
2515 return -ENOTSUPP;
2516}
2517
2509/** 2518/**
2510 * Device operations part of the API to the USB controller hardware, 2519 * Device operations part of the API to the USB controller hardware,
2511 * which don't involve endpoints (or i/o) 2520 * which don't involve endpoints (or i/o)
@@ -2514,6 +2523,7 @@ out:
2514static const struct usb_gadget_ops usb_gadget_ops = { 2523static const struct usb_gadget_ops usb_gadget_ops = {
2515 .vbus_session = ci13xxx_vbus_session, 2524 .vbus_session = ci13xxx_vbus_session,
2516 .wakeup = ci13xxx_wakeup, 2525 .wakeup = ci13xxx_wakeup,
2526 .vbus_draw = ci13xxx_vbus_draw,
2517}; 2527};
2518 2528
2519/** 2529/**
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
412static 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
422static 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
412static void msm_otg_start_host(struct otg_transceiver *otg, int on) 439static 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
593static 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
614static 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
654static 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
675static 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
700static 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
721static 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
740static 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
761static 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
796static 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 */
830static 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);