diff options
| -rw-r--r-- | arch/arm/mach-imx/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-imx/clk-cpu.c | 107 | ||||
| -rw-r--r-- | arch/arm/mach-imx/clk.h | 4 |
3 files changed, 112 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 6e4fcd8339cd..b8580f363e51 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
| @@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci- | |||
| 12 | obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o | 12 | obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o |
| 13 | 13 | ||
| 14 | imx5-pm-$(CONFIG_PM) += pm-imx5.o | 14 | imx5-pm-$(CONFIG_PM) += pm-imx5.o |
| 15 | obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o $(imx5-pm-y) | 15 | obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y) |
| 16 | 16 | ||
| 17 | obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ | 17 | obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ |
| 18 | clk-pfd.o clk-busy.o clk.o \ | 18 | clk-pfd.o clk-busy.o clk.o \ |
diff --git a/arch/arm/mach-imx/clk-cpu.c b/arch/arm/mach-imx/clk-cpu.c new file mode 100644 index 000000000000..aa1c345e2a19 --- /dev/null +++ b/arch/arm/mach-imx/clk-cpu.c | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * http://www.opensource.org/licenses/gpl-license.html | ||
| 9 | * http://www.gnu.org/copyleft/gpl.html | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/clk.h> | ||
| 13 | #include <linux/clk-provider.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | |||
| 16 | struct clk_cpu { | ||
| 17 | struct clk_hw hw; | ||
| 18 | struct clk *div; | ||
| 19 | struct clk *mux; | ||
| 20 | struct clk *pll; | ||
| 21 | struct clk *step; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw) | ||
| 25 | { | ||
| 26 | return container_of(hw, struct clk_cpu, hw); | ||
| 27 | } | ||
| 28 | |||
| 29 | static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw, | ||
| 30 | unsigned long parent_rate) | ||
| 31 | { | ||
| 32 | struct clk_cpu *cpu = to_clk_cpu(hw); | ||
| 33 | |||
| 34 | return clk_get_rate(cpu->div); | ||
| 35 | } | ||
| 36 | |||
| 37 | static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 38 | unsigned long *prate) | ||
| 39 | { | ||
| 40 | struct clk_cpu *cpu = to_clk_cpu(hw); | ||
| 41 | |||
| 42 | return clk_round_rate(cpu->pll, rate); | ||
| 43 | } | ||
| 44 | |||
| 45 | static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 46 | unsigned long parent_rate) | ||
| 47 | { | ||
| 48 | struct clk_cpu *cpu = to_clk_cpu(hw); | ||
| 49 | int ret; | ||
| 50 | |||
| 51 | /* switch to PLL bypass clock */ | ||
| 52 | ret = clk_set_parent(cpu->mux, cpu->step); | ||
| 53 | if (ret) | ||
| 54 | return ret; | ||
| 55 | |||
| 56 | /* reprogram PLL */ | ||
| 57 | ret = clk_set_rate(cpu->pll, rate); | ||
| 58 | if (ret) { | ||
| 59 | clk_set_parent(cpu->mux, cpu->pll); | ||
| 60 | return ret; | ||
| 61 | } | ||
| 62 | /* switch back to PLL clock */ | ||
| 63 | clk_set_parent(cpu->mux, cpu->pll); | ||
| 64 | |||
| 65 | /* Ensure the divider is what we expect */ | ||
| 66 | clk_set_rate(cpu->div, rate); | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static const struct clk_ops clk_cpu_ops = { | ||
| 72 | .recalc_rate = clk_cpu_recalc_rate, | ||
| 73 | .round_rate = clk_cpu_round_rate, | ||
| 74 | .set_rate = clk_cpu_set_rate, | ||
| 75 | }; | ||
| 76 | |||
| 77 | struct clk *imx_clk_cpu(const char *name, const char *parent_name, | ||
| 78 | struct clk *div, struct clk *mux, struct clk *pll, | ||
| 79 | struct clk *step) | ||
| 80 | { | ||
| 81 | struct clk_cpu *cpu; | ||
| 82 | struct clk *clk; | ||
| 83 | struct clk_init_data init; | ||
| 84 | |||
| 85 | cpu = kzalloc(sizeof(*cpu), GFP_KERNEL); | ||
| 86 | if (!cpu) | ||
| 87 | return ERR_PTR(-ENOMEM); | ||
| 88 | |||
| 89 | cpu->div = div; | ||
| 90 | cpu->mux = mux; | ||
| 91 | cpu->pll = pll; | ||
| 92 | cpu->step = step; | ||
| 93 | |||
| 94 | init.name = name; | ||
| 95 | init.ops = &clk_cpu_ops; | ||
| 96 | init.flags = 0; | ||
| 97 | init.parent_names = &parent_name; | ||
| 98 | init.num_parents = 1; | ||
| 99 | |||
| 100 | cpu->hw.init = &init; | ||
| 101 | |||
| 102 | clk = clk_register(NULL, &cpu->hw); | ||
| 103 | if (IS_ERR(clk)) | ||
| 104 | kfree(cpu); | ||
| 105 | |||
| 106 | return clk; | ||
| 107 | } | ||
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 4cdf8b6a74e8..5ef82e2f8fc5 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h | |||
| @@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, | |||
| 131 | CLK_SET_RATE_PARENT, mult, div); | 131 | CLK_SET_RATE_PARENT, mult, div); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | struct clk *imx_clk_cpu(const char *name, const char *parent_name, | ||
| 135 | struct clk *div, struct clk *mux, struct clk *pll, | ||
| 136 | struct clk *step); | ||
| 137 | |||
| 134 | #endif | 138 | #endif |
