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().

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...@linux.intel.com>
>>> Reviewed-by: Heikki Krogerus <heikki.kroge...@linux.intel.com>
>>> Reviewed-by: Felipe Balbi <ba...@kernel.org>
>>> ---
>>>  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...@linux.intel.com>
>>> +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...@linux.intel.com>
>>> +L: linux-usb@vger.kernel.org
>>> +S: Supported
>>> +F: include/linux/usb/intel-mux.h
>>> +F: drivers/usb/mux/intel-mux.c
>>> +
>>>  USB PRINTER DRIVER (usblp)
>>>  M: Pete Zaitcev <zait...@redhat.com>
>>>  L: linux-usb@vger.kernel.org
>>> 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...@linux.intel.com>
>>> + *
>>> + * 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...@linux.intel.com>
>>> + *
>>> + * 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to