>
> Changes for v3:
> - Remove the patch usb: chipidea: replace ci_role with usb_role
> as the existing ci->role usage can't map to usb_role.
> - Use the suggested ci_hdrc_cable for reuse current role change
> handling.
> - Fix build robot warning by add usb_role head file.
>
You may need to add "select USB_ROLE_SWITCH" at chipidea Kconfig to fix
build error.
> +static int ci_usb_role_switch_set(struct device *dev, enum usb_role
> +role) {
> + struct ci_hdrc *ci = dev_get_drvdata(dev);
> + struct ci_hdrc_cable *cable = NULL;
> + enum usb_role current_role = ci_role_to_usb_role(ci);
> +
> + if (current_role == role)
> + return 0;
> +
> + /* Stop current role */
> + if (current_role == USB_ROLE_DEVICE)
> + cable = &ci->platdata->vbus_extcon;
> + else if (current_role == USB_ROLE_HOST)
> + cable = &ci->platdata->id_extcon;
> +
> + if (cable) {
> + cable->changed = true;
> + cable->connected = false;
> + ci_irq(ci->irq, ci);
> + }
> +
> + cable = NULL;
> +
> + /* Start target role */
> + if (role == USB_ROLE_DEVICE)
> + cable = &ci->platdata->vbus_extcon;
> + else if (role == USB_ROLE_HOST)
> + cable = &ci->platdata->id_extcon;
> +
> + if (cable) {
> + if (ci->wq)
> + flush_workqueue(ci->wq);
> + cable->changed = true;
> + cable->connected = true;
> + ci_irq(ci->irq, ci);
> + }
> +
> + return 0;
> +}
> +
You may add spin_lock_irqsave in .set API either and pay attention to
flush_workqueue.
And you may improve low power management support for it later, other things are
ok for me.
I have tested it at imx8qm mek by adding .allow_userspace_control = true.
Peter
> +static struct usb_role_switch_desc ci_role_switch = {
> + .set = ci_usb_role_switch_set,
> + .get = ci_usb_role_switch_get,
> +};
> +
> static int ci_get_platdata(struct device *dev,
> struct ci_hdrc_platform_data *platdata) { @@ -726,6 +784,9 @@
> static int ci_get_platdata(struct device *dev,
> cable->connected = false;
> }
>
> + if (device_property_read_bool(dev, "usb-role-switch"))
> + ci_role_switch.fwnode = dev->fwnode;
> +
> platdata->pctl = devm_pinctrl_get(dev);
> if (!IS_ERR(platdata->pctl)) {
> struct pinctrl_state *p;
> @@ -1051,6 +1112,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
> }
> }
>
> + if (ci_role_switch.fwnode) {
> + ci->role_switch = usb_role_switch_register(dev,
> + &ci_role_switch);
> + if (IS_ERR(ci->role_switch)) {
> + ret = PTR_ERR(ci->role_switch);
> + goto deinit_otg;
> + }
> + }
> +
> if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
> if (ci->is_otg) {
> ci->role = ci_otg_role(ci);
> @@ -1115,6 +1185,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
> remove_debug:
> dbg_remove_files(ci);
> stop:
> + if (ci->role_switch)
> + usb_role_switch_unregister(ci->role_switch);
> +deinit_otg:
> if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
> ci_hdrc_otg_destroy(ci);
> deinit_gadget:
> @@ -1133,6 +1206,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
> {
> struct ci_hdrc *ci = platform_get_drvdata(pdev);
>
> + if (ci->role_switch)
> + usb_role_switch_unregister(ci->role_switch);
> +
> if (ci->supports_runtime_pm) {
> pm_runtime_get_sync(&pdev->dev);
> pm_runtime_disable(&pdev->dev);
> diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index
> f25d482..fbfb02e 100644
> --- a/drivers/usb/chipidea/otg.c
> +++ b/drivers/usb/chipidea/otg.c
> @@ -35,7 +35,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
> * detection overwrite OTGSC register value
> */
> cable = &ci->platdata->vbus_extcon;
> - if (!IS_ERR(cable->edev)) {
> + if (!IS_ERR(cable->edev) || ci->role_switch) {
> if (cable->changed)
> val |= OTGSC_BSVIS;
> else
> @@ -53,7 +53,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
> }
>
> cable = &ci->platdata->id_extcon;
> - if (!IS_ERR(cable->edev)) {
> + if (!IS_ERR(cable->edev) || ci->role_switch) {
> if (cable->changed)
> val |= OTGSC_IDIS;
> else
> @@ -83,7 +83,7 @@ void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
> struct ci_hdrc_cable *cable;
>
> cable = &ci->platdata->vbus_extcon;
> - if (!IS_ERR(cable->edev)) {
> + if (!IS_ERR(cable->edev) || ci->role_switch) {
> if (data & mask & OTGSC_BSVIS)
> cable->changed = false;
>
> @@ -97,7 +97,7 @@ void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
> }
>
> cable = &ci->platdata->id_extcon;
> - if (!IS_ERR(cable->edev)) {
> + if (!IS_ERR(cable->edev) || ci->role_switch) {
> if (data & mask & OTGSC_IDIS)
> cable->changed = false;
>
> --
> 2.7.4