From 9a89ed9d281ec1aac0b105456b414bcbda8f4383 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 12 Jan 2017 09:49:17 +0100 Subject: clk: imx: Add clk-cpu support Taken from the kernel as of 4.10-rc3. Needed for i.MX7 Signed-off-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-cpu.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/imx/clk.h | 3 ++ 3 files changed, 114 insertions(+) create mode 100644 drivers/clk/imx/clk-cpu.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 65d7859ed3..636bfdc2ef 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_COMMON_CLK) += \ clk-pfd.o \ clk-gate2.o \ clk-gate-exclusive.o \ + clk-cpu.o \ clk.o obj-$(CONFIG_ARCH_IMX1) += clk-imx1.o diff --git a/drivers/clk/imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c new file mode 100644 index 0000000000..bd1749fd87 --- /dev/null +++ b/drivers/clk/imx/clk-cpu.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014 Lucas Stach , Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +struct clk_cpu { + struct clk clk; + struct clk *div; + struct clk *mux; + struct clk *pll; + struct clk *step; +}; + +static inline struct clk_cpu *to_clk_cpu(struct clk *clk) +{ + return container_of(clk, struct clk_cpu, clk); +} + +static unsigned long clk_cpu_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct clk_cpu *cpu = to_clk_cpu(clk); + + return clk_get_rate(cpu->div); +} + +static long clk_cpu_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + struct clk_cpu *cpu = to_clk_cpu(clk); + + return clk_round_rate(cpu->pll, rate); +} + +static int clk_cpu_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_cpu *cpu = to_clk_cpu(clk); + int ret; + + /* switch to PLL bypass clock */ + ret = clk_set_parent(cpu->mux, cpu->step); + if (ret) + return ret; + + /* reprogram PLL */ + ret = clk_set_rate(cpu->pll, rate); + if (ret) { + clk_set_parent(cpu->mux, cpu->pll); + return ret; + } + /* switch back to PLL clock */ + clk_set_parent(cpu->mux, cpu->pll); + + /* Ensure the divider is what we expect */ + clk_set_rate(cpu->div, rate); + + return 0; +} + +static const struct clk_ops clk_cpu_ops = { + .recalc_rate = clk_cpu_recalc_rate, + .round_rate = clk_cpu_round_rate, + .set_rate = clk_cpu_set_rate, +}; + +struct clk *imx_clk_cpu(const char *name, const char *parent_name, + struct clk *div, struct clk *mux, struct clk *pll, + struct clk *step) +{ + struct clk_cpu *cpu; + int ret; + + cpu = xzalloc(sizeof(*cpu)); + + cpu->div = div; + cpu->mux = mux; + cpu->pll = pll; + cpu->step = step; + + cpu->clk.name = name; + cpu->clk.ops = &clk_cpu_ops; + cpu->clk.flags = 0; + cpu->clk.parent_names = &parent_name; + cpu->clk.num_parents = 1; + + ret = clk_register(&cpu->clk); + if (ret) + free(cpu); + + return &cpu->clk; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 1dbfbf7115..362b1592ad 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -125,5 +125,8 @@ struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void imx_check_clocks(struct clk *clks[], unsigned int count); +struct clk *imx_clk_cpu(const char *name, const char *parent_name, + struct clk *div, struct clk *mux, struct clk *pll, + struct clk *step); #endif /* __IMX_CLK_H */ -- cgit v1.2.3