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

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (144 commits)
  USB: add support for Dream Cheeky DL100B Webmail Notifier (1d34:0004)
  USB: serial: ftdi_sio: add support for TIOCSERGETLSR
  USB: ehci-mxc: Setup portsc register prior to accessing OTG viewport
  USB: atmel_usba_udc: fix freeing irq in usba_udc_remove()
  usb: ehci-omap: fix tll channel enable mask
  usb: ohci-omap3: fix trivial typo
  USB: gadget: ci13xxx: don't assume that PAGE_SIZE is 4096
  USB: gadget: ci13xxx: fix complete() callback for no_interrupt rq's
  USB: gadget: update ci13xxx to work with g_ether
  USB: gadgets: ci13xxx: fix probing of compiled-in gadget drivers
  Revert "USB: musb: pm: don't rely fully on clock support"
  Revert "USB: musb: blackfin: pm: make it work"
  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
  ...

Manually fix up trivial conflicts in USB Kconfig changes in:
	arch/arm/mach-omap2/Kconfig
	arch/sh/Kconfig
	drivers/usb/Kconfig
	drivers/usb/host/ehci-hcd.c
and annoying chip clock data conflicts in:
	arch/arm/mach-omap2/clock3xxx_data.c
	arch/arm/mach-omap2/clock44xx_data.c
This commit is contained in:
Linus Torvalds 2011-01-07 13:16:28 -08:00
commit 3e5b08cbbf
136 changed files with 15410 additions and 2020 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

@ -48,6 +48,7 @@ config ARCH_OMAP4
select ARM_ERRATA_720789
select ARCH_HAS_OPP
select PM_OPP if PM
select USB_ARCH_HAS_EHCI
comment "OMAP Core Type"
depends on ARCH_OMAP2

View File

@ -209,9 +209,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

@ -44,6 +44,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
@ -250,12 +251,29 @@ static void __init omap_4430sdp_init_irq(void)
gic_init_irq();
}
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.phy_reset = false,
.reset_gpio_port[0] = -EINVAL,
.reset_gpio_port[1] = -EINVAL,
.reset_gpio_port[2] = -EINVAL,
};
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_UTMI,
.mode = MUSB_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,
@ -475,6 +493,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[] = {
@ -555,10 +574,14 @@ 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())
/* 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();

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 @@ static void __init n8x0_usb_init(void)
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

@ -134,10 +134,17 @@ static void __init omap4_ehci_init(void)
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,
@ -347,6 +354,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[] = {
@ -394,8 +402,6 @@ 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);
}

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

@ -3286,6 +3286,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "usbtll_fck", &usbtll_fck, CK_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),
@ -3313,14 +3314,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_3430ES2PLUS | CK_36XX),
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_3430ES2PLUS | CK_36XX),
CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1, CK_3430ES1),
CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2, CK_3430ES2PLUS | CK_36XX),
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_34XX | CK_36XX),
CLK(NULL, "pka_ick", &pka_ick, CK_34XX | CK_36XX),
CLK(NULL, "core_l4_ick", &core_l4_ick, CK_3XXX),
CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "icr_ick", &icr_ick, CK_34XX | CK_36XX),
CLK("omap-aes", "ick", &aes2_ick, CK_34XX | CK_36XX),
@ -3366,8 +3368,11 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cam_ick", &cam_ick, CK_34XX | CK_36XX),
CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_34XX | CK_36XX),
CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "hs_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "fs_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("ehci-omap.0", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2PLUS | CK_36XX),
CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX),
CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX),
@ -3445,8 +3450,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

@ -3198,6 +3198,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, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X),
CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk, CK_443X),
CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk, CK_443X),
@ -3209,14 +3210,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

@ -224,7 +224,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

@ -349,6 +349,7 @@ config CPU_SUBTYPE_SH7720
select CPU_HAS_DSP
select SYS_SUPPORTS_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_ARCH_HAS_OHCI
help
Select SH7720 if you have a SH3-DSP SH7720 CPU.
@ -357,6 +358,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.
@ -437,6 +439,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.
@ -463,6 +466,8 @@ config CPU_SUBTYPE_SH7786
select CPU_HAS_PTEAEX
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_WANT_OPTIONAL_GPIOLIB
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

@ -1604,6 +1604,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },

View File

@ -200,6 +200,8 @@
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
#define USB_VENDOR_ID_ELO 0x04E7
#define USB_DEVICE_ID_ELO_TS2700 0x0020

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

@ -42,17 +42,13 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_W90X900
default y if ARCH_DAVINCI_DA8XX
default y if ARCH_CNS3XXX
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
@ -68,6 +64,9 @@ config USB_ARCH_HAS_EHCI
default y if ARCH_MXC
default y if ARCH_OMAP3
default y if ARCH_CNS3XXX
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;
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. */
return status;
}
static int usb_runtime_resume(struct device *dev)
{
/* 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;
/* Runtime resume for a USB device means resuming both the device
* and all its interfaces.
*/
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;
}
static int usb_runtime_idle(struct 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.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)
return 0;
}
pm_runtime_suspend(dev);
/* An idle USB device can be suspended if it passes the various
* autosuspend checks.
*/
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 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
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

@ -2057,8 +2057,10 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
usba_ep_cleanup_debugfs(&usba_ep[i]);
usba_cleanup_debugfs(udc);
if (gpio_is_valid(udc->vbus_pin))
if (gpio_is_valid(udc->vbus_pin)) {
free_irq(gpio_to_irq(udc->vbus_pin), udc);
gpio_free(udc->vbus_pin);
}
free_irq(udc->irq, udc);
kfree(usba_ep);

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
@ -1449,7 +1460,7 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
mReq->ptr->page[0] = mReq->req.dma;
for (i = 1; i < 5; i++)
mReq->ptr->page[i] =
(mReq->req.dma + i * PAGE_SIZE) & ~TD_RESERVED_MASK;
(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
/*
* QH configuration
@ -1540,7 +1551,7 @@ __acquires(mEp->lock)
list_del_init(&mReq->queue);
mReq->req.status = -ESHUTDOWN;
if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
@ -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;
@ -1789,18 +1794,20 @@ __acquires(mEp->lock)
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
if (!list_empty(&mEp->qh[mEp->dir].queue)) {
struct ci13xxx_req* mReqEnq;
mReqEnq = list_entry(mEp->qh[mEp->dir].queue.next,
struct ci13xxx_req, queue);
_hardware_enqueue(mEp, mReqEnq);
}
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
}
if (!list_empty(&mEp->qh[mEp->dir].queue)) {
mReq = list_entry(mEp->qh[mEp->dir].queue.next,
struct ci13xxx_req, queue);
_hardware_enqueue(mEp, mReq);
}
done:
return retval;
}
@ -2061,7 +2068,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 +2076,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 +2090,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;
}
@ -2157,8 +2159,8 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
goto done;
}
if (req->length > (4 * PAGE_SIZE)) {
req->length = (4 * PAGE_SIZE);
if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
req->length = (4 * CI13XXX_PAGE_SIZE);
retval = -EMSGSIZE;
warn("request length truncated");
}
@ -2170,8 +2172,10 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
mReq->req.actual = 0;
list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue);
if (list_is_singular(&mEp->qh[mEp->dir].queue))
retval = _hardware_enqueue(mEp, mReq);
if (retval == -EALREADY || retval == -EBUSY) {
if (retval == -EALREADY) {
dbg_event(_usb_addr(mEp), "QUEUE", retval);
retval = 0;
}
@ -2209,7 +2213,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
list_del_init(&mReq->queue);
req->status = -ECONNRESET;
if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
@ -2332,12 +2336,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
@ -2358,7 +2397,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
if (driver == NULL ||
bind == NULL ||
driver->unbind == NULL ||
driver->setup == NULL ||
driver->disconnect == NULL ||
driver->suspend == NULL ||
@ -2372,13 +2410,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
/* alloc resources */
udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
sizeof(struct ci13xxx_qh),
64, PAGE_SIZE);
64, CI13XXX_PAGE_SIZE);
if (udc->qh_pool == NULL)
return -ENOMEM;
udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
sizeof(struct ci13xxx_td),
64, PAGE_SIZE);
64, CI13XXX_PAGE_SIZE);
if (udc->td_pool == NULL) {
dma_pool_destroy(udc->qh_pool);
udc->qh_pool = NULL;
@ -2390,7 +2428,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 +2447,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 +2468,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 +2475,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 +2525,22 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
spin_lock_irqsave(udc->lock, flags);
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);
udc->gadget.ops = NULL;
udc->gadget.dev.driver = NULL;
}
/* free resources */
for (i = 0; i < hw_ep_max; i++) {
@ -2544,6 +2597,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 +2663,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 +2680,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 = device_register(&udc->gadget.dev);
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 done;
goto put_transceiver;
}
retval = device_register(&udc->gadget.dev);
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 +2770,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 +2782,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

@ -19,6 +19,7 @@
/******************************************************************************
* DEFINE
*****************************************************************************/
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX (16)
#define CTRL_PAYLOAD_MAX (64)
#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */
@ -97,9 +98,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 +124,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 +176,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)
if (bcdDevice)
cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
/* 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 @@ static void dummy_timer (unsigned long _dum)
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 @@ static void dummy_timer (unsigned long _dum)
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
@ -1221,6 +1234,21 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER cns3xxx_ehci_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

@ -36,14 +36,8 @@ struct ehci_mxc_priv {
static int ehci_mxc_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct device *dev = hcd->self.controller;
struct mxc_usbh_platform_data *pdata = dev_get_platdata(dev);
int retval;
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@ -65,12 +59,6 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
ehci_reset(ehci);
/* set up the PORTSCx register */
ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
/* is this really needed? */
msleep(10);
ehci_port_power(ehci, 0);
return 0;
}
@ -100,6 +88,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 +104,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)
@ -125,6 +116,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
int irq, ret;
struct ehci_mxc_priv *priv;
struct device *dev = &pdev->dev;
struct ehci_hcd *ehci;
dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
@ -212,6 +204,19 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
if (ret < 0)
goto err_init;
ehci = hcd_to_ehci(hcd);
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
/* set up the PORTSCx register */
ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
/* is this really needed? */
msleep(10);
/* Initialize the transceiver */
if (pdata->otg) {
pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;

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>
@ -86,9 +90,9 @@
#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num)
#define OMAP_TLL_CHANNEL_COUNT 3
#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 1)
#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 2)
#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 4)
#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0)
#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1)
#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2)
/* UHH Register Set */
#define OMAP_UHH_REVISION (0x00)
@ -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);
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,6 +498,7 @@ 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 (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)
@ -386,30 +509,45 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
/* 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))
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 (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
if (is_ehci_phy_mode(omap->port_mode[0]))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
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)
if (is_ehci_phy_mode(omap->port_mode[1]))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
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)
if (is_ehci_phy_mode(omap->port_mode[2]))
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
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 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
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 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
}
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

@ -648,7 +648,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
ret = omap3_start_ohci(omap, hcd);
if (ret) {
dev_dbg(&pdev->dev, "failed to start ehci\n");
dev_dbg(&pdev->dev, "failed to start ohci\n");
goto err_start;
}

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

@ -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;
}

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

@ -1,5 +1,5 @@
/*
* USB LED driver - 1.1
* USB LED driver
*
* Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
*
@ -20,12 +20,17 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
#define DRIVER_DESC "USB LED Driver"
#define VENDOR_ID 0x0fc5
#define PRODUCT_ID 0x1223
enum led_type {
DELCOM_VISUAL_SIGNAL_INDICATOR,
DREAM_CHEEKY_WEBMAIL_NOTIFIER,
};
/* table of devices that work with this driver */
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
{ USB_DEVICE(0x0fc5, 0x1223),
.driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR },
{ USB_DEVICE(0x1d34, 0x0004),
.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
{ },
};
MODULE_DEVICE_TABLE (usb, id_table);
@ -35,15 +40,12 @@ struct usb_led {
unsigned char blue;
unsigned char red;
unsigned char green;
enum led_type type;
};
#define BLUE 0x04
#define RED 0x02
#define GREEN 0x01
static void change_color(struct usb_led *led)
{
int retval;
unsigned char color = 0x07;
unsigned char *buffer;
buffer = kmalloc(8, GFP_KERNEL);
@ -52,12 +54,16 @@ static void change_color(struct usb_led *led)
return;
}
switch (led->type) {
case DELCOM_VISUAL_SIGNAL_INDICATOR: {
unsigned char color = 0x07;
if (led->blue)
color &= ~(BLUE);
color &= ~0x04;
if (led->red)
color &= ~(RED);
color &= ~0x02;
if (led->green)
color &= ~(GREEN);
color &= ~0x01;
dev_dbg(&led->udev->dev,
"blue = %d, red = %d, green = %d, color = %.2x\n",
led->blue, led->red, led->green, color);
@ -71,6 +77,36 @@ static void change_color(struct usb_led *led)
buffer,
8,
2000);
break;
}
case DREAM_CHEEKY_WEBMAIL_NOTIFIER:
dev_dbg(&led->udev->dev,
"red = %d, green = %d, blue = %d\n",
led->red, led->green, led->blue);
buffer[0] = led->red;
buffer[1] = led->green;
buffer[2] = led->blue;
buffer[3] = buffer[4] = buffer[5] = 0;
buffer[6] = 0x1a;
buffer[7] = 0x05;
retval = usb_control_msg(led->udev,
usb_sndctrlpipe(led->udev, 0),
0x09,
0x21,
0x200,
0,
buffer,
8,
2000);
break;
default:
dev_err(&led->udev->dev, "unknown device type %d\n", led->type);
}
if (retval)
dev_dbg(&led->udev->dev, "retval = %d\n", retval);
kfree(buffer);
@ -107,11 +143,12 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "Out of memory\n");
dev_err(&interface->dev, "out of memory\n");
goto error_mem;
}
dev->udev = usb_get_dev(udev);
dev->type = id->driver_info;
usb_set_intfdata (interface, dev);
@ -125,6 +162,31 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
if (retval)
goto error;
if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) {
unsigned char *enable;
enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL);
if (!enable) {
dev_err(&interface->dev, "out of memory\n");
retval = -ENOMEM;
goto error;
}
retval = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
0x09,
0x21,
0x200,
0,
enable,
8,
2000);
kfree(enable);
if (retval != 8)
goto error;
}
dev_info(&interface->dev, "USB LED device now attached\n");
return 0;

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 @@ static irqreturn_t am35x_interrupt(int irq, void *hci)
/* 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 @@ static irqreturn_t am35x_interrupt(int irq, void *hci)
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,28 +311,28 @@ 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;
}
static void musb_platform_reg_init(struct musb *musb)
static void bfin_musb_reg_init(struct musb *musb)
{
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
@ -362,7 +370,7 @@ static void musb_platform_reg_init(struct musb *musb)
SSYNC();
}
int __init musb_platform_init(struct musb *musb, void *board_data)
static int bfin_musb_init(struct musb *musb)
{
/*
@ -386,25 +394,124 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
return -ENODEV;
}
musb_platform_reg_init(musb);
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;
}
#ifdef CONFIG_PM
void musb_platform_save_context(struct musb *musb,
struct musb_context_registers *musb_context)
static int bfin_musb_exit(struct musb *musb)
{
gpio_free(musb->config->gpio_vrsel);
otg_put_transceiver(musb->xceiv);
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
@ -413,20 +520,50 @@ void musb_platform_save_context(struct musb *musb,
* wakeup event.
*/
gpio_set_value(musb->config->gpio_vrsel, 0);
}
void musb_platform_restore_context(struct musb *musb,
struct musb_context_registers *musb_context)
{
musb_platform_reg_init(musb);
}
#endif
int musb_platform_exit(struct musb *musb)
{
gpio_free(musb->config->gpio_vrsel);
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
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)

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