Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: chipidea: core: add sysfs group

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>

+72 -3
+9
Documentation/ABI/testing/sysfs-platform-chipidea-usb2
··· 1 + What: /sys/bus/platform/devices/ci_hdrc.0/role 2 + Date: Mar 2017 3 + Contact: Peter Chen <peter.chen@nxp.com> 4 + Description: 5 + It returns string "gadget" or "host" when read it, it indicates 6 + current controller role. 7 + 8 + It will do role switch when write "gadget" or "host" to it. 9 + Only controller at dual-role configuration supports writing.
+61 -3
drivers/usb/chipidea/core.c
··· 841 841 } 842 842 } 843 843 844 + static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr, 845 + char *buf) 846 + { 847 + struct ci_hdrc *ci = dev_get_drvdata(dev); 848 + 849 + return sprintf(buf, "%s\n", ci_role(ci)->name); 850 + } 851 + 852 + static ssize_t ci_role_store(struct device *dev, 853 + struct device_attribute *attr, const char *buf, size_t n) 854 + { 855 + struct ci_hdrc *ci = dev_get_drvdata(dev); 856 + enum ci_role role; 857 + int ret; 858 + 859 + if (!(ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET])) { 860 + dev_warn(dev, "Current configuration is not dual-role, quit\n"); 861 + return -EPERM; 862 + } 863 + 864 + for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) 865 + if (!strncmp(buf, ci->roles[role]->name, 866 + strlen(ci->roles[role]->name))) 867 + break; 868 + 869 + if (role == CI_ROLE_END || role == ci->role) 870 + return -EINVAL; 871 + 872 + pm_runtime_get_sync(dev); 873 + disable_irq(ci->irq); 874 + ci_role_stop(ci); 875 + ret = ci_role_start(ci, role); 876 + if (!ret && ci->role == CI_ROLE_GADGET) 877 + ci_handle_vbus_change(ci); 878 + enable_irq(ci->irq); 879 + pm_runtime_put_sync(dev); 880 + 881 + return (ret == 0) ? n : ret; 882 + } 883 + static DEVICE_ATTR(role, 0644, ci_role_show, ci_role_store); 884 + 885 + static struct attribute *ci_attrs[] = { 886 + &dev_attr_role.attr, 887 + NULL, 888 + }; 889 + 890 + static struct attribute_group ci_attr_group = { 891 + .attrs = ci_attrs, 892 + }; 893 + 844 894 static int ci_hdrc_probe(struct platform_device *pdev) 845 895 { 846 896 struct device *dev = &pdev->dev; ··· 1057 1007 ci_hdrc_otg_fsm_start(ci); 1058 1008 1059 1009 device_set_wakeup_capable(&pdev->dev, true); 1060 - 1061 1010 ret = dbg_create_files(ci); 1062 - if (!ret) 1063 - return 0; 1011 + if (ret) 1012 + goto stop; 1064 1013 1014 + ret = sysfs_create_group(&dev->kobj, &ci_attr_group); 1015 + if (ret) 1016 + goto remove_debug; 1017 + 1018 + return 0; 1019 + 1020 + remove_debug: 1021 + dbg_remove_files(ci); 1065 1022 stop: 1066 1023 ci_role_destroy(ci); 1067 1024 deinit_phy: ··· 1090 1033 } 1091 1034 1092 1035 dbg_remove_files(ci); 1036 + sysfs_remove_group(&ci->dev->kobj, &ci_attr_group); 1093 1037 ci_role_destroy(ci); 1094 1038 ci_hdrc_enter_lpm(ci, true); 1095 1039 ci_usb_phy_exit(ci);
+2
drivers/usb/chipidea/udc.c
··· 1978 1978 */ 1979 1979 if (ci->is_otg) 1980 1980 hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); 1981 + 1982 + ci->vbus_active = 0; 1981 1983 } 1982 1984 1983 1985 /**