On Fri, Feb 16, 2018 at 12:47 PM, Hans de Goede <hdegoede@xxxxxxxxxx> wrote: > Various Intel SoCs (Cherry Trail, Broxton and others) have an internal USB > role switch for swiching the OTG USB data lines between the xHCI host > controller and the dwc3 gadget controller. > > Note on some Cherry Trail systems there is ACPI/AML code listening to > edge interrupts on the id-pin (through an _AIE ACPI method) and switching > the role between ROLE_HOST and ROLE_NONE based on the id-pin. Note it does > not set the role to ROLE_DEVICE, because device-mode is usually not used > under Windows. > > The presence of AML code which modifies the cfg0 reg (on some systems) > means that we our read/write/modify of cfg0 may race with the AML code > doing the same to avoid this we take the global ACPI lock while doing > the read/write/modify. > +/* register definition */ > +#define DUAL_ROLE_CFG0 0x68 > +#define SW_VBUS_VALID (1 << 24) > +#define SW_IDPIN_EN (1 << 21) > +#define SW_IDPIN (1 << 20) > + > +#define DUAL_ROLE_CFG1 0x6c > +#define HOST_MODE (1 << 29) Does it make sense to use BIT() macro above? > +struct intel_xhci_acpi_match { > + const char *hid; > + int hrv; > +}; Consider to unify with struct acpi_ac_bl. > +static const struct intel_xhci_acpi_match allow_userspace_ctrl_ids[] = { > + { "INT33F4", 3 }, /* X-Powers AXP288 PMIC */ > +}; > + > +static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role) > +{ > + struct intel_xhci_usb_data *data = dev_get_drvdata(dev); > + unsigned long timeout; > + acpi_status status; > + u32 glk = -1U; I prefer to see consistency and moreover less confusing set, like ~0U > + u32 val; > + > + /* > + * On many CHT devices ACPI event (_AEI) handlers read / modify / > + * write the cfg0 register, just like we do. Take the ACPI lock > + * to avoid us racing with the AML code. > + */ > + status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk); FOREVER?! Wouldn't be slightly long under certain circumstances? > + if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) { > + dev_err(dev, "Error could not acquire lock\n"); > + return -EIO; > + } > + acpi_release_global_lock(glk); > + /* Polling on CFG1 register to confirm mode switch.*/ > + do { > + val = readl(data->base + DUAL_ROLE_CFG1); > + if (!!(val & HOST_MODE) == (role == USB_ROLE_HOST)) I would prefer ^ instead of first ==, but it's up to you. > + return 0; > + > + /* Interval for polling is set to about 5 - 10 ms */ > + usleep_range(5000, 10000); > + } while (time_before(jiffies, timeout)); > + > + dev_warn(dev, "Timeout waiting for role-switch\n"); > + return -ETIMEDOUT; > +} > +static int intel_xhci_usb_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct intel_xhci_usb_data *data; > + struct resource *res; > + resource_size_t size; > + int i, ret; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + size = (res->end + 1) - res->start; resource_size() > + data->base = devm_ioremap_nocache(dev, res->start, size); So, what's wrong with devm_ioremap_resource() ? ...which also prints an error message. > + if (IS_ERR(data->base)) { > + ret = PTR_ERR(data->base); > + dev_err(dev, "Error iomaping registers: %d\n", ret); At least printing return code is useless. Driver core does this. > + return ret; > + } > + > + data->role_sw = usb_role_switch_register(dev, &sw_desc); > + if (IS_ERR(data->role_sw)) { > + ret = PTR_ERR(data->role_sw); > + dev_err(dev, "Error registering role-switch: %d\n", ret); Ditto. > + return ret; > + } > + > + return 0; > +} > +static const struct platform_device_id intel_xhci_usb_table[] = { > + { .name = DRV_NAME }, > + {}, No comma, please. > +}; -- With Best Regards, Andy Shevchenko -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html