Loading Documentation/devicetree/bindings/usb/msm-hsusb.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -68,6 +68,7 @@ Optional properties : - interrupt-names : Optional interrupt resource entries are: - interrupt-names : Optional interrupt resource entries are: "async_irq" : Interrupt from HSPHY for asynchronous wakeup events in LPM. "async_irq" : Interrupt from HSPHY for asynchronous wakeup events in LPM. "pmic_id_irq" : Interrupt from PMIC for external ID pin notification. "pmic_id_irq" : Interrupt from PMIC for external ID pin notification. "phy_irq" : Interrupt from PHY. Used for ID detection. - qcom,hsusb-otg-disable-reset: If present then core is RESET only during - qcom,hsusb-otg-disable-reset: If present then core is RESET only during init, otherwise core is RESET for every cable disconnect as well init, otherwise core is RESET for every cable disconnect as well - qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC - qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC Loading drivers/usb/phy/phy-msm-usb.c +108 −5 Original line number Original line Diff line number Diff line Loading @@ -756,6 +756,9 @@ static int msm_otg_reset(struct usb_phy *phy) ULPI_SET(ULPI_PWR_CLK_MNG_REG)); ULPI_SET(ULPI_PWR_CLK_MNG_REG)); /* Enable PMIC pull-up */ /* Enable PMIC pull-up */ pm8xxx_usb_id_pullup(1); pm8xxx_usb_id_pullup(1); if (motg->phy_irq) writeb_relaxed(USB_PHY_ID_MASK, USB2_PHY_USB_PHY_INTERRUPT_MASK1); } } if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) Loading Loading @@ -1098,7 +1101,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg) bool dp_dm_hv_int = false; bool dp_dm_hv_int = false; u32 val; u32 val; if (motg->pdata->otg_control == OTG_PHY_CONTROL) if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq) bsv_id_hv_int = true; bsv_id_hv_int = true; if (motg->host_bus_suspend || motg->device_bus_suspend) if (motg->host_bus_suspend || motg->device_bus_suspend) dp_dm_hv_int = true; dp_dm_hv_int = true; Loading Loading @@ -1130,6 +1134,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg) default: default: break; break; } } pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n", __func__, bsv_id_hv_int, dp_dm_hv_int); } } static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) Loading @@ -1138,7 +1144,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) bool dp_dm_hv_int = false; bool dp_dm_hv_int = false; u32 val; u32 val; if (motg->pdata->otg_control == OTG_PHY_CONTROL) if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq) bsv_id_hv_int = true; bsv_id_hv_int = true; if (motg->host_bus_suspend || motg->device_bus_suspend) if (motg->host_bus_suspend || motg->device_bus_suspend) dp_dm_hv_int = true; dp_dm_hv_int = true; Loading Loading @@ -1171,6 +1178,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) default: default: break; break; } } pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n", __func__, bsv_id_hv_int, dp_dm_hv_int); } } static void msm_otg_enter_phy_retention(struct msm_otg *motg) static void msm_otg_enter_phy_retention(struct msm_otg *motg) Loading @@ -1192,6 +1201,7 @@ static void msm_otg_enter_phy_retention(struct msm_otg *motg) default: default: break; break; } } pr_debug("USB PHY is in retention\n"); } } static void msm_otg_exit_phy_retention(struct msm_otg *motg) static void msm_otg_exit_phy_retention(struct msm_otg *motg) Loading @@ -1214,6 +1224,25 @@ static void msm_otg_exit_phy_retention(struct msm_otg *motg) default: default: break; break; } } pr_debug("USB PHY is exited from retention\n"); } static void msm_id_status_w(struct work_struct *w); static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data) { struct msm_otg *motg = data; if (atomic_read(&motg->in_lpm)) { pr_debug("PHY ID IRQ in LPM\n"); motg->phy_irq_pending = true; if (!atomic_read(&motg->pm_suspended)) pm_request_resume(motg->phy.dev); } else { pr_debug("PHY ID IRQ outside LPM\n"); msm_id_status_w(&motg->id_status_work.work); } return IRQ_HANDLED; } } #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) Loading Loading @@ -1471,6 +1500,8 @@ phcd_retry: else else enable_irq_wake(motg->irq); enable_irq_wake(motg->irq); if (motg->phy_irq) enable_irq_wake(motg->phy_irq); if (motg->pdata->pmic_id_irq) if (motg->pdata->pmic_id_irq) enable_irq_wake(motg->pdata->pmic_id_irq); enable_irq_wake(motg->pdata->pmic_id_irq); if (motg->ext_id_irq) if (motg->ext_id_irq) Loading Loading @@ -1658,6 +1689,8 @@ skip_phy_resume: else else disable_irq_wake(motg->irq); disable_irq_wake(motg->irq); if (motg->phy_irq) disable_irq_wake(motg->phy_irq); if (motg->pdata->pmic_id_irq) if (motg->pdata->pmic_id_irq) disable_irq_wake(motg->pdata->pmic_id_irq); disable_irq_wake(motg->pdata->pmic_id_irq); if (motg->ext_id_irq) if (motg->ext_id_irq) Loading Loading @@ -1691,6 +1724,11 @@ skip_phy_resume: if (motg->async_irq) if (motg->async_irq) disable_irq(motg->async_irq); disable_irq(motg->async_irq); if (motg->phy_irq_pending) { motg->phy_irq_pending = false; msm_id_status_w(&motg->id_status_work.work); } if (motg->host_bus_suspend) if (motg->host_bus_suspend) usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(hcd); Loading Loading @@ -2212,6 +2250,31 @@ static bool msm_otg_read_pmic_id_state(struct msm_otg *motg) return !!id; return !!id; } } static bool msm_otg_read_phy_id_state(struct msm_otg *motg) { u8 val; /* * clear the pending/outstanding interrupts and * read the ID status from the SRC_STATUS register. */ writeb_relaxed(USB_PHY_ID_MASK, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1); writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD); /* * Databook says 200 usec delay is required for * clearing the interrupts. */ udelay(200); writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD); val = readb_relaxed(USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS); if (val & USB_PHY_IDDIG_1_0) return false; /* ID is grounded */ else return true; } static int msm_otg_mhl_register_callback(struct msm_otg *motg, static int msm_otg_mhl_register_callback(struct msm_otg *motg, void (*callback)(int on)) void (*callback)(int on)) { { Loading Loading @@ -2922,6 +2985,11 @@ static void msm_otg_init_sm(struct msm_otg *motg) set_bit(ID, &motg->inputs); set_bit(ID, &motg->inputs); else else clear_bit(ID, &motg->inputs); clear_bit(ID, &motg->inputs); } else if (motg->phy_irq) { if (msm_otg_read_phy_id_state(motg)) set_bit(ID, &motg->inputs); else clear_bit(ID, &motg->inputs); } } /* /* * VBUS initial state is reported after PMIC * VBUS initial state is reported after PMIC Loading Loading @@ -3870,6 +3938,8 @@ static void msm_id_status_w(struct work_struct *w) id_state = msm_otg_read_pmic_id_state(motg); id_state = msm_otg_read_pmic_id_state(motg); else if (motg->ext_id_irq) else if (motg->ext_id_irq) id_state = gpio_get_value(motg->pdata->usb_id_gpio); id_state = gpio_get_value(motg->pdata->usb_id_gpio); else if (motg->phy_irq) id_state = msm_otg_read_phy_id_state(motg); if (id_state) { if (id_state) { if (!test_and_set_bit(ID, &motg->inputs)) { if (!test_and_set_bit(ID, &motg->inputs)) { Loading Loading @@ -5313,12 +5383,38 @@ static int msm_otg_probe(struct platform_device *pdev) goto destroy_wlock; goto destroy_wlock; } } motg->phy_irq = platform_get_irq_byname(pdev, "phy_irq"); if (motg->phy_irq < 0) { dev_dbg(&pdev->dev, "phy_irq is not present\n"); motg->phy_irq = 0; } else { /* clear all interrupts before enabling the IRQ */ writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR0); writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1); writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD); /* * Databook says 200 usec delay is required for * clearing the interrupts. */ udelay(200); writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD); ret = request_irq(motg->phy_irq, msm_otg_phy_irq_handler, IRQF_TRIGGER_RISING, "msm_otg_phy_irq", motg); if (ret < 0) { dev_err(&pdev->dev, "phy_irq request fail %d\n", ret); goto free_irq; } } if (motg->async_irq) { if (motg->async_irq) { ret = request_irq(motg->async_irq, msm_otg_irq, ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_TRIGGER_RISING, "msm_otg", motg); IRQF_TRIGGER_RISING, "msm_otg", motg); if (ret) { if (ret) { dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n"); dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n"); goto free_irq; goto free_phy_irq; } } disable_irq(motg->async_irq); disable_irq(motg->async_irq); } } Loading Loading @@ -5355,7 +5451,8 @@ static int msm_otg_probe(struct platform_device *pdev) } } if (motg->pdata->mode == USB_OTG && if (motg->pdata->mode == USB_OTG && motg->pdata->otg_control == OTG_PMIC_CONTROL) { motg->pdata->otg_control == OTG_PMIC_CONTROL && !motg->phy_irq) { if (gpio_is_valid(motg->pdata->usb_id_gpio)) { if (gpio_is_valid(motg->pdata->usb_id_gpio)) { /* usb_id_gpio request */ /* usb_id_gpio request */ Loading Loading @@ -5406,7 +5503,7 @@ static int msm_otg_probe(struct platform_device *pdev) motg->pdata->pmic_id_irq || motg->ext_id_irq)) motg->pdata->pmic_id_irq || motg->ext_id_irq)) motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION; motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION; if (motg->pdata->otg_control == OTG_PHY_CONTROL) if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq) motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM; motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM; if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int) if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int) Loading Loading @@ -5494,6 +5591,9 @@ remove_phy: free_async_irq: free_async_irq: if (motg->async_irq) if (motg->async_irq) free_irq(motg->async_irq, motg); free_irq(motg->async_irq, motg); free_phy_irq: if (motg->phy_irq) free_irq(motg->phy_irq, motg); free_irq: free_irq: free_irq(motg->irq, motg); free_irq(motg->irq, motg); destroy_wlock: destroy_wlock: Loading Loading @@ -5585,6 +5685,8 @@ static int msm_otg_remove(struct platform_device *pdev) wake_lock_destroy(&motg->wlock); wake_lock_destroy(&motg->wlock); msm_hsusb_mhl_switch_enable(motg, 0); msm_hsusb_mhl_switch_enable(motg, 0); if (motg->phy_irq) free_irq(motg->phy_irq, motg); if (motg->pdata->pmic_id_irq) if (motg->pdata->pmic_id_irq) free_irq(motg->pdata->pmic_id_irq, motg); free_irq(motg->pdata->pmic_id_irq, motg); usb_remove_phy(phy); usb_remove_phy(phy); Loading Loading @@ -5735,6 +5837,7 @@ static int msm_otg_pm_resume(struct device *dev) motg->pm_done = 0; motg->pm_done = 0; if (motg->async_int || motg->sm_work_pending || if (motg->async_int || motg->sm_work_pending || motg->phy_irq_pending || !pm_runtime_suspended(dev)) { !pm_runtime_suspended(dev)) { pm_runtime_get_noresume(dev); pm_runtime_get_noresume(dev); ret = msm_otg_resume(motg); ret = msm_otg_resume(motg); Loading include/linux/usb/msm_hsusb.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -357,6 +357,8 @@ struct msm_otg_platform_data { * @pdata: otg device platform data. * @pdata: otg device platform data. * @irq: IRQ number assigned for HSUSB controller. * @irq: IRQ number assigned for HSUSB controller. * @async_irq: IRQ number used by some controllers during low power state * @async_irq: IRQ number used by some controllers during low power state * @phy_irq: IRQ number assigned for PHY to notify events like id and line state changes. * @pclk: clock struct of iface_clk. * @pclk: clock struct of iface_clk. * @core_clk: clock struct of core_bus_clk. * @core_clk: clock struct of core_bus_clk. * @sleep_clk: clock struct of sleep_clk for USB PHY. * @sleep_clk: clock struct of sleep_clk for USB PHY. Loading Loading @@ -408,12 +410,14 @@ struct msm_otg_platform_data { the charger detection starts. When USB is disconnected and in lpm the charger detection starts. When USB is disconnected and in lpm pm_done is set to true. pm_done is set to true. * @ext_id_irq: IRQ for ID interrupt. * @ext_id_irq: IRQ for ID interrupt. * @phy_irq_pending: Gets set when PHY IRQ arrives in LPM. */ */ struct msm_otg { struct msm_otg { struct usb_phy phy; struct usb_phy phy; struct msm_otg_platform_data *pdata; struct msm_otg_platform_data *pdata; int irq; int irq; int async_irq; int async_irq; int phy_irq; struct clk *xo_clk; struct clk *xo_clk; struct clk *pclk; struct clk *pclk; struct clk *core_clk; struct clk *core_clk; Loading Loading @@ -546,6 +550,7 @@ struct msm_otg { bool pm_done; bool pm_done; struct qpnp_vadc_chip *vadc_dev; struct qpnp_vadc_chip *vadc_dev; int ext_id_irq; int ext_id_irq; bool phy_irq_pending; }; }; struct ci13xxx_platform_data { struct ci13xxx_platform_data { Loading include/linux/usb/msm_hsusb_hw.h +18 −0 Original line number Original line Diff line number Diff line Loading @@ -135,4 +135,22 @@ #define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094) #define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094) #define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2) #define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2) #define USB2_PHY_USB_PHY_IRQ_CMD (MSM_USB_PHY_CSR_BASE + 0x0D0) #define USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS (MSM_USB_PHY_CSR_BASE + 0x05C) #define USB2_PHY_USB_PHY_INTERRUPT_STATUS0 (MSM_USB_PHY_CSR_BASE + 0x03C) #define USB2_PHY_USB_PHY_INTERRUPT_STATUS1 (MSM_USB_PHY_CSR_BASE + 0x040) #define USB2_PHY_USB_PHY_INTERRUPT_CLEAR0 (MSM_USB_PHY_CSR_BASE + 0x0DC) #define USB2_PHY_USB_PHY_INTERRUPT_CLEAR1 (MSM_USB_PHY_CSR_BASE + 0x0E0) #define USB2_PHY_USB_PHY_INTERRUPT_MASK0 (MSM_USB_PHY_CSR_BASE + 0x0D4) #define USB2_PHY_USB_PHY_INTERRUPT_MASK1 (MSM_USB_PHY_CSR_BASE + 0x0D8) #define USB_PHY_IDDIG_1_0 BIT(7) #define USB_PHY_IDDIG_RISE_MASK BIT(0) #define USB_PHY_IDDIG_FALL_MASK BIT(1) #define USB_PHY_ID_MASK (USB_PHY_IDDIG_RISE_MASK | USB_PHY_IDDIG_FALL_MASK) #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */ #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */ Loading
Documentation/devicetree/bindings/usb/msm-hsusb.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -68,6 +68,7 @@ Optional properties : - interrupt-names : Optional interrupt resource entries are: - interrupt-names : Optional interrupt resource entries are: "async_irq" : Interrupt from HSPHY for asynchronous wakeup events in LPM. "async_irq" : Interrupt from HSPHY for asynchronous wakeup events in LPM. "pmic_id_irq" : Interrupt from PMIC for external ID pin notification. "pmic_id_irq" : Interrupt from PMIC for external ID pin notification. "phy_irq" : Interrupt from PHY. Used for ID detection. - qcom,hsusb-otg-disable-reset: If present then core is RESET only during - qcom,hsusb-otg-disable-reset: If present then core is RESET only during init, otherwise core is RESET for every cable disconnect as well init, otherwise core is RESET for every cable disconnect as well - qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC - qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC Loading
drivers/usb/phy/phy-msm-usb.c +108 −5 Original line number Original line Diff line number Diff line Loading @@ -756,6 +756,9 @@ static int msm_otg_reset(struct usb_phy *phy) ULPI_SET(ULPI_PWR_CLK_MNG_REG)); ULPI_SET(ULPI_PWR_CLK_MNG_REG)); /* Enable PMIC pull-up */ /* Enable PMIC pull-up */ pm8xxx_usb_id_pullup(1); pm8xxx_usb_id_pullup(1); if (motg->phy_irq) writeb_relaxed(USB_PHY_ID_MASK, USB2_PHY_USB_PHY_INTERRUPT_MASK1); } } if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) Loading Loading @@ -1098,7 +1101,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg) bool dp_dm_hv_int = false; bool dp_dm_hv_int = false; u32 val; u32 val; if (motg->pdata->otg_control == OTG_PHY_CONTROL) if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq) bsv_id_hv_int = true; bsv_id_hv_int = true; if (motg->host_bus_suspend || motg->device_bus_suspend) if (motg->host_bus_suspend || motg->device_bus_suspend) dp_dm_hv_int = true; dp_dm_hv_int = true; Loading Loading @@ -1130,6 +1134,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg) default: default: break; break; } } pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n", __func__, bsv_id_hv_int, dp_dm_hv_int); } } static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) Loading @@ -1138,7 +1144,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) bool dp_dm_hv_int = false; bool dp_dm_hv_int = false; u32 val; u32 val; if (motg->pdata->otg_control == OTG_PHY_CONTROL) if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq) bsv_id_hv_int = true; bsv_id_hv_int = true; if (motg->host_bus_suspend || motg->device_bus_suspend) if (motg->host_bus_suspend || motg->device_bus_suspend) dp_dm_hv_int = true; dp_dm_hv_int = true; Loading Loading @@ -1171,6 +1178,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg) default: default: break; break; } } pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n", __func__, bsv_id_hv_int, dp_dm_hv_int); } } static void msm_otg_enter_phy_retention(struct msm_otg *motg) static void msm_otg_enter_phy_retention(struct msm_otg *motg) Loading @@ -1192,6 +1201,7 @@ static void msm_otg_enter_phy_retention(struct msm_otg *motg) default: default: break; break; } } pr_debug("USB PHY is in retention\n"); } } static void msm_otg_exit_phy_retention(struct msm_otg *motg) static void msm_otg_exit_phy_retention(struct msm_otg *motg) Loading @@ -1214,6 +1224,25 @@ static void msm_otg_exit_phy_retention(struct msm_otg *motg) default: default: break; break; } } pr_debug("USB PHY is exited from retention\n"); } static void msm_id_status_w(struct work_struct *w); static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data) { struct msm_otg *motg = data; if (atomic_read(&motg->in_lpm)) { pr_debug("PHY ID IRQ in LPM\n"); motg->phy_irq_pending = true; if (!atomic_read(&motg->pm_suspended)) pm_request_resume(motg->phy.dev); } else { pr_debug("PHY ID IRQ outside LPM\n"); msm_id_status_w(&motg->id_status_work.work); } return IRQ_HANDLED; } } #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) Loading Loading @@ -1471,6 +1500,8 @@ phcd_retry: else else enable_irq_wake(motg->irq); enable_irq_wake(motg->irq); if (motg->phy_irq) enable_irq_wake(motg->phy_irq); if (motg->pdata->pmic_id_irq) if (motg->pdata->pmic_id_irq) enable_irq_wake(motg->pdata->pmic_id_irq); enable_irq_wake(motg->pdata->pmic_id_irq); if (motg->ext_id_irq) if (motg->ext_id_irq) Loading Loading @@ -1658,6 +1689,8 @@ skip_phy_resume: else else disable_irq_wake(motg->irq); disable_irq_wake(motg->irq); if (motg->phy_irq) disable_irq_wake(motg->phy_irq); if (motg->pdata->pmic_id_irq) if (motg->pdata->pmic_id_irq) disable_irq_wake(motg->pdata->pmic_id_irq); disable_irq_wake(motg->pdata->pmic_id_irq); if (motg->ext_id_irq) if (motg->ext_id_irq) Loading Loading @@ -1691,6 +1724,11 @@ skip_phy_resume: if (motg->async_irq) if (motg->async_irq) disable_irq(motg->async_irq); disable_irq(motg->async_irq); if (motg->phy_irq_pending) { motg->phy_irq_pending = false; msm_id_status_w(&motg->id_status_work.work); } if (motg->host_bus_suspend) if (motg->host_bus_suspend) usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(hcd); Loading Loading @@ -2212,6 +2250,31 @@ static bool msm_otg_read_pmic_id_state(struct msm_otg *motg) return !!id; return !!id; } } static bool msm_otg_read_phy_id_state(struct msm_otg *motg) { u8 val; /* * clear the pending/outstanding interrupts and * read the ID status from the SRC_STATUS register. */ writeb_relaxed(USB_PHY_ID_MASK, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1); writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD); /* * Databook says 200 usec delay is required for * clearing the interrupts. */ udelay(200); writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD); val = readb_relaxed(USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS); if (val & USB_PHY_IDDIG_1_0) return false; /* ID is grounded */ else return true; } static int msm_otg_mhl_register_callback(struct msm_otg *motg, static int msm_otg_mhl_register_callback(struct msm_otg *motg, void (*callback)(int on)) void (*callback)(int on)) { { Loading Loading @@ -2922,6 +2985,11 @@ static void msm_otg_init_sm(struct msm_otg *motg) set_bit(ID, &motg->inputs); set_bit(ID, &motg->inputs); else else clear_bit(ID, &motg->inputs); clear_bit(ID, &motg->inputs); } else if (motg->phy_irq) { if (msm_otg_read_phy_id_state(motg)) set_bit(ID, &motg->inputs); else clear_bit(ID, &motg->inputs); } } /* /* * VBUS initial state is reported after PMIC * VBUS initial state is reported after PMIC Loading Loading @@ -3870,6 +3938,8 @@ static void msm_id_status_w(struct work_struct *w) id_state = msm_otg_read_pmic_id_state(motg); id_state = msm_otg_read_pmic_id_state(motg); else if (motg->ext_id_irq) else if (motg->ext_id_irq) id_state = gpio_get_value(motg->pdata->usb_id_gpio); id_state = gpio_get_value(motg->pdata->usb_id_gpio); else if (motg->phy_irq) id_state = msm_otg_read_phy_id_state(motg); if (id_state) { if (id_state) { if (!test_and_set_bit(ID, &motg->inputs)) { if (!test_and_set_bit(ID, &motg->inputs)) { Loading Loading @@ -5313,12 +5383,38 @@ static int msm_otg_probe(struct platform_device *pdev) goto destroy_wlock; goto destroy_wlock; } } motg->phy_irq = platform_get_irq_byname(pdev, "phy_irq"); if (motg->phy_irq < 0) { dev_dbg(&pdev->dev, "phy_irq is not present\n"); motg->phy_irq = 0; } else { /* clear all interrupts before enabling the IRQ */ writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR0); writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1); writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD); /* * Databook says 200 usec delay is required for * clearing the interrupts. */ udelay(200); writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD); ret = request_irq(motg->phy_irq, msm_otg_phy_irq_handler, IRQF_TRIGGER_RISING, "msm_otg_phy_irq", motg); if (ret < 0) { dev_err(&pdev->dev, "phy_irq request fail %d\n", ret); goto free_irq; } } if (motg->async_irq) { if (motg->async_irq) { ret = request_irq(motg->async_irq, msm_otg_irq, ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_TRIGGER_RISING, "msm_otg", motg); IRQF_TRIGGER_RISING, "msm_otg", motg); if (ret) { if (ret) { dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n"); dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n"); goto free_irq; goto free_phy_irq; } } disable_irq(motg->async_irq); disable_irq(motg->async_irq); } } Loading Loading @@ -5355,7 +5451,8 @@ static int msm_otg_probe(struct platform_device *pdev) } } if (motg->pdata->mode == USB_OTG && if (motg->pdata->mode == USB_OTG && motg->pdata->otg_control == OTG_PMIC_CONTROL) { motg->pdata->otg_control == OTG_PMIC_CONTROL && !motg->phy_irq) { if (gpio_is_valid(motg->pdata->usb_id_gpio)) { if (gpio_is_valid(motg->pdata->usb_id_gpio)) { /* usb_id_gpio request */ /* usb_id_gpio request */ Loading Loading @@ -5406,7 +5503,7 @@ static int msm_otg_probe(struct platform_device *pdev) motg->pdata->pmic_id_irq || motg->ext_id_irq)) motg->pdata->pmic_id_irq || motg->ext_id_irq)) motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION; motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION; if (motg->pdata->otg_control == OTG_PHY_CONTROL) if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq) motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM; motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM; if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int) if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int) Loading Loading @@ -5494,6 +5591,9 @@ remove_phy: free_async_irq: free_async_irq: if (motg->async_irq) if (motg->async_irq) free_irq(motg->async_irq, motg); free_irq(motg->async_irq, motg); free_phy_irq: if (motg->phy_irq) free_irq(motg->phy_irq, motg); free_irq: free_irq: free_irq(motg->irq, motg); free_irq(motg->irq, motg); destroy_wlock: destroy_wlock: Loading Loading @@ -5585,6 +5685,8 @@ static int msm_otg_remove(struct platform_device *pdev) wake_lock_destroy(&motg->wlock); wake_lock_destroy(&motg->wlock); msm_hsusb_mhl_switch_enable(motg, 0); msm_hsusb_mhl_switch_enable(motg, 0); if (motg->phy_irq) free_irq(motg->phy_irq, motg); if (motg->pdata->pmic_id_irq) if (motg->pdata->pmic_id_irq) free_irq(motg->pdata->pmic_id_irq, motg); free_irq(motg->pdata->pmic_id_irq, motg); usb_remove_phy(phy); usb_remove_phy(phy); Loading Loading @@ -5735,6 +5837,7 @@ static int msm_otg_pm_resume(struct device *dev) motg->pm_done = 0; motg->pm_done = 0; if (motg->async_int || motg->sm_work_pending || if (motg->async_int || motg->sm_work_pending || motg->phy_irq_pending || !pm_runtime_suspended(dev)) { !pm_runtime_suspended(dev)) { pm_runtime_get_noresume(dev); pm_runtime_get_noresume(dev); ret = msm_otg_resume(motg); ret = msm_otg_resume(motg); Loading
include/linux/usb/msm_hsusb.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -357,6 +357,8 @@ struct msm_otg_platform_data { * @pdata: otg device platform data. * @pdata: otg device platform data. * @irq: IRQ number assigned for HSUSB controller. * @irq: IRQ number assigned for HSUSB controller. * @async_irq: IRQ number used by some controllers during low power state * @async_irq: IRQ number used by some controllers during low power state * @phy_irq: IRQ number assigned for PHY to notify events like id and line state changes. * @pclk: clock struct of iface_clk. * @pclk: clock struct of iface_clk. * @core_clk: clock struct of core_bus_clk. * @core_clk: clock struct of core_bus_clk. * @sleep_clk: clock struct of sleep_clk for USB PHY. * @sleep_clk: clock struct of sleep_clk for USB PHY. Loading Loading @@ -408,12 +410,14 @@ struct msm_otg_platform_data { the charger detection starts. When USB is disconnected and in lpm the charger detection starts. When USB is disconnected and in lpm pm_done is set to true. pm_done is set to true. * @ext_id_irq: IRQ for ID interrupt. * @ext_id_irq: IRQ for ID interrupt. * @phy_irq_pending: Gets set when PHY IRQ arrives in LPM. */ */ struct msm_otg { struct msm_otg { struct usb_phy phy; struct usb_phy phy; struct msm_otg_platform_data *pdata; struct msm_otg_platform_data *pdata; int irq; int irq; int async_irq; int async_irq; int phy_irq; struct clk *xo_clk; struct clk *xo_clk; struct clk *pclk; struct clk *pclk; struct clk *core_clk; struct clk *core_clk; Loading Loading @@ -546,6 +550,7 @@ struct msm_otg { bool pm_done; bool pm_done; struct qpnp_vadc_chip *vadc_dev; struct qpnp_vadc_chip *vadc_dev; int ext_id_irq; int ext_id_irq; bool phy_irq_pending; }; }; struct ci13xxx_platform_data { struct ci13xxx_platform_data { Loading
include/linux/usb/msm_hsusb_hw.h +18 −0 Original line number Original line Diff line number Diff line Loading @@ -135,4 +135,22 @@ #define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094) #define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094) #define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2) #define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2) #define USB2_PHY_USB_PHY_IRQ_CMD (MSM_USB_PHY_CSR_BASE + 0x0D0) #define USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS (MSM_USB_PHY_CSR_BASE + 0x05C) #define USB2_PHY_USB_PHY_INTERRUPT_STATUS0 (MSM_USB_PHY_CSR_BASE + 0x03C) #define USB2_PHY_USB_PHY_INTERRUPT_STATUS1 (MSM_USB_PHY_CSR_BASE + 0x040) #define USB2_PHY_USB_PHY_INTERRUPT_CLEAR0 (MSM_USB_PHY_CSR_BASE + 0x0DC) #define USB2_PHY_USB_PHY_INTERRUPT_CLEAR1 (MSM_USB_PHY_CSR_BASE + 0x0E0) #define USB2_PHY_USB_PHY_INTERRUPT_MASK0 (MSM_USB_PHY_CSR_BASE + 0x0D4) #define USB2_PHY_USB_PHY_INTERRUPT_MASK1 (MSM_USB_PHY_CSR_BASE + 0x0D8) #define USB_PHY_IDDIG_1_0 BIT(7) #define USB_PHY_IDDIG_RISE_MASK BIT(0) #define USB_PHY_IDDIG_FALL_MASK BIT(1) #define USB_PHY_ID_MASK (USB_PHY_IDDIG_RISE_MASK | USB_PHY_IDDIG_FALL_MASK) #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */ #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */