static int pmic_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { int rc = 0; if (offset < 8)/* it is GPIO */ rc = intel_scu_ipc_update_register(GPIO0 + offset, GPIO_DRV | (value ? GPIO_DOU : 0), GPIO_DRV | GPIO_DOU | GPIO_DIR); else if (offset < 16)/* it is GPOSW */ rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8, GPOSW_DRV | (value ? GPOSW_DOU : 0), GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV); else if (offset > 15 && offset < 24)/* it is GPO */ rc = intel_scu_ipc_update_register(GPO, value ? 1 << (offset - 16) : 0, 1 << (offset - 16)); else { printk(KERN_ERR "%s: invalid PMIC GPIO pin %d!\n", __func__, offset); WARN_ON(1); } return rc; }
static void pmic_program_irqtype(int gpio, int type) { if (type & IRQ_TYPE_EDGE_RISING) intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20); else intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20); if (type & IRQ_TYPE_EDGE_FALLING) intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10); else intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); };
int basin_cove_get_id(struct dwc_otg2 *otg) { int ret, id = RID_UNKNOWN; u8 idsts, pmic_id; ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0); if (ret) otg_err(otg, "Fail to enable ACA&ID detection logic\n"); ret = intel_scu_ipc_ioread8(PMIC_USBIDSTS, &idsts); if (ret) { otg_err(otg, "Fail to read id\n"); return id; } if (idsts & USBIDSTS_ID_FLOAT_STS) id = RID_FLOAT; else if (idsts & USBIDSTS_ID_RARBRC_STS(1)) id = RID_A; else if (idsts & USBIDSTS_ID_RARBRC_STS(2)) id = RID_B; else if (idsts & USBIDSTS_ID_RARBRC_STS(3)) id = RID_C; else { /* PMIC A0 reports ID_GND = 0 for RID_GND but PMIC B0 reports * ID_GND = 1 for RID_GND */ ret = intel_scu_ipc_ioread8(0x00, &pmic_id); if (ret) { otg_err(otg, "Fail to read PMIC ID register\n"); } else if (((pmic_id & VENDOR_ID_MASK) == BASIN_COVE_PMIC_ID) && ((pmic_id & PMIC_MAJOR_REV) == PMIC_A0_MAJOR_REV)) { if (idsts & USBIDSTS_ID_GND) id = RID_GND; } else { if (!(idsts & USBIDSTS_ID_GND)) id = RID_GND; } } ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0, 0); if (ret) otg_err(otg, "Fail to enable ACA&ID detection logic\n"); return id; }
static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { if (offset < 8)/* it is GPIO */ intel_scu_ipc_update_register(GPIO0 + offset, GPIO_DRV | (value ? GPIO_DOU : 0), GPIO_DRV | GPIO_DOU); else if (offset < 16)/* it is GPOSW */ intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8, GPOSW_DRV | (value ? GPOSW_DOU : 0), GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV); else if (offset > 15 && offset < 24) /* it is GPO */ intel_scu_ipc_update_register(GPO, value ? 1 << (offset - 16) : 0, 1 << (offset - 16)); }
static int ps_hdmi_hpd_suspend(struct device *dev) { int ret = 0; pr_debug("Entered %s\n", __func__); /* suspend process is irreversible */ ret = intel_scu_ipc_update_register(PS_MSIC_IRQLVL1_MASK, 0xff, PS_VREG_MASK); if (ret) { pr_debug("%s: Failed to mask VREG IRQ.\n", __func__); } ret = intel_scu_ipc_iowrite8(PS_MSIC_VHDMICNT, PS_VHDMI_OFF); if (ret) { pr_debug("%s: Failed to power off VHDMI.\n", __func__); } ret = intel_scu_ipc_iowrite8(PS_MSIC_VCC330CNT, PS_VCC330_OFF); if (ret) { pr_debug("%s: Failed to power off VCC330.\n", __func__); } pr_debug("Exiting %s\n", __func__); return ret; }
/** * sst_sc_reg_access - IPC read/write wrapper * * @sc_access: array of data, addresses and mask * @type: operation type * @num_val: number of reg to opertae on * * Reads/writes/read-modify operations on registers accessed through SCU (sound * card and few SST DSP regsisters that are not accissible to IA) */ int sst_sc_reg_access(struct sc_reg_access *sc_access, int type, int num_val) { int i, retval = 0; if (type == PMIC_WRITE) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr, sc_access[i].value); if (retval) { pr_err("sst: IPC write failed!!! %d\n", retval); return retval; } } } else if (type == PMIC_READ) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr, &(sc_access[i].value)); if (retval) { pr_err("sst: IPC read failed!!!!!%d\n", retval); return retval; } } } else { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_update_register( sc_access[i].reg_addr, sc_access[i].value, sc_access[i].mask); if (retval) { pr_err("sst: IPC Modify failed!!!%d\n", retval); return retval; } } } return retval; }
/** * sst_sc_reg_access - IPC read/write wrapper * * @sc_access: array of data, addresses and mask * @type: operation type * @num_val: number of reg to opertae on * * Reads/writes/read-modify operations on registers accessed through SCU (sound * card and few SST DSP regsisters that are not accissible to IA) */ int sst_sc_reg_access(struct sc_reg_access *sc_access, int type, int num_val) { int i, retval = 0; if (type == PMIC_WRITE) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr, sc_access[i].value); if (retval) goto err; } } else if (type == PMIC_READ) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr, &(sc_access[i].value)); if (retval) goto err; } } else { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_update_register( sc_access[i].reg_addr, sc_access[i].value, sc_access[i].mask); if (retval) goto err; } } return 0; err: pr_err("IPC failed for cmd %d, %d\n", retval, type); pr_err("reg:0x%2x addr:0x%2x\n", sc_access[i].reg_addr, sc_access[i].value); return retval; }
/* This function is used to control VUSBPHY or assert/deassert USBRST_N * pin to control usb2 phy enter/exit low power mode. */ static int control_usb_phy_power(u16 addr, bool on_off) { int ret; u8 mask, bits; if (addr == PMIC_VLDOCNT) mask = PMIC_VLDOCNT_VUSBPHYEN; else if (addr == PMIC_USBPHYCTRL) mask = PMIC_USBPHYCTRL_D0; else return -EINVAL; if (on_off) bits = mask; else bits = 0x00; ret = intel_scu_ipc_update_register(addr, bits, mask); /* Debounce 10ms for turn on VUSBPHY */ if (on_off) usleep_range(10000, 11000); return ret; }
/* * Platform specific resume function after deep-sleep * This function is used to carry out any specific actviity * to aid HDMI IP resume in the context of system resume. * This function will always be scheduled to execute after * the system has finished resuming. */ void ps_post_resume_wq(struct work_struct *work) { hdmi_context_t *ctx = container_of(work, hdmi_context_t, post_resume_work); int ret = 0; pr_debug("Entered %s\n", __func__); if (ctx == NULL) { pr_err("%s: NULL context!\n", __func__); return; } /* While going to suspend state, the HPD interrupts from MSIC * were masked. During the resume, we do not immediately unmask * the interrupt to avoid race between the resultant hotplug * handlers and system resume activity. Instead, we simply turn * on the HDMI MSIC power rails and schedule this function to be * called after the system finishes a complete resume. At this * time, it is safe to re-enable HPD interrupts. */ ret = intel_scu_ipc_update_register(PS_MSIC_IRQLVL1_MASK, 0x0, PS_VREG_MASK); if (ret) { pr_debug("%s: Failed to unmask VREG IRQ.\n", __func__); goto exit; } exit: pr_debug("Exiting %s\n", __func__); }
static void handle_VW2_event(int event, void *dev_data) { uint8_t irq_status, beh_data; struct ocd_info *cinfo = (struct ocd_info *)dev_data; int ret; dev_info(cinfo->dev, "EM:BCU: BCU Event %d has occured\n", event); /* Notify using UEvent */ kobject_uevent(&cinfo->dev->kobj, KOBJ_CHANGE); ret = intel_scu_ipc_ioread8(S_BCUINT, &irq_status); if (ret) goto ipc_fail; dev_dbg(cinfo->dev, "EM:BCU: S_BCUINT: %x\n", irq_status); /* If Vsys is below WARN2 level-No action required from driver */ if (!(irq_status & SVWARN2)) { /* Vsys is above WARN2 level */ ret = intel_scu_ipc_ioread8(CAMFLDIS_BEH, &beh_data); if (ret) goto ipc_fail; if (IS_ASSRT_ON_VW2(beh_data) && IS_STICKY(beh_data)) { ret = intel_scu_ipc_update_register(S_BCUCTRL, 0xFF, SBCUCTRL_CAMFLDIS); if (ret) goto ipc_fail; } ret = intel_scu_ipc_ioread8(BCUDISW2_BEH, &beh_data); if (ret) goto ipc_fail; if (IS_ASSRT_ON_VW2(beh_data) && IS_STICKY(beh_data)) { ret = intel_scu_ipc_update_register(S_BCUCTRL, 0xFF, SBCUCTRL_BCUDISW2); if (ret) goto ipc_fail; } } return; ipc_fail: dev_err(cinfo->dev, "EM:BCU: ipc read/write failed:func:%s()\n", __func__); return; }
static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { if (offset >= 8) { pr_err("only pin 0-7 support input\n"); return -1;/* we only have 8 GPIO can use as input */ } return intel_scu_ipc_update_register(GPIO0 + offset, GPIO_DIR, GPIO_DIR); }
static enum power_supply_charger_cable_type basin_cove_aca_check(struct dwc_otg2 *otg) { u8 rarbrc; int ret; enum power_supply_charger_cable_type type = POWER_SUPPLY_CHARGER_TYPE_NONE; ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL, USBIDCTRL_ACA_DETEN_D1, USBIDCTRL_ACA_DETEN_D1); if (ret) otg_err(otg, "Fail to enable ACA&ID detection logic\n"); /* Wait >66.1ms (for TCHGD_SERX_DEB) */ msleep(66); /* Read decoded RID value */ ret = intel_scu_ipc_ioread8(PMIC_USBIDSTS, &rarbrc); if (ret) otg_err(otg, "Fail to read decoded RID value\n"); rarbrc &= USBIDSTS_ID_RARBRC_STS(3); rarbrc >>= 1; /* If ID_RARBRC_STS==01: ACA-Dock detected * If ID_RARBRC_STS==00: MHL detected */ if (rarbrc == 1) { /* ACA-Dock */ type = POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK; } else if (!rarbrc) { /* MHL */ type = POWER_SUPPLY_CHARGER_TYPE_MHL; } ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL, USBIDCTRL_ACA_DETEN_D1, 0); if (ret) otg_err(otg, "Fail to enable ACA&ID detection logic\n"); return type; }
static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct msic_gpio *mg = &msic_gpio; u16 ctlo = offset < mg->ngpio_lv ? mg->gpio0_lv_ctlo + offset : mg->gpio0_hv_ctlo + (offset - mg->ngpio_lv); intel_scu_ipc_update_register(ctlo, value ? CTLO_DOUT_H : CTLO_DOUT_L, CTLO_DOUT_MASK); }
static int ps_hdmi_hpd_suspend(struct device *dev) { int ret = 0, err = 0; pr_debug("Entered %s\n", __func__); ret = intel_scu_ipc_update_register(PS_MSIC_IRQLVL1_MASK, 0xff, PS_VREG_MASK); if (ret) { pr_debug("%s: Failed to mask VREG IRQ.\n", __func__); goto err1; } ret = intel_scu_ipc_iowrite8(PS_MSIC_VHDMICNT, PS_VHDMI_OFF); if (ret) { pr_debug("%s: Failed to power off VHDMI.\n", __func__); goto err2; } ret = intel_scu_ipc_iowrite8(PS_MSIC_VCC330CNT, PS_VCC330_OFF); if (ret) { pr_debug("%s: Failed to power off VCC330.\n", __func__); goto err3; } pr_debug("Exiting %s\n", __func__); return ret; err3: err |= intel_scu_ipc_iowrite8(PS_MSIC_VHDMICNT, PS_VHDMI_ON | PS_VHDMI_DB_30MS); err2: err |= intel_scu_ipc_update_register(PS_MSIC_IRQLVL1_MASK, 0x0, PS_VREG_MASK); err1: pr_debug("Exiting %s and err = %d\n", __func__, err); return ret; }
static irqreturn_t ocd_intrpt_thread_handler(int irq, void *dev_data) { int ret, event; unsigned int irq_data; struct ocd_info *cinfo = (struct ocd_info *)dev_data; if (!cinfo) return IRQ_NONE; mutex_lock(&ocd_update_lock); irq_data = ioread8(cinfo->bcu_intr_addr); /* we are not handling(no action taken) GSMPULSE_IRQ and TXPWRTH_IRQ event */ if (irq_data & VWARN1_IRQ) { event = WARN1; handle_VW1_event(event, dev_data); } else if (irq_data & VWARN2_IRQ) { event = WARN2; handle_VW2_event(event, dev_data); } else if (irq_data & VCRIT_IRQ) { event = CRIT; handle_VC_event(event, dev_data); } else if (irq_data & GSMPULSE_IRQ) { event = GSMPULSE; dev_info(cinfo->dev, "EM:BCU: BCU Event %d has occured\n", event); } else if (irq_data & TXPWRTH_IRQ) { event = TXPWRTH; dev_info(cinfo->dev, "EM:BCU: BCU Event %d has occured\n", event); } else { event = UNKNOWN; dev_err(cinfo->dev, "EM:BCU: Invalid Interrupt\n"); } /* Unmask BCU Interrupt in the mask register */ ret = intel_scu_ipc_update_register(MIRQLVL1, 0x00, BCU_ALERT); if (ret) { dev_err(cinfo->dev, "EM:BCU: Unmasking of BCU failed:%d\n", ret); goto ipc_fail; } ret = IRQ_HANDLED; ipc_fail: mutex_unlock(&ocd_update_lock); return ret; }
int sd_cv_sw_take_control() { int retval = 0; int cmd_retry_count = 3; do { retval = intel_scu_ipc_update_register( SDCV_CHGRCTRL0_ADDR, SDCV_SWCONTROL_ENABLE, SDCV_CHGRCTRL0_SWCONTROL_MASK); if (retval) { cmd_retry_count--; pr_err("%s: * Error enabling sw control. " "Charging may continue in h/w control mode\n", __func__); msleep(1); } } while (retval && cmd_retry_count > 0); cmd_retry_count = 3; do { retval = intel_scu_ipc_update_register( SDCV_CHGRCTRL0_ADDR, SDCV_CCSM_OFF_ENABLE, SDCV_CHGRCTRL0_CCSM_OFF_MASK); if (retval) { cmd_retry_count--; pr_err("%s: * Error disable CCSM. " "Charging may continue in h/w control mode\n", __func__); msleep(1); } } while (retval && cmd_retry_count > 0); return retval; }
static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) { int count = data->count; if (count == 0 || count == 3 || count > 4) return -EINVAL; switch (cmd) { case INTE_SCU_IPC_REGISTER_READ: return intel_scu_ipc_readv(data->addr, data->data, count); case INTE_SCU_IPC_REGISTER_WRITE: return intel_scu_ipc_writev(data->addr, data->data, count); case INTE_SCU_IPC_REGISTER_UPDATE: return intel_scu_ipc_update_register(data->addr[0], data->data[0], data->mask); default: return -ENOTTY; } }
int dwc3_intel_suspend(struct dwc_otg2 *otg) { int ret; struct usb_phy *phy; struct pci_dev *pci_dev; struct usb_hcd *hcd = NULL; pci_power_t state = PCI_D3cold; if (!otg) return 0; hcd = container_of(otg->otg.host, struct usb_hcd, self); pci_dev = to_pci_dev(otg->dev); if (otg->state == DWC_STATE_A_HOST && otg->suspend_host) { /* Check if USB2 ULPI PHY is hang via access its internal * registers. If hang, then do hard reset before enter * hibernation mode. Otherwise, the USB2 PHY can't enter * suspended state which will blocking U2PMU can't get ready * then can't enter D0i3hot forever in SCU FW. */ if (!is_utmi_phy(otg)) { phy = usb_get_phy(USB_PHY_TYPE_USB2); if (!phy) return -ENODEV; if (usb_phy_io_read(phy, ULPI_VENDOR_ID_LOW) < 0) { enable_usb_phy(otg, 0); enable_usb_phy(otg, 1); } usb_put_phy(phy); } ret = otg->suspend_host(hcd); if (ret) { otg_err(otg, "dwc3-host enter suspend faield: %d\n", ret); return ret; } } if (otg->state == DWC_STATE_B_PERIPHERAL || otg->state == DWC_STATE_A_HOST) state = PCI_D3hot; set_sus_phy(otg, 1); if (pci_save_state(pci_dev)) { otg_err(otg, "pci_save_state failed!\n"); return -EIO; } pci_disable_device(pci_dev); if ((state == PCI_D3cold) && is_utmi_phy(otg)) { /* Important!! Whenever the VUSBPHY rail is disabled, SW * must assert USBRST# to isolate the SOC’s DP/DM pins from the * outside world. There is a risk of damage to the SOC if a * peripheral were to bias DP/DM to 3.3V when the SOC is * unpowered. */ ret = intel_scu_ipc_update_register(PMIC_USBPHYCTRL, 0x0, USBPHYRSTB); if (ret) otg_err(otg, "%s: ipc update failed\n", __func__); } pci_set_power_state(pci_dev, state); 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; }
static enum power_supply_charger_cable_type dwc3_intel_get_charger_type(struct dwc_otg2 *otg) { int ret; struct usb_phy *phy; u8 val, vdat_det, chgd_serx_dm; unsigned long timeout, interval; enum power_supply_charger_cable_type type = POWER_SUPPLY_CHARGER_TYPE_NONE; if (!charger_detect_enable(otg)) return cap_record.chrg_type; if (dwc3_intel_get_id(otg) == RID_GND) return POWER_SUPPLY_CHARGER_TYPE_B_DEVICE; phy = usb_get_phy(USB_PHY_TYPE_USB2); if (!phy) { otg_err(otg, "Get USB2 PHY failed\n"); return POWER_SUPPLY_CHARGER_TYPE_NONE; } /* PHY Enable: * Power on PHY */ enable_usb_phy(otg, true); if (is_basin_cove(otg)) { /* Enable ACA: * Enable ACA & ID detection logic. */ ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0); if (ret) otg_err(otg, "Fail to enable ACA&ID detection logic\n"); } /* DCD Enable: Change OPMODE to 01 (Non-driving), * TermSel to 0, & * XcvrSel to 01 (enable FS xcvr) */ usb_phy_io_write(phy, FUNCCTRL_OPMODE(1) | FUNCCTRL_XCVRSELECT(1), TUSB1211_FUNC_CTRL_SET); usb_phy_io_write(phy, FUNCCTRL_OPMODE(2) | FUNCCTRL_XCVRSELECT(2) | FUNCCTRL_TERMSELECT, TUSB1211_FUNC_CTRL_CLR); /*Enable SW control*/ usb_phy_io_write(phy, PWCTRL_SW_CONTROL, TUSB1211_POWER_CONTROL_SET); /* Enable IDPSRC */ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN, TUSB1211_VENDOR_SPECIFIC3_SET); /* Check DCD result, use same polling parameter */ timeout = jiffies + msecs_to_jiffies(DATACON_TIMEOUT); interval = DATACON_INTERVAL * 1000; /* us */ /* DCD Check: * Delay 66.5 ms. (Note: * TIDP_SRC_ON + TCHGD_SERX_DEB = * 347.8us + 66.1ms). */ usleep_range(66500, 67000); while (!time_after(jiffies, timeout)) { /* Read DP logic level. */ val = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4); if (val < 0) { otg_err(otg, "ULPI read error! try again\n"); continue; } if (!(val & VS4_CHGD_SERX_DP)) { otg_info(otg, "Data contact detected!\n"); break; } /* Polling interval */ usleep_range(interval, interval + 2000); } /* Disable DP pullup (Idp_src) */ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN, TUSB1211_VENDOR_SPECIFIC3_CLR); /* ID Check: * Check ID pin state. */ val = dwc3_intel_get_id(otg); if (val == RID_GND) { type = POWER_SUPPLY_CHARGER_TYPE_B_DEVICE; goto cleanup; } else if (val != RID_FLOAT) { type = dwc3_intel_aca_check(otg); goto cleanup; } /* SE1 Det Enable: * Read DP/DM logic level. Note: use DEBUG * because VS4 isn’t enabled in this situation. */ val = usb_phy_io_read(phy, TUSB1211_DEBUG); if (val < 0) otg_err(otg, "ULPI read error!\n"); val &= DEBUG_LINESTATE; /* If '11': SE1 detected; goto 'Cleanup'. * Else: goto 'Pri Det Enable'. */ if (val == 3) { type = POWER_SUPPLY_CHARGER_TYPE_SE1; goto cleanup; } /* Pri Det Enable: * Enable VDPSRC. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET); /* Wait >106.1ms (40ms for BC * Tvdpsrc_on, 66.1ms for TI CHGD_SERX_DEB). */ msleep(107); /* Pri Det Check: * Check if DM > VDATREF. */ vdat_det = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL); if (vdat_det < 0) otg_err(otg, "ULPI read error!\n"); vdat_det &= PWCTRL_VDAT_DET; /* Check if DM<VLGC */ chgd_serx_dm = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4); if (chgd_serx_dm < 0) otg_err(otg, "ULPI read error!\n"); chgd_serx_dm &= VS4_CHGD_SERX_DM; /* If VDAT_DET==0 || CHGD_SERX_DM==1: SDP detected * If VDAT_DET==1 && CHGD_SERX_DM==0: CDP/DCP */ if (vdat_det == 0 || chgd_serx_dm == 1) type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP; /* Disable VDPSRC. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR); /* If SDP, goto “Cleanup”. * Else, goto “Sec Det Enable” */ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_SDP) goto cleanup; /* Sec Det Enable: * delay 1ms. */ usleep_range(1000, 1500); /* Swap DP & DM */ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_CLR); /* Enable 'VDMSRC'. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET); /* Wait >73ms (40ms for BC Tvdmsrc_on, 33ms for TI TVDPSRC_DEB) */ msleep(80); /* Sec Det Check: * Check if DP>VDATREF. */ val = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL); if (val < 0) otg_err(otg, "ULPI read error!\n"); val &= PWCTRL_VDAT_DET; /* If VDAT_DET==0: CDP detected. * If VDAT_DET==1: DCP detected. */ if (!val) type = POWER_SUPPLY_CHARGER_TYPE_USB_CDP; else type = POWER_SUPPLY_CHARGER_TYPE_USB_DCP; /* Disable VDMSRC. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR); /* Swap DP & DM. */ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_SET); cleanup: /* If DCP detected, assert VDPSRC. */ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_DCP) usb_phy_io_write(phy, PWCTRL_SW_CONTROL | PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET); usb_put_phy(phy); switch (type) { case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK: case POWER_SUPPLY_CHARGER_TYPE_ACA_A: case POWER_SUPPLY_CHARGER_TYPE_ACA_B: case POWER_SUPPLY_CHARGER_TYPE_ACA_C: case POWER_SUPPLY_CHARGER_TYPE_USB_DCP: case POWER_SUPPLY_CHARGER_TYPE_USB_CDP: case POWER_SUPPLY_CHARGER_TYPE_SE1: dwc_otg_charger_hwdet(true); break; default: break; }; return type; }
static inline int gpadc_set_bits(u16 addr, u8 mask) { return intel_scu_ipc_update_register(addr, 0xff, mask); }
static int mrfl_ocd_probe(struct platform_device *pdev) { int ret; struct ocd_platform_data *ocd_plat_data; struct ocd_bcove_config_data ocd_config_data; struct ocd_info *cinfo = kzalloc(sizeof(struct ocd_info), GFP_KERNEL); if (!cinfo) { dev_err(&pdev->dev, "kzalloc failed\n"); return -ENOMEM; } cinfo->pdev = pdev; cinfo->irq = platform_get_irq(pdev, 0); platform_set_drvdata(pdev, cinfo); /* Creating a sysfs group with mrfl_ocd_gr attributes */ ret = sysfs_create_group(&pdev->dev.kobj, &mrfl_ocd_gr); if (ret) { dev_err(&pdev->dev, "sysfs create group failed\n"); goto exit_free; } /* Registering with hwmon class */ cinfo->dev = hwmon_device_register(&pdev->dev); if (IS_ERR(cinfo->dev)) { ret = PTR_ERR(cinfo->dev); cinfo->dev = NULL; dev_err(&pdev->dev, "hwmon_dev_regs failed\n"); goto exit_sysfs; } cinfo->bcu_intr_addr = ioremap_nocache(PMIC_SRAM_BCU_ADDR, IOMAP_LEN); if (!cinfo->bcu_intr_addr) { ret = -ENOMEM; dev_err(&pdev->dev, "ioremap_nocache failed\n"); goto exit_hwmon; } /* Unmask 2nd level BCU Interrupts-VW1,VW2&VC in the mask register */ ret = intel_scu_ipc_update_register(MBCUIRQ, 0x00, VWARN1_IRQ | VWARN2_IRQ | VCRIT_IRQ); if (ret) { dev_err(&pdev->dev, "EM:BCU: Unmasking of VW1 failed:%d\n", ret); goto exit_ioremap; } /* Unmask 1st level BCU interrupt in the mask register */ ret = intel_scu_ipc_update_register(MIRQLVL1, 0x00, BCU_ALERT); if (ret) { dev_err(&pdev->dev, "EM:BCU: Unmasking of BCU failed:%d\n", ret); goto exit_ioremap; } /* Register for Interrupt Handler */ ret = request_threaded_irq(cinfo->irq, NULL, ocd_intrpt_thread_handler, IRQF_TRIGGER_RISING, DRIVER_NAME, cinfo); if (ret) { dev_err(&pdev->dev, "EM:BCU: request_threaded_irq failed:%d\n", ret); goto exit_ioremap; } /*Read BCU configuration values from smip*/ ocd_plat_data = pdev->dev.platform_data; /* FIXME: Enable this code once SMIP driver is available for MRFLD */ #if 0 ret = ocd_plat_data->bcu_config_data(&ocd_config_data); if (ret) { dev_err(&pdev->dev, "EM:BCU:Read SMIP failed:%d\n", ret); goto exit_freeirq; } /* Program the BCU with default values read from the smip*/ ret = program_bcu(&ocd_config_data); if (ret) { dev_err(&pdev->dev, "EM:BCU:program_bcu() failed:%d\n", ret); goto exit_freeirq; } #endif enable_volt_trip_points(); enable_current_trip_points(); return 0; exit_freeirq: free_irq(cinfo->irq, cinfo); exit_ioremap: iounmap(cinfo->bcu_intr_addr); exit_hwmon: hwmon_device_unregister(cinfo->dev); exit_sysfs: sysfs_remove_group(&pdev->dev.kobj, &mrfl_ocd_gr); exit_free: kfree(cinfo); return ret; }