On 03/17/2016 03:27 PM, Chanwoo Choi wrote: > Hi Lu, > > On 2016년 03월 17일 16:16, Lu Baolu wrote: >> Hi Chanwoo, >> >> On 03/17/2016 02:07 PM, Chanwoo Choi wrote: >>> Hi Lu, >>> >>> To handle extcon (external connector), I implemented the unique id >>> for each external connector on patch[1] instead of using the ambiguous string type. >>> [1] 2a9de9c0f08d6 (extcon: Use the unique id for external connector instead of string) >>> >>> So I recommend that you should use the unique id (ex. EXTCON_USB, EXTCON_USB_HOST) >>> with extcon_register_notifier(), extcon_get_cable_state_() and extcon_set_cable_state_(). >>> >>> extcon_register_interest() is deprecated-> extcon_register_notifier() >>> extcon_get_cable_state() is deprecated -> extcon_get_cable_state_() >>> extcon_set_cable_state() is deprecated -> extcon_set_cable_state_() >> Sure. I will use the new interfaces with a refreshed patch serial later. >> >>> >>> You can refer to usage for new function with unique id on patch[2] >>> [2] 5960387a2fb83 (usb: dwc3: omap: Replace deprecated API of extcon) >> Thanks. That's helpful. >> >> By the way, is extcon_get_extcon_dev() still available? > Yes. > This function find the extcon device with string name. > > If extcon client driver use the platform_data to get the name of extcon device, > the extcon client driver should use the extcon_get_extcon_dev() funtcion. > Because we can not pass the point(instance) of extcon device through platform_data. > > But, if extcon client driver support the devicetree, > we better to use the extcon_get_edev_by_phandle(). That's clear. Thank you! Best regards, Baolu > > Best Regards, > Chanwoo Choi > >>> I'm sorry for late reply. I add the some comment on below. >> Never mind. Thank you for reminding me. >> >> Best regards, >> Baolu >> >>> >>> On 2016년 03월 17일 14:46, Lu Baolu wrote: >>>> Several Intel PCHs and SOCs have an internal mux that is used to >>>> share one USB port between device controller and host controller. >>>> >>>> A usb port mux could be abstracted as the following elements: >>>> 1) mux state: HOST or PERIPHERAL; >>>> 2) an extcon cable which triggers the change of mux state between >>>> HOST and PERIPHERAL; >>>> 3) The required action to do the real port switch. >>>> >>>> This patch adds the common code to handle usb port mux. With this >>>> common code, the individual mux driver, which always is platform >>>> dependent, could focus on the real operation of mux switch. >>>> >>>> Signed-off-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> >>>> Reviewed-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> >>>> Reviewed-by: Felipe Balbi <balbi@xxxxxxxxxx> >>>> --- >>>> Documentation/ABI/testing/sysfs-bus-platform | 15 +++ >>>> MAINTAINERS | 7 ++ >>>> drivers/usb/Kconfig | 2 + >>>> drivers/usb/Makefile | 1 + >>>> drivers/usb/mux/Kconfig | 12 ++ >>>> drivers/usb/mux/Makefile | 4 + >>>> drivers/usb/mux/intel-mux.c | 180 +++++++++++++++++++++++++++ >>>> include/linux/usb/intel-mux.h | 43 +++++++ >>>> 8 files changed, 264 insertions(+) >>>> create mode 100644 drivers/usb/mux/Kconfig >>>> create mode 100644 drivers/usb/mux/Makefile >>>> create mode 100644 drivers/usb/mux/intel-mux.c >>>> create mode 100644 include/linux/usb/intel-mux.h >>>> >>>> diff --git a/Documentation/ABI/testing/sysfs-bus-platform b/Documentation/ABI/testing/sysfs-bus-platform >>>> index 5172a61..23bf76e 100644 >>>> --- a/Documentation/ABI/testing/sysfs-bus-platform >>>> +++ b/Documentation/ABI/testing/sysfs-bus-platform >>>> @@ -18,3 +18,18 @@ Description: >>>> devices to opt-out of driver binding using a driver_override >>>> name such as "none". Only a single driver may be specified in >>>> the override, there is no support for parsing delimiters. >>>> + >>>> +What: /sys/bus/platform/devices/.../port_mux >>>> +Date: Febuary 2016 >>>> +Contact: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> >>>> +Description: >>>> + In some platforms, a single USB port is shared between a USB host >>>> + controller and a device controller. A USB mux driver is needed to >>>> + handle the port mux. port_mux attribute shows and stores the mux >>>> + state. >>>> + For read: >>>> + 'peripheral' - mux switched to PERIPHERAL controller; >>>> + 'host' - mux switched to HOST controller. >>>> + For write: >>>> + 'peripheral' - mux will be switched to PERIPHERAL controller; >>>> + 'host' - mux will be switched to HOST controller. >>>> diff --git a/MAINTAINERS b/MAINTAINERS >>>> index da3e4d8..0dbee11 100644 >>>> --- a/MAINTAINERS >>>> +++ b/MAINTAINERS >>>> @@ -11399,6 +11399,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git >>>> S: Maintained >>>> F: drivers/usb/phy/ >>>> >>>> +USB PORT MUX DRIVER >>>> +M: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> >>>> +L: linux-usb@xxxxxxxxxxxxxxx >>>> +S: Supported >>>> +F: include/linux/usb/intel-mux.h >>>> +F: drivers/usb/mux/intel-mux.c >>>> + >>>> USB PRINTER DRIVER (usblp) >>>> M: Pete Zaitcev <zaitcev@xxxxxxxxxx> >>>> L: linux-usb@xxxxxxxxxxxxxxx >>>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig >>>> index 8ed451d..dbd6620 100644 >>>> --- a/drivers/usb/Kconfig >>>> +++ b/drivers/usb/Kconfig >>>> @@ -149,6 +149,8 @@ endif # USB >>>> >>>> source "drivers/usb/phy/Kconfig" >>>> >>>> +source "drivers/usb/mux/Kconfig" >>>> + >>>> source "drivers/usb/gadget/Kconfig" >>>> >>>> config USB_LED_TRIG >>>> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile >>>> index d5c57f1..6433f0c 100644 >>>> --- a/drivers/usb/Makefile >>>> +++ b/drivers/usb/Makefile >>>> @@ -6,6 +6,7 @@ >>>> >>>> obj-$(CONFIG_USB) += core/ >>>> obj-$(CONFIG_USB_SUPPORT) += phy/ >>>> +obj-$(CONFIG_USB_SUPPORT) += mux/ >>>> >>>> obj-$(CONFIG_USB_DWC3) += dwc3/ >>>> obj-$(CONFIG_USB_DWC2) += dwc2/ >>>> diff --git a/drivers/usb/mux/Kconfig b/drivers/usb/mux/Kconfig >>>> new file mode 100644 >>>> index 0000000..62e2cc3 >>>> --- /dev/null >>>> +++ b/drivers/usb/mux/Kconfig >>>> @@ -0,0 +1,12 @@ >>>> +# >>>> +# USB port mux driver configuration >>>> +# >>>> +menu "USB Port MUX drivers" >>>> +config INTEL_USB_MUX >>>> + select EXTCON >>>> + def_bool n >>>> + help >>>> + Common code for all Intel dual role port mux drivers. All Intel >>>> + usb port mux drivers should select it. >>>> + >>>> +endmenu >>>> diff --git a/drivers/usb/mux/Makefile b/drivers/usb/mux/Makefile >>>> new file mode 100644 >>>> index 0000000..84f0ae8 >>>> --- /dev/null >>>> +++ b/drivers/usb/mux/Makefile >>>> @@ -0,0 +1,4 @@ >>>> +# >>>> +# Makefile for USB port mux drivers >>>> +# >>>> +obj-$(CONFIG_INTEL_USB_MUX) += intel-mux.o >>>> diff --git a/drivers/usb/mux/intel-mux.c b/drivers/usb/mux/intel-mux.c >>>> new file mode 100644 >>>> index 0000000..bb7b192 >>>> --- /dev/null >>>> +++ b/drivers/usb/mux/intel-mux.c >>>> @@ -0,0 +1,180 @@ >>>> +/** >>>> + * intel_mux.c - USB Port Mux support >>>> + * >>>> + * Copyright (C) 2016 Intel Corporation >>>> + * >>>> + * Author: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> >>>> + * >>>> + * This program is free software; you can redistribute it and/or modify >>>> + * it under the terms of the GNU General Public License version 2 as >>>> + * published by the Free Software Foundation. >>>> + */ >>>> +#include <linux/slab.h> >>>> +#include <linux/notifier.h> >>>> +#include <linux/extcon.h> >>>> +#include <linux/err.h> >>>> + >>>> +struct intel_usb_mux { >>>> + struct device *dev; >>>> + char *cable_name; >>>> + int (*cable_set_cb)(struct device *dev); >>>> + int (*cable_unset_cb)(struct device *dev); >>>> + >>>> + struct notifier_block nb; >>>> + struct extcon_specific_cable_nb obj; >>>> + >>>> + /* >>>> + * The state of the mux. >>>> + * 0, 1 - mux switch state >>>> + * -1 - uninitialized state >>>> + */ >>>> + int mux_state; >>>> + >>>> + /* lock for mux_state */ >>>> + struct mutex mux_mutex; >>>> +}; >>>> + >>>> +static int usb_mux_change_state(struct intel_usb_mux *mux, int state) >>>> +{ >>>> + int ret; >>>> + struct device *dev = mux->dev; >>>> + >>>> + dev_WARN_ONCE(dev, >>>> + !mutex_is_locked(&mux->mux_mutex), >>>> + "mutex is unlocked\n"); >>>> + >>>> + mux->mux_state = state; >>>> + >>>> + if (mux->mux_state) >>>> + ret = mux->cable_set_cb(dev); >>>> + else >>>> + ret = mux->cable_unset_cb(dev); >>>> + >>>> + return ret; >>>> +} >>>> + >>>> +static int usb_mux_notifier(struct notifier_block *nb, >>>> + unsigned long event, void *ptr) >>>> +{ >>>> + struct intel_usb_mux *mux; >>>> + int state; >>>> + int ret = NOTIFY_DONE; >>>> + >>>> + mux = container_of(nb, struct intel_usb_mux, nb); >>>> + >>>> + state = extcon_get_cable_state(mux->obj.edev, >>>> + mux->cable_name); >>> Use the extcon_get_cable_stet_(). >>> >>>> + >>>> + if (mux->mux_state == -1 || mux->mux_state != state) { >>>> + mutex_lock(&mux->mux_mutex); >>>> + ret = usb_mux_change_state(mux, state); >>>> + mutex_unlock(&mux->mux_mutex); >>>> + } >>>> + >>>> + return ret; >>>> +} >>>> + >>>> +static ssize_t port_mux_show(struct device *dev, >>>> + struct device_attribute *attr, char *buf) >>>> +{ >>>> + struct intel_usb_mux *mux = dev_get_drvdata(dev); >>>> + >>>> + if (dev_WARN_ONCE(dev, !mux, "mux without data structure\n")) >>>> + return 0; >>>> + >>>> + return sprintf(buf, "%s\n", mux->mux_state ? "host" : "peripheral"); >>>> +} >>>> + >>>> +static ssize_t port_mux_store(struct device *dev, >>>> + struct device_attribute *attr, >>>> + const char *buf, size_t count) >>>> +{ >>>> + struct intel_usb_mux *mux = dev_get_drvdata(dev); >>>> + int state; >>>> + >>>> + if (dev_WARN_ONCE(dev, !mux, "mux without data structure\n")) >>>> + return -EINVAL; >>>> + >>>> + if (sysfs_streq(buf, "peripheral")) >>>> + state = 0; >>>> + else if (sysfs_streq(buf, "host")) >>>> + state = 1; >>>> + else >>>> + return -EINVAL; >>>> + >>>> + mutex_lock(&mux->mux_mutex); >>>> + usb_mux_change_state(mux, state); >>>> + mutex_unlock(&mux->mux_mutex); >>>> + >>>> + return count; >>>> +} >>>> +static DEVICE_ATTR_RW(port_mux); >>>> + >>>> +int intel_usb_mux_bind_cable(struct device *dev, >>>> + char *extcon_name, >>>> + char *cable_name, >>>> + int (*cable_set_cb)(struct device *dev), >>>> + int (*cable_unset_cb)(struct device *dev)) >>>> +{ >>>> + int ret; >>>> + struct intel_usb_mux *mux; >>>> + >>>> + if (!cable_name) >>>> + return -ENODEV; >>>> + >>>> + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); >>>> + if (!mux) >>>> + return -ENOMEM; >>>> + >>>> + mux->dev = dev; >>>> + mux->cable_name = kstrdup(cable_name, GFP_KERNEL); >>>> + mux->cable_set_cb = cable_set_cb; >>>> + mux->cable_unset_cb = cable_unset_cb; >>>> + mux->nb.notifier_call = usb_mux_notifier; >>>> + mutex_init(&mux->mux_mutex); >>>> + mux->mux_state = -1; >>>> + dev_set_drvdata(dev, mux); >>>> + ret = extcon_register_interest(&mux->obj, extcon_name, >>>> + cable_name, &mux->nb); >>> Use the extcon_register_notifier() >>> >>>> + if (ret) { >>>> + kfree(mux->cable_name); >>>> + dev_err(dev, "failed to register extcon notifier\n"); >>>> + return -ENODEV; >>>> + } >>>> + >>>> + usb_mux_notifier(&mux->nb, 0, NULL); >>>> + >>>> + /* register the sysfs interface */ >>>> + ret = device_create_file(dev, &dev_attr_port_mux); >>>> + if (ret) { >>>> + extcon_unregister_interest(&mux->obj); >>> Use the extcon_unregister_notifier() >>> >>>> + kfree(mux->cable_name); >>>> + dev_err(dev, "failed to create sysfs attribute\n"); >>>> + return -ENODEV; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> +EXPORT_SYMBOL_GPL(intel_usb_mux_bind_cable); >>>> + >>>> +int intel_usb_mux_unbind_cable(struct device *dev) >>>> +{ >>>> + struct intel_usb_mux *mux = dev_get_drvdata(dev); >>>> + >>>> + device_remove_file(dev, &dev_attr_port_mux); >>>> + extcon_unregister_interest(&mux->obj); >>> Use the extcon_unregister_notifier() >>> >>>> + kfree(mux->cable_name); >>>> + >>>> + return 0; >>>> +} >>>> +EXPORT_SYMBOL_GPL(intel_usb_mux_unbind_cable); >>>> + >>>> +#ifdef CONFIG_PM_SLEEP >>>> +void intel_usb_mux_complete(struct device *dev) >>>> +{ >>>> + struct intel_usb_mux *mux = dev_get_drvdata(dev); >>>> + >>>> + usb_mux_notifier(&mux->nb, 0, NULL); >>>> +} >>>> +EXPORT_SYMBOL_GPL(intel_usb_mux_complete); >>>> +#endif >>>> diff --git a/include/linux/usb/intel-mux.h b/include/linux/usb/intel-mux.h >>>> new file mode 100644 >>>> index 0000000..fd5612d >>>> --- /dev/null >>>> +++ b/include/linux/usb/intel-mux.h >>>> @@ -0,0 +1,43 @@ >>>> +/** >>>> + * intel_mux.h - USB Port Mux definitions >>>> + * >>>> + * Copyright (C) 2016 Intel Corporation >>>> + * >>>> + * Author: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> >>>> + * >>>> + * This program is free software; you can redistribute it and/or modify >>>> + * it under the terms of the GNU General Public License version 2 as >>>> + * published by the Free Software Foundation. >>>> + */ >>>> + >>>> +#ifndef __LINUX_USB_INTEL_MUX_H >>>> +#define __LINUX_USB_INTEL_MUX_H >>>> + >>>> +#if IS_ENABLED(CONFIG_INTEL_USB_MUX) >>>> +int intel_usb_mux_bind_cable(struct device *dev, char *extcon_name, >>>> + char *cable_name, >>>> + int (*cable_set_cb)(struct device *dev), >>>> + int (*cable_unset_cb)(struct device *dev)); >>>> +int intel_usb_mux_unbind_cable(struct device *dev); >>>> +#ifdef CONFIG_PM_SLEEP >>>> +void intel_usb_mux_complete(struct device *dev); >>>> +#endif >>>> + >>>> +#else >>>> +static inline int >>>> +intel_usb_mux_bind_cable(struct device *dev, >>>> + char *extcon_name, >>>> + char *cable_name, >>>> + int (*cable_set_cb)(struct device *dev), >>>> + int (*cable_unset_cb)(struct device *dev)) >>>> +{ >>>> + return -ENODEV; >>>> +} >>>> + >>>> +static inline int intel_usb_mux_unbind_cable(struct device *dev) >>>> +{ >>>> + return 0; >>>> +} >>>> +#endif /* CONFIG_INTEL_USB_MUX */ >>>> + >>>> +#endif /* __LINUX_USB_INTEL_MUX_H */ >>>> >>> Best Regards, >>> Chanwoo Choi >>> >> >> > -- 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