The first version of the driver was published on the
linux-usb-devel
mailing list on Jan 3, 2005.
By now the driver is included in the 2.6.13 and later
mainline kernels. A
version for the 2.6.10
and a
version for the 2.6.12
kernels are downloadable. These driver versions are not
maintained; I have no intention to backport
fixes or improvements to these past versions.
Also, I have no plans to put
up a driver for 2.6.11. If you happen to need to backport
from a newer driver version then please be aware that
through these kernel versions extensive USB core changes
were made, which affected host controller drivers.
I.e., USB host controller glue layer changed incompatibly
from 2.6.10 to 2.6.11 as well as from 2.6.11 to 2.6.12.
Known bugs
Power switching of ports does not work.
To avoid this bug, the ports should be always powered. I.e.,
in your platform-specific code you should define
no_power_switching = 1
Platform support code
Here are a few recommendations about setting the members of the
struct isp116x_platform_data , which you must
define and initialize to reflect specifics of your platform.
As a rule, set a struct member iff you know you need to set it.
-
int_act_high, int_edge_triggered
- Whenever your
platform supports level-triggered interrupts, use these.
Success with configuring level-triggered interrupts has
been reported even on platforms, which don‘t
support level-triggered interrupts, but for which the
166 ns edge-triggered interrupt pulse is too short to
be detected (like PXA255 SoC).
-
no_power_switching
- Set this to 1 to avoid a bug in the driver.
-
reset
- It has been recommended in the past to implement and use
hardware reset as it is more thorough than the software
reset. However, recently the software reset has been working
too. Set it to NULL to use software reset.
-
clock
- This hasn‘t been tested at all. Set to NULL.
-
delay
- Read CAREFULLY the comments in
both
include/linux/usb_isp116x.h and
drivers/usb/host/isp116x-hcd.c as wrong choice
of the delay type or an incorrect implementation
of the platform-specific delay function is the major source
of problems when trying to get the driver working.
Here is an example platform code I used on my LH7A400
(a SoC with an ARM core) based boards; in my case it went
into arch/arm/mach-lh7a40x/arch-lpd7a40x.c file.
#include <linux/usb_isp116x.h>
/* GPIO port A bit 2 is hardware reset for isp116x */
#define ISP116x_RESET_PORT GPIO_PAD
#define ISP116x_RESET_DIR_PORT GPIO_PADD
#define ISP116x_RESET_BIT (1<<2)
/* Hardware reset */
static void isp116x_pfm_reset(struct device *dev, int set)
{
unsigned long flags;
local_irq_save(flags);
if (set) {
ISP116x_RESET_PORT &= ~ISP116x_RESET_BIT;
barrier();
ISP116x_RESET_DIR_PORT |= ISP116x_RESET_BIT;
} else {
ISP116x_RESET_PORT |= ISP116x_RESET_BIT;
barrier();
ISP116x_RESET_DIR_PORT |= ISP116x_RESET_BIT;
}
local_irq_restore(flags);
}
/* Platform delay */
static void isp116x_pfm_delay(struct device *dev, int delay)
{
/* On this platform, we work with 200MHz clock, giving
5 ns per instruction. The cycle below involves 2
instructions and we lose 2 more instruction times due
to pipeline flush at jump. I.e., we consume 20 ns
per cycle.
*/
int cyc = delay / 20;
__asm__ volatile ("0:\n"
" subs %0, %1, #1\n"
" bge 0b\n"
:"=r" (cyc)
:"0"(cyc)
);
}
/* Define chip configuration */
static struct isp116x_platform_data isp116x_pfm_data = {
.sel15Kres = 1,
.remote_wakeup_enable = 1,
.no_power_switching = 1,
.reset = isp116x_pfm_reset,
.delay = isp116x_pfm_delay,
};
/* Define chip address and IRQ line */
static struct resource isp116x_pfm_resources[] = {
[0] = { /// data (A0 = 0)
.start = USB_IO_PHYS,
.end = USB_IO_PHYS + 1,
.flags = IORESOURCE_MEM,
},
[1] = { /// addr (A0 = 1)
.start = USB_IO_PHYS + 2,
.end = USB_IO_PHYS + 3,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_USB,
.end = IRQ_USB,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device isp116x_pfm_usbhost_device = {
.name = "isp116x-hcd",
.num_resources = ARRAY_SIZE(isp116x_pfm_resources),
.resource = isp116x_pfm_resources,
.dev.platform_data = &isp116x_pfm_data,
};
static struct platform_device *lpd7a40x_devs[] __initdata = {
...
&isp116x_pfm_usbhost_device,
};
|