1 /* 2 * Freescale QUICC Engine USB Host Controller Driver 3 * 4 * Copyright (c) Freescale Semicondutor, Inc. 2006. 5 * Shlomi Gridish <gridish@freescale.com> 6 * Jerry Huang <Chang-Ming.Huang@freescale.com> 7 * Copyright (c) Logic Product Development, Inc. 2007 8 * Peter Barada <peterb@logicpd.com> 9 * Copyright (c) MontaVista Software, Inc. 2008. 10 * Anton Vorontsov <avorontsov@ru.mvista.com> 11 * 12 * This program is free software; you can redistribute it and/or modify it 13 * under the terms of the GNU General Public License as published by the 14 * Free Software Foundation; either version 2 of the License, or (at your 15 * option) any later version. 16 */ 17 18 #include <linux/kernel.h> 19 #include <linux/types.h> 20 #include <linux/spinlock.h> 21 #include <linux/delay.h> 22 #include <linux/errno.h> 23 #include <linux/io.h> 24 #include <linux/usb.h> 25 #include <linux/usb/hcd.h> 26 #include <linux/gpio.h> 27 #include <asm/qe.h> 28 #include "fhci.h" 29 30 /* virtual root hub specific descriptor */ 31 static u8 root_hub_des[] = { 32 0x09, /* blength */ 33 0x29, /* bDescriptorType;hub-descriptor */ 34 0x01, /* bNbrPorts */ 35 0x00, /* wHubCharacteristics */ 36 0x00, 37 0x01, /* bPwrOn2pwrGood;2ms */ 38 0x00, /* bHubContrCurrent;0mA */ 39 0x00, /* DeviceRemoveable */ 40 0xff, /* PortPwrCtrlMask */ 41 }; 42 43 static void fhci_gpio_set_value(struct fhci_hcd *fhci, int gpio_nr, bool on) 44 { 45 int gpio = fhci->gpios[gpio_nr]; 46 bool alow = fhci->alow_gpios[gpio_nr]; 47 48 if (!gpio_is_valid(gpio)) 49 return; 50 51 gpio_set_value(gpio, on ^ alow); 52 mdelay(5); 53 } 54 55 void fhci_config_transceiver(struct fhci_hcd *fhci, 56 enum fhci_port_status status) 57 { 58 fhci_dbg(fhci, "-> %s: %d\n", __func__, status); 59 60 switch (status) { 61 case FHCI_PORT_POWER_OFF: 62 fhci_gpio_set_value(fhci, GPIO_POWER, false); 63 break; 64 case FHCI_PORT_DISABLED: 65 case FHCI_PORT_WAITING: 66 fhci_gpio_set_value(fhci, GPIO_POWER, true); 67 break; 68 case FHCI_PORT_LOW: 69 fhci_gpio_set_value(fhci, GPIO_SPEED, false); 70 break; 71 case FHCI_PORT_FULL: 72 fhci_gpio_set_value(fhci, GPIO_SPEED, true); 73 break; 74 default: 75 WARN_ON(1); 76 break; 77 } 78 79 fhci_dbg(fhci, "<- %s: %d\n", __func__, status); 80 } 81 82 /* disable the USB port by clearing the EN bit in the USBMOD register */ 83 void fhci_port_disable(struct fhci_hcd *fhci) 84 { 85 struct fhci_usb *usb = (struct fhci_usb *)fhci->usb_lld; 86 enum fhci_port_status port_status; 87 88 fhci_dbg(fhci, "-> %s\n", __func__); 89 90 fhci_stop_sof_timer(fhci); 91 92 fhci_flush_all_transmissions(usb); 93 94 fhci_usb_disable_interrupt((struct fhci_usb *)fhci->usb_lld); 95 port_status = usb->port_status; 96 usb->port_status = FHCI_PORT_DISABLED; 97 98 /* Enable IDLE since we want to know if something comes along */ 99 usb->saved_msk |= USB_E_IDLE_MASK; 100 out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk); 101 102 /* check if during the disconnection process attached new device */ 103 if (port_status == FHCI_PORT_WAITING) 104 fhci_device_connected_interrupt(fhci); 105 usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_ENABLE; 106 usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE; 107 fhci_usb_enable_interrupt((struct fhci_usb *)fhci->usb_lld); 108 109 fhci_dbg(fhci, "<- %s\n", __func__); 110 } 111 112 /* enable the USB port by setting the EN bit in the USBMOD register */ 113 void fhci_port_enable(void *lld) 114 { 115 struct fhci_usb *usb = (struct fhci_usb *)lld; 116 struct fhci_hcd *fhci = usb->fhci; 117 118 fhci_dbg(fhci, "-> %s\n", __func__); 119 120 fhci_config_transceiver(fhci, usb->port_status); 121 122 if ((usb->port_status != FHCI_PORT_FULL) && 123 (usb->port_status != FHCI_PORT_LOW)) 124 fhci_start_sof_timer(fhci); 125 126 usb->vroot_hub->port.wPortStatus |= USB_PORT_STAT_ENABLE; 127 usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE; 128 129 fhci_dbg(fhci, "<- %s\n", __func__); 130 } 131 132 void fhci_io_port_generate_reset(struct fhci_hcd *fhci) 133 { 134 fhci_dbg(fhci, "-> %s\n", __func__); 135 136 gpio_direction_output(fhci->gpios[GPIO_USBOE], 0); 137 gpio_direction_output(fhci->gpios[GPIO_USBTP], 0); 138 gpio_direction_output(fhci->gpios[GPIO_USBTN], 0); 139 140 mdelay(5); 141 142 qe_pin_set_dedicated(fhci->pins[PIN_USBOE]); 143 qe_pin_set_dedicated(fhci->pins[PIN_USBTP]); 144 qe_pin_set_dedicated(fhci->pins[PIN_USBTN]); 145 146 fhci_dbg(fhci, "<- %s\n", __func__); 147 } 148 149 /* generate the RESET condition on the bus */ 150 void fhci_port_reset(void *lld) 151 { 152 struct fhci_usb *usb = (struct fhci_usb *)lld; 153 struct fhci_hcd *fhci = usb->fhci; 154 u8 mode; 155 u16 mask; 156 157 fhci_dbg(fhci, "-> %s\n", __func__); 158 159 fhci_stop_sof_timer(fhci); 160 /* disable the USB controller */ 161 mode = in_8(&fhci->regs->usb_usmod); 162 out_8(&fhci->regs->usb_usmod, mode & (~USB_MODE_EN)); 163 164 /* disable idle interrupts */ 165 mask = in_be16(&fhci->regs->usb_usbmr); 166 out_be16(&fhci->regs->usb_usbmr, mask & (~USB_E_IDLE_MASK)); 167 168 fhci_io_port_generate_reset(fhci); 169 170 /* enable interrupt on this endpoint */ 171 out_be16(&fhci->regs->usb_usbmr, mask); 172 173 /* enable the USB controller */ 174 mode = in_8(&fhci->regs->usb_usmod); 175 out_8(&fhci->regs->usb_usmod, mode | USB_MODE_EN); 176 fhci_start_sof_timer(fhci); 177 178 fhci_dbg(fhci, "<- %s\n", __func__); 179 } 180 181 int fhci_hub_status_data(struct usb_hcd *hcd, char *buf) 182 { 183 struct fhci_hcd *fhci = hcd_to_fhci(hcd); 184 int ret = 0; 185 unsigned long flags; 186 187 fhci_dbg(fhci, "-> %s\n", __func__); 188 189 spin_lock_irqsave(&fhci->lock, flags); 190 191 if (fhci->vroot_hub->port.wPortChange & (USB_PORT_STAT_C_CONNECTION | 192 USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_SUSPEND | 193 USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_OVERCURRENT)) { 194 *buf = 1 << 1; 195 ret = 1; 196 fhci_dbg(fhci, "-- %s\n", __func__); 197 } 198 199 spin_unlock_irqrestore(&fhci->lock, flags); 200 201 fhci_dbg(fhci, "<- %s\n", __func__); 202 203 return ret; 204 } 205 206 int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, 207 u16 wIndex, char *buf, u16 wLength) 208 { 209 struct fhci_hcd *fhci = hcd_to_fhci(hcd); 210 int retval = 0; 211 int len = 0; 212 struct usb_hub_status *hub_status; 213 struct usb_port_status *port_status; 214 unsigned long flags; 215 216 spin_lock_irqsave(&fhci->lock, flags); 217 218 fhci_dbg(fhci, "-> %s\n", __func__); 219 220 switch (typeReq) { 221 case ClearHubFeature: 222 switch (wValue) { 223 case C_HUB_LOCAL_POWER: 224 case C_HUB_OVER_CURRENT: 225 break; 226 default: 227 goto error; 228 } 229 break; 230 case ClearPortFeature: 231 fhci->vroot_hub->feature &= (1 << wValue); 232 233 switch (wValue) { 234 case USB_PORT_FEAT_ENABLE: 235 fhci->vroot_hub->port.wPortStatus &= 236 ~USB_PORT_STAT_ENABLE; 237 fhci_port_disable(fhci); 238 break; 239 case USB_PORT_FEAT_C_ENABLE: 240 fhci->vroot_hub->port.wPortChange &= 241 ~USB_PORT_STAT_C_ENABLE; 242 break; 243 case USB_PORT_FEAT_SUSPEND: 244 fhci->vroot_hub->port.wPortStatus &= 245 ~USB_PORT_STAT_SUSPEND; 246 fhci_stop_sof_timer(fhci); 247 break; 248 case USB_PORT_FEAT_C_SUSPEND: 249 fhci->vroot_hub->port.wPortChange &= 250 ~USB_PORT_STAT_C_SUSPEND; 251 break; 252 case USB_PORT_FEAT_POWER: 253 fhci->vroot_hub->port.wPortStatus &= 254 ~USB_PORT_STAT_POWER; 255 fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); 256 break; 257 case USB_PORT_FEAT_C_CONNECTION: 258 fhci->vroot_hub->port.wPortChange &= 259 ~USB_PORT_STAT_C_CONNECTION; 260 break; 261 case USB_PORT_FEAT_C_OVER_CURRENT: 262 fhci->vroot_hub->port.wPortChange &= 263 ~USB_PORT_STAT_C_OVERCURRENT; 264 break; 265 case USB_PORT_FEAT_C_RESET: 266 fhci->vroot_hub->port.wPortChange &= 267 ~USB_PORT_STAT_C_RESET; 268 break; 269 default: 270 goto error; 271 } 272 break; 273 case GetHubDescriptor: 274 memcpy(buf, root_hub_des, sizeof(root_hub_des)); 275 buf[3] = 0x11; /* per-port power, no ovrcrnt */ 276 len = (buf[0] < wLength) ? buf[0] : wLength; 277 break; 278 case GetHubStatus: 279 hub_status = (struct usb_hub_status *)buf; 280 hub_status->wHubStatus = 281 cpu_to_le16(fhci->vroot_hub->hub.wHubStatus); 282 hub_status->wHubChange = 283 cpu_to_le16(fhci->vroot_hub->hub.wHubChange); 284 len = 4; 285 break; 286 case GetPortStatus: 287 port_status = (struct usb_port_status *)buf; 288 port_status->wPortStatus = 289 cpu_to_le16(fhci->vroot_hub->port.wPortStatus); 290 port_status->wPortChange = 291 cpu_to_le16(fhci->vroot_hub->port.wPortChange); 292 len = 4; 293 break; 294 case SetHubFeature: 295 switch (wValue) { 296 case C_HUB_OVER_CURRENT: 297 case C_HUB_LOCAL_POWER: 298 break; 299 default: 300 goto error; 301 } 302 break; 303 case SetPortFeature: 304 fhci->vroot_hub->feature |= (1 << wValue); 305 306 switch (wValue) { 307 case USB_PORT_FEAT_ENABLE: 308 fhci->vroot_hub->port.wPortStatus |= 309 USB_PORT_STAT_ENABLE; 310 fhci_port_enable(fhci->usb_lld); 311 break; 312 case USB_PORT_FEAT_SUSPEND: 313 fhci->vroot_hub->port.wPortStatus |= 314 USB_PORT_STAT_SUSPEND; 315 fhci_stop_sof_timer(fhci); 316 break; 317 case USB_PORT_FEAT_RESET: 318 fhci->vroot_hub->port.wPortStatus |= 319 USB_PORT_STAT_RESET; 320 fhci_port_reset(fhci->usb_lld); 321 fhci->vroot_hub->port.wPortStatus |= 322 USB_PORT_STAT_ENABLE; 323 fhci->vroot_hub->port.wPortStatus &= 324 ~USB_PORT_STAT_RESET; 325 break; 326 case USB_PORT_FEAT_POWER: 327 fhci->vroot_hub->port.wPortStatus |= 328 USB_PORT_STAT_POWER; 329 fhci_config_transceiver(fhci, FHCI_PORT_WAITING); 330 break; 331 default: 332 goto error; 333 } 334 break; 335 default: 336 error: 337 retval = -EPIPE; 338 } 339 340 fhci_dbg(fhci, "<- %s\n", __func__); 341 342 spin_unlock_irqrestore(&fhci->lock, flags); 343 344 return retval; 345 } 346