forked from Minki/linux
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:
commit
971f115a50
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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();
|
||||
|
@ -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")
|
||||
|
@ -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();
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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[] = {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
86
arch/arm/mach-tegra/include/mach/usb_phy.h
Normal file
86
arch/arm/mach-tegra/include/mach/usb_phy.h
Normal 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 */
|
795
arch/arm/mach-tegra/usb_phy.c
Normal file
795
arch/arm/mach-tegra/usb_phy.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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"
|
||||
|
@ -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
1061
drivers/mfd/omap-usb-host.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 *)®);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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++;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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 (
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
1744
drivers/usb/gadget/fusb300_udc.c
Normal file
1744
drivers/usb/gadget/fusb300_udc.c
Normal file
File diff suppressed because it is too large
Load Diff
687
drivers/usb/gadget/fusb300_udc.h
Normal file
687
drivers/usb/gadget/fusb300_udc.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
383
drivers/usb/host/ehci-pmcmsp.c
Normal file
383
drivers/usb/host/ehci-pmcmsp.c
Normal 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,
|
||||
},
|
||||
};
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
715
drivers/usb/host/ehci-tegra.c
Normal file
715
drivers/usb/host/ehci-tegra.c
Normal 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",
|
||||
}
|
||||
};
|
@ -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*/
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user