Merge branch 'usb-next' into musb-merge

* usb-next: (132 commits)
  USB: uas: Use GFP_NOIO instead of GFP_KERNEL in I/O submission path
  USB: uas: Ensure we only bind to a UAS interface
  USB: uas: Rename sense pipe and sense urb to status pipe and status urb
  USB: uas: Use kzalloc instead of kmalloc
  USB: uas: Fix up the Sense IU
  usb: musb: core: kill unneeded #include's
  DA8xx: assign name to MUSB IRQ resource
  usb: gadget: g_ncm added
  usb: gadget: f_ncm.c added
  usb: gadget: u_ether: prepare for NCM
  usb: pch_udc: Fix setup transfers with data out
  usb: pch_udc: Fix compile error, warnings and checkpatch warnings
  usb: add ab8500 usb transceiver driver
  USB: gadget: Implement runtime PM for MSM bus glue driver
  USB: gadget: Implement runtime PM for ci13xxx gadget
  USB: gadget: Add USB controller driver for MSM SoC
  USB: gadget: Introduce ci13xxx_udc_driver struct
  USB: gadget: Initialize ci13xxx gadget device's coherent DMA mask
  USB: gadget: Fix "scheduling while atomic" bugs in ci13xxx_udc
  USB: gadget: Separate out PCI bus code from ci13xxx_udc
  ...
This commit is contained in:
Greg Kroah-Hartman 2010-12-16 10:05:06 -08:00
commit 36facadd9e
130 changed files with 15279 additions and 1965 deletions

View File

@ -2,7 +2,7 @@
Alan Stern <stern@rowland.harvard.edu>
December 11, 2009
October 28, 2010
@ -107,9 +107,14 @@ allowed to issue dynamic suspends.
The user interface for controlling dynamic PM is located in the power/
subdirectory of each USB device's sysfs directory, that is, in
/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
relevant attribute files are: wakeup, control, and autosuspend.
(There may also be a file named "level"; this file was deprecated
as of the 2.6.35 kernel and replaced by the "control" file.)
relevant attribute files are: wakeup, control, and
autosuspend_delay_ms. (There may also be a file named "level"; this
file was deprecated as of the 2.6.35 kernel and replaced by the
"control" file. In 2.6.38 the "autosuspend" file will be deprecated
and replaced by the "autosuspend_delay_ms" file. The only difference
is that the newer file expresses the delay in milliseconds whereas the
older file uses seconds. Confusingly, both files are present in 2.6.37
but only "autosuspend" works.)
power/wakeup
@ -140,33 +145,36 @@ as of the 2.6.35 kernel and replaced by the "control" file.)
suspended and autoresume was not allowed. This
setting is no longer supported.)
power/autosuspend
power/autosuspend_delay_ms
This file contains an integer value, which is the
number of seconds the device should remain idle before
the kernel will autosuspend it (the idle-delay time).
The default is 2. 0 means to autosuspend as soon as
the device becomes idle, and negative values mean
never to autosuspend. You can write a number to the
file to change the autosuspend idle-delay time.
number of milliseconds the device should remain idle
before the kernel will autosuspend it (the idle-delay
time). The default is 2000. 0 means to autosuspend
as soon as the device becomes idle, and negative
values mean never to autosuspend. You can write a
number to the file to change the autosuspend
idle-delay time.
Writing "-1" to power/autosuspend and writing "on" to power/control do
essentially the same thing -- they both prevent the device from being
autosuspended. Yes, this is a redundancy in the API.
Writing "-1" to power/autosuspend_delay_ms and writing "on" to
power/control do essentially the same thing -- they both prevent the
device from being autosuspended. Yes, this is a redundancy in the
API.
(In 2.6.21 writing "0" to power/autosuspend would prevent the device
from being autosuspended; the behavior was changed in 2.6.22. The
power/autosuspend attribute did not exist prior to 2.6.21, and the
power/level attribute did not exist prior to 2.6.22. power/control
was added in 2.6.34.)
was added in 2.6.34, and power/autosuspend_delay_ms was added in
2.6.37 but did not become functional until 2.6.38.)
Changing the default idle-delay time
------------------------------------
The default autosuspend idle-delay time is controlled by a module
parameter in usbcore. You can specify the value when usbcore is
loaded. For example, to set it to 5 seconds instead of 2 you would
The default autosuspend idle-delay time (in seconds) is controlled by
a module parameter in usbcore. You can specify the value when usbcore
is loaded. For example, to set it to 5 seconds instead of 2 you would
do:
modprobe usbcore autosuspend=5
@ -234,25 +242,23 @@ every device.
If a driver knows that its device has proper suspend/resume support,
it can enable autosuspend all by itself. For example, the video
driver for a laptop's webcam might do this, since these devices are
rarely used and so should normally be autosuspended.
driver for a laptop's webcam might do this (in recent kernels they
do), since these devices are rarely used and so should normally be
autosuspended.
Sometimes it turns out that even when a device does work okay with
autosuspend there are still problems. For example, there are
experimental patches adding autosuspend support to the usbhid driver,
which manages keyboards and mice, among other things. Tests with a
number of keyboards showed that typing on a suspended keyboard, while
causing the keyboard to do a remote wakeup all right, would
nonetheless frequently result in lost keystrokes. Tests with mice
showed that some of them would issue a remote-wakeup request in
response to button presses but not to motion, and some in response to
neither.
autosuspend there are still problems. For example, the usbhid driver,
which manages keyboards and mice, has autosuspend support. Tests with
a number of keyboards show that typing on a suspended keyboard, while
causing the keyboard to do a remote wakeup all right, will nonetheless
frequently result in lost keystrokes. Tests with mice show that some
of them will issue a remote-wakeup request in response to button
presses but not to motion, and some in response to neither.
The kernel will not prevent you from enabling autosuspend on devices
that can't handle it. It is even possible in theory to damage a
device by suspending it at the wrong time -- for example, suspending a
USB hard disk might cause it to spin down without parking the heads.
(Highly unlikely, but possible.) Take care.
device by suspending it at the wrong time. (Highly unlikely, but
possible.) Take care.
The driver interface for Power Management
@ -336,10 +342,6 @@ autosuspend the interface's device. When the usage counter is = 0
then the interface is considered to be idle, and the kernel may
autosuspend the device.
(There is a similar usage counter field in struct usb_device,
associated with the device itself rather than any of its interfaces.
This counter is used only by the USB core.)
Drivers need not be concerned about balancing changes to the usage
counter; the USB core will undo any remaining "get"s when a driver
is unbound from its interface. As a corollary, drivers must not call
@ -409,11 +411,11 @@ during autosuspend. For example, there's not much point
autosuspending a keyboard if the user can't cause the keyboard to do a
remote wakeup by typing on it. If the driver sets
intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
device if remote wakeup isn't available or has been disabled through
the power/wakeup attribute. (If the device is already autosuspended,
though, setting this flag won't cause the kernel to autoresume it.
Normally a driver would set this flag in its probe method, at which
time the device is guaranteed not to be autosuspended.)
device if remote wakeup isn't available. (If the device is already
autosuspended, though, setting this flag won't cause the kernel to
autoresume it. Normally a driver would set this flag in its probe
method, at which time the device is guaranteed not to be
autosuspended.)
If a driver does its I/O asynchronously in interrupt context, it
should call usb_autopm_get_interface_async() before starting output and
@ -422,20 +424,19 @@ it receives an input event, it should call
usb_mark_last_busy(struct usb_device *udev);
in the event handler. This sets udev->last_busy to the current time.
udev->last_busy is the field used for idle-delay calculations;
updating it will cause any pending autosuspend to be moved back. Most
of the usb_autopm_* routines will also set the last_busy field to the
current time.
in the event handler. This tells the PM core that the device was just
busy and therefore the next autosuspend idle-delay expiration should
be pushed back. Many of the usb_autopm_* routines also make this call,
so drivers need to worry only when interrupt-driven input arrives.
Asynchronous operation is always subject to races. For example, a
driver may call one of the usb_autopm_*_interface_async() routines at
a time when the core has just finished deciding the device has been
idle for long enough but not yet gotten around to calling the driver's
suspend method. The suspend method must be responsible for
synchronizing with the output request routine and the URB completion
handler; it should cause autosuspends to fail with -EBUSY if the
driver needs to use the device.
driver may call the usb_autopm_get_interface_async() routine at a time
when the core has just finished deciding the device has been idle for
long enough but not yet gotten around to calling the driver's suspend
method. The suspend method must be responsible for synchronizing with
the I/O request routine and the URB completion handler; it should
cause autosuspends to fail with -EBUSY if the driver needs to use the
device.
External suspend calls should never be allowed to fail in this way,
only autosuspend calls. The driver can tell them apart by checking
@ -472,7 +473,9 @@ Firstly, a device may already be autosuspended when a system suspend
occurs. Since system suspends are supposed to be as transparent as
possible, the device should remain suspended following the system
resume. But this theory may not work out well in practice; over time
the kernel's behavior in this regard has changed.
the kernel's behavior in this regard has changed. As of 2.6.37 the
policy is to resume all devices during a system resume and let them
handle their own runtime suspends afterward.
Secondly, a dynamic power-management event may occur as a system
suspend is underway. The window for this is short, since system

View File

@ -64,17 +64,19 @@ static struct resource usb_resources[] = {
{
.start = IRQ_USBINT,
.flags = IORESOURCE_IRQ,
.name = "mc"
},
{
/* placeholder for the dedicated CPPI IRQ */
.flags = IORESOURCE_IRQ,
.name = "dma"
},
};
static u64 usb_dmamask = DMA_BIT_MASK(32);
static struct platform_device usb_dev = {
.name = "musb_hdrc",
.name = "musb-davinci",
.id = -1,
.dev = {
.platform_data = &usb_data,
@ -110,6 +112,7 @@ static struct resource da8xx_usb20_resources[] = {
{
.start = IRQ_DA8XX_USB_INT,
.flags = IORESOURCE_IRQ,
.name = "mc",
},
};
@ -121,6 +124,7 @@ int __init da8xx_register_usb20(unsigned mA, unsigned potpgt)
usb_dev.resource = da8xx_usb20_resources;
usb_dev.num_resources = ARRAY_SIZE(da8xx_usb20_resources);
usb_dev.name = "musb-da8xx";
return platform_device_register(&usb_dev);
}

View File

@ -44,6 +44,7 @@ config ARCH_OMAP4
select ARM_GIC
select PL310_ERRATA_588369
select ARM_ERRATA_720789
select USB_ARCH_HAS_EHCI
comment "OMAP Core Type"
depends on ARCH_OMAP2

View File

@ -168,9 +168,11 @@ obj-$(CONFIG_MACH_IGEP0030) += board-igep0030.o \
obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \
hsmmc.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \
hsmmc.o
hsmmc.o \
omap_phy_internal.o
obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \
hsmmc.o
hsmmc.o \
omap_phy_internal.o
obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o

View File

@ -42,6 +42,7 @@
#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
@ -225,12 +226,29 @@ static void __init omap_4430sdp_init_irq(void)
omap_gpio_init();
}
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_PERIPHERAL,
.mode = MUSB_OTG,
.power = 100,
};
static struct twl4030_usb_data omap4_usbphy_data = {
.phy_init = omap4430_phy_init,
.phy_exit = omap4430_phy_exit,
.phy_power = omap4430_phy_power,
.phy_set_clock = omap4430_phy_set_clk,
};
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
@ -450,6 +468,7 @@ static struct twl4030_platform_data sdp4430_twldata = {
.vaux1 = &sdp4430_vaux1,
.vaux2 = &sdp4430_vaux2,
.vaux3 = &sdp4430_vaux3,
.usb = &omap4_usbphy_data
};
static struct i2c_board_info __initdata sdp4430_i2c_boardinfo[] = {
@ -514,11 +533,15 @@ static void __init omap_4430sdp_init(void)
platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
omap_serial_init();
omap4_twl6030_hsmmc_init(mmc);
/* OMAP4 SDP uses internal transceiver so register nop transceiver */
usb_nop_xceiv_register();
/* FIXME: allow multi-omap to boot until musb is updated for omap4 */
if (!cpu_is_omap44xx())
usb_musb_init(&musb_board_data);
/* Power on the ULPI PHY */
if (gpio_is_valid(OMAP4SDP_MDM_PWR_EN_GPIO)) {
/* FIXME: Assumes pad is already muxed for GPIO mode */
gpio_request(OMAP4SDP_MDM_PWR_EN_GPIO, "USBB1 PHY VMDM_3V3");
gpio_direction_output(OMAP4SDP_MDM_PWR_EN_GPIO, 1);
}
usb_ehci_init(&ehci_pdata);
usb_musb_init(&musb_board_data);
status = omap_ethernet_init();
if (status) {

View File

@ -46,8 +46,7 @@ static struct device *mmc_device;
#define TUSB6010_GPIO_ENABLE 0
#define TUSB6010_DMACHAN 0x3f
#if defined(CONFIG_USB_TUSB6010) || \
defined(CONFIG_USB_TUSB6010_MODULE)
#ifdef CONFIG_USB_MUSB_TUSB6010
/*
* Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
* 1.5 V voltage regulators of PM companion chip. Companion chip will then
@ -134,7 +133,7 @@ err:
static void __init n8x0_usb_init(void) {}
#endif /*CONFIG_USB_TUSB6010 */
#endif /*CONFIG_USB_MUSB_TUSB6010 */
static struct omap2_mcspi_device_config p54spi_mcspi_config = {

View File

@ -133,10 +133,17 @@ error1:
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_UTMI,
.mode = MUSB_PERIPHERAL,
.mode = MUSB_OTG,
.power = 100,
};
static struct twl4030_usb_data omap4_usbphy_data = {
.phy_init = omap4430_phy_init,
.phy_exit = omap4430_phy_exit,
.phy_power = omap4430_phy_power,
.phy_set_clock = omap4430_phy_set_clk,
};
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
@ -345,6 +352,7 @@ static struct twl4030_platform_data omap4_panda_twldata = {
.vaux1 = &omap4_panda_vaux1,
.vaux2 = &omap4_panda_vaux2,
.vaux3 = &omap4_panda_vaux3,
.usb = &omap4_usbphy_data,
};
static struct i2c_board_info __initdata omap4_panda_i2c_boardinfo[] = {
@ -377,9 +385,7 @@ static void __init omap4_panda_init(void)
/* OMAP4 Panda uses internal transceiver so register nop transceiver */
usb_nop_xceiv_register();
omap4_ehci_init();
/* FIXME: allow multi-omap to boot until musb is updated for omap4 */
if (!cpu_is_omap44xx())
usb_musb_init(&musb_board_data);
usb_musb_init(&musb_board_data);
}
static void __init omap4_panda_map_io(void)

View File

@ -1877,7 +1877,7 @@ static struct omap_clk omap2420_clks[] = {
CLK("omap-aes", "ick", &aes_ick, CK_242X),
CLK(NULL, "pka_ick", &pka_ick, CK_242X),
CLK(NULL, "usb_fck", &usb_fck, CK_242X),
CLK("musb_hdrc", "fck", &osc_ck, CK_242X),
CLK("musb-hdrc", "fck", &osc_ck, CK_242X),
};
/*

View File

@ -1983,7 +1983,7 @@ static struct omap_clk omap2430_clks[] = {
CLK("omap-aes", "ick", &aes_ick, CK_243X),
CLK(NULL, "pka_ick", &pka_ick, CK_243X),
CLK(NULL, "usb_fck", &usb_fck, CK_243X),
CLK("musb_hdrc", "ick", &usbhs_ick, CK_243X),
CLK("musb-omap2430", "ick", &usbhs_ick, CK_243X),
CLK("mmci-omap-hs.0", "ick", &mmchs1_ick, CK_243X),
CLK("mmci-omap-hs.0", "fck", &mmchs1_fck, CK_243X),
CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_243X),

View File

@ -3278,6 +3278,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2 | CK_AM35XX),
CLK("ehci-omap.0", "usbtll_fck", &usbtll_fck, CK_3430ES2 | CK_AM35XX),
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),
@ -3305,14 +3306,15 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1, CK_3430ES1),
CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2, CK_3430ES2),
CLK(NULL, "core_l3_ick", &core_l3_ick, CK_3XXX),
CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es1, CK_3430ES1),
CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es2, CK_3430ES2),
CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1, CK_3430ES1),
CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2, CK_3430ES2),
CLK(NULL, "sdrc_ick", &sdrc_ick, CK_3XXX),
CLK(NULL, "gpmc_fck", &gpmc_fck, CK_3XXX),
CLK(NULL, "security_l3_ick", &security_l3_ick, CK_343X),
CLK(NULL, "pka_ick", &pka_ick, CK_343X),
CLK(NULL, "core_l4_ick", &core_l4_ick, CK_3XXX),
CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2 | CK_AM35XX),
CLK("ehci-omap.0", "usbtll_ick", &usbtll_ick, CK_3430ES2 | CK_AM35XX),
CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "icr_ick", &icr_ick, CK_343X),
CLK("omap-aes", "ick", &aes2_ick, CK_343X),
@ -3358,8 +3360,11 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cam_ick", &cam_ick, CK_343X),
CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X),
CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2 | CK_AM35XX),
CLK("ehci-omap.0", "hs_fck", &usbhost_120m_fck, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2 | CK_AM35XX),
CLK("ehci-omap.0", "fs_fck", &usbhost_48m_fck, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2 | CK_AM35XX),
CLK("ehci-omap.0", "usbhost_ick", &usbhost_ick, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2),
CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX),
CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX),
@ -3437,8 +3442,8 @@ static struct omap_clk omap3xxx_clks[] = {
CLK("davinci_emac", "phy_clk", &emac_fck, CK_AM35XX),
CLK("vpfe-capture", "master", &vpfe_ick, CK_AM35XX),
CLK("vpfe-capture", "slave", &vpfe_fck, CK_AM35XX),
CLK("musb_hdrc", "ick", &hsotgusb_ick_am35xx, CK_AM35XX),
CLK("musb_hdrc", "fck", &hsotgusb_fck_am35xx, CK_AM35XX),
CLK("musb-am35x", "ick", &hsotgusb_ick_am35xx, CK_AM35XX),
CLK("musb-am35x", "fck", &hsotgusb_fck_am35xx, CK_AM35XX),
CLK(NULL, "hecc_ck", &hecc_ck, CK_AM35XX),
CLK(NULL, "uart4_ick", &uart4_ick_am35xx, CK_AM35XX),
};

View File

@ -2937,6 +2937,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(NULL, "usb_host_hs_utmi_p3_clk", &usb_host_hs_utmi_p3_clk, CK_443X),
CLK(NULL, "usb_host_hs_hsic60m_p1_clk", &usb_host_hs_hsic60m_p1_clk, CK_443X),
CLK(NULL, "usb_host_hs_hsic60m_p2_clk", &usb_host_hs_hsic60m_p2_clk, CK_443X),
@ -2948,14 +2949,18 @@ 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(NULL, "otg_60m_gfclk", &otg_60m_gfclk, CK_443X),
CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk, CK_443X),
CLK("musb_hdrc", "ick", &usb_otg_hs_ick, CK_443X),
CLK("musb-omap2430", "ick", &usb_otg_hs_ick, CK_443X),
CLK(NULL, "usb_phy_cm_clk32k", &usb_phy_cm_clk32k, CK_443X),
CLK(NULL, "usb_tll_hs_usb_ch2_clk", &usb_tll_hs_usb_ch2_clk, CK_443X),
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(NULL, "usim_ck", &usim_ck, CK_443X),
CLK(NULL, "usim_fclk", &usim_fclk, CK_443X),
CLK(NULL, "usim_fck", &usim_fck, CK_443X),

View File

@ -0,0 +1,149 @@
/*
* This file configures the internal USB PHY in OMAP4430. Used
* with TWL6030 transceiver and MUSB on OMAP4430.
*
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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; either version 2 of the License, or
* (at your option) any later version.
*
* Author: Hema HK <hemahk@ti.com>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/usb.h>
#include <plat/usb.h>
/* OMAP control module register for UTMI PHY */
#define CONTROL_DEV_CONF 0x300
#define PHY_PD 0x1
#define USBOTGHS_CONTROL 0x33c
#define AVALID BIT(0)
#define BVALID BIT(1)
#define VBUSVALID BIT(2)
#define SESSEND BIT(3)
#define IDDIG BIT(4)
static struct clk *phyclk, *clk48m, *clk32k;
static void __iomem *ctrl_base;
int omap4430_phy_init(struct device *dev)
{
ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K);
if (!ctrl_base) {
dev_err(dev, "control module ioremap failed\n");
return -ENOMEM;
}
/* Power down the phy */
__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
if (IS_ERR(phyclk)) {
dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n");
iounmap(ctrl_base);
return PTR_ERR(phyclk);
}
clk48m = clk_get(dev, "ocp2scp_usb_phy_phy_48m");
if (IS_ERR(clk48m)) {
dev_err(dev, "cannot clk_get ocp2scp_usb_phy_phy_48m\n");
clk_put(phyclk);
iounmap(ctrl_base);
return PTR_ERR(clk48m);
}
clk32k = clk_get(dev, "usb_phy_cm_clk32k");
if (IS_ERR(clk32k)) {
dev_err(dev, "cannot clk_get usb_phy_cm_clk32k\n");
clk_put(phyclk);
clk_put(clk48m);
iounmap(ctrl_base);
return PTR_ERR(clk32k);
}
return 0;
}
int omap4430_phy_set_clk(struct device *dev, int on)
{
static int state;
if (on && !state) {
/* Enable the phy clocks */
clk_enable(phyclk);
clk_enable(clk48m);
clk_enable(clk32k);
state = 1;
} else if (state) {
/* Disable the phy clocks */
clk_disable(phyclk);
clk_disable(clk48m);
clk_disable(clk32k);
state = 0;
}
return 0;
}
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 +
USBOTGHS_CONTROL);
else
/*
* Enable VBUS Valid, AValid and IDDIG
* high impedence
*/
__raw_writel(IDDIG | AVALID | VBUSVALID,
ctrl_base + USBOTGHS_CONTROL);
} else {
/* Enable session END and IDIG to high impedence. */
__raw_writel(SESSEND | IDDIG, ctrl_base +
USBOTGHS_CONTROL);
/* Disable the clocks */
omap4430_phy_set_clk(dev, 0);
/* Power down the phy */
__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
}
return 0;
}
int omap4430_phy_exit(struct device *dev)
{
if (ctrl_base)
iounmap(ctrl_base);
if (phyclk)
clk_put(phyclk);
if (clk48m)
clk_put(clk48m);
if (clk32k)
clk_put(clk32k);
return 0;
}

View File

@ -34,22 +34,15 @@
static struct resource ehci_resources[] = {
{
.start = OMAP34XX_EHCI_BASE,
.end = OMAP34XX_EHCI_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_EHCI_IRQ,
.flags = IORESOURCE_IRQ,
}
};
@ -214,13 +207,148 @@ 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)
{
switch (port_mode[0]) {
case EHCI_HCD_OMAP_MODE_PHY:
omap_mux_init_signal("usbb1_ulpiphy_stp",
OMAP_PIN_OUTPUT);
omap_mux_init_signal("usbb1_ulpiphy_clk",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dir",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_nxt",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat0",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat1",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat2",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat3",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat4",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat5",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat6",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpiphy_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_TLL:
omap_mux_init_signal("usbb1_ulpitll_stp",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("usbb1_ulpitll_clk",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dir",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_nxt",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat0",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat1",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat2",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat3",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat4",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat5",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat6",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb1_ulpitll_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_UNKNOWN:
default:
break;
}
switch (port_mode[1]) {
case EHCI_HCD_OMAP_MODE_PHY:
omap_mux_init_signal("usbb2_ulpiphy_stp",
OMAP_PIN_OUTPUT);
omap_mux_init_signal("usbb2_ulpiphy_clk",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dir",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_nxt",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat0",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat1",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat2",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat3",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat4",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat5",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat6",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpiphy_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_TLL:
omap_mux_init_signal("usbb2_ulpitll_stp",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("usbb2_ulpitll_clk",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dir",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_nxt",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat0",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat1",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat2",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat3",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat4",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat5",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat6",
OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_signal("usbb2_ulpitll_dat7",
OMAP_PIN_INPUT_PULLDOWN);
break;
case EHCI_HCD_OMAP_MODE_UNKNOWN:
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())
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");

View File

@ -30,8 +30,101 @@
#include <mach/irqs.h>
#include <mach/am35xx.h>
#include <plat/usb.h>
#include "control.h"
#ifdef CONFIG_USB_MUSB_SOC
#if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
static void am35x_musb_reset(void)
{
u32 regval;
/* Reset the musb interface */
regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
regval |= AM35XX_USBOTGSS_SW_RST;
omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
regval &= ~AM35XX_USBOTGSS_SW_RST;
omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
}
static void am35x_musb_phy_power(u8 on)
{
unsigned long timeout = jiffies + msecs_to_jiffies(100);
u32 devconf2;
if (on) {
/*
* Start the on-chip PHY and its PLL.
*/
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
devconf2 |= CONF2_PHY_PLLON;
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
pr_info(KERN_INFO "Waiting for PHY clock good...\n");
while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
& CONF2_PHYCLKGD)) {
cpu_relax();
if (time_after(jiffies, timeout)) {
pr_err(KERN_ERR "musb PHY clock good timed out\n");
break;
}
}
} else {
/*
* Power down the on-chip PHY.
*/
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
devconf2 &= ~CONF2_PHY_PLLON;
devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
}
}
static void am35x_musb_clear_irq(void)
{
u32 regval;
regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
regval |= AM35XX_USBOTGSS_INT_CLR;
omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
}
static void am35x_musb_set_mode(u8 musb_mode)
{
u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
devconf2 &= ~CONF2_OTGMODE;
switch (musb_mode) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case MUSB_HOST: /* Force VBUS valid, ID = 0 */
devconf2 |= CONF2_FORCE_HOST;
break;
#endif
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
devconf2 |= CONF2_FORCE_DEVICE;
break;
#endif
#ifdef CONFIG_USB_MUSB_OTG
case MUSB_OTG: /* Don't override the VBUS/ID comparators */
devconf2 |= CONF2_NO_OVERRIDE;
break;
#endif
default:
pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode);
}
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
}
static struct resource musb_resources[] = {
[0] = { /* start and end set dynamically */
@ -40,10 +133,12 @@ static struct resource musb_resources[] = {
[1] = { /* general IRQ */
.start = INT_243X_HS_USB_MC,
.flags = IORESOURCE_IRQ,
.name = "mc",
},
[2] = { /* DMA IRQ */
.start = INT_243X_HS_USB_DMA,
.flags = IORESOURCE_IRQ,
.name = "dma",
},
};
@ -75,7 +170,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = DMA_BIT_MASK(32);
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-omap2430",
.id = -1,
.dev = {
.dma_mask = &musb_dmamask,
@ -91,8 +186,13 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
if (cpu_is_omap243x()) {
musb_resources[0].start = OMAP243X_HS_BASE;
} else if (cpu_is_omap3517() || cpu_is_omap3505()) {
musb_device.name = "musb-am35x";
musb_resources[0].start = AM35XX_IPSS_USBOTGSS_BASE;
musb_resources[1].start = INT_35XX_USBOTG_IRQ;
board_data->set_phy_power = am35x_musb_phy_power;
board_data->clear_irq = am35x_musb_clear_irq;
board_data->set_mode = am35x_musb_set_mode;
board_data->reset = am35x_musb_reset;
} else if (cpu_is_omap34xx()) {
musb_resources[0].start = OMAP34XX_HSUSB_OTG_BASE;
} else if (cpu_is_omap44xx()) {

View File

@ -223,7 +223,7 @@ static struct resource tusb_resources[] = {
static u64 tusb_dmamask = ~(u32)0;
static struct platform_device tusb_device = {
.name = "musb_hdrc",
.name = "musb-tusb",
.id = -1,
.dev = {
.dma_mask = &tusb_dmamask,

View File

@ -52,5 +52,10 @@
#define OMAP4_MMU1_BASE 0x55082000
#define OMAP4_MMU2_BASE 0x4A066000
#define OMAP44XX_USBTLL_BASE (L4_44XX_BASE + 0x62000)
#define OMAP44XX_UHH_CONFIG_BASE (L4_44XX_BASE + 0x64000)
#define OMAP44XX_HSUSB_OHCI_BASE (L4_44XX_BASE + 0x64800)
#define OMAP44XX_HSUSB_EHCI_BASE (L4_44XX_BASE + 0x64C00)
#endif /* __ASM_ARCH_OMAP44XX_H */

View File

@ -11,6 +11,7 @@ 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 {
@ -69,6 +70,10 @@ struct omap_musb_board_data {
u8 mode;
u16 power;
unsigned extvbus:1;
void (*set_phy_power)(u8 on);
void (*clear_irq)(void);
void (*set_mode)(u8 mode);
void (*reset)(void);
};
enum musb_interface {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI};
@ -79,6 +84,11 @@ extern void usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata);
extern void usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata);
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);
#endif

View File

@ -83,7 +83,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = ~(u32)0;
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-blackfin",
.id = 0,
.dev = {
.dma_mask = &musb_dmamask,

View File

@ -82,11 +82,13 @@ static struct resource musb_resources[] = {
.start = IRQ_USB_INT0,
.end = IRQ_USB_INT0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "mc"
},
[2] = { /* DMA IRQ */
.start = IRQ_USB_DMA,
.end = IRQ_USB_DMA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "dma"
},
};
@ -118,7 +120,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = ~(u32)0;
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-blackfin",
.id = 0,
.dev = {
.dma_mask = &musb_dmamask,

View File

@ -46,11 +46,13 @@ static struct resource musb_resources[] = {
.start = IRQ_USB_INT0,
.end = IRQ_USB_INT0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "mc"
},
[2] = { /* DMA IRQ */
.start = IRQ_USB_DMA,
.end = IRQ_USB_DMA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "dma"
},
};
@ -82,7 +84,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = ~(u32)0;
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-blackfin",
.id = 0,
.dev = {
.dma_mask = &musb_dmamask,

View File

@ -86,11 +86,13 @@ static struct resource musb_resources[] = {
.start = IRQ_USB_INT0,
.end = IRQ_USB_INT0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "mc"
},
[2] = { /* DMA IRQ */
.start = IRQ_USB_DMA,
.end = IRQ_USB_DMA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "dma"
},
};
@ -122,7 +124,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = ~(u32)0;
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-blackfin",
.id = 0,
.dev = {
.dma_mask = &musb_dmamask,

View File

@ -91,7 +91,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = ~(u32)0;
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-blackfin",
.id = 0,
.dev = {
.dma_mask = &musb_dmamask,

View File

@ -482,11 +482,13 @@ static struct resource musb_resources[] = {
.start = IRQ_USB_INT0,
.end = IRQ_USB_INT0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "mc"
},
[2] = { /* DMA IRQ */
.start = IRQ_USB_DMA,
.end = IRQ_USB_DMA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "dma"
},
};
@ -518,7 +520,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = ~(u32)0;
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-blackfin",
.id = 0,
.dev = {
.dma_mask = &musb_dmamask,

View File

@ -587,11 +587,13 @@ static struct resource musb_resources[] = {
.start = IRQ_USB_INT0,
.end = IRQ_USB_INT0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "mc"
},
[2] = { /* DMA IRQ */
.start = IRQ_USB_DMA,
.end = IRQ_USB_DMA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
.name = "dma"
},
};
@ -623,7 +625,7 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = ~(u32)0;
static struct platform_device musb_device = {
.name = "musb_hdrc",
.name = "musb-blackfin",
.id = 0,
.dev = {
.dma_mask = &musb_dmamask,

View File

@ -346,6 +346,7 @@ config CPU_SUBTYPE_SH7720
select CPU_SH3
select CPU_HAS_DSP
select SYS_SUPPORTS_CMT
select USB_ARCH_HAS_OHCI
help
Select SH7720 if you have a SH3-DSP SH7720 CPU.
@ -354,6 +355,7 @@ config CPU_SUBTYPE_SH7721
select CPU_SH3
select CPU_HAS_DSP
select SYS_SUPPORTS_CMT
select USB_ARCH_HAS_OHCI
help
Select SH7721 if you have a SH3-DSP SH7721 CPU.
@ -431,6 +433,7 @@ config CPU_SUBTYPE_SH7757
config CPU_SUBTYPE_SH7763
bool "Support SH7763 processor"
select CPU_SH4A
select USB_ARCH_HAS_OHCI
help
Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
@ -455,6 +458,8 @@ config CPU_SUBTYPE_SH7786
select CPU_SHX3
select CPU_HAS_PTEAEX
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select USB_ARCH_HAS_OHCI
select USB_ARCH_HAS_EHCI
config CPU_SUBTYPE_SHX3
bool "Support SH-X3 processor"

View File

@ -522,10 +522,37 @@ static struct platform_device dma0_device = {
},
};
static struct resource usb_ohci_resources[] = {
#define USB_EHCI_START 0xffe70000
#define USB_OHCI_START 0xffe70400
static struct resource usb_ehci_resources[] = {
[0] = {
.start = 0xffe70400,
.end = 0xffe704ff,
.start = USB_EHCI_START,
.end = USB_EHCI_START + 0x3ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 77,
.end = 77,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device usb_ehci_device = {
.name = "sh_ehci",
.id = -1,
.dev = {
.dma_mask = &usb_ehci_device.dev.coherent_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(usb_ehci_resources),
.resource = usb_ehci_resources,
};
static struct resource usb_ohci_resources[] = {
[0] = {
.start = USB_OHCI_START,
.end = USB_OHCI_START + 0x3ff,
.flags = IORESOURCE_MEM,
},
[1] = {
@ -535,12 +562,11 @@ static struct resource usb_ohci_resources[] = {
},
};
static u64 usb_ohci_dma_mask = DMA_BIT_MASK(32);
static struct platform_device usb_ohci_device = {
.name = "sh_ohci",
.id = -1,
.dev = {
.dma_mask = &usb_ohci_dma_mask,
.dma_mask = &usb_ohci_device.dev.coherent_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(usb_ohci_resources),
@ -570,6 +596,7 @@ static struct platform_device *sh7786_early_devices[] __initdata = {
static struct platform_device *sh7786_devices[] __initdata = {
&dma0_device,
&usb_ehci_device,
&usb_ohci_device,
};

View File

@ -452,7 +452,8 @@ static int poseidon_probe(struct usb_interface *interface,
device_init_wakeup(&udev->dev, 1);
#ifdef CONFIG_PM
pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
pm_runtime_set_autosuspend_delay(&pd->udev->dev,
1000 * PM_SUSPEND_DELAY);
usb_enable_autosuspend(pd->udev);
if (in_hibernation(pd)) {

View File

@ -95,7 +95,8 @@
#define twl_has_rtc() false
#endif
#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\
defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE)
#define twl_has_usb() true
#else
#define twl_has_usb() false
@ -682,6 +683,43 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
usb3v1.dev = child;
}
}
if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
static struct regulator_consumer_supply usb3v3 = {
.supply = "vusb",
};
if (twl_has_regulator()) {
/* this is a template that gets copied */
struct regulator_init_data usb_fixed = {
.constraints.valid_modes_mask =
REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.constraints.valid_ops_mask =
REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
};
child = add_regulator_linked(TWL6030_REG_VUSB,
&usb_fixed, &usb3v3, 1);
if (IS_ERR(child))
return PTR_ERR(child);
}
child = add_child(0, "twl6030_usb",
pdata->usb, sizeof(*pdata->usb),
true,
/* irq1 = VBUS_PRES, irq0 = USB ID */
pdata->irq_base + USBOTG_INTR_OFFSET,
pdata->irq_base + USB_PRES_INTR_OFFSET);
if (IS_ERR(child))
return PTR_ERR(child);
/* we need to connect regulators to this transceiver */
if (twl_has_regulator() && child)
usb3v3.dev = child;
}
if (twl_has_watchdog()) {
child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
@ -815,10 +853,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6030_REG_VUSB, pdata->vusb);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
if (IS_ERR(child))
return PTR_ERR(child);

View File

@ -74,7 +74,7 @@ static int twl6030_interrupt_mapping[24] = {
USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */
USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */
USBOTG_INTR_OFFSET, /* Bit 18 ID */
USBOTG_INTR_OFFSET, /* Bit 19 VBUS */
USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */
CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */
CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */
CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */
@ -128,6 +128,13 @@ static int twl6030_irq_thread(void *data)
sts.bytes[3] = 0; /* Only 24 bits are valid*/
/*
* Since VBUS status bit is not reliable for VBUS disconnect
* use CHARGER VBUS detection status bit instead.
*/
if (sts.bytes[2] & 0x10)
sts.bytes[2] |= 0x08;
for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
local_irq_disable();
if (sts.int_sts & 0x1) {

View File

@ -514,7 +514,7 @@ int i2400mu_probe(struct usb_interface *iface,
#ifdef CONFIG_PM
iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */
device_init_wakeup(dev, 1);
usb_dev->autosuspend_delay = 15 * HZ;
pm_runtime_set_autosuspend_delay(&usb_dev->dev, 15000);
usb_enable_autosuspend(usb_dev);
#endif

View File

@ -277,7 +277,7 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
if(psAdapter->bDoSuspend)
{
#ifdef CONFIG_PM
udev->autosuspend_delay = 0;
pm_runtime_set_autosuspend_delay(&udev->dev, 0);
intf->needs_remote_wakeup = 1;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
udev->autosuspend_disabled = 0;

View File

@ -41,17 +41,13 @@ config USB_ARCH_HAS_OHCI
default y if MFD_TC6393XB
default y if ARCH_W90X900
default y if ARCH_DAVINCI_DA8XX
default y if PLAT_SPEAR
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
# MIPS:
default y if MIPS_ALCHEMY
default y if MACH_JZ4740
# SH:
default y if CPU_SUBTYPE_SH7720
default y if CPU_SUBTYPE_SH7721
default y if CPU_SUBTYPE_SH7763
default y if CPU_SUBTYPE_SH7786
# more:
default PCI
@ -66,6 +62,9 @@ config USB_ARCH_HAS_EHCI
default y if ARCH_AT91SAM9G45
default y if ARCH_MXC
default y if ARCH_OMAP3
default y if ARCH_VT8500
default y if PLAT_SPEAR
default y if ARCH_MSM
default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.

View File

@ -27,7 +27,6 @@
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/usb/hcd.h>
#include <linux/pm_runtime.h>
#include "usb.h"
@ -1262,6 +1261,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
udev->reset_resume);
}
}
usb_mark_last_busy(udev);
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
@ -1329,7 +1329,6 @@ int usb_resume(struct device *dev, pm_message_t msg)
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
udev->last_busy = jiffies;
do_unbind_rebind(udev, DO_REBIND);
}
}
@ -1397,33 +1396,8 @@ void usb_autosuspend_device(struct usb_device *udev)
{
int status;
udev->last_busy = jiffies;
status = pm_runtime_put_sync(&udev->dev);
dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&udev->dev.power.usage_count),
status);
}
/**
* usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces
* @udev: the usb_device to autosuspend
*
* This routine should be called when a core subsystem thinks @udev may
* be ready to autosuspend.
*
* @udev's usage counter left unchanged. If it is 0 and all the interfaces
* are inactive then an autosuspend will be attempted. The attempt may
* fail or be delayed.
*
* The caller must hold @udev's device lock.
*
* This routine can run only in process context.
*/
void usb_try_autosuspend_device(struct usb_device *udev)
{
int status;
status = pm_runtime_idle(&udev->dev);
usb_mark_last_busy(udev);
status = pm_runtime_put_sync_autosuspend(&udev->dev);
dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&udev->dev.power.usage_count),
status);
@ -1482,7 +1456,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
struct usb_device *udev = interface_to_usbdev(intf);
int status;
udev->last_busy = jiffies;
usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
status = pm_runtime_put_sync(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
@ -1509,32 +1483,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
void usb_autopm_put_interface_async(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
unsigned long last_busy;
int status = 0;
int status;
last_busy = udev->last_busy;
udev->last_busy = jiffies;
usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
pm_runtime_put_noidle(&intf->dev);
if (udev->dev.power.runtime_auto) {
/* Optimization: Don't schedule a delayed autosuspend if
* the timer is already running and the expiration time
* wouldn't change.
*
* We have to use the interface's timer. Attempts to
* schedule a suspend for the device would fail because
* the interface is still active.
*/
if (intf->dev.power.timer_expires == 0 ||
round_jiffies_up(last_busy) !=
round_jiffies_up(jiffies)) {
status = pm_schedule_suspend(&intf->dev,
jiffies_to_msecs(
round_jiffies_up_relative(
udev->autosuspend_delay)));
}
}
status = pm_runtime_put(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&intf->dev.power.usage_count),
status);
@ -1554,7 +1507,7 @@ void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
udev->last_busy = jiffies;
usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
pm_runtime_put_noidle(&intf->dev);
}
@ -1612,18 +1565,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
*/
int usb_autopm_get_interface_async(struct usb_interface *intf)
{
int status = 0;
enum rpm_status s;
/* Don't request a resume unless the interface is already suspending
* or suspended. Doing so would force a running suspend timer to be
* cancelled.
*/
pm_runtime_get_noresume(&intf->dev);
s = ACCESS_ONCE(intf->dev.power.runtime_status);
if (s == RPM_SUSPENDING || s == RPM_SUSPENDED)
status = pm_request_resume(&intf->dev);
int status;
status = pm_runtime_get(&intf->dev);
if (status < 0 && status != -EINPROGRESS)
pm_runtime_put_noidle(&intf->dev);
else
@ -1650,7 +1594,7 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
udev->last_busy = jiffies;
usb_mark_last_busy(udev);
atomic_inc(&intf->pm_usage_cnt);
pm_runtime_get_noresume(&intf->dev);
}
@ -1661,7 +1605,6 @@ static int autosuspend_check(struct usb_device *udev)
{
int w, i;
struct usb_interface *intf;
unsigned long suspend_time, j;
/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
@ -1701,87 +1644,46 @@ static int autosuspend_check(struct usb_device *udev)
return -EOPNOTSUPP;
}
udev->do_remote_wakeup = w;
/* If everything is okay but the device hasn't been idle for long
* enough, queue a delayed autosuspend request.
*/
j = ACCESS_ONCE(jiffies);
suspend_time = udev->last_busy + udev->autosuspend_delay;
if (time_before(j, suspend_time)) {
pm_schedule_suspend(&udev->dev, jiffies_to_msecs(
round_jiffies_up_relative(suspend_time - j)));
return -EAGAIN;
}
return 0;
}
static int usb_runtime_suspend(struct device *dev)
{
int status = 0;
struct usb_device *udev = to_usb_device(dev);
int status;
/* A USB device can be suspended if it passes the various autosuspend
* checks. Runtime suspend for a USB device means suspending all the
* interfaces and then the device itself.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)
return -EAGAIN;
if (autosuspend_check(udev) != 0)
return -EAGAIN;
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
/* If an interface fails the suspend, adjust the last_busy
* time so that we don't get another suspend attempt right
* away.
*/
if (status) {
udev->last_busy = jiffies +
(udev->autosuspend_delay == 0 ?
HZ/2 : 0);
}
/* Prevent the parent from suspending immediately after */
else if (udev->parent)
udev->parent->last_busy = jiffies;
}
/* Runtime suspend for a USB interface doesn't mean anything. */
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
return status;
}
static int usb_runtime_resume(struct device *dev)
{
struct usb_device *udev = to_usb_device(dev);
int status;
/* Runtime resume for a USB device means resuming both the device
* and all its interfaces.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
int status;
status = usb_resume_both(udev, PMSG_AUTO_RESUME);
udev->last_busy = jiffies;
return status;
}
/* Runtime resume for a USB interface doesn't mean anything. */
return 0;
status = usb_resume_both(udev, PMSG_AUTO_RESUME);
return status;
}
static int usb_runtime_idle(struct device *dev)
{
struct usb_device *udev = to_usb_device(dev);
/* An idle USB device can be suspended if it passes the various
* autosuspend checks. An idle interface can be suspended at
* any time.
* autosuspend checks.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)
return 0;
}
pm_runtime_suspend(dev);
if (autosuspend_check(udev) == 0)
pm_runtime_autosuspend(dev);
return 0;
}

View File

@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>

View File

@ -38,7 +38,6 @@
#include <asm/unaligned.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>

View File

@ -24,7 +24,6 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@ -1804,8 +1803,15 @@ int usb_new_device(struct usb_device *udev)
/* Tell the runtime-PM framework the device is active */
pm_runtime_set_active(&udev->dev);
pm_runtime_get_noresume(&udev->dev);
pm_runtime_use_autosuspend(&udev->dev);
pm_runtime_enable(&udev->dev);
/* By default, forbid autosuspend for all devices. It will be
* allowed for hubs during binding.
*/
usb_disable_autosuspend(udev);
err = usb_enumerate_device(udev); /* Read descriptors */
if (err < 0)
goto fail;
@ -1831,6 +1837,8 @@ int usb_new_device(struct usb_device *udev)
}
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
usb_mark_last_busy(udev);
pm_runtime_put_sync_autosuspend(&udev->dev);
return err;
fail:
@ -2221,6 +2229,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
usb_set_device_state(udev, USB_STATE_SUSPENDED);
msleep(10);
}
usb_mark_last_busy(hub->hdev);
return status;
}

View File

@ -1804,6 +1804,7 @@ free_interfaces:
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
intf->minor = -1;
device_initialize(&intf->dev);
pm_runtime_no_callbacks(&intf->dev);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);

View File

@ -117,21 +117,6 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
#ifdef CONFIG_USB_SUSPEND
/* By default, disable autosuspend for all devices. The hub driver
* will enable it for hubs.
*/
usb_disable_autosuspend(udev);
/* Autosuspend can also be disabled if the initial autosuspend_delay
* is negative.
*/
if (udev->autosuspend_delay < 0)
usb_autoresume_device(udev);
#endif
/* For the present, all devices default to USB-PERSIST enabled */
#if 0 /* was: #ifdef CONFIG_PM */
/* Hubs are automatically enabled for USB-PERSIST */

View File

@ -233,8 +233,6 @@ static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
#ifdef CONFIG_PM
static const char power_group[] = "power";
static ssize_t
show_persist(struct device *dev, struct device_attribute *attr, char *buf)
{
@ -278,7 +276,7 @@ static int add_persist_attributes(struct device *dev)
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_persist.attr,
power_group);
power_group_name);
}
return rc;
}
@ -287,7 +285,7 @@ static void remove_persist_attributes(struct device *dev)
{
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_persist.attr,
power_group);
power_group_name);
}
#else
@ -336,44 +334,20 @@ static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL);
static ssize_t
show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->autosuspend_delay / HZ);
return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000);
}
static ssize_t
set_autosuspend(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int value, old_delay;
int rc;
int value;
if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
value <= - INT_MAX/HZ)
if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/1000 ||
value <= -INT_MAX/1000)
return -EINVAL;
value *= HZ;
usb_lock_device(udev);
old_delay = udev->autosuspend_delay;
udev->autosuspend_delay = value;
if (old_delay < 0) { /* Autosuspend wasn't allowed */
if (value >= 0)
usb_autosuspend_device(udev);
} else { /* Autosuspend was allowed */
if (value < 0) {
rc = usb_autoresume_device(udev);
if (rc < 0) {
count = rc;
udev->autosuspend_delay = old_delay;
}
} else {
usb_try_autosuspend_device(udev);
}
}
usb_unlock_device(udev);
pm_runtime_set_autosuspend_delay(dev, value * 1000);
return count;
}
@ -438,44 +412,30 @@ set_level(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
static struct attribute *power_attrs[] = {
&dev_attr_autosuspend.attr,
&dev_attr_level.attr,
&dev_attr_connected_duration.attr,
&dev_attr_active_duration.attr,
NULL,
};
static struct attribute_group power_attr_group = {
.name = power_group_name,
.attrs = power_attrs,
};
static int add_power_attributes(struct device *dev)
{
int rc = 0;
if (is_usb_device(dev)) {
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_autosuspend.attr,
power_group);
if (rc == 0)
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_level.attr,
power_group);
if (rc == 0)
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_connected_duration.attr,
power_group);
if (rc == 0)
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_active_duration.attr,
power_group);
}
if (is_usb_device(dev))
rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
return rc;
}
static void remove_power_attributes(struct device *dev)
{
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_active_duration.attr,
power_group);
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_connected_duration.attr,
power_group);
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_level.attr,
power_group);
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_autosuspend.attr,
power_group);
sysfs_unmerge_group(&dev->kobj, &power_attr_group);
}
#else

View File

@ -445,7 +445,8 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
pm_runtime_set_autosuspend_delay(&dev->dev,
usb_autosuspend_delay * 1000);
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
#endif

View File

@ -75,14 +75,12 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
#ifdef CONFIG_USB_SUSPEND
extern void usb_autosuspend_device(struct usb_device *udev);
extern void usb_try_autosuspend_device(struct usb_device *udev);
extern int usb_autoresume_device(struct usb_device *udev);
extern int usb_remote_wakeup(struct usb_device *dev);
#else
#define usb_autosuspend_device(udev) do {} while (0)
#define usb_try_autosuspend_device(udev) do {} while (0)
static inline int usb_autoresume_device(struct usb_device *udev)
{
return 0;

View File

@ -338,6 +338,19 @@ config USB_S3C2410_DEBUG
boolean "S3C2410 udc debug messages"
depends on USB_GADGET_S3C2410
config USB_GADGET_PXA_U2O
boolean "PXA9xx Processor USB2.0 controller"
select USB_GADGET_DUALSPEED
help
PXA9xx Processor series include a high speed USB2.0 device
controller, which support high speed and full speed USB peripheral.
config USB_PXA_U2O
tristate
depends on USB_GADGET_PXA_U2O
default USB_GADGET
select USB_GADGET_SELECTED
#
# Controllers available in both integrated and discrete versions
#
@ -414,8 +427,8 @@ config USB_FSL_QE
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_CI13XXX
boolean "MIPS USB CI13xxx"
config USB_GADGET_CI13XXX_PCI
boolean "MIPS USB CI13xxx PCI UDC"
depends on PCI
select USB_GADGET_DUALSPEED
help
@ -426,9 +439,9 @@ config USB_GADGET_CI13XXX
dynamically linked module called "ci13xxx_udc" and force all
gadget drivers to also be dynamically linked.
config USB_CI13XXX
config USB_CI13XXX_PCI
tristate
depends on USB_GADGET_CI13XXX
depends on USB_GADGET_CI13XXX_PCI
default USB_GADGET
select USB_GADGET_SELECTED
@ -495,6 +508,49 @@ config USB_LANGWELL
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_EG20T
boolean "Intel EG20T(Topcliff) USB Device controller"
depends on PCI
select USB_GADGET_DUALSPEED
help
This is a USB device driver for EG20T PCH.
EG20T PCH is the platform controller hub that is used in Intel's
general embedded platform. EG20T PCH has USB device interface.
Using this interface, it is able to access system devices connected
to USB device.
This driver enables USB device function.
USB device is a USB peripheral controller which
supports both full and high speed USB 2.0 data transfers.
This driver supports both control transfer and bulk transfer modes.
This driver dose not support interrupt transfer or isochronous
transfer modes.
config USB_EG20T
tristate
depends on USB_GADGET_EG20T
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_CI13XXX_MSM
boolean "MIPS USB CI13xxx for MSM"
depends on ARCH_MSM
select USB_GADGET_DUALSPEED
select USB_MSM_OTG_72K
help
MSM SoC has chipidea USB controller. This driver uses
ci13xxx_udc core.
This driver depends on OTG driver for PHY initialization,
clock management, powering up VBUS, and power management.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "ci13xxx_msm" and force all
gadget drivers to also be dynamically linked.
config USB_CI13XXX_MSM
tristate
depends on USB_GADGET_CI13XXX_MSM
default USB_GADGET
select USB_GADGET_SELECTED
#
# LAST -- dummy/emulated controller
@ -685,6 +741,19 @@ config USB_ETH_EEM
If you say "y" here, the Ethernet gadget driver will use the EEM
protocol rather than ECM. If unsure, say "n".
config USB_G_NCM
tristate "Network Control Model (NCM) support"
depends on NET
select CRC32
help
This driver implements USB CDC NCM subclass standard. NCM is
an advanced protocol for Ethernet encapsulation, allows grouping
of several ethernet frames into one USB transfer and diffferent
alignment possibilities.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_ncm".
config USB_GADGETFS
tristate "Gadget Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL

View File

@ -21,9 +21,13 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
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
#
# USB gadget drivers
@ -43,6 +47,7 @@ g_hid-y := hid.o
g_dbgp-y := dbgp.o
g_nokia-y := nokia.o
g_webcam-y := webcam.o
g_ncm-y := ncm.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@ -60,3 +65,4 @@ obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o

View File

@ -3359,7 +3359,6 @@ static int udc_probe(struct udc *dev)
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.release = gadget_release;
dev->gadget.name = name;
dev->gadget.name = name;
dev->gadget.is_dualspeed = 1;
/* init registers, interrupts, ... */

View File

@ -0,0 +1,134 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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 Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h>
#include "ci13xxx_udc.c"
#define MSM_USB_BASE (udc->regs)
static irqreturn_t msm_udc_irq(int irq, void *data)
{
return udc_irq();
}
static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
{
struct device *dev = udc->gadget.dev.parent;
int val;
switch (event) {
case CI13XXX_CONTROLLER_RESET_EVENT:
dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel(0, USB_AHBMODE);
break;
case CI13XXX_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n");
/*
* Put the transceiver in non-driving mode. Otherwise host
* may not detect soft-disconnection.
*/
val = otg_io_read(udc->transceiver, ULPI_FUNC_CTRL);
val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
otg_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
break;
default:
dev_dbg(dev, "unknown ci13xxx_udc event\n");
break;
}
}
static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
.name = "ci13xxx_msm",
.flags = CI13XXX_REGS_SHARED |
CI13XXX_REQUIRE_TRANSCEIVER |
CI13XXX_PULLUP_ON_VBUS |
CI13XXX_DISABLE_STREAMING,
.notify_event = ci13xxx_msm_notify_event,
};
static int ci13xxx_msm_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *regs;
int irq;
int ret;
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get platform resource mem\n");
return -ENXIO;
}
regs = ioremap(res->start, resource_size(res));
if (!regs) {
dev_err(&pdev->dev, "ioremap failed\n");
return -ENOMEM;
}
ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs);
if (ret < 0) {
dev_err(&pdev->dev, "udc_probe failed\n");
goto iounmap;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "IRQ not found\n");
ret = -ENXIO;
goto udc_remove;
}
ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "request_irq failed\n");
goto udc_remove;
}
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
udc_remove:
udc_remove();
iounmap:
iounmap(regs);
return ret;
}
static struct platform_driver ci13xxx_msm_driver = {
.probe = ci13xxx_msm_probe,
.driver = { .name = "msm_hsusb", },
};
static int __init ci13xxx_msm_init(void)
{
return platform_driver_register(&ci13xxx_msm_driver);
}
module_init(ci13xxx_msm_init);

View File

@ -0,0 +1,176 @@
/*
* ci13xxx_pci.c - MIPS USB IP core family device controller
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
*
* Author: David Lopo
*
* 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
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "ci13xxx_udc.c"
/* driver name */
#define UDC_DRIVER_NAME "ci13xxx_pci"
/******************************************************************************
* PCI block
*****************************************************************************/
/**
* ci13xxx_pci_irq: interrut handler
* @irq: irq number
* @pdev: USB Device Controller interrupt source
*
* This function returns IRQ_HANDLED if the IRQ has been handled
* This is an ISR don't trace, use attribute interface instead
*/
static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
{
if (irq == 0) {
dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
return IRQ_HANDLED;
}
return udc_irq();
}
static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
.name = UDC_DRIVER_NAME,
};
/**
* ci13xxx_pci_probe: PCI probe
* @pdev: USB device controller being probed
* @id: PCI hotplug ID connecting controller to UDC framework
*
* This function returns an error code
* Allocates basic PCI resources for this USB device controller, and then
* invokes the udc_probe() method to start the UDC associated with it
*/
static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
void __iomem *regs = NULL;
int retval = 0;
if (id == NULL)
return -EINVAL;
retval = pci_enable_device(pdev);
if (retval)
goto done;
if (!pdev->irq) {
dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
retval = -ENODEV;
goto disable_device;
}
retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
if (retval)
goto disable_device;
/* BAR 0 holds all the registers */
regs = pci_iomap(pdev, 0, 0);
if (!regs) {
dev_err(&pdev->dev, "Error mapping memory!");
retval = -EFAULT;
goto release_regions;
}
pci_set_drvdata(pdev, (__force void *)regs);
pci_set_master(pdev);
pci_try_set_mwi(pdev);
retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs);
if (retval)
goto iounmap;
/* our device does not have MSI capability */
retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
UDC_DRIVER_NAME, pdev);
if (retval)
goto gadget_remove;
return 0;
gadget_remove:
udc_remove();
iounmap:
pci_iounmap(pdev, regs);
release_regions:
pci_release_regions(pdev);
disable_device:
pci_disable_device(pdev);
done:
return retval;
}
/**
* ci13xxx_pci_remove: PCI remove
* @pdev: USB Device Controller being removed
*
* Reverses the effect of ci13xxx_pci_probe(),
* first invoking the udc_remove() and then releases
* all PCI resources allocated for this USB device controller
*/
static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
{
free_irq(pdev->irq, pdev);
udc_remove();
pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
pci_release_regions(pdev);
pci_disable_device(pdev);
}
/**
* PCI device table
* PCI device structure
*
* Check "pci.h" for details
*/
static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
{ PCI_DEVICE(0x153F, 0x1004) },
{ PCI_DEVICE(0x153F, 0x1006) },
{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
static struct pci_driver ci13xxx_pci_driver = {
.name = UDC_DRIVER_NAME,
.id_table = ci13xxx_pci_id_table,
.probe = ci13xxx_pci_probe,
.remove = __devexit_p(ci13xxx_pci_remove),
};
/**
* ci13xxx_pci_init: module init
*
* Driver load
*/
static int __init ci13xxx_pci_init(void)
{
return pci_register_driver(&ci13xxx_pci_driver);
}
module_init(ci13xxx_pci_init);
/**
* ci13xxx_pci_exit: module exit
*
* Driver unload
*/
static void __exit ci13xxx_pci_exit(void)
{
pci_unregister_driver(&ci13xxx_pci_driver);
}
module_exit(ci13xxx_pci_exit);
MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
MODULE_LICENSE("GPL");
MODULE_VERSION("June 2008");

View File

@ -22,7 +22,6 @@
* - ENDPT: endpoint operations (Gadget API)
* - GADGET: gadget operations (Gadget API)
* - BUS: bus glue code, bus abstraction layer
* - PCI: PCI core interface and PCI resources (interrupts, memory...)
*
* Compile Options
* - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
@ -60,11 +59,11 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include "ci13xxx_udc.h"
@ -75,9 +74,6 @@
/* ctrl register bank access */
static DEFINE_SPINLOCK(udc_lock);
/* driver name */
#define UDC_DRIVER_NAME "ci13xxx_udc"
/* control endpoint description */
static const struct usb_endpoint_descriptor
ctrl_endpt_desc = {
@ -132,6 +128,9 @@ static struct {
size_t size; /* bank size */
} hw_bank;
/* MSM specific */
#define ABS_AHBBURST (0x0090UL)
#define ABS_AHBMODE (0x0098UL)
/* UDC register map */
#define ABS_CAPLENGTH (0x100UL)
#define ABS_HCCPARAMS (0x108UL)
@ -248,13 +247,7 @@ static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
return (reg & mask) >> ffs_nr(mask);
}
/**
* hw_device_reset: resets chip (execute without interruption)
* @base: register base address
*
* This function returns an error code
*/
static int hw_device_reset(void __iomem *base)
static int hw_device_init(void __iomem *base)
{
u32 reg;
@ -271,25 +264,6 @@ static int hw_device_reset(void __iomem *base)
hw_bank.size += CAP_LAST;
hw_bank.size /= sizeof(u32);
/* should flush & stop before reset */
hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
while (hw_cread(CAP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
/* USBMODE should be configured step by step */
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */
if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
pr_err("cannot enter in device mode");
pr_err("lpm = %i", hw_bank.lpm);
return -ENODEV;
}
reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
if (reg == 0 || reg > ENDPT_MAX)
return -ENODEV;
@ -304,6 +278,43 @@ static int hw_device_reset(void __iomem *base)
return 0;
}
/**
* hw_device_reset: resets chip (execute without interruption)
* @base: register base address
*
* This function returns an error code
*/
static int hw_device_reset(struct ci13xxx *udc)
{
/* should flush & stop before reset */
hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
while (hw_cread(CAP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
if (udc->udc_driver->notify_event)
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_RESET_EVENT);
if (udc->udc_driver->flags && CI13XXX_DISABLE_STREAMING)
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
/* USBMODE should be configured step by step */
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */
if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
pr_err("cannot enter in device mode");
pr_err("lpm = %i", hw_bank.lpm);
return -ENODEV;
}
return 0;
}
/**
* hw_device_state: enables/disables interrupts & starts/stops device (execute
@ -1557,8 +1568,6 @@ __acquires(mEp->lock)
* Caller must hold lock
*/
static int _gadget_stop_activity(struct usb_gadget *gadget)
__releases(udc->lock)
__acquires(udc->lock)
{
struct usb_ep *ep;
struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
@ -1570,8 +1579,6 @@ __acquires(udc->lock)
if (gadget == NULL)
return -EINVAL;
spin_unlock(udc->lock);
/* flush all endpoints */
gadget_for_each_ep(ep, gadget) {
usb_ep_fifo_flush(ep);
@ -1591,8 +1598,6 @@ __acquires(udc->lock)
mEp->status = NULL;
}
spin_lock(udc->lock);
return 0;
}
@ -1621,6 +1626,7 @@ __acquires(udc->lock)
dbg_event(0xFF, "BUS RST", 0);
spin_unlock(udc->lock);
retval = _gadget_stop_activity(&udc->gadget);
if (retval)
goto done;
@ -1629,10 +1635,9 @@ __acquires(udc->lock)
if (retval)
goto done;
spin_unlock(udc->lock);
retval = usb_ep_enable(&mEp->ep, &ctrl_endpt_desc);
if (!retval) {
mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_KERNEL);
mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_ATOMIC);
if (mEp->status == NULL) {
usb_ep_disable(&mEp->ep);
retval = -ENOMEM;
@ -2061,7 +2066,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
struct ci13xxx_req *mReq = NULL;
unsigned long flags;
trace("%p, %i", ep, gfp_flags);
@ -2070,8 +2074,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
return NULL;
}
spin_lock_irqsave(mEp->lock, flags);
mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
if (mReq != NULL) {
INIT_LIST_HEAD(&mReq->queue);
@ -2086,8 +2088,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
spin_unlock_irqrestore(mEp->lock, flags);
return (mReq == NULL) ? NULL : &mReq->req;
}
@ -2332,12 +2332,47 @@ static const struct usb_ep_ops usb_ep_ops = {
/******************************************************************************
* GADGET block
*****************************************************************************/
static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
{
struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
unsigned long flags;
int gadget_ready = 0;
if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
return -EOPNOTSUPP;
spin_lock_irqsave(udc->lock, flags);
udc->vbus_active = is_active;
if (udc->driver)
gadget_ready = 1;
spin_unlock_irqrestore(udc->lock, flags);
if (gadget_ready) {
if (is_active) {
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(udc);
hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
} else {
hw_device_state(0);
if (udc->udc_driver->notify_event)
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_STOPPED_EVENT);
_gadget_stop_activity(&udc->gadget);
pm_runtime_put_sync(&_gadget->dev);
}
}
return 0;
}
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
* Check "usb_gadget.h" for details
*/
static const struct usb_gadget_ops usb_gadget_ops;
static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci13xxx_vbus_session,
};
/**
* usb_gadget_probe_driver: register a gadget driver
@ -2390,7 +2425,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
info("hw_ep_max = %d", hw_ep_max);
udc->driver = driver;
udc->gadget.ops = NULL;
udc->gadget.dev.driver = NULL;
retval = 0;
@ -2410,9 +2444,11 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
/* this allocation cannot be random */
for (k = RX; k <= TX; k++) {
INIT_LIST_HEAD(&mEp->qh[k].queue);
spin_unlock_irqrestore(udc->lock, flags);
mEp->qh[k].ptr = dma_pool_alloc(udc->qh_pool,
GFP_KERNEL,
&mEp->qh[k].dma);
spin_lock_irqsave(udc->lock, flags);
if (mEp->qh[k].ptr == NULL)
retval = -ENOMEM;
else
@ -2429,7 +2465,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
/* bind gadget */
driver->driver.bus = NULL;
udc->gadget.ops = &usb_gadget_ops;
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(udc->lock, flags);
@ -2437,12 +2472,24 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
spin_lock_irqsave(udc->lock, flags);
if (retval) {
udc->gadget.ops = NULL;
udc->gadget.dev.driver = NULL;
goto done;
}
pm_runtime_get_sync(&udc->gadget.dev);
if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
if (udc->vbus_active) {
if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
hw_device_reset(udc);
} else {
pm_runtime_put_sync(&udc->gadget.dev);
goto done;
}
}
retval = hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
if (retval)
pm_runtime_put_sync(&udc->gadget.dev);
done:
spin_unlock_irqrestore(udc->lock, flags);
@ -2475,19 +2522,22 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
spin_lock_irqsave(udc->lock, flags);
hw_device_state(0);
if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
udc->vbus_active) {
hw_device_state(0);
if (udc->udc_driver->notify_event)
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_STOPPED_EVENT);
_gadget_stop_activity(&udc->gadget);
pm_runtime_put(&udc->gadget.dev);
}
/* unbind gadget */
if (udc->gadget.ops != NULL) {
_gadget_stop_activity(&udc->gadget);
spin_unlock_irqrestore(udc->lock, flags);
driver->unbind(&udc->gadget); /* MAY SLEEP */
spin_lock_irqsave(udc->lock, flags);
spin_unlock_irqrestore(udc->lock, flags);
driver->unbind(&udc->gadget); /* MAY SLEEP */
spin_lock_irqsave(udc->lock, flags);
udc->gadget.ops = NULL;
udc->gadget.dev.driver = NULL;
}
udc->gadget.dev.driver = NULL;
/* free resources */
for (i = 0; i < hw_ep_max; i++) {
@ -2544,6 +2594,14 @@ static irqreturn_t udc_irq(void)
}
spin_lock(udc->lock);
if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
USBMODE_CM_DEVICE) {
spin_unlock(udc->lock);
return IRQ_NONE;
}
}
intr = hw_test_and_clear_intr_active();
if (intr) {
isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
@ -2602,14 +2660,16 @@ static void udc_release(struct device *dev)
* No interrupts active, the IRQ has not been requested yet
* Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
*/
static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
void __iomem *regs)
{
struct ci13xxx *udc;
int retval = 0;
trace("%p, %p, %p", dev, regs, name);
if (dev == NULL || regs == NULL || name == NULL)
if (dev == NULL || regs == NULL || driver == NULL ||
driver->name == NULL)
return -EINVAL;
udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
@ -2617,42 +2677,77 @@ static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
return -ENOMEM;
udc->lock = &udc_lock;
udc->regs = regs;
udc->udc_driver = driver;
retval = hw_device_reset(regs);
if (retval)
goto done;
udc->gadget.ops = NULL;
udc->gadget.ops = &usb_gadget_ops;
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.is_dualspeed = 1;
udc->gadget.is_otg = 0;
udc->gadget.name = name;
udc->gadget.name = driver->name;
INIT_LIST_HEAD(&udc->gadget.ep_list);
udc->gadget.ep0 = NULL;
dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.dev.dma_mask = dev->dma_mask;
udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
udc->gadget.dev.parent = dev;
udc->gadget.dev.release = udc_release;
retval = hw_device_init(regs);
if (retval < 0)
goto free_udc;
udc->transceiver = otg_get_transceiver();
if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
if (udc->transceiver == NULL) {
retval = -ENODEV;
goto free_udc;
}
}
if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
retval = hw_device_reset(udc);
if (retval)
goto put_transceiver;
}
retval = device_register(&udc->gadget.dev);
if (retval)
goto done;
if (retval) {
put_device(&udc->gadget.dev);
goto put_transceiver;
}
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
retval = dbg_create_files(&udc->gadget.dev);
#endif
if (retval) {
device_unregister(&udc->gadget.dev);
goto done;
if (retval)
goto unreg_device;
if (udc->transceiver) {
retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
if (retval)
goto remove_dbg;
}
pm_runtime_no_callbacks(&udc->gadget.dev);
pm_runtime_enable(&udc->gadget.dev);
_udc = udc;
return retval;
done:
err("error = %i", retval);
remove_dbg:
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
dbg_remove_files(&udc->gadget.dev);
#endif
unreg_device:
device_unregister(&udc->gadget.dev);
put_transceiver:
if (udc->transceiver)
otg_put_transceiver(udc->transceiver);
free_udc:
kfree(udc);
_udc = NULL;
return retval;
@ -2672,6 +2767,10 @@ static void udc_remove(void)
return;
}
if (udc->transceiver) {
otg_set_peripheral(udc->transceiver, &udc->gadget);
otg_put_transceiver(udc->transceiver);
}
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
dbg_remove_files(&udc->gadget.dev);
#endif
@ -2680,156 +2779,3 @@ static void udc_remove(void)
kfree(udc);
_udc = NULL;
}
/******************************************************************************
* PCI block
*****************************************************************************/
/**
* ci13xxx_pci_irq: interrut handler
* @irq: irq number
* @pdev: USB Device Controller interrupt source
*
* This function returns IRQ_HANDLED if the IRQ has been handled
* This is an ISR don't trace, use attribute interface instead
*/
static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
{
if (irq == 0) {
dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
return IRQ_HANDLED;
}
return udc_irq();
}
/**
* ci13xxx_pci_probe: PCI probe
* @pdev: USB device controller being probed
* @id: PCI hotplug ID connecting controller to UDC framework
*
* This function returns an error code
* Allocates basic PCI resources for this USB device controller, and then
* invokes the udc_probe() method to start the UDC associated with it
*/
static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
void __iomem *regs = NULL;
int retval = 0;
if (id == NULL)
return -EINVAL;
retval = pci_enable_device(pdev);
if (retval)
goto done;
if (!pdev->irq) {
dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
retval = -ENODEV;
goto disable_device;
}
retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
if (retval)
goto disable_device;
/* BAR 0 holds all the registers */
regs = pci_iomap(pdev, 0, 0);
if (!regs) {
dev_err(&pdev->dev, "Error mapping memory!");
retval = -EFAULT;
goto release_regions;
}
pci_set_drvdata(pdev, (__force void *)regs);
pci_set_master(pdev);
pci_try_set_mwi(pdev);
retval = udc_probe(&pdev->dev, regs, UDC_DRIVER_NAME);
if (retval)
goto iounmap;
/* our device does not have MSI capability */
retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
UDC_DRIVER_NAME, pdev);
if (retval)
goto gadget_remove;
return 0;
gadget_remove:
udc_remove();
iounmap:
pci_iounmap(pdev, regs);
release_regions:
pci_release_regions(pdev);
disable_device:
pci_disable_device(pdev);
done:
return retval;
}
/**
* ci13xxx_pci_remove: PCI remove
* @pdev: USB Device Controller being removed
*
* Reverses the effect of ci13xxx_pci_probe(),
* first invoking the udc_remove() and then releases
* all PCI resources allocated for this USB device controller
*/
static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
{
free_irq(pdev->irq, pdev);
udc_remove();
pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
pci_release_regions(pdev);
pci_disable_device(pdev);
}
/**
* PCI device table
* PCI device structure
*
* Check "pci.h" for details
*/
static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
{ PCI_DEVICE(0x153F, 0x1004) },
{ PCI_DEVICE(0x153F, 0x1006) },
{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
static struct pci_driver ci13xxx_pci_driver = {
.name = UDC_DRIVER_NAME,
.id_table = ci13xxx_pci_id_table,
.probe = ci13xxx_pci_probe,
.remove = __devexit_p(ci13xxx_pci_remove),
};
/**
* ci13xxx_pci_init: module init
*
* Driver load
*/
static int __init ci13xxx_pci_init(void)
{
return pci_register_driver(&ci13xxx_pci_driver);
}
module_init(ci13xxx_pci_init);
/**
* ci13xxx_pci_exit: module exit
*
* Driver unload
*/
static void __exit ci13xxx_pci_exit(void)
{
pci_unregister_driver(&ci13xxx_pci_driver);
}
module_exit(ci13xxx_pci_exit);
MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
MODULE_LICENSE("GPL");
MODULE_VERSION("June 2008");

View File

@ -97,9 +97,24 @@ struct ci13xxx_ep {
struct dma_pool *td_pool;
};
struct ci13xxx;
struct ci13xxx_udc_driver {
const char *name;
unsigned long flags;
#define CI13XXX_REGS_SHARED BIT(0)
#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
#define CI13XXX_PULLUP_ON_VBUS BIT(2)
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_STOPPED_EVENT 1
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
/* CI13XXX UDC descriptor & global resources */
struct ci13xxx {
spinlock_t *lock; /* ctrl register bank access */
void __iomem *regs; /* registers address space */
struct dma_pool *qh_pool; /* DMA pool for queue heads */
struct dma_pool *td_pool; /* DMA pool for transfer descs */
@ -108,6 +123,9 @@ struct ci13xxx {
struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
struct usb_gadget_driver *driver; /* 3rd party gadget driver */
struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
int vbus_active; /* is VBUS active */
struct otg_transceiver *transceiver; /* Transceiver struct */
};
/******************************************************************************
@ -157,6 +175,7 @@ struct ci13xxx {
#define USBMODE_CM_DEVICE (0x02UL << 0)
#define USBMODE_CM_HOST (0x03UL << 0)
#define USBMODE_SLOM BIT(3)
#define USBMODE_SDIS BIT(4)
/* ENDPTCTRL */
#define ENDPTCTRL_RXS BIT(0)

View File

@ -1126,7 +1126,7 @@ static int composite_bind(struct usb_gadget *gadget)
cdev->desc = *composite->dev;
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
/* stirng overrides */
/* string overrides */
if (iManufacturer || !cdev->desc.iManufacturer) {
if (!iManufacturer && !composite->iManufacturer &&
!*composite_manufacturer)
@ -1188,6 +1188,8 @@ composite_suspend(struct usb_gadget *gadget)
composite->suspend(cdev);
cdev->suspended = 1;
usb_gadget_vbus_draw(gadget, 2);
}
static void
@ -1195,6 +1197,7 @@ composite_resume(struct usb_gadget *gadget)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_function *f;
u8 maxpower;
/* REVISIT: should we have config level
* suspend/resume callbacks?
@ -1207,6 +1210,11 @@ composite_resume(struct usb_gadget *gadget)
if (f->resume)
f->resume(f);
}
maxpower = cdev->config->bMaxPower;
usb_gadget_vbus_draw(gadget, maxpower ?
(2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
}
cdev->suspended = 0;

View File

@ -1197,6 +1197,139 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
#define Ep_InRequest (Ep_Request | USB_DIR_IN)
/**
* handle_control_request() - handles all control transfers
* @dum: pointer to dummy (the_controller)
* @urb: the urb request to handle
* @setup: pointer to the setup data for a USB device control
* request
* @status: pointer to request handling status
*
* Return 0 - if the request was handled
* 1 - if the request wasn't handles
* error code on error
*/
static int handle_control_request(struct dummy *dum, struct urb *urb,
struct usb_ctrlrequest *setup,
int *status)
{
struct dummy_ep *ep2;
int ret_val = 1;
unsigned w_index;
unsigned w_value;
w_index = le16_to_cpu(setup->wIndex);
w_value = le16_to_cpu(setup->wValue);
switch (setup->bRequest) {
case USB_REQ_SET_ADDRESS:
if (setup->bRequestType != Dev_Request)
break;
dum->address = w_value;
*status = 0;
dev_dbg(udc_dev(dum), "set_address = %d\n",
w_value);
ret_val = 0;
break;
case USB_REQ_SET_FEATURE:
if (setup->bRequestType == Dev_Request) {
ret_val = 0;
switch (w_value) {
case USB_DEVICE_REMOTE_WAKEUP:
break;
case USB_DEVICE_B_HNP_ENABLE:
dum->gadget.b_hnp_enable = 1;
break;
case USB_DEVICE_A_HNP_SUPPORT:
dum->gadget.a_hnp_support = 1;
break;
case USB_DEVICE_A_ALT_HNP_SUPPORT:
dum->gadget.a_alt_hnp_support = 1;
break;
default:
ret_val = -EOPNOTSUPP;
}
if (ret_val == 0) {
dum->devstatus |= (1 << w_value);
*status = 0;
}
} else if (setup->bRequestType == Ep_Request) {
/* endpoint halt */
ep2 = find_endpoint(dum, w_index);
if (!ep2 || ep2->ep.name == ep0name) {
ret_val = -EOPNOTSUPP;
break;
}
ep2->halted = 1;
ret_val = 0;
*status = 0;
}
break;
case USB_REQ_CLEAR_FEATURE:
if (setup->bRequestType == Dev_Request) {
ret_val = 0;
switch (w_value) {
case USB_DEVICE_REMOTE_WAKEUP:
w_value = USB_DEVICE_REMOTE_WAKEUP;
break;
default:
ret_val = -EOPNOTSUPP;
break;
}
if (ret_val == 0) {
dum->devstatus &= ~(1 << w_value);
*status = 0;
}
} else if (setup->bRequestType == Ep_Request) {
/* endpoint halt */
ep2 = find_endpoint(dum, w_index);
if (!ep2) {
ret_val = -EOPNOTSUPP;
break;
}
if (!ep2->wedged)
ep2->halted = 0;
ret_val = 0;
*status = 0;
}
break;
case USB_REQ_GET_STATUS:
if (setup->bRequestType == Dev_InRequest
|| setup->bRequestType == Intf_InRequest
|| setup->bRequestType == Ep_InRequest) {
char *buf;
/*
* device: remote wakeup, selfpowered
* interface: nothing
* endpoint: halt
*/
buf = (char *)urb->transfer_buffer;
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType == Ep_InRequest) {
ep2 = find_endpoint(dum, w_index);
if (!ep2) {
ret_val = -EOPNOTSUPP;
break;
}
buf[0] = ep2->halted;
} else if (setup->bRequestType ==
Dev_InRequest) {
buf[0] = (u8)dum->devstatus;
} else
buf[0] = 0;
}
if (urb->transfer_buffer_length > 1)
buf[1] = 0;
urb->actual_length = min_t(u32, 2,
urb->transfer_buffer_length);
ret_val = 0;
*status = 0;
}
break;
}
return ret_val;
}
/* drive both sides of the transfers; looks like irq handlers to
* both drivers except the callbacks aren't in_irq().
*/
@ -1299,14 +1432,8 @@ restart:
if (ep == &dum->ep [0] && ep->setup_stage) {
struct usb_ctrlrequest setup;
int value = 1;
struct dummy_ep *ep2;
unsigned w_index;
unsigned w_value;
setup = *(struct usb_ctrlrequest*) urb->setup_packet;
w_index = le16_to_cpu(setup.wIndex);
w_value = le16_to_cpu(setup.wValue);
/* paranoia, in case of stale queued data */
list_for_each_entry (req, &ep->queue, queue) {
list_del_init (&req->queue);
@ -1328,117 +1455,9 @@ restart:
ep->last_io = jiffies;
ep->setup_stage = 0;
ep->halted = 0;
switch (setup.bRequest) {
case USB_REQ_SET_ADDRESS:
if (setup.bRequestType != Dev_Request)
break;
dum->address = w_value;
status = 0;
dev_dbg (udc_dev(dum), "set_address = %d\n",
w_value);
value = 0;
break;
case USB_REQ_SET_FEATURE:
if (setup.bRequestType == Dev_Request) {
value = 0;
switch (w_value) {
case USB_DEVICE_REMOTE_WAKEUP:
break;
case USB_DEVICE_B_HNP_ENABLE:
dum->gadget.b_hnp_enable = 1;
break;
case USB_DEVICE_A_HNP_SUPPORT:
dum->gadget.a_hnp_support = 1;
break;
case USB_DEVICE_A_ALT_HNP_SUPPORT:
dum->gadget.a_alt_hnp_support
= 1;
break;
default:
value = -EOPNOTSUPP;
}
if (value == 0) {
dum->devstatus |=
(1 << w_value);
status = 0;
}
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
ep2 = find_endpoint (dum, w_index);
if (!ep2 || ep2->ep.name == ep0name) {
value = -EOPNOTSUPP;
break;
}
ep2->halted = 1;
value = 0;
status = 0;
}
break;
case USB_REQ_CLEAR_FEATURE:
if (setup.bRequestType == Dev_Request) {
switch (w_value) {
case USB_DEVICE_REMOTE_WAKEUP:
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
value = 0;
status = 0;
break;
default:
value = -EOPNOTSUPP;
break;
}
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
ep2 = find_endpoint (dum, w_index);
if (!ep2) {
value = -EOPNOTSUPP;
break;
}
if (!ep2->wedged)
ep2->halted = 0;
value = 0;
status = 0;
}
break;
case USB_REQ_GET_STATUS:
if (setup.bRequestType == Dev_InRequest
|| setup.bRequestType
== Intf_InRequest
|| setup.bRequestType
== Ep_InRequest
) {
char *buf;
// device: remote wakeup, selfpowered
// interface: nothing
// endpoint: halt
buf = (char *)urb->transfer_buffer;
if (urb->transfer_buffer_length > 0) {
if (setup.bRequestType ==
Ep_InRequest) {
ep2 = find_endpoint (dum, w_index);
if (!ep2) {
value = -EOPNOTSUPP;
break;
}
buf [0] = ep2->halted;
} else if (setup.bRequestType ==
Dev_InRequest) {
buf [0] = (u8)
dum->devstatus;
} else
buf [0] = 0;
}
if (urb->transfer_buffer_length > 1)
buf [1] = 0;
urb->actual_length = min_t(u32, 2,
urb->transfer_buffer_length);
value = 0;
status = 0;
}
break;
}
value = handle_control_request(dum, urb, &setup,
&status);
/* gadget driver handles all other requests. block
* until setup() returns; no reentrancy issues etc.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1407
drivers/usb/gadget/f_ncm.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3392,25 +3392,28 @@ static int __init fsg_bind(struct usb_gadget *gadget)
dev_set_name(&curlun->dev,"%s-lun%d",
dev_name(&gadget->dev), i);
if ((rc = device_register(&curlun->dev)) != 0) {
kref_get(&fsg->ref);
rc = device_register(&curlun->dev);
if (rc) {
INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
goto out;
}
if ((rc = device_create_file(&curlun->dev,
&dev_attr_ro)) != 0 ||
(rc = device_create_file(&curlun->dev,
&dev_attr_nofua)) != 0 ||
(rc = device_create_file(&curlun->dev,
&dev_attr_file)) != 0) {
device_unregister(&curlun->dev);
put_device(&curlun->dev);
goto out;
}
curlun->registered = 1;
kref_get(&fsg->ref);
rc = device_create_file(&curlun->dev, &dev_attr_ro);
if (rc)
goto out;
rc = device_create_file(&curlun->dev, &dev_attr_nofua);
if (rc)
goto out;
rc = device_create_file(&curlun->dev, &dev_attr_file);
if (rc)
goto out;
if (mod_data.file[i] && *mod_data.file[i]) {
if ((rc = fsg_lun_open(curlun,
mod_data.file[i])) != 0)
rc = fsg_lun_open(curlun, mod_data.file[i]);
if (rc)
goto out;
} else if (!mod_data.removable) {
ERROR(fsg, "no file given for LUN%d\n", i);

View File

@ -1,7 +1,29 @@
/*
* g_ffs.c -- user mode file system API for USB composite function controllers
*
* Copyright (C) 2010 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.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; 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.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) "g_ffs: " fmt
#include <linux/module.h>
#include <linux/utsname.h>
/*
* kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
@ -43,7 +65,6 @@ static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
#include "f_fs.c"
#define DRIVER_NAME "g_ffs"
#define DRIVER_DESC "USB Function Filesystem"
#define DRIVER_VERSION "24 Aug 2004"
@ -73,8 +94,6 @@ MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
static const struct usb_descriptor_header *gfs_otg_desc[] = {
(const struct usb_descriptor_header *)
&(const struct usb_otg_descriptor) {
@ -91,8 +110,7 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = {
NULL
};
/* string IDs are assigned dynamically */
/* String IDs are assigned dynamically */
static struct usb_string gfs_strings[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
{ .s = "FunctionFS + RNDIS" },
@ -114,8 +132,6 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
NULL,
};
struct gfs_configuration {
struct usb_configuration c;
int (*eth)(struct usb_configuration *c, u8 *ethaddr);
@ -138,7 +154,6 @@ struct gfs_configuration {
#endif
};
static int gfs_bind(struct usb_composite_dev *cdev);
static int gfs_unbind(struct usb_composite_dev *cdev);
static int gfs_do_config(struct usb_configuration *c);
@ -151,11 +166,9 @@ static struct usb_composite_driver gfs_driver = {
.iProduct = DRIVER_DESC,
};
static struct ffs_data *gfs_ffs_data;
static unsigned long gfs_registered;
static int gfs_init(void)
{
ENTER();
@ -175,7 +188,6 @@ static void gfs_exit(void)
}
module_exit(gfs_exit);
static int functionfs_ready_callback(struct ffs_data *ffs)
{
int ret;
@ -200,14 +212,11 @@ static void functionfs_closed_callback(struct ffs_data *ffs)
usb_composite_unregister(&gfs_driver);
}
static int functionfs_check_dev_callback(const char *dev_name)
{
return 0;
}
static int gfs_bind(struct usb_composite_dev *cdev)
{
int ret, i;
@ -274,7 +283,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
return 0;
}
static int gfs_do_config(struct usb_configuration *c)
{
struct gfs_configuration *gc =
@ -315,7 +323,6 @@ static int gfs_do_config(struct usb_configuration *c)
return 0;
}
#ifdef CONFIG_USB_FUNCTIONFS_ETH
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])

View File

@ -96,7 +96,7 @@
/* Mentor high speed "dual role" controller, in peripheral role */
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name)
#define gadget_is_musbhdrc(g) !strcmp("musb-hdrc", (g)->name)
#else
#define gadget_is_musbhdrc(g) 0
#endif
@ -120,10 +120,10 @@
#define gadget_is_fsl_qe(g) 0
#endif
#ifdef CONFIG_USB_GADGET_CI13XXX
#define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name))
#ifdef CONFIG_USB_GADGET_CI13XXX_PCI
#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name))
#else
#define gadget_is_ci13xxx(g) 0
#define gadget_is_ci13xxx_pci(g) 0
#endif
// CONFIG_USB_GADGET_SX2
@ -142,6 +142,17 @@
#define gadget_is_s3c_hsotg(g) 0
#endif
#ifdef CONFIG_USB_GADGET_EG20T
#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
#else
#define gadget_is_pch(g) 0
#endif
#ifdef CONFIG_USB_GADGET_CI13XXX_MSM
#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name))
#else
#define gadget_is_ci13xxx_msm(g) 0
#endif
/**
* usb_gadget_controller_number - support bcdDevice id convention
@ -192,7 +203,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x21;
else if (gadget_is_fsl_qe(gadget))
return 0x22;
else if (gadget_is_ci13xxx(gadget))
else if (gadget_is_ci13xxx_pci(gadget))
return 0x23;
else if (gadget_is_langwell(gadget))
return 0x24;
@ -200,6 +211,10 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x25;
else if (gadget_is_s3c_hsotg(gadget))
return 0x26;
else if (gadget_is_pch(gadget))
return 0x27;
else if (gadget_is_ci13xxx_msm(gadget))
return 0x28;
return -ENOENT;
}

View File

@ -1191,13 +1191,17 @@ static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
return IRQ_HANDLED;
}
#ifndef MX1_INT_USBD0
#define MX1_INT_USBD0 MX1_USBD_INT0
#endif
static irqreturn_t imx_udc_bulk_irq(int irq, void *dev)
{
struct imx_udc_struct *imx_usb = dev;
struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - USBD_INT0];
struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0];
int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
dump_ep_intr(__func__, irq - USBD_INT0, intr, imx_usb->dev);
dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev);
if (!imx_usb->driver) {
__raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));

View File

@ -23,9 +23,6 @@
/* Helper macros */
#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */
#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0)
#define irq_to_ep(irq) (((irq) >= USBD_INT0) || ((irq) <= USBD_INT6) \
? ((irq) - USBD_INT0) : (USBD_INT6)) /*should not happen*/
#define ep_to_irq(ep) (EP_NO((ep)) + USBD_INT0)
#define IMX_USB_NB_EP 6
/* Driver structures */

View File

@ -2225,6 +2225,7 @@ static void handle_setup_packet(struct langwell_udc *dev,
u16 wValue = le16_to_cpu(setup->wValue);
u16 wIndex = le16_to_cpu(setup->wIndex);
u16 wLength = le16_to_cpu(setup->wLength);
u32 portsc1;
dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
@ -2313,6 +2314,28 @@ static void handle_setup_packet(struct langwell_udc *dev,
dev->dev_status &= ~(1 << wValue);
}
break;
case USB_DEVICE_TEST_MODE:
dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n");
if ((wIndex & 0xff) ||
(dev->gadget.speed != USB_SPEED_HIGH))
ep0_stall(dev);
switch (wIndex >> 8) {
case TEST_J:
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
case TEST_FORCE_EN:
if (prime_status_phase(dev, EP_DIR_IN))
ep0_stall(dev);
portsc1 = readl(&dev->op_regs->portsc1);
portsc1 |= (wIndex & 0xf00) << 8;
writel(portsc1, &dev->op_regs->portsc1);
goto end;
default:
rc = -EOPNOTSUPP;
}
break;
default:
rc = -EOPNOTSUPP;
break;

View File

@ -102,7 +102,7 @@ static struct fsg_module_parameters mod_data = {
};
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
static unsigned long msg_registered = 0;
static unsigned long msg_registered;
static void msg_cleanup(void);
static int msg_thread_exits(struct fsg_common *common)

294
drivers/usb/gadget/mv_udc.h Normal file
View File

@ -0,0 +1,294 @@
#ifndef __MV_UDC_H
#define __MV_UDC_H
#define VUSBHS_MAX_PORTS 8
#define DQH_ALIGNMENT 2048
#define DTD_ALIGNMENT 64
#define DMA_BOUNDARY 4096
#define EP_DIR_IN 1
#define EP_DIR_OUT 0
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define EP0_MAX_PKT_SIZE 64
/* ep0 transfer state */
#define WAIT_FOR_SETUP 0
#define DATA_STATE_XMIT 1
#define DATA_STATE_NEED_ZLP 2
#define WAIT_FOR_OUT_STATUS 3
#define DATA_STATE_RECV 4
#define CAPLENGTH_MASK (0xff)
#define DCCPARAMS_DEN_MASK (0x1f)
#define HCSPARAMS_PPC (0x10)
/* Frame Index Register Bit Masks */
#define USB_FRINDEX_MASKS 0x3fff
/* Command Register Bit Masks */
#define USBCMD_RUN_STOP (0x00000001)
#define USBCMD_CTRL_RESET (0x00000002)
#define USBCMD_SETUP_TRIPWIRE_SET (0x00002000)
#define USBCMD_SETUP_TRIPWIRE_CLEAR (~USBCMD_SETUP_TRIPWIRE_SET)
#define USBCMD_ATDTW_TRIPWIRE_SET (0x00004000)
#define USBCMD_ATDTW_TRIPWIRE_CLEAR (~USBCMD_ATDTW_TRIPWIRE_SET)
/* bit 15,3,2 are for frame list size */
#define USBCMD_FRAME_SIZE_1024 (0x00000000) /* 000 */
#define USBCMD_FRAME_SIZE_512 (0x00000004) /* 001 */
#define USBCMD_FRAME_SIZE_256 (0x00000008) /* 010 */
#define USBCMD_FRAME_SIZE_128 (0x0000000C) /* 011 */
#define USBCMD_FRAME_SIZE_64 (0x00008000) /* 100 */
#define USBCMD_FRAME_SIZE_32 (0x00008004) /* 101 */
#define USBCMD_FRAME_SIZE_16 (0x00008008) /* 110 */
#define USBCMD_FRAME_SIZE_8 (0x0000800C) /* 111 */
#define EPCTRL_TX_ALL_MASK (0xFFFF0000)
#define EPCTRL_RX_ALL_MASK (0x0000FFFF)
#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000)
#define EPCTRL_TX_EP_STALL (0x00010000)
#define EPCTRL_RX_EP_STALL (0x00000001)
#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040)
#define EPCTRL_RX_ENABLE (0x00000080)
#define EPCTRL_TX_ENABLE (0x00800000)
#define EPCTRL_CONTROL (0x00000000)
#define EPCTRL_ISOCHRONOUS (0x00040000)
#define EPCTRL_BULK (0x00080000)
#define EPCTRL_INT (0x000C0000)
#define EPCTRL_TX_TYPE (0x000C0000)
#define EPCTRL_RX_TYPE (0x0000000C)
#define EPCTRL_DATA_TOGGLE_INHIBIT (0x00000020)
#define EPCTRL_TX_EP_TYPE_SHIFT (18)
#define EPCTRL_RX_EP_TYPE_SHIFT (2)
#define EPCOMPLETE_MAX_ENDPOINTS (16)
/* endpoint list address bit masks */
#define USB_EP_LIST_ADDRESS_MASK 0xfffff800
#define PORTSCX_W1C_BITS 0x2a
#define PORTSCX_PORT_RESET 0x00000100
#define PORTSCX_PORT_POWER 0x00001000
#define PORTSCX_FORCE_FULL_SPEED_CONNECT 0x01000000
#define PORTSCX_PAR_XCVR_SELECT 0xC0000000
#define PORTSCX_PORT_FORCE_RESUME 0x00000040
#define PORTSCX_PORT_SUSPEND 0x00000080
#define PORTSCX_PORT_SPEED_FULL 0x00000000
#define PORTSCX_PORT_SPEED_LOW 0x04000000
#define PORTSCX_PORT_SPEED_HIGH 0x08000000
#define PORTSCX_PORT_SPEED_MASK 0x0C000000
/* USB MODE Register Bit Masks */
#define USBMODE_CTRL_MODE_IDLE 0x00000000
#define USBMODE_CTRL_MODE_DEVICE 0x00000002
#define USBMODE_CTRL_MODE_HOST 0x00000003
#define USBMODE_CTRL_MODE_RSV 0x00000001
#define USBMODE_SETUP_LOCK_OFF 0x00000008
#define USBMODE_STREAM_DISABLE 0x00000010
/* USB STS Register Bit Masks */
#define USBSTS_INT 0x00000001
#define USBSTS_ERR 0x00000002
#define USBSTS_PORT_CHANGE 0x00000004
#define USBSTS_FRM_LST_ROLL 0x00000008
#define USBSTS_SYS_ERR 0x00000010
#define USBSTS_IAA 0x00000020
#define USBSTS_RESET 0x00000040
#define USBSTS_SOF 0x00000080
#define USBSTS_SUSPEND 0x00000100
#define USBSTS_HC_HALTED 0x00001000
#define USBSTS_RCL 0x00002000
#define USBSTS_PERIODIC_SCHEDULE 0x00004000
#define USBSTS_ASYNC_SCHEDULE 0x00008000
/* Interrupt Enable Register Bit Masks */
#define USBINTR_INT_EN (0x00000001)
#define USBINTR_ERR_INT_EN (0x00000002)
#define USBINTR_PORT_CHANGE_DETECT_EN (0x00000004)
#define USBINTR_ASYNC_ADV_AAE (0x00000020)
#define USBINTR_ASYNC_ADV_AAE_ENABLE (0x00000020)
#define USBINTR_ASYNC_ADV_AAE_DISABLE (0xFFFFFFDF)
#define USBINTR_RESET_EN (0x00000040)
#define USBINTR_SOF_UFRAME_EN (0x00000080)
#define USBINTR_DEVICE_SUSPEND (0x00000100)
#define USB_DEVICE_ADDRESS_MASK (0xfe000000)
#define USB_DEVICE_ADDRESS_BIT_SHIFT (25)
struct mv_cap_regs {
u32 caplength_hciversion;
u32 hcsparams; /* HC structural parameters */
u32 hccparams; /* HC Capability Parameters*/
u32 reserved[5];
u32 dciversion; /* DC version number and reserved 16 bits */
u32 dccparams; /* DC Capability Parameters */
};
struct mv_op_regs {
u32 usbcmd; /* Command register */
u32 usbsts; /* Status register */
u32 usbintr; /* Interrupt enable */
u32 frindex; /* Frame index */
u32 reserved1[1];
u32 deviceaddr; /* Device Address */
u32 eplistaddr; /* Endpoint List Address */
u32 ttctrl; /* HOST TT status and control */
u32 burstsize; /* Programmable Burst Size */
u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */
u32 reserved[4];
u32 epnak; /* Endpoint NAK */
u32 epnaken; /* Endpoint NAK Enable */
u32 configflag; /* Configured Flag register */
u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */
u32 otgsc;
u32 usbmode; /* USB Host/Device mode */
u32 epsetupstat; /* Endpoint Setup Status */
u32 epprime; /* Endpoint Initialize */
u32 epflush; /* Endpoint De-initialize */
u32 epstatus; /* Endpoint Status */
u32 epcomplete; /* Endpoint Interrupt On Complete */
u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */
u32 mcr; /* Mux Control */
u32 isr; /* Interrupt Status */
u32 ier; /* Interrupt Enable */
};
struct mv_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
spinlock_t lock;
struct completion *done;
struct platform_device *dev;
int irq;
struct mv_cap_regs __iomem *cap_regs;
struct mv_op_regs __iomem *op_regs;
unsigned int phy_regs;
unsigned int max_eps;
struct mv_dqh *ep_dqh;
size_t ep_dqh_size;
dma_addr_t ep_dqh_dma;
struct dma_pool *dtd_pool;
struct mv_ep *eps;
struct mv_dtd *dtd_head;
struct mv_dtd *dtd_tail;
unsigned int dtd_entries;
struct mv_req *status_req;
struct usb_ctrlrequest local_setup_buff;
unsigned int resume_state; /* USB state to resume */
unsigned int usb_state; /* USB current state */
unsigned int ep0_state; /* Endpoint zero state */
unsigned int ep0_dir;
unsigned int dev_addr;
int errors;
unsigned softconnect:1,
vbus_active:1,
remote_wakeup:1,
softconnected:1,
force_fs:1;
struct clk *clk;
};
/* endpoint data structure */
struct mv_ep {
struct usb_ep ep;
struct mv_udc *udc;
struct list_head queue;
struct mv_dqh *dqh;
const struct usb_endpoint_descriptor *desc;
u32 direction;
char name[14];
unsigned stopped:1,
wedge:1,
ep_type:2,
ep_num:8;
};
/* request data structure */
struct mv_req {
struct usb_request req;
struct mv_dtd *dtd, *head, *tail;
struct mv_ep *ep;
struct list_head queue;
unsigned dtd_count;
unsigned mapped:1;
};
#define EP_QUEUE_HEAD_MULT_POS 30
#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000
#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16
#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
#define EP_QUEUE_HEAD_IOS 0x00008000
#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001
#define EP_QUEUE_HEAD_IOC 0x00008000
#define EP_QUEUE_HEAD_MULTO 0x00000C00
#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040
#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080
#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF
#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0
#define EP_QUEUE_FRINDEX_MASK 0x000007FF
#define EP_MAX_LENGTH_TRANSFER 0x4000
struct mv_dqh {
/* Bits 16..26 Bit 15 is Interrupt On Setup */
u32 max_packet_length;
u32 curr_dtd_ptr; /* Current dTD Pointer */
u32 next_dtd_ptr; /* Next dTD Pointer */
/* Total bytes (16..30), IOC (15), INT (8), STS (0-7) */
u32 size_ioc_int_sts;
u32 buff_ptr0; /* Buffer pointer Page 0 (12-31) */
u32 buff_ptr1; /* Buffer pointer Page 1 (12-31) */
u32 buff_ptr2; /* Buffer pointer Page 2 (12-31) */
u32 buff_ptr3; /* Buffer pointer Page 3 (12-31) */
u32 buff_ptr4; /* Buffer pointer Page 4 (12-31) */
u32 reserved1;
/* 8 bytes of setup data that follows the Setup PID */
u8 setup_buffer[8];
u32 reserved2[4];
};
#define DTD_NEXT_TERMINATE (0x00000001)
#define DTD_IOC (0x00008000)
#define DTD_STATUS_ACTIVE (0x00000080)
#define DTD_STATUS_HALTED (0x00000040)
#define DTD_STATUS_DATA_BUFF_ERR (0x00000020)
#define DTD_STATUS_TRANSACTION_ERR (0x00000008)
#define DTD_RESERVED_FIELDS (0x00007F00)
#define DTD_ERROR_MASK (0x68)
#define DTD_ADDR_MASK (0xFFFFFFE0)
#define DTD_PACKET_SIZE 0x7FFF0000
#define DTD_LENGTH_BIT_POS (16)
struct mv_dtd {
u32 dtd_next;
u32 size_ioc_sts;
u32 buff_ptr0; /* Buffer pointer Page 0 */
u32 buff_ptr1; /* Buffer pointer Page 1 */
u32 buff_ptr2; /* Buffer pointer Page 2 */
u32 buff_ptr3; /* Buffer pointer Page 3 */
u32 buff_ptr4; /* Buffer pointer Page 4 */
u32 scratch_ptr;
/* 32 bytes */
dma_addr_t td_dma; /* dma address for this td */
struct mv_dtd *next_dtd_virt;
};
extern int mv_udc_phy_init(unsigned int base);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,214 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <mach/cputype.h>
#ifdef CONFIG_ARCH_MMP
#define UTMI_REVISION 0x0
#define UTMI_CTRL 0x4
#define UTMI_PLL 0x8
#define UTMI_TX 0xc
#define UTMI_RX 0x10
#define UTMI_IVREF 0x14
#define UTMI_T0 0x18
#define UTMI_T1 0x1c
#define UTMI_T2 0x20
#define UTMI_T3 0x24
#define UTMI_T4 0x28
#define UTMI_T5 0x2c
#define UTMI_RESERVE 0x30
#define UTMI_USB_INT 0x34
#define UTMI_DBG_CTL 0x38
#define UTMI_OTG_ADDON 0x3c
/* For UTMICTRL Register */
#define UTMI_CTRL_USB_CLK_EN (1 << 31)
/* pxa168 */
#define UTMI_CTRL_SUSPEND_SET1 (1 << 30)
#define UTMI_CTRL_SUSPEND_SET2 (1 << 29)
#define UTMI_CTRL_RXBUF_PDWN (1 << 24)
#define UTMI_CTRL_TXBUF_PDWN (1 << 11)
#define UTMI_CTRL_INPKT_DELAY_SHIFT 30
#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28
#define UTMI_CTRL_PU_REF_SHIFT 20
#define UTMI_CTRL_ARC_PULLDN_SHIFT 12
#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1
#define UTMI_CTRL_PWR_UP_SHIFT 0
/* For UTMI_PLL Register */
#define UTMI_PLL_CLK_BLK_EN_SHIFT 24
#define UTMI_PLL_FBDIV_SHIFT 4
#define UTMI_PLL_REFDIV_SHIFT 0
#define UTMI_PLL_FBDIV_MASK 0x00000FF0
#define UTMI_PLL_REFDIV_MASK 0x0000000F
#define UTMI_PLL_ICP_MASK 0x00007000
#define UTMI_PLL_KVCO_MASK 0x00031000
#define UTMI_PLL_PLLCALI12_SHIFT 29
#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)
#define UTMI_PLL_PLLVDD18_SHIFT 27
#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)
#define UTMI_PLL_PLLVDD12_SHIFT 25
#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)
#define UTMI_PLL_KVCO_SHIFT 15
#define UTMI_PLL_ICP_SHIFT 12
/* For UTMI_TX Register */
#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27
#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)
#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK 26
#define UTMI_TX_REG_EXT_FS_RCAL_EN (0x1 << 26)
#define UTMI_TX_LOW_VDD_EN_SHIFT 11
#define UTMI_TX_IMPCAL_VTH_SHIFT 14
#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14)
#define UTMI_TX_CK60_PHSEL_SHIFT 17
#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)
#define UTMI_TX_TXVDD12_SHIFT 22
#define UTMI_TX_TXVDD12_MASK (0x3 << 22)
#define UTMI_TX_AMP_SHIFT 0
#define UTMI_TX_AMP_MASK (0x7 << 0)
/* For UTMI_RX Register */
#define UTMI_RX_SQ_THRESH_SHIFT 4
#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)
#define UTMI_REG_SQ_LENGTH_SHIFT 15
#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)
#define REG_RCAL_START 0x00001000
#define VCOCAL_START 0x00200000
#define KVCO_EXT 0x00400000
#define PLL_READY 0x00800000
#define CLK_BLK_EN 0x01000000
#endif
static unsigned int u2o_read(unsigned int base, unsigned int offset)
{
return readl(base + offset);
}
static void u2o_set(unsigned int base, unsigned int offset, unsigned int value)
{
unsigned int reg;
reg = readl(base + offset);
reg |= value;
writel(reg, base + offset);
readl(base + offset);
}
static void u2o_clear(unsigned int base, unsigned int offset,
unsigned int value)
{
unsigned int reg;
reg = readl(base + offset);
reg &= ~value;
writel(reg, base + offset);
readl(base + offset);
}
static void u2o_write(unsigned int base, unsigned int offset,
unsigned int value)
{
writel(value, base + offset);
readl(base + offset);
}
#ifdef CONFIG_ARCH_MMP
int mv_udc_phy_init(unsigned int base)
{
unsigned long timeout;
/* Initialize the USB PHY power */
if (cpu_is_pxa910()) {
u2o_set(base, UTMI_CTRL, (1 << UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
| (1 << UTMI_CTRL_PU_REF_SHIFT));
}
u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PLL_PWR_UP_SHIFT);
u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PWR_UP_SHIFT);
/* UTMI_PLL settings */
u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
u2o_set(base, UTMI_PLL, (0xee << UTMI_PLL_FBDIV_SHIFT)
| (0xb << UTMI_PLL_REFDIV_SHIFT)
| (3 << UTMI_PLL_PLLVDD18_SHIFT)
| (3 << UTMI_PLL_PLLVDD12_SHIFT)
| (3 << UTMI_PLL_PLLCALI12_SHIFT)
| (1 << UTMI_PLL_ICP_SHIFT) | (3 << UTMI_PLL_KVCO_SHIFT));
/* UTMI_TX */
u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
| UTMI_TX_TXVDD12_MASK
| UTMI_TX_CK60_PHSEL_MASK | UTMI_TX_IMPCAL_VTH_MASK
| UTMI_TX_REG_EXT_FS_RCAL_MASK | UTMI_TX_AMP_MASK);
u2o_set(base, UTMI_TX, (3 << UTMI_TX_TXVDD12_SHIFT)
| (4 << UTMI_TX_CK60_PHSEL_SHIFT)
| (4 << UTMI_TX_IMPCAL_VTH_SHIFT)
| (8 << UTMI_TX_REG_EXT_FS_RCAL_SHIFT)
| (3 << UTMI_TX_AMP_SHIFT));
/* UTMI_RX */
u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
| UTMI_REG_SQ_LENGTH_MASK);
if (cpu_is_pxa168())
u2o_set(base, UTMI_RX, (7 << UTMI_RX_SQ_THRESH_SHIFT)
| (2 << UTMI_REG_SQ_LENGTH_SHIFT));
else
u2o_set(base, UTMI_RX, (0x7 << UTMI_RX_SQ_THRESH_SHIFT)
| (2 << UTMI_REG_SQ_LENGTH_SHIFT));
/* UTMI_IVREF */
if (cpu_is_pxa168())
/*
* fixing Microsoft Altair board interface with NEC hub issue -
* Set UTMI_IVREF from 0x4a3 to 0x4bf
*/
u2o_write(base, UTMI_IVREF, 0x4bf);
/* calibrate */
timeout = jiffies + 100;
while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
if (time_after(jiffies, timeout))
return -ETIME;
cpu_relax();
}
/* toggle VCOCAL_START bit of UTMI_PLL */
udelay(200);
u2o_set(base, UTMI_PLL, VCOCAL_START);
udelay(40);
u2o_clear(base, UTMI_PLL, VCOCAL_START);
/* toggle REG_RCAL_START bit of UTMI_TX */
udelay(200);
u2o_set(base, UTMI_TX, REG_RCAL_START);
udelay(40);
u2o_clear(base, UTMI_TX, REG_RCAL_START);
udelay(200);
/* make sure phy is ready */
timeout = jiffies + 100;
while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
if (time_after(jiffies, timeout))
return -ETIME;
cpu_relax();
}
if (cpu_is_pxa168()) {
u2o_set(base, UTMI_RESERVE, 1 << 5);
/* Turn on UTMI PHY OTG extension */
u2o_write(base, UTMI_OTG_ADDON, 1);
}
return 0;
}
#else
int mv_udc_phy_init(unsigned int base)
{
return 0;
}
#endif

248
drivers/usb/gadget/ncm.c Normal file
View File

@ -0,0 +1,248 @@
/*
* ncm.c -- NCM gadget driver
*
* Copyright (C) 2010 Nokia Corporation
* Contact: Yauheni Kaliuta <yauheni.kaliuta@nokia.com>
*
* The driver borrows from ether.c which is:
*
* Copyright (C) 2003-2005,2008 David Brownell
* Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
* Copyright (C) 2008 Nokia 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.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define DEBUG */
/* #define VERBOSE_DEBUG */
#include <linux/kernel.h>
#include <linux/utsname.h>
#include "u_ether.h"
#define DRIVER_DESC "NCM Gadget"
/*-------------------------------------------------------------------------*/
/*
* Kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
* separate compilation ... ensuring init/exit sections work to shrink
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
#include "f_ncm.c"
#include "u_ether.c"
/*-------------------------------------------------------------------------*/
/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures.
*/
/* Thanks to NetChip Technologies for donating this product ID.
* It's for devices with only CDC Ethernet configurations.
*/
#define CDC_VENDOR_NUM 0x0525 /* NetChip */
#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
/*-------------------------------------------------------------------------*/
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = cpu_to_le16 (0x0200),
.bDeviceClass = USB_CLASS_COMM,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id defaults change according to what configs
* we support. (As does bNumConfigurations.) These values can
* also be overridden by module parameters.
*/
.idVendor = cpu_to_le16 (CDC_VENDOR_NUM),
.idProduct = cpu_to_le16 (CDC_PRODUCT_NUM),
/* .bcdDevice = f(hardware) */
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
/* NO SERIAL NUMBER */
.bNumConfigurations = 1,
};
static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
/* REVISIT SRP-only hardware is possible, although
* it would not be called "OTG" ...
*/
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
};
static const struct usb_descriptor_header *otg_desc[] = {
(struct usb_descriptor_header *) &otg_descriptor,
NULL,
};
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
#define STRING_PRODUCT_IDX 1
static char manufacturer[50];
static struct usb_string strings_dev[] = {
[STRING_MANUFACTURER_IDX].s = manufacturer,
[STRING_PRODUCT_IDX].s = DRIVER_DESC,
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *dev_strings[] = {
&stringtab_dev,
NULL,
};
static u8 hostaddr[ETH_ALEN];
/*-------------------------------------------------------------------------*/
static int __init ncm_do_config(struct usb_configuration *c)
{
/* FIXME alloc iConfiguration string, set it in c->strings */
if (gadget_is_otg(c->cdev->gadget)) {
c->descriptors = otg_desc;
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
return ncm_bind_config(c, hostaddr);
}
static struct usb_configuration ncm_config_driver = {
/* .label = f(hardware) */
.label = "CDC Ethernet (NCM)",
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
/*-------------------------------------------------------------------------*/
static int __init gncm_bind(struct usb_composite_dev *cdev)
{
int gcnum;
struct usb_gadget *gadget = cdev->gadget;
int status;
/* set up network link layer */
status = gether_setup(cdev->gadget, hostaddr);
if (status < 0)
return status;
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
else {
/* We assume that can_support_ecm() tells the truth;
* but if the controller isn't recognized at all then
* that assumption is a bit more likely to be wrong.
*/
dev_warn(&gadget->dev,
"controller '%s' not recognized; trying %s\n",
gadget->name,
ncm_config_driver.label);
device_desc.bcdDevice =
cpu_to_le16(0x0300 | 0x0099);
}
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
*/
/* device descriptor strings: manufacturer, product */
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
gadget->name);
status = usb_string_id(cdev);
if (status < 0)
goto fail;
strings_dev[STRING_MANUFACTURER_IDX].id = status;
device_desc.iManufacturer = status;
status = usb_string_id(cdev);
if (status < 0)
goto fail;
strings_dev[STRING_PRODUCT_IDX].id = status;
device_desc.iProduct = status;
status = usb_add_config(cdev, &ncm_config_driver,
ncm_do_config);
if (status < 0)
goto fail;
dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
return 0;
fail:
gether_cleanup();
return status;
}
static int __exit gncm_unbind(struct usb_composite_dev *cdev)
{
gether_cleanup();
return 0;
}
static struct usb_composite_driver ncm_driver = {
.name = "g_ncm",
.dev = &device_desc,
.strings = dev_strings,
.unbind = __exit_p(gncm_unbind),
};
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Yauheni Kaliuta");
MODULE_LICENSE("GPL");
static int __init init(void)
{
return usb_composite_probe(&ncm_driver, gncm_bind);
}
module_init(init);
static void __exit cleanup(void)
{
usb_composite_unregister(&ncm_driver);
}
module_exit(cleanup);

2947
drivers/usb/gadget/pch_udc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -255,6 +255,7 @@ static int gaudio_open_snd_dev(struct gaudio *card)
ERROR(card, "No such PCM capture device: %s\n", fn_cap);
snd->substream = NULL;
snd->card = NULL;
snd->filp = NULL;
} else {
pcm_file = snd->filp->private_data;
snd->substream = pcm_file->substream;
@ -273,17 +274,17 @@ static int gaudio_close_snd_dev(struct gaudio *gau)
/* Close control device */
snd = &gau->control;
if (!IS_ERR(snd->filp))
if (snd->filp)
filp_close(snd->filp, current->files);
/* Close PCM playback device and setup substream */
snd = &gau->playback;
if (!IS_ERR(snd->filp))
if (snd->filp)
filp_close(snd->filp, current->files);
/* Close PCM capture device and setup substream */
snd = &gau->capture;
if (!IS_ERR(snd->filp))
if (snd->filp)
filp_close(snd->filp, current->files);
return 0;
@ -304,8 +305,7 @@ int __init gaudio_setup(struct gaudio *card)
ret = gaudio_open_snd_dev(card);
if (ret)
ERROR(card, "we need at least one control device\n");
if (!the_card)
else if (!the_card)
the_card = card;
return ret;

View File

@ -240,6 +240,9 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
size += out->maxpacket - 1;
size -= size % out->maxpacket;
if (dev->port_usb->is_fixed)
size = max(size, dev->port_usb->fixed_out_len);
skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
if (skb == NULL) {
DBG(dev, "no rx skb\n");
@ -578,12 +581,19 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
req->context = skb;
req->complete = tx_complete;
/* NCM requires no zlp if transfer is dwNtbInMaxSize */
if (dev->port_usb->is_fixed &&
length == dev->port_usb->fixed_in_len &&
(length % in->maxpacket) == 0)
req->zero = 0;
else
req->zero = 1;
/* use zlp framing on tx for strict CDC-Ether conformance,
* though any robust network rx path ignores extra padding.
* and some hardware doesn't like to write zlps.
*/
req->zero = 1;
if (!dev->zlp && (length % in->maxpacket) == 0)
if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
length++;
req->length = length;

View File

@ -62,6 +62,10 @@ struct gether {
/* hooks for added framing, as needed for RNDIS and EEM. */
u32 header_len;
/* NCM requires fixed size bundles */
bool is_fixed;
u32 fixed_out_len;
u32 fixed_in_len;
struct sk_buff *(*wrap)(struct gether *port,
struct sk_buff *skb);
int (*unwrap)(struct gether *port,
@ -103,6 +107,7 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
/* each configuration may bind one instance of an ethernet link */
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int eem_bind_config(struct usb_configuration *c);
#ifdef USB_ETH_RNDIS

View File

@ -133,6 +133,25 @@ config USB_EHCI_MXC
---help---
Variation of ARC USB block used in some Freescale chips.
config USB_EHCI_HCD_OMAP
bool "EHCI support for OMAP3 and later chips"
depends on USB_EHCI_HCD && ARCH_OMAP
default y
--- help ---
Enables support for the on-chip EHCI controller on
OMAP3 and later chips.
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
---help---
Enables support for the USB Host controller present on the
Qualcomm chipsets. Root Hub has inbuilt TT.
This driver depends on OTG driver for PHY initialization,
clock management, powering up VBUS, and power management.
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"
depends on USB_EHCI_HCD && PPC_OF

View File

@ -99,6 +99,7 @@ static const struct hc_driver ehci_atmel_hc_driver = {
.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,
@ -110,6 +111,8 @@ static const struct hc_driver ehci_atmel_hc_driver = {
.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 __init ehci_atmel_drv_probe(struct platform_device *pdev)

View File

@ -879,7 +879,7 @@ static int fill_buffer(struct debug_buffer *buf)
int ret = 0;
if (!buf->output_buf)
buf->output_buf = (char *)vmalloc(buf->alloc_size);
buf->output_buf = vmalloc(buf->alloc_size);
if (!buf->output_buf) {
ret = -ENOMEM;

View File

@ -114,6 +114,9 @@ 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"
@ -529,6 +532,11 @@ 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;
}
#ifdef EHCI_STATS
ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
@ -1166,12 +1174,17 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_mxc_driver
#endif
#ifdef CONFIG_CPU_SUBTYPE_SH7786
#include "ehci-sh.c"
#define PLATFORM_DRIVER ehci_hcd_sh_driver
#endif
#ifdef CONFIG_SOC_AU1200
#include "ehci-au1xxx.c"
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
#ifdef CONFIG_ARCH_OMAP3
#ifdef CONFIG_USB_EHCI_HCD_OMAP
#include "ehci-omap.c"
#define PLATFORM_DRIVER ehci_hcd_omap_driver
#endif
@ -1216,6 +1229,21 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_octeon_driver
#endif
#ifdef CONFIG_ARCH_VT8500
#include "ehci-vt8500.c"
#define PLATFORM_DRIVER vt8500_ehci_driver
#endif
#ifdef CONFIG_PLAT_SPEAR
#include "ehci-spear.c"
#define PLATFORM_DRIVER spear_ehci_hcd_driver
#endif
#ifdef CONFIG_USB_EHCI_MSM
#include "ehci-msm.c"
#define PLATFORM_DRIVER ehci_msm_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)

345
drivers/usb/host/ehci-msm.c Normal file
View File

@ -0,0 +1,345 @@
/* ehci-msm.c - HSUSB Host Controller Driver Implementation
*
* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
*
* Partly derived from ehci-fsl.c and ehci-hcd.c
* Copyright (c) 2000-2004 by David Brownell
* Copyright (c) 2005 MontaVista Software
*
* All source code in this file is licensed under the following license except
* where indicated.
*
* 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 published
* by the Free Software Foundation.
*
* 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, you can find it at http://www.fsf.org
*/
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/usb/otg.h>
#include <linux/usb/msm_hsusb_hw.h>
#define MSM_USB_BASE (hcd->regs)
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);
int retval;
ehci->caps = USB_CAPLENGTH;
ehci->regs = USB_CAPLENGTH +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
/* cache the data to minimize the chip reads*/
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
ehci->sbrn = HCD_USB2;
/* data structure init */
retval = ehci_init(hcd);
if (retval)
return retval;
retval = ehci_reset(ehci);
if (retval)
return retval;
/* bursts of unspecified length. */
writel(0, USB_AHBBURST);
/* Use the AHB transactor */
writel(0, USB_AHBMODE);
/* Disable streaming mode and select host mode */
writel(0x13, USB_USBMODE);
ehci_port_power(ehci, 1);
return 0;
}
static struct hc_driver msm_hc_driver = {
.description = hcd_name,
.product_desc = "Qualcomm On-Chip EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_USB2 | HCD_MEMORY,
.reset = ehci_msm_reset,
.start = ehci_msm_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* 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,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
/*
* PM support
*/
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
};
static int ehci_msm_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct resource *res;
int ret;
dev_dbg(&pdev->dev, "ehci_msm proble\n");
hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
return -ENOMEM;
}
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
ret = hcd->irq;
goto put_hcd;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Unable to get memory resource\n");
ret = -ENODEV;
goto put_hcd;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
goto put_hcd;
}
/*
* OTG driver takes care of PHY initialization, clock management,
* powering up VBUS, mapping of registers address space and power
* management.
*/
otg = otg_get_transceiver();
if (!otg) {
dev_err(&pdev->dev, "unable to find transceiver\n");
ret = -ENODEV;
goto unmap;
}
ret = otg_set_host(otg, &hcd->self);
if (ret < 0) {
dev_err(&pdev->dev, "unable to register with transceiver\n");
goto put_transceiver;
}
device_init_wakeup(&pdev->dev, 1);
/*
* OTG device parent of HCD takes care of putting
* hardware into low power mode.
*/
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
put_transceiver:
otg_put_transceiver(otg);
unmap:
iounmap(hcd->regs);
put_hcd:
usb_put_hcd(hcd);
return ret;
}
static int __devexit ehci_msm_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
otg_set_host(otg, NULL);
otg_put_transceiver(otg);
usb_put_hcd(hcd);
return 0;
}
#ifdef CONFIG_PM
static int ehci_msm_pm_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
bool wakeup = device_may_wakeup(dev);
dev_dbg(dev, "ehci-msm PM suspend\n");
/*
* EHCI helper function has also the same check before manipulating
* port wakeup flags. We do check here the same condition before
* calling the same helper function to avoid bringing hardware
* from Low power mode when there is no need for adjusting port
* wakeup flags.
*/
if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
pm_runtime_resume(dev);
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
wakeup);
}
return 0;
}
static int ehci_msm_pm_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
dev_dbg(dev, "ehci-msm PM resume\n");
ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
return 0;
}
#else
#define ehci_msm_pm_suspend NULL
#define ehci_msm_pm_resume NULL
#endif
static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
.suspend = ehci_msm_pm_suspend,
.resume = ehci_msm_pm_resume,
};
static struct platform_driver ehci_msm_driver = {
.probe = ehci_msm_probe,
.remove = __devexit_p(ehci_msm_remove),
.driver = {
.name = "msm_hsusb_host",
.pm = &ehci_msm_dev_pm_ops,
},
};

View File

@ -100,6 +100,7 @@ static const struct hc_driver ehci_mxc_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
@ -115,6 +116,8 @@ static const struct hc_driver ehci_mxc_hc_driver = {
.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_mxc_drv_probe(struct platform_device *pdev)

View File

@ -1,11 +1,12 @@
/*
* ehci-omap.c - driver for USBHOST on OMAP 34xx processor
* ehci-omap.c - driver for USBHOST on OMAP3/4 processors
*
* Bus Glue for OMAP34xx USBHOST 3 port EHCI controller
* Tested on OMAP3430 ES2.0 SDP
* Bus Glue for the EHCI controllers in OMAP3/4
* Tested on several OMAP3 boards, and OMAP4 Pandaboard
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
* Copyright (C) 2007-2010 Texas Instruments, Inc.
* Author: Vikram Pandita <vikram.pandita@ti.com>
* Author: Anand Gadiyar <gadiyar@ti.com>
*
* Copyright (C) 2009 Nokia Corporation
* Contact: Felipe Balbi <felipe.balbi@nokia.com>
@ -26,11 +27,14 @@
* 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 Feb 12, 2010):
* TODO (last updated Nov 21, 2010):
* - add kernel-doc
* - enable AUTOIDLE
* - add suspend/resume
* - move workarounds to board-files
* - factor out code common to OHCI
* - add HSIC and TLL support
* - convert to use hwmod and runtime PM
*/
#include <linux/platform_device.h>
@ -114,6 +118,23 @@
#define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9)
#define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10)
/* OMAP4-specific defines */
#define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2)
#define OMAP4_UHH_SYSCONFIG_NOIDLE (1 << 2)
#define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4)
#define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4)
#define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0)
#define OMAP4_P1_MODE_CLEAR (3 << 16)
#define OMAP4_P1_MODE_TLL (1 << 16)
#define OMAP4_P1_MODE_HSIC (3 << 16)
#define OMAP4_P2_MODE_CLEAR (3 << 18)
#define OMAP4_P2_MODE_TLL (1 << 18)
#define OMAP4_P2_MODE_HSIC (3 << 18)
#define OMAP_REV2_TLL_CHANNEL_COUNT 2
#define OMAP_UHH_DEBUG_CSR (0x44)
/* EHCI Register Set */
@ -127,6 +148,17 @@
#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8
#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0
/* Values of UHH_REVISION - Note: these are not given in the TRM */
#define OMAP_EHCI_REV1 0x00000010 /* OMAP3 */
#define OMAP_EHCI_REV2 0x50700100 /* OMAP4 */
#define is_omap_ehci_rev1(x) (x->omap_ehci_rev == OMAP_EHCI_REV1)
#define is_omap_ehci_rev2(x) (x->omap_ehci_rev == OMAP_EHCI_REV2)
#define is_ehci_phy_mode(x) (x == EHCI_HCD_OMAP_MODE_PHY)
#define is_ehci_tll_mode(x) (x == EHCI_HCD_OMAP_MODE_TLL)
#define is_ehci_hsic_mode(x) (x == EHCI_HCD_OMAP_MODE_HSIC)
/*-------------------------------------------------------------------------*/
static inline void ehci_omap_writel(void __iomem *base, u32 reg, u32 val)
@ -156,10 +188,14 @@ struct ehci_hcd_omap {
struct device *dev;
struct clk *usbhost_ick;
struct clk *usbhost2_120m_fck;
struct clk *usbhost1_48m_fck;
struct clk *usbhost_hs_fck;
struct clk *usbhost_fs_fck;
struct clk *usbtll_fck;
struct clk *usbtll_ick;
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
struct clk *utmi_p1_fck;
struct clk *utmi_p2_fck;
/* FIXME the following two workarounds are
* board specific not silicon-specific so these
@ -176,6 +212,9 @@ struct ehci_hcd_omap {
/* phy reset workaround */
int phy_reset;
/* IP revision */
u32 omap_ehci_rev;
/* desired phy_mode: TLL, PHY */
enum ehci_hcd_omap_mode port_mode[OMAP3_HS_USB_PORTS];
@ -191,13 +230,14 @@ struct ehci_hcd_omap {
/*-------------------------------------------------------------------------*/
static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask)
static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask,
u8 tll_channel_count)
{
unsigned reg;
int i;
/* Program the 3 TLL channels upfront */
for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
for (i = 0; i < tll_channel_count; i++) {
reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
/* Disable AutoIdle, BitStuffing and use SDR Mode */
@ -217,7 +257,7 @@ static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask)
ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg);
/* Enable channels now */
for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
for (i = 0; i < tll_channel_count; i++) {
reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
/* Enable only the reg that is needed */
@ -286,19 +326,19 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
}
clk_enable(omap->usbhost_ick);
omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck");
if (IS_ERR(omap->usbhost2_120m_fck)) {
ret = PTR_ERR(omap->usbhost2_120m_fck);
omap->usbhost_hs_fck = clk_get(omap->dev, "hs_fck");
if (IS_ERR(omap->usbhost_hs_fck)) {
ret = PTR_ERR(omap->usbhost_hs_fck);
goto err_host_120m_fck;
}
clk_enable(omap->usbhost2_120m_fck);
clk_enable(omap->usbhost_hs_fck);
omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck");
if (IS_ERR(omap->usbhost1_48m_fck)) {
ret = PTR_ERR(omap->usbhost1_48m_fck);
omap->usbhost_fs_fck = clk_get(omap->dev, "fs_fck");
if (IS_ERR(omap->usbhost_fs_fck)) {
ret = PTR_ERR(omap->usbhost_fs_fck);
goto err_host_48m_fck;
}
clk_enable(omap->usbhost1_48m_fck);
clk_enable(omap->usbhost_fs_fck);
if (omap->phy_reset) {
/* Refer: ISSUE1 */
@ -333,6 +373,80 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
}
clk_enable(omap->usbtll_ick);
omap->omap_ehci_rev = ehci_omap_readl(omap->uhh_base,
OMAP_UHH_REVISION);
dev_dbg(omap->dev, "OMAP UHH_REVISION 0x%x\n",
omap->omap_ehci_rev);
/*
* Enable per-port clocks as needed (newer controllers only).
* - External ULPI clock for PHY mode
* - Internal clocks for TLL and HSIC modes (TODO)
*/
if (is_omap_ehci_rev2(omap)) {
switch (omap->port_mode[0]) {
case EHCI_HCD_OMAP_MODE_PHY:
omap->xclk60mhsp1_ck = clk_get(omap->dev,
"xclk60mhsp1_ck");
if (IS_ERR(omap->xclk60mhsp1_ck)) {
ret = PTR_ERR(omap->xclk60mhsp1_ck);
dev_err(omap->dev,
"Unable to get Port1 ULPI clock\n");
}
omap->utmi_p1_fck = clk_get(omap->dev,
"utmi_p1_gfclk");
if (IS_ERR(omap->utmi_p1_fck)) {
ret = PTR_ERR(omap->utmi_p1_fck);
dev_err(omap->dev,
"Unable to get utmi_p1_fck\n");
}
ret = clk_set_parent(omap->utmi_p1_fck,
omap->xclk60mhsp1_ck);
if (ret != 0) {
dev_err(omap->dev,
"Unable to set P1 f-clock\n");
}
break;
case EHCI_HCD_OMAP_MODE_TLL:
/* TODO */
default:
break;
}
switch (omap->port_mode[1]) {
case EHCI_HCD_OMAP_MODE_PHY:
omap->xclk60mhsp2_ck = clk_get(omap->dev,
"xclk60mhsp2_ck");
if (IS_ERR(omap->xclk60mhsp2_ck)) {
ret = PTR_ERR(omap->xclk60mhsp2_ck);
dev_err(omap->dev,
"Unable to get Port2 ULPI clock\n");
}
omap->utmi_p2_fck = clk_get(omap->dev,
"utmi_p2_gfclk");
if (IS_ERR(omap->utmi_p2_fck)) {
ret = PTR_ERR(omap->utmi_p2_fck);
dev_err(omap->dev,
"Unable to get utmi_p2_fck\n");
}
ret = clk_set_parent(omap->utmi_p2_fck,
omap->xclk60mhsp2_ck);
if (ret != 0) {
dev_err(omap->dev,
"Unable to set P2 f-clock\n");
}
break;
case EHCI_HCD_OMAP_MODE_TLL:
/* TODO */
default:
break;
}
}
/* perform TLL soft reset, and wait until reset is complete */
ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
OMAP_USBTLL_SYSCONFIG_SOFTRESET);
@ -360,12 +474,20 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
/* Put UHH in NoIdle/NoStandby mode */
reg = ehci_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;
if (is_omap_ehci_rev1(omap)) {
reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
| OMAP_UHH_SYSCONFIG_SIDLEMODE
| OMAP_UHH_SYSCONFIG_CACTIVITY
| OMAP_UHH_SYSCONFIG_MIDLEMODE);
reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
} else if (is_omap_ehci_rev2(omap)) {
reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
}
ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
@ -376,40 +498,56 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
if (is_omap_ehci_rev1(omap)) {
if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
/* Bypass the TLL module for PHY mode operation */
if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
else
reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
} else {
dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
/* Bypass the TLL module for PHY mode operation */
if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
if (is_ehci_phy_mode(omap->port_mode[0]) ||
is_ehci_phy_mode(omap->port_mode[1]) ||
is_ehci_phy_mode(omap->port_mode[2]))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
else
reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
} else {
dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
if (is_ehci_phy_mode(omap->port_mode[0]))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
else if (is_ehci_tll_mode(omap->port_mode[0]))
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
if (is_ehci_phy_mode(omap->port_mode[1]))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
else if (is_ehci_tll_mode(omap->port_mode[1]))
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
if (is_ehci_phy_mode(omap->port_mode[2]))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
else if (is_ehci_tll_mode(omap->port_mode[2]))
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
}
} else if (is_omap_ehci_rev2(omap)) {
/* Clear port mode fields for PHY mode*/
reg &= ~OMAP4_P1_MODE_CLEAR;
reg &= ~OMAP4_P2_MODE_CLEAR;
if (is_ehci_tll_mode(omap->port_mode[0]))
reg |= OMAP4_P1_MODE_TLL;
else if (is_ehci_hsic_mode(omap->port_mode[0]))
reg |= OMAP4_P1_MODE_HSIC;
if (is_ehci_tll_mode(omap->port_mode[1]))
reg |= OMAP4_P2_MODE_TLL;
else if (is_ehci_hsic_mode(omap->port_mode[1]))
reg |= OMAP4_P2_MODE_HSIC;
}
ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
@ -438,7 +576,7 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK;
/* Enable UTMI mode for required TLL channels */
omap_usb_utmi_init(omap, tll_ch_mask);
omap_usb_utmi_init(omap, tll_ch_mask, OMAP_TLL_CHANNEL_COUNT);
}
if (omap->phy_reset) {
@ -464,6 +602,14 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
return 0;
err_sys_status:
clk_disable(omap->utmi_p2_fck);
clk_put(omap->utmi_p2_fck);
clk_disable(omap->xclk60mhsp2_ck);
clk_put(omap->xclk60mhsp2_ck);
clk_disable(omap->utmi_p1_fck);
clk_put(omap->utmi_p1_fck);
clk_disable(omap->xclk60mhsp1_ck);
clk_put(omap->xclk60mhsp1_ck);
clk_disable(omap->usbtll_ick);
clk_put(omap->usbtll_ick);
@ -472,8 +618,8 @@ err_tll_ick:
clk_put(omap->usbtll_fck);
err_tll_fck:
clk_disable(omap->usbhost1_48m_fck);
clk_put(omap->usbhost1_48m_fck);
clk_disable(omap->usbhost_fs_fck);
clk_put(omap->usbhost_fs_fck);
if (omap->phy_reset) {
if (gpio_is_valid(omap->reset_gpio_port[0]))
@ -484,8 +630,8 @@ err_tll_fck:
}
err_host_48m_fck:
clk_disable(omap->usbhost2_120m_fck);
clk_put(omap->usbhost2_120m_fck);
clk_disable(omap->usbhost_hs_fck);
clk_put(omap->usbhost_hs_fck);
err_host_120m_fck:
clk_disable(omap->usbhost_ick);
@ -503,6 +649,8 @@ static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
/* Reset OMAP modules for insmod/rmmod to work */
ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
is_omap_ehci_rev2(omap) ?
OMAP4_UHH_SYSCONFIG_SOFTRESET :
OMAP_UHH_SYSCONFIG_SOFTRESET);
while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
& (1 << 0))) {
@ -550,16 +698,16 @@ static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
omap->usbhost_ick = NULL;
}
if (omap->usbhost1_48m_fck != NULL) {
clk_disable(omap->usbhost1_48m_fck);
clk_put(omap->usbhost1_48m_fck);
omap->usbhost1_48m_fck = NULL;
if (omap->usbhost_fs_fck != NULL) {
clk_disable(omap->usbhost_fs_fck);
clk_put(omap->usbhost_fs_fck);
omap->usbhost_fs_fck = NULL;
}
if (omap->usbhost2_120m_fck != NULL) {
clk_disable(omap->usbhost2_120m_fck);
clk_put(omap->usbhost2_120m_fck);
omap->usbhost2_120m_fck = NULL;
if (omap->usbhost_hs_fck != NULL) {
clk_disable(omap->usbhost_hs_fck);
clk_put(omap->usbhost_hs_fck);
omap->usbhost_hs_fck = NULL;
}
if (omap->usbtll_ick != NULL) {
@ -568,6 +716,32 @@ static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
omap->usbtll_ick = NULL;
}
if (is_omap_ehci_rev2(omap)) {
if (omap->xclk60mhsp1_ck != NULL) {
clk_disable(omap->xclk60mhsp1_ck);
clk_put(omap->xclk60mhsp1_ck);
omap->xclk60mhsp1_ck = NULL;
}
if (omap->utmi_p1_fck != NULL) {
clk_disable(omap->utmi_p1_fck);
clk_put(omap->utmi_p1_fck);
omap->utmi_p1_fck = NULL;
}
if (omap->xclk60mhsp2_ck != NULL) {
clk_disable(omap->xclk60mhsp2_ck);
clk_put(omap->xclk60mhsp2_ck);
omap->xclk60mhsp2_ck = NULL;
}
if (omap->utmi_p2_fck != NULL) {
clk_disable(omap->utmi_p2_fck);
clk_put(omap->utmi_p2_fck);
omap->utmi_p2_fck = NULL;
}
}
if (omap->phy_reset) {
if (gpio_is_valid(omap->reset_gpio_port[0]))
gpio_free(omap->reset_gpio_port[0]);

View File

@ -22,6 +22,9 @@
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
#endif
/* defined here to avoid adding to pci_ids.h for single instance use */
#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
/*-------------------------------------------------------------------------*/
/* called after powerup, by probe or system-pm "wakeup" */
@ -41,6 +44,35 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
return 0;
}
static int ehci_quirk_amd_SB800(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)
return 0;
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;
}
if (!amd_nb_dev)
amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
if (!amd_nb_dev)
ehci_err(ehci, "QUIRK: unable to get AMD NB device\n");
ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\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)
{
@ -99,6 +131,9 @@ 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_SB800(ehci))
ehci->amd_l1_fix = 1;
retval = ehci_halt(ehci);
if (retval)
return retval;
@ -137,6 +172,10 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
ehci_info(ehci, "disable lpm for langwell/penwell\n");
ehci->has_lpm = 0;
}
if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) {
hcd->has_tt = 1;
tdi_reset(ehci);
}
break;
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {

View File

@ -1590,6 +1590,63 @@ 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 (
@ -1616,6 +1673,12 @@ itd_link_urb (
urb->interval,
next_uframe >> 3, next_uframe & 0x7);
}
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_l1_fix == 1)
ehci_quirk_amd_L1(ehci, 1);
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
/* fill iTDs uframe by uframe */
@ -1740,6 +1803,11 @@ itd_complete (
(void) disable_periodic(ehci);
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 (unlikely(list_is_singular(&stream->td_list))) {
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;
@ -2025,6 +2093,12 @@ sitd_link_urb (
(next_uframe >> 3) & (ehci->periodic_size - 1),
stream->interval, hc32_to_cpu(ehci, stream->splits));
}
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_l1_fix == 1)
ehci_quirk_amd_L1(ehci, 1);
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
/* fill sITDs frame by frame */
@ -2125,6 +2199,11 @@ sitd_complete (
(void) disable_periodic(ehci);
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 (list_is_singular(&stream->td_list)) {
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;

243
drivers/usb/host/ehci-sh.c Normal file
View File

@ -0,0 +1,243 @@
/*
* SuperH EHCI host controller driver
*
* Copyright (C) 2010 Paul Mundt
*
* Based on ohci-sh.c and ehci-atmel.c.
*
* 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.
*/
#include <linux/platform_device.h>
#include <linux/clk.h>
struct ehci_sh_priv {
struct clk *iclk, *fclk;
struct usb_hcd *hcd;
};
static int ehci_sh_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int ret;
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");
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
ret = ehci_halt(ehci);
if (unlikely(ret))
return ret;
ret = ehci_init(hcd);
if (unlikely(ret))
return ret;
ehci->sbrn = 0x20;
ehci_reset(ehci);
ehci_port_power(ehci, 0);
return ret;
}
static const struct hc_driver ehci_sh_hc_driver = {
.description = hcd_name,
.product_desc = "SuperH EHCI",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_USB2 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
.reset = ehci_sh_reset,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* 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,
#ifdef CONFIG_PM
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
.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_sh_probe(struct platform_device *pdev)
{
const struct hc_driver *driver = &ehci_sh_hc_driver;
struct resource *res;
struct ehci_sh_priv *priv;
struct usb_hcd *hcd;
int irq, ret;
if (usb_disabled())
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no register addr. Check %s setup!\n",
dev_name(&pdev->dev));
ret = -ENODEV;
goto fail_create_hcd;
}
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev,
"Found HC with no IRQ. Check %s setup!\n",
dev_name(&pdev->dev));
ret = -ENODEV;
goto fail_create_hcd;
}
/* initialize hcd */
hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd) {
ret = -ENOMEM;
goto fail_create_hcd;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {
dev_dbg(&pdev->dev, "controller already in use\n");
ret = -EBUSY;
goto fail_request_resource;
}
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
ret = -ENXIO;
goto fail_ioremap;
}
priv = kmalloc(sizeof(struct ehci_sh_priv), GFP_KERNEL);
if (!priv) {
dev_dbg(&pdev->dev, "error allocating priv data\n");
ret = -ENOMEM;
goto fail_alloc;
}
/* These are optional, we don't care if they fail */
priv->fclk = clk_get(&pdev->dev, "usb_fck");
if (IS_ERR(priv->fclk))
priv->fclk = NULL;
priv->iclk = clk_get(&pdev->dev, "usb_ick");
if (IS_ERR(priv->iclk))
priv->iclk = NULL;
clk_enable(priv->fclk);
clk_enable(priv->iclk);
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to add hcd");
goto fail_add_hcd;
}
priv->hcd = hcd;
platform_set_drvdata(pdev, priv);
return ret;
fail_add_hcd:
clk_disable(priv->iclk);
clk_disable(priv->fclk);
clk_put(priv->iclk);
clk_put(priv->fclk);
kfree(priv);
fail_alloc:
iounmap(hcd->regs);
fail_ioremap:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
fail_request_resource:
usb_put_hcd(hcd);
fail_create_hcd:
dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret);
return ret;
}
static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
{
struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
struct usb_hcd *hcd = priv->hcd;
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
platform_set_drvdata(pdev, NULL);
clk_disable(priv->fclk);
clk_disable(priv->iclk);
clk_put(priv->fclk);
clk_put(priv->iclk);
kfree(priv);
return 0;
}
static void ehci_hcd_sh_shutdown(struct platform_device *pdev)
{
struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
struct usb_hcd *hcd = priv->hcd;
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
static struct platform_driver ehci_hcd_sh_driver = {
.probe = ehci_hcd_sh_probe,
.remove = __exit_p(ehci_hcd_sh_remove),
.shutdown = ehci_hcd_sh_shutdown,
.driver = {
.name = "sh_ehci",
.owner = THIS_MODULE,
},
};
MODULE_ALIAS("platform:sh_ehci");

View File

@ -0,0 +1,212 @@
/*
* Driver for EHCI HCD on SPEAR SOC
*
* Copyright (C) 2010 ST Micro Electronics,
* Deepak Sikri <deepak.sikri@st.com>
*
* Based on various ehci-*.c drivers
*
* 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.
*/
#include <linux/platform_device.h>
#include <linux/clk.h>
struct spear_ehci {
struct ehci_hcd ehci;
struct clk *clk;
};
#define to_spear_ehci(hcd) (struct spear_ehci *)hcd_to_ehci(hcd)
static void spear_start_ehci(struct spear_ehci *ehci)
{
clk_enable(ehci->clk);
}
static void spear_stop_ehci(struct spear_ehci *ehci)
{
clk_disable(ehci->clk);
}
static int ehci_spear_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval = 0;
/* registers start at offset 0x0 */
ehci->caps = hcd->regs;
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
&ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
return retval;
retval = ehci_init(hcd);
if (retval)
return retval;
ehci_reset(ehci);
ehci_port_power(ehci, 0);
return retval;
}
static const struct hc_driver ehci_spear_hc_driver = {
.description = hcd_name,
.product_desc = "SPEAr EHCI",
.hcd_priv_size = sizeof(struct spear_ehci),
/* generic hardware linkage */
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/* basic lifecycle operations */
.reset = ehci_spear_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/* 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 spear_ehci_hcd_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd ;
struct spear_ehci *ehci;
struct resource *res;
struct clk *usbh_clk;
const struct hc_driver *driver = &ehci_spear_hc_driver;
int *pdata = pdev->dev.platform_data;
int irq, retval;
char clk_name[20] = "usbh_clk";
if (pdata == NULL)
return -EFAULT;
if (usb_disabled())
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
retval = irq;
goto fail_irq_get;
}
if (*pdata >= 0)
sprintf(clk_name, "usbh.%01d_clk", *pdata);
usbh_clk = clk_get(NULL, clk_name);
if (IS_ERR(usbh_clk)) {
dev_err(&pdev->dev, "Error getting interface clock\n");
retval = PTR_ERR(usbh_clk);
goto fail_get_usbh_clk;
}
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
goto fail_create_hcd;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
retval = -ENODEV;
goto fail_request_resource;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {
retval = -EBUSY;
goto fail_request_resource;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
retval = -ENOMEM;
goto fail_ioremap;
}
ehci = (struct spear_ehci *)hcd_to_ehci(hcd);
ehci->clk = usbh_clk;
spear_start_ehci(ehci);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
if (retval)
goto fail_add_hcd;
return retval;
fail_add_hcd:
spear_stop_ehci(ehci);
iounmap(hcd->regs);
fail_ioremap:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
fail_request_resource:
usb_put_hcd(hcd);
fail_create_hcd:
clk_put(usbh_clk);
fail_get_usbh_clk:
fail_irq_get:
dev_err(&pdev->dev, "init fail, %d\n", retval);
return retval ;
}
static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct spear_ehci *ehci_p = to_spear_ehci(hcd);
if (!hcd)
return 0;
if (in_interrupt())
BUG();
usb_remove_hcd(hcd);
if (ehci_p->clk)
spear_stop_ehci(ehci_p);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
if (ehci_p->clk)
clk_put(ehci_p->clk);
return 0;
}
static struct platform_driver spear_ehci_hcd_driver = {
.probe = spear_ehci_hcd_drv_probe,
.remove = spear_ehci_hcd_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "spear-ehci",
.bus = &platform_bus_type
}
};
MODULE_ALIAS("platform:spear-ehci");

View File

@ -0,0 +1,172 @@
/*
* drivers/usb/host/ehci-vt8500.c
*
* Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
*
* Based on ehci-au1xxx.c
*
* 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/platform_device.h>
static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int rc = 0;
if (!udev->parent) /* udev is root hub itself, impossible */
rc = -1;
/* we only support lpm device connected to root hub yet */
if (ehci->has_lpm && !udev->parent->parent) {
rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum);
if (!rc)
rc = ehci_lpm_check(ehci, udev->portnum);
}
return rc;
}
static const struct hc_driver vt8500_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "VT8500 EHCI",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = ehci_init,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* 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,
/*
* call back when device connected and addressed
*/
.update_device = ehci_update_device,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int vt8500_ehci_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct resource *res;
int ret;
if (usb_disabled())
return -ENODEV;
if (pdev->resource[1].flags != IORESOURCE_IRQ) {
pr_debug("resource[1] is not IORESOURCE_IRQ");
return -ENOMEM;
}
hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500");
if (!hcd)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed");
ret = -EBUSY;
goto err1;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
pr_debug("ioremap failed");
ret = -ENOMEM;
goto err2;
}
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
ehci->regs = hcd->regs + 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);
ehci_port_power(ehci, 1);
ret = usb_add_hcd(hcd, pdev->resource[1].start,
IRQF_DISABLED | IRQF_SHARED);
if (ret == 0) {
platform_set_drvdata(pdev, hcd);
return ret;
}
iounmap(hcd->regs);
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
return ret;
}
static int vt8500_ehci_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver vt8500_ehci_driver = {
.probe = vt8500_ehci_drv_probe,
.remove = vt8500_ehci_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "vt8500-ehci",
.owner = THIS_MODULE,
}
};
MODULE_ALIAS("platform:vt8500-ehci");

View File

@ -130,6 +130,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
@ -147,6 +148,8 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
#endif
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int __devinit ehci_w90x900_probe(struct platform_device *pdev)

View File

@ -117,6 +117,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support

View File

@ -131,6 +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 fs_i_thresh:1; /* Intel iso scheduling */
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/

View File

@ -1081,6 +1081,11 @@ MODULE_LICENSE ("GPL");
#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
#endif
#ifdef CONFIG_PLAT_SPEAR
#include "ohci-spear.c"
#define PLATFORM_DRIVER spear_ohci_hcd_driver
#endif
#ifdef CONFIG_PPC_PS3
#include "ohci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver

View File

@ -109,7 +109,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
hcd->regs = (void __iomem *)res->start;
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret != 0) {
err("Failed to add hcd");
usb_put_hcd(hcd);

View File

@ -0,0 +1,240 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* Copyright (C) 2010 ST Microelectronics.
* Deepak Sikri<deepak.sikri@st.com>
*
* Based on various ohci-*.c drivers
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/signal.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
struct spear_ohci {
struct ohci_hcd ohci;
struct clk *clk;
};
#define to_spear_ohci(hcd) (struct spear_ohci *)hcd_to_ohci(hcd)
static void spear_start_ohci(struct spear_ohci *ohci)
{
clk_enable(ohci->clk);
}
static void spear_stop_ohci(struct spear_ohci *ohci)
{
clk_disable(ohci->clk);
}
static int __devinit ohci_spear_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int ret;
ret = ohci_init(ohci);
if (ret < 0)
return ret;
ohci->regs = hcd->regs;
ret = ohci_run(ohci);
if (ret < 0) {
dev_err(hcd->self.controller, "can't start\n");
ohci_stop(hcd);
return ret;
}
create_debug_files(ohci);
#ifdef DEBUG
ohci_dump(ohci, 1);
#endif
return 0;
}
static const struct hc_driver ohci_spear_hc_driver = {
.description = hcd_name,
.product_desc = "SPEAr OHCI",
.hcd_priv_size = sizeof(struct spear_ohci),
/* generic hardware linkage */
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
/* basic lifecycle operations */
.start = ohci_spear_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
/* managing i/o requests and associated device resources */
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
/* scheduling support */
.get_frame_number = ohci_get_frame,
/* root hub support */
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.start_port_reset = ohci_start_port_reset,
};
static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
{
const struct hc_driver *driver = &ohci_spear_hc_driver;
struct usb_hcd *hcd = NULL;
struct clk *usbh_clk;
struct spear_ohci *ohci_p;
struct resource *res;
int retval, irq;
int *pdata = pdev->dev.platform_data;
char clk_name[20] = "usbh_clk";
if (pdata == NULL)
return -EFAULT;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
retval = irq;
goto fail_irq_get;
}
if (*pdata >= 0)
sprintf(clk_name, "usbh.%01d_clk", *pdata);
usbh_clk = clk_get(NULL, clk_name);
if (IS_ERR(usbh_clk)) {
dev_err(&pdev->dev, "Error getting interface clock\n");
retval = PTR_ERR(usbh_clk);
goto fail_get_usbh_clk;
}
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
goto fail_create_hcd;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
retval = -ENODEV;
goto fail_request_resource;
}
hcd->rsrc_start = pdev->resource[0].start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dev_dbg(&pdev->dev, "request_mem_region failed\n");
retval = -EBUSY;
goto fail_request_resource;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
dev_dbg(&pdev->dev, "ioremap failed\n");
retval = -ENOMEM;
goto fail_ioremap;
}
ohci_p = (struct spear_ohci *)hcd_to_ohci(hcd);
ohci_p->clk = usbh_clk;
spear_start_ohci(ohci_p);
ohci_hcd_init(hcd_to_ohci(hcd));
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), IRQF_DISABLED);
if (retval == 0)
return retval;
spear_stop_ohci(ohci_p);
iounmap(hcd->regs);
fail_ioremap:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
fail_request_resource:
usb_put_hcd(hcd);
fail_create_hcd:
clk_put(usbh_clk);
fail_get_usbh_clk:
fail_irq_get:
dev_err(&pdev->dev, "init fail, %d\n", retval);
return retval;
}
static int spear_ohci_hcd_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct spear_ohci *ohci_p = to_spear_ohci(hcd);
usb_remove_hcd(hcd);
if (ohci_p->clk)
spear_stop_ohci(ohci_p);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
if (ohci_p->clk)
clk_put(ohci_p->clk);
platform_set_drvdata(pdev, NULL);
return 0;
}
#if defined(CONFIG_PM)
static int spear_ohci_hcd_drv_suspend(struct platform_device *dev,
pm_message_t message)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
struct spear_ohci *ohci_p = to_spear_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
spear_stop_ohci(ohci_p);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
return 0;
}
static int spear_ohci_hcd_drv_resume(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
struct spear_ohci *ohci_p = to_spear_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
spear_start_ohci(ohci_p);
ohci_finish_controller_resume(hcd);
return 0;
}
#endif
/* Driver definition to register with the platform bus */
static struct platform_driver spear_ohci_hcd_driver = {
.probe = spear_ohci_hcd_drv_probe,
.remove = spear_ohci_hcd_drv_remove,
#ifdef CONFIG_PM
.suspend = spear_ohci_hcd_drv_suspend,
.resume = spear_ohci_hcd_drv_resume,
#endif
.driver = {
.owner = THIS_MODULE,
.name = "spear-ohci",
},
};
MODULE_ALIAS("platform:spear-ohci");

View File

@ -569,7 +569,7 @@ static int uhci_init(struct usb_hcd *hcd)
*/
static void uhci_shutdown(struct pci_dev *pdev)
{
struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev);
struct usb_hcd *hcd = pci_get_drvdata(pdev);
uhci_hc_died(hcd_to_uhci(hcd));
}

View File

@ -29,7 +29,7 @@ static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
if (uhci->is_stopped)
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
}
static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
@ -195,7 +195,9 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
} else {
struct uhci_td *ntd;
ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
ntd = list_entry(td->fl_list.next,
struct uhci_td,
fl_list);
uhci->frame[td->frame] = LINK_TO_TD(ntd);
uhci->frame_cpu[td->frame] = ntd;
}
@ -728,7 +730,7 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
urbp->urb = urb;
urb->hcpriv = urbp;
INIT_LIST_HEAD(&urbp->node);
INIT_LIST_HEAD(&urbp->td_list);
@ -846,7 +848,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
/* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE;
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_explen(pktsze),
data);
@ -857,7 +859,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
}
/*
* Build the final TD for control status
* Build the final TD for control status
*/
td = uhci_alloc_td(uhci);
if (!td)

View File

@ -356,7 +356,7 @@ static void __exit whci_hc_driver_exit(void)
module_exit(whci_hc_driver_exit);
/* PCI device ID's that we handle (so it gets loaded) */
static struct pci_device_id whci_hcd_id_table[] = {
static struct pci_device_id __used whci_hcd_id_table[] = {
{ PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
{ /* empty last entry */ }
};

View File

@ -436,6 +436,28 @@ static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp,
return length;
}
/*
* This is the look-ahead pass in case of 'C Zi', when actual_length cannot
* be used to determine the length of the whole contiguous buffer.
*/
static unsigned int mon_bin_collate_isodesc(const struct mon_reader_bin *rp,
struct urb *urb, unsigned int ndesc)
{
struct usb_iso_packet_descriptor *fp;
unsigned int length;
length = 0;
fp = urb->iso_frame_desc;
while (ndesc-- != 0) {
if (fp->actual_length != 0) {
if (fp->offset + fp->actual_length > length)
length = fp->offset + fp->actual_length;
}
fp++;
}
return length;
}
static void mon_bin_get_isodesc(const struct mon_reader_bin *rp,
unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc)
{
@ -478,6 +500,10 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
/*
* Find the maximum allowable length, then allocate space.
*/
urb_length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
length = urb_length;
if (usb_endpoint_xfer_isoc(epd)) {
if (urb->number_of_packets < 0) {
ndesc = 0;
@ -486,14 +512,16 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
} else {
ndesc = urb->number_of_packets;
}
if (ev_type == 'C' && usb_urb_dir_in(urb))
length = mon_bin_collate_isodesc(rp, urb, ndesc);
} else {
ndesc = 0;
}
lendesc = ndesc*sizeof(struct mon_bin_isodesc);
urb_length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
length = urb_length;
/* not an issue unless there's a subtle bug in a HCD somewhere */
if (length >= urb->transfer_buffer_length)
length = urb->transfer_buffer_length;
if (length >= rp->b_size/5)
length = rp->b_size/5;

View File

@ -12,6 +12,7 @@ config USB_MUSB_HDRC
depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
select TWL4030_USB if MACH_OMAP_3430SDP
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
select USB_OTG_UTILS
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
@ -30,57 +31,41 @@ config USB_MUSB_HDRC
If you do not know what this is, please say N.
To compile this driver as a module, choose M here; the
module will be called "musb_hdrc".
module will be called "musb-hdrc".
config USB_MUSB_SOC
boolean
choice
prompt "Platform Glue Layer"
depends on USB_MUSB_HDRC
default y if ARCH_DAVINCI
default y if ARCH_OMAP2430
default y if ARCH_OMAP3
default y if ARCH_OMAP4
default y if (BF54x && !BF544)
default y if (BF52x && !BF522 && !BF523)
comment "DaVinci 35x and 644x USB support"
depends on USB_MUSB_HDRC && ARCH_DAVINCI_DMx
config USB_MUSB_DAVINCI
bool "DaVinci"
depends on ARCH_DAVINCI_DMx
comment "DA8xx/OMAP-L1x USB support"
depends on USB_MUSB_HDRC && ARCH_DAVINCI_DA8XX
config USB_MUSB_DA8XX
bool "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
comment "OMAP 243x high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP2430
config USB_MUSB_TUSB6010
bool "TUSB6010"
depends on ARCH_OMAP
comment "OMAP 343x high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP3
comment "OMAP 44xx high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP4
comment "Blackfin high speed USB Support"
depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
config USB_MUSB_OMAP2PLUS
bool "OMAP2430 and onwards"
depends on ARCH_OMAP2PLUS
config USB_MUSB_AM35X
bool
depends on USB_MUSB_HDRC && !ARCH_OMAP2430 && !ARCH_OMAP4
select NOP_USB_XCEIV
default MACH_OMAP3517EVM
help
Select this option if your platform is based on AM35x. As
AM35x has an updated MUSB with CPPI4.1 DMA so this config
is introduced to differentiate musb ip between OMAP3x and
AM35x platforms.
bool "AM35x"
depends on ARCH_OMAP
config USB_TUSB6010
boolean "TUSB 6010 support"
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
select NOP_USB_XCEIV
default y
help
The TUSB 6010 chip, from Texas Instruments, connects a discrete
HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ
(a high speed serial link). It can use system-specific external
DMA controllers.
config USB_MUSB_BLACKFIN
bool "Blackfin"
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
config USB_MUSB_UX500
bool "U8500 and U5500"
depends on (ARCH_U8500 && AB8500_USB) || (ARCH_U5500)
endchoice
choice
prompt "Driver Mode"
@ -158,7 +143,7 @@ config USB_MUSB_HDRC_HCD
config MUSB_PIO_ONLY
bool 'Disable DMA (always use PIO)'
depends on USB_MUSB_HDRC
default USB_TUSB6010 || ARCH_DAVINCI_DA8XX || USB_MUSB_AM35X
default USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
help
All data is copied between memory and FIFO by the CPU.
DMA controllers are ignored.
@ -171,21 +156,21 @@ config MUSB_PIO_ONLY
config USB_INVENTRA_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN || ARCH_OMAP4
default USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
help
Enable DMA transfers using Mentor's engine.
config USB_TI_CPPI_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
default ARCH_DAVINCI
default USB_MUSB_DAVINCI
help
Enable DMA transfers when TI CPPI DMA is available.
config USB_TUSB_OMAP_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
depends on USB_TUSB6010
depends on USB_MUSB_TUSB6010
depends on ARCH_OMAP
default y
help

View File

@ -8,22 +8,19 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
musb_hdrc-y := musb_core.o
musb_hdrc-$(CONFIG_ARCH_DAVINCI_DMx) += davinci.o
musb_hdrc-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx.o
musb_hdrc-$(CONFIG_USB_TUSB6010) += tusb6010.o
musb_hdrc-$(CONFIG_ARCH_OMAP2430) += omap2430.o
ifeq ($(CONFIG_USB_MUSB_AM35X),y)
musb_hdrc-$(CONFIG_ARCH_OMAP3430) += am35x.o
else
musb_hdrc-$(CONFIG_ARCH_OMAP3430) += omap2430.o
endif
musb_hdrc-$(CONFIG_ARCH_OMAP4) += omap2430.o
musb_hdrc-$(CONFIG_BF54x) += blackfin.o
musb_hdrc-$(CONFIG_BF52x) += blackfin.o
musb_hdrc-$(CONFIG_USB_GADGET_MUSB_HDRC) += musb_gadget_ep0.o musb_gadget.o
musb_hdrc-$(CONFIG_USB_MUSB_HDRC_HCD) += musb_virthub.o musb_host.o
musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o
# Hardware Glue Layer
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o
obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o
obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
# the kconfig must guarantee that only one of the
# possible I/O schemes will be enabled at a time ...
# PIO only, or DMA (several potential schemes).

View File

@ -29,8 +29,9 @@
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <plat/control.h>
#include <plat/usb.h>
#include "musb_core.h"
@ -80,51 +81,18 @@
#define USB_MENTOR_CORE_OFFSET 0x400
static inline void phy_on(void)
{
unsigned long timeout = jiffies + msecs_to_jiffies(100);
u32 devconf2;
/*
* Start the on-chip PHY and its PLL.
*/
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
devconf2 |= CONF2_PHY_PLLON;
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
DBG(1, "Waiting for PHY clock good...\n");
while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
& CONF2_PHYCLKGD)) {
cpu_relax();
if (time_after(jiffies, timeout)) {
DBG(1, "musb PHY clock good timed out\n");
break;
}
}
}
static inline void phy_off(void)
{
u32 devconf2;
/*
* Power down the on-chip PHY.
*/
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
devconf2 &= ~CONF2_PHY_PLLON;
devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
}
struct am35x_glue {
struct device *dev;
struct platform_device *musb;
struct clk *phy_clk;
struct clk *clk;
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
/*
* musb_platform_enable - enable interrupts
* am35x_musb_enable - enable interrupts
*/
void musb_platform_enable(struct musb *musb)
static void am35x_musb_enable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
u32 epmask;
@ -143,9 +111,9 @@ void musb_platform_enable(struct musb *musb)
}
/*
* musb_platform_disable - disable HDRC and flush interrupts
* am35x_musb_disable - disable HDRC and flush interrupts
*/
void musb_platform_disable(struct musb *musb)
static void am35x_musb_disable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
@ -162,7 +130,7 @@ void musb_platform_disable(struct musb *musb)
#define portstate(stmt)
#endif
static void am35x_set_vbus(struct musb *musb, int is_on)
static void am35x_musb_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
}
@ -221,7 +189,7 @@ static void otg_timer(unsigned long _musb)
spin_unlock_irqrestore(&musb->lock, flags);
}
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
{
static unsigned long last_timer;
@ -251,13 +219,16 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
mod_timer(&otg_workaround, timeout);
}
static irqreturn_t am35x_interrupt(int irq, void *hci)
static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
{
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
u32 epintr, usbintr, lvl_intr;
u32 epintr, usbintr;
spin_lock_irqsave(&musb->lock, flags);
@ -346,9 +317,8 @@ eoi:
/* EOI needs to be written for the IRQ to be re-asserted. */
if (ret == IRQ_HANDLED || epintr || usbintr) {
/* clear level interrupt */
lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
if (data->clear_irq)
data->clear_irq();
/* write EOI */
musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
}
@ -362,137 +332,85 @@ eoi:
return ret;
}
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
{
u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
int retval = 0;
devconf2 &= ~CONF2_OTGMODE;
switch (musb_mode) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case MUSB_HOST: /* Force VBUS valid, ID = 0 */
devconf2 |= CONF2_FORCE_HOST;
break;
#endif
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
devconf2 |= CONF2_FORCE_DEVICE;
break;
#endif
#ifdef CONFIG_USB_MUSB_OTG
case MUSB_OTG: /* Don't override the VBUS/ID comparators */
devconf2 |= CONF2_NO_OVERRIDE;
break;
#endif
default:
DBG(2, "Trying to set unsupported mode %u\n", musb_mode);
}
if (data->set_mode)
data->set_mode(musb_mode);
else
retval = -EIO;
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
return 0;
return retval;
}
int __init musb_platform_init(struct musb *musb, void *board_data)
static int am35x_musb_init(struct musb *musb)
{
struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
void __iomem *reg_base = musb->ctrl_base;
u32 rev, lvl_intr, sw_reset;
int status;
u32 rev;
musb->mregs += USB_MENTOR_CORE_OFFSET;
clk_enable(musb->clock);
DBG(2, "musb->clock=%lud\n", clk_get_rate(musb->clock));
musb->phy_clock = clk_get(musb->controller, "fck");
if (IS_ERR(musb->phy_clock)) {
status = PTR_ERR(musb->phy_clock);
goto exit0;
}
clk_enable(musb->phy_clock);
DBG(2, "musb->phy_clock=%lud\n", clk_get_rate(musb->phy_clock));
/* Returns zero if e.g. not clocked */
rev = musb_readl(reg_base, USB_REVISION_REG);
if (!rev) {
status = -ENODEV;
goto exit1;
}
if (!rev)
return -ENODEV;
usb_nop_xceiv_register();
musb->xceiv = otg_get_transceiver();
if (!musb->xceiv) {
status = -ENODEV;
goto exit1;
}
if (!musb->xceiv)
return -ENODEV;
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
musb->board_set_vbus = am35x_set_vbus;
/* Global reset */
sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
sw_reset |= AM35XX_USBOTGSS_SW_RST;
omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
sw_reset &= ~AM35XX_USBOTGSS_SW_RST;
omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
/* Reset the musb */
if (data->reset)
data->reset();
/* Reset the controller */
musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
/* Start the on-chip PHY and its PLL. */
phy_on();
if (data->set_phy_power)
data->set_phy_power(1);
msleep(5);
musb->isr = am35x_interrupt;
musb->isr = am35x_musb_interrupt;
/* clear level interrupt */
lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
if (data->clear_irq)
data->clear_irq();
return 0;
exit1:
clk_disable(musb->phy_clock);
clk_put(musb->phy_clock);
exit0:
clk_disable(musb->clock);
return status;
}
int musb_platform_exit(struct musb *musb)
static int am35x_musb_exit(struct musb *musb)
{
struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
phy_off();
/* Shutdown the on-chip PHY and its PLL. */
if (data->set_phy_power)
data->set_phy_power(0);
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
clk_disable(musb->clock);
clk_disable(musb->phy_clock);
clk_put(musb->phy_clock);
return 0;
}
#ifdef CONFIG_PM
void musb_platform_save_context(struct musb *musb,
struct musb_context_registers *musb_context)
{
phy_off();
}
void musb_platform_restore_context(struct musb *musb,
struct musb_context_registers *musb_context)
{
phy_on();
}
#endif
/* AM35x supports only 32bit read operation */
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
@ -522,3 +440,215 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
memcpy(dst, &val, len);
}
}
static const struct musb_platform_ops am35x_ops = {
.init = am35x_musb_init,
.exit = am35x_musb_exit,
.enable = am35x_musb_enable,
.disable = am35x_musb_disable,
.set_mode = am35x_musb_set_mode,
.try_idle = am35x_musb_try_idle,
.set_vbus = am35x_musb_set_vbus,
};
static u64 am35x_dmamask = DMA_BIT_MASK(32);
static int __init am35x_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
struct am35x_glue *glue;
struct clk *phy_clk;
struct clk *clk;
int ret = -ENOMEM;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
}
musb = platform_device_alloc("musb-hdrc", -1);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1;
}
phy_clk = clk_get(&pdev->dev, "fck");
if (IS_ERR(phy_clk)) {
dev_err(&pdev->dev, "failed to get PHY clock\n");
ret = PTR_ERR(phy_clk);
goto err2;
}
clk = clk_get(&pdev->dev, "ick");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk);
goto err3;
}
ret = clk_enable(phy_clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable PHY clock\n");
goto err4;
}
ret = clk_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
goto err5;
}
musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &am35x_dmamask;
musb->dev.coherent_dma_mask = am35x_dmamask;
glue->dev = &pdev->dev;
glue->musb = musb;
glue->phy_clk = phy_clk;
glue->clk = clk;
pdata->platform_ops = &am35x_ops;
platform_set_drvdata(pdev, glue);
ret = platform_device_add_resources(musb, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto err6;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
goto err6;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
goto err6;
}
return 0;
err6:
clk_disable(clk);
err5:
clk_disable(phy_clk);
err4:
clk_put(clk);
err3:
clk_put(phy_clk);
err2:
platform_device_put(musb);
err1:
kfree(glue);
err0:
return ret;
}
static int __exit am35x_remove(struct platform_device *pdev)
{
struct am35x_glue *glue = platform_get_drvdata(pdev);
platform_device_del(glue->musb);
platform_device_put(glue->musb);
clk_disable(glue->clk);
clk_disable(glue->phy_clk);
clk_put(glue->clk);
clk_put(glue->phy_clk);
kfree(glue);
return 0;
}
#ifdef CONFIG_PM
static int am35x_suspend(struct device *dev)
{
struct am35x_glue *glue = dev_get_drvdata(dev);
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
/* Shutdown the on-chip PHY and its PLL. */
if (data->set_phy_power)
data->set_phy_power(0);
clk_disable(glue->phy_clk);
clk_disable(glue->clk);
return 0;
}
static int am35x_resume(struct device *dev)
{
struct am35x_glue *glue = dev_get_drvdata(dev);
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
int ret;
/* Start the on-chip PHY and its PLL. */
if (data->set_phy_power)
data->set_phy_power(1);
ret = clk_enable(glue->phy_clk);
if (ret) {
dev_err(dev, "failed to enable PHY clock\n");
return ret;
}
ret = clk_enable(glue->clk);
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}
return 0;
}
static struct dev_pm_ops am35x_pm_ops = {
.suspend = am35x_suspend,
.resume = am35x_resume,
};
#define DEV_PM_OPS &am35x_pm_ops
#else
#define DEV_PM_OPS NULL
#endif
static struct platform_driver am35x_driver = {
.remove = __exit_p(am35x_remove),
.driver = {
.name = "musb-am35x",
.pm = DEV_PM_OPS,
},
};
MODULE_DESCRIPTION("AM35x MUSB Glue Layer");
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
MODULE_LICENSE("GPL v2");
static int __init am35x_init(void)
{
return platform_driver_probe(&am35x_driver, am35x_probe);
}
subsys_initcall(am35x_init);
static void __exit am35x_exit(void)
{
platform_driver_unregister(&am35x_driver);
}
module_exit(am35x_exit);

View File

@ -15,12 +15,20 @@
#include <linux/list.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include "musb_core.h"
#include "blackfin.h"
struct bfin_glue {
struct device *dev;
struct platform_device *musb;
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
/*
* Load an endpoint's FIFO
*/
@ -278,7 +286,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
DBG(4, "state is %s\n", otg_state_string(musb));
}
void musb_platform_enable(struct musb *musb)
static void bfin_musb_enable(struct musb *musb)
{
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
@ -286,11 +294,11 @@ void musb_platform_enable(struct musb *musb)
}
}
void musb_platform_disable(struct musb *musb)
static void bfin_musb_disable(struct musb *musb)
{
}
static void bfin_set_vbus(struct musb *musb, int is_on)
static void bfin_musb_set_vbus(struct musb *musb, int is_on)
{
int value = musb->config->gpio_vrsel_active;
if (!is_on)
@ -303,51 +311,29 @@ static void bfin_set_vbus(struct musb *musb, int is_on)
musb_readb(musb->mregs, MUSB_DEVCTL));
}
static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
{
return 0;
}
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
{
if (!is_otg_enabled(musb) && is_host_enabled(musb))
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
}
int musb_platform_get_vbus_status(struct musb *musb)
static int bfin_musb_get_vbus_status(struct musb *musb)
{
return 0;
}
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
{
return -EIO;
}
int __init musb_platform_init(struct musb *musb, void *board_data)
static void bfin_musb_reg_init(struct musb *musb)
{
/*
* Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
* and OTG HOST modes, while rev 1.1 and greater require PE7 to
* be low for DEVICE mode and high for HOST mode. We set it high
* here because we are in host mode
*/
if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
musb->config->gpio_vrsel);
return -ENODEV;
}
gpio_direction_output(musb->config->gpio_vrsel, 0);
usb_nop_xceiv_register();
musb->xceiv = otg_get_transceiver();
if (!musb->xceiv) {
gpio_free(musb->config->gpio_vrsel);
return -ENODEV;
}
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
SSYNC();
@ -382,21 +368,47 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
SSYNC();
}
static int bfin_musb_init(struct musb *musb)
{
/*
* Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
* and OTG HOST modes, while rev 1.1 and greater require PE7 to
* be low for DEVICE mode and high for HOST mode. We set it high
* here because we are in host mode
*/
if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
musb->config->gpio_vrsel);
return -ENODEV;
}
gpio_direction_output(musb->config->gpio_vrsel, 0);
usb_nop_xceiv_register();
musb->xceiv = otg_get_transceiver();
if (!musb->xceiv) {
gpio_free(musb->config->gpio_vrsel);
return -ENODEV;
}
bfin_musb_reg_init(musb);
if (is_host_enabled(musb)) {
musb->board_set_vbus = bfin_set_vbus;
setup_timer(&musb_conn_timer,
musb_conn_timer_handler, (unsigned long) musb);
}
if (is_peripheral_enabled(musb))
musb->xceiv->set_power = bfin_set_power;
musb->xceiv->set_power = bfin_musb_set_power;
musb->isr = blackfin_interrupt;
return 0;
}
int musb_platform_exit(struct musb *musb)
static int bfin_musb_exit(struct musb *musb)
{
gpio_free(musb->config->gpio_vrsel);
@ -404,3 +416,154 @@ int musb_platform_exit(struct musb *musb)
usb_nop_xceiv_unregister();
return 0;
}
static const struct musb_platform_ops bfin_ops = {
.init = bfin_musb_init,
.exit = bfin_musb_exit,
.enable = bfin_musb_enable,
.disable = bfin_musb_disable,
.set_mode = bfin_musb_set_mode,
.try_idle = bfin_musb_try_idle,
.vbus_status = bfin_musb_vbus_status,
.set_vbus = bfin_musb_set_vbus,
};
static u64 bfin_dmamask = DMA_BIT_MASK(32);
static int __init bfin_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
struct bfin_glue *glue;
int ret = -ENOMEM;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
}
musb = platform_device_alloc("musb-hdrc", -1);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1;
}
musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &bfin_dmamask;
musb->dev.coherent_dma_mask = bfin_dmamask;
glue->dev = &pdev->dev;
glue->musb = musb;
pdata->platform_ops = &bfin_ops;
platform_set_drvdata(pdev, glue);
ret = platform_device_add_resources(musb, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto err2;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
goto err2;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
goto err2;
}
return 0;
err2:
platform_device_put(musb);
err1:
kfree(glue);
err0:
return ret;
}
static int __exit bfin_remove(struct platform_device *pdev)
{
struct bfin_glue *glue = platform_get_drvdata(pdev);
platform_device_del(glue->musb);
platform_device_put(glue->musb);
kfree(glue);
return 0;
}
#ifdef CONFIG_PM
static int bfin_suspend(struct device *dev)
{
struct bfin_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
if (is_host_active(musb))
/*
* During hibernate gpio_vrsel will change from high to low
* low which will generate wakeup event resume the system
* immediately. Set it to 0 before hibernate to avoid this
* wakeup event.
*/
gpio_set_value(musb->config->gpio_vrsel, 0);
return 0;
}
static int bfin_resume(struct device *dev)
{
struct bfin_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
bfin_musb_reg_init(musb);
return 0;
}
static struct dev_pm_ops bfin_pm_ops = {
.suspend = bfin_suspend,
.resume = bfin_resume,
};
#define DEV_PM_OPS &bfin_pm_op,
#else
#define DEV_PM_OPS NULL
#endif
static struct platform_driver bfin_driver = {
.remove = __exit_p(bfin_remove),
.driver = {
.name = "musb-bfin",
.pm = DEV_PM_OPS,
},
};
MODULE_DESCRIPTION("Blackfin MUSB Glue Layer");
MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>");
MODULE_LICENSE("GPL v2");
static int __init bfin_init(void)
{
return platform_driver_probe(&bfin_driver, bfin_probe);
}
subsys_initcall(bfin_init);
static void __exit bfin_exit(void)
{
platform_driver_unregister(&bfin_driver);
}
module_exit(bfin_exit);

View File

@ -1308,7 +1308,7 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
struct cppi *controller;
struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev);
int irq = platform_get_irq(pdev, 1);
int irq = platform_get_irq_byname(pdev, "dma");
controller = kzalloc(sizeof *controller, GFP_KERNEL);
if (!controller)

View File

@ -29,6 +29,8 @@
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <mach/da8xx.h>
#include <mach/usb.h>
@ -78,6 +80,12 @@
#define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG)
struct da8xx_glue {
struct device *dev;
struct platform_device *musb;
struct clk *clk;
};
/*
* REVISIT (PM): we should be able to keep the PHY in low power mode most
* of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0
@ -131,9 +139,9 @@ static inline void phy_off(void)
*/
/**
* musb_platform_enable - enable interrupts
* da8xx_musb_enable - enable interrupts
*/
void musb_platform_enable(struct musb *musb)
static void da8xx_musb_enable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
u32 mask;
@ -151,9 +159,9 @@ void musb_platform_enable(struct musb *musb)
}
/**
* musb_platform_disable - disable HDRC and flush interrupts
* da8xx_musb_disable - disable HDRC and flush interrupts
*/
void musb_platform_disable(struct musb *musb)
static void da8xx_musb_disable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
@ -170,7 +178,7 @@ void musb_platform_disable(struct musb *musb)
#define portstate(stmt)
#endif
static void da8xx_set_vbus(struct musb *musb, int is_on)
static void da8xx_musb_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
}
@ -252,7 +260,7 @@ static void otg_timer(unsigned long _musb)
spin_unlock_irqrestore(&musb->lock, flags);
}
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
{
static unsigned long last_timer;
@ -282,7 +290,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
mod_timer(&otg_workaround, timeout);
}
static irqreturn_t da8xx_interrupt(int irq, void *hci)
static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
{
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
@ -380,7 +388,7 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)
return ret;
}
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)
{
u32 cfgchip2 = __raw_readl(CFGCHIP2);
@ -409,15 +417,13 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
return 0;
}
int __init musb_platform_init(struct musb *musb, void *board_data)
static int da8xx_musb_init(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
u32 rev;
musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
clk_enable(musb->clock);
/* Returns zero if e.g. not clocked */
rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG);
if (!rev)
@ -431,8 +437,6 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
musb->board_set_vbus = da8xx_set_vbus;
/* Reset the controller */
musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
@ -446,14 +450,13 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
rev, __raw_readl(CFGCHIP2),
musb_readb(reg_base, DA8XX_USB_CTRL_REG));
musb->isr = da8xx_interrupt;
musb->isr = da8xx_musb_interrupt;
return 0;
fail:
clk_disable(musb->clock);
return -ENODEV;
}
int musb_platform_exit(struct musb *musb)
static int da8xx_musb_exit(struct musb *musb)
{
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
@ -463,7 +466,140 @@ int musb_platform_exit(struct musb *musb)
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
clk_disable(musb->clock);
return 0;
}
static const struct musb_platform_ops da8xx_ops = {
.init = da8xx_musb_init,
.exit = da8xx_musb_exit,
.enable = da8xx_musb_enable,
.disable = da8xx_musb_disable,
.set_mode = da8xx_musb_set_mode,
.try_idle = da8xx_musb_try_idle,
.set_vbus = da8xx_musb_set_vbus,
};
static u64 da8xx_dmamask = DMA_BIT_MASK(32);
static int __init da8xx_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
struct da8xx_glue *glue;
struct clk *clk;
int ret = -ENOMEM;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
}
musb = platform_device_alloc("musb-hdrc", -1);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1;
}
clk = clk_get(&pdev->dev, "usb20");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk);
goto err2;
}
ret = clk_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
goto err3;
}
musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &da8xx_dmamask;
musb->dev.coherent_dma_mask = da8xx_dmamask;
glue->dev = &pdev->dev;
glue->musb = musb;
glue->clk = clk;
pdata->platform_ops = &da8xx_ops;
platform_set_drvdata(pdev, glue);
ret = platform_device_add_resources(musb, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto err4;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
goto err4;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
goto err4;
}
return 0;
err4:
clk_disable(clk);
err3:
clk_put(clk);
err2:
platform_device_put(musb);
err1:
kfree(glue);
err0:
return ret;
}
static int __exit da8xx_remove(struct platform_device *pdev)
{
struct da8xx_glue *glue = platform_get_drvdata(pdev);
platform_device_del(glue->musb);
platform_device_put(glue->musb);
clk_disable(glue->clk);
clk_put(glue->clk);
kfree(glue);
return 0;
}
static struct platform_driver da8xx_driver = {
.remove = __exit_p(da8xx_remove),
.driver = {
.name = "musb-da8xx",
},
};
MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer");
MODULE_AUTHOR("Sergei Shtylyov <sshtylyov@ru.mvista.com>");
MODULE_LICENSE("GPL v2");
static int __init da8xx_init(void)
{
return platform_driver_probe(&da8xx_driver, da8xx_probe);
}
subsys_initcall(da8xx_init);
static void __exit da8xx_exit(void)
{
platform_driver_unregister(&da8xx_driver);
}
module_exit(da8xx_exit);

View File

@ -30,6 +30,8 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <mach/hardware.h>
#include <mach/memory.h>
@ -51,6 +53,12 @@
#define USB_PHY_CTRL IO_ADDRESS(USBPHY_CTL_PADDR)
#define DM355_DEEPSLEEP IO_ADDRESS(DM355_DEEPSLEEP_PADDR)
struct davinci_glue {
struct device *dev;
struct platform_device *musb;
struct clk *clk;
};
/* REVISIT (PM) we should be able to keep the PHY in low power mode most
* of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
* and, when in host mode, autosuspending idle root ports... PHYPLLON
@ -83,7 +91,7 @@ static inline void phy_off(void)
static int dma_off = 1;
void musb_platform_enable(struct musb *musb)
static void davinci_musb_enable(struct musb *musb)
{
u32 tmp, old, val;
@ -116,7 +124,7 @@ void musb_platform_enable(struct musb *musb)
/*
* Disable the HDRC and flush interrupts
*/
void musb_platform_disable(struct musb *musb)
static void davinci_musb_disable(struct musb *musb)
{
/* because we don't set CTRLR.UINT, "important" to:
* - not read/write INTRUSB/INTRUSBE
@ -167,7 +175,7 @@ static void evm_deferred_drvvbus(struct work_struct *ignored)
#endif /* EVM */
static void davinci_source_power(struct musb *musb, int is_on, int immediate)
static void davinci_musb_source_power(struct musb *musb, int is_on, int immediate)
{
#ifdef CONFIG_MACH_DAVINCI_EVM
if (is_on)
@ -190,10 +198,10 @@ static void davinci_source_power(struct musb *musb, int is_on, int immediate)
#endif
}
static void davinci_set_vbus(struct musb *musb, int is_on)
static void davinci_musb_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
davinci_source_power(musb, is_on, 0);
davinci_musb_source_power(musb, is_on, 0);
}
@ -259,7 +267,7 @@ static void otg_timer(unsigned long _musb)
spin_unlock_irqrestore(&musb->lock, flags);
}
static irqreturn_t davinci_interrupt(int irq, void *__hci)
static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
{
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
@ -345,7 +353,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* NOTE: this must complete poweron within 100 msec
* (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
*/
davinci_source_power(musb, drvvbus, 0);
davinci_musb_source_power(musb, drvvbus, 0);
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
otg_state_string(musb),
@ -370,13 +378,13 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
return retval;
}
int musb_platform_set_mode(struct musb *musb, u8 mode)
static int davinci_musb_set_mode(struct musb *musb, u8 mode)
{
/* EVM can't do this (right?) */
return -EIO;
}
int __init musb_platform_init(struct musb *musb, void *board_data)
static int davinci_musb_init(struct musb *musb)
{
void __iomem *tibase = musb->ctrl_base;
u32 revision;
@ -388,8 +396,6 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
musb->mregs += DAVINCI_BASE_OFFSET;
clk_enable(musb->clock);
/* returns zero if e.g. not clocked */
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
if (revision == 0)
@ -398,8 +404,7 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
musb->board_set_vbus = davinci_set_vbus;
davinci_source_power(musb, 0, 1);
davinci_musb_source_power(musb, 0, 1);
/* dm355 EVM swaps D+/D- for signal integrity, and
* is clocked from the main 24 MHz crystal.
@ -440,18 +445,16 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
revision, __raw_readl(USB_PHY_CTRL),
musb_readb(tibase, DAVINCI_USB_CTRL_REG));
musb->isr = davinci_interrupt;
musb->isr = davinci_musb_interrupt;
return 0;
fail:
clk_disable(musb->clock);
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return -ENODEV;
}
int musb_platform_exit(struct musb *musb)
static int davinci_musb_exit(struct musb *musb)
{
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
@ -465,7 +468,7 @@ int musb_platform_exit(struct musb *musb)
__raw_writel(deepsleep, DM355_DEEPSLEEP);
}
davinci_source_power(musb, 0 /*off*/, 1);
davinci_musb_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */
if (is_host_enabled(musb) && musb->xceiv->default_a) {
@ -495,10 +498,141 @@ int musb_platform_exit(struct musb *musb)
phy_off();
clk_disable(musb->clock);
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return 0;
}
static const struct musb_platform_ops davinci_ops = {
.init = davinci_musb_init,
.exit = davinci_musb_exit,
.enable = davinci_musb_enable,
.disable = davinci_musb_disable,
.set_mode = davinci_musb_set_mode,
.set_vbus = davinci_musb_set_vbus,
};
static u64 davinci_dmamask = DMA_BIT_MASK(32);
static int __init davinci_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
struct davinci_glue *glue;
struct clk *clk;
int ret = -ENOMEM;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
}
musb = platform_device_alloc("musb-hdrc", -1);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1;
}
clk = clk_get(&pdev->dev, "usb");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk);
goto err2;
}
ret = clk_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
goto err3;
}
musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &davinci_dmamask;
musb->dev.coherent_dma_mask = davinci_dmamask;
glue->dev = &pdev->dev;
glue->musb = musb;
glue->clk = clk;
pdata->platform_ops = &davinci_ops;
platform_set_drvdata(pdev, glue);
ret = platform_device_add_resources(musb, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto err4;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
goto err4;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
goto err4;
}
return 0;
err4:
clk_disable(clk);
err3:
clk_put(clk);
err2:
platform_device_put(musb);
err1:
kfree(glue);
err0:
return ret;
}
static int __exit davinci_remove(struct platform_device *pdev)
{
struct davinci_glue *glue = platform_get_drvdata(pdev);
platform_device_del(glue->musb);
platform_device_put(glue->musb);
clk_disable(glue->clk);
clk_put(glue->clk);
kfree(glue);
return 0;
}
static struct platform_driver davinci_driver = {
.remove = __exit_p(davinci_remove),
.driver = {
.name = "musb-davinci",
},
};
MODULE_DESCRIPTION("DaVinci MUSB Glue Layer");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("GPL v2");
static int __init davinci_init(void)
{
return platform_driver_probe(&davinci_driver, davinci_probe);
}
subsys_initcall(davinci_init);
static void __exit davinci_exit(void)
{
platform_driver_unregister(&davinci_driver);
}
module_exit(davinci_exit);

View File

@ -99,19 +99,8 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#ifdef CONFIG_ARM
#include <mach/hardware.h>
#include <mach/memory.h>
#include <asm/mach-types.h>
#endif
#include "musb_core.h"
#ifdef CONFIG_ARCH_DAVINCI
#include "davinci.h"
#endif
#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
@ -126,7 +115,7 @@ MODULE_PARM_DESC(debug, "Debug message level. Default = 0");
#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
#define MUSB_DRIVER_NAME "musb_hdrc"
#define MUSB_DRIVER_NAME "musb-hdrc"
const char musb_driver_name[] = MUSB_DRIVER_NAME;
MODULE_DESCRIPTION(DRIVER_INFO);
@ -230,7 +219,7 @@ static struct otg_io_access_ops musb_ulpi_access = {
/*-------------------------------------------------------------------------*/
#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN)
/*
* Load an endpoint's FIFO
@ -390,7 +379,7 @@ void musb_otg_timer_func(unsigned long data)
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
musb_set_vbus(musb, 0);
musb_platform_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
@ -571,7 +560,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->ep0_stage = MUSB_EP0_START;
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
musb_set_vbus(musb, 1);
musb_platform_set_vbus(musb, 1);
handled = IRQ_HANDLED;
}
@ -642,7 +631,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
/* go through A_WAIT_VFALL then start a new session */
if (!ignore)
musb_set_vbus(musb, 0);
musb_platform_set_vbus(musb, 0);
handled = IRQ_HANDLED;
}
@ -1049,8 +1038,6 @@ static void musb_shutdown(struct platform_device *pdev)
spin_lock_irqsave(&musb->lock, flags);
musb_platform_disable(musb);
musb_generic_disable(musb);
if (musb->clock)
clk_put(musb->clock);
spin_unlock_irqrestore(&musb->lock, flags);
if (!is_otg_enabled(musb) && is_host_enabled(musb))
@ -1074,10 +1061,11 @@ static void musb_shutdown(struct platform_device *pdev)
* We don't currently use dynamic fifo setup capability to do anything
* more than selecting one of a bunch of predefined configurations.
*/
#if defined(CONFIG_USB_TUSB6010) || \
defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
|| defined(CONFIG_ARCH_OMAP4)
#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_OMAP2PLUS) \
|| defined(CONFIG_USB_MUSB_AM35X)
static ushort __initdata fifo_mode = 4;
#elif defined(CONFIG_USB_MUSB_UX500)
static ushort __initdata fifo_mode = 5;
#else
static ushort __initdata fifo_mode = 2;
#endif
@ -1501,7 +1489,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
struct musb_hw_ep *hw_ep = musb->endpoints + i;
hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
#ifdef CONFIG_USB_TUSB6010
#ifdef CONFIG_USB_MUSB_TUSB6010
hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
hw_ep->fifo_sync_va =
@ -1548,7 +1536,8 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
defined(CONFIG_ARCH_OMAP4)
defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \
defined(CONFIG_ARCH_U5500)
static irqreturn_t generic_interrupt(int irq, void *__hci)
{
@ -1904,6 +1893,7 @@ allocate_instance(struct device *dev,
}
musb->controller = dev;
return musb;
}
@ -2000,30 +1990,14 @@ bad_config:
spin_lock_init(&musb->lock);
musb->board_mode = plat->mode;
musb->board_set_power = plat->set_power;
musb->set_clock = plat->set_clock;
musb->min_power = plat->min_power;
/* Clock usage is chip-specific ... functional clock (DaVinci,
* OMAP2430), or PHY ref (some TUSB6010 boards). All this core
* code does is make sure a clock handle is available; platform
* code manages it during start/stop and suspend/resume.
*/
if (plat->clock) {
musb->clock = clk_get(dev, plat->clock);
if (IS_ERR(musb->clock)) {
status = PTR_ERR(musb->clock);
musb->clock = NULL;
goto fail1;
}
}
musb->ops = plat->platform_ops;
/* The musb_platform_init() call:
* - adjusts musb->mregs and musb->isr if needed,
* - may initialize an integrated tranceiver
* - initializes musb->xceiv, usually by otg_get_transceiver()
* - activates clocks.
* - stops powering VBUS
* - assigns musb->board_set_vbus if host mode is enabled
*
* There are various transciever configurations. Blackfin,
* DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
@ -2031,9 +2005,9 @@ bad_config:
* isp1504, non-OTG, etc) mostly hooking up through ULPI.
*/
musb->isr = generic_interrupt;
status = musb_platform_init(musb, plat->board_data);
status = musb_platform_init(musb);
if (status < 0)
goto fail2;
goto fail1;
if (!musb->isr) {
status = -ENODEV;
@ -2186,10 +2160,6 @@ fail3:
device_init_wakeup(dev, 0);
musb_platform_exit(musb);
fail2:
if (musb->clock)
clk_put(musb->clock);
fail1:
dev_err(musb->controller,
"musb_init_controller failed with status %d\n", status);
@ -2215,7 +2185,7 @@ static u64 *orig_dma_mask;
static int __init musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int irq = platform_get_irq(pdev, 0);
int irq = platform_get_irq_byname(pdev, "mc");
int status;
struct resource *iomem;
void __iomem *base;
@ -2265,144 +2235,138 @@ static int __exit musb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static struct musb_context_registers musb_context;
void musb_save_context(struct musb *musb)
static void musb_save_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
void __iomem *epio;
if (is_host_enabled(musb)) {
musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
musb_context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
}
musb_context.power = musb_readb(musb_base, MUSB_POWER);
musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
musb_context.index = musb_readb(musb_base, MUSB_INDEX);
musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
musb->context.power = musb_readb(musb_base, MUSB_POWER);
musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
musb->context.index = musb_readb(musb_base, MUSB_INDEX);
musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
for (i = 0; i < musb->config->num_eps; ++i) {
epio = musb->endpoints[i].regs;
musb_context.index_regs[i].txmaxp =
musb->context.index_regs[i].txmaxp =
musb_readw(epio, MUSB_TXMAXP);
musb_context.index_regs[i].txcsr =
musb->context.index_regs[i].txcsr =
musb_readw(epio, MUSB_TXCSR);
musb_context.index_regs[i].rxmaxp =
musb->context.index_regs[i].rxmaxp =
musb_readw(epio, MUSB_RXMAXP);
musb_context.index_regs[i].rxcsr =
musb->context.index_regs[i].rxcsr =
musb_readw(epio, MUSB_RXCSR);
if (musb->dyn_fifo) {
musb_context.index_regs[i].txfifoadd =
musb->context.index_regs[i].txfifoadd =
musb_read_txfifoadd(musb_base);
musb_context.index_regs[i].rxfifoadd =
musb->context.index_regs[i].rxfifoadd =
musb_read_rxfifoadd(musb_base);
musb_context.index_regs[i].txfifosz =
musb->context.index_regs[i].txfifosz =
musb_read_txfifosz(musb_base);
musb_context.index_regs[i].rxfifosz =
musb->context.index_regs[i].rxfifosz =
musb_read_rxfifosz(musb_base);
}
if (is_host_enabled(musb)) {
musb_context.index_regs[i].txtype =
musb->context.index_regs[i].txtype =
musb_readb(epio, MUSB_TXTYPE);
musb_context.index_regs[i].txinterval =
musb->context.index_regs[i].txinterval =
musb_readb(epio, MUSB_TXINTERVAL);
musb_context.index_regs[i].rxtype =
musb->context.index_regs[i].rxtype =
musb_readb(epio, MUSB_RXTYPE);
musb_context.index_regs[i].rxinterval =
musb->context.index_regs[i].rxinterval =
musb_readb(epio, MUSB_RXINTERVAL);
musb_context.index_regs[i].txfunaddr =
musb->context.index_regs[i].txfunaddr =
musb_read_txfunaddr(musb_base, i);
musb_context.index_regs[i].txhubaddr =
musb->context.index_regs[i].txhubaddr =
musb_read_txhubaddr(musb_base, i);
musb_context.index_regs[i].txhubport =
musb->context.index_regs[i].txhubport =
musb_read_txhubport(musb_base, i);
musb_context.index_regs[i].rxfunaddr =
musb->context.index_regs[i].rxfunaddr =
musb_read_rxfunaddr(musb_base, i);
musb_context.index_regs[i].rxhubaddr =
musb->context.index_regs[i].rxhubaddr =
musb_read_rxhubaddr(musb_base, i);
musb_context.index_regs[i].rxhubport =
musb->context.index_regs[i].rxhubport =
musb_read_rxhubport(musb_base, i);
}
}
musb_platform_save_context(musb, &musb_context);
}
void musb_restore_context(struct musb *musb)
static void musb_restore_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
void __iomem *ep_target_regs;
void __iomem *epio;
musb_platform_restore_context(musb, &musb_context);
if (is_host_enabled(musb)) {
musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
musb_write_ulpi_buscontrol(musb->mregs, musb_context.busctl);
musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
}
musb_writeb(musb_base, MUSB_POWER, musb_context.power);
musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl);
musb_writeb(musb_base, MUSB_POWER, musb->context.power);
musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
for (i = 0; i < musb->config->num_eps; ++i) {
epio = musb->endpoints[i].regs;
musb_writew(epio, MUSB_TXMAXP,
musb_context.index_regs[i].txmaxp);
musb->context.index_regs[i].txmaxp);
musb_writew(epio, MUSB_TXCSR,
musb_context.index_regs[i].txcsr);
musb->context.index_regs[i].txcsr);
musb_writew(epio, MUSB_RXMAXP,
musb_context.index_regs[i].rxmaxp);
musb->context.index_regs[i].rxmaxp);
musb_writew(epio, MUSB_RXCSR,
musb_context.index_regs[i].rxcsr);
musb->context.index_regs[i].rxcsr);
if (musb->dyn_fifo) {
musb_write_txfifosz(musb_base,
musb_context.index_regs[i].txfifosz);
musb->context.index_regs[i].txfifosz);
musb_write_rxfifosz(musb_base,
musb_context.index_regs[i].rxfifosz);
musb->context.index_regs[i].rxfifosz);
musb_write_txfifoadd(musb_base,
musb_context.index_regs[i].txfifoadd);
musb->context.index_regs[i].txfifoadd);
musb_write_rxfifoadd(musb_base,
musb_context.index_regs[i].rxfifoadd);
musb->context.index_regs[i].rxfifoadd);
}
if (is_host_enabled(musb)) {
musb_writeb(epio, MUSB_TXTYPE,
musb_context.index_regs[i].txtype);
musb->context.index_regs[i].txtype);
musb_writeb(epio, MUSB_TXINTERVAL,
musb_context.index_regs[i].txinterval);
musb->context.index_regs[i].txinterval);
musb_writeb(epio, MUSB_RXTYPE,
musb_context.index_regs[i].rxtype);
musb->context.index_regs[i].rxtype);
musb_writeb(epio, MUSB_RXINTERVAL,
musb_context.index_regs[i].rxinterval);
musb->context.index_regs[i].rxinterval);
musb_write_txfunaddr(musb_base, i,
musb_context.index_regs[i].txfunaddr);
musb->context.index_regs[i].txfunaddr);
musb_write_txhubaddr(musb_base, i,
musb_context.index_regs[i].txhubaddr);
musb->context.index_regs[i].txhubaddr);
musb_write_txhubport(musb_base, i,
musb_context.index_regs[i].txhubport);
musb->context.index_regs[i].txhubport);
ep_target_regs =
musb_read_target_reg_base(i, musb_base);
musb_write_rxfunaddr(ep_target_regs,
musb_context.index_regs[i].rxfunaddr);
musb->context.index_regs[i].rxfunaddr);
musb_write_rxhubaddr(ep_target_regs,
musb_context.index_regs[i].rxhubaddr);
musb->context.index_regs[i].rxhubaddr);
musb_write_rxhubport(ep_target_regs,
musb_context.index_regs[i].rxhubport);
musb->context.index_regs[i].rxhubport);
}
}
}
@ -2413,9 +2377,6 @@ static int musb_suspend(struct device *dev)
unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev);
if (!musb->clock)
return 0;
spin_lock_irqsave(&musb->lock, flags);
if (is_peripheral_active(musb)) {
@ -2430,10 +2391,6 @@ static int musb_suspend(struct device *dev)
musb_save_context(musb);
if (musb->set_clock)
musb->set_clock(musb->clock, 0);
else
clk_disable(musb->clock);
spin_unlock_irqrestore(&musb->lock, flags);
return 0;
}
@ -2443,14 +2400,6 @@ static int musb_resume_noirq(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct musb *musb = dev_to_musb(&pdev->dev);
if (!musb->clock)
return 0;
if (musb->set_clock)
musb->set_clock(musb->clock, 1);
else
clk_enable(musb->clock);
musb_restore_context(musb);
/* for static cmos like DaVinci, register values were preserved

View File

@ -222,7 +222,7 @@ enum musb_g_ep0_state {
#endif
/* TUSB mapping: "flat" plus ep0 special cases */
#if defined(CONFIG_USB_TUSB6010)
#if defined(CONFIG_USB_MUSB_TUSB6010)
#define musb_ep_select(_mbase, _epnum) \
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
@ -253,6 +253,29 @@ enum musb_g_ep0_state {
/******************************** TYPES *************************************/
/**
* struct musb_platform_ops - Operations passed to musb_core by HW glue layer
* @init: turns on clocks, sets up platform-specific registers, etc
* @exit: undoes @init
* @set_mode: forcefully changes operating mode
* @try_ilde: tries to idle the IP
* @vbus_status: returns vbus status if possible
* @set_vbus: forces vbus status
*/
struct musb_platform_ops {
int (*init)(struct musb *musb);
int (*exit)(struct musb *musb);
void (*enable)(struct musb *musb);
void (*disable)(struct musb *musb);
int (*set_mode)(struct musb *musb, u8 mode);
void (*try_idle)(struct musb *musb, unsigned long timeout);
int (*vbus_status)(struct musb *musb);
void (*set_vbus)(struct musb *musb, int on);
};
/*
* struct musb_hw_ep - endpoint hardware (bidirectional)
*
@ -263,7 +286,7 @@ struct musb_hw_ep {
void __iomem *fifo;
void __iomem *regs;
#ifdef CONFIG_USB_TUSB6010
#ifdef CONFIG_USB_MUSB_TUSB6010
void __iomem *conf;
#endif
@ -280,7 +303,7 @@ struct musb_hw_ep {
struct dma_channel *tx_channel;
struct dma_channel *rx_channel;
#ifdef CONFIG_USB_TUSB6010
#ifdef CONFIG_USB_MUSB_TUSB6010
/* TUSB has "asynchronous" and "synchronous" dma modes */
dma_addr_t fifo_async;
dma_addr_t fifo_sync;
@ -323,14 +346,43 @@ static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep)
#endif
}
struct musb_csr_regs {
/* FIFO registers */
u16 txmaxp, txcsr, rxmaxp, rxcsr;
u16 rxfifoadd, txfifoadd;
u8 txtype, txinterval, rxtype, rxinterval;
u8 rxfifosz, txfifosz;
u8 txfunaddr, txhubaddr, txhubport;
u8 rxfunaddr, rxhubaddr, rxhubport;
};
struct musb_context_registers {
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
defined(CONFIG_ARCH_OMAP4)
u32 otg_sysconfig, otg_forcestandby;
#endif
u8 power;
u16 intrtxe, intrrxe;
u8 intrusbe;
u16 frame;
u8 index, testmode;
u8 devctl, busctl, misc;
struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
};
/*
* struct musb - Driver instance data.
*/
struct musb {
/* device lock */
spinlock_t lock;
struct clk *clock;
struct clk *phy_clock;
const struct musb_platform_ops *ops;
struct musb_context_registers context;
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
u16 hwvers;
@ -359,11 +411,7 @@ struct musb {
struct timer_list otg_timer;
#endif
/* called with IRQs blocked; ON/nonzero implies starting a session,
* and waiting at least a_wait_vrise_tmout.
*/
void (*board_set_vbus)(struct musb *, int is_on);
struct notifier_block nb;
struct dma_controller *dma_controller;
@ -371,7 +419,7 @@ struct musb {
void __iomem *ctrl_base;
void __iomem *mregs;
#ifdef CONFIG_USB_TUSB6010
#ifdef CONFIG_USB_MUSB_TUSB6010
dma_addr_t async;
dma_addr_t sync;
void __iomem *sync_va;
@ -398,8 +446,6 @@ struct musb {
u8 board_mode; /* enum musb_mode */
int (*board_set_power)(int state);
int (*set_clock)(struct clk *clk, int is_active);
u8 min_power; /* vbus for periph, in mA/2 */
bool is_host;
@ -458,52 +504,6 @@ struct musb {
#endif
};
#ifdef CONFIG_PM
struct musb_csr_regs {
/* FIFO registers */
u16 txmaxp, txcsr, rxmaxp, rxcsr;
u16 rxfifoadd, txfifoadd;
u8 txtype, txinterval, rxtype, rxinterval;
u8 rxfifosz, txfifosz;
u8 txfunaddr, txhubaddr, txhubport;
u8 rxfunaddr, rxhubaddr, rxhubport;
};
struct musb_context_registers {
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
defined(CONFIG_ARCH_OMAP4)
u32 otg_sysconfig, otg_forcestandby;
#endif
u8 power;
u16 intrtxe, intrrxe;
u8 intrusbe;
u16 frame;
u8 index, testmode;
u8 devctl, busctl, misc;
struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
};
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
defined(CONFIG_ARCH_OMAP4)
extern void musb_platform_save_context(struct musb *musb,
struct musb_context_registers *musb_context);
extern void musb_platform_restore_context(struct musb *musb,
struct musb_context_registers *musb_context);
#else
#define musb_platform_save_context(m, x) do {} while (0)
#define musb_platform_restore_context(m, x) do {} while (0)
#endif
#endif
static inline void musb_set_vbus(struct musb *musb, int is_on)
{
musb->board_set_vbus(musb, is_on);
}
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
static inline struct musb *gadget_to_musb(struct usb_gadget *g)
{
@ -592,29 +592,63 @@ extern void musb_load_testpacket(struct musb *);
extern irqreturn_t musb_interrupt(struct musb *);
extern void musb_platform_enable(struct musb *musb);
extern void musb_platform_disable(struct musb *musb);
extern void musb_hnp_stop(struct musb *musb);
extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
{
if (musb->ops->set_vbus)
musb->ops->set_vbus(musb, is_on);
}
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
defined(CONFIG_ARCH_DAVINCI_DA8XX) || \
defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
defined(CONFIG_ARCH_OMAP4)
extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
#else
#define musb_platform_try_idle(x, y) do {} while (0)
#endif
static inline void musb_platform_enable(struct musb *musb)
{
if (musb->ops->enable)
musb->ops->enable(musb);
}
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN)
extern int musb_platform_get_vbus_status(struct musb *musb);
#else
#define musb_platform_get_vbus_status(x) 0
#endif
static inline void musb_platform_disable(struct musb *musb)
{
if (musb->ops->disable)
musb->ops->disable(musb);
}
extern int __init musb_platform_init(struct musb *musb, void *board_data);
extern int musb_platform_exit(struct musb *musb);
static inline int musb_platform_set_mode(struct musb *musb, u8 mode)
{
if (!musb->ops->set_mode)
return 0;
return musb->ops->set_mode(musb, mode);
}
static inline void musb_platform_try_idle(struct musb *musb,
unsigned long timeout)
{
if (musb->ops->try_idle)
musb->ops->try_idle(musb, timeout);
}
static inline int musb_platform_get_vbus_status(struct musb *musb)
{
if (!musb->ops->vbus_status)
return 0;
return musb->ops->vbus_status(musb);
}
static inline int musb_platform_init(struct musb *musb)
{
if (!musb->ops->init)
return -EINVAL;
return musb->ops->init(musb);
}
static inline int musb_platform_exit(struct musb *musb)
{
if (!musb->ops->exit)
return -EINVAL;
return musb->ops->exit(musb);
}
#endif /* __MUSB_CORE_H__ */

View File

@ -1136,13 +1136,16 @@ struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
struct musb_request *request = NULL;
request = kzalloc(sizeof *request, gfp_flags);
if (request) {
INIT_LIST_HEAD(&request->request.list);
request->request.dma = DMA_ADDR_INVALID;
request->epnum = musb_ep->current_epnum;
request->ep = musb_ep;
if (!request) {
DBG(4, "not enough memory\n");
return NULL;
}
INIT_LIST_HEAD(&request->request.list);
request->request.dma = DMA_ADDR_INVALID;
request->epnum = musb_ep->current_epnum;
request->ep = musb_ep;
return &request->request;
}

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