int dwc3_intel_byt_b_idle(struct dwc_otg2 *otg) { u32 gctl, tmp; enable_usb_phy(otg, false); dwc_otg_charger_hwdet(false); /* Disable hibernation mode by default */ gctl = otg_read(otg, GCTL); gctl &= ~GCTL_GBL_HIBERNATION_EN; otg_write(otg, GCTL, gctl); /* Reset ADP related registers */ otg_write(otg, ADPCFG, 0); otg_write(otg, ADPCTL, 0); otg_write(otg, ADPEVTEN, 0); tmp = otg_read(otg, ADPEVT); otg_write(otg, ADPEVT, tmp); otg_write(otg, OCFG, 0); otg_write(otg, OEVTEN, 0); tmp = otg_read(otg, OEVT); otg_write(otg, OEVT, tmp); otg_write(otg, OCTL, OCTL_PERI_MODE); /* Force config to device mode as default */ gctl = otg_read(otg, GCTL); gctl &= ~GCTL_PRT_CAP_DIR; gctl |= GCTL_PRT_CAP_DIR_DEV << GCTL_PRT_CAP_DIR_SHIFT; otg_write(otg, GCTL, gctl); mdelay(100); return 0; }
static int sleep_until_event(struct dwc_otg2 *otg, u32 otg_mask, u32 user_mask, u32 *otg_events, u32 *user_events, int timeout) { int rc = 0; pm_runtime_mark_last_busy(otg->dev); pm_runtime_put_autosuspend(otg->dev); /* Wait until it occurs, or timeout, or interrupt. */ if (timeout) { otg_dbg(otg, "Waiting for event (timeout=%d)...\n", timeout); rc = sleep_main_thread_until_condition_timeout(otg, check_event(otg, otg_mask, user_mask, otg_events, user_events), timeout); } else { otg_dbg(otg, "Waiting for event (no timeout)...\n"); rc = sleep_main_thread_until_condition(otg, check_event(otg, otg_mask, user_mask, otg_events, user_events)); } pm_runtime_get_sync(otg->dev); /* Disable the events */ otg_write(otg, OEVTEN, 0); otg_write(otg, ADPEVTEN, 0); otg_dbg(otg, "Woke up rc=%d\n", rc); return rc; }
int dwc3_intel_platform_init(struct dwc_otg2 *otg) { int retval; struct intel_dwc_otg_pdata *data; data = (struct intel_dwc_otg_pdata *)otg->otg_data; /* Init a_bus_drop callback */ otg->usb2_phy.a_bus_drop = dwc_a_bus_drop; otg->usb2_phy.vbus_state = VBUS_ENABLED; /* Get usb2 phy type */ otg->usb2_phy.intf = data->usb2_phy_type; /* Turn off VUSBPHY if it haven't used by USB2 PHY. * Otherwise, it will consume ~2.6mA(on VSYS) on MOFD. */ if (!data->using_vusbphy) { retval = control_usb_phy_power(PMIC_VLDOCNT, false); if (retval) otg_err(otg, "Fail to turn off VUSBPHY\n"); } else if (!is_utmi_phy(otg)) { /* If the current USB2 PHY low power controlled by VUSBPHY. Then * we need to de-assert USBRST pin to make USB2 PHY always stay * in active state. */ retval = control_usb_phy_power(PMIC_USBPHYCTRL, true); if (retval) otg_err(otg, "Fail to de-assert USBRST#\n"); } else { /* If we are using utmi phy, and through VUSBPHY to do power * control. Then we need to assert USBRST# for external ULPI phy * to ask it under inactive state saving power. */ retval = control_usb_phy_power(PMIC_USBPHYCTRL, false); if (retval) otg_err(otg, "Fail to de-assert USBRST#\n"); } /* Don't let phy go to suspend mode, which * will cause FS/LS devices enum failed in host mode. */ set_sus_phy(otg, 0); retval = device_create_file(otg->dev, &dev_attr_otg_id); if (retval < 0) { otg_dbg(otg, "Can't register sysfs attribute: %d\n", retval); return -ENOMEM; } otg_dbg(otg, "\n"); otg_write(otg, OEVTEN, 0); otg_write(otg, OCTL, 0); dwc3_switch_mode(otg, GCTL_PRT_CAP_DIR_OTG); return 0; }
int dwc3_intel_b_idle(struct dwc_otg2 *otg) { u32 gctl, tmp; /* Disable hibernation mode by default */ gctl = otg_read(otg, GCTL); gctl &= ~GCTL_GBL_HIBERNATION_EN; otg_write(otg, GCTL, gctl); /* Reset ADP related registers */ otg_write(otg, ADPCFG, 0); otg_write(otg, ADPCTL, 0); otg_write(otg, ADPEVTEN, 0); tmp = otg_read(otg, ADPEVT); otg_write(otg, ADPEVT, tmp); otg_write(otg, OCFG, 0); otg_write(otg, OEVTEN, 0); tmp = otg_read(otg, OEVT); otg_write(otg, OEVT, tmp); /* Force config to otg mode as default. */ dwc3_switch_mode(otg, GCTL_PRT_CAP_DIR_OTG); if (!is_hybridvp(otg)) { dwc_otg_charger_hwdet(false); enable_usb_phy(otg, false); } mdelay(100); return 0; }
/* Disable auto-resume feature for USB2 PHY. This is one * silicon workaround. It will cause fabric timeout error * for LS case after resume from hibernation */ static void disable_phy_auto_resume(struct dwc_otg2 *otg) { u32 data = 0; data = otg_read(otg, GUSB2PHYCFG0); data &= ~GUSB2PHYCFG_ULPI_AUTO_RESUME; otg_write(otg, GUSB2PHYCFG0, data); }
void dwc3_switch_mode(struct dwc_otg2 *otg, u32 mode) { u32 reg; reg = otg_read(otg, GCTL); reg &= ~(GCTL_PRT_CAP_DIR_OTG << GCTL_PRT_CAP_DIR_SHIFT); reg |= mode << GCTL_PRT_CAP_DIR_SHIFT; otg_write(otg, GCTL, reg); }
static void set_sus_phy(struct dwc_otg2 *otg, int bit) { u32 data = 0; data = otg_read(otg, GUSB2PHYCFG0); if (bit) data |= GUSB2PHYCFG_SUS_PHY; else data &= ~GUSB2PHYCFG_SUS_PHY; otg_write(otg, GUSB2PHYCFG0, data); data = otg_read(otg, GUSB3PIPECTL0); if (bit) data |= GUSB3PIPECTL_SUS_EN; else data &= ~GUSB3PIPECTL_SUS_EN; otg_write(otg, GUSB3PIPECTL0, data); }
static int ulpi_read(struct usb_phy *phy, u32 reg) { struct dwc_otg2 *otg = container_of(phy, struct dwc_otg2, usb2_phy); u32 val32 = 0, count = 10000; u8 val, tmp; if (phy->intf != USB2_PHY_ULPI) return -ENODEV; reg &= 0xFF; while (count) { if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSBSY) udelay(1); else break; count--; } if (!count) { otg_err(otg, "USB2 PHY always busy!!\n"); return -EBUSY; } count = 10000; /* Determine if use extend registers access */ if (reg & EXTEND_ULPI_REGISTER_ACCESS_MASK) { otg_dbg(otg, "Access extend registers 0x%x\n", reg); val32 = GUSB2PHYACC0_NEWREGREQ | GUSB2PHYACC0_REGADDR(ULPI_ACCESS_EXTENDED) | GUSB2PHYACC0_VCTRL(reg); } else { otg_dbg(otg, "Access normal registers 0x%x\n", reg); val32 = GUSB2PHYACC0_NEWREGREQ | GUSB2PHYACC0_REGADDR(reg) | GUSB2PHYACC0_VCTRL(0x00); } otg_write(otg, GUSB2PHYACC0, val32); while (count) { if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSDONE) { val = otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_REGDATA_MASK; otg_dbg(otg, "%s - reg 0x%x data 0x%x\n", __func__, reg, val); goto cleanup; } udelay(1); count--; } otg_err(otg, "%s read PHY data failed.\n", __func__); return -ETIMEDOUT; cleanup: /* Clear GUSB2PHYACC0[16:21] before return. * Otherwise, it will cause PHY can't in workable * state. This is one dwc3 controller silicon bug. */ tmp = otg_read(otg, GUSB2PHYACC0); otg_write(otg, GUSB2PHYACC0, tmp & ~GUSB2PHYACC0_REGADDR(0x3F)); return val; }
int dwc3_intel_byt_platform_init(struct dwc_otg2 *otg) { struct intel_dwc_otg_pdata *data; u32 gctl; int id_value; int retval; data = (struct intel_dwc_otg_pdata *)otg->otg_data; if (data) INIT_DELAYED_WORK(&data->suspend_discon_work, dwc_otg_suspend_discon_work); if (data && data->gpio_cs && data->gpio_reset) { retval = gpio_request(data->gpio_cs, "phy_cs"); if (retval < 0) { otg_err(otg, "failed to request CS pin %d\n", data->gpio_cs); return retval; } retval = gpio_request(data->gpio_reset, "phy_reset"); if (retval < 0) { otg_err(otg, "failed to request RESET pin %d\n", data->gpio_reset); return retval; } } if (data && data->gpio_id) { dev_info(otg->dev, "USB ID detection - Enabled - GPIO\n"); /* Set ID default value to 1 Floating */ data->id = 1; retval = gpio_request(data->gpio_id, "gpio_id"); if (retval < 0) { otg_err(otg, "failed to request ID pin %d\n", data->gpio_id); return retval; } retval = gpio_direction_input(data->gpio_id); if (retval < 0) { otg_err(otg, "failed to request ID pin %d\n", data->gpio_id); return retval; } retval = request_threaded_irq(gpio_to_irq(data->gpio_id), NULL, dwc3_gpio_id_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "dwc-gpio-id", otg->dev); if (retval < 0) { otg_err(otg, "failed to request interrupt gpio ID\n"); return retval; } otg_dbg(otg, "GPIO ID request/Interrupt reuqest Done\n"); id_value = dwc3_check_gpio_id(otg); if ((id_value == 0 || id_value == 1) && (data->id != id_value)) { data->id = id_value; dev_info(otg->dev, "ID notification (id = %d)\n", data->id); atomic_notifier_call_chain(&otg->usb2_phy.notifier, USB_EVENT_ID, &id_value); } else otg_dbg(otg, "Get incorrect ID value %d\n", id_value); } /* Don't let phy go to suspend mode, which * will cause FS/LS devices enum failed in host mode. */ set_sus_phy(otg, 0); retval = device_create_file(otg->dev, &dev_attr_otg_id); if (retval < 0) { otg_dbg(otg, "Can't register sysfs attribute: %d\n", retval); return -ENOMEM; } retval = device_create_file(otg->dev, &dev_attr_vbus_evt); if (retval < 0) { otg_dbg(otg, "Can't register sysfs attribute: %d\n", retval); return -ENOMEM; } otg_dbg(otg, "\n"); otg_write(otg, OEVTEN, 0); otg_write(otg, OCTL, 0); gctl = otg_read(otg, GCTL); gctl |= GCTL_PRT_CAP_DIR_OTG << GCTL_PRT_CAP_DIR_SHIFT; otg_write(otg, GCTL, gctl); return 0; }
int dwc3_intel_resume(struct dwc_otg2 *otg) { struct pci_dev *pci_dev; struct usb_hcd *hcd = NULL; u32 data; int ret; if (!otg) return 0; hcd = container_of(otg->otg.host, struct usb_hcd, self); /* After resume from D0i3cold. The UTMI PHY D+ drive issue * reproduced due to all setting be reseted. So switch to OTG * mode avoid D+ drive too early. */ if ((otg->state == DWC_STATE_B_IDLE || otg->state == DWC_STATE_CHARGING || otg->state == DWC_STATE_WAIT_VBUS_FALL || otg->state == DWC_STATE_WAIT_VBUS_RAISE) && is_utmi_phy(otg)) { /* Reconnect DP/DM between Pmic and SOC for support host * and device mode. */ ret = intel_scu_ipc_update_register(PMIC_USBPHYCTRL, USBPHYRSTB, USBPHYRSTB); if (ret) otg_err(otg, "%s: ipc update failed\n", __func__); otg_write(otg, OEVTEN, 0); otg_write(otg, OCTL, 0); dwc3_switch_mode(otg, GCTL_PRT_CAP_DIR_OTG); } /* This is one SCU WA. SCU should set GUSB2PHYCFG0 * bit 4 for ULPI setting. But SCU haven't do that. * So do WA first until SCU fix. */ data = otg_read(otg, GUSB2PHYCFG0); if (is_utmi_phy(otg)) data &= ~(1 << 4); else data |= (1 << 4); otg_write(otg, GUSB2PHYCFG0, data); pci_dev = to_pci_dev(otg->dev); /* From synopsys spec 12.2.11. * Software cannot access memory-mapped I/O space * for 10ms. Delay 5 ms here should be enough. Too * long a delay causes hibernation exit failure. */ mdelay(5); pci_restore_state(pci_dev); if (pci_enable_device(pci_dev) < 0) { otg_err(otg, "pci_enable_device failed.\n"); return -EIO; } set_sus_phy(otg, 0); /* Delay 1ms waiting PHY clock debounce. * Without this debounce, will met fabric error randomly. **/ mdelay(1); if (otg->state == DWC_STATE_A_HOST && otg->resume_host) otg->resume_host(hcd); return 0; }