[COMMON] usb: dwc3: move TypeC configuration to otg
authorKisang Lee <kisang80.lee@samsung.com>
Mon, 25 Jun 2018 01:13:38 +0000 (10:13 +0900)
committerTaekki Kim <taekki.kim@samsung.com>
Mon, 25 Jun 2018 13:40:18 +0000 (22:40 +0900)
Change-Id: Ie1160e2011aab2b357d37bd1018246a0e5aa94aa
Signed-off-by: Kisang Lee <kisang80.lee@samsung.com>
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/otg.c
drivers/usb/dwc3/otg.h

index 7e46b654720450d8f2aa1e5b0ce9b124a5fb261b..621624d94f0ef0ace070eafb4e3c7c7f32de6d4e 100644 (file)
@@ -30,9 +30,6 @@
 #include <linux/of_platform.h>
 #include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
-#if defined(CONFIG_TYPEC)
-#include <linux/usb/typec.h>
-#endif
 
 #include <linux/io.h>
 #include <linux/usb/otg-fsm.h>
@@ -48,16 +45,6 @@ struct dwc3_exynos_rsw {
        struct work_struct      work;
 };
 
-#if defined(CONFIG_TYPEC)
-struct intf_typec {
-       /* struct mutex lock; */ /* device lock */
-       struct device *dev;
-       struct typec_port *port;
-       struct typec_capability cap;
-       struct typec_partner *partner;
-};
-#endif
-
 struct dwc3_exynos {
        struct platform_device  *usb2_phy;
        struct platform_device  *usb3_phy;
@@ -71,9 +58,6 @@ struct dwc3_exynos {
        int                     idle_ip_index;
 
        struct dwc3_exynos_rsw  rsw;
-#if defined(CONFIG_TYPEC)
-       struct intf_typec       *typec;
-#endif
 };
 
 void dwc3_otg_run_sm(struct otg_fsm *fsm);
@@ -424,9 +408,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
        struct device           *dev = &pdev->dev;
        struct device_node      *node = dev->of_node;
        int                     ret;
-#if defined(CONFIG_TYPEC)
-       struct intf_typec       *typec;
-#endif
 
        pr_info("%s: +++\n", __func__);
        exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
@@ -509,28 +490,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
                goto populate_err;
        }
 
-#if defined(CONFIG_TYPEC)
-       typec = devm_kzalloc(dev, sizeof(*typec), GFP_KERNEL);
-       if (!typec)
-               return -ENOMEM;
-
-       /* mutex_init(&md05->lock); */
-       typec->dev = dev;
-
-       typec->cap.type = TYPEC_PORT_DRP;
-       typec->cap.revision = USB_TYPEC_REV_1_1;
-       typec->cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
-
-       typec->port = typec_register_port(dev, &typec->cap);
-       if (!typec->port)
-               return -ENODEV;
-
-       typec_set_data_role(typec->port, TYPEC_DEVICE);
-       typec_set_pwr_role(typec->port, TYPEC_SINK);
-       typec_set_pwr_opmode(typec->port, TYPEC_PWR_MODE_USB);
-       exynos->typec = typec;
-#endif
-
        pr_info("%s: ---\n", __func__);
        return 0;
 
@@ -572,10 +531,6 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
        if (exynos->vdd10)
                regulator_disable(exynos->vdd10);
 
-#if defined(CONFIG_TYPEC)
-       typec_unregister_partner(exynos->typec->partner);
-       typec_unregister_port(exynos->typec->port);
-#endif
 
        return 0;
 }
index aa21ba4b080202d45695c44eb8ee04f4a5a00e89..d33e24dae9814b311a400920c88f899b4e8b0599 100644 (file)
-/**\r
- * otg.c - DesignWare USB3 DRD Controller OTG\r
- *\r
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.\r
- * Copyright (c) 2013 Samsung Electronics Co., Ltd.\r
- *             http://www.samsung.com\r
- *\r
- * Authors: Ido Shayevitz <idos@codeaurora.org>\r
- *         Anton Tikhomirov <av.tikhomirov@samsung.com>\r
- *         Minho Lee <minho55.lee@samsung.com>\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License version 2  of\r
- * the License as published by the Free Software Foundation.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- */\r
-\r
-#include <linux/mutex.h>\r
-#include <linux/platform_device.h>\r
-#include <linux/regulator/consumer.h>\r
-#include <linux/pm_runtime.h>\r
-#include <linux/usb/samsung_usb.h>\r
-#include <linux/mfd/samsung/s2mps18-private.h>\r
-#ifdef CONFIG_EXYNOS_PD\r
-#include <soc/samsung/exynos-pm.h>\r
-#endif\r
-\r
-#include "core.h"\r
-#include "otg.h"\r
-#include "io.h"\r
-\r
-/* -------------------------------------------------------------------------- */\r
-int otg_connection;\r
-static int dwc3_otg_statemachine(struct otg_fsm *fsm)\r
-{\r
-       struct usb_otg *otg = fsm->otg;\r
-       enum usb_otg_state prev_state = otg->state;\r
-       int ret = 0;\r
-\r
-       if (fsm->reset) {\r
-               if (otg->state == OTG_STATE_A_HOST) {\r
-                       otg_drv_vbus(fsm, 0);\r
-                       otg_start_host(fsm, 0);\r
-               } else if (otg->state == OTG_STATE_B_PERIPHERAL) {\r
-                       otg_start_gadget(fsm, 0);\r
-               }\r
-\r
-               otg->state = OTG_STATE_UNDEFINED;\r
-               goto exit;\r
-       }\r
-\r
-       switch (otg->state) {\r
-       case OTG_STATE_UNDEFINED:\r
-               if (fsm->id)\r
-                       otg->state = OTG_STATE_B_IDLE;\r
-               else\r
-                       otg->state = OTG_STATE_A_IDLE;\r
-               break;\r
-       case OTG_STATE_B_IDLE:\r
-               if (!fsm->id) {\r
-                       otg->state = OTG_STATE_A_IDLE;\r
-               } else if (fsm->b_sess_vld) {\r
-                       ret = otg_start_gadget(fsm, 1);\r
-                       if (!ret)\r
-                               otg->state = OTG_STATE_B_PERIPHERAL;\r
-                       else\r
-                               pr_err("OTG SM: cannot start gadget\n");\r
-               }\r
-               break;\r
-       case OTG_STATE_B_PERIPHERAL:\r
-               if (!fsm->id || !fsm->b_sess_vld) {\r
-                       ret = otg_start_gadget(fsm, 0);\r
-                       if (!ret)\r
-                               otg->state = OTG_STATE_B_IDLE;\r
-                       else\r
-                               pr_err("OTG SM: cannot stop gadget\n");\r
-               }\r
-               break;\r
-       case OTG_STATE_A_IDLE:\r
-               if (fsm->id) {\r
-                       otg->state = OTG_STATE_B_IDLE;\r
-               } else {\r
-                       ret = otg_start_host(fsm, 1);\r
-                       if (!ret) {\r
-                               otg_drv_vbus(fsm, 1);\r
-                               otg->state = OTG_STATE_A_HOST;\r
-                       } else {\r
-                               pr_err("OTG SM: cannot start host\n");\r
-                       }\r
-               }\r
-               break;\r
-       case OTG_STATE_A_HOST:\r
-               if (fsm->id) {\r
-                       otg_drv_vbus(fsm, 0);\r
-                       ret = otg_start_host(fsm, 0);\r
-                       if (!ret)\r
-                               otg->state = OTG_STATE_A_IDLE;\r
-                       else\r
-                               pr_err("OTG SM: cannot stop host\n");\r
-               }\r
-               break;\r
-       default:\r
-               pr_err("OTG SM: invalid state\n");\r
-       }\r
-\r
-exit:\r
-       if (!ret)\r
-               ret = (otg->state != prev_state);\r
-\r
-       pr_debug("OTG SM: %s => %s\n", usb_otg_state_string(prev_state),\r
-               (ret > 0) ? usb_otg_state_string(otg->state) : "(no change)");\r
-\r
-       return ret;\r
-}\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-static struct dwc3_ext_otg_ops *dwc3_otg_exynos_rsw_probe(struct dwc3 *dwc)\r
-{\r
-       struct dwc3_ext_otg_ops *ops;\r
-       bool ext_otg;\r
-\r
-       ext_otg = dwc3_exynos_rsw_available(dwc->dev->parent);\r
-       if (!ext_otg)\r
-               return NULL;\r
-\r
-       /* Allocate and init otg instance */\r
-       ops = devm_kzalloc(dwc->dev, sizeof(struct dwc3_ext_otg_ops),\r
-                       GFP_KERNEL);\r
-       if (!ops) {\r
-                dev_err(dwc->dev, "unable to allocate dwc3_ext_otg_ops\n");\r
-                return NULL;\r
-       }\r
-\r
-       ops->setup = dwc3_exynos_rsw_setup;\r
-       ops->exit = dwc3_exynos_rsw_exit;\r
-       ops->start = dwc3_exynos_rsw_start;\r
-       ops->stop = dwc3_exynos_rsw_stop;\r
-\r
-       return ops;\r
-}\r
-\r
-static void dwc3_otg_set_host_mode(struct dwc3_otg *dotg)\r
-{\r
-       struct dwc3 *dwc = dotg->dwc;\r
-       u32 reg;\r
-\r
-       if (dotg->regs) {\r
-               reg = dwc3_readl(dotg->regs, DWC3_OCTL);\r
-               reg &= ~DWC3_OTG_OCTL_PERIMODE;\r
-               dwc3_writel(dotg->regs, DWC3_OCTL, reg);\r
-       } else {\r
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);\r
-       }\r
-}\r
-\r
-static void dwc3_otg_set_peripheral_mode(struct dwc3_otg *dotg)\r
-{\r
-       struct dwc3 *dwc = dotg->dwc;\r
-       u32 reg;\r
-\r
-       if (dotg->regs) {\r
-               reg = dwc3_readl(dotg->regs, DWC3_OCTL);\r
-               reg |= DWC3_OTG_OCTL_PERIMODE;\r
-               dwc3_writel(dotg->regs, DWC3_OCTL, reg);\r
-       } else {\r
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);\r
-       }\r
-}\r
-\r
-static void dwc3_otg_drv_vbus(struct otg_fsm *fsm, int on)\r
-{\r
-       struct dwc3_otg *dotg = container_of(fsm, struct dwc3_otg, fsm);\r
-       int ret;\r
-\r
-       if (IS_ERR(dotg->vbus_reg)) {\r
-               dev_err(dotg->dwc->dev, "vbus regulator is not available\n");\r
-               return;\r
-       }\r
-\r
-       if (on)\r
-               ret = regulator_enable(dotg->vbus_reg);\r
-       else\r
-               ret = regulator_disable(dotg->vbus_reg);\r
-\r
-       if (ret)\r
-               dev_err(dotg->dwc->dev, "failed to turn Vbus %s\n",\r
-                                               on ? "on" : "off");\r
-}\r
-\r
-static void dwc3_otg_ldo_control(struct otg_fsm *fsm, int on)\r
-{\r
-#if defined(OTG_LDO_CONTROL_ENABLED)\r
-       struct usb_otg  *otg = fsm->otg;\r
-       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);\r
-       struct device   *dev = dotg->dwc->dev;\r
-       int i;\r
-\r
-       dev_info(dev, "Turn %s LDO\n", on ? "on" : "off");\r
-\r
-       if (on) {\r
-               for (i = 0; i < dotg->ldos; i++)\r
-                       s2m_ldo_set_mode(dotg->ldo_num[i], 0x3);\r
-       } else {\r
-               for (i = 0; i < dotg->ldos; i++)\r
-                       s2m_ldo_set_mode(dotg->ldo_num[i], 0x1);\r
-       }\r
-#endif\r
-\r
-       return;\r
-}\r
-static int dwc3_otg_start_host(struct otg_fsm *fsm, int on)\r
-{\r
-       struct usb_otg  *otg = fsm->otg;\r
-       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);\r
-       struct dwc3     *dwc = dotg->dwc;\r
-       struct device   *dev = dotg->dwc->dev;\r
-       int ret = 0;\r
-\r
-       if (!dotg->dwc->xhci) {\r
-               dev_err(dev, "%s: does not have any xhci\n", __func__);\r
-               return -EINVAL;\r
-       }\r
-\r
-       dev_info(dev, "Turn %s host\n", on ? "on" : "off");\r
-       if (on) {\r
-               otg_connection = 1;\r
-               dwc3_otg_ldo_control(fsm, 1);\r
-               pm_runtime_get_sync(dev);\r
-               ret = dwc3_phy_setup(dwc);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "%s: failed to setup phy\n",\r
-                                       __func__);\r
-                       goto err1;\r
-               }\r
-               ret = dwc3_core_init(dwc);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "%s: failed to reinitialize core\n",\r
-                                       __func__);\r
-                       goto err1;\r
-               }\r
-\r
-               phy_conn(dwc->usb2_generic_phy, 1);\r
-\r
-               /**\r
-                * In case there is not a resistance to detect VBUS,\r
-                * DP/DM controls by S/W are needed at this point.\r
-                */\r
-               if (dwc->is_not_vbus_pad) {\r
-                       phy_set(dwc->usb2_generic_phy,\r
-                                       SET_DPDM_PULLDOWN, NULL);\r
-                       phy_set(dwc->usb3_generic_phy,\r
-                                       SET_DPDM_PULLDOWN, NULL);\r
-               }\r
-\r
-               dwc3_otg_set_host_mode(dotg);\r
-               ret = platform_device_add(dwc->xhci);\r
-               if (ret) {\r
-                       dev_err(dev, "%s: cannot add xhci\n", __func__);\r
-                       goto err2;\r
-               }\r
-       } else {\r
-               otg_connection = 0;\r
-               platform_device_del(dwc->xhci);\r
-err2:\r
-               phy_conn(dwc->usb2_generic_phy, 0);\r
-\r
-               dwc3_core_exit(dwc);\r
-err1:\r
-               pm_runtime_put_sync(dev);\r
-               dwc3_otg_ldo_control(fsm, 0);\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-static int dwc3_otg_start_gadget(struct otg_fsm *fsm, int on)\r
-{\r
-       struct usb_otg  *otg = fsm->otg;\r
-       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);\r
-       struct dwc3     *dwc = dotg->dwc;\r
-       struct device   *dev = dotg->dwc->dev;\r
-       int ret = 0;\r
-\r
-       if (!otg->gadget) {\r
-               dev_err(dev, "%s does not have any gadget\n", __func__);\r
-               return -EINVAL;\r
-       }\r
-\r
-       dev_info(dev, "Turn %s gadget %s\n",\r
-                       on ? "on" : "off", otg->gadget->name);\r
-\r
-       if (on) {\r
-               wake_lock(&dotg->wakelock);\r
-               ret = pm_runtime_get_sync(dev);\r
-               dev_info(dev, "%s pm_runtime_get_sync = %d\n",\r
-                               __func__, ret);\r
-               ret = dwc3_phy_setup(dwc);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "%s: failed to setup phy\n",\r
-                                       __func__);\r
-                       goto err1;\r
-               }\r
-\r
-               ret = dwc3_core_init(dwc);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "%s: failed to reinitialize core\n",\r
-                                       __func__);\r
-                       goto err1;\r
-               }\r
-\r
-               dwc3_otg_set_peripheral_mode(dotg);\r
-               ret = usb_gadget_vbus_connect(otg->gadget);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "%s: vbus connect failed\n",\r
-                                       __func__);\r
-                       goto err2;\r
-               }\r
-\r
-       } else {\r
-               if (dwc->is_not_vbus_pad)\r
-                       dwc3_gadget_disconnect_proc(dwc);\r
-               /* avoid missing disconnect interrupt */\r
-               ret = wait_for_completion_timeout(&dwc->disconnect,\r
-                               msecs_to_jiffies(200));\r
-               if (!ret) {\r
-                       dev_err(dwc->dev, "%s: disconnect completion timeout\n",\r
-                                       __func__);\r
-                       return ret;\r
-               }\r
-               ret = usb_gadget_vbus_disconnect(otg->gadget);\r
-               if (ret)\r
-                       dev_err(dwc->dev, "%s: vbus disconnect failed\n",\r
-                                       __func__);\r
-err2:\r
-               dwc3_core_exit(dwc);\r
-err1:\r
-               pm_runtime_put_sync(dev);\r
-               wake_unlock(&dotg->wakelock);\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-static struct otg_fsm_ops dwc3_otg_fsm_ops = {\r
-       .drv_vbus       = dwc3_otg_drv_vbus,\r
-       .start_host     = dwc3_otg_start_host,\r
-       .start_gadget   = dwc3_otg_start_gadget,\r
-};\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-void dwc3_otg_run_sm(struct otg_fsm *fsm)\r
-{\r
-       struct dwc3_otg *dotg = container_of(fsm, struct dwc3_otg, fsm);\r
-       int             state_changed;\r
-\r
-       /* Prevent running SM on early system resume */\r
-       if (!dotg->ready)\r
-               return;\r
-\r
-       mutex_lock(&fsm->lock);\r
-\r
-       do {\r
-               state_changed = dwc3_otg_statemachine(fsm);\r
-       } while (state_changed > 0);\r
-\r
-       mutex_unlock(&fsm->lock);\r
-}\r
-\r
-/* Bind/Unbind the peripheral controller driver */\r
-static int dwc3_otg_set_peripheral(struct usb_otg *otg,\r
-                               struct usb_gadget *gadget)\r
-{\r
-       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);\r
-       struct otg_fsm  *fsm = &dotg->fsm;\r
-       struct device   *dev = dotg->dwc->dev;\r
-\r
-       if (gadget) {\r
-               dev_info(dev, "Binding gadget %s\n", gadget->name);\r
-\r
-               otg->gadget = gadget;\r
-       } else {\r
-               dev_info(dev, "Unbinding gadget\n");\r
-\r
-               mutex_lock(&fsm->lock);\r
-\r
-               if (otg->state == OTG_STATE_B_PERIPHERAL) {\r
-                       /* Reset OTG Statemachine */\r
-                       fsm->reset = 1;\r
-                       dwc3_otg_statemachine(fsm);\r
-                       fsm->reset = 0;\r
-               }\r
-               otg->gadget = NULL;\r
-\r
-               mutex_unlock(&fsm->lock);\r
-\r
-               dwc3_otg_run_sm(fsm);\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-static int dwc3_otg_get_id_state(struct dwc3_otg *dotg)\r
-{\r
-       u32 reg = dwc3_readl(dotg->regs, DWC3_OSTS);\r
-\r
-       return !!(reg & DWC3_OTG_OSTS_CONIDSTS);\r
-}\r
-\r
-static int dwc3_otg_get_b_sess_state(struct dwc3_otg *dotg)\r
-{\r
-       u32 reg = dwc3_readl(dotg->regs, DWC3_OSTS);\r
-\r
-       return !!(reg & DWC3_OTG_OSTS_BSESVALID);\r
-}\r
-\r
-static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)\r
-{\r
-       struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;\r
-       struct otg_fsm  *fsm = &dotg->fsm;\r
-       u32 oevt, handled_events = 0;\r
-       irqreturn_t ret = IRQ_NONE;\r
-\r
-       oevt = dwc3_readl(dotg->regs, DWC3_OEVT);\r
-\r
-       /* ID */\r
-       if (oevt & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) {\r
-               fsm->id = dwc3_otg_get_id_state(dotg);\r
-               handled_events |= DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT;\r
-       }\r
-\r
-       /* VBus */\r
-       if (oevt & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) {\r
-               fsm->b_sess_vld = dwc3_otg_get_b_sess_state(dotg);\r
-               handled_events |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;\r
-       }\r
-\r
-       if (handled_events) {\r
-               dwc3_writel(dotg->regs, DWC3_OEVT, handled_events);\r
-               ret = IRQ_WAKE_THREAD;\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-static irqreturn_t dwc3_otg_thread_interrupt(int irq, void *_dotg)\r
-{\r
-       struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;\r
-\r
-       dwc3_otg_run_sm(&dotg->fsm);\r
-\r
-       return IRQ_HANDLED;\r
-}\r
-\r
-static void dwc3_otg_enable_irq(struct dwc3_otg *dotg)\r
-{\r
-       /* Enable only connector ID status & VBUS change events */\r
-       dwc3_writel(dotg->regs, DWC3_OEVTEN,\r
-                       DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |\r
-                       DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);\r
-}\r
-\r
-static void dwc3_otg_disable_irq(struct dwc3_otg *dotg)\r
-{\r
-       dwc3_writel(dotg->regs, DWC3_OEVTEN, 0x0);\r
-}\r
-\r
-static void dwc3_otg_reset(struct dwc3_otg *dotg)\r
-{\r
-       /*\r
-        * OCFG[2] - OTG-Version = 0\r
-        * OCFG[1] - HNPCap = 0\r
-        * OCFG[0] - SRPCap = 0\r
-        */\r
-       dwc3_writel(dotg->regs, DWC3_OCFG, 0x0);\r
-\r
-       /*\r
-        * OCTL[6] - PeriMode = 1\r
-        * OCTL[5] - PrtPwrCtl = 0\r
-        * OCTL[4] - HNPReq = 0\r
-        * OCTL[3] - SesReq = 0\r
-        * OCTL[2] - TermSelDLPulse = 0\r
-        * OCTL[1] - DevSetHNPEn = 0\r
-        * OCTL[0] - HstSetHNPEn = 0\r
-        */\r
-       dwc3_writel(dotg->regs, DWC3_OCTL, DWC3_OTG_OCTL_PERIMODE);\r
-\r
-       /* Clear all otg events (interrupts) indications  */\r
-       dwc3_writel(dotg->regs, DWC3_OEVT, DWC3_OEVT_CLEAR_ALL);\r
-}\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-static ssize_t\r
-dwc3_otg_show_state(struct device *dev,\r
-               struct device_attribute *attr, char *buf)\r
-{\r
-       struct dwc3     *dwc = dev_get_drvdata(dev);\r
-       struct usb_otg  *otg = &dwc->dotg->otg;\r
-\r
-       return snprintf(buf, PAGE_SIZE, "%s\n",\r
-                       usb_otg_state_string(otg->state));\r
-}\r
-\r
-static DEVICE_ATTR(state, S_IRUSR | S_IRGRP,\r
-       dwc3_otg_show_state, NULL);\r
-\r
-static ssize_t\r
-dwc3_otg_show_b_sess(struct device *dev,\r
-               struct device_attribute *attr, char *buf)\r
-{\r
-       struct dwc3     *dwc = dev_get_drvdata(dev);\r
-       struct otg_fsm  *fsm = &dwc->dotg->fsm;\r
-\r
-       return snprintf(buf, PAGE_SIZE, "%d\n", fsm->b_sess_vld);\r
-}\r
-\r
-static ssize_t\r
-dwc3_otg_store_b_sess(struct device *dev,\r
-               struct device_attribute *attr, const char *buf, size_t n)\r
-{\r
-       struct dwc3     *dwc = dev_get_drvdata(dev);\r
-       struct otg_fsm  *fsm = &dwc->dotg->fsm;\r
-       int             b_sess_vld;\r
-\r
-       if (sscanf(buf, "%d", &b_sess_vld) != 1)\r
-               return -EINVAL;\r
-\r
-       fsm->b_sess_vld = !!b_sess_vld;\r
-\r
-       dwc3_otg_run_sm(fsm);\r
-\r
-       return n;\r
-}\r
-\r
-static DEVICE_ATTR(b_sess, S_IWUSR | S_IRUSR | S_IRGRP,\r
-       dwc3_otg_show_b_sess, dwc3_otg_store_b_sess);\r
-\r
-static ssize_t\r
-dwc3_otg_show_id(struct device *dev,\r
-               struct device_attribute *attr, char *buf)\r
-{\r
-       struct dwc3     *dwc = dev_get_drvdata(dev);\r
-       struct otg_fsm  *fsm = &dwc->dotg->fsm;\r
-\r
-       return snprintf(buf, PAGE_SIZE, "%d\n", fsm->id);\r
-}\r
-\r
-static ssize_t\r
-dwc3_otg_store_id(struct device *dev,\r
-               struct device_attribute *attr, const char *buf, size_t n)\r
-{\r
-       struct dwc3     *dwc = dev_get_drvdata(dev);\r
-       struct otg_fsm  *fsm = &dwc->dotg->fsm;\r
-       int id;\r
-\r
-       if (sscanf(buf, "%d", &id) != 1)\r
-               return -EINVAL;\r
-\r
-       fsm->id = !!id;\r
-\r
-       dwc3_otg_run_sm(fsm);\r
-\r
-       return n;\r
-}\r
-\r
-static DEVICE_ATTR(id, S_IWUSR | S_IRUSR | S_IRGRP,\r
-       dwc3_otg_show_id, dwc3_otg_store_id);\r
-\r
-static struct attribute *dwc3_otg_attributes[] = {\r
-       &dev_attr_id.attr,\r
-       &dev_attr_b_sess.attr,\r
-       &dev_attr_state.attr,\r
-       NULL\r
-};\r
-\r
-static const struct attribute_group dwc3_otg_attr_group = {\r
-       .attrs = dwc3_otg_attributes,\r
-};\r
-\r
-/**\r
- * dwc3_otg_start\r
- * @dwc: pointer to our controller context structure\r
- */\r
-int dwc3_otg_start(struct dwc3 *dwc)\r
-{\r
-       struct dwc3_otg *dotg = dwc->dotg;\r
-       struct otg_fsm  *fsm = &dotg->fsm;\r
-       int             ret;\r
-\r
-       if (dotg->ext_otg_ops) {\r
-               ret = dwc3_ext_otg_start(dotg);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "failed to start external OTG\n");\r
-                       return ret;\r
-               }\r
-       } else {\r
-               dotg->regs = dwc->regs;\r
-\r
-               dwc3_otg_reset(dotg);\r
-\r
-               dotg->fsm.id = dwc3_otg_get_id_state(dotg);\r
-               dotg->fsm.b_sess_vld = dwc3_otg_get_b_sess_state(dotg);\r
-\r
-               dotg->irq = platform_get_irq(to_platform_device(dwc->dev), 0);\r
-               ret = devm_request_threaded_irq(dwc->dev, dotg->irq,\r
-                               dwc3_otg_interrupt,\r
-                               dwc3_otg_thread_interrupt,\r
-                               IRQF_SHARED, "dwc3-otg", dotg);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "failed to request irq #%d --> %d\n",\r
-                                       dotg->irq, ret);\r
-                       return ret;\r
-               }\r
-\r
-               dwc3_otg_enable_irq(dotg);\r
-       }\r
-\r
-       dotg->ready = 1;\r
-\r
-       dwc3_otg_run_sm(fsm);\r
-\r
-       return 0;\r
-}\r
-\r
-/**\r
- * dwc3_otg_stop\r
- * @dwc: pointer to our controller context structure\r
- */\r
-void dwc3_otg_stop(struct dwc3 *dwc)\r
-{\r
-       struct dwc3_otg         *dotg = dwc->dotg;\r
-\r
-       if (dotg->ext_otg_ops) {\r
-               dwc3_ext_otg_stop(dotg);\r
-       } else {\r
-               dwc3_otg_disable_irq(dotg);\r
-               free_irq(dotg->irq, dotg);\r
-       }\r
-\r
-       dotg->ready = 0;\r
-}\r
-\r
-/* -------------------------------------------------------------------------- */\r
-bool otg_is_connect(void)\r
-{\r
-       if (otg_connection)\r
-               return true;\r
-       else\r
-               return false;\r
-}\r
-EXPORT_SYMBOL_GPL(otg_is_connect);\r
-\r
-int dwc3_otg_init(struct dwc3 *dwc)\r
-{\r
-       struct dwc3_otg *dotg;\r
-       struct dwc3_ext_otg_ops *ops = NULL;\r
-       int ret = 0;\r
-\r
-       dev_info(dwc->dev, "%s\n", __func__);\r
-\r
-       /* EXYNOS SoCs don't have HW OTG, but support SW OTG. */\r
-       ops = dwc3_otg_exynos_rsw_probe(dwc);\r
-       if (!ops)\r
-               return 0;\r
-\r
-       /* Allocate and init otg instance */\r
-       dotg = devm_kzalloc(dwc->dev, sizeof(struct dwc3_otg), GFP_KERNEL);\r
-       if (!dotg) {\r
-               dev_err(dwc->dev, "unable to allocate dwc3_otg\n");\r
-               return -ENOMEM;\r
-       }\r
-\r
-       /* This reference is used by dwc3 modules for checking otg existance */\r
-       dwc->dotg = dotg;\r
-       dotg->dwc = dwc;\r
-\r
-       ret = of_property_read_u32(dwc->dev->of_node,"ldos", &dotg->ldos);\r
-       if (ret < 0) {\r
-               dev_err(dwc->dev, "can't get ldo information\n");\r
-               return -EINVAL;\r
-       } else {\r
-               if (dotg->ldos) {\r
-                       dev_info(dwc->dev, "have %d LDOs for supporting USB L2 suspend \n", dotg->ldos);\r
-                       dotg->ldo_num = (int *)devm_kmalloc(dwc->dev, sizeof(int) * (dotg->ldos),\r
-                               GFP_KERNEL);\r
-                       ret = of_property_read_u32_array(dwc->dev->of_node,\r
-                                       "ldo_number", dotg->ldo_num, dotg->ldos);\r
-               } else {\r
-                       dev_info(dwc->dev, "don't have LDOs for supporting USB L2 suspend \n");\r
-               }\r
-       }\r
-\r
-       dotg->ext_otg_ops = ops;\r
-\r
-       dotg->otg.set_peripheral = dwc3_otg_set_peripheral;\r
-       dotg->otg.set_host = NULL;\r
-\r
-       dotg->otg.state = OTG_STATE_UNDEFINED;\r
-\r
-       mutex_init(&dotg->fsm.lock);\r
-       dotg->fsm.ops = &dwc3_otg_fsm_ops;\r
-       dotg->fsm.otg = &dotg->otg;\r
-\r
-       dotg->vbus_reg = devm_regulator_get(dwc->dev->parent, "dwc3-vbus");\r
-       if (IS_ERR(dotg->vbus_reg))\r
-               dev_err(dwc->dev, "failed to obtain vbus regulator\n");\r
-\r
-       if (dotg->ext_otg_ops) {\r
-               ret = dwc3_ext_otg_setup(dotg);\r
-               if (ret) {\r
-                       dev_err(dwc->dev, "failed to setup OTG\n");\r
-                       return ret;\r
-               }\r
-       }\r
-\r
-       wake_lock_init(&dotg->wakelock, WAKE_LOCK_SUSPEND, "dwc3-otg");\r
-\r
-       ret = sysfs_create_group(&dwc->dev->kobj, &dwc3_otg_attr_group);\r
-       if (ret)\r
-               dev_err(dwc->dev, "failed to create dwc3 otg attributes\n");\r
-\r
-#ifdef CONFIG_SOC_EXYNOS9810\r
-       register_usb_is_connect(NULL);\r
-#endif\r
-\r
-       return 0;\r
-}\r
-\r
-void dwc3_otg_exit(struct dwc3 *dwc)\r
-{\r
-       struct dwc3_otg *dotg = dwc->dotg;\r
-\r
-       if (!dotg->ext_otg_ops)\r
-               return;\r
-\r
-       dwc3_ext_otg_exit(dotg);\r
-\r
-       sysfs_remove_group(&dwc->dev->kobj, &dwc3_otg_attr_group);\r
-       wake_lock_destroy(&dotg->wakelock);\r
-       free_irq(dotg->irq, dotg);\r
-       dotg->otg.state = OTG_STATE_UNDEFINED;\r
-       kfree(dotg);\r
-       dwc->dotg = NULL;\r
-}\r
+/**
+ * otg.c - DesignWare USB3 DRD Controller OTG
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Authors: Ido Shayevitz <idos@codeaurora.org>
+ *         Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *         Minho Lee <minho55.lee@samsung.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/samsung_usb.h>
+#include <linux/mfd/samsung/s2mps18-private.h>
+#ifdef CONFIG_EXYNOS_PD
+#include <soc/samsung/exynos-pm.h>
+#endif
+
+#if defined(CONFIG_TYPEC)
+#include <linux/usb/typec.h>
+#endif
+
+#include "core.h"
+#include "otg.h"
+#include "io.h"
+
+/* -------------------------------------------------------------------------- */
+
+#if defined(CONFIG_TYPEC)
+struct intf_typec {
+       /* struct mutex lock; */ /* device lock */
+       struct device *dev;
+       struct typec_port *port;
+       struct typec_capability cap;
+       struct typec_partner *partner;
+};
+#endif
+
+int otg_connection;
+static int dwc3_otg_statemachine(struct otg_fsm *fsm)
+{
+       struct usb_otg *otg = fsm->otg;
+       enum usb_otg_state prev_state = otg->state;
+       int ret = 0;
+
+       if (fsm->reset) {
+               if (otg->state == OTG_STATE_A_HOST) {
+                       otg_drv_vbus(fsm, 0);
+                       otg_start_host(fsm, 0);
+               } else if (otg->state == OTG_STATE_B_PERIPHERAL) {
+                       otg_start_gadget(fsm, 0);
+               }
+
+               otg->state = OTG_STATE_UNDEFINED;
+               goto exit;
+       }
+
+       switch (otg->state) {
+       case OTG_STATE_UNDEFINED:
+               if (fsm->id)
+                       otg->state = OTG_STATE_B_IDLE;
+               else
+                       otg->state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_B_IDLE:
+               if (!fsm->id) {
+                       otg->state = OTG_STATE_A_IDLE;
+               } else if (fsm->b_sess_vld) {
+                       ret = otg_start_gadget(fsm, 1);
+                       if (!ret)
+                               otg->state = OTG_STATE_B_PERIPHERAL;
+                       else
+                               pr_err("OTG SM: cannot start gadget\n");
+               }
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (!fsm->id || !fsm->b_sess_vld) {
+                       ret = otg_start_gadget(fsm, 0);
+                       if (!ret)
+                               otg->state = OTG_STATE_B_IDLE;
+                       else
+                               pr_err("OTG SM: cannot stop gadget\n");
+               }
+               break;
+       case OTG_STATE_A_IDLE:
+               if (fsm->id) {
+                       otg->state = OTG_STATE_B_IDLE;
+               } else {
+                       ret = otg_start_host(fsm, 1);
+                       if (!ret) {
+                               otg_drv_vbus(fsm, 1);
+                               otg->state = OTG_STATE_A_HOST;
+                       } else {
+                               pr_err("OTG SM: cannot start host\n");
+                       }
+               }
+               break;
+       case OTG_STATE_A_HOST:
+               if (fsm->id) {
+                       otg_drv_vbus(fsm, 0);
+                       ret = otg_start_host(fsm, 0);
+                       if (!ret)
+                               otg->state = OTG_STATE_A_IDLE;
+                       else
+                               pr_err("OTG SM: cannot stop host\n");
+               }
+               break;
+       default:
+               pr_err("OTG SM: invalid state\n");
+       }
+
+exit:
+       if (!ret)
+               ret = (otg->state != prev_state);
+
+       pr_debug("OTG SM: %s => %s\n", usb_otg_state_string(prev_state),
+               (ret > 0) ? usb_otg_state_string(otg->state) : "(no change)");
+
+       return ret;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct dwc3_ext_otg_ops *dwc3_otg_exynos_rsw_probe(struct dwc3 *dwc)
+{
+       struct dwc3_ext_otg_ops *ops;
+       bool ext_otg;
+
+       ext_otg = dwc3_exynos_rsw_available(dwc->dev->parent);
+       if (!ext_otg)
+               return NULL;
+
+       /* Allocate and init otg instance */
+       ops = devm_kzalloc(dwc->dev, sizeof(struct dwc3_ext_otg_ops),
+                       GFP_KERNEL);
+       if (!ops) {
+                dev_err(dwc->dev, "unable to allocate dwc3_ext_otg_ops\n");
+                return NULL;
+       }
+
+       ops->setup = dwc3_exynos_rsw_setup;
+       ops->exit = dwc3_exynos_rsw_exit;
+       ops->start = dwc3_exynos_rsw_start;
+       ops->stop = dwc3_exynos_rsw_stop;
+
+       return ops;
+}
+
+static void dwc3_otg_set_host_mode(struct dwc3_otg *dotg)
+{
+       struct dwc3 *dwc = dotg->dwc;
+       u32 reg;
+
+       if (dotg->regs) {
+               reg = dwc3_readl(dotg->regs, DWC3_OCTL);
+               reg &= ~DWC3_OTG_OCTL_PERIMODE;
+               dwc3_writel(dotg->regs, DWC3_OCTL, reg);
+       } else {
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+       }
+}
+
+static void dwc3_otg_set_peripheral_mode(struct dwc3_otg *dotg)
+{
+       struct dwc3 *dwc = dotg->dwc;
+       u32 reg;
+
+       if (dotg->regs) {
+               reg = dwc3_readl(dotg->regs, DWC3_OCTL);
+               reg |= DWC3_OTG_OCTL_PERIMODE;
+               dwc3_writel(dotg->regs, DWC3_OCTL, reg);
+       } else {
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+       }
+}
+
+static void dwc3_otg_drv_vbus(struct otg_fsm *fsm, int on)
+{
+       struct dwc3_otg *dotg = container_of(fsm, struct dwc3_otg, fsm);
+       int ret;
+
+       if (IS_ERR(dotg->vbus_reg)) {
+               dev_err(dotg->dwc->dev, "vbus regulator is not available\n");
+               return;
+       }
+
+       if (on)
+               ret = regulator_enable(dotg->vbus_reg);
+       else
+               ret = regulator_disable(dotg->vbus_reg);
+
+       if (ret)
+               dev_err(dotg->dwc->dev, "failed to turn Vbus %s\n",
+                                               on ? "on" : "off");
+}
+
+static void dwc3_otg_ldo_control(struct otg_fsm *fsm, int on)
+{
+#if defined(OTG_LDO_CONTROL_ENABLED)
+       struct usb_otg  *otg = fsm->otg;
+       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+       struct device   *dev = dotg->dwc->dev;
+       int i;
+
+       dev_info(dev, "Turn %s LDO\n", on ? "on" : "off");
+
+       if (on) {
+               for (i = 0; i < dotg->ldos; i++)
+                       s2m_ldo_set_mode(dotg->ldo_num[i], 0x3);
+       } else {
+               for (i = 0; i < dotg->ldos; i++)
+                       s2m_ldo_set_mode(dotg->ldo_num[i], 0x1);
+       }
+#endif
+
+       return;
+}
+static int dwc3_otg_start_host(struct otg_fsm *fsm, int on)
+{
+       struct usb_otg  *otg = fsm->otg;
+       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+       struct dwc3     *dwc = dotg->dwc;
+       struct device   *dev = dotg->dwc->dev;
+       int ret = 0;
+
+       if (!dotg->dwc->xhci) {
+               dev_err(dev, "%s: does not have any xhci\n", __func__);
+               return -EINVAL;
+       }
+
+       dev_info(dev, "Turn %s host\n", on ? "on" : "off");
+       if (on) {
+               otg_connection = 1;
+               dwc3_otg_ldo_control(fsm, 1);
+               pm_runtime_get_sync(dev);
+               ret = dwc3_phy_setup(dwc);
+               if (ret) {
+                       dev_err(dwc->dev, "%s: failed to setup phy\n",
+                                       __func__);
+                       goto err1;
+               }
+               ret = dwc3_core_init(dwc);
+               if (ret) {
+                       dev_err(dwc->dev, "%s: failed to reinitialize core\n",
+                                       __func__);
+                       goto err1;
+               }
+
+               phy_conn(dwc->usb2_generic_phy, 1);
+
+               /**
+                * In case there is not a resistance to detect VBUS,
+                * DP/DM controls by S/W are needed at this point.
+                */
+               if (dwc->is_not_vbus_pad) {
+                       phy_set(dwc->usb2_generic_phy,
+                                       SET_DPDM_PULLDOWN, NULL);
+                       phy_set(dwc->usb3_generic_phy,
+                                       SET_DPDM_PULLDOWN, NULL);
+               }
+
+               dwc3_otg_set_host_mode(dotg);
+               ret = platform_device_add(dwc->xhci);
+               if (ret) {
+                       dev_err(dev, "%s: cannot add xhci\n", __func__);
+                       goto err2;
+               }
+       } else {
+               otg_connection = 0;
+               platform_device_del(dwc->xhci);
+err2:
+               phy_conn(dwc->usb2_generic_phy, 0);
+
+               dwc3_core_exit(dwc);
+err1:
+               pm_runtime_put_sync(dev);
+               dwc3_otg_ldo_control(fsm, 0);
+       }
+
+       return ret;
+}
+
+static int dwc3_otg_start_gadget(struct otg_fsm *fsm, int on)
+{
+       struct usb_otg  *otg = fsm->otg;
+       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+       struct dwc3     *dwc = dotg->dwc;
+       struct device   *dev = dotg->dwc->dev;
+       int ret = 0;
+
+       if (!otg->gadget) {
+               dev_err(dev, "%s does not have any gadget\n", __func__);
+               return -EINVAL;
+       }
+
+       dev_info(dev, "Turn %s gadget %s\n",
+                       on ? "on" : "off", otg->gadget->name);
+
+       if (on) {
+               wake_lock(&dotg->wakelock);
+               ret = pm_runtime_get_sync(dev);
+               dev_info(dev, "%s pm_runtime_get_sync = %d\n",
+                               __func__, ret);
+               ret = dwc3_phy_setup(dwc);
+               if (ret) {
+                       dev_err(dwc->dev, "%s: failed to setup phy\n",
+                                       __func__);
+                       goto err1;
+               }
+
+               ret = dwc3_core_init(dwc);
+               if (ret) {
+                       dev_err(dwc->dev, "%s: failed to reinitialize core\n",
+                                       __func__);
+                       goto err1;
+               }
+
+               dwc3_otg_set_peripheral_mode(dotg);
+               ret = usb_gadget_vbus_connect(otg->gadget);
+               if (ret) {
+                       dev_err(dwc->dev, "%s: vbus connect failed\n",
+                                       __func__);
+                       goto err2;
+               }
+
+       } else {
+               if (dwc->is_not_vbus_pad)
+                       dwc3_gadget_disconnect_proc(dwc);
+               /* avoid missing disconnect interrupt */
+               ret = wait_for_completion_timeout(&dwc->disconnect,
+                               msecs_to_jiffies(200));
+               if (!ret) {
+                       dev_err(dwc->dev, "%s: disconnect completion timeout\n",
+                                       __func__);
+                       return ret;
+               }
+               ret = usb_gadget_vbus_disconnect(otg->gadget);
+               if (ret)
+                       dev_err(dwc->dev, "%s: vbus disconnect failed\n",
+                                       __func__);
+err2:
+               dwc3_core_exit(dwc);
+err1:
+               pm_runtime_put_sync(dev);
+               wake_unlock(&dotg->wakelock);
+       }
+
+       return ret;
+}
+
+static struct otg_fsm_ops dwc3_otg_fsm_ops = {
+       .drv_vbus       = dwc3_otg_drv_vbus,
+       .start_host     = dwc3_otg_start_host,
+       .start_gadget   = dwc3_otg_start_gadget,
+};
+
+/* -------------------------------------------------------------------------- */
+
+void dwc3_otg_run_sm(struct otg_fsm *fsm)
+{
+       struct dwc3_otg *dotg = container_of(fsm, struct dwc3_otg, fsm);
+       int             state_changed;
+
+       /* Prevent running SM on early system resume */
+       if (!dotg->ready)
+               return;
+
+       mutex_lock(&fsm->lock);
+
+       do {
+               state_changed = dwc3_otg_statemachine(fsm);
+       } while (state_changed > 0);
+
+       mutex_unlock(&fsm->lock);
+}
+
+/* Bind/Unbind the peripheral controller driver */
+static int dwc3_otg_set_peripheral(struct usb_otg *otg,
+                               struct usb_gadget *gadget)
+{
+       struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+       struct otg_fsm  *fsm = &dotg->fsm;
+       struct device   *dev = dotg->dwc->dev;
+
+       if (gadget) {
+               dev_info(dev, "Binding gadget %s\n", gadget->name);
+
+               otg->gadget = gadget;
+       } else {
+               dev_info(dev, "Unbinding gadget\n");
+
+               mutex_lock(&fsm->lock);
+
+               if (otg->state == OTG_STATE_B_PERIPHERAL) {
+                       /* Reset OTG Statemachine */
+                       fsm->reset = 1;
+                       dwc3_otg_statemachine(fsm);
+                       fsm->reset = 0;
+               }
+               otg->gadget = NULL;
+
+               mutex_unlock(&fsm->lock);
+
+               dwc3_otg_run_sm(fsm);
+       }
+
+       return 0;
+}
+
+static int dwc3_otg_get_id_state(struct dwc3_otg *dotg)
+{
+       u32 reg = dwc3_readl(dotg->regs, DWC3_OSTS);
+
+       return !!(reg & DWC3_OTG_OSTS_CONIDSTS);
+}
+
+static int dwc3_otg_get_b_sess_state(struct dwc3_otg *dotg)
+{
+       u32 reg = dwc3_readl(dotg->regs, DWC3_OSTS);
+
+       return !!(reg & DWC3_OTG_OSTS_BSESVALID);
+}
+
+static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
+{
+       struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
+       struct otg_fsm  *fsm = &dotg->fsm;
+       u32 oevt, handled_events = 0;
+       irqreturn_t ret = IRQ_NONE;
+
+       oevt = dwc3_readl(dotg->regs, DWC3_OEVT);
+
+       /* ID */
+       if (oevt & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) {
+               fsm->id = dwc3_otg_get_id_state(dotg);
+               handled_events |= DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT;
+       }
+
+       /* VBus */
+       if (oevt & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) {
+               fsm->b_sess_vld = dwc3_otg_get_b_sess_state(dotg);
+               handled_events |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
+       }
+
+       if (handled_events) {
+               dwc3_writel(dotg->regs, DWC3_OEVT, handled_events);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       return ret;
+}
+
+static irqreturn_t dwc3_otg_thread_interrupt(int irq, void *_dotg)
+{
+       struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
+
+       dwc3_otg_run_sm(&dotg->fsm);
+
+       return IRQ_HANDLED;
+}
+
+static void dwc3_otg_enable_irq(struct dwc3_otg *dotg)
+{
+       /* Enable only connector ID status & VBUS change events */
+       dwc3_writel(dotg->regs, DWC3_OEVTEN,
+                       DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
+                       DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
+}
+
+static void dwc3_otg_disable_irq(struct dwc3_otg *dotg)
+{
+       dwc3_writel(dotg->regs, DWC3_OEVTEN, 0x0);
+}
+
+static void dwc3_otg_reset(struct dwc3_otg *dotg)
+{
+       /*
+        * OCFG[2] - OTG-Version = 0
+        * OCFG[1] - HNPCap = 0
+        * OCFG[0] - SRPCap = 0
+        */
+       dwc3_writel(dotg->regs, DWC3_OCFG, 0x0);
+
+       /*
+        * OCTL[6] - PeriMode = 1
+        * OCTL[5] - PrtPwrCtl = 0
+        * OCTL[4] - HNPReq = 0
+        * OCTL[3] - SesReq = 0
+        * OCTL[2] - TermSelDLPulse = 0
+        * OCTL[1] - DevSetHNPEn = 0
+        * OCTL[0] - HstSetHNPEn = 0
+        */
+       dwc3_writel(dotg->regs, DWC3_OCTL, DWC3_OTG_OCTL_PERIMODE);
+
+       /* Clear all otg events (interrupts) indications  */
+       dwc3_writel(dotg->regs, DWC3_OEVT, DWC3_OEVT_CLEAR_ALL);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static ssize_t
+dwc3_otg_show_state(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       struct usb_otg  *otg = &dwc->dotg->otg;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       usb_otg_state_string(otg->state));
+}
+
+static DEVICE_ATTR(state, S_IRUSR | S_IRGRP,
+       dwc3_otg_show_state, NULL);
+
+static ssize_t
+dwc3_otg_show_b_sess(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       struct otg_fsm  *fsm = &dwc->dotg->fsm;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", fsm->b_sess_vld);
+}
+
+static ssize_t
+dwc3_otg_store_b_sess(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t n)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       struct otg_fsm  *fsm = &dwc->dotg->fsm;
+       int             b_sess_vld;
+
+       if (sscanf(buf, "%d", &b_sess_vld) != 1)
+               return -EINVAL;
+
+       fsm->b_sess_vld = !!b_sess_vld;
+
+       dwc3_otg_run_sm(fsm);
+
+       return n;
+}
+
+static DEVICE_ATTR(b_sess, S_IWUSR | S_IRUSR | S_IRGRP,
+       dwc3_otg_show_b_sess, dwc3_otg_store_b_sess);
+
+static ssize_t
+dwc3_otg_show_id(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       struct otg_fsm  *fsm = &dwc->dotg->fsm;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", fsm->id);
+}
+
+static ssize_t
+dwc3_otg_store_id(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t n)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       struct otg_fsm  *fsm = &dwc->dotg->fsm;
+       int id;
+
+       if (sscanf(buf, "%d", &id) != 1)
+               return -EINVAL;
+
+       fsm->id = !!id;
+
+       dwc3_otg_run_sm(fsm);
+
+       return n;
+}
+
+static DEVICE_ATTR(id, S_IWUSR | S_IRUSR | S_IRGRP,
+       dwc3_otg_show_id, dwc3_otg_store_id);
+
+static struct attribute *dwc3_otg_attributes[] = {
+       &dev_attr_id.attr,
+       &dev_attr_b_sess.attr,
+       &dev_attr_state.attr,
+       NULL
+};
+
+static const struct attribute_group dwc3_otg_attr_group = {
+       .attrs = dwc3_otg_attributes,
+};
+
+/**
+ * dwc3_otg_start
+ * @dwc: pointer to our controller context structure
+ */
+int dwc3_otg_start(struct dwc3 *dwc)
+{
+       struct dwc3_otg *dotg = dwc->dotg;
+       struct otg_fsm  *fsm = &dotg->fsm;
+       int             ret;
+
+       if (dotg->ext_otg_ops) {
+               ret = dwc3_ext_otg_start(dotg);
+               if (ret) {
+                       dev_err(dwc->dev, "failed to start external OTG\n");
+                       return ret;
+               }
+       } else {
+               dotg->regs = dwc->regs;
+
+               dwc3_otg_reset(dotg);
+
+               dotg->fsm.id = dwc3_otg_get_id_state(dotg);
+               dotg->fsm.b_sess_vld = dwc3_otg_get_b_sess_state(dotg);
+
+               dotg->irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+               ret = devm_request_threaded_irq(dwc->dev, dotg->irq,
+                               dwc3_otg_interrupt,
+                               dwc3_otg_thread_interrupt,
+                               IRQF_SHARED, "dwc3-otg", dotg);
+               if (ret) {
+                       dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+                                       dotg->irq, ret);
+                       return ret;
+               }
+
+               dwc3_otg_enable_irq(dotg);
+       }
+
+       dotg->ready = 1;
+
+       dwc3_otg_run_sm(fsm);
+
+       return 0;
+}
+
+/**
+ * dwc3_otg_stop
+ * @dwc: pointer to our controller context structure
+ */
+void dwc3_otg_stop(struct dwc3 *dwc)
+{
+       struct dwc3_otg         *dotg = dwc->dotg;
+
+       if (dotg->ext_otg_ops) {
+               dwc3_ext_otg_stop(dotg);
+       } else {
+               dwc3_otg_disable_irq(dotg);
+               free_irq(dotg->irq, dotg);
+       }
+
+       dotg->ready = 0;
+}
+
+/* -------------------------------------------------------------------------- */
+bool otg_is_connect(void)
+{
+       if (otg_connection)
+               return true;
+       else
+               return false;
+}
+EXPORT_SYMBOL_GPL(otg_is_connect);
+
+int dwc3_otg_init(struct dwc3 *dwc)
+{
+       struct dwc3_otg *dotg;
+       struct dwc3_ext_otg_ops *ops = NULL;
+       int ret = 0;
+#if defined(CONFIG_TYPEC)
+       struct intf_typec       *typec;
+       struct typec_partner_desc partner;
+#endif
+
+
+       dev_info(dwc->dev, "%s\n", __func__);
+
+       /* EXYNOS SoCs don't have HW OTG, but support SW OTG. */
+       ops = dwc3_otg_exynos_rsw_probe(dwc);
+       if (!ops)
+               return 0;
+
+       /* Allocate and init otg instance */
+       dotg = devm_kzalloc(dwc->dev, sizeof(struct dwc3_otg), GFP_KERNEL);
+       if (!dotg) {
+               dev_err(dwc->dev, "unable to allocate dwc3_otg\n");
+               return -ENOMEM;
+       }
+
+       /* This reference is used by dwc3 modules for checking otg existance */
+       dwc->dotg = dotg;
+       dotg->dwc = dwc;
+
+       ret = of_property_read_u32(dwc->dev->of_node,"ldos", &dotg->ldos);
+       if (ret < 0) {
+               dev_err(dwc->dev, "can't get ldo information\n");
+               return -EINVAL;
+       } else {
+               if (dotg->ldos) {
+                       dev_info(dwc->dev, "have %d LDOs for supporting USB L2 suspend \n", dotg->ldos);
+                       dotg->ldo_num = (int *)devm_kmalloc(dwc->dev, sizeof(int) * (dotg->ldos),
+                               GFP_KERNEL);
+                       ret = of_property_read_u32_array(dwc->dev->of_node,
+                                       "ldo_number", dotg->ldo_num, dotg->ldos);
+               } else {
+                       dev_info(dwc->dev, "don't have LDOs for supporting USB L2 suspend \n");
+               }
+       }
+
+       dotg->ext_otg_ops = ops;
+
+       dotg->otg.set_peripheral = dwc3_otg_set_peripheral;
+       dotg->otg.set_host = NULL;
+
+       dotg->otg.state = OTG_STATE_UNDEFINED;
+
+       mutex_init(&dotg->fsm.lock);
+       dotg->fsm.ops = &dwc3_otg_fsm_ops;
+       dotg->fsm.otg = &dotg->otg;
+
+       dotg->vbus_reg = devm_regulator_get(dwc->dev->parent, "dwc3-vbus");
+       if (IS_ERR(dotg->vbus_reg))
+               dev_err(dwc->dev, "failed to obtain vbus regulator\n");
+
+       if (dotg->ext_otg_ops) {
+               ret = dwc3_ext_otg_setup(dotg);
+               if (ret) {
+                       dev_err(dwc->dev, "failed to setup OTG\n");
+                       return ret;
+               }
+       }
+
+#if defined(CONFIG_TYPEC)
+       typec = devm_kzalloc(dwc->dev, sizeof(*typec), GFP_KERNEL);
+       if (!typec)
+               return -ENOMEM;
+
+       /* mutex_init(&md05->lock); */
+       typec->dev = dwc->dev;
+
+       typec->cap.type = TYPEC_PORT_DRP;
+       typec->cap.revision = USB_TYPEC_REV_1_1;
+       typec->cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
+
+       typec->port = typec_register_port(dwc->dev, &typec->cap);
+       if (!typec->port)
+               return -ENODEV;
+
+       typec_set_data_role(typec->port, TYPEC_DEVICE);
+       typec_set_pwr_role(typec->port, TYPEC_SINK);
+       typec_set_pwr_opmode(typec->port, TYPEC_PWR_MODE_USB);
+
+       dotg->typec = typec;
+
+       typec->partner = typec_register_partner(typec->port, &partner);
+       if (!dotg->typec->partner)
+               dev_err(dwc->dev, "failed register partner\n");
+#endif
+
+
+       wake_lock_init(&dotg->wakelock, WAKE_LOCK_SUSPEND, "dwc3-otg");
+
+       ret = sysfs_create_group(&dwc->dev->kobj, &dwc3_otg_attr_group);
+       if (ret)
+               dev_err(dwc->dev, "failed to create dwc3 otg attributes\n");
+
+#ifdef CONFIG_SOC_EXYNOS9810
+       register_usb_is_connect(NULL);
+#endif
+
+       return 0;
+}
+
+void dwc3_otg_exit(struct dwc3 *dwc)
+{
+       struct dwc3_otg *dotg = dwc->dotg;
+
+       if (!dotg->ext_otg_ops)
+               return;
+
+#if defined(CONFIG_TYPEC)
+       typec_unregister_partner(dotg->typec->partner);
+       typec_unregister_port(dotg->typec->port);
+#endif
+
+       dwc3_ext_otg_exit(dotg);
+
+       sysfs_remove_group(&dwc->dev->kobj, &dwc3_otg_attr_group);
+       wake_lock_destroy(&dotg->wakelock);
+       free_irq(dotg->irq, dotg);
+       dotg->otg.state = OTG_STATE_UNDEFINED;
+       kfree(dotg);
+       dwc->dotg = NULL;
+}
index d51dafd95d08dbe47e970f1e9777ebf628e55e99..2c850d32f146171b52ab06df12738bf0e5a9a5c3 100644 (file)
-/**\r
- * otg.c - DesignWare USB3 DRD Controller OTG\r
- *\r
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.\r
- * Copyright (c) 2013 Samsung Electronics Co., Ltd.\r
- *             http://www.samsung.com\r
- *\r
- * Authors: Ido Shayevitz <idos@codeaurora.org>\r
- *         Anton Tikhomirov <av.tikhomirov@samsung.com>\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License version 2  of\r
- * the License as published by the Free Software Foundation.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- */\r
-\r
-#ifndef __LINUX_USB_DWC3_OTG_H\r
-#define __LINUX_USB_DWC3_OTG_H\r
-#include <linux/wakelock.h>\r
-#include <linux/usb/otg-fsm.h>\r
-\r
-struct dwc3_ext_otg_ops {\r
-       int     (*setup)(struct device *dev, struct otg_fsm *fsm);\r
-       void    (*exit)(struct device *dev);\r
-       int     (*start) (struct device *dev);\r
-       void    (*stop)(struct device *dev);\r
-};\r
-\r
-/**\r
- * struct dwc3_otg: OTG driver data. Shared by HCD and DCD.\r
- * @otg: USB OTG Transceiver structure.\r
- * @fsm: OTG Final State Machine.\r
- * @dwc: pointer to our controller context structure.\r
- * @irq: IRQ number assigned for HSUSB controller.\r
- * @regs: ioremapped register base address.\r
- * @wakelock: prevents the system from entering suspend while\r
- *             host or peripheral mode is active.\r
- * @vbus_reg: Vbus regulator.\r
- * @ready: is one when OTG is ready for operation.\r
- * @ext_otg_ops: external OTG engine ops.\r
- */\r
-struct dwc3_otg {\r
-       struct usb_otg          otg;\r
-       struct otg_fsm          fsm;\r
-       struct dwc3             *dwc;\r
-       int                     irq;\r
-       void __iomem            *regs;\r
-       struct wake_lock        wakelock;\r
-\r
-       unsigned                ready:1;\r
-       int                     otg_connection;\r
-\r
-       struct regulator        *vbus_reg;\r
-       int                     *ldo_num;\r
-       int                     ldos;\r
-\r
-       struct dwc3_ext_otg_ops *ext_otg_ops;\r
-};\r
-\r
-static inline int dwc3_ext_otg_setup(struct dwc3_otg *dotg)\r
-{\r
-       struct device *dev = dotg->dwc->dev->parent;\r
-\r
-       if (!dotg->ext_otg_ops->setup)\r
-               return -EOPNOTSUPP;\r
-       return dotg->ext_otg_ops->setup(dev, &dotg->fsm);\r
-}\r
-\r
-static inline int dwc3_ext_otg_exit(struct dwc3_otg *dotg)\r
-{\r
-       struct device *dev = dotg->dwc->dev->parent;\r
-\r
-       if (!dotg->ext_otg_ops->exit)\r
-               return -EOPNOTSUPP;\r
-       dotg->ext_otg_ops->exit(dev);\r
-       return 0;\r
-}\r
-\r
-static inline int dwc3_ext_otg_start(struct dwc3_otg *dotg)\r
-{\r
-       struct device *dev = dotg->dwc->dev->parent;\r
-\r
-       if (!dotg->ext_otg_ops->start)\r
-               return -EOPNOTSUPP;\r
-       return dotg->ext_otg_ops->start(dev);\r
-}\r
-\r
-static inline int dwc3_ext_otg_stop(struct dwc3_otg *dotg)\r
-{\r
-       struct device *dev = dotg->dwc->dev->parent;\r
-\r
-       if (!dotg->ext_otg_ops->stop)\r
-               return -EOPNOTSUPP;\r
-       dotg->ext_otg_ops->stop(dev);\r
-       return 0;\r
-}\r
-\r
-bool dwc3_exynos_rsw_available(struct device *dev);\r
-int dwc3_exynos_rsw_setup(struct device *dev, struct otg_fsm *fsm);\r
-void dwc3_exynos_rsw_exit(struct device *dev);\r
-int dwc3_exynos_rsw_start(struct device *dev);\r
-void dwc3_exynos_rsw_stop(struct device *dev);\r
-\r
-#endif /* __LINUX_USB_DWC3_OTG_H */\r
+/**
+ * otg.c - DesignWare USB3 DRD Controller OTG
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Authors: Ido Shayevitz <idos@codeaurora.org>
+ *         Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_DWC3_OTG_H
+#define __LINUX_USB_DWC3_OTG_H
+#include <linux/wakelock.h>
+#include <linux/usb/otg-fsm.h>
+
+struct dwc3_ext_otg_ops {
+       int     (*setup)(struct device *dev, struct otg_fsm *fsm);
+       void    (*exit)(struct device *dev);
+       int     (*start) (struct device *dev);
+       void    (*stop)(struct device *dev);
+};
+
+/**
+ * struct dwc3_otg: OTG driver data. Shared by HCD and DCD.
+ * @otg: USB OTG Transceiver structure.
+ * @fsm: OTG Final State Machine.
+ * @dwc: pointer to our controller context structure.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @regs: ioremapped register base address.
+ * @wakelock: prevents the system from entering suspend while
+ *             host or peripheral mode is active.
+ * @vbus_reg: Vbus regulator.
+ * @ready: is one when OTG is ready for operation.
+ * @ext_otg_ops: external OTG engine ops.
+ */
+struct dwc3_otg {
+       struct usb_otg          otg;
+       struct otg_fsm          fsm;
+       struct dwc3             *dwc;
+       int                     irq;
+       void __iomem            *regs;
+       struct wake_lock        wakelock;
+
+       unsigned                ready:1;
+       int                     otg_connection;
+
+       struct regulator        *vbus_reg;
+       int                     *ldo_num;
+       int                     ldos;
+
+       struct dwc3_ext_otg_ops *ext_otg_ops;
+#if defined(CONFIG_TYPEC)
+       struct intf_typec       *typec;
+#endif
+};
+
+static inline int dwc3_ext_otg_setup(struct dwc3_otg *dotg)
+{
+       struct device *dev = dotg->dwc->dev->parent;
+
+       if (!dotg->ext_otg_ops->setup)
+               return -EOPNOTSUPP;
+       return dotg->ext_otg_ops->setup(dev, &dotg->fsm);
+}
+
+static inline int dwc3_ext_otg_exit(struct dwc3_otg *dotg)
+{
+       struct device *dev = dotg->dwc->dev->parent;
+
+       if (!dotg->ext_otg_ops->exit)
+               return -EOPNOTSUPP;
+       dotg->ext_otg_ops->exit(dev);
+       return 0;
+}
+
+static inline int dwc3_ext_otg_start(struct dwc3_otg *dotg)
+{
+       struct device *dev = dotg->dwc->dev->parent;
+
+       if (!dotg->ext_otg_ops->start)
+               return -EOPNOTSUPP;
+       return dotg->ext_otg_ops->start(dev);
+}
+
+static inline int dwc3_ext_otg_stop(struct dwc3_otg *dotg)
+{
+       struct device *dev = dotg->dwc->dev->parent;
+
+       if (!dotg->ext_otg_ops->stop)
+               return -EOPNOTSUPP;
+       dotg->ext_otg_ops->stop(dev);
+       return 0;
+}
+
+bool dwc3_exynos_rsw_available(struct device *dev);
+int dwc3_exynos_rsw_setup(struct device *dev, struct otg_fsm *fsm);
+void dwc3_exynos_rsw_exit(struct device *dev);
+int dwc3_exynos_rsw_start(struct device *dev);
+void dwc3_exynos_rsw_stop(struct device *dev);
+
+#endif /* __LINUX_USB_DWC3_OTG_H */