Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (172 commits)
  USB: Add support for SuperSpeed isoc endpoints
  xhci: Clean up cycle bit math used during stalls.
  xhci: Fix cycle bit calculation during stall handling.
  xhci: Update internal dequeue pointers after stalls.
  USB: Disable auto-suspend for USB 3.0 hubs.
  USB: Remove bogus USB_PORT_STAT_SUPER_SPEED symbol.
  xhci: Return canceled URBs immediately when host is halted.
  xhci: Fixes for suspend/resume of shared HCDs.
  xhci: Fix re-init on power loss after resume.
  xhci: Make roothub functions deal with device removal.
  xhci: Limit roothub ports to 15 USB3 & 31 USB2 ports.
  xhci: Return a USB 3.0 hub descriptor for USB3 roothub.
  xhci: Register second xHCI roothub.
  xhci: Change xhci_find_slot_id_by_port() API.
  xhci: Refactor bus suspend state into a struct.
  xhci: Index with a port array instead of PORTSC addresses.
  USB: Set usb_hcd->state and flags for shared roothubs.
  usb: Make core allocate resources per PCI-device.
  usb: Store bus type in usb_hcd, not in driver flags.
  usb: Change usb_hcd->bandwidth_mutex to a pointer.
  ...
This commit is contained in:
Linus Torvalds 2011-03-16 15:04:26 -07:00
commit 971f115a50
167 changed files with 10879 additions and 4080 deletions

View File

@ -12,6 +12,10 @@ Controller Drivers (HCD). So, if HCD is buggy, the traces reported by
usbmon may not correspond to bus transactions precisely. This is the same
situation as with tcpdump.
Two APIs are currently implemented: "text" and "binary". The binary API
is available through a character device in /dev namespace and is an ABI.
The text API is deprecated since 2.6.35, but available for convenience.
* How to use usbmon to collect raw text traces
Unlike the packet socket, usbmon has an interface which provides traces
@ -162,39 +166,11 @@ Here is the list of words, from left to right:
not machine words, but really just a byte stream split into words to make
it easier to read. Thus, the last word may contain from one to four bytes.
The length of collected data is limited and can be less than the data length
report in Data Length word.
Here is an example of code to read the data stream in a well known programming
language:
class ParsedLine {
int data_len; /* Available length of data */
byte data[];
void parseData(StringTokenizer st) {
int availwords = st.countTokens();
data = new byte[availwords * 4];
data_len = 0;
while (st.hasMoreTokens()) {
String data_str = st.nextToken();
int len = data_str.length() / 2;
int i;
int b; // byte is signed, apparently?! XXX
for (i = 0; i < len; i++) {
// data[data_len] = Byte.parseByte(
// data_str.substring(i*2, i*2 + 2),
// 16);
b = Integer.parseInt(
data_str.substring(i*2, i*2 + 2),
16);
if (b >= 128)
b *= -1;
data[data_len] = (byte) b;
data_len++;
}
}
}
}
reported in the Data Length word. In the case of an Isochronous input (Zi)
completion where the received data is sparse in the buffer, the length of
the collected data can be greater than the Data Length value (because Data
Length counts only the bytes that were received whereas the Data words
contain the entire transfer buffer).
Examples:

View File

@ -229,7 +229,7 @@ usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o
obj-y += $(usbfs-m) $(usbfs-y)
obj-y += usb-musb.o
obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o
obj-y += usb-ehci.o
obj-y += usb-host.o
onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o
obj-y += $(onenand-m) $(onenand-y)

View File

@ -653,11 +653,11 @@ static void enable_board_wakeup_source(void)
OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = 57,
@ -816,7 +816,7 @@ static void __init omap_3430sdp_init(void)
board_flash_init(sdp_flash_partitions, chip_sel_3430);
sdp3430_display_init();
enable_board_wakeup_source();
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
}
MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")

View File

@ -54,11 +54,11 @@ static void enable_board_wakeup_source(void)
OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = 126,
@ -211,7 +211,7 @@ static void __init omap_sdp_init(void)
board_smc91x_init();
board_flash_init(sdp_flash_partitions, chip_sel_sdp);
enable_board_wakeup_source();
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
}
MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")

View File

@ -44,7 +44,6 @@
#define ETH_KS8851_IRQ 34
#define ETH_KS8851_POWER_ON 48
#define ETH_KS8851_QUART 138
#define OMAP4SDP_MDM_PWR_EN_GPIO 157
#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184
#define OMAP4_SFH7741_ENABLE_GPIO 188
@ -251,16 +250,6 @@ static void __init omap_4430sdp_init_irq(void)
gic_init_irq();
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.phy_reset = false,
.reset_gpio_port[0] = -EINVAL,
.reset_gpio_port[1] = -EINVAL,
.reset_gpio_port[2] = -EINVAL,
};
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_UTMI,
.mode = MUSB_OTG,
@ -272,6 +261,7 @@ static struct twl4030_usb_data omap4_usbphy_data = {
.phy_exit = omap4430_phy_exit,
.phy_power = omap4430_phy_power,
.phy_set_clock = omap4430_phy_set_clk,
.phy_suspend = omap4430_phy_suspend,
};
static struct omap2_hsmmc_info mmc[] = {
@ -576,14 +566,6 @@ static void __init omap_4430sdp_init(void)
omap_serial_init();
omap4_twl6030_hsmmc_init(mmc);
/* Power on the ULPI PHY */
status = gpio_request(OMAP4SDP_MDM_PWR_EN_GPIO, "USBB1 PHY VMDM_3V3");
if (status)
pr_err("%s: Could not get USBB1 PHY GPIO\n", __func__);
else
gpio_direction_output(OMAP4SDP_MDM_PWR_EN_GPIO, 1);
usb_ehci_init(&ehci_pdata);
usb_musb_init(&musb_board_data);
status = omap_ethernet_init();

View File

@ -59,10 +59,10 @@ static void __init am3517_crane_init_irq(void)
omap_init_irq();
}
static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static struct usbhs_omap_board_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = GPIO_USB_NRESET,
@ -103,7 +103,7 @@ static void __init am3517_crane_init(void)
return;
}
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
}
MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD")

View File

@ -430,15 +430,15 @@ static __init void am3517_evm_musb_init(void)
usb_musb_init(&musb_board_data);
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
#if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \
defined(CONFIG_PANEL_SHARP_LQ043T1DG01_MODULE)
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
#else
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
#endif
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = 57,
@ -502,7 +502,7 @@ static void __init am3517_evm_init(void)
/* Configure GPIO for EHCI port */
omap_mux_init_gpio(57, OMAP_PIN_OUTPUT);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
am3517_evm_hecc_init(&am3517_evm_hecc_pdata);
/* DSS */
am3517_evm_display_init();

View File

@ -605,10 +605,10 @@ static struct omap2_hsmmc_info mmc[] = {
{} /* Terminator */
};
static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static struct usbhs_omap_board_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = OMAP_MAX_GPIO_LINES + 6,
@ -810,7 +810,7 @@ static void __init cm_t35_init(void)
cm_t35_init_display();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
}
MACHINE_START(CM_T35, "Compulab CM-T35")

View File

@ -167,10 +167,10 @@ static inline void cm_t3517_init_rtc(void) {}
#define HSUSB2_RESET_GPIO (147)
#define USB_HUB_RESET_GPIO (152)
static struct ehci_hcd_omap_platform_data cm_t3517_ehci_pdata __initdata = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static struct usbhs_omap_board_data cm_t3517_ehci_pdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = HSUSB1_RESET_GPIO,
@ -192,7 +192,7 @@ static int cm_t3517_init_usbh(void)
msleep(1);
}
usb_ehci_init(&cm_t3517_ehci_pdata);
usbhs_init(&cm_t3517_ehci_pdata);
return 0;
}

View File

@ -620,11 +620,11 @@ static struct omap_musb_board_data musb_board_data = {
.power = 100,
};
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = -EINVAL,
@ -803,7 +803,7 @@ static void __init devkit8000_init(void)
devkit8000_ads7846_init();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
devkit8000_flash_init();
/* Ensure SDRC pins are mux'd for self-refresh */

View File

@ -627,10 +627,10 @@ static struct omap_musb_board_data musb_board_data = {
.power = 100,
};
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = IGEP2_GPIO_USBH_NRESET,
@ -699,7 +699,7 @@ static void __init igep2_init(void)
platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
omap_serial_init();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
igep2_flash_init();
igep2_leds_init();

View File

@ -408,10 +408,10 @@ static void __init igep3_wifi_bt_init(void)
void __init igep3_wifi_bt_init(void) {}
#endif
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = -EINVAL,
@ -435,7 +435,7 @@ static void __init igep3_init(void)
platform_add_devices(igep3_devices, ARRAY_SIZE(igep3_devices));
omap_serial_init();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
igep3_flash_init();
igep3_leds_init();

View File

@ -586,11 +586,11 @@ static void __init omap3beagle_flash_init(void)
}
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = -EINVAL,
@ -625,7 +625,7 @@ static void __init omap3_beagle_init(void)
gpio_direction_output(170, true);
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
omap3beagle_flash_init();
/* Ensure SDRC pins are mux'd for self-refresh */

View File

@ -638,11 +638,11 @@ static struct platform_device *omap3_evm_devices[] __initdata = {
&omap3_evm_dss_device,
};
static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
static struct usbhs_omap_board_data usbhs_bdata __initdata = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
/* PHY reset GPIO will be runtime programmed based on EVM version */
@ -700,7 +700,7 @@ static void __init omap3_evm_init(void)
/* setup EHCI phy reset config */
omap_mux_init_gpio(21, OMAP_PIN_INPUT_PULLUP);
ehci_pdata.reset_gpio_port[1] = 21;
usbhs_bdata.reset_gpio_port[1] = 21;
/* EVM REV >= E can supply 500mA with EXTVBUS programming */
musb_board_data.power = 500;
@ -708,10 +708,10 @@ static void __init omap3_evm_init(void)
} else {
/* setup EHCI phy reset on MDC */
omap_mux_init_gpio(135, OMAP_PIN_OUTPUT);
ehci_pdata.reset_gpio_port[1] = 135;
usbhs_bdata.reset_gpio_port[1] = 135;
}
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
ads7846_dev_init();
omap3evm_init_smsc911x();
omap3_evm_display_init();

View File

@ -681,11 +681,11 @@ static struct platform_device *omap3pandora_devices[] __initdata = {
&pandora_vwlan_device,
};
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = 16,
@ -716,7 +716,7 @@ static void __init omap3pandora_init(void)
spi_register_board_info(omap3pandora_spi_board_info,
ARRAY_SIZE(omap3pandora_spi_board_info));
omap3pandora_ads7846_init();
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
usb_musb_init(&musb_board_data);
gpmc_nand_init(&pandora_nand_data);

View File

@ -608,10 +608,10 @@ static struct platform_device *omap3_stalker_devices[] __initdata = {
&keys_gpio,
};
static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = -EINVAL,
@ -649,7 +649,7 @@ static void __init omap3_stalker_init(void)
omap_serial_init();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
ads7846_dev_init();
omap_mux_init_gpio(21, OMAP_PIN_OUTPUT);

View File

@ -468,11 +468,11 @@ static void __init omap3touchbook_flash_init(void)
}
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = -EINVAL,
@ -527,7 +527,7 @@ static void __init omap3_touchbook_init(void)
ARRAY_SIZE(omap3_ads7846_spi_board_info));
omap3_ads7846_init();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
omap3touchbook_flash_init();
/* Ensure SDRC pins are mux'd for self-refresh */

View File

@ -83,10 +83,10 @@ static void __init omap4_panda_init_irq(void)
gic_init_irq();
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = false,
.reset_gpio_port[0] = -EINVAL,
.reset_gpio_port[1] = -EINVAL,
@ -128,7 +128,7 @@ static void __init omap4_ehci_init(void)
gpio_set_value(GPIO_HUB_NRESET, 0);
gpio_set_value(GPIO_HUB_NRESET, 1);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
/* enable power to hub */
gpio_set_value(GPIO_HUB_POWER, 1);
@ -153,6 +153,7 @@ static struct twl4030_usb_data omap4_usbphy_data = {
.phy_exit = omap4430_phy_exit,
.phy_power = omap4430_phy_power,
.phy_set_clock = omap4430_phy_set_clk,
.phy_suspend = omap4430_phy_suspend,
};
static struct omap2_hsmmc_info mmc[] = {

View File

@ -423,10 +423,10 @@ static struct platform_device *overo_devices[] __initdata = {
&overo_lcd_device,
};
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = -EINVAL,
@ -454,7 +454,7 @@ static void __init overo_init(void)
omap_serial_init();
overo_flash_init();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
overo_ads7846_init();
overo_init_smsc911x();

View File

@ -106,10 +106,10 @@ static struct mtd_partition zoom_nand_partitions[] = {
},
};
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
.phy_reset = true,
.reset_gpio_port[0] = -EINVAL,
.reset_gpio_port[1] = ZOOM3_EHCI_RESET_GPIO,
@ -123,7 +123,7 @@ static void __init omap_zoom_init(void)
} else if (machine_is_omap_zoom3()) {
omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
omap_mux_init_gpio(ZOOM3_EHCI_RESET_GPIO, OMAP_PIN_OUTPUT);
usb_ehci_init(&ehci_pdata);
usbhs_init(&usbhs_bdata);
}
board_nand_init(zoom_nand_partitions,

View File

@ -3286,7 +3286,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs-omap.0", "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("omap-mcbsp.1", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK("omap-mcbsp.5", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK(NULL, "core_96m_fck", &core_96m_fck, CK_3XXX),
@ -3322,7 +3322,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "pka_ick", &pka_ick, CK_34XX | CK_36XX),
CLK(NULL, "core_l4_ick", &core_l4_ick, CK_3XXX),
CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs-omap.0", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "icr_ick", &icr_ick, CK_34XX | CK_36XX),
CLK("omap-aes", "ick", &aes2_ick, CK_34XX | CK_36XX),
@ -3368,11 +3368,20 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cam_ick", &cam_ick, CK_34XX | CK_36XX),
CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_34XX | CK_36XX),
CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "hs_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs-omap.0", "hs_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "fs_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs-omap.0", "fs_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs-omap.0", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs-omap.0", "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "usb_tll_hs_usb_ch0_clk", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "usb_tll_hs_usb_ch1_clk", &dummy_ck, CK_3XXX),
CLK("usbhs-omap.0", "init_60m_fclk", &dummy_ck, CK_3XXX),
CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2PLUS | CK_36XX),
CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX),
CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX),

View File

@ -3197,7 +3197,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "uart3_fck", &uart3_fck, CK_443X),
CLK(NULL, "uart4_fck", &uart4_fck, CK_443X),
CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X),
CLK("ehci-omap.0", "fs_fck", &usb_host_fs_fck, CK_443X),
CLK("usbhs-omap.0", "fs_fck", &usb_host_fs_fck, CK_443X),
CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X),
CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk, CK_443X),
CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk, CK_443X),
@ -3209,8 +3209,8 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "usb_host_hs_hsic480m_p2_clk", &usb_host_hs_hsic480m_p2_clk, CK_443X),
CLK(NULL, "usb_host_hs_func48mclk", &usb_host_hs_func48mclk, CK_443X),
CLK(NULL, "usb_host_hs_fck", &usb_host_hs_fck, CK_443X),
CLK("ehci-omap.0", "hs_fck", &usb_host_hs_fck, CK_443X),
CLK("ehci-omap.0", "usbhost_ick", &dummy_ck, CK_443X),
CLK("usbhs-omap.0", "hs_fck", &usb_host_hs_fck, CK_443X),
CLK("usbhs-omap.0", "usbhost_ick", &dummy_ck, CK_443X),
CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk, CK_443X),
CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk, CK_443X),
CLK("musb-omap2430", "ick", &usb_otg_hs_ick, CK_443X),
@ -3219,8 +3219,8 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk, CK_443X),
CLK(NULL, "usb_tll_hs_usb_ch1_clk", &usb_tll_hs_usb_ch1_clk, CK_443X),
CLK(NULL, "usb_tll_hs_ick", &usb_tll_hs_ick, CK_443X),
CLK("ehci-omap.0", "usbtll_ick", &usb_tll_hs_ick, CK_443X),
CLK("ehci-omap.0", "usbtll_fck", &dummy_ck, CK_443X),
CLK("usbhs-omap.0", "usbtll_ick", &usb_tll_hs_ick, CK_443X),
CLK("usbhs-omap.0", "usbtll_fck", &dummy_ck, CK_443X),
CLK(NULL, "usim_ck", &usim_ck, CK_443X),
CLK(NULL, "usim_fclk", &usim_fclk, CK_443X),
CLK(NULL, "usim_fck", &usim_fck, CK_443X),

View File

@ -43,6 +43,7 @@
static struct clk *phyclk, *clk48m, *clk32k;
static void __iomem *ctrl_base;
static int usbotghs_control;
int omap4430_phy_init(struct device *dev)
{
@ -103,13 +104,6 @@ int omap4430_phy_set_clk(struct device *dev, int on)
int omap4430_phy_power(struct device *dev, int ID, int on)
{
if (on) {
/* enabled the clocks */
omap4430_phy_set_clk(dev, 1);
/* power on the phy */
if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) {
__raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF);
mdelay(200);
}
if (ID)
/* enable VBUS valid, IDDIG groung */
__raw_writel(AVALID | VBUSVALID, ctrl_base +
@ -125,10 +119,31 @@ int omap4430_phy_power(struct device *dev, int ID, int on)
/* Enable session END and IDIG to high impedence. */
__raw_writel(SESSEND | IDDIG, ctrl_base +
USBOTGHS_CONTROL);
}
return 0;
}
int omap4430_phy_suspend(struct device *dev, int suspend)
{
if (suspend) {
/* Disable the clocks */
omap4430_phy_set_clk(dev, 0);
/* Power down the phy */
__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
/* save the context */
usbotghs_control = __raw_readl(ctrl_base + USBOTGHS_CONTROL);
} else {
/* Enable the internel phy clcoks */
omap4430_phy_set_clk(dev, 1);
/* power on the phy */
if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) {
__raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF);
mdelay(200);
}
/* restore the context */
__raw_writel(usbotghs_control, ctrl_base + USBOTGHS_CONTROL);
}
return 0;

View File

@ -1,14 +1,15 @@
/*
* linux/arch/arm/mach-omap2/usb-ehci.c
* usb-host.c - OMAP USB Host
*
* This file will contain the board specific details for the
* Synopsys EHCI host controller on OMAP3430
* Synopsys EHCI/OHCI host controller on OMAP3430 and onwards
*
* Copyright (C) 2007 Texas Instruments
* Copyright (C) 2007-2011 Texas Instruments
* Author: Vikram Pandita <vikram.pandita@ti.com>
* Author: Keshava Munegowda <keshava_mgowda@ti.com>
*
* Generalization by:
* Felipe Balbi <felipe.balbi@nokia.com>
* Felipe Balbi <balbi@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -19,7 +20,7 @@
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
@ -30,44 +31,56 @@
#include "mux.h"
#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
#ifdef CONFIG_MFD_OMAP_USB_HOST
static struct resource ehci_resources[] = {
#define OMAP_USBHS_DEVICE "usbhs-omap"
static struct resource usbhs_resources[] = {
{
.name = "uhh",
.flags = IORESOURCE_MEM,
},
{
.name = "tll",
.flags = IORESOURCE_MEM,
},
{
.name = "ehci",
.flags = IORESOURCE_MEM,
},
{ /* general IRQ */
.flags = IORESOURCE_IRQ,
{
.name = "ehci-irq",
.flags = IORESOURCE_IRQ,
},
{
.name = "ohci",
.flags = IORESOURCE_MEM,
},
{
.name = "ohci-irq",
.flags = IORESOURCE_IRQ,
}
};
static u64 ehci_dmamask = ~(u32)0;
static struct platform_device ehci_device = {
.name = "ehci-omap",
.id = 0,
.dev = {
.dma_mask = &ehci_dmamask,
.coherent_dma_mask = 0xffffffff,
.platform_data = NULL,
},
.num_resources = ARRAY_SIZE(ehci_resources),
.resource = ehci_resources,
static struct platform_device usbhs_device = {
.name = OMAP_USBHS_DEVICE,
.id = 0,
.num_resources = ARRAY_SIZE(usbhs_resources),
.resource = usbhs_resources,
};
static struct usbhs_omap_platform_data usbhs_data;
static struct ehci_hcd_omap_platform_data ehci_data;
static struct ohci_hcd_omap_platform_data ohci_data;
/* MUX settings for EHCI pins */
/*
* setup_ehci_io_mux - initialize IO pad mux for USBHOST
*/
static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
static void setup_ehci_io_mux(const enum usbhs_omap_port_mode *port_mode)
{
switch (port_mode[0]) {
case EHCI_HCD_OMAP_MODE_PHY:
case OMAP_EHCI_PORT_MODE_PHY:
omap_mux_init_signal("hsusb1_stp", OMAP_PIN_OUTPUT);
omap_mux_init_signal("hsusb1_clk", OMAP_PIN_OUTPUT);
omap_mux_init_signal("hsusb1_dir", OMAP_PIN_INPUT_PULLDOWN);
@ -81,7 +94,7 @@ static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("hsusb1_data6", OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("hsusb1_data7", OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_TLL:
case OMAP_EHCI_PORT_MODE_TLL:
omap_mux_init_signal("hsusb1_tll_stp",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("hsusb1_tll_clk",
@ -107,14 +120,14 @@ static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("hsusb1_tll_data7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_UNKNOWN:
case OMAP_USBHS_PORT_MODE_UNUSED:
/* FALLTHROUGH */
default:
break;
}
switch (port_mode[1]) {
case EHCI_HCD_OMAP_MODE_PHY:
case OMAP_EHCI_PORT_MODE_PHY:
omap_mux_init_signal("hsusb2_stp", OMAP_PIN_OUTPUT);
omap_mux_init_signal("hsusb2_clk", OMAP_PIN_OUTPUT);
omap_mux_init_signal("hsusb2_dir", OMAP_PIN_INPUT_PULLDOWN);
@ -136,7 +149,7 @@ static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("hsusb2_data7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_TLL:
case OMAP_EHCI_PORT_MODE_TLL:
omap_mux_init_signal("hsusb2_tll_stp",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("hsusb2_tll_clk",
@ -162,17 +175,17 @@ static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("hsusb2_tll_data7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_UNKNOWN:
case OMAP_USBHS_PORT_MODE_UNUSED:
/* FALLTHROUGH */
default:
break;
}
switch (port_mode[2]) {
case EHCI_HCD_OMAP_MODE_PHY:
case OMAP_EHCI_PORT_MODE_PHY:
printk(KERN_WARNING "Port3 can't be used in PHY mode\n");
break;
case EHCI_HCD_OMAP_MODE_TLL:
case OMAP_EHCI_PORT_MODE_TLL:
omap_mux_init_signal("hsusb3_tll_stp",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("hsusb3_tll_clk",
@ -198,7 +211,7 @@ static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("hsusb3_tll_data7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_UNKNOWN:
case OMAP_USBHS_PORT_MODE_UNUSED:
/* FALLTHROUGH */
default:
break;
@ -207,10 +220,10 @@ static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
return;
}
static void setup_4430ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
static void setup_4430ehci_io_mux(const enum usbhs_omap_port_mode *port_mode)
{
switch (port_mode[0]) {
case EHCI_HCD_OMAP_MODE_PHY:
case OMAP_EHCI_PORT_MODE_PHY:
omap_mux_init_signal("usbb1_ulpiphy_stp",
OMAP_PIN_OUTPUT);
omap_mux_init_signal("usbb1_ulpiphy_clk",
@ -236,7 +249,7 @@ static void setup_4430ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("usbb1_ulpiphy_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_TLL:
case OMAP_EHCI_PORT_MODE_TLL:
omap_mux_init_signal("usbb1_ulpitll_stp",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("usbb1_ulpitll_clk",
@ -262,12 +275,12 @@ static void setup_4430ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("usbb1_ulpitll_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_UNKNOWN:
case OMAP_USBHS_PORT_MODE_UNUSED:
default:
break;
}
switch (port_mode[1]) {
case EHCI_HCD_OMAP_MODE_PHY:
case OMAP_EHCI_PORT_MODE_PHY:
omap_mux_init_signal("usbb2_ulpiphy_stp",
OMAP_PIN_OUTPUT);
omap_mux_init_signal("usbb2_ulpiphy_clk",
@ -293,7 +306,7 @@ static void setup_4430ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("usbb2_ulpiphy_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_TLL:
case OMAP_EHCI_PORT_MODE_TLL:
omap_mux_init_signal("usbb2_ulpitll_stp",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("usbb2_ulpitll_clk",
@ -319,90 +332,13 @@ static void setup_4430ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
omap_mux_init_signal("usbb2_ulpitll_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_UNKNOWN:
case OMAP_USBHS_PORT_MODE_UNUSED:
default:
break;
}
}
void __init usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata)
{
platform_device_add_data(&ehci_device, pdata, sizeof(*pdata));
/* Setup Pin IO MUX for EHCI */
if (cpu_is_omap34xx()) {
ehci_resources[0].start = OMAP34XX_EHCI_BASE;
ehci_resources[0].end = OMAP34XX_EHCI_BASE + SZ_1K - 1;
ehci_resources[1].start = OMAP34XX_UHH_CONFIG_BASE;
ehci_resources[1].end = OMAP34XX_UHH_CONFIG_BASE + SZ_1K - 1;
ehci_resources[2].start = OMAP34XX_USBTLL_BASE;
ehci_resources[2].end = OMAP34XX_USBTLL_BASE + SZ_4K - 1;
ehci_resources[3].start = INT_34XX_EHCI_IRQ;
setup_ehci_io_mux(pdata->port_mode);
} else if (cpu_is_omap44xx()) {
ehci_resources[0].start = OMAP44XX_HSUSB_EHCI_BASE;
ehci_resources[0].end = OMAP44XX_HSUSB_EHCI_BASE + SZ_1K - 1;
ehci_resources[1].start = OMAP44XX_UHH_CONFIG_BASE;
ehci_resources[1].end = OMAP44XX_UHH_CONFIG_BASE + SZ_2K - 1;
ehci_resources[2].start = OMAP44XX_USBTLL_BASE;
ehci_resources[2].end = OMAP44XX_USBTLL_BASE + SZ_4K - 1;
ehci_resources[3].start = OMAP44XX_IRQ_EHCI;
setup_4430ehci_io_mux(pdata->port_mode);
}
if (platform_device_register(&ehci_device) < 0) {
printk(KERN_ERR "Unable to register HS-USB (EHCI) device\n");
return;
}
}
#else
void __init usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata)
{
}
#endif /* CONFIG_USB_EHCI_HCD */
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
static struct resource ohci_resources[] = {
{
.start = OMAP34XX_OHCI_BASE,
.end = OMAP34XX_OHCI_BASE + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = OMAP34XX_UHH_CONFIG_BASE,
.end = OMAP34XX_UHH_CONFIG_BASE + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = OMAP34XX_USBTLL_BASE,
.end = OMAP34XX_USBTLL_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{ /* general IRQ */
.start = INT_34XX_OHCI_IRQ,
.flags = IORESOURCE_IRQ,
}
};
static u64 ohci_dmamask = DMA_BIT_MASK(32);
static struct platform_device ohci_device = {
.name = "ohci-omap3",
.id = 0,
.dev = {
.dma_mask = &ohci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(ohci_resources),
.resource = ohci_resources,
};
static void setup_ohci_io_mux(const enum ohci_omap3_port_mode *port_mode)
static void setup_ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
{
switch (port_mode[0]) {
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
@ -430,7 +366,7 @@ static void setup_ohci_io_mux(const enum ohci_omap3_port_mode *port_mode)
omap_mux_init_signal("mm1_txdat",
OMAP_PIN_INPUT_PULLDOWN);
break;
case OMAP_OHCI_PORT_MODE_UNUSED:
case OMAP_USBHS_PORT_MODE_UNUSED:
/* FALLTHROUGH */
default:
break;
@ -461,7 +397,7 @@ static void setup_ohci_io_mux(const enum ohci_omap3_port_mode *port_mode)
omap_mux_init_signal("mm2_txdat",
OMAP_PIN_INPUT_PULLDOWN);
break;
case OMAP_OHCI_PORT_MODE_UNUSED:
case OMAP_USBHS_PORT_MODE_UNUSED:
/* FALLTHROUGH */
default:
break;
@ -492,31 +428,147 @@ static void setup_ohci_io_mux(const enum ohci_omap3_port_mode *port_mode)
omap_mux_init_signal("mm3_txdat",
OMAP_PIN_INPUT_PULLDOWN);
break;
case OMAP_OHCI_PORT_MODE_UNUSED:
case OMAP_USBHS_PORT_MODE_UNUSED:
/* FALLTHROUGH */
default:
break;
}
}
void __init usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata)
static void setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
{
platform_device_add_data(&ohci_device, pdata, sizeof(*pdata));
switch (port_mode[0]) {
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
omap_mux_init_signal("usbb1_mm_rxdp",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_mm_rxdm",
OMAP_PIN_INPUT_PULLDOWN);
/* Setup Pin IO MUX for OHCI */
if (cpu_is_omap34xx())
setup_ohci_io_mux(pdata->port_mode);
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
omap_mux_init_signal("usbb1_mm_rxrcv",
OMAP_PIN_INPUT_PULLDOWN);
if (platform_device_register(&ohci_device) < 0) {
pr_err("Unable to register FS-USB (OHCI) device\n");
return;
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
omap_mux_init_signal("usbb1_mm_txen",
OMAP_PIN_INPUT_PULLDOWN);
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
omap_mux_init_signal("usbb1_mm_txdat",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_mm_txse0",
OMAP_PIN_INPUT_PULLDOWN);
break;
case OMAP_USBHS_PORT_MODE_UNUSED:
default:
break;
}
switch (port_mode[1]) {
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
omap_mux_init_signal("usbb2_mm_rxdp",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_mm_rxdm",
OMAP_PIN_INPUT_PULLDOWN);
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
omap_mux_init_signal("usbb2_mm_rxrcv",
OMAP_PIN_INPUT_PULLDOWN);
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
omap_mux_init_signal("usbb2_mm_txen",
OMAP_PIN_INPUT_PULLDOWN);
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
omap_mux_init_signal("usbb2_mm_txdat",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_mm_txse0",
OMAP_PIN_INPUT_PULLDOWN);
break;
case OMAP_USBHS_PORT_MODE_UNUSED:
default:
break;
}
}
void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
{
int i;
for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
usbhs_data.port_mode[i] = pdata->port_mode[i];
ohci_data.port_mode[i] = pdata->port_mode[i];
ehci_data.port_mode[i] = pdata->port_mode[i];
ehci_data.reset_gpio_port[i] = pdata->reset_gpio_port[i];
ehci_data.regulator[i] = pdata->regulator[i];
}
ehci_data.phy_reset = pdata->phy_reset;
ohci_data.es2_compatibility = pdata->es2_compatibility;
usbhs_data.ehci_data = &ehci_data;
usbhs_data.ohci_data = &ohci_data;
if (cpu_is_omap34xx()) {
usbhs_resources[0].start = OMAP34XX_UHH_CONFIG_BASE;
usbhs_resources[0].end = OMAP34XX_UHH_CONFIG_BASE + SZ_1K - 1;
usbhs_resources[1].start = OMAP34XX_USBTLL_BASE;
usbhs_resources[1].end = OMAP34XX_USBTLL_BASE + SZ_4K - 1;
usbhs_resources[2].start = OMAP34XX_EHCI_BASE;
usbhs_resources[2].end = OMAP34XX_EHCI_BASE + SZ_1K - 1;
usbhs_resources[3].start = INT_34XX_EHCI_IRQ;
usbhs_resources[4].start = OMAP34XX_OHCI_BASE;
usbhs_resources[4].end = OMAP34XX_OHCI_BASE + SZ_1K - 1;
usbhs_resources[5].start = INT_34XX_OHCI_IRQ;
setup_ehci_io_mux(pdata->port_mode);
setup_ohci_io_mux(pdata->port_mode);
} else if (cpu_is_omap44xx()) {
usbhs_resources[0].start = OMAP44XX_UHH_CONFIG_BASE;
usbhs_resources[0].end = OMAP44XX_UHH_CONFIG_BASE + SZ_1K - 1;
usbhs_resources[1].start = OMAP44XX_USBTLL_BASE;
usbhs_resources[1].end = OMAP44XX_USBTLL_BASE + SZ_4K - 1;
usbhs_resources[2].start = OMAP44XX_HSUSB_EHCI_BASE;
usbhs_resources[2].end = OMAP44XX_HSUSB_EHCI_BASE + SZ_1K - 1;
usbhs_resources[3].start = OMAP44XX_IRQ_EHCI;
usbhs_resources[4].start = OMAP44XX_HSUSB_OHCI_BASE;
usbhs_resources[4].end = OMAP44XX_HSUSB_OHCI_BASE + SZ_1K - 1;
usbhs_resources[5].start = OMAP44XX_IRQ_OHCI;
setup_4430ehci_io_mux(pdata->port_mode);
setup_4430ohci_io_mux(pdata->port_mode);
}
if (platform_device_add_data(&usbhs_device,
&usbhs_data, sizeof(usbhs_data)) < 0) {
printk(KERN_ERR "USBHS platform_device_add_data failed\n");
goto init_end;
}
if (platform_device_register(&usbhs_device) < 0)
printk(KERN_ERR "USBHS platform_device_register failed\n");
init_end:
return;
}
#else
void __init usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata)
void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
{
}
#endif /* CONFIG_USB_OHCI_HCD */
#endif

View File

@ -214,6 +214,10 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
if (platform_device_register(&musb_device) < 0)
printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
if (cpu_is_omap44xx())
omap4430_phy_init(dev);
}
#else

View File

@ -162,29 +162,10 @@ struct gpio_chip h1940_latch_gpiochip = {
.get = h1940_gpiolib_latch_get,
};
static void h1940_udc_pullup(enum s3c2410_udc_cmd_e cmd)
{
printk(KERN_DEBUG "udc: pullup(%d)\n",cmd);
switch (cmd)
{
case S3C2410_UDC_P_ENABLE :
gpio_set_value(H1940_LATCH_USB_DP, 1);
break;
case S3C2410_UDC_P_DISABLE :
gpio_set_value(H1940_LATCH_USB_DP, 0);
break;
case S3C2410_UDC_P_RESET :
break;
default:
break;
}
}
static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
.udc_command = h1940_udc_pullup,
.vbus_pin = S3C2410_GPG(5),
.vbus_pin_inverted = 1,
.pullup_pin = H1940_LATCH_USB_DP,
};
static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = {
@ -475,9 +456,6 @@ static void __init h1940_init(void)
gpio_direction_output(H1940_LATCH_LCD_P4, 0);
gpio_direction_output(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
gpio_request(H1940_LATCH_USB_DP, "USB pullup");
gpio_direction_output(H1940_LATCH_USB_DP, 0);
gpio_request(H1940_LATCH_SD_POWER, "SD power");
gpio_direction_output(H1940_LATCH_SD_POWER, 0);

View File

@ -84,26 +84,10 @@ static struct s3c2410_uartcfg n30_uartcfgs[] = {
},
};
static void n30_udc_pullup(enum s3c2410_udc_cmd_e cmd)
{
switch (cmd) {
case S3C2410_UDC_P_ENABLE :
gpio_set_value(S3C2410_GPB(3), 1);
break;
case S3C2410_UDC_P_DISABLE :
gpio_set_value(S3C2410_GPB(3), 0);
break;
case S3C2410_UDC_P_RESET :
break;
default:
break;
}
}
static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
.udc_command = n30_udc_pullup,
.vbus_pin = S3C2410_GPG(1),
.vbus_pin_inverted = 0,
.pullup_pin = S3C2410_GPB(3),
};
static struct gpio_keys_button n30_buttons[] = {
@ -596,9 +580,6 @@ static void __init n30_init(void)
platform_add_devices(n35_devices, ARRAY_SIZE(n35_devices));
}
WARN_ON(gpio_request(S3C2410_GPB(3), "udc pup"));
gpio_direction_output(S3C2410_GPB(3), 0);
}
MACHINE_START(N30, "Acer-N30")

View File

@ -78,28 +78,9 @@ static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
}
};
static void smdk2413_udc_pullup(enum s3c2410_udc_cmd_e cmd)
{
printk(KERN_DEBUG "udc: pullup(%d)\n",cmd);
switch (cmd)
{
case S3C2410_UDC_P_ENABLE :
gpio_set_value(S3C2410_GPF(2), 1);
break;
case S3C2410_UDC_P_DISABLE :
gpio_set_value(S3C2410_GPF(2), 0);
break;
case S3C2410_UDC_P_RESET :
break;
default:
break;
}
}
static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = {
.udc_command = smdk2413_udc_pullup,
.pullup_pin = S3C2410_GPF(2),
};
@ -133,9 +114,6 @@ static void __init smdk2413_machine_init(void)
{ /* Turn off suspend on both USB ports, and switch the
* selectable USB port to USB device mode. */
WARN_ON(gpio_request(S3C2410_GPF(2), "udc pull"));
gpio_direction_output(S3C2410_GPF(2), 0);
s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
S3C2410_MISCCR_USBSUSPND0 |
S3C2410_MISCCR_USBSUSPND1, 0x0);

View File

@ -455,28 +455,10 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = {
};
static void gta02_udc_command(enum s3c2410_udc_cmd_e cmd)
{
switch (cmd) {
case S3C2410_UDC_P_ENABLE:
pr_debug("%s S3C2410_UDC_P_ENABLE\n", __func__);
gpio_direction_output(GTA02_GPIO_USB_PULLUP, 1);
break;
case S3C2410_UDC_P_DISABLE:
pr_debug("%s S3C2410_UDC_P_DISABLE\n", __func__);
gpio_direction_output(GTA02_GPIO_USB_PULLUP, 0);
break;
case S3C2410_UDC_P_RESET:
pr_debug("%s S3C2410_UDC_P_RESET\n", __func__);
/* FIXME: Do something here. */
}
}
/* Get PMU to set USB current limit accordingly. */
static struct s3c2410_udc_mach_info gta02_udc_cfg = {
static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = {
.vbus_draw = gta02_udc_vbus_draw,
.udc_command = gta02_udc_command,
.pullup_pin = GTA02_GPIO_USB_PULLUP,
};
/* USB */

View File

@ -97,26 +97,8 @@ static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = {
/* USB device UDC support */
static void mini2440_udc_pullup(enum s3c2410_udc_cmd_e cmd)
{
pr_debug("udc: pullup(%d)\n", cmd);
switch (cmd) {
case S3C2410_UDC_P_ENABLE :
gpio_set_value(S3C2410_GPC(5), 1);
break;
case S3C2410_UDC_P_DISABLE :
gpio_set_value(S3C2410_GPC(5), 0);
break;
case S3C2410_UDC_P_RESET :
break;
default:
break;
}
}
static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = {
.udc_command = mini2440_udc_pullup,
.pullup_pin = S3C2410_GPC(5),
};
@ -644,10 +626,6 @@ static void __init mini2440_init(void)
s3c2410_gpio_setpin(S3C2410_GPB(1), 0);
s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);
/* Make sure the D+ pullup pin is output */
WARN_ON(gpio_request(S3C2410_GPC(5), "udc pup"));
gpio_direction_output(S3C2410_GPC(5), 0);
/* mark the key as input, without pullups (there is one on the board) */
for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {
s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);

View File

@ -566,26 +566,10 @@ static struct s3c2410_platform_nand rx1950_nand_info = {
.sets = rx1950_nand_sets,
};
static void rx1950_udc_pullup(enum s3c2410_udc_cmd_e cmd)
{
switch (cmd) {
case S3C2410_UDC_P_ENABLE:
gpio_direction_output(S3C2410_GPJ(5), 1);
break;
case S3C2410_UDC_P_DISABLE:
gpio_direction_output(S3C2410_GPJ(5), 0);
break;
case S3C2410_UDC_P_RESET:
break;
default:
break;
}
}
static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
.udc_command = rx1950_udc_pullup,
.vbus_pin = S3C2410_GPG(5),
.vbus_pin_inverted = 1,
.pullup_pin = S3C2410_GPJ(5),
};
static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
@ -750,9 +734,6 @@ static void __init rx1950_init_machine(void)
S3C2410_MISCCR_USBSUSPND0 |
S3C2410_MISCCR_USBSUSPND1, 0x0);
WARN_ON(gpio_request(S3C2410_GPJ(5), "UDC pullup"));
gpio_direction_output(S3C2410_GPJ(5), 0);
/* mmc power is disabled by default */
WARN_ON(gpio_request(S3C2410_GPJ(1), "MMC power"));
gpio_direction_output(S3C2410_GPJ(1), 0);

View File

@ -10,6 +10,9 @@ config ARCH_TEGRA_2x_SOC
select CPU_V7
select ARM_GIC
select ARCH_REQUIRE_GPIOLIB
select USB_ARCH_HAS_EHCI if USB_SUPPORT
select USB_ULPI if USB_SUPPORT
select USB_ULPI_VIEWPORT if USB_SUPPORT
help
Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller

View File

@ -17,6 +17,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
obj-$(CONFIG_TEGRA_PCI) += pcie.o
obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
obj-${CONFIG_MACH_HARMONY} += board-harmony.o
obj-${CONFIG_MACH_HARMONY} += board-harmony-pinmux.o

View File

@ -0,0 +1,86 @@
/*
* arch/arm/mach-tegra/include/mach/usb_phy.h
*
* Copyright (C) 2010 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __MACH_USB_PHY_H
#define __MACH_USB_PHY_H
#include <linux/clk.h>
#include <linux/usb/otg.h>
struct tegra_utmip_config {
u8 hssync_start_delay;
u8 elastic_limit;
u8 idle_wait_delay;
u8 term_range_adj;
u8 xcvr_setup;
u8 xcvr_lsfslew;
u8 xcvr_lsrslew;
};
struct tegra_ulpi_config {
int reset_gpio;
const char *clk;
};
enum tegra_usb_phy_port_speed {
TEGRA_USB_PHY_PORT_SPEED_FULL = 0,
TEGRA_USB_PHY_PORT_SPEED_LOW,
TEGRA_USB_PHY_PORT_SPEED_HIGH,
};
enum tegra_usb_phy_mode {
TEGRA_USB_PHY_MODE_DEVICE,
TEGRA_USB_PHY_MODE_HOST,
};
struct tegra_xtal_freq;
struct tegra_usb_phy {
int instance;
const struct tegra_xtal_freq *freq;
void __iomem *regs;
void __iomem *pad_regs;
struct clk *clk;
struct clk *pll_u;
struct clk *pad_clk;
enum tegra_usb_phy_mode mode;
void *config;
struct otg_transceiver *ulpi;
};
struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
void *config, enum tegra_usb_phy_mode phy_mode);
int tegra_usb_phy_power_on(struct tegra_usb_phy *phy);
void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
void tegra_usb_phy_power_off(struct tegra_usb_phy *phy);
void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
enum tegra_usb_phy_port_speed port_speed);
void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
void tegra_usb_phy_close(struct tegra_usb_phy *phy);
#endif /* __MACH_USB_PHY_H */

View File

@ -0,0 +1,795 @@
/*
* arch/arm/mach-tegra/usb_phy.c
*
* Copyright (C) 2010 Google, Inc.
*
* Author:
* Erik Gilling <konkers@google.com>
* Benoit Goby <benoit@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/resource.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
#include <asm/mach-types.h>
#include <mach/usb_phy.h>
#include <mach/iomap.h>
#define ULPI_VIEWPORT 0x170
#define USB_PORTSC1 0x184
#define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
#define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26)
#define USB_PORTSC1_PHCD (1 << 23)
#define USB_PORTSC1_WKOC (1 << 22)
#define USB_PORTSC1_WKDS (1 << 21)
#define USB_PORTSC1_WKCN (1 << 20)
#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16)
#define USB_PORTSC1_PP (1 << 12)
#define USB_PORTSC1_SUSP (1 << 7)
#define USB_PORTSC1_PE (1 << 2)
#define USB_PORTSC1_CCS (1 << 0)
#define USB_SUSP_CTRL 0x400
#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
#define USB_SUSP_CLR (1 << 5)
#define USB_PHY_CLK_VALID (1 << 7)
#define UTMIP_RESET (1 << 11)
#define UHSIC_RESET (1 << 11)
#define UTMIP_PHY_ENABLE (1 << 12)
#define ULPI_PHY_ENABLE (1 << 13)
#define USB_SUSP_SET (1 << 14)
#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
#define USB1_LEGACY_CTRL 0x410
#define USB1_NO_LEGACY_MODE (1 << 0)
#define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
(1 << 1)
#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
#define ULPI_TIMING_CTRL_0 0x424
#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
#define ULPI_TIMING_CTRL_1 0x428
#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
#define UTMIP_PLL_CFG1 0x804
#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
#define UTMIP_XCVR_CFG0 0x808
#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
#define UTMIP_BIAS_CFG0 0x80c
#define UTMIP_OTGPD (1 << 11)
#define UTMIP_BIASPD (1 << 10)
#define UTMIP_HSRX_CFG0 0x810
#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
#define UTMIP_HSRX_CFG1 0x814
#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
#define UTMIP_TX_CFG0 0x820
#define UTMIP_FS_PREABMLE_J (1 << 19)
#define UTMIP_HS_DISCON_DISABLE (1 << 8)
#define UTMIP_MISC_CFG0 0x824
#define UTMIP_DPDM_OBSERVE (1 << 26)
#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
#define UTMIP_MISC_CFG1 0x828
#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
#define UTMIP_DEBOUNCE_CFG0 0x82c
#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
#define UTMIP_BAT_CHRG_CFG0 0x830
#define UTMIP_PD_CHRG (1 << 0)
#define UTMIP_SPARE_CFG0 0x834
#define FUSE_SETUP_SEL (1 << 3)
#define UTMIP_XCVR_CFG1 0x838
#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
#define UTMIP_BIAS_CFG1 0x83c
#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
static DEFINE_SPINLOCK(utmip_pad_lock);
static int utmip_pad_count;
struct tegra_xtal_freq {
int freq;
u8 enable_delay;
u8 stable_count;
u8 active_delay;
u8 xtal_freq_count;
u16 debounce;
};
static const struct tegra_xtal_freq tegra_freq_table[] = {
{
.freq = 12000000,
.enable_delay = 0x02,
.stable_count = 0x2F,
.active_delay = 0x04,
.xtal_freq_count = 0x76,
.debounce = 0x7530,
},
{
.freq = 13000000,
.enable_delay = 0x02,
.stable_count = 0x33,
.active_delay = 0x05,
.xtal_freq_count = 0x7F,
.debounce = 0x7EF4,
},
{
.freq = 19200000,
.enable_delay = 0x03,
.stable_count = 0x4B,
.active_delay = 0x06,
.xtal_freq_count = 0xBB,
.debounce = 0xBB80,
},
{
.freq = 26000000,
.enable_delay = 0x04,
.stable_count = 0x66,
.active_delay = 0x09,
.xtal_freq_count = 0xFE,
.debounce = 0xFDE8,
},
};
static struct tegra_utmip_config utmip_default[] = {
[0] = {
.hssync_start_delay = 9,
.idle_wait_delay = 17,
.elastic_limit = 16,
.term_range_adj = 6,
.xcvr_setup = 9,
.xcvr_lsfslew = 1,
.xcvr_lsrslew = 1,
},
[2] = {
.hssync_start_delay = 9,
.idle_wait_delay = 17,
.elastic_limit = 16,
.term_range_adj = 6,
.xcvr_setup = 9,
.xcvr_lsfslew = 2,
.xcvr_lsrslew = 2,
},
};
static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
{
return (phy->instance == 1);
}
static int utmip_pad_open(struct tegra_usb_phy *phy)
{
phy->pad_clk = clk_get_sys("utmip-pad", NULL);
if (IS_ERR(phy->pad_clk)) {
pr_err("%s: can't get utmip pad clock\n", __func__);
return PTR_ERR(phy->pad_clk);
}
if (phy->instance == 0) {
phy->pad_regs = phy->regs;
} else {
phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
if (!phy->pad_regs) {
pr_err("%s: can't remap usb registers\n", __func__);
clk_put(phy->pad_clk);
return -ENOMEM;
}
}
return 0;
}
static void utmip_pad_close(struct tegra_usb_phy *phy)
{
if (phy->instance != 0)
iounmap(phy->pad_regs);
clk_put(phy->pad_clk);
}
static void utmip_pad_power_on(struct tegra_usb_phy *phy)
{
unsigned long val, flags;
void __iomem *base = phy->pad_regs;
clk_enable(phy->pad_clk);
spin_lock_irqsave(&utmip_pad_lock, flags);
if (utmip_pad_count++ == 0) {
val = readl(base + UTMIP_BIAS_CFG0);
val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
writel(val, base + UTMIP_BIAS_CFG0);
}
spin_unlock_irqrestore(&utmip_pad_lock, flags);
clk_disable(phy->pad_clk);
}
static int utmip_pad_power_off(struct tegra_usb_phy *phy)
{
unsigned long val, flags;
void __iomem *base = phy->pad_regs;
if (!utmip_pad_count) {
pr_err("%s: utmip pad already powered off\n", __func__);
return -EINVAL;
}
clk_enable(phy->pad_clk);
spin_lock_irqsave(&utmip_pad_lock, flags);
if (--utmip_pad_count == 0) {
val = readl(base + UTMIP_BIAS_CFG0);
val |= UTMIP_OTGPD | UTMIP_BIASPD;
writel(val, base + UTMIP_BIAS_CFG0);
}
spin_unlock_irqrestore(&utmip_pad_lock, flags);
clk_disable(phy->pad_clk);
return 0;
}
static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
{
unsigned long timeout = 2000;
do {
if ((readl(reg) & mask) == result)
return 0;
udelay(1);
timeout--;
} while (timeout);
return -1;
}
static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
if (phy->instance == 0) {
val = readl(base + USB_SUSP_CTRL);
val |= USB_SUSP_SET;
writel(val, base + USB_SUSP_CTRL);
udelay(10);
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_SUSP_SET;
writel(val, base + USB_SUSP_CTRL);
}
if (phy->instance == 2) {
val = readl(base + USB_PORTSC1);
val |= USB_PORTSC1_PHCD;
writel(val, base + USB_PORTSC1);
}
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
}
static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
if (phy->instance == 0) {
val = readl(base + USB_SUSP_CTRL);
val |= USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
udelay(10);
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
}
if (phy->instance == 2) {
val = readl(base + USB_PORTSC1);
val &= ~USB_PORTSC1_PHCD;
writel(val, base + USB_PORTSC1);
}
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
USB_PHY_CLK_VALID))
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
}
static int utmi_phy_power_on(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
struct tegra_utmip_config *config = phy->config;
val = readl(base + USB_SUSP_CTRL);
val |= UTMIP_RESET;
writel(val, base + USB_SUSP_CTRL);
if (phy->instance == 0) {
val = readl(base + USB1_LEGACY_CTRL);
val |= USB1_NO_LEGACY_MODE;
writel(val, base + USB1_LEGACY_CTRL);
}
val = readl(base + UTMIP_TX_CFG0);
val &= ~UTMIP_FS_PREABMLE_J;
writel(val, base + UTMIP_TX_CFG0);
val = readl(base + UTMIP_HSRX_CFG0);
val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
writel(val, base + UTMIP_HSRX_CFG0);
val = readl(base + UTMIP_HSRX_CFG1);
val &= ~UTMIP_HS_SYNC_START_DLY(~0);
val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
writel(val, base + UTMIP_HSRX_CFG1);
val = readl(base + UTMIP_DEBOUNCE_CFG0);
val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
writel(val, base + UTMIP_DEBOUNCE_CFG0);
val = readl(base + UTMIP_MISC_CFG0);
val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
writel(val, base + UTMIP_MISC_CFG0);
val = readl(base + UTMIP_MISC_CFG1);
val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
writel(val, base + UTMIP_MISC_CFG1);
val = readl(base + UTMIP_PLL_CFG1);
val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
writel(val, base + UTMIP_PLL_CFG1);
if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
val = readl(base + USB_SUSP_CTRL);
val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
writel(val, base + USB_SUSP_CTRL);
}
utmip_pad_power_on(phy);
val = readl(base + UTMIP_XCVR_CFG0);
val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
UTMIP_XCVR_HSSLEW_MSB(~0));
val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
writel(val, base + UTMIP_XCVR_CFG0);
val = readl(base + UTMIP_XCVR_CFG1);
val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
writel(val, base + UTMIP_XCVR_CFG1);
val = readl(base + UTMIP_BAT_CHRG_CFG0);
val &= ~UTMIP_PD_CHRG;
writel(val, base + UTMIP_BAT_CHRG_CFG0);
val = readl(base + UTMIP_BIAS_CFG1);
val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
writel(val, base + UTMIP_BIAS_CFG1);
if (phy->instance == 0) {
val = readl(base + UTMIP_SPARE_CFG0);
if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
val &= ~FUSE_SETUP_SEL;
else
val |= FUSE_SETUP_SEL;
writel(val, base + UTMIP_SPARE_CFG0);
}
if (phy->instance == 2) {
val = readl(base + USB_SUSP_CTRL);
val |= UTMIP_PHY_ENABLE;
writel(val, base + USB_SUSP_CTRL);
}
val = readl(base + USB_SUSP_CTRL);
val &= ~UTMIP_RESET;
writel(val, base + USB_SUSP_CTRL);
if (phy->instance == 0) {
val = readl(base + USB1_LEGACY_CTRL);
val &= ~USB1_VBUS_SENSE_CTL_MASK;
val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
writel(val, base + USB1_LEGACY_CTRL);
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_SUSP_SET;
writel(val, base + USB_SUSP_CTRL);
}
utmi_phy_clk_enable(phy);
if (phy->instance == 2) {
val = readl(base + USB_PORTSC1);
val &= ~USB_PORTSC1_PTS(~0);
writel(val, base + USB_PORTSC1);
}
return 0;
}
static void utmi_phy_power_off(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
utmi_phy_clk_disable(phy);
if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
writel(val, base + USB_SUSP_CTRL);
}
val = readl(base + USB_SUSP_CTRL);
val |= UTMIP_RESET;
writel(val, base + USB_SUSP_CTRL);
val = readl(base + UTMIP_BAT_CHRG_CFG0);
val |= UTMIP_PD_CHRG;
writel(val, base + UTMIP_BAT_CHRG_CFG0);
val = readl(base + UTMIP_XCVR_CFG0);
val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
UTMIP_FORCE_PDZI_POWERDOWN;
writel(val, base + UTMIP_XCVR_CFG0);
val = readl(base + UTMIP_XCVR_CFG1);
val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
UTMIP_FORCE_PDDR_POWERDOWN;
writel(val, base + UTMIP_XCVR_CFG1);
utmip_pad_power_off(phy);
}
static void utmi_phy_preresume(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
val = readl(base + UTMIP_TX_CFG0);
val |= UTMIP_HS_DISCON_DISABLE;
writel(val, base + UTMIP_TX_CFG0);
}
static void utmi_phy_postresume(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
val = readl(base + UTMIP_TX_CFG0);
val &= ~UTMIP_HS_DISCON_DISABLE;
writel(val, base + UTMIP_TX_CFG0);
}
static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
enum tegra_usb_phy_port_speed port_speed)
{
unsigned long val;
void __iomem *base = phy->regs;
val = readl(base + UTMIP_MISC_CFG0);
val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
else
val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
writel(val, base + UTMIP_MISC_CFG0);
udelay(1);
val = readl(base + UTMIP_MISC_CFG0);
val |= UTMIP_DPDM_OBSERVE;
writel(val, base + UTMIP_MISC_CFG0);
udelay(10);
}
static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
val = readl(base + UTMIP_MISC_CFG0);
val &= ~UTMIP_DPDM_OBSERVE;
writel(val, base + UTMIP_MISC_CFG0);
udelay(10);
}
static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
{
int ret;
unsigned long val;
void __iomem *base = phy->regs;
struct tegra_ulpi_config *config = phy->config;
gpio_direction_output(config->reset_gpio, 0);
msleep(5);
gpio_direction_output(config->reset_gpio, 1);
clk_enable(phy->clk);
msleep(1);
val = readl(base + USB_SUSP_CTRL);
val |= UHSIC_RESET;
writel(val, base + USB_SUSP_CTRL);
val = readl(base + ULPI_TIMING_CTRL_0);
val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
writel(val, base + ULPI_TIMING_CTRL_0);
val = readl(base + USB_SUSP_CTRL);
val |= ULPI_PHY_ENABLE;
writel(val, base + USB_SUSP_CTRL);
val = 0;
writel(val, base + ULPI_TIMING_CTRL_1);
val |= ULPI_DATA_TRIMMER_SEL(4);
val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
val |= ULPI_DIR_TRIMMER_SEL(4);
writel(val, base + ULPI_TIMING_CTRL_1);
udelay(10);
val |= ULPI_DATA_TRIMMER_LOAD;
val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
val |= ULPI_DIR_TRIMMER_LOAD;
writel(val, base + ULPI_TIMING_CTRL_1);
/* Fix VbusInvalid due to floating VBUS */
ret = otg_io_write(phy->ulpi, 0x40, 0x08);
if (ret) {
pr_err("%s: ulpi write failed\n", __func__);
return ret;
}
ret = otg_io_write(phy->ulpi, 0x80, 0x0B);
if (ret) {
pr_err("%s: ulpi write failed\n", __func__);
return ret;
}
val = readl(base + USB_PORTSC1);
val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
writel(val, base + USB_PORTSC1);
val = readl(base + USB_SUSP_CTRL);
val |= USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
udelay(100);
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
return 0;
}
static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
struct tegra_ulpi_config *config = phy->config;
/* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
* Controller to immediately bring the ULPI PHY out of low power
*/
val = readl(base + USB_PORTSC1);
val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
writel(val, base + USB_PORTSC1);
gpio_direction_output(config->reset_gpio, 0);
clk_disable(phy->clk);
}
struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
void *config, enum tegra_usb_phy_mode phy_mode)
{
struct tegra_usb_phy *phy;
struct tegra_ulpi_config *ulpi_config;
unsigned long parent_rate;
int i;
int err;
phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
if (!phy)
return ERR_PTR(-ENOMEM);
phy->instance = instance;
phy->regs = regs;
phy->config = config;
phy->mode = phy_mode;
if (!phy->config) {
if (phy_is_ulpi(phy)) {
pr_err("%s: ulpi phy configuration missing", __func__);
err = -EINVAL;
goto err0;
} else {
phy->config = &utmip_default[instance];
}
}
phy->pll_u = clk_get_sys(NULL, "pll_u");
if (IS_ERR(phy->pll_u)) {
pr_err("Can't get pll_u clock\n");
err = PTR_ERR(phy->pll_u);
goto err0;
}
clk_enable(phy->pll_u);
parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
if (tegra_freq_table[i].freq == parent_rate) {
phy->freq = &tegra_freq_table[i];
break;
}
}
if (!phy->freq) {
pr_err("invalid pll_u parent rate %ld\n", parent_rate);
err = -EINVAL;
goto err1;
}
if (phy_is_ulpi(phy)) {
ulpi_config = config;
phy->clk = clk_get_sys(NULL, ulpi_config->clk);
if (IS_ERR(phy->clk)) {
pr_err("%s: can't get ulpi clock\n", __func__);
err = -ENXIO;
goto err1;
}
tegra_gpio_enable(ulpi_config->reset_gpio);
gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
gpio_direction_output(ulpi_config->reset_gpio, 0);
phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
phy->ulpi->io_priv = regs + ULPI_VIEWPORT;
} else {
err = utmip_pad_open(phy);
if (err < 0)
goto err1;
}
return phy;
err1:
clk_disable(phy->pll_u);
clk_put(phy->pll_u);
err0:
kfree(phy);
return ERR_PTR(err);
}
int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
{
if (phy_is_ulpi(phy))
return ulpi_phy_power_on(phy);
else
return utmi_phy_power_on(phy);
}
void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
{
if (phy_is_ulpi(phy))
ulpi_phy_power_off(phy);
else
utmi_phy_power_off(phy);
}
void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_preresume(phy);
}
void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_postresume(phy);
}
void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
enum tegra_usb_phy_port_speed port_speed)
{
if (!phy_is_ulpi(phy))
utmi_phy_restore_start(phy, port_speed);
}
void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_restore_end(phy);
}
void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_clk_disable(phy);
}
void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_clk_enable(phy);
}
void tegra_usb_phy_close(struct tegra_usb_phy *phy)
{
if (phy_is_ulpi(phy))
clk_put(phy->clk);
else
utmip_pad_close(phy);
clk_disable(phy->pll_u);
clk_put(phy->pll_u);
kfree(phy);
}

View File

@ -7,15 +7,12 @@
#include <plat/board.h>
#define OMAP3_HS_USB_PORTS 3
enum ehci_hcd_omap_mode {
EHCI_HCD_OMAP_MODE_UNKNOWN,
EHCI_HCD_OMAP_MODE_PHY,
EHCI_HCD_OMAP_MODE_TLL,
EHCI_HCD_OMAP_MODE_HSIC,
};
enum ohci_omap3_port_mode {
OMAP_OHCI_PORT_MODE_UNUSED,
enum usbhs_omap_port_mode {
OMAP_USBHS_PORT_MODE_UNUSED,
OMAP_EHCI_PORT_MODE_PHY,
OMAP_EHCI_PORT_MODE_TLL,
OMAP_EHCI_PORT_MODE_HSIC,
OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0,
OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM,
OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0,
@ -25,24 +22,45 @@ enum ohci_omap3_port_mode {
OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0,
OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM,
OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0,
OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM,
OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM
};
struct ehci_hcd_omap_platform_data {
enum ehci_hcd_omap_mode port_mode[OMAP3_HS_USB_PORTS];
unsigned phy_reset:1;
struct usbhs_omap_board_data {
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
/* have to be valid if phy_reset is true and portx is in phy mode */
int reset_gpio_port[OMAP3_HS_USB_PORTS];
};
struct ohci_hcd_omap_platform_data {
enum ohci_omap3_port_mode port_mode[OMAP3_HS_USB_PORTS];
/* Set this to true for ES2.x silicon */
unsigned es2_compatibility:1;
unsigned phy_reset:1;
/*
* Regulators for USB PHYs.
* Each PHY can have a separate regulator.
*/
struct regulator *regulator[OMAP3_HS_USB_PORTS];
};
struct ehci_hcd_omap_platform_data {
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
int reset_gpio_port[OMAP3_HS_USB_PORTS];
struct regulator *regulator[OMAP3_HS_USB_PORTS];
unsigned phy_reset:1;
};
struct ohci_hcd_omap_platform_data {
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
unsigned es2_compatibility:1;
};
struct usbhs_omap_platform_data {
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
struct ehci_hcd_omap_platform_data *ehci_data;
struct ohci_hcd_omap_platform_data *ohci_data;
};
/*-------------------------------------------------------------------------*/
#define OMAP1_OTG_BASE 0xfffb0400
@ -80,18 +98,18 @@ enum musb_interface {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI};
extern void usb_musb_init(struct omap_musb_board_data *board_data);
extern void usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata);
extern void usbhs_init(const struct usbhs_omap_board_data *pdata);
extern void usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata);
extern int omap_usbhs_enable(struct device *dev);
extern void omap_usbhs_disable(struct device *dev);
extern int omap4430_phy_power(struct device *dev, int ID, int on);
extern int omap4430_phy_set_clk(struct device *dev, int on);
extern int omap4430_phy_init(struct device *dev);
extern int omap4430_phy_exit(struct device *dev);
extern int omap4430_phy_suspend(struct device *dev, int suspend);
#endif
/*
* FIXME correct answer depends on hmc_mode,
* as does (on omap1) any nonzero value for config->otg port number

View File

@ -27,6 +27,10 @@ enum s3c2410_udc_cmd_e {
struct s3c2410_udc_mach_info {
void (*udc_command)(enum s3c2410_udc_cmd_e);
void (*vbus_draw)(unsigned int ma);
unsigned int pullup_pin;
unsigned int pullup_pin_inverted;
unsigned int vbus_pin;
unsigned char vbus_pin_inverted;
};

View File

@ -624,6 +624,15 @@ config MFD_WL1273_CORE
driver connects the radio-wl1273 V4L2 module and the wl1273
audio codec.
config MFD_OMAP_USB_HOST
bool "Support OMAP USBHS core driver"
depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3
default y
help
This is the core driver for the OAMP EHCI and OHCI drivers.
This MFD driver does the required setup functionalities for
OMAP USB Host drivers.
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"

View File

@ -83,3 +83,4 @@ obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o

1061
drivers/mfd/omap-usb-host.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -255,8 +255,8 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
desc->wHubCharacteristics = (__force __u16)
(__constant_cpu_to_le16(0x0001));
desc->bNbrPorts = VHCI_NPORTS;
desc->bitmap[0] = 0xff;
desc->bitmap[1] = 0xff;
desc->u.hs.DeviceRemovable[0] = 0xff;
desc->u.hs.DeviceRemovable[1] = 0xff;
}
static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,

View File

@ -168,7 +168,6 @@ struct uea_softc {
union cmv_dsc cmv_dsc;
struct work_struct task;
struct workqueue_struct *work_q;
u16 pageno;
u16 ovl;
@ -1879,7 +1878,7 @@ static int uea_start_reset(struct uea_softc *sc)
/* start loading DSP */
sc->pageno = 0;
sc->ovl = 0;
queue_work(sc->work_q, &sc->task);
schedule_work(&sc->task);
/* wait for modem ready CMV */
ret = wait_cmv_ack(sc);
@ -2091,14 +2090,14 @@ static void uea_schedule_load_page_e1(struct uea_softc *sc,
{
sc->pageno = intr->e1_bSwapPageNo;
sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
queue_work(sc->work_q, &sc->task);
schedule_work(&sc->task);
}
static void uea_schedule_load_page_e4(struct uea_softc *sc,
struct intr_pkt *intr)
{
sc->pageno = intr->e4_bSwapPageNo;
queue_work(sc->work_q, &sc->task);
schedule_work(&sc->task);
}
/*
@ -2170,13 +2169,6 @@ static int uea_boot(struct uea_softc *sc)
init_waitqueue_head(&sc->sync_q);
sc->work_q = create_workqueue("ueagle-dsp");
if (!sc->work_q) {
uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
uea_leaves(INS_TO_USBDEV(sc));
return -ENOMEM;
}
if (UEA_CHIP_VERSION(sc) == ADI930)
load_XILINX_firmware(sc);
@ -2225,7 +2217,6 @@ err1:
sc->urb_int = NULL;
kfree(intr);
err0:
destroy_workqueue(sc->work_q);
uea_leaves(INS_TO_USBDEV(sc));
return -ENOMEM;
}
@ -2246,8 +2237,8 @@ static void uea_stop(struct uea_softc *sc)
kfree(sc->urb_int->transfer_buffer);
usb_free_urb(sc->urb_int);
/* stop any pending boot process, when no one can schedule work */
destroy_workqueue(sc->work_q);
/* flush the work item, when no one can schedule it */
flush_work_sync(&sc->task);
if (sc->dsp_firm)
release_firmware(sc->dsp_firm);

View File

@ -10,7 +10,7 @@
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/usb.h>
@ -22,7 +22,7 @@
*/
/* FIXME tune these based on pool statistics ... */
static const size_t pool_max [HCD_BUFFER_POOLS] = {
static const size_t pool_max[HCD_BUFFER_POOLS] = {
/* platforms without dma-friendly caches might need to
* prevent cacheline sharing...
*/
@ -51,7 +51,7 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = {
int hcd_buffer_create(struct usb_hcd *hcd)
{
char name[16];
int i, size;
int i, size;
if (!hcd->self.controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM))
@ -64,7 +64,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
snprintf(name, sizeof name, "buffer-%d", size);
hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
size, size, 0);
if (!hcd->pool [i]) {
if (!hcd->pool[i]) {
hcd_buffer_destroy(hcd);
return -ENOMEM;
}
@ -99,14 +99,14 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
*/
void *hcd_buffer_alloc(
struct usb_bus *bus,
struct usb_bus *bus,
size_t size,
gfp_t mem_flags,
dma_addr_t *dma
)
{
struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
int i;
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask &&
@ -116,21 +116,21 @@ void *hcd_buffer_alloc(
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
if (size <= pool_max[i])
return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
}
return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
}
void hcd_buffer_free(
struct usb_bus *bus,
struct usb_bus *bus,
size_t size,
void *addr,
void *addr,
dma_addr_t dma
)
{
struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
int i;
if (!addr)
return;
@ -142,8 +142,8 @@ void hcd_buffer_free(
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
dma_pool_free(hcd->pool [i], addr, dma);
if (size <= pool_max[i]) {
dma_pool_free(hcd->pool[i], addr, dma);
return;
}
}

View File

@ -1659,6 +1659,11 @@ static int usb_runtime_suspend(struct device *dev)
return -EAGAIN;
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
/* The PM core reacts badly unless the return code is 0,
* -EAGAIN, or -EBUSY, so always return -EBUSY on an error.
*/
if (status != 0)
return -EBUSY;
return status;
}

View File

@ -192,13 +192,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
retval = -ENODEV;
goto err1;
goto disable_pci;
}
hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
if (!hcd) {
retval = -ENOMEM;
goto err1;
goto disable_pci;
}
if (driver->flags & HCD_MEMORY) {
@ -209,13 +209,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
driver->description)) {
dev_dbg(&dev->dev, "controller already in use\n");
retval = -EBUSY;
goto err2;
goto clear_companion;
}
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
dev_dbg(&dev->dev, "error mapping memory\n");
retval = -EFAULT;
goto err3;
goto release_mem_region;
}
} else {
@ -236,7 +236,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (region == PCI_ROM_RESOURCE) {
dev_dbg(&dev->dev, "no i/o regions available\n");
retval = -EBUSY;
goto err2;
goto clear_companion;
}
}
@ -244,24 +244,24 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
goto err4;
goto unmap_registers;
set_hs_companion(dev, hcd);
if (pci_dev_run_wake(dev))
pm_runtime_put_noidle(&dev->dev);
return retval;
err4:
unmap_registers:
if (driver->flags & HCD_MEMORY) {
iounmap(hcd->regs);
err3:
release_mem_region:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
} else
release_region(hcd->rsrc_start, hcd->rsrc_len);
err2:
clear_companion:
clear_hs_companion(dev, hcd);
usb_put_hcd(hcd);
err1:
disable_pci:
pci_disable_device(dev);
dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
return retval;
@ -363,11 +363,17 @@ static int check_root_hub_suspended(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
if (!(hcd->state == HC_STATE_SUSPENDED ||
hcd->state == HC_STATE_HALT)) {
if (HCD_RH_RUNNING(hcd)) {
dev_warn(dev, "Root hub is not suspended\n");
return -EBUSY;
}
if (hcd->shared_hcd) {
hcd = hcd->shared_hcd;
if (HCD_RH_RUNNING(hcd)) {
dev_warn(dev, "Secondary root hub is not suspended\n");
return -EBUSY;
}
}
return 0;
}
@ -386,17 +392,22 @@ static int suspend_common(struct device *dev, bool do_wakeup)
if (retval)
return retval;
if (hcd->driver->pci_suspend) {
if (hcd->driver->pci_suspend && !HCD_DEAD(hcd)) {
/* Optimization: Don't suspend if a root-hub wakeup is
* pending and it would cause the HCD to wake up anyway.
*/
if (do_wakeup && HCD_WAKEUP_PENDING(hcd))
return -EBUSY;
if (do_wakeup && hcd->shared_hcd &&
HCD_WAKEUP_PENDING(hcd->shared_hcd))
return -EBUSY;
retval = hcd->driver->pci_suspend(hcd, do_wakeup);
suspend_report_result(hcd->driver->pci_suspend, retval);
/* Check again in case wakeup raced with pci_suspend */
if (retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) {
if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) ||
(retval == 0 && do_wakeup && hcd->shared_hcd &&
HCD_WAKEUP_PENDING(hcd->shared_hcd))) {
if (hcd->driver->pci_resume)
hcd->driver->pci_resume(hcd, false);
retval = -EBUSY;
@ -427,7 +438,9 @@ static int resume_common(struct device *dev, int event)
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
int retval;
if (hcd->state != HC_STATE_SUSPENDED) {
if (HCD_RH_RUNNING(hcd) ||
(hcd->shared_hcd &&
HCD_RH_RUNNING(hcd->shared_hcd))) {
dev_dbg(dev, "can't resume, not suspended!\n");
return 0;
}
@ -441,8 +454,10 @@ static int resume_common(struct device *dev, int event)
pci_set_master(pci_dev);
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->shared_hcd)
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
if (hcd->driver->pci_resume) {
if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
if (event != PM_EVENT_AUTO_RESUME)
wait_for_companions(pci_dev, hcd);
@ -450,6 +465,8 @@ static int resume_common(struct device *dev, int event)
event == PM_EVENT_RESTORE);
if (retval) {
dev_err(dev, "PCI post-resume error %d!\n", retval);
if (hcd->shared_hcd)
usb_hc_died(hcd->shared_hcd);
usb_hc_died(hcd);
}
}
@ -475,10 +492,11 @@ static int hcd_pci_suspend_noirq(struct device *dev)
pci_save_state(pci_dev);
/* If the root hub is HALTed rather than SUSPENDed,
* disallow remote wakeup.
/* If the root hub is dead rather than suspended, disallow remote
* wakeup. usb_hc_died() should ensure that both hosts are marked as
* dying, so we only need to check the primary roothub.
*/
if (hcd->state == HC_STATE_HALT)
if (HCD_DEAD(hcd))
device_set_wakeup_enable(dev, 0);
dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev));

View File

@ -297,7 +297,7 @@ static const u8 ss_rh_config_descriptor[] = {
/* one configuration */
0x09, /* __u8 bLength; */
0x02, /* __u8 bDescriptorType; Configuration */
0x19, 0x00, /* __le16 wTotalLength; FIXME */
0x1f, 0x00, /* __le16 wTotalLength; */
0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
@ -327,11 +327,14 @@ static const u8 ss_rh_config_descriptor[] = {
/* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
* see hub.c:hub_configure() for details. */
(USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
/*
* All 3.0 hubs should have an endpoint companion descriptor,
* but we're ignoring that for now. FIXME?
*/
0x0c, /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
/* one SuperSpeed endpoint companion descriptor */
0x06, /* __u8 ss_bLength */
0x30, /* __u8 ss_bDescriptorType; SuperSpeed EP Companion */
0x00, /* __u8 ss_bMaxBurst; allows 1 TX between ACKs */
0x00, /* __u8 ss_bmAttributes; 1 packet per service interval */
0x02, 0x00 /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */
};
/*-------------------------------------------------------------------------*/
@ -504,7 +507,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch (wValue & 0xff00) {
case USB_DT_DEVICE << 8:
switch (hcd->driver->flags & HCD_MASK) {
switch (hcd->speed) {
case HCD_USB3:
bufp = usb3_rh_dev_descriptor;
break;
@ -522,7 +525,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
patch_protocol = 1;
break;
case USB_DT_CONFIG << 8:
switch (hcd->driver->flags & HCD_MASK) {
switch (hcd->speed) {
case HCD_USB3:
bufp = ss_rh_config_descriptor;
len = sizeof ss_rh_config_descriptor;
@ -983,7 +986,7 @@ static int register_root_hub(struct usb_hcd *hcd)
spin_unlock_irq (&hcd_root_hub_lock);
/* Did the HC die before the root hub was registered? */
if (hcd->state == HC_STATE_HALT)
if (HCD_DEAD(hcd) || hcd->state == HC_STATE_HALT)
usb_hc_died (hcd); /* This time clean up */
}
@ -1089,13 +1092,10 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
* Check the host controller's state and add the URB to the
* endpoint's queue.
*/
switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
if (HCD_RH_RUNNING(hcd)) {
urb->unlinked = 0;
list_add_tail(&urb->urb_list, &urb->ep->urb_list);
break;
default:
} else {
rc = -ESHUTDOWN;
goto done;
}
@ -1153,6 +1153,8 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
"Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->shared_hcd)
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
}
return 0;
@ -1262,7 +1264,7 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
*dma_handle = 0;
}
void unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
dma_unmap_single(hcd->self.controller,
@ -1279,13 +1281,21 @@ void unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
/* Make it safe to call this routine more than once */
urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL);
}
EXPORT_SYMBOL_GPL(unmap_urb_setup_for_dma);
EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_setup_for_dma);
void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
if (hcd->driver->unmap_urb_for_dma)
hcd->driver->unmap_urb_for_dma(hcd, urb);
else
usb_hcd_unmap_urb_for_dma(hcd, urb);
}
void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
enum dma_data_direction dir;
unmap_urb_setup_for_dma(hcd, urb);
usb_hcd_unmap_urb_setup_for_dma(hcd, urb);
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (urb->transfer_flags & URB_DMA_MAP_SG)
@ -1314,10 +1324,19 @@ void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
urb->transfer_flags &= ~(URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
URB_DMA_MAP_SINGLE | URB_MAP_LOCAL);
}
EXPORT_SYMBOL_GPL(unmap_urb_for_dma);
EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_for_dma);
static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
if (hcd->driver->map_urb_for_dma)
return hcd->driver->map_urb_for_dma(hcd, urb, mem_flags);
else
return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
}
int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
enum dma_data_direction dir;
int ret = 0;
@ -1410,10 +1429,11 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
}
if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE |
URB_SETUP_MAP_LOCAL)))
unmap_urb_for_dma(hcd, urb);
usb_hcd_unmap_urb_for_dma(hcd, urb);
}
return ret;
}
EXPORT_SYMBOL_GPL(usb_hcd_map_urb_for_dma);
/*-------------------------------------------------------------------------*/
@ -1913,7 +1933,7 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (!HC_IS_RUNNING (hcd->state))
if (!HCD_RH_RUNNING(hcd))
return -ESHUTDOWN;
return hcd->driver->get_frame_number (hcd);
}
@ -1930,9 +1950,15 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
dev_dbg(&rhdev->dev, "bus %s%s\n",
(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend");
if (HCD_DEAD(hcd)) {
dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "suspend");
return 0;
}
if (!hcd->driver->bus_suspend) {
status = -ENOENT;
} else {
clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
hcd->state = HC_STATE_QUIESCING;
status = hcd->driver->bus_suspend(hcd);
}
@ -1940,7 +1966,12 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
hcd->state = HC_STATE_SUSPENDED;
} else {
hcd->state = old_state;
spin_lock_irq(&hcd_root_hub_lock);
if (!HCD_DEAD(hcd)) {
set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
hcd->state = old_state;
}
spin_unlock_irq(&hcd_root_hub_lock);
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"suspend", status);
}
@ -1955,9 +1986,13 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
dev_dbg(&rhdev->dev, "usb %s%s\n",
(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume");
if (HCD_DEAD(hcd)) {
dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "resume");
return 0;
}
if (!hcd->driver->bus_resume)
return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
if (HCD_RH_RUNNING(hcd))
return 0;
hcd->state = HC_STATE_RESUMING;
@ -1966,10 +2001,15 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
if (status == 0) {
/* TRSMRCY = 10 msec */
msleep(10);
usb_set_device_state(rhdev, rhdev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
hcd->state = HC_STATE_RUNNING;
spin_lock_irq(&hcd_root_hub_lock);
if (!HCD_DEAD(hcd)) {
usb_set_device_state(rhdev, rhdev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
hcd->state = HC_STATE_RUNNING;
}
spin_unlock_irq(&hcd_root_hub_lock);
} else {
hcd->state = old_state;
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
@ -2080,12 +2120,14 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
*/
local_irq_save(flags);
if (unlikely(hcd->state == HC_STATE_HALT || !HCD_HW_ACCESSIBLE(hcd))) {
if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) {
rc = IRQ_NONE;
} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
rc = IRQ_NONE;
} else {
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->shared_hcd)
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
if (unlikely(hcd->state == HC_STATE_HALT))
usb_hc_died(hcd);
@ -2105,7 +2147,9 @@ EXPORT_SYMBOL_GPL(usb_hcd_irq);
*
* This is called by bus glue to report a USB host controller that died
* while operations may still have been pending. It's called automatically
* by the PCI glue, so only glue for non-PCI busses should need to call it.
* by the PCI glue, so only glue for non-PCI busses should need to call it.
*
* Only call this function with the primary HCD.
*/
void usb_hc_died (struct usb_hcd *hcd)
{
@ -2114,6 +2158,8 @@ void usb_hc_died (struct usb_hcd *hcd)
dev_err (hcd->self.controller, "HC died; cleaning up\n");
spin_lock_irqsave (&hcd_root_hub_lock, flags);
clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
set_bit(HCD_FLAG_DEAD, &hcd->flags);
if (hcd->rh_registered) {
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
@ -2122,12 +2168,90 @@ void usb_hc_died (struct usb_hcd *hcd)
USB_STATE_NOTATTACHED);
usb_kick_khubd (hcd->self.root_hub);
}
if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
hcd = hcd->shared_hcd;
if (hcd->rh_registered) {
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
/* make khubd clean up old urbs and devices */
usb_set_device_state(hcd->self.root_hub,
USB_STATE_NOTATTACHED);
usb_kick_khubd(hcd->self.root_hub);
}
}
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
/* Make sure that the other roothub is also deallocated. */
}
EXPORT_SYMBOL_GPL (usb_hc_died);
/*-------------------------------------------------------------------------*/
/**
* usb_create_shared_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
* @dev: device for this HC, stored in hcd->self.controller
* @bus_name: value to store in hcd->self.bus_name
* @primary_hcd: a pointer to the usb_hcd structure that is sharing the
* PCI device. Only allocate certain resources for the primary HCD
* Context: !in_interrupt()
*
* Allocate a struct usb_hcd, with extra space at the end for the
* HC driver's private data. Initialize the generic members of the
* hcd structure.
*
* If memory is unavailable, returns NULL.
*/
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name,
struct usb_hcd *primary_hcd)
{
struct usb_hcd *hcd;
hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
if (!hcd) {
dev_dbg (dev, "hcd alloc failed\n");
return NULL;
}
if (primary_hcd == NULL) {
hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
GFP_KERNEL);
if (!hcd->bandwidth_mutex) {
kfree(hcd);
dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
return NULL;
}
mutex_init(hcd->bandwidth_mutex);
dev_set_drvdata(dev, hcd);
} else {
hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
hcd->primary_hcd = primary_hcd;
primary_hcd->primary_hcd = primary_hcd;
hcd->shared_hcd = primary_hcd;
primary_hcd->shared_hcd = hcd;
}
kref_init(&hcd->kref);
usb_bus_init(&hcd->self);
hcd->self.controller = dev;
hcd->self.bus_name = bus_name;
hcd->self.uses_dma = (dev->dma_mask != NULL);
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_USB_SUSPEND
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
hcd->driver = driver;
hcd->speed = driver->flags & HCD_MASK;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
return hcd;
}
EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
/**
* usb_create_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
@ -2141,43 +2265,31 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
*
* If memory is unavailable, returns NULL.
*/
struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name)
{
struct usb_hcd *hcd;
hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
if (!hcd) {
dev_dbg (dev, "hcd alloc failed\n");
return NULL;
}
dev_set_drvdata(dev, hcd);
kref_init(&hcd->kref);
usb_bus_init(&hcd->self);
hcd->self.controller = dev;
hcd->self.bus_name = bus_name;
hcd->self.uses_dma = (dev->dma_mask != NULL);
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_USB_SUSPEND
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
mutex_init(&hcd->bandwidth_mutex);
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
return hcd;
return usb_create_shared_hcd(driver, dev, bus_name, NULL);
}
EXPORT_SYMBOL_GPL(usb_create_hcd);
/*
* Roothubs that share one PCI device must also share the bandwidth mutex.
* Don't deallocate the bandwidth_mutex until the last shared usb_hcd is
* deallocated.
*
* Make sure to only deallocate the bandwidth_mutex when the primary HCD is
* freed. When hcd_release() is called for the non-primary HCD, set the
* primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be
* freed shortly).
*/
static void hcd_release (struct kref *kref)
{
struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
if (usb_hcd_is_primary_hcd(hcd))
kfree(hcd->bandwidth_mutex);
else
hcd->shared_hcd->shared_hcd = NULL;
kfree(hcd);
}
@ -2196,6 +2308,54 @@ void usb_put_hcd (struct usb_hcd *hcd)
}
EXPORT_SYMBOL_GPL(usb_put_hcd);
int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
{
if (!hcd->primary_hcd)
return 1;
return hcd == hcd->primary_hcd;
}
EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
static int usb_hcd_request_irqs(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags)
{
int retval;
if (hcd->driver->irq) {
/* IRQF_DISABLED doesn't work as advertised when used together
* with IRQF_SHARED. As usb_hcd_irq() will always disable
* interrupts we can remove it here.
*/
if (irqflags & IRQF_SHARED)
irqflags &= ~IRQF_DISABLED;
snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
hcd->driver->description, hcd->self.busnum);
retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
hcd->irq_descr, hcd);
if (retval != 0) {
dev_err(hcd->self.controller,
"request interrupt %d failed\n",
irqnum);
return retval;
}
hcd->irq = irqnum;
dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum,
(hcd->driver->flags & HCD_MEMORY) ?
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
} else {
hcd->irq = -1;
if (hcd->rsrc_start)
dev_info(hcd->self.controller, "%s 0x%08llx\n",
(hcd->driver->flags & HCD_MEMORY) ?
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
}
return 0;
}
/**
* usb_add_hcd - finish generic HCD structure initialization and register
* @hcd: the usb_hcd structure to initialize
@ -2236,7 +2396,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
hcd->self.root_hub = rhdev;
switch (hcd->driver->flags & HCD_MASK) {
switch (hcd->speed) {
case HCD_USB11:
rhdev->speed = USB_SPEED_FULL;
break;
@ -2256,6 +2416,12 @@ int usb_add_hcd(struct usb_hcd *hcd,
*/
device_init_wakeup(&rhdev->dev, 1);
/* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
* registered. But since the controller can die at any time,
* let's initialize the flag before touching the hardware.
*/
set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
/* "reset" is misnamed; its role is now one-time init. the controller
* should already have been reset (and boot firmware kicked off etc).
*/
@ -2271,38 +2437,15 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
/* enable irqs just before we start the controller */
if (hcd->driver->irq) {
/* IRQF_DISABLED doesn't work as advertised when used together
* with IRQF_SHARED. As usb_hcd_irq() will always disable
* interrupts we can remove it here.
*/
if (irqflags & IRQF_SHARED)
irqflags &= ~IRQF_DISABLED;
snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
hcd->driver->description, hcd->self.busnum);
if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
hcd->irq_descr, hcd)) != 0) {
dev_err(hcd->self.controller,
"request interrupt %d failed\n", irqnum);
if (usb_hcd_is_primary_hcd(hcd)) {
retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);
if (retval)
goto err_request_irq;
}
hcd->irq = irqnum;
dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum,
(hcd->driver->flags & HCD_MEMORY) ?
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
} else {
hcd->irq = -1;
if (hcd->rsrc_start)
dev_info(hcd->self.controller, "%s 0x%08llx\n",
(hcd->driver->flags & HCD_MEMORY) ?
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
}
if ((retval = hcd->driver->start(hcd)) < 0) {
hcd->state = HC_STATE_RUNNING;
retval = hcd->driver->start(hcd);
if (retval < 0) {
dev_err(hcd->self.controller, "startup error %d\n", retval);
goto err_hcd_driver_start;
}
@ -2323,6 +2466,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
return retval;
error_create_attr_group:
clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
if (HC_IS_RUNNING(hcd->state))
hcd->state = HC_STATE_QUIESCING;
spin_lock_irq(&hcd_root_hub_lock);
@ -2344,7 +2488,7 @@ err_register_root_hub:
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
err_hcd_driver_start:
if (hcd->irq >= 0)
if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0)
free_irq(irqnum, hcd);
err_request_irq:
err_hcd_driver_setup:
@ -2375,6 +2519,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_get_dev(rhdev);
sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group);
clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
if (HC_IS_RUNNING (hcd->state))
hcd->state = HC_STATE_QUIESCING;
@ -2407,8 +2552,10 @@ void usb_remove_hcd(struct usb_hcd *hcd)
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
if (hcd->irq >= 0)
free_irq(hcd->irq, hcd);
if (usb_hcd_is_primary_hcd(hcd)) {
if (hcd->irq >= 0)
free_irq(hcd->irq, hcd);
}
usb_put_dev(hcd->self.root_hub);
usb_deregister_bus(&hcd->self);

View File

@ -82,6 +82,10 @@ struct usb_hub {
void **port_owners;
};
static inline int hub_is_superspeed(struct usb_device *hdev)
{
return (hdev->descriptor.bDeviceProtocol == 3);
}
/* Protect struct usb_device->state and ->children members
* Note: Both are also protected by ->dev.sem, except that ->state can
@ -151,14 +155,14 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
static int usb_reset_and_verify_device(struct usb_device *udev);
static inline char *portspeed(int portstatus)
static inline char *portspeed(struct usb_hub *hub, int portstatus)
{
if (hub_is_superspeed(hub->hdev))
return "5.0 Gb/s";
if (portstatus & USB_PORT_STAT_HIGH_SPEED)
return "480 Mb/s";
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
return "1.5 Mb/s";
else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
return "5.0 Gb/s";
else
return "12 Mb/s";
}
@ -172,14 +176,23 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
}
/* USB 2.0 spec Section 11.24.4.5 */
static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
static int get_hub_descriptor(struct usb_device *hdev, void *data)
{
int i, ret;
int i, ret, size;
unsigned dtype;
if (hub_is_superspeed(hdev)) {
dtype = USB_DT_SS_HUB;
size = USB_DT_SS_HUB_SIZE;
} else {
dtype = USB_DT_HUB;
size = sizeof(struct usb_hub_descriptor);
}
for (i = 0; i < 3; i++) {
ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
USB_DT_HUB << 8, 0, data, size,
dtype << 8, 0, data, size,
USB_CTRL_GET_TIMEOUT);
if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
return ret;
@ -365,6 +378,16 @@ static int hub_port_status(struct usb_hub *hub, int port1,
} else {
*status = le16_to_cpu(hub->status->port.wPortStatus);
*change = le16_to_cpu(hub->status->port.wPortChange);
if ((hub->hdev->parent != NULL) &&
hub_is_superspeed(hub->hdev)) {
/* Translate the USB 3 port status */
u16 tmp = *status & USB_SS_PORT_STAT_MASK;
if (*status & USB_SS_PORT_STAT_POWER)
tmp |= USB_PORT_STAT_POWER;
*status = tmp;
}
ret = 0;
}
mutex_unlock(&hub->status_mutex);
@ -607,7 +630,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
if (hdev->children[port1-1] && set_state)
usb_set_device_state(hdev->children[port1-1],
USB_STATE_NOTATTACHED);
if (!hub->error)
if (!hub->error && !hub_is_superspeed(hub->hdev))
ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
if (ret)
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
@ -616,7 +639,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
}
/*
* Disable a port and mark a logical connnect-change event, so that some
* Disable a port and mark a logical connect-change event, so that some
* time later khubd will disconnect() any existing usb_device on the port
* and will re-enumerate if there actually is a device attached.
*/
@ -769,12 +792,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
* USB3 protocol ports will automatically transition
* to Enabled state when detect an USB3.0 device attach.
* Do not disable USB3 protocol ports.
* FIXME: USB3 root hub and external hubs are treated
* differently here.
*/
if (hdev->descriptor.bDeviceProtocol != 3 ||
(!hdev->parent &&
!(portstatus & USB_PORT_STAT_SUPER_SPEED))) {
if (!hub_is_superspeed(hdev)) {
clear_port_feature(hdev, port1,
USB_PORT_FEAT_ENABLE);
portstatus &= ~USB_PORT_STAT_ENABLE;
@ -795,6 +814,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_ENABLE);
}
if (portchange & USB_PORT_STAT_C_LINK_STATE) {
need_debounce_delay = true;
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_PORT_LINK_STATE);
}
/* We can forget about a "removed" device when there's a
* physical disconnect or the connect status changes.
@ -964,12 +988,23 @@ static int hub_configure(struct usb_hub *hub,
goto fail;
}
if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) {
ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
HUB_SET_DEPTH, USB_RT_HUB,
hdev->level - 1, 0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (ret < 0) {
message = "can't set hub depth";
goto fail;
}
}
/* Request the entire hub descriptor.
* hub->descriptor can handle USB_MAXCHILDREN ports,
* but the hub can/will return fewer bytes here.
*/
ret = get_hub_descriptor(hdev, hub->descriptor,
sizeof(*hub->descriptor));
ret = get_hub_descriptor(hdev, hub->descriptor);
if (ret < 0) {
message = "can't read hub descriptor";
goto fail;
@ -991,12 +1026,14 @@ static int hub_configure(struct usb_hub *hub,
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
/* FIXME for USB 3.0, skip for now */
if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
!(hub_is_superspeed(hdev))) {
int i;
char portstr [USB_MAXCHILDREN + 1];
for (i = 0; i < hdev->maxchild; i++)
portstr[i] = hub->descriptor->DeviceRemovable
portstr[i] = hub->descriptor->u.hs.DeviceRemovable
[((i + 1) / 8)] & (1 << ((i + 1) % 8))
? 'F' : 'R';
portstr[hdev->maxchild] = 0;
@ -1253,8 +1290,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
/* Hubs have proper suspend/resume support */
usb_enable_autosuspend(hdev);
/* Hubs have proper suspend/resume support. USB 3.0 device suspend is
* different from USB 2.0/1.1 device suspend, and unfortunately we
* don't support it yet. So leave autosuspend disabled for USB 3.0
* external hubs for now. Enable autosuspend for USB 3.0 roothubs,
* since that isn't a "real" hub.
*/
if (!hub_is_superspeed(hdev) || !hdev->parent)
usb_enable_autosuspend(hdev);
if (hdev->level == MAX_TOPO_LEVEL) {
dev_err(&intf->dev,
@ -1501,6 +1544,13 @@ void usb_set_device_state(struct usb_device *udev,
EXPORT_SYMBOL_GPL(usb_set_device_state);
/*
* Choose a device number.
*
* Device numbers are used as filenames in usbfs. On USB-1.1 and
* USB-2.0 buses they are also used as device addresses, however on
* USB-3.0 buses the address is assigned by the controller hardware
* and it usually is not the same as the device number.
*
* WUSB devices are simple: they have no hubs behind, so the mapping
* device <-> virtual port number becomes 1:1. Why? to simplify the
* life of the device connection logic in
@ -1522,7 +1572,7 @@ EXPORT_SYMBOL_GPL(usb_set_device_state);
* the HCD must setup data structures before issuing a set address
* command to the hardware.
*/
static void choose_address(struct usb_device *udev)
static void choose_devnum(struct usb_device *udev)
{
int devnum;
struct usb_bus *bus = udev->bus;
@ -1547,7 +1597,7 @@ static void choose_address(struct usb_device *udev)
}
}
static void release_address(struct usb_device *udev)
static void release_devnum(struct usb_device *udev)
{
if (udev->devnum > 0) {
clear_bit(udev->devnum, udev->bus->devmap.devicemap);
@ -1555,7 +1605,7 @@ static void release_address(struct usb_device *udev)
}
}
static void update_address(struct usb_device *udev, int devnum)
static void update_devnum(struct usb_device *udev, int devnum)
{
/* The address for a WUSB device is managed by wusbcore. */
if (!udev->wusb)
@ -1602,7 +1652,8 @@ void usb_disconnect(struct usb_device **pdev)
* this quiesces everyting except pending urbs.
*/
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
dev_info(&udev->dev, "USB disconnect, device number %d\n",
udev->devnum);
usb_lock_device(udev);
@ -1632,7 +1683,7 @@ void usb_disconnect(struct usb_device **pdev)
/* Free the device number and delete the parent's children[]
* (or root_hub) pointer.
*/
release_address(udev);
release_devnum(udev);
/* Avoid races with recursively_mark_NOTATTACHED() */
spin_lock_irq(&device_state_lock);
@ -2017,7 +2068,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
(portstatus & USB_PORT_STAT_ENABLE)) {
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_WIRELESS;
else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
else if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
@ -2073,7 +2124,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
update_address(udev, 0);
update_devnum(udev, 0);
if (hcd->driver->reset_device) {
status = hcd->driver->reset_device(hcd, udev);
if (status < 0) {
@ -2636,7 +2687,7 @@ static int hub_set_address(struct usb_device *udev, int devnum)
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
update_address(udev, devnum);
update_devnum(udev, devnum);
/* Device now using proper address. */
usb_set_device_state(udev, USB_STATE_ADDRESS);
usb_ep0_reinit(udev);
@ -2741,9 +2792,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
if (udev->speed != USB_SPEED_SUPER)
dev_info(&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
"%s %s speed %sUSB device number %d using %s\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, devnum);
devnum, udev->bus->controller->driver->name);
/* Set up TT records, if needed */
if (hdev->tt) {
@ -2773,10 +2824,6 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* value.
*/
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
/*
* An xHCI controller cannot send any packets to a device until
* a set address command successfully completes.
*/
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
struct usb_device_descriptor *buf;
int r = 0;
@ -2859,9 +2906,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (udev->speed == USB_SPEED_SUPER) {
devnum = udev->devnum;
dev_info(&udev->dev,
"%s SuperSpeed USB device using %s and address %d\n",
"%s SuperSpeed USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
udev->bus->controller->driver->name, devnum);
devnum, udev->bus->controller->driver->name);
}
/* cope with hardware quirkiness:
@ -2924,7 +2971,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
fail:
if (retval) {
hub_port_disable(hub, port1, 0);
update_address(udev, devnum); /* for disconnect processing */
update_devnum(udev, devnum); /* for disconnect processing */
}
mutex_unlock(&usb_address0_mutex);
return retval;
@ -3015,7 +3062,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
dev_dbg (hub_dev,
"port %d, status %04x, change %04x, %s\n",
port1, portstatus, portchange, portspeed (portstatus));
port1, portstatus, portchange, portspeed(hub, portstatus));
if (hub->has_indicators) {
set_port_led(hub, port1, HUB_LED_AUTO);
@ -3116,32 +3163,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
udev->level = hdev->level + 1;
udev->wusb = hub_is_wusb(hub);
/*
* USB 3.0 devices are reset automatically before the connect
* port status change appears, and the root hub port status
* shows the correct speed. We also get port change
* notifications for USB 3.0 devices from the USB 3.0 portion of
* an external USB 3.0 hub, but this isn't handled correctly yet
* FIXME.
*/
if (!(hcd->driver->flags & HCD_USB3))
udev->speed = USB_SPEED_UNKNOWN;
else if ((hdev->parent == NULL) &&
(portstatus & USB_PORT_STAT_SUPER_SPEED))
/* Only USB 3.0 devices are connected to SuperSpeed hubs. */
if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else
udev->speed = USB_SPEED_UNKNOWN;
/*
* Set the address.
* Note xHCI needs to issue an address device command later
* in the hub_port_init sequence for SS/HS/FS/LS devices,
* and xHC will assign an address to the device. But use
* kernel assigned address here, to avoid any address conflict
* issue.
*/
choose_address(udev);
choose_devnum(udev);
if (udev->devnum <= 0) {
status = -ENOTCONN; /* Don't retry */
goto loop;
@ -3233,7 +3261,7 @@ loop_disable:
hub_port_disable(hub, port1, 1);
loop:
usb_ep0_reinit(udev);
release_address(udev);
release_devnum(udev);
hub_free_dev(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
@ -3410,12 +3438,19 @@ static void hub_events(void)
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
dev_err (hub_dev,
"over-current change on port %d\n",
i);
u16 status = 0;
u16 unused;
dev_dbg(hub_dev, "over-current change on port "
"%d\n", i);
clear_port_feature(hdev, i,
USB_PORT_FEAT_C_OVER_CURRENT);
msleep(100); /* Cool down */
hub_power_on(hub, true);
hub_port_status(hub, i, &status, &unused);
if (status & USB_PORT_STAT_OVERCURRENT)
dev_err(hub_dev, "over-current "
"condition on port %d\n", i);
}
if (portchange & USB_PORT_STAT_C_RESET) {
@ -3425,6 +3460,25 @@ static void hub_events(void)
clear_port_feature(hdev, i,
USB_PORT_FEAT_C_RESET);
}
if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
hub_is_superspeed(hub->hdev)) {
dev_dbg(hub_dev,
"warm reset change on port %d\n",
i);
clear_port_feature(hdev, i,
USB_PORT_FEAT_C_BH_PORT_RESET);
}
if (portchange & USB_PORT_STAT_C_LINK_STATE) {
clear_port_feature(hub->hdev, i,
USB_PORT_FEAT_C_PORT_LINK_STATE);
}
if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
dev_warn(hub_dev,
"config error on port %d\n",
i);
clear_port_feature(hub->hdev, i,
USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
}
if (connect_change)
hub_port_connect_change(hub, i,
@ -3447,10 +3501,17 @@ static void hub_events(void)
hub->limited_power = 0;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (hub_dev, "overcurrent change\n");
msleep(500); /* Cool down */
u16 status = 0;
u16 unused;
dev_dbg(hub_dev, "over-current change\n");
clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
msleep(500); /* Cool down */
hub_power_on(hub, true);
hub_hub_status(hub, &status, &unused);
if (status & HUB_STATUS_OVERCURRENT)
dev_err(hub_dev, "over-current "
"condition\n");
}
}
@ -3699,13 +3760,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
if (!udev->actconfig)
goto done;
mutex_lock(&hcd->bandwidth_mutex);
mutex_lock(hcd->bandwidth_mutex);
ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
if (ret < 0) {
dev_warn(&udev->dev,
"Busted HC? Not enough HCD resources for "
"old configuration.\n");
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
@ -3716,10 +3777,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
dev_err(&udev->dev,
"can't restore configuration #%d (error=%d)\n",
udev->actconfig->desc.bConfigurationValue, ret);
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
usb_set_device_state(udev, USB_STATE_CONFIGURED);
/* Put interfaces back into the same altsettings as before.

View File

@ -1284,12 +1284,12 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
/* Make sure we have enough bandwidth for this alternate interface.
* Remove the current alt setting and add the new alt setting.
*/
mutex_lock(&hcd->bandwidth_mutex);
mutex_lock(hcd->bandwidth_mutex);
ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
if (ret < 0) {
dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
alternate);
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
@ -1311,10 +1311,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
} else if (ret < 0) {
/* Re-instate the old alt setting */
usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
/* FIXME drivers shouldn't need to replicate/bugfix the logic here
* when they implement async or easily-killable versions of this or
@ -1413,7 +1413,7 @@ int usb_reset_configuration(struct usb_device *dev)
config = dev->actconfig;
retval = 0;
mutex_lock(&hcd->bandwidth_mutex);
mutex_lock(hcd->bandwidth_mutex);
/* Make sure we have enough bandwidth for each alternate setting 0 */
for (i = 0; i < config->desc.bNumInterfaces; i++) {
struct usb_interface *intf = config->interface[i];
@ -1442,7 +1442,7 @@ reset_old_alts:
usb_hcd_alloc_bandwidth(dev, NULL,
alt, intf->cur_altsetting);
}
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
return retval;
}
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@ -1451,7 +1451,7 @@ reset_old_alts:
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0)
goto reset_old_alts;
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
/* re-init hc/hcd interface/endpoint state */
for (i = 0; i < config->desc.bNumInterfaces; i++) {
@ -1739,10 +1739,10 @@ free_interfaces:
* host controller will not allow submissions to dropped endpoints. If
* this call fails, the device state is unchanged.
*/
mutex_lock(&hcd->bandwidth_mutex);
mutex_lock(hcd->bandwidth_mutex);
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
if (ret < 0) {
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
}
@ -1761,11 +1761,11 @@ free_interfaces:
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
}
mutex_unlock(&hcd->bandwidth_mutex);
mutex_unlock(hcd->bandwidth_mutex);
usb_set_device_state(dev, USB_STATE_CONFIGURED);
/* Initialize the new interface structures and the

View File

@ -366,7 +366,16 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* FIXME SuperSpeed isoc endpoints have up to 16 bursts */
/* SuperSpeed isoc endpoints have up to 16 bursts of up to
* 3 packets each
*/
if (dev->speed == USB_SPEED_SUPER) {
int burst = 1 + ep->ss_ep_comp.bMaxBurst;
int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
max *= burst;
max *= mult;
}
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) {
int mult = 1 + ((max >> 11) & 0x03);

View File

@ -122,6 +122,19 @@ static inline int is_usb_device_driver(struct device_driver *drv)
for_devices;
}
/* translate USB error codes to codes user space understands */
static inline int usb_translate_errors(int error_code)
{
switch (error_code) {
case 0:
case -ENOMEM:
case -ENODEV:
return error_code;
default:
return -EIO;
}
}
/* for labeling diagnostics */
extern const char *usbcore_name;

View File

@ -601,7 +601,7 @@ try_again:
dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
goto err;
}
dbgp_printk("small write doned\n");
dbgp_printk("small write done\n");
dbgp_not_safe = 0;
return 0;

View File

@ -176,6 +176,18 @@ config USB_FSL_USB2
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_FUSB300
boolean "Faraday FUSB300 USB Peripheral Controller"
select USB_GADGET_DUALSPEED
help
Faraday usb device controller FUSB300 driver
config USB_FUSB300
tristate
depends on USB_GADGET_FUSB300
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_LH7A40X
boolean "LH7A40X"
depends on ARCH_LH7A40X
@ -540,7 +552,7 @@ config USB_GADGET_CI13XXX_MSM
boolean "MIPS USB CI13xxx for MSM"
depends on ARCH_MSM
select USB_GADGET_DUALSPEED
select USB_MSM_OTG_72K
select USB_MSM_OTG
help
MSM SoC has chipidea USB controller. This driver uses
ci13xxx_udc core.

View File

@ -28,6 +28,7 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
mv_udc-y := mv_udc_core.o mv_udc_phy.o
obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
#
# USB gadget drivers

View File

@ -1798,8 +1798,10 @@ static int __init at91udc_probe(struct platform_device *pdev)
}
retval = device_register(&udc->gadget.dev);
if (retval < 0)
if (retval < 0) {
put_device(&udc->gadget.dev);
goto fail0b;
}
/* don't do anything until we have both gadget driver and VBUS */
clk_enable(udc->iclk);

View File

@ -434,20 +434,6 @@ static int hw_ep_get_halt(int num, int dir)
return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0;
}
/**
* hw_ep_is_primed: test if endpoint is primed (execute without interruption)
* @num: endpoint number
* @dir: endpoint direction
*
* This function returns true if endpoint primed
*/
static int hw_ep_is_primed(int num, int dir)
{
u32 reg = hw_cread(CAP_ENDPTPRIME, ~0) | hw_cread(CAP_ENDPTSTAT, ~0);
return test_bit(hw_ep_bit(num, dir), (void *)&reg);
}
/**
* hw_test_and_clear_setup_status: test & clear setup status (execute without
* interruption)
@ -472,10 +458,6 @@ static int hw_ep_prime(int num, int dir, int is_ctrl)
{
int n = hw_ep_bit(num, dir);
/* the caller should flush first */
if (hw_ep_is_primed(num, dir))
return -EBUSY;
if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
return -EAGAIN;
@ -1434,6 +1416,8 @@ static inline u8 _usb_addr(struct ci13xxx_ep *ep)
static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
unsigned i;
int ret = 0;
unsigned length = mReq->req.length;
trace("%p, %p", mEp, mReq);
@ -1441,53 +1425,91 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
if (mReq->req.status == -EALREADY)
return -EALREADY;
if (hw_ep_is_primed(mEp->num, mEp->dir))
return -EBUSY;
mReq->req.status = -EALREADY;
if (mReq->req.length && !mReq->req.dma) {
if (length && !mReq->req.dma) {
mReq->req.dma = \
dma_map_single(mEp->device, mReq->req.buf,
mReq->req.length, mEp->dir ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
length, mEp->dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE);
if (mReq->req.dma == 0)
return -ENOMEM;
mReq->map = 1;
}
if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
&mReq->zdma);
if (mReq->zptr == NULL) {
if (mReq->map) {
dma_unmap_single(mEp->device, mReq->req.dma,
length, mEp->dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE);
mReq->req.dma = 0;
mReq->map = 0;
}
return -ENOMEM;
}
memset(mReq->zptr, 0, sizeof(*mReq->zptr));
mReq->zptr->next = TD_TERMINATE;
mReq->zptr->token = TD_STATUS_ACTIVE;
if (!mReq->req.no_interrupt)
mReq->zptr->token |= TD_IOC;
}
/*
* TD configuration
* TODO - handle requests which spawns into several TDs
*/
memset(mReq->ptr, 0, sizeof(*mReq->ptr));
mReq->ptr->next |= TD_TERMINATE;
mReq->ptr->token = mReq->req.length << ffs_nr(TD_TOTAL_BYTES);
mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
mReq->ptr->token &= TD_TOTAL_BYTES;
mReq->ptr->token |= TD_IOC;
mReq->ptr->token |= TD_STATUS_ACTIVE;
if (mReq->zptr) {
mReq->ptr->next = mReq->zdma;
} else {
mReq->ptr->next = TD_TERMINATE;
if (!mReq->req.no_interrupt)
mReq->ptr->token |= TD_IOC;
}
mReq->ptr->page[0] = mReq->req.dma;
for (i = 1; i < 5; i++)
mReq->ptr->page[i] =
(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
/*
* QH configuration
* At this point it's guaranteed exclusive access to qhead
* (endpt is not primed) so it's no need to use tripwire
*/
if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req *mReqPrev;
int n = hw_ep_bit(mEp->num, mEp->dir);
int tmp_stat;
mReqPrev = list_entry(mEp->qh.queue.prev,
struct ci13xxx_req, queue);
if (mReqPrev->zptr)
mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
else
mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
wmb();
if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto done;
do {
hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
} while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
if (tmp_stat)
goto done;
}
/* QH configuration */
mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
if (mReq->req.zero == 0)
mEp->qh.ptr->cap |= QH_ZLT;
else
mEp->qh.ptr->cap &= ~QH_ZLT;
mEp->qh.ptr->cap |= QH_ZLT;
wmb(); /* synchronize before ep prime */
return hw_ep_prime(mEp->num, mEp->dir,
ret = hw_ep_prime(mEp->num, mEp->dir,
mEp->type == USB_ENDPOINT_XFER_CONTROL);
done:
return ret;
}
/**
@ -1504,8 +1526,15 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
if (mReq->req.status != -EALREADY)
return -EINVAL;
if (hw_ep_is_primed(mEp->num, mEp->dir))
hw_ep_flush(mEp->num, mEp->dir);
if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
return -EBUSY;
if (mReq->zptr) {
if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
return -EBUSY;
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
mReq->zptr = NULL;
}
mReq->req.status = 0;
@ -1517,9 +1546,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
}
mReq->req.status = mReq->ptr->token & TD_STATUS;
if ((TD_STATUS_ACTIVE & mReq->req.status) != 0)
mReq->req.status = -ECONNRESET;
else if ((TD_STATUS_HALTED & mReq->req.status) != 0)
if ((TD_STATUS_HALTED & mReq->req.status) != 0)
mReq->req.status = -1;
else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
mReq->req.status = -1;
@ -1581,12 +1608,19 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
{
struct usb_ep *ep;
struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
unsigned long flags;
trace("%p", gadget);
if (gadget == NULL)
return -EINVAL;
spin_lock_irqsave(udc->lock, flags);
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->remote_wakeup = 0;
udc->suspended = 0;
spin_unlock_irqrestore(udc->lock, flags);
/* flush all endpoints */
gadget_for_each_ep(ep, gadget) {
usb_ep_fifo_flush(ep);
@ -1720,7 +1754,8 @@ __acquires(mEp->lock)
}
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
/* TODO: D1 - Remote Wakeup; D0 - Self Powered */
/* Assume that device is bus powered for now. */
*((u16 *)req->buf) = _udc->remote_wakeup << 1;
retval = 0;
} else if ((setup->bRequestType & USB_RECIP_MASK) \
== USB_RECIP_ENDPOINT) {
@ -1748,6 +1783,28 @@ __acquires(mEp->lock)
return retval;
}
/**
* isr_setup_status_complete: setup_status request complete function
* @ep: endpoint
* @req: request handled
*
* Caller must release lock. Put the port in test mode if test mode
* feature is selected.
*/
static void
isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
{
struct ci13xxx *udc = req->context;
unsigned long flags;
trace("%p, %p", ep, req);
spin_lock_irqsave(udc->lock, flags);
if (udc->test_mode)
hw_port_test_set(udc->test_mode);
spin_unlock_irqrestore(udc->lock, flags);
}
/**
* isr_setup_status_phase: queues the status phase of a setup transation
* @udc: udc struct
@ -1764,6 +1821,8 @@ __acquires(mEp->lock)
trace("%p", udc);
mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
udc->status->context = udc;
udc->status->complete = isr_setup_status_complete;
spin_unlock(mEp->lock);
retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
@ -1783,7 +1842,7 @@ static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
__releases(mEp->lock)
__acquires(mEp->lock)
{
struct ci13xxx_req *mReq;
struct ci13xxx_req *mReq, *mReqTemp;
int retval;
trace("%p", mEp);
@ -1791,34 +1850,25 @@ __acquires(mEp->lock)
if (list_empty(&mEp->qh.queue))
return -EINVAL;
/* pop oldest request */
mReq = list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
list_del_init(&mReq->queue);
list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
queue) {
retval = _hardware_dequeue(mEp, mReq);
if (retval < 0)
break;
list_del_init(&mReq->queue);
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
}
}
retval = _hardware_dequeue(mEp, mReq);
if (retval < 0) {
if (retval == EBUSY)
retval = 0;
if (retval < 0)
dbg_event(_usb_addr(mEp), "DONE", retval);
goto done;
}
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req* mReqEnq;
mReqEnq = list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
_hardware_enqueue(mEp, mReqEnq);
}
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
}
done:
return retval;
}
@ -1833,6 +1883,7 @@ __releases(udc->lock)
__acquires(udc->lock)
{
unsigned i;
u8 tmode = 0;
trace("%p", udc);
@ -1895,22 +1946,32 @@ __acquires(udc->lock)
switch (req.bRequest) {
case USB_REQ_CLEAR_FEATURE:
if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT)
goto delegate;
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
num &= USB_ENDPOINT_NUMBER_MASK;
if (!udc->ci13xxx_ep[num].wedge) {
spin_unlock(udc->lock);
err = usb_ep_clear_halt(
&udc->ci13xxx_ep[num].ep);
spin_lock(udc->lock);
if (err)
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
le16_to_cpu(req.wValue) ==
USB_ENDPOINT_HALT) {
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
num &= USB_ENDPOINT_NUMBER_MASK;
if (!udc->ci13xxx_ep[num].wedge) {
spin_unlock(udc->lock);
err = usb_ep_clear_halt(
&udc->ci13xxx_ep[num].ep);
spin_lock(udc->lock);
if (err)
break;
}
err = isr_setup_status_phase(udc);
} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
le16_to_cpu(req.wValue) ==
USB_DEVICE_REMOTE_WAKEUP) {
if (req.wLength != 0)
break;
udc->remote_wakeup = 0;
err = isr_setup_status_phase(udc);
} else {
goto delegate;
}
err = isr_setup_status_phase(udc);
break;
case USB_REQ_GET_STATUS:
if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
@ -1934,20 +1995,48 @@ __acquires(udc->lock)
err = isr_setup_status_phase(udc);
break;
case USB_REQ_SET_FEATURE:
if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT)
goto delegate;
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
num &= USB_ENDPOINT_NUMBER_MASK;
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
le16_to_cpu(req.wValue) ==
USB_ENDPOINT_HALT) {
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
num &= USB_ENDPOINT_NUMBER_MASK;
spin_unlock(udc->lock);
err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
spin_lock(udc->lock);
if (err)
break;
err = isr_setup_status_phase(udc);
spin_unlock(udc->lock);
err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
spin_lock(udc->lock);
if (!err)
isr_setup_status_phase(udc);
} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
if (req.wLength != 0)
break;
switch (le16_to_cpu(req.wValue)) {
case USB_DEVICE_REMOTE_WAKEUP:
udc->remote_wakeup = 1;
err = isr_setup_status_phase(udc);
break;
case USB_DEVICE_TEST_MODE:
tmode = le16_to_cpu(req.wIndex) >> 8;
switch (tmode) {
case TEST_J:
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
case TEST_FORCE_EN:
udc->test_mode = tmode;
err = isr_setup_status_phase(
udc);
break;
default:
break;
}
default:
goto delegate;
}
} else {
goto delegate;
}
break;
default:
delegate:
@ -2178,15 +2267,15 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
/* push request */
mReq->req.status = -EINPROGRESS;
mReq->req.actual = 0;
list_add_tail(&mReq->queue, &mEp->qh.queue);
if (list_is_singular(&mEp->qh.queue))
retval = _hardware_enqueue(mEp, mReq);
retval = _hardware_enqueue(mEp, mReq);
if (retval == -EALREADY) {
dbg_event(_usb_addr(mEp), "QUEUE", retval);
retval = 0;
}
if (!retval)
list_add_tail(&mReq->queue, &mEp->qh.queue);
done:
spin_unlock_irqrestore(mEp->lock, flags);
@ -2206,19 +2295,25 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
trace("%p, %p", ep, req);
if (ep == NULL || req == NULL || mEp->desc == NULL ||
list_empty(&mReq->queue) || list_empty(&mEp->qh.queue))
if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
mEp->desc == NULL || list_empty(&mReq->queue) ||
list_empty(&mEp->qh.queue))
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
if (mReq->req.status == -EALREADY)
_hardware_dequeue(mEp, mReq);
hw_ep_flush(mEp->num, mEp->dir);
/* pop request */
list_del_init(&mReq->queue);
if (mReq->map) {
dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
mReq->req.dma = 0;
mReq->map = 0;
}
req->status = -ECONNRESET;
if (mReq->req.complete != NULL) {
@ -2377,6 +2472,31 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
return 0;
}
static int ci13xxx_wakeup(struct usb_gadget *_gadget)
{
struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
unsigned long flags;
int ret = 0;
trace();
spin_lock_irqsave(udc->lock, flags);
if (!udc->remote_wakeup) {
ret = -EOPNOTSUPP;
dbg_trace("remote wakeup feature is not enabled\n");
goto out;
}
if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
ret = -EINVAL;
dbg_trace("port is not suspended\n");
goto out;
}
hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
out:
spin_unlock_irqrestore(udc->lock, flags);
return ret;
}
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
@ -2384,6 +2504,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
*/
static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci13xxx_vbus_session,
.wakeup = ci13xxx_wakeup,
};
/**
@ -2626,6 +2747,12 @@ static irqreturn_t udc_irq(void)
isr_statistics.pci++;
udc->gadget.speed = hw_port_is_high_speed() ?
USB_SPEED_HIGH : USB_SPEED_FULL;
if (udc->suspended) {
spin_unlock(udc->lock);
udc->driver->resume(&udc->gadget);
spin_lock(udc->lock);
udc->suspended = 0;
}
}
if (USBi_UEI & intr)
isr_statistics.uei++;
@ -2633,8 +2760,15 @@ static irqreturn_t udc_irq(void)
isr_statistics.ui++;
isr_tr_complete_handler(udc);
}
if (USBi_SLI & intr)
if (USBi_SLI & intr) {
if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
udc->suspended = 1;
spin_unlock(udc->lock);
udc->driver->suspend(&udc->gadget);
spin_lock(udc->lock);
}
isr_statistics.sli++;
}
retval = IRQ_HANDLED;
} else {
isr_statistics.none++;

View File

@ -33,6 +33,7 @@ struct ci13xxx_td {
/* 0 */
u32 next;
#define TD_TERMINATE BIT(0)
#define TD_ADDR_MASK (0xFFFFFFEUL << 5)
/* 1 */
u32 token;
#define TD_STATUS (0x00FFUL << 0)
@ -74,6 +75,8 @@ struct ci13xxx_req {
struct list_head queue;
struct ci13xxx_td *ptr;
dma_addr_t dma;
struct ci13xxx_td *zptr;
dma_addr_t zdma;
};
/* Extension of usb_ep */
@ -125,6 +128,10 @@ struct ci13xxx {
u32 ep0_dir; /* ep0 direction */
#define ep0out ci13xxx_ep[0]
#define ep0in ci13xxx_ep[16]
u8 remote_wakeup; /* Is remote wakeup feature
enabled by the host? */
u8 suspended; /* suspended by the host */
u8 test_mode; /* the selected test mode */
struct usb_gadget_driver *driver; /* 3rd party gadget driver */
struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
@ -152,6 +159,7 @@ struct ci13xxx {
#define USBCMD_RS BIT(0)
#define USBCMD_RST BIT(1)
#define USBCMD_SUTW BIT(13)
#define USBCMD_ATDTW BIT(14)
/* USBSTS & USBINTR */
#define USBi_UI BIT(0)
@ -165,6 +173,7 @@ struct ci13xxx {
#define DEVICEADDR_USBADR (0x7FUL << 25)
/* PORTSC */
#define PORTSC_FPR BIT(6)
#define PORTSC_SUSP BIT(7)
#define PORTSC_HSP BIT(9)
#define PORTSC_PTC (0x0FUL << 16)

View File

@ -813,7 +813,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
*/
req->zero = 0;
req->complete = composite_setup_complete;
req->length = USB_BUFSIZ;
req->length = 0;
gadget->ep0->driver_data = cdev;
switch (ctrl->bRequest) {
@ -887,7 +887,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown;
if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
@ -899,7 +899,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_GET_INTERFACE:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto unknown;
if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
@ -928,7 +928,7 @@ unknown:
*/
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
break;
@ -1258,16 +1258,16 @@ static struct usb_gadget_driver composite_driver = {
* while it was binding. That would usually be done in order to wait for
* some userspace participation.
*/
extern int usb_composite_probe(struct usb_composite_driver *driver,
int usb_composite_probe(struct usb_composite_driver *driver,
int (*bind)(struct usb_composite_dev *cdev))
{
if (!driver || !driver->dev || !bind || composite)
return -EINVAL;
if (!driver->iProduct)
driver->iProduct = driver->name;
if (!driver->name)
driver->name = "composite";
if (!driver->iProduct)
driver->iProduct = driver->name;
composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name;
composite = driver;

View File

@ -1593,8 +1593,8 @@ hub_descriptor (struct usb_hub_descriptor *desc)
desc->bDescLength = 9;
desc->wHubCharacteristics = cpu_to_le16(0x0001);
desc->bNbrPorts = 1;
desc->bitmap [0] = 0xff;
desc->bitmap [1] = 0xff;
desc->u.hs.DeviceRemovable[0] = 0xff;
desc->u.hs.DeviceRemovable[1] = 0xff;
}
static int dummy_hub_control (

View File

@ -128,6 +128,13 @@ ep_matches (
}
}
/*
* If the protocol driver hasn't yet decided on wMaxPacketSize
* and wants to know the maximum possible, provide the info.
*/
if (desc->wMaxPacketSize == 0)
desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket);
/* endpoint maxpacket size is an input parameter, except for bulk
* where it's an output parameter representing the full speed limit.
* the usb spec fixes high speed bulk maxpacket at 512 bytes.

View File

@ -368,6 +368,14 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
req->buf = data;
req->length = len;
/*
* UDC layer requires to provide a buffer even for ZLP, but should
* not use it at all. Let's provide some poisoned pointer to catch
* possible bug in the driver.
*/
if (req->buf == NULL)
req->buf = (void *)0xDEADBABE;
INIT_COMPLETION(ffs->ep0req_completion);
ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);

View File

@ -88,15 +88,18 @@ eenahb:
void fsl_udc_clk_finalize(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
#if defined(CONFIG_ARCH_MX35)
unsigned int v;
#if defined(CONFIG_SOC_IMX35)
if (cpu_is_mx35()) {
unsigned int v;
/* workaround ENGcm09152 for i.MX35 */
if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET));
writel(v | USBPHYCTRL_EVDO, MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET));
/* workaround ENGcm09152 for i.MX35 */
if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET));
writel(v | USBPHYCTRL_EVDO,
MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET));
}
}
#endif

View File

@ -766,7 +766,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
struct fsl_req *req = container_of(_req, struct fsl_req, req);
struct fsl_udc *udc;
unsigned long flags;
int is_iso = 0;
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
@ -781,7 +780,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
if (req->req.length > ep->ep.maxpacket)
return -EMSGSIZE;
is_iso = 1;
}
udc = ep->udc;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,687 @@
/*
* Fusb300 UDC (USB gadget)
*
* Copyright (C) 2010 Faraday Technology Corp.
*
* Author : Yuan-hsin Chen <yhchen@faraday-tech.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __FUSB300_UDC_H__
#define __FUSB300_UDC_H_
#include <linux/kernel.h>
#define FUSB300_OFFSET_GCR 0x00
#define FUSB300_OFFSET_GTM 0x04
#define FUSB300_OFFSET_DAR 0x08
#define FUSB300_OFFSET_CSR 0x0C
#define FUSB300_OFFSET_CXPORT 0x10
#define FUSB300_OFFSET_EPSET0(n) (0x20 + (n - 1) * 0x30)
#define FUSB300_OFFSET_EPSET1(n) (0x24 + (n - 1) * 0x30)
#define FUSB300_OFFSET_EPSET2(n) (0x28 + (n - 1) * 0x30)
#define FUSB300_OFFSET_EPFFR(n) (0x2c + (n - 1) * 0x30)
#define FUSB300_OFFSET_EPSTRID(n) (0x40 + (n - 1) * 0x30)
#define FUSB300_OFFSET_HSPTM 0x300
#define FUSB300_OFFSET_HSCR 0x304
#define FUSB300_OFFSET_SSCR0 0x308
#define FUSB300_OFFSET_SSCR1 0x30C
#define FUSB300_OFFSET_TT 0x310
#define FUSB300_OFFSET_DEVNOTF 0x314
#define FUSB300_OFFSET_DNC1 0x318
#define FUSB300_OFFSET_CS 0x31C
#define FUSB300_OFFSET_SOF 0x324
#define FUSB300_OFFSET_EFCS 0x328
#define FUSB300_OFFSET_IGR0 0x400
#define FUSB300_OFFSET_IGR1 0x404
#define FUSB300_OFFSET_IGR2 0x408
#define FUSB300_OFFSET_IGR3 0x40C
#define FUSB300_OFFSET_IGR4 0x410
#define FUSB300_OFFSET_IGR5 0x414
#define FUSB300_OFFSET_IGER0 0x420
#define FUSB300_OFFSET_IGER1 0x424
#define FUSB300_OFFSET_IGER2 0x428
#define FUSB300_OFFSET_IGER3 0x42C
#define FUSB300_OFFSET_IGER4 0x430
#define FUSB300_OFFSET_IGER5 0x434
#define FUSB300_OFFSET_DMAHMER 0x500
#define FUSB300_OFFSET_EPPRDRDY 0x504
#define FUSB300_OFFSET_DMAEPMR 0x508
#define FUSB300_OFFSET_DMAENR 0x50C
#define FUSB300_OFFSET_DMAAPR 0x510
#define FUSB300_OFFSET_AHBCR 0x514
#define FUSB300_OFFSET_EPPRD_W0(n) (0x520 + (n - 1) * 0x10)
#define FUSB300_OFFSET_EPPRD_W1(n) (0x524 + (n - 1) * 0x10)
#define FUSB300_OFFSET_EPPRD_W2(n) (0x528 + (n - 1) * 0x10)
#define FUSB300_OFFSET_EPRD_PTR(n) (0x52C + (n - 1) * 0x10)
#define FUSB300_OFFSET_BUFDBG_START 0x800
#define FUSB300_OFFSET_BUFDBG_END 0xBFC
#define FUSB300_OFFSET_EPPORT(n) (0x1010 + (n - 1) * 0x10)
/*
* * Global Control Register (offset = 000H)
* */
#define FUSB300_GCR_SF_RST (1 << 8)
#define FUSB300_GCR_VBUS_STATUS (1 << 7)
#define FUSB300_GCR_FORCE_HS_SUSP (1 << 6)
#define FUSB300_GCR_SYNC_FIFO1_CLR (1 << 5)
#define FUSB300_GCR_SYNC_FIFO0_CLR (1 << 4)
#define FUSB300_GCR_FIFOCLR (1 << 3)
#define FUSB300_GCR_GLINTEN (1 << 2)
#define FUSB300_GCR_DEVEN_FS 0x3
#define FUSB300_GCR_DEVEN_HS 0x2
#define FUSB300_GCR_DEVEN_SS 0x1
#define FUSB300_GCR_DEVDIS 0x0
#define FUSB300_GCR_DEVEN_MSK 0x3
/*
* *Global Test Mode (offset = 004H)
* */
#define FUSB300_GTM_TST_DIS_SOFGEN (1 << 16)
#define FUSB300_GTM_TST_CUR_EP_ENTRY(n) ((n & 0xF) << 12)
#define FUSB300_GTM_TST_EP_ENTRY(n) ((n & 0xF) << 8)
#define FUSB300_GTM_TST_EP_NUM(n) ((n & 0xF) << 4)
#define FUSB300_GTM_TST_FIFO_DEG (1 << 1)
#define FUSB300_GTM_TSTMODE (1 << 0)
/*
* * Device Address Register (offset = 008H)
* */
#define FUSB300_DAR_SETCONFG (1 << 7)
#define FUSB300_DAR_DRVADDR(x) (x & 0x7F)
#define FUSB300_DAR_DRVADDR_MSK 0x7F
/*
* *Control Transfer Configuration and Status Register
* (CX_Config_Status, offset = 00CH)
* */
#define FUSB300_CSR_LEN(x) ((x & 0xFFFF) << 8)
#define FUSB300_CSR_LEN_MSK (0xFFFF << 8)
#define FUSB300_CSR_EMP (1 << 4)
#define FUSB300_CSR_FUL (1 << 3)
#define FUSB300_CSR_CLR (1 << 2)
#define FUSB300_CSR_STL (1 << 1)
#define FUSB300_CSR_DONE (1 << 0)
/*
* * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 )
* */
#define FUSB300_EPSET0_CLRSEQNUM (1 << 2)
#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1)
#define FUSB300_EPSET0_STL (1 << 0)
/*
* * EPn Setting 1 (EPn_SET1, offset = 024H+(n-1)*30H, n=1~15)
* */
#define FUSB300_EPSET1_START_ENTRY(x) ((x & 0xFF) << 24)
#define FUSB300_EPSET1_START_ENTRY_MSK (0xFF << 24)
#define FUSB300_EPSET1_FIFOENTRY(x) ((x & 0x1F) << 12)
#define FUSB300_EPSET1_FIFOENTRY_MSK (0x1f << 12)
#define FUSB300_EPSET1_INTERVAL(x) ((x & 0x7) << 6)
#define FUSB300_EPSET1_BWNUM(x) ((x & 0x3) << 4)
#define FUSB300_EPSET1_TYPEISO (1 << 2)
#define FUSB300_EPSET1_TYPEBLK (2 << 2)
#define FUSB300_EPSET1_TYPEINT (3 << 2)
#define FUSB300_EPSET1_TYPE(x) ((x & 0x3) << 2)
#define FUSB300_EPSET1_TYPE_MSK (0x3 << 2)
#define FUSB300_EPSET1_DIROUT (0 << 1)
#define FUSB300_EPSET1_DIRIN (1 << 1)
#define FUSB300_EPSET1_DIR(x) ((x & 0x1) << 1)
#define FUSB300_EPSET1_DIRIN (1 << 1)
#define FUSB300_EPSET1_DIR_MSK ((0x1) << 1)
#define FUSB300_EPSET1_ACTDIS 0
#define FUSB300_EPSET1_ACTEN 1
/*
* *EPn Setting 2 (EPn_SET2, offset = 028H+(n-1)*30H, n=1~15)
* */
#define FUSB300_EPSET2_ADDROFS(x) ((x & 0x7FFF) << 16)
#define FUSB300_EPSET2_ADDROFS_MSK (0x7fff << 16)
#define FUSB300_EPSET2_MPS(x) (x & 0x7FF)
#define FUSB300_EPSET2_MPS_MSK 0x7FF
/*
* * EPn FIFO Register (offset = 2cH+(n-1)*30H)
* */
#define FUSB300_FFR_RST (1 << 31)
#define FUSB300_FF_FUL (1 << 30)
#define FUSB300_FF_EMPTY (1 << 29)
#define FUSB300_FFR_BYCNT 0x1FFFF
/*
* *EPn Stream ID (EPn_STR_ID, offset = 040H+(n-1)*30H, n=1~15)
* */
#define FUSB300_STRID_STREN (1 << 16)
#define FUSB300_STRID_STRID(x) (x & 0xFFFF)
/*
* *HS PHY Test Mode (offset = 300H)
* */
#define FUSB300_HSPTM_TSTPKDONE (1 << 4)
#define FUSB300_HSPTM_TSTPKT (1 << 3)
#define FUSB300_HSPTM_TSTSET0NAK (1 << 2)
#define FUSB300_HSPTM_TSTKSTA (1 << 1)
#define FUSB300_HSPTM_TSTJSTA (1 << 0)
/*
* *HS Control Register (offset = 304H)
* */
#define FUSB300_HSCR_HS_LPM_PERMIT (1 << 8)
#define FUSB300_HSCR_HS_LPM_RMWKUP (1 << 7)
#define FUSB300_HSCR_CAP_LPM_RMWKUP (1 << 6)
#define FUSB300_HSCR_HS_GOSUSP (1 << 5)
#define FUSB300_HSCR_HS_GORMWKU (1 << 4)
#define FUSB300_HSCR_CAP_RMWKUP (1 << 3)
#define FUSB300_HSCR_IDLECNT_0MS 0
#define FUSB300_HSCR_IDLECNT_1MS 1
#define FUSB300_HSCR_IDLECNT_2MS 2
#define FUSB300_HSCR_IDLECNT_3MS 3
#define FUSB300_HSCR_IDLECNT_4MS 4
#define FUSB300_HSCR_IDLECNT_5MS 5
#define FUSB300_HSCR_IDLECNT_6MS 6
#define FUSB300_HSCR_IDLECNT_7MS 7
/*
* * SS Controller Register 0 (offset = 308H)
* */
#define FUSB300_SSCR0_MAX_INTERVAL(x) ((x & 0x7) << 4)
#define FUSB300_SSCR0_U2_FUN_EN (1 << 1)
#define FUSB300_SSCR0_U1_FUN_EN (1 << 0)
/*
* * SS Controller Register 1 (offset = 30CH)
* */
#define FUSB300_SSCR1_GO_U3_DONE (1 << 8)
#define FUSB300_SSCR1_TXDEEMPH_LEVEL (1 << 7)
#define FUSB300_SSCR1_DIS_SCRMB (1 << 6)
#define FUSB300_SSCR1_FORCE_RECOVERY (1 << 5)
#define FUSB300_SSCR1_U3_WAKEUP_EN (1 << 4)
#define FUSB300_SSCR1_U2_EXIT_EN (1 << 3)
#define FUSB300_SSCR1_U1_EXIT_EN (1 << 2)
#define FUSB300_SSCR1_U2_ENTRY_EN (1 << 1)
#define FUSB300_SSCR1_U1_ENTRY_EN (1 << 0)
/*
* *SS Controller Register 2 (offset = 310H)
* */
#define FUSB300_SSCR2_SS_TX_SWING (1 << 25)
#define FUSB300_SSCR2_FORCE_LINKPM_ACCEPT (1 << 24)
#define FUSB300_SSCR2_U2_INACT_TIMEOUT(x) ((x & 0xFF) << 16)
#define FUSB300_SSCR2_U1TIMEOUT(x) ((x & 0xFF) << 8)
#define FUSB300_SSCR2_U2TIMEOUT(x) (x & 0xFF)
/*
* *SS Device Notification Control (DEV_NOTF, offset = 314H)
* */
#define FUSB300_DEVNOTF_CONTEXT0(x) ((x & 0xFFFFFF) << 8)
#define FUSB300_DEVNOTF_TYPE_DIS 0
#define FUSB300_DEVNOTF_TYPE_FUNCWAKE 1
#define FUSB300_DEVNOTF_TYPE_LTM 2
#define FUSB300_DEVNOTF_TYPE_BUSINT_ADJMSG 3
/*
* *BFM Arbiter Priority Register (BFM_ARB offset = 31CH)
* */
#define FUSB300_BFMARB_ARB_M1 (1 << 3)
#define FUSB300_BFMARB_ARB_M0 (1 << 2)
#define FUSB300_BFMARB_ARB_S1 (1 << 1)
#define FUSB300_BFMARB_ARB_S0 1
/*
* *Vendor Specific IO Control Register (offset = 320H)
* */
#define FUSB300_VSIC_VCTLOAD_N (1 << 8)
#define FUSB300_VSIC_VCTL(x) (x & 0x3F)
/*
* *SOF Mask Timer (offset = 324H)
* */
#define FUSB300_SOF_MASK_TIMER_HS 0x044c
#define FUSB300_SOF_MASK_TIMER_FS 0x2710
/*
* *Error Flag and Control Status (offset = 328H)
* */
#define FUSB300_EFCS_PM_STATE_U3 3
#define FUSB300_EFCS_PM_STATE_U2 2
#define FUSB300_EFCS_PM_STATE_U1 1
#define FUSB300_EFCS_PM_STATE_U0 0
/*
* *Interrupt Group 0 Register (offset = 400H)
* */
#define FUSB300_IGR0_EP15_PRD_INT (1 << 31)
#define FUSB300_IGR0_EP14_PRD_INT (1 << 30)
#define FUSB300_IGR0_EP13_PRD_INT (1 << 29)
#define FUSB300_IGR0_EP12_PRD_INT (1 << 28)
#define FUSB300_IGR0_EP11_PRD_INT (1 << 27)
#define FUSB300_IGR0_EP10_PRD_INT (1 << 26)
#define FUSB300_IGR0_EP9_PRD_INT (1 << 25)
#define FUSB300_IGR0_EP8_PRD_INT (1 << 24)
#define FUSB300_IGR0_EP7_PRD_INT (1 << 23)
#define FUSB300_IGR0_EP6_PRD_INT (1 << 22)
#define FUSB300_IGR0_EP5_PRD_INT (1 << 21)
#define FUSB300_IGR0_EP4_PRD_INT (1 << 20)
#define FUSB300_IGR0_EP3_PRD_INT (1 << 19)
#define FUSB300_IGR0_EP2_PRD_INT (1 << 18)
#define FUSB300_IGR0_EP1_PRD_INT (1 << 17)
#define FUSB300_IGR0_EPn_PRD_INT(n) (1 << (n + 16))
#define FUSB300_IGR0_EP15_FIFO_INT (1 << 15)
#define FUSB300_IGR0_EP14_FIFO_INT (1 << 14)
#define FUSB300_IGR0_EP13_FIFO_INT (1 << 13)
#define FUSB300_IGR0_EP12_FIFO_INT (1 << 12)
#define FUSB300_IGR0_EP11_FIFO_INT (1 << 11)
#define FUSB300_IGR0_EP10_FIFO_INT (1 << 10)
#define FUSB300_IGR0_EP9_FIFO_INT (1 << 9)
#define FUSB300_IGR0_EP8_FIFO_INT (1 << 8)
#define FUSB300_IGR0_EP7_FIFO_INT (1 << 7)
#define FUSB300_IGR0_EP6_FIFO_INT (1 << 6)
#define FUSB300_IGR0_EP5_FIFO_INT (1 << 5)
#define FUSB300_IGR0_EP4_FIFO_INT (1 << 4)
#define FUSB300_IGR0_EP3_FIFO_INT (1 << 3)
#define FUSB300_IGR0_EP2_FIFO_INT (1 << 2)
#define FUSB300_IGR0_EP1_FIFO_INT (1 << 1)
#define FUSB300_IGR0_EPn_FIFO_INT(n) (1 << n)
/*
* *Interrupt Group 1 Register (offset = 404H)
* */
#define FUSB300_IGR1_INTGRP5 (1 << 31)
#define FUSB300_IGR1_VBUS_CHG_INT (1 << 30)
#define FUSB300_IGR1_SYNF1_EMPTY_INT (1 << 29)
#define FUSB300_IGR1_SYNF0_EMPTY_INT (1 << 28)
#define FUSB300_IGR1_U3_EXIT_FAIL_INT (1 << 27)
#define FUSB300_IGR1_U2_EXIT_FAIL_INT (1 << 26)
#define FUSB300_IGR1_U1_EXIT_FAIL_INT (1 << 25)
#define FUSB300_IGR1_U2_ENTRY_FAIL_INT (1 << 24)
#define FUSB300_IGR1_U1_ENTRY_FAIL_INT (1 << 23)
#define FUSB300_IGR1_U3_EXIT_INT (1 << 22)
#define FUSB300_IGR1_U2_EXIT_INT (1 << 21)
#define FUSB300_IGR1_U1_EXIT_INT (1 << 20)
#define FUSB300_IGR1_U3_ENTRY_INT (1 << 19)
#define FUSB300_IGR1_U2_ENTRY_INT (1 << 18)
#define FUSB300_IGR1_U1_ENTRY_INT (1 << 17)
#define FUSB300_IGR1_HOT_RST_INT (1 << 16)
#define FUSB300_IGR1_WARM_RST_INT (1 << 15)
#define FUSB300_IGR1_RESM_INT (1 << 14)
#define FUSB300_IGR1_SUSP_INT (1 << 13)
#define FUSB300_IGR1_HS_LPM_INT (1 << 12)
#define FUSB300_IGR1_USBRST_INT (1 << 11)
#define FUSB300_IGR1_DEV_MODE_CHG_INT (1 << 9)
#define FUSB300_IGR1_CX_COMABT_INT (1 << 8)
#define FUSB300_IGR1_CX_COMFAIL_INT (1 << 7)
#define FUSB300_IGR1_CX_CMDEND_INT (1 << 6)
#define FUSB300_IGR1_CX_OUT_INT (1 << 5)
#define FUSB300_IGR1_CX_IN_INT (1 << 4)
#define FUSB300_IGR1_CX_SETUP_INT (1 << 3)
#define FUSB300_IGR1_INTGRP4 (1 << 2)
#define FUSB300_IGR1_INTGRP3 (1 << 1)
#define FUSB300_IGR1_INTGRP2 (1 << 0)
/*
* *Interrupt Group 2 Register (offset = 408H)
* */
#define FUSB300_IGR2_EP6_STR_ACCEPT_INT (1 << 29)
#define FUSB300_IGR2_EP6_STR_RESUME_INT (1 << 28)
#define FUSB300_IGR2_EP6_STR_REQ_INT (1 << 27)
#define FUSB300_IGR2_EP6_STR_NOTRDY_INT (1 << 26)
#define FUSB300_IGR2_EP6_STR_PRIME_INT (1 << 25)
#define FUSB300_IGR2_EP5_STR_ACCEPT_INT (1 << 24)
#define FUSB300_IGR2_EP5_STR_RESUME_INT (1 << 23)
#define FUSB300_IGR2_EP5_STR_REQ_INT (1 << 22)
#define FUSB300_IGR2_EP5_STR_NOTRDY_INT (1 << 21)
#define FUSB300_IGR2_EP5_STR_PRIME_INT (1 << 20)
#define FUSB300_IGR2_EP4_STR_ACCEPT_INT (1 << 19)
#define FUSB300_IGR2_EP4_STR_RESUME_INT (1 << 18)
#define FUSB300_IGR2_EP4_STR_REQ_INT (1 << 17)
#define FUSB300_IGR2_EP4_STR_NOTRDY_INT (1 << 16)
#define FUSB300_IGR2_EP4_STR_PRIME_INT (1 << 15)
#define FUSB300_IGR2_EP3_STR_ACCEPT_INT (1 << 14)
#define FUSB300_IGR2_EP3_STR_RESUME_INT (1 << 13)
#define FUSB300_IGR2_EP3_STR_REQ_INT (1 << 12)
#define FUSB300_IGR2_EP3_STR_NOTRDY_INT (1 << 11)
#define FUSB300_IGR2_EP3_STR_PRIME_INT (1 << 10)
#define FUSB300_IGR2_EP2_STR_ACCEPT_INT (1 << 9)
#define FUSB300_IGR2_EP2_STR_RESUME_INT (1 << 8)
#define FUSB300_IGR2_EP2_STR_REQ_INT (1 << 7)
#define FUSB300_IGR2_EP2_STR_NOTRDY_INT (1 << 6)
#define FUSB300_IGR2_EP2_STR_PRIME_INT (1 << 5)
#define FUSB300_IGR2_EP1_STR_ACCEPT_INT (1 << 4)
#define FUSB300_IGR2_EP1_STR_RESUME_INT (1 << 3)
#define FUSB300_IGR2_EP1_STR_REQ_INT (1 << 2)
#define FUSB300_IGR2_EP1_STR_NOTRDY_INT (1 << 1)
#define FUSB300_IGR2_EP1_STR_PRIME_INT (1 << 0)
#define FUSB300_IGR2_EP_STR_ACCEPT_INT(n) (1 << (5 * n - 1))
#define FUSB300_IGR2_EP_STR_RESUME_INT(n) (1 << (5 * n - 2))
#define FUSB300_IGR2_EP_STR_REQ_INT(n) (1 << (5 * n - 3))
#define FUSB300_IGR2_EP_STR_NOTRDY_INT(n) (1 << (5 * n - 4))
#define FUSB300_IGR2_EP_STR_PRIME_INT(n) (1 << (5 * n - 5))
/*
* *Interrupt Group 3 Register (offset = 40CH)
* */
#define FUSB300_IGR3_EP12_STR_ACCEPT_INT (1 << 29)
#define FUSB300_IGR3_EP12_STR_RESUME_INT (1 << 28)
#define FUSB300_IGR3_EP12_STR_REQ_INT (1 << 27)
#define FUSB300_IGR3_EP12_STR_NOTRDY_INT (1 << 26)
#define FUSB300_IGR3_EP12_STR_PRIME_INT (1 << 25)
#define FUSB300_IGR3_EP11_STR_ACCEPT_INT (1 << 24)
#define FUSB300_IGR3_EP11_STR_RESUME_INT (1 << 23)
#define FUSB300_IGR3_EP11_STR_REQ_INT (1 << 22)
#define FUSB300_IGR3_EP11_STR_NOTRDY_INT (1 << 21)
#define FUSB300_IGR3_EP11_STR_PRIME_INT (1 << 20)
#define FUSB300_IGR3_EP10_STR_ACCEPT_INT (1 << 19)
#define FUSB300_IGR3_EP10_STR_RESUME_INT (1 << 18)
#define FUSB300_IGR3_EP10_STR_REQ_INT (1 << 17)
#define FUSB300_IGR3_EP10_STR_NOTRDY_INT (1 << 16)
#define FUSB300_IGR3_EP10_STR_PRIME_INT (1 << 15)
#define FUSB300_IGR3_EP9_STR_ACCEPT_INT (1 << 14)
#define FUSB300_IGR3_EP9_STR_RESUME_INT (1 << 13)
#define FUSB300_IGR3_EP9_STR_REQ_INT (1 << 12)
#define FUSB300_IGR3_EP9_STR_NOTRDY_INT (1 << 11)
#define FUSB300_IGR3_EP9_STR_PRIME_INT (1 << 10)
#define FUSB300_IGR3_EP8_STR_ACCEPT_INT (1 << 9)
#define FUSB300_IGR3_EP8_STR_RESUME_INT (1 << 8)
#define FUSB300_IGR3_EP8_STR_REQ_INT (1 << 7)
#define FUSB300_IGR3_EP8_STR_NOTRDY_INT (1 << 6)
#define FUSB300_IGR3_EP8_STR_PRIME_INT (1 << 5)
#define FUSB300_IGR3_EP7_STR_ACCEPT_INT (1 << 4)
#define FUSB300_IGR3_EP7_STR_RESUME_INT (1 << 3)
#define FUSB300_IGR3_EP7_STR_REQ_INT (1 << 2)
#define FUSB300_IGR3_EP7_STR_NOTRDY_INT (1 << 1)
#define FUSB300_IGR3_EP7_STR_PRIME_INT (1 << 0)
#define FUSB300_IGR3_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1))
#define FUSB300_IGR3_EP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2))
#define FUSB300_IGR3_EP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3))
#define FUSB300_IGR3_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4))
#define FUSB300_IGR3_EP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5))
/*
* *Interrupt Group 4 Register (offset = 410H)
* */
#define FUSB300_IGR4_EP15_RX0_INT (1 << 31)
#define FUSB300_IGR4_EP14_RX0_INT (1 << 30)
#define FUSB300_IGR4_EP13_RX0_INT (1 << 29)
#define FUSB300_IGR4_EP12_RX0_INT (1 << 28)
#define FUSB300_IGR4_EP11_RX0_INT (1 << 27)
#define FUSB300_IGR4_EP10_RX0_INT (1 << 26)
#define FUSB300_IGR4_EP9_RX0_INT (1 << 25)
#define FUSB300_IGR4_EP8_RX0_INT (1 << 24)
#define FUSB300_IGR4_EP7_RX0_INT (1 << 23)
#define FUSB300_IGR4_EP6_RX0_INT (1 << 22)
#define FUSB300_IGR4_EP5_RX0_INT (1 << 21)
#define FUSB300_IGR4_EP4_RX0_INT (1 << 20)
#define FUSB300_IGR4_EP3_RX0_INT (1 << 19)
#define FUSB300_IGR4_EP2_RX0_INT (1 << 18)
#define FUSB300_IGR4_EP1_RX0_INT (1 << 17)
#define FUSB300_IGR4_EP_RX0_INT(x) (1 << (x + 16))
#define FUSB300_IGR4_EP15_STR_ACCEPT_INT (1 << 14)
#define FUSB300_IGR4_EP15_STR_RESUME_INT (1 << 13)
#define FUSB300_IGR4_EP15_STR_REQ_INT (1 << 12)
#define FUSB300_IGR4_EP15_STR_NOTRDY_INT (1 << 11)
#define FUSB300_IGR4_EP15_STR_PRIME_INT (1 << 10)
#define FUSB300_IGR4_EP14_STR_ACCEPT_INT (1 << 9)
#define FUSB300_IGR4_EP14_STR_RESUME_INT (1 << 8)
#define FUSB300_IGR4_EP14_STR_REQ_INT (1 << 7)
#define FUSB300_IGR4_EP14_STR_NOTRDY_INT (1 << 6)
#define FUSB300_IGR4_EP14_STR_PRIME_INT (1 << 5)
#define FUSB300_IGR4_EP13_STR_ACCEPT_INT (1 << 4)
#define FUSB300_IGR4_EP13_STR_RESUME_INT (1 << 3)
#define FUSB300_IGR4_EP13_STR_REQ_INT (1 << 2)
#define FUSB300_IGR4_EP13_STR_NOTRDY_INT (1 << 1)
#define FUSB300_IGR4_EP13_STR_PRIME_INT (1 << 0)
#define FUSB300_IGR4_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 12) - 1))
#define FUSB300_IGR4_EP_STR_RESUME_INT(n) (1 << (5 * (n - 12) - 2))
#define FUSB300_IGR4_EP_STR_REQ_INT(n) (1 << (5 * (n - 12) - 3))
#define FUSB300_IGR4_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 12) - 4))
#define FUSB300_IGR4_EP_STR_PRIME_INT(n) (1 << (5 * (n - 12) - 5))
/*
* *Interrupt Group 5 Register (offset = 414H)
* */
#define FUSB300_IGR5_EP_STL_INT(n) (1 << n)
/*
* *Interrupt Enable Group 0 Register (offset = 420H)
* */
#define FUSB300_IGER0_EEP15_PRD_INT (1 << 31)
#define FUSB300_IGER0_EEP14_PRD_INT (1 << 30)
#define FUSB300_IGER0_EEP13_PRD_INT (1 << 29)
#define FUSB300_IGER0_EEP12_PRD_INT (1 << 28)
#define FUSB300_IGER0_EEP11_PRD_INT (1 << 27)
#define FUSB300_IGER0_EEP10_PRD_INT (1 << 26)
#define FUSB300_IGER0_EEP9_PRD_INT (1 << 25)
#define FUSB300_IGER0_EP8_PRD_INT (1 << 24)
#define FUSB300_IGER0_EEP7_PRD_INT (1 << 23)
#define FUSB300_IGER0_EEP6_PRD_INT (1 << 22)
#define FUSB300_IGER0_EEP5_PRD_INT (1 << 21)
#define FUSB300_IGER0_EEP4_PRD_INT (1 << 20)
#define FUSB300_IGER0_EEP3_PRD_INT (1 << 19)
#define FUSB300_IGER0_EEP2_PRD_INT (1 << 18)
#define FUSB300_IGER0_EEP1_PRD_INT (1 << 17)
#define FUSB300_IGER0_EEPn_PRD_INT(n) (1 << (n + 16))
#define FUSB300_IGER0_EEP15_FIFO_INT (1 << 15)
#define FUSB300_IGER0_EEP14_FIFO_INT (1 << 14)
#define FUSB300_IGER0_EEP13_FIFO_INT (1 << 13)
#define FUSB300_IGER0_EEP12_FIFO_INT (1 << 12)
#define FUSB300_IGER0_EEP11_FIFO_INT (1 << 11)
#define FUSB300_IGER0_EEP10_FIFO_INT (1 << 10)
#define FUSB300_IGER0_EEP9_FIFO_INT (1 << 9)
#define FUSB300_IGER0_EEP8_FIFO_INT (1 << 8)
#define FUSB300_IGER0_EEP7_FIFO_INT (1 << 7)
#define FUSB300_IGER0_EEP6_FIFO_INT (1 << 6)
#define FUSB300_IGER0_EEP5_FIFO_INT (1 << 5)
#define FUSB300_IGER0_EEP4_FIFO_INT (1 << 4)
#define FUSB300_IGER0_EEP3_FIFO_INT (1 << 3)
#define FUSB300_IGER0_EEP2_FIFO_INT (1 << 2)
#define FUSB300_IGER0_EEP1_FIFO_INT (1 << 1)
#define FUSB300_IGER0_EEPn_FIFO_INT(n) (1 << n)
/*
* *Interrupt Enable Group 1 Register (offset = 424H)
* */
#define FUSB300_IGER1_EINT_GRP5 (1 << 31)
#define FUSB300_IGER1_VBUS_CHG_INT (1 << 30)
#define FUSB300_IGER1_SYNF1_EMPTY_INT (1 << 29)
#define FUSB300_IGER1_SYNF0_EMPTY_INT (1 << 28)
#define FUSB300_IGER1_U3_EXIT_FAIL_INT (1 << 27)
#define FUSB300_IGER1_U2_EXIT_FAIL_INT (1 << 26)
#define FUSB300_IGER1_U1_EXIT_FAIL_INT (1 << 25)
#define FUSB300_IGER1_U2_ENTRY_FAIL_INT (1 << 24)
#define FUSB300_IGER1_U1_ENTRY_FAIL_INT (1 << 23)
#define FUSB300_IGER1_U3_EXIT_INT (1 << 22)
#define FUSB300_IGER1_U2_EXIT_INT (1 << 21)
#define FUSB300_IGER1_U1_EXIT_INT (1 << 20)
#define FUSB300_IGER1_U3_ENTRY_INT (1 << 19)
#define FUSB300_IGER1_U2_ENTRY_INT (1 << 18)
#define FUSB300_IGER1_U1_ENTRY_INT (1 << 17)
#define FUSB300_IGER1_HOT_RST_INT (1 << 16)
#define FUSB300_IGER1_WARM_RST_INT (1 << 15)
#define FUSB300_IGER1_RESM_INT (1 << 14)
#define FUSB300_IGER1_SUSP_INT (1 << 13)
#define FUSB300_IGER1_LPM_INT (1 << 12)
#define FUSB300_IGER1_HS_RST_INT (1 << 11)
#define FUSB300_IGER1_EDEV_MODE_CHG_INT (1 << 9)
#define FUSB300_IGER1_CX_COMABT_INT (1 << 8)
#define FUSB300_IGER1_CX_COMFAIL_INT (1 << 7)
#define FUSB300_IGER1_CX_CMDEND_INT (1 << 6)
#define FUSB300_IGER1_CX_OUT_INT (1 << 5)
#define FUSB300_IGER1_CX_IN_INT (1 << 4)
#define FUSB300_IGER1_CX_SETUP_INT (1 << 3)
#define FUSB300_IGER1_INTGRP4 (1 << 2)
#define FUSB300_IGER1_INTGRP3 (1 << 1)
#define FUSB300_IGER1_INTGRP2 (1 << 0)
/*
* *Interrupt Enable Group 2 Register (offset = 428H)
* */
#define FUSB300_IGER2_EEP_STR_ACCEPT_INT(n) (1 << (5 * n - 1))
#define FUSB300_IGER2_EEP_STR_RESUME_INT(n) (1 << (5 * n - 2))
#define FUSB300_IGER2_EEP_STR_REQ_INT(n) (1 << (5 * n - 3))
#define FUSB300_IGER2_EEP_STR_NOTRDY_INT(n) (1 << (5 * n - 4))
#define FUSB300_IGER2_EEP_STR_PRIME_INT(n) (1 << (5 * n - 5))
/*
* *Interrupt Enable Group 3 Register (offset = 42CH)
* */
#define FUSB300_IGER3_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1))
#define FUSB300_IGER3_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2))
#define FUSB300_IGER3_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3))
#define FUSB300_IGER3_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4))
#define FUSB300_IGER3_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5))
/*
* *Interrupt Enable Group 4 Register (offset = 430H)
* */
#define FUSB300_IGER4_EEP_RX0_INT(n) (1 << (n + 16))
#define FUSB300_IGER4_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1))
#define FUSB300_IGER4_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2))
#define FUSB300_IGER4_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3))
#define FUSB300_IGER4_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4))
#define FUSB300_IGER4_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5))
/* EP PRD Ready (EP_PRD_RDY, offset = 504H) */
#define FUSB300_EPPRDR_EP15_PRD_RDY (1 << 15)
#define FUSB300_EPPRDR_EP14_PRD_RDY (1 << 14)
#define FUSB300_EPPRDR_EP13_PRD_RDY (1 << 13)
#define FUSB300_EPPRDR_EP12_PRD_RDY (1 << 12)
#define FUSB300_EPPRDR_EP11_PRD_RDY (1 << 11)
#define FUSB300_EPPRDR_EP10_PRD_RDY (1 << 10)
#define FUSB300_EPPRDR_EP9_PRD_RDY (1 << 9)
#define FUSB300_EPPRDR_EP8_PRD_RDY (1 << 8)
#define FUSB300_EPPRDR_EP7_PRD_RDY (1 << 7)
#define FUSB300_EPPRDR_EP6_PRD_RDY (1 << 6)
#define FUSB300_EPPRDR_EP5_PRD_RDY (1 << 5)
#define FUSB300_EPPRDR_EP4_PRD_RDY (1 << 4)
#define FUSB300_EPPRDR_EP3_PRD_RDY (1 << 3)
#define FUSB300_EPPRDR_EP2_PRD_RDY (1 << 2)
#define FUSB300_EPPRDR_EP1_PRD_RDY (1 << 1)
#define FUSB300_EPPRDR_EP_PRD_RDY(n) (1 << n)
/* AHB Bus Control Register (offset = 514H) */
#define FUSB300_AHBBCR_S1_SPLIT_ON (1 << 17)
#define FUSB300_AHBBCR_S0_SPLIT_ON (1 << 16)
#define FUSB300_AHBBCR_S1_1entry (0 << 12)
#define FUSB300_AHBBCR_S1_4entry (3 << 12)
#define FUSB300_AHBBCR_S1_8entry (5 << 12)
#define FUSB300_AHBBCR_S1_16entry (7 << 12)
#define FUSB300_AHBBCR_S0_1entry (0 << 8)
#define FUSB300_AHBBCR_S0_4entry (3 << 8)
#define FUSB300_AHBBCR_S0_8entry (5 << 8)
#define FUSB300_AHBBCR_S0_16entry (7 << 8)
#define FUSB300_AHBBCR_M1_BURST_SINGLE (0 << 4)
#define FUSB300_AHBBCR_M1_BURST_INCR (1 << 4)
#define FUSB300_AHBBCR_M1_BURST_INCR4 (3 << 4)
#define FUSB300_AHBBCR_M1_BURST_INCR8 (5 << 4)
#define FUSB300_AHBBCR_M1_BURST_INCR16 (7 << 4)
#define FUSB300_AHBBCR_M0_BURST_SINGLE 0
#define FUSB300_AHBBCR_M0_BURST_INCR 1
#define FUSB300_AHBBCR_M0_BURST_INCR4 3
#define FUSB300_AHBBCR_M0_BURST_INCR8 5
#define FUSB300_AHBBCR_M0_BURST_INCR16 7
#define FUSB300_IGER5_EEP_STL_INT(n) (1 << n)
/* WORD 0 Data Structure of PRD Table */
#define FUSB300_EPPRD0_M (1 << 30)
#define FUSB300_EPPRD0_O (1 << 29)
/* The finished prd */
#define FUSB300_EPPRD0_F (1 << 28)
#define FUSB300_EPPRD0_I (1 << 27)
#define FUSB300_EPPRD0_A (1 << 26)
/* To decide HW point to first prd at next time */
#define FUSB300_EPPRD0_L (1 << 25)
#define FUSB300_EPPRD0_H (1 << 24)
#define FUSB300_EPPRD0_BTC(n) (n & 0xFFFFFF)
/*----------------------------------------------------------------------*/
#define FUSB300_MAX_NUM_EP 16
#define FUSB300_FIFO_ENTRY_NUM 8
#define FUSB300_MAX_FIFO_ENTRY 8
#define SS_CTL_MAX_PACKET_SIZE 0x200
#define SS_BULK_MAX_PACKET_SIZE 0x400
#define SS_INT_MAX_PACKET_SIZE 0x400
#define SS_ISO_MAX_PACKET_SIZE 0x400
#define HS_BULK_MAX_PACKET_SIZE 0x200
#define HS_CTL_MAX_PACKET_SIZE 0x40
#define HS_INT_MAX_PACKET_SIZE 0x400
#define HS_ISO_MAX_PACKET_SIZE 0x400
struct fusb300_ep_info {
u8 epnum;
u8 type;
u8 interval;
u8 dir_in;
u16 maxpacket;
u16 addrofs;
u16 bw_num;
};
struct fusb300_request {
struct usb_request req;
struct list_head queue;
};
struct fusb300_ep {
struct usb_ep ep;
struct fusb300 *fusb300;
struct list_head queue;
unsigned stall:1;
unsigned wedged:1;
unsigned use_dma:1;
unsigned char epnum;
unsigned char type;
const struct usb_endpoint_descriptor *desc;
};
struct fusb300 {
spinlock_t lock;
void __iomem *reg;
unsigned long irq_trigger;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct fusb300_ep *ep[FUSB300_MAX_NUM_EP];
struct usb_request *ep0_req; /* for internal request */
__le16 ep0_data;
u32 ep0_length; /* for internal request */
u8 ep0_dir; /* 0/0x80 out/in */
u8 fifo_entry_num; /* next start fifo entry */
u32 addrofs; /* next fifo address offset */
u8 reenum; /* if re-enumeration */
};
#endif

View File

@ -258,7 +258,7 @@ static int pipe_buffer_setting(struct m66592 *m66592,
break;
case M66592_BULK:
/* isochronous pipes may be used as bulk pipes */
if (info->pipe > M66592_BASE_PIPENUM_BULK)
if (info->pipe >= M66592_BASE_PIPENUM_BULK)
bufnum = info->pipe - M66592_BASE_PIPENUM_BULK;
else
bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC;

View File

@ -367,7 +367,6 @@ struct pch_udc_dev {
static const char ep0_string[] = "ep0in";
static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */
struct pch_udc_dev *pch_udc; /* pointer to device object */
static int speed_fs;
module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
@ -383,6 +382,8 @@ MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
* @dma_mapped: DMA memory mapped for request
* @dma_done: DMA completed for request
* @chain_len: chain length
* @buf: Buffer memory for align adjustment
* @dma: DMA memory for align adjustment
*/
struct pch_udc_request {
struct usb_request req;
@ -394,6 +395,8 @@ struct pch_udc_request {
dma_mapped:1,
dma_done:1;
unsigned chain_len;
void *buf;
dma_addr_t dma;
};
static inline u32 pch_udc_readl(struct pch_udc_dev *dev, unsigned long reg)
@ -615,7 +618,7 @@ static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep,
/**
* pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint
* @ep: Reference to structure of type pch_udc_ep_regs
* @buf_size: The buffer size
* @buf_size: The buffer word size
*/
static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep,
u32 buf_size, u32 ep_in)
@ -635,7 +638,7 @@ static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep,
/**
* pch_udc_ep_set_maxpkt() - Set the Max packet size for the endpoint
* @ep: Reference to structure of type pch_udc_ep_regs
* @pkt_size: The packet size
* @pkt_size: The packet byte size
*/
static void pch_udc_ep_set_maxpkt(struct pch_udc_ep *ep, u32 pkt_size)
{
@ -920,25 +923,10 @@ static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep)
*/
static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir)
{
unsigned int loopcnt = 0;
struct pch_udc_dev *dev = ep->dev;
if (dir) { /* IN ep */
pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F);
return;
}
if (pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP)
return;
pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
/* Wait for RxFIFO Empty */
loopcnt = 10000;
while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) &&
--loopcnt)
udelay(5);
if (!loopcnt)
dev_err(&dev->pdev->dev, "RxFIFO not Empty\n");
pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
}
/**
@ -1220,14 +1208,31 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
dev = ep->dev;
if (req->dma_mapped) {
if (ep->in)
dma_unmap_single(&dev->pdev->dev, req->req.dma,
req->req.length, DMA_TO_DEVICE);
else
dma_unmap_single(&dev->pdev->dev, req->req.dma,
req->req.length, DMA_FROM_DEVICE);
if (req->dma == DMA_ADDR_INVALID) {
if (ep->in)
dma_unmap_single(&dev->pdev->dev, req->req.dma,
req->req.length,
DMA_TO_DEVICE);
else
dma_unmap_single(&dev->pdev->dev, req->req.dma,
req->req.length,
DMA_FROM_DEVICE);
req->req.dma = DMA_ADDR_INVALID;
} else {
if (ep->in)
dma_unmap_single(&dev->pdev->dev, req->dma,
req->req.length,
DMA_TO_DEVICE);
else {
dma_unmap_single(&dev->pdev->dev, req->dma,
req->req.length,
DMA_FROM_DEVICE);
memcpy(req->req.buf, req->buf, req->req.length);
}
kfree(req->buf);
req->dma = DMA_ADDR_INVALID;
}
req->dma_mapped = 0;
req->req.dma = DMA_ADDR_INVALID;
}
ep->halted = 1;
spin_unlock(&dev->lock);
@ -1268,12 +1273,18 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,
struct pch_udc_data_dma_desc *td = req->td_data;
unsigned i = req->chain_len;
dma_addr_t addr2;
dma_addr_t addr = (dma_addr_t)td->next;
td->next = 0x00;
for (; i > 1; --i) {
dma_addr_t addr = (dma_addr_t)td->next;
/* do not free first desc., will be done by free for request */
td = phys_to_virt(addr);
addr2 = (dma_addr_t)td->next;
pci_pool_free(dev->data_requests, td, addr);
td->next = 0x00;
addr = addr2;
}
req->chain_len = 1;
}
/**
@ -1301,23 +1312,23 @@ static int pch_udc_create_dma_chain(struct pch_udc_ep *ep,
if (req->chain_len > 1)
pch_udc_free_dma_chain(ep->dev, req);
for (; ; bytes -= buf_len, ++len) {
if (ep->in)
td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes);
else
td->status = PCH_UDC_BS_HST_BSY;
if (req->dma == DMA_ADDR_INVALID)
td->dataptr = req->req.dma;
else
td->dataptr = req->dma;
td->status = PCH_UDC_BS_HST_BSY;
for (; ; bytes -= buf_len, ++len) {
td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes);
if (bytes <= buf_len)
break;
last = td;
td = pci_pool_alloc(ep->dev->data_requests, gfp_flags,
&dma_addr);
if (!td)
goto nomem;
i += buf_len;
td->dataptr = req->req.dma + i;
td->dataptr = req->td_data->dataptr + i;
last->next = dma_addr;
}
@ -1352,28 +1363,15 @@ static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req,
{
int retval;
req->td_data->dataptr = req->req.dma;
req->td_data->status |= PCH_UDC_DMA_LAST;
/* Allocate and create a DMA chain */
retval = pch_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
if (retval) {
pr_err("%s: could not create DMA chain: %d\n",
__func__, retval);
pr_err("%s: could not create DMA chain:%d\n", __func__, retval);
return retval;
}
if (!ep->in)
return 0;
if (req->req.length <= ep->ep.maxpacket)
req->td_data->status = PCH_UDC_DMA_LAST | PCH_UDC_BS_HST_BSY |
req->req.length;
/* if bytes < max packet then tx bytes must
* be written in packet per buffer mode
*/
if ((req->req.length < ep->ep.maxpacket) || !ep->num)
if (ep->in)
req->td_data->status = (req->td_data->status &
~PCH_UDC_RXTX_BYTES) | req->req.length;
req->td_data->status = (req->td_data->status &
~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_BSY;
~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_RDY;
return 0;
}
@ -1529,6 +1527,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
if (!req)
return NULL;
req->req.dma = DMA_ADDR_INVALID;
req->dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&req->queue);
if (!ep->dev->dma_addr)
return &req->req;
@ -1613,16 +1612,33 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
/* map the buffer for dma */
if (usbreq->length &&
((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
if (ep->in)
usbreq->dma = dma_map_single(&dev->pdev->dev,
usbreq->buf,
usbreq->length,
DMA_TO_DEVICE);
else
usbreq->dma = dma_map_single(&dev->pdev->dev,
usbreq->buf,
usbreq->length,
DMA_FROM_DEVICE);
if (!((unsigned long)(usbreq->buf) & 0x03)) {
if (ep->in)
usbreq->dma = dma_map_single(&dev->pdev->dev,
usbreq->buf,
usbreq->length,
DMA_TO_DEVICE);
else
usbreq->dma = dma_map_single(&dev->pdev->dev,
usbreq->buf,
usbreq->length,
DMA_FROM_DEVICE);
} else {
req->buf = kzalloc(usbreq->length, GFP_ATOMIC);
if (!req->buf)
return -ENOMEM;
if (ep->in) {
memcpy(req->buf, usbreq->buf, usbreq->length);
req->dma = dma_map_single(&dev->pdev->dev,
req->buf,
usbreq->length,
DMA_TO_DEVICE);
} else
req->dma = dma_map_single(&dev->pdev->dev,
req->buf,
usbreq->length,
DMA_FROM_DEVICE);
}
req->dma_mapped = 1;
}
if (usbreq->length > 0) {
@ -1920,32 +1936,46 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
struct pch_udc_request *req;
struct pch_udc_dev *dev = ep->dev;
unsigned int count;
struct pch_udc_data_dma_desc *td;
dma_addr_t addr;
if (list_empty(&ep->queue))
return;
/* next request */
req = list_entry(ep->queue.next, struct pch_udc_request, queue);
if ((req->td_data_last->status & PCH_UDC_BUFF_STS) !=
PCH_UDC_BS_DMA_DONE)
return;
pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
pch_udc_ep_set_ddptr(ep, 0);
if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
PCH_UDC_RTS_SUCC) {
dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) "
"epstatus=0x%08x\n",
(req->td_data_last->status & PCH_UDC_RXTX_STS),
(int)(ep->epsts));
return;
}
count = req->td_data_last->status & PCH_UDC_RXTX_BYTES;
if ((req->td_data_last->status & PCH_UDC_BUFF_STS) ==
PCH_UDC_BS_DMA_DONE)
td = req->td_data_last;
else
td = req->td_data;
while (1) {
if ((td->status & PCH_UDC_RXTX_STS) != PCH_UDC_RTS_SUCC) {
dev_err(&dev->pdev->dev, "Invalid RXTX status=0x%08x "
"epstatus=0x%08x\n",
(req->td_data->status & PCH_UDC_RXTX_STS),
(int)(ep->epsts));
return;
}
if ((td->status & PCH_UDC_BUFF_STS) == PCH_UDC_BS_DMA_DONE)
if (td->status | PCH_UDC_DMA_LAST) {
count = td->status & PCH_UDC_RXTX_BYTES;
break;
}
if (td == req->td_data_last) {
dev_err(&dev->pdev->dev, "Not complete RX descriptor");
return;
}
addr = (dma_addr_t)td->next;
td = phys_to_virt(addr);
}
/* on 64k packets the RXBYTES field is zero */
if (!count && (req->req.length == UDC_DMA_MAXPACKET))
count = UDC_DMA_MAXPACKET;
req->td_data->status |= PCH_UDC_DMA_LAST;
req->td_data_last->status |= PCH_UDC_BS_HST_BSY;
td->status |= PCH_UDC_BS_HST_BSY;
req->dma_going = 0;
req->req.actual = count;

View File

@ -902,7 +902,7 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
int pwr_reg;
int ep0csr;
int i;
u32 idx;
u32 idx, idx2;
unsigned long flags;
spin_lock_irqsave(&dev->lock, flags);
@ -1017,6 +1017,20 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
}
}
/* what else causes this interrupt? a receive! who is it? */
if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) {
for (i = 1; i < S3C2410_ENDPOINTS; i++) {
idx2 = udc_read(S3C2410_UDC_INDEX_REG);
udc_write(i, S3C2410_UDC_INDEX_REG);
if (udc_read(S3C2410_UDC_OUT_CSR1_REG) & 0x1)
s3c2410_udc_handle_ep(&dev->ep[i]);
/* restore index */
udc_write(idx2, S3C2410_UDC_INDEX_REG);
}
}
dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
/* Restore old index */
@ -1467,7 +1481,9 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
{
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
if (udc_info && udc_info->udc_command) {
if (udc_info && (udc_info->udc_command ||
gpio_is_valid(udc_info->pullup_pin))) {
if (is_on)
s3c2410_udc_enable(udc);
else {
@ -1544,6 +1560,32 @@ static const struct usb_gadget_ops s3c2410_ops = {
.vbus_draw = s3c2410_vbus_draw,
};
static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
{
if (!udc_info)
return;
if (udc_info->udc_command) {
udc_info->udc_command(S3C2410_UDC_P_DISABLE);
} else if (gpio_is_valid(udc_info->pullup_pin)) {
int value;
switch (cmd) {
case S3C2410_UDC_P_ENABLE:
value = 1;
break;
case S3C2410_UDC_P_DISABLE:
value = 0;
break;
default:
return;
}
value ^= udc_info->pullup_pin_inverted;
gpio_set_value(udc_info->pullup_pin, value);
}
}
/*------------------------- gadget driver handling---------------------------*/
/*
* s3c2410_udc_disable
@ -1565,8 +1607,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev)
udc_write(0x1F, S3C2410_UDC_EP_INT_REG);
/* Good bye, cruel world */
if (udc_info && udc_info->udc_command)
udc_info->udc_command(S3C2410_UDC_P_DISABLE);
s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
/* Set speed to unknown */
dev->gadget.speed = USB_SPEED_UNKNOWN;
@ -1627,8 +1668,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);
/* time to say "hello, world" */
if (udc_info && udc_info->udc_command)
udc_info->udc_command(S3C2410_UDC_P_ENABLE);
s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
}
/*
@ -1903,6 +1943,17 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
udc->vbus = 1;
}
if (udc_info && !udc_info->udc_command &&
gpio_is_valid(udc_info->pullup_pin)) {
retval = gpio_request_one(udc_info->pullup_pin,
udc_info->vbus_pin_inverted ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
"udc pullup");
if (retval)
goto err_vbus_irq;
}
if (s3c2410_udc_debugfs_root) {
udc->regs_info = debugfs_create_file("registers", S_IRUGO,
s3c2410_udc_debugfs_root,
@ -1915,6 +1966,9 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
return 0;
err_vbus_irq:
if (udc_info && udc_info->vbus_pin > 0)
free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
err_gpio_claim:
if (udc_info && udc_info->vbus_pin > 0)
gpio_free(udc_info->vbus_pin);
@ -1942,6 +1996,10 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
debugfs_remove(udc->regs_info);
if (udc_info && !udc_info->udc_command &&
gpio_is_valid(udc_info->pullup_pin))
gpio_free(udc_info->pullup_pin);
if (udc_info && udc_info->vbus_pin > 0) {
irq = gpio_to_irq(udc_info->vbus_pin);
free_irq(irq, udc);
@ -1973,16 +2031,14 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
{
if (udc_info && udc_info->udc_command)
udc_info->udc_command(S3C2410_UDC_P_DISABLE);
s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
return 0;
}
static int s3c2410_udc_resume(struct platform_device *pdev)
{
if (udc_info && udc_info->udc_command)
udc_info->udc_command(S3C2410_UDC_P_ENABLE);
s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
return 0;
}

View File

@ -241,7 +241,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
size -= size % out->maxpacket;
if (dev->port_usb->is_fixed)
size = max(size, dev->port_usb->fixed_out_len);
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
if (skb == NULL) {

View File

@ -91,17 +91,28 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say Y.
config USB_EHCI_HCD_PMC_MSP
tristate "EHCI support for on-chip PMC MSP71xx USB controller"
depends on USB_EHCI_HCD && MSP_HAS_USB
default n
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
---help---
Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's.
If unsure, say N.
config USB_EHCI_BIG_ENDIAN_MMIO
bool
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
PPC_MPC512x || CPU_CAVIUM_OCTEON)
PPC_MPC512x || CPU_CAVIUM_OCTEON || \
PMC_MSP)
default y
config USB_EHCI_BIG_ENDIAN_DESC
bool
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
PPC_MPC512x)
PPC_MPC512x || PMC_MSP)
default y
config XPS_USB_HCD_XILINX
@ -145,7 +156,7 @@ config USB_EHCI_MSM
bool "Support for MSM on-chip EHCI USB controller"
depends on USB_EHCI_HCD && ARCH_MSM
select USB_EHCI_ROOT_HUB_TT
select USB_MSM_OTG_72K
select USB_MSM_OTG
---help---
Enables support for the USB Host controller present on the
Qualcomm chipsets. Root Hub has inbuilt TT.
@ -154,6 +165,14 @@ config USB_EHCI_MSM
This driver is not supported on boards like trout which
has an external PHY.
config USB_EHCI_TEGRA
boolean "NVIDIA Tegra HCD support"
depends on USB_EHCI_HCD && ARCH_TEGRA
select USB_EHCI_ROOT_HUB_TT
help
This driver enables support for the internal USB Host Controllers
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"
depends on USB_EHCI_HCD && PPC_OF
@ -162,6 +181,13 @@ config USB_EHCI_HCD_PPC_OF
Enables support for the USB controller present on the PowerPC
OpenFirmware platform bus.
config USB_EHCI_SH
bool "EHCI support for SuperH USB controller"
depends on USB_EHCI_HCD && SUPERH
---help---
Enables support for the on-chip EHCI controller on the SuperH.
If you use the PCI EHCI controller, this option is not necessary.
config USB_W90X900_EHCI
bool "W90X900(W90P910) EHCI support"
depends on USB_EHCI_HCD && ARCH_W90X900
@ -315,6 +341,13 @@ config USB_OHCI_HCD_SSB
If unsure, say N.
config USB_OHCI_SH
bool "OHCI support for SuperH USB controller"
depends on USB_OHCI_HCD && SUPERH
---help---
Enables support for the on-chip OHCI controller on the SuperH.
If you use the PCI OHCI controller, this option is not necessary.
config USB_CNS3XXX_OHCI
bool "Cavium CNS3XXX OHCI Module"
depends on USB_OHCI_HCD && ARCH_CNS3XXX

View File

@ -115,7 +115,7 @@ static const struct hc_driver ehci_atmel_hc_driver = {
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
const struct hc_driver *driver = &ehci_atmel_hc_driver;
@ -207,7 +207,7 @@ fail_create_hcd:
return retval;
}
static int __exit ehci_atmel_drv_remove(struct platform_device *pdev)
static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
@ -227,7 +227,7 @@ static int __exit ehci_atmel_drv_remove(struct platform_device *pdev)
static struct platform_driver ehci_atmel_driver = {
.probe = ehci_atmel_drv_probe,
.remove = __exit_p(ehci_atmel_drv_remove),
.remove = __devexit_p(ehci_atmel_drv_remove),
.shutdown = usb_hcd_platform_shutdown,
.driver.name = "atmel-ehci",
};

View File

@ -28,11 +28,9 @@
dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
#ifdef VERBOSE_DEBUG
# define vdbg dbg
# define ehci_vdbg ehci_dbg
#else
# define vdbg(fmt,args...) do { } while (0)
# define ehci_vdbg(ehci, fmt, args...) do { } while (0)
static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {}
#endif
#ifdef DEBUG

View File

@ -114,13 +114,11 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
/* for ASPM quirk of ISOC on AMD SB800 */
static struct pci_dev *amd_nb_dev;
/*-------------------------------------------------------------------------*/
#include "ehci.h"
#include "ehci-dbg.c"
#include "pci-quirks.h"
/*-------------------------------------------------------------------------*/
@ -532,10 +530,8 @@ static void ehci_stop (struct usb_hcd *hcd)
spin_unlock_irq (&ehci->lock);
ehci_mem_cleanup (ehci);
if (amd_nb_dev) {
pci_dev_put(amd_nb_dev);
amd_nb_dev = NULL;
}
if (ehci->amd_pll_fix == 1)
usb_amd_dev_put();
#ifdef EHCI_STATS
ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
@ -679,7 +675,12 @@ static int ehci_run (struct usb_hcd *hcd)
hcd->uses_new_polling = 1;
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
/*
* TDI driver does the ehci_reset in their reset callback.
* Don't reset here, because configuration settings will
* vanish.
*/
if (!ehci_is_TDI(ehci) && (retval = ehci_reset(ehci)) != 0) {
ehci_mem_cleanup(ehci);
return retval;
}
@ -1179,7 +1180,7 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_mxc_driver
#endif
#ifdef CONFIG_CPU_SUBTYPE_SH7786
#ifdef CONFIG_USB_EHCI_SH
#include "ehci-sh.c"
#define PLATFORM_DRIVER ehci_hcd_sh_driver
#endif
@ -1254,6 +1255,16 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_msm_driver
#endif
#ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
#include "ehci-pmcmsp.c"
#define PLATFORM_DRIVER ehci_hcd_msp_driver
#endif
#ifdef CONFIG_USB_EHCI_TEGRA
#include "ehci-tegra.c"
#define PLATFORM_DRIVER tegra_ehci_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)

View File

@ -106,6 +106,27 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
ehci->owned_ports = 0;
}
static int ehci_port_change(struct ehci_hcd *ehci)
{
int i = HCS_N_PORTS(ehci->hcs_params);
/* First check if the controller indicates a change event */
if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)
return 1;
/*
* Not all controllers appear to update this while going from D3 to D0,
* so check the individual port status registers as well
*/
while (i--)
if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC)
return 1;
return 0;
}
static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending, bool do_wakeup)
{
@ -173,7 +194,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
}
/* Does the root hub have a port wakeup pending? */
if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD))
if (!suspending && ehci_port_change(ehci))
usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
spin_unlock_irqrestore(&ehci->lock, flags);
@ -538,14 +559,15 @@ static ssize_t store_companion(struct device *dev,
}
static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
static inline void create_companion_file(struct ehci_hcd *ehci)
static inline int create_companion_file(struct ehci_hcd *ehci)
{
int i;
int i = 0;
/* with integrated TT there is no companion! */
if (!ehci_is_TDI(ehci))
i = device_create_file(ehci_to_hcd(ehci)->self.controller,
&dev_attr_companion);
return i;
}
static inline void remove_companion_file(struct ehci_hcd *ehci)
@ -695,8 +717,8 @@ ehci_hub_descriptor (
desc->bDescLength = 7 + 2 * temp;
/* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
memset (&desc->bitmap [0], 0, temp);
memset (&desc->bitmap [temp], 0xff, temp);
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
temp = 0x0008; /* per-port overcurrent reporting */
if (HCS_PPC (ehci->hcs_params))

View File

@ -17,7 +17,8 @@
*/
/* this file is part of ehci-hcd.c */
static int ehci_lpm_set_da(struct ehci_hcd *ehci, int dev_addr, int port_num)
static int __maybe_unused ehci_lpm_set_da(struct ehci_hcd *ehci,
int dev_addr, int port_num)
{
u32 __iomem portsc;
@ -37,7 +38,7 @@ static int ehci_lpm_set_da(struct ehci_hcd *ehci, int dev_addr, int port_num)
* this function is used to check if the device support LPM
* if yes, mark the PORTSC register with PORT_LPM bit
*/
static int ehci_lpm_check(struct ehci_hcd *ehci, int port)
static int __maybe_unused ehci_lpm_check(struct ehci_hcd *ehci, int port)
{
u32 __iomem *portsc ;
u32 val32;

View File

@ -1,6 +1,6 @@
/* ehci-msm.c - HSUSB Host Controller Driver Implementation
*
* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
*
* Partly derived from ehci-fsl.c and ehci-hcd.c
* Copyright (c) 2000-2004 by David Brownell
@ -34,92 +34,6 @@
static struct otg_transceiver *otg;
/*
* ehci_run defined in drivers/usb/host/ehci-hcd.c reset the controller and
* the configuration settings in ehci_msm_reset vanish after controller is
* reset. Resetting the controler in ehci_run seems to be un-necessary
* provided HCD reset the controller before calling ehci_run. Most of the HCD
* do but some are not. So this function is same as ehci_run but we don't
* reset the controller here.
*/
static int ehci_msm_run(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
u32 temp;
u32 hcc_params;
hcd->uses_new_polling = 1;
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
/*
* hcc_params controls whether ehci->regs->segment must (!!!)
* be used; it constrains QH/ITD/SITD and QTD locations.
* pci_pool consistent memory always uses segment zero.
* streaming mappings for I/O buffers, like pci_map_single(),
* can return segments above 4GB, if the device allows.
*
* NOTE: the dma mask is visible through dma_supported(), so
* drivers can pass this info along ... like NETIF_F_HIGHDMA,
* Scsi_Host.highmem_io, and so forth. It's readonly to all
* host side drivers though.
*/
hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_64BIT_ADDR(hcc_params))
ehci_writel(ehci, 0, &ehci->regs->segment);
/*
* Philips, Intel, and maybe others need CMD_RUN before the
* root hub will detect new devices (why?); NEC doesn't
*/
ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
ehci->command |= CMD_RUN;
ehci_writel(ehci, ehci->command, &ehci->regs->command);
dbg_cmd(ehci, "init", ehci->command);
/*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices
* are explicitly handed to companion controller(s), so no TT is
* involved with the root hub. (Except where one is integrated,
* and there's no companion controller unless maybe for USB OTG.)
*
* Turning on the CF flag will transfer ownership of all ports
* from the companions to the EHCI controller. If any of the
* companions are in the middle of a port reset at the time, it
* could cause trouble. Write-locking ehci_cf_port_reset_rwsem
* guarantees that no resets are in progress. After we set CF,
* a short delay lets the hardware catch up; new resets shouldn't
* be started before the port switching actions could complete.
*/
down_write(&ehci_cf_port_reset_rwsem);
hcd->state = HC_STATE_RUNNING;
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
usleep_range(5000, 5500);
up_write(&ehci_cf_port_reset_rwsem);
ehci->last_periodic_enable = ktime_get_real();
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info(ehci,
"USB %x.%x started, EHCI %x.%02x%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff,
ignore_oc ? ", overcurrent ignored" : "");
ehci_writel(ehci, INTR_MASK,
&ehci->regs->intr_enable); /* Turn On Interrupts */
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
* since the class device isn't created that early.
*/
create_debug_files(ehci);
create_companion_file(ehci);
return 0;
}
static int ehci_msm_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@ -128,6 +42,8 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
ehci->caps = USB_CAPLENGTH;
ehci->regs = USB_CAPLENGTH +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache the data to minimize the chip reads*/
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
@ -135,6 +51,10 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
hcd->has_tt = 1;
ehci->sbrn = HCD_USB2;
retval = ehci_halt(ehci);
if (retval)
return retval;
/* data structure init */
retval = ehci_init(hcd);
if (retval)
@ -167,7 +87,7 @@ static struct hc_driver msm_hc_driver = {
.flags = HCD_USB2 | HCD_MEMORY,
.reset = ehci_msm_reset,
.start = ehci_msm_run,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,

File diff suppressed because it is too large Load Diff

View File

@ -105,7 +105,8 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
ehci_reset(ehci);
hcd->has_tt = 1;
retval = ehci_halt(ehci);
if (retval)
return retval;
@ -117,7 +118,7 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
if (retval)
return retval;
hcd->has_tt = 1;
ehci_reset(ehci);
ehci_port_power(ehci, 0);

View File

@ -44,42 +44,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
return 0;
}
static int ehci_quirk_amd_hudson(struct ehci_hcd *ehci)
{
struct pci_dev *amd_smbus_dev;
u8 rev = 0;
amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
if (amd_smbus_dev) {
pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
if (rev < 0x40) {
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
return 0;
}
} else {
amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x780b, NULL);
if (!amd_smbus_dev)
return 0;
pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
if (rev < 0x11 || rev > 0x18) {
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
return 0;
}
}
if (!amd_nb_dev)
amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
ehci_info(ehci, "QUIRK: Enable exception for AMD Hudson ASPM\n");
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
return 1;
}
/* called during probe() after chip reset completes */
static int ehci_pci_setup(struct usb_hcd *hcd)
{
@ -138,9 +102,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
if (ehci_quirk_amd_hudson(ehci))
ehci->amd_l1_fix = 1;
retval = ehci_halt(ehci);
if (retval)
return retval;
@ -191,6 +152,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
break;
case PCI_VENDOR_ID_AMD:
/* AMD PLL quirk */
if (usb_amd_find_chipset_info())
ehci->amd_pll_fix = 1;
/* AMD8111 EHCI doesn't work, according to AMD errata */
if (pdev->device == 0x7463) {
ehci_info(ehci, "ignoring AMD8111 (errata)\n");
@ -236,6 +200,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
break;
case PCI_VENDOR_ID_ATI:
/* AMD PLL quirk */
if (usb_amd_find_chipset_info())
ehci->amd_pll_fix = 1;
/* SB600 and old version of SB700 have a bug in EHCI controller,
* which causes usb devices lose response in some cases.
*/

View File

@ -0,0 +1,383 @@
/*
* PMC MSP EHCI (Host Controller Driver) for USB.
*
* (C) Copyright 2006-2010 PMC-Sierra Inc
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
*/
/* includes */
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/usb.h>
#include <msp_usb.h>
/* stream disable*/
#define USB_CTRL_MODE_STREAM_DISABLE 0x10
/* threshold */
#define USB_CTRL_FIFO_THRESH 0x00300000
/* register offset for usb_mode */
#define USB_EHCI_REG_USB_MODE 0x68
/* register offset for usb fifo */
#define USB_EHCI_REG_USB_FIFO 0x24
/* register offset for usb status */
#define USB_EHCI_REG_USB_STATUS 0x44
/* serial/parallel transceiver */
#define USB_EHCI_REG_BIT_STAT_STS (1<<29)
/* TWI USB0 host device pin */
#define MSP_PIN_USB0_HOST_DEV 49
/* TWI USB1 host device pin */
#define MSP_PIN_USB1_HOST_DEV 50
static void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci)
{
u8 *base;
u8 *statreg;
u8 *fiforeg;
u32 val;
struct ehci_regs *reg_base = ehci->regs;
/* get register base */
base = (u8 *)reg_base + USB_EHCI_REG_USB_MODE;
statreg = (u8 *)reg_base + USB_EHCI_REG_USB_STATUS;
fiforeg = (u8 *)reg_base + USB_EHCI_REG_USB_FIFO;
/* Disable controller mode stream */
val = ehci_readl(ehci, (u32 *)base);
ehci_writel(ehci, (val | USB_CTRL_MODE_STREAM_DISABLE),
(u32 *)base);
/* clear STS to select parallel transceiver interface */
val = ehci_readl(ehci, (u32 *)statreg);
val = val & ~USB_EHCI_REG_BIT_STAT_STS;
ehci_writel(ehci, val, (u32 *)statreg);
/* write to set the proper fifo threshold */
ehci_writel(ehci, USB_CTRL_FIFO_THRESH, (u32 *)fiforeg);
/* set TWI GPIO USB_HOST_DEV pin high */
gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1);
#ifdef CONFIG_MSP_HAS_DUAL_USB
gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1);
#endif
}
/* called during probe() after chip reset completes */
static int ehci_msp_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
ehci->big_endian_mmio = 1;
ehci->big_endian_desc = 1;
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
retval = ehci_halt(ehci);
if (retval)
return retval;
ehci_reset(ehci);
/* data structure init */
retval = ehci_init(hcd);
if (retval)
return retval;
usb_hcd_tdi_set_mode(ehci);
ehci_port_power(ehci, 0);
return retval;
}
/* configure so an HC device and id are always provided
* always called with process context; sleeping is OK
*/
static int usb_hcd_msp_map_regs(struct mspusb_device *dev)
{
struct resource *res;
struct platform_device *pdev = &dev->dev;
u32 res_len;
int retval;
/* MAB register space */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res == NULL)
return -ENOMEM;
res_len = res->end - res->start + 1;
if (!request_mem_region(res->start, res_len, "mab regs"))
return -EBUSY;
dev->mab_regs = ioremap_nocache(res->start, res_len);
if (dev->mab_regs == NULL) {
retval = -ENOMEM;
goto err1;
}
/* MSP USB register space */
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (res == NULL) {
retval = -ENOMEM;
goto err2;
}
res_len = res->end - res->start + 1;
if (!request_mem_region(res->start, res_len, "usbid regs")) {
retval = -EBUSY;
goto err2;
}
dev->usbid_regs = ioremap_nocache(res->start, res_len);
if (dev->usbid_regs == NULL) {
retval = -ENOMEM;
goto err3;
}
return 0;
err3:
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
res_len = res->end - res->start + 1;
release_mem_region(res->start, res_len);
err2:
iounmap(dev->mab_regs);
err1:
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
res_len = res->end - res->start + 1;
release_mem_region(res->start, res_len);
dev_err(&pdev->dev, "Failed to map non-EHCI regs.\n");
return retval;
}
/**
* usb_hcd_msp_probe - initialize PMC MSP-based HCDs
* Context: !in_interrupt()
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*
*/
int usb_hcd_msp_probe(const struct hc_driver *driver,
struct platform_device *dev)
{
int retval;
struct usb_hcd *hcd;
struct resource *res;
struct ehci_hcd *ehci ;
hcd = usb_create_hcd(driver, &dev->dev, "pmcmsp");
if (!hcd)
return -ENOMEM;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (res == NULL) {
pr_debug("No IOMEM resource info for %s.\n", dev->name);
retval = -ENOMEM;
goto err1;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = res->end - res->start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, dev->name)) {
retval = -EBUSY;
goto err1;
}
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
pr_debug("ioremap failed");
retval = -ENOMEM;
goto err2;
}
res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(&dev->dev, "No IRQ resource info for %s.\n", dev->name);
retval = -ENOMEM;
goto err3;
}
/* Map non-EHCI register spaces */
retval = usb_hcd_msp_map_regs(to_mspusb_device(dev));
if (retval != 0)
goto err3;
ehci = hcd_to_ehci(hcd);
ehci->big_endian_mmio = 1;
ehci->big_endian_desc = 1;
retval = usb_add_hcd(hcd, res->start, IRQF_SHARED);
if (retval == 0)
return 0;
usb_remove_hcd(hcd);
err3:
iounmap(hcd->regs);
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
return retval;
}
/**
* usb_hcd_msp_remove - shutdown processing for PMC MSP-based HCDs
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_msp_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*
* may be called without controller electrically present
* may be called with controller, bus, and devices active
*/
void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev)
{
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
}
#ifdef CONFIG_MSP_HAS_DUAL_USB
/*
* Wrapper around the main ehci_irq. Since both USB host controllers are
* sharing the same IRQ, need to first determine whether we're the intended
* recipient of this interrupt.
*/
static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd)
{
u32 int_src;
struct device *dev = hcd->self.controller;
struct platform_device *pdev;
struct mspusb_device *mdev;
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
/* need to reverse-map a couple of containers to get our device */
pdev = to_platform_device(dev);
mdev = to_mspusb_device(pdev);
/* Check to see if this interrupt is for this host controller */
int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat);
if (int_src & (1 << pdev->id))
return ehci_irq(hcd);
/* Not for this device */
return IRQ_NONE;
}
#endif /* DUAL_USB */
static const struct hc_driver ehci_msp_hc_driver = {
.description = hcd_name,
.product_desc = "PMC MSP EHCI",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
#ifdef CONFIG_MSP_HAS_DUAL_USB
.irq = ehci_msp_irq,
#else
.irq = ehci_irq,
#endif
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = ehci_msp_setup,
.start = ehci_run,
.shutdown = ehci_shutdown,
.start = ehci_run,
.stop = ehci_stop,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int ehci_hcd_msp_drv_probe(struct platform_device *pdev)
{
int ret;
pr_debug("In ehci_hcd_msp_drv_probe");
if (usb_disabled())
return -ENODEV;
gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO");
#ifdef CONFIG_MSP_HAS_DUAL_USB
gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO");
#endif
ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev);
return ret;
}
static int ehci_hcd_msp_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_hcd_msp_remove(hcd, pdev);
/* free TWI GPIO USB_HOST_DEV pin */
gpio_free(MSP_PIN_USB0_HOST_DEV);
#ifdef CONFIG_MSP_HAS_DUAL_USB
gpio_free(MSP_PIN_USB1_HOST_DEV);
#endif
return 0;
}
MODULE_ALIAS("pmcmsp-ehci");
static struct platform_driver ehci_hcd_msp_driver = {
.probe = ehci_hcd_msp_drv_probe,
.remove = ehci_hcd_msp_drv_remove,
.driver = {
.name = "pmcmsp-ehci",
.owner = THIS_MODULE,
},
};

View File

@ -1107,22 +1107,24 @@ submit_async (
struct list_head *qtd_list,
gfp_t mem_flags
) {
struct ehci_qtd *qtd;
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
int rc;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
epnum = urb->ep->desc.bEndpointAddress;
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
"%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
__func__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
qtd, urb->ep->hcpriv);
{
struct ehci_qtd *qtd;
qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
ehci_dbg(ehci,
"%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
__func__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
qtd, urb->ep->hcpriv);
}
#endif
spin_lock_irqsave (&ehci->lock, flags);

View File

@ -1048,8 +1048,6 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
* not like a QH -- no persistent state (toggle, halt)
*/
if (stream->refcount == 1) {
int is_in;
// BUG_ON (!list_empty(&stream->td_list));
while (!list_empty (&stream->free_list)) {
@ -1076,7 +1074,6 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
}
}
is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
stream->bEndpointAddress &= 0x0f;
if (stream->ep)
stream->ep->hcpriv = NULL;
@ -1590,63 +1587,6 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
*hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
}
#define AB_REG_BAR_LOW 0xe0
#define AB_REG_BAR_HIGH 0xe1
#define AB_INDX(addr) ((addr) + 0x00)
#define AB_DATA(addr) ((addr) + 0x04)
#define NB_PCIE_INDX_ADDR 0xe0
#define NB_PCIE_INDX_DATA 0xe4
#define NB_PIF0_PWRDOWN_0 0x01100012
#define NB_PIF0_PWRDOWN_1 0x01100013
static void ehci_quirk_amd_L1(struct ehci_hcd *ehci, int disable)
{
u32 addr, addr_low, addr_high, val;
outb_p(AB_REG_BAR_LOW, 0xcd6);
addr_low = inb_p(0xcd7);
outb_p(AB_REG_BAR_HIGH, 0xcd6);
addr_high = inb_p(0xcd7);
addr = addr_high << 8 | addr_low;
outl_p(0x30, AB_INDX(addr));
outl_p(0x40, AB_DATA(addr));
outl_p(0x34, AB_INDX(addr));
val = inl_p(AB_DATA(addr));
if (disable) {
val &= ~0x8;
val |= (1 << 4) | (1 << 9);
} else {
val |= 0x8;
val &= ~((1 << 4) | (1 << 9));
}
outl_p(val, AB_DATA(addr));
if (amd_nb_dev) {
addr = NB_PIF0_PWRDOWN_0;
pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
if (disable)
val &= ~(0x3f << 7);
else
val |= 0x3f << 7;
pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
addr = NB_PIF0_PWRDOWN_1;
pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
if (disable)
val &= ~(0x3f << 7);
else
val |= 0x3f << 7;
pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
}
return;
}
/* fit urb's itds into the selected schedule slot; activate as needed */
static int
itd_link_urb (
@ -1675,8 +1615,8 @@ itd_link_urb (
}
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_l1_fix == 1)
ehci_quirk_amd_L1(ehci, 1);
if (ehci->amd_pll_fix == 1)
usb_amd_quirk_pll_disable();
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@ -1804,8 +1744,8 @@ itd_complete (
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_l1_fix == 1)
ehci_quirk_amd_L1(ehci, 0);
if (ehci->amd_pll_fix == 1)
usb_amd_quirk_pll_enable();
}
if (unlikely(list_is_singular(&stream->td_list))) {
@ -2095,8 +2035,8 @@ sitd_link_urb (
}
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_l1_fix == 1)
ehci_quirk_amd_L1(ehci, 1);
if (ehci->amd_pll_fix == 1)
usb_amd_quirk_pll_disable();
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@ -2200,8 +2140,8 @@ sitd_complete (
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_l1_fix == 1)
ehci_quirk_amd_L1(ehci, 0);
if (ehci->amd_pll_fix == 1)
usb_amd_quirk_pll_enable();
}
if (list_is_singular(&stream->td_list)) {

View File

@ -0,0 +1,715 @@
/*
* EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs
*
* Copyright (C) 2010 Google, Inc.
* Copyright (C) 2009 NVIDIA Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/platform_data/tegra_usb.h>
#include <linux/irq.h>
#include <linux/usb/otg.h>
#include <mach/usb_phy.h>
#define TEGRA_USB_DMA_ALIGN 32
struct tegra_ehci_hcd {
struct ehci_hcd *ehci;
struct tegra_usb_phy *phy;
struct clk *clk;
struct clk *emc_clk;
struct otg_transceiver *transceiver;
int host_resumed;
int bus_suspended;
int port_resuming;
int power_down_on_bus_suspend;
enum tegra_usb_phy_port_speed port_speed;
};
static void tegra_ehci_power_up(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
clk_enable(tegra->emc_clk);
clk_enable(tegra->clk);
tegra_usb_phy_power_on(tegra->phy);
tegra->host_resumed = 1;
}
static void tegra_ehci_power_down(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
tegra->host_resumed = 0;
tegra_usb_phy_power_off(tegra->phy);
clk_disable(tegra->clk);
clk_disable(tegra->emc_clk);
}
static int tegra_ehci_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
u16 wValue,
u16 wIndex,
char *buf,
u16 wLength
)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
u32 __iomem *status_reg;
u32 temp;
unsigned long flags;
int retval = 0;
status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
spin_lock_irqsave(&ehci->lock, flags);
/*
* In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
* that are write on clear, by writing back the register read value, so
* USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
*/
if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
ehci_writel(ehci, temp & ~PORT_PE, status_reg);
goto done;
}
else if (typeReq == GetPortStatus) {
temp = ehci_readl(ehci, status_reg);
if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
/* Resume completed, re-enable disconnect detection */
tegra->port_resuming = 0;
tegra_usb_phy_postresume(tegra->phy);
}
}
else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
retval = -EPIPE;
goto done;
}
temp &= ~PORT_WKCONN_E;
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
/*
* If a transaction is in progress, there may be a delay in
* suspending the port. Poll until the port is suspended.
*/
if (handshake(ehci, status_reg, PORT_SUSPEND,
PORT_SUSPEND, 5000))
pr_err("%s: timeout waiting for SUSPEND\n", __func__);
set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
goto done;
}
/*
* Tegra host controller will time the resume operation to clear the bit
* when the port control state switches to HS or FS Idle. This behavior
* is different from EHCI where the host controller driver is required
* to set this bit to a zero after the resume duration is timed in the
* driver.
*/
else if (typeReq == ClearPortFeature &&
wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
if ((temp & PORT_RESET) || !(temp & PORT_PE)) {
retval = -EPIPE;
goto done;
}
if (!(temp & PORT_SUSPEND))
goto done;
/* Disable disconnect detection during port resume */
tegra_usb_phy_preresume(tegra->phy);
ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
/* start resume signalling */
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(20);
spin_lock_irqsave(&ehci->lock, flags);
/* Poll until the controller clears RESUME and SUSPEND */
if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000))
pr_err("%s: timeout waiting for RESUME\n", __func__);
if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000))
pr_err("%s: timeout waiting for SUSPEND\n", __func__);
ehci->reset_done[wIndex-1] = 0;
tegra->port_resuming = 1;
goto done;
}
spin_unlock_irqrestore(&ehci->lock, flags);
/* Handle the hub control events here */
return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
done:
spin_unlock_irqrestore(&ehci->lock, flags);
return retval;
}
static void tegra_ehci_restart(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
ehci_reset(ehci);
/* setup the frame list and Async q heads */
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
/* setup the command register and set the controller in RUN mode */
ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
ehci->command |= CMD_RUN;
ehci_writel(ehci, ehci->command, &ehci->regs->command);
down_write(&ehci_cf_port_reset_rwsem);
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
/* flush posted writes */
ehci_readl(ehci, &ehci->regs->command);
up_write(&ehci_cf_port_reset_rwsem);
}
static int tegra_usb_suspend(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
struct ehci_regs __iomem *hw = tegra->ehci->regs;
unsigned long flags;
spin_lock_irqsave(&tegra->ehci->lock, flags);
tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3;
ehci_halt(tegra->ehci);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
spin_unlock_irqrestore(&tegra->ehci->lock, flags);
tegra_ehci_power_down(hcd);
return 0;
}
static int tegra_usb_resume(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_regs __iomem *hw = ehci->regs;
unsigned long val;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
tegra_ehci_power_up(hcd);
if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) {
/* Wait for the phy to detect new devices
* before we restart the controller */
msleep(10);
goto restart;
}
/* Force the phy to keep data lines in suspend state */
tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed);
/* Enable host mode */
tdi_reset(ehci);
/* Enable Port Power */
val = readl(&hw->port_status[0]);
val |= PORT_POWER;
writel(val, &hw->port_status[0]);
udelay(10);
/* Check if the phy resume from LP0. When the phy resume from LP0
* USB register will be reset. */
if (!readl(&hw->async_next)) {
/* Program the field PTC based on the saved speed mode */
val = readl(&hw->port_status[0]);
val &= ~PORT_TEST(~0);
if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH)
val |= PORT_TEST_FORCE;
else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL)
val |= PORT_TEST(6);
else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
val |= PORT_TEST(7);
writel(val, &hw->port_status[0]);
udelay(10);
/* Disable test mode by setting PTC field to NORMAL_OP */
val = readl(&hw->port_status[0]);
val &= ~PORT_TEST(~0);
writel(val, &hw->port_status[0]);
udelay(10);
}
/* Poll until CCS is enabled */
if (handshake(ehci, &hw->port_status[0], PORT_CONNECT,
PORT_CONNECT, 2000)) {
pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__);
goto restart;
}
/* Poll until PE is enabled */
if (handshake(ehci, &hw->port_status[0], PORT_PE,
PORT_PE, 2000)) {
pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__);
goto restart;
}
/* Clear the PCI status, to avoid an interrupt taken upon resume */
val = readl(&hw->status);
val |= STS_PCD;
writel(val, &hw->status);
/* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */
val = readl(&hw->port_status[0]);
if ((val & PORT_POWER) && (val & PORT_PE)) {
val |= PORT_SUSPEND;
writel(val, &hw->port_status[0]);
/* Wait until port suspend completes */
if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND,
PORT_SUSPEND, 1000)) {
pr_err("%s: timeout waiting for PORT_SUSPEND\n",
__func__);
goto restart;
}
}
tegra_ehci_phy_restore_end(tegra->phy);
return 0;
restart:
if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH)
tegra_ehci_phy_restore_end(tegra->phy);
tegra_ehci_restart(hcd);
return 0;
}
static void tegra_ehci_shutdown(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
/* ehci_shutdown touches the USB controller registers, make sure
* controller has clocks to it */
if (!tegra->host_resumed)
tegra_ehci_power_up(hcd);
ehci_shutdown(hcd);
}
static int tegra_ehci_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(readl(&ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params);
/* switch to host mode */
hcd->has_tt = 1;
ehci_reset(ehci);
retval = ehci_halt(ehci);
if (retval)
return retval;
/* data structure init */
retval = ehci_init(hcd);
if (retval)
return retval;
ehci->sbrn = 0x20;
ehci_port_power(ehci, 1);
return retval;
}
#ifdef CONFIG_PM
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
int error_status = 0;
error_status = ehci_bus_suspend(hcd);
if (!error_status && tegra->power_down_on_bus_suspend) {
tegra_usb_suspend(hcd);
tegra->bus_suspended = 1;
}
return error_status;
}
static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
if (tegra->bus_suspended && tegra->power_down_on_bus_suspend) {
tegra_usb_resume(hcd);
tegra->bus_suspended = 0;
}
tegra_usb_phy_preresume(tegra->phy);
tegra->port_resuming = 1;
return ehci_bus_resume(hcd);
}
#endif
struct temp_buffer {
void *kmalloc_ptr;
void *old_xfer_buffer;
u8 data[0];
};
static void free_temp_buffer(struct urb *urb)
{
enum dma_data_direction dir;
struct temp_buffer *temp;
if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
return;
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
temp = container_of(urb->transfer_buffer, struct temp_buffer,
data);
if (dir == DMA_FROM_DEVICE)
memcpy(temp->old_xfer_buffer, temp->data,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->old_xfer_buffer;
kfree(temp->kmalloc_ptr);
urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
}
static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
{
enum dma_data_direction dir;
struct temp_buffer *temp, *kmalloc_ptr;
size_t kmalloc_size;
if (urb->num_sgs || urb->sg ||
urb->transfer_buffer_length == 0 ||
!((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
return 0;
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
/* Allocate a buffer with enough padding for alignment */
kmalloc_size = urb->transfer_buffer_length +
sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1;
kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
if (!kmalloc_ptr)
return -ENOMEM;
/* Position our struct temp_buffer such that data is aligned */
temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
temp->kmalloc_ptr = kmalloc_ptr;
temp->old_xfer_buffer = urb->transfer_buffer;
if (dir == DMA_TO_DEVICE)
memcpy(temp->data, urb->transfer_buffer,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->data;
urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
return 0;
}
static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
int ret;
ret = alloc_temp_buffer(urb, mem_flags);
if (ret)
return ret;
ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
if (ret)
free_temp_buffer(urb);
return ret;
}
static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
usb_hcd_unmap_urb_for_dma(hcd, urb);
free_temp_buffer(urb);
}
static const struct hc_driver tegra_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Tegra EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
.flags = HCD_USB2 | HCD_MEMORY,
.reset = tegra_ehci_setup,
.irq = ehci_irq,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = tegra_ehci_shutdown,
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.map_urb_for_dma = tegra_ehci_map_urb_for_dma,
.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.hub_control = tegra_ehci_hub_control,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
#ifdef CONFIG_PM
.bus_suspend = tegra_ehci_bus_suspend,
.bus_resume = tegra_ehci_bus_resume,
#endif
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
};
static int tegra_ehci_probe(struct platform_device *pdev)
{
struct resource *res;
struct usb_hcd *hcd;
struct tegra_ehci_hcd *tegra;
struct tegra_ehci_platform_data *pdata;
int err = 0;
int irq;
int instance = pdev->id;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "Platform data missing\n");
return -EINVAL;
}
tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
if (!tegra)
return -ENOMEM;
hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
err = -ENOMEM;
goto fail_hcd;
}
platform_set_drvdata(pdev, tegra);
tegra->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(tegra->clk)) {
dev_err(&pdev->dev, "Can't get ehci clock\n");
err = PTR_ERR(tegra->clk);
goto fail_clk;
}
err = clk_enable(tegra->clk);
if (err)
goto fail_clken;
tegra->emc_clk = clk_get(&pdev->dev, "emc");
if (IS_ERR(tegra->emc_clk)) {
dev_err(&pdev->dev, "Can't get emc clock\n");
err = PTR_ERR(tegra->emc_clk);
goto fail_emc_clk;
}
clk_enable(tegra->emc_clk);
clk_set_rate(tegra->emc_clk, 400000000);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Failed to get I/O memory\n");
err = -ENXIO;
goto fail_io;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
hcd->regs = ioremap(res->start, resource_size(res));
if (!hcd->regs) {
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
err = -ENOMEM;
goto fail_io;
}
tegra->phy = tegra_usb_phy_open(instance, hcd->regs, pdata->phy_config,
TEGRA_USB_PHY_MODE_HOST);
if (IS_ERR(tegra->phy)) {
dev_err(&pdev->dev, "Failed to open USB phy\n");
err = -ENXIO;
goto fail_phy;
}
err = tegra_usb_phy_power_on(tegra->phy);
if (err) {
dev_err(&pdev->dev, "Failed to power on the phy\n");
goto fail;
}
tegra->host_resumed = 1;
tegra->power_down_on_bus_suspend = pdata->power_down_on_bus_suspend;
tegra->ehci = hcd_to_ehci(hcd);
irq = platform_get_irq(pdev, 0);
if (!irq) {
dev_err(&pdev->dev, "Failed to get IRQ\n");
err = -ENODEV;
goto fail;
}
set_irq_flags(irq, IRQF_VALID);
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->operating_mode == TEGRA_USB_OTG) {
tegra->transceiver = otg_get_transceiver();
if (tegra->transceiver)
otg_set_host(tegra->transceiver, &hcd->self);
}
#endif
err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
goto fail;
}
return err;
fail:
#ifdef CONFIG_USB_OTG_UTILS
if (tegra->transceiver) {
otg_set_host(tegra->transceiver, NULL);
otg_put_transceiver(tegra->transceiver);
}
#endif
tegra_usb_phy_close(tegra->phy);
fail_phy:
iounmap(hcd->regs);
fail_io:
clk_disable(tegra->emc_clk);
clk_put(tegra->emc_clk);
fail_emc_clk:
clk_disable(tegra->clk);
fail_clken:
clk_put(tegra->clk);
fail_clk:
usb_put_hcd(hcd);
fail_hcd:
kfree(tegra);
return err;
}
#ifdef CONFIG_PM
static int tegra_ehci_resume(struct platform_device *pdev)
{
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
if (tegra->bus_suspended)
return 0;
return tegra_usb_resume(hcd);
}
static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
{
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
if (tegra->bus_suspended)
return 0;
if (time_before(jiffies, tegra->ehci->next_statechange))
msleep(10);
return tegra_usb_suspend(hcd);
}
#endif
static int tegra_ehci_remove(struct platform_device *pdev)
{
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
if (tegra == NULL || hcd == NULL)
return -EINVAL;
#ifdef CONFIG_USB_OTG_UTILS
if (tegra->transceiver) {
otg_set_host(tegra->transceiver, NULL);
otg_put_transceiver(tegra->transceiver);
}
#endif
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
tegra_usb_phy_close(tegra->phy);
iounmap(hcd->regs);
clk_disable(tegra->clk);
clk_put(tegra->clk);
clk_disable(tegra->emc_clk);
clk_put(tegra->emc_clk);
kfree(tegra);
return 0;
}
static void tegra_ehci_hcd_shutdown(struct platform_device *pdev)
{
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
static struct platform_driver tegra_ehci_driver = {
.probe = tegra_ehci_probe,
.remove = tegra_ehci_remove,
#ifdef CONFIG_PM
.suspend = tegra_ehci_suspend,
.resume = tegra_ehci_resume,
#endif
.shutdown = tegra_ehci_hcd_shutdown,
.driver = {
.name = "tegra-ehci",
}
};

View File

@ -131,7 +131,7 @@ struct ehci_hcd { /* one per controller */
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
unsigned amd_l1_fix:1;
unsigned amd_pll_fix:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/

View File

@ -927,7 +927,8 @@ static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
if (state == US_CTRL_SETUP) {
dir = TD_DIR_SETUP;
if (unsuitable_for_dma(urb->setup_dma))
unmap_urb_setup_for_dma(imx21->hcd, urb);
usb_hcd_unmap_urb_setup_for_dma(imx21->hcd,
urb);
etd->dma_handle = urb->setup_dma;
etd->cpu_buffer = urb->setup_packet;
bufround = 0;
@ -943,7 +944,7 @@ static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
dir = usb_pipeout(pipe) ? TD_DIR_OUT : TD_DIR_IN;
bufround = (dir == TD_DIR_IN) ? 1 : 0;
if (unsuitable_for_dma(urb->transfer_dma))
unmap_urb_for_dma(imx21->hcd, urb);
usb_hcd_unmap_urb_for_dma(imx21->hcd, urb);
etd->dma_handle = urb->transfer_dma;
etd->cpu_buffer = urb->transfer_buffer;
@ -1471,8 +1472,8 @@ static int get_hub_descriptor(struct usb_hcd *hcd,
0x0010 | /* No over current protection */
0);
desc->bitmap[0] = 1 << 1;
desc->bitmap[1] = ~0;
desc->u.hs.DeviceRemovable[0] = 1 << 1;
desc->u.hs.DeviceRemovable[1] = ~0;
return 0;
}

View File

@ -951,9 +951,9 @@ static void isp116x_hub_descriptor(struct isp116x *isp116x,
/* Power switching, device type, overcurrent. */
desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f));
desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
/* two bitmaps: ports removable, and legacy PortPwrCtrlMask */
desc->bitmap[0] = 0;
desc->bitmap[1] = ~0;
/* ports removable, and legacy PortPwrCtrlMask */
desc->u.hs.DeviceRemovable[0] = 0;
desc->u.hs.DeviceRemovable[1] = ~0;
}
/* Perform reset of a given port.

View File

@ -226,7 +226,6 @@ static int claim_ptd_buffers(struct isp1362_ep_queue *epq,
static inline void release_ptd_buffers(struct isp1362_ep_queue *epq, struct isp1362_ep *ep)
{
int index = ep->ptd_index;
int last = ep->ptd_index + ep->num_ptds;
if (last > epq->buf_count)
@ -236,10 +235,8 @@ static inline void release_ptd_buffers(struct isp1362_ep_queue *epq, struct isp1
epq->buf_map, epq->skip_map);
BUG_ON(last > epq->buf_count);
for (; index < last; index++) {
__clear_bit(index, &epq->buf_map);
__set_bit(index, &epq->skip_map);
}
bitmap_clear(&epq->buf_map, ep->ptd_index, ep->num_ptds);
bitmap_set(&epq->skip_map, ep->ptd_index, ep->num_ptds);
epq->buf_avail += ep->num_ptds;
epq->ptd_count--;
@ -1555,9 +1552,9 @@ static void isp1362_hub_descriptor(struct isp1362_hcd *isp1362_hcd,
desc->wHubCharacteristics = cpu_to_le16((reg >> 8) & 0x1f);
DBG(0, "%s: hubcharacteristics = %02x\n", __func__, cpu_to_le16((reg >> 8) & 0x1f));
desc->bPwrOn2PwrGood = (reg >> 24) & 0xff;
/* two bitmaps: ports removable, and legacy PortPwrCtrlMask */
desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
desc->bitmap[1] = ~0;
/* ports removable, and legacy PortPwrCtrlMask */
desc->u.hs.DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
desc->u.hs.DeviceRemovable[1] = ~0;
DBG(3, "%s: exit\n", __func__);
}

File diff suppressed because it is too large Load Diff

View File

@ -69,6 +69,7 @@ void deinit_kmem_cache(void);
#define HC_INTERRUPT_ENABLE 0x314
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
#define INTERRUPT_ENABLE_SOT_MASK (HC_INTL_INT | HC_SOT_INT | HC_EOT_INT)
#define HC_ISO_INT (1 << 9)
#define HC_ATL_INT (1 << 8)
@ -83,37 +84,29 @@ void deinit_kmem_cache(void);
#define HC_INT_IRQ_MASK_AND_REG 0x328
#define HC_ATL_IRQ_MASK_AND_REG 0x32C
/* Register sets */
#define HC_BEGIN_OF_ATL 0x0c00
#define HC_BEGIN_OF_INT 0x0800
#define HC_BEGIN_OF_ISO 0x0400
#define HC_BEGIN_OF_PAYLOAD 0x1000
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
#define ATL_REGS_OFFSET (0xc00)
#define INT_REGS_OFFSET (0x800)
/* Philips Transfer Descriptor (PTD) */
/* Philips Proprietary Transfer Descriptor (PTD) */
typedef __u32 __bitwise __dw;
struct ptd {
__le32 dw0;
__le32 dw1;
__le32 dw2;
__le32 dw3;
__le32 dw4;
__le32 dw5;
__le32 dw6;
__le32 dw7;
__dw dw0;
__dw dw1;
__dw dw2;
__dw dw3;
__dw dw4;
__dw dw5;
__dw dw6;
__dw dw7;
};
#define PTD_OFFSET 0x0400
#define ISO_PTD_OFFSET 0x0400
#define INT_PTD_OFFSET 0x0800
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
struct inter_packet_info {
void *data_buffer;
u32 payload;
#define PTD_FIRE_NEXT (1 << 0)
#define PTD_URB_FINISHED (1 << 1)
struct urb *urb;
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
};
@ -122,15 +115,6 @@ struct inter_packet_info {
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct isp1760_qtd *qtd);
#define isp1760_dbg(priv, fmt, args...) \
dev_dbg(priv_to_hcd(priv)->self.controller, fmt, ##args)
#define isp1760_info(priv, fmt, args...) \
dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
#define isp1760_err(priv, fmt, args...) \
dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
/*
* Device flags that can vary from board to board. All of these
* indicate the most "atypical" case, so that a devflags of 0 is
@ -167,10 +151,8 @@ struct memory_chunk {
#define BLOCK_2_SIZE 1024
#define BLOCK_3_SIZE 8192
#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
#define PAYLOAD_SIZE 0xf000
/* I saw if some reloads if the pointer was negative */
#define ISP1760_NULL_POINTER (0x400)
#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
#define PAYLOAD_AREA_SIZE 0xf000
/* ATL */
/* DW0 */
@ -224,6 +206,4 @@ struct memory_chunk {
#define NAK_COUNTER (0)
#define ERR_COUNTER (2)
#define HC_ATL_PL_SIZE (8192)
#endif

View File

@ -75,6 +75,7 @@ static const char hcd_name [] = "ohci_hcd";
#define STATECHANGE_DELAY msecs_to_jiffies(300)
#include "ohci.h"
#include "pci-quirks.h"
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
@ -85,18 +86,8 @@ static int ohci_restart (struct ohci_hcd *ohci);
#endif
#ifdef CONFIG_PCI
static void quirk_amd_pll(int state);
static void amd_iso_dev_put(void);
static void sb800_prefetch(struct ohci_hcd *ohci, int on);
#else
static inline void quirk_amd_pll(int state)
{
return;
}
static inline void amd_iso_dev_put(void)
{
return;
}
static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
{
return;
@ -912,7 +903,7 @@ static void ohci_stop (struct usb_hcd *hcd)
if (quirk_zfmicro(ohci))
del_timer(&ohci->unlink_watchdog);
if (quirk_amdiso(ohci))
amd_iso_dev_put();
usb_amd_dev_put();
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
@ -1068,10 +1059,7 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_da8xx_driver
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7763) || \
defined(CONFIG_CPU_SUBTYPE_SH7786)
#ifdef CONFIG_USB_OHCI_SH
#include "ohci-sh.c"
#define PLATFORM_DRIVER ohci_hcd_sh_driver
#endif

View File

@ -580,15 +580,16 @@ ohci_hub_descriptor (
temp |= 0x0008;
desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp);
/* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
rh = roothub_b (ohci);
memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
desc->bitmap [0] = rh & RH_B_DR;
memset(desc->u.hs.DeviceRemovable, 0xff,
sizeof(desc->u.hs.DeviceRemovable));
desc->u.hs.DeviceRemovable[0] = rh & RH_B_DR;
if (ohci->num_ports > 7) {
desc->bitmap [1] = (rh & RH_B_DR) >> 8;
desc->bitmap [2] = 0xff;
desc->u.hs.DeviceRemovable[1] = (rh & RH_B_DR) >> 8;
desc->u.hs.DeviceRemovable[2] = 0xff;
} else
desc->bitmap [1] = 0xff;
desc->u.hs.DeviceRemovable[1] = 0xff;
}
/*-------------------------------------------------------------------------*/

View File

@ -7,6 +7,7 @@
* Copyright (C) 2007-2010 Texas Instruments, Inc.
* Author: Vikram Pandita <vikram.pandita@ti.com>
* Author: Anand Gadiyar <gadiyar@ti.com>
* Author: Keshava Munegowda <keshava_mgowda@ti.com>
*
* Based on ehci-omap.c and some other ohci glue layers
*
@ -24,150 +25,15 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* TODO (last updated Mar 10th, 2010):
* TODO (last updated Feb 27, 2011):
* - add kernel-doc
* - Factor out code common to EHCI to a separate file
* - Make EHCI and OHCI coexist together
* - needs newer silicon versions to actually work
* - the last one to be loaded currently steps on the other's toes
* - Add hooks for configuring transceivers, etc. at init/exit
* - Add aggressive clock-management code
*/
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <plat/usb.h>
/*
* OMAP USBHOST Register addresses: VIRTUAL ADDRESSES
* Use ohci_omap_readl()/ohci_omap_writel() functions
*/
/* TLL Register Set */
#define OMAP_USBTLL_REVISION (0x00)
#define OMAP_USBTLL_SYSCONFIG (0x10)
#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8)
#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3)
#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2)
#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1)
#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0)
#define OMAP_USBTLL_SYSSTATUS (0x14)
#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0)
#define OMAP_USBTLL_IRQSTATUS (0x18)
#define OMAP_USBTLL_IRQENABLE (0x1C)
#define OMAP_TLL_SHARED_CONF (0x30)
#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6)
#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5)
#define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2)
#define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1)
#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0)
#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num)
#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24
#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11)
#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10)
#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9)
#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8)
#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1)
#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
#define OMAP_TLL_CHANNEL_COUNT 3
/* UHH Register Set */
#define OMAP_UHH_REVISION (0x00)
#define OMAP_UHH_SYSCONFIG (0x10)
#define OMAP_UHH_SYSCONFIG_MIDLEMODE (1 << 12)
#define OMAP_UHH_SYSCONFIG_CACTIVITY (1 << 8)
#define OMAP_UHH_SYSCONFIG_SIDLEMODE (1 << 3)
#define OMAP_UHH_SYSCONFIG_ENAWAKEUP (1 << 2)
#define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 1)
#define OMAP_UHH_SYSCONFIG_AUTOIDLE (1 << 0)
#define OMAP_UHH_SYSSTATUS (0x14)
#define OMAP_UHH_SYSSTATUS_UHHRESETDONE (1 << 0)
#define OMAP_UHH_SYSSTATUS_OHCIRESETDONE (1 << 1)
#define OMAP_UHH_SYSSTATUS_EHCIRESETDONE (1 << 2)
#define OMAP_UHH_HOSTCONFIG (0x40)
#define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0)
#define OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS (1 << 0)
#define OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS (1 << 11)
#define OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS (1 << 12)
#define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2)
#define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3)
#define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN (1 << 4)
#define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN (1 << 5)
#define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS (1 << 8)
#define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9)
#define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10)
#define OMAP_UHH_DEBUG_CSR (0x44)
/*-------------------------------------------------------------------------*/
static inline void ohci_omap_writel(void __iomem *base, u32 reg, u32 val)
{
__raw_writel(val, base + reg);
}
static inline u32 ohci_omap_readl(void __iomem *base, u32 reg)
{
return __raw_readl(base + reg);
}
static inline void ohci_omap_writeb(void __iomem *base, u8 reg, u8 val)
{
__raw_writeb(val, base + reg);
}
static inline u8 ohci_omap_readb(void __iomem *base, u8 reg)
{
return __raw_readb(base + reg);
}
/*-------------------------------------------------------------------------*/
struct ohci_hcd_omap3 {
struct ohci_hcd *ohci;
struct device *dev;
struct clk *usbhost_ick;
struct clk *usbhost2_120m_fck;
struct clk *usbhost1_48m_fck;
struct clk *usbtll_fck;
struct clk *usbtll_ick;
/* port_mode: TLL/PHY, 2/3/4/6-PIN, DP-DM/DAT-SE0 */
enum ohci_omap3_port_mode port_mode[OMAP3_HS_USB_PORTS];
void __iomem *uhh_base;
void __iomem *tll_base;
void __iomem *ohci_base;
unsigned es2_compatibility:1;
};
/*-------------------------------------------------------------------------*/
static void ohci_omap3_clock_power(struct ohci_hcd_omap3 *omap, int on)
{
if (on) {
clk_enable(omap->usbtll_ick);
clk_enable(omap->usbtll_fck);
clk_enable(omap->usbhost_ick);
clk_enable(omap->usbhost1_48m_fck);
clk_enable(omap->usbhost2_120m_fck);
} else {
clk_disable(omap->usbhost2_120m_fck);
clk_disable(omap->usbhost1_48m_fck);
clk_disable(omap->usbhost_ick);
clk_disable(omap->usbtll_fck);
clk_disable(omap->usbtll_ick);
}
}
static int ohci_omap3_init(struct usb_hcd *hcd)
{
dev_dbg(hcd->self.controller, "starting OHCI controller\n");
@ -175,7 +41,6 @@ static int ohci_omap3_init(struct usb_hcd *hcd)
return ohci_init(hcd_to_ohci(hcd));
}
/*-------------------------------------------------------------------------*/
static int ohci_omap3_start(struct usb_hcd *hcd)
@ -202,325 +67,6 @@ static int ohci_omap3_start(struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
/*
* convert the port-mode enum to a value we can use in the FSLSMODE
* field of USBTLL_CHANNEL_CONF
*/
static unsigned ohci_omap3_fslsmode(enum ohci_omap3_port_mode mode)
{
switch (mode) {
case OMAP_OHCI_PORT_MODE_UNUSED:
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
return 0x0;
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
return 0x1;
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
return 0x2;
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
return 0x3;
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
return 0x4;
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
return 0x5;
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
return 0x6;
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
return 0x7;
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
return 0xA;
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
return 0xB;
default:
pr_warning("Invalid port mode, using default\n");
return 0x0;
}
}
static void ohci_omap3_tll_config(struct ohci_hcd_omap3 *omap)
{
u32 reg;
int i;
/* Program TLL SHARED CONF */
reg = ohci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF);
reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN;
reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN;
reg |= OMAP_TLL_SHARED_CONF_USB_DIVRATION;
reg |= OMAP_TLL_SHARED_CONF_FCLK_IS_ON;
ohci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg);
/* Program each TLL channel */
/*
* REVISIT: Only the 3-pin and 4-pin PHY modes have
* actually been tested.
*/
for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
/* Enable only those channels that are actually used */
if (omap->port_mode[i] == OMAP_OHCI_PORT_MODE_UNUSED)
continue;
reg = ohci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
reg |= ohci_omap3_fslsmode(omap->port_mode[i])
<< OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT;
reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS;
reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;
ohci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg);
}
}
/* omap3_start_ohci
* - Start the TI USBHOST controller
*/
static int omap3_start_ohci(struct ohci_hcd_omap3 *omap, struct usb_hcd *hcd)
{
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
u32 reg = 0;
int ret = 0;
dev_dbg(omap->dev, "starting TI OHCI USB Controller\n");
/* Get all the clock handles we need */
omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick");
if (IS_ERR(omap->usbhost_ick)) {
dev_err(omap->dev, "could not get usbhost_ick\n");
ret = PTR_ERR(omap->usbhost_ick);
goto err_host_ick;
}
omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck");
if (IS_ERR(omap->usbhost2_120m_fck)) {
dev_err(omap->dev, "could not get usbhost_120m_fck\n");
ret = PTR_ERR(omap->usbhost2_120m_fck);
goto err_host_120m_fck;
}
omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck");
if (IS_ERR(omap->usbhost1_48m_fck)) {
dev_err(omap->dev, "could not get usbhost_48m_fck\n");
ret = PTR_ERR(omap->usbhost1_48m_fck);
goto err_host_48m_fck;
}
omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck");
if (IS_ERR(omap->usbtll_fck)) {
dev_err(omap->dev, "could not get usbtll_fck\n");
ret = PTR_ERR(omap->usbtll_fck);
goto err_tll_fck;
}
omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick");
if (IS_ERR(omap->usbtll_ick)) {
dev_err(omap->dev, "could not get usbtll_ick\n");
ret = PTR_ERR(omap->usbtll_ick);
goto err_tll_ick;
}
/* Now enable all the clocks in the correct order */
ohci_omap3_clock_power(omap, 1);
/* perform TLL soft reset, and wait until reset is complete */
ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
OMAP_USBTLL_SYSCONFIG_SOFTRESET);
/* Wait for TLL reset to complete */
while (!(ohci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
cpu_relax();
if (time_after(jiffies, timeout)) {
dev_dbg(omap->dev, "operation timed out\n");
ret = -EINVAL;
goto err_sys_status;
}
}
dev_dbg(omap->dev, "TLL reset done\n");
/* (1<<3) = no idle mode only for initial debugging */
ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
OMAP_USBTLL_SYSCONFIG_CACTIVITY);
/* Put UHH in NoIdle/NoStandby mode */
reg = ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
| OMAP_UHH_SYSCONFIG_SIDLEMODE
| OMAP_UHH_SYSCONFIG_CACTIVITY
| OMAP_UHH_SYSCONFIG_MIDLEMODE);
reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
reg &= ~OMAP_UHH_SYSCONFIG_SOFTRESET;
ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
reg = ohci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
/*
* REVISIT: Pi_CONNECT_STATUS controls MStandby
* assertion and Swakeup generation - let us not
* worry about this for now. OMAP HWMOD framework
* might take care of this later. If not, we can
* update these registers when adding aggressive
* clock management code.
*
* For now, turn off all the Pi_CONNECT_STATUS bits
*
if (omap->port_mode[0] == OMAP_OHCI_PORT_MODE_UNUSED)
reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
if (omap->port_mode[1] == OMAP_OHCI_PORT_MODE_UNUSED)
reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
if (omap->port_mode[2] == OMAP_OHCI_PORT_MODE_UNUSED)
reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
*/
reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
if (omap->es2_compatibility) {
/*
* All OHCI modes need to go through the TLL,
* unlike in the EHCI case. So use UTMI mode
* for all ports for OHCI, on ES2.x silicon
*/
dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
} else {
dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
if (omap->port_mode[0] == OMAP_OHCI_PORT_MODE_UNUSED)
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
else
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
if (omap->port_mode[1] == OMAP_OHCI_PORT_MODE_UNUSED)
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
else
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
if (omap->port_mode[2] == OMAP_OHCI_PORT_MODE_UNUSED)
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
else
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
}
ohci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
ohci_omap3_tll_config(omap);
return 0;
err_sys_status:
ohci_omap3_clock_power(omap, 0);
clk_put(omap->usbtll_ick);
err_tll_ick:
clk_put(omap->usbtll_fck);
err_tll_fck:
clk_put(omap->usbhost1_48m_fck);
err_host_48m_fck:
clk_put(omap->usbhost2_120m_fck);
err_host_120m_fck:
clk_put(omap->usbhost_ick);
err_host_ick:
return ret;
}
static void omap3_stop_ohci(struct ohci_hcd_omap3 *omap, struct usb_hcd *hcd)
{
unsigned long timeout = jiffies + msecs_to_jiffies(100);
dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n");
/* Reset USBHOST for insmod/rmmod to work */
ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
OMAP_UHH_SYSCONFIG_SOFTRESET);
while (!(ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
& OMAP_UHH_SYSSTATUS_UHHRESETDONE)) {
cpu_relax();
if (time_after(jiffies, timeout))
dev_dbg(omap->dev, "operation timed out\n");
}
while (!(ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
& OMAP_UHH_SYSSTATUS_OHCIRESETDONE)) {
cpu_relax();
if (time_after(jiffies, timeout))
dev_dbg(omap->dev, "operation timed out\n");
}
while (!(ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
& OMAP_UHH_SYSSTATUS_EHCIRESETDONE)) {
cpu_relax();
if (time_after(jiffies, timeout))
dev_dbg(omap->dev, "operation timed out\n");
}
ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1));
while (!(ohci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
& (1 << 0))) {
cpu_relax();
if (time_after(jiffies, timeout))
dev_dbg(omap->dev, "operation timed out\n");
}
ohci_omap3_clock_power(omap, 0);
if (omap->usbtll_fck != NULL) {
clk_put(omap->usbtll_fck);
omap->usbtll_fck = NULL;
}
if (omap->usbhost_ick != NULL) {
clk_put(omap->usbhost_ick);
omap->usbhost_ick = NULL;
}
if (omap->usbhost1_48m_fck != NULL) {
clk_put(omap->usbhost1_48m_fck);
omap->usbhost1_48m_fck = NULL;
}
if (omap->usbhost2_120m_fck != NULL) {
clk_put(omap->usbhost2_120m_fck);
omap->usbhost2_120m_fck = NULL;
}
if (omap->usbtll_ick != NULL) {
clk_put(omap->usbtll_ick);
omap->usbtll_ick = NULL;
}
dev_dbg(omap->dev, "Clock to USB host has been disabled\n");
}
/*-------------------------------------------------------------------------*/
static const struct hc_driver ohci_omap3_hc_driver = {
.description = hcd_name,
.product_desc = "OMAP3 OHCI Host Controller",
@ -580,107 +126,77 @@ static const struct hc_driver ohci_omap3_hc_driver = {
*/
static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
{
struct ohci_hcd_omap_platform_data *pdata = pdev->dev.platform_data;
struct ohci_hcd_omap3 *omap;
struct resource *res;
struct usb_hcd *hcd;
int ret = -ENODEV;
int irq;
struct device *dev = &pdev->dev;
struct usb_hcd *hcd = NULL;
void __iomem *regs = NULL;
struct resource *res;
int ret = -ENODEV;
int irq;
if (usb_disabled())
goto err_disabled;
goto err_end;
if (!pdata) {
dev_dbg(&pdev->dev, "missing platform_data\n");
goto err_pdata;
if (!dev->parent) {
dev_err(dev, "Missing parent device\n");
return -ENODEV;
}
irq = platform_get_irq(pdev, 0);
omap = kzalloc(sizeof(*omap), GFP_KERNEL);
if (!omap) {
ret = -ENOMEM;
goto err_disabled;
irq = platform_get_irq_byname(pdev, "ohci-irq");
if (irq < 0) {
dev_err(dev, "OHCI irq failed\n");
return -ENODEV;
}
hcd = usb_create_hcd(&ohci_omap3_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
res = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "ohci");
if (!ret) {
dev_err(dev, "UHH OHCI get resource failed\n");
return -ENOMEM;
}
regs = ioremap(res->start, resource_size(res));
if (!regs) {
dev_err(dev, "UHH OHCI ioremap failed\n");
return -ENOMEM;
}
hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
dev_name(dev));
if (!hcd) {
ret = -ENOMEM;
goto err_create_hcd;
dev_err(dev, "usb_create_hcd failed\n");
goto err_io;
}
platform_set_drvdata(pdev, omap);
omap->dev = &pdev->dev;
omap->port_mode[0] = pdata->port_mode[0];
omap->port_mode[1] = pdata->port_mode[1];
omap->port_mode[2] = pdata->port_mode[2];
omap->es2_compatibility = pdata->es2_compatibility;
omap->ohci = hcd_to_ohci(hcd);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
hcd->regs = regs;
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
dev_err(&pdev->dev, "OHCI ioremap failed\n");
ret = -ENOMEM;
goto err_ioremap;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
omap->uhh_base = ioremap(res->start, resource_size(res));
if (!omap->uhh_base) {
dev_err(&pdev->dev, "UHH ioremap failed\n");
ret = -ENOMEM;
goto err_uhh_ioremap;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
omap->tll_base = ioremap(res->start, resource_size(res));
if (!omap->tll_base) {
dev_err(&pdev->dev, "TLL ioremap failed\n");
ret = -ENOMEM;
goto err_tll_ioremap;
}
ret = omap3_start_ohci(omap, hcd);
ret = omap_usbhs_enable(dev);
if (ret) {
dev_dbg(&pdev->dev, "failed to start ohci\n");
goto err_start;
dev_dbg(dev, "failed to start ohci\n");
goto err_end;
}
ohci_hcd_init(omap->ohci);
ohci_hcd_init(hcd_to_ohci(hcd));
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (ret) {
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
dev_dbg(dev, "failed to add hcd with err %d\n", ret);
goto err_add_hcd;
}
return 0;
err_add_hcd:
omap3_stop_ohci(omap, hcd);
omap_usbhs_disable(dev);
err_start:
iounmap(omap->tll_base);
err_tll_ioremap:
iounmap(omap->uhh_base);
err_uhh_ioremap:
iounmap(hcd->regs);
err_ioremap:
err_end:
usb_put_hcd(hcd);
err_create_hcd:
kfree(omap);
err_pdata:
err_disabled:
err_io:
iounmap(regs);
return ret;
}
@ -699,24 +215,20 @@ err_disabled:
*/
static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev)
{
struct ohci_hcd_omap3 *omap = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ohci_to_hcd(omap->ohci);
struct device *dev = &pdev->dev;
struct usb_hcd *hcd = dev_get_drvdata(dev);
usb_remove_hcd(hcd);
omap3_stop_ohci(omap, hcd);
iounmap(hcd->regs);
iounmap(omap->tll_base);
iounmap(omap->uhh_base);
usb_remove_hcd(hcd);
omap_usbhs_disable(dev);
usb_put_hcd(hcd);
kfree(omap);
return 0;
}
static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
{
struct ohci_hcd_omap3 *omap = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ohci_to_hcd(omap->ohci);
struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);

View File

@ -22,24 +22,6 @@
#include <linux/io.h>
/* constants used to work around PM-related transfer
* glitches in some AMD 700 series southbridges
*/
#define AB_REG_BAR 0xf0
#define AB_INDX(addr) ((addr) + 0x00)
#define AB_DATA(addr) ((addr) + 0x04)
#define AX_INDXC 0X30
#define AX_DATAC 0x34
#define NB_PCIE_INDX_ADDR 0xe0
#define NB_PCIE_INDX_DATA 0xe4
#define PCIE_P_CNTL 0x10040
#define BIF_NB 0x10002
static struct pci_dev *amd_smbus_dev;
static struct pci_dev *amd_hb_dev;
static int amd_ohci_iso_count;
/*-------------------------------------------------------------------------*/
static int broken_suspend(struct usb_hcd *hcd)
@ -168,15 +150,18 @@ static int ohci_quirk_nec(struct usb_hcd *hcd)
static int ohci_quirk_amd700(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
u8 rev = 0;
struct pci_dev *amd_smbus_dev;
u8 rev;
if (!amd_smbus_dev)
amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI,
PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);
if (usb_amd_find_chipset_info())
ohci->flags |= OHCI_QUIRK_AMD_PLL;
amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI,
PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);
if (!amd_smbus_dev)
return 0;
pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
rev = amd_smbus_dev->revision;
/* SB800 needs pre-fetch fix */
if ((rev >= 0x40) && (rev <= 0x4f)) {
@ -184,19 +169,8 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
ohci_dbg(ohci, "enabled AMD prefetch quirk\n");
}
if ((rev > 0x3b) || (rev < 0x30)) {
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
return 0;
}
amd_ohci_iso_count++;
if (!amd_hb_dev)
amd_hb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9600, NULL);
ohci->flags |= OHCI_QUIRK_AMD_ISO;
ohci_dbg(ohci, "enabled AMD ISO transfers quirk\n");
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
return 0;
}
@ -215,74 +189,6 @@ static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
return 0;
}
/*
* The hardware normally enables the A-link power management feature, which
* lets the system lower the power consumption in idle states.
*
* Assume the system is configured to have USB 1.1 ISO transfers going
* to or from a USB device. Without this quirk, that stream may stutter
* or have breaks occasionally. For transfers going to speakers, this
* makes a very audible mess...
*
* That audio playback corruption is due to the audio stream getting
* interrupted occasionally when the link goes in lower power state
* This USB quirk prevents the link going into that lower power state
* during audio playback or other ISO operations.
*/
static void quirk_amd_pll(int on)
{
u32 addr;
u32 val;
u32 bit = (on > 0) ? 1 : 0;
pci_read_config_dword(amd_smbus_dev, AB_REG_BAR, &addr);
/* BIT names/meanings are NDA-protected, sorry ... */
outl(AX_INDXC, AB_INDX(addr));
outl(0x40, AB_DATA(addr));
outl(AX_DATAC, AB_INDX(addr));
val = inl(AB_DATA(addr));
val &= ~((1 << 3) | (1 << 4) | (1 << 9));
val |= (bit << 3) | ((!bit) << 4) | ((!bit) << 9);
outl(val, AB_DATA(addr));
if (amd_hb_dev) {
addr = PCIE_P_CNTL;
pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val);
val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12));
val |= bit | (bit << 3) | (bit << 12);
val |= ((!bit) << 4) | ((!bit) << 9);
pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val);
addr = BIF_NB;
pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val);
val &= ~(1 << 8);
val |= bit << 8;
pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val);
}
}
static void amd_iso_dev_put(void)
{
amd_ohci_iso_count--;
if (amd_ohci_iso_count == 0) {
if (amd_smbus_dev) {
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
}
if (amd_hb_dev) {
pci_dev_put(amd_hb_dev);
amd_hb_dev = NULL;
}
}
}
static void sb800_prefetch(struct ohci_hcd *ohci, int on)
{
struct pci_dev *pdev;

View File

@ -52,7 +52,7 @@ __acquires(ohci->lock)
ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
if (quirk_amdiso(ohci))
quirk_amd_pll(1);
usb_amd_quirk_pll_enable();
if (quirk_amdprefetch(ohci))
sb800_prefetch(ohci, 0);
}
@ -686,7 +686,7 @@ static void td_submit_urb (
}
if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
if (quirk_amdiso(ohci))
quirk_amd_pll(0);
usb_amd_quirk_pll_disable();
if (quirk_amdprefetch(ohci))
sb800_prefetch(ohci, 1);
}

View File

@ -401,7 +401,7 @@ struct ohci_hcd {
#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
#define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/
#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */
// there are also chip quirks/bugs in init logic
@ -433,7 +433,7 @@ static inline int quirk_zfmicro(struct ohci_hcd *ohci)
}
static inline int quirk_amdiso(struct ohci_hcd *ohci)
{
return ohci->flags & OHCI_QUIRK_AMD_ISO;
return ohci->flags & OHCI_QUIRK_AMD_PLL;
}
static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
{

View File

@ -451,9 +451,9 @@ static void ehci_hub_descriptor(struct oxu_hcd *oxu,
temp = 1 + (ports / 8);
desc->bDescLength = 7 + 2 * temp;
/* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
memset(&desc->bitmap[0], 0, temp);
memset(&desc->bitmap[temp], 0xff, temp);
/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
temp = 0x0008; /* per-port overcurrent reporting */
if (HCS_PPC(oxu->hcs_params))

View File

@ -52,6 +52,264 @@
#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
/* AMD quirk use */
#define AB_REG_BAR_LOW 0xe0
#define AB_REG_BAR_HIGH 0xe1
#define AB_REG_BAR_SB700 0xf0
#define AB_INDX(addr) ((addr) + 0x00)
#define AB_DATA(addr) ((addr) + 0x04)
#define AX_INDXC 0x30
#define AX_DATAC 0x34
#define NB_PCIE_INDX_ADDR 0xe0
#define NB_PCIE_INDX_DATA 0xe4
#define PCIE_P_CNTL 0x10040
#define BIF_NB 0x10002
#define NB_PIF0_PWRDOWN_0 0x01100012
#define NB_PIF0_PWRDOWN_1 0x01100013
static struct amd_chipset_info {
struct pci_dev *nb_dev;
struct pci_dev *smbus_dev;
int nb_type;
int sb_type;
int isoc_reqs;
int probe_count;
int probe_result;
} amd_chipset;
static DEFINE_SPINLOCK(amd_lock);
int usb_amd_find_chipset_info(void)
{
u8 rev = 0;
unsigned long flags;
spin_lock_irqsave(&amd_lock, flags);
amd_chipset.probe_count++;
/* probe only once */
if (amd_chipset.probe_count > 1) {
spin_unlock_irqrestore(&amd_lock, flags);
return amd_chipset.probe_result;
}
amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
if (amd_chipset.smbus_dev) {
rev = amd_chipset.smbus_dev->revision;
if (rev >= 0x40)
amd_chipset.sb_type = 1;
else if (rev >= 0x30 && rev <= 0x3b)
amd_chipset.sb_type = 3;
} else {
amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
0x780b, NULL);
if (!amd_chipset.smbus_dev) {
spin_unlock_irqrestore(&amd_lock, flags);
return 0;
}
rev = amd_chipset.smbus_dev->revision;
if (rev >= 0x11 && rev <= 0x18)
amd_chipset.sb_type = 2;
}
if (amd_chipset.sb_type == 0) {
if (amd_chipset.smbus_dev) {
pci_dev_put(amd_chipset.smbus_dev);
amd_chipset.smbus_dev = NULL;
}
spin_unlock_irqrestore(&amd_lock, flags);
return 0;
}
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
if (amd_chipset.nb_dev) {
amd_chipset.nb_type = 1;
} else {
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
0x1510, NULL);
if (amd_chipset.nb_dev) {
amd_chipset.nb_type = 2;
} else {
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
0x9600, NULL);
if (amd_chipset.nb_dev)
amd_chipset.nb_type = 3;
}
}
amd_chipset.probe_result = 1;
printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
spin_unlock_irqrestore(&amd_lock, flags);
return amd_chipset.probe_result;
}
EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
/*
* The hardware normally enables the A-link power management feature, which
* lets the system lower the power consumption in idle states.
*
* This USB quirk prevents the link going into that lower power state
* during isochronous transfers.
*
* Without this quirk, isochronous stream on OHCI/EHCI/xHCI controllers of
* some AMD platforms may stutter or have breaks occasionally.
*/
static void usb_amd_quirk_pll(int disable)
{
u32 addr, addr_low, addr_high, val;
u32 bit = disable ? 0 : 1;
unsigned long flags;
spin_lock_irqsave(&amd_lock, flags);
if (disable) {
amd_chipset.isoc_reqs++;
if (amd_chipset.isoc_reqs > 1) {
spin_unlock_irqrestore(&amd_lock, flags);
return;
}
} else {
amd_chipset.isoc_reqs--;
if (amd_chipset.isoc_reqs > 0) {
spin_unlock_irqrestore(&amd_lock, flags);
return;
}
}
if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) {
outb_p(AB_REG_BAR_LOW, 0xcd6);
addr_low = inb_p(0xcd7);
outb_p(AB_REG_BAR_HIGH, 0xcd6);
addr_high = inb_p(0xcd7);
addr = addr_high << 8 | addr_low;
outl_p(0x30, AB_INDX(addr));
outl_p(0x40, AB_DATA(addr));
outl_p(0x34, AB_INDX(addr));
val = inl_p(AB_DATA(addr));
} else if (amd_chipset.sb_type == 3) {
pci_read_config_dword(amd_chipset.smbus_dev,
AB_REG_BAR_SB700, &addr);
outl(AX_INDXC, AB_INDX(addr));
outl(0x40, AB_DATA(addr));
outl(AX_DATAC, AB_INDX(addr));
val = inl(AB_DATA(addr));
} else {
spin_unlock_irqrestore(&amd_lock, flags);
return;
}
if (disable) {
val &= ~0x08;
val |= (1 << 4) | (1 << 9);
} else {
val |= 0x08;
val &= ~((1 << 4) | (1 << 9));
}
outl_p(val, AB_DATA(addr));
if (!amd_chipset.nb_dev) {
spin_unlock_irqrestore(&amd_lock, flags);
return;
}
if (amd_chipset.nb_type == 1 || amd_chipset.nb_type == 3) {
addr = PCIE_P_CNTL;
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, &val);
val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12));
val |= bit | (bit << 3) | (bit << 12);
val |= ((!bit) << 4) | ((!bit) << 9);
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, val);
addr = BIF_NB;
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, &val);
val &= ~(1 << 8);
val |= bit << 8;
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, val);
} else if (amd_chipset.nb_type == 2) {
addr = NB_PIF0_PWRDOWN_0;
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, &val);
if (disable)
val &= ~(0x3f << 7);
else
val |= 0x3f << 7;
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, val);
addr = NB_PIF0_PWRDOWN_1;
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_ADDR, addr);
pci_read_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, &val);
if (disable)
val &= ~(0x3f << 7);
else
val |= 0x3f << 7;
pci_write_config_dword(amd_chipset.nb_dev,
NB_PCIE_INDX_DATA, val);
}
spin_unlock_irqrestore(&amd_lock, flags);
return;
}
void usb_amd_quirk_pll_disable(void)
{
usb_amd_quirk_pll(1);
}
EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
void usb_amd_quirk_pll_enable(void)
{
usb_amd_quirk_pll(0);
}
EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable);
void usb_amd_dev_put(void)
{
unsigned long flags;
spin_lock_irqsave(&amd_lock, flags);
amd_chipset.probe_count--;
if (amd_chipset.probe_count > 0) {
spin_unlock_irqrestore(&amd_lock, flags);
return;
}
if (amd_chipset.nb_dev) {
pci_dev_put(amd_chipset.nb_dev);
amd_chipset.nb_dev = NULL;
}
if (amd_chipset.smbus_dev) {
pci_dev_put(amd_chipset.smbus_dev);
amd_chipset.smbus_dev = NULL;
}
amd_chipset.nb_type = 0;
amd_chipset.sb_type = 0;
amd_chipset.isoc_reqs = 0;
amd_chipset.probe_result = 0;
spin_unlock_irqrestore(&amd_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
/*
* Make sure the controller is completely inactive, unable to

View File

@ -1,7 +1,17 @@
#ifndef __LINUX_USB_PCI_QUIRKS_H
#define __LINUX_USB_PCI_QUIRKS_H
#ifdef CONFIG_PCI
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
int usb_amd_find_chipset_info(void);
void usb_amd_dev_put(void);
void usb_amd_quirk_pll_disable(void);
void usb_amd_quirk_pll_enable(void);
#else
static inline void usb_amd_quirk_pll_disable(void) {}
static inline void usb_amd_quirk_pll_enable(void) {}
static inline void usb_amd_dev_put(void) {}
#endif /* CONFIG_PCI */
#endif /* __LINUX_USB_PCI_QUIRKS_H */

View File

@ -2150,8 +2150,9 @@ static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
desc->bDescLength = 9;
desc->bPwrOn2PwrGood = 0;
desc->wHubCharacteristics = cpu_to_le16(0x0011);
desc->bitmap[0] = ((1 << r8a66597->max_root_hub) - 1) << 1;
desc->bitmap[1] = ~0;
desc->u.hs.DeviceRemovable[0] =
((1 << r8a66597->max_root_hub) - 1) << 1;
desc->u.hs.DeviceRemovable[1] = ~0;
}
static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,

View File

@ -1111,9 +1111,9 @@ sl811h_hub_descriptor (
desc->wHubCharacteristics = cpu_to_le16(temp);
/* two bitmaps: ports removable, and legacy PortPwrCtrlMask */
desc->bitmap[0] = 0 << 1;
desc->bitmap[1] = ~0;
/* ports removable, and legacy PortPwrCtrlMask */
desc->u.hs.DeviceRemovable[0] = 0 << 1;
desc->u.hs.DeviceRemovable[1] = ~0;
}
static void

View File

@ -2604,13 +2604,14 @@ static int u132_roothub_descriptor(struct u132 *u132,
retval = u132_read_pcimem(u132, roothub.b, &rh_b);
if (retval)
return retval;
memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
desc->bitmap[0] = rh_b & RH_B_DR;
memset(desc->u.hs.DeviceRemovable, 0xff,
sizeof(desc->u.hs.DeviceRemovable));
desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR;
if (u132->num_ports > 7) {
desc->bitmap[1] = (rh_b & RH_B_DR) >> 8;
desc->bitmap[2] = 0xff;
desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8;
desc->u.hs.DeviceRemovable[2] = 0xff;
} else
desc->bitmap[1] = 0xff;
desc->u.hs.DeviceRemovable[1] = 0xff;
return 0;
}

Some files were not shown because too many files have changed in this diff Show More