Commit fe370205 authored by Juha Yrjola's avatar Juha Yrjola

OMAP: Fix USB on Nokia 770

Also removed unused ochi_omap_host_enable() function.
Signed-off-by: default avatarJuha Yrjola <juha.yrjola@solidboot.com>
parent 5c96881e
...@@ -3,7 +3,11 @@ ...@@ -3,7 +3,11 @@
* *
* Tahvo USB transeiver * Tahvo USB transeiver
* *
* Copyright (C) 2005 Nokia Corporation * Copyright (C) 2005-2006 Nokia Corporation
*
* Parts copied from drivers/i2c/chips/isp1301_omap.c
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2004 David Brownell
* *
* Written by Juha Yrjl <juha.yrjola@nokia.com>, * Written by Juha Yrjl <juha.yrjola@nokia.com>,
* Tony Lindgren <tony@atomide.com>, and * Tony Lindgren <tony@atomide.com>, and
...@@ -85,8 +89,6 @@ ...@@ -85,8 +89,6 @@
#define TAHVO_MODE(tu) TAHVO_MODE_HOST #define TAHVO_MODE(tu) TAHVO_MODE_HOST
#endif #endif
extern int ohci_omap_host_enable(struct usb_bus *host, int enable);
struct tahvo_usb { struct tahvo_usb {
struct platform_device *pt_dev; struct platform_device *pt_dev;
struct otg_transceiver otg; struct otg_transceiver otg;
...@@ -130,14 +132,12 @@ static irqreturn_t omap_otg_irq(int irq, void *arg, struct pt_regs *regs) ...@@ -130,14 +132,12 @@ static irqreturn_t omap_otg_irq(int irq, void *arg, struct pt_regs *regs)
} else if (otg_irq & A_VBUS_ERR) { } else if (otg_irq & A_VBUS_ERR) {
OTG_IRQ_SRC_REG = A_VBUS_ERR; OTG_IRQ_SRC_REG = A_VBUS_ERR;
} else if (otg_irq & DRIVER_SWITCH) { } else if (otg_irq & DRIVER_SWITCH) {
if ((!(OTG_CTRL_REG & OTG_DRIVER_SEL)) && if ((!(OTG_CTRL_REG & OTG_DRIVER_SEL)) &&
tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) { tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) {
/* role is host */ /* role is host */
usb_bus_start_enum(tu->otg.host, usb_bus_start_enum(tu->otg.host,
tu->otg.host->otg_port); tu->otg.host->otg_port);
} }
OTG_IRQ_SRC_REG = DRIVER_SWITCH; OTG_IRQ_SRC_REG = DRIVER_SWITCH;
} else } else
return IRQ_NONE; return IRQ_NONE;
...@@ -155,7 +155,6 @@ static int omap_otg_init(void) ...@@ -155,7 +155,6 @@ static int omap_otg_init(void)
return -ENODEV; return -ENODEV;
} }
#endif #endif
/* some of these values are board-specific... */ /* some of these values are board-specific... */
OTG_SYSCON_2_REG |= OTG_EN OTG_SYSCON_2_REG |= OTG_EN
/* for B-device: */ /* for B-device: */
...@@ -223,6 +222,47 @@ static DEVICE_ATTR(vbus_state, 0444, vbus_state_show, NULL); ...@@ -223,6 +222,47 @@ static DEVICE_ATTR(vbus_state, 0444, vbus_state_show, NULL);
int vbus_active = 0; int vbus_active = 0;
#if 0
static int host_suspend(struct tahvo_usb *tu)
{
struct device *dev;
if (!tu->otg.host)
return -ENODEV;
/* Currently ASSUMES only the OTG port matters;
* other ports could be active...
*/
dev = tu->otg.host->controller;
return dev->driver->suspend(dev, PMSG_SUSPEND);
}
static int host_resume(struct tahvo_usb *tu)
{
struct device *dev;
if (!tu->otg.host)
return -ENODEV;
dev = tu->otg.host->controller;
return dev->driver->resume(dev);
}
#else
static int host_suspend(struct tahvo_usb *tu)
{
return 0;
}
static int host_resume(struct tahvo_usb *tu)
{
return 0;
}
#endif
static void check_vbus_state(struct tahvo_usb *tu) static void check_vbus_state(struct tahvo_usb *tu)
{ {
int reg, prev_state; int reg, prev_state;
...@@ -244,32 +284,27 @@ static void check_vbus_state(struct tahvo_usb *tu) ...@@ -244,32 +284,27 @@ static void check_vbus_state(struct tahvo_usb *tu)
case OTG_STATE_A_IDLE: case OTG_STATE_A_IDLE:
/* Session is now valid assuming the USB hub is driving Vbus */ /* Session is now valid assuming the USB hub is driving Vbus */
tu->otg.state = OTG_STATE_A_HOST; tu->otg.state = OTG_STATE_A_HOST;
if (tu->otg.host) host_resume(tu);
ohci_omap_host_enable(tu->otg.host, 1);
break; break;
default: default:
break; break;
} }
printk("USB cable connected\n"); printk("USB cable connected\n");
} else { } else {
vbus_active = 0;
switch (tu->otg.state) { switch (tu->otg.state) {
case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_PERIPHERAL:
OTG_CTRL_REG = (OTG_CTRL_REG & ~OTG_BSESSVLD) | OTG_BSESSEND;
if (tu->otg.gadget) if (tu->otg.gadget)
usb_gadget_vbus_disconnect(tu->otg.gadget); usb_gadget_vbus_disconnect(tu->otg.gadget);
tu->otg.state = OTG_STATE_B_IDLE; tu->otg.state = OTG_STATE_B_IDLE;
break; break;
case OTG_STATE_A_HOST: case OTG_STATE_A_HOST:
tu->otg.state = OTG_STATE_A_IDLE; tu->otg.state = OTG_STATE_A_IDLE;
if (tu->otg.host)
ohci_omap_host_enable(tu->otg.host, 0);
break; break;
default: default:
break; break;
} }
printk("USB cable disconnected\n"); printk("USB cable disconnected\n");
vbus_active = 0;
} }
prev_state = tu->vbus_state; prev_state = tu->vbus_state;
...@@ -280,11 +315,16 @@ static void check_vbus_state(struct tahvo_usb *tu) ...@@ -280,11 +315,16 @@ static void check_vbus_state(struct tahvo_usb *tu)
static void tahvo_usb_become_host(struct tahvo_usb *tu) static void tahvo_usb_become_host(struct tahvo_usb *tu)
{ {
u32 l;
/* Clear system and transceiver controlled bits /* Clear system and transceiver controlled bits
* also mark the A-session is always valid */ * also mark the A-session is always valid */
omap_otg_init(); omap_otg_init();
OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK))
| OTG_ASESSVLD; l = OTG_CTRL_REG;
l &= ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK);
l |= OTG_ASESSVLD;
OTG_CTRL_REG = l;
/* Power up the transceiver in USB host mode */ /* Power up the transceiver in USB host mode */
tahvo_write_reg(TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | tahvo_write_reg(TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
...@@ -296,8 +336,7 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu) ...@@ -296,8 +336,7 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu)
static void tahvo_usb_stop_host(struct tahvo_usb *tu) static void tahvo_usb_stop_host(struct tahvo_usb *tu)
{ {
if (tu->otg.host) host_suspend(tu);
ohci_omap_host_enable(tu->otg.host, 0);
tu->otg.state = OTG_STATE_A_IDLE; tu->otg.state = OTG_STATE_A_IDLE;
} }
...@@ -307,7 +346,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) ...@@ -307,7 +346,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
* and enable ID to mark peripheral mode and * and enable ID to mark peripheral mode and
* BSESSEND to mark no Vbus */ * BSESSEND to mark no Vbus */
omap_otg_init(); omap_otg_init();
OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK)) OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK|OTG_BSESSVLD))
| OTG_ID | OTG_BSESSEND; | OTG_ID | OTG_BSESSEND;
/* Power up transceiver and set it in USB perhiperal mode */ /* Power up transceiver and set it in USB perhiperal mode */
...@@ -328,24 +367,29 @@ static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu) ...@@ -328,24 +367,29 @@ static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
static void tahvo_usb_power_off(struct tahvo_usb *tu) static void tahvo_usb_power_off(struct tahvo_usb *tu)
{ {
u32 l;
int id; int id;
/* Disable gadget controller if any */ /* Disable gadget controller if any */
if (tu->otg.gadget) if (tu->otg.gadget)
usb_gadget_vbus_disconnect(tu->otg.gadget); usb_gadget_vbus_disconnect(tu->otg.gadget);
if (tu->otg.host) host_suspend(tu);
ohci_omap_host_enable(tu->otg.host, 0);
/* Disable OTG and interrupts */ /* Disable OTG and interrupts */
if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL) if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
id = OTG_ID; id = OTG_ID;
else id = 0; else
OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK)) | id; id = 0;
l = OTG_CTRL_REG;
l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
l |= id | OTG_BSESSEND;
OTG_CTRL_REG = l;
OTG_IRQ_EN_REG = 0; OTG_IRQ_EN_REG = 0;
#if 0
OTG_SYSCON_2_REG &= ~OTG_EN; OTG_SYSCON_2_REG &= ~OTG_EN;
#endif
OTG_SYSCON_1_REG |= OTG_IDLE_EN;
/* Power off transceiver */ /* Power off transceiver */
tahvo_write_reg(TAHVO_REG_USBR, 0); tahvo_write_reg(TAHVO_REG_USBR, 0);
...@@ -355,6 +399,10 @@ static void tahvo_usb_power_off(struct tahvo_usb *tu) ...@@ -355,6 +399,10 @@ static void tahvo_usb_power_off(struct tahvo_usb *tu)
static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA) static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA)
{ {
struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
dev_dbg(&tu->pt_dev->dev, "set_power %d mA\n", mA);
if (dev->state == OTG_STATE_B_PERIPHERAL) { if (dev->state == OTG_STATE_B_PERIPHERAL) {
/* REVISIT: Can Tahvo charge battery from VBUS? */ /* REVISIT: Can Tahvo charge battery from VBUS? */
} }
...@@ -363,8 +411,11 @@ static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA) ...@@ -363,8 +411,11 @@ static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA)
static int tahvo_usb_set_suspend(struct otg_transceiver *dev, int suspend) static int tahvo_usb_set_suspend(struct otg_transceiver *dev, int suspend)
{ {
struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
u16 w; u16 w;
dev_dbg(&tu->pt_dev->dev, "set_suspend\n");
w = tahvo_read_reg(TAHVO_REG_USBR); w = tahvo_read_reg(TAHVO_REG_USBR);
if (suspend) if (suspend)
w &= ~USBR_NSUSPEND; w &= ~USBR_NSUSPEND;
...@@ -380,6 +431,8 @@ static int tahvo_usb_start_srp(struct otg_transceiver *dev) ...@@ -380,6 +431,8 @@ static int tahvo_usb_start_srp(struct otg_transceiver *dev)
struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg); struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
u32 otg_ctrl; u32 otg_ctrl;
dev_dbg(&tu->pt_dev->dev, "start_srp\n");
if (!dev || tu->otg.state != OTG_STATE_B_IDLE) if (!dev || tu->otg.state != OTG_STATE_B_IDLE)
return -ENODEV; return -ENODEV;
...@@ -392,13 +445,14 @@ static int tahvo_usb_start_srp(struct otg_transceiver *dev) ...@@ -392,13 +445,14 @@ static int tahvo_usb_start_srp(struct otg_transceiver *dev)
OTG_CTRL_REG = otg_ctrl; OTG_CTRL_REG = otg_ctrl;
tu->otg.state = OTG_STATE_B_SRP_INIT; tu->otg.state = OTG_STATE_B_SRP_INIT;
pr_debug("otg: SRP, %s ... %06x\n", state_name(tu), OTG_CTRL_REG);
return 0; return 0;
} }
static int tahvo_usb_start_hnp(struct otg_transceiver *dev) static int tahvo_usb_start_hnp(struct otg_transceiver *otg)
{ {
struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
dev_dbg(&tu->pt_dev->dev, "start_hnp\n");
#ifdef CONFIG_USB_OTG #ifdef CONFIG_USB_OTG
/* REVISIT: Add this for OTG */ /* REVISIT: Add this for OTG */
#endif #endif
...@@ -409,26 +463,30 @@ static int tahvo_usb_set_host(struct otg_transceiver *otg, struct usb_bus *host) ...@@ -409,26 +463,30 @@ static int tahvo_usb_set_host(struct otg_transceiver *otg, struct usb_bus *host)
{ {
struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg); struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
if (!otg) dev_dbg(&tu->pt_dev->dev, "set_host %p\n", host);
if (otg == NULL)
return -ENODEV; return -ENODEV;
#if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP) #if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP)
mutex_lock(&tu->serialize); mutex_lock(&tu->serialize);
if (!host) { if (host == NULL) {
if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) if (TAHVO_MODE(tu) == TAHVO_MODE_HOST)
tahvo_usb_power_off(tu); tahvo_usb_power_off(tu);
tu->otg.host = 0; tu->otg.host = NULL;
mutex_unlock(&tu->serialize); mutex_unlock(&tu->serialize);
return 0; return 0;
} }
OTG_SYSCON_1_REG &= ~(OTG_IDLE_EN | HST_IDLE_EN | DEV_IDLE_EN);
if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) { if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) {
tu->otg.host = 0; tu->otg.host = NULL;
tahvo_usb_become_host(tu); tahvo_usb_become_host(tu);
} else } else
ohci_omap_host_enable(host, 0); host_suspend(tu);
tu->otg.host = host; tu->otg.host = host;
...@@ -445,6 +503,8 @@ static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadg ...@@ -445,6 +503,8 @@ static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadg
{ {
struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg); struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
dev_dbg(&tu->pt_dev->dev, "set_peripheral %p\n", gadget);
if (!otg) if (!otg)
return -ENODEV; return -ENODEV;
...@@ -455,7 +515,7 @@ static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadg ...@@ -455,7 +515,7 @@ static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadg
if (!gadget) { if (!gadget) {
if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL) if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
tahvo_usb_power_off(tu); tahvo_usb_power_off(tu);
tu->otg.gadget = 0; tu->otg.gadget = NULL;
mutex_unlock(&tu->serialize); mutex_unlock(&tu->serialize);
return 0; return 0;
} }
...@@ -552,6 +612,8 @@ static int tahvo_usb_probe(struct device *dev) ...@@ -552,6 +612,8 @@ static int tahvo_usb_probe(struct device *dev)
struct tahvo_usb *tu; struct tahvo_usb *tu;
int ret; int ret;
dev_dbg(dev, "probe\n");
/* Create driver data */ /* Create driver data */
tu = kmalloc(sizeof(*tu), GFP_KERNEL); tu = kmalloc(sizeof(*tu), GFP_KERNEL);
if (!tu) if (!tu)
...@@ -618,6 +680,8 @@ static int tahvo_usb_probe(struct device *dev) ...@@ -618,6 +680,8 @@ static int tahvo_usb_probe(struct device *dev)
static int tahvo_usb_remove(struct device *dev) static int tahvo_usb_remove(struct device *dev)
{ {
dev_dbg(dev, "remove\n");
tahvo_free_irq(TAHVO_INT_VBUSON); tahvo_free_irq(TAHVO_INT_VBUSON);
flush_scheduled_work(); flush_scheduled_work();
otg_set_transceiver(0); otg_set_transceiver(0);
......
...@@ -257,6 +257,10 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) ...@@ -257,6 +257,10 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
} }
ohci_writel(ohci, rh, &ohci->regs->roothub.a); ohci_writel(ohci, rh, &ohci->regs->roothub.a);
distrust_firmware = 0; distrust_firmware = 0;
} else if (machine_is_nokia770()) {
/* We require a self-powered hub, which should have
* plenty of power. */
ohci_to_hcd(ohci)->power_budget = 0;
} }
/* FIXME khubd hub requests should manage power switching */ /* FIXME khubd hub requests should manage power switching */
...@@ -281,47 +285,6 @@ static void omap_stop_hc(struct platform_device *pdev) ...@@ -281,47 +285,6 @@ static void omap_stop_hc(struct platform_device *pdev)
void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
int ohci_omap_host_enable(struct usb_bus *host, int enable)
{
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
int retval;
if (host_enabled == enable)
return 0;
host_enabled = enable;
if (!host_initialized)
return 0;
hcd = (struct usb_hcd *)host->hcpriv;
ohci = hcd_to_ohci(hcd);
if (enable) {
omap_ohci_clock_power(1);
if ((retval = ohci_init(ohci)) < 0) {
dev_err(hcd->self.controller, "init error %d\n",
retval);
return retval;
}
if ((retval = hcd->driver->start(hcd)) < 0) {
dev_err(hcd->self.controller, "startup error %d\n",
retval);
return retval;
}
} else {
usb_disconnect(&hcd->self.root_hub);
hcd->driver->stop(hcd);
omap_ohci_clock_power(0);
}
return 0;
}
/** /**
* usb_hcd_omap_probe - initialize OMAP-based HCDs * usb_hcd_omap_probe - initialize OMAP-based HCDs
* Context: !in_interrupt() * Context: !in_interrupt()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment