Commit b38bcc8e authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'usb-ci-v5.5-rc1' of...

Merge tag 'usb-ci-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb into usb-next

Peter writes:

- Improve the Vbus handler
- Improve the HSIC handler for i.mx serial SoC
- Some other tiny changes

* tag 'usb-ci-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb:
  usb: chipidea: imx: pinctrl for HSIC is optional
  usb: chipidea: imx: refine the error handling for hsic
  usb: chipidea: imx: change hsic power regulator as optional
  usb: chipidea: imx: check data->usbmisc_data against NULL before access
  usb: chipidea: core: change vbus-regulator as optional
  usb: chipidea: imx: enable vbus and id wakeup only for OTG events
  usb: chipidea: udc: protect usb interrupt enable
  usb: chipidea: udc: add new API ci_hdrc_gadget_connect
parents 347bc8cb 4d614128
Loading
Loading
Loading
Loading
+50 −29
Original line number Diff line number Diff line
@@ -274,11 +274,14 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)

	switch (event) {
	case CI_HDRC_IMX_HSIC_ACTIVE_EVENT:
		if (data->pinctrl) {
			ret = pinctrl_select_state(data->pinctrl,
					data->pinctrl_hsic_active);
			if (ret)
			dev_err(dev, "hsic_active select failed, err=%d\n",
				dev_err(dev,
					"hsic_active select failed, err=%d\n",
					ret);
		}
		break;
	case CI_HDRC_IMX_HSIC_SUSPEND_EVENT:
		ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data);
@@ -306,7 +309,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
	const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
	struct device_node *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	struct pinctrl_state *pinctrl_hsic_idle;

	of_id = of_match_device(ci_hdrc_imx_dt_ids, dev);
	if (!of_id)
@@ -330,12 +332,42 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
		pdata.flags |= CI_HDRC_IMX_IS_HSIC;
		data->usbmisc_data->hsic = 1;
		data->pinctrl = devm_pinctrl_get(dev);
		if (IS_ERR(data->pinctrl)) {
		if (PTR_ERR(data->pinctrl) == -ENODEV)
			data->pinctrl = NULL;
		else if (IS_ERR(data->pinctrl)) {
			if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER)
				dev_err(dev, "pinctrl get failed, err=%ld\n",
					PTR_ERR(data->pinctrl));
			return PTR_ERR(data->pinctrl);
		}

		data->hsic_pad_regulator =
				devm_regulator_get_optional(dev, "hsic");
		if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
			/* no pad regualator is needed */
			data->hsic_pad_regulator = NULL;
		} else if (IS_ERR(data->hsic_pad_regulator)) {
			if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER)
				dev_err(dev,
					"Get HSIC pad regulator error: %ld\n",
					PTR_ERR(data->hsic_pad_regulator));
			return PTR_ERR(data->hsic_pad_regulator);
		}

		if (data->hsic_pad_regulator) {
			ret = regulator_enable(data->hsic_pad_regulator);
			if (ret) {
				dev_err(dev,
					"Failed to enable HSIC pad regulator\n");
				return ret;
			}
		}
	}

	/* HSIC pinctrl handling */
	if (data->pinctrl) {
		struct pinctrl_state *pinctrl_hsic_idle;

		pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle");
		if (IS_ERR(pinctrl_hsic_idle)) {
			dev_err(dev,
@@ -358,27 +390,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
					PTR_ERR(data->pinctrl_hsic_active));
			return PTR_ERR(data->pinctrl_hsic_active);
		}

		data->hsic_pad_regulator = devm_regulator_get(dev, "hsic");
		if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) {
			return -EPROBE_DEFER;
		} else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
			/* no pad regualator is needed */
			data->hsic_pad_regulator = NULL;
		} else if (IS_ERR(data->hsic_pad_regulator)) {
			dev_err(dev, "Get HSIC pad regulator error: %ld\n",
					PTR_ERR(data->hsic_pad_regulator));
			return PTR_ERR(data->hsic_pad_regulator);
		}

		if (data->hsic_pad_regulator) {
			ret = regulator_enable(data->hsic_pad_regulator);
			if (ret) {
				dev_err(dev,
					"Failed to enable HSIC pad regulator\n");
				return ret;
			}
		}
	}

	if (pdata.flags & CI_HDRC_PMQOS)
@@ -433,6 +444,16 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
		goto err_clk;
	}

	if (data->usbmisc_data) {
		if (!IS_ERR(pdata.id_extcon.edev) ||
		    of_property_read_bool(np, "usb-role-switch"))
			data->usbmisc_data->ext_id = 1;

		if (!IS_ERR(pdata.vbus_extcon.edev) ||
		    of_property_read_bool(np, "usb-role-switch"))
			data->usbmisc_data->ext_vbus = 1;
	}

	ret = imx_usbmisc_init_post(data->usbmisc_data);
	if (ret) {
		dev_err(dev, "usbmisc post failed, ret=%d\n", ret);
+2 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ struct imx_usbmisc_data {
	unsigned int evdo:1; /* set external vbus divider option */
	unsigned int ulpi:1; /* connected to an ULPI phy */
	unsigned int hsic:1; /* HSIC controlller */
	unsigned int ext_id:1; /* ID from exteranl event */
	unsigned int ext_vbus:1; /* Vbus from exteranl event */
};

int imx_usbmisc_init(struct imx_usbmisc_data *data);
+1 −1
Original line number Diff line number Diff line
@@ -683,7 +683,7 @@ static int ci_get_platdata(struct device *dev,

	if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) {
		/* Get the vbus regulator */
		platdata->reg_vbus = devm_regulator_get(dev, "vbus");
		platdata->reg_vbus = devm_regulator_get_optional(dev, "vbus");
		if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) {
			return -EPROBE_DEFER;
		} else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) {
+38 −35
Original line number Diff line number Diff line
@@ -1524,29 +1524,24 @@ static const struct usb_ep_ops usb_ep_ops = {
/******************************************************************************
 * GADGET block
 *****************************************************************************/
static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
/**
 * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded
 */
static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
{
	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
	unsigned long flags;
	int gadget_ready = 0;

	spin_lock_irqsave(&ci->lock, flags);
	ci->vbus_active = is_active;
	if (ci->driver)
		gadget_ready = 1;
	spin_unlock_irqrestore(&ci->lock, flags);

	if (ci->usb_phy)
		usb_phy_set_charger_state(ci->usb_phy, is_active ?
			USB_CHARGER_PRESENT : USB_CHARGER_ABSENT);

	if (gadget_ready) {
	if (is_active) {
		pm_runtime_get_sync(&_gadget->dev);
		hw_device_reset(ci);
		spin_lock_irqsave(&ci->lock, flags);
		if (ci->driver) {
			hw_device_state(ci, ci->ep0out->qh.dma);
			usb_gadget_set_state(_gadget, USB_STATE_POWERED);
			usb_udc_vbus_handler(_gadget, true);
		}
		spin_unlock_irqrestore(&ci->lock, flags);
	} else {
		usb_udc_vbus_handler(_gadget, false);
		if (ci->driver)
@@ -1561,6 +1556,22 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
	}
}

static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{
	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
	unsigned long flags;

	spin_lock_irqsave(&ci->lock, flags);
	ci->vbus_active = is_active;
	spin_unlock_irqrestore(&ci->lock, flags);

	if (ci->usb_phy)
		usb_phy_set_charger_state(ci->usb_phy, is_active ?
			USB_CHARGER_PRESENT : USB_CHARGER_ABSENT);

	if (ci->driver)
		ci_hdrc_gadget_connect(_gadget, is_active);

	return 0;
}

@@ -1785,18 +1796,10 @@ static int ci_udc_start(struct usb_gadget *gadget,
		return retval;
	}

	pm_runtime_get_sync(&ci->gadget.dev);
	if (ci->vbus_active) {
		hw_device_reset(ci);
	} else {
	if (ci->vbus_active)
		ci_hdrc_gadget_connect(gadget, 1);
	else
		usb_udc_vbus_handler(&ci->gadget, false);
		pm_runtime_put_sync(&ci->gadget.dev);
		return retval;
	}

	retval = hw_device_state(ci, ci->ep0out->qh.dma);
	if (retval)
		pm_runtime_put_sync(&ci->gadget.dev);

	return retval;
}
@@ -1826,6 +1829,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
	unsigned long flags;

	spin_lock_irqsave(&ci->lock, flags);
	ci->driver = NULL;

	if (ci->vbus_active) {
		hw_device_state(ci, 0);
@@ -1838,7 +1842,6 @@ static int ci_udc_stop(struct usb_gadget *gadget)
		pm_runtime_put(&ci->gadget.dev);
	}

	ci->driver = NULL;
	spin_unlock_irqrestore(&ci->lock, flags);

	ci_udc_stop_for_otg_fsm(ci);
+23 −8
Original line number Diff line number Diff line
@@ -100,6 +100,9 @@
#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID	MX7D_USB_VBUS_WAKEUP_SOURCE(2)
#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END	MX7D_USB_VBUS_WAKEUP_SOURCE(3)

#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \
				 MX6_BM_ID_WAKEUP)

struct usbmisc_ops {
	/* It's called once when probe a usb device */
	int (*init)(struct imx_usbmisc_data *data);
@@ -330,14 +333,25 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
	return 0;
}

static u32 usbmisc_wakeup_setting(struct imx_usbmisc_data *data)
{
	u32 wakeup_setting = MX6_USB_OTG_WAKEUP_BITS;

	if (data->ext_id)
		wakeup_setting &= ~MX6_BM_ID_WAKEUP;

	if (data->ext_vbus)
		wakeup_setting &= ~MX6_BM_VBUS_WAKEUP;

	return wakeup_setting;
}

static int usbmisc_imx6q_set_wakeup
	(struct imx_usbmisc_data *data, bool enabled)
{
	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
	unsigned long flags;
	u32 val;
	u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
		MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
	int ret = 0;

	if (data->index > 3)
@@ -346,11 +360,12 @@ static int usbmisc_imx6q_set_wakeup
	spin_lock_irqsave(&usbmisc->lock, flags);
	val = readl(usbmisc->base + data->index * 4);
	if (enabled) {
		val |= wakeup_setting;
		val &= ~MX6_USB_OTG_WAKEUP_BITS;
		val |= usbmisc_wakeup_setting(data);
	} else {
		if (val & MX6_BM_WAKEUP_INTR)
			pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
		val &= ~wakeup_setting;
		val &= ~MX6_USB_OTG_WAKEUP_BITS;
	}
	writel(val, usbmisc->base + data->index * 4);
	spin_unlock_irqrestore(&usbmisc->lock, flags);
@@ -547,17 +562,17 @@ static int usbmisc_imx7d_set_wakeup
	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
	unsigned long flags;
	u32 val;
	u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
		MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);

	spin_lock_irqsave(&usbmisc->lock, flags);
	val = readl(usbmisc->base);
	if (enabled) {
		writel(val | wakeup_setting, usbmisc->base);
		val &= ~MX6_USB_OTG_WAKEUP_BITS;
		val |= usbmisc_wakeup_setting(data);
		writel(val, usbmisc->base);
	} else {
		if (val & MX6_BM_WAKEUP_INTR)
			dev_dbg(data->dev, "wakeup int\n");
		writel(val & ~wakeup_setting, usbmisc->base);
		writel(val & ~MX6_USB_OTG_WAKEUP_BITS, usbmisc->base);
	}
	spin_unlock_irqrestore(&usbmisc->lock, flags);