I've been experimenting with the OHCI interface on the Zaurus SL-C3000 (Spitz) and have found a few things I wouldn't mind opinions on.
Firstly, the NDP register in roothub.a on the PXA270 isn't standard and the number of ports is really the value of NDP+1. The chip supports three ports and whilst I don't have the third connected but it was confusing me when it only reported two! I've included a patch below which corrects this - I'm not sure if this is the right way to do it and am open to comments. There is a counting error in pxa27x_ohci_set_port_power() and pxa27x_ohci_clear_port_power() as port 3 can't be accessed. Also, pxa27x_ohci_clear_port_power() doesn't appear to do anything sane and accesses the wrong register bits. The patch below fixes them. I'm not sure these functions are even needed as doesn't the ohci driver handle this? Does the ohci driver require port power settings to be in a particular state before init? Maybe they can just be deleted? The driver currently assumes PMM_PERPORT_MODE and the patch alters it to be selected by the machine specific code. This machine specific code should probably be moved into the appropriate arch/arm/mach-pxa board drivers. If this is the preferred course of action, I'll write a patch to do this. I've included the spitz code for reference. The main difference is only a global power control is used and over current monitoring is disabled. There is logic to go into the board support file to control switching between host and udc mode. I think my hardware might support detection of the mode but I'm not sure how it will be possible to switch between the two drivers... Richard Index: linux-2.6.12/drivers/usb/host/ohci-dbg.c =================================================================== --- linux-2.6.12.orig/drivers/usb/host/ohci-dbg.c 2005-08-23 10:56:47.000000000 +0100 +++ linux-2.6.12/drivers/usb/host/ohci-dbg.c 2005-08-23 11:06:45.000000000 +0100 @@ -233,7 +233,7 @@ temp = roothub_a (controller); if (temp == ~(u32)0) return; - ndp = (temp & RH_A_NDP); + ndp = OHCI_GETPORTNUM(temp & RH_A_NDP); if (verbose) { ohci_dbg_sw (controller, next, size, Index: linux-2.6.12/drivers/usb/host/ohci-hcd.c =================================================================== --- linux-2.6.12.orig/drivers/usb/host/ohci-hcd.c 2005-08-23 10:56:47.000000000 +0100 +++ linux-2.6.12/drivers/usb/host/ohci-hcd.c 2005-08-23 11:16:55.000000000 +0100 @@ -561,7 +561,7 @@ msleep(temp); temp = roothub_a (ohci); if (!(temp & RH_A_NPS)) { - unsigned ports = temp & RH_A_NDP; + unsigned ports = OHCI_GETPORTNUM(temp); /* power down each port */ for (temp = 0; temp < ports; temp++) @@ -861,7 +861,7 @@ * and that if we try to turn them back on the root hub * will respond to CSC processing. */ - i = roothub_a (ohci) & RH_A_NDP; + i = OHCI_GETPORTNUM(roothub_a (ohci)); while (i--) ohci_writel (ohci, RH_PS_PSS, &ohci->regs->roothub.portstatus [temp]); Index: linux-2.6.12/drivers/usb/host/ohci-pxa27x.c =================================================================== --- linux-2.6.12.orig/drivers/usb/host/ohci-pxa27x.c 2005-08-23 10:56:47.000000000 +0100 +++ linux-2.6.12/drivers/usb/host/ohci-pxa27x.c 2005-08-23 10:58:16.000000000 +0100 @@ -23,6 +23,7 @@ #include <asm/mach-types.h> #include <asm/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/spitz.h> #define PMM_NPS_MODE 1 @@ -81,7 +82,7 @@ static int pxa27x_ohci_set_port_power( int port ) { if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE) - && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) { + && (port>0) && (port<=PXA_UHC_MAX_PORTNUM) ) { UHCRHPS(port) |= 0x100; return 0; } @@ -94,8 +95,8 @@ static int pxa27x_ohci_clear_port_power( int port ) { if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE) - && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) { - UHCRHPS(port) |= 0x200; + && (port>0) && (port<=PXA_UHC_MAX_PORTNUM) ) { + UHCRHPS(port) &= ~0x100; return 0; } @@ -130,11 +131,35 @@ Polarity Low to active low. Supply power to USB ports. */ UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) & ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); + + pxa27x_ohci_pmm_state=PMM_PERPORT_MODE; + } + if (machine_is_spitz()) { + /* Only Port 2 is connected */ + pxa_gpio_mode(SPITZ_GPIO_USB_CONNECT | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_USB_HOST | GPIO_OUT); + pxa_gpio_mode(SPITZ_GPIO_USB_DEVICE | GPIO_IN); + + /* Setup USB Port 2 Output Control Register */ + UP2OCR = UP2OCR_HXS | UP2OCR_HXOE | UP2OCR_DPPDE | UP2OCR_DMPDE; + + GPSR(SPITZ_GPIO_USB_HOST) = GPIO_bit(SPITZ_GPIO_USB_HOST); + + UHCHR = (UHCHR) & + ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); + + UHCRHDA |= RH_A_NOCP; + + pxa27x_ohci_pmm_state=PMM_NPS_MODE; } UHCHR &= ~UHCHR_SSE; UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE); + + /* Clear any OTG Pin Hold */ + if (PSSR & PSSR_OTGPH) + PSSR |= PSSR_OTGPH; } static void pxa27x_stop_hc(struct platform_device *dev) @@ -198,17 +223,19 @@ pxa27x_start_hc(dev); /* Select Power Management Mode */ - pxa27x_ohci_select_pmm( PMM_PERPORT_MODE ); + pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state); - /* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */ - if (pxa27x_ohci_set_port_power(1) < 0) - printk(KERN_ERR "Setting port 1 power failed.\n"); + if (pxa27x_ohci_pmm_state == PMM_PERPORT_MODE) { + /* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */ + if (pxa27x_ohci_set_port_power(1) < 0) + printk(KERN_ERR "Setting port 1 power failed.\n"); - if (pxa27x_ohci_clear_port_power(2) < 0) - printk(KERN_ERR "Setting port 2 power failed.\n"); + if (pxa27x_ohci_set_port_power(2) < 0) + printk(KERN_ERR "Setting port 2 power failed.\n"); - if (pxa27x_ohci_clear_port_power(3) < 0) - printk(KERN_ERR "Setting port 3 power failed.\n"); + if (pxa27x_ohci_set_port_power(3) < 0) + printk(KERN_ERR "Setting port 3 power failed.\n"); + } ohci_hcd_init(hcd_to_ohci(hcd)); Index: linux-2.6.12/drivers/usb/host/ohci-hub.c =================================================================== --- linux-2.6.12.orig/drivers/usb/host/ohci-hub.c 2005-08-16 17:00:48.000000000 +0100 +++ linux-2.6.12/drivers/usb/host/ohci-hub.c 2005-08-23 11:05:35.000000000 +0100 @@ -184,7 +184,7 @@ if (status != -EINPROGRESS) return status; - temp = roothub_a (ohci) & RH_A_NDP; + temp = OHCI_GETPORTNUM(roothub_a (ohci)); enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, @@ -319,10 +319,10 @@ goto done; } - ports = roothub_a (ohci) & RH_A_NDP; + ports = OHCI_GETPORTNUM(roothub_a (ohci)); if (ports > MAX_ROOT_PORTS) { ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports, - ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); + OHCI_GETPORTNUM(ohci_readl (ohci, &ohci->regs->roothub.a))); /* retry later; "should not happen" */ goto done; } @@ -395,7 +395,7 @@ struct usb_hub_descriptor *desc ) { u32 rh = roothub_a (ohci); - int ports = rh & RH_A_NDP; + int ports = OHCI_GETPORTNUM(rh); u16 temp; desc->bDescriptorType = 0x29; Index: linux-2.6.12/drivers/usb/host/ohci.h =================================================================== --- linux-2.6.12.orig/drivers/usb/host/ohci.h 2005-08-21 22:27:56.000000000 +0100 +++ linux-2.6.12/drivers/usb/host/ohci.h 2005-08-23 11:03:59.000000000 +0100 @@ -321,6 +321,11 @@ #define RH_A_NOCP (1 << 12) /* no over current protection */ #define RH_A_POTPGT (0xff << 24) /* power on to power good time */ +#ifdef CONFIG_PXA27x +#define OHCI_GETPORTNUM(x) ((x & RH_A_NDP) + 1) +#else +#define OHCI_GETPORTNUM(x) (x & RH_A_NDP) +#endif /* hcd-private per-urb state */ typedef struct urb_priv { ------------------------------------------------------- SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel