コード例 #1
0
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;
}
コード例 #2
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;
}
コード例 #3
0
static int dwc3_intel_byt_notify_charger_type(struct dwc_otg2 *otg,
		enum power_supply_charger_event event)
{
	struct power_supply_cable_props cap;
	unsigned long flags;

	/* Just return if charger detection is not enabled */
	if (!charger_detect_enable(otg) && !sdp_charging(otg))
		return 0;

	/* If OTG driver doesn't do charger detection, then no need
	 * to do notification on charger removal events */
	if (!charger_detect_enable(otg) &&
		(event == POWER_SUPPLY_CHARGER_EVENT_DISCONNECT)) {
		otg_err(otg, "%s: disconnect ignore!\n", __func__);
		return -EINVAL;
	}

	if (event > POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) {
		otg_err(otg,
		"%s: Invalid power_supply_charger_event!\n", __func__);
		return -EINVAL;
	}

	if ((otg->charging_cap.chrg_type ==
			POWER_SUPPLY_CHARGER_TYPE_USB_SDP) &&
			((otg->charging_cap.ma != 100) &&
			 (otg->charging_cap.ma != 150) &&
			 (otg->charging_cap.ma != 500) &&
			 (otg->charging_cap.ma != 900))) {
		otg_err(otg, "%s: invalid SDP current!\n", __func__);
		return -EINVAL;
	}

	spin_lock_irqsave(&otg->lock, flags);
	cap.chrg_type = otg->charging_cap.chrg_type;
	cap.ma = otg->charging_cap.ma;
	cap.chrg_evt = event;
	spin_unlock_irqrestore(&otg->lock, flags);

	if (sdp_charging(otg))
		atomic_notifier_call_chain(&otg->usb2_phy.notifier,
				USB_EVENT_ENUMERATED, &cap.ma);
	else
		atomic_notifier_call_chain(&otg->usb2_phy.notifier,
				USB_EVENT_CHARGER, &cap);

	return 0;
}
コード例 #4
0
static ssize_t store_vbus_evt(struct device *_dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	unsigned long flags;
	struct dwc_otg2	*otg = dwc3_get_otg();

	if (count != 2) {
		otg_err(otg, "return EINVAL\n");
		return -EINVAL;
	}

	if (count > 0 && buf[count-1] == '\n')
		((char *) buf)[count-1] = 0;

	switch (buf[0]) {
	case '1':
		otg_dbg(otg, "Change the VBUS to High\n");
		otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT;
		spin_lock_irqsave(&otg->lock, flags);
		dwc3_wakeup_otg_thread(otg);
		spin_unlock_irqrestore(&otg->lock, flags);
		return count;
	case '0':
		otg_dbg(otg, "Change the VBUS to Low\n");
		otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
		spin_lock_irqsave(&otg->lock, flags);
		dwc3_wakeup_otg_thread(otg);
		spin_unlock_irqrestore(&otg->lock, flags);
		return count;
	default:
		return -EINVAL;
	}

	return count;
}
コード例 #5
0
int dwc3_intel_byt_resume(struct dwc_otg2 *otg)
{
	struct pci_dev *pci_dev;

	if (!otg)
		return 0;

	pci_dev = to_pci_dev(otg->dev);

	/* From synopsys spec 12.2.11.
	 * Software cannot access memory-mapped I/O space
	 * for 10ms.
	 */
	mdelay(10);

	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);

	return 0;
}
コード例 #6
0
static enum dwc_otg_state do_wait_vbus_fall(struct dwc_otg2 *otg)
{
	int ret;

	u32 otg_events = 0;
	u32 user_events = 0;
	u32 otg_mask = 0;
	u32 user_mask = 0;

	otg_mask = OEVT_A_DEV_SESS_END_DET_EVNT;

	ret = sleep_until_event(otg, otg_mask,
			user_mask, &otg_events,
			&user_events, VBUS_TIMEOUT);
	if (ret < 0)
		return DWC_STATE_EXIT;

	if (otg_events & OEVT_A_DEV_SESS_END_DET_EVNT) {
		otg_dbg(otg, "OEVT_A_DEV_SESS_END_DET_EVNT\n");
		if (otg->charging_cap.chrg_type ==
				POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)
			dwc_otg_notify_charger_type(otg,
				POWER_SUPPLY_CHARGER_EVENT_DISCONNECT);
		return DWC_STATE_B_IDLE;
	}

	/* timeout*/
	if (!ret) {
		otg_err(otg, "Haven't get VBus drop event! Maybe something wrong\n");
		return DWC_STATE_B_IDLE;
	}

	return DWC_STATE_INVALID;
}
コード例 #7
0
int shady_cove_get_id(struct dwc_otg2 *otg)
{
	u8 schgrirq1;
	struct iio_channel *chan;
	int ret, rid, id = RID_UNKNOWN;

	ret = intel_scu_ipc_ioread8(PMIC_SCHGRIRQ1, &schgrirq1);
	if (ret) {
		otg_err(otg, "Fail to read id\n");
		return id;
	}

	/* PMIC_SCHGRIRQ1_SUSBIDDET bit definition:
	 * 0 = RID_A/B/C ; 1 = RID_GND ; 2 = RID_FLOAT */
	if (schgrirq1 & PMIC_SCHGRIRQ1_SUSBIDDET(2))
		return RID_FLOAT;
	else if (schgrirq1 & PMIC_SCHGRIRQ1_SUSBIDDET(1))
		return RID_GND;

	chan = iio_channel_get(NULL, "USBID");
	if (IS_ERR_OR_NULL(chan)) {
		otg_err(otg, "%s: Fail to get USBID channel\n", __func__);
		return id;
	}

	ret = iio_read_channel_raw(chan, &rid);
	if (ret) {
		otg_err(otg, "%s: Fail to read USBID channel", __func__);
		goto done;
	}

	if ((rid > 11150) && (rid < 13640))
		id = RID_A;
	else if ((rid > 6120) && (rid < 7480))
		id = RID_B;
	else if ((rid > 3285) && (rid < 4015))
		id = RID_C;

done:

	iio_channel_release(chan);
	return id;
}
コード例 #8
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;
}
コード例 #9
0
static ssize_t store_otg_id(struct device *_dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	unsigned long flags;
	struct dwc_otg2 *otg = dwc3_get_otg();

	if (!otg)
		return 0;
	if (count != 2) {
		otg_err(otg, "return EINVAL\n");
		return -EINVAL;
	}

	if (count > 0 && buf[count-1] == '\n')
		((char *) buf)[count-1] = 0;

	switch (buf[0]) {
	case 'a':
	case 'A':
		otg_dbg(otg, "Change ID to A\n");
		otg->user_events |= USER_ID_A_CHANGE_EVENT;
		spin_lock_irqsave(&otg->lock, flags);
		dwc3_wakeup_otg_thread(otg);
		otg_id = 0;
		spin_unlock_irqrestore(&otg->lock, flags);
		return count;
	case 'b':
	case 'B':
		otg_dbg(otg, "Change ID to B\n");
		otg->user_events |= USER_ID_B_CHANGE_EVENT;
		spin_lock_irqsave(&otg->lock, flags);
		dwc3_wakeup_otg_thread(otg);
		otg_id = 1;
		spin_unlock_irqrestore(&otg->lock, flags);
		return count;
	default:
		otg_err(otg, "Just support change ID to A!\n");
		return -EINVAL;
	}

	return count;
}
コード例 #10
0
static int dwc3_intel_notify_charger_type(struct dwc_otg2 *otg,
		enum power_supply_charger_event event)
{
	struct power_supply_cable_props cap;
	int ret = 0;
	unsigned long flags;

	if (!charger_detect_enable(otg) &&
		((otg->charging_cap.chrg_type !=
		POWER_SUPPLY_CHARGER_TYPE_USB_SDP) ||
		 event == POWER_SUPPLY_CHARGER_EVENT_DISCONNECT))
		return 0;

	if (event > POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) {
		otg_err(otg,
		"%s: Invalid power_supply_charger_event!\n", __func__);
		return -EINVAL;
	}

	if ((otg->charging_cap.chrg_type ==
			POWER_SUPPLY_CHARGER_TYPE_USB_SDP) &&
			((otg->charging_cap.ma != 0) &&
			 (otg->charging_cap.ma != 100) &&
			 (otg->charging_cap.ma != 150) &&
			 (otg->charging_cap.ma != 500) &&
			 (otg->charging_cap.ma != 900))) {
		otg_err(otg, "%s: invalid SDP current!\n", __func__);
		return -EINVAL;
	}

	spin_lock_irqsave(&otg->lock, flags);
	cap.chrg_type = otg->charging_cap.chrg_type;
	cap.ma = otg->charging_cap.ma;
	cap.chrg_evt = event;
	spin_unlock_irqrestore(&otg->lock, flags);

	atomic_notifier_call_chain(&otg->usb2_phy.notifier, USB_EVENT_CHARGER,
			&cap);

	return ret;
}
コード例 #11
0
/**
 * static int __init s3c6410_otg_module_init(void)
 * 
 * @brief module_init function
 * 
 * @return it returns result of platform_driver_register
 * @remark 
 * This function is called when the s3c6410_otg_driver is installed with the
 * insmod command. It registers the s3c6410_otg_driver structure with the
 * appropriate bus driver. This will cause the s3c6410_otg_driver_probe function
 * to be called. In addition, the bus driver will automatically expose
 * attributes defined for the device and driver in the special sysfs file
 * system.
 */
static int __init s3c6410_otg_module_init(void) 
{ 
	int	ret_val = 0;
	
	otg_dbg(OTG_DBG_OTGHCDI_DRIVER, "s3c_otg_module_init \n");		

	ret_val = platform_driver_register(&s3c6410_otg_driver);
	if (ret_val < 0) 
	{		
		otg_err(OTG_DBG_OTGHCDI_DRIVER, "platform_driver_register \n");		
	}
	return ret_val;    
} 
コード例 #12
0
static void start_peripheral(struct dwc_otg2 *otg)
{
	struct usb_gadget *gadget;
	int ret;

	if (dwc3_otg_pdata->prepare_start_peripheral)
		ret = dwc3_otg_pdata->prepare_start_peripheral(otg);

	gadget = otg->otg.gadget;
	if (!gadget) {
		otg_err(otg, "Haven't set gadget yet!\n");
		return;
	}

	otg->start_device(gadget);
}
コード例 #13
0
static void otg_power_work(struct work_struct *work)
{
	struct sec_otghost *otghost = container_of(work,
				struct sec_otghost, work);
	struct sec_otghost_data *hdata = otghost->otg_data;

	if (hdata && hdata->set_pwr_cb) {
		pr_info("otg power off - don't turn off the power\n");
		hdata->set_pwr_cb(0);
#ifdef CONFIG_USB_HOST_NOTIFY
		if (g_pUsbHcd)
			host_state_notify(&g_pUsbHcd->ndev,
					NOTIFY_HOST_OVERCURRENT);
#endif
	} else {
		otg_err(true, "invalid otghost data\n");
	}
}
コード例 #14
0
/* This function will control VUSBPHY to power gate/ungate USBPHY.
 * If current platform haven't using VUSBPHY, then assert/deassert
 * USBRST_N pin to make PHY enter reset state.
 */
static int enable_usb_phy(struct dwc_otg2 *otg, bool on_off)
{
	struct intel_dwc_otg_pdata *data;
	int ret;

	if (!otg || !otg->otg_data)
		return -EINVAL;

	data = (struct intel_dwc_otg_pdata *)otg->otg_data;
	if (data->using_vusbphy)
		ret = control_usb_phy_power(PMIC_VLDOCNT, on_off);
	else
		ret = control_usb_phy_power(PMIC_USBPHYCTRL, on_off);

	if (ret)
		otg_err(otg, "dwc3 %s usb phy failed\n",
				on_off ? "enable" : "disable");

	return ret;
}
コード例 #15
0
static int start_host(struct dwc_otg2 *otg)
{
	int ret = 0;
	struct usb_hcd *hcd = NULL;

	otg_dbg(otg, "\n");

	if (!otg->otg.host) {
		otg_err(otg, "Haven't set host yet!\n");
		return -ENODEV;
	}

	if (dwc3_otg_pdata->prepare_start_host)
		ret = dwc3_otg_pdata->prepare_start_host(otg);

	/* Start host driver */
	hcd = container_of(otg->otg.host, struct usb_hcd, self);
	ret = otg->start_host(hcd);

	return ret;
}
コード例 #16
0
int dwc3_intel_byt_suspend(struct dwc_otg2 *otg)
{
	struct pci_dev *pci_dev;
	pci_power_t state = PCI_D3hot;

	if (!otg)
		return 0;

	pci_dev = to_pci_dev(otg->dev);

	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);
	pci_set_power_state(pci_dev, state);

	return 0;
}
コード例 #17
0
static int dwc_otg2_set_peripheral(struct usb_otg *x,
                                   struct usb_gadget *gadget)
{
    struct dwc_otg2 *otg;

    if (!x) {
        otg_err(otg, "otg is NULL!\n");
        return -ENODEV;
    }

    otg = xceiv_to_dwc_otg2(x);
    otg_dbg(otg, "\n");

    if (!gadget) {
        otg->otg.gadget = NULL;
        stop_main_thread(otg);
        return -ENODEV;
    }

    otg->otg.gadget = gadget;
    otg->usb2_phy.state = OTG_STATE_B_IDLE;
    start_main_thread(otg);
    return 0;
}
コード例 #18
0
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;
}
コード例 #19
0
static enum dwc_otg_state do_a_host(struct dwc_otg2 *otg)
{
	int rc = 0;
	u32 otg_events, user_events, otg_mask, user_mask;
	int id = RID_UNKNOWN;
	unsigned long flags;

	/* If Battery low and connected charger is not ACA-DOCK.
	 * Then stop trying to start host mode. */
	if ((otg->usb2_phy.vbus_state == VBUS_DISABLED) &&
			(otg->charging_cap.chrg_type !=
			POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)) {
		otg_uevent_trigger(&otg->usb2_phy);
		return DWC_STATE_B_IDLE;
	}

	if (otg->charging_cap.chrg_type !=
			POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK) {
		dwc_otg_enable_vbus(otg, 1);

		/* meant receive vbus valid event*/
		if (do_wait_vbus_raise(otg) == DWC_STATE_A_HOST)
			otg_err(otg, "Drive VBUS maybe fail!\n");
	}

	rc = start_host(otg);
	if (rc < 0) {
		stop_host(otg);
		otg_err(otg, "start_host failed!");
		return DWC_STATE_INVALID;
	}

stay_host:
	otg_events = 0;
	user_events = 0;

	user_mask = USER_A_BUS_DROP |
				USER_ID_B_CHANGE_EVENT;
	otg_mask = OEVT_CONN_ID_STS_CHNG_EVNT |
			OEVT_A_DEV_SESS_END_DET_EVNT;

	rc = sleep_until_event(otg,
			otg_mask, user_mask,
			&otg_events, &user_events, 0);
	if (rc < 0) {
		stop_host(otg);
		return DWC_STATE_EXIT;
	}

	/* Higher priority first */
	if (otg_events & OEVT_A_DEV_SESS_END_DET_EVNT) {
		otg_dbg(otg, "OEVT_A_DEV_SESS_END_DET_EVNT\n");

		/* ACA-Dock plug out */
		if (otg->charging_cap.chrg_type ==
				POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)
			dwc_otg_notify_charger_type(otg,
					POWER_SUPPLY_CHARGER_EVENT_DISCONNECT);
		else
			dwc_otg_enable_vbus(otg, 0);

		stop_host(otg);
		return DWC_STATE_B_IDLE;
	}

	if (user_events & USER_A_BUS_DROP) {
		/* Due to big consume by DUT, even ACA-Dock connected,
		 * the battery capability still maybe decrease. For this
		 * case, still save host mode. Because DUT haven't drive VBus.*/
		if (otg->charging_cap.chrg_type ==
				POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)
			goto stay_host;

		dwc_otg_enable_vbus(otg, 0);
		stop_host(otg);
		return DWC_STATE_B_IDLE;
	}

	if (otg_events & OEVT_CONN_ID_STS_CHNG_EVNT) {
		otg_dbg(otg, "OEVT_CONN_ID_STS_CHNG_EVNT\n");
		id = get_id(otg);

		/* Plug out ACA_DOCK/USB device */
		if (id == RID_FLOAT) {
			if (otg->charging_cap.chrg_type ==
					POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK) {
				/* ACA_DOCK plug out, receive
				 * id change prior to vBus change
				 */
				dwc_otg_notify_charger_type(otg,
					POWER_SUPPLY_CHARGER_EVENT_DISCONNECT);

				stop_host(otg);
			} else {
				/* Normal USB device plug out */
				spin_lock_irqsave(&otg->lock, flags);
				otg->charging_cap.chrg_type =
					POWER_SUPPLY_CHARGER_TYPE_NONE;
				spin_unlock_irqrestore(&otg->lock, flags);

				stop_host(otg);
				dwc_otg_enable_vbus(otg, 0);
			}
		} else if (id == RID_GND || id == RID_A) {
			otg_dbg(otg, "Stay DWC_STATE_A_HOST!!\n");
			/* Prevent user fast plug in after plug out.
			 * It will cause the first ID change event lost.
			 * So need to check real ID currently.
			 */
			goto stay_host;
		} else {
			otg_err(otg, "Meet invalid charger cases!");
			spin_lock_irqsave(&otg->lock, flags);
			otg->charging_cap.chrg_type =
				POWER_SUPPLY_CHARGER_TYPE_NONE;
			spin_unlock_irqrestore(&otg->lock, flags);

			stop_host(otg);
		}
		return DWC_STATE_WAIT_VBUS_FALL;
	}

	/* Higher priority first */
	if (user_events & USER_ID_B_CHANGE_EVENT) {
		otg_dbg(otg, "USER_ID_B_CHANGE_EVENT\n");
		stop_host(otg);
		otg->user_events |= USER_ID_B_CHANGE_EVENT;
		return DWC_STATE_B_IDLE;
	}

	/* Invalid state */
	return DWC_STATE_INVALID;
}
コード例 #20
0
static enum dwc_otg_state do_charger_detection(struct dwc_otg2 *otg)
{
	enum dwc_otg_state state = DWC_STATE_INVALID;
	enum power_supply_charger_cable_type charger =
			POWER_SUPPLY_CHARGER_TYPE_NONE;
	unsigned long flags, ma = 0;

	charger = get_charger_type(otg);
	switch (charger) {
	case POWER_SUPPLY_CHARGER_TYPE_ACA_A:
	case POWER_SUPPLY_CHARGER_TYPE_ACA_B:
	case POWER_SUPPLY_CHARGER_TYPE_ACA_C:
		otg_err(otg, "Ignore micro ACA charger.\n");
		charger = POWER_SUPPLY_CHARGER_TYPE_NONE;
		break;
	case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
	case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
		state = DWC_STATE_B_PERIPHERAL;
		break;
	case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
		state = DWC_STATE_A_HOST;
		break;
	case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
	case POWER_SUPPLY_CHARGER_TYPE_SE1:
		state = DWC_STATE_CHARGING;
		break;
	case POWER_SUPPLY_CHARGER_TYPE_NONE:
	default:
		if (is_self_powered_b_device(otg)) {
			state = DWC_STATE_A_HOST;
			charger = POWER_SUPPLY_CHARGER_TYPE_B_DEVICE;
			break;
		}
	};

	switch (charger) {
	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:
		ma = 1500;
		break;
	case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
		break;
	default:
		otg_err(otg, "Charger type is not valid to notify battery\n");
		return -EINVAL;
	}

	spin_lock_irqsave(&otg->lock, flags);
	otg->charging_cap.chrg_type = charger;
	otg->charging_cap.ma = ma;
	spin_unlock_irqrestore(&otg->lock, flags);

	switch (charger) {
	case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
	case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
	case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
	case POWER_SUPPLY_CHARGER_TYPE_SE1:
		if (dwc_otg_notify_charger_type(otg,
					POWER_SUPPLY_CHARGER_EVENT_CONNECT) < 0)
			otg_err(otg, "Notify battery type failed!\n");
		break;
	case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
	/* SDP is complicate, it will be handle in set_power */
	default:
		break;
	}

	return state;
}
コード例 #21
0
static int dwc3_intel_set_power(struct usb_phy *_otg,
		unsigned ma)
{
	unsigned long flags;
	struct dwc_otg2 *otg = dwc3_get_otg();
	struct power_supply_cable_props cap;
	struct intel_dwc_otg_pdata *data;

	data = (struct intel_dwc_otg_pdata *)otg->otg_data;

	/* On ANN, due the VBUS haven't connect to internal USB PHY. So
	 * controller can't get disconnect interrupt which depend on vbus drop
	 * detection.
	 * So controller will receive early suspend and suspend interrupt. But
	 * we can detect vbus status to determine current scenario is real
	 * suspend or vbus drop.
	 */
	if (data->detect_vbus_drop && ma == OTG_DEVICE_SUSPEND) {
		if (!check_vbus_status(otg)) {
			cap.chrg_type = otg->charging_cap.chrg_type;
			cap.ma = otg->charging_cap.ma;
			cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
			atomic_notifier_call_chain(&otg->usb2_phy.notifier,
						USB_EVENT_CHARGER, &cap);
			return 0;
		}
	}

	if (otg->charging_cap.chrg_type ==
			POWER_SUPPLY_CHARGER_TYPE_USB_CDP)
		return 0;
	else if (otg->charging_cap.chrg_type !=
			POWER_SUPPLY_CHARGER_TYPE_USB_SDP) {
		otg_err(otg, "%s: currently, chrg type is not SDP!\n",
				__func__);
		return -EINVAL;
	}

	if (ma == OTG_DEVICE_SUSPEND) {
		spin_lock_irqsave(&otg->lock, flags);
		cap.chrg_type = otg->charging_cap.chrg_type;
		cap.ma = otg->charging_cap.ma;
		cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_SUSPEND;
		spin_unlock_irqrestore(&otg->lock, flags);

		/* mA is zero mean D+/D- opened cable.
		 * If SMIP set, then notify 500mA.
		 * Otherwise, notify 0mA.
		*/
		if (!cap.ma) {
			if (data->charging_compliance) {
				cap.ma = 500;
				cap.chrg_evt =
					POWER_SUPPLY_CHARGER_EVENT_CONNECT;
			}
		/* For standard SDP, if SMIP set, then ignore suspend */
		} else if (data->charging_compliance)
			return 0;
		/* Stander SDP(cap.mA != 0) and SMIP not set.
		 * Should send 0mA with SUSPEND event
		 */
		else
			cap.ma = 0;

		atomic_notifier_call_chain(&otg->usb2_phy.notifier,
				USB_EVENT_CHARGER, &cap);
		otg_dbg(otg, "Notify EM");
		otg_dbg(otg, "POWER_SUPPLY_CHARGER_EVENT_SUSPEND\n");

		return 0;
	} else if (ma == OTG_DEVICE_RESUME) {
		otg_dbg(otg, "Notify EM");
		otg_dbg(otg, "POWER_SUPPLY_CHARGER_EVENT_CONNECT\n");
		dwc3_intel_notify_charger_type(otg,
				POWER_SUPPLY_CHARGER_EVENT_CONNECT);

		return 0;
	}

	/* For SMIP set case, only need to report 500/900mA */
	if (data->charging_compliance) {
		if ((ma != OTG_USB2_500MA) &&
				(ma != OTG_USB3_900MA))
			return 0;
	}

	/* Covert macro to integer number*/
	switch (ma) {
	case OTG_USB2_0MA:
		ma = 0;
		break;
	case OTG_USB2_100MA:
		ma = 100;
		break;
	case OTG_USB3_150MA:
		ma = 150;
		break;
	case OTG_USB2_500MA:
		ma = 500;
		break;
	case OTG_USB3_900MA:
		ma = 900;
		break;
	default:
		otg_err(otg, "Device driver set invalid SDP current value!\n");
		return -EINVAL;
	}

	spin_lock_irqsave(&otg->lock, flags);
	otg->charging_cap.ma = ma;
	spin_unlock_irqrestore(&otg->lock, flags);

	dwc3_intel_notify_charger_type(otg,
			POWER_SUPPLY_CHARGER_EVENT_CONNECT);

	return 0;
}
コード例 #22
0
static int dwc3_intel_handle_notification(struct notifier_block *nb,
		unsigned long event, void *data)
{
	int state;
	unsigned long flags, valid_chrg_type;
	struct dwc_otg2 *otg = dwc3_get_otg();
	struct power_supply_cable_props *cap;

	if (!otg)
		return NOTIFY_BAD;

	valid_chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP |
		POWER_SUPPLY_CHARGER_TYPE_USB_CDP |
		POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK;

	spin_lock_irqsave(&otg->lock, flags);
	switch (event) {
	case USB_EVENT_ID:
		otg->otg_events |= OEVT_CONN_ID_STS_CHNG_EVNT;
		state = NOTIFY_OK;
		break;
	case USB_EVENT_VBUS:
		/* WA for EM driver which should not sent VBUS event
		 * if UTMI PHY selected. */
		if (!charger_detect_enable(otg)) {
			state = NOTIFY_OK;
			goto done;
		}

		if (*(int *)data) {
			otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT;
			otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT;
		} else {
			otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
			otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT;
		}
		state = NOTIFY_OK;
		break;
	case USB_EVENT_CHARGER:
		if (charger_detect_enable(otg)) {
			state = NOTIFY_DONE;
			goto done;
		}
		cap = (struct power_supply_cable_props *)data;
		if (!(cap->chrg_type & valid_chrg_type)) {
			otg_err(otg, "Ignore invalid charger type!\n");
			state = NOTIFY_DONE;
			goto done;
		}

		/* Ignore the events which send by USB driver itself. */
		if (cap->chrg_evt == POWER_SUPPLY_CHARGER_EVENT_CONNECT)
			if (cap_record.chrg_type == POWER_SUPPLY_CHARGER_TYPE_USB_SDP) {
				state = NOTIFY_DONE;
				goto done;
			}

		if (cap->chrg_evt == POWER_SUPPLY_CHARGER_EVENT_CONNECT) {
			otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT;
			otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT;

			cap_record.chrg_type = cap->chrg_type;
			cap_record.ma = cap->ma;
			cap_record.chrg_evt = cap->chrg_evt;
		} else if (cap->chrg_evt ==
				POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) {
			otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
			otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT;

			cap_record.chrg_type = POWER_SUPPLY_CHARGER_TYPE_NONE;
			cap_record.ma = 0;
			cap_record.chrg_evt =
				POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
		}

		if (cap->chrg_type == POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)
			otg->otg_events |= OEVT_CONN_ID_STS_CHNG_EVNT;

		state = NOTIFY_OK;
		break;
	default:
		otg_dbg(otg, "DWC OTG Notify unknow notify message\n");
		state = NOTIFY_DONE;
	}

	dwc3_wakeup_otg_thread(otg);
done:
	spin_unlock_irqrestore(&otg->lock, flags);

	return state;

}
コード例 #23
0
static int dwc3_intel_byt_set_power(struct usb_phy *_otg,
		unsigned ma)
{
	unsigned long flags;
	struct dwc_otg2 *otg = dwc3_get_otg();
	struct power_supply_cable_props cap;
	struct intel_dwc_otg_pdata *data;

	data = (struct intel_dwc_otg_pdata *)otg->otg_data;
	if (!data)
		return -EINVAL;

	if (ma == OTG_USB2_100MA ||
		ma == OTG_USB3_150MA ||
		ma == OTG_USB2_500MA ||
		ma == OTG_USB3_900MA ||
		ma == OTG_DEVICE_RESUME) {
		otg_dbg(otg, "cancel discon work\n");
		__cancel_delayed_work(&data->suspend_discon_work);
	} else if (ma == OTG_DEVICE_SUSPEND) {
		otg_dbg(otg, "schedule discon work\n");
		schedule_delayed_work(&data->suspend_discon_work,
				SUSPEND_DISCONNECT_TIMEOUT);
	}

	/* Needn't notify charger capability if charger_detection disable */
	if (!charger_detect_enable(otg) && !sdp_charging(otg))
		return 0;

	if (ma == OTG_DEVICE_SUSPEND) {
		spin_lock_irqsave(&otg->lock, flags);
		cap.chrg_type = otg->charging_cap.chrg_type;
		cap.ma = otg->charging_cap.ma;
		cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_SUSPEND;
		spin_unlock_irqrestore(&otg->lock, flags);

		/* ma is zero mean D+/D- opened cable.
		 * If SMIP set, then notify 500ma.
		 * Otherwise, notify 0ma.
		*/
		if (!cap.ma) {
			if (data->charging_compliance) {
				cap.ma = 500;
				cap.chrg_evt =
					POWER_SUPPLY_CHARGER_EVENT_CONNECT;
			}
		/* For standard SDP, if SMIP set, then ignore suspend */
		} else if (data->charging_compliance)
			return 0;
		/* Stander SDP(cap.ma != 0) and SMIP not set.
		 * Should send 0ma with SUSPEND event
		 */
		else
			cap.ma = 2;

		if (sdp_charging(otg))
			atomic_notifier_call_chain(&otg->usb2_phy.notifier,
					USB_EVENT_ENUMERATED, &cap.ma);
		else
			atomic_notifier_call_chain(&otg->usb2_phy.notifier,
					USB_EVENT_CHARGER, &cap);
		otg_dbg(otg, "Notify EM	CHARGER_EVENT_SUSPEND\n");

		return 0;
	} else if (ma == OTG_DEVICE_RESUME) {
		otg_dbg(otg, "Notify EM CHARGER_EVENT_CONNECT\n");
		dwc3_intel_byt_notify_charger_type(otg,
				POWER_SUPPLY_CHARGER_EVENT_CONNECT);

		return 0;
	}

	/* For SMIP set case, only need to report 500/900ma */
	if (data->charging_compliance) {
		if ((ma != OTG_USB2_500MA) &&
				(ma != OTG_USB3_900MA))
			return 0;
	}

	/* Covert macro to integer number*/
	switch (ma) {
	case OTG_USB2_100MA:
		ma = 100;
		break;
	case OTG_USB3_150MA:
		ma = 150;
		break;
	case OTG_USB2_500MA:
		ma = 500;
		break;
	case OTG_USB3_900MA:
		ma = 900;
		break;
	default:
		otg_err(otg, "Device driver set invalid SDP current value!\n");
		return -EINVAL;
	}

	spin_lock_irqsave(&otg->lock, flags);
	otg->charging_cap.ma = ma;
	spin_unlock_irqrestore(&otg->lock, flags);

	dwc3_intel_byt_notify_charger_type(otg,
			POWER_SUPPLY_CHARGER_EVENT_CONNECT);

	return 0;
}
コード例 #24
0
static int dwc3_otg_create_children(struct dwc_otg2 *otg,
		struct resource *res, int num)
{
	struct platform_device *dwc_host, *dwc_gadget;
	enum dwc3_otg_mode mode = dwc3_otg_pdata->mode;
	int retval = 0, i;

	if (!otg || !res)
		return -EINVAL;

	if (num != 2)
		return -EINVAL;

	dwc_host = dwc_gadget = NULL;

	for (i = 0; i < 2; i++) {
		if (res[i].flags == IORESOURCE_MEM) {
			otg->usb2_phy.io_priv = ioremap_nocache(
				res[i].start, res[i].end - res[i].start);
			if (!otg->usb2_phy.io_priv) {
				otg_err(otg, "dwc3 otg ioremap failed\n");
				return -ENOMEM;
			}
			break;
		}
	}

	/* resource have no mem io resource */
	if (!otg->usb2_phy.io_priv)
		return -EINVAL;

	platform_par = kzalloc(sizeof(*platform_par), GFP_KERNEL);
	if (!platform_par) {
		otg_err(otg, "alloc dwc_device_par failed\n");
		goto err1;
	}

	platform_par->io_addr = otg->usb2_phy.io_priv;
	platform_par->len = res[i].end - res[i].start;

	if (mode == DWC3_DEVICE_ONLY)
		goto device_only;

	dwc_host = platform_device_alloc(DWC3_HOST_NAME,
			HOST_DEVID);
	if (!dwc_host) {
		otg_err(otg, "couldn't allocate dwc3 host device\n");
		goto err2;
	}

	retval = platform_device_add_resources(dwc_host, res, num);
	if (retval) {
		otg_err(otg, "couldn't add resources to dwc3 device\n");
		goto err3;
	}

	platform_device_add_data(dwc_host, platform_par,
			sizeof(struct dwc_device_par));

	dwc_host->dev.dma_mask = otg->dev->dma_mask;
	dwc_host->dev.dma_parms = otg->dev->dma_parms;
	dwc_host->dev.parent = otg->dev;

	retval = platform_device_add(dwc_host);
	if (retval)	{
		otg_err(otg, "failed to register dwc3 host\n");
		goto err1;
	}

	otg->host = dwc_host;

	if (mode != DWC3_DRD)
		return 0;

device_only:
	dwc_gadget = platform_device_alloc(DWC3_DEVICE_NAME,
			GADGET_DEVID);
	if (!dwc_gadget) {
		otg_err(otg, "couldn't allocate dwc3 device\n");
		goto err3;
	}

	retval = platform_device_add_resources(dwc_gadget,
				res, num);
	if (retval) {
		otg_err(otg, "couldn't add resources to dwc3 device\n");
		goto err3;
	}

	dwc_gadget->dev.dma_mask = otg->dev->dma_mask;
	dwc_gadget->dev.dma_parms = otg->dev->dma_parms;
	dwc_gadget->dev.parent = otg->dev;

	platform_device_add_data(dwc_gadget, platform_par,
			sizeof(struct dwc_device_par));
	retval = platform_device_add(dwc_gadget);
	if (retval) {
		otg_err(otg, "failed to register dwc3 gadget\n");
		goto err3;
	}
	otg->gadget = dwc_gadget;

	return 0;

err3:
	if (mode == DWC3_DRD)
		platform_device_unregister(dwc_host);

err2:
	kfree(platform_par);

err1:
	iounmap(otg->usb2_phy.io_priv);

	return retval;
}
コード例 #25
0
static struct dwc_otg2 *dwc3_otg_alloc(struct device *dev)
{
	struct dwc_otg2 *otg = NULL;
	struct usb_phy *usb_phy;
	int retval;

	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
	if (!otg) {
		dev_err(dev, "Alloc otg failed\n");
		return NULL;
	}

	the_transceiver = otg;
	otg->otg_data = dev->platform_data;

	usb_phy = &otg->usb2_phy;
	otg->otg.phy = usb_phy;
	otg->usb2_phy.otg = &otg->otg;

	otg->dev		= dev;
	otg->usb3_phy.dev		= otg->dev;
	otg->usb3_phy.label		= "dwc-usb3-phy";
	otg->usb3_phy.state		= OTG_STATE_UNDEFINED;
	otg->usb3_phy.otg	= &otg->otg;
	otg->usb2_phy.dev		= otg->dev;
	otg->usb2_phy.label		= "dwc-usb2-phy";
	otg->usb2_phy.state		= OTG_STATE_UNDEFINED;
	otg->usb2_phy.set_power	= dwc3_otg_pdata->set_power;
	otg->usb2_phy.get_chrg_status	= dwc_otg_get_chrg_status;
	otg->usb2_phy.io_ops = &dwc_otg_io_ops;
	otg->usb2_phy.otg	= &otg->otg;
	otg->otg.set_host	= dwc_otg2_set_host;
	otg->otg.set_peripheral	= dwc_otg2_set_peripheral;
	ATOMIC_INIT_NOTIFIER_HEAD(&otg->usb2_phy.notifier);
	ATOMIC_INIT_NOTIFIER_HEAD(&otg->usb3_phy.notifier);

	otg->state = DWC_STATE_B_IDLE;
	spin_lock_init(&otg->lock);
	init_waitqueue_head(&otg->main_wq);

	/* Register otg notifier to monitor ID and VBus change events */
	otg->nb.notifier_call = dwc_otg_handle_notification;
	usb_register_notifier(&otg->usb2_phy, &otg->nb);

	otg_dbg(otg, "Version: %s\n", VERSION);
	retval = usb_add_phy(&otg->usb2_phy, USB_PHY_TYPE_USB2);
	if (retval) {
		otg_err(otg, "can't register transceiver, err: %d\n",
			retval);
		goto err1;
	}

	retval = usb_add_phy(&otg->usb3_phy, USB_PHY_TYPE_USB3);
	if (retval) {
		otg_err(otg, "can't register transceiver, err: %d\n",
			retval);
		goto err2;
	}

	return otg;

err2:
	usb_remove_phy(&otg->usb2_phy);

err1:
	kfree(otg);
	otg = NULL;

	return otg;
}
コード例 #26
0
static enum power_supply_charger_cable_type
			dwc3_intel_byt_get_charger_type(struct dwc_otg2 *otg)
{
	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;

	/* No need to do charger detection if not enabled */
	if (!charger_detect_enable(otg))
		return POWER_SUPPLY_CHARGER_TYPE_USB_SDP;

	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);

	/* Wait 10ms (~5ms before PHY de-asserts DIR,
	 * XXus for initial Link reg sync-up).*/
	msleep(20);

	/* 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);

	/* 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;
}
コード例 #27
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;
}
コード例 #28
0
static int dwc_otg_probe(struct pci_dev *pdev,
			const struct pci_device_id *id)
{
	int retval = 0;
	struct resource		res[2];
	struct dwc_otg2 *otg = NULL;
	unsigned long resource, len;

	if (!dwc3_otg_pdata)
		return -ENODEV;

	if (pci_enable_device(pdev) < 0) {
		dev_err(&pdev->dev, "pci device enable failed\n");
		return -ENODEV;
	}

	pci_set_power_state(pdev, PCI_D0);
	pci_set_master(pdev);

	otg = dwc3_otg_alloc(&pdev->dev);
	if (!otg) {
		dev_err(&pdev->dev, "dwc3 otg init failed\n");
		goto err;
	}

	/* control register: BAR 0 */
	resource = pci_resource_start(pdev, 0);
	len = pci_resource_len(pdev, 0);
	if (!request_mem_region(resource, len, driver_name)) {
		otg_err(otg, "Request memory region failed\n");
		retval = -EBUSY;
		goto err;
	}

	otg_dbg(otg, "dwc otg pci resouce: 0x%lu, len: 0x%lu\n",
			resource, len);
	otg_dbg(otg, "vendor: 0x%x, device: 0x%x\n",
			pdev->vendor, pdev->device);

	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));

	res[0].start	= pci_resource_start(pdev, 0);
	res[0].end	= pci_resource_end(pdev, 0);
	res[0].name	= "dwc_usb3_io";
	res[0].flags	= IORESOURCE_MEM;

	res[1].start	= pdev->irq;
	res[1].name	= "dwc_usb3_irq";
	res[1].flags	= IORESOURCE_IRQ;

	retval = dwc3_otg_create_children(otg, res, ARRAY_SIZE(res));
	if (retval) {
		otg_err(otg, "dwc3 otg create alloc children failed\n");
		goto err;
	}

	otg->irqnum = pdev->irq;

	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "dwc_otg_wakelock");

	if (dwc3_otg_pdata->platform_init) {
		retval = dwc3_otg_pdata->platform_init(otg);
		if (retval)
			goto err;
	}

	pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_allow(&pdev->dev);
	pm_runtime_mark_last_busy(otg->dev);
	pm_runtime_put_autosuspend(&pdev->dev);

	return 0;

err:
	if (the_transceiver)
		dwc_otg_remove(pdev);

	return retval;
}
コード例 #29
0
static int s3c6410_otg_drv_probe (struct platform_device *pdev)
{

	int ret_val = 0;
	u32 reg_val = 0;
	
	otg_dbg(OTG_DBG_OTGHCDI_DRIVER, "s3c_otg_drv_probe \n");
	
	otg_clock = clk_get(&pdev->dev, "otg");
	if (otg_clock == NULL) {
		printk(KERN_INFO "failed to find otg clock source\n");
		return -ENOENT;
	}
	clk_enable(otg_clock);

///init for host mode
/** 
	Allocate memory for the base HCD &	Initialize the base HCD.
*/
	g_pUsbHcd = usb_create_hcd(&s3c6410_otg_hc_driver, &pdev->dev, dev_name(&pdev->dev));
	if (g_pUsbHcd == NULL) 
	{
		ret_val = -ENOMEM;
		otg_err(OTG_DBG_OTGHCDI_DRIVER, "failed to usb_create_hcd\n");
		goto err_out_clk;
	}


//	mapping hcd resource & device resource
	
	g_pUsbHcd->rsrc_start = pdev->resource[0].start;
	g_pUsbHcd->rsrc_len   = pdev->resource[0].end - pdev->resource[0].start + 1;

	if (!request_mem_region(g_pUsbHcd->rsrc_start, g_pUsbHcd->rsrc_len, gHcdName)) 
	{
		otg_err(OTG_DBG_OTGHCDI_DRIVER, "failed to request_mem_region\n");
		reg_val = -EBUSY;
		goto err_out_create_hcd;
	}


//Physical address => Virtual address
	g_pUsbHcd->regs = S3C_VA_OTG; 
	g_pUsbHcd->self.otg_port = 1;
	
	g_pUDCBase = (u8 *)g_pUsbHcd->regs;

	/// call others' init()
	reg_val = otg_hcd_init_modules();
	if( reg_val != USB_ERR_SUCCESS)
	{		
		otg_err(OTG_DBG_OTGHCDI_DRIVER, "failed to otg_hcd_init_modules\n");
		reg_val = USB_ERR_FAIL;
		goto err_out_create_hcd;
	}

	/**
	 * Attempt to ensure this device is really a s3c6410 USB-OTG Controller.
	 * Read and verify the SNPSID register contents. The value should be
	 * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX".
	 */
	//reg_val = read_reg_32((unsigned int *)((u8 *)g_pUsbHcd->regs + 0x40)); 
	
	reg_val = read_reg_32(0x40); 
	if ((reg_val & 0xFFFFF000) != 0x4F542000) 
	{
		otg_err(OTG_DBG_OTGHCDI_DRIVER, "Bad value for SNPSID: 0x%x\n", reg_val);
		ret_val = -EINVAL;
		goto err_out_create_hcd_init;
	}

	/*
	 * Finish generic HCD initialization and start the HCD. This function
	 * allocates the DMA buffer pool, registers the USB bus, requests the
	 * IRQ line, and calls s3c6410_otghcd_start method.
	 */
	ret_val = usb_add_hcd(g_pUsbHcd, pdev->resource[1].start, IRQF_DISABLED);
	if (ret_val < 0) 
	{
		goto err_out_create_hcd_init;
	}

	otg_dbg(OTG_DBG_OTGHCDI_DRIVER,"OTG HCD Initialized HCD, bus=%s, usbbus=%d\n", 
		    "EMSP OTG Controller", g_pUsbHcd->self.busnum);
	return USB_ERR_SUCCESS;

err_out_create_hcd_init:	
	otg_hcd_deinit_modules();
	release_mem_region(g_pUsbHcd->rsrc_start, g_pUsbHcd->rsrc_len);

err_out_create_hcd: 
	usb_put_hcd(g_pUsbHcd);
	
err_out_clk:
	
	return ret_val;
}
コード例 #30
0
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;
}