summaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/at91/pmc.c9
-rw-r--r--drivers/clk/clk.c12
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c14
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c23
-rw-r--r--drivers/clk/shmobile/Makefile1
-rw-r--r--drivers/clk/shmobile/clk-sh73a0.c218
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c1
8 files changed, 255 insertions, 24 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1c0832d9475a..0b474a04730f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -13,6 +13,7 @@ config COMMON_CLK
bool
select HAVE_CLK_PREPARE
select CLKDEV_LOOKUP
+ select SRCU
---help---
The common clock framework is a single definition of struct
clk, useful across many platforms, as well as an
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 386999b4f8eb..f07c8152e5cc 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -27,6 +27,15 @@
void __iomem *at91_pmc_base;
EXPORT_SYMBOL_GPL(at91_pmc_base);
+void at91rm9200_idle(void)
+{
+ /*
+ * Disable the processor clock. The processor will be automatically
+ * re-enabled by an interrupt or by a reset.
+ */
+ at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+}
+
void at91sam9_idle(void)
{
at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index a27f14116cc9..eb0152961d3c 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2414,7 +2414,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
goto fail_out;
}
- clk->name = kstrdup(hw->init->name, GFP_KERNEL);
+ clk->name = kstrdup_const(hw->init->name, GFP_KERNEL);
if (!clk->name) {
pr_err("%s: could not allocate clk->name\n", __func__);
ret = -ENOMEM;
@@ -2441,7 +2441,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
/* copy each string name in case parent_names is __initdata */
for (i = 0; i < clk->num_parents; i++) {
- clk->parent_names[i] = kstrdup(hw->init->parent_names[i],
+ clk->parent_names[i] = kstrdup_const(hw->init->parent_names[i],
GFP_KERNEL);
if (!clk->parent_names[i]) {
pr_err("%s: could not copy parent_names\n", __func__);
@@ -2468,10 +2468,10 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
fail_parent_names_copy:
while (--i >= 0)
- kfree(clk->parent_names[i]);
+ kfree_const(clk->parent_names[i]);
kfree(clk->parent_names);
fail_parent_names:
- kfree(clk->name);
+ kfree_const(clk->name);
fail_name:
kfree(clk);
fail_out:
@@ -2490,10 +2490,10 @@ static void __clk_release(struct kref *ref)
kfree(clk->parents);
while (--i >= 0)
- kfree(clk->parent_names[i]);
+ kfree_const(clk->parent_names[i]);
kfree(clk->parent_names);
- kfree(clk->name);
+ kfree_const(clk->name);
kfree(clk);
}
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index eeadbb6b5206..05d7a0bc0599 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -190,7 +190,7 @@ 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_macref_p) = { "mac_src", "ext_gmac" };
+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" };
PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" };
@@ -575,18 +575,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
- COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0,
+ 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(0, "macref", mux_macref_p, 0,
+ MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0,
RK3288_CLKSEL_CON(21), 4, 1, MFLAGS),
- GATE(0, "sclk_macref_out", "macref", 0,
+ GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 3, GFLAGS),
- GATE(SCLK_MACREF, "sclk_macref", "macref", 0,
+ GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 2, GFLAGS),
- GATE(SCLK_MAC_RX, "sclk_mac_rx", "macref", 0,
+ GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 0, GFLAGS),
- GATE(SCLK_MAC_TX, "sclk_mac_tx", "macref", 0,
+ GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 1, GFLAGS),
COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0,
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 848d602efc06..07d666cc6a29 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -635,8 +635,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP3, 0, 1),
MUX(0, "mout_user_aclk400_mscl", mout_user_aclk400_mscl_p,
SRC_TOP3, 4, 1),
- MUX(0, "mout_user_aclk200_disp1", mout_user_aclk200_disp1_p,
- SRC_TOP3, 8, 1),
+ MUX(CLK_MOUT_USER_ACLK200_DISP1, "mout_user_aclk200_disp1",
+ mout_user_aclk200_disp1_p, SRC_TOP3, 8, 1),
MUX(0, "mout_user_aclk200_fsys2", mout_user_aclk200_fsys2_p,
SRC_TOP3, 12, 1),
MUX(0, "mout_user_aclk400_wcore", mout_user_aclk400_wcore_p,
@@ -663,8 +663,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(CLK_MOUT_USER_ACLK333, "mout_user_aclk333", mout_user_aclk333_p,
SRC_TOP4, 28, 1),
- MUX(0, "mout_user_aclk400_disp1", mout_user_aclk400_disp1_p,
- SRC_TOP5, 0, 1),
+ MUX(CLK_MOUT_USER_ACLK400_DISP1, "mout_user_aclk400_disp1",
+ mout_user_aclk400_disp1_p, SRC_TOP5, 0, 1),
MUX(0, "mout_user_aclk66_psgen", mout_user_aclk66_peric_p,
SRC_TOP5, 4, 1),
MUX(0, "mout_user_aclk333_g2d", mout_user_aclk333_g2d_p,
@@ -675,8 +675,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP5, 16, 1),
MUX(0, "mout_user_aclk300_jpeg", mout_user_aclk300_jpeg_p,
SRC_TOP5, 20, 1),
- MUX(0, "mout_user_aclk300_disp1", mout_user_aclk300_disp1_p,
- SRC_TOP5, 24, 1),
+ MUX(CLK_MOUT_USER_ACLK300_DISP1, "mout_user_aclk300_disp1",
+ mout_user_aclk300_disp1_p, SRC_TOP5, 24, 1),
MUX(0, "mout_user_aclk300_gscl", mout_user_aclk300_gscl_p,
SRC_TOP5, 28, 1),
@@ -693,7 +693,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP10, 0, 1),
MUX(0, "mout_sw_aclk400_mscl", mout_sw_aclk400_mscl_p,
SRC_TOP10, 4, 1),
- MUX(0, "mout_sw_aclk200", mout_sw_aclk200_p, SRC_TOP10, 8, 1),
+ MUX(CLK_MOUT_SW_ACLK200, "mout_sw_aclk200", mout_sw_aclk200_p,
+ SRC_TOP10, 8, 1),
MUX(0, "mout_sw_aclk200_fsys2", mout_sw_aclk200_fsys2_p,
SRC_TOP10, 12, 1),
MUX(0, "mout_sw_aclk400_wcore", mout_sw_aclk400_wcore_p,
@@ -717,8 +718,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(CLK_MOUT_SW_ACLK333, "mout_sw_aclk333", mout_sw_aclk333_p,
SRC_TOP11, 28, 1),
- MUX(0, "mout_sw_aclk400_disp1", mout_sw_aclk400_disp1_p,
- SRC_TOP12, 4, 1),
+ MUX(CLK_MOUT_SW_ACLK400, "mout_sw_aclk400_disp1",
+ mout_sw_aclk400_disp1_p, SRC_TOP12, 4, 1),
MUX(0, "mout_sw_aclk333_g2d", mout_sw_aclk333_g2d_p,
SRC_TOP12, 8, 1),
MUX(0, "mout_sw_aclk266_g2d", mout_sw_aclk266_g2d_p,
@@ -726,8 +727,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(0, "mout_sw_aclk_g3d", mout_sw_aclk_g3d_p, SRC_TOP12, 16, 1),
MUX(0, "mout_sw_aclk300_jpeg", mout_sw_aclk300_jpeg_p,
SRC_TOP12, 20, 1),
- MUX(0, "mout_sw_aclk300_disp1", mout_sw_aclk300_disp1_p,
- SRC_TOP12, 24, 1),
+ MUX(CLK_MOUT_SW_ACLK300, "mout_sw_aclk300_disp1",
+ mout_sw_aclk300_disp1_p, SRC_TOP12, 24, 1),
MUX(0, "mout_sw_aclk300_gscl", mout_sw_aclk300_gscl_p,
SRC_TOP12, 28, 1),
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index bef4e4fa6688..0689d7fb2666 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o
diff --git a/drivers/clk/shmobile/clk-sh73a0.c b/drivers/clk/shmobile/clk-sh73a0.c
new file mode 100644
index 000000000000..cd529cfe412f
--- /dev/null
+++ b/drivers/clk/shmobile/clk-sh73a0.c
@@ -0,0 +1,218 @@
+/*
+ * sh73a0 Core CPG Clocks
+ *
+ * Copyright (C) 2014 Ulrich Hecht
+ *
+ * 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 of the License.
+ */
+
+#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/spinlock.h>
+
+struct sh73a0_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_SD0CKCR 0x74
+#define CPG_SD1CKCR 0x78
+#define CPG_SD2CKCR 0x7c
+#define CPG_PLLECR 0xd0
+#define CPG_PLL0CR 0xd8
+#define CPG_PLL1CR 0x28
+#define CPG_PLL2CR 0x2c
+#define CPG_PLL3CR 0xdc
+#define CPG_CKSCR 0xc0
+#define CPG_DSI0PHYCR 0x6c
+#define CPG_DSI1PHYCR 0x70
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ const char *parent;
+ unsigned int reg;
+ unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "zg", "pll0", CPG_FRQCRA, 16 },
+ { "m3", "pll1", CPG_FRQCRA, 12 },
+ { "b", "pll1", CPG_FRQCRA, 8 },
+ { "m1", "pll1", CPG_FRQCRA, 4 },
+ { "m2", "pll1", CPG_FRQCRA, 0 },
+ { "zx", "pll1", CPG_FRQCRB, 12 },
+ { "hp", "pll1", CPG_FRQCRB, 4 },
+ { NULL, NULL, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+ { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
+ { 12, 7 }, { 0, 0 }
+};
+
+static const struct clk_div_table z_div_table[] = {
+ /* ZSEL == 0 */
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 1 },
+ { 6, 1 }, { 7, 1 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 },
+ { 12, 1 }, { 13, 1 }, { 14, 1 }, { 15, 1 },
+ /* ZSEL == 1 */
+ { 16, 2 }, { 17, 3 }, { 18, 4 }, { 19, 6 }, { 20, 8 }, { 21, 12 },
+ { 22, 16 }, { 24, 24 }, { 27, 48 }, { 0, 0 }
+};
+
+static struct clk * __init
+sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ unsigned int shift, reg, width;
+ const char *parent_name;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "main")) {
+ /* extal1, extal1_div2, extal2, extal2_div2 */
+ u32 parent_idx = (clk_readl(cpg->reg + CPG_CKSCR) >> 28) & 3;
+
+ parent_name = of_clk_get_parent_name(np, parent_idx >> 1);
+ div = (parent_idx & 1) + 1;
+ } else if (!strncmp(name, "pll", 3)) {
+ void __iomem *enable_reg = cpg->reg;
+ u32 enable_bit = name[3] - '0';
+
+ parent_name = "main";
+ switch (enable_bit) {
+ case 0:
+ enable_reg += CPG_PLL0CR;
+ break;
+ case 1:
+ enable_reg += CPG_PLL1CR;
+ break;
+ case 2:
+ enable_reg += CPG_PLL2CR;
+ break;
+ case 3:
+ enable_reg += CPG_PLL3CR;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ if (clk_readl(cpg->reg + CPG_PLLECR) & BIT(enable_bit)) {
+ mult = ((clk_readl(enable_reg) >> 24) & 0x3f) + 1;
+ /* handle CFG bit for PLL1 and PLL2 */
+ if (enable_bit == 1 || enable_bit == 2)
+ if (clk_readl(enable_reg) & BIT(20))
+ mult *= 2;
+ }
+ } else if (!strcmp(name, "dsi0phy") || !strcmp(name, "dsi1phy")) {
+ u32 phy_no = name[3] - '0';
+ void __iomem *dsi_reg = cpg->reg +
+ (phy_no ? CPG_DSI1PHYCR : CPG_DSI0PHYCR);
+
+ parent_name = phy_no ? "dsi1pck" : "dsi0pck";
+ mult = __raw_readl(dsi_reg);
+ if (!(mult & 0x8000))
+ mult = 1;
+ else
+ mult = (mult & 0x3f) + 1;
+ } else if (!strcmp(name, "z")) {
+ parent_name = "pll0";
+ table = z_div_table;
+ reg = CPG_FRQCRB;
+ shift = 24;
+ width = 5;
+ } else {
+ struct div4_clk *c;
+
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name)) {
+ parent_name = c->parent;
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ width = 4;
+ break;
+ }
+ }
+ if (!c->name)
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!table) {
+ return clk_register_fixed_factor(NULL, name, parent_name, 0,
+ mult, div);
+ } else {
+ return clk_register_divider_table(NULL, name, parent_name, 0,
+ cpg->reg + reg, shift, width, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init sh73a0_cpg_clocks_init(struct device_node *np)
+{
+ struct sh73a0_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+ if (WARN_ON(cpg->reg == NULL))
+ return;
+
+ /* Set SDHI clocks to a known state */
+ clk_writel(0x108, cpg->reg + CPG_SD0CKCR);
+ clk_writel(0x108, cpg->reg + CPG_SD1CKCR);
+ clk_writel(0x108, cpg->reg + CPG_SD2CKCR);
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = sh73a0_cpg_register_clock(np, cpg, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(sh73a0_cpg_clks, "renesas,sh73a0-cpg-clocks",
+ sh73a0_cpg_clocks_init);
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 69937eaba795..379324eb5486 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -1408,6 +1408,7 @@ static void __init sun6i_init_clocks(struct device_node *node)
ARRAY_SIZE(sun6i_critical_clocks));
}
CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
+CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
static void __init sun9i_init_clocks(struct device_node *node)