aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/usb/mtu3/mtu3_plat.c
diff options
context:
space:
mode:
authorChunfeng Yun <chunfeng.yun@mediatek.com>2016-10-19 10:28:26 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-10-27 17:02:41 +0200
commitd0ed062a8b75b9c9ba5a942894636f2d9bb72040 (patch)
tree13f0860c5451f03778668e823b7c9321b5089d00 /drivers/usb/mtu3/mtu3_plat.c
parentusb: mtu3: host only mode support (diff)
downloadwireguard-linux-d0ed062a8b75b9c9ba5a942894636f2d9bb72040.tar.xz
wireguard-linux-d0ed062a8b75b9c9ba5a942894636f2d9bb72040.zip
usb: mtu3: dual-role mode support
support dual-role mode; there are two ways to switch between host and device modes, one is by idpin, another is by debugfs which depends on user input. Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/mtu3/mtu3_plat.c')
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c86
1 files changed, 82 insertions, 4 deletions
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index facb76c2877b..783367805c99 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -142,13 +142,10 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
phy_err:
ssusb_phy_exit(ssusb);
-
phy_init_err:
clk_disable_unprepare(ssusb->sys_clk);
-
clk_err:
regulator_disable(ssusb->vusb33);
-
vusb33_err:
return ret;
@@ -170,10 +167,39 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
}
+static int get_iddig_pinctrl(struct ssusb_mtk *ssusb)
+{
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+ otg_sx->id_pinctrl = devm_pinctrl_get(ssusb->dev);
+ if (IS_ERR(otg_sx->id_pinctrl)) {
+ dev_err(ssusb->dev, "Cannot find id pinctrl!\n");
+ return PTR_ERR(otg_sx->id_pinctrl);
+ }
+
+ otg_sx->id_float =
+ pinctrl_lookup_state(otg_sx->id_pinctrl, "id_float");
+ if (IS_ERR(otg_sx->id_float)) {
+ dev_err(ssusb->dev, "Cannot find pinctrl id_float!\n");
+ return PTR_ERR(otg_sx->id_float);
+ }
+
+ otg_sx->id_ground =
+ pinctrl_lookup_state(otg_sx->id_pinctrl, "id_ground");
+ if (IS_ERR(otg_sx->id_ground)) {
+ dev_err(ssusb->dev, "Cannot find pinctrl id_ground!\n");
+ return PTR_ERR(otg_sx->id_ground);
+ }
+
+ return 0;
+}
+
static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
{
struct device_node *node = pdev->dev.of_node;
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
struct device *dev = &pdev->dev;
+ struct regulator *vbus;
struct resource *res;
int i;
int ret;
@@ -230,6 +256,37 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
if (ret)
return ret;
+ if (ssusb->dr_mode != USB_DR_MODE_OTG)
+ return 0;
+
+ /* if dual-role mode is supported */
+ vbus = devm_regulator_get(&pdev->dev, "vbus");
+ if (IS_ERR(vbus)) {
+ dev_err(dev, "failed to get vbus\n");
+ return PTR_ERR(vbus);
+ }
+ otg_sx->vbus = vbus;
+
+ otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
+ otg_sx->manual_drd_enabled =
+ of_property_read_bool(node, "enable-manual-drd");
+
+ if (of_property_read_bool(node, "extcon")) {
+ otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
+ if (IS_ERR(otg_sx->edev)) {
+ dev_err(ssusb->dev, "couldn't get extcon device\n");
+ return -EPROBE_DEFER;
+ }
+ if (otg_sx->manual_drd_enabled) {
+ ret = get_iddig_pinctrl(ssusb);
+ if (ret)
+ return ret;
+ }
+ }
+
+ dev_info(dev, "dr_mode: %d, is_u3_dr: %d\n",
+ ssusb->dr_mode, otg_sx->is_u3_drd);
+
return 0;
}
@@ -292,6 +349,21 @@ static int mtu3_probe(struct platform_device *pdev)
goto comm_exit;
}
break;
+ case USB_DR_MODE_OTG:
+ ret = ssusb_gadget_init(ssusb);
+ if (ret) {
+ dev_err(dev, "failed to initialize gadget\n");
+ goto comm_exit;
+ }
+
+ ret = ssusb_host_init(ssusb, node);
+ if (ret) {
+ dev_err(dev, "failed to initialize host\n");
+ goto gadget_exit;
+ }
+
+ ssusb_otg_switch_init(ssusb);
+ break;
default:
dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode);
ret = -EINVAL;
@@ -300,9 +372,10 @@ static int mtu3_probe(struct platform_device *pdev)
return 0;
+gadget_exit:
+ ssusb_gadget_exit(ssusb);
comm_exit:
ssusb_rscs_exit(ssusb);
-
comm_init_err:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
@@ -321,6 +394,11 @@ static int mtu3_remove(struct platform_device *pdev)
case USB_DR_MODE_HOST:
ssusb_host_exit(ssusb);
break;
+ case USB_DR_MODE_OTG:
+ ssusb_otg_switch_exit(ssusb);
+ ssusb_gadget_exit(ssusb);
+ ssusb_host_exit(ssusb);
+ break;
default:
return -EINVAL;
}