* [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage
@ 2013-01-16 8:59 Peter Chen
2013-01-16 8:59 ` [PATCH v3 2/3] usb: mxs-phy: add set_suspend API Peter Chen
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Peter Chen @ 2013-01-16 8:59 UTC (permalink / raw)
To: linux-arm-kernel
This mxs usbphy is only needs to be on after system boots
up, and software never needs to control it anymore.
Meanwhile, usbphy's parent needs to be notified if usb
is suspend or not. So we design below mxs usbphy usage:
- usbphy1_gate and usbphy2_gate:
Their parents are dummy clock, we only needs to enable
it after system boots up.
- usbphy1 and usbphy2
Usage reserved bit for this clock, in that case, the refcount
will be updated, but without hardware changing.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
Changes for v3:
- Add new clk for usbphy clk gate which is only used
at system boots up process.
Changes for v2:
- Use reserved bit for usb phy clk control
arch/arm/mach-imx/clk-imx6q.c | 26 ++++++++++++++++++++++----
1 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 7f2c10c..ccb24cf 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -154,8 +154,8 @@ enum mx6q_clks {
usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg,
pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg,
ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,
- sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref,
- clk_max
+ sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
+ usbphy2_gate, clk_max
};
static struct clk *clk[clk_max];
@@ -208,8 +208,21 @@ int __init mx6q_clocks_init(void)
clk[pll7_usb_host] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3);
clk[pll8_mlb] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll8_mlb", "osc", base + 0xd0, 0x0);
- clk[usbphy1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 6);
- clk[usbphy2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 6);
+ /*
+ * Bit 20 is the reserved and read-only bit, we do this only for:
+ * - Do nothing for usbphy clk_enable/disable
+ * - Keep refcount when do usbphy clk_enable/disable, in that case,
+ * the clk framework may need to enable/disable usbphy's parent
+ */
+ clk[usbphy1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ clk[usbphy2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+
+ /*
+ * usbphy*_gate needs to be on after system boots up, and software
+ * never needs to control it anymore.
+ */
+ clk[usbphy1_gate] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ clk[usbphy2_gate] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
clk[sata_ref] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
clk[pcie_ref] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
@@ -436,6 +449,11 @@ int __init mx6q_clocks_init(void)
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clk[clks_init_on[i]]);
+ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
+ clk_prepare_enable(clk[usbphy1_gate]);
+ clk_prepare_enable(clk[usbphy2_gate]);
+ }
+
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
base = of_iomap(np, 0);
WARN_ON(!base);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 2/3] usb: mxs-phy: add set_suspend API
2013-01-16 8:59 [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage Peter Chen
@ 2013-01-16 8:59 ` Peter Chen
2013-01-16 8:59 ` [PATCH v3 3/3] usb: chipidea: imx: Add system suspend/resume API Peter Chen
2013-01-17 2:11 ` [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage Shawn Guo
2 siblings, 0 replies; 4+ messages in thread
From: Peter Chen @ 2013-01-16 8:59 UTC (permalink / raw)
To: linux-arm-kernel
It needs to call set_suspend during USB suspend/resume
Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
drivers/usb/otg/mxs-phy.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c
index 7630272..5158332 100644
--- a/drivers/usb/otg/mxs-phy.c
+++ b/drivers/usb/otg/mxs-phy.c
@@ -76,6 +76,25 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
clk_disable_unprepare(mxs_phy->clk);
}
+static int mxs_phy_suspend(struct usb_phy *x, int suspend)
+{
+ struct mxs_phy *mxs_phy = to_mxs_phy(x);
+
+ if (suspend) {
+ writel_relaxed(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+ writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
+ x->io_priv + HW_USBPHY_CTRL_SET);
+ clk_disable_unprepare(mxs_phy->clk);
+ } else {
+ clk_prepare_enable(mxs_phy->clk);
+ writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
+ x->io_priv + HW_USBPHY_CTRL_CLR);
+ writel_relaxed(0, x->io_priv + HW_USBPHY_PWD);
+ }
+
+ return 0;
+}
+
static int mxs_phy_on_connect(struct usb_phy *phy,
enum usb_device_speed speed)
{
@@ -137,6 +156,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy->phy.label = DRIVER_NAME;
mxs_phy->phy.init = mxs_phy_init;
mxs_phy->phy.shutdown = mxs_phy_shutdown;
+ mxs_phy->phy.set_suspend = mxs_phy_suspend;
mxs_phy->phy.notify_connect = mxs_phy_on_connect;
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 3/3] usb: chipidea: imx: Add system suspend/resume API
2013-01-16 8:59 [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage Peter Chen
2013-01-16 8:59 ` [PATCH v3 2/3] usb: mxs-phy: add set_suspend API Peter Chen
@ 2013-01-16 8:59 ` Peter Chen
2013-01-17 2:11 ` [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage Shawn Guo
2 siblings, 0 replies; 4+ messages in thread
From: Peter Chen @ 2013-01-16 8:59 UTC (permalink / raw)
To: linux-arm-kernel
During the system suspend/resume procedure, the USB also
needs to go suspend/resume procedure, this patch adds
related APIs. It is tested at i.mx6q sabrelite. Meanwhile,
it fixes the bug that the USB will out of work after
system suspend/resume.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
drivers/usb/chipidea/bits.h | 1 +
drivers/usb/chipidea/ci13xxx_imx.c | 61 ++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index ba9c6ef..d1467bb 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -47,6 +47,7 @@
#define PORTSC_FPR BIT(6)
#define PORTSC_SUSP BIT(7)
#define PORTSC_HSP BIT(9)
+#define PORTSC_PHCD BIT(23) /* phy suspend mode */
#define PORTSC_PTC (0x0FUL << 16)
/* DEVLC */
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index 342eab0..dd257b1 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -25,6 +25,7 @@
#include <linux/mfd/syscon.h>
#include "ci.h"
+#include "bits.h"
#include "ci13xxx_imx.h"
#define pdev_to_phy(pdev) \
@@ -321,6 +322,63 @@ static int ci13xxx_imx_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int ci13xxx_imx_suspend(struct device *dev)
+{
+ struct ci13xxx_imx_data *data =
+ platform_get_drvdata(to_platform_device(dev));
+ struct platform_device *plat_ci;
+ struct ci13xxx *ci;
+
+ plat_ci = data->ci_pdev;
+ ci = platform_get_drvdata(plat_ci);
+
+ hw_write(ci, OP_PORTSC, PORTSC_PHCD, 1);
+
+ if (data->phy)
+ usb_phy_set_suspend(data->phy, 1);
+
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int ci13xxx_imx_resume(struct device *dev)
+{
+ int ret;
+ struct ci13xxx_imx_data *data =
+ platform_get_drvdata(to_platform_device(dev));
+ struct platform_device *plat_ci;
+ struct ci13xxx *ci;
+
+ plat_ci = data->ci_pdev;
+ ci = platform_get_drvdata(plat_ci);
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(dev,
+ "Failed to prepare or enable clock, err=%d\n", ret);
+ return ret;
+ }
+
+ if (hw_read(ci, OP_PORTSC, PORTSC_PHCD)) {
+ hw_write(ci, OP_PORTSC, PORTSC_PHCD, 0);
+ /* Some clks sync between Controller and USB PHY */
+ mdelay(1);
+ }
+
+ if (data->phy)
+ usb_phy_set_suspend(data->phy, 0);
+
+ return ret;
+}
+
+static const struct dev_pm_ops ci13xxx_imx_pm_ops = {
+ .suspend = ci13xxx_imx_suspend,
+ .resume = ci13xxx_imx_resume,
+};
+#endif
+
static const struct of_device_id ci13xxx_imx_dt_ids[] = {
{ .compatible = "fsl,imx27-usb", },
{ /* sentinel */ }
@@ -334,6 +392,9 @@ static struct platform_driver ci13xxx_imx_driver = {
.name = "imx_usb",
.owner = THIS_MODULE,
.of_match_table = ci13xxx_imx_dt_ids,
+#ifdef CONFIG_PM
+ .pm = &ci13xxx_imx_pm_ops,
+#endif
},
};
--
1.7.0.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage
2013-01-16 8:59 [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage Peter Chen
2013-01-16 8:59 ` [PATCH v3 2/3] usb: mxs-phy: add set_suspend API Peter Chen
2013-01-16 8:59 ` [PATCH v3 3/3] usb: chipidea: imx: Add system suspend/resume API Peter Chen
@ 2013-01-17 2:11 ` Shawn Guo
2 siblings, 0 replies; 4+ messages in thread
From: Shawn Guo @ 2013-01-17 2:11 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Jan 16, 2013 at 04:59:03PM +0800, Peter Chen wrote:
> This mxs usbphy is only needs to be on after system boots
> up, and software never needs to control it anymore.
> Meanwhile, usbphy's parent needs to be notified if usb
> is suspend or not. So we design below mxs usbphy usage:
>
> - usbphy1_gate and usbphy2_gate:
> Their parents are dummy clock, we only needs to enable
> it after system boots up.
> - usbphy1 and usbphy2
> Usage reserved bit for this clock, in that case, the refcount
> will be updated, but without hardware changing.
>
Ok, so we change the clocks usbphy1 and ushphy2 to access a reserved bit
for gating. Then usbphy driver can play the clocks to maintain the use
count for parent PLL, which may have other child clocks, while leaving
the actual gating control to hardware.
Meanwhile, we add new clocks usbphy1_gate and ushphy2_gate being the
children of dummy clock to accessing the real gate bit. Then clock
initialization can call clk_prepare_enable to enable for only once.
Though I feel this is a total hack, I do not see any other better option
to fulfill the hardware requirement with the least churn to software.
So I'm fine with it.
See one minor comment below.
> Signed-off-by: Peter Chen <peter.chen@freescale.com>
> ---
> Changes for v3:
> - Add new clk for usbphy clk gate which is only used
> at system boots up process.
>
> Changes for v2:
> - Use reserved bit for usb phy clk control
>
> arch/arm/mach-imx/clk-imx6q.c | 26 ++++++++++++++++++++++----
> 1 files changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
> index 7f2c10c..ccb24cf 100644
> --- a/arch/arm/mach-imx/clk-imx6q.c
> +++ b/arch/arm/mach-imx/clk-imx6q.c
> @@ -154,8 +154,8 @@ enum mx6q_clks {
> usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg,
> pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg,
> ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,
> - sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref,
> - clk_max
> + sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
> + usbphy2_gate, clk_max
usbphy1_gate and usbphy2_gate need to be numbered in binding doc.
Shawn
> };
>
> static struct clk *clk[clk_max];
> @@ -208,8 +208,21 @@ int __init mx6q_clocks_init(void)
> clk[pll7_usb_host] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3);
> clk[pll8_mlb] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll8_mlb", "osc", base + 0xd0, 0x0);
>
> - clk[usbphy1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 6);
> - clk[usbphy2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 6);
> + /*
> + * Bit 20 is the reserved and read-only bit, we do this only for:
> + * - Do nothing for usbphy clk_enable/disable
> + * - Keep refcount when do usbphy clk_enable/disable, in that case,
> + * the clk framework may need to enable/disable usbphy's parent
> + */
> + clk[usbphy1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
> + clk[usbphy2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
> +
> + /*
> + * usbphy*_gate needs to be on after system boots up, and software
> + * never needs to control it anymore.
> + */
> + clk[usbphy1_gate] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
> + clk[usbphy2_gate] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
>
> clk[sata_ref] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
> clk[pcie_ref] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
> @@ -436,6 +449,11 @@ int __init mx6q_clocks_init(void)
> for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
> clk_prepare_enable(clk[clks_init_on[i]]);
>
> + if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
> + clk_prepare_enable(clk[usbphy1_gate]);
> + clk_prepare_enable(clk[usbphy2_gate]);
> + }
> +
> np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
> base = of_iomap(np, 0);
> WARN_ON(!base);
> --
> 1.7.0.4
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-01-17 2:11 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-16 8:59 [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage Peter Chen
2013-01-16 8:59 ` [PATCH v3 2/3] usb: mxs-phy: add set_suspend API Peter Chen
2013-01-16 8:59 ` [PATCH v3 3/3] usb: chipidea: imx: Add system suspend/resume API Peter Chen
2013-01-17 2:11 ` [PATCH v3 1/3] ARM i.MX6: change mxs usbphy clock usage Shawn Guo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).