[x86] add rootwait option to the kernel command line (#6209)
[openwrt.git] / target / linux / s3c24xx / patches-2.6.31 / 100-udc-poll-vbus.patch
1 From 6d17298d12f873a9b03e5e79ab745fda75bd5b4e Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Tue, 21 Jul 2009 12:51:33 +0200
4 Subject: [PATCH] 100-udc-poll-vbus.patch
5
6 ---
7  arch/arm/plat-s3c24xx/include/plat/udc.h |    1 +
8  drivers/usb/gadget/s3c2410_udc.c         |   38 ++++++++++++++++++++++
9  drivers/usb/host/ohci-s3c2410.c          |   50 ++++++++++++++++++++++++++++-
10  3 files changed, 87 insertions(+), 2 deletions(-)
11
12 diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h b/arch/arm/plat-s3c24xx/include/plat/udc.h
13 index 546bb40..763aeba 100644
14 --- a/arch/arm/plat-s3c24xx/include/plat/udc.h
15 +++ b/arch/arm/plat-s3c24xx/include/plat/udc.h
16 @@ -27,6 +27,7 @@ enum s3c2410_udc_cmd_e {
17  struct s3c2410_udc_mach_info {
18         void    (*udc_command)(enum s3c2410_udc_cmd_e);
19         void    (*vbus_draw)(unsigned int ma);
20 +       int     (*get_vbus_status)(void);
21         unsigned int vbus_pin;
22         unsigned char vbus_pin_inverted;
23  };
24 diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
25 index a9b452f..1c7e5d7 100644
26 --- a/drivers/usb/gadget/s3c2410_udc.c
27 +++ b/drivers/usb/gadget/s3c2410_udc.c
28 @@ -73,6 +73,7 @@ static void __iomem           *base_addr;
29  static u64                     rsrc_start;
30  static u64                     rsrc_len;
31  static struct dentry           *s3c2410_udc_debugfs_root;
32 +static struct timer_list       vbus_poll_timer;
33  
34  static inline u32 udc_read(u32 reg)
35  {
36 @@ -133,6 +134,8 @@ static int dprintk(int level, const char *fmt, ...)
37         return 0;
38  }
39  #endif
40 +
41 +#ifdef CONFIG_USB_GADGET_DEBUG_FS
42  static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
43  {
44         u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
45 @@ -196,6 +199,7 @@ static const struct file_operations s3c2410_udc_debugfs_fops = {
46         .release        = single_release,
47         .owner          = THIS_MODULE,
48  };
49 +#endif
50  
51  /* io macros */
52  
53 @@ -842,6 +846,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
54         u32                     ep_csr1;
55         u32                     idx;
56  
57 +handle_ep_again:
58         if (likely (!list_empty(&ep->queue)))
59                 req = list_entry(ep->queue.next,
60                                 struct s3c2410_request, queue);
61 @@ -881,6 +886,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
62  
63                 if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
64                         s3c2410_udc_read_fifo(ep,req);
65 +                       if (s3c2410_udc_fifo_count_out())
66 +                               goto handle_ep_again;
67                 }
68         }
69  }
70 @@ -1519,6 +1526,20 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
71         return IRQ_HANDLED;
72  }
73  
74 +static void s3c2410_udc_vbus_poll(unsigned long _data)
75 +{
76 +       struct s3c2410_udc      *data = (struct s3c2410_udc *)_data;
77 +       int                     v;
78 +
79 +       dprintk(DEBUG_NORMAL, "%s()\n", __func__);
80 +       if (udc_info && udc_info->get_vbus_status) {
81 +               v = udc_info->get_vbus_status();
82 +               if ((v > -1) && (v != data->vbus))
83 +                       s3c2410_udc_vbus_session(&data->gadget, v);
84 +               mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(900));
85 +       }
86 +}
87 +
88  static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
89  {
90         dprintk(DEBUG_NORMAL, "%s()\n", __func__);
91 @@ -1676,6 +1697,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
92                 goto register_error;
93         }
94  
95 +       if (udc_info && udc_info->get_vbus_status && !udc_info->vbus_pin) {
96 +               mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(50));
97 +               return 0; /* just return, vbus change will enable udc */
98 +       }
99 +
100         /* Enable udc */
101         s3c2410_udc_enable(udc);
102  
103 @@ -1706,6 +1732,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
104         if (driver->disconnect)
105                 driver->disconnect(&udc->gadget);
106  
107 +       driver->unbind(&udc->gadget);
108         device_del(&udc->gadget.dev);
109         udc->driver = NULL;
110  
111 @@ -1892,10 +1919,16 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
112                 }
113  
114                 dev_dbg(dev, "got irq %i\n", irq);
115 +       } else if (udc_info && udc_info->get_vbus_status) {
116 +               udc->vbus = 0;
117 +               init_timer(&vbus_poll_timer);
118 +               vbus_poll_timer.function = s3c2410_udc_vbus_poll;
119 +               vbus_poll_timer.data = (unsigned long) udc;
120         } else {
121                 udc->vbus = 1;
122         }
123  
124 +#ifdef CONFIG_USB_GADGET_DEBUG_FS
125         if (s3c2410_udc_debugfs_root) {
126                 udc->regs_info = debugfs_create_file("registers", S_IRUGO,
127                                 s3c2410_udc_debugfs_root,
128 @@ -1903,6 +1936,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
129                 if (!udc->regs_info)
130                         dev_warn(dev, "debugfs file creation failed\n");
131         }
132 +#endif
133  
134         dev_dbg(dev, "probe ok\n");
135  
136 @@ -1938,6 +1972,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
137         if (udc_info && udc_info->vbus_pin > 0) {
138                 irq = gpio_to_irq(udc_info->vbus_pin);
139                 free_irq(irq, udc);
140 +       } else if (udc_info && udc_info->get_vbus_status) {
141 +               del_timer_sync(&vbus_poll_timer);
142         }
143  
144         free_irq(IRQ_USBD, udc);
145 @@ -2012,12 +2048,14 @@ static int __init udc_init(void)
146  
147         dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
148  
149 +#ifdef CONFIG_USB_GADGET_DEBUG_FS
150         s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
151         if (IS_ERR(s3c2410_udc_debugfs_root)) {
152                 printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
153                         gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
154                 s3c2410_udc_debugfs_root = NULL;
155         }
156 +#endif
157  
158         retval = platform_driver_register(&udc_driver_2410);
159         if (retval)
160 diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
161 index a68af2d..3b85d41 100644
162 --- a/drivers/usb/host/ohci-s3c2410.c
163 +++ b/drivers/usb/host/ohci-s3c2410.c
164 @@ -21,6 +21,8 @@
165  
166  #include <linux/platform_device.h>
167  #include <linux/clk.h>
168 +#include <mach/gpio-fns.h>
169 +#include <mach/regs-gpio.h>
170  #include <plat/usb-control.h>
171  
172  #define valid_port(idx) ((idx) == 1 || (idx) == 2)
173 @@ -306,6 +308,42 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
174         local_irq_restore(flags);
175  }
176  
177 +/* switching of USB pads */
178 +static ssize_t show_usb_mode(struct device *dev, struct device_attribute *attr,
179 +                            char *buf)
180 +{
181 +       if (__raw_readl(S3C24XX_MISCCR) & S3C2410_MISCCR_USBHOST)
182 +               return sprintf(buf, "host\n");
183 +
184 +       return sprintf(buf, "device\n");
185 +}
186 +
187 +static ssize_t set_usb_mode(struct device *dev, struct device_attribute *attr,
188 +                           const char *buf, size_t count)
189 +{
190 +       if (!strncmp(buf, "host", 4)) {
191 +               printk(KERN_WARNING "s3c2410: changing usb to host\n");
192 +               s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST,
193 +                                     S3C2410_MISCCR_USBHOST);
194 +               /* FIXME:
195 +                * - call machine-specific disable-pullup function i
196 +                * - enable +Vbus (if hardware supports it)
197 +                */
198 +               s3c2410_gpio_setpin(S3C2410_GPB(9), 0);
199 +       } else if (!strncmp(buf, "device", 6)) {
200 +               printk(KERN_WARNING "s3c2410: changing usb to device\n");
201 +               s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, 0);
202 +               s3c2410_gpio_setpin(S3C2410_GPB(9), 1);
203 +       } else {
204 +               printk(KERN_WARNING "s3c2410: unknown mode\n");
205 +               return -EINVAL;
206 +       }
207 +
208 +       return count;
209 +}
210 +
211 +static DEVICE_ATTR(usb_mode, S_IRUGO | S_IWUSR, show_usb_mode, set_usb_mode);
212 +
213  /* may be called without controller electrically present */
214  /* may be called with controller, bus, and devices active */
215  
216 @@ -486,15 +524,23 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
217         return 0;
218  }
219  
220 +static int ohci_hcd_s3c2410_drv_resume(struct platform_device *pdev)
221 +{
222 +       struct usb_hcd *hcd = platform_get_drvdata(pdev);
223 +
224 +       ohci_finish_controller_resume(hcd);
225 +       return 0;
226 +}
227 +
228  static struct platform_driver ohci_hcd_s3c2410_driver = {
229         .probe          = ohci_hcd_s3c2410_drv_probe,
230         .remove         = ohci_hcd_s3c2410_drv_remove,
231         .shutdown       = usb_hcd_platform_shutdown,
232         /*.suspend      = ohci_hcd_s3c2410_drv_suspend, */
233 -       /*.resume       = ohci_hcd_s3c2410_drv_resume, */
234 +       .resume         = ohci_hcd_s3c2410_drv_resume,
235         .driver         = {
236                 .owner  = THIS_MODULE,
237 -               .name   = "s3c2410-ohci",
238 +               .name   = "s3c-ohci",
239         },
240  };
241  
242 -- 
243 1.5.6.5
244