summaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/at91/clk-main.c7
-rw-r--r--drivers/clk/at91/clk-master.c7
-rw-r--r--drivers/clk/at91/clk-peripheral.c6
-rw-r--r--drivers/clk/at91/clk-programmable.c40
-rw-r--r--drivers/clk/at91/clk-slow.c16
-rw-r--r--drivers/clk/at91/clk-smd.c7
-rw-r--r--drivers/clk/at91/clk-usb.c47
-rw-r--r--drivers/clk/at91/pmc.c1
-rw-r--r--drivers/clk/at91/pmc.h124
-rw-r--r--drivers/clk/bcm/clk-kona.c53
-rw-r--r--drivers/clk/berlin/berlin2-pll.c4
-rw-r--r--drivers/clk/clk-axi-clkgen.c1
-rw-r--r--drivers/clk/clk-bcm2835.c5
-rw-r--r--drivers/clk/clk-cdce706.c3
-rw-r--r--drivers/clk/clk-cdce925.c1
-rw-r--r--drivers/clk/clk-clps711x.c1
-rw-r--r--drivers/clk/clk-composite.c61
-rw-r--r--drivers/clk/clk-divider.c28
-rw-r--r--drivers/clk/clk-efm32gg.c1
-rw-r--r--drivers/clk/clk-fixed-factor.c5
-rw-r--r--drivers/clk/clk-fractional-divider.c8
-rw-r--r--drivers/clk/clk-gate.c4
-rw-r--r--drivers/clk/clk-gpio-gate.c207
-rw-r--r--drivers/clk/clk-gpio.c325
-rw-r--r--drivers/clk/clk-highbank.c1
-rw-r--r--drivers/clk/clk-moxart.c1
-rw-r--r--drivers/clk/clk-mux.c7
-rw-r--r--drivers/clk/clk-nomadik.c3
-rw-r--r--drivers/clk/clk-palmas.c1
-rw-r--r--drivers/clk/clk-rk808.c1
-rw-r--r--drivers/clk/clk-s2mps11.c32
-rw-r--r--drivers/clk/clk-si5351.c22
-rw-r--r--drivers/clk/clk-si570.c1
-rw-r--r--drivers/clk/clk-stm32f4.c5
-rw-r--r--drivers/clk/clk-twl6040.c13
-rw-r--r--drivers/clk/clk-u300.c2
-rw-r--r--drivers/clk/clk-wm831x.c1
-rw-r--r--drivers/clk/clk-xgene.c28
-rw-r--r--drivers/clk/clk.c346
-rw-r--r--drivers/clk/h8300/clk-div.c4
-rw-r--r--drivers/clk/h8300/clk-h8s2678.c20
-rw-r--r--drivers/clk/hisilicon/Kconfig2
-rw-r--r--drivers/clk/hisilicon/Makefile2
-rw-r--r--drivers/clk/hisilicon/clk-hi3620.c41
-rw-r--r--drivers/clk/hisilicon/clk-hi6220-stub.c276
-rw-r--r--drivers/clk/hisilicon/clk-hip04.c2
-rw-r--r--drivers/clk/hisilicon/clk.c14
-rw-r--r--drivers/clk/hisilicon/clkgate-separated.c2
-rw-r--r--drivers/clk/imx/Makefile1
-rw-r--r--drivers/clk/imx/clk-imx1.c1
-rw-r--r--drivers/clk/imx/clk-imx21.c1
-rw-r--r--drivers/clk/imx/clk-imx31.c3
-rw-r--r--drivers/clk/imx/clk-imx35.c6
-rw-r--r--drivers/clk/imx/clk-imx6q.c7
-rw-r--r--drivers/clk/imx/clk-imx6ul.c432
-rw-r--r--drivers/clk/imx/clk-pfd.c1
-rw-r--r--drivers/clk/imx/clk-pllv1.c1
-rw-r--r--drivers/clk/imx/clk-pllv3.c1
-rw-r--r--drivers/clk/ingenic/cgu.c1
-rw-r--r--drivers/clk/keystone/gate.c1
-rw-r--r--drivers/clk/keystone/pll.c4
-rw-r--r--drivers/clk/mediatek/clk-gate.h3
-rw-r--r--drivers/clk/mediatek/clk-mt8135.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8173.c25
-rw-r--r--drivers/clk/mediatek/clk-mtk.h9
-rw-r--r--drivers/clk/mediatek/clk-pll.c39
-rw-r--r--drivers/clk/meson/clk-cpu.c1
-rw-r--r--drivers/clk/meson/clkc.c1
-rw-r--r--drivers/clk/mmp/clk-apbc.c1
-rw-r--r--drivers/clk/mmp/clk-apmu.c1
-rw-r--r--drivers/clk/mmp/clk-gate.c3
-rw-r--r--drivers/clk/mmp/clk-mix.c71
-rw-r--r--drivers/clk/mmp/clk.c3
-rw-r--r--drivers/clk/mvebu/clk-cpu.c9
-rw-r--r--drivers/clk/mvebu/common.c2
-rw-r--r--drivers/clk/mxs/clk-div.c1
-rw-r--r--drivers/clk/mxs/clk-frac.c1
-rw-r--r--drivers/clk/mxs/clk-imx23.c3
-rw-r--r--drivers/clk/mxs/clk-imx28.c2
-rw-r--r--drivers/clk/mxs/clk-pll.c1
-rw-r--r--drivers/clk/mxs/clk-ref.c1
-rw-r--r--drivers/clk/mxs/clk.h3
-rw-r--r--drivers/clk/nxp/clk-lpc18xx-cgu.c1
-rw-r--r--drivers/clk/pistachio/clk-pistachio.c19
-rw-r--r--drivers/clk/pistachio/clk-pll.c81
-rw-r--r--drivers/clk/pistachio/clk.c1
-rw-r--r--drivers/clk/pistachio/clk.h14
-rw-r--r--drivers/clk/pxa/clk-pxa25x.c2
-rw-r--r--drivers/clk/pxa/clk-pxa27x.c2
-rw-r--r--drivers/clk/pxa/clk-pxa3xx.c4
-rw-r--r--drivers/clk/qcom/clk-branch.c2
-rw-r--r--drivers/clk/qcom/clk-pll.c93
-rw-r--r--drivers/clk/qcom/clk-pll.h1
-rw-r--r--drivers/clk/qcom/clk-rcg.c63
-rw-r--r--drivers/clk/qcom/clk-rcg2.c97
-rw-r--r--drivers/clk/qcom/common.c5
-rw-r--r--drivers/clk/qcom/gcc-apq8084.c13
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c10
-rw-r--r--drivers/clk/qcom/gcc-msm8660.c8
-rw-r--r--drivers/clk/qcom/gcc-msm8916.c26
-rw-r--r--drivers/clk/qcom/gcc-msm8960.c12
-rw-r--r--drivers/clk/qcom/gcc-msm8974.c5
-rw-r--r--drivers/clk/qcom/lcc-ipq806x.c6
-rw-r--r--drivers/clk/qcom/lcc-msm8960.c8
-rw-r--r--drivers/clk/qcom/mmcc-apq8084.c20
-rw-r--r--drivers/clk/qcom/mmcc-msm8960.c27
-rw-r--r--drivers/clk/qcom/mmcc-msm8974.c16
-rw-r--r--drivers/clk/rockchip/Makefile2
-rw-r--r--drivers/clk/rockchip/clk-cpu.c1
-rw-r--r--drivers/clk/rockchip/clk-inverter.c116
-rw-r--r--drivers/clk/rockchip/clk-mmc-phase.c9
-rw-r--r--drivers/clk/rockchip/clk-pll.c100
-rw-r--r--drivers/clk/rockchip/clk-rk3188.c18
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c15
-rw-r--r--drivers/clk/rockchip/clk-rk3368.c881
-rw-r--r--drivers/clk/rockchip/clk.c7
-rw-r--r--drivers/clk/rockchip/clk.h82
-rw-r--r--drivers/clk/samsung/clk-cpu.c7
-rw-r--r--drivers/clk/samsung/clk-exynos-audss.c3
-rw-r--r--drivers/clk/samsung/clk-exynos-clkout.c2
-rw-r--r--drivers/clk/samsung/clk-exynos3250.c34
-rw-r--r--drivers/clk/samsung/clk-exynos4.c4
-rw-r--r--drivers/clk/samsung/clk-exynos4415.c2
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c33
-rw-r--r--drivers/clk/samsung/clk-exynos5260.c2
-rw-r--r--drivers/clk/samsung/clk-exynos5410.c2
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c3
-rw-r--r--drivers/clk/samsung/clk-exynos5433.c2
-rw-r--r--drivers/clk/samsung/clk-exynos5440.c2
-rw-r--r--drivers/clk/samsung/clk-exynos7.c2
-rw-r--r--drivers/clk/samsung/clk-pll.c20
-rw-r--r--drivers/clk/samsung/clk-s3c2410-dclk.c6
-rw-r--r--drivers/clk/samsung/clk-s3c2410.c2
-rw-r--r--drivers/clk/samsung/clk-s3c2412.c2
-rw-r--r--drivers/clk/samsung/clk-s3c2443.c2
-rw-r--r--drivers/clk/samsung/clk-s3c64xx.c3
-rw-r--r--drivers/clk/samsung/clk-s5pv210-audss.c2
-rw-r--r--drivers/clk/samsung/clk-s5pv210.c4
-rw-r--r--drivers/clk/samsung/clk.c4
-rw-r--r--drivers/clk/samsung/clk.h3
-rw-r--r--drivers/clk/shmobile/clk-div6.c8
-rw-r--r--drivers/clk/shmobile/clk-mstp.c87
-rw-r--r--drivers/clk/shmobile/clk-r8a73a4.c2
-rw-r--r--drivers/clk/shmobile/clk-r8a7740.c2
-rw-r--r--drivers/clk/shmobile/clk-r8a7778.c4
-rw-r--r--drivers/clk/shmobile/clk-r8a7779.c4
-rw-r--r--drivers/clk/shmobile/clk-rcar-gen2.c4
-rw-r--r--drivers/clk/shmobile/clk-rz.c3
-rw-r--r--drivers/clk/shmobile/clk-sh73a0.c2
-rw-r--r--drivers/clk/sirf/clk-atlas6.c1
-rw-r--r--drivers/clk/sirf/clk-atlas7.c25
-rw-r--r--drivers/clk/sirf/clk-common.c14
-rw-r--r--drivers/clk/sirf/clk-prima2.c1
-rw-r--r--drivers/clk/socfpga/clk-gate-a10.c3
-rw-r--r--drivers/clk/socfpga/clk-gate.c5
-rw-r--r--drivers/clk/socfpga/clk-periph-a10.c3
-rw-r--r--drivers/clk/socfpga/clk-periph.c23
-rw-r--r--drivers/clk/socfpga/clk-pll-a10.c1
-rw-r--r--drivers/clk/socfpga/clk-pll.c3
-rw-r--r--drivers/clk/socfpga/clk.h3
-rw-r--r--drivers/clk/spear/clk-aux-synth.c2
-rw-r--r--drivers/clk/spear/clk-frac-synth.c2
-rw-r--r--drivers/clk/spear/clk-gpt-synth.c2
-rw-r--r--drivers/clk/spear/clk-vco-pll.c4
-rw-r--r--drivers/clk/spear/clk.c2
-rw-r--r--drivers/clk/spear/clk.h2
-rw-r--r--drivers/clk/spear/spear1310_clock.c3
-rw-r--r--drivers/clk/spear/spear1340_clock.c3
-rw-r--r--drivers/clk/spear/spear3xx_clock.c2
-rw-r--r--drivers/clk/spear/spear6xx_clock.c3
-rw-r--r--drivers/clk/st/clk-flexgen.c13
-rw-r--r--drivers/clk/st/clkgen-fsyn.c19
-rw-r--r--drivers/clk/st/clkgen-mux.c93
-rw-r--r--drivers/clk/st/clkgen-pll.c9
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk-a20-gmac.c4
-rw-r--r--drivers/clk/sunxi/clk-factors.c39
-rw-r--r--drivers/clk/sunxi/clk-mod0.c3
-rw-r--r--drivers/clk/sunxi/clk-simple-gates.c158
-rw-r--r--drivers/clk/sunxi/clk-sun6i-ar100.c36
-rw-r--r--drivers/clk/sunxi/clk-sun8i-mbus.c2
-rw-r--r--drivers/clk/sunxi/clk-sun9i-core.c2
-rw-r--r--drivers/clk/sunxi/clk-sun9i-mmc.c3
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c227
-rw-r--r--drivers/clk/sunxi/clk-usb.c3
-rw-r--r--drivers/clk/tegra/Makefile3
-rw-r--r--drivers/clk/tegra/clk-dfll.c1757
-rw-r--r--drivers/clk/tegra/clk-dfll.h54
-rw-r--r--drivers/clk/tegra/clk-divider.c1
-rw-r--r--drivers/clk/tegra/clk-emc.c36
-rw-r--r--drivers/clk/tegra/clk-periph-gate.c1
-rw-r--r--drivers/clk/tegra/clk-periph.c1
-rw-r--r--drivers/clk/tegra/clk-pll-out.c1
-rw-r--r--drivers/clk/tegra/clk-pll.c20
-rw-r--r--drivers/clk/tegra/clk-super.c1
-rw-r--r--drivers/clk/tegra/clk-tegra-audio.c1
-rw-r--r--drivers/clk/tegra/clk-tegra-fixed.c1
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c1
-rw-r--r--drivers/clk/tegra/clk-tegra-pmc.c1
-rw-r--r--drivers/clk/tegra/clk-tegra-super-gen4.c5
-rw-r--r--drivers/clk/tegra/clk-tegra114.c2
-rw-r--r--drivers/clk/tegra/clk-tegra124-dfll-fcpu.c166
-rw-r--r--drivers/clk/tegra/clk-tegra124.c83
-rw-r--r--drivers/clk/tegra/clk-tegra20.c1
-rw-r--r--drivers/clk/tegra/clk-tegra30.c1
-rw-r--r--drivers/clk/tegra/clk.c40
-rw-r--r--drivers/clk/tegra/clk.h3
-rw-r--r--drivers/clk/tegra/cvb.c140
-rw-r--r--drivers/clk/tegra/cvb.h67
-rw-r--r--drivers/clk/ti/Makefile19
-rw-r--r--drivers/clk/ti/apll.c11
-rw-r--r--drivers/clk/ti/autoidle.c115
-rw-r--r--drivers/clk/ti/clk-2xxx.c4
-rw-r--r--drivers/clk/ti/clk-33xx.c3
-rw-r--r--drivers/clk/ti/clk-3xxx-legacy.c1
-rw-r--r--drivers/clk/ti/clk-3xxx.c235
-rw-r--r--drivers/clk/ti/clk-43xx.c4
-rw-r--r--drivers/clk/ti/clk-44xx.c2
-rw-r--r--drivers/clk/ti/clk-54xx.c2
-rw-r--r--drivers/clk/ti/clk-7xx.c3
-rw-r--r--drivers/clk/ti/clk-814x.c33
-rw-r--r--drivers/clk/ti/clk-816x.c4
-rw-r--r--drivers/clk/ti/clk-dra7-atl.c1
-rw-r--r--drivers/clk/ti/clk.c154
-rw-r--r--drivers/clk/ti/clkt_dflt.c316
-rw-r--r--drivers/clk/ti/clkt_dpll.c370
-rw-r--r--drivers/clk/ti/clkt_iclk.c101
-rw-r--r--drivers/clk/ti/clock.h105
-rw-r--r--drivers/clk/ti/clockdomain.c83
-rw-r--r--drivers/clk/ti/composite.c4
-rw-r--r--drivers/clk/ti/divider.c8
-rw-r--r--drivers/clk/ti/dpll.c9
-rw-r--r--drivers/clk/ti/dpll3xxx.c817
-rw-r--r--drivers/clk/ti/dpll44xx.c227
-rw-r--r--drivers/clk/ti/fapll.c4
-rw-r--r--drivers/clk/ti/fixed-factor.c2
-rw-r--r--drivers/clk/ti/gate.c6
-rw-r--r--drivers/clk/ti/interface.c2
-rw-r--r--drivers/clk/ti/mux.c6
-rw-r--r--drivers/clk/ux500/Makefile1
-rw-r--r--drivers/clk/ux500/abx500-clk.c1
-rw-r--r--drivers/clk/ux500/clk-prcmu.c16
-rw-r--r--drivers/clk/ux500/clk-sysctrl.c2
-rw-r--r--drivers/clk/ux500/clk.h3
-rw-r--r--drivers/clk/ux500/u8500_clk.c526
-rw-r--r--drivers/clk/ux500/u8500_of_clk.c165
-rw-r--r--drivers/clk/ux500/u8540_clk.c198
-rw-r--r--drivers/clk/ux500/u9540_clk.c5
-rw-r--r--drivers/clk/versatile/clk-icst.c5
-rw-r--r--drivers/clk/versatile/clk-impd1.c1
-rw-r--r--drivers/clk/versatile/clk-realview.c5
-rw-r--r--drivers/clk/versatile/clk-sp810.c83
-rw-r--r--drivers/clk/versatile/clk-versatile.c4
-rw-r--r--drivers/clk/zte/Makefile2
-rw-r--r--drivers/clk/zte/clk-zx296702.c126
-rw-r--r--drivers/clk/zte/clk.c (renamed from drivers/clk/zte/clk-pll.c)141
-rw-r--r--drivers/clk/zte/clk.h9
-rw-r--r--drivers/clk/zynq/Makefile2
-rw-r--r--drivers/clk/zynq/clkc.c1
260 files changed, 9135 insertions, 2379 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c4cf075a2320..d08b3e5985be 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
-obj-$(CONFIG_COMMON_CLK) += clk-gpio-gate.o
+obj-$(CONFIG_COMMON_CLK) += clk-gpio.o
ifeq ($(CONFIG_OF), y)
obj-$(CONFIG_COMMON_CLK) += clk-conf.o
endif
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 27dfa965cfed..fd7247deabdc 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -614,17 +614,12 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
int num_parents;
unsigned int irq;
const char *name = np->name;
- int i;
num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > 2)
return;
- for (i = 0; i < num_parents; ++i) {
- parent_names[i] = of_clk_get_parent_name(np, i);
- if (!parent_names[i])
- return;
- }
+ of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index 5b3ded5205a2..620ea323356b 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -222,7 +222,6 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
{
struct clk *clk;
int num_parents;
- int i;
unsigned int irq;
const char *parent_names[MASTER_SOURCE_MAX];
const char *name = np->name;
@@ -232,11 +231,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
return;
- for (i = 0; i < num_parents; ++i) {
- parent_names[i] = of_clk_get_parent_name(np, i);
- if (!parent_names[i])
- return;
- }
+ of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index df2c1afa52b4..e4d7b574f1ea 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -134,7 +134,7 @@ at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
{
- struct clk *parent;
+ struct clk_hw *parent;
unsigned long parent_rate;
int shift = 0;
@@ -142,8 +142,8 @@ static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
return;
if (periph->range.max) {
- parent = clk_get_parent_by_index(periph->hw.clk, 0);
- parent_rate = __clk_get_rate(parent);
+ parent = clk_hw_get_parent_by_index(&periph->hw, 0);
+ parent_rate = clk_hw_get_rate(parent);
if (!parent_rate)
return;
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index 8c86c0f7847a..14b270b85fec 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -54,46 +54,47 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
return parent_rate >> pres;
}
-static long clk_programmable_determine_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_hw)
+static int clk_programmable_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- struct clk *parent = NULL;
+ struct clk_hw *parent;
long best_rate = -EINVAL;
unsigned long parent_rate;
unsigned long tmp_rate;
int shift;
int i;
- for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
- parent = clk_get_parent_by_index(hw->clk, i);
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+ parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_hw_get_rate(parent);
for (shift = 0; shift < PROG_PRES_MASK; shift++) {
tmp_rate = parent_rate >> shift;
- if (tmp_rate <= rate)
+ if (tmp_rate <= req->rate)
break;
}
- if (tmp_rate > rate)
+ if (tmp_rate > req->rate)
continue;
- if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
+ if (best_rate < 0 ||
+ (req->rate - tmp_rate) < (req->rate - best_rate)) {
best_rate = tmp_rate;
- *best_parent_rate = parent_rate;
- *best_parent_hw = __clk_get_hw(parent);
+ req->best_parent_rate = parent_rate;
+ req->best_parent_hw = parent;
}
if (!best_rate)
break;
}
- return best_rate;
+ if (best_rate < 0)
+ return best_rate;
+
+ req->rate = best_rate;
+ return 0;
}
static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
@@ -230,7 +231,6 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
{
int num;
u32 id;
- int i;
struct clk *clk;
int num_parents;
const char *parent_names[PROG_SOURCE_MAX];
@@ -241,11 +241,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
return;
- for (i = 0; i < num_parents; ++i) {
- parent_names[i] = of_clk_get_parent_name(np, i);
- if (!parent_names[i])
- return;
- }
+ of_clk_parent_fill(np, parent_names, num_parents);
num = of_get_child_count(np);
if (!num || num > (PROG_ID_MAX + 1))
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
index 98a84a865fe1..d0d5076a9b94 100644
--- a/drivers/clk/at91/clk-slow.c
+++ b/drivers/clk/at91/clk-slow.c
@@ -10,8 +10,10 @@
*
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/clk/at91_pmc.h>
#include <linux/delay.h>
#include <linux/of.h>
@@ -371,17 +373,12 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
const char *parent_names[2];
int num_parents;
const char *name = np->name;
- int i;
num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > 2)
return;
- for (i = 0; i < num_parents; ++i) {
- parent_names[i] = of_clk_get_parent_name(np, i);
- if (!parent_names[i])
- return;
- }
+ of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
@@ -449,17 +446,12 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
const char *parent_names[2];
int num_parents;
const char *name = np->name;
- int i;
num_parents = of_clk_get_parent_count(np);
if (num_parents != 2)
return;
- for (i = 0; i < num_parents; ++i) {
- parent_names[i] = of_clk_get_parent_name(np, i);
- if (!parent_names[i])
- return;
- }
+ of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c
index 3817ea865ca2..a7f8501cfa05 100644
--- a/drivers/clk/at91/clk-smd.c
+++ b/drivers/clk/at91/clk-smd.c
@@ -145,7 +145,6 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
struct at91_pmc *pmc)
{
struct clk *clk;
- int i;
int num_parents;
const char *parent_names[SMD_SOURCE_MAX];
const char *name = np->name;
@@ -154,11 +153,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
return;
- for (i = 0; i < num_parents; i++) {
- parent_names[i] = of_clk_get_parent_name(np, i);
- if (!parent_names[i])
- return;
- }
+ of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index b0cbd2b1ff59..8ab8502778a2 100644
--- a/drivers/clk/at91/clk-usb.c
+++ b/drivers/clk/at91/clk-usb.c
@@ -56,47 +56,43 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
}
-static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_hw)
+static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- struct clk *parent = NULL;
+ struct clk_hw *parent;
long best_rate = -EINVAL;
unsigned long tmp_rate;
int best_diff = -1;
int tmp_diff;
int i;
- for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
int div;
- parent = clk_get_parent_by_index(hw->clk, i);
+ parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) {
unsigned long tmp_parent_rate;
- tmp_parent_rate = rate * div;
- tmp_parent_rate = __clk_round_rate(parent,
+ tmp_parent_rate = req->rate * div;
+ tmp_parent_rate = clk_hw_round_rate(parent,
tmp_parent_rate);
tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div);
- if (tmp_rate < rate)
- tmp_diff = rate - tmp_rate;
+ if (tmp_rate < req->rate)
+ tmp_diff = req->rate - tmp_rate;
else
- tmp_diff = tmp_rate - rate;
+ tmp_diff = tmp_rate - req->rate;
if (best_diff < 0 || best_diff > tmp_diff) {
best_rate = tmp_rate;
best_diff = tmp_diff;
- *best_parent_rate = tmp_parent_rate;
- *best_parent_hw = __clk_get_hw(parent);
+ req->best_parent_rate = tmp_parent_rate;
+ req->best_parent_hw = parent;
}
- if (!best_diff || tmp_rate < rate)
+ if (!best_diff || tmp_rate < req->rate)
break;
}
@@ -104,7 +100,11 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
break;
}
- return best_rate;
+ if (best_rate < 0)
+ return best_rate;
+
+ req->rate = best_rate;
+ return 0;
}
static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
@@ -273,7 +273,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
- struct clk *parent = __clk_get_parent(hw->clk);
+ struct clk_hw *parent = clk_hw_get_parent(hw);
unsigned long bestrate = 0;
int bestdiff = -1;
unsigned long tmprate;
@@ -287,7 +287,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
continue;
tmp_parent_rate = rate * usb->divisors[i];
- tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
+ tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate);
tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
if (tmprate < rate)
tmpdiff = rate - tmprate;
@@ -373,7 +373,6 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
struct at91_pmc *pmc)
{
struct clk *clk;
- int i;
int num_parents;
const char *parent_names[USB_SOURCE_MAX];
const char *name = np->name;
@@ -382,11 +381,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
return;
- for (i = 0; i < num_parents; i++) {
- parent_names[i] = of_clk_get_parent_name(np, i);
- if (!parent_names[i])
- return;
- }
+ of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 39be2be82b0a..d1844f1f3729 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -125,7 +125,6 @@ static int pmc_irq_map(struct irq_domain *h, unsigned int virq,
irq_set_chip_and_handler(virq, &pmc_irq,
handle_level_irq);
- set_irq_flags(virq, IRQF_VALID);
irq_set_chip_data(virq, pmc);
return 0;
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index eb8e5dc9076d..8b87771c69b2 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -59,71 +59,63 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range);
-extern void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
- struct at91_pmc *pmc);
-
-extern void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
- struct at91_pmc *pmc);
-
-extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
- struct at91_pmc *pmc);
-
-extern void __init of_at91rm9200_clk_master_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
- struct at91_pmc *pmc);
-
-extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
- struct at91_pmc *pmc);
-
-extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
- struct at91_pmc *pmc);
-
-extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
- struct at91_pmc *pmc);
-
-#if defined(CONFIG_HAVE_AT91_UTMI)
-extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
- struct at91_pmc *pmc);
-#endif
-
-#if defined(CONFIG_HAVE_AT91_USB_CLK)
-extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
- struct at91_pmc *pmc);
-extern void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
- struct at91_pmc *pmc);
-#endif
-
-#if defined(CONFIG_HAVE_AT91_SMD)
-extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
- struct at91_pmc *pmc);
-#endif
-
-#if defined(CONFIG_HAVE_AT91_H32MX)
-extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
- struct at91_pmc *pmc);
-#endif
+void of_at91sam9260_clk_slow_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91rm9200_clk_main_osc_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91rm9200_clk_main_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9x5_clk_main_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91rm9200_clk_pll_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9g45_clk_pll_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9g20_clk_pllb_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_sama5d3_clk_pll_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91rm9200_clk_master_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9x5_clk_master_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91rm9200_clk_sys_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91rm9200_clk_periph_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9x5_clk_periph_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91rm9200_clk_prog_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9g45_clk_prog_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9x5_clk_prog_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91sam9x5_clk_utmi_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91rm9200_clk_usb_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9x5_clk_usb_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+void of_at91sam9n12_clk_usb_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_at91sam9x5_clk_smd_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+void of_sama5d4_clk_h32mx_setup(struct device_node *np,
+ struct at91_pmc *pmc);
#endif /* __PMC_H_ */
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 79a98506c433..3a15347b4233 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/kernel.h>
+#include <linux/clk.h>
/*
* "Policies" affect the frequencies of bus clocks provided by a
@@ -1010,25 +1011,23 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
struct bcm_clk_div *div = &bcm_clk->u.peri->div;
if (!divider_exists(div))
- return __clk_get_rate(hw->clk);
+ return clk_hw_get_rate(hw);
/* Quietly avoid a zero rate */
return round_rate(bcm_clk->ccu, div, &bcm_clk->u.peri->pre_div,
rate ? rate : 1, *parent_rate, NULL);
}
-static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate, struct clk_hw **best_parent)
+static int kona_peri_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct kona_clk *bcm_clk = to_kona_clk(hw);
- struct clk *clk = hw->clk;
- struct clk *current_parent;
+ struct clk_hw *current_parent;
unsigned long parent_rate;
unsigned long best_delta;
unsigned long best_rate;
u32 parent_count;
+ long rate;
u32 which;
/*
@@ -1037,18 +1036,25 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
*/
WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT);
parent_count = (u32)bcm_clk->init_data.num_parents;
- if (parent_count < 2)
- return kona_peri_clk_round_rate(hw, rate, best_parent_rate);
+ if (parent_count < 2) {
+ rate = kona_peri_clk_round_rate(hw, req->rate,
+ &req->best_parent_rate);
+ if (rate < 0)
+ return rate;
+
+ req->rate = rate;
+ return 0;
+ }
/* Unless we can do better, stick with current parent */
- current_parent = clk_get_parent(clk);
- parent_rate = __clk_get_rate(current_parent);
- best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
- best_delta = abs(best_rate - rate);
+ current_parent = clk_hw_get_parent(hw);
+ parent_rate = clk_hw_get_rate(current_parent);
+ best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate);
+ best_delta = abs(best_rate - req->rate);
/* Check whether any other parent clock can produce a better result */
for (which = 0; which < parent_count; which++) {
- struct clk *parent = clk_get_parent_by_index(clk, which);
+ struct clk_hw *parent = clk_hw_get_parent_by_index(hw, which);
unsigned long delta;
unsigned long other_rate;
@@ -1057,18 +1063,20 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
continue;
/* We don't support CLK_SET_RATE_PARENT */
- parent_rate = __clk_get_rate(parent);
- other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
- delta = abs(other_rate - rate);
+ parent_rate = clk_hw_get_rate(parent);
+ other_rate = kona_peri_clk_round_rate(hw, req->rate,
+ &parent_rate);
+ delta = abs(other_rate - req->rate);
if (delta < best_delta) {
best_delta = delta;
best_rate = other_rate;
- *best_parent = __clk_get_hw(parent);
- *best_parent_rate = parent_rate;
+ req->best_parent_hw = parent;
+ req->best_parent_rate = parent_rate;
}
}
- return best_rate;
+ req->rate = best_rate;
+ return 0;
}
static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
@@ -1130,7 +1138,7 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
if (parent_rate > (unsigned long)LONG_MAX)
return -EINVAL;
- if (rate == __clk_get_rate(hw->clk))
+ if (rate == clk_hw_get_rate(hw))
return 0;
if (!divider_exists(div))
@@ -1249,6 +1257,7 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
unsigned long flags;
unsigned int which;
struct clk **clks = ccu->clk_data.clks;
+ struct kona_clk *kona_clks = ccu->kona_clks;
bool success = true;
flags = ccu_lock(ccu);
@@ -1259,7 +1268,7 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
if (!clks[which])
continue;
- bcm_clk = to_kona_clk(__clk_get_hw(clks[which]));
+ bcm_clk = &kona_clks[which];
success &= __kona_clk_init(bcm_clk);
}
diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c
index f4b8d324b083..1c2294d3ba85 100644
--- a/drivers/clk/berlin/berlin2-pll.c
+++ b/drivers/clk/berlin/berlin2-pll.c
@@ -61,7 +61,7 @@ berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK;
rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK;
if (rfdiv == 0) {
- pr_warn("%s has zero rfdiv\n", __clk_get_name(hw->clk));
+ pr_warn("%s has zero rfdiv\n", clk_hw_get_name(hw));
rfdiv = 1;
}
@@ -70,7 +70,7 @@ berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
vcodiv = map->vcodiv[vcodivsel];
if (vcodiv == 0) {
pr_warn("%s has zero vcodiv (index %d)\n",
- __clk_get_name(hw->clk), vcodivsel);
+ clk_hw_get_name(hw), vcodivsel);
vcodiv = 1;
}
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c
index e619285c6def..3bcd42fbb55e 100644
--- a/drivers/clk/clk-axi-clkgen.c
+++ b/drivers/clk/clk-axi-clkgen.c
@@ -10,7 +10,6 @@
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
-#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c
index 6b950ca8b711..dd295e498309 100644
--- a/drivers/clk/clk-bcm2835.c
+++ b/drivers/clk/clk-bcm2835.c
@@ -32,11 +32,6 @@ void __init bcm2835_init_clocks(void)
struct clk *clk;
int ret;
- clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
- 250000000);
- if (IS_ERR(clk))
- pr_err("sys_pclk not registered\n");
-
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
126000000);
if (IS_ERR(clk))
diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c
index f01164fada5d..01877f64eff6 100644
--- a/drivers/clk/clk-cdce706.c
+++ b/drivers/clk/clk-cdce706.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -309,7 +310,7 @@ static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
if (!mul)
div = CDCE706_DIVIDER_DIVIDER_MAX;
- if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
unsigned long best_diff = rate;
unsigned long best_div = 0;
struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c
index 85fafb41e6ca..089bf88ffa8d 100644
--- a/drivers/clk/clk-cdce925.c
+++ b/drivers/clk/clk-cdce925.c
@@ -10,6 +10,7 @@
* Copyright (C) 2014, Topic Embedded Products
* Licenced under GPL
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/module.h>
diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c
index 715eec1a9902..ff4ef4f1df62 100644
--- a/drivers/clk/clk-clps711x.c
+++ b/drivers/clk/clk-clps711x.c
@@ -9,7 +9,6 @@
* (at your option) any later version.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/io.h>
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 616f5aef3c26..4735de0660cc 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -55,78 +55,77 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
return rate_ops->recalc_rate(rate_hw, parent_rate);
}
-static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+static int clk_composite_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_composite *composite = to_clk_composite(hw);
const struct clk_ops *rate_ops = composite->rate_ops;
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *rate_hw = composite->rate_hw;
struct clk_hw *mux_hw = composite->mux_hw;
- struct clk *parent;
+ struct clk_hw *parent;
unsigned long parent_rate;
long tmp_rate, best_rate = 0;
unsigned long rate_diff;
unsigned long best_rate_diff = ULONG_MAX;
+ long rate;
int i;
if (rate_hw && rate_ops && rate_ops->determine_rate) {
__clk_hw_set_clk(rate_hw, hw);
- return rate_ops->determine_rate(rate_hw, rate, min_rate,
- max_rate,
- best_parent_rate,
- best_parent_p);
+ return rate_ops->determine_rate(rate_hw, req);
} else if (rate_hw && rate_ops && rate_ops->round_rate &&
mux_hw && mux_ops && mux_ops->set_parent) {
- *best_parent_p = NULL;
+ req->best_parent_hw = NULL;
- if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
- parent = clk_get_parent(mux_hw->clk);
- *best_parent_p = __clk_get_hw(parent);
- *best_parent_rate = __clk_get_rate(parent);
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
+ parent = clk_hw_get_parent(mux_hw);
+ req->best_parent_hw = parent;
+ req->best_parent_rate = clk_hw_get_rate(parent);
- return rate_ops->round_rate(rate_hw, rate,
- best_parent_rate);
+ rate = rate_ops->round_rate(rate_hw, req->rate,
+ &req->best_parent_rate);
+ if (rate < 0)
+ return rate;
+
+ req->rate = rate;
+ return 0;
}
- for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
- parent = clk_get_parent_by_index(mux_hw->clk, i);
+ for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
+ parent = clk_hw_get_parent_by_index(mux_hw, i);
if (!parent)
continue;
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_hw_get_rate(parent);
- tmp_rate = rate_ops->round_rate(rate_hw, rate,
+ tmp_rate = rate_ops->round_rate(rate_hw, req->rate,
&parent_rate);
if (tmp_rate < 0)
continue;
- rate_diff = abs(rate - tmp_rate);
+ rate_diff = abs(req->rate - tmp_rate);
- if (!rate_diff || !*best_parent_p
+ if (!rate_diff || !req->best_parent_hw
|| best_rate_diff > rate_diff) {
- *best_parent_p = __clk_get_hw(parent);
- *best_parent_rate = parent_rate;
+ req->best_parent_hw = parent;
+ req->best_parent_rate = parent_rate;
best_rate_diff = rate_diff;
best_rate = tmp_rate;
}
if (!rate_diff)
- return rate;
+ return 0;
}
- return best_rate;
+ req->rate = best_rate;
+ return 0;
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
__clk_hw_set_clk(mux_hw, hw);
- return mux_ops->determine_rate(mux_hw, rate, min_rate,
- max_rate, best_parent_rate,
- best_parent_p);
+ return mux_ops->determine_rate(mux_hw, req);
} else {
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
- return 0;
+ return -EINVAL;
}
}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 706b5783c360..f24d0a19ae70 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -78,12 +78,14 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
}
static unsigned int _get_div(const struct clk_div_table *table,
- unsigned int val, unsigned long flags)
+ unsigned int val, unsigned long flags, u8 width)
{
if (flags & CLK_DIVIDER_ONE_BASED)
return val;
if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
+ if (flags & CLK_DIVIDER_MAX_AT_ZERO)
+ return val ? val : div_mask(width) + 1;
if (table)
return _get_table_div(table, val);
return val + 1;
@@ -101,12 +103,14 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
}
static unsigned int _get_val(const struct clk_div_table *table,
- unsigned int div, unsigned long flags)
+ unsigned int div, unsigned long flags, u8 width)
{
if (flags & CLK_DIVIDER_ONE_BASED)
return div;
if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div);
+ if (flags & CLK_DIVIDER_MAX_AT_ZERO)
+ return (div == div_mask(width) + 1) ? 0 : div;
if (table)
return _get_table_val(table, div);
return div - 1;
@@ -117,13 +121,14 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
const struct clk_div_table *table,
unsigned long flags)
{
+ struct clk_divider *divider = to_clk_divider(hw);
unsigned int div;
- div = _get_div(table, val, flags);
+ div = _get_div(table, val, flags, divider->width);
if (!div) {
WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
- __clk_get_name(hw->clk));
+ clk_hw_get_name(hw));
return parent_rate;
}
@@ -285,7 +290,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
maxdiv = _get_maxdiv(table, width, flags);
- if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
+ if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
bestdiv = _div_round(table, parent_rate, rate, flags);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
@@ -311,7 +316,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
*best_parent_rate = parent_rate_saved;
return i;
}
- parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+ parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
rate * i);
now = DIV_ROUND_UP(parent_rate, i);
if (_is_best_div(rate, now, best, flags)) {
@@ -323,7 +328,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!bestdiv) {
bestdiv = _get_maxdiv(table, width, flags);
- *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
+ *best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
}
return bestdiv;
@@ -351,7 +356,8 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
bestdiv = readl(divider->reg) >> divider->shift;
bestdiv &= div_mask(divider->width);
- bestdiv = _get_div(divider->table, bestdiv, divider->flags);
+ bestdiv = _get_div(divider->table, bestdiv, divider->flags,
+ divider->width);
return DIV_ROUND_UP(*prate, bestdiv);
}
@@ -370,7 +376,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
if (!_is_valid_div(table, div, flags))
return -EINVAL;
- value = _get_val(table, div, flags);
+ value = _get_val(table, div, flags, width);
return min_t(unsigned int, value, div_mask(width));
}
@@ -389,6 +395,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
+ else
+ __acquire(divider->lock);
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = div_mask(divider->width) << (divider->shift + 16);
@@ -401,6 +409,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
+ else
+ __release(divider->lock);
return 0;
}
diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c
index 73a8d0ff530c..bac4553f04b8 100644
--- a/drivers/clk/clk-efm32gg.c
+++ b/drivers/clk/clk-efm32gg.c
@@ -6,7 +6,6 @@
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*/
-#include <linux/clk.h>
#include <linux/io.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index fccabe497f6e..83de57aeceea 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -41,12 +41,11 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
- if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
unsigned long best_parent;
best_parent = (rate / fix->mult) * fix->div;
- *prate = __clk_round_rate(__clk_get_parent(hw->clk),
- best_parent);
+ *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
}
return (*prate / fix->div) * fix->mult;
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
index 140eb5844dc4..e85f856b8592 100644
--- a/drivers/clk/clk-fractional-divider.c
+++ b/drivers/clk/clk-fractional-divider.c
@@ -27,11 +27,15 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
+ else
+ __acquire(fd->lock);
val = clk_readl(fd->reg);
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
+ else
+ __release(fd->lock);
m = (val & fd->mmask) >> fd->mshift;
n = (val & fd->nmask) >> fd->nshift;
@@ -80,6 +84,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
+ else
+ __acquire(fd->lock);
val = clk_readl(fd->reg);
val &= ~(fd->mmask | fd->nmask);
@@ -88,6 +94,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
+ else
+ __release(fd->lock);
return 0;
}
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 551dd0672794..de0b322f5f58 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -52,6 +52,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
+ else
+ __acquire(gate->lock);
if (gate->flags & CLK_GATE_HIWORD_MASK) {
reg = BIT(gate->bit_idx + 16);
@@ -70,6 +72,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
+ else
+ __release(gate->lock);
}
static int clk_gate_enable(struct clk_hw *hw)
diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c
deleted file mode 100644
index f564e624fb93..000000000000
--- a/drivers/clk/clk-gpio-gate.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
- * Author: Jyri Sarha <jsarha@ti.com>
- *
- * 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.
- *
- * Gpio gated clock implementation
- */
-
-#include <linux/clk-provider.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of_gpio.h>
-#include <linux/err.h>
-#include <linux/device.h>
-
-/**
- * DOC: basic gpio gated clock which can be enabled and disabled
- * with gpio output
- * Traits of this clock:
- * prepare - clk_(un)prepare only ensures parent is (un)prepared
- * enable - clk_enable and clk_disable are functional & control gpio
- * rate - inherits rate from parent. No clk_set_rate support
- * parent - fixed parent. No clk_set_parent support
- */
-
-#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
-
-static int clk_gpio_gate_enable(struct clk_hw *hw)
-{
- struct clk_gpio *clk = to_clk_gpio(hw);
-
- gpiod_set_value(clk->gpiod, 1);
-
- return 0;
-}
-
-static void clk_gpio_gate_disable(struct clk_hw *hw)
-{
- struct clk_gpio *clk = to_clk_gpio(hw);
-
- gpiod_set_value(clk->gpiod, 0);
-}
-
-static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
-{
- struct clk_gpio *clk = to_clk_gpio(hw);
-
- return gpiod_get_value(clk->gpiod);
-}
-
-const struct clk_ops clk_gpio_gate_ops = {
- .enable = clk_gpio_gate_enable,
- .disable = clk_gpio_gate_disable,
- .is_enabled = clk_gpio_gate_is_enabled,
-};
-EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
-
-/**
- * clk_register_gpio - register a gpip clock with the clock framework
- * @dev: device that is registering this clock
- * @name: name of this clock
- * @parent_name: name of this clock's parent
- * @gpio: gpio number to gate this clock
- * @active_low: true if gpio should be set to 0 to enable clock
- * @flags: clock flags
- */
-struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
- const char *parent_name, unsigned gpio, bool active_low,
- unsigned long flags)
-{
- struct clk_gpio *clk_gpio = NULL;
- struct clk *clk = ERR_PTR(-EINVAL);
- struct clk_init_data init = { NULL };
- unsigned long gpio_flags;
- int err;
-
- if (active_low)
- gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH;
- else
- gpio_flags = GPIOF_OUT_INIT_LOW;
-
- if (dev)
- err = devm_gpio_request_one(dev, gpio, gpio_flags, name);
- else
- err = gpio_request_one(gpio, gpio_flags, name);
-
- if (err) {
- pr_err("%s: %s: Error requesting clock control gpio %u\n",
- __func__, name, gpio);
- return ERR_PTR(err);
- }
-
- if (dev)
- clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio),
- GFP_KERNEL);
- else
- clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL);
-
- if (!clk_gpio) {
- clk = ERR_PTR(-ENOMEM);
- goto clk_register_gpio_gate_err;
- }
-
- init.name = name;
- init.ops = &clk_gpio_gate_ops;
- init.flags = flags | CLK_IS_BASIC;
- init.parent_names = (parent_name ? &parent_name : NULL);
- init.num_parents = (parent_name ? 1 : 0);
-
- clk_gpio->gpiod = gpio_to_desc(gpio);
- clk_gpio->hw.init = &init;
-
- clk = clk_register(dev, &clk_gpio->hw);
-
- if (!IS_ERR(clk))
- return clk;
-
- if (!dev)
- kfree(clk_gpio);
-
-clk_register_gpio_gate_err:
- if (!dev)
- gpio_free(gpio);
-
- return clk;
-}
-EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
-
-#ifdef CONFIG_OF
-/**
- * The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER
- * can not be handled properly at of_clk_init() call time.
- */
-
-struct clk_gpio_gate_delayed_register_data {
- struct device_node *node;
- struct mutex lock;
- struct clk *clk;
-};
-
-static struct clk *of_clk_gpio_gate_delayed_register_get(
- struct of_phandle_args *clkspec,
- void *_data)
-{
- struct clk_gpio_gate_delayed_register_data *data = _data;
- struct clk *clk;
- const char *clk_name = data->node->name;
- const char *parent_name;
- int gpio;
- enum of_gpio_flags of_flags;
-
- mutex_lock(&data->lock);
-
- if (data->clk) {
- mutex_unlock(&data->lock);
- return data->clk;
- }
-
- gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0,
- &of_flags);
- if (gpio < 0) {
- mutex_unlock(&data->lock);
- if (gpio != -EPROBE_DEFER)
- pr_err("%s: %s: Can't get 'enable-gpios' DT property\n",
- __func__, clk_name);
- return ERR_PTR(gpio);
- }
-
- parent_name = of_clk_get_parent_name(data->node, 0);
-
- clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio,
- of_flags & OF_GPIO_ACTIVE_LOW, 0);
- if (IS_ERR(clk)) {
- mutex_unlock(&data->lock);
- return clk;
- }
-
- data->clk = clk;
- mutex_unlock(&data->lock);
-
- return clk;
-}
-
-/**
- * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock
- */
-static void __init of_gpio_gate_clk_setup(struct device_node *node)
-{
- struct clk_gpio_gate_delayed_register_data *data;
-
- data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data),
- GFP_KERNEL);
- if (!data)
- return;
-
- data->node = node;
- mutex_init(&data->lock);
-
- of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data);
-}
-CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
-#endif
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
new file mode 100644
index 000000000000..10819e248414
--- /dev/null
+++ b/drivers/clk/clk-gpio.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors:
+ * Jyri Sarha <jsarha@ti.com>
+ * Sergej Sawazki <ce3a@gmx.de>
+ *
+ * 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.
+ *
+ * Gpio controlled clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+/**
+ * DOC: basic gpio gated clock which can be enabled and disabled
+ * with gpio output
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gpio
+ * rate - inherits rate from parent. No clk_set_rate support
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
+
+static int clk_gpio_gate_enable(struct clk_hw *hw)
+{
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ gpiod_set_value(clk->gpiod, 1);
+
+ return 0;
+}
+
+static void clk_gpio_gate_disable(struct clk_hw *hw)
+{
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ gpiod_set_value(clk->gpiod, 0);
+}
+
+static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ return gpiod_get_value(clk->gpiod);
+}
+
+const struct clk_ops clk_gpio_gate_ops = {
+ .enable = clk_gpio_gate_enable,
+ .disable = clk_gpio_gate_disable,
+ .is_enabled = clk_gpio_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
+
+/**
+ * DOC: basic clock multiplexer which can be controlled with a gpio output
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * rate - rate is only affected by parent switching. No clk_set_rate support
+ * parent - parent is adjustable through clk_set_parent
+ */
+
+static u8 clk_gpio_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ return gpiod_get_value(clk->gpiod);
+}
+
+static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ gpiod_set_value(clk->gpiod, index);
+
+ return 0;
+}
+
+const struct clk_ops clk_gpio_mux_ops = {
+ .get_parent = clk_gpio_mux_get_parent,
+ .set_parent = clk_gpio_mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_gpio_mux_ops);
+
+static struct clk *clk_register_gpio(struct device *dev, const char *name,
+ const char * const *parent_names, u8 num_parents, unsigned gpio,
+ bool active_low, unsigned long flags,
+ const struct clk_ops *clk_gpio_ops)
+{
+ struct clk_gpio *clk_gpio;
+ struct clk *clk;
+ struct clk_init_data init = {};
+ unsigned long gpio_flags;
+ int err;
+
+ if (dev)
+ clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
+ else
+ clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL);
+
+ if (!clk_gpio)
+ return ERR_PTR(-ENOMEM);
+
+ if (active_low)
+ gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH;
+ else
+ gpio_flags = GPIOF_OUT_INIT_LOW;
+
+ if (dev)
+ err = devm_gpio_request_one(dev, gpio, gpio_flags, name);
+ else
+ err = gpio_request_one(gpio, gpio_flags, name);
+ if (err) {
+ if (err != -EPROBE_DEFER)
+ pr_err("%s: %s: Error requesting clock control gpio %u\n",
+ __func__, name, gpio);
+ if (!dev)
+ kfree(clk_gpio);
+
+ return ERR_PTR(err);
+ }
+
+ init.name = name;
+ init.ops = clk_gpio_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ clk_gpio->gpiod = gpio_to_desc(gpio);
+ clk_gpio->hw.init = &init;
+
+ if (dev)
+ clk = devm_clk_register(dev, &clk_gpio->hw);
+ else
+ clk = clk_register(NULL, &clk_gpio->hw);
+
+ if (!IS_ERR(clk))
+ return clk;
+
+ if (!dev) {
+ gpiod_put(clk_gpio->gpiod);
+ kfree(clk_gpio);
+ }
+
+ return clk;
+}
+
+/**
+ * clk_register_gpio_gate - register a gpio clock gate with the clock framework
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @parent_name: name of this clock's parent
+ * @gpio: gpio number to gate this clock
+ * @active_low: true if gpio should be set to 0 to enable clock
+ * @flags: clock flags
+ */
+struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
+ const char *parent_name, unsigned gpio, bool active_low,
+ unsigned long flags)
+{
+ return clk_register_gpio(dev, name,
+ (parent_name ? &parent_name : NULL),
+ (parent_name ? 1 : 0), gpio, active_low, flags,
+ &clk_gpio_gate_ops);
+}
+EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
+
+/**
+ * clk_register_gpio_mux - register a gpio clock mux with the clock framework
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @parent_names: names of this clock's parents
+ * @num_parents: number of parents listed in @parent_names
+ * @gpio: gpio number to gate this clock
+ * @active_low: true if gpio should be set to 0 to enable clock
+ * @flags: clock flags
+ */
+struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
+ const char * const *parent_names, u8 num_parents, unsigned gpio,
+ bool active_low, unsigned long flags)
+{
+ if (num_parents != 2) {
+ pr_err("mux-clock %s must have 2 parents\n", name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_gpio(dev, name, parent_names, num_parents,
+ gpio, active_low, flags, &clk_gpio_mux_ops);
+}
+EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
+
+#ifdef CONFIG_OF
+/**
+ * clk_register_get() has to be delayed, because -EPROBE_DEFER
+ * can not be handled properly at of_clk_init() call time.
+ */
+
+struct clk_gpio_delayed_register_data {
+ const char *gpio_name;
+ struct device_node *node;
+ struct mutex lock;
+ struct clk *clk;
+ struct clk *(*clk_register_get)(const char *name,
+ const char * const *parent_names, u8 num_parents,
+ unsigned gpio, bool active_low);
+};
+
+static struct clk *of_clk_gpio_delayed_register_get(
+ struct of_phandle_args *clkspec, void *_data)
+{
+ struct clk_gpio_delayed_register_data *data = _data;
+ struct clk *clk;
+ const char **parent_names;
+ int i, num_parents;
+ int gpio;
+ enum of_gpio_flags of_flags;
+
+ mutex_lock(&data->lock);
+
+ if (data->clk) {
+ mutex_unlock(&data->lock);
+ return data->clk;
+ }
+
+ gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0,
+ &of_flags);
+ if (gpio < 0) {
+ mutex_unlock(&data->lock);
+ if (gpio == -EPROBE_DEFER)
+ pr_debug("%s: %s: GPIOs not yet available, retry later\n",
+ data->node->name, __func__);
+ else
+ pr_err("%s: %s: Can't get '%s' DT property\n",
+ data->node->name, __func__,
+ data->gpio_name);
+ return ERR_PTR(gpio);
+ }
+
+ num_parents = of_clk_get_parent_count(data->node);
+
+ parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
+ if (!parent_names) {
+ clk = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(data->node, i);
+
+ clk = data->clk_register_get(data->node->name, parent_names,
+ num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW);
+ if (IS_ERR(clk))
+ goto out;
+
+ data->clk = clk;
+out:
+ mutex_unlock(&data->lock);
+ kfree(parent_names);
+
+ return clk;
+}
+
+static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
+ const char * const *parent_names, u8 num_parents,
+ unsigned gpio, bool active_low)
+{
+ return clk_register_gpio_gate(NULL, name, parent_names[0],
+ gpio, active_low, 0);
+}
+
+static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
+ const char * const *parent_names, u8 num_parents, unsigned gpio,
+ bool active_low)
+{
+ return clk_register_gpio_mux(NULL, name, parent_names, num_parents,
+ gpio, active_low, 0);
+}
+
+static void __init of_gpio_clk_setup(struct device_node *node,
+ const char *gpio_name,
+ struct clk *(*clk_register_get)(const char *name,
+ const char * const *parent_names,
+ u8 num_parents,
+ unsigned gpio, bool active_low))
+{
+ struct clk_gpio_delayed_register_data *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return;
+
+ data->node = node;
+ data->gpio_name = gpio_name;
+ data->clk_register_get = clk_register_get;
+ mutex_init(&data->lock);
+
+ of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data);
+}
+
+static void __init of_gpio_gate_clk_setup(struct device_node *node)
+{
+ of_gpio_clk_setup(node, "enable-gpios",
+ of_clk_gpio_gate_delayed_register_get);
+}
+CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
+
+void __init of_gpio_mux_clk_setup(struct device_node *node)
+{
+ of_gpio_clk_setup(node, "select-gpios",
+ of_clk_gpio_mux_delayed_register_get);
+}
+CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup);
+#endif
diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 2e7e9d9798cb..be3a21abb185 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c
index 5181b89c3cb2..f37f719643ec 100644
--- a/drivers/clk/clk-moxart.c
+++ b/drivers/clk/clk-moxart.c
@@ -10,6 +10,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 6066a01b20ea..7129c86a79db 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -10,7 +10,6 @@
* Simple multiplexer clock implementation
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -32,7 +31,7 @@
static u8 clk_mux_get_parent(struct clk_hw *hw)
{
struct clk_mux *mux = to_clk_mux(hw);
- int num_parents = __clk_get_num_parents(hw->clk);
+ int num_parents = clk_hw_get_num_parents(hw);
u32 val;
/*
@@ -85,6 +84,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
+ else
+ __acquire(mux->lock);
if (mux->flags & CLK_MUX_HIWORD_MASK) {
val = mux->mask << (mux->shift + 16);
@@ -97,6 +98,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
+ else
+ __release(mux->lock);
return 0;
}
diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
index c9487179f25f..e4d8a991c58f 100644
--- a/drivers/clk/clk-nomadik.c
+++ b/drivers/clk/clk-nomadik.c
@@ -8,8 +8,7 @@
#define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk-provider.h>
diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c
index 45a535ab48aa..8e3039f0c3f9 100644
--- a/drivers/clk/clk-palmas.c
+++ b/drivers/clk/clk-palmas.c
@@ -18,7 +18,6 @@
*/
#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/mfd/palmas.h>
#include <linux/module.h>
diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c
index 83902b9cd49e..0fee2f4ca258 100644
--- a/drivers/clk/clk-rk808.c
+++ b/drivers/clk/clk-rk808.c
@@ -15,7 +15,6 @@
* more details.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c
index 9b13a303d3f8..d266299dfdb1 100644
--- a/drivers/clk/clk-s2mps11.c
+++ b/drivers/clk/clk-s2mps11.c
@@ -58,21 +58,17 @@ static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
static int s2mps11_clk_prepare(struct clk_hw *hw)
{
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
- int ret;
- ret = regmap_update_bits(s2mps11->iodev->regmap_pmic,
+ return regmap_update_bits(s2mps11->iodev->regmap_pmic,
s2mps11->reg,
s2mps11->mask, s2mps11->mask);
-
- return ret;
}
static void s2mps11_clk_unprepare(struct clk_hw *hw)
{
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
- int ret;
- ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
+ regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
s2mps11->mask, ~s2mps11->mask);
}
@@ -186,15 +182,15 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
struct clk_init_data *clks_init;
int i, ret = 0;
- s2mps11_clks = devm_kzalloc(&pdev->dev, sizeof(*s2mps11_clk) *
- S2MPS11_CLKS_NUM, GFP_KERNEL);
+ s2mps11_clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
+ sizeof(*s2mps11_clk), GFP_KERNEL);
if (!s2mps11_clks)
return -ENOMEM;
s2mps11_clk = s2mps11_clks;
- clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
- S2MPS11_CLKS_NUM, GFP_KERNEL);
+ clk_table = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
+ sizeof(struct clk *), GFP_KERNEL);
if (!clk_table)
return -ENOMEM;
@@ -246,7 +242,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
s2mps11_name(s2mps11_clk), NULL);
if (!s2mps11_clk->lookup) {
ret = -ENOMEM;
- goto err_lup;
+ goto err_reg;
}
}
@@ -265,16 +261,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, s2mps11_clks);
return ret;
-err_lup:
- devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
+
err_reg:
- while (s2mps11_clk > s2mps11_clks) {
- if (s2mps11_clk->lookup) {
- clkdev_drop(s2mps11_clk->lookup);
- devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
- }
- s2mps11_clk--;
- }
+ while (--i >= 0)
+ clkdev_drop(s2mps11_clks[i].lookup);
return ret;
}
@@ -322,7 +312,7 @@ static int __init s2mps11_clk_init(void)
}
subsys_initcall(s2mps11_clk_init);
-static void __init s2mps11_clk_cleanup(void)
+static void __exit s2mps11_clk_cleanup(void)
{
platform_driver_unregister(&s2mps11_clk_driver);
}
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index e39e1e680b3c..5596c0aac22f 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/clkdev.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -439,7 +439,7 @@ static unsigned long si5351_pll_recalc_rate(struct clk_hw *hw,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk),
+ __func__, clk_hw_get_name(hw),
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
parent_rate, (unsigned long)rate);
@@ -497,7 +497,7 @@ static long si5351_pll_round_rate(struct clk_hw *hw, unsigned long rate,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: a = %lu, b = %lu, c = %lu, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk), a, b, c,
+ __func__, clk_hw_get_name(hw), a, b, c,
*parent_rate, rate);
return rate;
@@ -521,7 +521,7 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk),
+ __func__, clk_hw_get_name(hw),
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
parent_rate, rate);
@@ -632,7 +632,7 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, m = %lu, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk),
+ __func__, clk_hw_get_name(hw),
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
m, parent_rate, (unsigned long)rate);
@@ -663,7 +663,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
divby4 = 1;
/* multisync can set pll */
- if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
/*
* find largest integer divider for max
* vco frequency and given target rate
@@ -745,7 +745,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: a = %lu, b = %lu, c = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk), a, b, c, divby4,
+ __func__, clk_hw_get_name(hw), a, b, c, divby4,
*parent_rate, rate);
return rate;
@@ -777,7 +777,7 @@ static int si5351_msynth_set_rate(struct clk_hw *hw, unsigned long rate,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk),
+ __func__, clk_hw_get_name(hw),
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
divby4, parent_rate, rate);
@@ -1013,7 +1013,7 @@ static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
rate = SI5351_CLKOUT_MIN_FREQ;
/* request frequency if multisync master */
- if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
/* use r divider for frequencies below 1MHz */
rdiv = SI5351_OUTPUT_CLK_DIV_1;
while (rate < SI5351_MULTISYNTH_MIN_FREQ &&
@@ -1042,7 +1042,7 @@ static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
+ __func__, clk_hw_get_name(hw), (1 << rdiv),
*parent_rate, rate);
return rate;
@@ -1093,7 +1093,7 @@ static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
- __func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
+ __func__, clk_hw_get_name(hw), (1 << rdiv),
parent_rate, rate);
return 0;
diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c
index 20a5aec98b1a..cf478aa9fa5d 100644
--- a/drivers/clk/clk-si570.c
+++ b/drivers/clk/clk-si570.c
@@ -19,6 +19,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/module.h>
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 3f6f7ad39490..fd89e771107e 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -175,11 +175,10 @@ static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
mult = 2;
- if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
unsigned long best_parent = rate / mult;
- *prate =
- __clk_round_rate(__clk_get_parent(hw->clk), best_parent);
+ *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
}
return *prate * mult;
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c
index 4a755135bcd3..8e5ed649a098 100644
--- a/drivers/clk/clk-twl6040.c
+++ b/drivers/clk/clk-twl6040.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/clk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
@@ -91,7 +90,7 @@ static int twl6040_clk_probe(struct platform_device *pdev)
clkdata->twl6040 = twl6040;
clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
- clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
+ clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
if (IS_ERR(clkdata->clk))
return PTR_ERR(clkdata->clk);
@@ -100,21 +99,11 @@ static int twl6040_clk_probe(struct platform_device *pdev)
return 0;
}
-static int twl6040_clk_remove(struct platform_device *pdev)
-{
- struct twl6040_clk *clkdata = platform_get_drvdata(pdev);
-
- clk_unregister(clkdata->clk);
-
- return 0;
-}
-
static struct platform_driver twl6040_clk_driver = {
.driver = {
.name = "twl6040-clk",
},
.probe = twl6040_clk_probe,
- .remove = twl6040_clk_remove,
};
module_platform_driver(twl6040_clk_driver);
diff --git a/drivers/clk/clk-u300.c b/drivers/clk/clk-u300.c
index 18bf5e576b93..95d1742dac30 100644
--- a/drivers/clk/clk-u300.c
+++ b/drivers/clk/clk-u300.c
@@ -5,8 +5,8 @@
* Author: Linus Walleij <linus.walleij@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
-#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk-provider.h>
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c
index ef67719f4e52..43f9d15255f4 100644
--- a/drivers/clk/clk-wm831x.c
+++ b/drivers/clk/clk-wm831x.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/module.h>
diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index f26b3ac36b27..96a6190acac2 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -60,7 +60,6 @@ enum xgene_pll_type {
struct xgene_clk_pll {
struct clk_hw hw;
- const char *name;
void __iomem *reg;
spinlock_t *lock;
u32 pll_offset;
@@ -75,7 +74,7 @@ static int xgene_clk_pll_is_enabled(struct clk_hw *hw)
u32 data;
data = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
- pr_debug("%s pll %s\n", pllclk->name,
+ pr_debug("%s pll %s\n", clk_hw_get_name(hw),
data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled");
return data & REGSPEC_RESET_F1_MASK ? 0 : 1;
@@ -113,7 +112,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw,
fref = parent_rate / nref;
fvco = fref * nfb;
}
- pr_debug("%s pll recalc rate %ld parent %ld\n", pllclk->name,
+ pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw),
fvco / nout, parent_rate);
return fvco / nout;
@@ -146,7 +145,6 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
- apmclk->name = name;
apmclk->reg = reg;
apmclk->lock = lock;
apmclk->pll_offset = pll_offset;
@@ -210,7 +208,6 @@ struct xgene_dev_parameters {
struct xgene_clk {
struct clk_hw hw;
- const char *name;
spinlock_t *lock;
struct xgene_dev_parameters param;
};
@@ -228,7 +225,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
spin_lock_irqsave(pclk->lock, flags);
if (pclk->param.csr_reg != NULL) {
- pr_debug("%s clock enabled\n", pclk->name);
+ pr_debug("%s clock enabled\n", clk_hw_get_name(hw));
reg = __pa(pclk->param.csr_reg);
/* First enable the clock */
data = xgene_clk_read(pclk->param.csr_reg +
@@ -237,7 +234,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
xgene_clk_write(data, pclk->param.csr_reg +
pclk->param.reg_clk_offset);
pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n",
- pclk->name, &reg,
+ clk_hw_get_name(hw), &reg,
pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
data);
@@ -248,7 +245,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
xgene_clk_write(data, pclk->param.csr_reg +
pclk->param.reg_csr_offset);
pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n",
- pclk->name, &reg,
+ clk_hw_get_name(hw), &reg,
pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
data);
}
@@ -269,7 +266,7 @@ static void xgene_clk_disable(struct clk_hw *hw)
spin_lock_irqsave(pclk->lock, flags);
if (pclk->param.csr_reg != NULL) {
- pr_debug("%s clock disabled\n", pclk->name);
+ pr_debug("%s clock disabled\n", clk_hw_get_name(hw));
/* First put the CSR in reset */
data = xgene_clk_read(pclk->param.csr_reg +
pclk->param.reg_csr_offset);
@@ -295,10 +292,10 @@ static int xgene_clk_is_enabled(struct clk_hw *hw)
u32 data = 0;
if (pclk->param.csr_reg != NULL) {
- pr_debug("%s clock checking\n", pclk->name);
+ pr_debug("%s clock checking\n", clk_hw_get_name(hw));
data = xgene_clk_read(pclk->param.csr_reg +
pclk->param.reg_clk_offset);
- pr_debug("%s clock is %s\n", pclk->name,
+ pr_debug("%s clock is %s\n", clk_hw_get_name(hw),
data & pclk->param.reg_clk_mask ? "enabled" :
"disabled");
}
@@ -321,11 +318,13 @@ static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw,
data &= (1 << pclk->param.reg_divider_width) - 1;
pr_debug("%s clock recalc rate %ld parent %ld\n",
- pclk->name, parent_rate / data, parent_rate);
+ clk_hw_get_name(hw),
+ parent_rate / data, parent_rate);
+
return parent_rate / data;
} else {
pr_debug("%s clock recalc rate %ld parent %ld\n",
- pclk->name, parent_rate, parent_rate);
+ clk_hw_get_name(hw), parent_rate, parent_rate);
return parent_rate;
}
}
@@ -357,7 +356,7 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
data |= divider;
xgene_clk_write(data, pclk->param.divider_reg +
pclk->param.reg_divider_offset);
- pr_debug("%s clock set rate %ld\n", pclk->name,
+ pr_debug("%s clock set rate %ld\n", clk_hw_get_name(hw),
parent_rate / divider_save);
} else {
divider_save = 1;
@@ -419,7 +418,6 @@ static struct clk *xgene_register_clk(struct device *dev,
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
- apmclk->name = name;
apmclk->lock = lock;
apmclk->hw.init = &init;
apmclk->param = *parameters;
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index ddb4b541016f..43e2c3ad6c31 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -9,6 +9,7 @@
* Standard functionality for the common clock API. See Documentation/clk.txt
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/clk-conf.h>
#include <linux/module.h>
@@ -56,8 +57,11 @@ struct clk_core {
struct clk_core *new_parent;
struct clk_core *new_child;
unsigned long flags;
+ bool orphan;
unsigned int enable_count;
unsigned int prepare_count;
+ unsigned long min_rate;
+ unsigned long max_rate;
unsigned long accuracy;
int phase;
struct hlist_head children;
@@ -111,12 +115,14 @@ static void clk_prepare_unlock(void)
}
static unsigned long clk_enable_lock(void)
+ __acquires(enable_lock)
{
unsigned long flags;
if (!spin_trylock_irqsave(&enable_lock, flags)) {
if (enable_owner == current) {
enable_refcnt++;
+ __acquire(enable_lock);
return flags;
}
spin_lock_irqsave(&enable_lock, flags);
@@ -129,12 +135,15 @@ static unsigned long clk_enable_lock(void)
}
static void clk_enable_unlock(unsigned long flags)
+ __releases(enable_lock)
{
WARN_ON_ONCE(enable_owner != current);
WARN_ON_ONCE(enable_refcnt == 0);
- if (--enable_refcnt)
+ if (--enable_refcnt) {
+ __release(enable_lock);
return;
+ }
enable_owner = NULL;
spin_unlock_irqrestore(&enable_lock, flags);
}
@@ -269,27 +278,29 @@ const char *__clk_get_name(struct clk *clk)
}
EXPORT_SYMBOL_GPL(__clk_get_name);
+const char *clk_hw_get_name(const struct clk_hw *hw)
+{
+ return hw->core->name;
+}
+EXPORT_SYMBOL_GPL(clk_hw_get_name);
+
struct clk_hw *__clk_get_hw(struct clk *clk)
{
return !clk ? NULL : clk->core->hw;
}
EXPORT_SYMBOL_GPL(__clk_get_hw);
-u8 __clk_get_num_parents(struct clk *clk)
+unsigned int clk_hw_get_num_parents(const struct clk_hw *hw)
{
- return !clk ? 0 : clk->core->num_parents;
+ return hw->core->num_parents;
}
-EXPORT_SYMBOL_GPL(__clk_get_num_parents);
+EXPORT_SYMBOL_GPL(clk_hw_get_num_parents);
-struct clk *__clk_get_parent(struct clk *clk)
+struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw)
{
- if (!clk)
- return NULL;
-
- /* TODO: Create a per-user clk and change callers to call clk_put */
- return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
+ return hw->core->parent ? hw->core->parent->hw : NULL;
}
-EXPORT_SYMBOL_GPL(__clk_get_parent);
+EXPORT_SYMBOL_GPL(clk_hw_get_parent);
static struct clk_core *__clk_lookup_subtree(const char *name,
struct clk_core *core)
@@ -348,18 +359,16 @@ static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
return core->parents[index];
}
-struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+struct clk_hw *
+clk_hw_get_parent_by_index(const struct clk_hw *hw, unsigned int index)
{
struct clk_core *parent;
- if (!clk)
- return NULL;
-
- parent = clk_core_get_parent_by_index(clk->core, index);
+ parent = clk_core_get_parent_by_index(hw->core, index);
- return !parent ? NULL : parent->hw->clk;
+ return !parent ? NULL : parent->hw;
}
-EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
+EXPORT_SYMBOL_GPL(clk_hw_get_parent_by_index);
unsigned int __clk_get_enable_count(struct clk *clk)
{
@@ -387,14 +396,11 @@ out:
return ret;
}
-unsigned long __clk_get_rate(struct clk *clk)
+unsigned long clk_hw_get_rate(const struct clk_hw *hw)
{
- if (!clk)
- return 0;
-
- return clk_core_get_rate_nolock(clk->core);
+ return clk_core_get_rate_nolock(hw->core);
}
-EXPORT_SYMBOL_GPL(__clk_get_rate);
+EXPORT_SYMBOL_GPL(clk_hw_get_rate);
static unsigned long __clk_get_accuracy(struct clk_core *core)
{
@@ -410,12 +416,15 @@ unsigned long __clk_get_flags(struct clk *clk)
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
-bool __clk_is_prepared(struct clk *clk)
+unsigned long clk_hw_get_flags(const struct clk_hw *hw)
{
- if (!clk)
- return false;
+ return hw->core->flags;
+}
+EXPORT_SYMBOL_GPL(clk_hw_get_flags);
- return clk_core_is_prepared(clk->core);
+bool clk_hw_is_prepared(const struct clk_hw *hw)
+{
+ return clk_core_is_prepared(hw->core);
}
bool __clk_is_enabled(struct clk *clk)
@@ -436,28 +445,31 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now,
return now <= rate && now > best;
}
-static long
-clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p,
+static int
+clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req,
unsigned long flags)
{
struct clk_core *core = hw->core, *parent, *best_parent = NULL;
- int i, num_parents;
- unsigned long parent_rate, best = 0;
+ int i, num_parents, ret;
+ unsigned long best = 0;
+ struct clk_rate_request parent_req = *req;
/* if NO_REPARENT flag set, pass through to current parent */
if (core->flags & CLK_SET_RATE_NO_REPARENT) {
parent = core->parent;
- if (core->flags & CLK_SET_RATE_PARENT)
- best = __clk_determine_rate(parent ? parent->hw : NULL,
- rate, min_rate, max_rate);
- else if (parent)
+ if (core->flags & CLK_SET_RATE_PARENT) {
+ ret = __clk_determine_rate(parent ? parent->hw : NULL,
+ &parent_req);
+ if (ret)
+ return ret;
+
+ best = parent_req.rate;
+ } else if (parent) {
best = clk_core_get_rate_nolock(parent);
- else
+ } else {
best = clk_core_get_rate_nolock(core);
+ }
+
goto out;
}
@@ -467,24 +479,33 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
parent = clk_core_get_parent_by_index(core, i);
if (!parent)
continue;
- if (core->flags & CLK_SET_RATE_PARENT)
- parent_rate = __clk_determine_rate(parent->hw, rate,
- min_rate,
- max_rate);
- else
- parent_rate = clk_core_get_rate_nolock(parent);
- if (mux_is_better_rate(rate, parent_rate, best, flags)) {
+
+ if (core->flags & CLK_SET_RATE_PARENT) {
+ parent_req = *req;
+ ret = __clk_determine_rate(parent->hw, &parent_req);
+ if (ret)
+ continue;
+ } else {
+ parent_req.rate = clk_core_get_rate_nolock(parent);
+ }
+
+ if (mux_is_better_rate(req->rate, parent_req.rate,
+ best, flags)) {
best_parent = parent;
- best = parent_rate;
+ best = parent_req.rate;
}
}
+ if (!best_parent)
+ return -EINVAL;
+
out:
if (best_parent)
- *best_parent_p = best_parent->hw;
- *best_parent_rate = best;
+ req->best_parent_hw = best_parent->hw;
+ req->best_parent_rate = best;
+ req->rate = best;
- return best;
+ return 0;
}
struct clk *__clk_lookup(const char *name)
@@ -500,8 +521,8 @@ static void clk_core_get_boundaries(struct clk_core *core,
{
struct clk *clk_user;
- *min_rate = 0;
- *max_rate = ULONG_MAX;
+ *min_rate = core->min_rate;
+ *max_rate = core->max_rate;
hlist_for_each_entry(clk_user, &core->clks, clks_node)
*min_rate = max(*min_rate, clk_user->min_rate);
@@ -510,33 +531,30 @@ static void clk_core_get_boundaries(struct clk_core *core,
*max_rate = min(*max_rate, clk_user->max_rate);
}
+void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
+ unsigned long max_rate)
+{
+ hw->core->min_rate = min_rate;
+ hw->core->max_rate = max_rate;
+}
+EXPORT_SYMBOL_GPL(clk_hw_set_rate_range);
+
/*
* Helper for finding best parent to provide a given frequency. This can be used
* directly as a determine_rate callback (e.g. for a mux), or from a more
* complex clock that may combine a mux with other operations.
*/
-long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+int __clk_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
- best_parent_rate,
- best_parent_p, 0);
+ return clk_mux_determine_rate_flags(hw, req, 0);
}
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
-long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+int __clk_mux_determine_rate_closest(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
- best_parent_rate,
- best_parent_p,
- CLK_MUX_ROUND_CLOSEST);
+ return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST);
}
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
@@ -759,14 +777,11 @@ int clk_enable(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_enable);
-static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
- unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate)
+static int clk_core_round_rate_nolock(struct clk_core *core,
+ struct clk_rate_request *req)
{
- unsigned long parent_rate = 0;
struct clk_core *parent;
- struct clk_hw *parent_hw;
+ long rate;
lockdep_assert_held(&prepare_lock);
@@ -774,21 +789,30 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
return 0;
parent = core->parent;
- if (parent)
- parent_rate = parent->rate;
+ if (parent) {
+ req->best_parent_hw = parent->hw;
+ req->best_parent_rate = parent->rate;
+ } else {
+ req->best_parent_hw = NULL;
+ req->best_parent_rate = 0;
+ }
if (core->ops->determine_rate) {
- parent_hw = parent ? parent->hw : NULL;
- return core->ops->determine_rate(core->hw, rate,
- min_rate, max_rate,
- &parent_rate, &parent_hw);
- } else if (core->ops->round_rate)
- return core->ops->round_rate(core->hw, rate, &parent_rate);
- else if (core->flags & CLK_SET_RATE_PARENT)
- return clk_core_round_rate_nolock(core->parent, rate, min_rate,
- max_rate);
- else
- return core->rate;
+ return core->ops->determine_rate(core->hw, req);
+ } else if (core->ops->round_rate) {
+ rate = core->ops->round_rate(core->hw, req->rate,
+ &req->best_parent_rate);
+ if (rate < 0)
+ return rate;
+
+ req->rate = rate;
+ } else if (core->flags & CLK_SET_RATE_PARENT) {
+ return clk_core_round_rate_nolock(parent, req);
+ } else {
+ req->rate = core->rate;
+ }
+
+ return 0;
}
/**
@@ -800,38 +824,32 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
*
* Useful for clk_ops such as .set_rate and .determine_rate.
*/
-unsigned long __clk_determine_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate)
+int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
- if (!hw)
+ if (!hw) {
+ req->rate = 0;
return 0;
+ }
- return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
+ return clk_core_round_rate_nolock(hw->core, req);
}
EXPORT_SYMBOL_GPL(__clk_determine_rate);
-/**
- * __clk_round_rate - round the given rate for a clk
- * @clk: round the rate of this clock
- * @rate: the rate which is to be rounded
- *
- * Useful for clk_ops such as .set_rate
- */
-unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
{
- unsigned long min_rate;
- unsigned long max_rate;
+ int ret;
+ struct clk_rate_request req;
- if (!clk)
- return 0;
+ clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate);
+ req.rate = rate;
- clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
+ ret = clk_core_round_rate_nolock(hw->core, &req);
+ if (ret)
+ return 0;
- return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
+ return req.rate;
}
-EXPORT_SYMBOL_GPL(__clk_round_rate);
+EXPORT_SYMBOL_GPL(clk_hw_round_rate);
/**
* clk_round_rate - round the given rate for a clk
@@ -844,16 +862,24 @@ EXPORT_SYMBOL_GPL(__clk_round_rate);
*/
long clk_round_rate(struct clk *clk, unsigned long rate)
{
- unsigned long ret;
+ struct clk_rate_request req;
+ int ret;
if (!clk)
return 0;
clk_prepare_lock();
- ret = __clk_round_rate(clk, rate);
+
+ clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
+ req.rate = rate;
+
+ ret = clk_core_round_rate_nolock(clk->core, &req);
clk_prepare_unlock();
- return ret;
+ if (ret)
+ return ret;
+
+ return req.rate;
}
EXPORT_SYMBOL_GPL(clk_round_rate);
@@ -1064,18 +1090,40 @@ static int clk_fetch_parent_index(struct clk_core *core,
return -EINVAL;
}
+/*
+ * Update the orphan status of @core and all its children.
+ */
+static void clk_core_update_orphan_status(struct clk_core *core, bool is_orphan)
+{
+ struct clk_core *child;
+
+ core->orphan = is_orphan;
+
+ hlist_for_each_entry(child, &core->children, child_node)
+ clk_core_update_orphan_status(child, is_orphan);
+}
+
static void clk_reparent(struct clk_core *core, struct clk_core *new_parent)
{
+ bool was_orphan = core->orphan;
+
hlist_del(&core->child_node);
if (new_parent) {
+ bool becomes_orphan = new_parent->orphan;
+
/* avoid duplicate POST_RATE_CHANGE notifications */
if (new_parent->new_child == core)
new_parent->new_child = NULL;
hlist_add_head(&core->child_node, &new_parent->children);
+
+ if (was_orphan != becomes_orphan)
+ clk_core_update_orphan_status(core, becomes_orphan);
} else {
hlist_add_head(&core->child_node, &clk_orphan_list);
+ if (!was_orphan)
+ clk_core_update_orphan_status(core, true);
}
core->parent = new_parent;
@@ -1160,14 +1208,8 @@ static int __clk_set_parent(struct clk_core *core, struct clk_core *parent,
flags = clk_enable_lock();
clk_reparent(core, old_parent);
clk_enable_unlock(flags);
+ __clk_set_parent_after(core, old_parent, parent);
- if (core->prepare_count) {
- flags = clk_enable_lock();
- clk_core_disable(core);
- clk_core_disable(parent);
- clk_enable_unlock(flags);
- clk_core_unprepare(parent);
- }
return ret;
}
@@ -1249,7 +1291,6 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
{
struct clk_core *top = core;
struct clk_core *old_parent, *parent;
- struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
unsigned long min_rate;
@@ -1270,20 +1311,29 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
/* find the closest rate and parent clk/rate */
if (core->ops->determine_rate) {
- parent_hw = parent ? parent->hw : NULL;
- ret = core->ops->determine_rate(core->hw, rate,
- min_rate,
- max_rate,
- &best_parent_rate,
- &parent_hw);
+ struct clk_rate_request req;
+
+ req.rate = rate;
+ req.min_rate = min_rate;
+ req.max_rate = max_rate;
+ if (parent) {
+ req.best_parent_hw = parent->hw;
+ req.best_parent_rate = parent->rate;
+ } else {
+ req.best_parent_hw = NULL;
+ req.best_parent_rate = 0;
+ }
+
+ ret = core->ops->determine_rate(core->hw, &req);
if (ret < 0)
return NULL;
- new_rate = ret;
- parent = parent_hw ? parent_hw->core : NULL;
+ best_parent_rate = req.best_parent_rate;
+ new_rate = req.rate;
+ parent = req.best_parent_hw ? req.best_parent_hw->core : NULL;
} else if (core->ops->round_rate) {
ret = core->ops->round_rate(core->hw, rate,
- &best_parent_rate);
+ &best_parent_rate);
if (ret < 0)
return NULL;
@@ -1592,8 +1642,12 @@ struct clk *clk_get_parent(struct clk *clk)
{
struct clk *parent;
+ if (!clk)
+ return NULL;
+
clk_prepare_lock();
- parent = __clk_get_parent(clk);
+ /* TODO: Create a per-user clk and change callers to call clk_put */
+ parent = !clk->core->parent ? NULL : clk->core->parent->hw->clk;
clk_prepare_unlock();
return parent;
@@ -2324,13 +2378,17 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
* clocks and re-parent any that are children of the clock currently
* being clk_init'd.
*/
- if (core->parent)
+ if (core->parent) {
hlist_add_head(&core->child_node,
&core->parent->children);
- else if (core->flags & CLK_IS_ROOT)
+ core->orphan = core->parent->orphan;
+ } else if (core->flags & CLK_IS_ROOT) {
hlist_add_head(&core->child_node, &clk_root_list);
- else
+ core->orphan = false;
+ } else {
hlist_add_head(&core->child_node, &clk_orphan_list);
+ core->orphan = true;
+ }
/*
* Set clk's accuracy. The preferred method is to use
@@ -2479,6 +2537,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
core->hw = hw;
core->flags = hw->init->flags;
core->num_parents = hw->init->num_parents;
+ core->min_rate = 0;
+ core->max_rate = ULONG_MAX;
hw->core = core;
/* allocate local copy in case parent_names is __initdata */
@@ -3054,8 +3114,6 @@ struct clock_provider {
struct list_head node;
};
-static LIST_HEAD(clk_provider_list);
-
/*
* This function looks for a parent clock. If there is one, then it
* checks that the provider for this parent clock was initialized, in
@@ -3106,14 +3164,24 @@ void __init of_clk_init(const struct of_device_id *matches)
struct clock_provider *clk_provider, *next;
bool is_init_done;
bool force = false;
+ LIST_HEAD(clk_provider_list);
if (!matches)
matches = &__clk_of_table;
/* First prepare the list of the clocks providers */
for_each_matching_node_and_match(np, matches, &match) {
- struct clock_provider *parent =
- kzalloc(sizeof(struct clock_provider), GFP_KERNEL);
+ struct clock_provider *parent;
+
+ parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+ if (!parent) {
+ list_for_each_entry_safe(clk_provider, next,
+ &clk_provider_list, node) {
+ list_del(&clk_provider->node);
+ kfree(clk_provider);
+ }
+ return;
+ }
parent->clk_init_cb = match->data;
parent->np = np;
diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c
index 56f9eba91b83..1dd5d14d5dbe 100644
--- a/drivers/clk/h8300/clk-div.c
+++ b/drivers/clk/h8300/clk-div.c
@@ -4,8 +4,6 @@
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/of.h>
@@ -15,7 +13,7 @@ static DEFINE_SPINLOCK(clklock);
static void __init h8300_div_clk_setup(struct device_node *node)
{
- unsigned int num_parents;
+ int num_parents;
struct clk *clk;
const char *clk_name = node->name;
const char *parent_name;
diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c
index 4701b093e497..2a38eb4a2552 100644
--- a/drivers/clk/h8300/clk-h8s2678.c
+++ b/drivers/clk/h8300/clk-h8s2678.c
@@ -4,8 +4,6 @@
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/device.h>
@@ -28,7 +26,7 @@ static unsigned long pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct pll_clock *pll_clock = to_pll_clock(hw);
- int mul = 1 << (ctrl_inb((unsigned long)pll_clock->pllcr) & 3);
+ int mul = 1 << (readb(pll_clock->pllcr) & 3);
return parent_rate * mul;
}
@@ -65,13 +63,13 @@ static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
pll = ((rate / parent_rate) / 2) & 0x03;
spin_lock_irqsave(&clklock, flags);
- val = ctrl_inb((unsigned long)pll_clock->sckcr);
+ val = readb(pll_clock->sckcr);
val |= 0x08;
- ctrl_outb(val, (unsigned long)pll_clock->sckcr);
- val = ctrl_inb((unsigned long)pll_clock->pllcr);
+ writeb(val, pll_clock->sckcr);
+ val = readb(pll_clock->pllcr);
val &= ~0x03;
val |= pll;
- ctrl_outb(val, (unsigned long)pll_clock->pllcr);
+ writeb(val, pll_clock->pllcr);
spin_unlock_irqrestore(&clklock, flags);
return 0;
}
@@ -84,7 +82,7 @@ static const struct clk_ops pll_ops = {
static void __init h8s2678_pll_clk_setup(struct device_node *node)
{
- unsigned int num_parents;
+ int num_parents;
struct clk *clk;
const char *clk_name = node->name;
const char *parent_name;
@@ -98,11 +96,9 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node)
}
- pll_clock = kzalloc(sizeof(struct pll_clock), GFP_KERNEL);
- if (!pll_clock) {
- pr_err("%s: failed to alloc memory", clk_name);
+ pll_clock = kzalloc(sizeof(*pll_clock), GFP_KERNEL);
+ if (!pll_clock)
return;
- }
pll_clock->sckcr = of_iomap(node, 0);
if (pll_clock->sckcr == NULL) {
diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
index b4165ba75d9f..2c16807341dc 100644
--- a/drivers/clk/hisilicon/Kconfig
+++ b/drivers/clk/hisilicon/Kconfig
@@ -1,6 +1,6 @@
config COMMON_CLK_HI6220
bool "Hi6220 Clock Driver"
- depends on ARCH_HISI || COMPILE_TEST
+ depends on (ARCH_HISI || COMPILE_TEST) && MAILBOX
default ARCH_HISI
help
Build the Hisilicon Hi6220 clock driver based on the common clock framework.
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index 48f0116a032a..4a1001a11f04 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -7,4 +7,4 @@ obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
-obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
+obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o clk-hi6220-stub.o
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index 715d34a5ef9b..7d03fe17d66f 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -25,13 +25,11 @@
#include <linux/kernel.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
-#include <linux/clk.h>
#include <dt-bindings/clock/hi3620-clock.h>
@@ -294,34 +292,29 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
}
}
-static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+static int mmc_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_mmc *mclk = to_mmc(hw);
- unsigned long best = 0;
- if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
- rate = 13000000;
- best = 26000000;
- } else if (rate <= 26000000) {
- rate = 25000000;
- best = 180000000;
- } else if (rate <= 52000000) {
- rate = 50000000;
- best = 360000000;
- } else if (rate <= 100000000) {
- rate = 100000000;
- best = 720000000;
+ if ((req->rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
+ req->rate = 13000000;
+ req->best_parent_rate = 26000000;
+ } else if (req->rate <= 26000000) {
+ req->rate = 25000000;
+ req->best_parent_rate = 180000000;
+ } else if (req->rate <= 52000000) {
+ req->rate = 50000000;
+ req->best_parent_rate = 360000000;
+ } else if (req->rate <= 100000000) {
+ req->rate = 100000000;
+ req->best_parent_rate = 720000000;
} else {
/* max is 180M */
- rate = 180000000;
- best = 1440000000;
+ req->rate = 180000000;
+ req->best_parent_rate = 1440000000;
}
- *best_parent_rate = best;
- return rate;
+ return -EINVAL;
}
static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
diff --git a/drivers/clk/hisilicon/clk-hi6220-stub.c b/drivers/clk/hisilicon/clk-hi6220-stub.c
new file mode 100644
index 000000000000..2c4add11c1ca
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi6220-stub.c
@@ -0,0 +1,276 @@
+/*
+ * Hi6220 stub clock driver
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ * Copyright (c) 2015 Linaro Limited.
+ *
+ * Author: Leo Yan <leo.yan@linaro.org>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mailbox_client.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+/* Stub clocks id */
+#define HI6220_STUB_ACPU0 0
+#define HI6220_STUB_ACPU1 1
+#define HI6220_STUB_GPU 2
+#define HI6220_STUB_DDR 5
+
+/* Mailbox message */
+#define HI6220_MBOX_MSG_LEN 8
+
+#define HI6220_MBOX_FREQ 0xA
+#define HI6220_MBOX_CMD_SET 0x3
+#define HI6220_MBOX_OBJ_AP 0x0
+
+/* CPU dynamic frequency scaling */
+#define ACPU_DFS_FREQ_MAX 0x1724
+#define ACPU_DFS_CUR_FREQ 0x17CC
+#define ACPU_DFS_FLAG 0x1B30
+#define ACPU_DFS_FREQ_REQ 0x1B34
+#define ACPU_DFS_FREQ_LMT 0x1B38
+#define ACPU_DFS_LOCK_FLAG 0xAEAEAEAE
+
+#define to_stub_clk(hw) container_of(hw, struct hi6220_stub_clk, hw)
+
+struct hi6220_stub_clk {
+ u32 id;
+
+ struct device *dev;
+ struct clk_hw hw;
+
+ struct regmap *dfs_map;
+ struct mbox_client cl;
+ struct mbox_chan *mbox;
+};
+
+struct hi6220_mbox_msg {
+ unsigned char type;
+ unsigned char cmd;
+ unsigned char obj;
+ unsigned char src;
+ unsigned char para[4];
+};
+
+union hi6220_mbox_data {
+ unsigned int data[HI6220_MBOX_MSG_LEN];
+ struct hi6220_mbox_msg msg;
+};
+
+static unsigned int hi6220_acpu_get_freq(struct hi6220_stub_clk *stub_clk)
+{
+ unsigned int freq;
+
+ regmap_read(stub_clk->dfs_map, ACPU_DFS_CUR_FREQ, &freq);
+ return freq;
+}
+
+static int hi6220_acpu_set_freq(struct hi6220_stub_clk *stub_clk,
+ unsigned int freq)
+{
+ union hi6220_mbox_data data;
+
+ /* set the frequency in sram */
+ regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, freq);
+
+ /* compound mailbox message */
+ data.msg.type = HI6220_MBOX_FREQ;
+ data.msg.cmd = HI6220_MBOX_CMD_SET;
+ data.msg.obj = HI6220_MBOX_OBJ_AP;
+ data.msg.src = HI6220_MBOX_OBJ_AP;
+
+ mbox_send_message(stub_clk->mbox, &data);
+ return 0;
+}
+
+static int hi6220_acpu_round_freq(struct hi6220_stub_clk *stub_clk,
+ unsigned int freq)
+{
+ unsigned int limit_flag, limit_freq = UINT_MAX;
+ unsigned int max_freq;
+
+ /* check the constrained frequency */
+ regmap_read(stub_clk->dfs_map, ACPU_DFS_FLAG, &limit_flag);
+ if (limit_flag == ACPU_DFS_LOCK_FLAG)
+ regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, &limit_freq);
+
+ /* check the supported maximum frequency */
+ regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_MAX, &max_freq);
+
+ /* calculate the real maximum frequency */
+ max_freq = min(max_freq, limit_freq);
+
+ if (WARN_ON(freq > max_freq))
+ freq = max_freq;
+
+ return freq;
+}
+
+static unsigned long hi6220_stub_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ u32 rate = 0;
+ struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
+
+ switch (stub_clk->id) {
+ case HI6220_STUB_ACPU0:
+ rate = hi6220_acpu_get_freq(stub_clk);
+
+ /* convert from kHz to Hz */
+ rate *= 1000;
+ break;
+
+ default:
+ dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
+ __func__, stub_clk->id);
+ break;
+ }
+
+ return rate;
+}
+
+static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
+ unsigned long new_rate = rate / 1000; /* kHz */
+ int ret = 0;
+
+ switch (stub_clk->id) {
+ case HI6220_STUB_ACPU0:
+ ret = hi6220_acpu_set_freq(stub_clk, new_rate);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ default:
+ dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
+ __func__, stub_clk->id);
+ break;
+ }
+
+ pr_debug("%s: set rate=%ldkHz\n", __func__, new_rate);
+ return ret;
+}
+
+static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
+ unsigned long new_rate = rate / 1000; /* kHz */
+
+ switch (stub_clk->id) {
+ case HI6220_STUB_ACPU0:
+ new_rate = hi6220_acpu_round_freq(stub_clk, new_rate);
+
+ /* convert from kHz to Hz */
+ new_rate *= 1000;
+ break;
+
+ default:
+ dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
+ __func__, stub_clk->id);
+ break;
+ }
+
+ return new_rate;
+}
+
+static const struct clk_ops hi6220_stub_clk_ops = {
+ .recalc_rate = hi6220_stub_clk_recalc_rate,
+ .round_rate = hi6220_stub_clk_round_rate,
+ .set_rate = hi6220_stub_clk_set_rate,
+};
+
+static int hi6220_stub_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct clk_init_data init;
+ struct hi6220_stub_clk *stub_clk;
+ struct clk *clk;
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+
+ stub_clk = devm_kzalloc(dev, sizeof(*stub_clk), GFP_KERNEL);
+ if (!stub_clk)
+ return -ENOMEM;
+
+ stub_clk->dfs_map = syscon_regmap_lookup_by_phandle(np,
+ "hisilicon,hi6220-clk-sram");
+ if (IS_ERR(stub_clk->dfs_map)) {
+ dev_err(dev, "failed to get sram regmap\n");
+ return PTR_ERR(stub_clk->dfs_map);
+ }
+
+ stub_clk->hw.init = &init;
+ stub_clk->dev = dev;
+ stub_clk->id = HI6220_STUB_ACPU0;
+
+ /* Use mailbox client with blocking mode */
+ stub_clk->cl.dev = dev;
+ stub_clk->cl.tx_done = NULL;
+ stub_clk->cl.tx_block = true;
+ stub_clk->cl.tx_tout = 500;
+ stub_clk->cl.knows_txdone = false;
+
+ /* Allocate mailbox channel */
+ stub_clk->mbox = mbox_request_channel(&stub_clk->cl, 0);
+ if (IS_ERR(stub_clk->mbox)) {
+ dev_err(dev, "failed get mailbox channel\n");
+ return PTR_ERR(stub_clk->mbox);
+ };
+
+ init.name = "acpu0";
+ init.ops = &hi6220_stub_clk_ops;
+ init.num_parents = 0;
+ init.flags = CLK_IS_ROOT;
+
+ clk = devm_clk_register(dev, &stub_clk->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (ret) {
+ dev_err(dev, "failed to register OF clock provider\n");
+ return ret;
+ }
+
+ /* initialize buffer to zero */
+ regmap_write(stub_clk->dfs_map, ACPU_DFS_FLAG, 0x0);
+ regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, 0x0);
+ regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, 0x0);
+
+ dev_dbg(dev, "Registered clock '%s'\n", init.name);
+ return 0;
+}
+
+static const struct of_device_id hi6220_stub_clk_of_match[] = {
+ { .compatible = "hisilicon,hi6220-stub-clk", },
+ {}
+};
+
+static struct platform_driver hi6220_stub_clk_driver = {
+ .driver = {
+ .name = "hi6220-stub-clk",
+ .of_match_table = hi6220_stub_clk_of_match,
+ },
+ .probe = hi6220_stub_clk_probe,
+};
+
+static int __init hi6220_stub_clk_init(void)
+{
+ return platform_driver_register(&hi6220_stub_clk_driver);
+}
+subsys_initcall(hi6220_stub_clk_init);
diff --git a/drivers/clk/hisilicon/clk-hip04.c b/drivers/clk/hisilicon/clk-hip04.c
index 132b57a0ce09..8ca967308343 100644
--- a/drivers/clk/hisilicon/clk-hip04.c
+++ b/drivers/clk/hisilicon/clk-hip04.c
@@ -24,13 +24,11 @@
#include <linux/kernel.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
-#include <linux/clk.h>
#include <dt-bindings/clock/hip04-clock.h>
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
index c90a89739b03..9f8e76676553 100644
--- a/drivers/clk/hisilicon/clk.c
+++ b/drivers/clk/hisilicon/clk.c
@@ -24,15 +24,14 @@
*/
#include <linux/kernel.h>
-#include <linux/clk-provider.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
-#include <linux/clk.h>
#include "clk.h"
@@ -45,14 +44,9 @@ struct hisi_clock_data __init *hisi_clk_init(struct device_node *np,
struct clk **clk_table;
void __iomem *base;
- if (np) {
- base = of_iomap(np, 0);
- if (!base) {
- pr_err("failed to map Hisilicon clock registers\n");
- goto err;
- }
- } else {
- pr_err("failed to find Hisilicon clock node in DTS\n");
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("%s: failed to map clock registers\n", __func__);
goto err;
}
diff --git a/drivers/clk/hisilicon/clkgate-separated.c b/drivers/clk/hisilicon/clkgate-separated.c
index b03d5a7246f9..a47812f56a17 100644
--- a/drivers/clk/hisilicon/clkgate-separated.c
+++ b/drivers/clk/hisilicon/clkgate-separated.c
@@ -25,10 +25,8 @@
#include <linux/kernel.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include <linux/clk.h>
#include "clk.h"
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 75fae169ce8f..1ada68abb158 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -22,5 +22,6 @@ obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o
obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
+obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o
obj-$(CONFIG_SOC_VF610) += clk-vf610.o
diff --git a/drivers/clk/imx/clk-imx1.c b/drivers/clk/imx/clk-imx1.c
index c2647fa19f28..99cf802fa51f 100644
--- a/drivers/clk/imx/clk-imx1.c
+++ b/drivers/clk/imx/clk-imx1.c
@@ -15,7 +15,6 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
diff --git a/drivers/clk/imx/clk-imx21.c b/drivers/clk/imx/clk-imx21.c
index dba987e3b89f..e63188eb08ac 100644
--- a/drivers/clk/imx/clk-imx21.c
+++ b/drivers/clk/imx/clk-imx21.c
@@ -9,7 +9,6 @@
* of the License, or (at your option) any later version.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c
index fe66c40b7be2..1f8383475bb3 100644
--- a/drivers/clk/imx/clk-imx31.c
+++ b/drivers/clk/imx/clk-imx31.c
@@ -147,7 +147,8 @@ int __init mx31_clocks_init(unsigned long fref)
clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2");
clk_register_clkdev(clk[pwm_gate], "pwm", NULL);
clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
- clk_register_clkdev(clk[rtc_gate], NULL, "imx21-rtc");
+ clk_register_clkdev(clk[ckil], "ref", "imx21-rtc");
+ clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc");
clk_register_clkdev(clk[epit1_gate], "epit", NULL);
clk_register_clkdev(clk[epit2_gate], "epit", NULL);
clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0");
diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
index 69138ba3dec7..8623cd4e49fd 100644
--- a/drivers/clk/imx/clk-imx35.c
+++ b/drivers/clk/imx/clk-imx35.c
@@ -66,7 +66,7 @@ static const char *std_sel[] = {"ppll", "arm"};
static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"};
enum mx35_clks {
- ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
+ ckih, ckil, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel,
esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre,
spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre,
@@ -107,6 +107,7 @@ int __init mx35_clocks_init(void)
}
clk[ckih] = imx_clk_fixed("ckih", 24000000);
+ clk[ckil] = imx_clk_fixed("ckih", 32768);
clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL);
clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL);
@@ -258,6 +259,9 @@ int __init mx35_clocks_init(void)
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1");
clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2");
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2");
+ /* i.mx35 has the i.mx21 type rtc */
+ clk_register_clkdev(clk[ckil], "ref", "imx21-rtc");
+ clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc");
clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0");
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0");
clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.0");
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index d046f8e43de8..b2c1c047dc94 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -381,6 +381,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_ASRC] = imx_clk_gate2_shared("asrc", "asrc_podf", base + 0x68, 6, &share_count_asrc);
clk[IMX6QDL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
clk[IMX6QDL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
+ clk[IMX6QDL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
+ clk[IMX6QDL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ clk[IMX6QDL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
clk[IMX6QDL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
clk[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16);
clk[IMX6QDL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
@@ -494,6 +497,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
}
+ clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
+ if (clk_on_imx6dl())
+ clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
+
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
new file mode 100644
index 000000000000..aaa36650695f
--- /dev/null
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/clock/imx6ul-clock.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+
+#include "clk.h"
+
+#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
+#define CCDR 0x4
+
+static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
+static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
+static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
+static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
+static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
+static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
+static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
+static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
+static const char *ca7_secondary_sels[] = { "pll2_pfd2_396m", "pll2_bus", };
+static const char *step_sels[] = { "osc", "ca7_secondary_sel", };
+static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
+static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", };
+static const char *axi_sels[] = {"periph", "axi_alt_sel", };
+static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
+static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", };
+static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", };
+static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
+static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
+static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
+static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *eim_slow_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd0_720m", };
+static const char *spdif_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", };
+static const char *sai_sels[] = { "pll3_pfd2_508m", "pll5_video_div", "pll4_audio_div", };
+static const char *lcdif_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", };
+static const char *sim_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
+static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", };
+static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
+static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
+static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", };
+static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", };
+static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", "dummy", };
+static const char *ecspi_sels[] = { "pll3_60m", "osc", };
+static const char *uart_sels[] = { "pll3_80m", "osc", };
+static const char *perclk_sels[] = { "ipg", "osc", };
+static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
+static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+
+static struct clk *clks[IMX6UL_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static int const clks_init_on[] __initconst = {
+ IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, IMX6UL_CLK_AIPSTZ3,
+ IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM,
+ IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG,
+};
+
+static struct clk_div_table clk_enet_ref_table[] = {
+ { .val = 0, .div = 20, },
+ { .val = 1, .div = 10, },
+ { .val = 2, .div = 5, },
+ { .val = 3, .div = 4, },
+ { }
+};
+
+static struct clk_div_table post_div_table[] = {
+ { .val = 2, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 0, .div = 4, },
+ { }
+};
+
+static struct clk_div_table video_div_table[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 1, },
+ { .val = 3, .div = 4, },
+ { }
+};
+
+static u32 share_count_asrc;
+static u32 share_count_audio;
+static u32 share_count_sai1;
+static u32 share_count_sai2;
+static u32 share_count_sai3;
+
+static void __init imx6ul_clocks_init(struct device_node *ccm_node)
+{
+ struct device_node *np;
+ void __iomem *base;
+ int i;
+
+ clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+
+ clks[IMX6UL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
+ clks[IMX6UL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+
+ /* ipp_di clock is external input */
+ clks[IMX6UL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
+ clks[IMX6UL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+ clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
+ clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
+ clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
+ clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
+ clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
+ clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
+ clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
+
+ clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
+
+ /* Do not bypass PLLs initially */
+ clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]);
+ clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]);
+ clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]);
+ clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]);
+ clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]);
+ clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]);
+ clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]);
+
+ clks[IMX6UL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
+ clks[IMX6UL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ clks[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ clks[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ clks[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ clks[IMX6UL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ clks[IMX6UL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+
+ /*
+ * 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 many need to enable/disable usbphy's parent
+ */
+ clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ clks[IMX6UL_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.
+ */
+ clks[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+
+ /* name parent_name reg idx */
+ clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
+ clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+ clks[IMX6UL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+ base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
+ clks[IMX6UL_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
+ base + 0xe0, 2, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
+
+ clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
+ clks[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+ clks[IMX6UL_CLK_ENET_PTP] = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
+
+ clks[IMX6UL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ clks[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+ clks[IMX6UL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ clks[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+
+ /* name parent_name mult div */
+ clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ clks[IMX6UL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ clks[IMX6UL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ clks[IMX6UL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
+
+ np = ccm_node;
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
+ clks[IMX6UL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+ clks[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+ clks[IMX6UL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+ clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ clks[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
+ clks[IMX6UL_CLK_GPMI_SEL] = imx_clk_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
+ clks[IMX6UL_CLK_BCH_SEL] = imx_clk_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
+ clks[IMX6UL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6UL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6UL_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
+ clks[IMX6UL_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
+ clks[IMX6UL_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
+ clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
+ clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
+ clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
+ clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
+ clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+ clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+ clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
+ clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
+ clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
+ clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+ clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+ clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+
+ clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ clks[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
+ clks[IMX6UL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "qspi1_sel", 1, 7);
+
+ clks[IMX6UL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+ clks[IMX6UL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ clks[IMX6UL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ clks[IMX6UL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
+ clks[IMX6UL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3);
+ clks[IMX6UL_CLK_QSPI1_PDOF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
+ clks[IMX6UL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
+ clks[IMX6UL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
+ clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
+ clks[IMX6UL_CLK_GPMI_PODF] = imx_clk_divider("gpmi_podf", "gpmi_sel", base + 0x24, 22, 3);
+ clks[IMX6UL_CLK_BCH_PODF] = imx_clk_divider("bch_podf", "bch_sel", base + 0x24, 19, 3);
+ clks[IMX6UL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ clks[IMX6UL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ clks[IMX6UL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
+ clks[IMX6UL_CLK_SAI3_PRED] = imx_clk_divider("sai3_pred", "sai3_sel", base + 0x28, 22, 3);
+ clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6);
+ clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3);
+ clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6);
+ clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
+ clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
+ clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3);
+ clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6);
+ clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
+ clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
+ clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3);
+ clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
+ clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
+ clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
+
+ clks[IMX6UL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ clks[IMX6UL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ clks[IMX6UL_CLK_AXI_PODF] = imx_clk_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+
+ /* CCGR0 */
+ clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0);
+ clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2);
+ clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4);
+ clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
+ clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
+ clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
+ clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
+ clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16);
+ clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
+ clks[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20);
+ clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x68, 24);
+ clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x68, 26);
+ clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
+ clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
+ clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
+
+ /* CCGR1 */
+ clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
+ clks[IMX6UL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
+ clks[IMX6UL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
+ clks[IMX6UL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
+ clks[IMX6UL_CLK_ADC2] = imx_clk_gate2("adc2", "ipg", base + 0x6c, 8);
+ clks[IMX6UL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
+ clks[IMX6UL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
+ clks[IMX6UL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
+ clks[IMX6UL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
+ clks[IMX6UL_CLK_ADC1] = imx_clk_gate2("adc1", "ipg", base + 0x6c, 16);
+ clks[IMX6UL_CLK_GPT1_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
+ clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
+ clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
+ clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24);
+
+ /* CCGR2 */
+ clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2);
+ clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
+ clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
+ clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
+ clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
+ clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14);
+ clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28);
+ clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30);
+
+ /* CCGR3 */
+ clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2);
+ clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
+ clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
+ clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4);
+ clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6);
+ clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6);
+ clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
+ clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
+ clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
+ clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20);
+ clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24);
+ clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28);
+
+ /* CCGR4 */
+ clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12);
+ clks[IMX6UL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
+ clks[IMX6UL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
+ clks[IMX6UL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
+ clks[IMX6UL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
+ clks[IMX6UL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "bch_podf", base + 0x78, 24);
+ clks[IMX6UL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "gpmi_podf", base + 0x78, 26);
+ clks[IMX6UL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc_podf", base + 0x78, 28);
+ clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30);
+
+ /* CCGR5 */
+ clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
+ clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
+ clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
+ clks[IMX6UL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
+ clks[IMX6UL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
+ clks[IMX6UL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
+ clks[IMX6UL_CLK_SAI3] = imx_clk_gate2_shared("sai3", "sai3_podf", base + 0x7c, 22, &share_count_sai3);
+ clks[IMX6UL_CLK_SAI3_IPG] = imx_clk_gate2_shared("sai3_ipg", "ipg", base + 0x7c, 22, &share_count_sai3);
+ clks[IMX6UL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24);
+ clks[IMX6UL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24);
+ clks[IMX6UL_CLK_UART7_IPG] = imx_clk_gate2("uart7_ipg", "ipg", base + 0x7c, 26);
+ clks[IMX6UL_CLK_UART7_SERIAL] = imx_clk_gate2("uart7_serial", "uart_podf", base + 0x7c, 26);
+ clks[IMX6UL_CLK_SAI1] = imx_clk_gate2_shared("sai1", "sai1_podf", base + 0x7c, 28, &share_count_sai1);
+ clks[IMX6UL_CLK_SAI1_IPG] = imx_clk_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1);
+ clks[IMX6UL_CLK_SAI2] = imx_clk_gate2_shared("sai2", "sai2_podf", base + 0x7c, 30, &share_count_sai2);
+ clks[IMX6UL_CLK_SAI2_IPG] = imx_clk_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2);
+
+ /* CCGR6 */
+ clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
+ clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6);
+ clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8);
+ clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10);
+ clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16);
+ clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14);
+ clks[IMX6UL_CLK_UART8_SERIAL] = imx_clk_gate2("uart8_serial", "uart_podf", base + 0x80, 14);
+ clks[IMX6UL_CLK_WDOG3] = imx_clk_gate2("wdog3", "ipg", base + 0x80, 20);
+ clks[IMX6UL_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24);
+ clks[IMX6UL_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26);
+ clks[IMX6UL_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
+ clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("Pwm7", "perclk", base + 0x80, 30);
+
+ /* mask handshake of mmdc */
+ writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ if (IS_ERR(clks[i]))
+ pr_err("i.MX6UL clk %d: register failed with %ld\n", i, PTR_ERR(clks[i]));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ /* set perclk to from OSC */
+ clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]);
+
+ clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000);
+ clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
+ clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
+
+ /* keep all the clks on just for bringup */
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ clk_prepare_enable(clks[clks_init_on[i]]);
+
+ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
+ clk_prepare_enable(clks[IMX6UL_CLK_USBPHY1_GATE]);
+ clk_prepare_enable(clks[IMX6UL_CLK_USBPHY2_GATE]);
+ }
+
+ clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]);
+ clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
+
+ clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
+}
+
+CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index 0b0f6f66ec56..04a3e78ea1bc 100644
--- a/drivers/clk/imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
@@ -10,7 +10,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/slab.h>
diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c
index c34ad8a611dd..8564e4342c7d 100644
--- a/drivers/clk/imx/clk-pllv1.c
+++ b/drivers/clk/imx/clk-pllv1.c
@@ -1,4 +1,3 @@
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/slab.h>
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index f0d15fb9d783..6addf8f58b97 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -10,7 +10,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index b936cdd1a13c..7cfb7b2a2ed6 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -16,6 +16,7 @@
*/
#include <linux/bitops.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/delay.h>
diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c
index 86f1e362eafb..aed5af23895b 100644
--- a/drivers/clk/keystone/gate.c
+++ b/drivers/clk/keystone/gate.c
@@ -10,7 +10,6 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c
index 4a375ead70e9..3f553d0ae0b5 100644
--- a/drivers/clk/keystone/pll.c
+++ b/drivers/clk/keystone/pll.c
@@ -10,7 +10,6 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -309,8 +308,7 @@ static void __init of_pll_mux_clk_init(struct device_node *node)
return;
}
- parents[0] = of_clk_get_parent_name(node, 0);
- parents[1] = of_clk_get_parent_name(node, 1);
+ of_clk_parent_fill(node, parents, 2);
if (!parents[0] || !parents[1]) {
pr_err("%s: missing parent clocks\n", __func__);
return;
diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
index 6b6780b1e9c5..11e25c992948 100644
--- a/drivers/clk/mediatek/clk-gate.h
+++ b/drivers/clk/mediatek/clk-gate.h
@@ -16,9 +16,10 @@
#define __DRV_CLK_GATE_H
#include <linux/regmap.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
+struct clk;
+
struct mtk_clk_gate {
struct clk_hw hw;
struct regmap *regmap;
diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c
index 08b4b849b491..07c21e44b4b3 100644
--- a/drivers/clk/mediatek/clk-mt8135.c
+++ b/drivers/clk/mediatek/clk-mt8135.c
@@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
index 8b6523d15fb8..90eff85f4285 100644
--- a/drivers/clk/mediatek/clk-mt8173.c
+++ b/drivers/clk/mediatek/clk-mt8173.c
@@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
@@ -795,8 +796,9 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
#define CON0_MT8173_RST_BAR BIT(24)
-#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \
- _tuner_reg, _pcw_reg, _pcw_shift) { \
+#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
+ _pcw_shift, _div_table) { \
.id = _id, \
.name = _name, \
.reg = _reg, \
@@ -811,14 +813,31 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
.tuner_reg = _tuner_reg, \
.pcw_reg = _pcw_reg, \
.pcw_shift = _pcw_shift, \
+ .div_table = _div_table, \
}
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
+ _pcw_shift) \
+ PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
+ NULL)
+
+static const struct mtk_pll_div_table mmpll_div_table[] = {
+ { .div = 0, .freq = MT8173_PLL_FMAX },
+ { .div = 1, .freq = 1000000000 },
+ { .div = 2, .freq = 702000000 },
+ { .div = 3, .freq = 253500000 },
+ { .div = 4, .freq = 126750000 },
+ { } /* sentinel */
+};
+
static const struct mtk_pll_data plls[] = {
PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0),
PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0),
PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0),
PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14),
- PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0),
+ PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0, mmpll_div_table),
PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0),
PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0),
PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0),
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index 9dda9d8ad10b..c5cbecb3d218 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -17,9 +17,10 @@
#include <linux/regmap.h>
#include <linux/bitops.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
+struct clk;
+
#define MAX_MUX_GATE_BIT 31
#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1)
@@ -134,6 +135,11 @@ struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
#define HAVE_RST_BAR BIT(0)
+struct mtk_pll_div_table {
+ u32 div;
+ unsigned long freq;
+};
+
struct mtk_pll_data {
int id;
const char *name;
@@ -150,6 +156,7 @@ struct mtk_pll_data {
int pcwbits;
uint32_t pcw_reg;
int pcw_shift;
+ const struct mtk_pll_div_table *div_table;
};
void __init mtk_clk_register_plls(struct device_node *node,
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
index 44409e98c52f..622e7b6c62b4 100644
--- a/drivers/clk/mediatek/clk-pll.c
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -90,20 +90,23 @@ static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
int postdiv)
{
- u32 con1, pd, val;
+ u32 con1, val;
int pll_en;
- /* set postdiv */
- pd = readl(pll->pd_addr);
- pd &= ~(POSTDIV_MASK << pll->data->pd_shift);
- pd |= (ffs(postdiv) - 1) << pll->data->pd_shift;
- writel(pd, pll->pd_addr);
-
pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
- /* set pcw */
- val = readl(pll->pcw_addr);
+ /* set postdiv */
+ val = readl(pll->pd_addr);
+ val &= ~(POSTDIV_MASK << pll->data->pd_shift);
+ val |= (ffs(postdiv) - 1) << pll->data->pd_shift;
+
+ /* postdiv and pcw need to set at the same time if on same register */
+ if (pll->pd_addr != pll->pcw_addr) {
+ writel(val, pll->pd_addr);
+ val = readl(pll->pcw_addr);
+ }
+ /* set pcw */
val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
pll->data->pcw_shift);
val |= pcw << pll->data->pcw_shift;
@@ -135,16 +138,28 @@ static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
u32 freq, u32 fin)
{
unsigned long fmin = 1000 * MHZ;
+ const struct mtk_pll_div_table *div_table = pll->data->div_table;
u64 _pcw;
u32 val;
if (freq > pll->data->fmax)
freq = pll->data->fmax;
- for (val = 0; val < 4; val++) {
+ if (div_table) {
+ if (freq > div_table[0].freq)
+ freq = div_table[0].freq;
+
+ for (val = 0; div_table[val + 1].freq != 0; val++) {
+ if (freq > div_table[val + 1].freq)
+ break;
+ }
*postdiv = 1 << val;
- if (freq * *postdiv >= fmin)
- break;
+ } else {
+ for (val = 0; val < 5; val++) {
+ *postdiv = 1 << val;
+ if ((u64)freq * *postdiv >= fmin)
+ break;
+ }
}
/* _pcw = freq * postdiv / fin * 2^pcwfbits */
diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c
index 71ad493b94df..f7c30ea54ca8 100644
--- a/drivers/clk/meson/clk-cpu.c
+++ b/drivers/clk/meson/clk-cpu.c
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/slab.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#define MESON_CPU_CLK_CNTL1 0x00
diff --git a/drivers/clk/meson/clkc.c b/drivers/clk/meson/clkc.c
index b8c511c5e7a7..c83ae1367abc 100644
--- a/drivers/clk/meson/clkc.c
+++ b/drivers/clk/meson/clkc.c
@@ -15,7 +15,6 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c
index 09d41c717c52..4c717db05f2d 100644
--- a/drivers/clk/mmp/clk-apbc.c
+++ b/drivers/clk/mmp/clk-apbc.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/delay.h>
diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c
index cdcf2d7f321e..47b5542ce50f 100644
--- a/drivers/clk/mmp/clk-apmu.c
+++ b/drivers/clk/mmp/clk-apmu.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/delay.h>
diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c
index adbd9d64ded2..d20cd3431ac2 100644
--- a/drivers/clk/mmp/clk-gate.c
+++ b/drivers/clk/mmp/clk-gate.c
@@ -27,7 +27,6 @@
static int mmp_clk_gate_enable(struct clk_hw *hw)
{
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
- struct clk *clk = hw->clk;
unsigned long flags = 0;
unsigned long rate;
u32 tmp;
@@ -44,7 +43,7 @@ static int mmp_clk_gate_enable(struct clk_hw *hw)
spin_unlock_irqrestore(gate->lock, flags);
if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
- rate = __clk_get_rate(clk);
+ rate = clk_hw_get_rate(hw);
/* Need delay 2 cycles. */
udelay(2000000/rate);
}
diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c
index de6a873175d2..c554833cffc5 100644
--- a/drivers/clk/mmp/clk-mix.c
+++ b/drivers/clk/mmp/clk-mix.c
@@ -63,7 +63,7 @@ static unsigned int _get_div(struct mmp_clk_mix *mix, unsigned int val)
static unsigned int _get_mux(struct mmp_clk_mix *mix, unsigned int val)
{
- int num_parents = __clk_get_num_parents(mix->hw.clk);
+ int num_parents = clk_hw_get_num_parents(&mix->hw);
int i;
if (mix->mux_flags & CLK_MUX_INDEX_BIT)
@@ -113,15 +113,15 @@ static void _filter_clk_table(struct mmp_clk_mix *mix,
{
int i;
struct mmp_clk_mix_clk_table *item;
- struct clk *parent, *clk;
+ struct clk_hw *parent, *hw;
unsigned long parent_rate;
- clk = mix->hw.clk;
+ hw = &mix->hw;
for (i = 0; i < table_size; i++) {
item = &table[i];
- parent = clk_get_parent_by_index(clk, item->parent_index);
- parent_rate = __clk_get_rate(parent);
+ parent = clk_hw_get_parent_by_index(hw, item->parent_index);
+ parent_rate = clk_hw_get_rate(parent);
if (parent_rate % item->rate) {
item->valid = 0;
} else {
@@ -181,7 +181,7 @@ static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val,
if (timeout == 0) {
pr_err("%s:%s cannot do frequency change\n",
- __func__, __clk_get_name(mix->hw.clk));
+ __func__, clk_hw_get_name(&mix->hw));
ret = -EBUSY;
goto error;
}
@@ -201,27 +201,22 @@ error:
return ret;
}
-static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_clk)
+static int mmp_clk_mix_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
struct mmp_clk_mix_clk_table *item;
- struct clk *parent, *parent_best, *mix_clk;
+ struct clk_hw *parent, *parent_best;
unsigned long parent_rate, mix_rate, mix_rate_best, parent_rate_best;
unsigned long gap, gap_best;
u32 div_val_max;
unsigned int div;
int i, j;
- mix_clk = hw->clk;
- parent = NULL;
mix_rate_best = 0;
parent_rate_best = 0;
- gap_best = rate;
+ gap_best = ULONG_MAX;
parent_best = NULL;
if (mix->table) {
@@ -229,11 +224,11 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
item = &mix->table[i];
if (item->valid == 0)
continue;
- parent = clk_get_parent_by_index(mix_clk,
+ parent = clk_hw_get_parent_by_index(hw,
item->parent_index);
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_hw_get_rate(parent);
mix_rate = parent_rate / item->divisor;
- gap = abs(mix_rate - rate);
+ gap = abs(mix_rate - req->rate);
if (parent_best == NULL || gap < gap_best) {
parent_best = parent;
parent_rate_best = parent_rate;
@@ -244,14 +239,14 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
}
}
} else {
- for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
- parent = clk_get_parent_by_index(mix_clk, i);
- parent_rate = __clk_get_rate(parent);
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+ parent = clk_hw_get_parent_by_index(hw, i);
+ parent_rate = clk_hw_get_rate(parent);
div_val_max = _get_maxdiv(mix);
for (j = 0; j < div_val_max; j++) {
div = _get_div(mix, j);
mix_rate = parent_rate / div;
- gap = abs(mix_rate - rate);
+ gap = abs(mix_rate - req->rate);
if (parent_best == NULL || gap < gap_best) {
parent_best = parent;
parent_rate_best = parent_rate;
@@ -265,10 +260,14 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
}
found:
- *best_parent_rate = parent_rate_best;
- *best_parent_clk = __clk_get_hw(parent_best);
+ if (!parent_best)
+ return -EINVAL;
+
+ req->best_parent_rate = parent_rate_best;
+ req->best_parent_hw = parent_best;
+ req->rate = mix_rate_best;
- return mix_rate_best;
+ return 0;
}
static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw,
@@ -381,20 +380,19 @@ static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
struct mmp_clk_mix_clk_table *item;
unsigned long parent_rate;
unsigned int best_divisor;
- struct clk *mix_clk, *parent;
+ struct clk_hw *parent;
int i;
best_divisor = best_parent_rate / rate;
- mix_clk = hw->clk;
if (mix->table) {
for (i = 0; i < mix->table_size; i++) {
item = &mix->table[i];
if (item->valid == 0)
continue;
- parent = clk_get_parent_by_index(mix_clk,
+ parent = clk_hw_get_parent_by_index(hw,
item->parent_index);
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_hw_get_rate(parent);
if (parent_rate == best_parent_rate
&& item->divisor == best_divisor)
break;
@@ -407,13 +405,13 @@ static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
else
return -EINVAL;
} else {
- for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
- parent = clk_get_parent_by_index(mix_clk, i);
- parent_rate = __clk_get_rate(parent);
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+ parent = clk_hw_get_parent_by_index(hw, i);
+ parent_rate = clk_hw_get_rate(parent);
if (parent_rate == best_parent_rate)
break;
}
- if (i < __clk_get_num_parents(mix_clk))
+ if (i < clk_hw_get_num_parents(hw))
return _set_rate(mix, _get_mux_val(mix, i),
_get_div_val(mix, best_divisor), 1, 1);
else
@@ -468,20 +466,20 @@ struct clk *mmp_clk_register_mix(struct device *dev,
memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info));
if (config->table) {
table_bytes = sizeof(*config->table) * config->table_size;
- mix->table = kzalloc(table_bytes, GFP_KERNEL);
+ mix->table = kmemdup(config->table, table_bytes, GFP_KERNEL);
if (!mix->table) {
pr_err("%s:%s: could not allocate mmp mix table\n",
__func__, name);
kfree(mix);
return ERR_PTR(-ENOMEM);
}
- memcpy(mix->table, config->table, table_bytes);
mix->table_size = config->table_size;
}
if (config->mux_table) {
table_bytes = sizeof(u32) * num_parents;
- mix->mux_table = kzalloc(table_bytes, GFP_KERNEL);
+ mix->mux_table = kmemdup(config->mux_table, table_bytes,
+ GFP_KERNEL);
if (!mix->mux_table) {
pr_err("%s:%s: could not allocate mmp mix mux-table\n",
__func__, name);
@@ -489,7 +487,6 @@ struct clk *mmp_clk_register_mix(struct device *dev,
kfree(mix);
return ERR_PTR(-ENOMEM);
}
- memcpy(mix->mux_table, config->mux_table, table_bytes);
}
mix->div_flags = config->div_flags;
diff --git a/drivers/clk/mmp/clk.c b/drivers/clk/mmp/clk.c
index cf038ef54c59..61893fe73251 100644
--- a/drivers/clk/mmp/clk.c
+++ b/drivers/clk/mmp/clk.c
@@ -1,7 +1,6 @@
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c
index 3821a88077ea..5837eb8a212f 100644
--- a/drivers/clk/mvebu/clk-cpu.c
+++ b/drivers/clk/mvebu/clk-cpu.c
@@ -10,7 +10,8 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/io.h>
@@ -120,7 +121,7 @@ static int clk_cpu_on_set_rate(struct clk_hw *hwclk, unsigned long rate,
if (!cpuclk->pmu_dfs)
return -ENODEV;
- cur_rate = __clk_get_rate(hwclk->clk);
+ cur_rate = clk_hw_get_rate(hwclk);
reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL2_OFFSET);
fabric_div = (reg >> SYS_CTRL_CLK_DIVIDER_CTRL2_NBCLK_RATIO_SHIFT) &
@@ -196,7 +197,6 @@ static void __init of_cpu_clk_setup(struct device_node *node)
for_each_node_by_type(dn, "cpu") {
struct clk_init_data init;
struct clk *clk;
- struct clk *parent_clk;
char *clk_name = kzalloc(5, GFP_KERNEL);
int cpu, err;
@@ -208,9 +208,8 @@ static void __init of_cpu_clk_setup(struct device_node *node)
goto bail_out;
sprintf(clk_name, "cpu%d", cpu);
- parent_clk = of_clk_get(node, 0);
- cpuclk[cpu].parent_name = __clk_get_name(parent_clk);
+ cpuclk[cpu].parent_name = of_clk_get_parent_name(node, 0);
cpuclk[cpu].clk_name = clk_name;
cpuclk[cpu].cpu = cpu;
cpuclk[cpu].reg_base = clock_complex_base;
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index 15b370ff3748..4a22429cd7a2 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -13,8 +13,8 @@
*/
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c
index 90e1da93877e..049ee27d5a22 100644
--- a/drivers/clk/mxs/clk-div.c
+++ b/drivers/clk/mxs/clk-div.c
@@ -9,7 +9,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/slab.h>
diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c
index e6aa6b567d68..73f0240569ac 100644
--- a/drivers/clk/mxs/clk-frac.c
+++ b/drivers/clk/mxs/clk-frac.c
@@ -9,7 +9,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index 32216f9b7f03..f01876af6bb8 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -9,9 +9,8 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk/mxs.h>
-#include <linux/clkdev.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index a68670868baa..6b572b759f9a 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -9,9 +9,9 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk/mxs.h>
#include <linux/clkdev.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
diff --git a/drivers/clk/mxs/clk-pll.c b/drivers/clk/mxs/clk-pll.c
index fadae41833ec..d4ca79a868e0 100644
--- a/drivers/clk/mxs/clk-pll.c
+++ b/drivers/clk/mxs/clk-pll.c
@@ -9,7 +9,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
diff --git a/drivers/clk/mxs/clk-ref.c b/drivers/clk/mxs/clk-ref.c
index 4adeed6c2f94..495f99b7965e 100644
--- a/drivers/clk/mxs/clk-ref.c
+++ b/drivers/clk/mxs/clk-ref.c
@@ -9,7 +9,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h
index f07d821dd75d..a4590956d2a2 100644
--- a/drivers/clk/mxs/clk.h
+++ b/drivers/clk/mxs/clk.h
@@ -12,7 +12,8 @@
#ifndef __MXS_CLK_H
#define __MXS_CLK_H
-#include <linux/clk.h>
+struct clk;
+
#include <linux/clk-provider.h>
#include <linux/spinlock.h>
diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c
index 81e9e1c788f4..e0a3cb8970ab 100644
--- a/drivers/clk/nxp/clk-lpc18xx-cgu.c
+++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c
@@ -8,7 +8,6 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/kernel.h>
diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c
index 8c0fe8828f99..c4ceb5eaf46c 100644
--- a/drivers/clk/pistachio/clk-pistachio.c
+++ b/drivers/clk/pistachio/clk-pistachio.c
@@ -159,9 +159,15 @@ PNAME(mux_debug) = { "mips_pll_mux", "rpu_v_pll_mux",
"wifi_pll_mux", "bt_pll_mux" };
static u32 mux_debug_idx[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10 };
-static unsigned int pistachio_critical_clks[] __initdata = {
- CLK_MIPS,
- CLK_PERIPH_SYS,
+static unsigned int pistachio_critical_clks_core[] __initdata = {
+ CLK_MIPS
+};
+
+static unsigned int pistachio_critical_clks_sys[] __initdata = {
+ PERIPH_CLK_SYS,
+ PERIPH_CLK_SYS_BUS,
+ PERIPH_CLK_DDR,
+ PERIPH_CLK_ROM,
};
static void __init pistachio_clk_init(struct device_node *np)
@@ -193,8 +199,8 @@ static void __init pistachio_clk_init(struct device_node *np)
pistachio_clk_register_provider(p);
- pistachio_clk_force_enable(p, pistachio_critical_clks,
- ARRAY_SIZE(pistachio_critical_clks));
+ pistachio_clk_force_enable(p, pistachio_critical_clks_core,
+ ARRAY_SIZE(pistachio_critical_clks_core));
}
CLK_OF_DECLARE(pistachio_clk, "img,pistachio-clk", pistachio_clk_init);
@@ -261,6 +267,9 @@ static void __init pistachio_clk_periph_init(struct device_node *np)
ARRAY_SIZE(pistachio_periph_gates));
pistachio_clk_register_provider(p);
+
+ pistachio_clk_force_enable(p, pistachio_critical_clks_sys,
+ ARRAY_SIZE(pistachio_critical_clks_sys));
}
CLK_OF_DECLARE(pistachio_clk_periph, "img,pistachio-clk-periph",
pistachio_clk_periph_init);
diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c
index e17dada0dd21..7e8daab9025b 100644
--- a/drivers/clk/pistachio/clk-pll.c
+++ b/drivers/clk/pistachio/clk-pll.c
@@ -65,6 +65,12 @@
#define MIN_OUTPUT_FRAC 12000000UL
#define MAX_OUTPUT_FRAC 1600000000UL
+/* Fractional PLL operating modes */
+enum pll_mode {
+ PLL_MODE_FRAC,
+ PLL_MODE_INT,
+};
+
struct pistachio_clk_pll {
struct clk_hw hw;
void __iomem *base;
@@ -88,12 +94,10 @@ static inline void pll_lock(struct pistachio_clk_pll *pll)
cpu_relax();
}
-static inline u32 do_div_round_closest(u64 dividend, u32 divisor)
+static inline u64 do_div_round_closest(u64 dividend, u64 divisor)
{
dividend += divisor / 2;
- do_div(dividend, divisor);
-
- return dividend;
+ return div64_u64(dividend, divisor);
}
static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
@@ -101,6 +105,29 @@ static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
return container_of(hw, struct pistachio_clk_pll, hw);
}
+static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
+{
+ struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+ u32 val;
+
+ val = pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_DSMPD;
+ return val ? PLL_MODE_INT : PLL_MODE_FRAC;
+}
+
+static inline void pll_frac_set_mode(struct clk_hw *hw, enum pll_mode mode)
+{
+ struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+ u32 val;
+
+ val = pll_readl(pll, PLL_CTRL3);
+ if (mode == PLL_MODE_INT)
+ val |= PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD;
+ else
+ val &= ~(PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD);
+
+ pll_writel(pll, val, PLL_CTRL3);
+}
+
static struct pistachio_pll_rate_table *
pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref,
unsigned long fout)
@@ -136,8 +163,7 @@ static int pll_gf40lp_frac_enable(struct clk_hw *hw)
u32 val;
val = pll_readl(pll, PLL_CTRL3);
- val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_DACPD |
- PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD |
+ val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD |
PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD);
pll_writel(pll, val, PLL_CTRL3);
@@ -173,8 +199,8 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
struct pistachio_pll_rate_table *params;
int enabled = pll_gf40lp_frac_is_enabled(hw);
- u32 val, vco, old_postdiv1, old_postdiv2;
- const char *name = __clk_get_name(hw->clk);
+ u64 val, vco, old_postdiv1, old_postdiv2;
+ const char *name = clk_hw_get_name(hw);
if (rate < MIN_OUTPUT_FRAC || rate > MAX_OUTPUT_FRAC)
return -EINVAL;
@@ -183,17 +209,21 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
if (!params || !params->refdiv)
return -EINVAL;
- vco = params->fref * params->fbdiv / params->refdiv;
+ /* calculate vco */
+ vco = params->fref;
+ vco *= (params->fbdiv << 24) + params->frac;
+ vco = div64_u64(vco, params->refdiv << 24);
+
if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC)
- pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco,
+ pr_warn("%s: VCO %llu is out of range %lu..%lu\n", name, vco,
MIN_VCO_FRAC_FRAC, MAX_VCO_FRAC_FRAC);
- val = params->fref / params->refdiv;
+ val = div64_u64(params->fref, params->refdiv);
if (val < MIN_PFD)
- pr_warn("%s: PFD %u is too low (min %lu)\n",
+ pr_warn("%s: PFD %llu is too low (min %lu)\n",
name, val, MIN_PFD);
if (val > vco / 16)
- pr_warn("%s: PFD %u is too high (max %u)\n",
+ pr_warn("%s: PFD %llu is too high (max %llu)\n",
name, val, vco / 16);
val = pll_readl(pll, PLL_CTRL1);
@@ -227,6 +257,12 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
(params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT);
pll_writel(pll, val, PLL_CTRL2);
+ /* set operating mode */
+ if (params->frac)
+ pll_frac_set_mode(hw, PLL_MODE_FRAC);
+ else
+ pll_frac_set_mode(hw, PLL_MODE_INT);
+
if (enabled)
pll_lock(pll);
@@ -237,8 +273,7 @@ static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
- u32 val, prediv, fbdiv, frac, postdiv1, postdiv2;
- u64 rate = parent_rate;
+ u64 val, prediv, fbdiv, frac, postdiv1, postdiv2, rate;
val = pll_readl(pll, PLL_CTRL1);
prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
@@ -251,7 +286,13 @@ static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
PLL_FRAC_CTRL2_POSTDIV2_MASK;
frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK;
- rate *= (fbdiv << 24) + frac;
+ /* get operating mode (int/frac) and calculate rate accordingly */
+ rate = parent_rate;
+ if (pll_frac_get_mode(hw) == PLL_MODE_FRAC)
+ rate *= (fbdiv << 24) + frac;
+ else
+ rate *= (fbdiv << 24);
+
rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24);
return rate;
@@ -279,7 +320,7 @@ static int pll_gf40lp_laint_enable(struct clk_hw *hw)
u32 val;
val = pll_readl(pll, PLL_CTRL1);
- val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_DSMPD |
+ val &= ~(PLL_INT_CTRL1_PD |
PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD);
pll_writel(pll, val, PLL_CTRL1);
@@ -316,7 +357,7 @@ static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
struct pistachio_pll_rate_table *params;
int enabled = pll_gf40lp_laint_is_enabled(hw);
u32 val, vco, old_postdiv1, old_postdiv2;
- const char *name = __clk_get_name(hw->clk);
+ const char *name = clk_hw_get_name(hw);
if (rate < MIN_OUTPUT_LA || rate > MAX_OUTPUT_LA)
return -EINVAL;
@@ -325,12 +366,12 @@ static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
if (!params || !params->refdiv)
return -EINVAL;
- vco = params->fref * params->fbdiv / params->refdiv;
+ vco = div_u64(params->fref * params->fbdiv, params->refdiv);
if (vco < MIN_VCO_LA || vco > MAX_VCO_LA)
pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco,
MIN_VCO_LA, MAX_VCO_LA);
- val = params->fref / params->refdiv;
+ val = div_u64(params->fref, params->refdiv);
if (val < MIN_PFD)
pr_warn("%s: PFD %u is too low (min %lu)\n",
name, val, MIN_PFD);
diff --git a/drivers/clk/pistachio/clk.c b/drivers/clk/pistachio/clk.c
index 85faa83e1bd7..698cad4f509e 100644
--- a/drivers/clk/pistachio/clk.c
+++ b/drivers/clk/pistachio/clk.c
@@ -6,6 +6,7 @@
* version 2, as published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/kernel.h>
#include <linux/of.h>
diff --git a/drivers/clk/pistachio/clk.h b/drivers/clk/pistachio/clk.h
index 52fabbc24624..8d45178dbde3 100644
--- a/drivers/clk/pistachio/clk.h
+++ b/drivers/clk/pistachio/clk.h
@@ -95,13 +95,13 @@ struct pistachio_fixed_factor {
}
struct pistachio_pll_rate_table {
- unsigned long fref;
- unsigned long fout;
- unsigned int refdiv;
- unsigned int fbdiv;
- unsigned int postdiv1;
- unsigned int postdiv2;
- unsigned int frac;
+ unsigned long long fref;
+ unsigned long long fout;
+ unsigned long long refdiv;
+ unsigned long long fbdiv;
+ unsigned long long postdiv1;
+ unsigned long long postdiv2;
+ unsigned long long frac;
};
enum pistachio_pll_type {
diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c
index 6cd88d963a7f..542e45ef5087 100644
--- a/drivers/clk/pxa/clk-pxa25x.c
+++ b/drivers/clk/pxa/clk-pxa25x.c
@@ -79,7 +79,7 @@ unsigned int pxa25x_get_clk_frequency_khz(int info)
clks[3] / 1000000, (clks[3] % 1000000) / 10000);
}
- return (unsigned int)clks[0];
+ return (unsigned int)clks[0] / KHz;
}
static unsigned long clk_pxa25x_memory_get_rate(struct clk_hw *hw,
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c
index 9a31b77eed23..5b82d30baf9f 100644
--- a/drivers/clk/pxa/clk-pxa27x.c
+++ b/drivers/clk/pxa/clk-pxa27x.c
@@ -80,7 +80,7 @@ unsigned int pxa27x_get_clk_frequency_khz(int info)
pr_info("System bus clock: %ld.%02ldMHz\n",
clks[4] / 1000000, (clks[4] % 1000000) / 10000);
}
- return (unsigned int)clks[0];
+ return (unsigned int)clks[0] / KHz;
}
bool pxa27x_is_ppll_disabled(void)
diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c
index 4b93a1efb36d..4af4eed5f89f 100644
--- a/drivers/clk/pxa/clk-pxa3xx.c
+++ b/drivers/clk/pxa/clk-pxa3xx.c
@@ -78,7 +78,7 @@ unsigned int pxa3xx_get_clk_frequency_khz(int info)
pr_info("System bus clock: %ld.%02ldMHz\n",
clks[4] / 1000000, (clks[4] % 1000000) / 10000);
}
- return (unsigned int)clks[0];
+ return (unsigned int)clks[0] / KHz;
}
static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw,
@@ -126,7 +126,7 @@ PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
-#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
+#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENB : &CKENA)
#define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
div_hp, bit, is_lp, flags) \
PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 6b4d2bcb1a53..26f7af315066 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -75,7 +75,7 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
bool (check_halt)(const struct clk_branch *, bool))
{
bool voted = br->halt_check & BRANCH_VOTED;
- const char *name = __clk_get_name(br->clkr.hw.clk);
+ const char *name = clk_hw_get_name(&br->clkr.hw);
/* Skip checking halt bit if the clock is in hardware gated mode */
if (clk_branch_in_hwcg_mode(br))
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index 245d5063a385..5b940d629045 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -135,19 +135,19 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
return NULL;
}
-static long
-clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate, unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p)
+static int
+clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
struct clk_pll *pll = to_clk_pll(hw);
const struct pll_freq_tbl *f;
- f = find_freq(pll->freq_tbl, rate);
+ f = find_freq(pll->freq_tbl, req->rate);
if (!f)
- return clk_pll_recalc_rate(hw, *p_rate);
+ req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate);
+ else
+ req->rate = f->freq;
- return f->freq;
+ return 0;
}
static int
@@ -194,7 +194,7 @@ static int wait_for_pll(struct clk_pll *pll)
u32 val;
int count;
int ret;
- const char *name = __clk_get_name(pll->clkr.hw.clk);
+ const char *name = clk_hw_get_name(&pll->clkr.hw);
/* Wait for pll to enable. */
for (count = 200; count > 0; count--) {
@@ -213,7 +213,7 @@ static int wait_for_pll(struct clk_pll *pll)
static int clk_pll_vote_enable(struct clk_hw *hw)
{
int ret;
- struct clk_pll *p = to_clk_pll(__clk_get_hw(__clk_get_parent(hw->clk)));
+ struct clk_pll *p = to_clk_pll(clk_hw_get_parent(hw));
ret = clk_enable_regmap(hw);
if (ret)
@@ -292,3 +292,78 @@ void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
clk_pll_set_fsm_mode(pll, regmap, 0);
}
EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp);
+
+static int clk_pll_sr2_enable(struct clk_hw *hw)
+{
+ struct clk_pll *pll = to_clk_pll(hw);
+ int ret;
+ u32 mode;
+
+ ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
+ if (ret)
+ return ret;
+
+ /* Disable PLL bypass mode. */
+ ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
+ PLL_BYPASSNL);
+ if (ret)
+ return ret;
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ udelay(10);
+
+ /* De-assert active-low PLL reset. */
+ ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
+ PLL_RESET_N);
+ if (ret)
+ return ret;
+
+ ret = wait_for_pll(pll);
+ if (ret)
+ return ret;
+
+ /* Enable PLL output. */
+ return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
+ PLL_OUTCTRL);
+}
+
+static int
+clk_pll_sr2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
+{
+ struct clk_pll *pll = to_clk_pll(hw);
+ const struct pll_freq_tbl *f;
+ bool enabled;
+ u32 mode;
+ u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
+
+ f = find_freq(pll->freq_tbl, rate);
+ if (!f)
+ return -EINVAL;
+
+ regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
+ enabled = (mode & enable_mask) == enable_mask;
+
+ if (enabled)
+ clk_pll_disable(hw);
+
+ regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
+ regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
+ regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
+
+ if (enabled)
+ clk_pll_sr2_enable(hw);
+
+ return 0;
+}
+
+const struct clk_ops clk_pll_sr2_ops = {
+ .enable = clk_pll_sr2_enable,
+ .disable = clk_pll_disable,
+ .set_rate = clk_pll_sr2_set_rate,
+ .recalc_rate = clk_pll_recalc_rate,
+ .determine_rate = clk_pll_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_pll_sr2_ops);
diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h
index c9c0cda306d0..ffd0c63bddbc 100644
--- a/drivers/clk/qcom/clk-pll.h
+++ b/drivers/clk/qcom/clk-pll.h
@@ -62,6 +62,7 @@ struct clk_pll {
extern const struct clk_ops clk_pll_ops;
extern const struct clk_ops clk_pll_vote_ops;
+extern const struct clk_ops clk_pll_sr2_ops;
#define to_clk_pll(_hw) container_of(to_clk_regmap(_hw), struct clk_pll, clkr)
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c
index 7b3d62674203..bccedc4b5756 100644
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -45,7 +45,7 @@ static u32 src_to_ns(struct src_sel *s, u8 src, u32 ns)
static u8 clk_rcg_get_parent(struct clk_hw *hw)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
- int num_parents = __clk_get_num_parents(hw->clk);
+ int num_parents = clk_hw_get_num_parents(hw);
u32 ns;
int i, ret;
@@ -59,7 +59,7 @@ static u8 clk_rcg_get_parent(struct clk_hw *hw)
err:
pr_debug("%s: Clock %s has invalid parent, using default.\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return 0;
}
@@ -72,7 +72,7 @@ static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank)
static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
{
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
- int num_parents = __clk_get_num_parents(hw->clk);
+ int num_parents = clk_hw_get_num_parents(hw);
u32 ns, reg;
int bank;
int i, ret;
@@ -95,7 +95,7 @@ static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
err:
pr_debug("%s: Clock %s has invalid parent, using default.\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return 0;
}
@@ -404,14 +404,12 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
return calc_rate(parent_rate, m, n, mode, pre_div);
}
-static long _freq_tbl_determine_rate(struct clk_hw *hw,
- const struct freq_tbl *f, unsigned long rate,
- unsigned long min_rate, unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p_hw,
+static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
+ struct clk_rate_request *req,
const struct parent_map *parent_map)
{
- unsigned long clk_flags;
- struct clk *p;
+ unsigned long clk_flags, rate = req->rate;
+ struct clk_hw *p;
int index;
f = qcom_find_freq(f, rate);
@@ -422,8 +420,8 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
if (index < 0)
return index;
- clk_flags = __clk_get_flags(hw->clk);
- p = clk_get_parent_by_index(hw->clk, index);
+ clk_flags = clk_hw_get_flags(hw);
+ p = clk_hw_get_parent_by_index(hw, index);
if (clk_flags & CLK_SET_RATE_PARENT) {
rate = rate * f->pre_div;
if (f->n) {
@@ -433,27 +431,26 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
rate = tmp;
}
} else {
- rate = __clk_get_rate(p);
+ rate = clk_hw_get_rate(p);
}
- *p_hw = __clk_get_hw(p);
- *p_rate = rate;
+ req->best_parent_hw = p;
+ req->best_parent_rate = rate;
+ req->rate = f->freq;
- return f->freq;
+ return 0;
}
-static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate, unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p)
+static int clk_rcg_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
- max_rate, p_rate, p, rcg->s.parent_map);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req,
+ rcg->s.parent_map);
}
-static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate, unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p)
+static int clk_dyn_rcg_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
u32 reg;
@@ -464,24 +461,22 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
bank = reg_to_bank(rcg, reg);
s = &rcg->s[bank];
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
- max_rate, p_rate, p, s->parent_map);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map);
}
-static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate, unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p_hw)
+static int clk_rcg_bypass_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
const struct freq_tbl *f = rcg->freq_tbl;
- struct clk *p;
+ struct clk_hw *p;
int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src);
- p = clk_get_parent_by_index(hw->clk, index);
- *p_hw = __clk_get_hw(p);
- *p_rate = __clk_round_rate(p, rate);
+ req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
+ req->best_parent_rate = clk_hw_round_rate(p, req->rate);
+ req->rate = req->best_parent_rate;
- return *p_rate;
+ return 0;
}
static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 92936f0912d2..9aec1761fd29 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -63,7 +63,7 @@ static int clk_rcg2_is_enabled(struct clk_hw *hw)
static u8 clk_rcg2_get_parent(struct clk_hw *hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int num_parents = __clk_get_num_parents(hw->clk);
+ int num_parents = clk_hw_get_num_parents(hw);
u32 cfg;
int i, ret;
@@ -80,7 +80,7 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw)
err:
pr_debug("%s: Clock %s has invalid parent, using default.\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return 0;
}
@@ -89,7 +89,7 @@ static int update_config(struct clk_rcg2 *rcg)
int count, ret;
u32 cmd;
struct clk_hw *hw = &rcg->clkr.hw;
- const char *name = __clk_get_name(hw->clk);
+ const char *name = clk_hw_get_name(hw);
ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
CMD_UPDATE, CMD_UPDATE);
@@ -176,12 +176,11 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
return calc_rate(parent_rate, m, n, mode, hid_div);
}
-static long _freq_tbl_determine_rate(struct clk_hw *hw,
- const struct freq_tbl *f, unsigned long rate,
- unsigned long *p_rate, struct clk_hw **p_hw)
+static int _freq_tbl_determine_rate(struct clk_hw *hw,
+ const struct freq_tbl *f, struct clk_rate_request *req)
{
- unsigned long clk_flags;
- struct clk *p;
+ unsigned long clk_flags, rate = req->rate;
+ struct clk_hw *p;
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
int index;
@@ -193,8 +192,8 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
if (index < 0)
return index;
- clk_flags = __clk_get_flags(hw->clk);
- p = clk_get_parent_by_index(hw->clk, index);
+ clk_flags = clk_hw_get_flags(hw);
+ p = clk_hw_get_parent_by_index(hw, index);
if (clk_flags & CLK_SET_RATE_PARENT) {
if (f->pre_div) {
rate /= 2;
@@ -208,21 +207,21 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
rate = tmp;
}
} else {
- rate = __clk_get_rate(p);
+ rate = clk_hw_get_rate(p);
}
- *p_hw = __clk_get_hw(p);
- *p_rate = rate;
+ req->best_parent_hw = p;
+ req->best_parent_rate = rate;
+ req->rate = f->freq;
- return f->freq;
+ return 0;
}
-static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate, unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p)
+static int clk_rcg2_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
}
static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
@@ -374,35 +373,33 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
return clk_edp_pixel_set_rate(hw, rate, parent_rate);
}
-static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p)
+static int clk_edp_pixel_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
const struct freq_tbl *f = rcg->freq_tbl;
const struct frac_entry *frac;
int delta = 100000;
- s64 src_rate = *p_rate;
s64 request;
u32 mask = BIT(rcg->hid_width) - 1;
u32 hid_div;
int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
/* Force the correct parent */
- *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, index));
+ req->best_parent_hw = clk_hw_get_parent_by_index(hw, index);
+ req->best_parent_rate = clk_hw_get_rate(req->best_parent_hw);
- if (src_rate == 810000000)
+ if (req->best_parent_rate == 810000000)
frac = frac_table_810m;
else
frac = frac_table_675m;
for (; frac->num; frac++) {
- request = rate;
+ request = req->rate;
request *= frac->den;
request = div_s64(request, frac->num);
- if ((src_rate < (request - delta)) ||
- (src_rate > (request + delta)))
+ if ((req->best_parent_rate < (request - delta)) ||
+ (req->best_parent_rate > (request + delta)))
continue;
regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
@@ -410,8 +407,10 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
hid_div >>= CFG_SRC_DIV_SHIFT;
hid_div &= mask;
- return calc_rate(src_rate, frac->num, frac->den, !!frac->den,
- hid_div);
+ req->rate = calc_rate(req->best_parent_rate,
+ frac->num, frac->den,
+ !!frac->den, hid_div);
+ return 0;
}
return -EINVAL;
@@ -428,28 +427,28 @@ const struct clk_ops clk_edp_pixel_ops = {
};
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
-static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate, unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p_hw)
+static int clk_byte_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
const struct freq_tbl *f = rcg->freq_tbl;
int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
unsigned long parent_rate, div;
u32 mask = BIT(rcg->hid_width) - 1;
- struct clk *p;
+ struct clk_hw *p;
- if (rate == 0)
+ if (req->rate == 0)
return -EINVAL;
- p = clk_get_parent_by_index(hw->clk, index);
- *p_hw = __clk_get_hw(p);
- *p_rate = parent_rate = __clk_round_rate(p, rate);
+ req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
+ req->best_parent_rate = parent_rate = clk_hw_round_rate(p, req->rate);
- div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
+ div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1;
div = min_t(u32, div, mask);
- return calc_rate(parent_rate, 0, 0, 0, div);
+ req->rate = calc_rate(parent_rate, 0, 0, 0, div);
+
+ return 0;
}
static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -494,10 +493,8 @@ static const struct frac_entry frac_table_pixel[] = {
{ }
};
-static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *p_rate, struct clk_hw **p)
+static int clk_pixel_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
unsigned long request, src_rate;
@@ -505,20 +502,20 @@ static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
const struct freq_tbl *f = rcg->freq_tbl;
const struct frac_entry *frac = frac_table_pixel;
int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
- struct clk *parent = clk_get_parent_by_index(hw->clk, index);
- *p = __clk_get_hw(parent);
+ req->best_parent_hw = clk_hw_get_parent_by_index(hw, index);
for (; frac->num; frac++) {
- request = (rate * frac->den) / frac->num;
+ request = (req->rate * frac->den) / frac->num;
- src_rate = __clk_round_rate(parent, request);
+ src_rate = clk_hw_round_rate(req->best_parent_hw, request);
if ((src_rate < (request - delta)) ||
(src_rate > (request + delta)))
continue;
- *p_rate = src_rate;
- return (src_rate * frac->num) / frac->den;
+ req->best_parent_rate = src_rate;
+ req->rate = (src_rate * frac->num) / frac->den;
+ return 0;
}
return -EINVAL;
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index f7101e330b1d..2dedceefd21d 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -12,6 +12,7 @@
*/
#include <linux/export.h>
+#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
@@ -45,7 +46,7 @@ EXPORT_SYMBOL_GPL(qcom_find_freq);
int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src)
{
- int i, num_parents = __clk_get_num_parents(hw->clk);
+ int i, num_parents = clk_hw_get_num_parents(hw);
for (i = 0; i < num_parents; i++)
if (src == map[i].src)
@@ -144,3 +145,5 @@ void qcom_cc_remove(struct platform_device *pdev)
reset_controller_unregister(platform_get_drvdata(pdev));
}
EXPORT_SYMBOL_GPL(qcom_cc_remove);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c
index 54a756b90a37..3563019b8e3c 100644
--- a/drivers/clk/qcom/gcc-apq8084.c
+++ b/drivers/clk/qcom/gcc-apq8084.c
@@ -48,7 +48,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = {
{ P_GPLL0, 1 }
};
-static const char *gcc_xo_gpll0[] = {
+static const char * const gcc_xo_gpll0[] = {
"xo",
"gpll0_vote",
};
@@ -59,7 +59,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
{ P_GPLL4, 5 }
};
-static const char *gcc_xo_gpll0_gpll4[] = {
+static const char * const gcc_xo_gpll0_gpll4[] = {
"xo",
"gpll0_vote",
"gpll4_vote",
@@ -70,7 +70,7 @@ static const struct parent_map gcc_xo_sata_asic0_map[] = {
{ P_SATA_ASIC0_CLK, 2 }
};
-static const char *gcc_xo_sata_asic0[] = {
+static const char * const gcc_xo_sata_asic0[] = {
"xo",
"sata_asic0_clk",
};
@@ -80,7 +80,7 @@ static const struct parent_map gcc_xo_sata_rx_map[] = {
{ P_SATA_RX_CLK, 2}
};
-static const char *gcc_xo_sata_rx[] = {
+static const char * const gcc_xo_sata_rx[] = {
"xo",
"sata_rx_clk",
};
@@ -90,7 +90,7 @@ static const struct parent_map gcc_xo_pcie_map[] = {
{ P_PCIE_0_1_PIPE_CLK, 2 }
};
-static const char *gcc_xo_pcie[] = {
+static const char * const gcc_xo_pcie[] = {
"xo",
"pcie_pipe",
};
@@ -100,7 +100,7 @@ static const struct parent_map gcc_xo_pcie_sleep_map[] = {
{ P_SLEEP_CLK, 6 }
};
-static const char *gcc_xo_pcie_sleep[] = {
+static const char * const gcc_xo_pcie_sleep[] = {
"xo",
"sleep_clk_src",
};
@@ -2105,6 +2105,7 @@ static struct clk_branch gcc_ce1_clk = {
"ce1_clk_src",
},
.num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index 563969942a1d..40e480220cd3 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -188,7 +188,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = {
{ P_PLL8, 3 }
};
-static const char *gcc_pxo_pll8[] = {
+static const char * const gcc_pxo_pll8[] = {
"pxo",
"pll8_vote",
};
@@ -199,7 +199,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = {
{ P_CXO, 5 }
};
-static const char *gcc_pxo_pll8_cxo[] = {
+static const char * const gcc_pxo_pll8_cxo[] = {
"pxo",
"pll8_vote",
"cxo",
@@ -215,7 +215,7 @@ static const struct parent_map gcc_pxo_pll3_sata_map[] = {
{ P_PLL3, 6 }
};
-static const char *gcc_pxo_pll3[] = {
+static const char * const gcc_pxo_pll3[] = {
"pxo",
"pll3",
};
@@ -226,7 +226,7 @@ static const struct parent_map gcc_pxo_pll8_pll0[] = {
{ P_PLL0, 2 }
};
-static const char *gcc_pxo_pll8_pll0_map[] = {
+static const char * const gcc_pxo_pll8_pll0_map[] = {
"pxo",
"pll8_vote",
"pll0_vote",
@@ -240,7 +240,7 @@ static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = {
{ P_PLL18, 1 }
};
-static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = {
+static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = {
"pxo",
"pll8_vote",
"pll0_vote",
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c
index fc6b12da5b30..b02826ed770a 100644
--- a/drivers/clk/qcom/gcc-msm8660.c
+++ b/drivers/clk/qcom/gcc-msm8660.c
@@ -70,7 +70,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = {
{ P_PLL8, 3 }
};
-static const char *gcc_pxo_pll8[] = {
+static const char * const gcc_pxo_pll8[] = {
"pxo",
"pll8_vote",
};
@@ -81,7 +81,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = {
{ P_CXO, 5 }
};
-static const char *gcc_pxo_pll8_cxo[] = {
+static const char * const gcc_pxo_pll8_cxo[] = {
"pxo",
"pll8_vote",
"cxo",
@@ -1917,7 +1917,7 @@ static struct clk_rcg usb_fs1_xcvr_fs_src = {
}
};
-static const char *usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" };
+static const char * const usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" };
static struct clk_branch usb_fs1_xcvr_fs_clk = {
.halt_reg = 0x2fcc,
@@ -1984,7 +1984,7 @@ static struct clk_rcg usb_fs2_xcvr_fs_src = {
}
};
-static const char *usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" };
+static const char * const usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" };
static struct clk_branch usb_fs2_xcvr_fs_clk = {
.halt_reg = 0x2fcc,
diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c
index c66f7bc2ae87..22a4e1e732c0 100644
--- a/drivers/clk/qcom/gcc-msm8916.c
+++ b/drivers/clk/qcom/gcc-msm8916.c
@@ -51,7 +51,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = {
{ P_GPLL0, 1 },
};
-static const char *gcc_xo_gpll0[] = {
+static const char * const gcc_xo_gpll0[] = {
"xo",
"gpll0_vote",
};
@@ -62,7 +62,7 @@ static const struct parent_map gcc_xo_gpll0_bimc_map[] = {
{ P_BIMC, 2 },
};
-static const char *gcc_xo_gpll0_bimc[] = {
+static const char * const gcc_xo_gpll0_bimc[] = {
"xo",
"gpll0_vote",
"bimc_pll_vote",
@@ -75,7 +75,7 @@ static const struct parent_map gcc_xo_gpll0a_gpll1_gpll2a_map[] = {
{ P_GPLL2_AUX, 2 },
};
-static const char *gcc_xo_gpll0a_gpll1_gpll2a[] = {
+static const char * const gcc_xo_gpll0a_gpll1_gpll2a[] = {
"xo",
"gpll0_vote",
"gpll1_vote",
@@ -88,7 +88,7 @@ static const struct parent_map gcc_xo_gpll0_gpll2_map[] = {
{ P_GPLL2, 2 },
};
-static const char *gcc_xo_gpll0_gpll2[] = {
+static const char * const gcc_xo_gpll0_gpll2[] = {
"xo",
"gpll0_vote",
"gpll2_vote",
@@ -99,7 +99,7 @@ static const struct parent_map gcc_xo_gpll0a_map[] = {
{ P_GPLL0_AUX, 2 },
};
-static const char *gcc_xo_gpll0a[] = {
+static const char * const gcc_xo_gpll0a[] = {
"xo",
"gpll0_vote",
};
@@ -111,7 +111,7 @@ static const struct parent_map gcc_xo_gpll0_gpll1a_sleep_map[] = {
{ P_SLEEP_CLK, 6 },
};
-static const char *gcc_xo_gpll0_gpll1a_sleep[] = {
+static const char * const gcc_xo_gpll0_gpll1a_sleep[] = {
"xo",
"gpll0_vote",
"gpll1_vote",
@@ -124,7 +124,7 @@ static const struct parent_map gcc_xo_gpll0_gpll1a_map[] = {
{ P_GPLL1_AUX, 2 },
};
-static const char *gcc_xo_gpll0_gpll1a[] = {
+static const char * const gcc_xo_gpll0_gpll1a[] = {
"xo",
"gpll0_vote",
"gpll1_vote",
@@ -135,7 +135,7 @@ static const struct parent_map gcc_xo_dsibyte_map[] = {
{ P_DSI0_PHYPLL_BYTE, 2 },
};
-static const char *gcc_xo_dsibyte[] = {
+static const char * const gcc_xo_dsibyte[] = {
"xo",
"dsi0pllbyte",
};
@@ -146,7 +146,7 @@ static const struct parent_map gcc_xo_gpll0a_dsibyte_map[] = {
{ P_DSI0_PHYPLL_BYTE, 1 },
};
-static const char *gcc_xo_gpll0a_dsibyte[] = {
+static const char * const gcc_xo_gpll0a_dsibyte[] = {
"xo",
"gpll0_vote",
"dsi0pllbyte",
@@ -158,7 +158,7 @@ static const struct parent_map gcc_xo_gpll0_dsiphy_map[] = {
{ P_DSI0_PHYPLL_DSI, 2 },
};
-static const char *gcc_xo_gpll0_dsiphy[] = {
+static const char * const gcc_xo_gpll0_dsiphy[] = {
"xo",
"gpll0_vote",
"dsi0pll",
@@ -170,7 +170,7 @@ static const struct parent_map gcc_xo_gpll0a_dsiphy_map[] = {
{ P_DSI0_PHYPLL_DSI, 1 },
};
-static const char *gcc_xo_gpll0a_dsiphy[] = {
+static const char * const gcc_xo_gpll0a_dsiphy[] = {
"xo",
"gpll0_vote",
"dsi0pll",
@@ -183,7 +183,7 @@ static const struct parent_map gcc_xo_gpll0a_gpll1_gpll2_map[] = {
{ P_GPLL2, 2 },
};
-static const char *gcc_xo_gpll0a_gpll1_gpll2[] = {
+static const char * const gcc_xo_gpll0a_gpll1_gpll2[] = {
"xo",
"gpll0_vote",
"gpll1_vote",
@@ -2278,7 +2278,7 @@ static struct clk_branch gcc_prng_ahb_clk = {
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x45004,
- .enable_mask = BIT(0),
+ .enable_mask = BIT(8),
.hw.init = &(struct clk_init_data){
.name = "gcc_prng_ahb_clk",
.parent_names = (const char *[]){
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index eb6a4f9fa107..aa294b1bad34 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -125,7 +125,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = {
{ P_PLL8, 3 }
};
-static const char *gcc_pxo_pll8[] = {
+static const char * const gcc_pxo_pll8[] = {
"pxo",
"pll8_vote",
};
@@ -136,7 +136,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = {
{ P_CXO, 5 }
};
-static const char *gcc_pxo_pll8_cxo[] = {
+static const char * const gcc_pxo_pll8_cxo[] = {
"pxo",
"pll8_vote",
"cxo",
@@ -148,7 +148,7 @@ static const struct parent_map gcc_pxo_pll8_pll3_map[] = {
{ P_PLL3, 6 }
};
-static const char *gcc_pxo_pll8_pll3[] = {
+static const char * const gcc_pxo_pll8_pll3[] = {
"pxo",
"pll8_vote",
"pll3",
@@ -2085,7 +2085,7 @@ static struct clk_rcg usb_hsic_xcvr_fs_src = {
}
};
-static const char *usb_hsic_xcvr_fs_src_p[] = { "usb_hsic_xcvr_fs_src" };
+static const char * const usb_hsic_xcvr_fs_src_p[] = { "usb_hsic_xcvr_fs_src" };
static struct clk_branch usb_hsic_xcvr_fs_clk = {
.halt_reg = 0x2fc8,
@@ -2181,7 +2181,7 @@ static struct clk_rcg usb_fs1_xcvr_fs_src = {
}
};
-static const char *usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" };
+static const char * const usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" };
static struct clk_branch usb_fs1_xcvr_fs_clk = {
.halt_reg = 0x2fcc,
@@ -2248,7 +2248,7 @@ static struct clk_rcg usb_fs2_xcvr_fs_src = {
}
};
-static const char *usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" };
+static const char * const usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" };
static struct clk_branch usb_fs2_xcvr_fs_clk = {
.halt_reg = 0x2fcc,
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index c39d09874e74..2bcf87538f9d 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -44,7 +44,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = {
{ P_GPLL0, 1 }
};
-static const char *gcc_xo_gpll0[] = {
+static const char * const gcc_xo_gpll0[] = {
"xo",
"gpll0_vote",
};
@@ -55,7 +55,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
{ P_GPLL4, 5 }
};
-static const char *gcc_xo_gpll0_gpll4[] = {
+static const char * const gcc_xo_gpll0_gpll4[] = {
"xo",
"gpll0_vote",
"gpll4_vote",
@@ -1783,6 +1783,7 @@ static struct clk_branch gcc_ce1_clk = {
"ce1_clk_src",
},
.num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
index 47f0ac16d149..93ad42b14366 100644
--- a/drivers/clk/qcom/lcc-ipq806x.c
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -71,7 +71,7 @@ static const struct parent_map lcc_pxo_pll4_map[] = {
{ P_PLL4, 2 }
};
-static const char *lcc_pxo_pll4[] = {
+static const char * const lcc_pxo_pll4[] = {
"pxo",
"pll4_vote",
};
@@ -146,7 +146,7 @@ static struct clk_rcg mi2s_osr_src = {
},
};
-static const char *lcc_mi2s_parents[] = {
+static const char * const lcc_mi2s_parents[] = {
"mi2s_osr_src",
};
@@ -340,7 +340,7 @@ static struct clk_rcg spdif_src = {
},
};
-static const char *lcc_spdif_parents[] = {
+static const char * const lcc_spdif_parents[] = {
"spdif_src",
};
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
index d0df9d5fc3af..ecb96c284675 100644
--- a/drivers/clk/qcom/lcc-msm8960.c
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -57,7 +57,7 @@ static const struct parent_map lcc_pxo_pll4_map[] = {
{ P_PLL4, 2 }
};
-static const char *lcc_pxo_pll4[] = {
+static const char * const lcc_pxo_pll4[] = {
"pxo",
"pll4_vote",
};
@@ -127,7 +127,7 @@ static struct clk_rcg mi2s_osr_src = {
},
};
-static const char *lcc_mi2s_parents[] = {
+static const char * const lcc_mi2s_parents[] = {
"mi2s_osr_src",
};
@@ -233,7 +233,7 @@ static struct clk_rcg prefix##_osr_src = { \
}, \
}; \
\
-static const char *lcc_##prefix##_parents[] = { \
+static const char * const lcc_##prefix##_parents[] = { \
#prefix "_osr_src", \
}; \
\
@@ -445,7 +445,7 @@ static struct clk_rcg slimbus_src = {
},
};
-static const char *lcc_slimbus_parents[] = {
+static const char * const lcc_slimbus_parents[] = {
"slimbus_src",
};
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c
index 1b17df2cb0af..f0ee6bde11af 100644
--- a/drivers/clk/qcom/mmcc-apq8084.c
+++ b/drivers/clk/qcom/mmcc-apq8084.c
@@ -53,7 +53,7 @@ static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = {
{ P_GPLL0, 5 }
};
-static const char *mmcc_xo_mmpll0_mmpll1_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_mmpll1_gpll0[] = {
"xo",
"mmpll0_vote",
"mmpll1_vote",
@@ -69,7 +69,7 @@ static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = {
{ P_DSI1PLL, 3 }
};
-static const char *mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = {
"xo",
"mmpll0_vote",
"hdmipll",
@@ -86,7 +86,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = {
{ P_MMPLL2, 3 }
};
-static const char *mmcc_xo_mmpll0_1_2_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_1_2_gpll0[] = {
"xo",
"mmpll0_vote",
"mmpll1_vote",
@@ -102,7 +102,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = {
{ P_MMPLL3, 3 }
};
-static const char *mmcc_xo_mmpll0_1_3_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_1_3_gpll0[] = {
"xo",
"mmpll0_vote",
"mmpll1_vote",
@@ -119,7 +119,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = {
{ P_DSI1PLL, 2 }
};
-static const char *mmcc_xo_dsi_hdmi_edp[] = {
+static const char * const mmcc_xo_dsi_hdmi_edp[] = {
"xo",
"edp_link_clk",
"hdmipll",
@@ -137,7 +137,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = {
{ P_DSI1PLL, 2 }
};
-static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = {
+static const char * const mmcc_xo_dsi_hdmi_edp_gpll0[] = {
"xo",
"edp_link_clk",
"hdmipll",
@@ -155,7 +155,7 @@ static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = {
{ P_DSI1PLL_BYTE, 2 }
};
-static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
+static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
"xo",
"edp_link_clk",
"hdmipll",
@@ -172,7 +172,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll0_map[] = {
{ P_MMPLL4, 3 }
};
-static const char *mmcc_xo_mmpll0_1_4_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_1_4_gpll0[] = {
"xo",
"mmpll0",
"mmpll1",
@@ -189,7 +189,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_map[] = {
{ P_GPLL1, 4 }
};
-static const char *mmcc_xo_mmpll0_1_4_gpll1_0[] = {
+static const char * const mmcc_xo_mmpll0_1_4_gpll1_0[] = {
"xo",
"mmpll0",
"mmpll1",
@@ -208,7 +208,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_sleep_map[] = {
{ P_MMSLEEP, 6 }
};
-static const char *mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = {
+static const char * const mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = {
"xo",
"mmpll0",
"mmpll1",
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c
index 9711bca9cc06..bad02aebf959 100644
--- a/drivers/clk/qcom/mmcc-msm8960.c
+++ b/drivers/clk/qcom/mmcc-msm8960.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
@@ -50,7 +51,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_map[] = {
{ P_PLL2, 1 }
};
-static const char *mmcc_pxo_pll8_pll2[] = {
+static const char * const mmcc_pxo_pll8_pll2[] = {
"pxo",
"pll8_vote",
"pll2",
@@ -63,7 +64,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_pll3_map[] = {
{ P_PLL3, 3 }
};
-static const char *mmcc_pxo_pll8_pll2_pll15[] = {
+static const char * const mmcc_pxo_pll8_pll2_pll15[] = {
"pxo",
"pll8_vote",
"pll2",
@@ -77,7 +78,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_pll15_map[] = {
{ P_PLL15, 3 }
};
-static const char *mmcc_pxo_pll8_pll2_pll3[] = {
+static const char * const mmcc_pxo_pll8_pll2_pll3[] = {
"pxo",
"pll8_vote",
"pll2",
@@ -508,8 +509,7 @@ static int pix_rdi_set_parent(struct clk_hw *hw, u8 index)
int ret = 0;
u32 val;
struct clk_pix_rdi *rdi = to_clk_pix_rdi(hw);
- struct clk *clk = hw->clk;
- int num_parents = __clk_get_num_parents(hw->clk);
+ int num_parents = clk_hw_get_num_parents(hw);
/*
* These clocks select three inputs via two muxes. One mux selects
@@ -520,7 +520,8 @@ static int pix_rdi_set_parent(struct clk_hw *hw, u8 index)
* needs to be on at what time.
*/
for (i = 0; i < num_parents; i++) {
- ret = clk_prepare_enable(clk_get_parent_by_index(clk, i));
+ struct clk_hw *p = clk_hw_get_parent_by_index(hw, i);
+ ret = clk_prepare_enable(p->clk);
if (ret)
goto err;
}
@@ -548,8 +549,10 @@ static int pix_rdi_set_parent(struct clk_hw *hw, u8 index)
udelay(1);
err:
- for (i--; i >= 0; i--)
- clk_disable_unprepare(clk_get_parent_by_index(clk, i));
+ for (i--; i >= 0; i--) {
+ struct clk_hw *p = clk_hw_get_parent_by_index(hw, i);
+ clk_disable_unprepare(p->clk);
+ }
return ret;
}
@@ -579,7 +582,7 @@ static const struct clk_ops clk_ops_pix_rdi = {
.determine_rate = __clk_mux_determine_rate,
};
-static const char *pix_rdi_parents[] = {
+static const char * const pix_rdi_parents[] = {
"csi0_clk",
"csi1_clk",
"csi2_clk",
@@ -709,7 +712,7 @@ static struct clk_rcg csiphytimer_src = {
},
};
-static const char *csixphy_timer_src[] = { "csiphytimer_src" };
+static const char * const csixphy_timer_src[] = { "csiphytimer_src" };
static struct clk_branch csiphy0_timer_clk = {
.halt_reg = 0x01e8,
@@ -1385,7 +1388,7 @@ static const struct parent_map mmcc_pxo_hdmi_map[] = {
{ P_HDMI_PLL, 3 }
};
-static const char *mmcc_pxo_hdmi[] = {
+static const char * const mmcc_pxo_hdmi[] = {
"pxo",
"hdmi_pll",
};
@@ -1428,7 +1431,7 @@ static struct clk_rcg tv_src = {
},
};
-static const char *tv_src_name[] = { "tv_src" };
+static const char * const tv_src_name[] = { "tv_src" };
static struct clk_branch tv_enc_clk = {
.halt_reg = 0x01d4,
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c
index 07f4cc159ad3..0987bf443e1f 100644
--- a/drivers/clk/qcom/mmcc-msm8974.c
+++ b/drivers/clk/qcom/mmcc-msm8974.c
@@ -56,7 +56,7 @@ static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = {
{ P_GPLL0, 5 }
};
-static const char *mmcc_xo_mmpll0_mmpll1_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_mmpll1_gpll0[] = {
"xo",
"mmpll0_vote",
"mmpll1_vote",
@@ -72,7 +72,7 @@ static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = {
{ P_DSI1PLL, 3 }
};
-static const char *mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = {
"xo",
"mmpll0_vote",
"hdmipll",
@@ -89,7 +89,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = {
{ P_MMPLL2, 3 }
};
-static const char *mmcc_xo_mmpll0_1_2_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_1_2_gpll0[] = {
"xo",
"mmpll0_vote",
"mmpll1_vote",
@@ -105,7 +105,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = {
{ P_MMPLL3, 3 }
};
-static const char *mmcc_xo_mmpll0_1_3_gpll0[] = {
+static const char * const mmcc_xo_mmpll0_1_3_gpll0[] = {
"xo",
"mmpll0_vote",
"mmpll1_vote",
@@ -121,7 +121,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_gpll1_0_map[] = {
{ P_GPLL1, 4 }
};
-static const char *mmcc_xo_mmpll0_1_gpll1_0[] = {
+static const char * const mmcc_xo_mmpll0_1_gpll1_0[] = {
"xo",
"mmpll0_vote",
"mmpll1_vote",
@@ -138,7 +138,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = {
{ P_DSI1PLL, 2 }
};
-static const char *mmcc_xo_dsi_hdmi_edp[] = {
+static const char * const mmcc_xo_dsi_hdmi_edp[] = {
"xo",
"edp_link_clk",
"hdmipll",
@@ -156,7 +156,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = {
{ P_DSI1PLL, 2 }
};
-static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = {
+static const char * const mmcc_xo_dsi_hdmi_edp_gpll0[] = {
"xo",
"edp_link_clk",
"hdmipll",
@@ -174,7 +174,7 @@ static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = {
{ P_DSI1PLL_BYTE, 2 }
};
-static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
+static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
"xo",
"edp_link_clk",
"hdmipll",
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 2714097f90db..b27edd6c8183 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -6,8 +6,10 @@ obj-y += clk-rockchip.o
obj-y += clk.o
obj-y += clk-pll.o
obj-y += clk-cpu.o
+obj-y += clk-inverter.o
obj-y += clk-mmc-phase.o
obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
obj-y += clk-rk3188.o
obj-y += clk-rk3288.o
+obj-y += clk-rk3368.o
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
index fb7721bd37e6..330870a6d8bf 100644
--- a/drivers/clk/rockchip/clk-cpu.c
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -35,6 +35,7 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include "clk.h"
diff --git a/drivers/clk/rockchip/clk-inverter.c b/drivers/clk/rockchip/clk-inverter.c
new file mode 100644
index 000000000000..7cbf43beb3c6
--- /dev/null
+++ b/drivers/clk/rockchip/clk-inverter.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2015 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include "clk.h"
+
+struct rockchip_inv_clock {
+ struct clk_hw hw;
+ void __iomem *reg;
+ int shift;
+ int flags;
+ spinlock_t *lock;
+};
+
+#define to_inv_clock(_hw) container_of(_hw, struct rockchip_inv_clock, hw)
+
+#define INVERTER_MASK 0x1
+
+static int rockchip_inv_get_phase(struct clk_hw *hw)
+{
+ struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
+ u32 val;
+
+ val = readl(inv_clock->reg) >> inv_clock->shift;
+ val &= INVERTER_MASK;
+ return val ? 180 : 0;
+}
+
+static int rockchip_inv_set_phase(struct clk_hw *hw, int degrees)
+{
+ struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
+ u32 val;
+
+ if (degrees % 180 == 0) {
+ val = !!degrees;
+ } else {
+ pr_err("%s: unsupported phase %d for %s\n",
+ __func__, degrees, clk_hw_get_name(hw));
+ return -EINVAL;
+ }
+
+ if (inv_clock->flags & ROCKCHIP_INVERTER_HIWORD_MASK) {
+ writel(HIWORD_UPDATE(val, INVERTER_MASK, inv_clock->shift),
+ inv_clock->reg);
+ } else {
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(inv_clock->lock, flags);
+
+ reg = readl(inv_clock->reg);
+ reg &= ~BIT(inv_clock->shift);
+ reg |= val;
+ writel(reg, inv_clock->reg);
+
+ spin_unlock_irqrestore(inv_clock->lock, flags);
+ }
+
+ return 0;
+}
+
+static const struct clk_ops rockchip_inv_clk_ops = {
+ .get_phase = rockchip_inv_get_phase,
+ .set_phase = rockchip_inv_set_phase,
+};
+
+struct clk *rockchip_clk_register_inverter(const char *name,
+ const char *const *parent_names, u8 num_parents,
+ void __iomem *reg, int shift, int flags,
+ spinlock_t *lock)
+{
+ struct clk_init_data init;
+ struct rockchip_inv_clock *inv_clock;
+ struct clk *clk;
+
+ inv_clock = kmalloc(sizeof(*inv_clock), GFP_KERNEL);
+ if (!inv_clock)
+ return NULL;
+
+ init.name = name;
+ init.num_parents = num_parents;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.parent_names = parent_names;
+ init.ops = &rockchip_inv_clk_ops;
+
+ inv_clock->hw.init = &init;
+ inv_clock->reg = reg;
+ inv_clock->shift = shift;
+ inv_clock->flags = flags;
+ inv_clock->lock = lock;
+
+ clk = clk_register(NULL, &inv_clock->hw);
+ if (IS_ERR(clk))
+ goto err_free;
+
+ return clk;
+
+err_free:
+ kfree(inv_clock);
+ return NULL;
+}
diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
index e9f8df324e7c..9b613426e968 100644
--- a/drivers/clk/rockchip/clk-mmc-phase.c
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -14,7 +14,10 @@
*/
#include <linux/slab.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
#include "clk.h"
struct rockchip_mmc_clock {
@@ -105,7 +108,7 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), mmc_clock->reg);
pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n",
- __clk_get_name(hw->clk), degrees, delay_num,
+ clk_hw_get_name(hw), degrees, delay_num,
mmc_clock->reg, raw_value>>(mmc_clock->shift),
rockchip_mmc_get_phase(hw)
);
@@ -131,6 +134,7 @@ struct clk *rockchip_clk_register_mmc(const char *name,
if (!mmc_clock)
return NULL;
+ init.name = name;
init.num_parents = num_parents;
init.parent_names = parent_names;
init.ops = &rockchip_mmc_clk_ops;
@@ -139,9 +143,6 @@ struct clk *rockchip_clk_register_mmc(const char *name,
mmc_clock->reg = reg;
mmc_clock->shift = shift;
- if (name)
- init.name = name;
-
clk = clk_register(NULL, &mmc_clock->hw);
if (IS_ERR(clk))
goto err_free;
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 76027261f7ed..7737a1df1e4b 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/delay.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include "clk.h"
@@ -121,8 +120,8 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
#define RK3066_PLLCON0_NR_SHIFT 8
#define RK3066_PLLCON1_NF_MASK 0x1fff
#define RK3066_PLLCON1_NF_SHIFT 0
-#define RK3066_PLLCON2_BWADJ_MASK 0xfff
-#define RK3066_PLLCON2_BWADJ_SHIFT 0
+#define RK3066_PLLCON2_NB_MASK 0xfff
+#define RK3066_PLLCON2_NB_SHIFT 0
#define RK3066_PLLCON3_RESET (1 << 5)
#define RK3066_PLLCON3_PWRDOWN (1 << 1)
#define RK3066_PLLCON3_BYPASS (1 << 0)
@@ -137,7 +136,7 @@ static unsigned long rockchip_rk3066_pll_recalc_rate(struct clk_hw *hw,
pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(3));
if (pllcon & RK3066_PLLCON3_BYPASS) {
pr_debug("%s: pll %s is bypassed\n", __func__,
- __clk_get_name(hw->clk));
+ clk_hw_get_name(hw));
return prate;
}
@@ -175,13 +174,13 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
}
pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
- __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
+ __func__, clk_hw_get_name(hw), old_rate, drate, prate);
/* Get required rate settings from table */
rate = rockchip_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
@@ -208,8 +207,8 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
writel_relaxed(HIWORD_UPDATE(rate->nf - 1, RK3066_PLLCON1_NF_MASK,
RK3066_PLLCON1_NF_SHIFT),
pll->reg_base + RK3066_PLLCON(1));
- writel_relaxed(HIWORD_UPDATE(rate->bwadj, RK3066_PLLCON2_BWADJ_MASK,
- RK3066_PLLCON2_BWADJ_SHIFT),
+ writel_relaxed(HIWORD_UPDATE(rate->nb - 1, RK3066_PLLCON2_NB_MASK,
+ RK3066_PLLCON2_NB_SHIFT),
pll->reg_base + RK3066_PLLCON(2));
/* leave reset and wait the reset_delay */
@@ -262,14 +261,14 @@ static void rockchip_rk3066_pll_init(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
const struct rockchip_pll_rate_table *rate;
- unsigned int nf, nr, no, bwadj;
+ unsigned int nf, nr, no, nb;
unsigned long drate;
u32 pllcon;
if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
return;
- drate = __clk_get_rate(hw->clk);
+ drate = clk_hw_get_rate(hw);
rate = rockchip_get_pll_settings(pll, drate);
/* when no rate setting for the current rate, rely on clk_set_rate */
@@ -284,25 +283,25 @@ static void rockchip_rk3066_pll_init(struct clk_hw *hw)
nf = ((pllcon >> RK3066_PLLCON1_NF_SHIFT) & RK3066_PLLCON1_NF_MASK) + 1;
pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(2));
- bwadj = (pllcon >> RK3066_PLLCON2_BWADJ_SHIFT) & RK3066_PLLCON2_BWADJ_MASK;
+ nb = ((pllcon >> RK3066_PLLCON2_NB_SHIFT) & RK3066_PLLCON2_NB_MASK) + 1;
- pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), bwadj(%d:%d)\n",
- __func__, __clk_get_name(hw->clk), drate, rate->nr, nr,
- rate->no, no, rate->nf, nf, rate->bwadj, bwadj);
+ pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), nb(%d:%d)\n",
+ __func__, clk_hw_get_name(hw), drate, rate->nr, nr,
+ rate->no, no, rate->nf, nf, rate->nb, nb);
if (rate->nr != nr || rate->no != no || rate->nf != nf
- || rate->bwadj != bwadj) {
- struct clk *parent = __clk_get_parent(hw->clk);
+ || rate->nb != nb) {
+ struct clk_hw *parent = clk_hw_get_parent(hw);
unsigned long prate;
if (!parent) {
pr_warn("%s: parent of %s not available\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return;
}
pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
- __func__, __clk_get_name(hw->clk));
- prate = __clk_get_rate(parent);
+ __func__, clk_hw_get_name(hw));
+ prate = clk_hw_get_rate(parent);
rockchip_rk3066_pll_set_rate(hw, drate, prate);
}
}
@@ -354,6 +353,35 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
if (!pll)
return ERR_PTR(-ENOMEM);
+ /* create the mux on top of the real pll */
+ pll->pll_mux_ops = &clk_mux_ops;
+ pll_mux = &pll->pll_mux;
+ pll_mux->reg = base + mode_offset;
+ pll_mux->shift = mode_shift;
+ pll_mux->mask = PLL_MODE_MASK;
+ pll_mux->flags = 0;
+ pll_mux->lock = lock;
+ pll_mux->hw.init = &init;
+
+ if (pll_type == pll_rk3066)
+ pll_mux->flags |= CLK_MUX_HIWORD_MASK;
+
+ /* the actual muxing is xin24m, pll-output, xin32k */
+ pll_parents[0] = parent_names[0];
+ pll_parents[1] = pll_name;
+ pll_parents[2] = parent_names[1];
+
+ init.name = name;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.ops = pll->pll_mux_ops;
+ init.parent_names = pll_parents;
+ init.num_parents = ARRAY_SIZE(pll_parents);
+
+ mux_clk = clk_register(NULL, &pll_mux->hw);
+ if (IS_ERR(mux_clk))
+ goto err_mux;
+
+ /* now create the actual pll */
init.name = pll_name;
/* keep all plls untouched for now */
@@ -399,47 +427,19 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
pll->flags = clk_pll_flags;
pll->lock = lock;
- /* create the mux on top of the real pll */
- pll->pll_mux_ops = &clk_mux_ops;
- pll_mux = &pll->pll_mux;
- pll_mux->reg = base + mode_offset;
- pll_mux->shift = mode_shift;
- pll_mux->mask = PLL_MODE_MASK;
- pll_mux->flags = 0;
- pll_mux->lock = lock;
- pll_mux->hw.init = &init;
-
- if (pll_type == pll_rk3066)
- pll_mux->flags |= CLK_MUX_HIWORD_MASK;
-
pll_clk = clk_register(NULL, &pll->hw);
if (IS_ERR(pll_clk)) {
pr_err("%s: failed to register pll clock %s : %ld\n",
__func__, name, PTR_ERR(pll_clk));
- mux_clk = pll_clk;
goto err_pll;
}
- /* the actual muxing is xin24m, pll-output, xin32k */
- pll_parents[0] = parent_names[0];
- pll_parents[1] = pll_name;
- pll_parents[2] = parent_names[1];
-
- init.name = name;
- init.flags = CLK_SET_RATE_PARENT;
- init.ops = pll->pll_mux_ops;
- init.parent_names = pll_parents;
- init.num_parents = ARRAY_SIZE(pll_parents);
-
- mux_clk = clk_register(NULL, &pll_mux->hw);
- if (IS_ERR(mux_clk))
- goto err_mux;
-
return mux_clk;
-err_mux:
- clk_unregister(pll_clk);
err_pll:
+ clk_unregister(mux_clk);
+ mux_clk = pll_clk;
+err_mux:
kfree(pll);
return mux_clk;
}
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index e4f9d472f1ff..ed02bbc7b11f 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -13,6 +13,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -201,7 +202,7 @@ PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" };
PNAME(mux_aclk_cpu_p) = { "apll", "gpll" };
PNAME(mux_sclk_cif0_p) = { "cif0_pre", "xin24m" };
PNAME(mux_sclk_i2s0_p) = { "i2s0_pre", "i2s0_frac", "xin12m" };
-PNAME(mux_sclk_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" };
+PNAME(mux_sclk_spdif_p) = { "spdif_pre", "spdif_frac", "xin12m" };
PNAME(mux_sclk_uart0_p) = { "uart0_pre", "uart0_frac", "xin24m" };
PNAME(mux_sclk_uart1_p) = { "uart1_pre", "uart1_frac", "xin24m" };
PNAME(mux_sclk_uart2_p) = { "uart2_pre", "uart2_frac", "xin24m" };
@@ -235,6 +236,7 @@ static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = {
#define MFLAGS CLK_MUX_HIWORD_MASK
#define DFLAGS CLK_DIVIDER_HIWORD_MASK
#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
/* 2 ^ (val + 1) */
static struct clk_div_table div_core_peri_t[] = {
@@ -310,6 +312,8 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
GATE(0, "pclkin_cif0", "ext_cif0", 0,
RK2928_CLKGATE_CON(3), 3, GFLAGS),
+ INVERTER(0, "pclk_cif0", "pclkin_cif0",
+ RK2928_CLKSEL_CON(30), 8, IFLAGS),
/*
* the 480m are generated inside the usb block from these clocks,
@@ -334,8 +338,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0,
RK2928_CLKSEL_CON(23), 0,
RK2928_CLKGATE_CON(2), 7, GFLAGS),
- MUX(SCLK_HSADC, "sclk_hsadc", mux_sclk_hsadc_p, 0,
+ MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0,
RK2928_CLKSEL_CON(22), 4, 2, MFLAGS),
+ INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out",
+ RK2928_CLKSEL_CON(22), 7, IFLAGS),
COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0,
RK2928_CLKSEL_CON(24), 8, 8, DFLAGS,
@@ -344,10 +350,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(5), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 13, GFLAGS),
- COMPOSITE_FRAC(0, "spdif_frac", "spdif_pll", 0,
+ COMPOSITE_FRAC(0, "spdif_frac", "spdif_pre", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(9), 0,
RK2928_CLKGATE_CON(0), 14, GFLAGS),
- MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0,
+ MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(5), 8, 2, MFLAGS),
/*
@@ -557,6 +563,8 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
GATE(0, "pclkin_cif1", "ext_cif1", 0,
RK2928_CLKGATE_CON(3), 4, GFLAGS),
+ INVERTER(0, "pclk_cif1", "pclkin_cif1",
+ RK2928_CLKSEL_CON(30), 12, IFLAGS),
COMPOSITE(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0,
RK2928_CLKSEL_CON(33), 8, 1, MFLAGS, 0, 5, DFLAGS,
@@ -809,7 +817,7 @@ static void __init rk3188_clk_init(struct device_node *np)
rate = pll->rate_table;
while (rate->rate > 0) {
- rate->bwadj = 0;
+ rate->nb = 1;
rate++;
}
}
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index fdb0c7c95a66..9040878e3e2b 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -84,7 +84,7 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
RK3066_PLL_RATE( 742500000, 8, 495, 2),
RK3066_PLL_RATE( 696000000, 1, 58, 2),
RK3066_PLL_RATE( 600000000, 1, 50, 2),
- RK3066_PLL_RATE_BWADJ(594000000, 1, 198, 8, 1),
+ RK3066_PLL_RATE_NB(594000000, 1, 198, 8, 1),
RK3066_PLL_RATE( 552000000, 1, 46, 2),
RK3066_PLL_RATE( 504000000, 1, 84, 4),
RK3066_PLL_RATE( 500000000, 3, 125, 2),
@@ -189,7 +189,7 @@ PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" };
PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" };
PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" };
-PNAME(mux_cif_out_p) = { "cif_src", "xin24m" };
+PNAME(mux_vip_out_p) = { "vip_src", "xin24m" };
PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" };
PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" };
PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" };
@@ -223,6 +223,7 @@ static struct clk_div_table div_hclk_cpu_t[] = {
#define MFLAGS CLK_MUX_HIWORD_MASK
#define DFLAGS CLK_DIVIDER_HIWORD_MASK
#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
/*
@@ -434,7 +435,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(26), 8, 1, MFLAGS,
RK3288_CLKGATE_CON(3), 7, GFLAGS),
- COMPOSITE_NOGATE(0, "sclk_vip_out", mux_cif_out_p, 0,
+ COMPOSITE_NOGATE(0, "sclk_vip_out", mux_vip_out_p, 0,
RK3288_CLKSEL_CON(26), 15, 1, MFLAGS, 9, 5, DFLAGS),
DIV(0, "pclk_pd_alive", "gpll", 0,
@@ -578,7 +579,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
RK3288_CLKGATE_CON(2), 5, GFLAGS),
- MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0,
+ MUX(SCLK_MAC, "mac_clk", mux_mac_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(21), 4, 1, MFLAGS),
GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 3, GFLAGS),
@@ -592,8 +593,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS,
RK3288_CLKGATE_CON(2), 6, GFLAGS),
- MUX(SCLK_HSADC, "sclk_hsadc_out", mux_hsadcout_p, 0,
+ MUX(0, "sclk_hsadc_out", mux_hsadcout_p, 0,
RK3288_CLKSEL_CON(22), 4, 1, MFLAGS),
+ INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out",
+ RK3288_CLKSEL_CON(22), 7, IFLAGS),
GATE(0, "jtag", "ext_jtag", 0,
RK3288_CLKGATE_CON(4), 14, GFLAGS),
@@ -768,7 +771,9 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
*/
GATE(0, "pclk_vip_in", "ext_vip", 0, RK3288_CLKGATE_CON(16), 0, GFLAGS),
+ INVERTER(0, "pclk_vip", "pclk_vip_in", RK3288_CLKSEL_CON(29), 4, IFLAGS),
GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS),
+ INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS),
};
static const char *const rk3288_critical_clocks[] __initconst = {
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
new file mode 100644
index 000000000000..9c5d61e698ef
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -0,0 +1,881 @@
+/*
+ * Copyright (c) 2015 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/rk3368-cru.h>
+#include "clk.h"
+
+#define RK3368_GRF_SOC_STATUS0 0x480
+
+enum rk3368_plls {
+ apllb, aplll, dpll, cpll, gpll, npll,
+};
+
+static struct rockchip_pll_rate_table rk3368_pll_rates[] = {
+ RK3066_PLL_RATE(2208000000, 1, 92, 1),
+ RK3066_PLL_RATE(2184000000, 1, 91, 1),
+ RK3066_PLL_RATE(2160000000, 1, 90, 1),
+ RK3066_PLL_RATE(2136000000, 1, 89, 1),
+ RK3066_PLL_RATE(2112000000, 1, 88, 1),
+ RK3066_PLL_RATE(2088000000, 1, 87, 1),
+ RK3066_PLL_RATE(2064000000, 1, 86, 1),
+ RK3066_PLL_RATE(2040000000, 1, 85, 1),
+ RK3066_PLL_RATE(2016000000, 1, 84, 1),
+ RK3066_PLL_RATE(1992000000, 1, 83, 1),
+ RK3066_PLL_RATE(1968000000, 1, 82, 1),
+ RK3066_PLL_RATE(1944000000, 1, 81, 1),
+ RK3066_PLL_RATE(1920000000, 1, 80, 1),
+ RK3066_PLL_RATE(1896000000, 1, 79, 1),
+ RK3066_PLL_RATE(1872000000, 1, 78, 1),
+ RK3066_PLL_RATE(1848000000, 1, 77, 1),
+ RK3066_PLL_RATE(1824000000, 1, 76, 1),
+ RK3066_PLL_RATE(1800000000, 1, 75, 1),
+ RK3066_PLL_RATE(1776000000, 1, 74, 1),
+ RK3066_PLL_RATE(1752000000, 1, 73, 1),
+ RK3066_PLL_RATE(1728000000, 1, 72, 1),
+ RK3066_PLL_RATE(1704000000, 1, 71, 1),
+ RK3066_PLL_RATE(1680000000, 1, 70, 1),
+ RK3066_PLL_RATE(1656000000, 1, 69, 1),
+ RK3066_PLL_RATE(1632000000, 1, 68, 1),
+ RK3066_PLL_RATE(1608000000, 1, 67, 1),
+ RK3066_PLL_RATE(1560000000, 1, 65, 1),
+ RK3066_PLL_RATE(1512000000, 1, 63, 1),
+ RK3066_PLL_RATE(1488000000, 1, 62, 1),
+ RK3066_PLL_RATE(1464000000, 1, 61, 1),
+ RK3066_PLL_RATE(1440000000, 1, 60, 1),
+ RK3066_PLL_RATE(1416000000, 1, 59, 1),
+ RK3066_PLL_RATE(1392000000, 1, 58, 1),
+ RK3066_PLL_RATE(1368000000, 1, 57, 1),
+ RK3066_PLL_RATE(1344000000, 1, 56, 1),
+ RK3066_PLL_RATE(1320000000, 1, 55, 1),
+ RK3066_PLL_RATE(1296000000, 1, 54, 1),
+ RK3066_PLL_RATE(1272000000, 1, 53, 1),
+ RK3066_PLL_RATE(1248000000, 1, 52, 1),
+ RK3066_PLL_RATE(1224000000, 1, 51, 1),
+ RK3066_PLL_RATE(1200000000, 1, 50, 1),
+ RK3066_PLL_RATE(1176000000, 1, 49, 1),
+ RK3066_PLL_RATE(1128000000, 1, 47, 1),
+ RK3066_PLL_RATE(1104000000, 1, 46, 1),
+ RK3066_PLL_RATE(1008000000, 1, 84, 2),
+ RK3066_PLL_RATE( 912000000, 1, 76, 2),
+ RK3066_PLL_RATE( 888000000, 1, 74, 2),
+ RK3066_PLL_RATE( 816000000, 1, 68, 2),
+ RK3066_PLL_RATE( 792000000, 1, 66, 2),
+ RK3066_PLL_RATE( 696000000, 1, 58, 2),
+ RK3066_PLL_RATE( 672000000, 1, 56, 2),
+ RK3066_PLL_RATE( 648000000, 1, 54, 2),
+ RK3066_PLL_RATE( 624000000, 1, 52, 2),
+ RK3066_PLL_RATE( 600000000, 1, 50, 2),
+ RK3066_PLL_RATE( 576000000, 1, 48, 2),
+ RK3066_PLL_RATE( 552000000, 1, 46, 2),
+ RK3066_PLL_RATE( 528000000, 1, 88, 4),
+ RK3066_PLL_RATE( 504000000, 1, 84, 4),
+ RK3066_PLL_RATE( 480000000, 1, 80, 4),
+ RK3066_PLL_RATE( 456000000, 1, 76, 4),
+ RK3066_PLL_RATE( 408000000, 1, 68, 4),
+ RK3066_PLL_RATE( 312000000, 1, 52, 4),
+ RK3066_PLL_RATE( 252000000, 1, 84, 8),
+ RK3066_PLL_RATE( 216000000, 1, 72, 8),
+ RK3066_PLL_RATE( 126000000, 2, 84, 8),
+ RK3066_PLL_RATE( 48000000, 2, 32, 8),
+ { /* sentinel */ },
+};
+
+PNAME(mux_pll_p) = { "xin24m", "xin32k" };
+PNAME(mux_armclkb_p) = { "apllb_core", "gpllb_core" };
+PNAME(mux_armclkl_p) = { "aplll_core", "gplll_core" };
+PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" };
+PNAME(mux_cs_src_p) = { "apllb_cs", "aplll_cs", "gpll_cs"};
+PNAME(mux_aclk_bus_src_p) = { "cpll_aclk_bus", "gpll_aclk_bus" };
+
+PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" };
+PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" };
+PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" };
+PNAME(mux_pll_src_cpll_gpll_usb_p) = { "cpll", "gpll", "usbphy_480m" };
+PNAME(mux_pll_src_cpll_gpll_usb_usb_p) = { "cpll", "gpll", "usbphy_480m",
+ "usbphy_480m" };
+PNAME(mux_pll_src_cpll_gpll_usb_npll_p) = { "cpll", "gpll", "usbphy_480m",
+ "npll" };
+PNAME(mux_pll_src_cpll_gpll_npll_npll_p) = { "cpll", "gpll", "npll", "npll" };
+PNAME(mux_pll_src_cpll_gpll_npll_usb_p) = { "cpll", "gpll", "npll",
+ "usbphy_480m" };
+
+PNAME(mux_i2s_8ch_pre_p) = { "i2s_8ch_src", "i2s_8ch_frac",
+ "ext_i2s", "xin12m" };
+PNAME(mux_i2s_8ch_clkout_p) = { "i2s_8ch_pre", "xin12m" };
+PNAME(mux_i2s_2ch_p) = { "i2s_2ch_src", "i2s_2ch_frac",
+ "dummy", "xin12m" };
+PNAME(mux_spdif_8ch_p) = { "spdif_8ch_pre", "spdif_8ch_frac",
+ "ext_i2s", "xin12m" };
+PNAME(mux_edp_24m_p) = { "dummy", "xin24m" };
+PNAME(mux_vip_out_p) = { "vip_src", "xin24m" };
+PNAME(mux_usbphy480m_p) = { "usbotg_out", "xin24m" };
+PNAME(mux_hsic_usbphy480m_p) = { "usbotg_out", "dummy" };
+PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy_480m" };
+PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" };
+PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" };
+PNAME(mux_uart2_p) = { "uart2_src", "xin24m" };
+PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" };
+PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" };
+PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" };
+PNAME(mux_mmc_src_p) = { "cpll", "gpll", "usbphy_480m", "xin24m" };
+
+static struct rockchip_pll_clock rk3368_pll_clks[] __initdata = {
+ [apllb] = PLL(pll_rk3066, PLL_APLLB, "apllb", mux_pll_p, 0, RK3368_PLL_CON(0),
+ RK3368_PLL_CON(3), 8, 1, 0, rk3368_pll_rates),
+ [aplll] = PLL(pll_rk3066, PLL_APLLL, "aplll", mux_pll_p, 0, RK3368_PLL_CON(4),
+ RK3368_PLL_CON(7), 8, 0, 0, rk3368_pll_rates),
+ [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK3368_PLL_CON(8),
+ RK3368_PLL_CON(11), 8, 2, 0, NULL),
+ [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3368_PLL_CON(12),
+ RK3368_PLL_CON(15), 8, 3, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates),
+ [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3368_PLL_CON(16),
+ RK3368_PLL_CON(19), 8, 4, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates),
+ [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3368_PLL_CON(20),
+ RK3368_PLL_CON(23), 8, 5, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates),
+};
+
+static struct clk_div_table div_ddrphy_t[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 3, .div = 4 },
+ { /* sentinel */ },
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
+
+static const struct rockchip_cpuclk_reg_data rk3368_cpuclkb_data = {
+ .core_reg = RK3368_CLKSEL_CON(0),
+ .div_core_shift = 0,
+ .div_core_mask = 0x1f,
+ .mux_core_shift = 15,
+};
+
+static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = {
+ .core_reg = RK3368_CLKSEL_CON(2),
+ .div_core_shift = 0,
+ .div_core_mask = 0x1f,
+ .mux_core_shift = 7,
+};
+
+#define RK3368_DIV_ACLKM_MASK 0x1f
+#define RK3368_DIV_ACLKM_SHIFT 8
+#define RK3368_DIV_ATCLK_MASK 0x1f
+#define RK3368_DIV_ATCLK_SHIFT 0
+#define RK3368_DIV_PCLK_DBG_MASK 0x1f
+#define RK3368_DIV_PCLK_DBG_SHIFT 8
+
+#define RK3368_CLKSEL0(_offs, _aclkm) \
+ { \
+ .reg = RK3288_CLKSEL_CON(0 + _offs), \
+ .val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK, \
+ RK3368_DIV_ACLKM_SHIFT), \
+ }
+#define RK3368_CLKSEL1(_offs, _atclk, _pdbg) \
+ { \
+ .reg = RK3288_CLKSEL_CON(1 + _offs), \
+ .val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK, \
+ RK3368_DIV_ATCLK_SHIFT) | \
+ HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK, \
+ RK3368_DIV_PCLK_DBG_SHIFT), \
+ }
+
+/* cluster_b: aclkm in clksel0, rest in clksel1 */
+#define RK3368_CPUCLKB_RATE(_prate, _aclkm, _atclk, _pdbg) \
+ { \
+ .prate = _prate, \
+ .divs = { \
+ RK3368_CLKSEL0(0, _aclkm), \
+ RK3368_CLKSEL1(0, _atclk, _pdbg), \
+ }, \
+ }
+
+/* cluster_l: aclkm in clksel2, rest in clksel3 */
+#define RK3368_CPUCLKL_RATE(_prate, _aclkm, _atclk, _pdbg) \
+ { \
+ .prate = _prate, \
+ .divs = { \
+ RK3368_CLKSEL0(2, _aclkm), \
+ RK3368_CLKSEL1(2, _atclk, _pdbg), \
+ }, \
+ }
+
+static struct rockchip_cpuclk_rate_table rk3368_cpuclkb_rates[] __initdata = {
+ RK3368_CPUCLKB_RATE(1512000000, 2, 6, 6),
+ RK3368_CPUCLKB_RATE(1488000000, 2, 5, 5),
+ RK3368_CPUCLKB_RATE(1416000000, 2, 5, 5),
+ RK3368_CPUCLKB_RATE(1200000000, 2, 4, 4),
+ RK3368_CPUCLKB_RATE(1008000000, 2, 4, 4),
+ RK3368_CPUCLKB_RATE( 816000000, 2, 3, 3),
+ RK3368_CPUCLKB_RATE( 696000000, 2, 3, 3),
+ RK3368_CPUCLKB_RATE( 600000000, 2, 2, 2),
+ RK3368_CPUCLKB_RATE( 408000000, 2, 2, 2),
+ RK3368_CPUCLKB_RATE( 312000000, 2, 2, 2),
+};
+
+static struct rockchip_cpuclk_rate_table rk3368_cpuclkl_rates[] __initdata = {
+ RK3368_CPUCLKL_RATE(1512000000, 2, 7, 7),
+ RK3368_CPUCLKL_RATE(1488000000, 2, 6, 6),
+ RK3368_CPUCLKL_RATE(1416000000, 2, 6, 6),
+ RK3368_CPUCLKL_RATE(1200000000, 2, 5, 5),
+ RK3368_CPUCLKL_RATE(1008000000, 2, 5, 5),
+ RK3368_CPUCLKL_RATE( 816000000, 2, 4, 4),
+ RK3368_CPUCLKL_RATE( 696000000, 2, 3, 3),
+ RK3368_CPUCLKL_RATE( 600000000, 2, 3, 3),
+ RK3368_CPUCLKL_RATE( 408000000, 2, 2, 2),
+ RK3368_CPUCLKL_RATE( 312000000, 2, 2, 2),
+};
+
+static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
+ /*
+ * Clock-Architecture Diagram 2
+ */
+
+ MUX(SCLK_USBPHY480M, "usbphy_480m", mux_usbphy480m_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(13), 8, 1, MFLAGS),
+
+ GATE(0, "apllb_core", "apllb", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(0), 0, GFLAGS),
+ GATE(0, "gpllb_core", "gpll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(0), 1, GFLAGS),
+
+ GATE(0, "aplll_core", "aplll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(0), 4, GFLAGS),
+ GATE(0, "gplll_core", "gpll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(0), 5, GFLAGS),
+
+ DIV(0, "aclkm_core_b", "armclkb", 0,
+ RK3368_CLKSEL_CON(0), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY),
+ DIV(0, "atclk_core_b", "armclkb", 0,
+ RK3368_CLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY),
+ DIV(0, "pclk_dbg_b", "armclkb", 0,
+ RK3368_CLKSEL_CON(1), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY),
+
+ DIV(0, "aclkm_core_l", "armclkl", 0,
+ RK3368_CLKSEL_CON(2), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY),
+ DIV(0, "atclk_core_l", "armclkl", 0,
+ RK3368_CLKSEL_CON(3), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY),
+ DIV(0, "pclk_dbg_l", "armclkl", 0,
+ RK3368_CLKSEL_CON(3), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY),
+
+ GATE(0, "apllb_cs", "apllb", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(0), 9, GFLAGS),
+ GATE(0, "aplll_cs", "aplll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(0), 10, GFLAGS),
+ GATE(0, "gpll_cs", "gpll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(0), 8, GFLAGS),
+ COMPOSITE_NOGATE(0, "sclk_cs_pre", mux_cs_src_p, CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS),
+ COMPOSITE_NOMUX(0, "clkin_trace", "sclk_cs_pre", CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(4), 8, 5, DFLAGS,
+ RK3368_CLKGATE_CON(0), 13, GFLAGS),
+
+ COMPOSITE(0, "aclk_cci_pre", mux_pll_src_cpll_gpll_usb_npll_p, CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(0), 12, GFLAGS),
+ GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3368_CLKGATE_CON(7), 10, GFLAGS),
+
+ GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(1), 8, GFLAGS),
+ GATE(0, "gpll_ddr", "gpll", 0,
+ RK3368_CLKGATE_CON(1), 9, GFLAGS),
+ COMPOSITE_NOGATE_DIVTBL(0, "ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(13), 4, 1, MFLAGS, 0, 2, DFLAGS, div_ddrphy_t),
+
+ GATE(0, "sclk_ddr", "ddrphy_div4", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(6), 14, GFLAGS),
+ GATE(0, "sclk_ddr4x", "ddrphy_src", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(6), 15, GFLAGS),
+
+ GATE(0, "gpll_aclk_bus", "gpll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(1), 10, GFLAGS),
+ GATE(0, "cpll_aclk_bus", "cpll", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(1), 11, GFLAGS),
+ COMPOSITE_NOGATE(0, "aclk_bus_src", mux_aclk_bus_src_p, CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(8), 7, 1, MFLAGS, 0, 5, DFLAGS),
+
+ GATE(ACLK_BUS, "aclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(1), 0, GFLAGS),
+ COMPOSITE_NOMUX(PCLK_BUS, "pclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(8), 12, 3, DFLAGS,
+ RK3368_CLKGATE_CON(1), 2, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_BUS, "hclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(8), 8, 2, DFLAGS,
+ RK3368_CLKGATE_CON(1), 1, GFLAGS),
+ COMPOSITE_NOMUX(0, "sclk_crypto", "aclk_bus_src", 0,
+ RK3368_CLKSEL_CON(10), 14, 2, DFLAGS,
+ RK3368_CLKGATE_CON(7), 2, GFLAGS),
+
+ COMPOSITE(0, "fclk_mcu_src", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(12), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(1), 3, GFLAGS),
+ /*
+ * stclk_mcu is listed as child of fclk_mcu_src in diagram 5,
+ * but stclk_mcu has an additional own divider in diagram 2
+ */
+ COMPOSITE_NOMUX(0, "stclk_mcu", "fclk_mcu_src", 0,
+ RK3368_CLKSEL_CON(12), 8, 3, DFLAGS,
+ RK3368_CLKGATE_CON(13), 13, GFLAGS),
+
+ COMPOSITE(0, "i2s_8ch_src", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(27), 12, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(6), 1, GFLAGS),
+ COMPOSITE_FRAC(0, "i2s_8ch_frac", "i2s_8ch_src", CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(28), 0,
+ RK3368_CLKGATE_CON(6), 2, GFLAGS),
+ MUX(0, "i2s_8ch_pre", mux_i2s_8ch_pre_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(27), 8, 2, MFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "i2s_8ch_clkout", mux_i2s_8ch_clkout_p, 0,
+ RK3368_CLKSEL_CON(27), 15, 1, MFLAGS,
+ RK3368_CLKGATE_CON(6), 0, GFLAGS),
+ GATE(SCLK_I2S_8CH, "sclk_i2s_8ch", "i2s_8ch_pre", CLK_SET_RATE_PARENT,
+ RK3368_CLKGATE_CON(6), 3, GFLAGS),
+ COMPOSITE(0, "spdif_8ch_src", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(31), 12, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(6), 4, GFLAGS),
+ COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_src", CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(32), 0,
+ RK3368_CLKGATE_CON(6), 5, GFLAGS),
+ COMPOSITE_NODIV(SCLK_SPDIF_8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0,
+ RK3368_CLKSEL_CON(31), 8, 2, MFLAGS,
+ RK3368_CLKGATE_CON(6), 6, GFLAGS),
+ COMPOSITE(0, "i2s_2ch_src", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(53), 12, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(5), 13, GFLAGS),
+ COMPOSITE_FRAC(0, "i2s_2ch_frac", "i2s_2ch_src", CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(54), 0,
+ RK3368_CLKGATE_CON(5), 14, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S_2CH, "sclk_i2s_2ch", mux_i2s_2ch_p, 0,
+ RK3368_CLKSEL_CON(53), 8, 2, MFLAGS,
+ RK3368_CLKGATE_CON(5), 15, GFLAGS),
+
+ COMPOSITE(0, "sclk_tsp", mux_pll_src_cpll_gpll_npll_p, 0,
+ RK3368_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(6), 12, GFLAGS),
+ GATE(0, "sclk_hsadc_tsp", "ext_hsadc_tsp", 0,
+ RK3368_CLKGATE_CON(13), 7, GFLAGS),
+
+ MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(35), 12, 1, MFLAGS),
+ COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
+ RK3368_CLKSEL_CON(37), 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(2), 4, GFLAGS),
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(37), 8, 1, MFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 3
+ */
+
+ COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_usb_p, 0,
+ RK3368_CLKSEL_CON(15), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(4), 6, GFLAGS),
+ COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb_p, 0,
+ RK3368_CLKSEL_CON(15), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3368_CLKGATE_CON(4), 7, GFLAGS),
+
+ /*
+ * We introduce a virtual node of hclk_vodec_pre_v to split one clock
+ * struct with a gate and a fix divider into two node in software.
+ */
+ GATE(0, "hclk_video_pre_v", "aclk_vdpu", 0,
+ RK3368_CLKGATE_CON(4), 8, GFLAGS),
+
+ COMPOSITE(0, "sclk_hevc_cabac_src", mux_pll_src_cpll_gpll_npll_usb_p, 0,
+ RK3368_CLKSEL_CON(17), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(5), 1, GFLAGS),
+ COMPOSITE(0, "sclk_hevc_core_src", mux_pll_src_cpll_gpll_npll_usb_p, 0,
+ RK3368_CLKSEL_CON(17), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3368_CLKGATE_CON(5), 2, GFLAGS),
+
+ COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb_p, CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(19), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(4), 0, GFLAGS),
+ DIV(0, "hclk_vio", "aclk_vio0", 0,
+ RK3368_CLKSEL_CON(21), 0, 5, DFLAGS),
+
+ COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb_p, 0,
+ RK3368_CLKSEL_CON(18), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3368_CLKGATE_CON(4), 3, GFLAGS),
+ COMPOSITE(SCLK_RGA, "sclk_rga", mux_pll_src_cpll_gpll_usb_p, 0,
+ RK3368_CLKSEL_CON(18), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(4), 4, GFLAGS),
+
+ COMPOSITE(DCLK_VOP, "dclk_vop", mux_pll_src_cpll_gpll_npll_p, 0,
+ RK3368_CLKSEL_CON(20), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3368_CLKGATE_CON(4), 1, GFLAGS),
+
+ GATE(SCLK_VOP0_PWM, "sclk_vop0_pwm", "xin24m", 0,
+ RK3368_CLKGATE_CON(4), 2, GFLAGS),
+
+ COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_cpll_gpll_npll_npll_p, 0,
+ RK3368_CLKSEL_CON(22), 6, 2, MFLAGS, 0, 6, DFLAGS,
+ RK3368_CLKGATE_CON(4), 9, GFLAGS),
+
+ GATE(0, "pclk_isp_in", "ext_isp", 0,
+ RK3368_CLKGATE_CON(17), 2, GFLAGS),
+ INVERTER(PCLK_ISP, "pclk_isp", "pclk_isp_in",
+ RK3368_CLKSEL_CON(21), 6, IFLAGS),
+
+ GATE(0, "pclk_vip_in", "ext_vip", 0,
+ RK3368_CLKGATE_CON(16), 13, GFLAGS),
+ INVERTER(PCLK_VIP, "pclk_vip", "pclk_vip_in",
+ RK3368_CLKSEL_CON(21), 13, IFLAGS),
+
+ GATE(SCLK_HDMI_HDCP, "sclk_hdmi_hdcp", "xin24m", 0,
+ RK3368_CLKGATE_CON(4), 13, GFLAGS),
+ GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0,
+ RK3368_CLKGATE_CON(5), 12, GFLAGS),
+
+ COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(21), 15, 1, MFLAGS,
+ RK3368_CLKGATE_CON(4), 5, GFLAGS),
+ COMPOSITE_NOGATE(0, "sclk_vip_out", mux_vip_out_p, 0,
+ RK3368_CLKSEL_CON(21), 14, 1, MFLAGS, 8, 5, DFLAGS),
+
+ COMPOSITE_NODIV(SCLK_EDP_24M, "sclk_edp_24m", mux_edp_24m_p, 0,
+ RK3368_CLKSEL_CON(23), 8, 1, MFLAGS,
+ RK3368_CLKGATE_CON(5), 4, GFLAGS),
+ COMPOSITE(SCLK_EDP, "sclk_edp", mux_pll_src_cpll_gpll_npll_npll_p, 0,
+ RK3368_CLKSEL_CON(23), 6, 2, MFLAGS, 0, 6, DFLAGS,
+ RK3368_CLKGATE_CON(5), 3, GFLAGS),
+
+ COMPOSITE(SCLK_HDCP, "sclk_hdcp", mux_pll_src_cpll_gpll_npll_npll_p, 0,
+ RK3368_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 6, DFLAGS,
+ RK3368_CLKGATE_CON(5), 5, GFLAGS),
+
+ DIV(0, "pclk_pd_alive", "gpll", 0,
+ RK3368_CLKSEL_CON(10), 8, 5, DFLAGS),
+
+ /* sclk_timer has a gate in the sgrf */
+
+ COMPOSITE_NOMUX(0, "pclk_pd_pmu", "gpll", CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(10), 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(7), 9, GFLAGS),
+ GATE(SCLK_PVTM_PMU, "sclk_pvtm_pmu", "xin24m", 0,
+ RK3368_CLKGATE_CON(7), 3, GFLAGS),
+ COMPOSITE(0, "sclk_gpu_core_src", mux_pll_src_cpll_gpll_usb_npll_p, 0,
+ RK3368_CLKSEL_CON(14), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(4), 11, GFLAGS),
+ MUX(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(14), 14, 1, MFLAGS),
+ COMPOSITE_NOMUX(0, "aclk_gpu_mem_pre", "aclk_gpu_src", 0,
+ RK3368_CLKSEL_CON(14), 8, 5, DFLAGS,
+ RK3368_CLKGATE_CON(5), 8, GFLAGS),
+ COMPOSITE_NOMUX(0, "aclk_gpu_cfg_pre", "aclk_gpu_src", 0,
+ RK3368_CLKSEL_CON(16), 8, 5, DFLAGS,
+ RK3368_CLKGATE_CON(5), 9, GFLAGS),
+ GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0,
+ RK3368_CLKGATE_CON(7), 11, GFLAGS),
+
+ COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(9), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(3), 0, GFLAGS),
+ COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0,
+ RK3368_CLKSEL_CON(9), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
+ RK3368_CLKGATE_CON(3), 3, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED,
+ RK3368_CLKSEL_CON(9), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
+ RK3368_CLKGATE_CON(3), 2, GFLAGS),
+ GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(3), 1, GFLAGS),
+
+ GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3368_CLKGATE_CON(4), 14, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 4
+ */
+
+ COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(45), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(3), 7, GFLAGS),
+ COMPOSITE(SCLK_SPI1, "sclk_spi1", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(45), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3368_CLKGATE_CON(3), 8, GFLAGS),
+ COMPOSITE(SCLK_SPI2, "sclk_spi2", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(46), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3368_CLKGATE_CON(3), 9, GFLAGS),
+
+
+ COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0,
+ RK3368_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(7), 12, GFLAGS),
+ COMPOSITE(SCLK_SDIO0, "sclk_sdio0", mux_mmc_src_p, 0,
+ RK3368_CLKSEL_CON(48), 8, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(7), 13, GFLAGS),
+ COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0,
+ RK3368_CLKSEL_CON(51), 8, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(7), 15, GFLAGS),
+
+ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3368_SDMMC_CON0, 1),
+ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3368_SDMMC_CON1, 0),
+
+ MMC(SCLK_SDIO0_DRV, "sdio0_drv", "sclk_sdio0", RK3368_SDIO0_CON0, 1),
+ MMC(SCLK_SDIO0_SAMPLE, "sdio0_sample", "sclk_sdio0", RK3368_SDIO0_CON1, 0),
+
+ MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3368_EMMC_CON0, 1),
+ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3368_EMMC_CON1, 0),
+
+ GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin24m", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(8), 1, GFLAGS),
+
+ /* pmu_grf_soc_con0[6] allows to select between xin32k and pvtm_pmu */
+ GATE(SCLK_OTG_ADP, "sclk_otg_adp", "xin32k", CLK_IGNORE_UNUSED,
+ RK3368_CLKGATE_CON(8), 4, GFLAGS),
+
+ /* pmu_grf_soc_con0[6] allows to select between xin32k and pvtm_pmu */
+ COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin32k", 0,
+ RK3368_CLKSEL_CON(25), 0, 6, DFLAGS,
+ RK3368_CLKGATE_CON(3), 5, GFLAGS),
+
+ COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0,
+ RK3368_CLKSEL_CON(25), 8, 8, DFLAGS,
+ RK3368_CLKGATE_CON(3), 6, GFLAGS),
+
+ COMPOSITE(SCLK_NANDC0, "sclk_nandc0", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(47), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(7), 8, GFLAGS),
+
+ COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(52), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(6), 7, GFLAGS),
+
+ COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gpll_usb_usb_p, 0,
+ RK3368_CLKSEL_CON(33), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(2), 0, GFLAGS),
+ COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(34), 0,
+ RK3368_CLKGATE_CON(2), 1, GFLAGS),
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(33), 8, 2, MFLAGS),
+
+ COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
+ RK3368_CLKSEL_CON(35), 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(2), 2, GFLAGS),
+ COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(36), 0,
+ RK3368_CLKGATE_CON(2), 3, GFLAGS),
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(35), 8, 2, MFLAGS),
+
+ COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
+ RK3368_CLKSEL_CON(39), 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(2), 6, GFLAGS),
+ COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(40), 0,
+ RK3368_CLKGATE_CON(2), 7, GFLAGS),
+ MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(39), 8, 2, MFLAGS),
+
+ COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
+ RK3368_CLKSEL_CON(41), 0, 7, DFLAGS,
+ RK3368_CLKGATE_CON(2), 8, GFLAGS),
+ COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(42), 0,
+ RK3368_CLKGATE_CON(2), 9, GFLAGS),
+ MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(41), 8, 2, MFLAGS),
+
+ COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
+ RK3368_CLKSEL_CON(43), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3368_CLKGATE_CON(3), 4, GFLAGS),
+ MUX(SCLK_MAC, "mac_clk", mux_mac_p, CLK_SET_RATE_PARENT,
+ RK3368_CLKSEL_CON(43), 8, 1, MFLAGS),
+ GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0,
+ RK3368_CLKGATE_CON(7), 7, GFLAGS),
+ GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0,
+ RK3368_CLKGATE_CON(7), 6, GFLAGS),
+ GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0,
+ RK3368_CLKGATE_CON(7), 4, GFLAGS),
+ GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0,
+ RK3368_CLKGATE_CON(7), 5, GFLAGS),
+
+ GATE(0, "jtag", "ext_jtag", 0,
+ RK3368_CLKGATE_CON(7), 0, GFLAGS),
+
+ COMPOSITE_NODIV(0, "hsic_usbphy_480m", mux_hsic_usbphy480m_p, 0,
+ RK3368_CLKSEL_CON(26), 8, 2, MFLAGS,
+ RK3368_CLKGATE_CON(8), 0, GFLAGS),
+ COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0,
+ RK3368_CLKSEL_CON(26), 12, 2, MFLAGS,
+ RK3368_CLKGATE_CON(8), 7, GFLAGS),
+ GATE(SCLK_HSICPHY12M, "sclk_hsicphy12m", "xin12m", 0,
+ RK3368_CLKGATE_CON(8), 6, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 5
+ */
+
+ /* aclk_cci_pre gates */
+ GATE(0, "aclk_core_niu_cpup", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 4, GFLAGS),
+ GATE(0, "aclk_core_niu_cci", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 3, GFLAGS),
+ GATE(0, "aclk_cci400", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 2, GFLAGS),
+ GATE(0, "aclk_adb400m_pd_core_b", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 1, GFLAGS),
+ GATE(0, "aclk_adb400m_pd_core_l", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 0, GFLAGS),
+
+ /* aclkm_core_* gates */
+ GATE(0, "aclk_adb400s_pd_core_b", "aclkm_core_b", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(10), 0, GFLAGS),
+ GATE(0, "aclk_adb400s_pd_core_l", "aclkm_core_l", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(9), 0, GFLAGS),
+
+ /* armclk* gates */
+ GATE(0, "sclk_dbg_pd_core_b", "armclkb", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(10), 1, GFLAGS),
+ GATE(0, "sclk_dbg_pd_core_l", "armclkl", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(9), 1, GFLAGS),
+
+ /* sclk_cs_pre gates */
+ GATE(0, "sclk_dbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 7, GFLAGS),
+ GATE(0, "pclk_core_niu_sdbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 6, GFLAGS),
+ GATE(0, "hclk_core_niu_dbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 5, GFLAGS),
+
+ /* aclk_bus gates */
+ GATE(0, "aclk_strc_sys", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 12, GFLAGS),
+ GATE(ACLK_DMAC_BUS, "aclk_dmac_bus", "aclk_bus", 0, RK3368_CLKGATE_CON(12), 11, GFLAGS),
+ GATE(0, "sclk_intmem1", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 6, GFLAGS),
+ GATE(0, "sclk_intmem0", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 5, GFLAGS),
+ GATE(0, "aclk_intmem", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 4, GFLAGS),
+ GATE(0, "aclk_gic400", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(13), 9, GFLAGS),
+
+ /* sclk_ddr gates */
+ GATE(0, "nclk_ddrupctl", "sclk_ddr", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(13), 2, GFLAGS),
+
+ /* clk_hsadc_tsp is part of diagram2 */
+
+ /* fclk_mcu_src gates */
+ GATE(0, "hclk_noc_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 14, GFLAGS),
+ GATE(0, "fclk_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 12, GFLAGS),
+ GATE(0, "hclk_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 11, GFLAGS),
+
+ /* hclk_cpu gates */
+ GATE(HCLK_SPDIF, "hclk_spdif", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 10, GFLAGS),
+ GATE(HCLK_ROM, "hclk_rom", "hclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 9, GFLAGS),
+ GATE(HCLK_I2S_2CH, "hclk_i2s_2ch", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 8, GFLAGS),
+ GATE(HCLK_I2S_8CH, "hclk_i2s_8ch", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 7, GFLAGS),
+ GATE(HCLK_TSP, "hclk_tsp", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 10, GFLAGS),
+ GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 4, GFLAGS),
+ GATE(MCLK_CRYPTO, "mclk_crypto", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 3, GFLAGS),
+
+ /* pclk_cpu gates */
+ GATE(PCLK_DDRPHY, "pclk_ddrphy", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 14, GFLAGS),
+ GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 13, GFLAGS),
+ GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 3, GFLAGS),
+ GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 2, GFLAGS),
+ GATE(PCLK_MAILBOX, "pclk_mailbox", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 1, GFLAGS),
+ GATE(PCLK_PWM0, "pclk_pwm0", "pclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 0, GFLAGS),
+ GATE(PCLK_SIM, "pclk_sim", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 8, GFLAGS),
+ GATE(PCLK_PWM1, "pclk_pwm1", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 6, GFLAGS),
+ GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 5, GFLAGS),
+ GATE(0, "pclk_efuse_256", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 1, GFLAGS),
+ GATE(0, "pclk_efuse_1024", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 0, GFLAGS),
+
+ /*
+ * video clk gates
+ * aclk_video(_pre) can actually select between parents of aclk_vdpu
+ * and aclk_vepu by setting bit GRF_SOC_CON0[7].
+ */
+ GATE(ACLK_VIDEO, "aclk_video", "aclk_vdpu", 0, RK3368_CLKGATE_CON(15), 0, GFLAGS),
+ GATE(SCLK_HEVC_CABAC, "sclk_hevc_cabac", "sclk_hevc_cabac_src", 0, RK3368_CLKGATE_CON(15), 3, GFLAGS),
+ GATE(SCLK_HEVC_CORE, "sclk_hevc_core", "sclk_hevc_core_src", 0, RK3368_CLKGATE_CON(15), 2, GFLAGS),
+ GATE(HCLK_VIDEO, "hclk_video", "hclk_video_pre", 0, RK3368_CLKGATE_CON(15), 1, GFLAGS),
+
+ /* aclk_rga_pre gates */
+ GATE(ACLK_VIO1_NOC, "aclk_vio1_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 10, GFLAGS),
+ GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3368_CLKGATE_CON(16), 0, GFLAGS),
+ GATE(ACLK_HDCP, "aclk_hdcp", "aclk_rga_pre", 0, RK3368_CLKGATE_CON(17), 10, GFLAGS),
+
+ /* aclk_vio0 gates */
+ GATE(ACLK_VIP, "aclk_vip", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 11, GFLAGS),
+ GATE(ACLK_VIO0_NOC, "aclk_vio0_noc", "aclk_vio0", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 9, GFLAGS),
+ GATE(ACLK_VOP, "aclk_vop", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 5, GFLAGS),
+ GATE(ACLK_VOP_IEP, "aclk_vop_iep", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 4, GFLAGS),
+ GATE(ACLK_IEP, "aclk_iep", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 2, GFLAGS),
+
+ /* sclk_isp gates */
+ GATE(HCLK_ISP, "hclk_isp", "sclk_isp", 0, RK3368_CLKGATE_CON(16), 14, GFLAGS),
+ GATE(ACLK_ISP, "aclk_isp", "sclk_isp", 0, RK3368_CLKGATE_CON(17), 0, GFLAGS),
+
+ /* hclk_vio gates */
+ GATE(HCLK_VIP, "hclk_vip", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 12, GFLAGS),
+ GATE(HCLK_VIO_NOC, "hclk_vio_noc", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 8, GFLAGS),
+ GATE(HCLK_VIO_AHB_ARBI, "hclk_vio_ahb_arbi", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 7, GFLAGS),
+ GATE(HCLK_VOP, "hclk_vop", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 6, GFLAGS),
+ GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 3, GFLAGS),
+ GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 1, GFLAGS),
+ GATE(HCLK_VIO_HDCPMMU, "hclk_hdcpmmu", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 12, GFLAGS),
+ GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 7, GFLAGS),
+
+ /*
+ * pclk_vio gates
+ * pclk_vio comes from the exactly same source as hclk_vio
+ */
+ GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 11, GFLAGS),
+ GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 9, GFLAGS),
+ GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 8, GFLAGS),
+ GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 6, GFLAGS),
+ GATE(PCLK_MIPI_CSI, "pclk_mipi_csi", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS),
+ GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 3, GFLAGS),
+
+ /* ext_vip gates in diagram3 */
+
+ /* gpu gates */
+ GATE(SCLK_GPU_CORE, "sclk_gpu_core", "sclk_gpu_core_src", 0, RK3368_CLKGATE_CON(18), 2, GFLAGS),
+ GATE(ACLK_GPU_MEM, "aclk_gpu_mem", "aclk_gpu_mem_pre", 0, RK3368_CLKGATE_CON(18), 1, GFLAGS),
+ GATE(ACLK_GPU_CFG, "aclk_gpu_cfg", "aclk_gpu_cfg_pre", 0, RK3368_CLKGATE_CON(18), 0, GFLAGS),
+
+ /* aclk_peri gates */
+ GATE(ACLK_DMAC_PERI, "aclk_dmac_peri", "aclk_peri", 0, RK3368_CLKGATE_CON(19), 3, GFLAGS),
+ GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 2, GFLAGS),
+ GATE(HCLK_SFC, "hclk_sfc", "aclk_peri", 0, RK3368_CLKGATE_CON(20), 15, GFLAGS),
+ GATE(ACLK_GMAC, "aclk_gmac", "aclk_peri", 0, RK3368_CLKGATE_CON(20), 13, GFLAGS),
+ GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 8, GFLAGS),
+ GATE(ACLK_PERI_MMU, "aclk_peri_mmu", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(21), 4, GFLAGS),
+
+ /* hclk_peri gates */
+ GATE(0, "hclk_peri_axi_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 0, GFLAGS),
+ GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 11, GFLAGS),
+ GATE(0, "hclk_mmc_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 10, GFLAGS),
+ GATE(0, "hclk_emem_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 9, GFLAGS),
+ GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 7, GFLAGS),
+ GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 6, GFLAGS),
+ GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 5, GFLAGS),
+ GATE(HCLK_HOST1, "hclk_host1", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 4, GFLAGS),
+ GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 3, GFLAGS),
+ GATE(0, "pmu_hclk_otg0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 2, GFLAGS),
+ GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 1, GFLAGS),
+ GATE(HCLK_HSADC, "hclk_hsadc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 3, GFLAGS),
+ GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 2, GFLAGS),
+ GATE(HCLK_SDIO0, "hclk_sdio0", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 1, GFLAGS),
+ GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 0, GFLAGS),
+
+ /* pclk_peri gates */
+ GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 15, GFLAGS),
+ GATE(PCLK_I2C5, "pclk_i2c5", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 14, GFLAGS),
+ GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 13, GFLAGS),
+ GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 12, GFLAGS),
+ GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 11, GFLAGS),
+ GATE(PCLK_UART4, "pclk_uart4", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 10, GFLAGS),
+ GATE(PCLK_UART3, "pclk_uart3", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 9, GFLAGS),
+ GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 8, GFLAGS),
+ GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 7, GFLAGS),
+ GATE(PCLK_SPI2, "pclk_spi2", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 6, GFLAGS),
+ GATE(PCLK_SPI1, "pclk_spi1", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 5, GFLAGS),
+ GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 4, GFLAGS),
+ GATE(0, "pclk_peri_axi_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 1, GFLAGS),
+ GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 14, GFLAGS),
+ GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 0, GFLAGS),
+
+ /* pclk_pd_alive gates */
+ GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 8, GFLAGS),
+ GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 7, GFLAGS),
+ GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 12, GFLAGS),
+ GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 11, GFLAGS),
+ GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 3, GFLAGS),
+ GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 2, GFLAGS),
+ GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 1, GFLAGS),
+
+ /*
+ * pclk_vio gates
+ * pclk_vio comes from the exactly same source as hclk_vio
+ */
+ GATE(0, "pclk_dphyrx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS),
+ GATE(0, "pclk_dphytx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS),
+
+ /* pclk_pd_pmu gates */
+ GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 0, GFLAGS),
+ GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS),
+ GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 3, GFLAGS),
+ GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS),
+ GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 1, GFLAGS),
+ GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS),
+
+ /* timer gates */
+ GATE(0, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS),
+ GATE(0, "sclk_timer14", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 10, GFLAGS),
+ GATE(0, "sclk_timer13", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 9, GFLAGS),
+ GATE(0, "sclk_timer12", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 8, GFLAGS),
+ GATE(0, "sclk_timer11", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 7, GFLAGS),
+ GATE(0, "sclk_timer10", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 6, GFLAGS),
+ GATE(0, "sclk_timer05", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 5, GFLAGS),
+ GATE(0, "sclk_timer04", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 4, GFLAGS),
+ GATE(0, "sclk_timer03", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 3, GFLAGS),
+ GATE(0, "sclk_timer02", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 2, GFLAGS),
+ GATE(0, "sclk_timer01", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 1, GFLAGS),
+ GATE(0, "sclk_timer00", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 0, GFLAGS),
+};
+
+static void __init rk3368_clk_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+ struct clk *clk;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: could not map cru region\n", __func__);
+ return;
+ }
+
+ rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+
+ /* xin12m is created by a cru-internal divider */
+ clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock xin12m: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ /* ddrphy_div4 is created by a cru-internal divider */
+ clk = clk_register_fixed_factor(NULL, "ddrphy_div4", "ddrphy_src", 0, 1, 4);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock xin12m: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "hclk_video_pre",
+ "hclk_video_pre_v", 0, 1, 4);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
+ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock pclk_wdt: %ld\n",
+ __func__, PTR_ERR(clk));
+ else
+ rockchip_clk_add_lookup(clk, PCLK_WDT);
+
+ rockchip_clk_register_plls(rk3368_pll_clks,
+ ARRAY_SIZE(rk3368_pll_clks),
+ RK3368_GRF_SOC_STATUS0);
+ rockchip_clk_register_branches(rk3368_clk_branches,
+ ARRAY_SIZE(rk3368_clk_branches));
+
+ rockchip_clk_register_armclk(ARMCLKB, "armclkb",
+ mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p),
+ &rk3368_cpuclkb_data, rk3368_cpuclkb_rates,
+ ARRAY_SIZE(rk3368_cpuclkb_rates));
+
+ rockchip_clk_register_armclk(ARMCLKL, "armclkl",
+ mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p),
+ &rk3368_cpuclkl_data, rk3368_cpuclkl_rates,
+ ARRAY_SIZE(rk3368_cpuclkl_rates));
+
+ rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0),
+ ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+ rockchip_register_restart_notifier(RK3368_GLB_SRST_FST);
+}
+CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init);
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index 052b94db0ff9..24938815655f 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -277,6 +277,13 @@ void __init rockchip_clk_register_branches(
list->div_shift
);
break;
+ case branch_inverter:
+ clk = rockchip_clk_register_inverter(
+ list->name, list->parent_names,
+ list->num_parents,
+ reg_base + list->muxdiv_offset,
+ list->div_shift, list->div_flags, &clk_lock);
+ break;
}
/* none of the cases above matched */
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 6b092673048a..dc8ecb2673b7 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -24,29 +24,29 @@
#define CLK_ROCKCHIP_CLK_H
#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
+
+struct clk;
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
/* register positions shared by RK2928, RK3066 and RK3188 */
-#define RK2928_PLL_CON(x) (x * 0x4)
+#define RK2928_PLL_CON(x) ((x) * 0x4)
#define RK2928_MODE_CON 0x40
-#define RK2928_CLKSEL_CON(x) (x * 0x4 + 0x44)
-#define RK2928_CLKGATE_CON(x) (x * 0x4 + 0xd0)
+#define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44)
+#define RK2928_CLKGATE_CON(x) ((x) * 0x4 + 0xd0)
#define RK2928_GLB_SRST_FST 0x100
#define RK2928_GLB_SRST_SND 0x104
-#define RK2928_SOFTRST_CON(x) (x * 0x4 + 0x110)
+#define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110)
#define RK2928_MISC_CON 0x134
#define RK3288_PLL_CON(x) RK2928_PLL_CON(x)
#define RK3288_MODE_CON 0x50
-#define RK3288_CLKSEL_CON(x) (x * 0x4 + 0x60)
-#define RK3288_CLKGATE_CON(x) (x * 0x4 + 0x160)
+#define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60)
+#define RK3288_CLKGATE_CON(x) ((x) * 0x4 + 0x160)
#define RK3288_GLB_SRST_FST 0x1b0
#define RK3288_GLB_SRST_SND 0x1b4
-#define RK3288_SOFTRST_CON(x) (x * 0x4 + 0x1b8)
+#define RK3288_SOFTRST_CON(x) ((x) * 0x4 + 0x1b8)
#define RK3288_MISC_CON 0x1e8
#define RK3288_SDMMC_CON0 0x200
#define RK3288_SDMMC_CON1 0x204
@@ -57,6 +57,22 @@
#define RK3288_EMMC_CON0 0x218
#define RK3288_EMMC_CON1 0x21c
+#define RK3368_PLL_CON(x) RK2928_PLL_CON(x)
+#define RK3368_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
+#define RK3368_CLKGATE_CON(x) ((x) * 0x4 + 0x200)
+#define RK3368_GLB_SRST_FST 0x280
+#define RK3368_GLB_SRST_SND 0x284
+#define RK3368_SOFTRST_CON(x) ((x) * 0x4 + 0x300)
+#define RK3368_MISC_CON 0x380
+#define RK3368_SDMMC_CON0 0x400
+#define RK3368_SDMMC_CON1 0x404
+#define RK3368_SDIO0_CON0 0x408
+#define RK3368_SDIO0_CON1 0x40c
+#define RK3368_SDIO1_CON0 0x410
+#define RK3368_SDIO1_CON1 0x414
+#define RK3368_EMMC_CON0 0x418
+#define RK3368_EMMC_CON1 0x41c
+
enum rockchip_pll_type {
pll_rk3066,
};
@@ -67,16 +83,16 @@ enum rockchip_pll_type {
.nr = _nr, \
.nf = _nf, \
.no = _no, \
- .bwadj = (_nf >> 1), \
+ .nb = ((_nf) < 2) ? 1 : (_nf) >> 1, \
}
-#define RK3066_PLL_RATE_BWADJ(_rate, _nr, _nf, _no, _bw) \
+#define RK3066_PLL_RATE_NB(_rate, _nr, _nf, _no, _nb) \
{ \
.rate = _rate##U, \
.nr = _nr, \
.nf = _nf, \
.no = _no, \
- .bwadj = _bw, \
+ .nb = _nb, \
}
struct rockchip_pll_rate_table {
@@ -84,7 +100,7 @@ struct rockchip_pll_rate_table {
unsigned int nr;
unsigned int nf;
unsigned int no;
- unsigned int bwadj;
+ unsigned int nb;
};
/**
@@ -182,6 +198,13 @@ struct clk *rockchip_clk_register_mmc(const char *name,
const char *const *parent_names, u8 num_parents,
void __iomem *reg, int shift);
+#define ROCKCHIP_INVERTER_HIWORD_MASK BIT(0)
+
+struct clk *rockchip_clk_register_inverter(const char *name,
+ const char *const *parent_names, u8 num_parents,
+ void __iomem *reg, int shift, int flags,
+ spinlock_t *lock);
+
#define PNAME(x) static const char *const x[] __initconst
enum rockchip_clk_branch_type {
@@ -191,6 +214,7 @@ enum rockchip_clk_branch_type {
branch_fraction_divider,
branch_gate,
branch_mmc,
+ branch_inverter,
};
struct rockchip_clk_branch {
@@ -308,6 +332,26 @@ struct rockchip_clk_branch {
.gate_offset = -1, \
}
+#define COMPOSITE_NOGATE_DIVTBL(_id, cname, pnames, f, mo, ms, \
+ mw, mf, ds, dw, df, dt) \
+ { \
+ .id = _id, \
+ .branch_type = branch_composite, \
+ .name = cname, \
+ .parent_names = pnames, \
+ .num_parents = ARRAY_SIZE(pnames), \
+ .flags = f, \
+ .muxdiv_offset = mo, \
+ .mux_shift = ms, \
+ .mux_width = mw, \
+ .mux_flags = mf, \
+ .div_shift = ds, \
+ .div_width = dw, \
+ .div_flags = df, \
+ .div_table = dt, \
+ .gate_offset = -1, \
+ }
+
#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\
{ \
.id = _id, \
@@ -394,6 +438,18 @@ struct rockchip_clk_branch {
.div_shift = shift, \
}
+#define INVERTER(_id, cname, pname, io, is, if) \
+ { \
+ .id = _id, \
+ .branch_type = branch_inverter, \
+ .name = cname, \
+ .parent_names = (const char *[]){ pname }, \
+ .num_parents = 1, \
+ .muxdiv_offset = io, \
+ .div_shift = is, \
+ .div_flags = if, \
+ }
+
void rockchip_clk_init(struct device_node *np, void __iomem *base,
unsigned long nr_clks);
struct regmap *rockchip_clk_get_grf(void);
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
index 3a1fe07cfe9e..7c1e1f58e2da 100644
--- a/drivers/clk/samsung/clk-cpu.c
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -33,6 +33,9 @@
*/
#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include "clk-cpu.h"
#define E4210_SRC_CPU 0x0
@@ -97,8 +100,8 @@ static void wait_until_mux_stable(void __iomem *mux_reg, u32 mux_pos,
static long exynos_cpuclk_round_rate(struct clk_hw *hw,
unsigned long drate, unsigned long *prate)
{
- struct clk *parent = __clk_get_parent(hw->clk);
- *prate = __clk_round_rate(parent, drate);
+ struct clk_hw *parent = clk_hw_get_parent(hw);
+ *prate = clk_hw_round_rate(parent, drate);
return *prate;
}
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index 454b02ae486a..4e9584d79089 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -9,8 +9,9 @@
* Common Clock Framework support for Audio Subsystem Clock Controller.
*/
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c
index 03a52228b6d1..7cd02ff37a1f 100644
--- a/drivers/clk/samsung/clk-exynos-clkout.c
+++ b/drivers/clk/samsung/clk-exynos-clkout.c
@@ -9,8 +9,8 @@
* Clock driver for Exynos clock output
*/
+#include <linux/slab.h>
#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index 538de66a759e..fdd41b17a24f 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -8,8 +8,6 @@
* Common Clock Framework support for Exynos3250 SoC.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -19,6 +17,7 @@
#include <dt-bindings/clock/exynos3250.h>
#include "clk.h"
+#include "clk-cpu.h"
#include "clk-pll.h"
#define SRC_LEFTBUS 0x4200
@@ -319,8 +318,10 @@ static struct samsung_mux_clock mux_clks[] __initdata = {
MUX(CLK_MOUT_MPLL_USER_C, "mout_mpll_user_c", mout_mpll_user_p,
SRC_CPU, 24, 1),
MUX(CLK_MOUT_HPM, "mout_hpm", mout_hpm_p, SRC_CPU, 20, 1),
- MUX(CLK_MOUT_CORE, "mout_core", mout_core_p, SRC_CPU, 16, 1),
- MUX(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1),
+ MUX_F(CLK_MOUT_CORE, "mout_core", mout_core_p, SRC_CPU, 16, 1,
+ CLK_SET_RATE_PARENT, 0),
+ MUX_F(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
+ CLK_SET_RATE_PARENT, 0),
};
static struct samsung_div_clock div_clks[] __initdata = {
@@ -772,6 +773,26 @@ static struct samsung_cmu_info cmu_info __initdata = {
.nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_clk_regs),
};
+#define E3250_CPU_DIV0(apll, pclk_dbg, atb, corem) \
+ (((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) | \
+ ((corem) << 4))
+#define E3250_CPU_DIV1(hpm, copy) \
+ (((hpm) << 4) | ((copy) << 0))
+
+static const struct exynos_cpuclk_cfg_data e3250_armclk_d[] __initconst = {
+ { 1000000, E3250_CPU_DIV0(1, 7, 4, 1), E3250_CPU_DIV1(7, 7), },
+ { 900000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 800000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 700000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 600000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 500000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 400000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 300000, E3250_CPU_DIV0(1, 5, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 200000, E3250_CPU_DIV0(1, 3, 3, 1), E3250_CPU_DIV1(7, 7), },
+ { 100000, E3250_CPU_DIV0(1, 1, 1, 1), E3250_CPU_DIV1(7, 7), },
+ { 0 },
+};
+
static void __init exynos3250_cmu_init(struct device_node *np)
{
struct samsung_clk_provider *ctx;
@@ -780,6 +801,11 @@ static void __init exynos3250_cmu_init(struct device_node *np)
if (!ctx)
return;
+ exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
+ mout_core_p[0], mout_core_p[1], 0x14200,
+ e3250_armclk_d, ARRAY_SIZE(e3250_armclk_d),
+ CLK_CPU_HAS_DIV1);
+
exynos3_core_down_clock(ctx->reg_base);
}
CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index cae2c048488d..251f48dcd12d 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -11,8 +11,8 @@
*/
#include <dt-bindings/clock/exynos4.h>
+#include <linux/slab.h>
#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -86,6 +86,7 @@
#define DIV_PERIL4 0xc560
#define DIV_PERIL5 0xc564
#define E4X12_DIV_CAM1 0xc568
+#define E4X12_GATE_BUS_FSYS1 0xc744
#define GATE_SCLK_CAM 0xc820
#define GATE_IP_CAM 0xc920
#define GATE_IP_TV 0xc924
@@ -1097,6 +1098,7 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
0),
GATE(CLK_PPMUIMAGE, "ppmuimage", "aclk200", E4X12_GATE_IP_IMAGE, 9, 0,
0),
+ GATE(CLK_TSADC, "tsadc", "aclk133", E4X12_GATE_BUS_FSYS1, 16, 0, 0),
GATE(CLK_MIPI_HSI, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0),
GATE(CLK_CHIPID, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0),
GATE(CLK_SYSREG, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1,
diff --git a/drivers/clk/samsung/clk-exynos4415.c b/drivers/clk/samsung/clk-exynos4415.c
index 6c78b09c829f..92c39f6efec8 100644
--- a/drivers/clk/samsung/clk-exynos4415.c
+++ b/drivers/clk/samsung/clk-exynos4415.c
@@ -9,8 +9,6 @@
* Common Clock Framework support for Exynos4415 SoC.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index 70ec3d2608a1..55b83c7ef878 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -11,14 +11,13 @@
*/
#include <dt-bindings/clock/exynos5250.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
#include "clk.h"
+#include "clk-cpu.h"
#define APLL_LOCK 0x0
#define APLL_CON0 0x100
@@ -748,6 +747,32 @@ static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = {
VPLL_LOCK, VPLL_CON0, NULL),
};
+#define E5250_CPU_DIV0(apll, pclk_dbg, atb, periph, acp, cpud) \
+ ((((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) | \
+ ((periph) << 12) | ((acp) << 8) | ((cpud) << 4)))
+#define E5250_CPU_DIV1(hpm, copy) \
+ (((hpm) << 4) | (copy))
+
+static const struct exynos_cpuclk_cfg_data exynos5250_armclk_d[] __initconst = {
+ { 1700000, E5250_CPU_DIV0(5, 3, 7, 7, 7, 3), E5250_CPU_DIV1(2, 0), },
+ { 1600000, E5250_CPU_DIV0(4, 1, 7, 7, 7, 3), E5250_CPU_DIV1(2, 0), },
+ { 1500000, E5250_CPU_DIV0(4, 1, 7, 7, 7, 2), E5250_CPU_DIV1(2, 0), },
+ { 1400000, E5250_CPU_DIV0(4, 1, 6, 7, 7, 2), E5250_CPU_DIV1(2, 0), },
+ { 1300000, E5250_CPU_DIV0(3, 1, 6, 7, 7, 2), E5250_CPU_DIV1(2, 0), },
+ { 1200000, E5250_CPU_DIV0(3, 1, 5, 7, 7, 2), E5250_CPU_DIV1(2, 0), },
+ { 1100000, E5250_CPU_DIV0(3, 1, 5, 7, 7, 3), E5250_CPU_DIV1(2, 0), },
+ { 1000000, E5250_CPU_DIV0(2, 1, 4, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 900000, E5250_CPU_DIV0(2, 1, 4, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 800000, E5250_CPU_DIV0(2, 1, 4, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 700000, E5250_CPU_DIV0(1, 1, 3, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 600000, E5250_CPU_DIV0(1, 1, 3, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 500000, E5250_CPU_DIV0(1, 1, 2, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 400000, E5250_CPU_DIV0(1, 1, 2, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 300000, E5250_CPU_DIV0(1, 1, 1, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 200000, E5250_CPU_DIV0(1, 1, 1, 7, 7, 1), E5250_CPU_DIV1(2, 0), },
+ { 0 },
+};
+
static const struct of_device_id ext_clk_match[] __initconst = {
{ .compatible = "samsung,clock-xxti", .data = (void *)0, },
{ },
@@ -797,6 +822,10 @@ static void __init exynos5250_clk_init(struct device_node *np)
ARRAY_SIZE(exynos5250_div_clks));
samsung_clk_register_gate(ctx, exynos5250_gate_clks,
ARRAY_SIZE(exynos5250_gate_clks));
+ exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
+ mout_cpu_p[0], mout_cpu_p[1], 0x200,
+ exynos5250_armclk_d, ARRAY_SIZE(exynos5250_armclk_d),
+ CLK_CPU_HAS_DIV1);
/*
* Enable arm clock down (in idle) and set arm divider
diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c
index 06f96eb7cf93..d1a29f6c1084 100644
--- a/drivers/clk/samsung/clk-exynos5260.c
+++ b/drivers/clk/samsung/clk-exynos5260.c
@@ -9,8 +9,6 @@
* Common Clock Framework support for Exynos5260 SoC.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c
index 231475bc2b99..d5d5dcabc4a9 100644
--- a/drivers/clk/samsung/clk-exynos5410.c
+++ b/drivers/clk/samsung/clk-exynos5410.c
@@ -11,8 +11,6 @@
#include <dt-bindings/clock/exynos5410.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index a1d731ca8f48..389af3c15ec4 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -11,8 +11,7 @@
*/
#include <dt-bindings/clock/exynos5420.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index 39c95649d3d0..cee062c588de 100644
--- a/drivers/clk/samsung/clk-exynos5433.c
+++ b/drivers/clk/samsung/clk-exynos5433.c
@@ -9,8 +9,6 @@
* Common Clock Framework support for Exynos5443 SoC.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c
index 979e81389cdd..590813871ffe 100644
--- a/drivers/clk/samsung/clk-exynos5440.c
+++ b/drivers/clk/samsung/clk-exynos5440.c
@@ -10,8 +10,6 @@
*/
#include <dt-bindings/clock/exynos5440.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c
index 03d36e847b78..8524e667097e 100644
--- a/drivers/clk/samsung/clk-exynos7.c
+++ b/drivers/clk/samsung/clk-exynos7.c
@@ -8,8 +8,6 @@
*
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index bebc61b5fce1..b7dd396100d8 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -12,6 +12,8 @@
#include <linux/errno.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/clkdev.h>
#include "clk.h"
#include "clk-pll.h"
@@ -180,7 +182,7 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
@@ -288,7 +290,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
@@ -403,7 +405,7 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
@@ -455,7 +457,7 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
pr_err("%s: could not lock PLL %s\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return -EFAULT;
}
@@ -554,7 +556,7 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
@@ -614,7 +616,7 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
pr_err("%s: could not lock PLL %s\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return -EFAULT;
}
@@ -772,7 +774,7 @@ static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
@@ -1013,7 +1015,7 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
@@ -1111,7 +1113,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
- drate, __clk_get_name(hw->clk));
+ drate, clk_hw_get_name(hw));
return -EINVAL;
}
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c
index e56df5064889..e9eb935d7616 100644
--- a/drivers/clk/samsung/clk-s3c2410-dclk.c
+++ b/drivers/clk/samsung/clk-s3c2410-dclk.c
@@ -8,6 +8,10 @@
* Common Clock Framework support for s3c24xx external clock output.
*/
+#include <linux/clkdev.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include "clk.h"
@@ -57,7 +61,7 @@ struct s3c24xx_clkout {
static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw)
{
struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
- int num_parents = __clk_get_num_parents(hw->clk);
+ int num_parents = clk_hw_get_num_parents(hw);
u32 val;
val = readl_relaxed(S3C24XX_MISCCR) >> clkout->shift;
diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c
index 5d2f03461bc5..0945a8852299 100644
--- a/drivers/clk/samsung/clk-s3c2410.c
+++ b/drivers/clk/samsung/clk-s3c2410.c
@@ -8,8 +8,6 @@
* Common Clock Framework support for S3C2410 and following SoCs.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c
index 2ceedaf8ce18..44d6a9f4f5b2 100644
--- a/drivers/clk/samsung/clk-s3c2412.c
+++ b/drivers/clk/samsung/clk-s3c2412.c
@@ -8,8 +8,6 @@
* Common Clock Framework support for S3C2412 and S3C2413.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
index 0c3c182b902a..2c0a1ea3c80c 100644
--- a/drivers/clk/samsung/clk-s3c2443.c
+++ b/drivers/clk/samsung/clk-s3c2443.c
@@ -8,8 +8,6 @@
* Common Clock Framework support for S3C2443 and following SoCs.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 0f590e5550cb..d325ed1e196b 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -8,8 +8,7 @@
* Common Clock Framework support for all S3C64xx SoCs.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c
index de4455b75e8a..eefb84b22566 100644
--- a/drivers/clk/samsung/clk-s5pv210-audss.c
+++ b/drivers/clk/samsung/clk-s5pv210-audss.c
@@ -13,8 +13,8 @@
* Driver for Audio Subsystem Clock Controller of S5PV210-compatible SoCs.
*/
-#include <linux/clkdev.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c
index cf7e8fa7b624..759aaf342bea 100644
--- a/drivers/clk/samsung/clk-s5pv210.c
+++ b/drivers/clk/samsung/clk-s5pv210.c
@@ -11,8 +11,6 @@
* Common Clock Framework support for all S5PC110/S5PV210 SoCs.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -828,6 +826,8 @@ static void __init __s5pv210_clk_init(struct device_node *np,
s5pv210_clk_sleep_init();
+ samsung_clk_of_add_provider(np, ctx);
+
pr_info("%s clocks: mout_apll = %ld, mout_mpll = %ld\n"
"\tmout_epll = %ld, mout_vpll = %ld\n",
is_s5p6442 ? "S5P6442" : "S5PV210",
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 0117238391d6..f38a6c49f744 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -11,6 +11,10 @@
* clock framework for Samsung platforms.
*/
+#include <linux/slab.h>
+#include <linux/clkdev.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index b775fc29caa5..aa872d2c5105 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -13,10 +13,11 @@
#ifndef __SAMSUNG_CLK_H
#define __SAMSUNG_CLK_H
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include "clk-pll.h"
+struct clk;
+
/**
* struct samsung_clk_provider: information about clock provider
* @reg_base: virtual address for the register base.
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index 036a692c7219..b4c8d6746f68 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -11,12 +11,12 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/slab.h>
#define CPG_DIV6_CKSTP BIT(8)
#define CPG_DIV6_DIV(d) ((d) & 0x3f)
@@ -133,13 +133,13 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw)
hw_index = (clk_readl(clock->reg) >> clock->src_shift) &
(BIT(clock->src_width) - 1);
- for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
if (clock->parents[i] == hw_index)
return i;
}
pr_err("%s: %s DIV6 clock set to invalid parent %u\n",
- __func__, __clk_get_name(hw->clk), hw_index);
+ __func__, clk_hw_get_name(hw), hw_index);
return 0;
}
@@ -149,7 +149,7 @@ static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index)
u8 hw_index;
u32 mask;
- if (index >= __clk_get_num_parents(hw->clk))
+ if (index >= clk_hw_get_num_parents(hw))
return -EINVAL;
mask = ~((BIT(clock->src_width) - 1) << clock->src_shift);
diff --git a/drivers/clk/shmobile/clk-mstp.c b/drivers/clk/shmobile/clk-mstp.c
index 2d2fe773ac81..b1df7b2f1e97 100644
--- a/drivers/clk/shmobile/clk-mstp.c
+++ b/drivers/clk/shmobile/clk-mstp.c
@@ -2,6 +2,7 @@
* R-Car MSTP clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Glider bvba
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
@@ -10,11 +11,16 @@
* the Free Software Foundation; version 2 of the License.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
#include <linux/spinlock.h>
/*
@@ -236,3 +242,84 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
of_clk_add_provider(np, of_clk_src_onecell_get, &group->data);
}
CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init);
+
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
+int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args clkspec;
+ struct clk *clk;
+ int i = 0;
+ int error;
+
+ while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+ &clkspec)) {
+ if (of_device_is_compatible(clkspec.np,
+ "renesas,cpg-mstp-clocks"))
+ goto found;
+
+ of_node_put(clkspec.np);
+ i++;
+ }
+
+ return 0;
+
+found:
+ clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ error = pm_clk_create(dev);
+ if (error) {
+ dev_err(dev, "pm_clk_create failed %d\n", error);
+ goto fail_put;
+ }
+
+ error = pm_clk_add_clk(dev, clk);
+ if (error) {
+ dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+ goto fail_destroy;
+ }
+
+ return 0;
+
+fail_destroy:
+ pm_clk_destroy(dev);
+fail_put:
+ clk_put(clk);
+ return error;
+}
+
+void cpg_mstp_detach_dev(struct generic_pm_domain *domain, struct device *dev)
+{
+ if (!list_empty(&dev->power.subsys_data->clock_list))
+ pm_clk_destroy(dev);
+}
+
+void __init cpg_mstp_add_clk_domain(struct device_node *np)
+{
+ struct generic_pm_domain *pd;
+ u32 ncells;
+
+ if (of_property_read_u32(np, "#power-domain-cells", &ncells)) {
+ pr_warn("%s lacks #power-domain-cells\n", np->full_name);
+ return;
+ }
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return;
+
+ pd->name = np->name;
+
+ pd->flags = GENPD_FLAG_PM_CLK;
+ pm_genpd_init(pd, &simple_qos_governor, false);
+ pd->attach_dev = cpg_mstp_attach_dev;
+ pd->detach_dev = cpg_mstp_detach_dev;
+
+ of_genpd_add_provider_simple(np, pd);
+}
+#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
diff --git a/drivers/clk/shmobile/clk-r8a73a4.c b/drivers/clk/shmobile/clk-r8a73a4.c
index 29b9a0b0012a..9326204bed9d 100644
--- a/drivers/clk/shmobile/clk-r8a73a4.c
+++ b/drivers/clk/shmobile/clk-r8a73a4.c
@@ -9,10 +9,10 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
diff --git a/drivers/clk/shmobile/clk-r8a7740.c b/drivers/clk/shmobile/clk-r8a7740.c
index 1e2eaae21e01..1e6b1da58065 100644
--- a/drivers/clk/shmobile/clk-r8a7740.c
+++ b/drivers/clk/shmobile/clk-r8a7740.c
@@ -9,10 +9,10 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
diff --git a/drivers/clk/shmobile/clk-r8a7778.c b/drivers/clk/shmobile/clk-r8a7778.c
index cb33b57274bf..87c1d2f2fb57 100644
--- a/drivers/clk/shmobile/clk-r8a7778.c
+++ b/drivers/clk/shmobile/clk-r8a7778.c
@@ -9,9 +9,9 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/of_address.h>
+#include <linux/slab.h>
struct r8a7778_cpg {
struct clk_onecell_data data;
@@ -124,6 +124,8 @@ static void __init r8a7778_cpg_clocks_init(struct device_node *np)
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+
+ cpg_mstp_add_clk_domain(np);
}
CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks",
diff --git a/drivers/clk/shmobile/clk-r8a7779.c b/drivers/clk/shmobile/clk-r8a7779.c
index 652ecacb6daf..92275c5f2c60 100644
--- a/drivers/clk/shmobile/clk-r8a7779.c
+++ b/drivers/clk/shmobile/clk-r8a7779.c
@@ -11,12 +11,12 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <dt-bindings/clock/r8a7779-clock.h>
@@ -168,6 +168,8 @@ static void __init r8a7779_cpg_clocks_init(struct device_node *np)
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+
+ cpg_mstp_add_clk_domain(np);
}
CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
r8a7779_cpg_clocks_init);
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index acfb6d7dbd6b..745496f7ee9c 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -11,13 +11,13 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
struct rcar_gen2_cpg {
@@ -415,6 +415,8 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np)
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+
+ cpg_mstp_add_clk_domain(np);
}
CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks",
rcar_gen2_cpg_clocks_init);
diff --git a/drivers/clk/shmobile/clk-rz.c b/drivers/clk/shmobile/clk-rz.c
index 7e68e8630962..9766e3cb595f 100644
--- a/drivers/clk/shmobile/clk-rz.c
+++ b/drivers/clk/shmobile/clk-rz.c
@@ -10,6 +10,7 @@
*/
#include <linux/clk-provider.h>
+#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
@@ -99,5 +100,7 @@ static void __init rz_cpg_clocks_init(struct device_node *np)
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+
+ cpg_mstp_add_clk_domain(np);
}
CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init);
diff --git a/drivers/clk/shmobile/clk-sh73a0.c b/drivers/clk/shmobile/clk-sh73a0.c
index cd529cfe412f..8966f8bbfd72 100644
--- a/drivers/clk/shmobile/clk-sh73a0.c
+++ b/drivers/clk/shmobile/clk-sh73a0.c
@@ -9,12 +9,12 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
struct sh73a0_cpg {
diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c
index d63b76ca60c3..c5eaa9d16247 100644
--- a/drivers/clk/sirf/clk-atlas6.c
+++ b/drivers/clk/sirf/clk-atlas6.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/sirf/clk-atlas7.c b/drivers/clk/sirf/clk-atlas7.c
index db8ab691dbf6..a98e21fe773a 100644
--- a/drivers/clk/sirf/clk-atlas7.c
+++ b/drivers/clk/sirf/clk-atlas7.c
@@ -358,6 +358,7 @@ static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
if (regctrl0 & SIRFSOC_ABPLL_CTRL0_SSEN) {
rate = fin;
rate *= 1 << 24;
+ do_div(rate, nr);
do_div(rate, (256 * ((ssdiv >> ssdepth) << ssdepth)
+ (ssmod << ssdepth)));
} else {
@@ -465,6 +466,9 @@ static struct clk_pll clk_sys3pll = {
* double resolution mode:fout = fin * finc / 2^29
* normal mode:fout = fin * finc / 2^28
*/
+#define DTO_RESL_DOUBLE (1ULL << 29)
+#define DTO_RESL_NORMAL (1ULL << 28)
+
static int dto_clk_is_enabled(struct clk_hw *hw)
{
struct clk_dto *clk = to_dtoclk(hw);
@@ -509,9 +513,9 @@ static unsigned long dto_clk_recalc_rate(struct clk_hw *hw,
rate *= finc;
if (droff & BIT(0))
/* Double resolution off */
- do_div(rate, 1 << 28);
+ do_div(rate, DTO_RESL_NORMAL);
else
- do_div(rate, 1 << 29);
+ do_div(rate, DTO_RESL_DOUBLE);
return rate;
}
@@ -519,11 +523,11 @@ static unsigned long dto_clk_recalc_rate(struct clk_hw *hw,
static long dto_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
- u64 dividend = rate * (1 << 29);
+ u64 dividend = rate * DTO_RESL_DOUBLE;
do_div(dividend, *parent_rate);
dividend *= *parent_rate;
- do_div(dividend, 1 << 29);
+ do_div(dividend, DTO_RESL_DOUBLE);
return dividend;
}
@@ -531,7 +535,7 @@ static long dto_clk_round_rate(struct clk_hw *hw, unsigned long rate,
static int dto_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
- u64 dividend = rate * (1 << 29);
+ u64 dividend = rate * DTO_RESL_DOUBLE;
struct clk_dto *clk = to_dtoclk(hw);
do_div(dividend, parent_rate);
@@ -1161,7 +1165,7 @@ static struct atlas7_unit_init_data unit_list[] __initdata = {
{ 122, "spram1_cpudiv2", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 0, &leaf6_gate_lock },
{ 123, "spram2_cpudiv2", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 1, &leaf6_gate_lock },
{ 124, "coresight_cpudiv2", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 2, &leaf6_gate_lock },
- { 125, "thcpum_cpudiv4", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 3, &leaf6_gate_lock },
+ { 125, "coresight_tpiu", "cpum_tpiu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 3, &leaf6_gate_lock },
{ 126, "graphic_gpu", "gpum_gpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN7_SET, 0, &leaf7_gate_lock },
{ 127, "vss_sdr", "gpum_sdr", 0, SIRFSOC_CLKC_LEAF_CLK_EN7_SET, 1, &leaf7_gate_lock },
{ 128, "thgpum_nocr", "gpum_nocr", 0, SIRFSOC_CLKC_LEAF_CLK_EN7_SET, 2, &leaf7_gate_lock },
@@ -1174,9 +1178,13 @@ static struct atlas7_unit_init_data unit_list[] __initdata = {
{ 135, "thbtm_io", "btm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 7, &leaf8_gate_lock },
{ 136, "btslow", "xinw_fixdiv_btslow", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 25, &root1_gate_lock },
{ 137, "a7ca_btslow", "btslow", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 0, &leaf8_gate_lock },
+ { 138, "pwm_io", "io_mux", 0, SIRFSOC_CLKC_LEAF_CLK_EN0_SET, 0, &leaf0_gate_lock },
+ { 139, "pwm_xin", "xin", 0, SIRFSOC_CLKC_LEAF_CLK_EN0_SET, 1, &leaf0_gate_lock },
+ { 140, "pwm_xinw", "xinw", 0, SIRFSOC_CLKC_LEAF_CLK_EN0_SET, 2, &leaf0_gate_lock },
+ { 141, "thcgum_sys", "sys_mux", 0, SIRFSOC_CLKC_LEAF_CLK_EN0_SET, 3, &leaf0_gate_lock },
};
-static struct clk *atlas7_clks[ARRAY_SIZE(unit_list)];
+static struct clk *atlas7_clks[ARRAY_SIZE(unit_list) + ARRAY_SIZE(mux_list)];
static int unit_clk_is_enabled(struct clk_hw *hw)
{
@@ -1609,6 +1617,7 @@ static void __init atlas7_clk_init(struct device_node *np)
sirfsoc_clk_vbase + mux->mux_offset,
mux->shift, mux->width,
mux->mux_flags, NULL);
+ atlas7_clks[ARRAY_SIZE(unit_list) + i] = clk;
BUG_ON(!clk);
}
@@ -1620,7 +1629,7 @@ static void __init atlas7_clk_init(struct device_node *np)
}
clk_data.clks = atlas7_clks;
- clk_data.clk_num = ARRAY_SIZE(unit_list);
+ clk_data.clk_num = ARRAY_SIZE(unit_list) + ARRAY_SIZE(mux_list);
ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
BUG_ON(ret);
diff --git a/drivers/clk/sirf/clk-common.c b/drivers/clk/sirf/clk-common.c
index 9fc285d784d3..77e1e2491689 100644
--- a/drivers/clk/sirf/clk-common.c
+++ b/drivers/clk/sirf/clk-common.c
@@ -7,6 +7,8 @@
* Licensed under GPLv2 or later.
*/
+#include <linux/clk.h>
+
#define KHZ 1000
#define MHZ (KHZ * KHZ)
@@ -165,10 +167,10 @@ static long cpu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
* SiRF SoC has not cpu clock control,
* So bypass to it's parent pll.
*/
- struct clk *parent_clk = clk_get_parent(hw->clk);
- struct clk *pll_parent_clk = clk_get_parent(parent_clk);
- unsigned long pll_parent_rate = clk_get_rate(pll_parent_clk);
- return pll_clk_round_rate(__clk_get_hw(parent_clk), rate, &pll_parent_rate);
+ struct clk_hw *parent_clk = clk_hw_get_parent(hw);
+ struct clk_hw *pll_parent_clk = clk_hw_get_parent(parent_clk);
+ unsigned long pll_parent_rate = clk_hw_get_rate(pll_parent_clk);
+ return pll_clk_round_rate(parent_clk, rate, &pll_parent_rate);
}
static unsigned long cpu_clk_recalc_rate(struct clk_hw *hw,
@@ -178,8 +180,8 @@ static unsigned long cpu_clk_recalc_rate(struct clk_hw *hw,
* SiRF SoC has not cpu clock control,
* So return the parent pll rate.
*/
- struct clk *parent_clk = clk_get_parent(hw->clk);
- return __clk_get_rate(parent_clk);
+ struct clk_hw *parent_clk = clk_hw_get_parent(hw);
+ return clk_hw_get_rate(parent_clk);
}
static struct clk_ops std_pll_ops = {
diff --git a/drivers/clk/sirf/clk-prima2.c b/drivers/clk/sirf/clk-prima2.c
index 6968e2ebcd8a..f92c40264342 100644
--- a/drivers/clk/sirf/clk-prima2.c
+++ b/drivers/clk/sirf/clk-prima2.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/socfpga/clk-gate-a10.c b/drivers/clk/socfpga/clk-gate-a10.c
index 83c6780ff4b2..1cebf253e8fd 100644
--- a/drivers/clk/socfpga/clk-gate-a10.c
+++ b/drivers/clk/socfpga/clk-gate-a10.c
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
@@ -38,7 +39,7 @@ static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk,
div = socfpgaclk->fixed_div;
else if (socfpgaclk->div_reg) {
val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
- val &= div_mask(socfpgaclk->width);
+ val &= GENMASK(socfpgaclk->width - 1, 0);
div = (1 << val);
}
diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c
index 82449cd76fd7..aa7a6e6a15b6 100644
--- a/drivers/clk/socfpga/clk-gate.c
+++ b/drivers/clk/socfpga/clk-gate.c
@@ -15,8 +15,7 @@
* Based from clk-highbank.c
*
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
@@ -106,7 +105,7 @@ static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
div = socfpgaclk->fixed_div;
else if (socfpgaclk->div_reg) {
val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
- val &= div_mask(socfpgaclk->width);
+ val &= GENMASK(socfpgaclk->width - 1, 0);
/* Check for GPIO_DB_CLK by its offset */
if ((int) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET)
div = val + 1;
diff --git a/drivers/clk/socfpga/clk-periph-a10.c b/drivers/clk/socfpga/clk-periph-a10.c
index 9d0181b5a6a4..1f397cb72e89 100644
--- a/drivers/clk/socfpga/clk-periph-a10.c
+++ b/drivers/clk/socfpga/clk-periph-a10.c
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -37,7 +38,7 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
div = socfpgaclk->fixed_div;
} else if (socfpgaclk->div_reg) {
div = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
- div &= div_mask(socfpgaclk->width);
+ div &= GENMASK(socfpgaclk->width - 1, 0);
div += 1;
} else {
div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);
diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c
index 83aeaa219d14..52c883ea7706 100644
--- a/drivers/clk/socfpga/clk-periph.c
+++ b/drivers/clk/socfpga/clk-periph.c
@@ -15,8 +15,7 @@
* Based from clk-highbank.c
*
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -36,7 +35,7 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
} else {
if (socfpgaclk->div_reg) {
val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
- val &= div_mask(socfpgaclk->width);
+ val &= GENMASK(socfpgaclk->width - 1, 0);
parent_rate /= (val + 1);
}
div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
@@ -45,8 +44,17 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
return parent_rate / div;
}
+static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
+{
+ u32 clk_src;
+
+ clk_src = readl(clk_mgr_base_addr + CLKMGR_DBCTRL);
+ return clk_src & 0x1;
+}
+
static const struct clk_ops periclk_ops = {
.recalc_rate = clk_periclk_recalc_rate,
+ .get_parent = clk_periclk_get_parent,
};
static __init void __socfpga_periph_init(struct device_node *node,
@@ -56,7 +64,7 @@ static __init void __socfpga_periph_init(struct device_node *node,
struct clk *clk;
struct socfpga_periph_clk *periph_clk;
const char *clk_name = node->name;
- const char *parent_name;
+ const char *parent_name[SOCFPGA_MAX_PARENTS];
struct clk_init_data init;
int rc;
u32 fixed_div;
@@ -90,9 +98,10 @@ static __init void __socfpga_periph_init(struct device_node *node,
init.name = clk_name;
init.ops = ops;
init.flags = 0;
- parent_name = of_clk_get_parent_name(node, 0);
- init.parent_names = &parent_name;
- init.num_parents = 1;
+
+ init.num_parents = of_clk_parent_fill(node, parent_name,
+ SOCFPGA_MAX_PARENTS);
+ init.parent_names = parent_name;
periph_clk->hw.hw.init = &init;
diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c
index 1178b11babca..402d630bd531 100644
--- a/drivers/clk/socfpga/clk-pll-a10.c
+++ b/drivers/clk/socfpga/clk-pll-a10.c
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c
index 8f26b5234947..c7f463172e4b 100644
--- a/drivers/clk/socfpga/clk-pll.c
+++ b/drivers/clk/socfpga/clk-pll.c
@@ -15,8 +15,7 @@
* Based from clk-highbank.c
*
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h
index 603973ab7e29..814c7247bf73 100644
--- a/drivers/clk/socfpga/clk.h
+++ b/drivers/clk/socfpga/clk.h
@@ -18,16 +18,15 @@
#define __SOCFPGA_CLK_H
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
/* Clock Manager offsets */
#define CLKMGR_CTRL 0x0
#define CLKMGR_BYPASS 0x4
+#define CLKMGR_DBCTRL 0x10
#define CLKMGR_L4SRC 0x70
#define CLKMGR_PERPLL_SRC 0xAC
#define SOCFPGA_MAX_PARENTS 5
-#define div_mask(width) ((1 << (width)) - 1)
#define streq(a, b) (strcmp((a), (b)) == 0)
#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c
index bdfb4421c643..f271c350ef94 100644
--- a/drivers/clk/spear/clk-aux-synth.c
+++ b/drivers/clk/spear/clk-aux-synth.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c
index dffd4ce6c8b5..58d678b5b40a 100644
--- a/drivers/clk/spear/clk-frac-synth.c
+++ b/drivers/clk/spear/clk-frac-synth.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c
index 1afc18c4effc..1a722e99e76e 100644
--- a/drivers/clk/spear/clk-gpt-synth.c
+++ b/drivers/clk/spear/clk-gpt-synth.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c
index 1b9b65bca51e..dc21ca4601aa 100644
--- a/drivers/clk/spear/clk-vco-pll.c
+++ b/drivers/clk/spear/clk-vco-pll.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -87,7 +87,7 @@ static long clk_pll_round_rate_index(struct clk_hw *hw, unsigned long drate,
struct clk_pll *pll = to_clk_pll(hw);
unsigned long prev_rate, vco_prev_rate, rate = 0;
unsigned long vco_parent_rate =
- __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk)));
+ clk_hw_get_rate(clk_hw_get_parent(clk_hw_get_parent(hw)));
if (!prate) {
pr_err("%s: prate is must for pll clk\n", __func__);
diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c
index 628b6d5ed3d9..157fe099ea6a 100644
--- a/drivers/clk/spear/clk.c
+++ b/drivers/clk/spear/clk.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/clk/spear/clk.h b/drivers/clk/spear/clk.h
index 931737677dfa..9834944f08b1 100644
--- a/drivers/clk/spear/clk.h
+++ b/drivers/clk/spear/clk.h
@@ -2,7 +2,7 @@
* Clock framework definitions for SPEAr platform
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c
index 4daa5977793a..009bd1410cfa 100644
--- a/drivers/clk/spear/spear1310_clock.c
+++ b/drivers/clk/spear/spear1310_clock.c
@@ -4,14 +4,13 @@
* SPEAr1310 machine clock framework source file
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c
index 5a5c6648308d..9c7abfd951ba 100644
--- a/drivers/clk/spear/spear1340_clock.c
+++ b/drivers/clk/spear/spear1340_clock.c
@@ -4,14 +4,13 @@
* SPEAr1340 machine clock framework source file
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c
index bb5f387774e2..404a55edd613 100644
--- a/drivers/clk/spear/spear3xx_clock.c
+++ b/drivers/clk/spear/spear3xx_clock.c
@@ -2,7 +2,7 @@
* SPEAr3xx machines clock framework source file
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c
index 4f649c9cb094..e24f85cd4300 100644
--- a/drivers/clk/spear/spear6xx_clock.c
+++ b/drivers/clk/spear/spear6xx_clock.c
@@ -2,14 +2,13 @@
* SPEAr6xx machines clock framework source file
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/spinlock_types.h>
diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c
index 8dd8cce27361..bd355ee33766 100644
--- a/drivers/clk/st/clk-flexgen.c
+++ b/drivers/clk/st/clk-flexgen.c
@@ -5,6 +5,7 @@
* Author: Maxime Coquelin <maxime.coquelin@st.com> for ST-Microelectronics.
* License terms: GNU General Public License (GPL), version 2 */
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -44,7 +45,7 @@ static int flexgen_enable(struct clk_hw *hw)
clk_gate_ops.enable(fgate_hw);
- pr_debug("%s: flexgen output enabled\n", __clk_get_name(hw->clk));
+ pr_debug("%s: flexgen output enabled\n", clk_hw_get_name(hw));
return 0;
}
@@ -58,7 +59,7 @@ static void flexgen_disable(struct clk_hw *hw)
clk_gate_ops.disable(fgate_hw);
- pr_debug("%s: flexgen output disabled\n", __clk_get_name(hw->clk));
+ pr_debug("%s: flexgen output disabled\n", clk_hw_get_name(hw));
}
static int flexgen_is_enabled(struct clk_hw *hw)
@@ -108,7 +109,7 @@ static long flexgen_round_rate(struct clk_hw *hw, unsigned long rate,
/* Round div according to exact prate and wished rate */
div = clk_best_div(*prate, rate);
- if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
*prate = rate * div;
return rate;
}
@@ -243,7 +244,7 @@ static const char ** __init flexgen_get_parents(struct device_node *np,
int *num_parents)
{
const char **parents;
- int nparents, i;
+ int nparents;
nparents = of_clk_get_parent_count(np);
if (WARN_ON(nparents <= 0))
@@ -253,10 +254,8 @@ static const char ** __init flexgen_get_parents(struct device_node *np,
if (!parents)
return NULL;
- for (i = 0; i < nparents; i++)
- parents[i] = of_clk_get_parent_name(np, i);
+ *num_parents = of_clk_parent_fill(np, parents, nparents);
- *num_parents = nparents;
return parents;
}
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
index d9eb2e1d8471..83ccf142ff2a 100644
--- a/drivers/clk/st/clkgen-fsyn.c
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/of_address.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include "clkgen.h"
@@ -512,7 +513,7 @@ static unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw,
params.ndiv = CLKGEN_READ(pll, ndiv);
if (clk_fs660c32_vco_get_rate(parent_rate, &params, &rate))
pr_err("%s:%s error calculating rate\n",
- __clk_get_name(hw->clk), __func__);
+ clk_hw_get_name(hw), __func__);
pll->ndiv = params.ndiv;
@@ -557,7 +558,7 @@ static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate
clk_fs660c32_vco_get_rate(*prate, &params, &rate);
pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
- __func__, __clk_get_name(hw->clk),
+ __func__, clk_hw_get_name(hw),
rate, (unsigned int)params.sdiv,
(unsigned int)params.mdiv,
(unsigned int)params.pe, (unsigned int)params.nsdiv);
@@ -580,7 +581,7 @@ static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate,
clk_fs660c32_vco_get_rate(parent_rate, &params, &hwrate);
pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n",
- __func__, __clk_get_name(hw->clk),
+ __func__, clk_hw_get_name(hw),
hwrate, (unsigned int)params.ndiv);
if (!hwrate)
@@ -744,7 +745,7 @@ static int quadfs_fsynth_enable(struct clk_hw *hw)
struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
unsigned long flags = 0;
- pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+ pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw));
quadfs_fsynth_program_rate(fs);
@@ -769,7 +770,7 @@ static void quadfs_fsynth_disable(struct clk_hw *hw)
struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
unsigned long flags = 0;
- pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+ pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw));
if (fs->lock)
spin_lock_irqsave(fs->lock, flags);
@@ -786,7 +787,7 @@ static int quadfs_fsynth_is_enabled(struct clk_hw *hw)
u32 nsb = CLKGEN_READ(fs, nsb[fs->chan]);
pr_debug("%s: %s enable bit = 0x%x\n",
- __func__, __clk_get_name(hw->clk), nsb);
+ __func__, clk_hw_get_name(hw), nsb);
return fs->data->standby_polarity ? !nsb : !!nsb;
}
@@ -945,10 +946,10 @@ static unsigned long quadfs_recalc_rate(struct clk_hw *hw,
if (clk_fs_get_rate(parent_rate, &params, &rate)) {
pr_err("%s:%s error calculating rate\n",
- __clk_get_name(hw->clk), __func__);
+ clk_hw_get_name(hw), __func__);
}
- pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+ pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
return rate;
}
@@ -961,7 +962,7 @@ static long quadfs_round_rate(struct clk_hw *hw, unsigned long rate,
rate = quadfs_find_best_rate(hw, rate, *prate, &params);
pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
- __func__, __clk_get_name(hw->clk),
+ __func__, clk_hw_get_name(hw),
rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv,
(unsigned int)params.pe, (unsigned int)params.nsdiv);
diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c
index 717c4a91a17b..4f7f6c00b219 100644
--- a/drivers/clk/st/clkgen-mux.c
+++ b/drivers/clk/st/clkgen-mux.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/of_address.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
static DEFINE_SPINLOCK(clkgena_divmux_lock);
@@ -24,20 +25,17 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np,
int *num_parents)
{
const char **parents;
- int nparents, i;
+ int nparents;
nparents = of_clk_get_parent_count(np);
if (WARN_ON(nparents <= 0))
return ERR_PTR(-EINVAL);
- parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL);
+ parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);
if (!parents)
return ERR_PTR(-ENOMEM);
- for (i = 0; i < nparents; i++)
- parents[i] = of_clk_get_parent_name(np, i);
-
- *num_parents = nparents;
+ *num_parents = of_clk_parent_fill(np, parents, nparents);
return parents;
}
@@ -141,7 +139,7 @@ static u8 clkgena_divmux_get_parent(struct clk_hw *hw)
genamux->muxsel = clk_mux_ops.get_parent(mux_hw);
if ((s8)genamux->muxsel < 0) {
pr_debug("%s: %s: Invalid parent, setting to default.\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
genamux->muxsel = 0;
}
@@ -215,7 +213,7 @@ static const struct clk_ops clkgena_divmux_ops = {
/**
* clk_register_genamux - register a genamux clock with the clock framework
*/
-static struct clk *clk_register_genamux(const char *name,
+static struct clk * __init clk_register_genamux(const char *name,
const char **parent_names, u8 num_parents,
void __iomem *reg,
const struct clkgena_divmux_data *muxdata,
@@ -369,11 +367,10 @@ static const struct of_device_id clkgena_divmux_of_match[] = {
{}
};
-static void __iomem * __init clkgen_get_register_base(
- struct device_node *np)
+static void __iomem * __init clkgen_get_register_base(struct device_node *np)
{
struct device_node *pnode;
- void __iomem *reg = NULL;
+ void __iomem *reg;
pnode = of_get_parent(np);
if (!pnode)
@@ -398,7 +395,7 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np)
if (WARN_ON(!match))
return;
- data = (struct clkgena_divmux_data *)match->data;
+ data = match->data;
reg = clkgen_get_register_base(np);
if (!reg)
@@ -406,18 +403,18 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np)
parents = clkgen_mux_get_parents(np, &num_parents);
if (IS_ERR(parents))
- return;
+ goto err_parents;
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data)
- goto err;
+ goto err_alloc;
clk_data->clk_num = data->num_outputs;
- clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
+ clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
GFP_KERNEL);
if (!clk_data->clks)
- goto err;
+ goto err_alloc_clks;
for (i = 0; i < clk_data->clk_num; i++) {
struct clk *clk;
@@ -447,11 +444,13 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np)
of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
return;
err:
- if (clk_data)
- kfree(clk_data->clks);
-
+ kfree(clk_data->clks);
+err_alloc_clks:
kfree(clk_data);
+err_alloc:
kfree(parents);
+err_parents:
+ iounmap(reg);
}
CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup);
@@ -491,7 +490,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
void __iomem *reg;
const char *parent_name, *clk_name;
struct clk *clk;
- struct clkgena_prediv_data *data;
+ const struct clkgena_prediv_data *data;
match = of_match_node(clkgena_prediv_of_match, np);
if (!match) {
@@ -499,7 +498,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
return;
}
- data = (struct clkgena_prediv_data *)match->data;
+ data = match->data;
reg = clkgen_get_register_base(np);
if (!reg)
@@ -507,18 +506,18 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name)
- return;
+ goto err;
if (of_property_read_string_index(np, "clock-output-names",
0, &clk_name))
- return;
+ goto err;
clk = clk_register_divider_table(NULL, clk_name, parent_name,
CLK_GET_RATE_NOCACHE,
reg + data->offset, data->shift, 1,
0, data->table, NULL);
if (IS_ERR(clk))
- return;
+ goto err;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
pr_debug("%s: parent %s rate %u\n",
@@ -527,6 +526,8 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
(unsigned int)clk_get_rate(clk));
return;
+err:
+ iounmap(reg);
}
CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup);
@@ -630,7 +631,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
void __iomem *reg;
const char **parents;
int num_parents;
- struct clkgen_mux_data *data;
+ const struct clkgen_mux_data *data;
match = of_match_node(mux_of_match, np);
if (!match) {
@@ -638,7 +639,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
return;
}
- data = (struct clkgen_mux_data *)match->data;
+ data = match->data;
reg = of_iomap(np, 0);
if (!reg) {
@@ -650,7 +651,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
if (IS_ERR(parents)) {
pr_err("%s: Failed to get parents (%ld)\n",
__func__, PTR_ERR(parents));
- return;
+ goto err_parents;
}
clk = clk_register_mux(NULL, np->name, parents, num_parents,
@@ -666,12 +667,14 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np)
__clk_get_name(clk_get_parent(clk)),
(unsigned int)clk_get_rate(clk));
+ kfree(parents);
of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
err:
kfree(parents);
-
- return;
+err_parents:
+ iounmap(reg);
}
CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup);
@@ -707,12 +710,12 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np)
const char **parents;
int num_parents, i;
struct clk_onecell_data *clk_data;
- struct clkgen_vcc_data *data;
+ const struct clkgen_vcc_data *data;
match = of_match_node(vcc_of_match, np);
if (WARN_ON(!match))
return;
- data = (struct clkgen_vcc_data *)match->data;
+ data = match->data;
reg = of_iomap(np, 0);
if (!reg)
@@ -720,18 +723,18 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np)
parents = clkgen_mux_get_parents(np, &num_parents);
if (IS_ERR(parents))
- return;
+ goto err_parents;
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data)
- goto err;
+ goto err_alloc;
clk_data->clk_num = VCC_MAX_CHANNELS;
- clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
+ clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
GFP_KERNEL);
if (!clk_data->clks)
- goto err;
+ goto err_alloc_clks;
for (i = 0; i < clk_data->clk_num; i++) {
struct clk *clk;
@@ -750,21 +753,21 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np)
if (*clk_name == '\0')
continue;
- gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
- break;
+ goto err;
- div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div) {
kfree(gate);
- break;
+ goto err;
}
- mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux) {
kfree(gate);
kfree(div);
- break;
+ goto err;
}
gate->reg = reg + VCC_GATE_OFFSET;
@@ -823,10 +826,12 @@ err:
kfree(container_of(composite->mux_hw, struct clk_mux, hw));
}
- if (clk_data)
- kfree(clk_data->clks);
-
+ kfree(clk_data->clks);
+err_alloc_clks:
kfree(clk_data);
+err_alloc:
kfree(parents);
+err_parents:
+ iounmap(reg);
}
CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup);
diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c
index 72d1c27eaffa..47a38a994cac 100644
--- a/drivers/clk/st/clkgen-pll.c
+++ b/drivers/clk/st/clkgen-pll.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/of_address.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include "clkgen.h"
@@ -291,7 +292,7 @@ static unsigned long recalc_stm_pll800c65(struct clk_hw *hw,
res = (uint64_t)2 * (uint64_t)parent_rate * (uint64_t)ndiv;
rate = (unsigned long)div64_u64(res, mdiv * (1 << pdiv));
- pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+ pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
return rate;
@@ -316,7 +317,7 @@ static unsigned long recalc_stm_pll1600c65(struct clk_hw *hw,
/* Note: input is divided by 1000 to avoid overflow */
rate = ((2 * (parent_rate / 1000) * ndiv) / mdiv) * 1000;
- pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+ pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
return rate;
}
@@ -338,7 +339,7 @@ static unsigned long recalc_stm_pll3200c32(struct clk_hw *hw,
/* Note: input is divided to avoid overflow */
rate = ((2 * (parent_rate/1000) * ndiv) / idf) * 1000;
- pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+ pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
return rate;
}
@@ -365,7 +366,7 @@ static unsigned long recalc_stm_pll1200c32(struct clk_hw *hw,
/* Note: input is divided by 1000 to avoid overflow */
rate = (((parent_rate / 1000) * ldf) / (odf * idf)) * 1000;
- pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
+ pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
return rate;
}
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 058f273d6154..f5a35b82cc1a 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -6,6 +6,7 @@ obj-y += clk-sunxi.o clk-factors.o
obj-y += clk-a10-hosc.o
obj-y += clk-a20-gmac.o
obj-y += clk-mod0.o
+obj-y += clk-simple-gates.o
obj-y += clk-sun8i-mbus.o
obj-y += clk-sun9i-core.o
obj-y += clk-sun9i-mmc.o
diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c
index 0dcf4f205fb8..1611b036421c 100644
--- a/drivers/clk/sunxi/clk-a20-gmac.c
+++ b/drivers/clk/sunxi/clk-a20-gmac.c
@@ -80,9 +80,7 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
goto free_mux;
/* gmac clock requires exactly 2 parents */
- parents[0] = of_clk_get_parent_name(node, 0);
- parents[1] = of_clk_get_parent_name(node, 1);
- if (!parents[0] || !parents[1])
+ if (of_clk_parent_fill(node, parents, 2) != 2)
goto free_gate;
reg = of_iomap(node, 0);
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 8c20190a3e9f..59428dbd607a 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -79,41 +79,42 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
return rate;
}
-static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+static int clk_factors_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ struct clk_hw *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
/* find the parent that can help provide the fastest rate <= rate */
- num_parents = __clk_get_num_parents(clk);
+ num_parents = clk_hw_get_num_parents(hw);
for (i = 0; i < num_parents; i++) {
- parent = clk_get_parent_by_index(clk, i);
+ parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
- if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
- parent_rate = __clk_round_rate(parent, rate);
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)
+ parent_rate = clk_hw_round_rate(parent, req->rate);
else
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_hw_get_rate(parent);
- child_rate = clk_factors_round_rate(hw, rate, &parent_rate);
+ child_rate = clk_factors_round_rate(hw, req->rate,
+ &parent_rate);
- if (child_rate <= rate && child_rate > best_child_rate) {
+ if (child_rate <= req->rate && child_rate > best_child_rate) {
best_parent = parent;
best = parent_rate;
best_child_rate = child_rate;
}
}
- if (best_parent)
- *best_parent_p = __clk_get_hw(best_parent);
- *best_parent_rate = best;
+ if (!best_parent)
+ return -EINVAL;
- return best_child_rate;
+ req->best_parent_hw = best_parent;
+ req->best_parent_rate = best;
+ req->rate = best_child_rate;
+
+ return 0;
}
static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -174,9 +175,7 @@ struct clk *sunxi_factors_register(struct device_node *node,
int i = 0;
/* if we have a mux, we will have >1 parents */
- while (i < FACTORS_MAX_PARENTS &&
- (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
- i++;
+ i = of_clk_parent_fill(node, parents, FACTORS_MAX_PARENTS);
/*
* some factor clocks, such as pll5 and pll6, may have multiple
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index 9d028aec58e5..d167e1efb927 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -14,10 +14,11 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include "clk-factors.h"
diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
new file mode 100644
index 000000000000..6ce91180da1b
--- /dev/null
+++ b/drivers/clk/sunxi/clk-simple-gates.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2015 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_SPINLOCK(gates_lock);
+
+static void __init sunxi_simple_gates_setup(struct device_node *node,
+ const int protected[],
+ int nprotected)
+{
+ struct clk_onecell_data *clk_data;
+ const char *clk_parent, *clk_name;
+ struct property *prop;
+ struct resource res;
+ void __iomem *clk_reg;
+ void __iomem *reg;
+ const __be32 *p;
+ int number, i = 0, j;
+ u8 clk_bit;
+ u32 index;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg))
+ return;
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+
+ clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!clk_data)
+ goto err_unmap;
+
+ number = of_property_count_u32_elems(node, "clock-indices");
+ of_property_read_u32_index(node, "clock-indices", number - 1, &number);
+
+ clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
+ if (!clk_data->clks)
+ goto err_free_data;
+
+ of_property_for_each_u32(node, "clock-indices", prop, p, index) {
+ of_property_read_string_index(node, "clock-output-names",
+ i, &clk_name);
+
+ clk_reg = reg + 4 * (index / 32);
+ clk_bit = index % 32;
+
+ clk_data->clks[index] = clk_register_gate(NULL, clk_name,
+ clk_parent, 0,
+ clk_reg,
+ clk_bit,
+ 0, &gates_lock);
+ i++;
+
+ if (IS_ERR(clk_data->clks[index])) {
+ WARN_ON(true);
+ continue;
+ }
+
+ for (j = 0; j < nprotected; j++)
+ if (protected[j] == index)
+ clk_prepare_enable(clk_data->clks[index]);
+
+ }
+
+ clk_data->clk_num = number + 1;
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+ return;
+
+err_free_data:
+ kfree(clk_data);
+err_unmap:
+ iounmap(reg);
+ of_address_to_resource(node, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
+}
+
+static void __init sunxi_simple_gates_init(struct device_node *node)
+{
+ sunxi_simple_gates_setup(node, NULL, 0);
+}
+
+CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun4i_a10_axi, "allwinner,sun4i-a10-axi-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun5i_a10s_apb0, "allwinner,sun5i-a10s-apb0-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun5i_a10s_apb1, "allwinner,sun5i-a10s-apb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun5i_a13_apb0, "allwinner,sun5i-a13-apb0-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun5i_a13_apb1, "allwinner,sun5i-a13-apb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun6i_a31_apb1, "allwinner,sun6i-a31-apb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun6i_a31_apb2, "allwinner,sun6i-a31-apb2-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun7i_a20_apb0, "allwinner,sun7i-a20-apb0-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun7i_a20_apb1, "allwinner,sun7i-a20-apb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun8i_a23_ahb1, "allwinner,sun8i-a23-ahb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun8i_a23_apb1, "allwinner,sun8i-a23-apb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun8i_a23_apb2, "allwinner,sun8i-a23-apb2-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_ahb0, "allwinner,sun9i-a80-ahb0-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_ahb1, "allwinner,sun9i-a80-ahb1-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_ahb2, "allwinner,sun9i-a80-ahb2-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
+ sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
+ sunxi_simple_gates_init);
+
+static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
+ 14, /* ahb_sdram */
+};
+
+static void __init sun4i_a10_ahb_init(struct device_node *node)
+{
+ sunxi_simple_gates_setup(node, sun4i_a10_ahb_critical_clocks,
+ ARRAY_SIZE(sun4i_a10_ahb_critical_clocks));
+}
+CLK_OF_DECLARE(sun4i_a10_ahb, "allwinner,sun4i-a10-ahb-gates-clk",
+ sun4i_a10_ahb_init);
+CLK_OF_DECLARE(sun5i_a10s_ahb, "allwinner,sun5i-a10s-ahb-gates-clk",
+ sun4i_a10_ahb_init);
+CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
+ sun4i_a10_ahb_init);
+CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
+ sun4i_a10_ahb_init);
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
index 63cf149195ae..806fd019c05d 100644
--- a/drivers/clk/sunxi/clk-sun6i-ar100.c
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -44,28 +44,25 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw,
return (parent_rate >> shift) / (div + 1);
}
-static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_clk)
+static int ar100_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- int nparents = __clk_get_num_parents(hw->clk);
+ int nparents = clk_hw_get_num_parents(hw);
long best_rate = -EINVAL;
int i;
- *best_parent_clk = NULL;
+ req->best_parent_hw = NULL;
for (i = 0; i < nparents; i++) {
unsigned long parent_rate;
unsigned long tmp_rate;
- struct clk *parent;
+ struct clk_hw *parent;
unsigned long div;
int shift;
- parent = clk_get_parent_by_index(hw->clk, i);
- parent_rate = __clk_get_rate(parent);
- div = DIV_ROUND_UP(parent_rate, rate);
+ parent = clk_hw_get_parent_by_index(hw, i);
+ parent_rate = clk_hw_get_rate(parent);
+ div = DIV_ROUND_UP(parent_rate, req->rate);
/*
* The AR100 clk contains 2 divisors:
@@ -101,14 +98,19 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
continue;
tmp_rate = (parent_rate >> shift) / div;
- if (!*best_parent_clk || tmp_rate > best_rate) {
- *best_parent_clk = __clk_get_hw(parent);
- *best_parent_rate = parent_rate;
+ if (!req->best_parent_hw || tmp_rate > best_rate) {
+ req->best_parent_hw = parent;
+ req->best_parent_rate = parent_rate;
best_rate = tmp_rate;
}
}
- return best_rate;
+ if (best_rate < 0)
+ return best_rate;
+
+ req->rate = best_rate;
+
+ return 0;
}
static int ar100_set_parent(struct clk_hw *hw, u8 index)
@@ -180,7 +182,6 @@ static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev)
struct resource *r;
struct clk *clk;
int nparents;
- int i;
ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL);
if (!ar100)
@@ -195,8 +196,7 @@ static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev)
if (nparents > SUN6I_AR100_MAX_PARENTS)
nparents = SUN6I_AR100_MAX_PARENTS;
- for (i = 0; i < nparents; i++)
- parents[i] = of_clk_get_parent_name(np, i);
+ of_clk_parent_fill(np, parents, nparents);
of_property_read_string(np, "clock-output-names", &clk_name);
diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c
index 14cd026064bf..bf117a636d23 100644
--- a/drivers/clk/sunxi/clk-sun8i-mbus.c
+++ b/drivers/clk/sunxi/clk-sun8i-mbus.c
@@ -14,8 +14,8 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/of_address.h>
#include "clk-factors.h"
diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c
index 887f4ea161bb..6c4c98324d3c 100644
--- a/drivers/clk/sunxi/clk-sun9i-core.c
+++ b/drivers/clk/sunxi/clk-sun9i-core.c
@@ -14,8 +14,8 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/log2.h>
diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c
index 710c273648d7..3436a948b796 100644
--- a/drivers/clk/sunxi/clk-sun9i-mmc.c
+++ b/drivers/clk/sunxi/clk-sun9i-mmc.c
@@ -14,14 +14,15 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#define SUN9I_MMC_WIDTH 4
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index abf7b37faf73..413070d07b3f 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -14,11 +14,13 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/log2.h>
@@ -118,42 +120,42 @@ static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
return (parent_rate / calcm) >> calcp;
}
-static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_clk)
+static int sun6i_ahb1_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ struct clk_hw *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
/* find the parent that can help provide the fastest rate <= rate */
- num_parents = __clk_get_num_parents(clk);
+ num_parents = clk_hw_get_num_parents(hw);
for (i = 0; i < num_parents; i++) {
- parent = clk_get_parent_by_index(clk, i);
+ parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
- if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
- parent_rate = __clk_round_rate(parent, rate);
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)
+ parent_rate = clk_hw_round_rate(parent, req->rate);
else
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_hw_get_rate(parent);
- child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i,
+ child_rate = sun6i_ahb1_clk_round(req->rate, NULL, NULL, i,
parent_rate);
- if (child_rate <= rate && child_rate > best_child_rate) {
+ if (child_rate <= req->rate && child_rate > best_child_rate) {
best_parent = parent;
best = parent_rate;
best_child_rate = child_rate;
}
}
- if (best_parent)
- *best_parent_clk = __clk_get_hw(best_parent);
- *best_parent_rate = best;
+ if (!best_parent)
+ return -EINVAL;
- return best_child_rate;
+ req->best_parent_hw = best_parent;
+ req->best_parent_rate = best;
+ req->rate = best_child_rate;
+
+ return 0;
}
static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -195,17 +197,14 @@ static void __init sun6i_ahb1_clk_setup(struct device_node *node)
const char *clk_name = node->name;
const char *parents[SUN6I_AHB1_MAX_PARENTS];
void __iomem *reg;
- int i = 0;
+ int i;
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg))
return;
/* we have a mux, we will have >1 parents */
- while (i < SUN6I_AHB1_MAX_PARENTS &&
- (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
- i++;
-
+ i = of_clk_parent_fill(node, parents, SUN6I_AHB1_MAX_PARENTS);
of_property_read_string(node, "clock-output-names", &clk_name);
ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL);
@@ -786,14 +785,11 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
const char *clk_name = node->name;
const char *parents[SUNXI_MAX_PARENTS];
void __iomem *reg;
- int i = 0;
+ int i;
reg = of_iomap(node, 0);
- while (i < SUNXI_MAX_PARENTS &&
- (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
- i++;
-
+ i = of_clk_parent_fill(node, parents, SUNXI_MAX_PARENTS);
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_mux(NULL, clk_name, parents, i,
@@ -900,150 +896,6 @@ struct gates_data {
DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
};
-static const struct gates_data sun4i_axi_gates_data __initconst = {
- .mask = {1},
-};
-
-static const struct gates_data sun4i_ahb_gates_data __initconst = {
- .mask = {0x7F77FFF, 0x14FB3F},
-};
-
-static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = {
- .mask = {0x147667e7, 0x185915},
-};
-
-static const struct gates_data sun5i_a13_ahb_gates_data __initconst = {
- .mask = {0x107067e7, 0x185111},
-};
-
-static const struct gates_data sun6i_a31_ahb1_gates_data __initconst = {
- .mask = {0xEDFE7F62, 0x794F931},
-};
-
-static const struct gates_data sun7i_a20_ahb_gates_data __initconst = {
- .mask = { 0x12f77fff, 0x16ff3f },
-};
-
-static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = {
- .mask = {0x25386742, 0x2505111},
-};
-
-static const struct gates_data sun9i_a80_ahb0_gates_data __initconst = {
- .mask = {0xF5F12B},
-};
-
-static const struct gates_data sun9i_a80_ahb1_gates_data __initconst = {
- .mask = {0x1E20003},
-};
-
-static const struct gates_data sun9i_a80_ahb2_gates_data __initconst = {
- .mask = {0x9B7},
-};
-
-static const struct gates_data sun4i_apb0_gates_data __initconst = {
- .mask = {0x4EF},
-};
-
-static const struct gates_data sun5i_a10s_apb0_gates_data __initconst = {
- .mask = {0x469},
-};
-
-static const struct gates_data sun5i_a13_apb0_gates_data __initconst = {
- .mask = {0x61},
-};
-
-static const struct gates_data sun7i_a20_apb0_gates_data __initconst = {
- .mask = { 0x4ff },
-};
-
-static const struct gates_data sun9i_a80_apb0_gates_data __initconst = {
- .mask = {0xEB822},
-};
-
-static const struct gates_data sun4i_apb1_gates_data __initconst = {
- .mask = {0xFF00F7},
-};
-
-static const struct gates_data sun5i_a10s_apb1_gates_data __initconst = {
- .mask = {0xf0007},
-};
-
-static const struct gates_data sun5i_a13_apb1_gates_data __initconst = {
- .mask = {0xa0007},
-};
-
-static const struct gates_data sun6i_a31_apb1_gates_data __initconst = {
- .mask = {0x3031},
-};
-
-static const struct gates_data sun8i_a23_apb1_gates_data __initconst = {
- .mask = {0x3021},
-};
-
-static const struct gates_data sun6i_a31_apb2_gates_data __initconst = {
- .mask = {0x3F000F},
-};
-
-static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
- .mask = { 0xff80ff },
-};
-
-static const struct gates_data sun9i_a80_apb1_gates_data __initconst = {
- .mask = {0x3F001F},
-};
-
-static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
- .mask = {0x1F0007},
-};
-
-static void __init sunxi_gates_clk_setup(struct device_node *node,
- struct gates_data *data)
-{
- struct clk_onecell_data *clk_data;
- const char *clk_parent;
- const char *clk_name;
- void __iomem *reg;
- int qty;
- int i = 0;
- int j = 0;
-
- reg = of_iomap(node, 0);
-
- clk_parent = of_clk_get_parent_name(node, 0);
-
- /* Worst-case size approximation and memory allocation */
- qty = find_last_bit(data->mask, SUNXI_GATES_MAX_SIZE);
- clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
- if (!clk_data)
- return;
- clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
- if (!clk_data->clks) {
- kfree(clk_data);
- return;
- }
-
- for_each_set_bit(i, data->mask, SUNXI_GATES_MAX_SIZE) {
- of_property_read_string_index(node, "clock-output-names",
- j, &clk_name);
-
- clk_data->clks[i] = clk_register_gate(NULL, clk_name,
- clk_parent, 0,
- reg + 4 * (i/32), i % 32,
- 0, &clk_lock);
- WARN_ON(IS_ERR(clk_data->clks[i]));
- clk_register_clkdev(clk_data->clks[i], clk_name, NULL);
-
- j++;
- }
-
- /* Adjust to the real max */
- clk_data->clk_num = i;
-
- of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-}
-
-
-
/**
* sunxi_divs_clk_setup() helper data
*/
@@ -1281,34 +1133,6 @@ static const struct of_device_id clk_mux_match[] __initconst = {
{}
};
-/* Matches for gate clocks */
-static const struct of_device_id clk_gates_match[] __initconst = {
- {.compatible = "allwinner,sun4i-a10-axi-gates-clk", .data = &sun4i_axi_gates_data,},
- {.compatible = "allwinner,sun4i-a10-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
- {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,},
- {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
- {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
- {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
- {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,},
- {.compatible = "allwinner,sun9i-a80-ahb0-gates-clk", .data = &sun9i_a80_ahb0_gates_data,},
- {.compatible = "allwinner,sun9i-a80-ahb1-gates-clk", .data = &sun9i_a80_ahb1_gates_data,},
- {.compatible = "allwinner,sun9i-a80-ahb2-gates-clk", .data = &sun9i_a80_ahb2_gates_data,},
- {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
- {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
- {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
- {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,},
- {.compatible = "allwinner,sun9i-a80-apb0-gates-clk", .data = &sun9i_a80_apb0_gates_data,},
- {.compatible = "allwinner,sun4i-a10-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
- {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,},
- {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
- {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
- {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
- {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,},
- {.compatible = "allwinner,sun9i-a80-apb1-gates-clk", .data = &sun9i_a80_apb1_gates_data,},
- {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
- {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,},
- {}
-};
static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match,
void *function)
@@ -1340,9 +1164,6 @@ static void __init sunxi_init_clocks(const char *clocks[], int nclocks)
/* Register mux clocks */
of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup);
- /* Register gate clocks */
- of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup);
-
/* Protect the clocks that needs to stay on */
for (i = 0; i < nclocks; i++) {
struct clk *clk = clk_get(NULL, clocks[i]);
@@ -1354,7 +1175,6 @@ static void __init sunxi_init_clocks(const char *clocks[], int nclocks)
static const char *sun4i_a10_critical_clocks[] __initdata = {
"pll5_ddr",
- "ahb_sdram",
};
static void __init sun4i_a10_init_clocks(struct device_node *node)
@@ -1367,7 +1187,6 @@ CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks)
static const char *sun5i_critical_clocks[] __initdata = {
"cpu",
"pll5_ddr",
- "ahb_sdram",
};
static void __init sun5i_init_clocks(struct device_node *node)
diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
index 3a25f9588e67..1a72cd672839 100644
--- a/drivers/clk/sunxi/clk-usb.c
+++ b/drivers/clk/sunxi/clk-usb.c
@@ -14,11 +14,12 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index aec862ba7a17..826c325dc2e8 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -1,5 +1,6 @@
obj-y += clk.o
obj-y += clk-audio-sync.o
+obj-y += clk-dfll.o
obj-y += clk-divider.o
obj-y += clk-periph.o
obj-y += clk-periph-gate.o
@@ -16,4 +17,6 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
+obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124-dfll-fcpu.o
obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
+obj-y += cvb.o
diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
new file mode 100644
index 000000000000..c2ff859ee0e8
--- /dev/null
+++ b/drivers/clk/tegra/clk-dfll.c
@@ -0,0 +1,1757 @@
+/*
+ * clk-dfll.c - Tegra DFLL clock source common code
+ *
+ * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved.
+ *
+ * Aleksandr Frid <afrid@nvidia.com>
+ * Paul Walmsley <pwalmsley@nvidia.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * This library is for the DVCO and DFLL IP blocks on the Tegra124
+ * SoC. These IP blocks together are also known at NVIDIA as
+ * "CL-DVFS". To try to avoid confusion, this code refers to them
+ * collectively as the "DFLL."
+ *
+ * The DFLL is a root clocksource which tolerates some amount of
+ * supply voltage noise. Tegra124 uses it to clock the fast CPU
+ * complex when the target CPU speed is above a particular rate. The
+ * DFLL can be operated in either open-loop mode or closed-loop mode.
+ * In open-loop mode, the DFLL generates an output clock appropriate
+ * to the supply voltage. In closed-loop mode, when configured with a
+ * target frequency, the DFLL minimizes supply voltage while
+ * delivering an average frequency equal to the target.
+ *
+ * Devices clocked by the DFLL must be able to tolerate frequency
+ * variation. In the case of the CPU, it's important to note that the
+ * CPU cycle time will vary. This has implications for
+ * performance-measurement code and any code that relies on the CPU
+ * cycle time to delay for a certain length of time.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+
+#include "clk-dfll.h"
+
+/*
+ * DFLL control registers - access via dfll_{readl,writel}
+ */
+
+/* DFLL_CTRL: DFLL control register */
+#define DFLL_CTRL 0x00
+#define DFLL_CTRL_MODE_MASK 0x03
+
+/* DFLL_CONFIG: DFLL sample rate control */
+#define DFLL_CONFIG 0x04
+#define DFLL_CONFIG_DIV_MASK 0xff
+#define DFLL_CONFIG_DIV_PRESCALE 32
+
+/* DFLL_PARAMS: tuning coefficients for closed loop integrator */
+#define DFLL_PARAMS 0x08
+#define DFLL_PARAMS_CG_SCALE (0x1 << 24)
+#define DFLL_PARAMS_FORCE_MODE_SHIFT 22
+#define DFLL_PARAMS_FORCE_MODE_MASK (0x3 << DFLL_PARAMS_FORCE_MODE_SHIFT)
+#define DFLL_PARAMS_CF_PARAM_SHIFT 16
+#define DFLL_PARAMS_CF_PARAM_MASK (0x3f << DFLL_PARAMS_CF_PARAM_SHIFT)
+#define DFLL_PARAMS_CI_PARAM_SHIFT 8
+#define DFLL_PARAMS_CI_PARAM_MASK (0x7 << DFLL_PARAMS_CI_PARAM_SHIFT)
+#define DFLL_PARAMS_CG_PARAM_SHIFT 0
+#define DFLL_PARAMS_CG_PARAM_MASK (0xff << DFLL_PARAMS_CG_PARAM_SHIFT)
+
+/* DFLL_TUNE0: delay line configuration register 0 */
+#define DFLL_TUNE0 0x0c
+
+/* DFLL_TUNE1: delay line configuration register 1 */
+#define DFLL_TUNE1 0x10
+
+/* DFLL_FREQ_REQ: target DFLL frequency control */
+#define DFLL_FREQ_REQ 0x14
+#define DFLL_FREQ_REQ_FORCE_ENABLE (0x1 << 28)
+#define DFLL_FREQ_REQ_FORCE_SHIFT 16
+#define DFLL_FREQ_REQ_FORCE_MASK (0xfff << DFLL_FREQ_REQ_FORCE_SHIFT)
+#define FORCE_MAX 2047
+#define FORCE_MIN -2048
+#define DFLL_FREQ_REQ_SCALE_SHIFT 8
+#define DFLL_FREQ_REQ_SCALE_MASK (0xff << DFLL_FREQ_REQ_SCALE_SHIFT)
+#define DFLL_FREQ_REQ_SCALE_MAX 256
+#define DFLL_FREQ_REQ_FREQ_VALID (0x1 << 7)
+#define DFLL_FREQ_REQ_MULT_SHIFT 0
+#define DFLL_FREQ_REG_MULT_MASK (0x7f << DFLL_FREQ_REQ_MULT_SHIFT)
+#define FREQ_MAX 127
+
+/* DFLL_DROOP_CTRL: droop prevention control */
+#define DFLL_DROOP_CTRL 0x1c
+
+/* DFLL_OUTPUT_CFG: closed loop mode control registers */
+/* NOTE: access via dfll_i2c_{readl,writel} */
+#define DFLL_OUTPUT_CFG 0x20
+#define DFLL_OUTPUT_CFG_I2C_ENABLE (0x1 << 30)
+#define OUT_MASK 0x3f
+#define DFLL_OUTPUT_CFG_SAFE_SHIFT 24
+#define DFLL_OUTPUT_CFG_SAFE_MASK \
+ (OUT_MASK << DFLL_OUTPUT_CFG_SAFE_SHIFT)
+#define DFLL_OUTPUT_CFG_MAX_SHIFT 16
+#define DFLL_OUTPUT_CFG_MAX_MASK \
+ (OUT_MASK << DFLL_OUTPUT_CFG_MAX_SHIFT)
+#define DFLL_OUTPUT_CFG_MIN_SHIFT 8
+#define DFLL_OUTPUT_CFG_MIN_MASK \
+ (OUT_MASK << DFLL_OUTPUT_CFG_MIN_SHIFT)
+#define DFLL_OUTPUT_CFG_PWM_DELTA (0x1 << 7)
+#define DFLL_OUTPUT_CFG_PWM_ENABLE (0x1 << 6)
+#define DFLL_OUTPUT_CFG_PWM_DIV_SHIFT 0
+#define DFLL_OUTPUT_CFG_PWM_DIV_MASK \
+ (OUT_MASK << DFLL_OUTPUT_CFG_PWM_DIV_SHIFT)
+
+/* DFLL_OUTPUT_FORCE: closed loop mode voltage forcing control */
+#define DFLL_OUTPUT_FORCE 0x24
+#define DFLL_OUTPUT_FORCE_ENABLE (0x1 << 6)
+#define DFLL_OUTPUT_FORCE_VALUE_SHIFT 0
+#define DFLL_OUTPUT_FORCE_VALUE_MASK \
+ (OUT_MASK << DFLL_OUTPUT_FORCE_VALUE_SHIFT)
+
+/* DFLL_MONITOR_CTRL: internal monitor data source control */
+#define DFLL_MONITOR_CTRL 0x28
+#define DFLL_MONITOR_CTRL_FREQ 6
+
+/* DFLL_MONITOR_DATA: internal monitor data output */
+#define DFLL_MONITOR_DATA 0x2c
+#define DFLL_MONITOR_DATA_NEW_MASK (0x1 << 16)
+#define DFLL_MONITOR_DATA_VAL_SHIFT 0
+#define DFLL_MONITOR_DATA_VAL_MASK (0xFFFF << DFLL_MONITOR_DATA_VAL_SHIFT)
+
+/*
+ * I2C output control registers - access via dfll_i2c_{readl,writel}
+ */
+
+/* DFLL_I2C_CFG: I2C controller configuration register */
+#define DFLL_I2C_CFG 0x40
+#define DFLL_I2C_CFG_ARB_ENABLE (0x1 << 20)
+#define DFLL_I2C_CFG_HS_CODE_SHIFT 16
+#define DFLL_I2C_CFG_HS_CODE_MASK (0x7 << DFLL_I2C_CFG_HS_CODE_SHIFT)
+#define DFLL_I2C_CFG_PACKET_ENABLE (0x1 << 15)
+#define DFLL_I2C_CFG_SIZE_SHIFT 12
+#define DFLL_I2C_CFG_SIZE_MASK (0x7 << DFLL_I2C_CFG_SIZE_SHIFT)
+#define DFLL_I2C_CFG_SLAVE_ADDR_10 (0x1 << 10)
+#define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_7BIT 1
+#define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_10BIT 0
+
+/* DFLL_I2C_VDD_REG_ADDR: PMIC I2C address for closed loop mode */
+#define DFLL_I2C_VDD_REG_ADDR 0x44
+
+/* DFLL_I2C_STS: I2C controller status */
+#define DFLL_I2C_STS 0x48
+#define DFLL_I2C_STS_I2C_LAST_SHIFT 1
+#define DFLL_I2C_STS_I2C_REQ_PENDING 0x1
+
+/* DFLL_INTR_STS: DFLL interrupt status register */
+#define DFLL_INTR_STS 0x5c
+
+/* DFLL_INTR_EN: DFLL interrupt enable register */
+#define DFLL_INTR_EN 0x60
+#define DFLL_INTR_MIN_MASK 0x1
+#define DFLL_INTR_MAX_MASK 0x2
+
+/*
+ * Integrated I2C controller registers - relative to td->i2c_controller_base
+ */
+
+/* DFLL_I2C_CLK_DIVISOR: I2C controller clock divisor */
+#define DFLL_I2C_CLK_DIVISOR 0x6c
+#define DFLL_I2C_CLK_DIVISOR_MASK 0xffff
+#define DFLL_I2C_CLK_DIVISOR_FS_SHIFT 16
+#define DFLL_I2C_CLK_DIVISOR_HS_SHIFT 0
+#define DFLL_I2C_CLK_DIVISOR_PREDIV 8
+#define DFLL_I2C_CLK_DIVISOR_HSMODE_PREDIV 12
+
+/*
+ * Other constants
+ */
+
+/* MAX_DFLL_VOLTAGES: number of LUT entries in the DFLL IP block */
+#define MAX_DFLL_VOLTAGES 33
+
+/*
+ * REF_CLK_CYC_PER_DVCO_SAMPLE: the number of ref_clk cycles that the hardware
+ * integrates the DVCO counter over - used for debug rate monitoring and
+ * droop control
+ */
+#define REF_CLK_CYC_PER_DVCO_SAMPLE 4
+
+/*
+ * REF_CLOCK_RATE: the DFLL reference clock rate currently supported by this
+ * driver, in Hz
+ */
+#define REF_CLOCK_RATE 51000000UL
+
+#define DVCO_RATE_TO_MULT(rate, ref_rate) ((rate) / ((ref_rate) / 2))
+#define MULT_TO_DVCO_RATE(mult, ref_rate) ((mult) * ((ref_rate) / 2))
+
+/**
+ * enum dfll_ctrl_mode - DFLL hardware operating mode
+ * @DFLL_UNINITIALIZED: (uninitialized state - not in hardware bitfield)
+ * @DFLL_DISABLED: DFLL not generating an output clock
+ * @DFLL_OPEN_LOOP: DVCO running, but DFLL not adjusting voltage
+ * @DFLL_CLOSED_LOOP: DVCO running, and DFLL adjusting voltage to match
+ * the requested rate
+ *
+ * The integer corresponding to the last two states, minus one, is
+ * written to the DFLL hardware to change operating modes.
+ */
+enum dfll_ctrl_mode {
+ DFLL_UNINITIALIZED = 0,
+ DFLL_DISABLED = 1,
+ DFLL_OPEN_LOOP = 2,
+ DFLL_CLOSED_LOOP = 3,
+};
+
+/**
+ * enum dfll_tune_range - voltage range that the driver believes it's in
+ * @DFLL_TUNE_UNINITIALIZED: DFLL tuning not yet programmed
+ * @DFLL_TUNE_LOW: DFLL in the low-voltage range (or open-loop mode)
+ *
+ * Some DFLL tuning parameters may need to change depending on the
+ * DVCO's voltage; these states represent the ranges that the driver
+ * supports. These are software states; these values are never
+ * written into registers.
+ */
+enum dfll_tune_range {
+ DFLL_TUNE_UNINITIALIZED = 0,
+ DFLL_TUNE_LOW = 1,
+};
+
+/**
+ * struct dfll_rate_req - target DFLL rate request data
+ * @rate: target frequency, after the postscaling
+ * @dvco_target_rate: target frequency, after the postscaling
+ * @lut_index: LUT index at which voltage the dvco_target_rate will be reached
+ * @mult_bits: value to program to the MULT bits of the DFLL_FREQ_REQ register
+ * @scale_bits: value to program to the SCALE bits of the DFLL_FREQ_REQ register
+ */
+struct dfll_rate_req {
+ unsigned long rate;
+ unsigned long dvco_target_rate;
+ int lut_index;
+ u8 mult_bits;
+ u8 scale_bits;
+};
+
+struct tegra_dfll {
+ struct device *dev;
+ struct tegra_dfll_soc_data *soc;
+
+ void __iomem *base;
+ void __iomem *i2c_base;
+ void __iomem *i2c_controller_base;
+ void __iomem *lut_base;
+
+ struct regulator *vdd_reg;
+ struct clk *soc_clk;
+ struct clk *ref_clk;
+ struct clk *i2c_clk;
+ struct clk *dfll_clk;
+ struct reset_control *dvco_rst;
+ unsigned long ref_rate;
+ unsigned long i2c_clk_rate;
+ unsigned long dvco_rate_min;
+
+ enum dfll_ctrl_mode mode;
+ enum dfll_tune_range tune_range;
+ struct dentry *debugfs_dir;
+ struct clk_hw dfll_clk_hw;
+ const char *output_clock_name;
+ struct dfll_rate_req last_req;
+ unsigned long last_unrounded_rate;
+
+ /* Parameters from DT */
+ u32 droop_ctrl;
+ u32 sample_rate;
+ u32 force_mode;
+ u32 cf;
+ u32 ci;
+ u32 cg;
+ bool cg_scale;
+
+ /* I2C interface parameters */
+ u32 i2c_fs_rate;
+ u32 i2c_reg;
+ u32 i2c_slave_addr;
+
+ /* i2c_lut array entries are regulator framework selectors */
+ unsigned i2c_lut[MAX_DFLL_VOLTAGES];
+ int i2c_lut_size;
+ u8 lut_min, lut_max, lut_safe;
+};
+
+#define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw)
+
+/* mode_name: map numeric DFLL modes to names for friendly console messages */
+static const char * const mode_name[] = {
+ [DFLL_UNINITIALIZED] = "uninitialized",
+ [DFLL_DISABLED] = "disabled",
+ [DFLL_OPEN_LOOP] = "open_loop",
+ [DFLL_CLOSED_LOOP] = "closed_loop",
+};
+
+/*
+ * Register accessors
+ */
+
+static inline u32 dfll_readl(struct tegra_dfll *td, u32 offs)
+{
+ return __raw_readl(td->base + offs);
+}
+
+static inline void dfll_writel(struct tegra_dfll *td, u32 val, u32 offs)
+{
+ WARN_ON(offs >= DFLL_I2C_CFG);
+ __raw_writel(val, td->base + offs);
+}
+
+static inline void dfll_wmb(struct tegra_dfll *td)
+{
+ dfll_readl(td, DFLL_CTRL);
+}
+
+/* I2C output control registers - for addresses above DFLL_I2C_CFG */
+
+static inline u32 dfll_i2c_readl(struct tegra_dfll *td, u32 offs)
+{
+ return __raw_readl(td->i2c_base + offs);
+}
+
+static inline void dfll_i2c_writel(struct tegra_dfll *td, u32 val, u32 offs)
+{
+ __raw_writel(val, td->i2c_base + offs);
+}
+
+static inline void dfll_i2c_wmb(struct tegra_dfll *td)
+{
+ dfll_i2c_readl(td, DFLL_I2C_CFG);
+}
+
+/**
+ * dfll_is_running - is the DFLL currently generating a clock?
+ * @td: DFLL instance
+ *
+ * If the DFLL is currently generating an output clock signal, return
+ * true; otherwise return false.
+ */
+static bool dfll_is_running(struct tegra_dfll *td)
+{
+ return td->mode >= DFLL_OPEN_LOOP;
+}
+
+/*
+ * Runtime PM suspend/resume callbacks
+ */
+
+/**
+ * tegra_dfll_runtime_resume - enable all clocks needed by the DFLL
+ * @dev: DFLL device *
+ *
+ * Enable all clocks needed by the DFLL. Assumes that clk_prepare()
+ * has already been called on all the clocks.
+ *
+ * XXX Should also handle context restore when returning from off.
+ */
+int tegra_dfll_runtime_resume(struct device *dev)
+{
+ struct tegra_dfll *td = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(td->ref_clk);
+ if (ret) {
+ dev_err(dev, "could not enable ref clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(td->soc_clk);
+ if (ret) {
+ dev_err(dev, "could not enable register clock: %d\n", ret);
+ clk_disable(td->ref_clk);
+ return ret;
+ }
+
+ ret = clk_enable(td->i2c_clk);
+ if (ret) {
+ dev_err(dev, "could not enable i2c clock: %d\n", ret);
+ clk_disable(td->soc_clk);
+ clk_disable(td->ref_clk);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dfll_runtime_resume);
+
+/**
+ * tegra_dfll_runtime_suspend - disable all clocks needed by the DFLL
+ * @dev: DFLL device *
+ *
+ * Disable all clocks needed by the DFLL. Assumes that other code
+ * will later call clk_unprepare().
+ */
+int tegra_dfll_runtime_suspend(struct device *dev)
+{
+ struct tegra_dfll *td = dev_get_drvdata(dev);
+
+ clk_disable(td->ref_clk);
+ clk_disable(td->soc_clk);
+ clk_disable(td->i2c_clk);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dfll_runtime_suspend);
+
+/*
+ * DFLL tuning operations (per-voltage-range tuning settings)
+ */
+
+/**
+ * dfll_tune_low - tune to DFLL and CPU settings valid for any voltage
+ * @td: DFLL instance
+ *
+ * Tune the DFLL oscillator parameters and the CPU clock shaper for
+ * the low-voltage range. These settings are valid for any voltage,
+ * but may not be optimal.
+ */
+static void dfll_tune_low(struct tegra_dfll *td)
+{
+ td->tune_range = DFLL_TUNE_LOW;
+
+ dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0);
+ dfll_writel(td, td->soc->tune1, DFLL_TUNE1);
+ dfll_wmb(td);
+
+ if (td->soc->set_clock_trimmers_low)
+ td->soc->set_clock_trimmers_low();
+}
+
+/*
+ * Output clock scaler helpers
+ */
+
+/**
+ * dfll_scale_dvco_rate - calculate scaled rate from the DVCO rate
+ * @scale_bits: clock scaler value (bits in the DFLL_FREQ_REQ_SCALE field)
+ * @dvco_rate: the DVCO rate
+ *
+ * Apply the same scaling formula that the DFLL hardware uses to scale
+ * the DVCO rate.
+ */
+static unsigned long dfll_scale_dvco_rate(int scale_bits,
+ unsigned long dvco_rate)
+{
+ return (u64)dvco_rate * (scale_bits + 1) / DFLL_FREQ_REQ_SCALE_MAX;
+}
+
+/*
+ * Monitor control
+ */
+
+/**
+ * dfll_calc_monitored_rate - convert DFLL_MONITOR_DATA_VAL rate into real freq
+ * @monitor_data: value read from the DFLL_MONITOR_DATA_VAL bitfield
+ * @ref_rate: DFLL reference clock rate
+ *
+ * Convert @monitor_data from DFLL_MONITOR_DATA_VAL units into cycles
+ * per second. Returns the converted value.
+ */
+static u64 dfll_calc_monitored_rate(u32 monitor_data,
+ unsigned long ref_rate)
+{
+ return monitor_data * (ref_rate / REF_CLK_CYC_PER_DVCO_SAMPLE);
+}
+
+/**
+ * dfll_read_monitor_rate - return the DFLL's output rate from internal monitor
+ * @td: DFLL instance
+ *
+ * If the DFLL is enabled, return the last rate reported by the DFLL's
+ * internal monitoring hardware. This works in both open-loop and
+ * closed-loop mode, and takes the output scaler setting into account.
+ * Assumes that the monitor was programmed to monitor frequency before
+ * the sample period started. If the driver believes that the DFLL is
+ * currently uninitialized or disabled, it will return 0, since
+ * otherwise the DFLL monitor data register will return the last
+ * measured rate from when the DFLL was active.
+ */
+static u64 dfll_read_monitor_rate(struct tegra_dfll *td)
+{
+ u32 v, s;
+ u64 pre_scaler_rate, post_scaler_rate;
+
+ if (!dfll_is_running(td))
+ return 0;
+
+ v = dfll_readl(td, DFLL_MONITOR_DATA);
+ v = (v & DFLL_MONITOR_DATA_VAL_MASK) >> DFLL_MONITOR_DATA_VAL_SHIFT;
+ pre_scaler_rate = dfll_calc_monitored_rate(v, td->ref_rate);
+
+ s = dfll_readl(td, DFLL_FREQ_REQ);
+ s = (s & DFLL_FREQ_REQ_SCALE_MASK) >> DFLL_FREQ_REQ_SCALE_SHIFT;
+ post_scaler_rate = dfll_scale_dvco_rate(s, pre_scaler_rate);
+
+ return post_scaler_rate;
+}
+
+/*
+ * DFLL mode switching
+ */
+
+/**
+ * dfll_set_mode - change the DFLL control mode
+ * @td: DFLL instance
+ * @mode: DFLL control mode (see enum dfll_ctrl_mode)
+ *
+ * Change the DFLL's operating mode between disabled, open-loop mode,
+ * and closed-loop mode, or vice versa.
+ */
+static void dfll_set_mode(struct tegra_dfll *td,
+ enum dfll_ctrl_mode mode)
+{
+ td->mode = mode;
+ dfll_writel(td, mode - 1, DFLL_CTRL);
+ dfll_wmb(td);
+}
+
+/*
+ * DFLL-to-I2C controller interface
+ */
+
+/**
+ * dfll_i2c_set_output_enabled - enable/disable I2C PMIC voltage requests
+ * @td: DFLL instance
+ * @enable: whether to enable or disable the I2C voltage requests
+ *
+ * Set the master enable control for I2C control value updates. If disabled,
+ * then I2C control messages are inhibited, regardless of the DFLL mode.
+ */
+static int dfll_i2c_set_output_enabled(struct tegra_dfll *td, bool enable)
+{
+ u32 val;
+
+ val = dfll_i2c_readl(td, DFLL_OUTPUT_CFG);
+
+ if (enable)
+ val |= DFLL_OUTPUT_CFG_I2C_ENABLE;
+ else
+ val &= ~DFLL_OUTPUT_CFG_I2C_ENABLE;
+
+ dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG);
+ dfll_i2c_wmb(td);
+
+ return 0;
+}
+
+/**
+ * dfll_load_lut - load the voltage lookup table
+ * @td: struct tegra_dfll *
+ *
+ * Load the voltage-to-PMIC register value lookup table into the DFLL
+ * IP block memory. Look-up tables can be loaded at any time.
+ */
+static void dfll_load_i2c_lut(struct tegra_dfll *td)
+{
+ int i, lut_index;
+ u32 val;
+
+ for (i = 0; i < MAX_DFLL_VOLTAGES; i++) {
+ if (i < td->lut_min)
+ lut_index = td->lut_min;
+ else if (i > td->lut_max)
+ lut_index = td->lut_max;
+ else
+ lut_index = i;
+
+ val = regulator_list_hardware_vsel(td->vdd_reg,
+ td->i2c_lut[lut_index]);
+ __raw_writel(val, td->lut_base + i * 4);
+ }
+
+ dfll_i2c_wmb(td);
+}
+
+/**
+ * dfll_init_i2c_if - set up the DFLL's DFLL-I2C interface
+ * @td: DFLL instance
+ *
+ * During DFLL driver initialization, program the DFLL-I2C interface
+ * with the PMU slave address, vdd register offset, and transfer mode.
+ * This data is used by the DFLL to automatically construct I2C
+ * voltage-set commands, which are then passed to the DFLL's internal
+ * I2C controller.
+ */
+static void dfll_init_i2c_if(struct tegra_dfll *td)
+{
+ u32 val;
+
+ if (td->i2c_slave_addr > 0x7f) {
+ val = td->i2c_slave_addr << DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_10BIT;
+ val |= DFLL_I2C_CFG_SLAVE_ADDR_10;
+ } else {
+ val = td->i2c_slave_addr << DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_7BIT;
+ }
+ val |= DFLL_I2C_CFG_SIZE_MASK;
+ val |= DFLL_I2C_CFG_ARB_ENABLE;
+ dfll_i2c_writel(td, val, DFLL_I2C_CFG);
+
+ dfll_i2c_writel(td, td->i2c_reg, DFLL_I2C_VDD_REG_ADDR);
+
+ val = DIV_ROUND_UP(td->i2c_clk_rate, td->i2c_fs_rate * 8);
+ BUG_ON(!val || (val > DFLL_I2C_CLK_DIVISOR_MASK));
+ val = (val - 1) << DFLL_I2C_CLK_DIVISOR_FS_SHIFT;
+
+ /* default hs divisor just in case */
+ val |= 1 << DFLL_I2C_CLK_DIVISOR_HS_SHIFT;
+ __raw_writel(val, td->i2c_controller_base + DFLL_I2C_CLK_DIVISOR);
+ dfll_i2c_wmb(td);
+}
+
+/**
+ * dfll_init_out_if - prepare DFLL-to-PMIC interface
+ * @td: DFLL instance
+ *
+ * During DFLL driver initialization or resume from context loss,
+ * disable the I2C command output to the PMIC, set safe voltage and
+ * output limits, and disable and clear limit interrupts.
+ */
+static void dfll_init_out_if(struct tegra_dfll *td)
+{
+ u32 val;
+
+ td->lut_min = 0;
+ td->lut_max = td->i2c_lut_size - 1;
+ td->lut_safe = td->lut_min + 1;
+
+ dfll_i2c_writel(td, 0, DFLL_OUTPUT_CFG);
+ val = (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) |
+ (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) |
+ (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT);
+ dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG);
+ dfll_i2c_wmb(td);
+
+ dfll_writel(td, 0, DFLL_OUTPUT_FORCE);
+ dfll_i2c_writel(td, 0, DFLL_INTR_EN);
+ dfll_i2c_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK,
+ DFLL_INTR_STS);
+
+ dfll_load_i2c_lut(td);
+ dfll_init_i2c_if(td);
+}
+
+/*
+ * Set/get the DFLL's targeted output clock rate
+ */
+
+/**
+ * find_lut_index_for_rate - determine I2C LUT index for given DFLL rate
+ * @td: DFLL instance
+ * @rate: clock rate
+ *
+ * Determines the index of a I2C LUT entry for a voltage that approximately
+ * produces the given DFLL clock rate. This is used when forcing a value
+ * to the integrator during rate changes. Returns -ENOENT if a suitable
+ * LUT index is not found.
+ */
+static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)
+{
+ struct dev_pm_opp *opp;
+ int i, uv;
+
+ opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);
+ if (IS_ERR(opp))
+ return PTR_ERR(opp);
+ uv = dev_pm_opp_get_voltage(opp);
+
+ for (i = 0; i < td->i2c_lut_size; i++) {
+ if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv)
+ return i;
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * dfll_calculate_rate_request - calculate DFLL parameters for a given rate
+ * @td: DFLL instance
+ * @req: DFLL-rate-request structure
+ * @rate: the desired DFLL rate
+ *
+ * Populate the DFLL-rate-request record @req fields with the scale_bits
+ * and mult_bits fields, based on the target input rate. Returns 0 upon
+ * success, or -EINVAL if the requested rate in req->rate is too high
+ * or low for the DFLL to generate.
+ */
+static int dfll_calculate_rate_request(struct tegra_dfll *td,
+ struct dfll_rate_req *req,
+ unsigned long rate)
+{
+ u32 val;
+
+ /*
+ * If requested rate is below the minimum DVCO rate, active the scaler.
+ * In the future the DVCO minimum voltage should be selected based on
+ * chip temperature and the actual minimum rate should be calibrated
+ * at runtime.
+ */
+ req->scale_bits = DFLL_FREQ_REQ_SCALE_MAX - 1;
+ if (rate < td->dvco_rate_min) {
+ int scale;
+
+ scale = DIV_ROUND_CLOSEST(rate / 1000 * DFLL_FREQ_REQ_SCALE_MAX,
+ td->dvco_rate_min / 1000);
+ if (!scale) {
+ dev_err(td->dev, "%s: Rate %lu is too low\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+ req->scale_bits = scale - 1;
+ rate = td->dvco_rate_min;
+ }
+
+ /* Convert requested rate into frequency request and scale settings */
+ val = DVCO_RATE_TO_MULT(rate, td->ref_rate);
+ if (val > FREQ_MAX) {
+ dev_err(td->dev, "%s: Rate %lu is above dfll range\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+ req->mult_bits = val;
+ req->dvco_target_rate = MULT_TO_DVCO_RATE(req->mult_bits, td->ref_rate);
+ req->rate = dfll_scale_dvco_rate(req->scale_bits,
+ req->dvco_target_rate);
+ req->lut_index = find_lut_index_for_rate(td, req->dvco_target_rate);
+ if (req->lut_index < 0)
+ return req->lut_index;
+
+ return 0;
+}
+
+/**
+ * dfll_set_frequency_request - start the frequency change operation
+ * @td: DFLL instance
+ * @req: rate request structure
+ *
+ * Tell the DFLL to try to change its output frequency to the
+ * frequency represented by @req. DFLL must be in closed-loop mode.
+ */
+static void dfll_set_frequency_request(struct tegra_dfll *td,
+ struct dfll_rate_req *req)
+{
+ u32 val = 0;
+ int force_val;
+ int coef = 128; /* FIXME: td->cg_scale? */;
+
+ force_val = (req->lut_index - td->lut_safe) * coef / td->cg;
+ force_val = clamp(force_val, FORCE_MIN, FORCE_MAX);
+
+ val |= req->mult_bits << DFLL_FREQ_REQ_MULT_SHIFT;
+ val |= req->scale_bits << DFLL_FREQ_REQ_SCALE_SHIFT;
+ val |= ((u32)force_val << DFLL_FREQ_REQ_FORCE_SHIFT) &
+ DFLL_FREQ_REQ_FORCE_MASK;
+ val |= DFLL_FREQ_REQ_FREQ_VALID | DFLL_FREQ_REQ_FORCE_ENABLE;
+
+ dfll_writel(td, val, DFLL_FREQ_REQ);
+ dfll_wmb(td);
+}
+
+/**
+ * tegra_dfll_request_rate - set the next rate for the DFLL to tune to
+ * @td: DFLL instance
+ * @rate: clock rate to target
+ *
+ * Convert the requested clock rate @rate into the DFLL control logic
+ * settings. In closed-loop mode, update new settings immediately to
+ * adjust DFLL output rate accordingly. Otherwise, just save them
+ * until the next switch to closed loop. Returns 0 upon success,
+ * -EPERM if the DFLL driver has not yet been initialized, or -EINVAL
+ * if @rate is outside the DFLL's tunable range.
+ */
+static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
+{
+ int ret;
+ struct dfll_rate_req req;
+
+ if (td->mode == DFLL_UNINITIALIZED) {
+ dev_err(td->dev, "%s: Cannot set DFLL rate in %s mode\n",
+ __func__, mode_name[td->mode]);
+ return -EPERM;
+ }
+
+ ret = dfll_calculate_rate_request(td, &req, rate);
+ if (ret)
+ return ret;
+
+ td->last_unrounded_rate = rate;
+ td->last_req = req;
+
+ if (td->mode == DFLL_CLOSED_LOOP)
+ dfll_set_frequency_request(td, &td->last_req);
+
+ return 0;
+}
+
+/*
+ * DFLL enable/disable & open-loop <-> closed-loop transitions
+ */
+
+/**
+ * dfll_disable - switch from open-loop mode to disabled mode
+ * @td: DFLL instance
+ *
+ * Switch from OPEN_LOOP state to DISABLED state. Returns 0 upon success
+ * or -EPERM if the DFLL is not currently in open-loop mode.
+ */
+static int dfll_disable(struct tegra_dfll *td)
+{
+ if (td->mode != DFLL_OPEN_LOOP) {
+ dev_err(td->dev, "cannot disable DFLL in %s mode\n",
+ mode_name[td->mode]);
+ return -EINVAL;
+ }
+
+ dfll_set_mode(td, DFLL_DISABLED);
+ pm_runtime_put_sync(td->dev);
+
+ return 0;
+}
+
+/**
+ * dfll_enable - switch a disabled DFLL to open-loop mode
+ * @td: DFLL instance
+ *
+ * Switch from DISABLED state to OPEN_LOOP state. Returns 0 upon success
+ * or -EPERM if the DFLL is not currently disabled.
+ */
+static int dfll_enable(struct tegra_dfll *td)
+{
+ if (td->mode != DFLL_DISABLED) {
+ dev_err(td->dev, "cannot enable DFLL in %s mode\n",
+ mode_name[td->mode]);
+ return -EPERM;
+ }
+
+ pm_runtime_get_sync(td->dev);
+ dfll_set_mode(td, DFLL_OPEN_LOOP);
+
+ return 0;
+}
+
+/**
+ * dfll_set_open_loop_config - prepare to switch to open-loop mode
+ * @td: DFLL instance
+ *
+ * Prepare to switch the DFLL to open-loop mode. This switches the
+ * DFLL to the low-voltage tuning range, ensures that I2C output
+ * forcing is disabled, and disables the output clock rate scaler.
+ * The DFLL's low-voltage tuning range parameters must be
+ * characterized to keep the downstream device stable at any DVCO
+ * input voltage. No return value.
+ */
+static void dfll_set_open_loop_config(struct tegra_dfll *td)
+{
+ u32 val;
+
+ /* always tune low (safe) in open loop */
+ if (td->tune_range != DFLL_TUNE_LOW)
+ dfll_tune_low(td);
+
+ val = dfll_readl(td, DFLL_FREQ_REQ);
+ val |= DFLL_FREQ_REQ_SCALE_MASK;
+ val &= ~DFLL_FREQ_REQ_FORCE_ENABLE;
+ dfll_writel(td, val, DFLL_FREQ_REQ);
+ dfll_wmb(td);
+}
+
+/**
+ * tegra_dfll_lock - switch from open-loop to closed-loop mode
+ * @td: DFLL instance
+ *
+ * Switch from OPEN_LOOP state to CLOSED_LOOP state. Returns 0 upon success,
+ * -EINVAL if the DFLL's target rate hasn't been set yet, or -EPERM if the
+ * DFLL is not currently in open-loop mode.
+ */
+static int dfll_lock(struct tegra_dfll *td)
+{
+ struct dfll_rate_req *req = &td->last_req;
+
+ switch (td->mode) {
+ case DFLL_CLOSED_LOOP:
+ return 0;
+
+ case DFLL_OPEN_LOOP:
+ if (req->rate == 0) {
+ dev_err(td->dev, "%s: Cannot lock DFLL at rate 0\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dfll_i2c_set_output_enabled(td, true);
+ dfll_set_mode(td, DFLL_CLOSED_LOOP);
+ dfll_set_frequency_request(td, req);
+ return 0;
+
+ default:
+ BUG_ON(td->mode > DFLL_CLOSED_LOOP);
+ dev_err(td->dev, "%s: Cannot lock DFLL in %s mode\n",
+ __func__, mode_name[td->mode]);
+ return -EPERM;
+ }
+}
+
+/**
+ * tegra_dfll_unlock - switch from closed-loop to open-loop mode
+ * @td: DFLL instance
+ *
+ * Switch from CLOSED_LOOP state to OPEN_LOOP state. Returns 0 upon success,
+ * or -EPERM if the DFLL is not currently in open-loop mode.
+ */
+static int dfll_unlock(struct tegra_dfll *td)
+{
+ switch (td->mode) {
+ case DFLL_CLOSED_LOOP:
+ dfll_set_open_loop_config(td);
+ dfll_set_mode(td, DFLL_OPEN_LOOP);
+ dfll_i2c_set_output_enabled(td, false);
+ return 0;
+
+ case DFLL_OPEN_LOOP:
+ return 0;
+
+ default:
+ BUG_ON(td->mode > DFLL_CLOSED_LOOP);
+ dev_err(td->dev, "%s: Cannot unlock DFLL in %s mode\n",
+ __func__, mode_name[td->mode]);
+ return -EPERM;
+ }
+}
+
+/*
+ * Clock framework integration
+ *
+ * When the DFLL is being controlled by the CCF, always enter closed loop
+ * mode when the clk is enabled. This requires that a DFLL rate request
+ * has been set beforehand, which implies that a clk_set_rate() call is
+ * always required before a clk_enable().
+ */
+
+static int dfll_clk_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_dfll *td = clk_hw_to_dfll(hw);
+
+ return dfll_is_running(td);
+}
+
+static int dfll_clk_enable(struct clk_hw *hw)
+{
+ struct tegra_dfll *td = clk_hw_to_dfll(hw);
+ int ret;
+
+ ret = dfll_enable(td);
+ if (ret)
+ return ret;
+
+ ret = dfll_lock(td);
+ if (ret)
+ dfll_disable(td);
+
+ return ret;
+}
+
+static void dfll_clk_disable(struct clk_hw *hw)
+{
+ struct tegra_dfll *td = clk_hw_to_dfll(hw);
+ int ret;
+
+ ret = dfll_unlock(td);
+ if (!ret)
+ dfll_disable(td);
+}
+
+static unsigned long dfll_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tegra_dfll *td = clk_hw_to_dfll(hw);
+
+ return td->last_unrounded_rate;
+}
+
+static long dfll_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct tegra_dfll *td = clk_hw_to_dfll(hw);
+ struct dfll_rate_req req;
+ int ret;
+
+ ret = dfll_calculate_rate_request(td, &req, rate);
+ if (ret)
+ return ret;
+
+ /*
+ * Don't return the rounded rate, since it doesn't really matter as
+ * the output rate will be voltage controlled anyway, and cpufreq
+ * freaks out if any rounding happens.
+ */
+ return rate;
+}
+
+static int dfll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_dfll *td = clk_hw_to_dfll(hw);
+
+ return dfll_request_rate(td, rate);
+}
+
+static const struct clk_ops dfll_clk_ops = {
+ .is_enabled = dfll_clk_is_enabled,
+ .enable = dfll_clk_enable,
+ .disable = dfll_clk_disable,
+ .recalc_rate = dfll_clk_recalc_rate,
+ .round_rate = dfll_clk_round_rate,
+ .set_rate = dfll_clk_set_rate,
+};
+
+static struct clk_init_data dfll_clk_init_data = {
+ .flags = CLK_IS_ROOT,
+ .ops = &dfll_clk_ops,
+ .num_parents = 0,
+};
+
+/**
+ * dfll_register_clk - register the DFLL output clock with the clock framework
+ * @td: DFLL instance
+ *
+ * Register the DFLL's output clock with the Linux clock framework and register
+ * the DFLL driver as an OF clock provider. Returns 0 upon success or -EINVAL
+ * or -ENOMEM upon failure.
+ */
+static int dfll_register_clk(struct tegra_dfll *td)
+{
+ int ret;
+
+ dfll_clk_init_data.name = td->output_clock_name;
+ td->dfll_clk_hw.init = &dfll_clk_init_data;
+
+ td->dfll_clk = clk_register(td->dev, &td->dfll_clk_hw);
+ if (IS_ERR(td->dfll_clk)) {
+ dev_err(td->dev, "DFLL clock registration error\n");
+ return -EINVAL;
+ }
+
+ ret = of_clk_add_provider(td->dev->of_node, of_clk_src_simple_get,
+ td->dfll_clk);
+ if (ret) {
+ dev_err(td->dev, "of_clk_add_provider() failed\n");
+
+ clk_unregister(td->dfll_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * dfll_unregister_clk - unregister the DFLL output clock
+ * @td: DFLL instance
+ *
+ * Unregister the DFLL's output clock from the Linux clock framework
+ * and from clkdev. No return value.
+ */
+static void dfll_unregister_clk(struct tegra_dfll *td)
+{
+ of_clk_del_provider(td->dev->of_node);
+ clk_unregister(td->dfll_clk);
+ td->dfll_clk = NULL;
+}
+
+/*
+ * Debugfs interface
+ */
+
+#ifdef CONFIG_DEBUG_FS
+
+static int attr_enable_get(void *data, u64 *val)
+{
+ struct tegra_dfll *td = data;
+
+ *val = dfll_is_running(td);
+
+ return 0;
+}
+static int attr_enable_set(void *data, u64 val)
+{
+ struct tegra_dfll *td = data;
+
+ return val ? dfll_enable(td) : dfll_disable(td);
+}
+DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set,
+ "%llu\n");
+
+static int attr_lock_get(void *data, u64 *val)
+{
+ struct tegra_dfll *td = data;
+
+ *val = (td->mode == DFLL_CLOSED_LOOP);
+
+ return 0;
+}
+static int attr_lock_set(void *data, u64 val)
+{
+ struct tegra_dfll *td = data;
+
+ return val ? dfll_lock(td) : dfll_unlock(td);
+}
+DEFINE_SIMPLE_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set,
+ "%llu\n");
+
+static int attr_rate_get(void *data, u64 *val)
+{
+ struct tegra_dfll *td = data;
+
+ *val = dfll_read_monitor_rate(td);
+
+ return 0;
+}
+
+static int attr_rate_set(void *data, u64 val)
+{
+ struct tegra_dfll *td = data;
+
+ return dfll_request_rate(td, val);
+}
+DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n");
+
+static int attr_registers_show(struct seq_file *s, void *data)
+{
+ u32 val, offs;
+ struct tegra_dfll *td = s->private;
+
+ seq_puts(s, "CONTROL REGISTERS:\n");
+ for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) {
+ if (offs == DFLL_OUTPUT_CFG)
+ val = dfll_i2c_readl(td, offs);
+ else
+ val = dfll_readl(td, offs);
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs, val);
+ }
+
+ seq_puts(s, "\nI2C and INTR REGISTERS:\n");
+ for (offs = DFLL_I2C_CFG; offs <= DFLL_I2C_STS; offs += 4)
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
+ dfll_i2c_readl(td, offs));
+ for (offs = DFLL_INTR_STS; offs <= DFLL_INTR_EN; offs += 4)
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
+ dfll_i2c_readl(td, offs));
+
+ seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n");
+ offs = DFLL_I2C_CLK_DIVISOR;
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
+ __raw_readl(td->i2c_controller_base + offs));
+
+ seq_puts(s, "\nLUT:\n");
+ for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4)
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
+ __raw_readl(td->lut_base + offs));
+
+ return 0;
+}
+
+static int attr_registers_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, attr_registers_show, inode->i_private);
+}
+
+static const struct file_operations attr_registers_fops = {
+ .open = attr_registers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dfll_debug_init(struct tegra_dfll *td)
+{
+ int ret;
+
+ if (!td || (td->mode == DFLL_UNINITIALIZED))
+ return 0;
+
+ td->debugfs_dir = debugfs_create_dir("tegra_dfll_fcpu", NULL);
+ if (!td->debugfs_dir)
+ return -ENOMEM;
+
+ ret = -ENOMEM;
+
+ if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR,
+ td->debugfs_dir, td, &enable_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("lock", S_IRUGO,
+ td->debugfs_dir, td, &lock_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("rate", S_IRUGO,
+ td->debugfs_dir, td, &rate_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("registers", S_IRUGO,
+ td->debugfs_dir, td, &attr_registers_fops))
+ goto err_out;
+
+ return 0;
+
+err_out:
+ debugfs_remove_recursive(td->debugfs_dir);
+ return ret;
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+/*
+ * DFLL initialization
+ */
+
+/**
+ * dfll_set_default_params - program non-output related DFLL parameters
+ * @td: DFLL instance
+ *
+ * During DFLL driver initialization or resume from context loss,
+ * program parameters for the closed loop integrator, DVCO tuning,
+ * voltage droop control and monitor control.
+ */
+static void dfll_set_default_params(struct tegra_dfll *td)
+{
+ u32 val;
+
+ val = DIV_ROUND_UP(td->ref_rate, td->sample_rate * 32);
+ BUG_ON(val > DFLL_CONFIG_DIV_MASK);
+ dfll_writel(td, val, DFLL_CONFIG);
+
+ val = (td->force_mode << DFLL_PARAMS_FORCE_MODE_SHIFT) |
+ (td->cf << DFLL_PARAMS_CF_PARAM_SHIFT) |
+ (td->ci << DFLL_PARAMS_CI_PARAM_SHIFT) |
+ (td->cg << DFLL_PARAMS_CG_PARAM_SHIFT) |
+ (td->cg_scale ? DFLL_PARAMS_CG_SCALE : 0);
+ dfll_writel(td, val, DFLL_PARAMS);
+
+ dfll_tune_low(td);
+ dfll_writel(td, td->droop_ctrl, DFLL_DROOP_CTRL);
+ dfll_writel(td, DFLL_MONITOR_CTRL_FREQ, DFLL_MONITOR_CTRL);
+}
+
+/**
+ * dfll_init_clks - clk_get() the DFLL source clocks
+ * @td: DFLL instance
+ *
+ * Call clk_get() on the DFLL source clocks and save the pointers for later
+ * use. Returns 0 upon success or error (see devm_clk_get) if one or more
+ * of the clocks couldn't be looked up.
+ */
+static int dfll_init_clks(struct tegra_dfll *td)
+{
+ td->ref_clk = devm_clk_get(td->dev, "ref");
+ if (IS_ERR(td->ref_clk)) {
+ dev_err(td->dev, "missing ref clock\n");
+ return PTR_ERR(td->ref_clk);
+ }
+
+ td->soc_clk = devm_clk_get(td->dev, "soc");
+ if (IS_ERR(td->soc_clk)) {
+ dev_err(td->dev, "missing soc clock\n");
+ return PTR_ERR(td->soc_clk);
+ }
+
+ td->i2c_clk = devm_clk_get(td->dev, "i2c");
+ if (IS_ERR(td->i2c_clk)) {
+ dev_err(td->dev, "missing i2c clock\n");
+ return PTR_ERR(td->i2c_clk);
+ }
+ td->i2c_clk_rate = clk_get_rate(td->i2c_clk);
+
+ return 0;
+}
+
+/**
+ * dfll_init - Prepare the DFLL IP block for use
+ * @td: DFLL instance
+ *
+ * Do everything necessary to prepare the DFLL IP block for use. The
+ * DFLL will be left in DISABLED state. Called by dfll_probe().
+ * Returns 0 upon success, or passes along the error from whatever
+ * function returned it.
+ */
+static int dfll_init(struct tegra_dfll *td)
+{
+ int ret;
+
+ td->ref_rate = clk_get_rate(td->ref_clk);
+ if (td->ref_rate != REF_CLOCK_RATE) {
+ dev_err(td->dev, "unexpected ref clk rate %lu, expecting %lu",
+ td->ref_rate, REF_CLOCK_RATE);
+ return -EINVAL;
+ }
+
+ reset_control_deassert(td->dvco_rst);
+
+ ret = clk_prepare(td->ref_clk);
+ if (ret) {
+ dev_err(td->dev, "failed to prepare ref_clk\n");
+ return ret;
+ }
+
+ ret = clk_prepare(td->soc_clk);
+ if (ret) {
+ dev_err(td->dev, "failed to prepare soc_clk\n");
+ goto di_err1;
+ }
+
+ ret = clk_prepare(td->i2c_clk);
+ if (ret) {
+ dev_err(td->dev, "failed to prepare i2c_clk\n");
+ goto di_err2;
+ }
+
+ td->last_unrounded_rate = 0;
+
+ pm_runtime_enable(td->dev);
+ pm_runtime_get_sync(td->dev);
+
+ dfll_set_mode(td, DFLL_DISABLED);
+ dfll_set_default_params(td);
+
+ if (td->soc->init_clock_trimmers)
+ td->soc->init_clock_trimmers();
+
+ dfll_set_open_loop_config(td);
+
+ dfll_init_out_if(td);
+
+ pm_runtime_put_sync(td->dev);
+
+ return 0;
+
+di_err2:
+ clk_unprepare(td->soc_clk);
+di_err1:
+ clk_unprepare(td->ref_clk);
+
+ reset_control_assert(td->dvco_rst);
+
+ return ret;
+}
+
+/*
+ * DT data fetch
+ */
+
+/*
+ * Find a PMIC voltage register-to-voltage mapping for the given voltage.
+ * An exact voltage match is required.
+ */
+static int find_vdd_map_entry_exact(struct tegra_dfll *td, int uV)
+{
+ int i, n_voltages, reg_uV;
+
+ n_voltages = regulator_count_voltages(td->vdd_reg);
+ for (i = 0; i < n_voltages; i++) {
+ reg_uV = regulator_list_voltage(td->vdd_reg, i);
+ if (reg_uV < 0)
+ break;
+
+ if (uV == reg_uV)
+ return i;
+ }
+
+ dev_err(td->dev, "no voltage map entry for %d uV\n", uV);
+ return -EINVAL;
+}
+
+/*
+ * Find a PMIC voltage register-to-voltage mapping for the given voltage,
+ * rounding up to the closest supported voltage.
+ * */
+static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV)
+{
+ int i, n_voltages, reg_uV;
+
+ n_voltages = regulator_count_voltages(td->vdd_reg);
+ for (i = 0; i < n_voltages; i++) {
+ reg_uV = regulator_list_voltage(td->vdd_reg, i);
+ if (reg_uV < 0)
+ break;
+
+ if (uV <= reg_uV)
+ return i;
+ }
+
+ dev_err(td->dev, "no voltage map entry rounding to %d uV\n", uV);
+ return -EINVAL;
+}
+
+/**
+ * dfll_build_i2c_lut - build the I2C voltage register lookup table
+ * @td: DFLL instance
+ *
+ * The DFLL hardware has 33 bytes of look-up table RAM that must be filled with
+ * PMIC voltage register values that span the entire DFLL operating range.
+ * This function builds the look-up table based on the OPP table provided by
+ * the soc-specific platform driver (td->soc->opp_dev) and the PMIC
+ * register-to-voltage mapping queried from the regulator framework.
+ *
+ * On success, fills in td->i2c_lut and returns 0, or -err on failure.
+ */
+static int dfll_build_i2c_lut(struct tegra_dfll *td)
+{
+ int ret = -EINVAL;
+ int j, v, v_max, v_opp;
+ int selector;
+ unsigned long rate;
+ struct dev_pm_opp *opp;
+ int lut;
+
+ rcu_read_lock();
+
+ rate = ULONG_MAX;
+ opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate);
+ if (IS_ERR(opp)) {
+ dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n");
+ goto out;
+ }
+ v_max = dev_pm_opp_get_voltage(opp);
+
+ v = td->soc->min_millivolts * 1000;
+ lut = find_vdd_map_entry_exact(td, v);
+ if (lut < 0)
+ goto out;
+ td->i2c_lut[0] = lut;
+
+ for (j = 1, rate = 0; ; rate++) {
+ opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);
+ if (IS_ERR(opp))
+ break;
+ v_opp = dev_pm_opp_get_voltage(opp);
+
+ if (v_opp <= td->soc->min_millivolts * 1000)
+ td->dvco_rate_min = dev_pm_opp_get_freq(opp);
+
+ for (;;) {
+ v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j));
+ if (v >= v_opp)
+ break;
+
+ selector = find_vdd_map_entry_min(td, v);
+ if (selector < 0)
+ goto out;
+ if (selector != td->i2c_lut[j - 1])
+ td->i2c_lut[j++] = selector;
+ }
+
+ v = (j == MAX_DFLL_VOLTAGES - 1) ? v_max : v_opp;
+ selector = find_vdd_map_entry_exact(td, v);
+ if (selector < 0)
+ goto out;
+ if (selector != td->i2c_lut[j - 1])
+ td->i2c_lut[j++] = selector;
+
+ if (v >= v_max)
+ break;
+ }
+ td->i2c_lut_size = j;
+
+ if (!td->dvco_rate_min)
+ dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n",
+ td->soc->min_millivolts);
+ else
+ ret = 0;
+
+out:
+ rcu_read_unlock();
+
+ return ret;
+}
+
+/**
+ * read_dt_param - helper function for reading required parameters from the DT
+ * @td: DFLL instance
+ * @param: DT property name
+ * @dest: output pointer for the value read
+ *
+ * Read a required numeric parameter from the DFLL device node, or complain
+ * if the property doesn't exist. Returns a boolean indicating success for
+ * easy chaining of multiple calls to this function.
+ */
+static bool read_dt_param(struct tegra_dfll *td, const char *param, u32 *dest)
+{
+ int err = of_property_read_u32(td->dev->of_node, param, dest);
+
+ if (err < 0) {
+ dev_err(td->dev, "failed to read DT parameter %s: %d\n",
+ param, err);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * dfll_fetch_i2c_params - query PMIC I2C params from DT & regulator subsystem
+ * @td: DFLL instance
+ *
+ * Read all the parameters required for operation in I2C mode. The parameters
+ * can originate from the device tree or the regulator subsystem.
+ * Returns 0 on success or -err on failure.
+ */
+static int dfll_fetch_i2c_params(struct tegra_dfll *td)
+{
+ struct regmap *regmap;
+ struct device *i2c_dev;
+ struct i2c_client *i2c_client;
+ int vsel_reg, vsel_mask;
+ int ret;
+
+ if (!read_dt_param(td, "nvidia,i2c-fs-rate", &td->i2c_fs_rate))
+ return -EINVAL;
+
+ regmap = regulator_get_regmap(td->vdd_reg);
+ i2c_dev = regmap_get_device(regmap);
+ i2c_client = to_i2c_client(i2c_dev);
+
+ td->i2c_slave_addr = i2c_client->addr;
+
+ ret = regulator_get_hardware_vsel_register(td->vdd_reg,
+ &vsel_reg,
+ &vsel_mask);
+ if (ret < 0) {
+ dev_err(td->dev,
+ "regulator unsuitable for DFLL I2C operation\n");
+ return -EINVAL;
+ }
+ td->i2c_reg = vsel_reg;
+
+ ret = dfll_build_i2c_lut(td);
+ if (ret) {
+ dev_err(td->dev, "couldn't build I2C LUT\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * dfll_fetch_common_params - read DFLL parameters from the device tree
+ * @td: DFLL instance
+ *
+ * Read all the DT parameters that are common to both I2C and PWM operation.
+ * Returns 0 on success or -EINVAL on any failure.
+ */
+static int dfll_fetch_common_params(struct tegra_dfll *td)
+{
+ bool ok = true;
+
+ ok &= read_dt_param(td, "nvidia,droop-ctrl", &td->droop_ctrl);
+ ok &= read_dt_param(td, "nvidia,sample-rate", &td->sample_rate);
+ ok &= read_dt_param(td, "nvidia,force-mode", &td->force_mode);
+ ok &= read_dt_param(td, "nvidia,cf", &td->cf);
+ ok &= read_dt_param(td, "nvidia,ci", &td->ci);
+ ok &= read_dt_param(td, "nvidia,cg", &td->cg);
+ td->cg_scale = of_property_read_bool(td->dev->of_node,
+ "nvidia,cg-scale");
+
+ if (of_property_read_string(td->dev->of_node, "clock-output-names",
+ &td->output_clock_name)) {
+ dev_err(td->dev, "missing clock-output-names property\n");
+ ok = false;
+ }
+
+ return ok ? 0 : -EINVAL;
+}
+
+/*
+ * API exported to per-SoC platform drivers
+ */
+
+/**
+ * tegra_dfll_register - probe a Tegra DFLL device
+ * @pdev: DFLL platform_device *
+ * @soc: Per-SoC integration and characterization data for this DFLL instance
+ *
+ * Probe and initialize a DFLL device instance. Intended to be called
+ * by a SoC-specific shim driver that passes in per-SoC integration
+ * and configuration data via @soc. Returns 0 on success or -err on failure.
+ */
+int tegra_dfll_register(struct platform_device *pdev,
+ struct tegra_dfll_soc_data *soc)
+{
+ struct resource *mem;
+ struct tegra_dfll *td;
+ int ret;
+
+ if (!soc) {
+ dev_err(&pdev->dev, "no tegra_dfll_soc_data provided\n");
+ return -EINVAL;
+ }
+
+ td = devm_kzalloc(&pdev->dev, sizeof(*td), GFP_KERNEL);
+ if (!td)
+ return -ENOMEM;
+ td->dev = &pdev->dev;
+ platform_set_drvdata(pdev, td);
+
+ td->soc = soc;
+
+ td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu");
+ if (IS_ERR(td->vdd_reg)) {
+ dev_err(td->dev, "couldn't get vdd_cpu regulator\n");
+ return PTR_ERR(td->vdd_reg);
+ }
+
+ td->dvco_rst = devm_reset_control_get(td->dev, "dvco");
+ if (IS_ERR(td->dvco_rst)) {
+ dev_err(td->dev, "couldn't get dvco reset\n");
+ return PTR_ERR(td->dvco_rst);
+ }
+
+ ret = dfll_fetch_common_params(td);
+ if (ret) {
+ dev_err(td->dev, "couldn't parse device tree parameters\n");
+ return ret;
+ }
+
+ ret = dfll_fetch_i2c_params(td);
+ if (ret)
+ return ret;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(td->dev, "no control register resource\n");
+ return -ENODEV;
+ }
+
+ td->base = devm_ioremap(td->dev, mem->start, resource_size(mem));
+ if (!td->base) {
+ dev_err(td->dev, "couldn't ioremap DFLL control registers\n");
+ return -ENODEV;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!mem) {
+ dev_err(td->dev, "no i2c_base resource\n");
+ return -ENODEV;
+ }
+
+ td->i2c_base = devm_ioremap(td->dev, mem->start, resource_size(mem));
+ if (!td->i2c_base) {
+ dev_err(td->dev, "couldn't ioremap i2c_base resource\n");
+ return -ENODEV;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!mem) {
+ dev_err(td->dev, "no i2c_controller_base resource\n");
+ return -ENODEV;
+ }
+
+ td->i2c_controller_base = devm_ioremap(td->dev, mem->start,
+ resource_size(mem));
+ if (!td->i2c_controller_base) {
+ dev_err(td->dev,
+ "couldn't ioremap i2c_controller_base resource\n");
+ return -ENODEV;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ if (!mem) {
+ dev_err(td->dev, "no lut_base resource\n");
+ return -ENODEV;
+ }
+
+ td->lut_base = devm_ioremap(td->dev, mem->start, resource_size(mem));
+ if (!td->lut_base) {
+ dev_err(td->dev,
+ "couldn't ioremap lut_base resource\n");
+ return -ENODEV;
+ }
+
+ ret = dfll_init_clks(td);
+ if (ret) {
+ dev_err(&pdev->dev, "DFLL clock init error\n");
+ return ret;
+ }
+
+ /* Enable the clocks and set the device up */
+ ret = dfll_init(td);
+ if (ret)
+ return ret;
+
+ ret = dfll_register_clk(td);
+ if (ret) {
+ dev_err(&pdev->dev, "DFLL clk registration failed\n");
+ return ret;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ dfll_debug_init(td);
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dfll_register);
+
+/**
+ * tegra_dfll_unregister - release all of the DFLL driver resources for a device
+ * @pdev: DFLL platform_device *
+ *
+ * Unbind this driver from the DFLL hardware device represented by
+ * @pdev. The DFLL must be disabled for this to succeed. Returns 0
+ * upon success or -EBUSY if the DFLL is still active.
+ */
+int tegra_dfll_unregister(struct platform_device *pdev)
+{
+ struct tegra_dfll *td = platform_get_drvdata(pdev);
+
+ /* Try to prevent removal while the DFLL is active */
+ if (td->mode != DFLL_DISABLED) {
+ dev_err(&pdev->dev,
+ "must disable DFLL before removing driver\n");
+ return -EBUSY;
+ }
+
+ debugfs_remove_recursive(td->debugfs_dir);
+
+ dfll_unregister_clk(td);
+ pm_runtime_disable(&pdev->dev);
+
+ clk_unprepare(td->ref_clk);
+ clk_unprepare(td->soc_clk);
+ clk_unprepare(td->i2c_clk);
+
+ reset_control_assert(td->dvco_rst);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dfll_unregister);
diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
new file mode 100644
index 000000000000..2e4c0772a5dc
--- /dev/null
+++ b/drivers/clk/tegra/clk-dfll.h
@@ -0,0 +1,54 @@
+/*
+ * clk-dfll.h - prototypes and macros for the Tegra DFLL clocksource driver
+ * Copyright (C) 2013 NVIDIA Corporation. All rights reserved.
+ *
+ * Aleksandr Frid <afrid@nvidia.com>
+ * Paul Walmsley <pwalmsley@nvidia.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __DRIVERS_CLK_TEGRA_CLK_DFLL_H
+#define __DRIVERS_CLK_TEGRA_CLK_DFLL_H
+
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+
+/**
+ * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver
+ * @opp_dev: struct device * that holds the OPP table for the DFLL
+ * @min_millivolts: minimum voltage (in mV) that the DFLL can operate
+ * @tune0_low: DFLL tuning register 0 (low voltage range)
+ * @tune0_high: DFLL tuning register 0 (high voltage range)
+ * @tune1: DFLL tuning register 1
+ * @assert_dvco_reset: fn ptr to place the DVCO in reset
+ * @deassert_dvco_reset: fn ptr to release the DVCO reset
+ * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage
+ * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage
+ */
+struct tegra_dfll_soc_data {
+ struct device *dev;
+ unsigned int min_millivolts;
+ u32 tune0_low;
+ u32 tune0_high;
+ u32 tune1;
+ void (*init_clock_trimmers)(void);
+ void (*set_clock_trimmers_high)(void);
+ void (*set_clock_trimmers_low)(void);
+};
+
+int tegra_dfll_register(struct platform_device *pdev,
+ struct tegra_dfll_soc_data *soc);
+int tegra_dfll_unregister(struct platform_device *pdev);
+int tegra_dfll_runtime_suspend(struct device *dev);
+int tegra_dfll_runtime_resume(struct device *dev);
+
+#endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 59a5714dfe18..48c83efda4cf 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -19,7 +19,6 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
-#include <linux/clk.h>
#include "clk.h"
diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c
index 7649685c86bc..138a94b99b5b 100644
--- a/drivers/clk/tegra/clk-emc.c
+++ b/drivers/clk/tegra/clk-emc.c
@@ -103,7 +103,7 @@ static unsigned long emc_recalc_rate(struct clk_hw *hw,
* CCF wrongly assumes that the parent won't change during set_rate,
* so get the parent rate explicitly.
*/
- parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+ parent_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
val = readl(tegra->clk_regs + CLK_SOURCE_EMC);
div = val & CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK;
@@ -116,11 +116,7 @@ static unsigned long emc_recalc_rate(struct clk_hw *hw,
* safer since things have EMC rate floors. Also don't touch parent_rate
* since we don't want the CCF to play with our parent clocks.
*/
-static long emc_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_hw)
+static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
struct tegra_clk_emc *tegra;
u8 ram_code = tegra_read_ram_code();
@@ -135,22 +131,28 @@ static long emc_determine_rate(struct clk_hw *hw, unsigned long rate,
timing = tegra->timings + i;
- if (timing->rate > max_rate) {
+ if (timing->rate > req->max_rate) {
i = min(i, 1);
- return tegra->timings[i - 1].rate;
+ req->rate = tegra->timings[i - 1].rate;
+ return 0;
}
- if (timing->rate < min_rate)
+ if (timing->rate < req->min_rate)
continue;
- if (timing->rate >= rate)
- return timing->rate;
+ if (timing->rate >= req->rate) {
+ req->rate = timing->rate;
+ return 0;
+ }
}
- if (timing)
- return timing->rate;
+ if (timing) {
+ req->rate = timing->rate;
+ return 0;
+ }
- return __clk_get_rate(hw->clk);
+ req->rate = clk_hw_get_rate(hw);
+ return 0;
}
static u8 emc_get_parent(struct clk_hw *hw)
@@ -312,7 +314,7 @@ static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
tegra = container_of(hw, struct tegra_clk_emc, hw);
- if (__clk_get_rate(hw->clk) == rate)
+ if (clk_hw_get_rate(hw) == rate)
return 0;
/*
@@ -525,8 +527,8 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
if (IS_ERR(clk))
return clk;
- tegra->prev_parent = clk_get_parent_by_index(
- tegra->hw.clk, emc_get_parent(&tegra->hw));
+ tegra->prev_parent = clk_hw_get_parent_by_index(
+ &tegra->hw, emc_get_parent(&tegra->hw))->clk;
tegra->changing_timing = false;
/* Allow debugging tools to see the EMC clock */
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
index 0aa8830ae7cc..d28d6e95020f 100644
--- a/drivers/clk/tegra/clk-periph-gate.c
+++ b/drivers/clk/tegra/clk-periph-gate.c
@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index d84ae49d0e05..ec5b6113b012 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/export.h>
#include <linux/slab.h>
diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
index 3598987a451d..257cae0c1488 100644
--- a/drivers/clk/tegra/clk-pll-out.c
+++ b/drivers/clk/tegra/clk-pll-out.c
@@ -20,7 +20,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
-#include <linux/clk.h>
#include "clk.h"
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 05c6d08a6695..d6d4ecb88e94 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -18,8 +18,8 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/clk-provider.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include "clk.h"
@@ -264,7 +264,7 @@ static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll)
}
pr_err("%s: Timed out waiting for pll %s lock\n", __func__,
- __clk_get_name(pll->hw.clk));
+ clk_hw_get_name(&pll->hw));
return -1;
}
@@ -595,7 +595,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
if (pll->params->flags & TEGRA_PLL_FIXED) {
if (rate != pll->params->fixed_rate) {
pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
- __func__, __clk_get_name(hw->clk),
+ __func__, clk_hw_get_name(hw),
pll->params->fixed_rate, rate);
return -EINVAL;
}
@@ -605,7 +605,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
_calc_rate(hw, &cfg, rate, parent_rate)) {
pr_err("%s: Failed to set %s rate %lu\n", __func__,
- __clk_get_name(hw->clk), rate);
+ clk_hw_get_name(hw), rate);
WARN_ON(1);
return -EINVAL;
}
@@ -634,7 +634,7 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
/* PLLM is used for memory; we do not change rate */
if (pll->params->flags & TEGRA_PLLM)
- return __clk_get_rate(hw->clk);
+ return clk_hw_get_rate(hw);
if (_get_table_rate(hw, &cfg, rate, *prate) &&
_calc_rate(hw, &cfg, rate, *prate))
@@ -663,7 +663,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
if (_get_table_rate(hw, &sel, pll->params->fixed_rate,
parent_rate)) {
pr_err("Clock %s has unknown fixed frequency\n",
- __clk_get_name(hw->clk));
+ clk_hw_get_name(hw));
BUG();
}
return pll->params->fixed_rate;
@@ -1577,7 +1577,7 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
if (!pll_params->pdiv_tohw)
return ERR_PTR(-EINVAL);
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_get_rate(parent);
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
@@ -1674,7 +1674,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
return ERR_PTR(-EINVAL);
}
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_get_rate(parent);
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
@@ -1715,7 +1715,7 @@ struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name,
return ERR_PTR(-EINVAL);
}
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_get_rate(parent);
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
@@ -1848,7 +1848,7 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
val &= ~PLLSS_REF_SRC_SEL_MASK;
pll_writel_base(val, pll);
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_get_rate(parent);
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
index 2fd924d38606..131d1b5085e2 100644
--- a/drivers/clk/tegra/clk-super.c
+++ b/drivers/clk/tegra/clk-super.c
@@ -20,7 +20,6 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
-#include <linux/clk.h>
#include "clk.h"
diff --git a/drivers/clk/tegra/clk-tegra-audio.c b/drivers/clk/tegra/clk-tegra-audio.c
index 5c38aab2c5b8..11e3ad7ad7a3 100644
--- a/drivers/clk/tegra/clk-tegra-audio.c
+++ b/drivers/clk/tegra/clk-tegra-audio.c
@@ -15,7 +15,6 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c
index 605676d368eb..da0b5941c89f 100644
--- a/drivers/clk/tegra/clk-tegra-fixed.c
+++ b/drivers/clk/tegra/clk-tegra-fixed.c
@@ -15,7 +15,6 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 46af9244ba74..cb6ab830941d 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -15,7 +15,6 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
diff --git a/drivers/clk/tegra/clk-tegra-pmc.c b/drivers/clk/tegra/clk-tegra-pmc.c
index 08b21c1ee867..91377abfefa1 100644
--- a/drivers/clk/tegra/clk-tegra-pmc.c
+++ b/drivers/clk/tegra/clk-tegra-pmc.c
@@ -15,7 +15,6 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index feb3201c85ce..5b1d723932c5 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -15,7 +15,6 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -44,7 +43,9 @@ static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
"pll_p", "pll_p_out4", "unused",
- "unused", "pll_x" };
+ "unused", "pll_x", "unused", "unused",
+ "unused", "unused", "unused", "unused",
+ "dfllCPU_out" };
static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
"pll_p", "pll_p_out4", "unused",
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 8237d16b4075..db5871519bf5 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -15,9 +15,7 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/delay.h>
diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
new file mode 100644
index 000000000000..61253330c12b
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
@@ -0,0 +1,166 @@
+/*
+ * Tegra124 DFLL FCPU clock source driver
+ *
+ * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved.
+ *
+ * Aleksandr Frid <afrid@nvidia.com>
+ * Paul Walmsley <pwalmsley@nvidia.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <soc/tegra/fuse.h>
+
+#include "clk.h"
+#include "clk-dfll.h"
+#include "cvb.h"
+
+/* Maximum CPU frequency, indexed by CPU speedo id */
+static const unsigned long cpu_max_freq_table[] = {
+ [0] = 2014500000UL,
+ [1] = 2320500000UL,
+ [2] = 2116500000UL,
+ [3] = 2524500000UL,
+};
+
+static const struct cvb_table tegra124_cpu_cvb_tables[] = {
+ {
+ .speedo_id = -1,
+ .process_id = -1,
+ .min_millivolts = 900,
+ .max_millivolts = 1260,
+ .alignment = {
+ .step_uv = 10000, /* 10mV */
+ },
+ .speedo_scale = 100,
+ .voltage_scale = 1000,
+ .cvb_table = {
+ {204000000UL, {1112619, -29295, 402} },
+ {306000000UL, {1150460, -30585, 402} },
+ {408000000UL, {1190122, -31865, 402} },
+ {510000000UL, {1231606, -33155, 402} },
+ {612000000UL, {1274912, -34435, 402} },
+ {714000000UL, {1320040, -35725, 402} },
+ {816000000UL, {1366990, -37005, 402} },
+ {918000000UL, {1415762, -38295, 402} },
+ {1020000000UL, {1466355, -39575, 402} },
+ {1122000000UL, {1518771, -40865, 402} },
+ {1224000000UL, {1573009, -42145, 402} },
+ {1326000000UL, {1629068, -43435, 402} },
+ {1428000000UL, {1686950, -44715, 402} },
+ {1530000000UL, {1746653, -46005, 402} },
+ {1632000000UL, {1808179, -47285, 402} },
+ {1734000000UL, {1871526, -48575, 402} },
+ {1836000000UL, {1936696, -49855, 402} },
+ {1938000000UL, {2003687, -51145, 402} },
+ {2014500000UL, {2054787, -52095, 402} },
+ {2116500000UL, {2124957, -53385, 402} },
+ {2218500000UL, {2196950, -54665, 402} },
+ {2320500000UL, {2270765, -55955, 402} },
+ {2422500000UL, {2346401, -57235, 402} },
+ {2524500000UL, {2437299, -58535, 402} },
+ {0, { 0, 0, 0} },
+ },
+ .cpu_dfll_data = {
+ .tune0_low = 0x005020ff,
+ .tune0_high = 0x005040ff,
+ .tune1 = 0x00000060,
+ }
+ },
+};
+
+static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
+{
+ int process_id, speedo_id, speedo_value;
+ struct tegra_dfll_soc_data *soc;
+ const struct cvb_table *cvb;
+
+ process_id = tegra_sku_info.cpu_process_id;
+ speedo_id = tegra_sku_info.cpu_speedo_id;
+ speedo_value = tegra_sku_info.cpu_speedo_value;
+
+ if (speedo_id >= ARRAY_SIZE(cpu_max_freq_table)) {
+ dev_err(&pdev->dev, "unknown max CPU freq for speedo_id=%d\n",
+ speedo_id);
+ return -ENODEV;
+ }
+
+ soc = devm_kzalloc(&pdev->dev, sizeof(*soc), GFP_KERNEL);
+ if (!soc)
+ return -ENOMEM;
+
+ soc->dev = get_cpu_device(0);
+ if (!soc->dev) {
+ dev_err(&pdev->dev, "no CPU0 device\n");
+ return -ENODEV;
+ }
+
+ cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables,
+ ARRAY_SIZE(tegra124_cpu_cvb_tables),
+ process_id, speedo_id, speedo_value,
+ cpu_max_freq_table[speedo_id],
+ soc->dev);
+ if (IS_ERR(cvb)) {
+ dev_err(&pdev->dev, "couldn't build OPP table: %ld\n",
+ PTR_ERR(cvb));
+ return PTR_ERR(cvb);
+ }
+
+ soc->min_millivolts = cvb->min_millivolts;
+ soc->tune0_low = cvb->cpu_dfll_data.tune0_low;
+ soc->tune0_high = cvb->cpu_dfll_data.tune0_high;
+ soc->tune1 = cvb->cpu_dfll_data.tune1;
+
+ return tegra_dfll_register(pdev, soc);
+}
+
+static const struct of_device_id tegra124_dfll_fcpu_of_match[] = {
+ { .compatible = "nvidia,tegra124-dfll", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra124_dfll_fcpu_of_match);
+
+static const struct dev_pm_ops tegra124_dfll_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,
+ tegra_dfll_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra124_dfll_fcpu_driver = {
+ .probe = tegra124_dfll_fcpu_probe,
+ .remove = tegra_dfll_unregister,
+ .driver = {
+ .name = "tegra124-dfll",
+ .of_match_table = tegra124_dfll_fcpu_of_match,
+ .pm = &tegra124_dfll_pm_ops,
+ },
+};
+
+static int __init tegra124_dfll_fcpu_init(void)
+{
+ return platform_driver_register(&tegra124_dfll_fcpu_driver);
+}
+module_init(tegra124_dfll_fcpu_init);
+
+static void __exit tegra124_dfll_fcpu_exit(void)
+{
+ platform_driver_unregister(&tegra124_dfll_fcpu_driver);
+}
+module_exit(tegra124_dfll_fcpu_exit);
+
+MODULE_DESCRIPTION("Tegra124 DFLL clock source driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Aleksandr Frid <afrid@nvidia.com>");
+MODULE_AUTHOR("Paul Walmsley <pwalmsley@nvidia.com>");
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index e8cca3eac007..824d75883d2b 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -15,7 +15,6 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
@@ -24,6 +23,7 @@
#include <linux/export.h>
#include <linux/clk/tegra.h>
#include <dt-bindings/clock/tegra124-car.h>
+#include <dt-bindings/reset/tegra124-car.h>
#include "clk.h"
#include "clk-id.h"
@@ -39,6 +39,9 @@
#define CLK_SOURCE_CSITE 0x1d4
#define CLK_SOURCE_EMC 0x19c
+#define RST_DFLL_DVCO 0x2f4
+#define DVFS_DFLL_RESET_SHIFT 0
+
#define PLLC_BASE 0x80
#define PLLC_OUT 0x84
#define PLLC_MISC2 0x88
@@ -94,6 +97,8 @@
#define PMC_PLLM_WB0_OVERRIDE 0x1dc
#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+#define CCLKG_BURST_POLICY 0x368
+
#define UTMIP_PLL_CFG2 0x488
#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)
#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
@@ -126,6 +131,8 @@
#ifdef CONFIG_PM_SLEEP
static struct cpu_clk_suspend_context {
u32 clk_csite_src;
+ u32 cclkg_burst;
+ u32 cclkg_divider;
} tegra124_cpu_clk_sctx;
#endif
@@ -1319,12 +1326,22 @@ static void tegra124_cpu_clock_suspend(void)
tegra124_cpu_clk_sctx.clk_csite_src =
readl(clk_base + CLK_SOURCE_CSITE);
writel(3 << 30, clk_base + CLK_SOURCE_CSITE);
+
+ tegra124_cpu_clk_sctx.cclkg_burst =
+ readl(clk_base + CCLKG_BURST_POLICY);
+ tegra124_cpu_clk_sctx.cclkg_divider =
+ readl(clk_base + CCLKG_BURST_POLICY + 4);
}
static void tegra124_cpu_clock_resume(void)
{
writel(tegra124_cpu_clk_sctx.clk_csite_src,
clk_base + CLK_SOURCE_CSITE);
+
+ writel(tegra124_cpu_clk_sctx.cclkg_burst,
+ clk_base + CCLKG_BURST_POLICY);
+ writel(tegra124_cpu_clk_sctx.cclkg_divider,
+ clk_base + CCLKG_BURST_POLICY + 4);
}
#endif
@@ -1415,6 +1432,68 @@ static void __init tegra124_clock_apply_init_table(void)
}
/**
+ * tegra124_car_barrier - wait for pending writes to the CAR to complete
+ *
+ * Wait for any outstanding writes to the CAR MMIO space from this CPU
+ * to complete before continuing execution. No return value.
+ */
+static void tegra124_car_barrier(void)
+{
+ readl_relaxed(clk_base + RST_DFLL_DVCO);
+}
+
+/**
+ * tegra124_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset
+ *
+ * Assert the reset line of the DFLL's DVCO. No return value.
+ */
+static void tegra124_clock_assert_dfll_dvco_reset(void)
+{
+ u32 v;
+
+ v = readl_relaxed(clk_base + RST_DFLL_DVCO);
+ v |= (1 << DVFS_DFLL_RESET_SHIFT);
+ writel_relaxed(v, clk_base + RST_DFLL_DVCO);
+ tegra124_car_barrier();
+}
+
+/**
+ * tegra124_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset
+ *
+ * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to
+ * operate. No return value.
+ */
+static void tegra124_clock_deassert_dfll_dvco_reset(void)
+{
+ u32 v;
+
+ v = readl_relaxed(clk_base + RST_DFLL_DVCO);
+ v &= ~(1 << DVFS_DFLL_RESET_SHIFT);
+ writel_relaxed(v, clk_base + RST_DFLL_DVCO);
+ tegra124_car_barrier();
+}
+
+static int tegra124_reset_assert(unsigned long id)
+{
+ if (id == TEGRA124_RST_DFLL_DVCO)
+ tegra124_clock_assert_dfll_dvco_reset();
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int tegra124_reset_deassert(unsigned long id)
+{
+ if (id == TEGRA124_RST_DFLL_DVCO)
+ tegra124_clock_deassert_dfll_dvco_reset();
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
* tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs
*
* Program an initial clock rate and enable or disable clocks needed
@@ -1499,6 +1578,8 @@ static void __init tegra124_132_clock_init_post(struct device_node *np)
{
tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks,
&pll_x_params);
+ tegra_init_special_resets(1, tegra124_reset_assert,
+ tegra124_reset_deassert);
tegra_add_of_provider(np);
clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np,
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 41272dcc9e22..bf004f0e4f65 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -15,7 +15,6 @@
*/
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 0af3e834dd24..fad561a5896b 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -16,7 +16,6 @@
#include <linux/io.h>
#include <linux/delay.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 41cd87c67be6..2a3a4fe803d6 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/clkdev.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
@@ -49,7 +50,6 @@
#define RST_DEVICES_L 0x004
#define RST_DEVICES_H 0x008
#define RST_DEVICES_U 0x00C
-#define RST_DFLL_DVCO 0x2F4
#define RST_DEVICES_V 0x358
#define RST_DEVICES_W 0x35C
#define RST_DEVICES_X 0x28C
@@ -79,6 +79,11 @@ static struct clk **clks;
static int clk_num;
static struct clk_onecell_data clk_data;
+/* Handlers for SoC-specific reset lines */
+static int (*special_reset_assert)(unsigned long);
+static int (*special_reset_deassert)(unsigned long);
+static unsigned int num_special_reset;
+
static struct tegra_clk_periph_regs periph_regs[] = {
[0] = {
.enb_reg = CLK_OUT_ENB_L,
@@ -152,19 +157,29 @@ static int tegra_clk_rst_assert(struct reset_controller_dev *rcdev,
*/
tegra_read_chipid();
- writel_relaxed(BIT(id % 32),
- clk_base + periph_regs[id / 32].rst_set_reg);
+ if (id < periph_banks * 32) {
+ writel_relaxed(BIT(id % 32),
+ clk_base + periph_regs[id / 32].rst_set_reg);
+ return 0;
+ } else if (id < periph_banks * 32 + num_special_reset) {
+ return special_reset_assert(id);
+ }
- return 0;
+ return -EINVAL;
}
static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
- writel_relaxed(BIT(id % 32),
- clk_base + periph_regs[id / 32].rst_clr_reg);
+ if (id < periph_banks * 32) {
+ writel_relaxed(BIT(id % 32),
+ clk_base + periph_regs[id / 32].rst_clr_reg);
+ return 0;
+ } else if (id < periph_banks * 32 + num_special_reset) {
+ return special_reset_deassert(id);
+ }
- return 0;
+ return -EINVAL;
}
struct tegra_clk_periph_regs *get_reg_bank(int clkid)
@@ -286,10 +301,19 @@ void __init tegra_add_of_provider(struct device_node *np)
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
rst_ctlr.of_node = np;
- rst_ctlr.nr_resets = periph_banks * 32;
+ rst_ctlr.nr_resets = periph_banks * 32 + num_special_reset;
reset_controller_register(&rst_ctlr);
}
+void __init tegra_init_special_resets(unsigned int num,
+ int (*assert)(unsigned long),
+ int (*deassert)(unsigned long))
+{
+ num_special_reset = num;
+ special_reset_assert = assert;
+ special_reset_deassert = deassert;
+}
+
void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num)
{
int i;
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 75ddc8ff8bd4..0621887e06f7 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -591,6 +591,9 @@ struct tegra_devclk {
char *con_id;
};
+void tegra_init_special_resets(unsigned int num, int (*assert)(unsigned long),
+ int (*deassert)(unsigned long));
+
void tegra_init_from_table(struct tegra_clk_init_table *tbl,
struct clk *clks[], int clk_max);
diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c
new file mode 100644
index 000000000000..0204e0861134
--- /dev/null
+++ b/drivers/clk/tegra/cvb.c
@@ -0,0 +1,140 @@
+/*
+ * Utility functions for parsing Tegra CVB voltage tables
+ *
+ * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/pm_opp.h>
+
+#include "cvb.h"
+
+/* cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) */
+static inline int get_cvb_voltage(int speedo, int s_scale,
+ const struct cvb_coefficients *cvb)
+{
+ int mv;
+
+ /* apply only speedo scale: output mv = cvb_mv * v_scale */
+ mv = DIV_ROUND_CLOSEST(cvb->c2 * speedo, s_scale);
+ mv = DIV_ROUND_CLOSEST((mv + cvb->c1) * speedo, s_scale) + cvb->c0;
+ return mv;
+}
+
+static int round_cvb_voltage(int mv, int v_scale,
+ const struct rail_alignment *align)
+{
+ /* combined: apply voltage scale and round to cvb alignment step */
+ int uv;
+ int step = (align->step_uv ? : 1000) * v_scale;
+ int offset = align->offset_uv * v_scale;
+
+ uv = max(mv * 1000, offset) - offset;
+ uv = DIV_ROUND_UP(uv, step) * align->step_uv + align->offset_uv;
+ return uv / 1000;
+}
+
+enum {
+ DOWN,
+ UP
+};
+
+static int round_voltage(int mv, const struct rail_alignment *align, int up)
+{
+ if (align->step_uv) {
+ int uv;
+
+ uv = max(mv * 1000, align->offset_uv) - align->offset_uv;
+ uv = (uv + (up ? align->step_uv - 1 : 0)) / align->step_uv;
+ return (uv * align->step_uv + align->offset_uv) / 1000;
+ }
+ return mv;
+}
+
+static int build_opp_table(const struct cvb_table *d,
+ int speedo_value,
+ unsigned long max_freq,
+ struct device *opp_dev)
+{
+ int i, ret, dfll_mv, min_mv, max_mv;
+ const struct cvb_table_freq_entry *table = NULL;
+ const struct rail_alignment *align = &d->alignment;
+
+ min_mv = round_voltage(d->min_millivolts, align, UP);
+ max_mv = round_voltage(d->max_millivolts, align, DOWN);
+
+ for (i = 0; i < MAX_DVFS_FREQS; i++) {
+ table = &d->cvb_table[i];
+ if (!table->freq || (table->freq > max_freq))
+ break;
+
+ /*
+ * FIXME after clk_round_rate/clk_determine_rate prototypes
+ * have been updated
+ */
+ if (table->freq & (1<<31))
+ continue;
+
+ dfll_mv = get_cvb_voltage(
+ speedo_value, d->speedo_scale, &table->coefficients);
+ dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align);
+ dfll_mv = clamp(dfll_mv, min_mv, max_mv);
+
+ ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * tegra_cvb_build_opp_table - build OPP table from Tegra CVB tables
+ * @cvb_tables: array of CVB tables
+ * @sz: size of the previously mentioned array
+ * @process_id: process id of the HW module
+ * @speedo_id: speedo id of the HW module
+ * @speedo_value: speedo value of the HW module
+ * @max_rate: highest safe clock rate
+ * @opp_dev: the struct device * for which the OPP table is built
+ *
+ * On Tegra, a CVB table encodes the relationship between operating voltage
+ * and safe maximal frequency for a given module (e.g. GPU or CPU). This
+ * function calculates the optimal voltage-frequency operating points
+ * for the given arguments and exports them via the OPP library for the
+ * given @opp_dev. Returns a pointer to the struct cvb_table that matched
+ * or an ERR_PTR on failure.
+ */
+const struct cvb_table *tegra_cvb_build_opp_table(
+ const struct cvb_table *cvb_tables,
+ size_t sz, int process_id,
+ int speedo_id, int speedo_value,
+ unsigned long max_rate,
+ struct device *opp_dev)
+{
+ int i, ret;
+
+ for (i = 0; i < sz; i++) {
+ const struct cvb_table *d = &cvb_tables[i];
+
+ if (d->speedo_id != -1 && d->speedo_id != speedo_id)
+ continue;
+ if (d->process_id != -1 && d->process_id != process_id)
+ continue;
+
+ ret = build_opp_table(d, speedo_value, max_rate, opp_dev);
+ return ret ? ERR_PTR(ret) : d;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h
new file mode 100644
index 000000000000..f62cdc4f4234
--- /dev/null
+++ b/drivers/clk/tegra/cvb.h
@@ -0,0 +1,67 @@
+/*
+ * Utility functions for parsing Tegra CVB voltage tables
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __DRIVERS_CLK_TEGRA_CVB_H
+#define __DRIVERS_CLK_TEGRA_CVB_H
+
+#include <linux/types.h>
+
+struct device;
+
+#define MAX_DVFS_FREQS 40
+
+struct rail_alignment {
+ int offset_uv;
+ int step_uv;
+};
+
+struct cvb_coefficients {
+ int c0;
+ int c1;
+ int c2;
+};
+
+struct cvb_table_freq_entry {
+ unsigned long freq;
+ struct cvb_coefficients coefficients;
+};
+
+struct cvb_cpu_dfll_data {
+ u32 tune0_low;
+ u32 tune0_high;
+ u32 tune1;
+};
+
+struct cvb_table {
+ int speedo_id;
+ int process_id;
+
+ int min_millivolts;
+ int max_millivolts;
+ struct rail_alignment alignment;
+
+ int speedo_scale;
+ int voltage_scale;
+ struct cvb_table_freq_entry cvb_table[MAX_DVFS_FREQS];
+ struct cvb_cpu_dfll_data cpu_dfll_data;
+};
+
+const struct cvb_table *tegra_cvb_build_opp_table(
+ const struct cvb_table *cvb_tables,
+ size_t sz, int process_id,
+ int speedo_id, int speedo_value,
+ unsigned long max_rate,
+ struct device *opp_dev);
+
+#endif
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index 105ffd0f5e79..d4ac96087ccd 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -1,16 +1,19 @@
obj-y += clk.o autoidle.o clockdomain.o
clk-common = dpll.o composite.o divider.o gate.o \
- fixed-factor.o mux.o apll.o
-obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o
-obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o
+ fixed-factor.o mux.o apll.o \
+ clkt_dpll.o clkt_iclk.o clkt_dflt.o
+obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o
+obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-814x.o clk-816x.o
obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \
- clk-3xxx.o
-obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o
-obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o
+ clk-3xxx.o dpll3xxx.o
+obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o \
+ dpll3xxx.o dpll44xx.o
+obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o \
+ dpll3xxx.o dpll44xx.o
obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
- clk-dra7-atl.o
-obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o
+ clk-dra7-atl.o dpll3xxx.o dpll44xx.o
+obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o
ifdef CONFIG_ATAGS
obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o
diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c
index 49baf3831546..f3eab6e79027 100644
--- a/drivers/clk/ti/apll.c
+++ b/drivers/clk/ti/apll.c
@@ -15,6 +15,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -27,6 +28,8 @@
#include <linux/clk/ti.h>
#include <linux/delay.h>
+#include "clock.h"
+
#define APLL_FORCE_LOCK 0x1
#define APLL_AUTO_IDLE 0x2
#define MAX_APLL_WAIT_TRIES 1000000
@@ -47,7 +50,7 @@ static int dra7_apll_enable(struct clk_hw *hw)
if (!ad)
return -EINVAL;
- clk_name = __clk_get_name(clk->hw.clk);
+ clk_name = clk_hw_get_name(&clk->hw);
state <<= __ffs(ad->idlest_mask);
@@ -170,7 +173,6 @@ static void __init of_dra7_apll_setup(struct device_node *node)
struct clk_hw_omap *clk_hw = NULL;
struct clk_init_data *init = NULL;
const char **parent_names = NULL;
- int i;
ad = kzalloc(sizeof(*ad), GFP_KERNEL);
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
@@ -195,8 +197,7 @@ static void __init of_dra7_apll_setup(struct device_node *node)
if (!parent_names)
goto cleanup;
- for (i = 0; i < init->num_parents; i++)
- parent_names[i] = of_clk_get_parent_name(node, i);
+ of_clk_parent_fill(node, parent_names, init->num_parents);
init->parent_names = parent_names;
@@ -272,7 +273,7 @@ static int omap2_apll_enable(struct clk_hw *hw)
if (i == MAX_APLL_WAIT_TRIES) {
pr_warn("%s failed to transition to locked\n",
- __clk_get_name(clk->hw.clk));
+ clk_hw_get_name(&clk->hw));
return -EBUSY;
}
diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c
index e75c64c9e81c..345af43465f0 100644
--- a/drivers/clk/ti/autoidle.c
+++ b/drivers/clk/ti/autoidle.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
struct clk_ti_autoidle {
void __iomem *reg;
u8 shift;
@@ -33,8 +35,41 @@ struct clk_ti_autoidle {
#define AUTOIDLE_LOW 0x1
static LIST_HEAD(autoidle_clks);
+static LIST_HEAD(clk_hw_omap_clocks);
+
+/**
+ * omap2_clk_deny_idle - disable autoidle on an OMAP clock
+ * @clk: struct clk * to disable autoidle for
+ *
+ * Disable autoidle on an OMAP clock.
+ */
+int omap2_clk_deny_idle(struct clk *clk)
+{
+ struct clk_hw_omap *c;
-static void ti_allow_autoidle(struct clk_ti_autoidle *clk)
+ c = to_clk_hw_omap(__clk_get_hw(clk));
+ if (c->ops && c->ops->deny_idle)
+ c->ops->deny_idle(c);
+ return 0;
+}
+
+/**
+ * omap2_clk_allow_idle - enable autoidle on an OMAP clock
+ * @clk: struct clk * to enable autoidle for
+ *
+ * Enable autoidle on an OMAP clock.
+ */
+int omap2_clk_allow_idle(struct clk *clk)
+{
+ struct clk_hw_omap *c;
+
+ c = to_clk_hw_omap(__clk_get_hw(clk));
+ if (c->ops && c->ops->allow_idle)
+ c->ops->allow_idle(c);
+ return 0;
+}
+
+static void _allow_autoidle(struct clk_ti_autoidle *clk)
{
u32 val;
@@ -48,7 +83,7 @@ static void ti_allow_autoidle(struct clk_ti_autoidle *clk)
ti_clk_ll_ops->clk_writel(val, clk->reg);
}
-static void ti_deny_autoidle(struct clk_ti_autoidle *clk)
+static void _deny_autoidle(struct clk_ti_autoidle *clk)
{
u32 val;
@@ -63,31 +98,31 @@ static void ti_deny_autoidle(struct clk_ti_autoidle *clk)
}
/**
- * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks
+ * _clk_generic_allow_autoidle_all - enable autoidle for all clocks
*
* Enables hardware autoidle for all registered DT clocks, which have
* the feature.
*/
-void of_ti_clk_allow_autoidle_all(void)
+static void _clk_generic_allow_autoidle_all(void)
{
struct clk_ti_autoidle *c;
list_for_each_entry(c, &autoidle_clks, node)
- ti_allow_autoidle(c);
+ _allow_autoidle(c);
}
/**
- * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks
+ * _clk_generic_deny_autoidle_all - disable autoidle for all clocks
*
* Disables hardware autoidle for all registered DT clocks, which have
* the feature.
*/
-void of_ti_clk_deny_autoidle_all(void)
+static void _clk_generic_deny_autoidle_all(void)
{
struct clk_ti_autoidle *c;
list_for_each_entry(c, &autoidle_clks, node)
- ti_deny_autoidle(c);
+ _deny_autoidle(c);
}
/**
@@ -131,3 +166,67 @@ int __init of_ti_clk_autoidle_setup(struct device_node *node)
return 0;
}
+
+/**
+ * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock
+ * @hw: struct clk_hw * to initialize
+ *
+ * Add an OMAP clock @clk to the internal list of OMAP clocks. Used
+ * temporarily for autoidle handling, until this support can be
+ * integrated into the common clock framework code in some way. No
+ * return value.
+ */
+void omap2_init_clk_hw_omap_clocks(struct clk_hw *hw)
+{
+ struct clk_hw_omap *c;
+
+ if (clk_hw_get_flags(hw) & CLK_IS_BASIC)
+ return;
+
+ c = to_clk_hw_omap(hw);
+ list_add(&c->node, &clk_hw_omap_clocks);
+}
+
+/**
+ * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that
+ * support it
+ *
+ * Enable clock autoidle on all OMAP clocks that have allow_idle
+ * function pointers associated with them. This function is intended
+ * to be temporary until support for this is added to the common clock
+ * code. Returns 0.
+ */
+int omap2_clk_enable_autoidle_all(void)
+{
+ struct clk_hw_omap *c;
+
+ list_for_each_entry(c, &clk_hw_omap_clocks, node)
+ if (c->ops && c->ops->allow_idle)
+ c->ops->allow_idle(c);
+
+ _clk_generic_allow_autoidle_all();
+
+ return 0;
+}
+
+/**
+ * omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that
+ * support it
+ *
+ * Disable clock autoidle on all OMAP clocks that have allow_idle
+ * function pointers associated with them. This function is intended
+ * to be temporary until support for this is added to the common clock
+ * code. Returns 0.
+ */
+int omap2_clk_disable_autoidle_all(void)
+{
+ struct clk_hw_omap *c;
+
+ list_for_each_entry(c, &clk_hw_omap_clocks, node)
+ if (c->ops && c->ops->deny_idle)
+ c->ops->deny_idle(c);
+
+ _clk_generic_deny_autoidle_all();
+
+ return 0;
+}
diff --git a/drivers/clk/ti/clk-2xxx.c b/drivers/clk/ti/clk-2xxx.c
index c808ab3d2bb2..657c4fe07a95 100644
--- a/drivers/clk/ti/clk-2xxx.c
+++ b/drivers/clk/ti/clk-2xxx.c
@@ -16,9 +16,11 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-provider.h>
+#include <linux/clk.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
static struct ti_dt_clk omap2xxx_clks[] = {
DT_CLK(NULL, "func_32k_ck", "func_32k_ck"),
DT_CLK(NULL, "secure_32k_ck", "secure_32k_ck"),
diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c
index 028b33783d38..ef2ec64fe547 100644
--- a/drivers/clk/ti/clk-33xx.c
+++ b/drivers/clk/ti/clk-33xx.c
@@ -16,9 +16,12 @@
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
static struct ti_dt_clk am33xx_clks[] = {
DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"),
DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"),
diff --git a/drivers/clk/ti/clk-3xxx-legacy.c b/drivers/clk/ti/clk-3xxx-legacy.c
index 0b61548d569b..0fbf8a917955 100644
--- a/drivers/clk/ti/clk-3xxx-legacy.c
+++ b/drivers/clk/ti/clk-3xxx-legacy.c
@@ -15,6 +15,7 @@
*/
#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c
index 757636d166cf..676ee8f6d813 100644
--- a/drivers/clk/ti/clk-3xxx.c
+++ b/drivers/clk/ti/clk-3xxx.c
@@ -16,9 +16,220 @@
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
+/*
+ * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
+ * that are sourced by DPLL5, and both of these require this clock
+ * to be at 120 MHz for proper operation.
+ */
+#define DPLL5_FREQ_FOR_USBHOST 120000000
+
+#define OMAP3430ES2_ST_DSS_IDLE_SHIFT 1
+#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT 5
+#define OMAP3430ES2_ST_SSI_IDLE_SHIFT 8
+
+#define OMAP34XX_CM_IDLEST_VAL 1
+
+/*
+ * In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported
+ * in the same register at a bit offset of 0x8. The EN_ACK for ICK is
+ * at an offset of 4 from ICK enable bit.
+ */
+#define AM35XX_IPSS_ICK_MASK 0xF
+#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4
+#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8
+#define AM35XX_IPSS_CLK_IDLEST_VAL 0
+
+#define AM35XX_ST_IPSS_SHIFT 5
+
+/**
+ * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI
+ * @clk: struct clk * being enabled
+ * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
+ * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
+ * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
+ *
+ * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift
+ * from the CM_{I,F}CLKEN bit. Pass back the correct info via
+ * @idlest_reg and @idlest_bit. No return value.
+ */
+static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg,
+ u8 *idlest_bit,
+ u8 *idlest_val)
+{
+ u32 r;
+
+ r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
+ *idlest_reg = (__force void __iomem *)r;
+ *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
+ *idlest_val = OMAP34XX_CM_IDLEST_VAL;
+}
+
+const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = {
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+ .find_idlest = omap3430es2_clk_ssi_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
+
+/**
+ * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST
+ * @clk: struct clk * being enabled
+ * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
+ * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
+ * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
+ *
+ * Some OMAP modules on OMAP3 ES2+ chips have both initiator and
+ * target IDLEST bits. For our purposes, we are concerned with the
+ * target IDLEST bits, which exist at a different bit position than
+ * the *CLKEN bit position for these modules (DSS and USBHOST) (The
+ * default find_idlest code assumes that they are at the same
+ * position.) No return value.
+ */
+static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg,
+ u8 *idlest_bit,
+ u8 *idlest_val)
+{
+ u32 r;
+
+ r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
+ *idlest_reg = (__force void __iomem *)r;
+ /* USBHOST_IDLE has same shift */
+ *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT;
+ *idlest_val = OMAP34XX_CM_IDLEST_VAL;
+}
+
+const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = {
+ .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
+
+const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = {
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+ .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
+
+/**
+ * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB
+ * @clk: struct clk * being enabled
+ * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
+ * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
+ * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
+ *
+ * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different
+ * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via
+ * @idlest_reg and @idlest_bit. No return value.
+ */
+static void omap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg,
+ u8 *idlest_bit,
+ u8 *idlest_val)
+{
+ u32 r;
+
+ r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
+ *idlest_reg = (__force void __iomem *)r;
+ *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT;
+ *idlest_val = OMAP34XX_CM_IDLEST_VAL;
+}
+
+const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = {
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+ .find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
+
+/**
+ * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS
+ * @clk: struct clk * being enabled
+ * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
+ * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
+ * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
+ *
+ * The interface clocks on AM35xx IPSS reflects the clock idle status
+ * in the enable register itsel at a bit offset of 4 from the enable
+ * bit. A value of 1 indicates that clock is enabled.
+ */
+static void am35xx_clk_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg,
+ u8 *idlest_bit,
+ u8 *idlest_val)
+{
+ *idlest_reg = (__force void __iomem *)(clk->enable_reg);
+ *idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET;
+ *idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL;
+}
+
+/**
+ * am35xx_clk_find_companion - find companion clock to @clk
+ * @clk: struct clk * to find the companion clock of
+ * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
+ * @other_bit: u8 ** to return the companion clock bit shift in
+ *
+ * Some clocks don't have companion clocks. For example, modules with
+ * only an interface clock (such as HECC) don't have a companion
+ * clock. Right now, this code relies on the hardware exporting a bit
+ * in the correct companion register that indicates that the
+ * nonexistent 'companion clock' is active. Future patches will
+ * associate this type of code with per-module data structures to
+ * avoid this issue, and remove the casts. No return value.
+ */
+static void am35xx_clk_find_companion(struct clk_hw_omap *clk,
+ void __iomem **other_reg,
+ u8 *other_bit)
+{
+ *other_reg = (__force void __iomem *)(clk->enable_reg);
+ if (clk->enable_bit & AM35XX_IPSS_ICK_MASK)
+ *other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET;
+ else
+ *other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET;
+}
+
+const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = {
+ .find_idlest = am35xx_clk_find_idlest,
+ .find_companion = am35xx_clk_find_companion,
+};
+
+/**
+ * am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS
+ * @clk: struct clk * being enabled
+ * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
+ * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
+ * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
+ *
+ * The IPSS target CM_IDLEST bit is at a different shift from the
+ * CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg
+ * and @idlest_bit. No return value.
+ */
+static void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg,
+ u8 *idlest_bit,
+ u8 *idlest_val)
+{
+ u32 r;
+
+ r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
+ *idlest_reg = (__force void __iomem *)r;
+ *idlest_bit = AM35XX_ST_IPSS_SHIFT;
+ *idlest_val = OMAP34XX_CM_IDLEST_VAL;
+}
+
+const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = {
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+ .find_idlest = am35xx_clk_ipss_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"),
@@ -324,6 +535,30 @@ enum {
OMAP3_SOC_OMAP3630,
};
+/**
+ * omap3_clk_lock_dpll5 - locks DPLL5
+ *
+ * Locks DPLL5 to a pre-defined frequency. This is required for proper
+ * operation of USB.
+ */
+void __init omap3_clk_lock_dpll5(void)
+{
+ struct clk *dpll5_clk;
+ struct clk *dpll5_m2_clk;
+
+ dpll5_clk = clk_get(NULL, "dpll5_ck");
+ clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
+ clk_prepare_enable(dpll5_clk);
+
+ /* Program dpll5_m2_clk divider for no division */
+ dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
+ clk_prepare_enable(dpll5_m2_clk);
+ clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
+
+ clk_disable_unprepare(dpll5_m2_clk);
+ clk_disable_unprepare(dpll5_clk);
+}
+
static int __init omap3xxx_dt_clk_init(int soc_type)
{
if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 ||
diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c
index 3795fce8a830..097fc90bf19a 100644
--- a/drivers/clk/ti/clk-43xx.c
+++ b/drivers/clk/ti/clk-43xx.c
@@ -16,9 +16,12 @@
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
static struct ti_dt_clk am43xx_clks[] = {
DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"),
DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"),
@@ -71,6 +74,7 @@ static struct ti_dt_clk am43xx_clks[] = {
DT_CLK(NULL, "clk_24mhz", "clk_24mhz"),
DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"),
DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"),
+ DT_CLK(NULL, "dpll_clksel_mac_clk", "dpll_clksel_mac_clk"),
DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"),
DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"),
DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"),
diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c
index 581db7711f51..7a8b51b35f9f 100644
--- a/drivers/clk/ti/clk-44xx.c
+++ b/drivers/clk/ti/clk-44xx.c
@@ -16,6 +16,8 @@
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
/*
* OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section
* "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index 96c69a335975..59ce2fa2c104 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -17,6 +17,8 @@
#include <linux/io.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
#define OMAP5_DPLL_ABE_DEFFREQ 98304000
/*
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 63b8323df918..9b5b289e6334 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -16,11 +16,12 @@
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
#define DRA7_DPLL_ABE_DEFFREQ 180633600
#define DRA7_DPLL_GMAC_DEFFREQ 1000000000
#define DRA7_DPLL_USB_DEFFREQ 960000000
-
static struct ti_dt_clk dra7xx_clks[] = {
DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"),
DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"),
diff --git a/drivers/clk/ti/clk-814x.c b/drivers/clk/ti/clk-814x.c
new file mode 100644
index 000000000000..e172920798ea
--- /dev/null
+++ b/drivers/clk/ti/clk-814x.c
@@ -0,0 +1,33 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+#include "clock.h"
+
+static struct ti_dt_clk dm814_clks[] = {
+ DT_CLK(NULL, "devosc_ck", "devosc_ck"),
+ DT_CLK(NULL, "mpu_ck", "mpu_ck"),
+ DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"),
+ DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"),
+ DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"),
+ DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"),
+ DT_CLK(NULL, "timer_sys_ck", "devosc_ck"),
+ DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"),
+ DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"),
+ { .node_name = NULL },
+};
+
+int __init dm814x_dt_clk_init(void)
+{
+ ti_dt_clocks_register(dm814_clks);
+ omap2_clk_disable_autoidle_all();
+ omap2_clk_enable_init_clocks(NULL, 0);
+
+ return 0;
+}
diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c
index 9451e651a1ff..1dfad0c712cd 100644
--- a/drivers/clk/ti/clk-816x.c
+++ b/drivers/clk/ti/clk-816x.c
@@ -14,6 +14,8 @@
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
static struct ti_dt_clk dm816x_clks[] = {
DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
@@ -42,7 +44,7 @@ static const char *enable_init_clks[] = {
"ddr_pll_clk3",
};
-int __init ti81xx_dt_clk_init(void)
+int __init dm816x_dt_clk_init(void)
{
ti_dt_clocks_register(dm816x_clks);
omap2_clk_disable_autoidle_all();
diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c
index 19e543a32e2b..2e14dfb588f4 100644
--- a/drivers/clk/ti/clk-dra7-atl.c
+++ b/drivers/clk/ti/clk-dra7-atl.c
@@ -16,6 +16,7 @@
*/
#include <linux/module.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c
index 64bb5e8a3b8c..b5bcd77e8d0f 100644
--- a/drivers/clk/ti/clk.c
+++ b/drivers/clk/ti/clk.c
@@ -15,12 +15,15 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/list.h>
+#include <linux/regmap.h>
+#include <linux/bootmem.h>
#include "clock.h"
@@ -30,6 +33,63 @@
struct ti_clk_ll_ops *ti_clk_ll_ops;
static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS];
+static struct ti_clk_features ti_clk_features;
+
+struct clk_iomap {
+ struct regmap *regmap;
+ void __iomem *mem;
+};
+
+static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS];
+
+static void clk_memmap_writel(u32 val, void __iomem *reg)
+{
+ struct clk_omap_reg *r = (struct clk_omap_reg *)&reg;
+ struct clk_iomap *io = clk_memmaps[r->index];
+
+ if (io->regmap)
+ regmap_write(io->regmap, r->offset, val);
+ else
+ writel_relaxed(val, io->mem + r->offset);
+}
+
+static u32 clk_memmap_readl(void __iomem *reg)
+{
+ u32 val;
+ struct clk_omap_reg *r = (struct clk_omap_reg *)&reg;
+ struct clk_iomap *io = clk_memmaps[r->index];
+
+ if (io->regmap)
+ regmap_read(io->regmap, r->offset, &val);
+ else
+ val = readl_relaxed(io->mem + r->offset);
+
+ return val;
+}
+
+/**
+ * ti_clk_setup_ll_ops - setup low level clock operations
+ * @ops: low level clock ops descriptor
+ *
+ * Sets up low level clock operations for TI clock driver. This is used
+ * to provide various callbacks for the clock driver towards platform
+ * specific code. Returns 0 on success, -EBUSY if ll_ops have been
+ * registered already.
+ */
+int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops)
+{
+ if (ti_clk_ll_ops) {
+ pr_err("Attempt to register ll_ops multiple times.\n");
+ return -EBUSY;
+ }
+
+ ti_clk_ll_ops = ops;
+ ops->clk_readl = clk_memmap_readl;
+ ops->clk_writel = clk_memmap_writel;
+
+ return 0;
+}
+
/**
* ti_dt_clocks_register - register DT alias clocks during boot
* @oclks: list of clocks to register
@@ -134,32 +194,67 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index)
reg->offset = val;
- return (void __iomem *)tmp;
+ return (__force void __iomem *)tmp;
}
/**
- * ti_dt_clk_init_provider - init master clock provider
+ * omap2_clk_provider_init - init master clock provider
* @parent: master node
* @index: internal index for clk_reg_ops
+ * @syscon: syscon regmap pointer for accessing clock registers
+ * @mem: iomem pointer for the clock provider memory area, only used if
+ * syscon is not provided
*
* Initializes a master clock IP block. This basically sets up the
* mapping from clocks node to the memory map index. All the clocks
* are then initialized through the common of_clk_init call, and the
* clocks will access their memory maps based on the node layout.
+ * Returns 0 in success.
*/
-void ti_dt_clk_init_provider(struct device_node *parent, int index)
+int __init omap2_clk_provider_init(struct device_node *parent, int index,
+ struct regmap *syscon, void __iomem *mem)
{
struct device_node *clocks;
+ struct clk_iomap *io;
/* get clocks for this parent */
clocks = of_get_child_by_name(parent, "clocks");
if (!clocks) {
pr_err("%s missing 'clocks' child node.\n", parent->name);
- return;
+ return -EINVAL;
}
/* add clocks node info */
clocks_node_ptr[index] = clocks;
+
+ io = kzalloc(sizeof(*io), GFP_KERNEL);
+ if (!io)
+ return -ENOMEM;
+
+ io->regmap = syscon;
+ io->mem = mem;
+
+ clk_memmaps[index] = io;
+
+ return 0;
+}
+
+/**
+ * omap2_clk_legacy_provider_init - initialize a legacy clock provider
+ * @index: index for the clock provider
+ * @mem: iomem pointer for the clock provider memory area
+ *
+ * Initializes a legacy clock provider memory mapping.
+ */
+void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem)
+{
+ struct clk_iomap *io;
+
+ io = memblock_virt_alloc(sizeof(*io), 0);
+
+ io->mem = mem;
+
+ clk_memmaps[index] = io;
}
/**
@@ -244,11 +339,11 @@ struct clk __init *ti_clk_register_clk(struct ti_clk *setup)
if (!IS_ERR(clk)) {
setup->clk = clk;
if (setup->clkdm_name) {
- if (__clk_get_flags(clk) & CLK_IS_BASIC) {
+ clk_hw = __clk_get_hw(clk);
+ if (clk_hw_get_flags(clk_hw) & CLK_IS_BASIC) {
pr_warn("can't setup clkdm for basic clk %s\n",
setup->name);
} else {
- clk_hw = __clk_get_hw(clk);
to_clk_hw_omap(clk_hw)->clkdm_name =
setup->clkdm_name;
omap2_init_clk_clkdm(clk_hw);
@@ -311,3 +406,50 @@ int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks)
return 0;
}
#endif
+
+/**
+ * ti_clk_setup_features - setup clock features flags
+ * @features: features definition to use
+ *
+ * Initializes the clock driver features flags based on platform
+ * provided data. No return value.
+ */
+void __init ti_clk_setup_features(struct ti_clk_features *features)
+{
+ memcpy(&ti_clk_features, features, sizeof(*features));
+}
+
+/**
+ * ti_clk_get_features - get clock driver features flags
+ *
+ * Get TI clock driver features description. Returns a pointer
+ * to the current feature setup.
+ */
+const struct ti_clk_features *ti_clk_get_features(void)
+{
+ return &ti_clk_features;
+}
+
+/**
+ * omap2_clk_enable_init_clocks - prepare & enable a list of clocks
+ * @clk_names: ptr to an array of strings of clock names to enable
+ * @num_clocks: number of clock names in @clk_names
+ *
+ * Prepare and enable a list of clocks, named by @clk_names. No
+ * return value. XXX Deprecated; only needed until these clocks are
+ * properly claimed and enabled by the drivers or core code that uses
+ * them. XXX What code disables & calls clk_put on these clocks?
+ */
+void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks)
+{
+ struct clk *init_clk;
+ int i;
+
+ for (i = 0; i < num_clocks; i++) {
+ init_clk = clk_get(NULL, clk_names[i]);
+ if (WARN(IS_ERR(init_clk), "could not find init clock %s\n",
+ clk_names[i]))
+ continue;
+ clk_prepare_enable(init_clk);
+ }
+}
diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c
new file mode 100644
index 000000000000..90d7d8a21c49
--- /dev/null
+++ b/drivers/clk/ti/clkt_dflt.c
@@ -0,0 +1,316 @@
+/*
+ * Default clock type
+ *
+ * Copyright (C) 2005-2008, 2015 Texas Instruments, Inc.
+ * Copyright (C) 2004-2010 Nokia Corporation
+ *
+ * Contacts:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Paul Walmsley
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/clk/ti.h>
+#include <linux/delay.h>
+
+#include "clock.h"
+
+/*
+ * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait
+ * for a module to indicate that it is no longer in idle
+ */
+#define MAX_MODULE_ENABLE_WAIT 100000
+
+/*
+ * CM module register offsets, used for calculating the companion
+ * register addresses.
+ */
+#define CM_FCLKEN 0x0000
+#define CM_ICLKEN 0x0010
+
+/**
+ * _wait_idlest_generic - wait for a module to leave the idle state
+ * @clk: module clock to wait for (needed for register offsets)
+ * @reg: virtual address of module IDLEST register
+ * @mask: value to mask against to determine if the module is active
+ * @idlest: idle state indicator (0 or 1) for the clock
+ * @name: name of the clock (for printk)
+ *
+ * Wait for a module to leave idle, where its idle-status register is
+ * not inside the CM module. Returns 1 if the module left idle
+ * promptly, or 0 if the module did not leave idle before the timeout
+ * elapsed. XXX Deprecated - should be moved into drivers for the
+ * individual IP block that the IDLEST register exists in.
+ */
+static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg,
+ u32 mask, u8 idlest, const char *name)
+{
+ int i = 0, ena = 0;
+
+ ena = (idlest) ? 0 : mask;
+
+ /* Wait until module enters enabled state */
+ for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
+ if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena)
+ break;
+ udelay(1);
+ }
+
+ if (i < MAX_MODULE_ENABLE_WAIT)
+ pr_debug("omap clock: module associated with clock %s ready after %d loops\n",
+ name, i);
+ else
+ pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n",
+ name, MAX_MODULE_ENABLE_WAIT);
+
+ return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
+}
+
+/**
+ * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE
+ * @clk: struct clk * belonging to the module
+ *
+ * If the necessary clocks for the OMAP hardware IP block that
+ * corresponds to clock @clk are enabled, then wait for the module to
+ * indicate readiness (i.e., to leave IDLE). This code does not
+ * belong in the clock code and will be moved in the medium term to
+ * module-dependent code. No return value.
+ */
+static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
+{
+ void __iomem *companion_reg, *idlest_reg;
+ u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
+ s16 prcm_mod;
+ int r;
+
+ /* Not all modules have multiple clocks that their IDLEST depends on */
+ if (clk->ops->find_companion) {
+ clk->ops->find_companion(clk, &companion_reg, &other_bit);
+ if (!(ti_clk_ll_ops->clk_readl(companion_reg) &
+ (1 << other_bit)))
+ return;
+ }
+
+ clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
+ r = ti_clk_ll_ops->cm_split_idlest_reg(idlest_reg, &prcm_mod,
+ &idlest_reg_id);
+ if (r) {
+ /* IDLEST register not in the CM module */
+ _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit),
+ idlest_val, clk_hw_get_name(&clk->hw));
+ } else {
+ ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id,
+ idlest_bit);
+ }
+}
+
+/**
+ * omap2_clk_dflt_find_companion - find companion clock to @clk
+ * @clk: struct clk * to find the companion clock of
+ * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
+ * @other_bit: u8 ** to return the companion clock bit shift in
+ *
+ * Note: We don't need special code here for INVERT_ENABLE for the
+ * time being since INVERT_ENABLE only applies to clocks enabled by
+ * CM_CLKEN_PLL
+ *
+ * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's
+ * just a matter of XORing the bits.
+ *
+ * Some clocks don't have companion clocks. For example, modules with
+ * only an interface clock (such as MAILBOXES) don't have a companion
+ * clock. Right now, this code relies on the hardware exporting a bit
+ * in the correct companion register that indicates that the
+ * nonexistent 'companion clock' is active. Future patches will
+ * associate this type of code with per-module data structures to
+ * avoid this issue, and remove the casts. No return value.
+ */
+void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
+ void __iomem **other_reg, u8 *other_bit)
+{
+ u32 r;
+
+ /*
+ * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes
+ * it's just a matter of XORing the bits.
+ */
+ r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN));
+
+ *other_reg = (__force void __iomem *)r;
+ *other_bit = clk->enable_bit;
+}
+
+/**
+ * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk
+ * @clk: struct clk * to find IDLEST info for
+ * @idlest_reg: void __iomem ** to return the CM_IDLEST va in
+ * @idlest_bit: u8 * to return the CM_IDLEST bit shift in
+ * @idlest_val: u8 * to return the idle status indicator
+ *
+ * Return the CM_IDLEST register address and bit shift corresponding
+ * to the module that "owns" this clock. This default code assumes
+ * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that
+ * the IDLEST register address ID corresponds to the CM_*CLKEN
+ * register address ID (e.g., that CM_FCLKEN2 corresponds to
+ * CM_IDLEST2). This is not true for all modules. No return value.
+ */
+void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg, u8 *idlest_bit,
+ u8 *idlest_val)
+{
+ u32 r;
+
+ r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
+ *idlest_reg = (__force void __iomem *)r;
+ *idlest_bit = clk->enable_bit;
+
+ /*
+ * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
+ * 34xx reverses this, just to keep us on our toes
+ * AM35xx uses both, depending on the module.
+ */
+ *idlest_val = ti_clk_get_features()->cm_idlest_val;
+}
+
+/**
+ * omap2_dflt_clk_enable - enable a clock in the hardware
+ * @hw: struct clk_hw * of the clock to enable
+ *
+ * Enable the clock @hw in the hardware. We first call into the OMAP
+ * clockdomain code to "enable" the corresponding clockdomain if this
+ * is the first enabled user of the clockdomain. Then program the
+ * hardware to enable the clock. Then wait for the IP block that uses
+ * this clock to leave idle (if applicable). Returns the error value
+ * from clkdm_clk_enable() if it terminated with an error, or -EINVAL
+ * if @hw has a null clock enable_reg, or zero upon success.
+ */
+int omap2_dflt_clk_enable(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk;
+ u32 v;
+ int ret = 0;
+ bool clkdm_control;
+
+ if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL)
+ clkdm_control = false;
+ else
+ clkdm_control = true;
+
+ clk = to_clk_hw_omap(hw);
+
+ if (clkdm_control && clk->clkdm) {
+ ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
+ if (ret) {
+ WARN(1,
+ "%s: could not enable %s's clockdomain %s: %d\n",
+ __func__, clk_hw_get_name(hw),
+ clk->clkdm_name, ret);
+ return ret;
+ }
+ }
+
+ if (unlikely(!clk->enable_reg)) {
+ pr_err("%s: %s missing enable_reg\n", __func__,
+ clk_hw_get_name(hw));
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* FIXME should not have INVERT_ENABLE bit here */
+ v = ti_clk_ll_ops->clk_readl(clk->enable_reg);
+ if (clk->flags & INVERT_ENABLE)
+ v &= ~(1 << clk->enable_bit);
+ else
+ v |= (1 << clk->enable_bit);
+ ti_clk_ll_ops->clk_writel(v, clk->enable_reg);
+ v = ti_clk_ll_ops->clk_readl(clk->enable_reg); /* OCP barrier */
+
+ if (clk->ops && clk->ops->find_idlest)
+ _omap2_module_wait_ready(clk);
+
+ return 0;
+
+err:
+ if (clkdm_control && clk->clkdm)
+ ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
+ return ret;
+}
+
+/**
+ * omap2_dflt_clk_disable - disable a clock in the hardware
+ * @hw: struct clk_hw * of the clock to disable
+ *
+ * Disable the clock @hw in the hardware, and call into the OMAP
+ * clockdomain code to "disable" the corresponding clockdomain if all
+ * clocks/hwmods in that clockdomain are now disabled. No return
+ * value.
+ */
+void omap2_dflt_clk_disable(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk;
+ u32 v;
+
+ clk = to_clk_hw_omap(hw);
+ if (!clk->enable_reg) {
+ /*
+ * 'independent' here refers to a clock which is not
+ * controlled by its parent.
+ */
+ pr_err("%s: independent clock %s has no enable_reg\n",
+ __func__, clk_hw_get_name(hw));
+ return;
+ }
+
+ v = ti_clk_ll_ops->clk_readl(clk->enable_reg);
+ if (clk->flags & INVERT_ENABLE)
+ v |= (1 << clk->enable_bit);
+ else
+ v &= ~(1 << clk->enable_bit);
+ ti_clk_ll_ops->clk_writel(v, clk->enable_reg);
+ /* No OCP barrier needed here since it is a disable operation */
+
+ if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) &&
+ clk->clkdm)
+ ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
+}
+
+/**
+ * omap2_dflt_clk_is_enabled - is clock enabled in the hardware?
+ * @hw: struct clk_hw * to check
+ *
+ * Return 1 if the clock represented by @hw is enabled in the
+ * hardware, or 0 otherwise. Intended for use in the struct
+ * clk_ops.is_enabled function pointer.
+ */
+int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ u32 v;
+
+ v = ti_clk_ll_ops->clk_readl(clk->enable_reg);
+
+ if (clk->flags & INVERT_ENABLE)
+ v ^= BIT(clk->enable_bit);
+
+ v &= BIT(clk->enable_bit);
+
+ return v ? 1 : 0;
+}
+
+const struct clk_hw_omap_ops clkhwops_wait = {
+ .find_idlest = omap2_clk_dflt_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c
new file mode 100644
index 000000000000..9023ca9caf84
--- /dev/null
+++ b/drivers/clk/ti/clkt_dpll.c
@@ -0,0 +1,370 @@
+/*
+ * OMAP2/3/4 DPLL clock functions
+ *
+ * Copyright (C) 2005-2008 Texas Instruments, Inc.
+ * Copyright (C) 2004-2010 Nokia Corporation
+ *
+ * Contacts:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Paul Walmsley
+ *
+ * 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.
+ */
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/clk/ti.h>
+
+#include <asm/div64.h>
+
+#include "clock.h"
+
+/* DPLL rate rounding: minimum DPLL multiplier, divider values */
+#define DPLL_MIN_MULTIPLIER 2
+#define DPLL_MIN_DIVIDER 1
+
+/* Possible error results from _dpll_test_mult */
+#define DPLL_MULT_UNDERFLOW -1
+
+/*
+ * Scale factor to mitigate roundoff errors in DPLL rate rounding.
+ * The higher the scale factor, the greater the risk of arithmetic overflow,
+ * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR
+ * must be a power of DPLL_SCALE_BASE.
+ */
+#define DPLL_SCALE_FACTOR 64
+#define DPLL_SCALE_BASE 2
+#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \
+ (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
+
+/*
+ * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx.
+ * From device data manual section 4.3 "DPLL and DLL Specifications".
+ */
+#define OMAP3PLUS_DPLL_FINT_JTYPE_MIN 500000
+#define OMAP3PLUS_DPLL_FINT_JTYPE_MAX 2500000
+
+/* _dpll_test_fint() return codes */
+#define DPLL_FINT_UNDERFLOW -1
+#define DPLL_FINT_INVALID -2
+
+/* Private functions */
+
+/*
+ * _dpll_test_fint - test whether an Fint value is valid for the DPLL
+ * @clk: DPLL struct clk to test
+ * @n: divider value (N) to test
+ *
+ * Tests whether a particular divider @n will result in a valid DPLL
+ * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
+ * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate
+ * (assuming that it is counting N upwards), or -2 if the enclosing loop
+ * should skip to the next iteration (again assuming N is increasing).
+ */
+static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n)
+{
+ struct dpll_data *dd;
+ long fint, fint_min, fint_max;
+ int ret = 0;
+
+ dd = clk->dpll_data;
+
+ /* DPLL divider must result in a valid jitter correction val */
+ fint = clk_hw_get_rate(clk_hw_get_parent(&clk->hw)) / n;
+
+ if (dd->flags & DPLL_J_TYPE) {
+ fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN;
+ fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX;
+ } else {
+ fint_min = ti_clk_get_features()->fint_min;
+ fint_max = ti_clk_get_features()->fint_max;
+ }
+
+ if (!fint_min || !fint_max) {
+ WARN(1, "No fint limits available!\n");
+ return DPLL_FINT_INVALID;
+ }
+
+ if (fint < ti_clk_get_features()->fint_min) {
+ pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n",
+ n);
+ dd->max_divider = n;
+ ret = DPLL_FINT_UNDERFLOW;
+ } else if (fint > ti_clk_get_features()->fint_max) {
+ pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n",
+ n);
+ dd->min_divider = n;
+ ret = DPLL_FINT_INVALID;
+ } else if (fint > ti_clk_get_features()->fint_band1_max &&
+ fint < ti_clk_get_features()->fint_band2_min) {
+ pr_debug("rejecting n=%d due to Fint failure\n", n);
+ ret = DPLL_FINT_INVALID;
+ }
+
+ return ret;
+}
+
+static unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
+ unsigned int m, unsigned int n)
+{
+ unsigned long long num;
+
+ num = (unsigned long long)parent_rate * m;
+ do_div(num, n);
+ return num;
+}
+
+/*
+ * _dpll_test_mult - test a DPLL multiplier value
+ * @m: pointer to the DPLL m (multiplier) value under test
+ * @n: current DPLL n (divider) value under test
+ * @new_rate: pointer to storage for the resulting rounded rate
+ * @target_rate: the desired DPLL rate
+ * @parent_rate: the DPLL's parent clock rate
+ *
+ * This code tests a DPLL multiplier value, ensuring that the
+ * resulting rate will not be higher than the target_rate, and that
+ * the multiplier value itself is valid for the DPLL. Initially, the
+ * integer pointed to by the m argument should be prescaled by
+ * multiplying by DPLL_SCALE_FACTOR. The code will replace this with
+ * a non-scaled m upon return. This non-scaled m will result in a
+ * new_rate as close as possible to target_rate (but not greater than
+ * target_rate) given the current (parent_rate, n, prescaled m)
+ * triple. Returns DPLL_MULT_UNDERFLOW in the event that the
+ * non-scaled m attempted to underflow, which can allow the calling
+ * function to bail out early; or 0 upon success.
+ */
+static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
+ unsigned long target_rate,
+ unsigned long parent_rate)
+{
+ int r = 0, carry = 0;
+
+ /* Unscale m and round if necessary */
+ if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
+ carry = 1;
+ *m = (*m / DPLL_SCALE_FACTOR) + carry;
+
+ /*
+ * The new rate must be <= the target rate to avoid programming
+ * a rate that is impossible for the hardware to handle
+ */
+ *new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
+ if (*new_rate > target_rate) {
+ (*m)--;
+ *new_rate = 0;
+ }
+
+ /* Guard against m underflow */
+ if (*m < DPLL_MIN_MULTIPLIER) {
+ *m = DPLL_MIN_MULTIPLIER;
+ *new_rate = 0;
+ r = DPLL_MULT_UNDERFLOW;
+ }
+
+ if (*new_rate == 0)
+ *new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
+
+ return r;
+}
+
+/**
+ * _omap2_dpll_is_in_bypass - check if DPLL is in bypass mode or not
+ * @v: bitfield value of the DPLL enable
+ *
+ * Checks given DPLL enable bitfield to see whether the DPLL is in bypass
+ * mode or not. Returns 1 if the DPLL is in bypass, 0 otherwise.
+ */
+static int _omap2_dpll_is_in_bypass(u32 v)
+{
+ u8 mask, val;
+
+ mask = ti_clk_get_features()->dpll_bypass_vals;
+
+ /*
+ * Each set bit in the mask corresponds to a bypass value equal
+ * to the bitshift. Go through each set-bit in the mask and
+ * compare against the given register value.
+ */
+ while (mask) {
+ val = __ffs(mask);
+ mask ^= (1 << val);
+ if (v == val)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Public functions */
+u8 omap2_init_dpll_parent(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ u32 v;
+ struct dpll_data *dd;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ v = ti_clk_ll_ops->clk_readl(dd->control_reg);
+ v &= dd->enable_mask;
+ v >>= __ffs(dd->enable_mask);
+
+ /* Reparent the struct clk in case the dpll is in bypass */
+ if (_omap2_dpll_is_in_bypass(v))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
+ * @clk: struct clk * of a DPLL
+ *
+ * DPLLs can be locked or bypassed - basically, enabled or disabled.
+ * When locked, the DPLL output depends on the M and N values. When
+ * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
+ * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
+ * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
+ * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
+ * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
+ * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
+ * if the clock @clk is not a DPLL.
+ */
+unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
+{
+ long long dpll_clk;
+ u32 dpll_mult, dpll_div, v;
+ struct dpll_data *dd;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return 0;
+
+ /* Return bypass rate if DPLL is bypassed */
+ v = ti_clk_ll_ops->clk_readl(dd->control_reg);
+ v &= dd->enable_mask;
+ v >>= __ffs(dd->enable_mask);
+
+ if (_omap2_dpll_is_in_bypass(v))
+ return clk_get_rate(dd->clk_bypass);
+
+ v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg);
+ dpll_mult = v & dd->mult_mask;
+ dpll_mult >>= __ffs(dd->mult_mask);
+ dpll_div = v & dd->div1_mask;
+ dpll_div >>= __ffs(dd->div1_mask);
+
+ dpll_clk = (long long)clk_get_rate(dd->clk_ref) * dpll_mult;
+ do_div(dpll_clk, dpll_div + 1);
+
+ return dpll_clk;
+}
+
+/* DPLL rate rounding code */
+
+/**
+ * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
+ * @clk: struct clk * for a DPLL
+ * @target_rate: desired DPLL clock rate
+ *
+ * Given a DPLL and a desired target rate, round the target rate to a
+ * possible, programmable rate for this DPLL. Attempts to select the
+ * minimum possible n. Stores the computed (m, n) in the DPLL's
+ * dpll_data structure so set_rate() will not need to call this
+ * (expensive) function again. Returns ~0 if the target rate cannot
+ * be rounded, or the rounded rate upon success.
+ */
+long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
+ unsigned long *parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ int m, n, r, scaled_max_m;
+ int min_delta_m = INT_MAX, min_delta_n = INT_MAX;
+ unsigned long scaled_rt_rp;
+ unsigned long new_rate = 0;
+ struct dpll_data *dd;
+ unsigned long ref_rate;
+ long delta;
+ long prev_min_delta = LONG_MAX;
+ const char *clk_name;
+
+ if (!clk || !clk->dpll_data)
+ return ~0;
+
+ dd = clk->dpll_data;
+
+ ref_rate = clk_get_rate(dd->clk_ref);
+ clk_name = clk_hw_get_name(hw);
+ pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n",
+ clk_name, target_rate);
+
+ scaled_rt_rp = target_rate / (ref_rate / DPLL_SCALE_FACTOR);
+ scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
+
+ dd->last_rounded_rate = 0;
+
+ for (n = dd->min_divider; n <= dd->max_divider; n++) {
+ /* Is the (input clk, divider) pair valid for the DPLL? */
+ r = _dpll_test_fint(clk, n);
+ if (r == DPLL_FINT_UNDERFLOW)
+ break;
+ else if (r == DPLL_FINT_INVALID)
+ continue;
+
+ /* Compute the scaled DPLL multiplier, based on the divider */
+ m = scaled_rt_rp * n;
+
+ /*
+ * Since we're counting n up, a m overflow means we
+ * can bail out completely (since as n increases in
+ * the next iteration, there's no way that m can
+ * increase beyond the current m)
+ */
+ if (m > scaled_max_m)
+ break;
+
+ r = _dpll_test_mult(&m, n, &new_rate, target_rate,
+ ref_rate);
+
+ /* m can't be set low enough for this n - try with a larger n */
+ if (r == DPLL_MULT_UNDERFLOW)
+ continue;
+
+ /* skip rates above our target rate */
+ delta = target_rate - new_rate;
+ if (delta < 0)
+ continue;
+
+ if (delta < prev_min_delta) {
+ prev_min_delta = delta;
+ min_delta_m = m;
+ min_delta_n = n;
+ }
+
+ pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n",
+ clk_name, m, n, new_rate);
+
+ if (delta == 0)
+ break;
+ }
+
+ if (prev_min_delta == LONG_MAX) {
+ pr_debug("clock: %s: cannot round to rate %lu\n",
+ clk_name, target_rate);
+ return ~0;
+ }
+
+ dd->last_rounded_m = min_delta_m;
+ dd->last_rounded_n = min_delta_n;
+ dd->last_rounded_rate = target_rate - prev_min_delta;
+
+ return dd->last_rounded_rate;
+}
diff --git a/drivers/clk/ti/clkt_iclk.c b/drivers/clk/ti/clkt_iclk.c
new file mode 100644
index 000000000000..38c36908cf88
--- /dev/null
+++ b/drivers/clk/ti/clkt_iclk.c
@@ -0,0 +1,101 @@
+/*
+ * OMAP2/3 interface clock control
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Paul Walmsley
+ *
+ * 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.
+ */
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/clk/ti.h>
+
+#include "clock.h"
+
+/* Register offsets */
+#define OMAP24XX_CM_FCLKEN2 0x04
+#define CM_AUTOIDLE 0x30
+#define CM_ICLKEN 0x10
+#define CM_IDLEST 0x20
+
+#define OMAP24XX_CM_IDLEST_VAL 0
+
+/* Private functions */
+
+/* XXX */
+void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk)
+{
+ u32 v;
+ void __iomem *r;
+
+ r = (__force void __iomem *)
+ ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
+
+ v = ti_clk_ll_ops->clk_readl(r);
+ v |= (1 << clk->enable_bit);
+ ti_clk_ll_ops->clk_writel(v, r);
+}
+
+/* XXX */
+void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk)
+{
+ u32 v;
+ void __iomem *r;
+
+ r = (__force void __iomem *)
+ ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
+
+ v = ti_clk_ll_ops->clk_readl(r);
+ v &= ~(1 << clk->enable_bit);
+ ti_clk_ll_ops->clk_writel(v, r);
+}
+
+/**
+ * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS
+ * @clk: struct clk * being enabled
+ * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
+ * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
+ * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
+ *
+ * OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the
+ * CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function
+ * passes back the correct CM_IDLEST register address for I2CHS
+ * modules. No return value.
+ */
+static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg,
+ u8 *idlest_bit,
+ u8 *idlest_val)
+{
+ u32 r;
+
+ r = ((__force u32)clk->enable_reg ^ (OMAP24XX_CM_FCLKEN2 ^ CM_IDLEST));
+ *idlest_reg = (__force void __iomem *)r;
+ *idlest_bit = clk->enable_bit;
+ *idlest_val = OMAP24XX_CM_IDLEST_VAL;
+}
+
+/* Public data */
+
+const struct clk_hw_omap_ops clkhwops_iclk = {
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
+
+const struct clk_hw_omap_ops clkhwops_iclk_wait = {
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+ .find_idlest = omap2_clk_dflt_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
+
+/* 2430 I2CHS has non-standard IDLEST register */
+const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = {
+ .find_idlest = omap2430_clk_i2chs_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+};
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
index 404158d2d7f8..90f3f472ae1c 100644
--- a/drivers/clk/ti/clock.h
+++ b/drivers/clk/ti/clock.h
@@ -154,6 +154,35 @@ struct ti_clk_dpll {
u8 recal_st_bit;
};
+/* Composite clock component types */
+enum {
+ CLK_COMPONENT_TYPE_GATE = 0,
+ CLK_COMPONENT_TYPE_DIVIDER,
+ CLK_COMPONENT_TYPE_MUX,
+ CLK_COMPONENT_TYPE_MAX,
+};
+
+/**
+ * struct ti_dt_clk - OMAP DT clock alias declarations
+ * @lk: clock lookup definition
+ * @node_name: clock DT node to map to
+ */
+struct ti_dt_clk {
+ struct clk_lookup lk;
+ char *node_name;
+};
+
+#define DT_CLK(dev, con, name) \
+ { \
+ .lk = { \
+ .dev_id = dev, \
+ .con_id = con, \
+ }, \
+ .node_name = name, \
+ }
+
+typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *);
+
struct clk *ti_clk_register_gate(struct ti_clk *setup);
struct clk *ti_clk_register_interface(struct ti_clk *setup);
struct clk *ti_clk_register_mux(struct ti_clk *setup);
@@ -169,4 +198,80 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch);
struct clk *ti_clk_register_clk(struct ti_clk *setup);
int ti_clk_register_legacy_clks(struct ti_clk_alias *clks);
+void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index);
+void ti_dt_clocks_register(struct ti_dt_clk *oclks);
+int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
+ ti_of_clk_init_cb_t func);
+int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type);
+
+void omap2_init_clk_hw_omap_clocks(struct clk_hw *hw);
+int of_ti_clk_autoidle_setup(struct device_node *node);
+void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
+
+extern const struct clk_hw_omap_ops clkhwops_omap3_dpll;
+extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx;
+extern const struct clk_hw_omap_ops clkhwops_wait;
+extern const struct clk_hw_omap_ops clkhwops_iclk;
+extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait;
+extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
+extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait;
+
+extern const struct clk_ops ti_clk_divider_ops;
+extern const struct clk_ops ti_clk_mux_ops;
+
+int omap2_clkops_enable_clkdm(struct clk_hw *hw);
+void omap2_clkops_disable_clkdm(struct clk_hw *hw);
+
+int omap2_dflt_clk_enable(struct clk_hw *hw);
+void omap2_dflt_clk_disable(struct clk_hw *hw);
+int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
+void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
+ void __iomem **other_reg,
+ u8 *other_bit);
+void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
+ void __iomem **idlest_reg,
+ u8 *idlest_bit, u8 *idlest_val);
+
+void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk);
+void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk);
+
+u8 omap2_init_dpll_parent(struct clk_hw *hw);
+int omap3_noncore_dpll_enable(struct clk_hw *hw);
+void omap3_noncore_dpll_disable(struct clk_hw *hw);
+int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index);
+int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate,
+ u8 index);
+int omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req);
+long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
+ unsigned long *parent_rate);
+unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
+ unsigned long parent_rate);
+
+unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
+int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
+ unsigned long parent_rate);
+int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index);
+void omap3_clk_lock_dpll5(void);
+
+unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
+ unsigned long parent_rate);
+long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
+ unsigned long target_rate,
+ unsigned long *parent_rate);
+int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req);
+
+extern struct ti_clk_ll_ops *ti_clk_ll_ops;
+
#endif
diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c
index b82ef07f3403..b9bc3b8df659 100644
--- a/drivers/clk/ti/clockdomain.c
+++ b/drivers/clk/ti/clockdomain.c
@@ -15,15 +15,94 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
+/**
+ * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
+ * @hw: struct clk_hw * of the clock being enabled
+ *
+ * Increment the usecount of the clockdomain of the clock pointed to
+ * by @hw; if the usecount is 1, the clockdomain will be "enabled."
+ * Only needed for clocks that don't use omap2_dflt_clk_enable() as
+ * their enable function pointer. Passes along the return value of
+ * clkdm_clk_enable(), -EINVAL if @hw is not associated with a
+ * clockdomain, or 0 if clock framework-based clockdomain control is
+ * not implemented.
+ */
+int omap2_clkops_enable_clkdm(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk;
+ int ret = 0;
+
+ clk = to_clk_hw_omap(hw);
+
+ if (unlikely(!clk->clkdm)) {
+ pr_err("%s: %s: no clkdm set ?!\n", __func__,
+ clk_hw_get_name(hw));
+ return -EINVAL;
+ }
+
+ if (unlikely(clk->enable_reg))
+ pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__,
+ clk_hw_get_name(hw));
+
+ if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
+ pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
+ __func__, clk_hw_get_name(hw));
+ return 0;
+ }
+
+ ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
+ WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
+ __func__, clk_hw_get_name(hw), clk->clkdm_name, ret);
+
+ return ret;
+}
+
+/**
+ * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
+ * @hw: struct clk_hw * of the clock being disabled
+ *
+ * Decrement the usecount of the clockdomain of the clock pointed to
+ * by @hw; if the usecount is 0, the clockdomain will be "disabled."
+ * Only needed for clocks that don't use omap2_dflt_clk_disable() as their
+ * disable function pointer. No return value.
+ */
+void omap2_clkops_disable_clkdm(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk;
+
+ clk = to_clk_hw_omap(hw);
+
+ if (unlikely(!clk->clkdm)) {
+ pr_err("%s: %s: no clkdm set ?!\n", __func__,
+ clk_hw_get_name(hw));
+ return;
+ }
+
+ if (unlikely(clk->enable_reg))
+ pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__,
+ clk_hw_get_name(hw));
+
+ if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
+ pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
+ __func__, clk_hw_get_name(hw));
+ return;
+ }
+
+ ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
+}
+
static void __init of_ti_clockdomain_setup(struct device_node *node)
{
struct clk *clk;
@@ -41,12 +120,12 @@ static void __init of_ti_clockdomain_setup(struct device_node *node)
__func__, node->full_name, i, PTR_ERR(clk));
continue;
}
- if (__clk_get_flags(clk) & CLK_IS_BASIC) {
+ clk_hw = __clk_get_hw(clk);
+ if (clk_hw_get_flags(clk_hw) & CLK_IS_BASIC) {
pr_warn("can't setup clkdm for basic clk %s\n",
__clk_get_name(clk));
continue;
}
- clk_hw = __clk_get_hw(clk);
to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name;
omap2_init_clk_clkdm(clk_hw);
}
diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c
index 96f83cedb4b3..dbef218fe5ec 100644
--- a/drivers/clk/ti/composite.c
+++ b/drivers/clk/ti/composite.c
@@ -276,7 +276,6 @@ int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,
int num_parents;
const char **parent_names;
struct component_clk *clk;
- int i;
num_parents = of_clk_get_parent_count(node);
@@ -289,8 +288,7 @@ int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,
if (!parent_names)
return -ENOMEM;
- for (i = 0; i < num_parents; i++)
- parent_names[i] = of_clk_get_parent_name(node, i);
+ of_clk_parent_fill(node, parent_names, num_parents);
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index ff5f117950a9..5b1726829e6d 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -109,7 +109,7 @@ static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw,
if (!div) {
WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
- __clk_get_name(hw->clk));
+ clk_hw_get_name(hw));
return parent_rate;
}
@@ -155,7 +155,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
maxdiv = _get_maxdiv(divider);
- if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
+ if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
bestdiv = DIV_ROUND_UP(parent_rate, rate);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
@@ -181,7 +181,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
*best_parent_rate = parent_rate_saved;
return i;
}
- parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+ parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
MULT_ROUND_UP(rate, i));
now = DIV_ROUND_UP(parent_rate, i);
if (now <= rate && now > best) {
@@ -194,7 +194,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!bestdiv) {
bestdiv = _get_maxdiv(divider);
*best_parent_rate =
- __clk_round_rate(__clk_get_parent(hw->clk), 1);
+ clk_hw_round_rate(clk_hw_get_parent(hw), 1);
}
return bestdiv;
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 2aacf7a3bcae..5519b386edc0 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -15,6 +15,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -162,7 +163,7 @@ static void __init _register_dpll(struct clk_hw *hw,
clk = clk_register(NULL, &clk_hw->hw);
if (!IS_ERR(clk)) {
- omap2_init_clk_hw_omap_clocks(clk);
+ omap2_init_clk_hw_omap_clocks(&clk_hw->hw);
of_clk_add_provider(node, of_clk_src_simple_get, clk);
kfree(clk_hw->hw.init->parent_names);
kfree(clk_hw->hw.init);
@@ -319,7 +320,7 @@ static void _register_dpll_x2(struct device_node *node,
if (IS_ERR(clk)) {
kfree(clk_hw);
} else {
- omap2_init_clk_hw_omap_clocks(clk);
+ omap2_init_clk_hw_omap_clocks(&clk_hw->hw);
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
}
@@ -341,7 +342,6 @@ static void __init of_ti_dpll_setup(struct device_node *node,
struct clk_init_data *init = NULL;
const char **parent_names = NULL;
struct dpll_data *dd = NULL;
- int i;
u8 dpll_mode = 0;
dd = kzalloc(sizeof(*dd), GFP_KERNEL);
@@ -370,8 +370,7 @@ static void __init of_ti_dpll_setup(struct device_node *node,
if (!parent_names)
goto cleanup;
- for (i = 0; i < init->num_parents; i++)
- parent_names[i] = of_clk_get_parent_name(node, i);
+ of_clk_parent_fill(node, parent_names, init->num_parents);
init->parent_names = parent_names;
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
new file mode 100644
index 000000000000..f4dec00fb684
--- /dev/null
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -0,0 +1,817 @@
+/*
+ * OMAP3/4 - specific DPLL control functions
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Testing and integration fixes by Jouni Högander
+ *
+ * 36xx support added by Vishwanath BS, Richard Woodruff, and Nishanth
+ * Menon
+ *
+ * Parts of this code are based on code written by
+ * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/clkdev.h>
+#include <linux/clk/ti.h>
+
+#include "clock.h"
+
+/* CM_AUTOIDLE_PLL*.AUTO_* bit values */
+#define DPLL_AUTOIDLE_DISABLE 0x0
+#define DPLL_AUTOIDLE_LOW_POWER_STOP 0x1
+
+#define MAX_DPLL_WAIT_TRIES 1000000
+
+#define OMAP3XXX_EN_DPLL_LOCKED 0x7
+
+/* Forward declarations */
+static u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk);
+static void omap3_dpll_deny_idle(struct clk_hw_omap *clk);
+static void omap3_dpll_allow_idle(struct clk_hw_omap *clk);
+
+/* Private functions */
+
+/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
+static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits)
+{
+ const struct dpll_data *dd;
+ u32 v;
+
+ dd = clk->dpll_data;
+
+ v = ti_clk_ll_ops->clk_readl(dd->control_reg);
+ v &= ~dd->enable_mask;
+ v |= clken_bits << __ffs(dd->enable_mask);
+ ti_clk_ll_ops->clk_writel(v, dd->control_reg);
+}
+
+/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
+static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state)
+{
+ const struct dpll_data *dd;
+ int i = 0;
+ int ret = -EINVAL;
+ const char *clk_name;
+
+ dd = clk->dpll_data;
+ clk_name = clk_hw_get_name(&clk->hw);
+
+ state <<= __ffs(dd->idlest_mask);
+
+ while (((ti_clk_ll_ops->clk_readl(dd->idlest_reg) & dd->idlest_mask)
+ != state) && i < MAX_DPLL_WAIT_TRIES) {
+ i++;
+ udelay(1);
+ }
+
+ if (i == MAX_DPLL_WAIT_TRIES) {
+ pr_err("clock: %s failed transition to '%s'\n",
+ clk_name, (state) ? "locked" : "bypassed");
+ } else {
+ pr_debug("clock: %s transition to '%s' in %d loops\n",
+ clk_name, (state) ? "locked" : "bypassed", i);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/* From 3430 TRM ES2 4.7.6.2 */
+static u16 _omap3_dpll_compute_freqsel(struct clk_hw_omap *clk, u8 n)
+{
+ unsigned long fint;
+ u16 f = 0;
+
+ fint = clk_get_rate(clk->dpll_data->clk_ref) / n;
+
+ pr_debug("clock: fint is %lu\n", fint);
+
+ if (fint >= 750000 && fint <= 1000000)
+ f = 0x3;
+ else if (fint > 1000000 && fint <= 1250000)
+ f = 0x4;
+ else if (fint > 1250000 && fint <= 1500000)
+ f = 0x5;
+ else if (fint > 1500000 && fint <= 1750000)
+ f = 0x6;
+ else if (fint > 1750000 && fint <= 2100000)
+ f = 0x7;
+ else if (fint > 7500000 && fint <= 10000000)
+ f = 0xB;
+ else if (fint > 10000000 && fint <= 12500000)
+ f = 0xC;
+ else if (fint > 12500000 && fint <= 15000000)
+ f = 0xD;
+ else if (fint > 15000000 && fint <= 17500000)
+ f = 0xE;
+ else if (fint > 17500000 && fint <= 21000000)
+ f = 0xF;
+ else
+ pr_debug("clock: unknown freqsel setting for %d\n", n);
+
+ return f;
+}
+
+/*
+ * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to lock. Waits for the DPLL to report
+ * readiness before returning. Will save and restore the DPLL's
+ * autoidle state across the enable, per the CDP code. If the DPLL
+ * locked successfully, return 0; if the DPLL did not lock in the time
+ * allotted, or DPLL3 was passed in, return -EINVAL.
+ */
+static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk)
+{
+ const struct dpll_data *dd;
+ u8 ai;
+ u8 state = 1;
+ int r = 0;
+
+ pr_debug("clock: locking DPLL %s\n", clk_hw_get_name(&clk->hw));
+
+ dd = clk->dpll_data;
+ state <<= __ffs(dd->idlest_mask);
+
+ /* Check if already locked */
+ if ((ti_clk_ll_ops->clk_readl(dd->idlest_reg) & dd->idlest_mask) ==
+ state)
+ goto done;
+
+ ai = omap3_dpll_autoidle_read(clk);
+
+ if (ai)
+ omap3_dpll_deny_idle(clk);
+
+ _omap3_dpll_write_clken(clk, DPLL_LOCKED);
+
+ r = _omap3_wait_dpll_status(clk, 1);
+
+ if (ai)
+ omap3_dpll_allow_idle(clk);
+
+done:
+ return r;
+}
+
+/*
+ * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enter low-power bypass mode. In
+ * bypass mode, the DPLL's rate is set equal to its parent clock's
+ * rate. Waits for the DPLL to report readiness before returning.
+ * Will save and restore the DPLL's autoidle state across the enable,
+ * per the CDP code. If the DPLL entered bypass mode successfully,
+ * return 0; if the DPLL did not enter bypass in the time allotted, or
+ * DPLL3 was passed in, or the DPLL does not support low-power bypass,
+ * return -EINVAL.
+ */
+static int _omap3_noncore_dpll_bypass(struct clk_hw_omap *clk)
+{
+ int r;
+ u8 ai;
+
+ if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS)))
+ return -EINVAL;
+
+ pr_debug("clock: configuring DPLL %s for low-power bypass\n",
+ clk_hw_get_name(&clk->hw));
+
+ ai = omap3_dpll_autoidle_read(clk);
+
+ _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_BYPASS);
+
+ r = _omap3_wait_dpll_status(clk, 0);
+
+ if (ai)
+ omap3_dpll_allow_idle(clk);
+
+ return r;
+}
+
+/*
+ * _omap3_noncore_dpll_stop - instruct a DPLL to stop
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enter low-power stop. Will save and
+ * restore the DPLL's autoidle state across the stop, per the CDP
+ * code. If DPLL3 was passed in, or the DPLL does not support
+ * low-power stop, return -EINVAL; otherwise, return 0.
+ */
+static int _omap3_noncore_dpll_stop(struct clk_hw_omap *clk)
+{
+ u8 ai;
+
+ if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP)))
+ return -EINVAL;
+
+ pr_debug("clock: stopping DPLL %s\n", clk_hw_get_name(&clk->hw));
+
+ ai = omap3_dpll_autoidle_read(clk);
+
+ _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_STOP);
+
+ if (ai)
+ omap3_dpll_allow_idle(clk);
+
+ return 0;
+}
+
+/**
+ * _lookup_dco - Lookup DCO used by j-type DPLL
+ * @clk: pointer to a DPLL struct clk
+ * @dco: digital control oscillator selector
+ * @m: DPLL multiplier to set
+ * @n: DPLL divider to set
+ *
+ * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
+ *
+ * XXX This code is not needed for 3430/AM35xx; can it be optimized
+ * out in non-multi-OMAP builds for those chips?
+ */
+static void _lookup_dco(struct clk_hw_omap *clk, u8 *dco, u16 m, u8 n)
+{
+ unsigned long fint, clkinp; /* watch out for overflow */
+
+ clkinp = clk_hw_get_rate(clk_hw_get_parent(&clk->hw));
+ fint = (clkinp / n) * m;
+
+ if (fint < 1000000000)
+ *dco = 2;
+ else
+ *dco = 4;
+}
+
+/**
+ * _lookup_sddiv - Calculate sigma delta divider for j-type DPLL
+ * @clk: pointer to a DPLL struct clk
+ * @sd_div: target sigma-delta divider
+ * @m: DPLL multiplier to set
+ * @n: DPLL divider to set
+ *
+ * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
+ *
+ * XXX This code is not needed for 3430/AM35xx; can it be optimized
+ * out in non-multi-OMAP builds for those chips?
+ */
+static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
+{
+ unsigned long clkinp, sd; /* watch out for overflow */
+ int mod1, mod2;
+
+ clkinp = clk_hw_get_rate(clk_hw_get_parent(&clk->hw));
+
+ /*
+ * target sigma-delta to near 250MHz
+ * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)]
+ */
+ clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2 */
+ mod1 = (clkinp * m) % (250 * n);
+ sd = (clkinp * m) / (250 * n);
+ mod2 = sd % 10;
+ sd /= 10;
+
+ if (mod1 || mod2)
+ sd++;
+ *sd_div = sd;
+}
+
+/*
+ * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
+ * @clk: struct clk * of DPLL to set
+ * @freqsel: FREQSEL value to set
+ *
+ * Program the DPLL with the last M, N values calculated, and wait for
+ * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success.
+ */
+static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
+{
+ struct dpll_data *dd = clk->dpll_data;
+ u8 dco, sd_div;
+ u32 v;
+
+ /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
+ _omap3_noncore_dpll_bypass(clk);
+
+ /*
+ * Set jitter correction. Jitter correction applicable for OMAP343X
+ * only since freqsel field is no longer present on other devices.
+ */
+ if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) {
+ v = ti_clk_ll_ops->clk_readl(dd->control_reg);
+ v &= ~dd->freqsel_mask;
+ v |= freqsel << __ffs(dd->freqsel_mask);
+ ti_clk_ll_ops->clk_writel(v, dd->control_reg);
+ }
+
+ /* Set DPLL multiplier, divider */
+ v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg);
+
+ /* Handle Duty Cycle Correction */
+ if (dd->dcc_mask) {
+ if (dd->last_rounded_rate >= dd->dcc_rate)
+ v |= dd->dcc_mask; /* Enable DCC */
+ else
+ v &= ~dd->dcc_mask; /* Disable DCC */
+ }
+
+ v &= ~(dd->mult_mask | dd->div1_mask);
+ v |= dd->last_rounded_m << __ffs(dd->mult_mask);
+ v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
+
+ /* Configure dco and sd_div for dplls that have these fields */
+ if (dd->dco_mask) {
+ _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n);
+ v &= ~(dd->dco_mask);
+ v |= dco << __ffs(dd->dco_mask);
+ }
+ if (dd->sddiv_mask) {
+ _lookup_sddiv(clk, &sd_div, dd->last_rounded_m,
+ dd->last_rounded_n);
+ v &= ~(dd->sddiv_mask);
+ v |= sd_div << __ffs(dd->sddiv_mask);
+ }
+
+ ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg);
+
+ /* Set 4X multiplier and low-power mode */
+ if (dd->m4xen_mask || dd->lpmode_mask) {
+ v = ti_clk_ll_ops->clk_readl(dd->control_reg);
+
+ if (dd->m4xen_mask) {
+ if (dd->last_rounded_m4xen)
+ v |= dd->m4xen_mask;
+ else
+ v &= ~dd->m4xen_mask;
+ }
+
+ if (dd->lpmode_mask) {
+ if (dd->last_rounded_lpmode)
+ v |= dd->lpmode_mask;
+ else
+ v &= ~dd->lpmode_mask;
+ }
+
+ ti_clk_ll_ops->clk_writel(v, dd->control_reg);
+ }
+
+ /* We let the clock framework set the other output dividers later */
+
+ /* REVISIT: Set ramp-up delay? */
+
+ _omap3_noncore_dpll_lock(clk);
+
+ return 0;
+}
+
+/* Public functions */
+
+/**
+ * omap3_dpll_recalc - recalculate DPLL rate
+ * @clk: DPLL struct clk
+ *
+ * Recalculate and propagate the DPLL rate.
+ */
+unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+
+ return omap2_get_dpll_rate(clk);
+}
+
+/* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */
+
+/**
+ * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
+ * The choice of modes depends on the DPLL's programmed rate: if it is
+ * the same as the DPLL's parent clock, it will enter bypass;
+ * otherwise, it will enter lock. This code will wait for the DPLL to
+ * indicate readiness before returning, unless the DPLL takes too long
+ * to enter the target state. Intended to be used as the struct clk's
+ * enable function. If DPLL3 was passed in, or the DPLL does not
+ * support low-power stop, or if the DPLL took too long to enter
+ * bypass or lock, return -EINVAL; otherwise, return 0.
+ */
+int omap3_noncore_dpll_enable(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ int r;
+ struct dpll_data *dd;
+ struct clk_hw *parent;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (clk->clkdm) {
+ r = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
+ if (r) {
+ WARN(1,
+ "%s: could not enable %s's clockdomain %s: %d\n",
+ __func__, clk_hw_get_name(hw),
+ clk->clkdm_name, r);
+ return r;
+ }
+ }
+
+ parent = clk_hw_get_parent(hw);
+
+ if (clk_hw_get_rate(hw) == clk_get_rate(dd->clk_bypass)) {
+ WARN_ON(parent != __clk_get_hw(dd->clk_bypass));
+ r = _omap3_noncore_dpll_bypass(clk);
+ } else {
+ WARN_ON(parent != __clk_get_hw(dd->clk_ref));
+ r = _omap3_noncore_dpll_lock(clk);
+ }
+
+ return r;
+}
+
+/**
+ * omap3_noncore_dpll_disable - instruct a DPLL to enter low-power stop
+ * @clk: pointer to a DPLL struct clk
+ *
+ * Instructs a non-CORE DPLL to enter low-power stop. This function is
+ * intended for use in struct clkops. No return value.
+ */
+void omap3_noncore_dpll_disable(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+
+ _omap3_noncore_dpll_stop(clk);
+ if (clk->clkdm)
+ ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
+}
+
+/* Non-CORE DPLL rate set code */
+
+/**
+ * omap3_noncore_dpll_determine_rate - determine rate for a DPLL
+ * @hw: pointer to the clock to determine rate for
+ * @req: target rate request
+ *
+ * Determines which DPLL mode to use for reaching a desired target rate.
+ * Checks whether the DPLL shall be in bypass or locked mode, and if
+ * locked, calculates the M,N values for the DPLL via round-rate.
+ * Returns a 0 on success, negative error value in failure.
+ */
+int omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+
+ if (!req->rate)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (clk_get_rate(dd->clk_bypass) == req->rate &&
+ (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
+ req->best_parent_hw = __clk_get_hw(dd->clk_bypass);
+ } else {
+ req->rate = omap2_dpll_round_rate(hw, req->rate,
+ &req->best_parent_rate);
+ req->best_parent_hw = __clk_get_hw(dd->clk_ref);
+ }
+
+ req->best_parent_rate = req->rate;
+
+ return 0;
+}
+
+/**
+ * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
+ * @hw: pointer to the clock to set parent for
+ * @index: parent index to select
+ *
+ * Sets parent for a DPLL clock. This sets the DPLL into bypass or
+ * locked mode. Returns 0 with success, negative error value otherwise.
+ */
+int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ int ret;
+
+ if (!hw)
+ return -EINVAL;
+
+ if (index)
+ ret = _omap3_noncore_dpll_bypass(clk);
+ else
+ ret = _omap3_noncore_dpll_lock(clk);
+
+ return ret;
+}
+
+/**
+ * omap3_noncore_dpll_set_rate - set rate for a DPLL clock
+ * @hw: pointer to the clock to set parent for
+ * @rate: target rate for the clock
+ * @parent_rate: rate of the parent clock
+ *
+ * Sets rate for a DPLL clock. First checks if the clock parent is
+ * reference clock (in bypass mode, the rate of the clock can't be
+ * changed) and proceeds with the rate change operation. Returns 0
+ * with success, negative error value otherwise.
+ */
+int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+ u16 freqsel = 0;
+ int ret;
+
+ if (!hw || !rate)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (clk_hw_get_parent(hw) != __clk_get_hw(dd->clk_ref))
+ return -EINVAL;
+
+ if (dd->last_rounded_rate == 0)
+ return -EINVAL;
+
+ /* Freqsel is available only on OMAP343X devices */
+ if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) {
+ freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
+ WARN_ON(!freqsel);
+ }
+
+ pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
+ clk_hw_get_name(hw), rate);
+
+ ret = omap3_noncore_dpll_program(clk, freqsel);
+
+ return ret;
+}
+
+/**
+ * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
+ * @hw: pointer to the clock to set rate and parent for
+ * @rate: target rate for the DPLL
+ * @parent_rate: clock rate of the DPLL parent
+ * @index: new parent index for the DPLL, 0 - reference, 1 - bypass
+ *
+ * Sets rate and parent for a DPLL clock. If new parent is the bypass
+ * clock, only selects the parent. Otherwise proceeds with a rate
+ * change, as this will effectively also change the parent as the
+ * DPLL is put into locked mode. Returns 0 with success, negative error
+ * value otherwise.
+ */
+int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate,
+ u8 index)
+{
+ int ret;
+
+ if (!hw || !rate)
+ return -EINVAL;
+
+ /*
+ * clk-ref at index[0], in which case we only need to set rate,
+ * the parent will be changed automatically with the lock sequence.
+ * With clk-bypass case we only need to change parent.
+ */
+ if (index)
+ ret = omap3_noncore_dpll_set_parent(hw, index);
+ else
+ ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
+
+ return ret;
+}
+
+/* DPLL autoidle read/set code */
+
+/**
+ * omap3_dpll_autoidle_read - read a DPLL's autoidle bits
+ * @clk: struct clk * of the DPLL to read
+ *
+ * Return the DPLL's autoidle bits, shifted down to bit 0. Returns
+ * -EINVAL if passed a null pointer or if the struct clk does not
+ * appear to refer to a DPLL.
+ */
+static u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk)
+{
+ const struct dpll_data *dd;
+ u32 v;
+
+ if (!clk || !clk->dpll_data)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+
+ if (!dd->autoidle_reg)
+ return -EINVAL;
+
+ v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg);
+ v &= dd->autoidle_mask;
+ v >>= __ffs(dd->autoidle_mask);
+
+ return v;
+}
+
+/**
+ * omap3_dpll_allow_idle - enable DPLL autoidle bits
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Enable DPLL automatic idle control. This automatic idle mode
+ * switching takes effect only when the DPLL is locked, at least on
+ * OMAP3430. The DPLL will enter low-power stop when its downstream
+ * clocks are gated. No return value.
+ */
+static void omap3_dpll_allow_idle(struct clk_hw_omap *clk)
+{
+ const struct dpll_data *dd;
+ u32 v;
+
+ if (!clk || !clk->dpll_data)
+ return;
+
+ dd = clk->dpll_data;
+
+ if (!dd->autoidle_reg)
+ return;
+
+ /*
+ * REVISIT: CORE DPLL can optionally enter low-power bypass
+ * by writing 0x5 instead of 0x1. Add some mechanism to
+ * optionally enter this mode.
+ */
+ v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg);
+ v &= ~dd->autoidle_mask;
+ v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
+ ti_clk_ll_ops->clk_writel(v, dd->autoidle_reg);
+}
+
+/**
+ * omap3_dpll_deny_idle - prevent DPLL from automatically idling
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Disable DPLL automatic idle control. No return value.
+ */
+static void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
+{
+ const struct dpll_data *dd;
+ u32 v;
+
+ if (!clk || !clk->dpll_data)
+ return;
+
+ dd = clk->dpll_data;
+
+ if (!dd->autoidle_reg)
+ return;
+
+ v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg);
+ v &= ~dd->autoidle_mask;
+ v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
+ ti_clk_ll_ops->clk_writel(v, dd->autoidle_reg);
+}
+
+/* Clock control for DPLL outputs */
+
+/* Find the parent DPLL for the given clkoutx2 clock */
+static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw)
+{
+ struct clk_hw_omap *pclk = NULL;
+
+ /* Walk up the parents of clk, looking for a DPLL */
+ do {
+ do {
+ hw = clk_hw_get_parent(hw);
+ } while (hw && (clk_hw_get_flags(hw) & CLK_IS_BASIC));
+ if (!hw)
+ break;
+ pclk = to_clk_hw_omap(hw);
+ } while (pclk && !pclk->dpll_data);
+
+ /* clk does not have a DPLL as a parent? error in the clock data */
+ if (!pclk) {
+ WARN_ON(1);
+ return NULL;
+ }
+
+ return pclk;
+}
+
+/**
+ * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
+ * @clk: DPLL output struct clk
+ *
+ * Using parent clock DPLL data, look up DPLL state. If locked, set our
+ * rate to the dpll_clk * 2; otherwise, just use dpll_clk.
+ */
+unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ const struct dpll_data *dd;
+ unsigned long rate;
+ u32 v;
+ struct clk_hw_omap *pclk = NULL;
+
+ if (!parent_rate)
+ return 0;
+
+ pclk = omap3_find_clkoutx2_dpll(hw);
+
+ if (!pclk)
+ return 0;
+
+ dd = pclk->dpll_data;
+
+ WARN_ON(!dd->enable_mask);
+
+ v = ti_clk_ll_ops->clk_readl(dd->control_reg) & dd->enable_mask;
+ v >>= __ffs(dd->enable_mask);
+ if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
+ rate = parent_rate;
+ else
+ rate = parent_rate * 2;
+ return rate;
+}
+
+/* OMAP3/4 non-CORE DPLL clkops */
+const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
+ .allow_idle = omap3_dpll_allow_idle,
+ .deny_idle = omap3_dpll_deny_idle,
+};
+
+/**
+ * omap3_dpll4_set_rate - set rate for omap3 per-dpll
+ * @hw: clock to change
+ * @rate: target rate for clock
+ * @parent_rate: rate of the parent clock
+ *
+ * Check if the current SoC supports the per-dpll reprogram operation
+ * or not, and then do the rate change if supported. Returns -EINVAL
+ * if not supported, 0 for success, and potential error codes from the
+ * clock rate change.
+ */
+int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ /*
+ * According to the 12-5 CDP code from TI, "Limitation 2.5"
+ * on 3430ES1 prevents us from changing DPLL multipliers or dividers
+ * on DPLL4.
+ */
+ if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
+ pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
+ return -EINVAL;
+ }
+
+ return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
+}
+
+/**
+ * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
+ * @hw: clock to change
+ * @rate: target rate for clock
+ * @parent_rate: rate of the parent clock
+ * @index: parent index, 0 - reference clock, 1 - bypass clock
+ *
+ * Check if the current SoC support the per-dpll reprogram operation
+ * or not, and then do the rate + parent change if supported. Returns
+ * -EINVAL if not supported, 0 for success, and potential error codes
+ * from the clock rate change.
+ */
+int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index)
+{
+ if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
+ pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
+ return -EINVAL;
+ }
+
+ return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
+ index);
+}
diff --git a/drivers/clk/ti/dpll44xx.c b/drivers/clk/ti/dpll44xx.c
new file mode 100644
index 000000000000..660d7436ac24
--- /dev/null
+++ b/drivers/clk/ti/dpll44xx.c
@@ -0,0 +1,227 @@
+/*
+ * OMAP4-specific DPLL control functions
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Rajendra Nayak
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/clk/ti.h>
+
+#include "clock.h"
+
+/*
+ * Maximum DPLL input frequency (FINT) and output frequency (FOUT) that
+ * can supported when using the DPLL low-power mode. Frequencies are
+ * defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control,
+ * Status, and Low-Power Operation Mode".
+ */
+#define OMAP4_DPLL_LP_FINT_MAX 1000000
+#define OMAP4_DPLL_LP_FOUT_MAX 100000000
+
+/*
+ * Bitfield declarations
+ */
+#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BIT(8)
+#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BIT(10)
+#define OMAP4430_DPLL_REGM4XEN_MASK BIT(11)
+
+/* Static rate multiplier for OMAP4 REGM4XEN clocks */
+#define OMAP4430_REGM4XEN_MULT 4
+
+static void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg)
+ return;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = ti_clk_ll_ops->clk_readl(clk->clksel_reg);
+ /* Clear the bit to allow gatectrl */
+ v &= ~mask;
+ ti_clk_ll_ops->clk_writel(v, clk->clksel_reg);
+}
+
+static void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg)
+ return;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = ti_clk_ll_ops->clk_readl(clk->clksel_reg);
+ /* Set the bit to deny gatectrl */
+ v |= mask;
+ ti_clk_ll_ops->clk_writel(v, clk->clksel_reg);
+}
+
+const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = {
+ .allow_idle = omap4_dpllmx_allow_gatectrl,
+ .deny_idle = omap4_dpllmx_deny_gatectrl,
+};
+
+/**
+ * omap4_dpll_lpmode_recalc - compute DPLL low-power setting
+ * @dd: pointer to the dpll data structure
+ *
+ * Calculates if low-power mode can be enabled based upon the last
+ * multiplier and divider values calculated. If low-power mode can be
+ * enabled, then the bit to enable low-power mode is stored in the
+ * last_rounded_lpmode variable. This implementation is based upon the
+ * criteria for enabling low-power mode as described in the OMAP4430/60
+ * Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power
+ * Operation Mode".
+ */
+static void omap4_dpll_lpmode_recalc(struct dpll_data *dd)
+{
+ long fint, fout;
+
+ fint = clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1);
+ fout = fint * dd->last_rounded_m;
+
+ if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX))
+ dd->last_rounded_lpmode = 1;
+ else
+ dd->last_rounded_lpmode = 0;
+}
+
+/**
+ * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
+ * @clk: struct clk * of the DPLL to compute the rate for
+ *
+ * Compute the output rate for the OMAP4 DPLL represented by @clk.
+ * Takes the REGM4XEN bit into consideration, which is needed for the
+ * OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers)
+ * upon success, or 0 upon error.
+ */
+unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ u32 v;
+ unsigned long rate;
+ struct dpll_data *dd;
+
+ if (!clk || !clk->dpll_data)
+ return 0;
+
+ dd = clk->dpll_data;
+
+ rate = omap2_get_dpll_rate(clk);
+
+ /* regm4xen adds a multiplier of 4 to DPLL calculations */
+ v = ti_clk_ll_ops->clk_readl(dd->control_reg);
+ if (v & OMAP4430_DPLL_REGM4XEN_MASK)
+ rate *= OMAP4430_REGM4XEN_MULT;
+
+ return rate;
+}
+
+/**
+ * omap4_dpll_regm4xen_round_rate - round DPLL rate, considering REGM4XEN bit
+ * @clk: struct clk * of the DPLL to round a rate for
+ * @target_rate: the desired rate of the DPLL
+ *
+ * Compute the rate that would be programmed into the DPLL hardware
+ * for @clk if set_rate() were to be provided with the rate
+ * @target_rate. Takes the REGM4XEN bit into consideration, which is
+ * needed for the OMAP4 ABE DPLL. Returns the rounded rate (before
+ * M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or
+ * ~0 if an error occurred in omap2_dpll_round_rate().
+ */
+long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
+ unsigned long target_rate,
+ unsigned long *parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+ long r;
+
+ if (!clk || !clk->dpll_data)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+
+ dd->last_rounded_m4xen = 0;
+
+ /*
+ * First try to compute the DPLL configuration for
+ * target rate without using the 4X multiplier.
+ */
+ r = omap2_dpll_round_rate(hw, target_rate, NULL);
+ if (r != ~0)
+ goto out;
+
+ /*
+ * If we did not find a valid DPLL configuration, try again, but
+ * this time see if using the 4X multiplier can help. Enabling the
+ * 4X multiplier is equivalent to dividing the target rate by 4.
+ */
+ r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT,
+ NULL);
+ if (r == ~0)
+ return r;
+
+ dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
+ dd->last_rounded_m4xen = 1;
+
+out:
+ omap4_dpll_lpmode_recalc(dd);
+
+ return dd->last_rounded_rate;
+}
+
+/**
+ * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL
+ * @hw: pointer to the clock to determine rate for
+ * @req: target rate request
+ *
+ * Determines which DPLL mode to use for reaching a desired rate.
+ * Checks whether the DPLL shall be in bypass or locked mode, and if
+ * locked, calculates the M,N values for the DPLL via round-rate.
+ * Returns 0 on success and a negative error value otherwise.
+ */
+int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+
+ if (!req->rate)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (clk_get_rate(dd->clk_bypass) == req->rate &&
+ (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
+ req->best_parent_hw = __clk_get_hw(dd->clk_bypass);
+ } else {
+ req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate,
+ &req->best_parent_rate);
+ req->best_parent_hw = __clk_get_hw(dd->clk_ref);
+ }
+
+ req->best_parent_rate = req->rate;
+
+ return 0;
+}
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
index 730aa62454a2..f4b2e9888bdf 100644
--- a/drivers/clk/ti/fapll.c
+++ b/drivers/clk/ti/fapll.c
@@ -9,6 +9,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -558,8 +559,7 @@ static void __init ti_fapll_setup(struct device_node *node)
goto free;
}
- parent_name[0] = of_clk_get_parent_name(node, 0);
- parent_name[1] = of_clk_get_parent_name(node, 1);
+ of_clk_parent_fill(node, parent_name, 2);
init->parent_names = parent_name;
fd->clk_ref = of_clk_get(node, 0);
diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c
index c2c8a287408c..3cd406768909 100644
--- a/drivers/clk/ti/fixed-factor.c
+++ b/drivers/clk/ti/fixed-factor.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index 0c6fdfcd5f93..5429d3534363 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -62,7 +62,7 @@ static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
* (Any other value different from the Read value) to the
* corresponding CM_CLKSEL register will refresh the dividers.
*/
-static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
+static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *hw)
{
struct clk_divider *parent;
struct clk_hw *parent_hw;
@@ -70,10 +70,10 @@ static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
int ret;
/* Clear PWRDN bit of HSDIVIDER */
- ret = omap2_dflt_clk_enable(clk);
+ ret = omap2_dflt_clk_enable(hw);
/* Parent is the x2 node, get parent of parent for the m2 div */
- parent_hw = __clk_get_hw(__clk_get_parent(__clk_get_parent(clk->clk)));
+ parent_hw = clk_hw_get_parent(clk_hw_get_parent(hw));
parent = to_clk_divider(parent_hw);
/* Restore the dividers */
diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c
index c76230d8dd04..e505e6f8228d 100644
--- a/drivers/clk/ti/interface.c
+++ b/drivers/clk/ti/interface.c
@@ -63,7 +63,7 @@ static struct clk *_register_interface(struct device *dev, const char *name,
if (IS_ERR(clk))
kfree(clk_hw);
else
- omap2_init_clk_hw_omap_clocks(clk);
+ omap2_init_clk_hw_omap_clocks(&clk_hw->hw);
return clk;
}
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index 5cdeed538b08..69f08a1d047d 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -31,7 +31,7 @@
static u8 ti_clk_mux_get_parent(struct clk_hw *hw)
{
struct clk_mux *mux = to_clk_mux(hw);
- int num_parents = __clk_get_num_parents(hw->clk);
+ int num_parents = clk_hw_get_num_parents(hw);
u32 val;
/*
@@ -190,7 +190,6 @@ static void of_mux_clk_setup(struct device_node *node)
void __iomem *reg;
int num_parents;
const char **parent_names;
- int i;
u8 clk_mux_flags = 0;
u32 mask = 0;
u32 shift = 0;
@@ -205,8 +204,7 @@ static void of_mux_clk_setup(struct device_node *node)
if (!parent_names)
goto cleanup;
- for (i = 0; i < num_parents; i++)
- parent_names[i] = of_clk_get_parent_name(node, i);
+ of_clk_parent_fill(node, parent_names, num_parents);
reg = ti_clk_get_reg_addr(node, 0);
diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile
index 521483f0ba33..f3baef29859c 100644
--- a/drivers/clk/ux500/Makefile
+++ b/drivers/clk/ux500/Makefile
@@ -9,7 +9,6 @@ obj-y += clk-sysctrl.o
# Clock definitions
obj-y += u8500_of_clk.o
-obj-y += u8500_clk.o
obj-y += u9540_clk.o
obj-y += u8540_clk.o
diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c
index 3e5e05101302..222425d08ab6 100644
--- a/drivers/clk/ux500/abx500-clk.c
+++ b/drivers/clk/ux500/abx500-clk.c
@@ -13,7 +13,6 @@
#include <linux/platform_device.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index bf63c96acb1a..7f343821f4e4 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -43,7 +43,7 @@ static void clk_prcmu_unprepare(struct clk_hw *hw)
struct clk_prcmu *clk = to_clk_prcmu(hw);
if (prcmu_request_clock(clk->cg_sel, false))
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
- __clk_get_name(hw->clk));
+ clk_hw_get_name(hw));
else
clk->is_prepared = 0;
}
@@ -101,11 +101,11 @@ static int clk_prcmu_opp_prepare(struct clk_hw *hw)
if (!clk->opp_requested) {
err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
- (char *)__clk_get_name(hw->clk),
+ (char *)clk_hw_get_name(hw),
100);
if (err) {
pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return err;
}
clk->opp_requested = 1;
@@ -114,7 +114,7 @@ static int clk_prcmu_opp_prepare(struct clk_hw *hw)
err = prcmu_request_clock(clk->cg_sel, true);
if (err) {
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
- (char *)__clk_get_name(hw->clk));
+ (char *)clk_hw_get_name(hw));
clk->opp_requested = 0;
return err;
}
@@ -129,13 +129,13 @@ static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
if (prcmu_request_clock(clk->cg_sel, false)) {
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
- __clk_get_name(hw->clk));
+ clk_hw_get_name(hw));
return;
}
if (clk->opp_requested) {
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
- (char *)__clk_get_name(hw->clk));
+ (char *)clk_hw_get_name(hw));
clk->opp_requested = 0;
}
@@ -151,7 +151,7 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
err = prcmu_request_ape_opp_100_voltage(true);
if (err) {
pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
return err;
}
clk->opp_requested = 1;
@@ -174,7 +174,7 @@ static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
if (prcmu_request_clock(clk->cg_sel, false)) {
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
- __clk_get_name(hw->clk));
+ clk_hw_get_name(hw));
return;
}
diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c
index e364c9d4aa60..266ddea630d2 100644
--- a/drivers/clk/ux500/clk-sysctrl.c
+++ b/drivers/clk/ux500/clk-sysctrl.c
@@ -52,7 +52,7 @@ static void clk_sysctrl_unprepare(struct clk_hw *hw)
struct clk_sysctrl *clk = to_clk_sysctrl(hw);
if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0]))
dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n",
- __func__, __clk_get_name(hw->clk));
+ __func__, clk_hw_get_name(hw));
}
static unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw,
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h
index a2bb92d85ee0..b42485da704e 100644
--- a/drivers/clk/ux500/clk.h
+++ b/drivers/clk/ux500/clk.h
@@ -10,10 +10,11 @@
#ifndef __UX500_CLK_H
#define __UX500_CLK_H
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/types.h>
+struct clk;
+
struct clk *clk_reg_prcc_pclk(const char *name,
const char *parent_name,
resource_size_t phy_base,
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c
deleted file mode 100644
index 4626b97b7d83..000000000000
--- a/drivers/clk/ux500/u8500_clk.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Clock definitions for u8500 platform.
- *
- * Copyright (C) 2012 ST-Ericsson SA
- * Author: Ulf Hansson <ulf.hansson@linaro.org>
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
-#include <linux/mfd/dbx500-prcmu.h>
-#include <linux/platform_data/clk-ux500.h>
-#include "clk.h"
-
-void u8500_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
- u32 clkrst5_base, u32 clkrst6_base)
-{
- struct prcmu_fw_version *fw_version;
- const char *sgaclk_parent = NULL;
- struct clk *clk;
-
- /* Clock sources */
- clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
- CLK_IS_ROOT|CLK_IGNORE_UNUSED);
- clk_register_clkdev(clk, "soc0_pll", NULL);
-
- clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1,
- CLK_IS_ROOT|CLK_IGNORE_UNUSED);
- clk_register_clkdev(clk, "soc1_pll", NULL);
-
- clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR,
- CLK_IS_ROOT|CLK_IGNORE_UNUSED);
- clk_register_clkdev(clk, "ddr_pll", NULL);
-
- /* FIXME: Add sys, ulp and int clocks here. */
-
- clk = clk_register_fixed_rate(NULL, "rtc32k", "NULL",
- CLK_IS_ROOT|CLK_IGNORE_UNUSED,
- 32768);
- clk_register_clkdev(clk, "clk32k", NULL);
- clk_register_clkdev(clk, "apb_pclk", "rtc-pl031");
-
- /* PRCMU clocks */
- fw_version = prcmu_get_fw_version();
- if (fw_version != NULL) {
- switch (fw_version->project) {
- case PRCMU_FW_PROJECT_U8500_C2:
- case PRCMU_FW_PROJECT_U8520:
- case PRCMU_FW_PROJECT_U8420:
- sgaclk_parent = "soc0_pll";
- break;
- default:
- break;
- }
- }
-
- if (sgaclk_parent)
- clk = clk_reg_prcmu_gate("sgclk", sgaclk_parent,
- PRCMU_SGACLK, 0);
- else
- clk = clk_reg_prcmu_gate("sgclk", NULL,
- PRCMU_SGACLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "mali");
-
- clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "UART");
-
- clk = clk_reg_prcmu_gate("msp02clk", NULL, PRCMU_MSP02CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "MSP02");
-
- clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "MSP1");
-
- clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "I2C");
-
- clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "slim");
-
- clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "PERIPH1");
-
- clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "PERIPH2");
-
- clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "PERIPH3");
-
- clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "PERIPH5");
-
- clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "PERIPH6");
-
- clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "PERIPH7");
-
- clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "lcd");
- clk_register_clkdev(clk, "lcd", "mcde");
-
- clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BMLCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "bml");
-
- clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
-
- clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
-
- clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "hdmi");
- clk_register_clkdev(clk, "hdmi", "mcde");
-
- clk = clk_reg_prcmu_scalable("apeatclk", NULL, PRCMU_APEATCLK, 0,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "apeat");
-
- clk = clk_reg_prcmu_scalable("apetraceclk", NULL, PRCMU_APETRACECLK, 0,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "apetrace");
-
- clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "mcde");
- clk_register_clkdev(clk, "mcde", "mcde");
- clk_register_clkdev(clk, "dsisys", "dsilink.0");
- clk_register_clkdev(clk, "dsisys", "dsilink.1");
- clk_register_clkdev(clk, "dsisys", "dsilink.2");
-
- clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK,
- CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "ipi2");
-
- clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK,
- CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "dsialt");
-
- clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "dma40.0");
-
- clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "b2r2");
- clk_register_clkdev(clk, NULL, "b2r2_core");
- clk_register_clkdev(clk, NULL, "U8500-B2R2.0");
-
- clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "tv");
- clk_register_clkdev(clk, "tv", "mcde");
-
- clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "SSP");
-
- clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "rngclk");
-
- clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "uicc");
-
- clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT);
- clk_register_clkdev(clk, NULL, "mtu0");
- clk_register_clkdev(clk, NULL, "mtu1");
-
- clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, PRCMU_SDMMCCLK,
- 100000000,
- CLK_IS_ROOT|CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "sdmmc");
-
- clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
- PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, "dsihs2", "mcde");
- clk_register_clkdev(clk, "dsihs2", "dsilink.2");
-
-
- clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll",
- PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, "dsihs0", "mcde");
- clk_register_clkdev(clk, "dsihs0", "dsilink.0");
-
- clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll",
- PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, "dsihs1", "mcde");
- clk_register_clkdev(clk, "dsihs1", "dsilink.1");
-
- clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk",
- PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, "dsilp0", "dsilink.0");
- clk_register_clkdev(clk, "dsilp0", "mcde");
-
- clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk",
- PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, "dsilp1", "dsilink.1");
- clk_register_clkdev(clk, "dsilp1", "mcde");
-
- clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk",
- PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, "dsilp2", "dsilink.2");
- clk_register_clkdev(clk, "dsilp2", "mcde");
-
- clk = clk_reg_prcmu_scalable_rate("armss", NULL,
- PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED);
- clk_register_clkdev(clk, "armss", NULL);
-
- clk = clk_register_fixed_factor(NULL, "smp_twd", "armss",
- CLK_IGNORE_UNUSED, 1, 2);
- clk_register_clkdev(clk, NULL, "smp_twd");
-
- /*
- * FIXME: Add special handled PRCMU clocks here:
- * 1. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
- * 2. ab9540_clkout1yuv, see clkout0yuv
- */
-
- /* PRCC P-clocks */
- clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", clkrst1_base,
- BIT(0), 0);
- clk_register_clkdev(clk, "apb_pclk", "uart0");
-
- clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", clkrst1_base,
- BIT(1), 0);
- clk_register_clkdev(clk, "apb_pclk", "uart1");
-
- clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", clkrst1_base,
- BIT(2), 0);
- clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1");
-
- clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", clkrst1_base,
- BIT(3), 0);
- clk_register_clkdev(clk, "apb_pclk", "msp0");
- clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.0");
-
- clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", clkrst1_base,
- BIT(4), 0);
- clk_register_clkdev(clk, "apb_pclk", "msp1");
- clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.1");
-
- clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", clkrst1_base,
- BIT(5), 0);
- clk_register_clkdev(clk, "apb_pclk", "sdi0");
-
- clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", clkrst1_base,
- BIT(6), 0);
- clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2");
-
- clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", clkrst1_base,
- BIT(7), 0);
- clk_register_clkdev(clk, NULL, "spi3");
-
- clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", clkrst1_base,
- BIT(8), 0);
- clk_register_clkdev(clk, "apb_pclk", "slimbus0");
-
- clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", clkrst1_base,
- BIT(9), 0);
- clk_register_clkdev(clk, NULL, "gpio.0");
- clk_register_clkdev(clk, NULL, "gpio.1");
- clk_register_clkdev(clk, NULL, "gpioblock0");
-
- clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", clkrst1_base,
- BIT(10), 0);
- clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4");
-
- clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", clkrst1_base,
- BIT(11), 0);
- clk_register_clkdev(clk, "apb_pclk", "msp3");
- clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.3");
-
- clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", clkrst2_base,
- BIT(0), 0);
- clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3");
-
- clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", clkrst2_base,
- BIT(1), 0);
- clk_register_clkdev(clk, NULL, "spi2");
-
- clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", clkrst2_base,
- BIT(2), 0);
- clk_register_clkdev(clk, NULL, "spi1");
-
- clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", clkrst2_base,
- BIT(3), 0);
- clk_register_clkdev(clk, NULL, "pwl");
-
- clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", clkrst2_base,
- BIT(4), 0);
- clk_register_clkdev(clk, "apb_pclk", "sdi4");
-
- clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", clkrst2_base,
- BIT(5), 0);
- clk_register_clkdev(clk, "apb_pclk", "msp2");
- clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.2");
-
- clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", clkrst2_base,
- BIT(6), 0);
- clk_register_clkdev(clk, "apb_pclk", "sdi1");
-
- clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", clkrst2_base,
- BIT(7), 0);
- clk_register_clkdev(clk, "apb_pclk", "sdi3");
-
- clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", clkrst2_base,
- BIT(8), 0);
- clk_register_clkdev(clk, NULL, "spi0");
-
- clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", clkrst2_base,
- BIT(9), 0);
- clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
-
- clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", clkrst2_base,
- BIT(10), 0);
- clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
-
- clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", clkrst2_base,
- BIT(11), 0);
- clk_register_clkdev(clk, NULL, "gpio.6");
- clk_register_clkdev(clk, NULL, "gpio.7");
- clk_register_clkdev(clk, NULL, "gpioblock1");
-
- clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", clkrst2_base,
- BIT(12), 0);
-
- clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base,
- BIT(0), 0);
- clk_register_clkdev(clk, "fsmc", NULL);
- clk_register_clkdev(clk, NULL, "smsc911x.0");
-
- clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base,
- BIT(1), 0);
- clk_register_clkdev(clk, "apb_pclk", "ssp0");
-
- clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", clkrst3_base,
- BIT(2), 0);
- clk_register_clkdev(clk, "apb_pclk", "ssp1");
-
- clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", clkrst3_base,
- BIT(3), 0);
- clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0");
-
- clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", clkrst3_base,
- BIT(4), 0);
- clk_register_clkdev(clk, "apb_pclk", "sdi2");
-
- clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", clkrst3_base,
- BIT(5), 0);
- clk_register_clkdev(clk, "apb_pclk", "ske");
- clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
-
- clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", clkrst3_base,
- BIT(6), 0);
- clk_register_clkdev(clk, "apb_pclk", "uart2");
-
- clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", clkrst3_base,
- BIT(7), 0);
- clk_register_clkdev(clk, "apb_pclk", "sdi5");
-
- clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", clkrst3_base,
- BIT(8), 0);
- clk_register_clkdev(clk, NULL, "gpio.2");
- clk_register_clkdev(clk, NULL, "gpio.3");
- clk_register_clkdev(clk, NULL, "gpio.4");
- clk_register_clkdev(clk, NULL, "gpio.5");
- clk_register_clkdev(clk, NULL, "gpioblock2");
-
- clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", clkrst5_base,
- BIT(0), 0);
- clk_register_clkdev(clk, "usb", "musb-ux500.0");
-
- clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", clkrst5_base,
- BIT(1), 0);
- clk_register_clkdev(clk, NULL, "gpio.8");
- clk_register_clkdev(clk, NULL, "gpioblock3");
-
- clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", clkrst6_base,
- BIT(0), 0);
- clk_register_clkdev(clk, "apb_pclk", "rng");
-
- clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", clkrst6_base,
- BIT(1), 0);
- clk_register_clkdev(clk, NULL, "cryp0");
- clk_register_clkdev(clk, NULL, "cryp1");
-
- clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", clkrst6_base,
- BIT(2), 0);
- clk_register_clkdev(clk, NULL, "hash0");
-
- clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", clkrst6_base,
- BIT(3), 0);
- clk_register_clkdev(clk, NULL, "pka");
-
- clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", clkrst6_base,
- BIT(4), 0);
- clk_register_clkdev(clk, NULL, "hash1");
-
- clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", clkrst6_base,
- BIT(5), 0);
- clk_register_clkdev(clk, NULL, "cfgreg");
-
- clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", clkrst6_base,
- BIT(6), 0);
- clk_register_clkdev(clk, "apb_pclk", "mtu0");
-
- clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", clkrst6_base,
- BIT(7), 0);
- clk_register_clkdev(clk, "apb_pclk", "mtu1");
-
- /* PRCC K-clocks
- *
- * FIXME: Some drivers requires PERPIH[n| to be automatically enabled
- * by enabling just the K-clock, even if it is not a valid parent to
- * the K-clock. Until drivers get fixed we might need some kind of
- * "parent muxed join".
- */
-
- /* Periph1 */
- clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
- clkrst1_base, BIT(0), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "uart0");
-
- clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
- clkrst1_base, BIT(1), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "uart1");
-
- clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
- clkrst1_base, BIT(2), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "nmk-i2c.1");
-
- clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
- clkrst1_base, BIT(3), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "msp0");
- clk_register_clkdev(clk, NULL, "ux500-msp-i2s.0");
-
- clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
- clkrst1_base, BIT(4), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "msp1");
- clk_register_clkdev(clk, NULL, "ux500-msp-i2s.1");
-
- clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk",
- clkrst1_base, BIT(5), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "sdi0");
-
- clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
- clkrst1_base, BIT(6), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "nmk-i2c.2");
-
- clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
- clkrst1_base, BIT(8), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "slimbus0");
-
- clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
- clkrst1_base, BIT(9), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "nmk-i2c.4");
-
- clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
- clkrst1_base, BIT(10), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "msp3");
- clk_register_clkdev(clk, NULL, "ux500-msp-i2s.3");
-
- /* Periph2 */
- clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
- clkrst2_base, BIT(0), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "nmk-i2c.3");
-
- clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk",
- clkrst2_base, BIT(2), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "sdi4");
-
- clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
- clkrst2_base, BIT(3), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "msp2");
- clk_register_clkdev(clk, NULL, "ux500-msp-i2s.2");
-
- clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk",
- clkrst2_base, BIT(4), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "sdi1");
-
- clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
- clkrst2_base, BIT(5), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "sdi3");
-
- /* Note that rate is received from parent. */
- clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
- clkrst2_base, BIT(6),
- CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
- clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
- clkrst2_base, BIT(7),
- CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
-
- /* Periph3 */
- clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
- clkrst3_base, BIT(1), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "ssp0");
-
- clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
- clkrst3_base, BIT(2), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "ssp1");
-
- clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
- clkrst3_base, BIT(3), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "nmk-i2c.0");
-
- clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk",
- clkrst3_base, BIT(4), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "sdi2");
-
- clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
- clkrst3_base, BIT(5), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "ske");
- clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
-
- clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
- clkrst3_base, BIT(6), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "uart2");
-
- clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
- clkrst3_base, BIT(7), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "sdi5");
-
- /* Periph6 */
- clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
- clkrst6_base, BIT(0), CLK_SET_RATE_GATE);
- clk_register_clkdev(clk, NULL, "rng");
-}
diff --git a/drivers/clk/ux500/u8500_of_clk.c b/drivers/clk/ux500/u8500_of_clk.c
index e319ef912dc6..271c09644652 100644
--- a/drivers/clk/ux500/u8500_of_clk.c
+++ b/drivers/clk/ux500/u8500_of_clk.c
@@ -8,8 +8,7 @@
*/
#include <linux/of.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/of_address.h>
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
@@ -54,14 +53,25 @@ static const struct of_device_id u8500_clk_of_match[] = {
{ },
};
-void u8500_of_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
- u32 clkrst5_base, u32 clkrst6_base)
+/* CLKRST4 is missing making it hard to index things */
+enum clkrst_index {
+ CLKRST1_INDEX = 0,
+ CLKRST2_INDEX,
+ CLKRST3_INDEX,
+ CLKRST5_INDEX,
+ CLKRST6_INDEX,
+ CLKRST_MAX,
+};
+
+void u8500_clk_init(void)
{
struct prcmu_fw_version *fw_version;
struct device_node *np = NULL;
struct device_node *child = NULL;
const char *sgaclk_parent = NULL;
struct clk *clk, *rtc_clk, *twd_clk;
+ u32 bases[CLKRST_MAX];
+ int i;
if (of_have_populated_dt())
np = of_find_matching_node(NULL, u8500_clk_of_match);
@@ -69,6 +79,15 @@ void u8500_of_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
pr_err("Either DT or U8500 Clock node not found\n");
return;
}
+ for (i = 0; i < ARRAY_SIZE(bases); i++) {
+ struct resource r;
+
+ if (of_address_to_resource(np, i, &r))
+ /* Not much choice but to continue */
+ pr_err("failed to get CLKRST %d base address\n",
+ i + 1);
+ bases[i] = r.start;
+ }
/* Clock sources */
clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
@@ -246,179 +265,179 @@ void u8500_of_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
*/
/* PRCC P-clocks */
- clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", bases[CLKRST1_INDEX],
BIT(0), 0);
PRCC_PCLK_STORE(clk, 1, 0);
- clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", bases[CLKRST1_INDEX],
BIT(1), 0);
PRCC_PCLK_STORE(clk, 1, 1);
- clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", bases[CLKRST1_INDEX],
BIT(2), 0);
PRCC_PCLK_STORE(clk, 1, 2);
- clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", bases[CLKRST1_INDEX],
BIT(3), 0);
PRCC_PCLK_STORE(clk, 1, 3);
- clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", bases[CLKRST1_INDEX],
BIT(4), 0);
PRCC_PCLK_STORE(clk, 1, 4);
- clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", bases[CLKRST1_INDEX],
BIT(5), 0);
PRCC_PCLK_STORE(clk, 1, 5);
- clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", bases[CLKRST1_INDEX],
BIT(6), 0);
PRCC_PCLK_STORE(clk, 1, 6);
- clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", bases[CLKRST1_INDEX],
BIT(7), 0);
PRCC_PCLK_STORE(clk, 1, 7);
- clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", bases[CLKRST1_INDEX],
BIT(8), 0);
PRCC_PCLK_STORE(clk, 1, 8);
- clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", bases[CLKRST1_INDEX],
BIT(9), 0);
PRCC_PCLK_STORE(clk, 1, 9);
- clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", bases[CLKRST1_INDEX],
BIT(10), 0);
PRCC_PCLK_STORE(clk, 1, 10);
- clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", bases[CLKRST1_INDEX],
BIT(11), 0);
PRCC_PCLK_STORE(clk, 1, 11);
- clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", bases[CLKRST2_INDEX],
BIT(0), 0);
PRCC_PCLK_STORE(clk, 2, 0);
- clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", bases[CLKRST2_INDEX],
BIT(1), 0);
PRCC_PCLK_STORE(clk, 2, 1);
- clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", bases[CLKRST2_INDEX],
BIT(2), 0);
PRCC_PCLK_STORE(clk, 2, 2);
- clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", bases[CLKRST2_INDEX],
BIT(3), 0);
PRCC_PCLK_STORE(clk, 2, 3);
- clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", bases[CLKRST2_INDEX],
BIT(4), 0);
PRCC_PCLK_STORE(clk, 2, 4);
- clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", bases[CLKRST2_INDEX],
BIT(5), 0);
PRCC_PCLK_STORE(clk, 2, 5);
- clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", bases[CLKRST2_INDEX],
BIT(6), 0);
PRCC_PCLK_STORE(clk, 2, 6);
- clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", bases[CLKRST2_INDEX],
BIT(7), 0);
PRCC_PCLK_STORE(clk, 2, 7);
- clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", bases[CLKRST2_INDEX],
BIT(8), 0);
PRCC_PCLK_STORE(clk, 2, 8);
- clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", bases[CLKRST2_INDEX],
BIT(9), 0);
PRCC_PCLK_STORE(clk, 2, 9);
- clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", bases[CLKRST2_INDEX],
BIT(10), 0);
PRCC_PCLK_STORE(clk, 2, 10);
- clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", bases[CLKRST2_INDEX],
BIT(11), 0);
PRCC_PCLK_STORE(clk, 2, 11);
- clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", bases[CLKRST2_INDEX],
BIT(12), 0);
PRCC_PCLK_STORE(clk, 2, 12);
- clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", bases[CLKRST3_INDEX],
BIT(0), 0);
PRCC_PCLK_STORE(clk, 3, 0);
- clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", bases[CLKRST3_INDEX],
BIT(1), 0);
PRCC_PCLK_STORE(clk, 3, 1);
- clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", bases[CLKRST3_INDEX],
BIT(2), 0);
PRCC_PCLK_STORE(clk, 3, 2);
- clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", bases[CLKRST3_INDEX],
BIT(3), 0);
PRCC_PCLK_STORE(clk, 3, 3);
- clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", bases[CLKRST3_INDEX],
BIT(4), 0);
PRCC_PCLK_STORE(clk, 3, 4);
- clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", bases[CLKRST3_INDEX],
BIT(5), 0);
PRCC_PCLK_STORE(clk, 3, 5);
- clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", bases[CLKRST3_INDEX],
BIT(6), 0);
PRCC_PCLK_STORE(clk, 3, 6);
- clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", bases[CLKRST3_INDEX],
BIT(7), 0);
PRCC_PCLK_STORE(clk, 3, 7);
- clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", bases[CLKRST3_INDEX],
BIT(8), 0);
PRCC_PCLK_STORE(clk, 3, 8);
- clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", clkrst5_base,
+ clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", bases[CLKRST5_INDEX],
BIT(0), 0);
PRCC_PCLK_STORE(clk, 5, 0);
- clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", clkrst5_base,
+ clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", bases[CLKRST5_INDEX],
BIT(1), 0);
PRCC_PCLK_STORE(clk, 5, 1);
- clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", bases[CLKRST6_INDEX],
BIT(0), 0);
PRCC_PCLK_STORE(clk, 6, 0);
- clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", bases[CLKRST6_INDEX],
BIT(1), 0);
PRCC_PCLK_STORE(clk, 6, 1);
- clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", bases[CLKRST6_INDEX],
BIT(2), 0);
PRCC_PCLK_STORE(clk, 6, 2);
- clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", bases[CLKRST6_INDEX],
BIT(3), 0);
PRCC_PCLK_STORE(clk, 6, 3);
- clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", bases[CLKRST6_INDEX],
BIT(4), 0);
PRCC_PCLK_STORE(clk, 6, 4);
- clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", bases[CLKRST6_INDEX],
BIT(5), 0);
PRCC_PCLK_STORE(clk, 6, 5);
- clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", bases[CLKRST6_INDEX],
BIT(6), 0);
PRCC_PCLK_STORE(clk, 6, 6);
- clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", bases[CLKRST6_INDEX],
BIT(7), 0);
PRCC_PCLK_STORE(clk, 6, 7);
@@ -432,109 +451,109 @@ void u8500_of_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
/* Periph1 */
clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
- clkrst1_base, BIT(0), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(0), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 0);
clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
- clkrst1_base, BIT(1), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(1), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 1);
clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
- clkrst1_base, BIT(2), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(2), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 2);
clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
- clkrst1_base, BIT(3), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(3), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 3);
clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
- clkrst1_base, BIT(4), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(4), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 4);
clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk",
- clkrst1_base, BIT(5), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(5), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 5);
clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
- clkrst1_base, BIT(6), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(6), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 6);
clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
- clkrst1_base, BIT(8), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(8), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 8);
clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
- clkrst1_base, BIT(9), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(9), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 9);
clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
- clkrst1_base, BIT(10), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(10), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 1, 10);
/* Periph2 */
clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
- clkrst2_base, BIT(0), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(0), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 2, 0);
clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk",
- clkrst2_base, BIT(2), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(2), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 2, 2);
clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
- clkrst2_base, BIT(3), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(3), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 2, 3);
clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk",
- clkrst2_base, BIT(4), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(4), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 2, 4);
clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
- clkrst2_base, BIT(5), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(5), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 2, 5);
/* Note that rate is received from parent. */
clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
- clkrst2_base, BIT(6),
+ bases[CLKRST2_INDEX], BIT(6),
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
PRCC_KCLK_STORE(clk, 2, 6);
clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
- clkrst2_base, BIT(7),
+ bases[CLKRST2_INDEX], BIT(7),
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
PRCC_KCLK_STORE(clk, 2, 7);
/* Periph3 */
clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
- clkrst3_base, BIT(1), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(1), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 3, 1);
clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
- clkrst3_base, BIT(2), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(2), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 3, 2);
clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
- clkrst3_base, BIT(3), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(3), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 3, 3);
clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk",
- clkrst3_base, BIT(4), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(4), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 3, 4);
clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
- clkrst3_base, BIT(5), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(5), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 3, 5);
clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
- clkrst3_base, BIT(6), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(6), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 3, 6);
clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
- clkrst3_base, BIT(7), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(7), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 3, 7);
/* Periph6 */
clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
- clkrst6_base, BIT(0), CLK_SET_RATE_GATE);
+ bases[CLKRST6_INDEX], BIT(0), CLK_SET_RATE_GATE);
PRCC_KCLK_STORE(clk, 6, 0);
for_each_child_of_node(np, child) {
diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c
index 20c8add90d11..d7bcb7a86615 100644
--- a/drivers/clk/ux500/u8540_clk.c
+++ b/drivers/clk/ux500/u8540_clk.c
@@ -7,17 +7,51 @@
* License terms: GNU General Public License (GPL) version 2
*/
-#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
#include "clk.h"
-void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
- u32 clkrst5_base, u32 clkrst6_base)
+static const struct of_device_id u8540_clk_of_match[] = {
+ { .compatible = "stericsson,u8540-clks", },
+ { }
+};
+
+/* CLKRST4 is missing making it hard to index things */
+enum clkrst_index {
+ CLKRST1_INDEX = 0,
+ CLKRST2_INDEX,
+ CLKRST3_INDEX,
+ CLKRST5_INDEX,
+ CLKRST6_INDEX,
+ CLKRST_MAX,
+};
+
+void u8540_clk_init(void)
{
struct clk *clk;
+ struct device_node *np = NULL;
+ u32 bases[CLKRST_MAX];
+ int i;
+
+ if (of_have_populated_dt())
+ np = of_find_matching_node(NULL, u8540_clk_of_match);
+ if (!np) {
+ pr_err("Either DT or U8540 Clock node not found\n");
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(bases); i++) {
+ struct resource r;
+
+ if (of_address_to_resource(np, i, &r))
+ /* Not much choice but to continue */
+ pr_err("failed to get CLKRST %d base address\n",
+ i + 1);
+ bases[i] = r.start;
+ }
/* Clock sources. */
/* Fixed ClockGen */
@@ -219,151 +253,151 @@ void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
/* PRCC P-clocks */
/* Peripheral 1 : PRCC P-clocks */
- clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", bases[CLKRST1_INDEX],
BIT(0), 0);
clk_register_clkdev(clk, "apb_pclk", "uart0");
- clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", bases[CLKRST1_INDEX],
BIT(1), 0);
clk_register_clkdev(clk, "apb_pclk", "uart1");
- clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", bases[CLKRST1_INDEX],
BIT(2), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1");
- clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", bases[CLKRST1_INDEX],
BIT(3), 0);
clk_register_clkdev(clk, "apb_pclk", "msp0");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.0");
- clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", bases[CLKRST1_INDEX],
BIT(4), 0);
clk_register_clkdev(clk, "apb_pclk", "msp1");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.1");
- clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", bases[CLKRST1_INDEX],
BIT(5), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi0");
- clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", bases[CLKRST1_INDEX],
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2");
- clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", bases[CLKRST1_INDEX],
BIT(7), 0);
clk_register_clkdev(clk, NULL, "spi3");
- clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", bases[CLKRST1_INDEX],
BIT(8), 0);
clk_register_clkdev(clk, "apb_pclk", "slimbus0");
- clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", bases[CLKRST1_INDEX],
BIT(9), 0);
clk_register_clkdev(clk, NULL, "gpio.0");
clk_register_clkdev(clk, NULL, "gpio.1");
clk_register_clkdev(clk, NULL, "gpioblock0");
clk_register_clkdev(clk, "apb_pclk", "ab85xx-codec.0");
- clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", bases[CLKRST1_INDEX],
BIT(10), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4");
- clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", clkrst1_base,
+ clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", bases[CLKRST1_INDEX],
BIT(11), 0);
clk_register_clkdev(clk, "apb_pclk", "msp3");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.3");
/* Peripheral 2 : PRCC P-clocks */
- clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", bases[CLKRST2_INDEX],
BIT(0), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3");
- clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", bases[CLKRST2_INDEX],
BIT(1), 0);
clk_register_clkdev(clk, NULL, "spi2");
- clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", bases[CLKRST2_INDEX],
BIT(2), 0);
clk_register_clkdev(clk, NULL, "spi1");
- clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", bases[CLKRST2_INDEX],
BIT(3), 0);
clk_register_clkdev(clk, NULL, "pwl");
- clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", bases[CLKRST2_INDEX],
BIT(4), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi4");
- clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", bases[CLKRST2_INDEX],
BIT(5), 0);
clk_register_clkdev(clk, "apb_pclk", "msp2");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.2");
- clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", bases[CLKRST2_INDEX],
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi1");
- clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", bases[CLKRST2_INDEX],
BIT(7), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi3");
- clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", bases[CLKRST2_INDEX],
BIT(8), 0);
clk_register_clkdev(clk, NULL, "spi0");
- clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", bases[CLKRST2_INDEX],
BIT(9), 0);
clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
- clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", bases[CLKRST2_INDEX],
BIT(10), 0);
clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
- clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", bases[CLKRST2_INDEX],
BIT(11), 0);
clk_register_clkdev(clk, NULL, "gpio.6");
clk_register_clkdev(clk, NULL, "gpio.7");
clk_register_clkdev(clk, NULL, "gpioblock1");
- clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", clkrst2_base,
+ clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", bases[CLKRST2_INDEX],
BIT(12), 0);
clk_register_clkdev(clk, "msp4-pclk", "ab85xx-codec.0");
/* Peripheral 3 : PRCC P-clocks */
- clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", bases[CLKRST3_INDEX],
BIT(0), 0);
clk_register_clkdev(clk, NULL, "fsmc");
- clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", bases[CLKRST3_INDEX],
BIT(1), 0);
clk_register_clkdev(clk, "apb_pclk", "ssp0");
- clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", bases[CLKRST3_INDEX],
BIT(2), 0);
clk_register_clkdev(clk, "apb_pclk", "ssp1");
- clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", bases[CLKRST3_INDEX],
BIT(3), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0");
- clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", bases[CLKRST3_INDEX],
BIT(4), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi2");
- clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", bases[CLKRST3_INDEX],
BIT(5), 0);
clk_register_clkdev(clk, "apb_pclk", "ske");
clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
- clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", bases[CLKRST3_INDEX],
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "uart2");
- clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", bases[CLKRST3_INDEX],
BIT(7), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi5");
- clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", bases[CLKRST3_INDEX],
BIT(8), 0);
clk_register_clkdev(clk, NULL, "gpio.2");
clk_register_clkdev(clk, NULL, "gpio.3");
@@ -371,64 +405,64 @@ void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
clk_register_clkdev(clk, NULL, "gpio.5");
clk_register_clkdev(clk, NULL, "gpioblock2");
- clk = clk_reg_prcc_pclk("p3_pclk9", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk9", "per3clk", bases[CLKRST3_INDEX],
BIT(9), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.5");
- clk = clk_reg_prcc_pclk("p3_pclk10", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk10", "per3clk", bases[CLKRST3_INDEX],
BIT(10), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.6");
- clk = clk_reg_prcc_pclk("p3_pclk11", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk11", "per3clk", bases[CLKRST3_INDEX],
BIT(11), 0);
clk_register_clkdev(clk, "apb_pclk", "uart3");
- clk = clk_reg_prcc_pclk("p3_pclk12", "per3clk", clkrst3_base,
+ clk = clk_reg_prcc_pclk("p3_pclk12", "per3clk", bases[CLKRST3_INDEX],
BIT(12), 0);
clk_register_clkdev(clk, "apb_pclk", "uart4");
/* Peripheral 5 : PRCC P-clocks */
- clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", clkrst5_base,
+ clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", bases[CLKRST5_INDEX],
BIT(0), 0);
clk_register_clkdev(clk, "usb", "musb-ux500.0");
clk_register_clkdev(clk, "usbclk", "ab-iddet.0");
- clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", clkrst5_base,
+ clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", bases[CLKRST5_INDEX],
BIT(1), 0);
clk_register_clkdev(clk, NULL, "gpio.8");
clk_register_clkdev(clk, NULL, "gpioblock3");
/* Peripheral 6 : PRCC P-clocks */
- clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", bases[CLKRST6_INDEX],
BIT(0), 0);
clk_register_clkdev(clk, "apb_pclk", "rng");
- clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", bases[CLKRST6_INDEX],
BIT(1), 0);
clk_register_clkdev(clk, NULL, "cryp0");
clk_register_clkdev(clk, NULL, "cryp1");
- clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", bases[CLKRST6_INDEX],
BIT(2), 0);
clk_register_clkdev(clk, NULL, "hash0");
- clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", bases[CLKRST6_INDEX],
BIT(3), 0);
clk_register_clkdev(clk, NULL, "pka");
- clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", bases[CLKRST6_INDEX],
BIT(4), 0);
clk_register_clkdev(clk, NULL, "db8540-hash1");
- clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", bases[CLKRST6_INDEX],
BIT(5), 0);
clk_register_clkdev(clk, NULL, "cfgreg");
- clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", bases[CLKRST6_INDEX],
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "mtu0");
- clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", clkrst6_base,
+ clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", bases[CLKRST6_INDEX],
BIT(7), 0);
clk_register_clkdev(clk, "apb_pclk", "mtu1");
@@ -442,138 +476,138 @@ void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
/* Peripheral 1 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
- clkrst1_base, BIT(0), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart0");
clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
- clkrst1_base, BIT(1), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(1), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart1");
clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
- clkrst1_base, BIT(2), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(2), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.1");
clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
- clkrst1_base, BIT(3), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(3), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp0");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.0");
clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
- clkrst1_base, BIT(4), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(4), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp1");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.1");
clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmchclk",
- clkrst1_base, BIT(5), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(5), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi0");
clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
- clkrst1_base, BIT(6), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(6), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.2");
clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
- clkrst1_base, BIT(8), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(8), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "slimbus0");
clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
- clkrst1_base, BIT(9), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(9), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.4");
clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
- clkrst1_base, BIT(10), CLK_SET_RATE_GATE);
+ bases[CLKRST1_INDEX], BIT(10), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp3");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.3");
/* Peripheral 2 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
- clkrst2_base, BIT(0), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.3");
clk = clk_reg_prcc_kclk("p2_pwl_kclk", "rtc32k",
- clkrst2_base, BIT(1), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(1), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "pwl");
clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmchclk",
- clkrst2_base, BIT(2), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(2), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi4");
clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
- clkrst2_base, BIT(3), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(3), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp2");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.2");
clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmchclk",
- clkrst2_base, BIT(4), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(4), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi1");
clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
- clkrst2_base, BIT(5), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(5), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi3");
clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
- clkrst2_base, BIT(6),
+ bases[CLKRST2_INDEX], BIT(6),
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
clk_register_clkdev(clk, "hsir_hsirxclk", "ste_hsi.0");
clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
- clkrst2_base, BIT(7),
+ bases[CLKRST2_INDEX], BIT(7),
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
clk_register_clkdev(clk, "hsit_hsitxclk", "ste_hsi.0");
/* Should only be 9540, but might be added for 85xx as well */
clk = clk_reg_prcc_kclk("p2_msp4_kclk", "msp02clk",
- clkrst2_base, BIT(9), CLK_SET_RATE_GATE);
+ bases[CLKRST2_INDEX], BIT(9), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp4");
clk_register_clkdev(clk, "msp4", "ab85xx-codec.0");
/* Peripheral 3 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
- clkrst3_base, BIT(1), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(1), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "ssp0");
clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
- clkrst3_base, BIT(2), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(2), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "ssp1");
clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
- clkrst3_base, BIT(3), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(3), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.0");
clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmchclk",
- clkrst3_base, BIT(4), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(4), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi2");
clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
- clkrst3_base, BIT(5), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(5), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "ske");
clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
- clkrst3_base, BIT(6), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(6), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart2");
clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
- clkrst3_base, BIT(7), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(7), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi5");
clk = clk_reg_prcc_kclk("p3_i2c5_kclk", "i2cclk",
- clkrst3_base, BIT(8), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(8), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.5");
clk = clk_reg_prcc_kclk("p3_i2c6_kclk", "i2cclk",
- clkrst3_base, BIT(9), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(9), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.6");
clk = clk_reg_prcc_kclk("p3_uart3_kclk", "uartclk",
- clkrst3_base, BIT(10), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(10), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart3");
clk = clk_reg_prcc_kclk("p3_uart4_kclk", "uartclk",
- clkrst3_base, BIT(11), CLK_SET_RATE_GATE);
+ bases[CLKRST3_INDEX], BIT(11), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart4");
/* Peripheral 6 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p6_rng_kclk", "rngclk",
- clkrst6_base, BIT(0), CLK_SET_RATE_GATE);
+ bases[CLKRST6_INDEX], BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "rng");
}
diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c
index 44794782e7e0..2138a4c8cbca 100644
--- a/drivers/clk/ux500/u9540_clk.c
+++ b/drivers/clk/ux500/u9540_clk.c
@@ -7,15 +7,12 @@
* License terms: GNU General Public License (GPL) version 2
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
#include "clk.h"
-void u9540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
- u32 clkrst5_base, u32 clkrst6_base)
+void u9540_clk_init(void)
{
/* register clocks here */
}
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index bc96f103bd7c..a3893ea2199d 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -13,8 +13,9 @@
* ICST clock code from the ARM tree should probably be merged into this
* file.
*/
-#include <linux/clk.h>
-#include <linux/clkdev.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/export.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c
index 1cc1330dc570..65c842a21c62 100644
--- a/drivers/clk/versatile/clk-impd1.c
+++ b/drivers/clk/versatile/clk-impd1.c
@@ -7,7 +7,6 @@
* published by the Free Software Foundation.
*/
#include <linux/clk-provider.h>
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c
index c8b523117fb7..86f70997d59d 100644
--- a/drivers/clk/versatile/clk-realview.c
+++ b/drivers/clk/versatile/clk-realview.c
@@ -6,7 +6,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -33,13 +32,13 @@ static const struct icst_params realview_oscvco_params = {
.idx2s = icst307_idx2s,
};
-static const struct clk_icst_desc __initdata realview_osc0_desc = {
+static const struct clk_icst_desc realview_osc0_desc __initconst = {
.params = &realview_oscvco_params,
.vco_offset = REALVIEW_SYS_OSC0_OFFSET,
.lock_offset = REALVIEW_SYS_LOCK_OFFSET,
};
-static const struct clk_icst_desc __initdata realview_osc4_desc = {
+static const struct clk_icst_desc realview_osc4_desc __initconst = {
.params = &realview_oscvco_params,
.vco_offset = REALVIEW_SYS_OSC4_OFFSET,
.lock_offset = REALVIEW_SYS_LOCK_OFFSET,
diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c
index a96dd8e53fdb..a1cdef6b0f90 100644
--- a/drivers/clk/versatile/clk-sp810.c
+++ b/drivers/clk/versatile/clk-sp810.c
@@ -12,7 +12,8 @@
*/
#include <linux/amba/sp810.h>
-#include <linux/clkdev.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/of.h>
@@ -32,12 +33,9 @@ struct clk_sp810_timerclken {
struct clk_sp810 {
struct device_node *node;
- int refclk_index, timclk_index;
void __iomem *base;
spinlock_t lock;
struct clk_sp810_timerclken timerclken[4];
- struct clk *refclk;
- struct clk *timclk;
};
static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw)
@@ -70,55 +68,7 @@ static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index)
return 0;
}
-/*
- * FIXME - setting the parent every time .prepare is invoked is inefficient.
- * This is better handled by a dedicated clock tree configuration mechanism at
- * init-time. Revisit this later when such a mechanism exists
- */
-static int clk_sp810_timerclken_prepare(struct clk_hw *hw)
-{
- struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
- struct clk_sp810 *sp810 = timerclken->sp810;
- struct clk *old_parent = __clk_get_parent(hw->clk);
- struct clk *new_parent;
-
- if (!sp810->refclk)
- sp810->refclk = of_clk_get(sp810->node, sp810->refclk_index);
-
- if (!sp810->timclk)
- sp810->timclk = of_clk_get(sp810->node, sp810->timclk_index);
-
- if (WARN_ON(IS_ERR(sp810->refclk) || IS_ERR(sp810->timclk)))
- return -ENOENT;
-
- /* Select fastest parent */
- if (clk_get_rate(sp810->refclk) > clk_get_rate(sp810->timclk))
- new_parent = sp810->refclk;
- else
- new_parent = sp810->timclk;
-
- /* Switch the parent if necessary */
- if (old_parent != new_parent) {
- clk_prepare(new_parent);
- clk_set_parent(hw->clk, new_parent);
- clk_unprepare(old_parent);
- }
-
- return 0;
-}
-
-static void clk_sp810_timerclken_unprepare(struct clk_hw *hw)
-{
- struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
- struct clk_sp810 *sp810 = timerclken->sp810;
-
- clk_put(sp810->timclk);
- clk_put(sp810->refclk);
-}
-
static const struct clk_ops clk_sp810_timerclken_ops = {
- .prepare = clk_sp810_timerclken_prepare,
- .unprepare = clk_sp810_timerclken_unprepare,
.get_parent = clk_sp810_timerclken_get_parent,
.set_parent = clk_sp810_timerclken_set_parent,
};
@@ -128,8 +78,8 @@ static struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec,
{
struct clk_sp810 *sp810 = data;
- if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
- ARRAY_SIZE(sp810->timerclken)))
+ if (WARN_ON(clkspec->args_count != 1 ||
+ clkspec->args[0] >= ARRAY_SIZE(sp810->timerclken)))
return NULL;
return sp810->timerclken[clkspec->args[0]].clk;
@@ -139,24 +89,18 @@ static void __init clk_sp810_of_setup(struct device_node *node)
{
struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL);
const char *parent_names[2];
+ int num = ARRAY_SIZE(parent_names);
char name[12];
struct clk_init_data init;
int i;
+ bool deprecated;
if (!sp810) {
pr_err("Failed to allocate memory for SP810!\n");
return;
}
- sp810->refclk_index = of_property_match_string(node, "clock-names",
- "refclk");
- parent_names[0] = of_clk_get_parent_name(node, sp810->refclk_index);
-
- sp810->timclk_index = of_property_match_string(node, "clock-names",
- "timclk");
- parent_names[1] = of_clk_get_parent_name(node, sp810->timclk_index);
-
- if (!parent_names[0] || !parent_names[1]) {
+ if (of_clk_parent_fill(node, parent_names, num) != num) {
pr_warn("Failed to obtain parent clocks for SP810!\n");
return;
}
@@ -169,7 +113,9 @@ static void __init clk_sp810_of_setup(struct device_node *node)
init.ops = &clk_sp810_timerclken_ops;
init.flags = CLK_IS_BASIC;
init.parent_names = parent_names;
- init.num_parents = ARRAY_SIZE(parent_names);
+ init.num_parents = num;
+
+ deprecated = !of_find_property(node, "assigned-clock-parents", NULL);
for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) {
snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
@@ -178,6 +124,15 @@ static void __init clk_sp810_of_setup(struct device_node *node)
sp810->timerclken[i].channel = i;
sp810->timerclken[i].hw.init = &init;
+ /*
+ * If DT isn't setting the parent, force it to be
+ * the 1 MHz clock without going through the framework.
+ * We do this before clk_register() so that it can determine
+ * the parent and setup the tree properly.
+ */
+ if (deprecated)
+ init.ops->set_parent(&sp810->timerclken[i].hw, 1);
+
sp810->timerclken[i].clk = clk_register(NULL,
&sp810->timerclken[i].hw);
WARN_ON(IS_ERR(sp810->timerclken[i].clk));
diff --git a/drivers/clk/versatile/clk-versatile.c b/drivers/clk/versatile/clk-versatile.c
index 7a4f8635bd1e..a89a927567e0 100644
--- a/drivers/clk/versatile/clk-versatile.c
+++ b/drivers/clk/versatile/clk-versatile.c
@@ -8,8 +8,6 @@
* published by the Free Software Foundation.
*/
#include <linux/clk-provider.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -35,7 +33,7 @@ static const struct icst_params cp_auxosc_params = {
.idx2s = icst525_idx2s,
};
-static const struct clk_icst_desc __initdata cm_auxosc_desc = {
+static const struct clk_icst_desc cm_auxosc_desc __initconst = {
.params = &cp_auxosc_params,
.vco_offset = 0x1c,
.lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile
index 95b707c18108..74005aa322a2 100644
--- a/drivers/clk/zte/Makefile
+++ b/drivers/clk/zte/Makefile
@@ -1,2 +1,2 @@
-obj-y := clk-pll.o
+obj-y := clk.o
obj-$(CONFIG_SOC_ZX296702) += clk-zx296702.o
diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c
index 929d033594af..ebd20d852e73 100644
--- a/drivers/clk/zte/clk-zx296702.c
+++ b/drivers/clk/zte/clk-zx296702.c
@@ -36,10 +36,21 @@ static struct clk_onecell_data lsp1clk_data;
#define CLK_MUX1 (topcrm_base + 0x8c)
#define CLK_SDMMC1 (lsp0crpm_base + 0x0c)
+#define CLK_GPIO (lsp0crpm_base + 0x2c)
+#define CLK_SPDIF0 (lsp0crpm_base + 0x10)
+#define SPDIF0_DIV (lsp0crpm_base + 0x14)
+#define CLK_I2S0 (lsp0crpm_base + 0x18)
+#define I2S0_DIV (lsp0crpm_base + 0x1c)
+#define CLK_I2S1 (lsp0crpm_base + 0x20)
+#define I2S1_DIV (lsp0crpm_base + 0x24)
+#define CLK_I2S2 (lsp0crpm_base + 0x34)
+#define I2S2_DIV (lsp0crpm_base + 0x38)
#define CLK_UART0 (lsp1crpm_base + 0x20)
#define CLK_UART1 (lsp1crpm_base + 0x24)
#define CLK_SDMMC0 (lsp1crpm_base + 0x2c)
+#define CLK_SPDIF1 (lsp1crpm_base + 0x30)
+#define SPDIF1_DIV (lsp1crpm_base + 0x34)
static const struct zx_pll_config pll_a9_config[] = {
{ .rate = 700000000, .cfg0 = 0x800405d1, .cfg1 = 0x04555555 },
@@ -72,104 +83,119 @@ static const struct clk_div_table sec_wclk_divider[] = {
{ /* sentinel */ }
};
-static const char * matrix_aclk_sel[] = {
+static const char * const matrix_aclk_sel[] = {
"pll_mm0_198M",
"osc",
"clk_148M5",
"pll_lsp_104M",
};
-static const char * a9_wclk_sel[] = {
+static const char * const a9_wclk_sel[] = {
"pll_a9",
"osc",
"clk_500",
"clk_250",
};
-static const char * a9_as1_aclk_sel[] = {
+static const char * const a9_as1_aclk_sel[] = {
"clk_250",
"osc",
"pll_mm0_396M",
"pll_mac_333M",
};
-static const char * a9_trace_clkin_sel[] = {
+static const char * const a9_trace_clkin_sel[] = {
"clk_74M25",
"pll_mm1_108M",
"clk_125",
"clk_148M5",
};
-static const char * decppu_aclk_sel[] = {
+static const char * const decppu_aclk_sel[] = {
"clk_250",
"pll_mm0_198M",
"pll_lsp_104M",
"pll_audio_294M912",
};
-static const char * vou_main_wclk_sel[] = {
+static const char * const vou_main_wclk_sel[] = {
"clk_148M5",
"clk_74M25",
"clk_27",
"pll_mm1_54M",
};
-static const char * vou_scaler_wclk_sel[] = {
+static const char * const vou_scaler_wclk_sel[] = {
"clk_250",
"pll_mac_333M",
"pll_audio_294M912",
"pll_mm0_198M",
};
-static const char * r2d_wclk_sel[] = {
+static const char * const r2d_wclk_sel[] = {
"pll_audio_294M912",
"pll_mac_333M",
"pll_a9_350M",
"pll_mm0_396M",
};
-static const char * ddr_wclk_sel[] = {
+static const char * const ddr_wclk_sel[] = {
"pll_mac_333M",
"pll_ddr_266M",
"pll_audio_294M912",
"pll_mm0_198M",
};
-static const char * nand_wclk_sel[] = {
+static const char * const nand_wclk_sel[] = {
"pll_lsp_104M",
"osc",
};
-static const char * lsp_26_wclk_sel[] = {
+static const char * const lsp_26_wclk_sel[] = {
"pll_lsp_26M",
"osc",
};
-static const char * vl0_sel[] = {
+static const char * const vl0_sel[] = {
"vou_main_channel_div",
"vou_aux_channel_div",
};
-static const char * hdmi_sel[] = {
+static const char * const hdmi_sel[] = {
"vou_main_channel_wclk",
"vou_aux_channel_wclk",
};
-static const char * sdmmc0_wclk_sel[] = {
+static const char * const sdmmc0_wclk_sel[] = {
"lsp1_104M_wclk",
"lsp1_26M_wclk",
};
-static const char * sdmmc1_wclk_sel[] = {
+static const char * const sdmmc1_wclk_sel[] = {
"lsp0_104M_wclk",
"lsp0_26M_wclk",
};
-static const char * uart_wclk_sel[] = {
+static const char * const uart_wclk_sel[] = {
"lsp1_104M_wclk",
"lsp1_26M_wclk",
};
+static const char * const spdif0_wclk_sel[] = {
+ "lsp0_104M_wclk",
+ "lsp0_26M_wclk",
+};
+
+static const char * const spdif1_wclk_sel[] = {
+ "lsp1_104M_wclk",
+ "lsp1_26M_wclk",
+};
+
+static const char * const i2s_wclk_sel[] = {
+ "lsp0_104M_wclk",
+ "lsp0_26M_wclk",
+};
+
static inline struct clk *zx_divtbl(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width,
const struct clk_div_table *table)
@@ -185,7 +211,7 @@ static inline struct clk *zx_div(const char *name, const char *parent,
reg, shift, width, 0, &reg_lock);
}
-static inline struct clk *zx_mux(const char *name, const char **parents,
+static inline struct clk *zx_mux(const char *name, const char * const *parents,
int num_parents, void __iomem *reg, u8 shift, u8 width)
{
return clk_register_mux(NULL, name, parents, num_parents,
@@ -196,7 +222,7 @@ static inline struct clk *zx_gate(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_register_gate(NULL, name, parent, CLK_IGNORE_UNUSED,
- reg, shift, 0, &reg_lock);
+ reg, shift, CLK_SET_RATE_PARENT, &reg_lock);
}
static void __init zx296702_top_clocks_init(struct device_node *np)
@@ -585,7 +611,57 @@ static void __init zx296702_lsp0_clocks_init(struct device_node *np)
clk[ZX296702_SDMMC1_WCLK] =
zx_gate("sdmmc1_wclk", "sdmmc1_wclk_div", CLK_SDMMC1, 1);
clk[ZX296702_SDMMC1_PCLK] =
- zx_gate("sdmmc1_pclk", "lsp1_apb_pclk", CLK_SDMMC1, 0);
+ zx_gate("sdmmc1_pclk", "lsp0_apb_pclk", CLK_SDMMC1, 0);
+
+ clk[ZX296702_GPIO_CLK] =
+ zx_gate("gpio_clk", "lsp0_apb_pclk", CLK_GPIO, 0);
+
+ /* SPDIF */
+ clk[ZX296702_SPDIF0_WCLK_MUX] =
+ zx_mux("spdif0_wclk_mux", spdif0_wclk_sel,
+ ARRAY_SIZE(spdif0_wclk_sel), CLK_SPDIF0, 4, 1);
+ clk[ZX296702_SPDIF0_WCLK] =
+ zx_gate("spdif0_wclk", "spdif0_wclk_mux", CLK_SPDIF0, 1);
+ clk[ZX296702_SPDIF0_PCLK] =
+ zx_gate("spdif0_pclk", "lsp0_apb_pclk", CLK_SPDIF0, 0);
+
+ clk[ZX296702_SPDIF0_DIV] =
+ clk_register_zx_audio("spdif0_div", "spdif0_wclk", 0,
+ SPDIF0_DIV);
+
+ /* I2S */
+ clk[ZX296702_I2S0_WCLK_MUX] =
+ zx_mux("i2s0_wclk_mux", i2s_wclk_sel,
+ ARRAY_SIZE(i2s_wclk_sel), CLK_I2S0, 4, 1);
+ clk[ZX296702_I2S0_WCLK] =
+ zx_gate("i2s0_wclk", "i2s0_wclk_mux", CLK_I2S0, 1);
+ clk[ZX296702_I2S0_PCLK] =
+ zx_gate("i2s0_pclk", "lsp0_apb_pclk", CLK_I2S0, 0);
+
+ clk[ZX296702_I2S0_DIV] =
+ clk_register_zx_audio("i2s0_div", "i2s0_wclk", 0, I2S0_DIV);
+
+ clk[ZX296702_I2S1_WCLK_MUX] =
+ zx_mux("i2s1_wclk_mux", i2s_wclk_sel,
+ ARRAY_SIZE(i2s_wclk_sel), CLK_I2S1, 4, 1);
+ clk[ZX296702_I2S1_WCLK] =
+ zx_gate("i2s1_wclk", "i2s1_wclk_mux", CLK_I2S1, 1);
+ clk[ZX296702_I2S1_PCLK] =
+ zx_gate("i2s1_pclk", "lsp0_apb_pclk", CLK_I2S1, 0);
+
+ clk[ZX296702_I2S1_DIV] =
+ clk_register_zx_audio("i2s1_div", "i2s1_wclk", 0, I2S1_DIV);
+
+ clk[ZX296702_I2S2_WCLK_MUX] =
+ zx_mux("i2s2_wclk_mux", i2s_wclk_sel,
+ ARRAY_SIZE(i2s_wclk_sel), CLK_I2S2, 4, 1);
+ clk[ZX296702_I2S2_WCLK] =
+ zx_gate("i2s2_wclk", "i2s2_wclk_mux", CLK_I2S2, 1);
+ clk[ZX296702_I2S2_PCLK] =
+ zx_gate("i2s2_pclk", "lsp0_apb_pclk", CLK_I2S2, 0);
+
+ clk[ZX296702_I2S2_DIV] =
+ clk_register_zx_audio("i2s2_div", "i2s2_wclk", 0, I2S2_DIV);
for (i = 0; i < ARRAY_SIZE(lsp0clk); i++) {
if (IS_ERR(clk[i])) {
@@ -641,6 +717,18 @@ static void __init zx296702_lsp1_clocks_init(struct device_node *np)
clk[ZX296702_SDMMC0_PCLK] =
zx_gate("sdmmc0_pclk", "lsp1_apb_pclk", CLK_SDMMC0, 0);
+ clk[ZX296702_SPDIF1_WCLK_MUX] =
+ zx_mux("spdif1_wclk_mux", spdif1_wclk_sel,
+ ARRAY_SIZE(spdif1_wclk_sel), CLK_SPDIF1, 4, 1);
+ clk[ZX296702_SPDIF1_WCLK] =
+ zx_gate("spdif1_wclk", "spdif1_wclk_mux", CLK_SPDIF1, 1);
+ clk[ZX296702_SPDIF1_PCLK] =
+ zx_gate("spdif1_pclk", "lsp1_apb_pclk", CLK_SPDIF1, 0);
+
+ clk[ZX296702_SPDIF1_DIV] =
+ clk_register_zx_audio("spdif1_div", "spdif1_wclk", 0,
+ SPDIF1_DIV);
+
for (i = 0; i < ARRAY_SIZE(lsp1clk); i++) {
if (IS_ERR(clk[i])) {
pr_err("zx296702 clk %d: register failed with %ld\n",
diff --git a/drivers/clk/zte/clk-pll.c b/drivers/clk/zte/clk.c
index c3b221ae6cd7..7c73c538c43d 100644
--- a/drivers/clk/zte/clk-pll.c
+++ b/drivers/clk/zte/clk.c
@@ -13,10 +13,12 @@
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <asm/div64.h>
#include "clk.h"
#define to_clk_zx_pll(_hw) container_of(_hw, struct clk_zx_pll, hw)
+#define to_clk_zx_audio(_hw) container_of(_hw, struct clk_zx_audio, hw)
#define CFG0_CFG1_OFFSET 4
#define LOCK_FLAG BIT(30)
@@ -141,8 +143,9 @@ static const struct clk_ops zx_pll_ops = {
};
struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
- unsigned long flags, void __iomem *reg_base,
- const struct zx_pll_config *lookup_table, int count, spinlock_t *lock)
+ unsigned long flags, void __iomem *reg_base,
+ const struct zx_pll_config *lookup_table,
+ int count, spinlock_t *lock)
{
struct clk_zx_pll *zx_pll;
struct clk *clk;
@@ -170,3 +173,137 @@ struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
return clk;
}
+
+#define BPAR 1000000
+static u32 calc_reg(u32 parent_rate, u32 rate)
+{
+ u32 sel, integ, fra_div, tmp;
+ u64 tmp64 = (u64)parent_rate * BPAR;
+
+ do_div(tmp64, rate);
+ integ = (u32)tmp64 / BPAR;
+ integ = integ >> 1;
+
+ tmp = (u32)tmp64 % BPAR;
+ sel = tmp / BPAR;
+
+ tmp = tmp % BPAR;
+ fra_div = tmp * 0xff / BPAR;
+ tmp = (sel << 24) | (integ << 16) | (0xff << 8) | fra_div;
+
+ /* Set I2S integer divider as 1. This bit is reserved for SPDIF
+ * and do no harm.
+ */
+ tmp |= BIT(28);
+ return tmp;
+}
+
+static u32 calc_rate(u32 reg, u32 parent_rate)
+{
+ u32 sel, integ, fra_div, tmp;
+ u64 tmp64 = (u64)parent_rate * BPAR;
+
+ tmp = reg;
+ sel = (tmp >> 24) & BIT(0);
+ integ = (tmp >> 16) & 0xff;
+ fra_div = tmp & 0xff;
+
+ tmp = fra_div * BPAR;
+ tmp = tmp / 0xff;
+ tmp += sel * BPAR;
+ tmp += 2 * integ * BPAR;
+ do_div(tmp64, tmp);
+
+ return (u32)tmp64;
+}
+
+static unsigned long zx_audio_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw);
+ u32 reg;
+
+ reg = readl_relaxed(zx_audio->reg_base);
+ return calc_rate(reg, parent_rate);
+}
+
+static long zx_audio_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ u32 reg;
+
+ if (rate * 2 > *prate)
+ return -EINVAL;
+
+ reg = calc_reg(*prate, rate);
+ return calc_rate(reg, *prate);
+}
+
+static int zx_audio_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw);
+ u32 reg;
+
+ reg = calc_reg(parent_rate, rate);
+ writel_relaxed(reg, zx_audio->reg_base);
+
+ return 0;
+}
+
+#define ZX_AUDIO_EN BIT(25)
+static int zx_audio_enable(struct clk_hw *hw)
+{
+ struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw);
+ u32 reg;
+
+ reg = readl_relaxed(zx_audio->reg_base);
+ writel_relaxed(reg & ~ZX_AUDIO_EN, zx_audio->reg_base);
+ return 0;
+}
+
+static void zx_audio_disable(struct clk_hw *hw)
+{
+ struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw);
+ u32 reg;
+
+ reg = readl_relaxed(zx_audio->reg_base);
+ writel_relaxed(reg | ZX_AUDIO_EN, zx_audio->reg_base);
+}
+
+static const struct clk_ops zx_audio_ops = {
+ .recalc_rate = zx_audio_recalc_rate,
+ .round_rate = zx_audio_round_rate,
+ .set_rate = zx_audio_set_rate,
+ .enable = zx_audio_enable,
+ .disable = zx_audio_disable,
+};
+
+struct clk *clk_register_zx_audio(const char *name,
+ const char * const parent_name,
+ unsigned long flags,
+ void __iomem *reg_base)
+{
+ struct clk_zx_audio *zx_audio;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ zx_audio = kzalloc(sizeof(*zx_audio), GFP_KERNEL);
+ if (!zx_audio)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &zx_audio_ops;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ zx_audio->reg_base = reg_base;
+ zx_audio->hw.init = &init;
+
+ clk = clk_register(NULL, &zx_audio->hw);
+ if (IS_ERR(clk))
+ kfree(zx_audio);
+
+ return clk;
+}
diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
index 0914a82d0535..65ae08b818d3 100644
--- a/drivers/clk/zte/clk.h
+++ b/drivers/clk/zte/clk.h
@@ -29,4 +29,13 @@ struct clk_zx_pll {
struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg_base,
const struct zx_pll_config *lookup_table, int count, spinlock_t *lock);
+
+struct clk_zx_audio {
+ struct clk_hw hw;
+ void __iomem *reg_base;
+};
+
+struct clk *clk_register_zx_audio(const char *name,
+ const char * const parent_name,
+ unsigned long flags, void __iomem *reg_base);
#endif
diff --git a/drivers/clk/zynq/Makefile b/drivers/clk/zynq/Makefile
index 156d923f4fa9..0afc2e7cc5c1 100644
--- a/drivers/clk/zynq/Makefile
+++ b/drivers/clk/zynq/Makefile
@@ -1,3 +1,3 @@
# Zynq clock specific Makefile
-obj-$(CONFIG_ARCH_ZYNQ) += clkc.o pll.o
+obj-y += clkc.o pll.o
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index de614384bb44..38a65c3e62fc 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -19,6 +19,7 @@
*/
#include <linux/clk/zynq.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>