diff mbox

[v3,1/7] extcon: usb-gpio: Introduce gpio usb extcon driver

Message ID 54C8D2F4.9050404@ti.com
State Superseded, archived
Headers show

Commit Message

Roger Quadros Jan. 28, 2015, 12:15 p.m. UTC
This driver observes the USB ID pin connected over a GPIO and
updates the USB cable extcon states accordingly.

The existing GPIO extcon driver is not suitable for this purpose
as it needs to be taught to understand USB cable states and it
can't handle more than one cable per instance.

For the USB case we need to handle 2 cable states.
1) USB (attach/detach)
2) USB-Host (attach/detach)

This driver can be easily updated in the future to handle VBUS
events in case it happens to be available on GPIO for any platform.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
v3:
- removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
  IRQF_TRIGGER_FALLING
- Added disable_irq() to suspend() and enable_irq() to resume()

 .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
 drivers/extcon/Kconfig                             |   7 +
 drivers/extcon/Makefile                            |   1 +
 drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
 4 files changed, 259 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
 create mode 100644 drivers/extcon/extcon-usb-gpio.c

Comments

Chanwoo Choi Jan. 29, 2015, 1:49 a.m. UTC | #1
Hi Roger,

We need to discuss one point about 'id_irqwake'.
I don't recommend to use 'id_irqwake' field.

And I catch build warning by using "select" keywork in Kconfig.
It is my wrong guide of "select" keyword. So, I'll change it 
as 'depends on' keyword.

Looks good to me except for 'id_irqwake'. 
I'll apply this patch on 3.21 queue after completing this discussion.

On 01/28/2015 09:15 PM, Roger Quadros wrote:
> This driver observes the USB ID pin connected over a GPIO and
> updates the USB cable extcon states accordingly.
> 
> The existing GPIO extcon driver is not suitable for this purpose
> as it needs to be taught to understand USB cable states and it
> can't handle more than one cable per instance.
> 
> For the USB case we need to handle 2 cable states.
> 1) USB (attach/detach)
> 2) USB-Host (attach/detach)
> 
> This driver can be easily updated in the future to handle VBUS
> events in case it happens to be available on GPIO for any platform.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
> v3:
> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>   IRQF_TRIGGER_FALLING
> - Added disable_irq() to suspend() and enable_irq() to resume()
> 
>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>  drivers/extcon/Kconfig                             |   7 +
>  drivers/extcon/Makefile                            |   1 +
>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>  4 files changed, 259 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
> 
> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
> new file mode 100644
> index 0000000..85fe6b0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
> @@ -0,0 +1,18 @@
> +USB GPIO Extcon device
> +
> +This is a virtual device used to generate USB cable states from the USB ID pin
> +connected to a GPIO pin.
> +
> +Required properties:
> +- compatible: Should be "linux,extcon-usb-gpio"
> +- id-gpio: gpio for USB ID pin. See gpio binding.
> +
> +Example:
> +	extcon_usb1 {
> +		compatible = "linux,extcon-usb-gpio";
> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
> +	}
> +
> +	&omap_dwc3_1 {
> +		extcon = <&extcon_usb1>;
> +	};
> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
> index 6a1f7de..fd11536 100644
> --- a/drivers/extcon/Kconfig
> +++ b/drivers/extcon/Kconfig
> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>  	  detector and switch.
>  
> +config EXTCON_USB_GPIO
> +	tristate "USB GPIO extcon support"
> +	select GPIOLIB

I catch the build warning if using 'select' instead of 'depends on' as following:
It is my wrong guide to you. So, I'll modify it by using "depends on" as your original patch.

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage  -j 8
scripts/kconfig/conf --silentoldconfig Kconfig
drivers/gpio/Kconfig:34:error: recursive dependency detected!
drivers/gpio/Kconfig:34:	symbol GPIOLIB is selected by EXTCON_USB_GPIO
drivers/extcon/Kconfig:96:	symbol EXTCON_USB_GPIO depends on EXTCON
drivers/extcon/Kconfig:1:	symbol EXTCON is selected by CHARGER_MANAGER
drivers/power/Kconfig:316:	symbol CHARGER_MANAGER depends on POWER_SUPPLY
drivers/power/Kconfig:1:	symbol POWER_SUPPLY is selected by HID_SONY
drivers/hid/Kconfig:670:	symbol HID_SONY depends on NEW_LEDS
drivers/leds/Kconfig:8:	symbol NEW_LEDS is selected by BCMA_DRIVER_GPIO
drivers/bcma/Kconfig:75:	symbol BCMA_DRIVER_GPIO depends on GPIOLIB

> +	help
> +	  Say Y here to enable GPIO based USB cable detection extcon support.
> +	  Used typically if GPIO is used for USB ID pin detection.
> +
>  endif # MULTISTATE_SWITCH
> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
> index 0370b42..6a08a98 100644
> --- a/drivers/extcon/Makefile
> +++ b/drivers/extcon/Makefile
> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
> new file mode 100644
> index 0000000..99a58b2
> --- /dev/null
> +++ b/drivers/extcon/extcon-usb-gpio.c
> @@ -0,0 +1,233 @@
> +/**
> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
> + *
> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
> + * Author: Roger Quadros <rogerq@ti.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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/extcon.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
> +
> +struct usb_extcon_info {
> +	struct device *dev;
> +	struct extcon_dev *edev;
> +
> +	struct gpio_desc *id_gpiod;
> +	int id_irq;
> +	bool id_irqwake;		/* ID wakeup enabled flag */

Do you really think id_irqwake is necessary?
I think it is not necessary.

> +
> +	unsigned long debounce_jiffies;
> +	struct delayed_work wq_detcable;
> +};
> +
> +/* List of detectable cables */
> +enum {
> +	EXTCON_CABLE_USB = 0,
> +	EXTCON_CABLE_USB_HOST,
> +
> +	EXTCON_CABLE_END,
> +};
> +
> +static const char *usb_extcon_cable[] = {
> +	[EXTCON_CABLE_USB] = "USB",
> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",
> +	NULL,
> +};
> +

[snip]

> +
> +static int usb_extcon_remove(struct platform_device *pdev)
> +{
> +	struct usb_extcon_info *info = platform_get_drvdata(pdev);
> +
> +	cancel_delayed_work_sync(&info->wq_detcable);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int usb_extcon_suspend(struct device *dev)
> +{
> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
> +
> +	if (device_may_wakeup(dev))
> +		if (!enable_irq_wake(info->id_irq))
> +			info->id_irqwake = true;
> +

You can simplify this code as following without 'id_irqwake':

	if (device_may_wakeup(dev))
		enable_irq_wake(info->id_irq);

> +	/*
> +	 * We don't want to process any IRQs after this point
> +	 * as GPIOs used behind I2C subsystem might not be
> +	 * accessible until resume completes. So disable IRQ.
> +	 */
> +	disable_irq(info->id_irq);
> +
> +	return 0;
> +}
> +
> +static int usb_extcon_resume(struct device *dev)
> +{
> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
> +
> +	if (info->id_irqwake) {
> +		disable_irq_wake(info->id_irq);
> +		info->id_irqwake = false;
> +	}

ditto.

	if (device_may_wakeup(dev))
		disable_irq_wake(info->id_irq);

> +
> +	enable_irq(info->id_irq);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(usb_extcon_pm_ops,
> +			 usb_extcon_suspend, usb_extcon_resume);
> +
> +static struct of_device_id usb_extcon_dt_match[] = {
> +	{ .compatible = "linux,extcon-usb-gpio", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
> +
> +static struct platform_driver usb_extcon_driver = {
> +	.probe		= usb_extcon_probe,
> +	.remove		= usb_extcon_remove,
> +	.driver		= {
> +		.name	= "extcon-usb-gpio",
> +		.pm	= &usb_extcon_pm_ops,
> +		.of_match_table = usb_extcon_dt_match,
> +	},
> +};
> +
> +module_platform_driver(usb_extcon_driver);
> +
> +MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
> +MODULE_DESCRIPTION("USB GPIO extcon driver");
> +MODULE_LICENSE("GPL v2");
> 

Thanks,
Chanwoo Choi

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Roger Quadros Jan. 29, 2015, 11:26 a.m. UTC | #2
Chanwoo,

On 29/01/15 03:49, Chanwoo Choi wrote:
> Hi Roger,
> 
> We need to discuss one point about 'id_irqwake'.
> I don't recommend to use 'id_irqwake' field.
> 
> And I catch build warning by using "select" keywork in Kconfig.
> It is my wrong guide of "select" keyword. So, I'll change it 
> as 'depends on' keyword.
> 
> Looks good to me except for 'id_irqwake'. 
> I'll apply this patch on 3.21 queue after completing this discussion.
> 
> On 01/28/2015 09:15 PM, Roger Quadros wrote:
>> This driver observes the USB ID pin connected over a GPIO and
>> updates the USB cable extcon states accordingly.
>>
>> The existing GPIO extcon driver is not suitable for this purpose
>> as it needs to be taught to understand USB cable states and it
>> can't handle more than one cable per instance.
>>
>> For the USB case we need to handle 2 cable states.
>> 1) USB (attach/detach)
>> 2) USB-Host (attach/detach)
>>
>> This driver can be easily updated in the future to handle VBUS
>> events in case it happens to be available on GPIO for any platform.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>> v3:
>> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>>   IRQF_TRIGGER_FALLING
>> - Added disable_irq() to suspend() and enable_irq() to resume()
>>
>>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>>  drivers/extcon/Kconfig                             |   7 +
>>  drivers/extcon/Makefile                            |   1 +
>>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>>  4 files changed, 259 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
>>
>> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>> new file mode 100644
>> index 0000000..85fe6b0
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>> @@ -0,0 +1,18 @@
>> +USB GPIO Extcon device
>> +
>> +This is a virtual device used to generate USB cable states from the USB ID pin
>> +connected to a GPIO pin.
>> +
>> +Required properties:
>> +- compatible: Should be "linux,extcon-usb-gpio"
>> +- id-gpio: gpio for USB ID pin. See gpio binding.
>> +
>> +Example:
>> +	extcon_usb1 {
>> +		compatible = "linux,extcon-usb-gpio";
>> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
>> +	}
>> +
>> +	&omap_dwc3_1 {
>> +		extcon = <&extcon_usb1>;
>> +	};
>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>> index 6a1f7de..fd11536 100644
>> --- a/drivers/extcon/Kconfig
>> +++ b/drivers/extcon/Kconfig
>> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>>  	  detector and switch.
>>  
>> +config EXTCON_USB_GPIO
>> +	tristate "USB GPIO extcon support"
>> +	select GPIOLIB
> 
> I catch the build warning if using 'select' instead of 'depends on' as following:
> It is my wrong guide to you. So, I'll modify it by using "depends on" as your original patch.

OK. Thanks.

> 
> make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage  -j 8
> scripts/kconfig/conf --silentoldconfig Kconfig
> drivers/gpio/Kconfig:34:error: recursive dependency detected!
> drivers/gpio/Kconfig:34:	symbol GPIOLIB is selected by EXTCON_USB_GPIO
> drivers/extcon/Kconfig:96:	symbol EXTCON_USB_GPIO depends on EXTCON
> drivers/extcon/Kconfig:1:	symbol EXTCON is selected by CHARGER_MANAGER
> drivers/power/Kconfig:316:	symbol CHARGER_MANAGER depends on POWER_SUPPLY
> drivers/power/Kconfig:1:	symbol POWER_SUPPLY is selected by HID_SONY
> drivers/hid/Kconfig:670:	symbol HID_SONY depends on NEW_LEDS
> drivers/leds/Kconfig:8:	symbol NEW_LEDS is selected by BCMA_DRIVER_GPIO
> drivers/bcma/Kconfig:75:	symbol BCMA_DRIVER_GPIO depends on GPIOLIB
> 
>> +	help
>> +	  Say Y here to enable GPIO based USB cable detection extcon support.
>> +	  Used typically if GPIO is used for USB ID pin detection.
>> +
>>  endif # MULTISTATE_SWITCH
>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>> index 0370b42..6a08a98 100644
>> --- a/drivers/extcon/Makefile
>> +++ b/drivers/extcon/Makefile
>> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
>> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>> new file mode 100644
>> index 0000000..99a58b2
>> --- /dev/null
>> +++ b/drivers/extcon/extcon-usb-gpio.c
>> @@ -0,0 +1,233 @@
>> +/**
>> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
>> + *
>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>> + * Author: Roger Quadros <rogerq@ti.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.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/extcon.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/of_gpio.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/workqueue.h>
>> +
>> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
>> +
>> +struct usb_extcon_info {
>> +	struct device *dev;
>> +	struct extcon_dev *edev;
>> +
>> +	struct gpio_desc *id_gpiod;
>> +	int id_irq;
>> +	bool id_irqwake;		/* ID wakeup enabled flag */
> 
> Do you really think id_irqwake is necessary?
> I think it is not necessary.

I will explain below why it is necessary.

> 
>> +
>> +	unsigned long debounce_jiffies;
>> +	struct delayed_work wq_detcable;
>> +};
>> +
>> +/* List of detectable cables */
>> +enum {
>> +	EXTCON_CABLE_USB = 0,
>> +	EXTCON_CABLE_USB_HOST,
>> +
>> +	EXTCON_CABLE_END,
>> +};
>> +
>> +static const char *usb_extcon_cable[] = {
>> +	[EXTCON_CABLE_USB] = "USB",
>> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",
>> +	NULL,
>> +};
>> +
> 
> [snip]
> 
>> +
>> +static int usb_extcon_remove(struct platform_device *pdev)
>> +{
>> +	struct usb_extcon_info *info = platform_get_drvdata(pdev);
>> +
>> +	cancel_delayed_work_sync(&info->wq_detcable);
>> +
>> +	return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int usb_extcon_suspend(struct device *dev)
>> +{
>> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
>> +
>> +	if (device_may_wakeup(dev))
>> +		if (!enable_irq_wake(info->id_irq))
>> +			info->id_irqwake = true;
>> +
> 
> You can simplify this code as following without 'id_irqwake':
> 
> 	if (device_may_wakeup(dev))
> 		enable_irq_wake(info->id_irq);

enable_irq_wake() can fail. And if it does we need to keep track of it
to prevent unbalanced disable_irq_wake() call in resume().
That's the reason I've added the id_irqwake flag in struct usb_extcon_info.

> 
>> +	/*
>> +	 * We don't want to process any IRQs after this point
>> +	 * as GPIOs used behind I2C subsystem might not be
>> +	 * accessible until resume completes. So disable IRQ.
>> +	 */
>> +	disable_irq(info->id_irq);
>> +
>> +	return 0;
>> +}
>> +
>> +static int usb_extcon_resume(struct device *dev)
>> +{
>> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
>> +
>> +	if (info->id_irqwake) {
>> +		disable_irq_wake(info->id_irq);
>> +		info->id_irqwake = false;
>> +	}
> 
> ditto.
> 
> 	if (device_may_wakeup(dev))
> 		disable_irq_wake(info->id_irq);
> 
>> +
>> +	enable_irq(info->id_irq);
>> +
>> +	return 0;
>> +}
>> +#endif
>> +
>> +static SIMPLE_DEV_PM_OPS(usb_extcon_pm_ops,
>> +			 usb_extcon_suspend, usb_extcon_resume);
>> +
>> +static struct of_device_id usb_extcon_dt_match[] = {
>> +	{ .compatible = "linux,extcon-usb-gpio", },
>> +	{ /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
>> +
>> +static struct platform_driver usb_extcon_driver = {
>> +	.probe		= usb_extcon_probe,
>> +	.remove		= usb_extcon_remove,
>> +	.driver		= {
>> +		.name	= "extcon-usb-gpio",
>> +		.pm	= &usb_extcon_pm_ops,
>> +		.of_match_table = usb_extcon_dt_match,
>> +	},
>> +};
>> +
>> +module_platform_driver(usb_extcon_driver);
>> +
>> +MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
>> +MODULE_DESCRIPTION("USB GPIO extcon driver");
>> +MODULE_LICENSE("GPL v2");
>>
> 
cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chanwoo Choi Jan. 30, 2015, 12:06 a.m. UTC | #3
Hi Roger,

On 01/29/2015 08:26 PM, Roger Quadros wrote:
> Chanwoo,
> 
> On 29/01/15 03:49, Chanwoo Choi wrote:
>> Hi Roger,
>>
>> We need to discuss one point about 'id_irqwake'.
>> I don't recommend to use 'id_irqwake' field.
>>
>> And I catch build warning by using "select" keywork in Kconfig.
>> It is my wrong guide of "select" keyword. So, I'll change it 
>> as 'depends on' keyword.
>>
>> Looks good to me except for 'id_irqwake'. 
>> I'll apply this patch on 3.21 queue after completing this discussion.
>>
>> On 01/28/2015 09:15 PM, Roger Quadros wrote:
>>> This driver observes the USB ID pin connected over a GPIO and
>>> updates the USB cable extcon states accordingly.
>>>
>>> The existing GPIO extcon driver is not suitable for this purpose
>>> as it needs to be taught to understand USB cable states and it
>>> can't handle more than one cable per instance.
>>>
>>> For the USB case we need to handle 2 cable states.
>>> 1) USB (attach/detach)
>>> 2) USB-Host (attach/detach)
>>>
>>> This driver can be easily updated in the future to handle VBUS
>>> events in case it happens to be available on GPIO for any platform.
>>>
>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>> ---
>>> v3:
>>> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>>>   IRQF_TRIGGER_FALLING
>>> - Added disable_irq() to suspend() and enable_irq() to resume()
>>>
>>>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>>>  drivers/extcon/Kconfig                             |   7 +
>>>  drivers/extcon/Makefile                            |   1 +
>>>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>>>  4 files changed, 259 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
>>>
>>> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>> new file mode 100644
>>> index 0000000..85fe6b0
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>> @@ -0,0 +1,18 @@
>>> +USB GPIO Extcon device
>>> +
>>> +This is a virtual device used to generate USB cable states from the USB ID pin
>>> +connected to a GPIO pin.
>>> +
>>> +Required properties:
>>> +- compatible: Should be "linux,extcon-usb-gpio"
>>> +- id-gpio: gpio for USB ID pin. See gpio binding.
>>> +
>>> +Example:
>>> +	extcon_usb1 {
>>> +		compatible = "linux,extcon-usb-gpio";
>>> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
>>> +	}
>>> +
>>> +	&omap_dwc3_1 {
>>> +		extcon = <&extcon_usb1>;
>>> +	};
>>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>>> index 6a1f7de..fd11536 100644
>>> --- a/drivers/extcon/Kconfig
>>> +++ b/drivers/extcon/Kconfig
>>> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>>>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>>>  	  detector and switch.
>>>  
>>> +config EXTCON_USB_GPIO
>>> +	tristate "USB GPIO extcon support"
>>> +	select GPIOLIB
>>
>> I catch the build warning if using 'select' instead of 'depends on' as following:
>> It is my wrong guide to you. So, I'll modify it by using "depends on" as your original patch.
> 
> OK. Thanks.
> 
>>
>> make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage  -j 8
>> scripts/kconfig/conf --silentoldconfig Kconfig
>> drivers/gpio/Kconfig:34:error: recursive dependency detected!
>> drivers/gpio/Kconfig:34:	symbol GPIOLIB is selected by EXTCON_USB_GPIO
>> drivers/extcon/Kconfig:96:	symbol EXTCON_USB_GPIO depends on EXTCON
>> drivers/extcon/Kconfig:1:	symbol EXTCON is selected by CHARGER_MANAGER
>> drivers/power/Kconfig:316:	symbol CHARGER_MANAGER depends on POWER_SUPPLY
>> drivers/power/Kconfig:1:	symbol POWER_SUPPLY is selected by HID_SONY
>> drivers/hid/Kconfig:670:	symbol HID_SONY depends on NEW_LEDS
>> drivers/leds/Kconfig:8:	symbol NEW_LEDS is selected by BCMA_DRIVER_GPIO
>> drivers/bcma/Kconfig:75:	symbol BCMA_DRIVER_GPIO depends on GPIOLIB
>>
>>> +	help
>>> +	  Say Y here to enable GPIO based USB cable detection extcon support.
>>> +	  Used typically if GPIO is used for USB ID pin detection.
>>> +
>>>  endif # MULTISTATE_SWITCH
>>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>>> index 0370b42..6a08a98 100644
>>> --- a/drivers/extcon/Makefile
>>> +++ b/drivers/extcon/Makefile
>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>>>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>>>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>>>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
>>> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
>>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>>> new file mode 100644
>>> index 0000000..99a58b2
>>> --- /dev/null
>>> +++ b/drivers/extcon/extcon-usb-gpio.c
>>> @@ -0,0 +1,233 @@
>>> +/**
>>> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
>>> + *
>>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>>> + * Author: Roger Quadros <rogerq@ti.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.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + */
>>> +
>>> +#include <linux/extcon.h>
>>> +#include <linux/init.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/irq.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of_gpio.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/workqueue.h>
>>> +
>>> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
>>> +
>>> +struct usb_extcon_info {
>>> +	struct device *dev;
>>> +	struct extcon_dev *edev;
>>> +
>>> +	struct gpio_desc *id_gpiod;
>>> +	int id_irq;
>>> +	bool id_irqwake;		/* ID wakeup enabled flag */
>>
>> Do you really think id_irqwake is necessary?
>> I think it is not necessary.
> 
> I will explain below why it is necessary.
> 
>>
>>> +
>>> +	unsigned long debounce_jiffies;
>>> +	struct delayed_work wq_detcable;
>>> +};
>>> +
>>> +/* List of detectable cables */
>>> +enum {
>>> +	EXTCON_CABLE_USB = 0,
>>> +	EXTCON_CABLE_USB_HOST,
>>> +
>>> +	EXTCON_CABLE_END,
>>> +};
>>> +
>>> +static const char *usb_extcon_cable[] = {
>>> +	[EXTCON_CABLE_USB] = "USB",
>>> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",
>>> +	NULL,
>>> +};
>>> +
>>
>> [snip]
>>
>>> +
>>> +static int usb_extcon_remove(struct platform_device *pdev)
>>> +{
>>> +	struct usb_extcon_info *info = platform_get_drvdata(pdev);
>>> +
>>> +	cancel_delayed_work_sync(&info->wq_detcable);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +#ifdef CONFIG_PM_SLEEP
>>> +static int usb_extcon_suspend(struct device *dev)
>>> +{
>>> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
>>> +
>>> +	if (device_may_wakeup(dev))
>>> +		if (!enable_irq_wake(info->id_irq))
>>> +			info->id_irqwake = true;
>>> +
>>
>> You can simplify this code as following without 'id_irqwake':
>>
>> 	if (device_may_wakeup(dev))
>> 		enable_irq_wake(info->id_irq);
> 
> enable_irq_wake() can fail. And if it does we need to keep track of it
> to prevent unbalanced disable_irq_wake() call in resume().
> That's the reason I've added the id_irqwake flag in struct usb_extcon_info.

It is not proper solution using id_irqwake. If fail to execute enable_irq_wake(),
usb_extcon_suspend() function have to return error immediately.

> 
>>
>>> +	/*
>>> +	 * We don't want to process any IRQs after this point
>>> +	 * as GPIOs used behind I2C subsystem might not be
>>> +	 * accessible until resume completes. So disable IRQ.
>>> +	 */
>>> +	disable_irq(info->id_irq);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int usb_extcon_resume(struct device *dev)
>>> +{
>>> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
>>> +
>>> +	if (info->id_irqwake) {
>>> +		disable_irq_wake(info->id_irq);
>>> +		info->id_irqwake = false;
>>> +	}
>>
>> ditto.
>>
>> 	if (device_may_wakeup(dev))
>> 		disable_irq_wake(info->id_irq);
>>
>>> +
>>> +	enable_irq(info->id_irq);
>>> +
>>> +	return 0;
>>> +}
>>> +#endif
>>> +
>>> +static SIMPLE_DEV_PM_OPS(usb_extcon_pm_ops,
>>> +			 usb_extcon_suspend, usb_extcon_resume);
>>> +
>>> +static struct of_device_id usb_extcon_dt_match[] = {
>>> +	{ .compatible = "linux,extcon-usb-gpio", },
>>> +	{ /* sentinel */ }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
>>> +
>>> +static struct platform_driver usb_extcon_driver = {
>>> +	.probe		= usb_extcon_probe,
>>> +	.remove		= usb_extcon_remove,
>>> +	.driver		= {
>>> +		.name	= "extcon-usb-gpio",
>>> +		.pm	= &usb_extcon_pm_ops,
>>> +		.of_match_table = usb_extcon_dt_match,
>>> +	},
>>> +};
>>> +
>>> +module_platform_driver(usb_extcon_driver);
>>> +
>>> +MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
>>> +MODULE_DESCRIPTION("USB GPIO extcon driver");
>>> +MODULE_LICENSE("GPL v2");

Thanks,
Chanwoo

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chanwoo Choi Jan. 30, 2015, 12:11 a.m. UTC | #4
Hi Roger,

On 01/28/2015 09:15 PM, Roger Quadros wrote:
> This driver observes the USB ID pin connected over a GPIO and
> updates the USB cable extcon states accordingly.
> 
> The existing GPIO extcon driver is not suitable for this purpose
> as it needs to be taught to understand USB cable states and it
> can't handle more than one cable per instance.
> 
> For the USB case we need to handle 2 cable states.
> 1) USB (attach/detach)
> 2) USB-Host (attach/detach)
> 
> This driver can be easily updated in the future to handle VBUS
> events in case it happens to be available on GPIO for any platform.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
> v3:
> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>   IRQF_TRIGGER_FALLING
> - Added disable_irq() to suspend() and enable_irq() to resume()
> 
>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>  drivers/extcon/Kconfig                             |   7 +
>  drivers/extcon/Makefile                            |   1 +
>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>  4 files changed, 259 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
> 
> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
> new file mode 100644
> index 0000000..85fe6b0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
> @@ -0,0 +1,18 @@
> +USB GPIO Extcon device
> +
> +This is a virtual device used to generate USB cable states from the USB ID pin
> +connected to a GPIO pin.
> +
> +Required properties:
> +- compatible: Should be "linux,extcon-usb-gpio"
> +- id-gpio: gpio for USB ID pin. See gpio binding.
> +
> +Example:
> +	extcon_usb1 {
> +		compatible = "linux,extcon-usb-gpio";
> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
> +	}
> +
> +	&omap_dwc3_1 {
> +		extcon = <&extcon_usb1>;
> +	};
> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
> index 6a1f7de..fd11536 100644
> --- a/drivers/extcon/Kconfig
> +++ b/drivers/extcon/Kconfig
> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>  	  detector and switch.
>  
> +config EXTCON_USB_GPIO
> +	tristate "USB GPIO extcon support"
> +	select GPIOLIB
> +	help
> +	  Say Y here to enable GPIO based USB cable detection extcon support.
> +	  Used typically if GPIO is used for USB ID pin detection.
> +
>  endif # MULTISTATE_SWITCH
> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
> index 0370b42..6a08a98 100644
> --- a/drivers/extcon/Makefile
> +++ b/drivers/extcon/Makefile
> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
> new file mode 100644
> index 0000000..99a58b2
> --- /dev/null
> +++ b/drivers/extcon/extcon-usb-gpio.c
> @@ -0,0 +1,233 @@
> +/**
> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
> + *
> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
> + * Author: Roger Quadros <rogerq@ti.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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/extcon.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
> +
> +struct usb_extcon_info {
> +	struct device *dev;
> +	struct extcon_dev *edev;
> +
> +	struct gpio_desc *id_gpiod;
> +	int id_irq;
> +	bool id_irqwake;		/* ID wakeup enabled flag */
> +
> +	unsigned long debounce_jiffies;
> +	struct delayed_work wq_detcable;
> +};
> +
> +/* List of detectable cables */
> +enum {
> +	EXTCON_CABLE_USB = 0,
> +	EXTCON_CABLE_USB_HOST,
> +
> +	EXTCON_CABLE_END,
> +};
> +
> +static const char *usb_extcon_cable[] = {
> +	[EXTCON_CABLE_USB] = "USB",
> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",

I'll use the defined name for extcon cable name as soon because 
it has potential isseu about the conflict of extcon cable name between subsystems.
So, I recommend to use a captical letter as "USB-HOST" instead of "USB-Host".
If other extcon driver don't use the captical letter, I'll fix it.

[snip]

Thanks,
Chanwoo Choi
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Roger Quadros Jan. 30, 2015, 11:09 a.m. UTC | #5
Chanwoo,

On 30/01/15 02:06, Chanwoo Choi wrote:
> Hi Roger,
> 
> On 01/29/2015 08:26 PM, Roger Quadros wrote:
>> Chanwoo,
>>
>> On 29/01/15 03:49, Chanwoo Choi wrote:
>>> Hi Roger,
>>>
>>> We need to discuss one point about 'id_irqwake'.
>>> I don't recommend to use 'id_irqwake' field.
>>>
>>> And I catch build warning by using "select" keywork in Kconfig.
>>> It is my wrong guide of "select" keyword. So, I'll change it 
>>> as 'depends on' keyword.
>>>
>>> Looks good to me except for 'id_irqwake'. 
>>> I'll apply this patch on 3.21 queue after completing this discussion.
>>>
>>> On 01/28/2015 09:15 PM, Roger Quadros wrote:
>>>> This driver observes the USB ID pin connected over a GPIO and
>>>> updates the USB cable extcon states accordingly.
>>>>
>>>> The existing GPIO extcon driver is not suitable for this purpose
>>>> as it needs to be taught to understand USB cable states and it
>>>> can't handle more than one cable per instance.
>>>>
>>>> For the USB case we need to handle 2 cable states.
>>>> 1) USB (attach/detach)
>>>> 2) USB-Host (attach/detach)
>>>>
>>>> This driver can be easily updated in the future to handle VBUS
>>>> events in case it happens to be available on GPIO for any platform.
>>>>
>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>>> ---
>>>> v3:
>>>> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>>>>   IRQF_TRIGGER_FALLING
>>>> - Added disable_irq() to suspend() and enable_irq() to resume()
>>>>
>>>>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>>>>  drivers/extcon/Kconfig                             |   7 +
>>>>  drivers/extcon/Makefile                            |   1 +
>>>>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>>>>  4 files changed, 259 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>> new file mode 100644
>>>> index 0000000..85fe6b0
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>> @@ -0,0 +1,18 @@
>>>> +USB GPIO Extcon device
>>>> +
>>>> +This is a virtual device used to generate USB cable states from the USB ID pin
>>>> +connected to a GPIO pin.
>>>> +
>>>> +Required properties:
>>>> +- compatible: Should be "linux,extcon-usb-gpio"
>>>> +- id-gpio: gpio for USB ID pin. See gpio binding.
>>>> +
>>>> +Example:
>>>> +	extcon_usb1 {
>>>> +		compatible = "linux,extcon-usb-gpio";
>>>> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
>>>> +	}
>>>> +
>>>> +	&omap_dwc3_1 {
>>>> +		extcon = <&extcon_usb1>;
>>>> +	};
>>>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>>>> index 6a1f7de..fd11536 100644
>>>> --- a/drivers/extcon/Kconfig
>>>> +++ b/drivers/extcon/Kconfig
>>>> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>>>>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>>>>  	  detector and switch.
>>>>  
>>>> +config EXTCON_USB_GPIO
>>>> +	tristate "USB GPIO extcon support"
>>>> +	select GPIOLIB
>>>
>>> I catch the build warning if using 'select' instead of 'depends on' as following:
>>> It is my wrong guide to you. So, I'll modify it by using "depends on" as your original patch.
>>
>> OK. Thanks.
>>
>>>
>>> make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage  -j 8
>>> scripts/kconfig/conf --silentoldconfig Kconfig
>>> drivers/gpio/Kconfig:34:error: recursive dependency detected!
>>> drivers/gpio/Kconfig:34:	symbol GPIOLIB is selected by EXTCON_USB_GPIO
>>> drivers/extcon/Kconfig:96:	symbol EXTCON_USB_GPIO depends on EXTCON
>>> drivers/extcon/Kconfig:1:	symbol EXTCON is selected by CHARGER_MANAGER
>>> drivers/power/Kconfig:316:	symbol CHARGER_MANAGER depends on POWER_SUPPLY
>>> drivers/power/Kconfig:1:	symbol POWER_SUPPLY is selected by HID_SONY
>>> drivers/hid/Kconfig:670:	symbol HID_SONY depends on NEW_LEDS
>>> drivers/leds/Kconfig:8:	symbol NEW_LEDS is selected by BCMA_DRIVER_GPIO
>>> drivers/bcma/Kconfig:75:	symbol BCMA_DRIVER_GPIO depends on GPIOLIB
>>>
>>>> +	help
>>>> +	  Say Y here to enable GPIO based USB cable detection extcon support.
>>>> +	  Used typically if GPIO is used for USB ID pin detection.
>>>> +
>>>>  endif # MULTISTATE_SWITCH
>>>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>>>> index 0370b42..6a08a98 100644
>>>> --- a/drivers/extcon/Makefile
>>>> +++ b/drivers/extcon/Makefile
>>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>>>>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>>>>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>>>>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
>>>> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
>>>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>>>> new file mode 100644
>>>> index 0000000..99a58b2
>>>> --- /dev/null
>>>> +++ b/drivers/extcon/extcon-usb-gpio.c
>>>> @@ -0,0 +1,233 @@
>>>> +/**
>>>> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
>>>> + *
>>>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>>>> + * Author: Roger Quadros <rogerq@ti.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.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + */
>>>> +
>>>> +#include <linux/extcon.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/irq.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of_gpio.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/slab.h>
>>>> +#include <linux/workqueue.h>
>>>> +
>>>> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
>>>> +
>>>> +struct usb_extcon_info {
>>>> +	struct device *dev;
>>>> +	struct extcon_dev *edev;
>>>> +
>>>> +	struct gpio_desc *id_gpiod;
>>>> +	int id_irq;
>>>> +	bool id_irqwake;		/* ID wakeup enabled flag */
>>>
>>> Do you really think id_irqwake is necessary?
>>> I think it is not necessary.
>>
>> I will explain below why it is necessary.
>>
>>>
>>>> +
>>>> +	unsigned long debounce_jiffies;
>>>> +	struct delayed_work wq_detcable;
>>>> +};
>>>> +
>>>> +/* List of detectable cables */
>>>> +enum {
>>>> +	EXTCON_CABLE_USB = 0,
>>>> +	EXTCON_CABLE_USB_HOST,
>>>> +
>>>> +	EXTCON_CABLE_END,
>>>> +};
>>>> +
>>>> +static const char *usb_extcon_cable[] = {
>>>> +	[EXTCON_CABLE_USB] = "USB",
>>>> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",
>>>> +	NULL,
>>>> +};
>>>> +
>>>
>>> [snip]
>>>
>>>> +
>>>> +static int usb_extcon_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct usb_extcon_info *info = platform_get_drvdata(pdev);
>>>> +
>>>> +	cancel_delayed_work_sync(&info->wq_detcable);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int usb_extcon_suspend(struct device *dev)
>>>> +{
>>>> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
>>>> +
>>>> +	if (device_may_wakeup(dev))
>>>> +		if (!enable_irq_wake(info->id_irq))
>>>> +			info->id_irqwake = true;
>>>> +
>>>
>>> You can simplify this code as following without 'id_irqwake':
>>>
>>> 	if (device_may_wakeup(dev))
>>> 		enable_irq_wake(info->id_irq);
>>
>> enable_irq_wake() can fail. And if it does we need to keep track of it
>> to prevent unbalanced disable_irq_wake() call in resume().
>> That's the reason I've added the id_irqwake flag in struct usb_extcon_info.
> 
> It is not proper solution using id_irqwake. If fail to execute enable_irq_wake(),
> usb_extcon_suspend() function have to return error immediately.
> 

Your point is valid. I will now need to investigate why enable_irq_wake() is failing
when used for GPIO of PCA857x on DRA7-evm.

cheers,
-roger

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Roger Quadros Jan. 30, 2015, 1:57 p.m. UTC | #6
+Thomas (for irq/dummychip.c question)

Hi,

On 30/01/15 13:09, Roger Quadros wrote:
> Chanwoo,
> 
> On 30/01/15 02:06, Chanwoo Choi wrote:
>> Hi Roger,
>>
>> On 01/29/2015 08:26 PM, Roger Quadros wrote:
>>> Chanwoo,
>>>
>>> On 29/01/15 03:49, Chanwoo Choi wrote:
>>>> Hi Roger,
>>>>
>>>> We need to discuss one point about 'id_irqwake'.
>>>> I don't recommend to use 'id_irqwake' field.
>>>>
>>>> And I catch build warning by using "select" keywork in Kconfig.
>>>> It is my wrong guide of "select" keyword. So, I'll change it 
>>>> as 'depends on' keyword.
>>>>
>>>> Looks good to me except for 'id_irqwake'. 
>>>> I'll apply this patch on 3.21 queue after completing this discussion.
>>>>
>>>> On 01/28/2015 09:15 PM, Roger Quadros wrote:
>>>>> This driver observes the USB ID pin connected over a GPIO and
>>>>> updates the USB cable extcon states accordingly.
>>>>>
>>>>> The existing GPIO extcon driver is not suitable for this purpose
>>>>> as it needs to be taught to understand USB cable states and it
>>>>> can't handle more than one cable per instance.
>>>>>
>>>>> For the USB case we need to handle 2 cable states.
>>>>> 1) USB (attach/detach)
>>>>> 2) USB-Host (attach/detach)
>>>>>
>>>>> This driver can be easily updated in the future to handle VBUS
>>>>> events in case it happens to be available on GPIO for any platform.
>>>>>
>>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>>>> ---
>>>>> v3:
>>>>> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>>>>>   IRQF_TRIGGER_FALLING
>>>>> - Added disable_irq() to suspend() and enable_irq() to resume()
>>>>>
>>>>>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>>>>>  drivers/extcon/Kconfig                             |   7 +
>>>>>  drivers/extcon/Makefile                            |   1 +
>>>>>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>>>>>  4 files changed, 259 insertions(+)
>>>>>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>>>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>>> new file mode 100644
>>>>> index 0000000..85fe6b0
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>>> @@ -0,0 +1,18 @@
>>>>> +USB GPIO Extcon device
>>>>> +
>>>>> +This is a virtual device used to generate USB cable states from the USB ID pin
>>>>> +connected to a GPIO pin.
>>>>> +
>>>>> +Required properties:
>>>>> +- compatible: Should be "linux,extcon-usb-gpio"
>>>>> +- id-gpio: gpio for USB ID pin. See gpio binding.
>>>>> +
>>>>> +Example:
>>>>> +	extcon_usb1 {
>>>>> +		compatible = "linux,extcon-usb-gpio";
>>>>> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
>>>>> +	}
>>>>> +
>>>>> +	&omap_dwc3_1 {
>>>>> +		extcon = <&extcon_usb1>;
>>>>> +	};
>>>>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>>>>> index 6a1f7de..fd11536 100644
>>>>> --- a/drivers/extcon/Kconfig
>>>>> +++ b/drivers/extcon/Kconfig
>>>>> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>>>>>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>>>>>  	  detector and switch.
>>>>>  
>>>>> +config EXTCON_USB_GPIO
>>>>> +	tristate "USB GPIO extcon support"
>>>>> +	select GPIOLIB
>>>>
>>>> I catch the build warning if using 'select' instead of 'depends on' as following:
>>>> It is my wrong guide to you. So, I'll modify it by using "depends on" as your original patch.
>>>
>>> OK. Thanks.
>>>
>>>>
>>>> make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage  -j 8
>>>> scripts/kconfig/conf --silentoldconfig Kconfig
>>>> drivers/gpio/Kconfig:34:error: recursive dependency detected!
>>>> drivers/gpio/Kconfig:34:	symbol GPIOLIB is selected by EXTCON_USB_GPIO
>>>> drivers/extcon/Kconfig:96:	symbol EXTCON_USB_GPIO depends on EXTCON
>>>> drivers/extcon/Kconfig:1:	symbol EXTCON is selected by CHARGER_MANAGER
>>>> drivers/power/Kconfig:316:	symbol CHARGER_MANAGER depends on POWER_SUPPLY
>>>> drivers/power/Kconfig:1:	symbol POWER_SUPPLY is selected by HID_SONY
>>>> drivers/hid/Kconfig:670:	symbol HID_SONY depends on NEW_LEDS
>>>> drivers/leds/Kconfig:8:	symbol NEW_LEDS is selected by BCMA_DRIVER_GPIO
>>>> drivers/bcma/Kconfig:75:	symbol BCMA_DRIVER_GPIO depends on GPIOLIB
>>>>
>>>>> +	help
>>>>> +	  Say Y here to enable GPIO based USB cable detection extcon support.
>>>>> +	  Used typically if GPIO is used for USB ID pin detection.
>>>>> +
>>>>>  endif # MULTISTATE_SWITCH
>>>>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>>>>> index 0370b42..6a08a98 100644
>>>>> --- a/drivers/extcon/Makefile
>>>>> +++ b/drivers/extcon/Makefile
>>>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>>>>>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>>>>>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>>>>>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
>>>>> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
>>>>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>>>>> new file mode 100644
>>>>> index 0000000..99a58b2
>>>>> --- /dev/null
>>>>> +++ b/drivers/extcon/extcon-usb-gpio.c
>>>>> @@ -0,0 +1,233 @@
>>>>> +/**
>>>>> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
>>>>> + *
>>>>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>>>>> + * Author: Roger Quadros <rogerq@ti.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.
>>>>> + *
>>>>> + * This program is distributed in the hope that it will be useful,
>>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>> + * GNU General Public License for more details.
>>>>> + */
>>>>> +
>>>>> +#include <linux/extcon.h>
>>>>> +#include <linux/init.h>
>>>>> +#include <linux/interrupt.h>
>>>>> +#include <linux/irq.h>
>>>>> +#include <linux/kernel.h>
>>>>> +#include <linux/module.h>
>>>>> +#include <linux/of_gpio.h>
>>>>> +#include <linux/platform_device.h>
>>>>> +#include <linux/slab.h>
>>>>> +#include <linux/workqueue.h>
>>>>> +
>>>>> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
>>>>> +
>>>>> +struct usb_extcon_info {
>>>>> +	struct device *dev;
>>>>> +	struct extcon_dev *edev;
>>>>> +
>>>>> +	struct gpio_desc *id_gpiod;
>>>>> +	int id_irq;
>>>>> +	bool id_irqwake;		/* ID wakeup enabled flag */
>>>>
>>>> Do you really think id_irqwake is necessary?
>>>> I think it is not necessary.
>>>
>>> I will explain below why it is necessary.
>>>
>>>>
>>>>> +
>>>>> +	unsigned long debounce_jiffies;
>>>>> +	struct delayed_work wq_detcable;
>>>>> +};
>>>>> +
>>>>> +/* List of detectable cables */
>>>>> +enum {
>>>>> +	EXTCON_CABLE_USB = 0,
>>>>> +	EXTCON_CABLE_USB_HOST,
>>>>> +
>>>>> +	EXTCON_CABLE_END,
>>>>> +};
>>>>> +
>>>>> +static const char *usb_extcon_cable[] = {
>>>>> +	[EXTCON_CABLE_USB] = "USB",
>>>>> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",
>>>>> +	NULL,
>>>>> +};
>>>>> +
>>>>
>>>> [snip]
>>>>
>>>>> +
>>>>> +static int usb_extcon_remove(struct platform_device *pdev)
>>>>> +{
>>>>> +	struct usb_extcon_info *info = platform_get_drvdata(pdev);
>>>>> +
>>>>> +	cancel_delayed_work_sync(&info->wq_detcable);
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +#ifdef CONFIG_PM_SLEEP
>>>>> +static int usb_extcon_suspend(struct device *dev)
>>>>> +{
>>>>> +	struct usb_extcon_info *info = dev_get_drvdata(dev);
>>>>> +
>>>>> +	if (device_may_wakeup(dev))
>>>>> +		if (!enable_irq_wake(info->id_irq))
>>>>> +			info->id_irqwake = true;
>>>>> +
>>>>
>>>> You can simplify this code as following without 'id_irqwake':
>>>>
>>>> 	if (device_may_wakeup(dev))
>>>> 		enable_irq_wake(info->id_irq);
>>>
>>> enable_irq_wake() can fail. And if it does we need to keep track of it
>>> to prevent unbalanced disable_irq_wake() call in resume().
>>> That's the reason I've added the id_irqwake flag in struct usb_extcon_info.
>>
>> It is not proper solution using id_irqwake. If fail to execute enable_irq_wake(),
>> usb_extcon_suspend() function have to return error immediately.
>>
> 
> Your point is valid. I will now need to investigate why enable_irq_wake() is failing
> when used for GPIO of PCA857x on DRA7-evm.
> 

The reason of enable_irq_wake() failure with PCA857x is that it uses dummy_irq_chip which
doesn't have irq_set_wake() or IRQCHIP_SKIP_SET_WAKE flag set.

I can send out another patch to add IRQCHIP_SKIP_SET_WAKE to dummy_irq_chip.

Thomas, is this a reasonable option?

The problem at hand is that enable_irq_wake() on a IRQ line based off PCA857x GPIO chip fails.
PCA857x uses dummy_irq_chip to implement the IRQ feature.
http://lxr.free-electrons.com/source/drivers/gpio/gpio-pcf857x.c#L227

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Roger Quadros Jan. 30, 2015, 2:03 p.m. UTC | #7
On 30/01/15 02:11, Chanwoo Choi wrote:
> Hi Roger,
> 
> On 01/28/2015 09:15 PM, Roger Quadros wrote:
>> This driver observes the USB ID pin connected over a GPIO and
>> updates the USB cable extcon states accordingly.
>>
>> The existing GPIO extcon driver is not suitable for this purpose
>> as it needs to be taught to understand USB cable states and it
>> can't handle more than one cable per instance.
>>
>> For the USB case we need to handle 2 cable states.
>> 1) USB (attach/detach)
>> 2) USB-Host (attach/detach)
>>
>> This driver can be easily updated in the future to handle VBUS
>> events in case it happens to be available on GPIO for any platform.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>> v3:
>> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>>   IRQF_TRIGGER_FALLING
>> - Added disable_irq() to suspend() and enable_irq() to resume()
>>
>>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>>  drivers/extcon/Kconfig                             |   7 +
>>  drivers/extcon/Makefile                            |   1 +
>>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>>  4 files changed, 259 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
>>
>> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>> new file mode 100644
>> index 0000000..85fe6b0
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>> @@ -0,0 +1,18 @@
>> +USB GPIO Extcon device
>> +
>> +This is a virtual device used to generate USB cable states from the USB ID pin
>> +connected to a GPIO pin.
>> +
>> +Required properties:
>> +- compatible: Should be "linux,extcon-usb-gpio"
>> +- id-gpio: gpio for USB ID pin. See gpio binding.
>> +
>> +Example:
>> +	extcon_usb1 {
>> +		compatible = "linux,extcon-usb-gpio";
>> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
>> +	}
>> +
>> +	&omap_dwc3_1 {
>> +		extcon = <&extcon_usb1>;
>> +	};
>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>> index 6a1f7de..fd11536 100644
>> --- a/drivers/extcon/Kconfig
>> +++ b/drivers/extcon/Kconfig
>> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>>  	  detector and switch.
>>  
>> +config EXTCON_USB_GPIO
>> +	tristate "USB GPIO extcon support"
>> +	select GPIOLIB
>> +	help
>> +	  Say Y here to enable GPIO based USB cable detection extcon support.
>> +	  Used typically if GPIO is used for USB ID pin detection.
>> +
>>  endif # MULTISTATE_SWITCH
>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>> index 0370b42..6a08a98 100644
>> --- a/drivers/extcon/Makefile
>> +++ b/drivers/extcon/Makefile
>> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
>> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>> new file mode 100644
>> index 0000000..99a58b2
>> --- /dev/null
>> +++ b/drivers/extcon/extcon-usb-gpio.c
>> @@ -0,0 +1,233 @@
>> +/**
>> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
>> + *
>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>> + * Author: Roger Quadros <rogerq@ti.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.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/extcon.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/of_gpio.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/workqueue.h>
>> +
>> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
>> +
>> +struct usb_extcon_info {
>> +	struct device *dev;
>> +	struct extcon_dev *edev;
>> +
>> +	struct gpio_desc *id_gpiod;
>> +	int id_irq;
>> +	bool id_irqwake;		/* ID wakeup enabled flag */
>> +
>> +	unsigned long debounce_jiffies;
>> +	struct delayed_work wq_detcable;
>> +};
>> +
>> +/* List of detectable cables */
>> +enum {
>> +	EXTCON_CABLE_USB = 0,
>> +	EXTCON_CABLE_USB_HOST,
>> +
>> +	EXTCON_CABLE_END,
>> +};
>> +
>> +static const char *usb_extcon_cable[] = {
>> +	[EXTCON_CABLE_USB] = "USB",
>> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",
> 
> I'll use the defined name for extcon cable name as soon because 
> it has potential isseu about the conflict of extcon cable name between subsystems.
> So, I recommend to use a captical letter as "USB-HOST" instead of "USB-Host".
> If other extcon driver don't use the captical letter, I'll fix it.

Did you see patch 2 in this series?
In that I had fixed all instances to use "USB-Host" based on
http://lxr.free-electrons.com/source/drivers/extcon/extcon-class.c#L45

What do you suggest?
Skip patch 2 and convert all "USB-Host" to "USB-HOST"?

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chanwoo Choi Feb. 2, 2015, 5:06 a.m. UTC | #8
Hi Roger,

On 01/30/2015 11:03 PM, Roger Quadros wrote:
> On 30/01/15 02:11, Chanwoo Choi wrote:
>> Hi Roger,
>>
>> On 01/28/2015 09:15 PM, Roger Quadros wrote:
>>> This driver observes the USB ID pin connected over a GPIO and
>>> updates the USB cable extcon states accordingly.
>>>
>>> The existing GPIO extcon driver is not suitable for this purpose
>>> as it needs to be taught to understand USB cable states and it
>>> can't handle more than one cable per instance.
>>>
>>> For the USB case we need to handle 2 cable states.
>>> 1) USB (attach/detach)
>>> 2) USB-Host (attach/detach)
>>>
>>> This driver can be easily updated in the future to handle VBUS
>>> events in case it happens to be available on GPIO for any platform.
>>>
>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>> ---
>>> v3:
>>> - removed IRQF_NO_SUSPEND flag. Added IRQF_TRIGGER_RISING and
>>>   IRQF_TRIGGER_FALLING
>>> - Added disable_irq() to suspend() and enable_irq() to resume()
>>>
>>>  .../devicetree/bindings/extcon/extcon-usb-gpio.txt |  18 ++
>>>  drivers/extcon/Kconfig                             |   7 +
>>>  drivers/extcon/Makefile                            |   1 +
>>>  drivers/extcon/extcon-usb-gpio.c                   | 233 +++++++++++++++++++++
>>>  4 files changed, 259 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>>  create mode 100644 drivers/extcon/extcon-usb-gpio.c
>>>
>>> diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>> new file mode 100644
>>> index 0000000..85fe6b0
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
>>> @@ -0,0 +1,18 @@
>>> +USB GPIO Extcon device
>>> +
>>> +This is a virtual device used to generate USB cable states from the USB ID pin
>>> +connected to a GPIO pin.
>>> +
>>> +Required properties:
>>> +- compatible: Should be "linux,extcon-usb-gpio"
>>> +- id-gpio: gpio for USB ID pin. See gpio binding.
>>> +
>>> +Example:
>>> +	extcon_usb1 {
>>> +		compatible = "linux,extcon-usb-gpio";
>>> +		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
>>> +	}
>>> +
>>> +	&omap_dwc3_1 {
>>> +		extcon = <&extcon_usb1>;
>>> +	};
>>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>>> index 6a1f7de..fd11536 100644
>>> --- a/drivers/extcon/Kconfig
>>> +++ b/drivers/extcon/Kconfig
>>> @@ -93,4 +93,11 @@ config EXTCON_SM5502
>>>  	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
>>>  	  detector and switch.
>>>  
>>> +config EXTCON_USB_GPIO
>>> +	tristate "USB GPIO extcon support"
>>> +	select GPIOLIB
>>> +	help
>>> +	  Say Y here to enable GPIO based USB cable detection extcon support.
>>> +	  Used typically if GPIO is used for USB ID pin detection.
>>> +
>>>  endif # MULTISTATE_SWITCH
>>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>>> index 0370b42..6a08a98 100644
>>> --- a/drivers/extcon/Makefile
>>> +++ b/drivers/extcon/Makefile
>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>>>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>>>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>>>  obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
>>> +obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
>>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>>> new file mode 100644
>>> index 0000000..99a58b2
>>> --- /dev/null
>>> +++ b/drivers/extcon/extcon-usb-gpio.c
>>> @@ -0,0 +1,233 @@
>>> +/**
>>> + * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
>>> + *
>>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>>> + * Author: Roger Quadros <rogerq@ti.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.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + */
>>> +
>>> +#include <linux/extcon.h>
>>> +#include <linux/init.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/irq.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of_gpio.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/workqueue.h>
>>> +
>>> +#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
>>> +
>>> +struct usb_extcon_info {
>>> +	struct device *dev;
>>> +	struct extcon_dev *edev;
>>> +
>>> +	struct gpio_desc *id_gpiod;
>>> +	int id_irq;
>>> +	bool id_irqwake;		/* ID wakeup enabled flag */
>>> +
>>> +	unsigned long debounce_jiffies;
>>> +	struct delayed_work wq_detcable;
>>> +};
>>> +
>>> +/* List of detectable cables */
>>> +enum {
>>> +	EXTCON_CABLE_USB = 0,
>>> +	EXTCON_CABLE_USB_HOST,
>>> +
>>> +	EXTCON_CABLE_END,
>>> +};
>>> +
>>> +static const char *usb_extcon_cable[] = {
>>> +	[EXTCON_CABLE_USB] = "USB",
>>> +	[EXTCON_CABLE_USB_HOST] = "USB-Host",
>>
>> I'll use the defined name for extcon cable name as soon because 
>> it has potential isseu about the conflict of extcon cable name between subsystems.
>> So, I recommend to use a captical letter as "USB-HOST" instead of "USB-Host".
>> If other extcon driver don't use the captical letter, I'll fix it.
> 
> Did you see patch 2 in this series?
> In that I had fixed all instances to use "USB-Host" based on
> http://lxr.free-electrons.com/source/drivers/extcon/extcon-class.c#L45
> 
> What do you suggest?
> Skip patch 2 and convert all "USB-Host" to "USB-HOST"?

I replied my opinion about this on following patch[1].
[1] Re: [PATCH v2 2/7] usb: extcon: Fix USB-Host cable name

Thanks,
Chanwoo Choi

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
new file mode 100644
index 0000000..85fe6b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt
@@ -0,0 +1,18 @@ 
+USB GPIO Extcon device
+
+This is a virtual device used to generate USB cable states from the USB ID pin
+connected to a GPIO pin.
+
+Required properties:
+- compatible: Should be "linux,extcon-usb-gpio"
+- id-gpio: gpio for USB ID pin. See gpio binding.
+
+Example:
+	extcon_usb1 {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>;
+	}
+
+	&omap_dwc3_1 {
+		extcon = <&extcon_usb1>;
+	};
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 6a1f7de..fd11536 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -93,4 +93,11 @@  config EXTCON_SM5502
 	  Silicon Mitus SM5502. The SM5502 is a USB port accessory
 	  detector and switch.
 
+config EXTCON_USB_GPIO
+	tristate "USB GPIO extcon support"
+	select GPIOLIB
+	help
+	  Say Y here to enable GPIO based USB cable detection extcon support.
+	  Used typically if GPIO is used for USB ID pin detection.
+
 endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 0370b42..6a08a98 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -12,3 +12,4 @@  obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
 obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
 obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
 obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
+obj-$(CONFIG_EXTCON_USB_GPIO)	+= extcon-usb-gpio.o
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
new file mode 100644
index 0000000..99a58b2
--- /dev/null
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -0,0 +1,233 @@ 
+/**
+ * drivers/extcon/extcon-usb-gpio.c - USB GPIO extcon driver
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq@ti.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/extcon.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#define USB_GPIO_DEBOUNCE_MS	20	/* ms */
+
+struct usb_extcon_info {
+	struct device *dev;
+	struct extcon_dev *edev;
+
+	struct gpio_desc *id_gpiod;
+	int id_irq;
+	bool id_irqwake;		/* ID wakeup enabled flag */
+
+	unsigned long debounce_jiffies;
+	struct delayed_work wq_detcable;
+};
+
+/* List of detectable cables */
+enum {
+	EXTCON_CABLE_USB = 0,
+	EXTCON_CABLE_USB_HOST,
+
+	EXTCON_CABLE_END,
+};
+
+static const char *usb_extcon_cable[] = {
+	[EXTCON_CABLE_USB] = "USB",
+	[EXTCON_CABLE_USB_HOST] = "USB-Host",
+	NULL,
+};
+
+static void usb_extcon_detect_cable(struct work_struct *work)
+{
+	int id;
+	struct usb_extcon_info *info = container_of(to_delayed_work(work),
+						    struct usb_extcon_info,
+						    wq_detcable);
+
+	/* check ID and update cable state */
+	id = gpiod_get_value_cansleep(info->id_gpiod);
+	if (id) {
+		/*
+		 * ID = 1 means USB HOST cable detached.
+		 * As we don't have event for USB peripheral cable attached,
+		 * we simulate USB peripheral attach here.
+		 */
+		extcon_set_cable_state(info->edev,
+				       usb_extcon_cable[EXTCON_CABLE_USB_HOST],
+				       false);
+		extcon_set_cable_state(info->edev,
+				       usb_extcon_cable[EXTCON_CABLE_USB],
+				       true);
+	} else {
+		/*
+		 * ID = 0 means USB HOST cable attached.
+		 * As we don't have event for USB peripheral cable detached,
+		 * we simulate USB peripheral detach here.
+		 */
+		extcon_set_cable_state(info->edev,
+				       usb_extcon_cable[EXTCON_CABLE_USB],
+				       false);
+		extcon_set_cable_state(info->edev,
+				       usb_extcon_cable[EXTCON_CABLE_USB_HOST],
+				       true);
+	}
+}
+
+static irqreturn_t usb_irq_handler(int irq, void *dev_id)
+{
+	struct usb_extcon_info *info = dev_id;
+
+	queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
+			   info->debounce_jiffies);
+
+	return IRQ_HANDLED;
+}
+
+static int usb_extcon_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct usb_extcon_info *info;
+	int ret;
+
+	if (!np)
+		return -EINVAL;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = dev;
+	info->id_gpiod = devm_gpiod_get(&pdev->dev, "id");
+	if (IS_ERR(info->id_gpiod)) {
+		dev_err(dev, "failed to get ID GPIO\n");
+		return PTR_ERR(info->id_gpiod);
+	}
+
+	ret = gpiod_set_debounce(info->id_gpiod,
+				 USB_GPIO_DEBOUNCE_MS * 1000);
+	if (ret < 0)
+		info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS);
+
+	INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable);
+
+	info->id_irq = gpiod_to_irq(info->id_gpiod);
+	if (info->id_irq < 0) {
+		dev_err(dev, "failed to get ID IRQ\n");
+		return info->id_irq;
+	}
+
+	ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
+					usb_irq_handler,
+					IRQF_TRIGGER_RISING |
+					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					pdev->name, info);
+	if (ret < 0) {
+		dev_err(dev, "failed to request handler for ID IRQ\n");
+		return ret;
+	}
+
+	info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable);
+	if (IS_ERR(info->edev)) {
+		dev_err(dev, "failed to allocate extcon device\n");
+		return -ENOMEM;
+	}
+
+	ret = devm_extcon_dev_register(dev, info->edev);
+	if (ret < 0) {
+		dev_err(dev, "failed to register extcon device\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, info);
+	device_init_wakeup(dev, 1);
+
+	/* Perform initial detection */
+	usb_extcon_detect_cable(&info->wq_detcable.work);
+
+	return 0;
+}
+
+static int usb_extcon_remove(struct platform_device *pdev)
+{
+	struct usb_extcon_info *info = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&info->wq_detcable);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int usb_extcon_suspend(struct device *dev)
+{
+	struct usb_extcon_info *info = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		if (!enable_irq_wake(info->id_irq))
+			info->id_irqwake = true;
+
+	/*
+	 * We don't want to process any IRQs after this point
+	 * as GPIOs used behind I2C subsystem might not be
+	 * accessible until resume completes. So disable IRQ.
+	 */
+	disable_irq(info->id_irq);
+
+	return 0;
+}
+
+static int usb_extcon_resume(struct device *dev)
+{
+	struct usb_extcon_info *info = dev_get_drvdata(dev);
+
+	if (info->id_irqwake) {
+		disable_irq_wake(info->id_irq);
+		info->id_irqwake = false;
+	}
+
+	enable_irq(info->id_irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(usb_extcon_pm_ops,
+			 usb_extcon_suspend, usb_extcon_resume);
+
+static struct of_device_id usb_extcon_dt_match[] = {
+	{ .compatible = "linux,extcon-usb-gpio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
+
+static struct platform_driver usb_extcon_driver = {
+	.probe		= usb_extcon_probe,
+	.remove		= usb_extcon_remove,
+	.driver		= {
+		.name	= "extcon-usb-gpio",
+		.pm	= &usb_extcon_pm_ops,
+		.of_match_table = usb_extcon_dt_match,
+	},
+};
+
+module_platform_driver(usb_extcon_driver);
+
+MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
+MODULE_DESCRIPTION("USB GPIO extcon driver");
+MODULE_LICENSE("GPL v2");