summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/otg/msm_otg.c36
-rw-r--r--include/linux/usb/msm_hsusb.h7
2 files changed, 40 insertions, 3 deletions
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index f58b7dab75a..7792fef0be5 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -324,6 +324,9 @@ static int msm_otg_suspend(struct msm_otg *motg)
if (motg->core_clk)
clk_disable(motg->core_clk);
+ if (!IS_ERR(motg->pclk_src))
+ clk_disable(motg->pclk_src);
+
if (device_may_wakeup(otg->dev))
enable_irq_wake(motg->irq);
if (bus)
@@ -347,6 +350,9 @@ static int msm_otg_resume(struct msm_otg *motg)
if (!atomic_read(&motg->in_lpm))
return 0;
+ if (!IS_ERR(motg->pclk_src))
+ clk_enable(motg->pclk_src);
+
clk_enable(motg->pclk);
clk_enable(motg->clk);
if (motg->core_clk)
@@ -862,12 +868,31 @@ static int __init msm_otg_probe(struct platform_device *pdev)
ret = PTR_ERR(motg->clk);
goto put_phy_reset_clk;
}
+ clk_set_rate(motg->clk, 60000000);
+
+ /*
+ * If USB Core is running its protocol engine based on CORE CLK,
+ * CORE CLK must be running at >55Mhz for correct HSUSB
+ * operation and USB core cannot tolerate frequency changes on
+ * CORE CLK. For such USB cores, vote for maximum clk frequency
+ * on pclk source
+ */
+ if (motg->pdata->pclk_src_name) {
+ motg->pclk_src = clk_get(&pdev->dev,
+ motg->pdata->pclk_src_name);
+ if (IS_ERR(motg->pclk_src))
+ goto put_clk;
+ clk_set_rate(motg->pclk_src, INT_MAX);
+ clk_enable(motg->pclk_src);
+ } else
+ motg->pclk_src = ERR_PTR(-ENOENT);
+
motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
if (IS_ERR(motg->pclk)) {
dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
ret = PTR_ERR(motg->pclk);
- goto put_clk;
+ goto put_pclk_src;
}
/*
@@ -955,6 +980,11 @@ put_core_clk:
if (motg->core_clk)
clk_put(motg->core_clk);
clk_put(motg->pclk);
+put_pclk_src:
+ if (!IS_ERR(motg->pclk_src)) {
+ clk_disable(motg->pclk_src);
+ clk_put(motg->pclk_src);
+ }
put_clk:
clk_put(motg->clk);
put_phy_reset_clk:
@@ -1004,6 +1034,10 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
clk_disable(motg->clk);
if (motg->core_clk)
clk_disable(motg->core_clk);
+ if (!IS_ERR(motg->pclk_src)) {
+ clk_disable(motg->pclk_src);
+ clk_put(motg->pclk_src);
+ }
iounmap(motg->regs);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 3657403eac1..31ef1853f93 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -64,7 +64,8 @@ enum otg_control_type {
* @otg_control: OTG switch controlled by user/Id pin
* @default_mode: Default operational mode. Applicable only if
* OTG switch is controller by user.
- *
+ * @pclk_src_name: pclk is derived from ebi1_usb_clk in case of 7x27 and 8k
+ * dfab_usb_hs_clk in case of 8660 and 8960.
*/
struct msm_otg_platform_data {
int *phy_init_seq;
@@ -74,6 +75,7 @@ struct msm_otg_platform_data {
enum otg_control_type otg_control;
enum usb_mode_type default_mode;
void (*setup_gpio)(enum usb_otg_state state);
+ char *pclk_src_name;
};
/**
@@ -83,6 +85,7 @@ struct msm_otg_platform_data {
* @irq: IRQ number assigned for HSUSB controller.
* @clk: clock struct of usb_hs_clk.
* @pclk: clock struct of usb_hs_pclk.
+ * @pclk_src: pclk source for voting.
* @phy_reset_clk: clock struct of usb_phy_clk.
* @core_clk: clock struct of usb_hs_core_clk.
* @regs: ioremapped register base address.
@@ -90,7 +93,6 @@ struct msm_otg_platform_data {
* @sm_work: OTG state machine work.
* @in_lpm: indicates low power mode (LPM) state.
* @async_int: Async interrupt arrived.
- *
*/
struct msm_otg {
struct otg_transceiver otg;
@@ -98,6 +100,7 @@ struct msm_otg {
int irq;
struct clk *clk;
struct clk *pclk;
+ struct clk *pclk_src;
struct clk *phy_reset_clk;
struct clk *core_clk;
void __iomem *regs;