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