ipq806x: Add support for IPQ806x chip family
[openwrt/staging/wigyori.git] / target / linux / ipq806x / patches / 0169-clk-qcom-Add-support-for-Krait-clocks.patch
1 From 63ecfef8560631a15ee13129b2778cd4dffbcfe2 Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Wed, 18 Jun 2014 14:18:31 -0700
4 Subject: [PATCH 169/182] clk: qcom: Add support for Krait clocks
5
6 The Krait clocks are made up of a series of muxes and a divider
7 that choose between a fixed rate clock and dedicated HFPLLs for
8 each CPU. Instead of using mmio accesses to remux parents, the
9 Krait implementation exposes the remux control via cp15
10 registers. Support these clocks.
11
12 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
13 ---
14 drivers/clk/qcom/Kconfig | 4 ++
15 drivers/clk/qcom/Makefile | 1 +
16 drivers/clk/qcom/clk-krait.c | 121 ++++++++++++++++++++++++++++++++++++++++++
17 drivers/clk/qcom/clk-krait.h | 22 ++++++++
18 4 files changed, 148 insertions(+)
19 create mode 100644 drivers/clk/qcom/clk-krait.c
20 create mode 100644 drivers/clk/qcom/clk-krait.h
21
22 diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
23 index de8ba31..70b6a7c 100644
24 --- a/drivers/clk/qcom/Kconfig
25 +++ b/drivers/clk/qcom/Kconfig
26 @@ -61,3 +61,7 @@ config QCOM_HFPLL
27 Support for the high-frequency PLLs present on Qualcomm devices.
28 Say Y if you want to support CPU frequency scaling on devices
29 such as MSM8974, APQ8084, etc.
30 +
31 +config KRAIT_CLOCKS
32 + bool
33 + select KRAIT_L2_ACCESSORS
34 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
35 index d0d8e3d..6482165 100644
36 --- a/drivers/clk/qcom/Makefile
37 +++ b/drivers/clk/qcom/Makefile
38 @@ -7,6 +7,7 @@ clk-qcom-y += clk-rcg.o
39 clk-qcom-y += clk-rcg2.o
40 clk-qcom-y += clk-branch.o
41 clk-qcom-y += clk-generic.o
42 +clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
43 clk-qcom-y += clk-hfpll.o
44 clk-qcom-y += reset.o
45
46 diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c
47 new file mode 100644
48 index 0000000..4283426
49 --- /dev/null
50 +++ b/drivers/clk/qcom/clk-krait.c
51 @@ -0,0 +1,121 @@
52 +/*
53 + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
54 + *
55 + * This program is free software; you can redistribute it and/or modify
56 + * it under the terms of the GNU General Public License version 2 and
57 + * only version 2 as published by the Free Software Foundation.
58 + *
59 + * This program is distributed in the hope that it will be useful,
60 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
61 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62 + * GNU General Public License for more details.
63 + */
64 +
65 +#include <linux/kernel.h>
66 +#include <linux/module.h>
67 +#include <linux/init.h>
68 +#include <linux/io.h>
69 +#include <linux/delay.h>
70 +#include <linux/err.h>
71 +#include <linux/clk-provider.h>
72 +#include <linux/spinlock.h>
73 +
74 +#include <asm/krait-l2-accessors.h>
75 +
76 +#include "clk-krait.h"
77 +
78 +/* Secondary and primary muxes share the same cp15 register */
79 +static DEFINE_SPINLOCK(kpss_clock_reg_lock);
80 +
81 +#define LPL_SHIFT 8
82 +static void __kpss_mux_set_sel(struct mux_clk *mux, int sel)
83 +{
84 + unsigned long flags;
85 + u32 regval;
86 +
87 + spin_lock_irqsave(&kpss_clock_reg_lock, flags);
88 + regval = krait_get_l2_indirect_reg(mux->offset);
89 + regval &= ~(mux->mask << mux->shift);
90 + regval |= (sel & mux->mask) << mux->shift;
91 + if (mux->priv) {
92 + regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
93 + regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
94 + }
95 + krait_set_l2_indirect_reg(mux->offset, regval);
96 + spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
97 +
98 + /* Wait for switch to complete. */
99 + mb();
100 + udelay(1);
101 +}
102 +
103 +static int kpss_mux_set_sel(struct mux_clk *mux, int sel)
104 +{
105 + mux->en_mask = sel;
106 + /* Don't touch mux if CPU is off as it won't work */
107 + if (__clk_is_enabled(mux->hw.clk))
108 + __kpss_mux_set_sel(mux, sel);
109 + return 0;
110 +}
111 +
112 +static int kpss_mux_get_sel(struct mux_clk *mux)
113 +{
114 + u32 sel;
115 +
116 + sel = krait_get_l2_indirect_reg(mux->offset);
117 + sel >>= mux->shift;
118 + sel &= mux->mask;
119 + mux->en_mask = sel;
120 +
121 + return sel;
122 +}
123 +
124 +static int kpss_mux_enable(struct mux_clk *mux)
125 +{
126 + __kpss_mux_set_sel(mux, mux->en_mask);
127 + return 0;
128 +}
129 +
130 +static void kpss_mux_disable(struct mux_clk *mux)
131 +{
132 + __kpss_mux_set_sel(mux, mux->safe_sel);
133 +}
134 +
135 +const struct clk_mux_ops clk_mux_ops_kpss = {
136 + .enable = kpss_mux_enable,
137 + .disable = kpss_mux_disable,
138 + .set_mux_sel = kpss_mux_set_sel,
139 + .get_mux_sel = kpss_mux_get_sel,
140 +};
141 +EXPORT_SYMBOL_GPL(clk_mux_ops_kpss);
142 +
143 +/*
144 + * The divider can divide by 2, 4, 6 and 8. But we only really need div-2. So
145 + * force it to div-2 during handoff and treat it like a fixed div-2 clock.
146 + */
147 +static int kpss_div2_get_div(struct div_clk *div)
148 +{
149 + unsigned long flags;
150 + u32 regval;
151 + int val;
152 +
153 + spin_lock_irqsave(&kpss_clock_reg_lock, flags);
154 + regval = krait_get_l2_indirect_reg(div->offset);
155 + val = (regval >> div->shift) & div->mask;
156 + regval &= ~(div->mask << div->shift);
157 + if (div->priv)
158 + regval &= ~(div->mask << (div->shift + LPL_SHIFT));
159 + krait_set_l2_indirect_reg(div->offset, regval);
160 + spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
161 +
162 + val = (val + 1) * 2;
163 + WARN(val != 2, "Divider %s was configured to div-%d instead of 2!\n",
164 + __clk_get_name(div->hw.clk), val);
165 +
166 + return 2;
167 +}
168 +
169 +const struct clk_div_ops clk_div_ops_kpss_div2 = {
170 + .get_div = kpss_div2_get_div,
171 +};
172 +EXPORT_SYMBOL_GPL(clk_div_ops_kpss_div2);
173 diff --git a/drivers/clk/qcom/clk-krait.h b/drivers/clk/qcom/clk-krait.h
174 new file mode 100644
175 index 0000000..9c3eb38
176 --- /dev/null
177 +++ b/drivers/clk/qcom/clk-krait.h
178 @@ -0,0 +1,22 @@
179 +/*
180 + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
181 + *
182 + * This program is free software; you can redistribute it and/or modify
183 + * it under the terms of the GNU General Public License version 2 and
184 + * only version 2 as published by the Free Software Foundation.
185 + *
186 + * This program is distributed in the hope that it will be useful,
187 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
188 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
189 + * GNU General Public License for more details.
190 + */
191 +
192 +#ifndef __SOC_QCOM_CLOCK_KRAIT_H
193 +#define __SOC_QCOM_CLOCK_KRAIT_H
194 +
195 +#include <linux/clk/msm-clk-generic.h>
196 +
197 +extern const struct clk_mux_ops clk_mux_ops_kpss;
198 +extern const struct clk_div_ops clk_div_ops_kpss_div2;
199 +
200 +#endif
201 --
202 1.7.10.4
203