X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fohci-omap.c;h=27be1f9368853925da47e2b64cd18fb3ec59088e;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=d133ff22a4a7c55f81251d18061b95a3b3c03be0;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index d133ff22a..27be1f936 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -2,119 +2,113 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2004 David Brownell + * (C) Copyright 2000-2005 David Brownell * (C) Copyright 2002 Hewlett-Packard Company - * - * OMAP Bus Glue * - * Written by Christopher Hoover - * Based on fragments of previous driver by Russell King et al. + * OMAP Bus Glue * - * Modified for OMAP from ohci-sa1111.c by Tony Lindgren + * Modified for OMAP by Tony Lindgren * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc. + * and on ohci-sa1111.c by Christopher Hoover * * This file is licenced under the GPL. */ +#include /* IRQF_DISABLED */ +#include +#include +#include + #include #include #include -#include #include #include #include #include #include -#include "ohci-omap.h" + +/* OMAP-1510 OHCI has its own MMU for DMA */ +#define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */ +#define OMAP1510_LB_CLOCK_DIV 0xfffec10c +#define OMAP1510_LB_MMU_CTL 0xfffec208 +#define OMAP1510_LB_MMU_LCK 0xfffec224 +#define OMAP1510_LB_MMU_LD_TLB 0xfffec228 +#define OMAP1510_LB_MMU_CAM_H 0xfffec22c +#define OMAP1510_LB_MMU_CAM_L 0xfffec230 +#define OMAP1510_LB_MMU_RAM_H 0xfffec234 +#define OMAP1510_LB_MMU_RAM_L 0xfffec238 + #ifndef CONFIG_ARCH_OMAP #error "This file is OMAP bus glue. CONFIG_OMAP must be defined." #endif -extern int usb_disabled(void); -extern int ocpi_enable(void); - -/* - * OHCI clock initialization for OMAP-1510 and 1610 - */ -static int omap_ohci_clock_power(int on) -{ - if (on) { - if (cpu_is_omap1510()) { - /* Use DPLL, not APLL */ - omap_writel(omap_readl(ULPD_APLL_CTRL) & ~APLL_NDPLL_SWITCH, - ULPD_APLL_CTRL); - - /* Enable DPLL */ - omap_writel(omap_readl(ULPD_DPLL_CTRL) | DPLL_PLL_ENABLE, - ULPD_DPLL_CTRL); - - /* Software request for USB 48MHz clock */ - omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_REQ_REG_REQ, - ULPD_SOFT_REQ); +#ifdef CONFIG_TPS65010 +#include +#else - while (!(omap_readl(ULPD_DPLL_CTRL) & DPLL_LOCK)); - } +#define LOW 0 +#define HIGH 1 - if (cpu_is_omap16xx()) { - /* Enable OHCI */ - omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_OTG_REQ, - ULPD_SOFT_REQ); +#define GPIO1 1 - /* USB host clock request if not using OTG */ - omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_REQ, - ULPD_SOFT_REQ); +static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) +{ + return 0; +} - omap_writel(omap_readl(ULPD_STATUS_REQ) | USB_HOST_DPLL_REQ, - ULPD_STATUS_REQ); - } +#endif - /* Enable 48MHz clock to USB */ - omap_writel(omap_readl(ULPD_CLOCK_CTRL) | USB_MCLK_EN, - ULPD_CLOCK_CTRL); +extern int usb_disabled(void); +extern int ocpi_enable(void); - omap_writel(omap_readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK), - ARM_IDLECT2); +static struct clk *usb_host_ck; +static struct clk *usb_dc_ck; +static int host_enabled; +static int host_initialized; - omap_writel(omap_readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN, - MOD_CONF_CTRL_0); +static void omap_ohci_clock_power(int on) +{ + if (on) { + clk_enable(usb_dc_ck); + clk_enable(usb_host_ck); + /* guesstimate for T5 == 1x 32K clock + APLL lock time */ + udelay(100); } else { - /* Disable 48MHz clock to USB */ - omap_writel(omap_readl(ULPD_CLOCK_CTRL) & ~USB_MCLK_EN, - ULPD_CLOCK_CTRL); - - /* FIXME: The DPLL stays on for now */ + clk_disable(usb_host_ck); + clk_disable(usb_dc_ck); } - - return 0; } /* - * Hardware specific transceiver power on/off + * Board specific gang-switched transceiver power on/off. + * NOTE: OSK supplies power from DC, not battery. */ static int omap_ohci_transceiver_power(int on) { if (on) { if (machine_is_omap_innovator() && cpu_is_omap1510()) - fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) | 0x20, + fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) + | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) { - /* FIXME: GPIO1 -> 1 on the TPS65010 I2C chip */ - } + else if (machine_is_omap_osk()) + tps65010_set_gpio_out_value(GPIO1, LOW); } else { if (machine_is_omap_innovator() && cpu_is_omap1510()) - fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) & ~0x20, + fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) + & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) { - /* FIXME: GPIO1 -> 0 on the TPS65010 I2C chip */ - } + else if (machine_is_omap_osk()) + tps65010_set_gpio_out_value(GPIO1, HIGH); } return 0; } +#ifdef CONFIG_ARCH_OMAP15XX /* * OMAP-1510 specific Local Bus clock on/off */ @@ -133,8 +127,8 @@ static int omap_1510_local_bus_power(int on) /* * OMAP-1510 specific Local Bus initialization * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. - * See also arch/mach-omap/memory.h for __virt_to_dma() and - * __dma_to_virt() which need to match with the physical + * See also arch/mach-omap/memory.h for __virt_to_dma() and + * __dma_to_virt() which need to match with the physical * Local Bus address below. */ static int omap_1510_local_bus_init(void) @@ -142,7 +136,7 @@ static int omap_1510_local_bus_init(void) unsigned int tlb; unsigned long lbaddr, physaddr; - omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, + omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, OMAP1510_LB_CLOCK_DIV); /* Configure the Local Bus MMU table */ @@ -150,7 +144,7 @@ static int omap_1510_local_bus_init(void) lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; physaddr = tlb * 0x00100000 + PHYS_OFFSET; omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); - omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, + omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, OMAP1510_LB_MMU_CAM_L); omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); @@ -164,12 +158,16 @@ static int omap_1510_local_bus_init(void) return 0; } +#else +#define omap_1510_local_bus_power(x) {} +#define omap_1510_local_bus_init() {} +#endif #ifdef CONFIG_USB_OTG static void start_hnp(struct ohci_hcd *ohci) { - const unsigned port = ohci->hcd.self.otg_port - 1; + const unsigned port = ohci_to_hcd(ohci)->self.otg_port - 1; unsigned long flags; otg_start_hnp(ohci->transceiver); @@ -185,22 +183,24 @@ static void start_hnp(struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) +static int ohci_omap_init(struct usb_hcd *hcd) { - struct omap_usb_config *config = pdev->dev.platform_data; + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct omap_usb_config *config = hcd->self.controller->platform_data; int need_transceiver = (config->otg != 0); + int ret; - dev_dbg(&pdev->dev, "starting USB Controller\n"); + dev_dbg(hcd->self.controller, "starting USB Controller\n"); if (config->otg) { - ohci->hcd.self.otg_port = config->otg; + ohci_to_hcd(ohci)->self.otg_port = config->otg; /* default/minimum OTG power budget: 8 mA */ - ohci->power_budget = 8; + ohci_to_hcd(ohci)->power_budget = 8; } /* boards can use OTG transceivers in non-OTG modes */ need_transceiver = need_transceiver - || machine_is_omap_h2(); + || machine_is_omap_h2() || machine_is_omap_h3(); if (cpu_is_omap16xx()) ocpi_enable(); @@ -210,8 +210,8 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) ohci->transceiver = otg_get_transceiver(); if (ohci->transceiver) { int status = otg_set_host(ohci->transceiver, - &ohci->hcd.self); - dev_dbg(&pdev->dev, "init %s transceiver, status %d\n", + &ohci_to_hcd(ohci)->self); + dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n", ohci->transceiver->label, status); if (status) { if (ohci->transceiver) @@ -219,27 +219,54 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) return status; } } else { - dev_err(&pdev->dev, "can't find transceiver\n"); + dev_err(hcd->self.controller, "can't find transceiver\n"); return -ENODEV; } } #endif - if (machine_is_omap_osk()) { - omap_request_gpio(9); - omap_set_gpio_direction(9, 1); - omap_set_gpio_dataout(9, 1); - } - omap_ohci_clock_power(1); - omap_ohci_transceiver_power(1); - if (cpu_is_omap1510()) { omap_1510_local_bus_power(1); omap_1510_local_bus_init(); } + if ((ret = ohci_init(ohci)) < 0) + return ret; + + /* board-specific power switching and overcurrent support */ + if (machine_is_omap_osk() || machine_is_omap_innovator()) { + u32 rh = roothub_a (ohci); + + /* power switching (ganged by default) */ + rh &= ~RH_A_NPS; + + /* TPS2045 switch for internal transceiver (port 1) */ + if (machine_is_omap_osk()) { + ohci_to_hcd(ohci)->power_budget = 250; + + rh &= ~RH_A_NOCP; + + /* gpio9 for overcurrent detction */ + omap_cfg_reg(W8_1610_GPIO9); + omap_request_gpio(9); + omap_set_gpio_direction(9, 1 /* IN */); + + /* for paranoia's sake: disable USB.PUEN */ + omap_cfg_reg(W4_USB_HIGHZ); + } + ohci_writel(ohci, rh, &ohci->regs->roothub.a); + 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 */ + omap_ohci_transceiver_power(1); + /* board init will have already handled HMC and mux setup. * any external transceiver should already be initialized * too, so all configured ports use the right signaling now. @@ -248,30 +275,15 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) return 0; } -static void omap_stop_hc(struct platform_device *pdev) +static void ohci_omap_stop(struct usb_hcd *hcd) { - dev_dbg(&pdev->dev, "stopping USB Controller\n"); - - /* - * FIXME: Put the USB host controller into reset. - */ - - /* - * FIXME: Stop the USB clock. - */ - //omap_disable_device(dev); - + dev_dbg(hcd->self.controller, "stopping USB Controller\n"); + omap_ohci_clock_power(0); } /*-------------------------------------------------------------------------*/ -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 */ - - /** * usb_hcd_omap_probe - initialize OMAP-based HCDs * Context: !in_interrupt() @@ -280,99 +292,88 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. */ -int usb_hcd_omap_probe (const struct hc_driver *driver, +static int usb_hcd_omap_probe (const struct hc_driver *driver, struct platform_device *pdev) { - int retval; + int retval, irq; struct usb_hcd *hcd = 0; struct ohci_hcd *ohci; if (pdev->num_resources != 2) { - printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", + printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", pdev->num_resources); return -ENODEV; } - if (pdev->resource[0].flags != IORESOURCE_MEM - || pdev->resource[1].flags != IORESOURCE_IRQ) { + if (pdev->resource[0].flags != IORESOURCE_MEM + || pdev->resource[1].flags != IORESOURCE_IRQ) { printk(KERN_ERR "hcd probe: invalid resource type\n"); return -ENODEV; } - if (!request_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); - return -EBUSY; - } + usb_host_ck = clk_get(0, "usb_hhc_ck"); + if (IS_ERR(usb_host_ck)) + return PTR_ERR(usb_host_ck); - hcd = driver->hcd_alloc (); - if (hcd == NULL){ - dev_dbg(&pdev->dev, "hcd_alloc failed\n"); - retval = -ENOMEM; - goto err1; - } - dev_set_drvdata(&pdev->dev, hcd); - ohci = hcd_to_ohci(hcd); + if (!cpu_is_omap1510()) + usb_dc_ck = clk_get(0, "usb_dc_ck"); + else + usb_dc_ck = clk_get(0, "lb_ck"); - hcd->driver = (struct hc_driver *) driver; - hcd->description = driver->description; - hcd->irq = pdev->resource[1].start; - hcd->regs = (void *)pdev->resource[0].start; - hcd->self.controller = &pdev->dev; + if (IS_ERR(usb_dc_ck)) { + clk_put(usb_host_ck); + return PTR_ERR(usb_dc_ck); + } - retval = omap_start_hc(ohci, pdev); - if (retval < 0) - goto err2; - retval = hcd_buffer_create (hcd); - if (retval != 0) { - dev_dbg(&pdev->dev, "pool alloc fail\n"); - goto err1; + hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + retval = -ENOMEM; + goto err0; } + hcd->rsrc_start = pdev->resource[0].start; + hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - retval = request_irq (hcd->irq, usb_hcd_irq, - SA_INTERRUPT, hcd->description, hcd); - if (retval != 0) { - dev_dbg(&pdev->dev, "request_irq failed\n"); + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); retval = -EBUSY; - goto err2; + goto err1; } - dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); + hcd->regs = (void __iomem *) (int) IO_ADDRESS(hcd->rsrc_start); - usb_bus_init (&hcd->self); - hcd->self.op = &usb_hcd_operations; - hcd->self.hcpriv = (void *) hcd; - hcd->self.bus_name = pdev->dev.bus_id; - hcd->product_desc = "OMAP OHCI"; + ohci = hcd_to_ohci(hcd); + ohci_hcd_init(ohci); - INIT_LIST_HEAD (&hcd->dev_list); - usb_register_bus (&hcd->self); + host_initialized = 0; + host_enabled = 1; - if ((retval = driver->start (hcd)) < 0) - { - usb_hcd_omap_remove(hcd, pdev); - return retval; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + retval = -ENXIO; + goto err2; } + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); + if (retval) + goto err2; - return 0; - - err2: - hcd_buffer_destroy (hcd); - if (hcd) - driver->hcd_free(hcd); - err1: - omap_stop_hc(pdev); + host_initialized = 1; - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1); + if (!host_enabled) + omap_ohci_clock_power(0); - dev_set_drvdata(&pdev->dev, 0); + return 0; +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); +err0: + clk_put(usb_dc_ck); + clk_put(usb_host_ck); return retval; } -/* may be called without controller electrically present */ /* may be called with controller, bus, and devices active */ /** @@ -383,85 +384,47 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, * Reverses the effect of usb_hcd_omap_probe(), first invoking * the HCD's stop() method. It is always called from a thread * context, normally "rmmod", "apmd", or something similar. - * */ -void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) +static inline void +usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) { - void *base; - - dev_info(&pdev->dev, "remove: state %x\n", hcd->state); - - if (in_interrupt ()) - BUG (); - - hcd->state = USB_STATE_QUIESCING; - - dev_dbg(&pdev->dev, "roothub graceful disconnect\n"); - usb_disconnect (&hcd->self.root_hub); - - hcd->driver->stop (hcd); - hcd_buffer_destroy (hcd); - hcd->state = USB_STATE_HALT; + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + usb_remove_hcd(hcd); + if (ohci->transceiver) { + (void) otg_set_host(ohci->transceiver, 0); + put_device(ohci->transceiver->dev); + } if (machine_is_omap_osk()) omap_free_gpio(9); - - free_irq (hcd->irq, hcd); - - usb_deregister_bus (&hcd->self); - - base = hcd->regs; - hcd->driver->hcd_free (hcd); - - omap_stop_hc(pdev); - - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + clk_put(usb_dc_ck); + clk_put(usb_host_ck); } /*-------------------------------------------------------------------------*/ -static int __devinit +static int ohci_omap_start (struct usb_hcd *hcd) { struct omap_usb_config *config; struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; + if (!host_enabled) + return 0; config = hcd->self.controller->platform_data; - ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma, 0); - if (!ohci->hcca) - return -ENOMEM; - - memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); - if ((ret = ohci_mem_init (ohci)) < 0) { - ohci_stop (hcd); - return ret; - } - ohci->regs = hcd->regs; - - if (config->otg || config->rwc) + if (config->otg || config->rwc) { + ohci->hc_control = OHCI_CTRL_RWC; writel(OHCI_CTRL_RWC, &ohci->regs->control); - - if (hc_reset (ohci) < 0) { - ohci_stop (hcd); - return -ENODEV; } - if (hc_start (ohci) < 0) { - err ("can't start %s", ohci->hcd.self.bus_name); + if ((ret = ohci_run (ohci)) < 0) { + dev_err(hcd->self.controller, "can't start\n"); ohci_stop (hcd); - return -EBUSY; + return ret; } - if (ohci->power_budget) - hub_set_power_budget(ohci->hcd.self.root_hub, - ohci->power_budget); - create_debug_files (ohci); - -#ifdef DEBUG - ohci_dump (ohci, 1); -#endif return 0; } @@ -469,24 +432,22 @@ ohci_omap_start (struct usb_hcd *hcd) static const struct hc_driver ohci_omap_hc_driver = { .description = hcd_name, + .product_desc = "OMAP OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), /* * generic hardware linkage */ .irq = ohci_irq, - .flags = HCD_USB11, + .flags = HCD_USB11 | HCD_MEMORY, /* * basic lifecycle operations */ + .reset = ohci_omap_init, .start = ohci_omap_start, - .stop = ohci_stop, - - /* - * memory lifecycle (except per-request) - */ - .hcd_alloc = ohci_hcd_alloc, - .hcd_free = ohci_hcd_free, + .stop = ohci_omap_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -505,99 +466,61 @@ static const struct hc_driver ohci_omap_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ -static int ohci_hcd_omap_drv_probe(struct device *dev) +static int ohci_hcd_omap_drv_probe(struct platform_device *dev) { - return usb_hcd_omap_probe(&ohci_omap_hc_driver, - to_platform_device(dev)); + return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev); } -static int ohci_hcd_omap_drv_remove(struct device *dev) +static int ohci_hcd_omap_drv_remove(struct platform_device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct usb_hcd *hcd = platform_get_drvdata(dev); - usb_hcd_omap_remove(hcd, pdev); - if (ohci->transceiver) { - (void) otg_set_host(ohci->transceiver, 0); - put_device(ohci->transceiver->dev); - } - dev_set_drvdata(dev, NULL); + usb_hcd_omap_remove(hcd, dev); + platform_set_drvdata(dev, NULL); return 0; } /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) - -/* states match PCI usage, always suspending the root hub except that - * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset). - */ +#ifdef CONFIG_PM -static int ohci_omap_suspend(struct device *dev, u32 state, u32 level) +static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message) { - struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); - int status = -EINVAL; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev)); - if (state <= dev->power.power_state) - return 0; + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; - dev_dbg(dev, "suspend to %d\n", state); - down(&ohci->hcd.self.root_hub->serialize); - status = ohci_hub_suspend(&ohci->hcd); - if (status == 0) { - if (state >= 4) { - /* power off + reset */ - OTG_SYSCON_2_REG &= ~UHOST_EN; - ohci->hcd.self.root_hub->state = USB_STATE_SUSPENDED; - state = 4; - } - ohci->hcd.state = HCD_STATE_SUSPENDED; - dev->power.power_state = state; - } - up(&ohci->hcd.self.root_hub->serialize); - return status; + omap_ohci_clock_power(0); + ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; + dev->dev.power.power_state = PMSG_SUSPEND; + return 0; } -static int ohci_omap_resume(struct device *dev, u32 level) +static int ohci_omap_resume(struct platform_device *dev) { - struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); - int status = 0; - - switch (dev->power.power_state) { - case 0: - break; - case 4: - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - OTG_SYSCON_2_REG |= UHOST_EN; - /* FALLTHROUGH */ - default: - dev_dbg(dev, "resume from %d\n", dev->power.power_state); -#ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - status = usb_resume_device(ohci->hcd.self.root_hub); -#else - down(&ohci->hcd.self.root_hub->serialize); - status = ohci_hub_resume(&ohci->hcd); - up(&ohci->hcd.self.root_hub->serialize); -#endif - if (status == 0) - dev->power.power_state = 0; - break; - } - return status; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev)); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + omap_ohci_clock_power(1); + dev->dev.power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(platform_get_drvdata(dev)); + return 0; } #endif @@ -607,15 +530,18 @@ static int ohci_omap_resume(struct device *dev, u32 level) /* * Driver definition to register with the OMAP bus */ -static struct device_driver ohci_hcd_omap_driver = { - .name = "ohci", - .bus = &platform_bus_type, +static struct platform_driver ohci_hcd_omap_driver = { .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) + .shutdown = usb_hcd_platform_shutdown, +#ifdef CONFIG_PM .suspend = ohci_omap_suspend, .resume = ohci_omap_resume, #endif + .driver = { + .owner = THIS_MODULE, + .name = "ohci", + }, }; static int __init ohci_hcd_omap_init (void) @@ -627,12 +553,12 @@ static int __init ohci_hcd_omap_init (void) pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); - return driver_register(&ohci_hcd_omap_driver); + return platform_driver_register(&ohci_hcd_omap_driver); } static void __exit ohci_hcd_omap_cleanup (void) { - driver_unregister(&ohci_hcd_omap_driver); + platform_driver_unregister(&ohci_hcd_omap_driver); } module_init (ohci_hcd_omap_init);