Skip to content

Commit

Permalink
usb: chipidea: core: add sysfs group
Browse files Browse the repository at this point in the history
Sometimes, the user needs to adjust some properties for controllers, eg
the role for controller, we add sysfs group for them.

The attribute 'role' is used to switch host/gadget role dynamically, the
uewr can read the current role, and write the other role compare to
current one to finish the switch.

Signed-off-by: Peter Chen <peter.chen@nxp.com>
  • Loading branch information
Peter Chen committed Apr 14, 2017
1 parent 4f4555c commit a932a80
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 3 deletions.
9 changes: 9 additions & 0 deletions Documentation/ABI/testing/sysfs-platform-chipidea-usb2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
What: /sys/bus/platform/devices/ci_hdrc.0/role
Date: Mar 2017
Contact: Peter Chen <peter.chen@nxp.com>
Description:
It returns string "gadget" or "host" when read it, it indicates
current controller role.

It will do role switch when write "gadget" or "host" to it.
Only controller at dual-role configuration supports writing.
64 changes: 61 additions & 3 deletions drivers/usb/chipidea/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,56 @@ static void ci_get_otg_capable(struct ci_hdrc *ci)
}
}

static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);

return sprintf(buf, "%s\n", ci_role(ci)->name);
}

static ssize_t ci_role_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
enum ci_role role;
int ret;

if (!(ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET])) {
dev_warn(dev, "Current configuration is not dual-role, quit\n");
return -EPERM;
}

for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
if (!strncmp(buf, ci->roles[role]->name,
strlen(ci->roles[role]->name)))
break;

if (role == CI_ROLE_END || role == ci->role)
return -EINVAL;

pm_runtime_get_sync(dev);
disable_irq(ci->irq);
ci_role_stop(ci);
ret = ci_role_start(ci, role);
if (!ret && ci->role == CI_ROLE_GADGET)
ci_handle_vbus_change(ci);
enable_irq(ci->irq);
pm_runtime_put_sync(dev);

return (ret == 0) ? n : ret;
}
static DEVICE_ATTR(role, 0644, ci_role_show, ci_role_store);

static struct attribute *ci_attrs[] = {
&dev_attr_role.attr,
NULL,
};

static struct attribute_group ci_attr_group = {
.attrs = ci_attrs,
};

static int ci_hdrc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
Expand Down Expand Up @@ -1007,11 +1057,18 @@ static int ci_hdrc_probe(struct platform_device *pdev)
ci_hdrc_otg_fsm_start(ci);

device_set_wakeup_capable(&pdev->dev, true);

ret = dbg_create_files(ci);
if (!ret)
return 0;
if (ret)
goto stop;

ret = sysfs_create_group(&dev->kobj, &ci_attr_group);
if (ret)
goto remove_debug;

return 0;

remove_debug:
dbg_remove_files(ci);
stop:
ci_role_destroy(ci);
deinit_phy:
Expand All @@ -1033,6 +1090,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
}

dbg_remove_files(ci);
sysfs_remove_group(&ci->dev->kobj, &ci_attr_group);
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
ci_usb_phy_exit(ci);
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/chipidea/udc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1978,6 +1978,8 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
*/
if (ci->is_otg)
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);

ci->vbus_active = 0;
}

/**
Expand Down

0 comments on commit a932a80

Please sign in to comment.