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