Пример #1
0
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;
}
Пример #2
0
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);
};
Пример #3
0
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;
}
Пример #4
0
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));
}
Пример #5
0
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;
}
Пример #6
0
/**
 * 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;
}
Пример #7
0
/**
 * 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;
}
Пример #8
0
/* 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;
}
Пример #9
0
/*
 * 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__);
}
Пример #10
0
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;
}
Пример #11
0
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);
}
Пример #12
0
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);
}
Пример #14
0
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;
}
Пример #15
0
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;
}
Пример #16
0
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;
}
Пример #17
0
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;
	}
}
Пример #18
0
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;
}
Пример #19
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;
}
Пример #20
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);
}
Пример #22
0
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;
}