summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeshava Munegowda <keshava_mgowda@ti.com>2010-10-04 19:51:53 +0530
committerSebastien Jan <s-jan@ti.com>2010-11-03 15:57:59 +0100
commit1b7ebf21297507bd28a59f2511d503e56126d5f7 (patch)
treee3416220da28e685bcbe8b92fbec8883f2b75bd8
parent1c521b892c8ab13ea3267667acea46189ccaa253 (diff)
usb: omap: Runtime pm for EHCI and OHCI
The EHCI and OHCI drivers uses Run time pm APIs now. This change enables the global suspend and resume of EHCI and OHCI. Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
-rw-r--r--arch/arm/mach-omap2/usb-ehci.c458
-rw-r--r--arch/arm/plat-omap/include/plat/usb.h7
-rw-r--r--drivers/usb/host/ehci-omap.c52
-rw-r--r--drivers/usb/host/ohci-omap3.c42
4 files changed, 354 insertions, 205 deletions
diff --git a/arch/arm/mach-omap2/usb-ehci.c b/arch/arm/mach-omap2/usb-ehci.c
index 8fb32715e1ba..adc3305983af 100644
--- a/arch/arm/mach-omap2/usb-ehci.c
+++ b/arch/arm/mach-omap2/usb-ehci.c
@@ -33,6 +33,7 @@
#include <plat/usb.h>
#include <plat/omap_device.h>
#include <plat/omap_hwmod.h>
+#include <linux/pm_runtime.h>
#include "mux.h"
@@ -148,21 +149,6 @@ static const char uhhtllname[] = "uhhtll-omap";
#define USB_UHH_HS_HWMODNAME "usb_uhh_hs"
#define USB_TLL_HS_HWMODNAME "usb_tll_hs"
-struct usbhs_hwmod_apis {
- /* enable clocks and set sysconfig register*/
- int (*device_enable)(struct platform_device *pdev);
-
- /* Disable clock and reset the sysconfig register settings*/
- int (*device_idle)(struct platform_device *pdev);
-
- /* set the enable wakeup bit of sysconfig register */
- int (*enable_wakeup)(struct omap_device *od);
-
- /* Clear the enable wakeup bit of sysconfig register */
- int (*disable_wakeup)(struct omap_device *od);
-};
-
-
struct uhhtll_hcd_omap {
struct platform_device *pdev;
@@ -183,23 +169,27 @@ struct uhhtll_hcd_omap {
int count;
struct usbhs_omap_platform_data platdata;
- struct usbhs_hwmod_apis *apis;
};
+static struct uhhtll_hcd_omap uhhtll = {
+ .pdev = NULL,
+};
+
+static int uhhtll_get_platform_data(struct usbhs_omap_platform_data *pdata);
static int uhhtll_drv_enable(enum driver_type drvtype,
- int enable,
- struct platform_device *pdev,
- void *prvdata);
+ struct platform_device *pdev);
+
+static int uhhtll_drv_disable(enum driver_type drvtype,
+ struct platform_device *pdev);
+
+static int uhhtll_drv_suspend(enum driver_type drvtype,
+ struct platform_device *pdev);
+
+static int uhhtll_drv_resume(enum driver_type drvtype,
+ struct platform_device *pdev);
-static int uhhtll_get_platform_data(struct usbhs_omap_platform_data *pdata);
-static struct usbhs_hwmod_apis hmd_apis = {
- .device_enable = omap_device_enable,
- .device_idle = omap_device_idle,
- .enable_wakeup = omap_device_enable_wakeup,
- .disable_wakeup = omap_device_disable_wakeup,
-};
static struct omap_device_pm_latency omap_uhhtll_latency[] = {
{
@@ -209,15 +199,13 @@ static struct omap_device_pm_latency omap_uhhtll_latency[] = {
},
};
-static struct uhhtll_hcd_omap uhhtll = {
- .pdev = NULL,
- .apis = &hmd_apis,
-};
static struct uhhtll_apis uhhtll_export = {
- .prvdata = &hmd_apis,
.get_platform_data = uhhtll_get_platform_data,
- .enable = uhhtll_drv_enable
+ .enable = uhhtll_drv_enable,
+ .disable = uhhtll_drv_disable,
+ .suspend = uhhtll_drv_suspend,
+ .resume = uhhtll_drv_resume,
};
static void setup_ehci_io_mux(const enum usbhs_omap3_port_mode *port_mode);
@@ -289,10 +277,11 @@ static int uhhtll_hcd_omap_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ pm_runtime_enable(&pdev->dev);
+
omap->pdev = pdev;
/* TODO: USBTLL IRQ processing */
-
return 0;
}
@@ -314,6 +303,7 @@ static int uhhtll_hcd_omap_remove(struct platform_device *pdev)
return -EBUSY;
}
+ pm_runtime_disable(&omap->pdev->dev);
iounmap(omap->tll_base);
iounmap(omap->uhh_base);
omap->pdev = NULL;
@@ -390,10 +380,7 @@ static int uhhtll_enable(struct uhhtll_hcd_omap *omap)
if (omap->count > 0)
goto ok_end;
- ret = omap->apis->device_enable(omap->pdev);
-
- if (ret != 0)
- return ret;
+ pm_runtime_get_sync(&omap->pdev->dev);
if (cpu_is_omap44xx()) {
@@ -435,16 +422,6 @@ static int uhhtll_enable(struct uhhtll_hcd_omap *omap)
}
clk_enable(omap->usbhost_ick);
-#if 0
- omap->usbhost_hs_fck = clk_get(&omap->pdev->dev,
- "usbhost_120m_fck");
- if (IS_ERR(omap->usbhost_hs_fck)) {
- ret = PTR_ERR(omap->usbhost_hs_fck);
- goto err_host_hs_fck;
- }
- clk_enable(omap->usbhost_hs_fck);
-#endif
-
omap->usbhost_fs_fck = clk_get(&omap->pdev->dev,
"usbhost_48m_fck");
if (IS_ERR(omap->usbhost_fs_fck)) {
@@ -461,15 +438,6 @@ static int uhhtll_enable(struct uhhtll_hcd_omap *omap)
}
clk_enable(omap->usbtll_fck);
-#if 0
- omap->usbtll_ick = clk_get(&omap->pdev->dev, "usbtll_ick");
- if (IS_ERR(omap->usbtll_ick)) {
- ret = PTR_ERR(omap->usbtll_ick);
- goto err_tll_ick;
- }
- clk_enable(omap->usbtll_ick);
-#endif
-
/* perform TLL soft reset, and wait until reset is complete */
uhhtll_omap_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
OMAP_USBTLL_SYSCONFIG_SOFTRESET);
@@ -517,12 +485,6 @@ static int uhhtll_enable(struct uhhtll_hcd_omap *omap)
goto ok_end;
err_sys_status:
-#if 0
- clk_disable(omap->usbtll_ick);
- clk_put(omap->usbtll_ick);
-
-err_tll_ick:
-#endif
clk_disable(omap->usbtll_fck);
clk_put(omap->usbtll_fck);
@@ -531,25 +493,20 @@ err_tll_fck:
clk_put(omap->usbhost_fs_fck);
err_host_fs_fck:
-#if 0
- clk_disable(omap->usbhost_hs_fck);
- clk_put(omap->usbhost_hs_fck);
-
-err_host_hs_fck:
-#endif
clk_disable(omap->usbhost_ick);
clk_put(omap->usbhost_ick);
}
err_end:
+ pm_runtime_put_sync(&omap->pdev->dev);
return ret;
ok_end:
omap->count++;
return 0;
-
}
+
static void uhhtll_disable(struct uhhtll_hcd_omap *omap)
{
unsigned long timeout = jiffies + msecs_to_jiffies(100);
@@ -626,71 +583,32 @@ static void uhhtll_disable(struct uhhtll_hcd_omap *omap)
omap->usbtll_fck = NULL;
}
- omap->apis->device_idle(omap->pdev);
+ pm_runtime_put_sync(&omap->pdev->dev);
}
}
-static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
- struct platform_device *pdev,
- struct usbhs_hwmod_apis *hmd_apis)
+
+static int uhhtll_ehci_resume(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
{
struct usbhs_omap_platform_data *pdata = &omap->platdata;
- char supply[7];
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
u8 tll_ch_mask = 0;
unsigned reg = 0;
int ret = 0;
- int i;
-
- dev_dbg(&omap->pdev->dev, "Enable EHCI\n");
-
- /* get ehci regulator and enable */
- for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
- if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
- pdata->regulator[i] = NULL;
- continue;
- }
- snprintf(supply, sizeof(supply), "hsusb%d", i);
- pdata->regulator[i] = regulator_get(&omap->pdev->dev, supply);
- if (IS_ERR(pdata->regulator[i])) {
- pdata->regulator[i] = NULL;
- dev_dbg(&omap->pdev->dev,
- "failed to get ehci port%d regulator\n", i);
- } else {
- regulator_enable(pdata->regulator[i]);
- }
- }
-
- if (pdata->phy_reset) {
- /* Refer: ISSUE1 */
- if (gpio_is_valid(pdata->reset_gpio_port[0])) {
- gpio_request(pdata->reset_gpio_port[0],
- "USB1 PHY reset");
- gpio_direction_output(pdata->reset_gpio_port[0], 0);
- }
-
- if (gpio_is_valid(pdata->reset_gpio_port[1])) {
- gpio_request(pdata->reset_gpio_port[1],
- "USB2 PHY reset");
- gpio_direction_output(pdata->reset_gpio_port[1], 0);
- }
-
- /* Hold the PHY in RESET for enough time till DIR is high */
- udelay(10);
- }
+ dev_dbg(&omap->pdev->dev, "Resume EHCI\n");
ret = uhhtll_enable(omap);
- if (ret != 0)
- goto err_end;
-
- if (hmd_apis) {
- ret = hmd_apis->device_enable(pdev);
- if (ret != 0)
- goto err_host;
+ if (ret != 0) {
+ dev_err(&omap->pdev->dev,
+ "uhhtll_enable failed error:%d\n", ret);
+ return ret;
}
+ pm_runtime_get_sync(&pdev->dev);
+
if (cpu_is_omap44xx()) {
if ((pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) ||
@@ -704,21 +622,31 @@ static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
"utmi_p1_gfclk");
if (IS_ERR(omap->utmi_p1_fck)) {
ret = PTR_ERR(omap->utmi_p1_fck);
- goto err_host;
+ dev_err(&omap->pdev->dev,
+ "utmi_p1_gfclk failed error:%d\n",
+ ret);
+ goto err_end;
}
if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) {
omap->xclk60mhsp1_ck = clk_get(&omap->pdev->dev,
"xclk60mhsp1_ck");
if (IS_ERR(omap->xclk60mhsp1_ck)) {
ret = PTR_ERR(omap->xclk60mhsp1_ck);
+ dev_err(&omap->pdev->dev,
+ "xclk60mhsp1_ck failed"
+ "error:%d\n", ret);
goto err_xclk60mhsp1_ck;
}
/* Set the clock parent as External clock */
ret = clk_set_parent(omap->utmi_p1_fck,
omap->xclk60mhsp1_ck);
- if (ret != 0)
+ if (ret != 0) {
+ dev_err(&omap->pdev->dev,
+ "xclk60mhsp1_ck set parent"
+ "failed error:%d\n", ret);
goto err_xclk60mhsp1_ck1;
+ }
reg |= OMAP_UHH_HOST_P1_SET_ULPIPHY;
@@ -747,6 +675,8 @@ static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
"utmi_p2_gfclk");
if (IS_ERR(omap->utmi_p2_fck)) {
ret = PTR_ERR(omap->utmi_p2_fck);
+ dev_err(&omap->pdev->dev,
+ "utmi_p2_gfclk failed error:%d\n", ret);
goto err_utmi_p2_fck;
}
@@ -756,6 +686,9 @@ static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
if (IS_ERR(omap->xclk60mhsp2_ck)) {
ret = PTR_ERR(omap->xclk60mhsp2_ck);
+ dev_err(&omap->pdev->dev,
+ "xclk60mhsp2_ck failed"
+ "error:%d\n", ret);
goto err_xclk60mhsp2_ck;
}
@@ -763,8 +696,12 @@ static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
ret = clk_set_parent(omap->utmi_p2_fck,
omap->xclk60mhsp2_ck);
- if (ret != 0)
+ if (ret != 0) {
+ dev_err(&omap->pdev->dev,
+ "xclk60mhsp1_ck set parent"
+ "failed error:%d\n", ret);
goto err_xclk60mhsp2_ck1;
+ }
reg |= OMAP_UHH_HOST_P2_SET_ULPIPHY;
@@ -796,7 +733,7 @@ static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
cpu_relax();
if (time_after(jiffies, timeout)) {
- dev_dbg(&omap->pdev->dev,
+ dev_err(&omap->pdev->dev,
"operation timed out\n");
ret = -EINVAL;
goto err_44sys_status;
@@ -822,7 +759,7 @@ static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
OMAP4_TLL_CHANNEL_COUNT);
}
- goto host_ok;
+ goto ok_end;
err_44sys_status:
clk_disable(omap->utmi_p2_fck);
@@ -842,6 +779,7 @@ err_xclk60mhsp1_ck1:
err_xclk60mhsp1_ck:
clk_put(omap->utmi_p1_fck);
+ goto err_end;
} else {
@@ -903,48 +841,24 @@ err_xclk60mhsp1_ck:
omap_usb_utmi_init(omap, tll_ch_mask,
OMAP_TLL_CHANNEL_COUNT);
}
-
-
- goto host_ok;
}
-err_host:
- uhhtll_disable(omap);
err_end:
- if (pdata->phy_reset) {
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_free(pdata->reset_gpio_port[0]);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_free(pdata->reset_gpio_port[1]);
- }
+ pm_runtime_put_sync(&pdev->dev);
+ uhhtll_disable(omap);
return ret;
-host_ok:
- if (pdata->phy_reset) {
- /* Refer ISSUE1:
- * Hold the PHY in RESET for enough time till
- * PHY is settled and ready
- */
- udelay(10);
-
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value(pdata->reset_gpio_port[0], 1);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value(pdata->reset_gpio_port[1], 1);
- }
+ok_end:
return 0;
}
-static int uhhtll_ehci_disable(struct uhhtll_hcd_omap *omap,
- struct platform_device *pdev,
- struct usbhs_hwmod_apis *hmd_apis)
+static void uhhtll_ehci_suspend(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
{
struct usbhs_omap_platform_data *pdata = &omap->platdata;
- dev_dbg(&omap->pdev->dev, "Disable EHCI\n");
+ dev_dbg(&omap->pdev->dev, "suspend EHCI\n");
if ((pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) ||
(pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_TLL)) {
@@ -962,8 +876,8 @@ static int uhhtll_ehci_disable(struct uhhtll_hcd_omap *omap,
}
- if ((pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) ||
- (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_TLL)) {
+ if ((pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY) ||
+ (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_TLL)) {
if (omap->utmi_p2_fck != NULL) {
clk_disable(omap->utmi_p2_fck);
@@ -977,10 +891,95 @@ static int uhhtll_ehci_disable(struct uhhtll_hcd_omap *omap,
}
}
- if (hmd_apis)
- hmd_apis->device_idle(pdev);
-
+ pm_runtime_put_sync(&pdev->dev);
uhhtll_disable(omap);
+}
+
+
+
+static int uhhtll_ehci_enable(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
+{
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
+ char supply[7];
+ int ret = 0;
+ int i;
+
+ dev_dbg(&omap->pdev->dev, "Enable EHCI\n");
+
+ /* get ehci regulator and enable */
+ for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+ if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
+ pdata->regulator[i] = NULL;
+ continue;
+ }
+ snprintf(supply, sizeof(supply), "hsusb%d", i);
+ pdata->regulator[i] = regulator_get(&omap->pdev->dev, supply);
+ if (IS_ERR(pdata->regulator[i])) {
+ pdata->regulator[i] = NULL;
+ dev_dbg(&omap->pdev->dev,
+ "failed to get ehci port%d regulator\n", i);
+ } else {
+ regulator_enable(pdata->regulator[i]);
+ }
+ }
+
+ if (pdata->phy_reset) {
+ /* Refer: ISSUE1 */
+ if (!gpio_request(pdata->reset_gpio_port[0],
+ "USB1 PHY reset"))
+ gpio_direction_output(pdata->reset_gpio_port[0], 0);
+
+ if (!gpio_request(pdata->reset_gpio_port[1],
+ "USB2 PHY reset"))
+ gpio_direction_output(pdata->reset_gpio_port[1], 0);
+
+ /* Hold the PHY in RESET for enough time till DIR is high */
+ udelay(10);
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = uhhtll_ehci_resume(omap, pdev);
+
+ if (ret == 0) {
+ if (pdata->phy_reset) {
+ /* Refer ISSUE1:
+ * Hold the PHY in RESET for enough time till
+ * PHY is settled and ready
+ */
+ udelay(10);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_set_value(pdata->reset_gpio_port[0], 1);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_set_value(pdata->reset_gpio_port[1], 1);
+ }
+ } else {
+ uhhtll_disable(omap);
+ if (pdata->phy_reset) {
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_free(pdata->reset_gpio_port[0]);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_free(pdata->reset_gpio_port[1]);
+ }
+ }
+ return ret;
+}
+
+
+static void uhhtll_ehci_disable(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
+{
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
+
+ dev_dbg(&omap->pdev->dev, "Disable EHCI\n");
+
+ uhhtll_ehci_suspend(omap, pdev);
+
+ pm_runtime_disable(&pdev->dev);
if (pdata->phy_reset) {
if (gpio_is_valid(pdata->reset_gpio_port[0]))
@@ -992,8 +991,6 @@ static int uhhtll_ehci_disable(struct uhhtll_hcd_omap *omap,
dev_dbg(&omap->pdev->dev, " EHCI controller disabled\n");
- return 0;
-
}
static int is_ohci_port(enum usbhs_omap3_port_mode pmode)
@@ -1100,27 +1097,21 @@ static void ohci_omap3_tll_config(struct uhhtll_hcd_omap *omap,
}
-static int uhhtll_ohci_enable(struct uhhtll_hcd_omap *omap,
- struct platform_device *pdev,
- struct usbhs_hwmod_apis *hmd_apis)
+static int uhhtll_ohci_resume(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
{
struct usbhs_omap_platform_data *pdata = &omap->platdata;
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
u32 reg = 0;
int ret = 0;
- dev_dbg(&omap->pdev->dev, "Enable OHCI\n");
-
+ dev_dbg(&omap->pdev->dev, "Resume OHCI\n");
ret = uhhtll_enable(omap);
if (ret != 0)
return ret;
- if (hmd_apis) {
- ret = hmd_apis->device_enable(pdev);
- if (ret != 0)
- goto err_end;
- }
+ pm_runtime_get_sync(&pdev->dev);
if (cpu_is_omap44xx()) {
@@ -1262,18 +1253,17 @@ err_utmi_p1_fck:
}
err_end:
+ pm_runtime_put_sync(&pdev->dev);
uhhtll_disable(omap);
return ret;
-
}
-static int uuhhtll_ohci_disable(struct uhhtll_hcd_omap *omap,
- struct platform_device *pdev,
- struct usbhs_hwmod_apis *hmd_apis)
+static void uhhtll_ohci_suspend(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
{
struct usbhs_omap_platform_data *pdata = &omap->platdata;
- dev_dbg(&omap->pdev->dev, "Disable OHCI\n");
+ dev_dbg(&omap->pdev->dev, "Suspend OHCI\n");
if (is_ohci_port(pdata->port_mode[0])) {
@@ -1284,7 +1274,7 @@ static int uuhhtll_ohci_disable(struct uhhtll_hcd_omap *omap,
}
}
- if (is_ohci_port(pdata->port_mode[0])) {
+ if (is_ohci_port(pdata->port_mode[1])) {
if (omap->utmi_p2_fck != NULL) {
clk_disable(omap->utmi_p2_fck);
clk_put(omap->utmi_p2_fck);
@@ -1292,12 +1282,31 @@ static int uuhhtll_ohci_disable(struct uhhtll_hcd_omap *omap,
}
}
- if (hmd_apis)
- hmd_apis->device_idle(pdev);
-
+ pm_runtime_put_sync(&pdev->dev);
uhhtll_disable(omap);
+}
- return 0;
+
+
+static int uhhtll_ohci_enable(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
+{
+
+ dev_dbg(&omap->pdev->dev, "Enable OHCI\n");
+
+ pm_runtime_enable(&pdev->dev);
+
+ return uhhtll_ohci_resume(omap, pdev);
+}
+
+
+static void uhhtll_ohci_disable(struct uhhtll_hcd_omap *omap,
+ struct platform_device *pdev)
+{
+ dev_dbg(&omap->pdev->dev, "Disable OHCI\n");
+
+ uhhtll_ohci_suspend(omap, pdev);
+ pm_runtime_disable(&pdev->dev);
}
@@ -1321,28 +1330,23 @@ static int uhhtll_get_platform_data(struct usbhs_omap_platform_data *pdata)
}
-static int uhhtll_drv_enable(enum driver_type drvtype, int enable,
- struct platform_device *pdev,
- void *prvdata)
+static int uhhtll_drv_enable(enum driver_type drvtype,
+ struct platform_device *pdev)
{
struct uhhtll_hcd_omap *omap = &uhhtll;
- int ret = -ENODEV;
+ int ret = -EBUSY;
if (!omap->pdev) {
pr_err("UHH not yet intialized\n");
- return -EBUSY;
+ return ret;
}
down_interruptible(&omap->mutex);
if (drvtype == OMAP_EHCI)
- ret = (enable != 0) ?
- uhhtll_ehci_enable(omap, pdev, prvdata) :
- uhhtll_ehci_disable(omap, pdev, prvdata);
+ ret = uhhtll_ehci_enable(omap, pdev);
else if (drvtype == OMAP_OHCI)
- ret = (enable != 0) ?
- uhhtll_ohci_enable(omap, pdev, prvdata) :
- uuhhtll_ohci_disable(omap, pdev, prvdata);
+ ret = uhhtll_ohci_enable(omap, pdev);
up(&omap->mutex);
@@ -1351,6 +1355,76 @@ static int uhhtll_drv_enable(enum driver_type drvtype, int enable,
}
+static int uhhtll_drv_disable(enum driver_type drvtype,
+ struct platform_device *pdev)
+{
+ struct uhhtll_hcd_omap *omap = &uhhtll;
+
+ if (!omap->pdev) {
+ pr_err("UHH not yet intialized\n");
+ return -EBUSY;
+ }
+
+ down_interruptible(&omap->mutex);
+
+ if (drvtype == OMAP_EHCI)
+ uhhtll_ehci_disable(omap, pdev);
+ else if (drvtype == OMAP_OHCI)
+ uhhtll_ohci_disable(omap, pdev);
+
+ up(&omap->mutex);
+
+ return 0;
+
+}
+
+
+static int uhhtll_drv_suspend(enum driver_type drvtype,
+ struct platform_device *pdev)
+{
+ struct uhhtll_hcd_omap *omap = &uhhtll;
+
+ if (!omap->pdev) {
+ pr_err("UHH not yet intialized\n");
+ return -EBUSY;
+ }
+
+ down_interruptible(&omap->mutex);
+
+ if (drvtype == OMAP_EHCI)
+ uhhtll_ehci_suspend(omap, pdev);
+ else if (drvtype == OMAP_OHCI)
+ uhhtll_ohci_suspend(omap, pdev);
+
+ up(&omap->mutex);
+
+ return 0;
+}
+
+static int uhhtll_drv_resume(enum driver_type drvtype,
+ struct platform_device *pdev)
+{
+ struct uhhtll_hcd_omap *omap = &uhhtll;
+ int ret = -EBUSY;
+
+ if (!omap->pdev) {
+ pr_err("UHH not yet intialized\n");
+ return ret;
+ }
+
+ down_interruptible(&omap->mutex);
+
+ if (drvtype == OMAP_EHCI)
+ ret = uhhtll_ehci_resume(omap, pdev);
+ else if (drvtype == OMAP_OHCI)
+ ret = uhhtll_ohci_resume(omap, pdev);
+
+ up(&omap->mutex);
+
+
+ return ret;
+
+}
/* MUX settings for EHCI pins */
/*
diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h
index a65dc68a4a34..1b3ee5f4f141 100644
--- a/arch/arm/plat-omap/include/plat/usb.h
+++ b/arch/arm/plat-omap/include/plat/usb.h
@@ -49,10 +49,11 @@ struct usbhs_omap_platform_data {
};
struct uhhtll_apis {
- void *prvdata;
int (*get_platform_data) (struct usbhs_omap_platform_data *);
- int (*enable) (enum driver_type , int, struct platform_device *,
- void*);
+ int (*enable) (enum driver_type, struct platform_device *);
+ int (*disable) (enum driver_type, struct platform_device *);
+ int (*suspend) (enum driver_type, struct platform_device *);
+ int (*resume) (enum driver_type, struct platform_device *);
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 7727155f7aa7..2d192606dd70 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -190,7 +190,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
omap->ehci->caps = hcd->regs;
omap->ehci_base = hcd->regs;
- ret = uhhtllp->enable(OMAP_EHCI, 1, pdev, uhhtllp->prvdata);
+ ret = uhhtllp->enable(OMAP_EHCI, pdev);
if (ret) {
dev_dbg(&pdev->dev, "failed to start ehci\n");
goto err_uhh_ioremap;
@@ -238,7 +238,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
return 0;
err_add_hcd:
- uhhtllp->enable(OMAP_EHCI, 0, pdev, uhhtllp->prvdata);;
+ uhhtllp->disable(OMAP_EHCI, pdev);
err_uhh_ioremap:
iounmap(hcd->regs);
@@ -271,7 +271,7 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
struct usb_hcd *hcd = ehci_to_hcd(omap->ehci);
usb_remove_hcd(hcd);
- uhhtllp->enable(OMAP_EHCI, 0, pdev, uhhtllp->prvdata);;
+ uhhtllp->disable(OMAP_EHCI, pdev);
iounmap(hcd->regs);
usb_put_hcd(hcd);
kfree(omap);
@@ -288,19 +288,58 @@ static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
+
+#ifdef CONFIG_PM
+
+static int ehci_hcd_omap_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uhhtll_apis *uhhtllp = pdev->dev.platform_data;
+
+ dev_dbg(dev, "ehci_hcd_omap_suspend\n");
+ return uhhtllp->suspend(OMAP_EHCI, pdev);
+}
+
+static int ehci_hcd_omap_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ehci_hcd_omap *omap = platform_get_drvdata(pdev);
+ struct uhhtll_apis *uhhtllp = pdev->dev.platform_data;
+ int ret;
+
+ dev_dbg(dev, "ehci_hcd_omap_resume\n");
+ ret = uhhtllp->resume(OMAP_EHCI, pdev);
+
+ /* Route All ports to this controller again */
+ ehci_writel(omap->ehci, FLAG_CF, &omap->ehci->regs->configured_flag);
+
+ /* powerup the ports */
+ ehci_port_power(omap->ehci, 1);
+ return ret;
+}
+
+static const struct dev_pm_ops ehci_hcd_omap_dev_pm_ops = {
+ .suspend = ehci_hcd_omap_suspend,
+ .resume = ehci_hcd_omap_resume,
+};
+
+#define EHCI_HCD_OMAP_DEV_PM_OPS (&ehci_hcd_omap_dev_pm_ops)
+#else
+#define EHCI_HCD_OMAP_DEV_PM_OPS NULL
+#endif
+
+
static struct platform_driver ehci_hcd_omap_driver = {
.probe = ehci_hcd_omap_probe,
.remove = ehci_hcd_omap_remove,
.shutdown = ehci_hcd_omap_shutdown,
- /*.suspend = ehci_hcd_omap_suspend, */
- /*.resume = ehci_hcd_omap_resume, */
.driver = {
.name = "ehci-omap",
+ .pm = EHCI_HCD_OMAP_DEV_PM_OPS,
}
};
/*-------------------------------------------------------------------------*/
-
static const struct hc_driver ehci_omap_hc_driver = {
.description = hcd_name,
.product_desc = "OMAP-EHCI Host Controller",
@@ -340,7 +379,6 @@ static const struct hc_driver ehci_omap_hc_driver = {
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
-
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index f8da10a6e44e..3fd751e9f315 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -201,7 +201,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
/* we know this is the memory we want, no need to ioremap again */
omap->ohci_base = hcd->regs;
- ret = uhhtllp->enable(OMAP_OHCI, 1, pdev, uhhtllp->prvdata);
+ ret = uhhtllp->enable(OMAP_OHCI, pdev);
if (ret) {
dev_dbg(&pdev->dev, "failed to start ohci\n");
goto err_uhh_ioremap;
@@ -218,7 +218,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
return 0;
err_add_hcd:
- uhhtllp->enable(OMAP_OHCI, 0, pdev, uhhtllp->prvdata);
+ uhhtllp->disable(OMAP_OHCI, pdev);
err_uhh_ioremap:
iounmap(hcd->regs);
@@ -253,7 +253,7 @@ static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev)
struct uhhtll_apis *uhhtllp = pdev->dev.platform_data;
usb_remove_hcd(hcd);
- uhhtllp->enable(OMAP_OHCI, 0, pdev, uhhtllp->prvdata);
+ uhhtllp->disable(OMAP_OHCI, pdev);
iounmap(hcd->regs);
usb_put_hcd(hcd);
kfree(omap);
@@ -270,12 +270,48 @@ static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
+
+#ifdef CONFIG_PM
+
+static int ohci_hcd_omap_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uhhtll_apis *uhhtllp = pdev->dev.platform_data;
+
+ dev_err(dev, "ohci_hcd_omap_suspend\n");
+ return uhhtllp->suspend(OMAP_OHCI, pdev);
+}
+
+static int ohci_hcd_omap_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uhhtll_apis *uhhtllp = pdev->dev.platform_data;
+
+ dev_err(dev, "ohci_hcd_omap_resume\n");
+ return uhhtllp->resume(OMAP_OHCI, pdev);
+
+}
+
+static const struct dev_pm_ops ohci_hcd_omap_dev_pm_ops = {
+ .suspend = ohci_hcd_omap_suspend,
+ .resume = ohci_hcd_omap_resume,
+};
+
+#define OHCI_HCD_OMAP_DEV_PM_OPS (&ohci_hcd_omap_dev_pm_ops)
+#else
+#define OHCI_HCD_OMAP_DEV_PM_OPS NULL
+#endif
+
+
+
+
static struct platform_driver ohci_hcd_omap3_driver = {
.probe = ohci_hcd_omap3_probe,
.remove = __devexit_p(ohci_hcd_omap3_remove),
.shutdown = ohci_hcd_omap3_shutdown,
.driver = {
.name = "ohci-omap3",
+ .pm = OHCI_HCD_OMAP_DEV_PM_OPS,
},
};