[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CACVXFVN5zDESFqJRd9X0G=qy19Ah6pity6CG4STCf9=a5aQ3Dw@mail.gmail.com>
Date: Thu, 11 Aug 2011 23:20:30 +0800
From: Ming Lei <tom.leiming@...il.com>
To: Keshava Munegowda <keshava_mgowda@...com>
Cc: linux-usb@...r.kernel.org, linux-omap@...r.kernel.org,
linux-kernel@...r.kernel.org, balbi@...com, gadiyar@...com,
sameo@...ux.intel.com, parthab@...ia.ti.com, tony@...mide.com,
khilman@...com, b-cousson@...com, paul@...an.com,
johnstul@...ibm.com, vishwanath.bs@...com
Subject: Re: [PATCH 5/5 v4] mfd: omap: usb: Runtime PM support
Hi,
On Tue, Aug 9, 2011 at 10:15 PM, Keshava Munegowda
<keshava_mgowda@...com> wrote:
> From: Keshava Munegowda <Keshava_mgowda@...com>
>
> The usbhs core driver does not enable/disable the intefrace and
> fucntional clocks; These clocks are handled by hwmod and runtime pm,
> hence insted of the clock enable/disable, the runtime pm APIS are
> used. however,the port clocks are handled by the usbhs core.
>
> Signed-off-by: Keshava Munegowda <keshava_mgowda@...com>
> ---
> arch/arm/plat-omap/include/plat/usb.h | 3 -
> drivers/mfd/omap-usb-host.c | 722 +++++++++++++--------------------
> drivers/usb/host/ehci-omap.c | 19 +-
> drivers/usb/host/ohci-omap3.c | 14 +-
> 4 files changed, 286 insertions(+), 472 deletions(-)
>
> diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h
> index 17d3c93..2b66dc2 100644
> --- a/arch/arm/plat-omap/include/plat/usb.h
> +++ b/arch/arm/plat-omap/include/plat/usb.h
> @@ -100,9 +100,6 @@ extern void usb_musb_init(struct omap_musb_board_data *board_data);
>
> extern void usbhs_init(const struct usbhs_omap_board_data *pdata);
>
> -extern int omap_usbhs_enable(struct device *dev);
> -extern void omap_usbhs_disable(struct device *dev);
> -
> extern int omap4430_phy_power(struct device *dev, int ID, int on);
> extern int omap4430_phy_set_clk(struct device *dev, int on);
> extern int omap4430_phy_init(struct device *dev);
> diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
> index 5def51c..39cfae6 100644
> --- a/drivers/mfd/omap-usb-host.c
> +++ b/drivers/mfd/omap-usb-host.c
> @@ -26,6 +26,7 @@
> #include <linux/spinlock.h>
> #include <linux/gpio.h>
> #include <plat/usb.h>
> +#include <linux/pm_runtime.h>
>
> #define USBHS_DRIVER_NAME "usbhs_omap"
> #define OMAP_EHCI_DEVICE "ehci-omap"
> @@ -146,9 +147,6 @@
>
>
> struct usbhs_hcd_omap {
> - struct clk *usbhost_ick;
> - struct clk *usbhost_hs_fck;
> - struct clk *usbhost_fs_fck;
> struct clk *xclk60mhsp1_ck;
> struct clk *xclk60mhsp2_ck;
> struct clk *utmi_p1_fck;
> @@ -158,8 +156,6 @@ struct usbhs_hcd_omap {
> struct clk *usbhost_p2_fck;
> struct clk *usbtll_p2_fck;
> struct clk *init_60m_fclk;
> - struct clk *usbtll_fck;
> - struct clk *usbtll_ick;
>
> void __iomem *uhh_base;
> void __iomem *tll_base;
> @@ -168,7 +164,6 @@ struct usbhs_hcd_omap {
>
> u32 usbhs_rev;
> spinlock_t lock;
> - int count;
> };
> /*-------------------------------------------------------------------------*/
>
> @@ -318,269 +313,6 @@ err_end:
> return ret;
> }
>
> -/**
> - * usbhs_omap_probe - initialize TI-based HCDs
> - *
> - * Allocates basic resources for this USB host controller.
> - */
> -static int __devinit usbhs_omap_probe(struct platform_device *pdev)
> -{
> - struct device *dev = &pdev->dev;
> - struct usbhs_omap_platform_data *pdata = dev->platform_data;
> - struct usbhs_hcd_omap *omap;
> - struct resource *res;
> - int ret = 0;
> - int i;
> -
> - if (!pdata) {
> - dev_err(dev, "Missing platform data\n");
> - ret = -ENOMEM;
> - goto end_probe;
> - }
> -
> - omap = kzalloc(sizeof(*omap), GFP_KERNEL);
> - if (!omap) {
> - dev_err(dev, "Memory allocation failed\n");
> - ret = -ENOMEM;
> - goto end_probe;
> - }
> -
> - spin_lock_init(&omap->lock);
> -
> - for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
> - omap->platdata.port_mode[i] = pdata->port_mode[i];
> -
> - omap->platdata.ehci_data = pdata->ehci_data;
> - omap->platdata.ohci_data = pdata->ohci_data;
> -
> - omap->usbhost_ick = clk_get(dev, "usbhost_ick");
> - if (IS_ERR(omap->usbhost_ick)) {
> - ret = PTR_ERR(omap->usbhost_ick);
> - dev_err(dev, "usbhost_ick failed error:%d\n", ret);
> - goto err_end;
> - }
> -
> - omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
> - if (IS_ERR(omap->usbhost_hs_fck)) {
> - ret = PTR_ERR(omap->usbhost_hs_fck);
> - dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
> - goto err_usbhost_ick;
> - }
> -
> - omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
> - if (IS_ERR(omap->usbhost_fs_fck)) {
> - ret = PTR_ERR(omap->usbhost_fs_fck);
> - dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
> - goto err_usbhost_hs_fck;
> - }
> -
> - omap->usbtll_fck = clk_get(dev, "usbtll_fck");
> - if (IS_ERR(omap->usbtll_fck)) {
> - ret = PTR_ERR(omap->usbtll_fck);
> - dev_err(dev, "usbtll_fck failed error:%d\n", ret);
> - goto err_usbhost_fs_fck;
> - }
> -
> - omap->usbtll_ick = clk_get(dev, "usbtll_ick");
> - if (IS_ERR(omap->usbtll_ick)) {
> - ret = PTR_ERR(omap->usbtll_ick);
> - dev_err(dev, "usbtll_ick failed error:%d\n", ret);
> - goto err_usbtll_fck;
> - }
> -
> - omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
> - if (IS_ERR(omap->utmi_p1_fck)) {
> - ret = PTR_ERR(omap->utmi_p1_fck);
> - dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
> - goto err_usbtll_ick;
> - }
> -
> - omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
> - if (IS_ERR(omap->xclk60mhsp1_ck)) {
> - ret = PTR_ERR(omap->xclk60mhsp1_ck);
> - dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
> - goto err_utmi_p1_fck;
> - }
> -
> - omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
> - if (IS_ERR(omap->utmi_p2_fck)) {
> - ret = PTR_ERR(omap->utmi_p2_fck);
> - dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
> - goto err_xclk60mhsp1_ck;
> - }
> -
> - omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
> - if (IS_ERR(omap->xclk60mhsp2_ck)) {
> - ret = PTR_ERR(omap->xclk60mhsp2_ck);
> - dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
> - goto err_utmi_p2_fck;
> - }
> -
> - omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
> - if (IS_ERR(omap->usbhost_p1_fck)) {
> - ret = PTR_ERR(omap->usbhost_p1_fck);
> - dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
> - goto err_xclk60mhsp2_ck;
> - }
> -
> - omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
> - if (IS_ERR(omap->usbtll_p1_fck)) {
> - ret = PTR_ERR(omap->usbtll_p1_fck);
> - dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
> - goto err_usbhost_p1_fck;
> - }
> -
> - omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
> - if (IS_ERR(omap->usbhost_p2_fck)) {
> - ret = PTR_ERR(omap->usbhost_p2_fck);
> - dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
> - goto err_usbtll_p1_fck;
> - }
> -
> - omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
> - if (IS_ERR(omap->usbtll_p2_fck)) {
> - ret = PTR_ERR(omap->usbtll_p2_fck);
> - dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
> - goto err_usbhost_p2_fck;
> - }
> -
> - omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
> - if (IS_ERR(omap->init_60m_fclk)) {
> - ret = PTR_ERR(omap->init_60m_fclk);
> - dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
> - goto err_usbtll_p2_fck;
> - }
> -
> - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
> - if (!res) {
> - dev_err(dev, "UHH EHCI get resource failed\n");
> - ret = -ENODEV;
> - goto err_init_60m_fclk;
> - }
> -
> - omap->uhh_base = ioremap(res->start, resource_size(res));
> - if (!omap->uhh_base) {
> - dev_err(dev, "UHH ioremap failed\n");
> - ret = -ENOMEM;
> - goto err_init_60m_fclk;
> - }
> -
> - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll");
> - if (!res) {
> - dev_err(dev, "UHH EHCI get resource failed\n");
> - ret = -ENODEV;
> - goto err_tll;
> - }
> -
> - omap->tll_base = ioremap(res->start, resource_size(res));
> - if (!omap->tll_base) {
> - dev_err(dev, "TLL ioremap failed\n");
> - ret = -ENOMEM;
> - goto err_tll;
> - }
> -
> - platform_set_drvdata(pdev, omap);
> -
> - ret = omap_usbhs_alloc_children(pdev);
> - if (ret) {
> - dev_err(dev, "omap_usbhs_alloc_children failed\n");
> - goto err_alloc;
> - }
> -
> - goto end_probe;
> -
> -err_alloc:
> - iounmap(omap->tll_base);
> -
> -err_tll:
> - iounmap(omap->uhh_base);
> -
> -err_init_60m_fclk:
> - clk_put(omap->init_60m_fclk);
> -
> -err_usbtll_p2_fck:
> - clk_put(omap->usbtll_p2_fck);
> -
> -err_usbhost_p2_fck:
> - clk_put(omap->usbhost_p2_fck);
> -
> -err_usbtll_p1_fck:
> - clk_put(omap->usbtll_p1_fck);
> -
> -err_usbhost_p1_fck:
> - clk_put(omap->usbhost_p1_fck);
> -
> -err_xclk60mhsp2_ck:
> - clk_put(omap->xclk60mhsp2_ck);
> -
> -err_utmi_p2_fck:
> - clk_put(omap->utmi_p2_fck);
> -
> -err_xclk60mhsp1_ck:
> - clk_put(omap->xclk60mhsp1_ck);
> -
> -err_utmi_p1_fck:
> - clk_put(omap->utmi_p1_fck);
> -
> -err_usbtll_ick:
> - clk_put(omap->usbtll_ick);
> -
> -err_usbtll_fck:
> - clk_put(omap->usbtll_fck);
> -
> -err_usbhost_fs_fck:
> - clk_put(omap->usbhost_fs_fck);
> -
> -err_usbhost_hs_fck:
> - clk_put(omap->usbhost_hs_fck);
> -
> -err_usbhost_ick:
> - clk_put(omap->usbhost_ick);
> -
> -err_end:
> - kfree(omap);
> -
> -end_probe:
> - return ret;
> -}
> -
> -/**
> - * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
> - * @pdev: USB Host Controller being removed
> - *
> - * Reverses the effect of usbhs_omap_probe().
> - */
> -static int __devexit usbhs_omap_remove(struct platform_device *pdev)
> -{
> - struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
> -
> - if (omap->count != 0) {
> - dev_err(&pdev->dev,
> - "Either EHCI or OHCI is still using usbhs core\n");
> - return -EBUSY;
> - }
> -
> - iounmap(omap->tll_base);
> - iounmap(omap->uhh_base);
> - clk_put(omap->init_60m_fclk);
> - clk_put(omap->usbtll_p2_fck);
> - clk_put(omap->usbhost_p2_fck);
> - clk_put(omap->usbtll_p1_fck);
> - clk_put(omap->usbhost_p1_fck);
> - clk_put(omap->xclk60mhsp2_ck);
> - clk_put(omap->utmi_p2_fck);
> - clk_put(omap->xclk60mhsp1_ck);
> - clk_put(omap->utmi_p1_fck);
> - clk_put(omap->usbtll_ick);
> - clk_put(omap->usbtll_fck);
> - clk_put(omap->usbhost_fs_fck);
> - clk_put(omap->usbhost_hs_fck);
> - clk_put(omap->usbhost_ick);
> - kfree(omap);
> -
> - return 0;
> -}
> -
> static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
> {
> switch (pmode) {
> @@ -689,30 +421,70 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count)
> }
> }
>
> -static int usbhs_enable(struct device *dev)
> +static int usbhs_runtime_resume(struct device *dev)
> {
> struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
> struct usbhs_omap_platform_data *pdata = &omap->platdata;
> - unsigned long flags = 0;
> - int ret = 0;
> - unsigned long timeout;
> - unsigned reg;
>
> - dev_dbg(dev, "starting TI HSUSB Controller\n");
> + dev_dbg(dev, "usbhs_runtime_resume\n");
> +
> + if (!pdata) {
> + dev_dbg(dev, "missing platform_data\n");
> + return -ENODEV;
> + }
> +
> + if (is_ehci_tll_mode(pdata->port_mode[0])) {
> + clk_enable(omap->usbhost_p1_fck);
> + clk_enable(omap->usbtll_p1_fck);
> + }
> + if (is_ehci_tll_mode(pdata->port_mode[1])) {
> + clk_enable(omap->usbhost_p2_fck);
> + clk_enable(omap->usbtll_p2_fck);
> + }
> + clk_enable(omap->utmi_p1_fck);
> + clk_enable(omap->utmi_p2_fck);
> +
> + return 0;
> +}
> +
> +static int usbhs_runtime_suspend(struct device *dev)
> +{
> + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
> + struct usbhs_omap_platform_data *pdata = &omap->platdata;
> +
> + dev_dbg(dev, "usbhs_runtime_suspend\n");
> +
> if (!pdata) {
> dev_dbg(dev, "missing platform_data\n");
> return -ENODEV;
> }
>
> + if (is_ehci_tll_mode(pdata->port_mode[0])) {
> + clk_disable(omap->usbhost_p1_fck);
> + clk_disable(omap->usbtll_p1_fck);
> + }
> + if (is_ehci_tll_mode(pdata->port_mode[1])) {
> + clk_disable(omap->usbhost_p2_fck);
> + clk_disable(omap->usbtll_p2_fck);
> + }
> + clk_disable(omap->utmi_p2_fck);
> + clk_disable(omap->utmi_p1_fck);
> +
> + return 0;
> +}
> +
> +static void omap_usbhs_init(struct device *dev)
> +{
> + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
> + struct usbhs_omap_platform_data *pdata = &omap->platdata;
> + unsigned long flags = 0;
> + unsigned reg;
> +
> + dev_dbg(dev, "starting TI HSUSB Controller\n");
> +
> spin_lock_irqsave(&omap->lock, flags);
> - if (omap->count > 0)
> - goto end_count;
>
> - clk_enable(omap->usbhost_ick);
> - clk_enable(omap->usbhost_hs_fck);
> - clk_enable(omap->usbhost_fs_fck);
> - clk_enable(omap->usbtll_fck);
> - clk_enable(omap->usbtll_ick);
> + pm_runtime_get_sync(dev);
>
> if (pdata->ehci_data->phy_reset) {
> if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
> @@ -736,50 +508,6 @@ static int usbhs_enable(struct device *dev)
> omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
> dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
>
> - /* perform TLL soft reset, and wait until reset is complete */
> - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
> - OMAP_USBTLL_SYSCONFIG_SOFTRESET);
> -
> - /* Wait for TLL reset to complete */
> - timeout = jiffies + msecs_to_jiffies(1000);
> - while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
> - & OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
> - cpu_relax();
> -
> - if (time_after(jiffies, timeout)) {
> - dev_dbg(dev, "operation timed out\n");
> - ret = -EINVAL;
> - goto err_tll;
> - }
> - }
> -
> - dev_dbg(dev, "TLL RESET DONE\n");
> -
> - /* (1<<3) = no idle mode only for initial debugging */
> - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
> - OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
> - OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
> - OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
> -
> - /* Put UHH in NoIdle/NoStandby mode */
> - reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
> - if (is_omap_usbhs_rev1(omap)) {
> - reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
> - | OMAP_UHH_SYSCONFIG_SIDLEMODE
> - | OMAP_UHH_SYSCONFIG_CACTIVITY
> - | OMAP_UHH_SYSCONFIG_MIDLEMODE);
> - reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
> -
> -
> - } else if (is_omap_usbhs_rev2(omap)) {
> - reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
> - reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
> - reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
> - reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
> - }
> -
> - usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
> -
> reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
> /* setup ULPI bypass and burst configurations */
> reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
> @@ -825,49 +553,6 @@ static int usbhs_enable(struct device *dev)
> reg &= ~OMAP4_P1_MODE_CLEAR;
> reg &= ~OMAP4_P2_MODE_CLEAR;
>
> - if (is_ehci_phy_mode(pdata->port_mode[0])) {
> - ret = clk_set_parent(omap->utmi_p1_fck,
> - omap->xclk60mhsp1_ck);
> - if (ret != 0) {
> - dev_err(dev, "xclk60mhsp1_ck set parent"
> - "failed error:%d\n", ret);
> - goto err_tll;
> - }
> - } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
> - ret = clk_set_parent(omap->utmi_p1_fck,
> - omap->init_60m_fclk);
> - if (ret != 0) {
> - dev_err(dev, "init_60m_fclk set parent"
> - "failed error:%d\n", ret);
> - goto err_tll;
> - }
> - clk_enable(omap->usbhost_p1_fck);
> - clk_enable(omap->usbtll_p1_fck);
> - }
> -
> - if (is_ehci_phy_mode(pdata->port_mode[1])) {
> - ret = clk_set_parent(omap->utmi_p2_fck,
> - omap->xclk60mhsp2_ck);
> - if (ret != 0) {
> - dev_err(dev, "xclk60mhsp1_ck set parent"
> - "failed error:%d\n", ret);
> - goto err_tll;
> - }
> - } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
> - ret = clk_set_parent(omap->utmi_p2_fck,
> - omap->init_60m_fclk);
> - if (ret != 0) {
> - dev_err(dev, "init_60m_fclk set parent"
> - "failed error:%d\n", ret);
> - goto err_tll;
> - }
> - clk_enable(omap->usbhost_p2_fck);
> - clk_enable(omap->usbtll_p2_fck);
> - }
> -
> - clk_enable(omap->utmi_p1_fck);
> - clk_enable(omap->utmi_p2_fck);
> -
> if (is_ehci_tll_mode(pdata->port_mode[0]) ||
> (is_ohci_port(pdata->port_mode[0])))
> reg |= OMAP4_P1_MODE_TLL;
> @@ -913,12 +598,15 @@ static int usbhs_enable(struct device *dev)
> (pdata->ehci_data->reset_gpio_port[1], 1);
> }
>
> -end_count:
> - omap->count++;
> + pm_runtime_put_sync(dev);
> spin_unlock_irqrestore(&omap->lock, flags);
> - return 0;
> +}
> +
> +static void omap_usbhs_deinit(struct device *dev)
> +{
> + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
> + struct usbhs_omap_platform_data *pdata = &omap->platdata;
>
> -err_tll:
> if (pdata->ehci_data->phy_reset) {
> if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
> gpio_free(pdata->ehci_data->reset_gpio_port[0]);
> @@ -926,123 +614,257 @@ err_tll:
> if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
> gpio_free(pdata->ehci_data->reset_gpio_port[1]);
> }
> -
> - clk_disable(omap->usbtll_ick);
> - clk_disable(omap->usbtll_fck);
> - clk_disable(omap->usbhost_fs_fck);
> - clk_disable(omap->usbhost_hs_fck);
> - clk_disable(omap->usbhost_ick);
> - spin_unlock_irqrestore(&omap->lock, flags);
> - return ret;
> }
>
> -static void usbhs_disable(struct device *dev)
> +
> +/**
> + * usbhs_omap_probe - initialize TI-based HCDs
> + *
> + * Allocates basic resources for this USB host controller.
> + */
> +static int __devinit usbhs_omap_probe(struct platform_device *pdev)
> {
> - struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
> - struct usbhs_omap_platform_data *pdata = &omap->platdata;
> - unsigned long flags = 0;
> - unsigned long timeout;
> + struct device *dev = &pdev->dev;
> + struct usbhs_omap_platform_data *pdata = dev->platform_data;
> + struct usbhs_hcd_omap *omap;
> + struct resource *res;
> + int ret = 0;
> + int i;
>
> - dev_dbg(dev, "stopping TI HSUSB Controller\n");
> + if (!pdata) {
> + dev_err(dev, "Missing platform data\n");
> + ret = -ENOMEM;
> + goto end_probe;
> + }
>
> - spin_lock_irqsave(&omap->lock, flags);
> + omap = kzalloc(sizeof(*omap), GFP_KERNEL);
> + if (!omap) {
> + dev_err(dev, "Memory allocation failed\n");
> + ret = -ENOMEM;
> + goto end_probe;
> + }
> +
> + spin_lock_init(&omap->lock);
> +
> + for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
> + omap->platdata.port_mode[i] = pdata->port_mode[i];
>
> - if (omap->count == 0)
> - goto end_disble;
> + omap->platdata.ehci_data = pdata->ehci_data;
> + omap->platdata.ohci_data = pdata->ohci_data;
>
> - omap->count--;
> + pm_runtime_enable(dev);
>
> - if (omap->count != 0)
> - goto end_disble;
> + omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
> + if (IS_ERR(omap->utmi_p1_fck)) {
> + ret = PTR_ERR(omap->utmi_p1_fck);
> + dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
> + goto err_end;
> + }
> +
> + omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
> + if (IS_ERR(omap->xclk60mhsp1_ck)) {
> + ret = PTR_ERR(omap->xclk60mhsp1_ck);
> + dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
> + goto err_utmi_p1_fck;
> + }
>
> - /* Reset OMAP modules for insmod/rmmod to work */
> - usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG,
> - is_omap_usbhs_rev2(omap) ?
> - OMAP4_UHH_SYSCONFIG_SOFTRESET :
> - OMAP_UHH_SYSCONFIG_SOFTRESET);
> + omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
> + if (IS_ERR(omap->utmi_p2_fck)) {
> + ret = PTR_ERR(omap->utmi_p2_fck);
> + dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
> + goto err_xclk60mhsp1_ck;
> + }
>
> - timeout = jiffies + msecs_to_jiffies(100);
> - while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
> - & (1 << 0))) {
> - cpu_relax();
> + omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
> + if (IS_ERR(omap->xclk60mhsp2_ck)) {
> + ret = PTR_ERR(omap->xclk60mhsp2_ck);
> + dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
> + goto err_utmi_p2_fck;
> + }
>
> - if (time_after(jiffies, timeout))
> - dev_dbg(dev, "operation timed out\n");
> + omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
> + if (IS_ERR(omap->usbhost_p1_fck)) {
> + ret = PTR_ERR(omap->usbhost_p1_fck);
> + dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
> + goto err_xclk60mhsp2_ck;
> }
>
> - while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
> - & (1 << 1))) {
> - cpu_relax();
> + omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
> + if (IS_ERR(omap->usbtll_p1_fck)) {
> + ret = PTR_ERR(omap->usbtll_p1_fck);
> + dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
> + goto err_usbhost_p1_fck;
> + }
>
> - if (time_after(jiffies, timeout))
> - dev_dbg(dev, "operation timed out\n");
> + omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
> + if (IS_ERR(omap->usbhost_p2_fck)) {
> + ret = PTR_ERR(omap->usbhost_p2_fck);
> + dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
> + goto err_usbtll_p1_fck;
> }
>
> - while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
> - & (1 << 2))) {
> - cpu_relax();
> + omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
> + if (IS_ERR(omap->usbtll_p2_fck)) {
> + ret = PTR_ERR(omap->usbtll_p2_fck);
> + dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
> + goto err_usbhost_p2_fck;
> + }
>
> - if (time_after(jiffies, timeout))
> - dev_dbg(dev, "operation timed out\n");
> + omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
> + if (IS_ERR(omap->init_60m_fclk)) {
> + ret = PTR_ERR(omap->init_60m_fclk);
> + dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
> + goto err_usbtll_p2_fck;
> }
>
> - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1));
> + if (is_ehci_phy_mode(pdata->port_mode[0])) {
> + /* for OMAP3 , the clk set paretn fails */
> + ret = clk_set_parent(omap->utmi_p1_fck,
> + omap->xclk60mhsp1_ck);
> + if (ret != 0)
> + dev_err(dev, "xclk60mhsp1_ck set parent"
> + "failed error:%d\n", ret);
> + } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
> + ret = clk_set_parent(omap->utmi_p1_fck,
> + omap->init_60m_fclk);
> + if (ret != 0)
> + dev_err(dev, "init_60m_fclk set parent"
> + "failed error:%d\n", ret);
> + }
>
> - while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
> - & (1 << 0))) {
> - cpu_relax();
> + if (is_ehci_phy_mode(pdata->port_mode[1])) {
> + ret = clk_set_parent(omap->utmi_p2_fck,
> + omap->xclk60mhsp2_ck);
> + if (ret != 0)
> + dev_err(dev, "xclk60mhsp2_ck set parent"
> + "failed error:%d\n", ret);
> + } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
> + ret = clk_set_parent(omap->utmi_p2_fck,
> + omap->init_60m_fclk);
> + if (ret != 0)
> + dev_err(dev, "init_60m_fclk set parent"
> + "failed error:%d\n", ret);
> + }
>
> - if (time_after(jiffies, timeout))
> - dev_dbg(dev, "operation timed out\n");
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
> + if (!res) {
> + dev_err(dev, "UHH EHCI get resource failed\n");
> + ret = -ENODEV;
> + goto err_init_60m_fclk;
> }
>
> - if (is_omap_usbhs_rev2(omap)) {
> - if (is_ehci_tll_mode(pdata->port_mode[0]))
> - clk_disable(omap->usbtll_p1_fck);
> - if (is_ehci_tll_mode(pdata->port_mode[1]))
> - clk_disable(omap->usbtll_p2_fck);
> - clk_disable(omap->utmi_p2_fck);
> - clk_disable(omap->utmi_p1_fck);
> + omap->uhh_base = ioremap(res->start, resource_size(res));
> + if (!omap->uhh_base) {
> + dev_err(dev, "UHH ioremap failed\n");
> + ret = -ENOMEM;
> + goto err_init_60m_fclk;
> }
>
> - clk_disable(omap->usbtll_ick);
> - clk_disable(omap->usbtll_fck);
> - clk_disable(omap->usbhost_fs_fck);
> - clk_disable(omap->usbhost_hs_fck);
> - clk_disable(omap->usbhost_ick);
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll");
> + if (!res) {
> + dev_err(dev, "UHH EHCI get resource failed\n");
> + ret = -ENODEV;
> + goto err_tll;
> + }
>
> - /* The gpio_free migh sleep; so unlock the spinlock */
> - spin_unlock_irqrestore(&omap->lock, flags);
> + omap->tll_base = ioremap(res->start, resource_size(res));
> + if (!omap->tll_base) {
> + dev_err(dev, "TLL ioremap failed\n");
> + ret = -ENOMEM;
> + goto err_tll;
> + }
>
> - if (pdata->ehci_data->phy_reset) {
> - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
> - gpio_free(pdata->ehci_data->reset_gpio_port[0]);
> + platform_set_drvdata(pdev, omap);
>
> - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
> - gpio_free(pdata->ehci_data->reset_gpio_port[1]);
> + ret = omap_usbhs_alloc_children(pdev);
> + if (ret) {
> + dev_err(dev, "omap_usbhs_alloc_children failed\n");
> + goto err_alloc;
> }
> - return;
>
> -end_disble:
> - spin_unlock_irqrestore(&omap->lock, flags);
> -}
> + omap_usbhs_init(dev);
>
> -int omap_usbhs_enable(struct device *dev)
> -{
> - return usbhs_enable(dev->parent);
> + goto end_probe;
> +
> +err_alloc:
> + iounmap(omap->tll_base);
> +
> +err_tll:
> + iounmap(omap->uhh_base);
> +
> +err_init_60m_fclk:
> + clk_put(omap->init_60m_fclk);
> +
> +err_usbtll_p2_fck:
> + clk_put(omap->usbtll_p2_fck);
> +
> +err_usbhost_p2_fck:
> + clk_put(omap->usbhost_p2_fck);
> +
> +err_usbtll_p1_fck:
> + clk_put(omap->usbtll_p1_fck);
> +
> +err_usbhost_p1_fck:
> + clk_put(omap->usbhost_p1_fck);
> +
> +err_xclk60mhsp2_ck:
> + clk_put(omap->xclk60mhsp2_ck);
> +
> +err_utmi_p2_fck:
> + clk_put(omap->utmi_p2_fck);
> +
> +err_xclk60mhsp1_ck:
> + clk_put(omap->xclk60mhsp1_ck);
> +
> +err_utmi_p1_fck:
> + clk_put(omap->utmi_p1_fck);
> +
> +err_end:
> + pm_runtime_disable(dev);
> + kfree(omap);
> +
> +end_probe:
> + return ret;
> }
> -EXPORT_SYMBOL_GPL(omap_usbhs_enable);
>
> -void omap_usbhs_disable(struct device *dev)
> +/**
> + * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
> + * @pdev: USB Host Controller being removed
> + *
> + * Reverses the effect of usbhs_omap_probe().
> + */
> +static int __devexit usbhs_omap_remove(struct platform_device *pdev)
> {
> - usbhs_disable(dev->parent);
> + struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
> +
> + omap_usbhs_deinit(&pdev->dev);
> + iounmap(omap->tll_base);
> + iounmap(omap->uhh_base);
> + clk_put(omap->init_60m_fclk);
> + clk_put(omap->usbtll_p2_fck);
> + clk_put(omap->usbhost_p2_fck);
> + clk_put(omap->usbtll_p1_fck);
> + clk_put(omap->usbhost_p1_fck);
> + clk_put(omap->xclk60mhsp2_ck);
> + clk_put(omap->utmi_p2_fck);
> + clk_put(omap->xclk60mhsp1_ck);
> + clk_put(omap->utmi_p1_fck);
> + pm_runtime_disable(&pdev->dev);
> + kfree(omap);
> +
> + return 0;
> }
> -EXPORT_SYMBOL_GPL(omap_usbhs_disable);
> +
> +static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
> + .runtime_suspend = usbhs_runtime_suspend,
> + .runtime_resume = usbhs_runtime_resume,
> +};
>
> static struct platform_driver usbhs_omap_driver = {
> .driver = {
> .name = (char *)usbhs_driver_name,
> .owner = THIS_MODULE,
> + .pm = &usbhsomap_dev_pm_ops,
> },
> .remove = __exit_p(usbhs_omap_remove),
> };
> diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
> index 4524032..6551d30 100644
> --- a/drivers/usb/host/ehci-omap.c
> +++ b/drivers/usb/host/ehci-omap.c
> @@ -41,6 +41,7 @@
> #include <linux/usb/ulpi.h>
> #include <plat/usb.h>
> #include <linux/regulator/consumer.h>
> +#include <linux/pm_runtime.h>
>
> /* EHCI Register Set */
> #define EHCI_INSNREG04 (0xA0)
> @@ -190,11 +191,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
> }
> }
>
> - ret = omap_usbhs_enable(dev);
> - if (ret) {
> - dev_err(dev, "failed to start usbhs with err %d\n", ret);
> - goto err_enable;
> - }
> + pm_runtime_enable(dev);
> + pm_runtime_get_sync(dev);
>
> /*
> * An undocumented "feature" in the OMAP3 EHCI controller,
> @@ -240,11 +238,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
> return 0;
>
> err_add_hcd:
> - omap_usbhs_disable(dev);
> -
> -err_enable:
> disable_put_regulator(pdata);
> - usb_put_hcd(hcd);
This seems to be put before 'err_io' and after pm_runtime_put_sync,
doesn't it?
> + pm_runtime_put_sync(dev);
>
> err_io:
> iounmap(regs);
> @@ -266,10 +261,12 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
> struct usb_hcd *hcd = dev_get_drvdata(dev);
>
> usb_remove_hcd(hcd);
> - omap_usbhs_disable(dev);
> disable_put_regulator(dev->platform_data);
> - iounmap(hcd->regs);
> usb_put_hcd(hcd);
> + iounmap(hcd->regs);
> + pm_runtime_put_sync(dev);
> + pm_runtime_disable(dev);
> +
> return 0;
> }
>
> diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
> index 6048f2f..58e3dae 100644
> --- a/drivers/usb/host/ohci-omap3.c
> +++ b/drivers/usb/host/ohci-omap3.c
> @@ -31,6 +31,7 @@
>
> #include <linux/platform_device.h>
> #include <plat/usb.h>
> +#include <linux/pm_runtime.h>
>
> /*-------------------------------------------------------------------------*/
>
> @@ -172,11 +173,8 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
> hcd->rsrc_len = resource_size(res);
> hcd->regs = regs;
>
> - ret = omap_usbhs_enable(dev);
> - if (ret) {
> - dev_dbg(dev, "failed to start ohci\n");
> - goto err_end;
> - }
> + pm_runtime_enable(dev);
> + pm_runtime_get_sync(dev);
>
> ohci_hcd_init(hcd_to_ohci(hcd));
>
> @@ -189,7 +187,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
> return 0;
>
> err_add_hcd:
> - omap_usbhs_disable(dev);
> + pm_runtime_get_sync(dev);
should be pm_runtime_put_sync?
>
> err_end:
> usb_put_hcd(hcd);
> @@ -220,9 +218,9 @@ static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev)
>
> iounmap(hcd->regs);
> usb_remove_hcd(hcd);
> - omap_usbhs_disable(dev);
> + pm_runtime_put_sync(dev);
> + pm_runtime_disable(dev);
> usb_put_hcd(hcd);
> -
> return 0;
> }
>
> --
> 1.6.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists