bool pm_suspended;
struct icc_path *icc_path_ddr;
struct icc_path *icc_path_apps;
+
+ enum usb_role current_role;
};
#define to_dwc3_qcom(d) container_of((d), struct dwc3_qcom, dwc)
readl(base + offset);
}
-/*
- * TODO: Make the in-core role switching code invoke dwc3_qcom_vbus_override_enable(),
- * validate that the in-core extcon support is functional
- */
static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable)
{
if (enable) {
return 0;
}
+static void dwc3_qcom_set_role_notifier(struct dwc3 *dwc, enum usb_role next_role)
+{
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
+
+ if (qcom->current_role == next_role)
+ return;
+
+ if (pm_runtime_resume_and_get(qcom->dev)) {
+ dev_dbg(qcom->dev, "Failed to resume device\n");
+ return;
+ }
+
+ if (qcom->current_role == USB_ROLE_DEVICE)
+ dwc3_qcom_vbus_override_enable(qcom, false);
+ else if (qcom->current_role != USB_ROLE_DEVICE)
+ dwc3_qcom_vbus_override_enable(qcom, true);
+
+ pm_runtime_mark_last_busy(qcom->dev);
+ pm_runtime_put_sync(qcom->dev);
+
+ /*
+ * Current role changes via usb_role_switch_set_role callback protected
+ * internally by mutex lock.
+ */
+ qcom->current_role = next_role;
+}
+
+static void dwc3_qcom_run_stop_notifier(struct dwc3 *dwc, bool is_on)
+{
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
+
+ /*
+ * When autosuspend is enabled and controller goes to suspend
+ * after removing UDC from userspace, the next UDC write needs
+ * setting of QSCRATCH VBUS_VALID to "1" to generate a connect
+ * done event.
+ */
+ if (!is_on)
+ return;
+
+ dwc3_qcom_vbus_override_enable(qcom, true);
+ pm_runtime_mark_last_busy(qcom->dev);
+}
+
+struct dwc3_glue_ops dwc3_qcom_glue_ops = {
+ .pre_set_role = dwc3_qcom_set_role_notifier,
+ .pre_run_stop = dwc3_qcom_run_stop_notifier,
+};
+
static int dwc3_qcom_probe(struct platform_device *pdev)
{
struct dwc3_probe_data probe_data = {};
if (ignore_pipe_clk)
dwc3_qcom_select_utmi_clk(qcom);
+ qcom->mode = usb_get_dr_mode(dev);
+
+ if (qcom->mode == USB_DR_MODE_HOST) {
+ qcom->current_role = USB_ROLE_HOST;
+ } else if (qcom->mode == USB_DR_MODE_PERIPHERAL) {
+ qcom->current_role = USB_ROLE_DEVICE;
+ dwc3_qcom_vbus_override_enable(qcom, true);
+ } else {
+ if ((device_property_read_bool(dev, "usb-role-switch")) &&
+ (usb_get_role_switch_default_mode(dev) == USB_DR_MODE_HOST))
+ qcom->current_role = USB_ROLE_HOST;
+ else
+ qcom->current_role = USB_ROLE_DEVICE;
+ }
+
+ qcom->dwc.glue_ops = &dwc3_qcom_glue_ops;
+
qcom->dwc.dev = dev;
probe_data.dwc = &qcom->dwc;
probe_data.res = &res;
if (ret)
goto remove_core;
- qcom->mode = usb_get_dr_mode(dev);
-
- /* enable vbus override for device mode */
- if (qcom->mode != USB_DR_MODE_HOST)
- dwc3_qcom_vbus_override_enable(qcom, true);
-
wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
device_init_wakeup(&pdev->dev, wakeup_source);