0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/kernel.h>
0015 #include <linux/types.h>
0016 #include <linux/spinlock.h>
0017 #include <linux/delay.h>
0018 #include <linux/errno.h>
0019 #include <linux/io.h>
0020 #include <linux/usb.h>
0021 #include <linux/usb/hcd.h>
0022 #include <linux/gpio.h>
0023 #include <soc/fsl/qe/qe.h>
0024 #include "fhci.h"
0025
0026
0027 static u8 root_hub_des[] = {
0028 0x09,
0029 USB_DT_HUB,
0030 0x01,
0031 HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM,
0032 0x00,
0033 0x01,
0034 0x00,
0035 0x00,
0036 0xff,
0037 };
0038
0039 static void fhci_gpio_set_value(struct fhci_hcd *fhci, int gpio_nr, bool on)
0040 {
0041 int gpio = fhci->gpios[gpio_nr];
0042 bool alow = fhci->alow_gpios[gpio_nr];
0043
0044 if (!gpio_is_valid(gpio))
0045 return;
0046
0047 gpio_set_value(gpio, on ^ alow);
0048 mdelay(5);
0049 }
0050
0051 void fhci_config_transceiver(struct fhci_hcd *fhci,
0052 enum fhci_port_status status)
0053 {
0054 fhci_dbg(fhci, "-> %s: %d\n", __func__, status);
0055
0056 switch (status) {
0057 case FHCI_PORT_POWER_OFF:
0058 fhci_gpio_set_value(fhci, GPIO_POWER, false);
0059 break;
0060 case FHCI_PORT_DISABLED:
0061 case FHCI_PORT_WAITING:
0062 fhci_gpio_set_value(fhci, GPIO_POWER, true);
0063 break;
0064 case FHCI_PORT_LOW:
0065 fhci_gpio_set_value(fhci, GPIO_SPEED, false);
0066 break;
0067 case FHCI_PORT_FULL:
0068 fhci_gpio_set_value(fhci, GPIO_SPEED, true);
0069 break;
0070 default:
0071 WARN_ON(1);
0072 break;
0073 }
0074
0075 fhci_dbg(fhci, "<- %s: %d\n", __func__, status);
0076 }
0077
0078
0079 void fhci_port_disable(struct fhci_hcd *fhci)
0080 {
0081 struct fhci_usb *usb = (struct fhci_usb *)fhci->usb_lld;
0082 enum fhci_port_status port_status;
0083
0084 fhci_dbg(fhci, "-> %s\n", __func__);
0085
0086 fhci_stop_sof_timer(fhci);
0087
0088 fhci_flush_all_transmissions(usb);
0089
0090 fhci_usb_disable_interrupt((struct fhci_usb *)fhci->usb_lld);
0091 port_status = usb->port_status;
0092 usb->port_status = FHCI_PORT_DISABLED;
0093
0094
0095 usb->saved_msk |= USB_E_IDLE_MASK;
0096 out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
0097
0098
0099 if (port_status == FHCI_PORT_WAITING)
0100 fhci_device_connected_interrupt(fhci);
0101 usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_ENABLE;
0102 usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE;
0103 fhci_usb_enable_interrupt((struct fhci_usb *)fhci->usb_lld);
0104
0105 fhci_dbg(fhci, "<- %s\n", __func__);
0106 }
0107
0108
0109 void fhci_port_enable(void *lld)
0110 {
0111 struct fhci_usb *usb = (struct fhci_usb *)lld;
0112 struct fhci_hcd *fhci = usb->fhci;
0113
0114 fhci_dbg(fhci, "-> %s\n", __func__);
0115
0116 fhci_config_transceiver(fhci, usb->port_status);
0117
0118 if ((usb->port_status != FHCI_PORT_FULL) &&
0119 (usb->port_status != FHCI_PORT_LOW))
0120 fhci_start_sof_timer(fhci);
0121
0122 usb->vroot_hub->port.wPortStatus |= USB_PORT_STAT_ENABLE;
0123 usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE;
0124
0125 fhci_dbg(fhci, "<- %s\n", __func__);
0126 }
0127
0128 void fhci_io_port_generate_reset(struct fhci_hcd *fhci)
0129 {
0130 fhci_dbg(fhci, "-> %s\n", __func__);
0131
0132 gpio_direction_output(fhci->gpios[GPIO_USBOE], 0);
0133 gpio_direction_output(fhci->gpios[GPIO_USBTP], 0);
0134 gpio_direction_output(fhci->gpios[GPIO_USBTN], 0);
0135
0136 mdelay(5);
0137
0138 qe_pin_set_dedicated(fhci->pins[PIN_USBOE]);
0139 qe_pin_set_dedicated(fhci->pins[PIN_USBTP]);
0140 qe_pin_set_dedicated(fhci->pins[PIN_USBTN]);
0141
0142 fhci_dbg(fhci, "<- %s\n", __func__);
0143 }
0144
0145
0146 void fhci_port_reset(void *lld)
0147 {
0148 struct fhci_usb *usb = (struct fhci_usb *)lld;
0149 struct fhci_hcd *fhci = usb->fhci;
0150 u8 mode;
0151 u16 mask;
0152
0153 fhci_dbg(fhci, "-> %s\n", __func__);
0154
0155 fhci_stop_sof_timer(fhci);
0156
0157 mode = in_8(&fhci->regs->usb_usmod);
0158 out_8(&fhci->regs->usb_usmod, mode & (~USB_MODE_EN));
0159
0160
0161 mask = in_be16(&fhci->regs->usb_usbmr);
0162 out_be16(&fhci->regs->usb_usbmr, mask & (~USB_E_IDLE_MASK));
0163
0164 fhci_io_port_generate_reset(fhci);
0165
0166
0167 out_be16(&fhci->regs->usb_usbmr, mask);
0168
0169
0170 mode = in_8(&fhci->regs->usb_usmod);
0171 out_8(&fhci->regs->usb_usmod, mode | USB_MODE_EN);
0172 fhci_start_sof_timer(fhci);
0173
0174 fhci_dbg(fhci, "<- %s\n", __func__);
0175 }
0176
0177 int fhci_hub_status_data(struct usb_hcd *hcd, char *buf)
0178 {
0179 struct fhci_hcd *fhci = hcd_to_fhci(hcd);
0180 int ret = 0;
0181 unsigned long flags;
0182
0183 fhci_dbg(fhci, "-> %s\n", __func__);
0184
0185 spin_lock_irqsave(&fhci->lock, flags);
0186
0187 if (fhci->vroot_hub->port.wPortChange & (USB_PORT_STAT_C_CONNECTION |
0188 USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_SUSPEND |
0189 USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_OVERCURRENT)) {
0190 *buf = 1 << 1;
0191 ret = 1;
0192 fhci_dbg(fhci, "-- %s\n", __func__);
0193 }
0194
0195 spin_unlock_irqrestore(&fhci->lock, flags);
0196
0197 fhci_dbg(fhci, "<- %s\n", __func__);
0198
0199 return ret;
0200 }
0201
0202 int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
0203 u16 wIndex, char *buf, u16 wLength)
0204 {
0205 struct fhci_hcd *fhci = hcd_to_fhci(hcd);
0206 int retval = 0;
0207 struct usb_hub_status *hub_status;
0208 struct usb_port_status *port_status;
0209 unsigned long flags;
0210
0211 spin_lock_irqsave(&fhci->lock, flags);
0212
0213 fhci_dbg(fhci, "-> %s\n", __func__);
0214
0215 switch (typeReq) {
0216 case ClearHubFeature:
0217 switch (wValue) {
0218 case C_HUB_LOCAL_POWER:
0219 case C_HUB_OVER_CURRENT:
0220 break;
0221 default:
0222 goto error;
0223 }
0224 break;
0225 case ClearPortFeature:
0226 fhci->vroot_hub->feature &= (1 << wValue);
0227
0228 switch (wValue) {
0229 case USB_PORT_FEAT_ENABLE:
0230 fhci->vroot_hub->port.wPortStatus &=
0231 ~USB_PORT_STAT_ENABLE;
0232 fhci_port_disable(fhci);
0233 break;
0234 case USB_PORT_FEAT_C_ENABLE:
0235 fhci->vroot_hub->port.wPortChange &=
0236 ~USB_PORT_STAT_C_ENABLE;
0237 break;
0238 case USB_PORT_FEAT_SUSPEND:
0239 fhci->vroot_hub->port.wPortStatus &=
0240 ~USB_PORT_STAT_SUSPEND;
0241 fhci_stop_sof_timer(fhci);
0242 break;
0243 case USB_PORT_FEAT_C_SUSPEND:
0244 fhci->vroot_hub->port.wPortChange &=
0245 ~USB_PORT_STAT_C_SUSPEND;
0246 break;
0247 case USB_PORT_FEAT_POWER:
0248 fhci->vroot_hub->port.wPortStatus &=
0249 ~USB_PORT_STAT_POWER;
0250 fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF);
0251 break;
0252 case USB_PORT_FEAT_C_CONNECTION:
0253 fhci->vroot_hub->port.wPortChange &=
0254 ~USB_PORT_STAT_C_CONNECTION;
0255 break;
0256 case USB_PORT_FEAT_C_OVER_CURRENT:
0257 fhci->vroot_hub->port.wPortChange &=
0258 ~USB_PORT_STAT_C_OVERCURRENT;
0259 break;
0260 case USB_PORT_FEAT_C_RESET:
0261 fhci->vroot_hub->port.wPortChange &=
0262 ~USB_PORT_STAT_C_RESET;
0263 break;
0264 default:
0265 goto error;
0266 }
0267 break;
0268 case GetHubDescriptor:
0269 memcpy(buf, root_hub_des, sizeof(root_hub_des));
0270 break;
0271 case GetHubStatus:
0272 hub_status = (struct usb_hub_status *)buf;
0273 hub_status->wHubStatus =
0274 cpu_to_le16(fhci->vroot_hub->hub.wHubStatus);
0275 hub_status->wHubChange =
0276 cpu_to_le16(fhci->vroot_hub->hub.wHubChange);
0277 break;
0278 case GetPortStatus:
0279 port_status = (struct usb_port_status *)buf;
0280 port_status->wPortStatus =
0281 cpu_to_le16(fhci->vroot_hub->port.wPortStatus);
0282 port_status->wPortChange =
0283 cpu_to_le16(fhci->vroot_hub->port.wPortChange);
0284 break;
0285 case SetHubFeature:
0286 switch (wValue) {
0287 case C_HUB_OVER_CURRENT:
0288 case C_HUB_LOCAL_POWER:
0289 break;
0290 default:
0291 goto error;
0292 }
0293 break;
0294 case SetPortFeature:
0295 fhci->vroot_hub->feature |= (1 << wValue);
0296
0297 switch (wValue) {
0298 case USB_PORT_FEAT_ENABLE:
0299 fhci->vroot_hub->port.wPortStatus |=
0300 USB_PORT_STAT_ENABLE;
0301 fhci_port_enable(fhci->usb_lld);
0302 break;
0303 case USB_PORT_FEAT_SUSPEND:
0304 fhci->vroot_hub->port.wPortStatus |=
0305 USB_PORT_STAT_SUSPEND;
0306 fhci_stop_sof_timer(fhci);
0307 break;
0308 case USB_PORT_FEAT_RESET:
0309 fhci->vroot_hub->port.wPortStatus |=
0310 USB_PORT_STAT_RESET;
0311 fhci_port_reset(fhci->usb_lld);
0312 fhci->vroot_hub->port.wPortStatus |=
0313 USB_PORT_STAT_ENABLE;
0314 fhci->vroot_hub->port.wPortStatus &=
0315 ~USB_PORT_STAT_RESET;
0316 break;
0317 case USB_PORT_FEAT_POWER:
0318 fhci->vroot_hub->port.wPortStatus |=
0319 USB_PORT_STAT_POWER;
0320 fhci_config_transceiver(fhci, FHCI_PORT_WAITING);
0321 break;
0322 default:
0323 goto error;
0324 }
0325 break;
0326 default:
0327 error:
0328 retval = -EPIPE;
0329 }
0330
0331 fhci_dbg(fhci, "<- %s\n", __func__);
0332
0333 spin_unlock_irqrestore(&fhci->lock, flags);
0334
0335 return retval;
0336 }