Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/usb/gadget/pch_udc.c | 145 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 01ff48d..d77211c 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -15,6 +15,13 @@
#include <linux/interrupt.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/gpio.h>
+
+/* GPIO port for VBUS detecting */
+static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */
+
+#define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */
+#define PCH_VBUS_INTERVAL 10 /* VBUS polling interval (msec) */
/* Address offset of Registers */
#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */
@@ -296,6 +303,17 @@ struct pch_udc_ep {
};
/**
+ * struct pch_vbus_gpio_data - Structure holding GPIO informaton
+ * for detecting VBUS
+ * @port: gpio port number
+ * @irq_work_fall Structure for WorkQueue
+ */
+struct pch_vbus_gpio_data {
+ int port;
+ struct work_struct irq_work_fall;
+};
+
+/**
* struct pch_udc_dev - Structure holding complete information
* of the PCH USB device
* @gadget: gadget driver data
@@ -323,6 +341,7 @@ struct pch_udc_ep {
* @base_addr: for mapped device memory
* @irq: IRQ line for the device
* @cfg_data: current cfg, intf, and alt in use
+ * @vbus_gpio: GPIO informaton for detecting VBUS
*/
struct pch_udc_dev {
struct usb_gadget gadget;
@@ -349,7 +368,8 @@ struct pch_udc_dev {
unsigned long phys_addr;
void __iomem *base_addr;
unsigned irq;
- struct pch_udc_cfg_data cfg_data;
+ struct pch_udc_cfg_data cfg_data;
+ struct pch_vbus_gpio_data vbus_gpio;
};
#define PCH_UDC_PCI_BAR 1
@@ -1226,6 +1246,115 @@ static const struct usb_gadget_ops pch_udc_ops = {
};
/**
+ * pch_vbus_gpio_get_value() - This API gets value of GPIO port as VBUS status.
+ * @dev: Reference to the driver structure
+ *
+ * Return value:
+ * 1: VBUS is high
+ * 0: VBUS is low
+ * -1: It is not enable to detect VBUS using GPIO
+ */
+static int pch_vbus_gpio_get_value(struct pch_udc_dev *dev)
+{
+ int vbus = 0;
+
+ if (dev->vbus_gpio.port)
+ vbus = gpio_get_value(dev->vbus_gpio.port) ? 1 : 0;
+ else
+ vbus = -1;
+
+ return vbus;
+}
+
+/**
+ * pch_vbus_gpio_work_fall() - This API keeps watch on VBUS becoming Low.
+ * If VBUS is Low, disconnect is processed
+ * @irq_work: Structure for WorkQueue
+ *
+ */
+static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
+{
+ struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
+ struct pch_vbus_gpio_data, irq_work_fall);
+ struct pch_udc_dev *dev =
+ container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
+ int vbus_saved = -1;
+ int vbus;
+ int count;
+
+ if (!dev->vbus_gpio.port)
+ return;
+
+ for (count = 0; count < (PCH_VBUS_PERIOD / PCH_VBUS_INTERVAL);
+ count++) {
+ vbus = pch_vbus_gpio_get_value(dev);
+
+ if ((vbus_saved == vbus) && (vbus == 0)) {
+ dev_dbg(&dev->pdev->dev, "VBUS fell");
+ if (dev->driver
+ && dev->driver->disconnect) {
+ dev->driver->disconnect(
+ &dev->gadget);
+ }
+ pch_udc_reconnect(dev);
+ dev_dbg(&dev->pdev->dev, "VBUS fell");
+ return;
+ }
+ vbus_saved = vbus;
+ mdelay(PCH_VBUS_INTERVAL);
+ }
+}
+
+/**
+ * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
+ * @dev: Reference to the driver structure
+ * @vbus_gpio Number of GPIO port to detect gpio
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: GPIO port is invalid or can't be initialized.
+ */
+static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
+{
+ int err;
+
+ dev->vbus_gpio.port = 0;
+
+ if (vbus_gpio_port <= -1)
+ return -EINVAL;
+
+ err = gpio_is_valid(vbus_gpio_port);
+ if (!err) {
+ pr_err("%s: gpio port %d is invalid\n",
+ __func__, vbus_gpio_port);
+ return -EINVAL;
+ }
+
+ err = gpio_request(vbus_gpio_port, "pch_vbus");
+ if (err) {
+ pr_err("%s: can't request gpio port %d, err: %d\n",
+ __func__, vbus_gpio_port, err);
+ return -EINVAL;
+ }
+
+ dev->vbus_gpio.port = vbus_gpio_port;
+ gpio_direction_input(vbus_gpio_port);
+ INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall);
+
+ return 0;
+}
+
+/**
+ * pch_vbus_gpio_free() - This API frees resources of GPIO port
+ * @dev: Reference to the driver structure
+ */
+static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
+{
+ if (dev->vbus_gpio.port)
+ gpio_free(dev->vbus_gpio.port);
+}
+
+/**
* complete_req() - This API is invoked from the driver when processing
* of a request is complete
* @ep: Reference to the endpoint structure
@@ -2510,6 +2639,8 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
*/
static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
{
+ int vbus;
+
/* USB Reset Interrupt */
if (dev_intr & UDC_DEVINT_UR) {
pch_udc_svc_ur_interrupt(dev);
@@ -2535,14 +2666,19 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
spin_lock(&dev->lock);
}
- if (dev->vbus_session == 0) {
+ vbus = pch_vbus_gpio_get_value(dev);
+ if ((dev->vbus_session == 0)
+ && (vbus != 1)) {
if (dev->driver && dev->driver->disconnect) {
spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
pch_udc_reconnect(dev);
- }
+ } else if ((dev->vbus_session == 0)
+ && (vbus == 1))
+ schedule_work(&dev->vbus_gpio.irq_work_fall);
+
dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
}
/* Clear the SOF interrupt, if enabled */
@@ -2704,6 +2840,7 @@ static int pch_udc_pcd_init(struct pch_udc_dev *dev)
{
pch_udc_init(dev);
pch_udc_pcd_reinit(dev);
+ pch_vbus_gpio_init(dev, vbus_gpio_port);
return 0;
}
@@ -2882,6 +3019,8 @@ static void pch_udc_remove(struct pci_dev *pdev)
UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
kfree(dev->ep0out_buf);
+ pch_vbus_gpio_free(dev);
+
pch_udc_exit(dev);
if (dev->irq_registered)
--
1.7.7.6
Problem:
pch_udc continues operation even if VBUS becomes Low.
pch_udc performs D+ pulling up before VBUS becomes High.
USB device should be controlled according to VBUS state.
Root cause:
The current pch_udc is not always monitoring VBUS.
Solution:
The change of VBUS is detected using an interrupt of GPIO.
If VBUS became Low, pch_udc handles 'disconnect'.
After VBUS became High, a pull improves D+, and pch_udc
handles 'connect'.
Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/usb/gadget/pch_udc.c | 85 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 82 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index d77211c..942fe92 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -306,11 +306,15 @@ struct pch_udc_ep {
* struct pch_vbus_gpio_data - Structure holding GPIO informaton
* for detecting VBUS
* @port: gpio port number
+ * @intr: gpio interrupt number
* @irq_work_fall Structure for WorkQueue
+ * @irq_work_rise Structure for WorkQueue
*/
struct pch_vbus_gpio_data {
int port;
+ int intr;
struct work_struct irq_work_fall;
+ struct work_struct irq_work_rise;
};
/**
@@ -1296,8 +1300,10 @@ static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
dev->driver->disconnect(
&dev->gadget);
}
- pch_udc_reconnect(dev);
- dev_dbg(&dev->pdev->dev, "VBUS fell");
+ if (dev->vbus_gpio.intr)
+ pch_udc_init(dev);
+ else
+ pch_udc_reconnect(dev);
return;
}
vbus_saved = vbus;
@@ -1306,6 +1312,57 @@ static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
}
/**
+ * pch_vbus_gpio_work_rise() - This API checks VBUS is High.
+ * If VBUS is High, connect is processed
+ * @irq_work: Structure for WorkQueue
+ *
+ */
+static void pch_vbus_gpio_work_rise(struct work_struct *irq_work)
+{
+ struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
+ struct pch_vbus_gpio_data, irq_work_rise);
+ struct pch_udc_dev *dev =
+ container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
+ int vbus;
+
+ if (!dev->vbus_gpio.port)
+ return;
+
+ mdelay(PCH_VBUS_INTERVAL);
+ vbus = pch_vbus_gpio_get_value(dev);
+
+ if (vbus == 1) {
+ dev_dbg(&dev->pdev->dev, "VBUS rose");
+ pch_udc_reconnect(dev);
+ return;
+ }
+}
+
+/**
+ * pch_vbus_gpio_irq() - IRQ handler for GPIO intrerrupt for changing VBUS
+ * @irq: Interrupt request number
+ * @dev: Reference to the device structure
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: GPIO port is invalid or can't be initialized.
+ */
+static irqreturn_t pch_vbus_gpio_irq(int irq, void *data)
+{
+ struct pch_udc_dev *dev = (struct pch_udc_dev *)data;
+
+ if (!dev->vbus_gpio.port || !dev->vbus_gpio.intr)
+ return IRQ_NONE;
+
+ if (pch_vbus_gpio_get_value(dev))
+ schedule_work(&dev->vbus_gpio.irq_work_rise);
+ else
+ schedule_work(&dev->vbus_gpio.irq_work_fall);
+
+ return IRQ_HANDLED;
+}
+
+/**
* pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
* @dev: Reference to the driver structure
* @vbus_gpio Number of GPIO port to detect gpio
@@ -1317,8 +1374,10 @@ static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
{
int err;
+ int irq_num = 0;
dev->vbus_gpio.port = 0;
+ dev->vbus_gpio.intr = 0;
if (vbus_gpio_port <= -1)
return -EINVAL;
@@ -1341,6 +1400,21 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
gpio_direction_input(vbus_gpio_port);
INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall);
+ irq_num = gpio_to_irq(vbus_gpio_port);
+ if (irq_num > 0) {
+ irq_set_irq_type(irq_num, IRQ_TYPE_EDGE_BOTH);
+ err = request_irq(irq_num, pch_vbus_gpio_irq, 0,
+ "vbus_detect", dev);
+ if (!err) {
+ dev->vbus_gpio.intr = irq_num;
+ INIT_WORK(&dev->vbus_gpio.irq_work_rise,
+ pch_vbus_gpio_work_rise);
+ } else {
+ pr_err("%s: can't request irq %d, err: %d\n",
+ __func__, irq_num, err);
+ }
+ }
+
return 0;
}
@@ -1350,6 +1424,9 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
*/
static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
{
+ if (dev->vbus_gpio.intr)
+ free_irq(dev->vbus_gpio.intr, dev);
+
if (dev->vbus_gpio.port)
gpio_free(dev->vbus_gpio.port);
}
@@ -2677,6 +2754,7 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
pch_udc_reconnect(dev);
} else if ((dev->vbus_session == 0)
&& (vbus == 1))
+ &&!dev->vbus_gpio.intr)
schedule_work(&dev->vbus_gpio.irq_work_fall);
dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
@@ -2941,7 +3019,8 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
pch_udc_setup_ep0(dev);
/* clear SD */
- pch_udc_clear_disconnect(dev);
+ if ((pch_vbus_gpio_get_value(dev) != 0) || !dev->vbus_gpio.intr)
+ pch_udc_clear_disconnect(dev);
dev->connected = 1;
return 0;
--
1.7.7.6
Problem:
The GPIO ports used for detecting VBUS may be different
on each platform.
This should be easily modifiable.
Solution:
In configuration, GPI port number is specified.
Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/usb/gadget/Kconfig | 12 ++++++++++++
drivers/usb/gadget/pch_udc.c | 2 +-
2 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 23a4473..cd0ec15 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -491,6 +491,18 @@ config USB_EG20T
ML7213/ML7831 is companion chip for Intel Atom E6xx series.
ML7213/ML7831 is completely compatible for Intel EG20T PCH.
+config USB_VBUS_GPIO_PORT
+ int "GPIO pin used for detecting VBUS"
+ depends on USB_EG20T
+ default "-1"
+ help
+ Enter the GPIO port number used for detecting VBUS state.
+ If not used, specify -1(default).
+
+ If not used, this driver does not support USB suspend state.
+ If the GPIO port number that VBUS is not connected to is specified,
+ the USB device may not work.
+
config USB_CI13XXX_MSM
tristate "MIPS USB CI13xxx for MSM"
depends on ARCH_MSM
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 942fe92..44a86fc 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -18,7 +18,7 @@
#include <linux/gpio.h>
/* GPIO port for VBUS detecting */
-static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */
+static int vbus_gpio_port = CONFIG_USB_VBUS_GPIO_PORT;
#define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */
#define PCH_VBUS_INTERVAL 10 /* VBUS polling interval (msec) */
--
1.7.7.6
Hello.
On 03-02-2012 11:14, Tomoya MORINAGA wrote:
> Problem:
> The GPIO ports used for detecting VBUS may be different
> on each platform.
> This should be easily modifiable.
> Solution:
> In configuration, GPI port number is specified.
Isn't it better to pass this with driver's platform data.
> Signed-off-by: Tomoya MORINAGA <[email protected]>
WBR, Sergei
On Fri, Feb 03, 2012 at 02:50:02PM +0400, Sergei Shtylyov wrote:
> Hello.
>
> On 03-02-2012 11:14, Tomoya MORINAGA wrote:
>
> >Problem:
> > The GPIO ports used for detecting VBUS may be different
> > on each platform.
> > This should be easily modifiable.
> >Solution:
> > In configuration, GPI port number is specified.
>
> Isn't it better to pass this with driver's platform data.
Yes, please re-factor this port. This doesn't fit as a compile-time
choice.
--
balbi
On Fri, Feb 03, 2012 at 04:14:18PM +0900, Tomoya MORINAGA wrote:
> Problem:
> pch_udc continues operation even if VBUS becomes Low.
> pch_udc performs D+ pulling up before VBUS becomes High.
> USB device should be controlled according to VBUS state.
>
> Root cause:
> The current pch_udc is not always monitoring VBUS.
>
> Solution:
> The change of VBUS is detected using an interrupt of GPIO.
> If VBUS became Low, pch_udc handles 'disconnect'.
> After VBUS became High, a pull improves D+, and pch_udc
> handles 'connect'.
>
> Signed-off-by: Tomoya MORINAGA <[email protected]>
> ---
> drivers/usb/gadget/pch_udc.c | 85 ++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 82 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
> index d77211c..942fe92 100644
> --- a/drivers/usb/gadget/pch_udc.c
> +++ b/drivers/usb/gadget/pch_udc.c
> @@ -306,11 +306,15 @@ struct pch_udc_ep {
> * struct pch_vbus_gpio_data - Structure holding GPIO informaton
> * for detecting VBUS
> * @port: gpio port number
> + * @intr: gpio interrupt number
> * @irq_work_fall Structure for WorkQueue
> + * @irq_work_rise Structure for WorkQueue
> */
> struct pch_vbus_gpio_data {
> int port;
> + int intr;
> struct work_struct irq_work_fall;
> + struct work_struct irq_work_rise;
> };
>
> /**
> @@ -1296,8 +1300,10 @@ static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
> dev->driver->disconnect(
> &dev->gadget);
> }
> - pch_udc_reconnect(dev);
> - dev_dbg(&dev->pdev->dev, "VBUS fell");
> + if (dev->vbus_gpio.intr)
> + pch_udc_init(dev);
> + else
> + pch_udc_reconnect(dev);
> return;
> }
> vbus_saved = vbus;
> @@ -1306,6 +1312,57 @@ static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
> }
>
> /**
> + * pch_vbus_gpio_work_rise() - This API checks VBUS is High.
> + * If VBUS is High, connect is processed
> + * @irq_work: Structure for WorkQueue
> + *
> + */
> +static void pch_vbus_gpio_work_rise(struct work_struct *irq_work)
> +{
> + struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
> + struct pch_vbus_gpio_data, irq_work_rise);
> + struct pch_udc_dev *dev =
> + container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
> + int vbus;
> +
> + if (!dev->vbus_gpio.port)
> + return;
> +
> + mdelay(PCH_VBUS_INTERVAL);
> + vbus = pch_vbus_gpio_get_value(dev);
> +
> + if (vbus == 1) {
> + dev_dbg(&dev->pdev->dev, "VBUS rose");
> + pch_udc_reconnect(dev);
> + return;
> + }
> +}
> +
> +/**
> + * pch_vbus_gpio_irq() - IRQ handler for GPIO intrerrupt for changing VBUS
> + * @irq: Interrupt request number
> + * @dev: Reference to the device structure
> + *
> + * Return codes:
> + * 0: Success
> + * -EINVAL: GPIO port is invalid or can't be initialized.
> + */
> +static irqreturn_t pch_vbus_gpio_irq(int irq, void *data)
> +{
> + struct pch_udc_dev *dev = (struct pch_udc_dev *)data;
> +
> + if (!dev->vbus_gpio.port || !dev->vbus_gpio.intr)
> + return IRQ_NONE;
> +
> + if (pch_vbus_gpio_get_value(dev))
> + schedule_work(&dev->vbus_gpio.irq_work_rise);
> + else
> + schedule_work(&dev->vbus_gpio.irq_work_fall);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
> * @dev: Reference to the driver structure
> * @vbus_gpio Number of GPIO port to detect gpio
> @@ -1317,8 +1374,10 @@ static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
> static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
> {
> int err;
> + int irq_num = 0;
>
> dev->vbus_gpio.port = 0;
> + dev->vbus_gpio.intr = 0;
>
> if (vbus_gpio_port <= -1)
> return -EINVAL;
> @@ -1341,6 +1400,21 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
> gpio_direction_input(vbus_gpio_port);
> INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall);
>
> + irq_num = gpio_to_irq(vbus_gpio_port);
> + if (irq_num > 0) {
> + irq_set_irq_type(irq_num, IRQ_TYPE_EDGE_BOTH);
> + err = request_irq(irq_num, pch_vbus_gpio_irq, 0,
> + "vbus_detect", dev);
> + if (!err) {
> + dev->vbus_gpio.intr = irq_num;
> + INIT_WORK(&dev->vbus_gpio.irq_work_rise,
> + pch_vbus_gpio_work_rise);
> + } else {
> + pr_err("%s: can't request irq %d, err: %d\n",
> + __func__, irq_num, err);
> + }
> + }
> +
> return 0;
> }
>
> @@ -1350,6 +1424,9 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
> */
> static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
> {
> + if (dev->vbus_gpio.intr)
> + free_irq(dev->vbus_gpio.intr, dev);
> +
> if (dev->vbus_gpio.port)
> gpio_free(dev->vbus_gpio.port);
> }
> @@ -2677,6 +2754,7 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
> pch_udc_reconnect(dev);
> } else if ((dev->vbus_session == 0)
> && (vbus == 1))
> + &&!dev->vbus_gpio.intr)
This causes a compile error which I have fixed this time. Next time I
will silently drop the patch:
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index fb74cc8..a992084 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -2753,8 +2753,8 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
}
pch_udc_reconnect(dev);
} else if ((dev->vbus_session == 0)
- && (vbus == 1))
- &&!dev->vbus_gpio.intr)
+ && (vbus == 1)
+ && !dev->vbus_gpio.intr)
schedule_work(&dev->vbus_gpio.irq_work_fall);
dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
--
balbi
On Fri, Feb 03, 2012 at 04:14:18PM +0900, Tomoya MORINAGA wrote:
> Problem:
> pch_udc continues operation even if VBUS becomes Low.
> pch_udc performs D+ pulling up before VBUS becomes High.
> USB device should be controlled according to VBUS state.
>
> Root cause:
> The current pch_udc is not always monitoring VBUS.
>
> Solution:
> The change of VBUS is detected using an interrupt of GPIO.
> If VBUS became Low, pch_udc handles 'disconnect'.
> After VBUS became High, a pull improves D+, and pch_udc
> handles 'connect'.
>
> Signed-off-by: Tomoya MORINAGA <[email protected]>
applied my fixed version
thanks
--
balbi
2012年2月3日19:50 Sergei Shtylyov <[email protected]>:
> Isn't it better to pass this with driver's platform data.
To define GPIO port number, we must I'm supporting IntelCrown Bay
platform (Intel AtomE600 + PCH EG20T).
I made an initialization code(attached) for the Crown Bay platform.
Should I post this module to upstream? I need your advice.
If I should do, could you tell me which category we should put
it?
---
ROHM Co., Ltd.
tomoya