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

Reply via email to