aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea/core.c
diff options
context:
space:
mode:
authorIvan T. Ivanov <ivan.ivanov@linaro.org>2015-09-07 07:45:25 -0400
committerPeter Chen <peter.chen@freescale.com>2015-10-21 21:24:25 -0400
commit3ecb3e09b042e70799ff3a1ff464a5ecaa7547d9 (patch)
treefea2789cc3e67fac569c9a47d7035b1e33a032d2 /drivers/usb/chipidea/core.c
parentffa2366666f06ce1df3296d106d90e0c2e0cd6b7 (diff)
usb: chipidea: Use extcon framework for VBUS and ID detect
On recent Qualcomm platforms VBUS and ID lines are not routed to USB PHY LINK controller. Use extcon framework to receive connect and disconnect ID and VBUS notification. Signed-off-by: Ivan T. Ivanov <ivan.ivanov@linaro.org> Signed-off-by: Peter Chen <peter.chen@freescale.com>
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r--drivers/usb/chipidea/core.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 3feebf7f31f0..573c2876b263 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -47,6 +47,7 @@
47#include <linux/delay.h> 47#include <linux/delay.h>
48#include <linux/device.h> 48#include <linux/device.h>
49#include <linux/dma-mapping.h> 49#include <linux/dma-mapping.h>
50#include <linux/extcon.h>
50#include <linux/phy/phy.h> 51#include <linux/phy/phy.h>
51#include <linux/platform_device.h> 52#include <linux/platform_device.h>
52#include <linux/module.h> 53#include <linux/module.h>
@@ -602,9 +603,45 @@ static irqreturn_t ci_irq(int irq, void *data)
602 return ret; 603 return ret;
603} 604}
604 605
606static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event,
607 void *ptr)
608{
609 struct ci_hdrc_cable *vbus = container_of(nb, struct ci_hdrc_cable, nb);
610 struct ci_hdrc *ci = vbus->ci;
611
612 if (event)
613 vbus->state = true;
614 else
615 vbus->state = false;
616
617 vbus->changed = true;
618
619 ci_irq(ci->irq, ci);
620 return NOTIFY_DONE;
621}
622
623static int ci_id_notifier(struct notifier_block *nb, unsigned long event,
624 void *ptr)
625{
626 struct ci_hdrc_cable *id = container_of(nb, struct ci_hdrc_cable, nb);
627 struct ci_hdrc *ci = id->ci;
628
629 if (event)
630 id->state = false;
631 else
632 id->state = true;
633
634 id->changed = true;
635
636 ci_irq(ci->irq, ci);
637 return NOTIFY_DONE;
638}
639
605static int ci_get_platdata(struct device *dev, 640static int ci_get_platdata(struct device *dev,
606 struct ci_hdrc_platform_data *platdata) 641 struct ci_hdrc_platform_data *platdata)
607{ 642{
643 struct extcon_dev *ext_vbus, *ext_id;
644 struct ci_hdrc_cable *cable;
608 int ret; 645 int ret;
609 646
610 if (!platdata->phy_mode) 647 if (!platdata->phy_mode)
@@ -695,9 +732,91 @@ static int ci_get_platdata(struct device *dev,
695 platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST; 732 platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
696 } 733 }
697 734
735 ext_id = ERR_PTR(-ENODEV);
736 ext_vbus = ERR_PTR(-ENODEV);
737 if (of_property_read_bool(dev->of_node, "extcon")) {
738 /* Each one of them is not mandatory */
739 ext_vbus = extcon_get_edev_by_phandle(dev, 0);
740 if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
741 return PTR_ERR(ext_vbus);
742
743 ext_id = extcon_get_edev_by_phandle(dev, 1);
744 if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
745 return PTR_ERR(ext_id);
746 }
747
748 cable = &platdata->vbus_extcon;
749 cable->nb.notifier_call = ci_vbus_notifier;
750 cable->edev = ext_vbus;
751
752 if (!IS_ERR(ext_vbus)) {
753 ret = extcon_get_cable_state_(cable->edev, EXTCON_USB);
754 if (ret)
755 cable->state = true;
756 else
757 cable->state = false;
758 }
759
760 cable = &platdata->id_extcon;
761 cable->nb.notifier_call = ci_id_notifier;
762 cable->edev = ext_id;
763
764 if (!IS_ERR(ext_id)) {
765 ret = extcon_get_cable_state_(cable->edev, EXTCON_USB_HOST);
766 if (ret)
767 cable->state = false;
768 else
769 cable->state = true;
770 }
698 return 0; 771 return 0;
699} 772}
700 773
774static int ci_extcon_register(struct ci_hdrc *ci)
775{
776 struct ci_hdrc_cable *id, *vbus;
777 int ret;
778
779 id = &ci->platdata->id_extcon;
780 id->ci = ci;
781 if (!IS_ERR(id->edev)) {
782 ret = extcon_register_notifier(id->edev, EXTCON_USB_HOST,
783 &id->nb);
784 if (ret < 0) {
785 dev_err(ci->dev, "register ID failed\n");
786 return ret;
787 }
788 }
789
790 vbus = &ci->platdata->vbus_extcon;
791 vbus->ci = ci;
792 if (!IS_ERR(vbus->edev)) {
793 ret = extcon_register_notifier(vbus->edev, EXTCON_USB,
794 &vbus->nb);
795 if (ret < 0) {
796 extcon_unregister_notifier(id->edev, EXTCON_USB_HOST,
797 &id->nb);
798 dev_err(ci->dev, "register VBUS failed\n");
799 return ret;
800 }
801 }
802
803 return 0;
804}
805
806static void ci_extcon_unregister(struct ci_hdrc *ci)
807{
808 struct ci_hdrc_cable *cable;
809
810 cable = &ci->platdata->id_extcon;
811 if (!IS_ERR(cable->edev))
812 extcon_unregister_notifier(cable->edev, EXTCON_USB_HOST,
813 &cable->nb);
814
815 cable = &ci->platdata->vbus_extcon;
816 if (!IS_ERR(cable->edev))
817 extcon_unregister_notifier(cable->edev, EXTCON_USB, &cable->nb);
818}
819
701static DEFINE_IDA(ci_ida); 820static DEFINE_IDA(ci_ida);
702 821
703struct platform_device *ci_hdrc_add_device(struct device *dev, 822struct platform_device *ci_hdrc_add_device(struct device *dev,
@@ -921,6 +1040,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
921 if (ret) 1040 if (ret)
922 goto stop; 1041 goto stop;
923 1042
1043 ret = ci_extcon_register(ci);
1044 if (ret)
1045 goto stop;
1046
924 if (ci->supports_runtime_pm) { 1047 if (ci->supports_runtime_pm) {
925 pm_runtime_set_active(&pdev->dev); 1048 pm_runtime_set_active(&pdev->dev);
926 pm_runtime_enable(&pdev->dev); 1049 pm_runtime_enable(&pdev->dev);
@@ -938,6 +1061,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
938 if (!ret) 1061 if (!ret)
939 return 0; 1062 return 0;
940 1063
1064 ci_extcon_unregister(ci);
941stop: 1065stop:
942 ci_role_destroy(ci); 1066 ci_role_destroy(ci);
943deinit_phy: 1067deinit_phy:
@@ -957,6 +1081,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
957 } 1081 }
958 1082
959 dbg_remove_files(ci); 1083 dbg_remove_files(ci);
1084 ci_extcon_unregister(ci);
960 ci_role_destroy(ci); 1085 ci_role_destroy(ci);
961 ci_hdrc_enter_lpm(ci, true); 1086 ci_hdrc_enter_lpm(ci, true);
962 ci_usb_phy_exit(ci); 1087 ci_usb_phy_exit(ci);