aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch')
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch244
1 files changed, 244 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch b/target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch
new file mode 100644
index 0000000000..7b2b9b25ae
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch
@@ -0,0 +1,244 @@
+From 6d17298d12f873a9b03e5e79ab745fda75bd5b4e Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:51:33 +0200
+Subject: [PATCH] 100-udc-poll-vbus.patch
+
+---
+ arch/arm/plat-s3c24xx/include/plat/udc.h | 1 +
+ drivers/usb/gadget/s3c2410_udc.c | 38 ++++++++++++++++++++++
+ drivers/usb/host/ohci-s3c2410.c | 50 ++++++++++++++++++++++++++++-
+ 3 files changed, 87 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h b/arch/arm/plat-s3c24xx/include/plat/udc.h
+index 546bb40..763aeba 100644
+--- a/arch/arm/plat-s3c24xx/include/plat/udc.h
++++ b/arch/arm/plat-s3c24xx/include/plat/udc.h
+@@ -27,6 +27,7 @@ enum s3c2410_udc_cmd_e {
+ struct s3c2410_udc_mach_info {
+ void (*udc_command)(enum s3c2410_udc_cmd_e);
+ void (*vbus_draw)(unsigned int ma);
++ int (*get_vbus_status)(void);
+ unsigned int vbus_pin;
+ unsigned char vbus_pin_inverted;
+ };
+diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
+index a9b452f..1c7e5d7 100644
+--- a/drivers/usb/gadget/s3c2410_udc.c
++++ b/drivers/usb/gadget/s3c2410_udc.c
+@@ -73,6 +73,7 @@ static void __iomem *base_addr;
+ static u64 rsrc_start;
+ static u64 rsrc_len;
+ static struct dentry *s3c2410_udc_debugfs_root;
++static struct timer_list vbus_poll_timer;
+
+ static inline u32 udc_read(u32 reg)
+ {
+@@ -133,6 +134,8 @@ static int dprintk(int level, const char *fmt, ...)
+ return 0;
+ }
+ #endif
++
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
+ {
+ u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+@@ -196,6 +199,7 @@ static const struct file_operations s3c2410_udc_debugfs_fops = {
+ .release = single_release,
+ .owner = THIS_MODULE,
+ };
++#endif
+
+ /* io macros */
+
+@@ -842,6 +846,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+ u32 ep_csr1;
+ u32 idx;
+
++handle_ep_again:
+ if (likely (!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct s3c2410_request, queue);
+@@ -881,6 +886,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+
+ if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
+ s3c2410_udc_read_fifo(ep,req);
++ if (s3c2410_udc_fifo_count_out())
++ goto handle_ep_again;
+ }
+ }
+ }
+@@ -1519,6 +1526,20 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
+ return IRQ_HANDLED;
+ }
+
++static void s3c2410_udc_vbus_poll(unsigned long _data)
++{
++ struct s3c2410_udc *data = (struct s3c2410_udc *)_data;
++ int v;
++
++ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
++ if (udc_info && udc_info->get_vbus_status) {
++ v = udc_info->get_vbus_status();
++ if ((v > -1) && (v != data->vbus))
++ s3c2410_udc_vbus_session(&data->gadget, v);
++ mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(900));
++ }
++}
++
+ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
+ {
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+@@ -1676,6 +1697,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+ goto register_error;
+ }
+
++ if (udc_info && udc_info->get_vbus_status && !udc_info->vbus_pin) {
++ mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(50));
++ return 0; /* just return, vbus change will enable udc */
++ }
++
+ /* Enable udc */
+ s3c2410_udc_enable(udc);
+
+@@ -1706,6 +1732,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+ if (driver->disconnect)
+ driver->disconnect(&udc->gadget);
+
++ driver->unbind(&udc->gadget);
+ device_del(&udc->gadget.dev);
+ udc->driver = NULL;
+
+@@ -1892,10 +1919,16 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
+ }
+
+ dev_dbg(dev, "got irq %i\n", irq);
++ } else if (udc_info && udc_info->get_vbus_status) {
++ udc->vbus = 0;
++ init_timer(&vbus_poll_timer);
++ vbus_poll_timer.function = s3c2410_udc_vbus_poll;
++ vbus_poll_timer.data = (unsigned long) udc;
+ } else {
+ udc->vbus = 1;
+ }
+
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ if (s3c2410_udc_debugfs_root) {
+ udc->regs_info = debugfs_create_file("registers", S_IRUGO,
+ s3c2410_udc_debugfs_root,
+@@ -1903,6 +1936,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
+ if (!udc->regs_info)
+ dev_warn(dev, "debugfs file creation failed\n");
+ }
++#endif
+
+ dev_dbg(dev, "probe ok\n");
+
+@@ -1938,6 +1972,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
+ if (udc_info && udc_info->vbus_pin > 0) {
+ irq = gpio_to_irq(udc_info->vbus_pin);
+ free_irq(irq, udc);
++ } else if (udc_info && udc_info->get_vbus_status) {
++ del_timer_sync(&vbus_poll_timer);
+ }
+
+ free_irq(IRQ_USBD, udc);
+@@ -2012,12 +2048,14 @@ static int __init udc_init(void)
+
+ dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
+ if (IS_ERR(s3c2410_udc_debugfs_root)) {
+ printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
+ gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
+ s3c2410_udc_debugfs_root = NULL;
+ }
++#endif
+
+ retval = platform_driver_register(&udc_driver_2410);
+ if (retval)
+diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
+index a68af2d..3b85d41 100644
+--- a/drivers/usb/host/ohci-s3c2410.c
++++ b/drivers/usb/host/ohci-s3c2410.c
+@@ -21,6 +21,8 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
++#include <mach/gpio-fns.h>
++#include <mach/regs-gpio.h>
+ #include <plat/usb-control.h>
+
+ #define valid_port(idx) ((idx) == 1 || (idx) == 2)
+@@ -306,6 +308,42 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
+ local_irq_restore(flags);
+ }
+
++/* switching of USB pads */
++static ssize_t show_usb_mode(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ if (__raw_readl(S3C24XX_MISCCR) & S3C2410_MISCCR_USBHOST)
++ return sprintf(buf, "host\n");
++
++ return sprintf(buf, "device\n");
++}
++
++static ssize_t set_usb_mode(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ if (!strncmp(buf, "host", 4)) {
++ printk(KERN_WARNING "s3c2410: changing usb to host\n");
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST,
++ S3C2410_MISCCR_USBHOST);
++ /* FIXME:
++ * - call machine-specific disable-pullup function i
++ * - enable +Vbus (if hardware supports it)
++ */
++ s3c2410_gpio_setpin(S3C2410_GPB(9), 0);
++ } else if (!strncmp(buf, "device", 6)) {
++ printk(KERN_WARNING "s3c2410: changing usb to device\n");
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, 0);
++ s3c2410_gpio_setpin(S3C2410_GPB(9), 1);
++ } else {
++ printk(KERN_WARNING "s3c2410: unknown mode\n");
++ return -EINVAL;
++ }
++
++ return count;
++}
++
++static DEVICE_ATTR(usb_mode, S_IRUGO | S_IWUSR, show_usb_mode, set_usb_mode);
++
+ /* may be called without controller electrically present */
+ /* may be called with controller, bus, and devices active */
+
+@@ -486,15 +524,23 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++static int ohci_hcd_s3c2410_drv_resume(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ ohci_finish_controller_resume(hcd);
++ return 0;
++}
++
+ static struct platform_driver ohci_hcd_s3c2410_driver = {
+ .probe = ohci_hcd_s3c2410_drv_probe,
+ .remove = ohci_hcd_s3c2410_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ohci_hcd_s3c2410_drv_suspend, */
+- /*.resume = ohci_hcd_s3c2410_drv_resume, */
++ .resume = ohci_hcd_s3c2410_drv_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+- .name = "s3c2410-ohci",
++ .name = "s3c-ohci",
+ },
+ };
+
+--
+1.5.6.5
+