static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA) { static int power_supply_type; struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg); #if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM) static bool chglogo_check = false; #endif if (!dotg->psy || !dotg->charger) { dev_err(phy->dev, "no usb power supply/charger registered\n"); return 0; } if (dotg->charger->charging_disabled) return 0; #ifdef CONFIG_LGE_PM if (dotg->charger->chg_type == DWC3_SDP_CHARGER || dotg->charger->chg_type == DWC3_FLOATED_CHARGER) #else if (dotg->charger->chg_type == DWC3_SDP_CHARGER) #endif power_supply_type = POWER_SUPPLY_TYPE_USB; else if (dotg->charger->chg_type == DWC3_CDP_CHARGER) power_supply_type = POWER_SUPPLY_TYPE_USB_CDP; else if (dotg->charger->chg_type == DWC3_DCP_CHARGER || dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER) power_supply_type = POWER_SUPPLY_TYPE_USB_DCP; else power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN; #ifndef CONFIG_LGE_PM power_supply_set_supply_type(dotg->psy, power_supply_type); #endif #if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_G3) && defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) update_status(1, dotg->charger->chg_type); #endif #if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM) if (!chglogo_check && lge_get_boot_mode() == LGE_BOOT_MODE_CHARGERLOGO && dotg->charger->chg_type == DWC3_SDP_CHARGER) { if (mA > IUNIT) chglogo_check = true; else if (mA <= 2) { dotg->charger->max_power = mA; return 0; } } if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) { if (dotg->charger->chg_type == DWC3_DCP_CHARGER) mA = lge_pm_get_ta_current(); } #elif defined(CONFIG_LGE_PM) if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) { if (dotg->charger->chg_type == DWC3_SDP_CHARGER) { if (dotg->dwc->gadget.speed == USB_SPEED_SUPER) { if (dotg->charger->max_power > 2) dotg->charger->max_power = 0; mA = DWC3_USB30_CHG_CURRENT; } else { mA = lge_pm_get_usb_current(); } #ifdef CONFIG_QPNP_CHARGER /* For MST, boost current up over 900mA in spite of USB */ if (pseudo_batt_info.mode && mA == 500 ) mA = DWC3_USB30_CHG_CURRENT; #endif } else if (dotg->charger->chg_type == DWC3_DCP_CHARGER) { mA = lge_pm_get_ta_current(); } else if (dotg->charger->chg_type == DWC3_FLOATED_CHARGER) { mA = lge_pm_get_usb_current(); } } #endif if (dotg->charger->chg_type == DWC3_CDP_CHARGER) mA = DWC3_IDEV_CHG_MAX; if (dotg->charger->max_power == mA) return 0; dev_info(phy->dev, "Avail curr from USB = %u\n", mA); /* */ #ifdef CONFIG_LGE_PM #ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY if (dwc3_otg_get_psy(phy) < 0) goto psy_error; #else if (strcmp(dotg->psy->name, "usb")) { pr_info("%s psy name is %s, so change psy to usb.\n", __func__, dotg->psy->name); dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) goto psy_error; } #endif power_supply_set_supply_type(dotg->psy, power_supply_type); #endif #if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM) if (dotg->charger->max_power <= IUNIT && mA > 2) { #else if (dotg->charger->max_power <= 2 && mA > 2) { #endif /* Enable charging */ if (power_supply_set_online(dotg->psy, true)) goto psy_error; if (power_supply_set_current_limit(dotg->psy, 1000*mA)) goto psy_error; #ifdef CONFIG_QPNP_CHARGER if (!strncmp(dotg->psy->name, "ac", 2)) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) goto psy_error; if (power_supply_set_online(dotg->psy, true)) goto psy_error; if (power_supply_set_supply_type(dotg->psy, power_supply_type)) goto psy_error; if (power_supply_set_current_limit(dotg->psy, 1000*mA)) goto psy_error; dotg->psy = power_supply_get_by_name("ac"); if (!dotg->psy) goto psy_error; } #endif } else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) { /* Disable charging */ if (power_supply_set_online(dotg->psy, false)) goto psy_error; /* Set max current limit */ if (power_supply_set_current_limit(dotg->psy, 0)) goto psy_error; #ifdef CONFIG_QPNP_CHARGER if (!strncmp(dotg->psy->name, "ac", 2)) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) goto psy_error; if (power_supply_set_online(dotg->psy, false)) goto psy_error; if (power_supply_set_supply_type(dotg->psy, power_supply_type)) goto psy_error; if (power_supply_set_current_limit(dotg->psy, 0)) goto psy_error; dotg->psy = power_supply_get_by_name("ac"); if (!dotg->psy) goto psy_error; } #endif #ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY dotg->charger->chg_type = DWC3_INVALID_CHARGER; #endif } power_supply_changed(dotg->psy); dotg->charger->max_power = mA; #if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) #if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_G2) || defined (CONFIG_MACH_MSM8974_TIGERS) queue_work(touch_otg_wq, &dotg->touch_work); #endif #endif return 0; psy_error: dev_dbg(phy->dev, "power supply error when setting property\n"); return -ENXIO; } /* IRQs which OTG driver is interested in handling */ #define DWC3_OEVT_MASK (DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) /** * dwc3_otg_interrupt - interrupt handler for dwc3 otg events. * @_dotg: Pointer to out controller context structure * * Returns IRQ_HANDLED on success otherwise IRQ_NONE. */ static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg) { struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg; u32 osts, oevt_reg; int ret = IRQ_NONE; int handled_irqs = 0; struct usb_phy *phy = dotg->otg.phy; oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT); if (!(oevt_reg & DWC3_OEVT_MASK)) return IRQ_NONE; osts = dwc3_readl(dotg->regs, DWC3_OSTS); if ((oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) || (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)) { /* * ID sts has changed, set inputs later, in the workqueue * function, switch from A to B or from B to A. */ if (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) { if (osts & DWC3_OTG_OSTS_CONIDSTS) { dev_dbg(phy->dev, "ID set\n"); set_bit(ID, &dotg->inputs); } else { dev_dbg(phy->dev, "ID clear\n"); clear_bit(ID, &dotg->inputs); } handled_irqs |= DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT; } if (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) { if (osts & DWC3_OTG_OSTS_BSESVALID) { dev_dbg(phy->dev, "BSV set\n"); set_bit(B_SESS_VLD, &dotg->inputs); } else { dev_dbg(phy->dev, "BSV clear\n"); clear_bit(B_SESS_VLD, &dotg->inputs); } handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT; } queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0); ret = IRQ_HANDLED; /* Clear the interrupts we handled */ dwc3_writel(dotg->regs, DWC3_OEVT, handled_irqs); } return ret; } /** * dwc3_otg_init_sm - initialize OTG statemachine input * @dotg: Pointer to the dwc3_otg structure * */ void dwc3_otg_init_sm(struct dwc3_otg *dotg) { u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS); struct usb_phy *phy = dotg->otg.phy; struct dwc3_ext_xceiv *ext_xceiv; int ret; dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts); /* * VBUS initial state is reported after PMIC * driver initialization. Wait for it. */ ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5); if (!ret) { dev_err(phy->dev, "%s: completion timeout\n", __func__); /* We can safely assume no cable connected */ set_bit(ID, &dotg->inputs); } ext_xceiv = dotg->ext_xceiv; dwc3_otg_reset(dotg); if (ext_xceiv && !ext_xceiv->otg_capability) { if (osts & DWC3_OTG_OSTS_CONIDSTS) set_bit(ID, &dotg->inputs); else clear_bit(ID, &dotg->inputs); if (osts & DWC3_OTG_OSTS_BSESVALID) set_bit(B_SESS_VLD, &dotg->inputs); else clear_bit(B_SESS_VLD, &dotg->inputs); } }
static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA) { static int power_supply_type; struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg); #if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM) static bool chglogo_check = false; #endif if (!dotg->psy || !dotg->charger) { dev_err(phy->dev, "no usb power supply/charger registered\n"); return 0; } if (dotg->charger->charging_disabled) return 0; #ifdef CONFIG_LGE_PM if (dotg->charger->chg_type == DWC3_SDP_CHARGER || dotg->charger->chg_type == DWC3_FLOATED_CHARGER) #else if (dotg->charger->chg_type == DWC3_SDP_CHARGER) #endif power_supply_type = POWER_SUPPLY_TYPE_USB; else if (dotg->charger->chg_type == DWC3_CDP_CHARGER) power_supply_type = POWER_SUPPLY_TYPE_USB_CDP; else if (dotg->charger->chg_type == DWC3_DCP_CHARGER || dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER) power_supply_type = POWER_SUPPLY_TYPE_USB_DCP; else #ifdef CONFIG_LGE_PM /* [email protected] * healthd get battery psy type at init only. * If cable detach before healthd init, * healthd recognize usb psy as battery type. */ power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN; #else power_supply_type = POWER_SUPPLY_TYPE_BATTERY; #endif #ifndef CONFIG_LGE_PM power_supply_set_supply_type(dotg->psy, power_supply_type); #endif #if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) update_status(1, dotg->charger->chg_type); #endif #if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM) if (!chglogo_check && lge_get_boot_mode() == LGE_BOOT_MODE_CHARGERLOGO && dotg->charger->chg_type == DWC3_SDP_CHARGER) { if (mA > IUNIT) chglogo_check = true; else if (mA <= 2) { dotg->charger->max_power = mA; return 0; } } if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) { if (dotg->charger->chg_type == DWC3_DCP_CHARGER) mA = lge_pm_get_ta_current(); } #elif defined(CONFIG_LGE_PM) if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) { if (dotg->charger->chg_type == DWC3_SDP_CHARGER) { if (dotg->dwc->gadget.speed == USB_SPEED_SUPER) { if (dotg->charger->max_power > 2) dotg->charger->max_power = 0; mA = DWC3_USB30_CHG_CURRENT; } else { mA = lge_pm_get_usb_current(); } #ifdef CONFIG_QPNP_CHARGER /* For MST, boost current up over 900mA in spite of USB */ if (pseudo_batt_info.mode && mA == 500 ) mA = DWC3_USB30_CHG_CURRENT; #endif } else if (dotg->charger->chg_type == DWC3_DCP_CHARGER) { mA = lge_pm_get_ta_current(); } else if (dotg->charger->chg_type == DWC3_FLOATED_CHARGER) { mA = lge_pm_get_usb_current(); } } #endif if (dotg->charger->chg_type == DWC3_CDP_CHARGER) mA = DWC3_IDEV_CHG_MAX; if (dotg->charger->max_power == mA) return 0; dev_info(phy->dev, "Avail curr from USB = %u\n", mA); /* [email protected] make psy getter and move it above power_supply_type setter. 2014-02-06 */ #ifdef CONFIG_LGE_PM #ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY if (dwc3_otg_get_psy(phy) < 0) goto psy_error; #else if (strcmp(dotg->psy->name, "usb")) { pr_info("%s psy name is %s, so change psy to usb.\n", __func__, dotg->psy->name); dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) goto psy_error; } #endif power_supply_set_supply_type(dotg->psy, power_supply_type); #endif if (dotg->charger->max_power <= 2 && mA > 2) { /* Enable charging */ if (power_supply_set_online(dotg->psy, true)) goto psy_error; if (power_supply_set_current_limit(dotg->psy, 1000*mA)) goto psy_error; #ifdef CONFIG_QPNP_CHARGER if (!strncmp(dotg->psy->name, "ac", 2)) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) goto psy_error; if (power_supply_set_online(dotg->psy, true)) goto psy_error; if (power_supply_set_supply_type(dotg->psy, power_supply_type)) goto psy_error; if (power_supply_set_current_limit(dotg->psy, 1000*mA)) goto psy_error; dotg->psy = power_supply_get_by_name("ac"); if (!dotg->psy) goto psy_error; } #endif } else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) { /* Disable charging */ if (power_supply_set_online(dotg->psy, false)) goto psy_error; /* Set max current limit */ if (power_supply_set_current_limit(dotg->psy, 0)) goto psy_error; #ifdef CONFIG_QPNP_CHARGER if (!strncmp(dotg->psy->name, "ac", 2)) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) goto psy_error; if (power_supply_set_online(dotg->psy, false)) goto psy_error; if (power_supply_set_supply_type(dotg->psy, power_supply_type)) goto psy_error; if (power_supply_set_current_limit(dotg->psy, 0)) goto psy_error; dotg->psy = power_supply_get_by_name("ac"); if (!dotg->psy) goto psy_error; } #endif } power_supply_changed(dotg->psy); dotg->charger->max_power = mA; return 0; psy_error: dev_dbg(phy->dev, "power supply error when setting property\n"); return -ENXIO; }