2014-11-21 16:00:33

by Thomas Petazzoni

[permalink] [raw]
Subject: [PATCHv3 08/16] clk: mvebu: add suspend/resume for gatable clocks

This commit adds suspend/resume support for the gatable clock driver
used on Marvell EBU platforms. When getting out of suspend, the
Marvell EBU platforms go through the bootloader, which re-enables all
gatable clocks. However, upon resume, the clock framework will not
disable again all gatable clocks that are not used.

Therefore, if the clock driver does not save/restore the state of the
gatable clocks, all gatable clocks that are not claimed by any device
driver will remain enabled after a resume. This is why this driver
saves and restores the state of those clocks.

Since clocks aren't real devices, we don't have the normal ->suspend()
and ->resume() of the device model, and have to use the ->suspend()
and ->resume() hooks of the syscore_ops mechanism. This mechanism has
the unfortunate idea of not providing a way of passing private data,
which requires us to change the driver to make the assumption that
there is only once instance of the gatable clock control structure.

Signed-off-by: Thomas Petazzoni <[email protected]>
Cc: Mike Turquette <[email protected]>
Cc: [email protected]
Acked-by: Gregory CLEMENT <[email protected]>
---
drivers/clk/mvebu/common.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index b7fcb46..0d4d121 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/syscore_ops.h>

#include "common.h"

@@ -177,14 +178,17 @@ struct clk_gating_ctrl {
spinlock_t *lock;
struct clk **gates;
int num_gates;
+ void __iomem *base;
+ u32 saved_reg;
};

#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)

+static struct clk_gating_ctrl *ctrl;
+
static struct clk *clk_gating_get_src(
struct of_phandle_args *clkspec, void *data)
{
- struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data;
int n;

if (clkspec->args_count < 1)
@@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src(
return ERR_PTR(-ENODEV);
}

+static int mvebu_clk_gating_suspend(void)
+{
+ ctrl->saved_reg = readl(ctrl->base);
+ return 0;
+}
+
+static void mvebu_clk_gating_resume(void)
+{
+ writel(ctrl->saved_reg, ctrl->base);
+}
+
+static struct syscore_ops clk_gate_syscore_ops = {
+ .suspend = mvebu_clk_gating_suspend,
+ .resume = mvebu_clk_gating_resume,
+};
+
void __init mvebu_clk_gating_setup(struct device_node *np,
const struct clk_gating_soc_desc *desc)
{
- struct clk_gating_ctrl *ctrl;
struct clk *clk;
void __iomem *base;
const char *default_parent = NULL;
int n;

+ if (ctrl) {
+ pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n");
+ return;
+ }
+
base = of_iomap(np, 0);
if (WARN_ON(!base))
return;
@@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
/* lock must already be initialized */
ctrl->lock = &ctrl_gating_lock;

+ ctrl->base = base;
+
/* Count, allocate, and register clock gates */
for (n = 0; desc[n].name;)
n++;
@@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,

of_clk_add_provider(np, clk_gating_get_src, ctrl);

+ register_syscore_ops(&clk_gate_syscore_ops);
+
return;
gates_out:
kfree(ctrl);
--
2.1.0


2014-11-25 06:07:08

by Mike Turquette

[permalink] [raw]
Subject: Re: [PATCHv3 08/16] clk: mvebu: add suspend/resume for gatable clocks

Quoting Thomas Petazzoni (2014-11-21 08:00:05)
> This commit adds suspend/resume support for the gatable clock driver
> used on Marvell EBU platforms. When getting out of suspend, the
> Marvell EBU platforms go through the bootloader, which re-enables all
> gatable clocks. However, upon resume, the clock framework will not
> disable again all gatable clocks that are not used.
>
> Therefore, if the clock driver does not save/restore the state of the
> gatable clocks, all gatable clocks that are not claimed by any device
> driver will remain enabled after a resume. This is why this driver
> saves and restores the state of those clocks.
>
> Since clocks aren't real devices, we don't have the normal ->suspend()
> and ->resume() of the device model, and have to use the ->suspend()
> and ->resume() hooks of the syscore_ops mechanism. This mechanism has
> the unfortunate idea of not providing a way of passing private data,
> which requires us to change the driver to make the assumption that
> there is only once instance of the gatable clock control structure.
>
> Signed-off-by: Thomas Petazzoni <[email protected]>
> Cc: Mike Turquette <[email protected]>
> Cc: [email protected]
> Acked-by: Gregory CLEMENT <[email protected]>

Looks good to me. Which tree do you plan to take this through?

Regards,
Mike

> ---
> drivers/clk/mvebu/common.c | 32 ++++++++++++++++++++++++++++++--
> 1 file changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
> index b7fcb46..0d4d121 100644
> --- a/drivers/clk/mvebu/common.c
> +++ b/drivers/clk/mvebu/common.c
> @@ -19,6 +19,7 @@
> #include <linux/io.h>
> #include <linux/of.h>
> #include <linux/of_address.h>
> +#include <linux/syscore_ops.h>
>
> #include "common.h"
>
> @@ -177,14 +178,17 @@ struct clk_gating_ctrl {
> spinlock_t *lock;
> struct clk **gates;
> int num_gates;
> + void __iomem *base;
> + u32 saved_reg;
> };
>
> #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
>
> +static struct clk_gating_ctrl *ctrl;
> +
> static struct clk *clk_gating_get_src(
> struct of_phandle_args *clkspec, void *data)
> {
> - struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data;
> int n;
>
> if (clkspec->args_count < 1)
> @@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src(
> return ERR_PTR(-ENODEV);
> }
>
> +static int mvebu_clk_gating_suspend(void)
> +{
> + ctrl->saved_reg = readl(ctrl->base);
> + return 0;
> +}
> +
> +static void mvebu_clk_gating_resume(void)
> +{
> + writel(ctrl->saved_reg, ctrl->base);
> +}
> +
> +static struct syscore_ops clk_gate_syscore_ops = {
> + .suspend = mvebu_clk_gating_suspend,
> + .resume = mvebu_clk_gating_resume,
> +};
> +
> void __init mvebu_clk_gating_setup(struct device_node *np,
> const struct clk_gating_soc_desc *desc)
> {
> - struct clk_gating_ctrl *ctrl;
> struct clk *clk;
> void __iomem *base;
> const char *default_parent = NULL;
> int n;
>
> + if (ctrl) {
> + pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n");
> + return;
> + }
> +
> base = of_iomap(np, 0);
> if (WARN_ON(!base))
> return;
> @@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
> /* lock must already be initialized */
> ctrl->lock = &ctrl_gating_lock;
>
> + ctrl->base = base;
> +
> /* Count, allocate, and register clock gates */
> for (n = 0; desc[n].name;)
> n++;
> @@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
>
> of_clk_add_provider(np, clk_gating_get_src, ctrl);
>
> + register_syscore_ops(&clk_gate_syscore_ops);
> +
> return;
> gates_out:
> kfree(ctrl);
> --
> 2.1.0
>

2014-11-25 06:48:09

by Thomas Petazzoni

[permalink] [raw]
Subject: Re: [PATCHv3 08/16] clk: mvebu: add suspend/resume for gatable clocks

Mike,

On Mon, 24 Nov 2014 22:07:00 -0800, Mike Turquette wrote:
> Quoting Thomas Petazzoni (2014-11-21 08:00:05)
> > This commit adds suspend/resume support for the gatable clock driver
> > used on Marvell EBU platforms. When getting out of suspend, the
> > Marvell EBU platforms go through the bootloader, which re-enables all
> > gatable clocks. However, upon resume, the clock framework will not
> > disable again all gatable clocks that are not used.
> >
> > Therefore, if the clock driver does not save/restore the state of the
> > gatable clocks, all gatable clocks that are not claimed by any device
> > driver will remain enabled after a resume. This is why this driver
> > saves and restores the state of those clocks.
> >
> > Since clocks aren't real devices, we don't have the normal ->suspend()
> > and ->resume() of the device model, and have to use the ->suspend()
> > and ->resume() hooks of the syscore_ops mechanism. This mechanism has
> > the unfortunate idea of not providing a way of passing private data,
> > which requires us to change the driver to make the assumption that
> > there is only once instance of the gatable clock control structure.
> >
> > Signed-off-by: Thomas Petazzoni <[email protected]>
> > Cc: Mike Turquette <[email protected]>
> > Cc: [email protected]
> > Acked-by: Gregory CLEMENT <[email protected]>
>
> Looks good to me. Which tree do you plan to take this through?

I don't have any specific plans. Jason, do you have other clk changes
for 3.19, which justify a pull request from you to Mike? Or could Mike
just take this patch in his tree? There is no build dependency between
this patch and the other patches in the series, so it can go through
whatever tree.

Thanks,

Thomas
--
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

2014-11-26 04:03:29

by Jason Cooper

[permalink] [raw]
Subject: Re: [PATCHv3 08/16] clk: mvebu: add suspend/resume for gatable clocks

On Tue, Nov 25, 2014 at 07:48:01AM +0100, Thomas Petazzoni wrote:
> Mike,
>
> On Mon, 24 Nov 2014 22:07:00 -0800, Mike Turquette wrote:
> > Quoting Thomas Petazzoni (2014-11-21 08:00:05)
> > > This commit adds suspend/resume support for the gatable clock driver
> > > used on Marvell EBU platforms. When getting out of suspend, the
> > > Marvell EBU platforms go through the bootloader, which re-enables all
> > > gatable clocks. However, upon resume, the clock framework will not
> > > disable again all gatable clocks that are not used.
> > >
> > > Therefore, if the clock driver does not save/restore the state of the
> > > gatable clocks, all gatable clocks that are not claimed by any device
> > > driver will remain enabled after a resume. This is why this driver
> > > saves and restores the state of those clocks.
> > >
> > > Since clocks aren't real devices, we don't have the normal ->suspend()
> > > and ->resume() of the device model, and have to use the ->suspend()
> > > and ->resume() hooks of the syscore_ops mechanism. This mechanism has
> > > the unfortunate idea of not providing a way of passing private data,
> > > which requires us to change the driver to make the assumption that
> > > there is only once instance of the gatable clock control structure.
> > >
> > > Signed-off-by: Thomas Petazzoni <[email protected]>
> > > Cc: Mike Turquette <[email protected]>
> > > Cc: [email protected]
> > > Acked-by: Gregory CLEMENT <[email protected]>
> >
> > Looks good to me. Which tree do you plan to take this through?
>
> I don't have any specific plans. Jason, do you have other clk changes
> for 3.19, which justify a pull request from you to Mike? Or could Mike
> just take this patch in his tree? There is no build dependency between
> this patch and the other patches in the series, so it can go through
> whatever tree.

Well, I pulled the whole series into mvebu/soc-suspend to give it some
time in -next. It'd be easiest, with my current schedule, to send a
PR for it as-is. If that's ok with Mike, I'd appreciate it. Obviously,
I wouldn't make a habit of it... :-P

thx,

Jason.