obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
-obj-$(CONFIG_ARCH_RENESAS) += shmobile/
+obj-$(CONFIG_ARCH_RENESAS) += renesas/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
--- /dev/null
+obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
+obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7795) += renesas-cpg-mssr.o \
+ r8a7795-cpg-mssr.o clk-div6.o
+obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-mstp.o clk-div6.o
--- /dev/null
+/*
+ * r8a7790 Common Clock Framework support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License.
+ */
+
+#include <linux/clk-provider.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>
+
+#include "clk-div6.h"
+
+#define CPG_DIV6_CKSTP BIT(8)
+#define CPG_DIV6_DIV(d) ((d) & 0x3f)
+#define CPG_DIV6_DIV_MASK 0x3f
+
+/**
+ * struct div6_clock - CPG 6 bit divider clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: IO-remapped register
+ * @div: divisor value (1-64)
+ */
+struct div6_clock {
+ struct clk_hw hw;
+ void __iomem *reg;
+ unsigned int div;
+ u32 src_shift;
+ u32 src_width;
+ u8 *parents;
+};
+
+#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
+
+static int cpg_div6_clock_enable(struct clk_hw *hw)
+{
+ struct div6_clock *clock = to_div6_clock(hw);
+ u32 val;
+
+ val = (clk_readl(clock->reg) & ~(CPG_DIV6_DIV_MASK | CPG_DIV6_CKSTP))
+ | CPG_DIV6_DIV(clock->div - 1);
+ clk_writel(val, clock->reg);
+
+ return 0;
+}
+
+static void cpg_div6_clock_disable(struct clk_hw *hw)
+{
+ struct div6_clock *clock = to_div6_clock(hw);
+ u32 val;
+
+ val = clk_readl(clock->reg);
+ val |= CPG_DIV6_CKSTP;
+ /*
+ * DIV6 clocks require the divisor field to be non-zero when stopping
+ * the clock. However, some clocks (e.g. ZB on sh73a0) fail to be
+ * re-enabled later if the divisor field is changed when stopping the
+ * clock
+ */
+ if (!(val & CPG_DIV6_DIV_MASK))
+ val |= CPG_DIV6_DIV_MASK;
+ clk_writel(val, clock->reg);
+}
+
+static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
+{
+ struct div6_clock *clock = to_div6_clock(hw);
+
+ return !(clk_readl(clock->reg) & CPG_DIV6_CKSTP);
+}
+
+static unsigned long cpg_div6_clock_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct div6_clock *clock = to_div6_clock(hw);
+
+ return parent_rate / clock->div;
+}
+
+static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned int div;
+
+ if (!rate)
+ rate = 1;
+
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ return clamp_t(unsigned int, div, 1, 64);
+}
+
+static long cpg_div6_clock_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned int div = cpg_div6_clock_calc_div(rate, *parent_rate);
+
+ return *parent_rate / div;
+}
+
+static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct div6_clock *clock = to_div6_clock(hw);
+ unsigned int div = cpg_div6_clock_calc_div(rate, parent_rate);
+ u32 val;
+
+ clock->div = div;
+
+ val = clk_readl(clock->reg) & ~CPG_DIV6_DIV_MASK;
+ /* Only program the new divisor if the clock isn't stopped. */
+ if (!(val & CPG_DIV6_CKSTP))
+ clk_writel(val | CPG_DIV6_DIV(clock->div - 1), clock->reg);
+
+ return 0;
+}
+
+static u8 cpg_div6_clock_get_parent(struct clk_hw *hw)
+{
+ struct div6_clock *clock = to_div6_clock(hw);
+ unsigned int i;
+ u8 hw_index;
+
+ if (clock->src_width == 0)
+ return 0;
+
+ hw_index = (clk_readl(clock->reg) >> clock->src_shift) &
+ (BIT(clock->src_width) - 1);
+ 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_hw_get_name(hw), hw_index);
+ return 0;
+}
+
+static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct div6_clock *clock = to_div6_clock(hw);
+ u8 hw_index;
+ u32 mask;
+
+ if (index >= clk_hw_get_num_parents(hw))
+ return -EINVAL;
+
+ mask = ~((BIT(clock->src_width) - 1) << clock->src_shift);
+ hw_index = clock->parents[index];
+
+ clk_writel((clk_readl(clock->reg) & mask) |
+ (hw_index << clock->src_shift), clock->reg);
+
+ return 0;
+}
+
+static const struct clk_ops cpg_div6_clock_ops = {
+ .enable = cpg_div6_clock_enable,
+ .disable = cpg_div6_clock_disable,
+ .is_enabled = cpg_div6_clock_is_enabled,
+ .get_parent = cpg_div6_clock_get_parent,
+ .set_parent = cpg_div6_clock_set_parent,
+ .recalc_rate = cpg_div6_clock_recalc_rate,
+ .round_rate = cpg_div6_clock_round_rate,
+ .set_rate = cpg_div6_clock_set_rate,
+};
+
+
+/**
+ * cpg_div6_register - Register a DIV6 clock
+ * @name: Name of the DIV6 clock
+ * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8)
+ * @parent_names: Array containing the names of the parent clocks
+ * @reg: Mapped register used to control the DIV6 clock
+ */
+struct clk * __init cpg_div6_register(const char *name,
+ unsigned int num_parents,
+ const char **parent_names,
+ void __iomem *reg)
+{
+ unsigned int valid_parents;
+ struct clk_init_data init;
+ struct div6_clock *clock;
+ struct clk *clk;
+ unsigned int i;
+
+ clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+ if (!clock)
+ return ERR_PTR(-ENOMEM);
+
+ clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
+ GFP_KERNEL);
+ if (!clock->parents) {
+ clk = ERR_PTR(-ENOMEM);
+ goto free_clock;
+ }
+
+ clock->reg = reg;
+
+ /*
+ * Read the divisor. Disabling the clock overwrites the divisor, so we
+ * need to cache its value for the enable operation.
+ */
+ clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
+
+ switch (num_parents) {
+ case 1:
+ /* fixed parent clock */
+ clock->src_shift = clock->src_width = 0;
+ break;
+ case 4:
+ /* clock with EXSRC bits 6-7 */
+ clock->src_shift = 6;
+ clock->src_width = 2;
+ break;
+ case 8:
+ /* VCLK with EXSRC bits 12-14 */
+ clock->src_shift = 12;
+ clock->src_width = 3;
+ break;
+ default:
+ pr_err("%s: invalid number of parents for DIV6 clock %s\n",
+ __func__, name);
+ clk = ERR_PTR(-EINVAL);
+ goto free_parents;
+ }
+
+ /* Filter out invalid parents */
+ for (i = 0, valid_parents = 0; i < num_parents; i++) {
+ if (parent_names[i]) {
+ parent_names[valid_parents] = parent_names[i];
+ clock->parents[valid_parents] = i;
+ valid_parents++;
+ }
+ }
+
+ /* Register the clock. */
+ init.name = name;
+ init.ops = &cpg_div6_clock_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = parent_names;
+ init.num_parents = valid_parents;
+
+ clock->hw.init = &init;
+
+ clk = clk_register(NULL, &clock->hw);
+ if (IS_ERR(clk))
+ goto free_parents;
+
+ return clk;
+
+free_parents:
+ kfree(clock->parents);
+free_clock:
+ kfree(clock);
+ return clk;
+}
+
+static void __init cpg_div6_clock_init(struct device_node *np)
+{
+ unsigned int num_parents;
+ const char **parent_names;
+ const char *clk_name = np->name;
+ void __iomem *reg;
+ struct clk *clk;
+ unsigned int i;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents < 1) {
+ pr_err("%s: no parent found for %s DIV6 clock\n",
+ __func__, np->name);
+ return;
+ }
+
+ parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
+ GFP_KERNEL);
+ if (!parent_names)
+ return;
+
+ reg = of_iomap(np, 0);
+ if (reg == NULL) {
+ pr_err("%s: failed to map %s DIV6 clock register\n",
+ __func__, np->name);
+ goto error;
+ }
+
+ /* Parse the DT properties. */
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ clk = cpg_div6_register(clk_name, num_parents, parent_names, reg);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
+ __func__, np->name, PTR_ERR(clk));
+ goto error;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+ kfree(parent_names);
+ return;
+
+error:
+ if (reg)
+ iounmap(reg);
+ kfree(parent_names);
+}
+CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init);
--- /dev/null
+#ifndef __SHMOBILE_CLK_DIV6_H__
+#define __SHMOBILE_CLK_DIV6_H__
+
+struct clk *cpg_div6_register(const char *name, unsigned int num_parents,
+ const char **parent_names, void __iomem *reg);
+
+#endif
--- /dev/null
+/*
+ * EMMA Mobile EV2 common clock framework support
+ *
+ * Copyright (C) 2013 Takashi Yoshii <takashi.yoshii.ze@renesas.com>
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+/* EMEV2 SMU registers */
+#define USIAU0_RSTCTRL 0x094
+#define USIBU1_RSTCTRL 0x0ac
+#define USIBU2_RSTCTRL 0x0b0
+#define USIBU3_RSTCTRL 0x0b4
+#define IIC0_RSTCTRL 0x0dc
+#define IIC1_RSTCTRL 0x0e0
+#define STI_RSTCTRL 0x124
+#define STI_CLKSEL 0x688
+
+static DEFINE_SPINLOCK(lock);
+
+/* not pretty, but hey */
+static void __iomem *smu_base;
+
+static void __init emev2_smu_write(unsigned long value, int offs)
+{
+ BUG_ON(!smu_base || (offs >= PAGE_SIZE));
+ writel_relaxed(value, smu_base + offs);
+}
+
+static const struct of_device_id smu_id[] __initconst = {
+ { .compatible = "renesas,emev2-smu", },
+ {},
+};
+
+static void __init emev2_smu_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, smu_id);
+ BUG_ON(!np);
+ smu_base = of_iomap(np, 0);
+ BUG_ON(!smu_base);
+ of_node_put(np);
+
+ /* setup STI timer to run on 32.768 kHz and deassert reset */
+ emev2_smu_write(0, STI_CLKSEL);
+ emev2_smu_write(1, STI_RSTCTRL);
+
+ /* deassert reset for UART0->UART3 */
+ emev2_smu_write(2, USIAU0_RSTCTRL);
+ emev2_smu_write(2, USIBU1_RSTCTRL);
+ emev2_smu_write(2, USIBU2_RSTCTRL);
+ emev2_smu_write(2, USIBU3_RSTCTRL);
+
+ /* deassert reset for IIC0->IIC1 */
+ emev2_smu_write(1, IIC0_RSTCTRL);
+ emev2_smu_write(1, IIC1_RSTCTRL);
+}
+
+static void __init emev2_smu_clkdiv_init(struct device_node *np)
+{
+ u32 reg[2];
+ struct clk *clk;
+ const char *parent_name = of_clk_get_parent_name(np, 0);
+ if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2)))
+ return;
+ if (!smu_base)
+ emev2_smu_init();
+ clk = clk_register_divider(NULL, np->name, parent_name, 0,
+ smu_base + reg[0], reg[1], 8, 0, &lock);
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, np->name, NULL);
+ pr_debug("## %s %s %p\n", __func__, np->name, clk);
+}
+CLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv",
+ emev2_smu_clkdiv_init);
+
+static void __init emev2_smu_gclk_init(struct device_node *np)
+{
+ u32 reg[2];
+ struct clk *clk;
+ const char *parent_name = of_clk_get_parent_name(np, 0);
+ if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2)))
+ return;
+ if (!smu_base)
+ emev2_smu_init();
+ clk = clk_register_gate(NULL, np->name, parent_name, 0,
+ smu_base + reg[0], reg[1], 0, &lock);
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, np->name, NULL);
+ pr_debug("## %s %s %p\n", __func__, np->name, clk);
+}
+CLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk", emev2_smu_gclk_init);
--- /dev/null
+/*
+ * R-Car MSTP clocks
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; 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>
+
+/*
+ * MSTP clocks. We can't use standard gate clocks as we need to poll on the
+ * status register when enabling the clock.
+ */
+
+#define MSTP_MAX_CLOCKS 32
+
+/**
+ * struct mstp_clock_group - MSTP gating clocks group
+ *
+ * @data: clocks in this group
+ * @smstpcr: module stop control register
+ * @mstpsr: module stop status register (optional)
+ * @lock: protects writes to SMSTPCR
+ */
+struct mstp_clock_group {
+ struct clk_onecell_data data;
+ void __iomem *smstpcr;
+ void __iomem *mstpsr;
+ spinlock_t lock;
+};
+
+/**
+ * struct mstp_clock - MSTP gating clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @bit_index: control bit index
+ * @group: MSTP clocks group
+ */
+struct mstp_clock {
+ struct clk_hw hw;
+ u32 bit_index;
+ struct mstp_clock_group *group;
+};
+
+#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
+
+static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
+{
+ struct mstp_clock *clock = to_mstp_clock(hw);
+ struct mstp_clock_group *group = clock->group;
+ u32 bitmask = BIT(clock->bit_index);
+ unsigned long flags;
+ unsigned int i;
+ u32 value;
+
+ spin_lock_irqsave(&group->lock, flags);
+
+ value = clk_readl(group->smstpcr);
+ if (enable)
+ value &= ~bitmask;
+ else
+ value |= bitmask;
+ clk_writel(value, group->smstpcr);
+
+ spin_unlock_irqrestore(&group->lock, flags);
+
+ if (!enable || !group->mstpsr)
+ return 0;
+
+ for (i = 1000; i > 0; --i) {
+ if (!(clk_readl(group->mstpsr) & bitmask))
+ break;
+ cpu_relax();
+ }
+
+ if (!i) {
+ pr_err("%s: failed to enable %p[%d]\n", __func__,
+ group->smstpcr, clock->bit_index);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int cpg_mstp_clock_enable(struct clk_hw *hw)
+{
+ return cpg_mstp_clock_endisable(hw, true);
+}
+
+static void cpg_mstp_clock_disable(struct clk_hw *hw)
+{
+ cpg_mstp_clock_endisable(hw, false);
+}
+
+static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
+{
+ struct mstp_clock *clock = to_mstp_clock(hw);
+ struct mstp_clock_group *group = clock->group;
+ u32 value;
+
+ if (group->mstpsr)
+ value = clk_readl(group->mstpsr);
+ else
+ value = clk_readl(group->smstpcr);
+
+ return !(value & BIT(clock->bit_index));
+}
+
+static const struct clk_ops cpg_mstp_clock_ops = {
+ .enable = cpg_mstp_clock_enable,
+ .disable = cpg_mstp_clock_disable,
+ .is_enabled = cpg_mstp_clock_is_enabled,
+};
+
+static struct clk * __init
+cpg_mstp_clock_register(const char *name, const char *parent_name,
+ unsigned int index, struct mstp_clock_group *group)
+{
+ struct clk_init_data init;
+ struct mstp_clock *clock;
+ struct clk *clk;
+
+ clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+ if (!clock) {
+ pr_err("%s: failed to allocate MSTP clock.\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &cpg_mstp_clock_ops;
+ init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clock->bit_index = index;
+ clock->group = group;
+ clock->hw.init = &init;
+
+ clk = clk_register(NULL, &clock->hw);
+
+ if (IS_ERR(clk))
+ kfree(clock);
+
+ return clk;
+}
+
+static void __init cpg_mstp_clocks_init(struct device_node *np)
+{
+ struct mstp_clock_group *group;
+ const char *idxname;
+ struct clk **clks;
+ unsigned int i;
+
+ group = kzalloc(sizeof(*group), GFP_KERNEL);
+ clks = kmalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL);
+ if (group == NULL || clks == NULL) {
+ kfree(group);
+ kfree(clks);
+ pr_err("%s: failed to allocate group\n", __func__);
+ return;
+ }
+
+ spin_lock_init(&group->lock);
+ group->data.clks = clks;
+
+ group->smstpcr = of_iomap(np, 0);
+ group->mstpsr = of_iomap(np, 1);
+
+ if (group->smstpcr == NULL) {
+ pr_err("%s: failed to remap SMSTPCR\n", __func__);
+ kfree(group);
+ kfree(clks);
+ return;
+ }
+
+ for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
+ clks[i] = ERR_PTR(-ENOENT);
+
+ if (of_find_property(np, "clock-indices", &i))
+ idxname = "clock-indices";
+ else
+ idxname = "renesas,clock-indices";
+
+ for (i = 0; i < MSTP_MAX_CLOCKS; ++i) {
+ const char *parent_name;
+ const char *name;
+ u32 clkidx;
+ int ret;
+
+ /* Skip clocks with no name. */
+ ret = of_property_read_string_index(np, "clock-output-names",
+ i, &name);
+ if (ret < 0 || strlen(name) == 0)
+ continue;
+
+ parent_name = of_clk_get_parent_name(np, i);
+ ret = of_property_read_u32_index(np, idxname, i, &clkidx);
+ if (parent_name == NULL || ret < 0)
+ break;
+
+ if (clkidx >= MSTP_MAX_CLOCKS) {
+ pr_err("%s: invalid clock %s %s index %u\n",
+ __func__, np->name, name, clkidx);
+ continue;
+ }
+
+ clks[clkidx] = cpg_mstp_clock_register(name, parent_name,
+ clkidx, group);
+ if (!IS_ERR(clks[clkidx])) {
+ group->data.clk_num = max(group->data.clk_num,
+ clkidx + 1);
+ /*
+ * Register a clkdev to let board code retrieve the
+ * clock by name and register aliases for non-DT
+ * devices.
+ *
+ * FIXME: Remove this when all devices that require a
+ * clock will be instantiated from DT.
+ */
+ clk_register_clkdev(clks[clkidx], name, NULL);
+ } else {
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clks[clkidx]));
+ }
+ }
+
+ 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;
+
+ /* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */
+ if (!strcmp(clkspec.np->name, "zb_clk"))
+ 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 */
--- /dev/null
+/*
+ * r8a73a4 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/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>
+
+struct r8a73a4_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_CKSCR 0xc0
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_FRQCRC 0xe0
+#define CPG_PLL0CR 0xd8
+#define CPG_PLL1CR 0x28
+#define CPG_PLL2CR 0x2c
+#define CPG_PLL2HCR 0xe4
+#define CPG_PLL2SCR 0xf4
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ unsigned int reg;
+ unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "i", CPG_FRQCRA, 20 },
+ { "m3", CPG_FRQCRA, 12 },
+ { "b", CPG_FRQCRA, 8 },
+ { "m1", CPG_FRQCRA, 4 },
+ { "m2", CPG_FRQCRA, 0 },
+ { "zx", CPG_FRQCRB, 12 },
+ { "zs", CPG_FRQCRB, 8 },
+ { "hp", CPG_FRQCRB, 4 },
+ { 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, 10 }, { 0, 0 }
+};
+
+static struct clk * __init
+r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ const char *parent_name;
+ unsigned int shift, reg;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+
+ if (!strcmp(name, "main")) {
+ u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR);
+
+ switch ((ckscr >> 28) & 3) {
+ case 0: /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ break;
+ case 1: /* extal1 / 2 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 2;
+ break;
+ case 2: /* extal2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ break;
+ case 3: /* extal2 / 2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ div = 2;
+ break;
+ }
+ } else if (!strcmp(name, "pll0")) {
+ /* PLL0/1 are configurable multiplier clocks. Register them as
+ * fixed factor clocks for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+
+ parent_name = "main";
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(20))
+ div = 2;
+ } else if (!strcmp(name, "pll1")) {
+ u32 value = clk_readl(cpg->reg + CPG_PLL1CR);
+
+ parent_name = "main";
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(7))
+ div = 2;
+ } else if (!strncmp(name, "pll2", 4)) {
+ u32 value, cr;
+
+ switch (name[4]) {
+ case 0:
+ cr = CPG_PLL2CR;
+ break;
+ case 's':
+ cr = CPG_PLL2SCR;
+ break;
+ case 'h':
+ cr = CPG_PLL2HCR;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ value = clk_readl(cpg->reg + cr);
+ switch ((value >> 5) & 7) {
+ case 0:
+ parent_name = "main";
+ div = 2;
+ break;
+ case 1:
+ parent_name = "extal2";
+ div = 2;
+ break;
+ case 3:
+ parent_name = "extal2";
+ div = 4;
+ break;
+ case 4:
+ parent_name = "main";
+ break;
+ case 5:
+ parent_name = "extal2";
+ break;
+ default:
+ pr_warn("%s: unexpected parent of %s\n", __func__,
+ name);
+ return ERR_PTR(-EINVAL);
+ }
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ } else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
+ u32 shift = 8;
+
+ parent_name = "pll0";
+ if (name[1] == '2') {
+ div = 2;
+ shift = 0;
+ }
+ div *= 32;
+ mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift)
+ & 0x1f);
+ } else {
+ struct div4_clk *c;
+
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name))
+ break;
+ }
+ if (!c->name)
+ return ERR_PTR(-EINVAL);
+
+ parent_name = "pll1";
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ }
+
+ 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, 4, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a73a4_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;
+
+ 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 = r8a73a4_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(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
+ r8a73a4_cpg_clocks_init);
--- /dev/null
+/*
+ * r8a7740 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/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>
+
+struct r8a7740_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_PLLC2CR 0x2c
+#define CPG_USBCKCR 0x8c
+#define CPG_FRQCRC 0xe0
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ unsigned int reg;
+ unsigned int shift;
+ int flags;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "i", CPG_FRQCRA, 20, CLK_ENABLE_ON_INIT },
+ { "zg", CPG_FRQCRA, 16, CLK_ENABLE_ON_INIT },
+ { "b", CPG_FRQCRA, 8, CLK_ENABLE_ON_INIT },
+ { "m1", CPG_FRQCRA, 4, CLK_ENABLE_ON_INIT },
+ { "hp", CPG_FRQCRB, 4, 0 },
+ { "hpp", CPG_FRQCRC, 20, 0 },
+ { "usbp", CPG_FRQCRC, 16, 0 },
+ { "s", CPG_FRQCRC, 12, 0 },
+ { "zb", CPG_FRQCRC, 8, 0 },
+ { "m3", CPG_FRQCRC, 4, 0 },
+ { "cp", CPG_FRQCRC, 0, 0 },
+ { NULL, 0, 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 }, { 9, 32 }, { 10, 36 }, { 11, 48 },
+ { 13, 72 }, { 14, 96 }, { 0, 0 }
+};
+
+static u32 cpg_mode __initdata;
+
+static struct clk * __init
+r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ const char *parent_name;
+ unsigned int shift, reg;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "r")) {
+ switch (cpg_mode & (BIT(2) | BIT(1))) {
+ case BIT(1) | BIT(2):
+ /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 2048;
+ break;
+ case BIT(2):
+ /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 1024;
+ break;
+ default:
+ /* extalr */
+ parent_name = of_clk_get_parent_name(np, 2);
+ break;
+ }
+ } else if (!strcmp(name, "system")) {
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (cpg_mode & BIT(1))
+ div = 2;
+ } else if (!strcmp(name, "pllc0")) {
+ /* PLLC0/1 are configurable multiplier clocks. Register them as
+ * fixed factor clocks for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
+ parent_name = "system";
+ mult = ((value >> 24) & 0x7f) + 1;
+ } else if (!strcmp(name, "pllc1")) {
+ u32 value = clk_readl(cpg->reg + CPG_FRQCRA);
+ parent_name = "system";
+ mult = ((value >> 24) & 0x7f) + 1;
+ div = 2;
+ } else if (!strcmp(name, "pllc2")) {
+ u32 value = clk_readl(cpg->reg + CPG_PLLC2CR);
+ parent_name = "system";
+ mult = ((value >> 24) & 0x3f) + 1;
+ } else if (!strcmp(name, "usb24s")) {
+ u32 value = clk_readl(cpg->reg + CPG_USBCKCR);
+ if (value & BIT(7))
+ /* extal2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ else
+ parent_name = "system";
+ if (!(value & BIT(6)))
+ div = 2;
+ } else {
+ struct div4_clk *c;
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name)) {
+ parent_name = "pllc1";
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ 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, 4, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init r8a7740_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a7740_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ if (of_property_read_u32(np, "renesas,mode", &cpg_mode))
+ pr_warn("%s: missing renesas,mode property\n", __func__);
+
+ 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 = kzalloc(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;
+
+ 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 = r8a7740_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(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks",
+ r8a7740_cpg_clocks_init);
--- /dev/null
+/*
+ * r8a7778 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/clk/shmobile.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+struct r8a7778_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+/* PLL multipliers per bits 11, 12, and 18 of MODEMR */
+static const struct {
+ unsigned long plla_mult;
+ unsigned long pllb_mult;
+} r8a7778_rates[] __initconst = {
+ [0] = { 21, 21 },
+ [1] = { 24, 24 },
+ [2] = { 28, 28 },
+ [3] = { 32, 32 },
+ [5] = { 24, 21 },
+ [6] = { 28, 21 },
+ [7] = { 32, 24 },
+};
+
+/* Clock dividers per bits 1 and 2 of MODEMR */
+static const struct {
+ const char *name;
+ unsigned int div[4];
+} r8a7778_divs[6] __initconst = {
+ { "b", { 12, 12, 16, 18 } },
+ { "out", { 12, 12, 16, 18 } },
+ { "p", { 16, 12, 16, 12 } },
+ { "s", { 4, 3, 4, 3 } },
+ { "s1", { 8, 6, 8, 6 } },
+};
+
+static u32 cpg_mode_rates __initdata;
+static u32 cpg_mode_divs __initdata;
+
+static struct clk * __init
+r8a7778_cpg_register_clock(struct device_node *np, struct r8a7778_cpg *cpg,
+ const char *name)
+{
+ if (!strcmp(name, "plla")) {
+ return clk_register_fixed_factor(NULL, "plla",
+ of_clk_get_parent_name(np, 0), 0,
+ r8a7778_rates[cpg_mode_rates].plla_mult, 1);
+ } else if (!strcmp(name, "pllb")) {
+ return clk_register_fixed_factor(NULL, "pllb",
+ of_clk_get_parent_name(np, 0), 0,
+ r8a7778_rates[cpg_mode_rates].pllb_mult, 1);
+ } else {
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(r8a7778_divs); i++) {
+ if (!strcmp(name, r8a7778_divs[i].name)) {
+ return clk_register_fixed_factor(NULL,
+ r8a7778_divs[i].name,
+ "plla", 0, 1,
+ r8a7778_divs[i].div[cpg_mode_divs]);
+ }
+ }
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+
+static void __init r8a7778_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a7778_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;
+
+ 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 = r8a7778_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);
+
+ cpg_mstp_add_clk_domain(np);
+}
+
+CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks",
+ r8a7778_cpg_clocks_init);
+
+void __init r8a7778_clocks_init(u32 mode)
+{
+ BUG_ON(!(mode & BIT(19)));
+
+ cpg_mode_rates = (!!(mode & BIT(18)) << 2) |
+ (!!(mode & BIT(12)) << 1) |
+ (!!(mode & BIT(11)));
+ cpg_mode_divs = (!!(mode & BIT(2)) << 1) |
+ (!!(mode & BIT(1)));
+
+ of_clk_init(NULL);
+}
--- /dev/null
+/*
+ * r8a7779 Core CPG Clocks
+ *
+ * Copyright (C) 2013, 2014 Horms Solutions Ltd.
+ *
+ * Contact: Simon Horman <horms@verge.net.au>
+ *
+ * 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/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>
+
+#define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1)
+
+struct r8a7779_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+/* -----------------------------------------------------------------------------
+ * CPG Clock Data
+ */
+
+/*
+ * MD1 = 1 MD1 = 0
+ * (PLLA = 1500) (PLLA = 1600)
+ * (MHz) (MHz)
+ *------------------------------------------------+--------------------
+ * clkz 1000 (2/3) 800 (1/2)
+ * clkzs 250 (1/6) 200 (1/8)
+ * clki 750 (1/2) 800 (1/2)
+ * clks 250 (1/6) 200 (1/8)
+ * clks1 125 (1/12) 100 (1/16)
+ * clks3 187.5 (1/8) 200 (1/8)
+ * clks4 93.7 (1/16) 100 (1/16)
+ * clkp 62.5 (1/24) 50 (1/32)
+ * clkg 62.5 (1/24) 66.6 (1/24)
+ * clkb, CLKOUT
+ * (MD2 = 0) 62.5 (1/24) 66.6 (1/24)
+ * (MD2 = 1) 41.6 (1/36) 50 (1/32)
+ */
+
+#define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1)
+
+struct cpg_clk_config {
+ unsigned int z_mult;
+ unsigned int z_div;
+ unsigned int zs_and_s_div;
+ unsigned int s1_div;
+ unsigned int p_div;
+ unsigned int b_and_out_div;
+};
+
+static const struct cpg_clk_config cpg_clk_configs[4] __initconst = {
+ { 1, 2, 8, 16, 32, 24 },
+ { 2, 3, 6, 12, 24, 24 },
+ { 1, 2, 8, 16, 32, 32 },
+ { 2, 3, 6, 12, 24, 36 },
+};
+
+/*
+ * MD PLLA Ratio
+ * 12 11
+ *------------------------
+ * 0 0 x42
+ * 0 1 x48
+ * 1 0 x56
+ * 1 1 x64
+ */
+
+#define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11)
+
+static const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 };
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+static u32 cpg_mode __initdata;
+
+static struct clk * __init
+r8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg,
+ const struct cpg_clk_config *config,
+ unsigned int plla_mult, const char *name)
+{
+ const char *parent_name = "plla";
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "plla")) {
+ parent_name = of_clk_get_parent_name(np, 0);
+ mult = plla_mult;
+ } else if (!strcmp(name, "z")) {
+ div = config->z_div;
+ mult = config->z_mult;
+ } else if (!strcmp(name, "zs") || !strcmp(name, "s")) {
+ div = config->zs_and_s_div;
+ } else if (!strcmp(name, "s1")) {
+ div = config->s1_div;
+ } else if (!strcmp(name, "p")) {
+ div = config->p_div;
+ } else if (!strcmp(name, "b") || !strcmp(name, "out")) {
+ div = config->b_and_out_div;
+ } else {
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div);
+}
+
+static void __init r8a7779_cpg_clocks_init(struct device_node *np)
+{
+ const struct cpg_clk_config *config;
+ struct r8a7779_cpg *cpg;
+ struct clk **clks;
+ unsigned int i, plla_mult;
+ 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 = kzalloc(CPG_NUM_CLOCKS * 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;
+
+ config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)];
+ plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)];
+
+ 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 = r8a7779_cpg_register_clock(np, cpg, config,
+ plla_mult, 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);
+
+ cpg_mstp_add_clk_domain(np);
+}
+CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
+ r8a7779_cpg_clocks_init);
+
+void __init r8a7779_clocks_init(u32 mode)
+{
+ cpg_mode = mode;
+
+ of_clk_init(NULL);
+}
--- /dev/null
+/*
+ * rcar_gen2 Core CPG Clocks
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License.
+ */
+
+#include <linux/clk-provider.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 {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_FRQCRB 0x00000004
+#define CPG_FRQCRB_KICK BIT(31)
+#define CPG_SDCKCR 0x00000074
+#define CPG_PLL0CR 0x000000d8
+#define CPG_FRQCRC 0x000000e0
+#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
+#define CPG_FRQCRC_ZFC_SHIFT 8
+#define CPG_ADSPCKCR 0x0000025c
+#define CPG_RCANCKCR 0x00000270
+
+/* -----------------------------------------------------------------------------
+ * Z Clock
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable. clk->rate = parent->rate * mult / 32
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+struct cpg_z_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+ void __iomem *kick_reg;
+};
+
+#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
+
+static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cpg_z_clk *zclk = to_z_clk(hw);
+ unsigned int mult;
+ unsigned int val;
+
+ val = (clk_readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK)
+ >> CPG_FRQCRC_ZFC_SHIFT;
+ mult = 32 - val;
+
+ return div_u64((u64)parent_rate * mult, 32);
+}
+
+static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned long prate = *parent_rate;
+ unsigned int mult;
+
+ if (!prate)
+ prate = 1;
+
+ mult = div_u64((u64)rate * 32, prate);
+ mult = clamp(mult, 1U, 32U);
+
+ return *parent_rate / 32 * mult;
+}
+
+static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cpg_z_clk *zclk = to_z_clk(hw);
+ unsigned int mult;
+ u32 val, kick;
+ unsigned int i;
+
+ mult = div_u64((u64)rate * 32, parent_rate);
+ mult = clamp(mult, 1U, 32U);
+
+ if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
+ return -EBUSY;
+
+ val = clk_readl(zclk->reg);
+ val &= ~CPG_FRQCRC_ZFC_MASK;
+ val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
+ clk_writel(val, zclk->reg);
+
+ /*
+ * Set KICK bit in FRQCRB to update hardware setting and wait for
+ * clock change completion.
+ */
+ kick = clk_readl(zclk->kick_reg);
+ kick |= CPG_FRQCRB_KICK;
+ clk_writel(kick, zclk->kick_reg);
+
+ /*
+ * Note: There is no HW information about the worst case latency.
+ *
+ * Using experimental measurements, it seems that no more than
+ * ~10 iterations are needed, independently of the CPU rate.
+ * Since this value might be dependent on external xtal rate, pll1
+ * rate or even the other emulation clocks rate, use 1000 as a
+ * "super" safe value.
+ */
+ for (i = 1000; i; i--) {
+ if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
+ return 0;
+
+ cpu_relax();
+ }
+
+ return -ETIMEDOUT;
+}
+
+static const struct clk_ops cpg_z_clk_ops = {
+ .recalc_rate = cpg_z_clk_recalc_rate,
+ .round_rate = cpg_z_clk_round_rate,
+ .set_rate = cpg_z_clk_set_rate,
+};
+
+static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
+{
+ static const char *parent_name = "pll0";
+ struct clk_init_data init;
+ struct cpg_z_clk *zclk;
+ struct clk *clk;
+
+ zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);
+ if (!zclk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = "z";
+ init.ops = &cpg_z_clk_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ zclk->reg = cpg->reg + CPG_FRQCRC;
+ zclk->kick_reg = cpg->reg + CPG_FRQCRB;
+ zclk->hw.init = &init;
+
+ clk = clk_register(NULL, &zclk->hw);
+ if (IS_ERR(clk))
+ kfree(zclk);
+
+ return clk;
+}
+
+static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
+ struct device_node *np)
+{
+ const char *parent_name = of_clk_get_parent_name(np, 1);
+ struct clk_fixed_factor *fixed;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+ if (!fixed)
+ return ERR_PTR(-ENOMEM);
+
+ fixed->mult = 1;
+ fixed->div = 6;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(fixed);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_RCANCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
+ &fixed->hw, &clk_fixed_factor_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(fixed);
+ }
+
+ return clk;
+}
+
+/* ADSP divisors */
+static const struct clk_div_table cpg_adsp_div_table[] = {
+ { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 },
+ { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
+ { 10, 36 }, { 11, 48 }, { 0, 0 },
+};
+
+static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
+{
+ const char *parent_name = "pll1";
+ struct clk_divider *div;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->reg = cpg->reg + CPG_ADSPCKCR;
+ div->width = 4;
+ div->table = cpg_adsp_div_table;
+ div->lock = &cpg->lock;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(div);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_ADSPCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "adsp", &parent_name, 1, NULL, NULL,
+ &div->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(div);
+ }
+
+ return clk;
+}
+
+/* -----------------------------------------------------------------------------
+ * CPG Clock Data
+ */
+
+/*
+ * MD EXTAL PLL0 PLL1 PLL3
+ * 14 13 19 (MHz) *1 *1
+ *---------------------------------------------------
+ * 0 0 0 15 x 1 x172/2 x208/2 x106
+ * 0 0 1 15 x 1 x172/2 x208/2 x88
+ * 0 1 0 20 x 1 x130/2 x156/2 x80
+ * 0 1 1 20 x 1 x130/2 x156/2 x66
+ * 1 0 0 26 / 2 x200/2 x240/2 x122
+ * 1 0 1 26 / 2 x200/2 x240/2 x102
+ * 1 1 0 30 / 2 x172/2 x208/2 x106
+ * 1 1 1 30 / 2 x172/2 x208/2 x88
+ *
+ * *1 : Table 7.6 indicates VCO output (PLLx = VCO/2)
+ */
+#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \
+ (((md) & BIT(13)) >> 12) | \
+ (((md) & BIT(19)) >> 19))
+struct cpg_pll_config {
+ unsigned int extal_div;
+ unsigned int pll1_mult;
+ unsigned int pll3_mult;
+};
+
+static const struct cpg_pll_config cpg_pll_configs[8] __initconst = {
+ { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 },
+ { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 },
+};
+
+/* SDHI divisors */
+static const struct clk_div_table cpg_sdh_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 },
+ { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 },
+ { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 },
+};
+
+static const struct clk_div_table cpg_sd01_div_table[] = {
+ { 4, 8 },
+ { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
+ { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 },
+};
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+static u32 cpg_mode __initdata;
+
+static struct clk * __init
+rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
+ const struct cpg_pll_config *config,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ const char *parent_name;
+ unsigned int shift;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "main")) {
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = config->extal_div;
+ } else if (!strcmp(name, "pll0")) {
+ /* PLL0 is a configurable multiplier clock. Register it as a
+ * fixed factor clock for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+ parent_name = "main";
+ mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
+ } else if (!strcmp(name, "pll1")) {
+ parent_name = "main";
+ mult = config->pll1_mult / 2;
+ } else if (!strcmp(name, "pll3")) {
+ parent_name = "main";
+ mult = config->pll3_mult;
+ } else if (!strcmp(name, "lb")) {
+ parent_name = "pll1";
+ div = cpg_mode & BIT(18) ? 36 : 24;
+ } else if (!strcmp(name, "qspi")) {
+ parent_name = "pll1_div2";
+ div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
+ ? 8 : 10;
+ } else if (!strcmp(name, "sdh")) {
+ parent_name = "pll1";
+ table = cpg_sdh_div_table;
+ shift = 8;
+ } else if (!strcmp(name, "sd0")) {
+ parent_name = "pll1";
+ table = cpg_sd01_div_table;
+ shift = 4;
+ } else if (!strcmp(name, "sd1")) {
+ parent_name = "pll1";
+ table = cpg_sd01_div_table;
+ shift = 0;
+ } else if (!strcmp(name, "z")) {
+ return cpg_z_clk_register(cpg);
+ } else if (!strcmp(name, "rcan")) {
+ return cpg_rcan_clk_register(cpg, np);
+ } else if (!strcmp(name, "adsp")) {
+ return cpg_adsp_clk_register(cpg);
+ } else {
+ 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 + CPG_SDCKCR, shift,
+ 4, 0, table, &cpg->lock);
+}
+
+static void __init rcar_gen2_cpg_clocks_init(struct device_node *np)
+{
+ const struct cpg_pll_config *config;
+ struct rcar_gen2_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 = kzalloc(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.
+ */
+ pr_err("%s: failed to allocate cpg\n", __func__);
+ 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;
+
+ config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+
+ 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 = rcar_gen2_cpg_register_clock(np, cpg, config, 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);
+
+ cpg_mstp_add_clk_domain(np);
+}
+CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks",
+ rcar_gen2_cpg_clocks_init);
+
+void __init rcar_gen2_clocks_init(u32 mode)
+{
+ cpg_mode = mode;
+
+ of_clk_init(NULL);
+}
--- /dev/null
+/*
+ * rz Core CPG Clocks
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.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; version 2 of the License.
+ */
+
+#include <linux/clk-provider.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>
+
+struct rz_cpg {
+ struct clk_onecell_data data;
+ void __iomem *reg;
+};
+
+#define CPG_FRQCR 0x10
+#define CPG_FRQCR2 0x14
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+static struct clk * __init
+rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name)
+{
+ u32 val;
+ unsigned mult;
+ static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 };
+
+ if (strcmp(name, "pll") == 0) {
+ /* FIXME: cpg_mode should be read from GPIO. But no GPIO support yet */
+ unsigned cpg_mode = 0; /* hardcoded to EXTAL for now */
+ const char *parent_name = of_clk_get_parent_name(np, cpg_mode);
+
+ mult = cpg_mode ? (32 / 4) : 30;
+
+ return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, 1);
+ }
+
+ /* If mapping regs failed, skip non-pll clocks. System will boot anyhow */
+ if (!cpg->reg)
+ return ERR_PTR(-ENXIO);
+
+ /* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3)
+ * and the constraint that always g <= i. To get the rz platform started,
+ * let them run at fixed current speed and implement the details later.
+ */
+ if (strcmp(name, "i") == 0)
+ val = (clk_readl(cpg->reg + CPG_FRQCR) >> 8) & 3;
+ else if (strcmp(name, "g") == 0)
+ val = clk_readl(cpg->reg + CPG_FRQCR2) & 3;
+ else
+ return ERR_PTR(-EINVAL);
+
+ mult = frqcr_tab[val];
+ return clk_register_fixed_factor(NULL, name, "pll", 0, mult, 3);
+}
+
+static void __init rz_cpg_clocks_init(struct device_node *np)
+{
+ struct rz_cpg *cpg;
+ struct clk **clks;
+ unsigned i;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (WARN(num_clks <= 0, "can't count CPG clocks\n"))
+ return;
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
+ BUG_ON(!cpg || !clks);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+
+ 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 = rz_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);
+
+ cpg_mstp_add_clk_domain(np);
+}
+CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init);
--- /dev/null
+/*
+ * 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/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 {
+ 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);
--- /dev/null
+/*
+ * r8a7795 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-rcar-gen3.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * 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/bug.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+
+
+enum clk_ids {
+ /* Core Clock Outputs exported to DT */
+ LAST_DT_CORE_CLK = R8A7795_CLK_OSC,
+
+ /* External Input Clocks */
+ CLK_EXTAL,
+ CLK_EXTALR,
+
+ /* Internal Core Clocks */
+ CLK_MAIN,
+ CLK_PLL0,
+ CLK_PLL1,
+ CLK_PLL2,
+ CLK_PLL3,
+ CLK_PLL4,
+ CLK_PLL1_DIV2,
+ CLK_PLL1_DIV4,
+ CLK_S0,
+ CLK_S1,
+ CLK_S2,
+ CLK_S3,
+ CLK_SDSRC,
+ CLK_SSPSRC,
+
+ /* Module Clocks */
+ MOD_CLK_BASE
+};
+
+enum r8a7795_clk_types {
+ CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM,
+ CLK_TYPE_GEN3_PLL0,
+ CLK_TYPE_GEN3_PLL1,
+ CLK_TYPE_GEN3_PLL2,
+ CLK_TYPE_GEN3_PLL3,
+ CLK_TYPE_GEN3_PLL4,
+ CLK_TYPE_GEN3_SD,
+};
+
+static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+ DEF_INPUT("extalr", CLK_EXTALR),
+
+ /* Internal Core Clocks */
+ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+ DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
+ DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+ DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
+ DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+ DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
+
+ DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
+ DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1),
+ DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
+
+ /* Core Clock Outputs */
+ DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
+ DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
+ DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED("zx", R8A7795_CLK_ZX, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED("s0d1", R8A7795_CLK_S0D1, CLK_S0, 1, 1),
+ DEF_FIXED("s0d4", R8A7795_CLK_S0D4, CLK_S0, 4, 1),
+ DEF_FIXED("s1d1", R8A7795_CLK_S1D1, CLK_S1, 1, 1),
+ DEF_FIXED("s1d2", R8A7795_CLK_S1D2, CLK_S1, 2, 1),
+ DEF_FIXED("s1d4", R8A7795_CLK_S1D4, CLK_S1, 4, 1),
+ DEF_FIXED("s2d1", R8A7795_CLK_S2D1, CLK_S2, 1, 1),
+ DEF_FIXED("s2d2", R8A7795_CLK_S2D2, CLK_S2, 2, 1),
+ DEF_FIXED("s2d4", R8A7795_CLK_S2D4, CLK_S2, 4, 1),
+ DEF_FIXED("s3d1", R8A7795_CLK_S3D1, CLK_S3, 1, 1),
+ DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1),
+ DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1),
+
+ DEF_SD("sd0", R8A7795_CLK_SD0, CLK_PLL1_DIV2, 0x0074),
+ DEF_SD("sd1", R8A7795_CLK_SD1, CLK_PLL1_DIV2, 0x0078),
+ DEF_SD("sd2", R8A7795_CLK_SD2, CLK_PLL1_DIV2, 0x0268),
+ DEF_SD("sd3", R8A7795_CLK_SD3, CLK_PLL1_DIV2, 0x026c),
+
+ DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1),
+ DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1),
+
+ DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014),
+ DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250),
+ DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
+};
+
+static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
+ DEF_MOD("scif5", 202, R8A7795_CLK_S3D4),
+ DEF_MOD("scif4", 203, R8A7795_CLK_S3D4),
+ DEF_MOD("scif3", 204, R8A7795_CLK_S3D4),
+ DEF_MOD("scif1", 206, R8A7795_CLK_S3D4),
+ DEF_MOD("scif0", 207, R8A7795_CLK_S3D4),
+ DEF_MOD("msiof3", 208, R8A7795_CLK_MSO),
+ DEF_MOD("msiof2", 209, R8A7795_CLK_MSO),
+ DEF_MOD("msiof1", 210, R8A7795_CLK_MSO),
+ DEF_MOD("msiof0", 211, R8A7795_CLK_MSO),
+ DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S3D1),
+ DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1),
+ DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S3D1),
+ DEF_MOD("scif2", 310, R8A7795_CLK_S3D4),
+ DEF_MOD("sdif3", 311, R8A7795_CLK_SD3),
+ DEF_MOD("sdif2", 312, R8A7795_CLK_SD2),
+ DEF_MOD("sdif1", 313, R8A7795_CLK_SD1),
+ DEF_MOD("sdif0", 314, R8A7795_CLK_SD0),
+ DEF_MOD("pcie1", 318, R8A7795_CLK_S3D1),
+ DEF_MOD("pcie0", 319, R8A7795_CLK_S3D1),
+ DEF_MOD("usb3-if1", 327, R8A7795_CLK_S3D1),
+ DEF_MOD("usb3-if0", 328, R8A7795_CLK_S3D1),
+ DEF_MOD("usb-dmac0", 330, R8A7795_CLK_S3D1),
+ DEF_MOD("usb-dmac1", 331, R8A7795_CLK_S3D1),
+ DEF_MOD("intc-ex", 407, R8A7795_CLK_CP),
+ DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1),
+ DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4),
+ DEF_MOD("audmac1", 501, R8A7795_CLK_S3D4),
+ DEF_MOD("hscif4", 516, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif3", 517, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif1", 519, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1),
+ DEF_MOD("fcpvd3", 600, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvd2", 601, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvd1", 602, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvd0", 603, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvb1", 606, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvb0", 607, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvi2", 609, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvi1", 610, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpvi0", 611, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpf2", 613, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpf1", 614, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpf0", 615, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpci1", 616, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpci0", 617, R8A7795_CLK_S2D1),
+ DEF_MOD("fcpcs", 619, R8A7795_CLK_S2D1),
+ DEF_MOD("vspd3", 620, R8A7795_CLK_S2D1),
+ DEF_MOD("vspd2", 621, R8A7795_CLK_S2D1),
+ DEF_MOD("vspd1", 622, R8A7795_CLK_S2D1),
+ DEF_MOD("vspd0", 623, R8A7795_CLK_S2D1),
+ DEF_MOD("vspbc", 624, R8A7795_CLK_S2D1),
+ DEF_MOD("vspbd", 626, R8A7795_CLK_S2D1),
+ DEF_MOD("vspi2", 629, R8A7795_CLK_S2D1),
+ DEF_MOD("vspi1", 630, R8A7795_CLK_S2D1),
+ DEF_MOD("vspi0", 631, R8A7795_CLK_S2D1),
+ DEF_MOD("ehci2", 701, R8A7795_CLK_S3D4),
+ DEF_MOD("ehci1", 702, R8A7795_CLK_S3D4),
+ DEF_MOD("ehci0", 703, R8A7795_CLK_S3D4),
+ DEF_MOD("hsusb", 704, R8A7795_CLK_S3D4),
+ DEF_MOD("du3", 721, R8A7795_CLK_S2D1),
+ DEF_MOD("du2", 722, R8A7795_CLK_S2D1),
+ DEF_MOD("du1", 723, R8A7795_CLK_S2D1),
+ DEF_MOD("du0", 724, R8A7795_CLK_S2D1),
+ DEF_MOD("lvds", 727, R8A7795_CLK_S2D1),
+ DEF_MOD("hdmi1", 728, R8A7795_CLK_HDMI),
+ DEF_MOD("hdmi0", 729, R8A7795_CLK_HDMI),
+ DEF_MOD("etheravb", 812, R8A7795_CLK_S3D2),
+ DEF_MOD("sata0", 815, R8A7795_CLK_S3D2),
+ DEF_MOD("gpio7", 905, R8A7795_CLK_CP),
+ DEF_MOD("gpio6", 906, R8A7795_CLK_CP),
+ DEF_MOD("gpio5", 907, R8A7795_CLK_CP),
+ DEF_MOD("gpio4", 908, R8A7795_CLK_CP),
+ DEF_MOD("gpio3", 909, R8A7795_CLK_CP),
+ DEF_MOD("gpio2", 910, R8A7795_CLK_CP),
+ DEF_MOD("gpio1", 911, R8A7795_CLK_CP),
+ DEF_MOD("gpio0", 912, R8A7795_CLK_CP),
+ DEF_MOD("can-fd", 914, R8A7795_CLK_S3D2),
+ DEF_MOD("can-if1", 915, R8A7795_CLK_S3D4),
+ DEF_MOD("can-if0", 916, R8A7795_CLK_S3D4),
+ DEF_MOD("i2c6", 918, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c5", 919, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c4", 927, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c3", 928, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c2", 929, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c1", 930, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c0", 931, R8A7795_CLK_S3D2),
+ DEF_MOD("ssi-all", 1005, R8A7795_CLK_S3D4),
+ DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)),
+ DEF_MOD("scu-all", 1017, R8A7795_CLK_S3D4),
+ DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)),
+};
+
+static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
+ MOD_CLK_ID(408), /* INTC-AP (GIC) */
+};
+
+/* -----------------------------------------------------------------------------
+ * SDn Clock
+ *
+ */
+#define CPG_SD_STP_HCK BIT(9)
+#define CPG_SD_STP_CK BIT(8)
+
+#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
+#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
+
+#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
+{ \
+ .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
+ ((stp_ck) ? CPG_SD_STP_CK : 0) | \
+ ((sd_srcfc) << 2) | \
+ ((sd_fc) << 0), \
+ .div = (sd_div), \
+}
+
+struct sd_div_table {
+ u32 val;
+ unsigned int div;
+};
+
+struct sd_clock {
+ struct clk_hw hw;
+ void __iomem *reg;
+ const struct sd_div_table *div_table;
+ unsigned int div_num;
+ unsigned int div_min;
+ unsigned int div_max;
+};
+
+/* SDn divider
+ * sd_srcfc sd_fc div
+ * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
+ *-------------------------------------------------------------------
+ * 0 0 0 (1) 1 (4) 4
+ * 0 0 1 (2) 1 (4) 8
+ * 1 0 2 (4) 1 (4) 16
+ * 1 0 3 (8) 1 (4) 32
+ * 1 0 4 (16) 1 (4) 64
+ * 0 0 0 (1) 0 (2) 2
+ * 0 0 1 (2) 0 (2) 4
+ * 1 0 2 (4) 0 (2) 8
+ * 1 0 3 (8) 0 (2) 16
+ * 1 0 4 (16) 0 (2) 32
+ */
+static const struct sd_div_table cpg_sd_div_table[] = {
+/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
+ CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
+ CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),
+ CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16),
+ CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32),
+ CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64),
+ CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2),
+ CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4),
+ CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8),
+ CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16),
+ CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32),
+};
+
+#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw)
+
+static int cpg_sd_clock_enable(struct clk_hw *hw)
+{
+ struct sd_clock *clock = to_sd_clock(hw);
+ u32 val, sd_fc;
+ unsigned int i;
+
+ val = clk_readl(clock->reg);
+
+ sd_fc = val & CPG_SD_FC_MASK;
+ for (i = 0; i < clock->div_num; i++)
+ if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
+ break;
+
+ if (i >= clock->div_num)
+ return -EINVAL;
+
+ val &= ~(CPG_SD_STP_MASK);
+ val |= clock->div_table[i].val & CPG_SD_STP_MASK;
+
+ clk_writel(val, clock->reg);
+
+ return 0;
+}
+
+static void cpg_sd_clock_disable(struct clk_hw *hw)
+{
+ struct sd_clock *clock = to_sd_clock(hw);
+
+ clk_writel(clk_readl(clock->reg) | CPG_SD_STP_MASK, clock->reg);
+}
+
+static int cpg_sd_clock_is_enabled(struct clk_hw *hw)
+{
+ struct sd_clock *clock = to_sd_clock(hw);
+
+ return !(clk_readl(clock->reg) & CPG_SD_STP_MASK);
+}
+
+static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sd_clock *clock = to_sd_clock(hw);
+ unsigned long rate = parent_rate;
+ u32 val, sd_fc;
+ unsigned int i;
+
+ val = clk_readl(clock->reg);
+
+ sd_fc = val & CPG_SD_FC_MASK;
+ for (i = 0; i < clock->div_num; i++)
+ if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
+ break;
+
+ if (i >= clock->div_num)
+ return -EINVAL;
+
+ return DIV_ROUND_CLOSEST(rate, clock->div_table[i].div);
+}
+
+static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned int div;
+
+ if (!rate)
+ rate = 1;
+
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+ return clamp_t(unsigned int, div, clock->div_min, clock->div_max);
+}
+
+static long cpg_sd_clock_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct sd_clock *clock = to_sd_clock(hw);
+ unsigned int div = cpg_sd_clock_calc_div(clock, rate, *parent_rate);
+
+ return DIV_ROUND_CLOSEST(*parent_rate, div);
+}
+
+static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sd_clock *clock = to_sd_clock(hw);
+ unsigned int div = cpg_sd_clock_calc_div(clock, rate, parent_rate);
+ u32 val;
+ unsigned int i;
+
+ for (i = 0; i < clock->div_num; i++)
+ if (div == clock->div_table[i].div)
+ break;
+
+ if (i >= clock->div_num)
+ return -EINVAL;
+
+ val = clk_readl(clock->reg);
+ val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK);
+ val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK);
+ clk_writel(val, clock->reg);
+
+ return 0;
+}
+
+static const struct clk_ops cpg_sd_clock_ops = {
+ .enable = cpg_sd_clock_enable,
+ .disable = cpg_sd_clock_disable,
+ .is_enabled = cpg_sd_clock_is_enabled,
+ .recalc_rate = cpg_sd_clock_recalc_rate,
+ .round_rate = cpg_sd_clock_round_rate,
+ .set_rate = cpg_sd_clock_set_rate,
+};
+
+static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
+ void __iomem *base,
+ const char *parent_name)
+{
+ struct clk_init_data init;
+ struct sd_clock *clock;
+ struct clk *clk;
+ unsigned int i;
+
+ clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+ if (!clock)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = core->name;
+ init.ops = &cpg_sd_clock_ops;
+ init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clock->reg = base + core->offset;
+ clock->hw.init = &init;
+ clock->div_table = cpg_sd_div_table;
+ clock->div_num = ARRAY_SIZE(cpg_sd_div_table);
+
+ clock->div_max = clock->div_table[0].div;
+ clock->div_min = clock->div_max;
+ for (i = 1; i < clock->div_num; i++) {
+ clock->div_max = max(clock->div_max, clock->div_table[i].div);
+ clock->div_min = min(clock->div_min, clock->div_table[i].div);
+ }
+
+ clk = clk_register(NULL, &clock->hw);
+ if (IS_ERR(clk))
+ kfree(clock);
+
+ return clk;
+}
+
+#define CPG_PLL0CR 0x00d8
+#define CPG_PLL2CR 0x002c
+#define CPG_PLL4CR 0x01f4
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4
+ * 14 13 19 17 (MHz)
+ *-------------------------------------------------------------------
+ * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144
+ * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144
+ * 0 0 1 0 Prohibited setting
+ * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144
+ * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120
+ * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120
+ * 0 1 1 0 Prohibited setting
+ * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120
+ * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96
+ * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96
+ * 1 0 1 0 Prohibited setting
+ * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96
+ * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144
+ * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144
+ * 1 1 1 0 Prohibited setting
+ * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144
+ */
+#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
+ (((md) & BIT(13)) >> 11) | \
+ (((md) & BIT(19)) >> 18) | \
+ (((md) & BIT(17)) >> 17))
+
+struct cpg_pll_config {
+ unsigned int extal_div;
+ unsigned int pll1_mult;
+ unsigned int pll3_mult;
+};
+
+static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
+ /* EXTAL div PLL1 mult PLL3 mult */
+ { 1, 192, 192, },
+ { 1, 192, 128, },
+ { 0, /* Prohibited setting */ },
+ { 1, 192, 192, },
+ { 1, 160, 160, },
+ { 1, 160, 106, },
+ { 0, /* Prohibited setting */ },
+ { 1, 160, 160, },
+ { 1, 128, 128, },
+ { 1, 128, 84, },
+ { 0, /* Prohibited setting */ },
+ { 1, 128, 128, },
+ { 2, 192, 192, },
+ { 2, 192, 128, },
+ { 0, /* Prohibited setting */ },
+ { 2, 192, 192, },
+};
+
+static const struct cpg_pll_config *cpg_pll_config __initdata;
+
+static
+struct clk * __init r8a7795_cpg_clk_register(struct device *dev,
+ const struct cpg_core_clk *core,
+ const struct cpg_mssr_info *info,
+ struct clk **clks,
+ void __iomem *base)
+{
+ const struct clk *parent;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+ u32 value;
+
+ parent = clks[core->parent];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ switch (core->type) {
+ case CLK_TYPE_GEN3_MAIN:
+ div = cpg_pll_config->extal_div;
+ break;
+
+ case CLK_TYPE_GEN3_PLL0:
+ /*
+ * PLL0 is a configurable multiplier clock. Register it as a
+ * fixed factor clock for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ value = readl(base + CPG_PLL0CR);
+ mult = (((value >> 24) & 0x7f) + 1) * 2;
+ break;
+
+ case CLK_TYPE_GEN3_PLL1:
+ mult = cpg_pll_config->pll1_mult;
+ break;
+
+ case CLK_TYPE_GEN3_PLL2:
+ /*
+ * PLL2 is a configurable multiplier clock. Register it as a
+ * fixed factor clock for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ value = readl(base + CPG_PLL2CR);
+ mult = (((value >> 24) & 0x7f) + 1) * 2;
+ break;
+
+ case CLK_TYPE_GEN3_PLL3:
+ mult = cpg_pll_config->pll3_mult;
+ break;
+
+ case CLK_TYPE_GEN3_PLL4:
+ /*
+ * PLL4 is a configurable multiplier clock. Register it as a
+ * fixed factor clock for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ value = readl(base + CPG_PLL4CR);
+ mult = (((value >> 24) & 0x7f) + 1) * 2;
+ break;
+
+ case CLK_TYPE_GEN3_SD:
+ return cpg_sd_clk_register(core, base, __clk_get_name(parent));
+
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_fixed_factor(NULL, core->name,
+ __clk_get_name(parent), 0, mult, div);
+}
+
+/*
+ * Reset register definitions.
+ */
+#define MODEMR 0xe6160060
+
+static u32 rcar_gen3_read_mode_pins(void)
+{
+ void __iomem *modemr = ioremap_nocache(MODEMR, 4);
+ u32 mode;
+
+ BUG_ON(!modemr);
+ mode = ioread32(modemr);
+ iounmap(modemr);
+
+ return mode;
+}
+
+static int __init r8a7795_cpg_mssr_init(struct device *dev)
+{
+ u32 cpg_mode = rcar_gen3_read_mode_pins();
+
+ cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+ if (!cpg_pll_config->extal_div) {
+ dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
+ /* Core Clocks */
+ .core_clks = r8a7795_core_clks,
+ .num_core_clks = ARRAY_SIZE(r8a7795_core_clks),
+ .last_dt_core_clk = LAST_DT_CORE_CLK,
+ .num_total_core_clks = MOD_CLK_BASE,
+
+ /* Module Clocks */
+ .mod_clks = r8a7795_mod_clks,
+ .num_mod_clks = ARRAY_SIZE(r8a7795_mod_clks),
+ .num_hw_mod_clks = 12 * 32,
+
+ /* Critical Module Clocks */
+ .crit_mod_clks = r8a7795_crit_mod_clks,
+ .num_crit_mod_clks = ARRAY_SIZE(r8a7795_crit_mod_clks),
+
+ /* Callbacks */
+ .init = r8a7795_cpg_mssr_init,
+ .cpg_clk_register = r8a7795_cpg_clk_register,
+};
--- /dev/null
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * 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.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "clk-div6.h"
+
+#ifdef DEBUG
+#define WARN_DEBUG(x) do { } while (0)
+#else
+#define WARN_DEBUG(x) WARN_ON(x)
+#endif
+
+
+/*
+ * Module Standby and Software Reset register offets.
+ *
+ * If the registers exist, these are valid for SH-Mobile, R-Mobile,
+ * R-Car Gen 2, and R-Car Gen 3.
+ * These are NOT valid for R-Car Gen1 and RZ/A1!
+ */
+
+/*
+ * Module Stop Status Register offsets
+ */
+
+static const u16 mstpsr[] = {
+ 0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4,
+ 0x9A0, 0x9A4, 0x9A8, 0x9AC,
+};
+
+#define MSTPSR(i) mstpsr[i]
+
+
+/*
+ * System Module Stop Control Register offsets
+ */
+
+static const u16 smstpcr[] = {
+ 0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C,
+ 0x990, 0x994, 0x998, 0x99C,
+};
+
+#define SMSTPCR(i) smstpcr[i]
+
+
+/*
+ * Software Reset Register offsets
+ */
+
+static const u16 srcr[] = {
+ 0x0A0, 0x0A8, 0x0B0, 0x0B8, 0x0BC, 0x0C4, 0x1C8, 0x1CC,
+ 0x920, 0x924, 0x928, 0x92C,
+};
+
+#define SRCR(i) srcr[i]
+
+
+/* Realtime Module Stop Control Register offsets */
+#define RMSTPCR(i) (smstpcr[i] - 0x20)
+
+/* Modem Module Stop Control Register offsets (r8a73a4) */
+#define MMSTPCR(i) (smstpcr[i] + 0x20)
+
+/* Software Reset Clearing Register offsets */
+#define SRSTCLR(i) (0x940 + (i) * 4)
+
+
+/**
+ * Clock Pulse Generator / Module Standby and Software Reset Private Data
+ *
+ * @dev: CPG/MSSR device
+ * @base: CPG/MSSR register block base address
+ * @mstp_lock: protects writes to SMSTPCR
+ * @clks: Array containing all Core and Module Clocks
+ * @num_core_clks: Number of Core Clocks in clks[]
+ * @num_mod_clks: Number of Module Clocks in clks[]
+ * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ */
+struct cpg_mssr_priv {
+ struct device *dev;
+ void __iomem *base;
+ spinlock_t mstp_lock;
+
+ struct clk **clks;
+ unsigned int num_core_clks;
+ unsigned int num_mod_clks;
+ unsigned int last_dt_core_clk;
+};
+
+
+/**
+ * struct mstp_clock - MSTP gating clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @index: MSTP clock number
+ * @priv: CPG/MSSR private data
+ */
+struct mstp_clock {
+ struct clk_hw hw;
+ u32 index;
+ struct cpg_mssr_priv *priv;
+};
+
+#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
+
+static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
+{
+ struct mstp_clock *clock = to_mstp_clock(hw);
+ struct cpg_mssr_priv *priv = clock->priv;
+ unsigned int reg = clock->index / 32;
+ unsigned int bit = clock->index % 32;
+ struct device *dev = priv->dev;
+ u32 bitmask = BIT(bit);
+ unsigned long flags;
+ unsigned int i;
+ u32 value;
+
+ dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
+ enable ? "ON" : "OFF");
+ spin_lock_irqsave(&priv->mstp_lock, flags);
+
+ value = clk_readl(priv->base + SMSTPCR(reg));
+ if (enable)
+ value &= ~bitmask;
+ else
+ value |= bitmask;
+ clk_writel(value, priv->base + SMSTPCR(reg));
+
+ spin_unlock_irqrestore(&priv->mstp_lock, flags);
+
+ if (!enable)
+ return 0;
+
+ for (i = 1000; i > 0; --i) {
+ if (!(clk_readl(priv->base + MSTPSR(reg)) &
+ bitmask))
+ break;
+ cpu_relax();
+ }
+
+ if (!i) {
+ dev_err(dev, "Failed to enable SMSTP %p[%d]\n",
+ priv->base + SMSTPCR(reg), bit);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int cpg_mstp_clock_enable(struct clk_hw *hw)
+{
+ return cpg_mstp_clock_endisable(hw, true);
+}
+
+static void cpg_mstp_clock_disable(struct clk_hw *hw)
+{
+ cpg_mstp_clock_endisable(hw, false);
+}
+
+static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
+{
+ struct mstp_clock *clock = to_mstp_clock(hw);
+ struct cpg_mssr_priv *priv = clock->priv;
+ u32 value;
+
+ value = clk_readl(priv->base + MSTPSR(clock->index / 32));
+
+ return !(value & BIT(clock->index % 32));
+}
+
+static const struct clk_ops cpg_mstp_clock_ops = {
+ .enable = cpg_mstp_clock_enable,
+ .disable = cpg_mstp_clock_disable,
+ .is_enabled = cpg_mstp_clock_is_enabled,
+};
+
+static
+struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ unsigned int clkidx = clkspec->args[1];
+ struct cpg_mssr_priv *priv = data;
+ struct device *dev = priv->dev;
+ unsigned int idx;
+ const char *type;
+ struct clk *clk;
+
+ switch (clkspec->args[0]) {
+ case CPG_CORE:
+ type = "core";
+ if (clkidx > priv->last_dt_core_clk) {
+ dev_err(dev, "Invalid %s clock index %u\n", type,
+ clkidx);
+ return ERR_PTR(-EINVAL);
+ }
+ clk = priv->clks[clkidx];
+ break;
+
+ case CPG_MOD:
+ type = "module";
+ idx = MOD_CLK_PACK(clkidx);
+ if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
+ dev_err(dev, "Invalid %s clock index %u\n", type,
+ clkidx);
+ return ERR_PTR(-EINVAL);
+ }
+ clk = priv->clks[priv->num_core_clks + idx];
+ break;
+
+ default:
+ dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (IS_ERR(clk))
+ dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx,
+ PTR_ERR(clk));
+ else
+ dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n",
+ clkspec->args[0], clkspec->args[1], clk, clk);
+ return clk;
+}
+
+static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
+ const struct cpg_mssr_info *info,
+ struct cpg_mssr_priv *priv)
+{
+ struct clk *clk = NULL, *parent;
+ struct device *dev = priv->dev;
+ unsigned int id = core->id;
+ const char *parent_name;
+
+ WARN_DEBUG(id >= priv->num_core_clks);
+ WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+ switch (core->type) {
+ case CLK_TYPE_IN:
+ clk = of_clk_get_by_name(priv->dev->of_node, core->name);
+ break;
+
+ case CLK_TYPE_FF:
+ case CLK_TYPE_DIV6P1:
+ WARN_DEBUG(core->parent >= priv->num_core_clks);
+ parent = priv->clks[core->parent];
+ if (IS_ERR(parent)) {
+ clk = parent;
+ goto fail;
+ }
+
+ parent_name = __clk_get_name(parent);
+ if (core->type == CLK_TYPE_FF) {
+ clk = clk_register_fixed_factor(NULL, core->name,
+ parent_name, 0,
+ core->mult, core->div);
+ } else {
+ clk = cpg_div6_register(core->name, 1, &parent_name,
+ priv->base + core->offset);
+ }
+ break;
+
+ default:
+ if (info->cpg_clk_register)
+ clk = info->cpg_clk_register(dev, core, info,
+ priv->clks, priv->base);
+ else
+ dev_err(dev, "%s has unsupported core clock type %u\n",
+ core->name, core->type);
+ break;
+ }
+
+ if (IS_ERR_OR_NULL(clk))
+ goto fail;
+
+ dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk);
+ priv->clks[id] = clk;
+ return;
+
+fail:
+ dev_err(dev, "Failed to register %s clock %s: %ld\n", "core,",
+ core->name, PTR_ERR(clk));
+}
+
+static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
+ const struct cpg_mssr_info *info,
+ struct cpg_mssr_priv *priv)
+{
+ struct mstp_clock *clock = NULL;
+ struct device *dev = priv->dev;
+ unsigned int id = mod->id;
+ struct clk_init_data init;
+ struct clk *parent, *clk;
+ const char *parent_name;
+ unsigned int i;
+
+ WARN_DEBUG(id < priv->num_core_clks);
+ WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
+ WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
+ WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+ parent = priv->clks[mod->parent];
+ if (IS_ERR(parent)) {
+ clk = parent;
+ goto fail;
+ }
+
+ clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+ if (!clock) {
+ clk = ERR_PTR(-ENOMEM);
+ goto fail;
+ }
+
+ init.name = mod->name;
+ init.ops = &cpg_mstp_clock_ops;
+ init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+ for (i = 0; i < info->num_crit_mod_clks; i++)
+ if (id == info->crit_mod_clks[i]) {
+#ifdef CLK_ENABLE_HAND_OFF
+ dev_dbg(dev, "MSTP %s setting CLK_ENABLE_HAND_OFF\n",
+ mod->name);
+ init.flags |= CLK_ENABLE_HAND_OFF;
+ break;
+#else
+ dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n",
+ mod->name);
+ kfree(clock);
+ return;
+#endif
+ }
+
+ parent_name = __clk_get_name(parent);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clock->index = id - priv->num_core_clks;
+ clock->priv = priv;
+ clock->hw.init = &init;
+
+ clk = clk_register(NULL, &clock->hw);
+ if (IS_ERR(clk))
+ goto fail;
+
+ dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk);
+ priv->clks[id] = clk;
+ return;
+
+fail:
+ dev_err(dev, "Failed to register %s clock %s: %ld\n", "module,",
+ mod->name, PTR_ERR(clk));
+ kfree(clock);
+}
+
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
+struct cpg_mssr_clk_domain {
+ struct generic_pm_domain genpd;
+ struct device_node *np;
+ unsigned int num_core_pm_clks;
+ unsigned int core_pm_clks[0];
+};
+
+static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
+ struct cpg_mssr_clk_domain *pd)
+{
+ unsigned int i;
+
+ if (clkspec->np != pd->np || clkspec->args_count != 2)
+ return false;
+
+ switch (clkspec->args[0]) {
+ case CPG_CORE:
+ for (i = 0; i < pd->num_core_pm_clks; i++)
+ if (clkspec->args[1] == pd->core_pm_clks[i])
+ return true;
+ return false;
+
+ case CPG_MOD:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ struct cpg_mssr_clk_domain *pd =
+ container_of(genpd, struct cpg_mssr_clk_domain, genpd);
+ 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 (cpg_mssr_is_pm_clk(&clkspec, pd))
+ 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;
+}
+
+static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ if (!list_empty(&dev->power.subsys_data->clock_list))
+ pm_clk_destroy(dev);
+}
+
+static int __init cpg_mssr_add_clk_domain(struct device *dev,
+ const unsigned int *core_pm_clks,
+ unsigned int num_core_pm_clks)
+{
+ struct device_node *np = dev->of_node;
+ struct generic_pm_domain *genpd;
+ struct cpg_mssr_clk_domain *pd;
+ size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]);
+
+ pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ pd->np = np;
+ pd->num_core_pm_clks = num_core_pm_clks;
+ memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
+
+ genpd = &pd->genpd;
+ genpd->name = np->name;
+ genpd->flags = GENPD_FLAG_PM_CLK;
+ pm_genpd_init(genpd, &simple_qos_governor, false);
+ genpd->attach_dev = cpg_mssr_attach_dev;
+ genpd->detach_dev = cpg_mssr_detach_dev;
+
+ of_genpd_add_provider_simple(np, genpd);
+ return 0;
+}
+#else
+static inline int cpg_mssr_add_clk_domain(struct device *dev,
+ const unsigned int *core_pm_clks,
+ unsigned int num_core_pm_clks)
+{
+ return 0;
+}
+#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
+
+
+static const struct of_device_id cpg_mssr_match[] = {
+#ifdef CONFIG_ARCH_R8A7795
+ {
+ .compatible = "renesas,r8a7795-cpg-mssr",
+ .data = &r8a7795_cpg_mssr_info,
+ },
+#endif
+ { /* sentinel */ }
+};
+
+static void cpg_mssr_del_clk_provider(void *data)
+{
+ of_clk_del_provider(data);
+}
+
+static int __init cpg_mssr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct cpg_mssr_info *info;
+ struct cpg_mssr_priv *priv;
+ unsigned int nclks, i;
+ struct resource *res;
+ struct clk **clks;
+ int error;
+
+ info = of_match_node(cpg_mssr_match, np)->data;
+ if (info->init) {
+ error = info->init(dev);
+ if (error)
+ return error;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ spin_lock_init(&priv->mstp_lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+ clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ priv->clks = clks;
+ priv->num_core_clks = info->num_total_core_clks;
+ priv->num_mod_clks = info->num_hw_mod_clks;
+ priv->last_dt_core_clk = info->last_dt_core_clk;
+
+ for (i = 0; i < nclks; i++)
+ clks[i] = ERR_PTR(-ENOENT);
+
+ for (i = 0; i < info->num_core_clks; i++)
+ cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
+
+ for (i = 0; i < info->num_mod_clks; i++)
+ cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
+
+ error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
+ if (error)
+ return error;
+
+ error = devm_add_action_or_reset(dev,
+ cpg_mssr_del_clk_provider,
+ np);
+ if (error)
+ return error;
+
+ error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks,
+ info->num_core_pm_clks);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static struct platform_driver cpg_mssr_driver = {
+ .driver = {
+ .name = "renesas-cpg-mssr",
+ .of_match_table = cpg_mssr_match,
+ },
+};
+
+static int __init cpg_mssr_init(void)
+{
+ return platform_driver_probe(&cpg_mssr_driver, cpg_mssr_probe);
+}
+
+subsys_initcall(cpg_mssr_init);
+
+MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * 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.
+ */
+
+#ifndef __CLK_RENESAS_CPG_MSSR_H__
+#define __CLK_RENESAS_CPG_MSSR_H__
+
+ /*
+ * Definitions of CPG Core Clocks
+ *
+ * These include:
+ * - Clock outputs exported to DT
+ * - External input clocks
+ * - Internal CPG clocks
+ */
+
+struct cpg_core_clk {
+ /* Common */
+ const char *name;
+ unsigned int id;
+ unsigned int type;
+ /* Depending on type */
+ unsigned int parent; /* Core Clocks only */
+ unsigned int div;
+ unsigned int mult;
+ unsigned int offset;
+};
+
+enum clk_types {
+ /* Generic */
+ CLK_TYPE_IN, /* External Clock Input */
+ CLK_TYPE_FF, /* Fixed Factor Clock */
+ CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */
+
+ /* Custom definitions start here */
+ CLK_TYPE_CUSTOM,
+};
+
+#define DEF_TYPE(_name, _id, _type...) \
+ { .name = _name, .id = _id, .type = _type }
+#define DEF_BASE(_name, _id, _type, _parent...) \
+ DEF_TYPE(_name, _id, _type, .parent = _parent)
+
+#define DEF_INPUT(_name, _id) \
+ DEF_TYPE(_name, _id, CLK_TYPE_IN)
+#define DEF_FIXED(_name, _id, _parent, _div, _mult) \
+ DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
+#define DEF_DIV6P1(_name, _id, _parent, _offset) \
+ DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
+#define DEF_SD(_name, _id, _parent, _offset) \
+ DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
+
+
+ /*
+ * Definitions of Module Clocks
+ */
+
+struct mssr_mod_clk {
+ const char *name;
+ unsigned int id;
+ unsigned int parent; /* Add MOD_CLK_BASE for Module Clocks */
+};
+
+/* Convert from sparse base-100 to packed index space */
+#define MOD_CLK_PACK(x) ((x) - ((x) / 100) * (100 - 32))
+
+#define MOD_CLK_ID(x) (MOD_CLK_BASE + MOD_CLK_PACK(x))
+
+#define DEF_MOD(_name, _mod, _parent...) \
+ { .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent }
+
+
+struct device_node;
+
+ /**
+ * SoC-specific CPG/MSSR Description
+ *
+ * @core_clks: Array of Core Clock definitions
+ * @num_core_clks: Number of entries in core_clks[]
+ * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @num_total_core_clks: Total number of Core Clocks (exported + internal)
+ *
+ * @mod_clks: Array of Module Clock definitions
+ * @num_mod_clks: Number of entries in mod_clks[]
+ * @num_hw_mod_clks: Number of Module Clocks supported by the hardware
+ *
+ * @crit_mod_clks: Array with Module Clock IDs of critical clocks that
+ * should not be disabled without a knowledgeable driver
+ * @num_crit_mod_clks: Number of entries in crit_mod_clks[]
+ *
+ * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power
+ * Management, in addition to Module Clocks
+ * @num_core_pm_clks: Number of entries in core_pm_clks[]
+ *
+ * @init: Optional callback to perform SoC-specific initialization
+ * @cpg_clk_register: Optional callback to handle special Core Clock types
+ */
+
+struct cpg_mssr_info {
+ /* Core Clocks */
+ const struct cpg_core_clk *core_clks;
+ unsigned int num_core_clks;
+ unsigned int last_dt_core_clk;
+ unsigned int num_total_core_clks;
+
+ /* Module Clocks */
+ const struct mssr_mod_clk *mod_clks;
+ unsigned int num_mod_clks;
+ unsigned int num_hw_mod_clks;
+
+ /* Critical Module Clocks that should not be disabled */
+ const unsigned int *crit_mod_clks;
+ unsigned int num_crit_mod_clks;
+
+ /* Core Clocks suitable for PM, in addition to the Module Clocks */
+ const unsigned int *core_pm_clks;
+ unsigned int num_core_pm_clks;
+
+ /* Callbacks */
+ int (*init)(struct device *dev);
+ struct clk *(*cpg_clk_register)(struct device *dev,
+ const struct cpg_core_clk *core,
+ const struct cpg_mssr_info *info,
+ struct clk **clks, void __iomem *base);
+};
+
+extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
+#endif
+++ /dev/null
-obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
-obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o clk-mstp.o
-obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o clk-mstp.o
-obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o clk-mstp.o
-obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
-obj-$(CONFIG_ARCH_R8A7795) += renesas-cpg-mssr.o \
- r8a7795-cpg-mssr.o clk-div6.o
-obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-mstp.o clk-div6.o
+++ /dev/null
-/*
- * r8a7790 Common Clock Framework support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- *
- * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License.
- */
-
-#include <linux/clk-provider.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>
-
-#include "clk-div6.h"
-
-#define CPG_DIV6_CKSTP BIT(8)
-#define CPG_DIV6_DIV(d) ((d) & 0x3f)
-#define CPG_DIV6_DIV_MASK 0x3f
-
-/**
- * struct div6_clock - CPG 6 bit divider clock
- * @hw: handle between common and hardware-specific interfaces
- * @reg: IO-remapped register
- * @div: divisor value (1-64)
- */
-struct div6_clock {
- struct clk_hw hw;
- void __iomem *reg;
- unsigned int div;
- u32 src_shift;
- u32 src_width;
- u8 *parents;
-};
-
-#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
-
-static int cpg_div6_clock_enable(struct clk_hw *hw)
-{
- struct div6_clock *clock = to_div6_clock(hw);
- u32 val;
-
- val = (clk_readl(clock->reg) & ~(CPG_DIV6_DIV_MASK | CPG_DIV6_CKSTP))
- | CPG_DIV6_DIV(clock->div - 1);
- clk_writel(val, clock->reg);
-
- return 0;
-}
-
-static void cpg_div6_clock_disable(struct clk_hw *hw)
-{
- struct div6_clock *clock = to_div6_clock(hw);
- u32 val;
-
- val = clk_readl(clock->reg);
- val |= CPG_DIV6_CKSTP;
- /*
- * DIV6 clocks require the divisor field to be non-zero when stopping
- * the clock. However, some clocks (e.g. ZB on sh73a0) fail to be
- * re-enabled later if the divisor field is changed when stopping the
- * clock
- */
- if (!(val & CPG_DIV6_DIV_MASK))
- val |= CPG_DIV6_DIV_MASK;
- clk_writel(val, clock->reg);
-}
-
-static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
-{
- struct div6_clock *clock = to_div6_clock(hw);
-
- return !(clk_readl(clock->reg) & CPG_DIV6_CKSTP);
-}
-
-static unsigned long cpg_div6_clock_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct div6_clock *clock = to_div6_clock(hw);
-
- return parent_rate / clock->div;
-}
-
-static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
- unsigned long parent_rate)
-{
- unsigned int div;
-
- if (!rate)
- rate = 1;
-
- div = DIV_ROUND_CLOSEST(parent_rate, rate);
- return clamp_t(unsigned int, div, 1, 64);
-}
-
-static long cpg_div6_clock_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
-{
- unsigned int div = cpg_div6_clock_calc_div(rate, *parent_rate);
-
- return *parent_rate / div;
-}
-
-static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct div6_clock *clock = to_div6_clock(hw);
- unsigned int div = cpg_div6_clock_calc_div(rate, parent_rate);
- u32 val;
-
- clock->div = div;
-
- val = clk_readl(clock->reg) & ~CPG_DIV6_DIV_MASK;
- /* Only program the new divisor if the clock isn't stopped. */
- if (!(val & CPG_DIV6_CKSTP))
- clk_writel(val | CPG_DIV6_DIV(clock->div - 1), clock->reg);
-
- return 0;
-}
-
-static u8 cpg_div6_clock_get_parent(struct clk_hw *hw)
-{
- struct div6_clock *clock = to_div6_clock(hw);
- unsigned int i;
- u8 hw_index;
-
- if (clock->src_width == 0)
- return 0;
-
- hw_index = (clk_readl(clock->reg) >> clock->src_shift) &
- (BIT(clock->src_width) - 1);
- 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_hw_get_name(hw), hw_index);
- return 0;
-}
-
-static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index)
-{
- struct div6_clock *clock = to_div6_clock(hw);
- u8 hw_index;
- u32 mask;
-
- if (index >= clk_hw_get_num_parents(hw))
- return -EINVAL;
-
- mask = ~((BIT(clock->src_width) - 1) << clock->src_shift);
- hw_index = clock->parents[index];
-
- clk_writel((clk_readl(clock->reg) & mask) |
- (hw_index << clock->src_shift), clock->reg);
-
- return 0;
-}
-
-static const struct clk_ops cpg_div6_clock_ops = {
- .enable = cpg_div6_clock_enable,
- .disable = cpg_div6_clock_disable,
- .is_enabled = cpg_div6_clock_is_enabled,
- .get_parent = cpg_div6_clock_get_parent,
- .set_parent = cpg_div6_clock_set_parent,
- .recalc_rate = cpg_div6_clock_recalc_rate,
- .round_rate = cpg_div6_clock_round_rate,
- .set_rate = cpg_div6_clock_set_rate,
-};
-
-
-/**
- * cpg_div6_register - Register a DIV6 clock
- * @name: Name of the DIV6 clock
- * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8)
- * @parent_names: Array containing the names of the parent clocks
- * @reg: Mapped register used to control the DIV6 clock
- */
-struct clk * __init cpg_div6_register(const char *name,
- unsigned int num_parents,
- const char **parent_names,
- void __iomem *reg)
-{
- unsigned int valid_parents;
- struct clk_init_data init;
- struct div6_clock *clock;
- struct clk *clk;
- unsigned int i;
-
- clock = kzalloc(sizeof(*clock), GFP_KERNEL);
- if (!clock)
- return ERR_PTR(-ENOMEM);
-
- clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
- GFP_KERNEL);
- if (!clock->parents) {
- clk = ERR_PTR(-ENOMEM);
- goto free_clock;
- }
-
- clock->reg = reg;
-
- /*
- * Read the divisor. Disabling the clock overwrites the divisor, so we
- * need to cache its value for the enable operation.
- */
- clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
-
- switch (num_parents) {
- case 1:
- /* fixed parent clock */
- clock->src_shift = clock->src_width = 0;
- break;
- case 4:
- /* clock with EXSRC bits 6-7 */
- clock->src_shift = 6;
- clock->src_width = 2;
- break;
- case 8:
- /* VCLK with EXSRC bits 12-14 */
- clock->src_shift = 12;
- clock->src_width = 3;
- break;
- default:
- pr_err("%s: invalid number of parents for DIV6 clock %s\n",
- __func__, name);
- clk = ERR_PTR(-EINVAL);
- goto free_parents;
- }
-
- /* Filter out invalid parents */
- for (i = 0, valid_parents = 0; i < num_parents; i++) {
- if (parent_names[i]) {
- parent_names[valid_parents] = parent_names[i];
- clock->parents[valid_parents] = i;
- valid_parents++;
- }
- }
-
- /* Register the clock. */
- init.name = name;
- init.ops = &cpg_div6_clock_ops;
- init.flags = CLK_IS_BASIC;
- init.parent_names = parent_names;
- init.num_parents = valid_parents;
-
- clock->hw.init = &init;
-
- clk = clk_register(NULL, &clock->hw);
- if (IS_ERR(clk))
- goto free_parents;
-
- return clk;
-
-free_parents:
- kfree(clock->parents);
-free_clock:
- kfree(clock);
- return clk;
-}
-
-static void __init cpg_div6_clock_init(struct device_node *np)
-{
- unsigned int num_parents;
- const char **parent_names;
- const char *clk_name = np->name;
- void __iomem *reg;
- struct clk *clk;
- unsigned int i;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents < 1) {
- pr_err("%s: no parent found for %s DIV6 clock\n",
- __func__, np->name);
- return;
- }
-
- parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
- GFP_KERNEL);
- if (!parent_names)
- return;
-
- reg = of_iomap(np, 0);
- if (reg == NULL) {
- pr_err("%s: failed to map %s DIV6 clock register\n",
- __func__, np->name);
- goto error;
- }
-
- /* Parse the DT properties. */
- of_property_read_string(np, "clock-output-names", &clk_name);
-
- for (i = 0; i < num_parents; i++)
- parent_names[i] = of_clk_get_parent_name(np, i);
-
- clk = cpg_div6_register(clk_name, num_parents, parent_names, reg);
- if (IS_ERR(clk)) {
- pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
- __func__, np->name, PTR_ERR(clk));
- goto error;
- }
-
- of_clk_add_provider(np, of_clk_src_simple_get, clk);
-
- kfree(parent_names);
- return;
-
-error:
- if (reg)
- iounmap(reg);
- kfree(parent_names);
-}
-CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init);
+++ /dev/null
-#ifndef __SHMOBILE_CLK_DIV6_H__
-#define __SHMOBILE_CLK_DIV6_H__
-
-struct clk *cpg_div6_register(const char *name, unsigned int num_parents,
- const char **parent_names, void __iomem *reg);
-
-#endif
+++ /dev/null
-/*
- * EMMA Mobile EV2 common clock framework support
- *
- * Copyright (C) 2013 Takashi Yoshii <takashi.yoshii.ze@renesas.com>
- * Copyright (C) 2012 Magnus Damm
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-/* EMEV2 SMU registers */
-#define USIAU0_RSTCTRL 0x094
-#define USIBU1_RSTCTRL 0x0ac
-#define USIBU2_RSTCTRL 0x0b0
-#define USIBU3_RSTCTRL 0x0b4
-#define IIC0_RSTCTRL 0x0dc
-#define IIC1_RSTCTRL 0x0e0
-#define STI_RSTCTRL 0x124
-#define STI_CLKSEL 0x688
-
-static DEFINE_SPINLOCK(lock);
-
-/* not pretty, but hey */
-static void __iomem *smu_base;
-
-static void __init emev2_smu_write(unsigned long value, int offs)
-{
- BUG_ON(!smu_base || (offs >= PAGE_SIZE));
- writel_relaxed(value, smu_base + offs);
-}
-
-static const struct of_device_id smu_id[] __initconst = {
- { .compatible = "renesas,emev2-smu", },
- {},
-};
-
-static void __init emev2_smu_init(void)
-{
- struct device_node *np;
-
- np = of_find_matching_node(NULL, smu_id);
- BUG_ON(!np);
- smu_base = of_iomap(np, 0);
- BUG_ON(!smu_base);
- of_node_put(np);
-
- /* setup STI timer to run on 32.768 kHz and deassert reset */
- emev2_smu_write(0, STI_CLKSEL);
- emev2_smu_write(1, STI_RSTCTRL);
-
- /* deassert reset for UART0->UART3 */
- emev2_smu_write(2, USIAU0_RSTCTRL);
- emev2_smu_write(2, USIBU1_RSTCTRL);
- emev2_smu_write(2, USIBU2_RSTCTRL);
- emev2_smu_write(2, USIBU3_RSTCTRL);
-
- /* deassert reset for IIC0->IIC1 */
- emev2_smu_write(1, IIC0_RSTCTRL);
- emev2_smu_write(1, IIC1_RSTCTRL);
-}
-
-static void __init emev2_smu_clkdiv_init(struct device_node *np)
-{
- u32 reg[2];
- struct clk *clk;
- const char *parent_name = of_clk_get_parent_name(np, 0);
- if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2)))
- return;
- if (!smu_base)
- emev2_smu_init();
- clk = clk_register_divider(NULL, np->name, parent_name, 0,
- smu_base + reg[0], reg[1], 8, 0, &lock);
- of_clk_add_provider(np, of_clk_src_simple_get, clk);
- clk_register_clkdev(clk, np->name, NULL);
- pr_debug("## %s %s %p\n", __func__, np->name, clk);
-}
-CLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv",
- emev2_smu_clkdiv_init);
-
-static void __init emev2_smu_gclk_init(struct device_node *np)
-{
- u32 reg[2];
- struct clk *clk;
- const char *parent_name = of_clk_get_parent_name(np, 0);
- if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2)))
- return;
- if (!smu_base)
- emev2_smu_init();
- clk = clk_register_gate(NULL, np->name, parent_name, 0,
- smu_base + reg[0], reg[1], 0, &lock);
- of_clk_add_provider(np, of_clk_src_simple_get, clk);
- clk_register_clkdev(clk, np->name, NULL);
- pr_debug("## %s %s %p\n", __func__, np->name, clk);
-}
-CLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk", emev2_smu_gclk_init);
+++ /dev/null
-/*
- * R-Car MSTP clocks
- *
- * Copyright (C) 2013 Ideas On Board SPRL
- * Copyright (C) 2015 Glider bvba
- *
- * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; 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>
-
-/*
- * MSTP clocks. We can't use standard gate clocks as we need to poll on the
- * status register when enabling the clock.
- */
-
-#define MSTP_MAX_CLOCKS 32
-
-/**
- * struct mstp_clock_group - MSTP gating clocks group
- *
- * @data: clocks in this group
- * @smstpcr: module stop control register
- * @mstpsr: module stop status register (optional)
- * @lock: protects writes to SMSTPCR
- */
-struct mstp_clock_group {
- struct clk_onecell_data data;
- void __iomem *smstpcr;
- void __iomem *mstpsr;
- spinlock_t lock;
-};
-
-/**
- * struct mstp_clock - MSTP gating clock
- * @hw: handle between common and hardware-specific interfaces
- * @bit_index: control bit index
- * @group: MSTP clocks group
- */
-struct mstp_clock {
- struct clk_hw hw;
- u32 bit_index;
- struct mstp_clock_group *group;
-};
-
-#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
-
-static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
-{
- struct mstp_clock *clock = to_mstp_clock(hw);
- struct mstp_clock_group *group = clock->group;
- u32 bitmask = BIT(clock->bit_index);
- unsigned long flags;
- unsigned int i;
- u32 value;
-
- spin_lock_irqsave(&group->lock, flags);
-
- value = clk_readl(group->smstpcr);
- if (enable)
- value &= ~bitmask;
- else
- value |= bitmask;
- clk_writel(value, group->smstpcr);
-
- spin_unlock_irqrestore(&group->lock, flags);
-
- if (!enable || !group->mstpsr)
- return 0;
-
- for (i = 1000; i > 0; --i) {
- if (!(clk_readl(group->mstpsr) & bitmask))
- break;
- cpu_relax();
- }
-
- if (!i) {
- pr_err("%s: failed to enable %p[%d]\n", __func__,
- group->smstpcr, clock->bit_index);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int cpg_mstp_clock_enable(struct clk_hw *hw)
-{
- return cpg_mstp_clock_endisable(hw, true);
-}
-
-static void cpg_mstp_clock_disable(struct clk_hw *hw)
-{
- cpg_mstp_clock_endisable(hw, false);
-}
-
-static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
-{
- struct mstp_clock *clock = to_mstp_clock(hw);
- struct mstp_clock_group *group = clock->group;
- u32 value;
-
- if (group->mstpsr)
- value = clk_readl(group->mstpsr);
- else
- value = clk_readl(group->smstpcr);
-
- return !(value & BIT(clock->bit_index));
-}
-
-static const struct clk_ops cpg_mstp_clock_ops = {
- .enable = cpg_mstp_clock_enable,
- .disable = cpg_mstp_clock_disable,
- .is_enabled = cpg_mstp_clock_is_enabled,
-};
-
-static struct clk * __init
-cpg_mstp_clock_register(const char *name, const char *parent_name,
- unsigned int index, struct mstp_clock_group *group)
-{
- struct clk_init_data init;
- struct mstp_clock *clock;
- struct clk *clk;
-
- clock = kzalloc(sizeof(*clock), GFP_KERNEL);
- if (!clock) {
- pr_err("%s: failed to allocate MSTP clock.\n", __func__);
- return ERR_PTR(-ENOMEM);
- }
-
- init.name = name;
- init.ops = &cpg_mstp_clock_ops;
- init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
- init.parent_names = &parent_name;
- init.num_parents = 1;
-
- clock->bit_index = index;
- clock->group = group;
- clock->hw.init = &init;
-
- clk = clk_register(NULL, &clock->hw);
-
- if (IS_ERR(clk))
- kfree(clock);
-
- return clk;
-}
-
-static void __init cpg_mstp_clocks_init(struct device_node *np)
-{
- struct mstp_clock_group *group;
- const char *idxname;
- struct clk **clks;
- unsigned int i;
-
- group = kzalloc(sizeof(*group), GFP_KERNEL);
- clks = kmalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL);
- if (group == NULL || clks == NULL) {
- kfree(group);
- kfree(clks);
- pr_err("%s: failed to allocate group\n", __func__);
- return;
- }
-
- spin_lock_init(&group->lock);
- group->data.clks = clks;
-
- group->smstpcr = of_iomap(np, 0);
- group->mstpsr = of_iomap(np, 1);
-
- if (group->smstpcr == NULL) {
- pr_err("%s: failed to remap SMSTPCR\n", __func__);
- kfree(group);
- kfree(clks);
- return;
- }
-
- for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
- clks[i] = ERR_PTR(-ENOENT);
-
- if (of_find_property(np, "clock-indices", &i))
- idxname = "clock-indices";
- else
- idxname = "renesas,clock-indices";
-
- for (i = 0; i < MSTP_MAX_CLOCKS; ++i) {
- const char *parent_name;
- const char *name;
- u32 clkidx;
- int ret;
-
- /* Skip clocks with no name. */
- ret = of_property_read_string_index(np, "clock-output-names",
- i, &name);
- if (ret < 0 || strlen(name) == 0)
- continue;
-
- parent_name = of_clk_get_parent_name(np, i);
- ret = of_property_read_u32_index(np, idxname, i, &clkidx);
- if (parent_name == NULL || ret < 0)
- break;
-
- if (clkidx >= MSTP_MAX_CLOCKS) {
- pr_err("%s: invalid clock %s %s index %u\n",
- __func__, np->name, name, clkidx);
- continue;
- }
-
- clks[clkidx] = cpg_mstp_clock_register(name, parent_name,
- clkidx, group);
- if (!IS_ERR(clks[clkidx])) {
- group->data.clk_num = max(group->data.clk_num,
- clkidx + 1);
- /*
- * Register a clkdev to let board code retrieve the
- * clock by name and register aliases for non-DT
- * devices.
- *
- * FIXME: Remove this when all devices that require a
- * clock will be instantiated from DT.
- */
- clk_register_clkdev(clks[clkidx], name, NULL);
- } else {
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clks[clkidx]));
- }
- }
-
- 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;
-
- /* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */
- if (!strcmp(clkspec.np->name, "zb_clk"))
- 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 */
+++ /dev/null
-/*
- * r8a73a4 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/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>
-
-struct r8a73a4_cpg {
- struct clk_onecell_data data;
- spinlock_t lock;
- void __iomem *reg;
-};
-
-#define CPG_CKSCR 0xc0
-#define CPG_FRQCRA 0x00
-#define CPG_FRQCRB 0x04
-#define CPG_FRQCRC 0xe0
-#define CPG_PLL0CR 0xd8
-#define CPG_PLL1CR 0x28
-#define CPG_PLL2CR 0x2c
-#define CPG_PLL2HCR 0xe4
-#define CPG_PLL2SCR 0xf4
-
-#define CLK_ENABLE_ON_INIT BIT(0)
-
-struct div4_clk {
- const char *name;
- unsigned int reg;
- unsigned int shift;
-};
-
-static struct div4_clk div4_clks[] = {
- { "i", CPG_FRQCRA, 20 },
- { "m3", CPG_FRQCRA, 12 },
- { "b", CPG_FRQCRA, 8 },
- { "m1", CPG_FRQCRA, 4 },
- { "m2", CPG_FRQCRA, 0 },
- { "zx", CPG_FRQCRB, 12 },
- { "zs", CPG_FRQCRB, 8 },
- { "hp", CPG_FRQCRB, 4 },
- { 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, 10 }, { 0, 0 }
-};
-
-static struct clk * __init
-r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
- const char *name)
-{
- const struct clk_div_table *table = NULL;
- const char *parent_name;
- unsigned int shift, reg;
- unsigned int mult = 1;
- unsigned int div = 1;
-
-
- if (!strcmp(name, "main")) {
- u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR);
-
- switch ((ckscr >> 28) & 3) {
- case 0: /* extal1 */
- parent_name = of_clk_get_parent_name(np, 0);
- break;
- case 1: /* extal1 / 2 */
- parent_name = of_clk_get_parent_name(np, 0);
- div = 2;
- break;
- case 2: /* extal2 */
- parent_name = of_clk_get_parent_name(np, 1);
- break;
- case 3: /* extal2 / 2 */
- parent_name = of_clk_get_parent_name(np, 1);
- div = 2;
- break;
- }
- } else if (!strcmp(name, "pll0")) {
- /* PLL0/1 are configurable multiplier clocks. Register them as
- * fixed factor clocks for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
- */
- u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
-
- parent_name = "main";
- mult = ((value >> 24) & 0x7f) + 1;
- if (value & BIT(20))
- div = 2;
- } else if (!strcmp(name, "pll1")) {
- u32 value = clk_readl(cpg->reg + CPG_PLL1CR);
-
- parent_name = "main";
- /* XXX: enable bit? */
- mult = ((value >> 24) & 0x7f) + 1;
- if (value & BIT(7))
- div = 2;
- } else if (!strncmp(name, "pll2", 4)) {
- u32 value, cr;
-
- switch (name[4]) {
- case 0:
- cr = CPG_PLL2CR;
- break;
- case 's':
- cr = CPG_PLL2SCR;
- break;
- case 'h':
- cr = CPG_PLL2HCR;
- break;
- default:
- return ERR_PTR(-EINVAL);
- }
- value = clk_readl(cpg->reg + cr);
- switch ((value >> 5) & 7) {
- case 0:
- parent_name = "main";
- div = 2;
- break;
- case 1:
- parent_name = "extal2";
- div = 2;
- break;
- case 3:
- parent_name = "extal2";
- div = 4;
- break;
- case 4:
- parent_name = "main";
- break;
- case 5:
- parent_name = "extal2";
- break;
- default:
- pr_warn("%s: unexpected parent of %s\n", __func__,
- name);
- return ERR_PTR(-EINVAL);
- }
- /* XXX: enable bit? */
- mult = ((value >> 24) & 0x7f) + 1;
- } else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
- u32 shift = 8;
-
- parent_name = "pll0";
- if (name[1] == '2') {
- div = 2;
- shift = 0;
- }
- div *= 32;
- mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift)
- & 0x1f);
- } else {
- struct div4_clk *c;
-
- for (c = div4_clks; c->name; c++) {
- if (!strcmp(name, c->name))
- break;
- }
- if (!c->name)
- return ERR_PTR(-EINVAL);
-
- parent_name = "pll1";
- table = div4_div_table;
- reg = c->reg;
- shift = c->shift;
- }
-
- 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, 4, 0,
- table, &cpg->lock);
- }
-}
-
-static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
-{
- struct r8a73a4_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;
-
- 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 = r8a73a4_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(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
- r8a73a4_cpg_clocks_init);
+++ /dev/null
-/*
- * r8a7740 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/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>
-
-struct r8a7740_cpg {
- struct clk_onecell_data data;
- spinlock_t lock;
- void __iomem *reg;
-};
-
-#define CPG_FRQCRA 0x00
-#define CPG_FRQCRB 0x04
-#define CPG_PLLC2CR 0x2c
-#define CPG_USBCKCR 0x8c
-#define CPG_FRQCRC 0xe0
-
-#define CLK_ENABLE_ON_INIT BIT(0)
-
-struct div4_clk {
- const char *name;
- unsigned int reg;
- unsigned int shift;
- int flags;
-};
-
-static struct div4_clk div4_clks[] = {
- { "i", CPG_FRQCRA, 20, CLK_ENABLE_ON_INIT },
- { "zg", CPG_FRQCRA, 16, CLK_ENABLE_ON_INIT },
- { "b", CPG_FRQCRA, 8, CLK_ENABLE_ON_INIT },
- { "m1", CPG_FRQCRA, 4, CLK_ENABLE_ON_INIT },
- { "hp", CPG_FRQCRB, 4, 0 },
- { "hpp", CPG_FRQCRC, 20, 0 },
- { "usbp", CPG_FRQCRC, 16, 0 },
- { "s", CPG_FRQCRC, 12, 0 },
- { "zb", CPG_FRQCRC, 8, 0 },
- { "m3", CPG_FRQCRC, 4, 0 },
- { "cp", CPG_FRQCRC, 0, 0 },
- { NULL, 0, 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 }, { 9, 32 }, { 10, 36 }, { 11, 48 },
- { 13, 72 }, { 14, 96 }, { 0, 0 }
-};
-
-static u32 cpg_mode __initdata;
-
-static struct clk * __init
-r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg,
- const char *name)
-{
- const struct clk_div_table *table = NULL;
- const char *parent_name;
- unsigned int shift, reg;
- unsigned int mult = 1;
- unsigned int div = 1;
-
- if (!strcmp(name, "r")) {
- switch (cpg_mode & (BIT(2) | BIT(1))) {
- case BIT(1) | BIT(2):
- /* extal1 */
- parent_name = of_clk_get_parent_name(np, 0);
- div = 2048;
- break;
- case BIT(2):
- /* extal1 */
- parent_name = of_clk_get_parent_name(np, 0);
- div = 1024;
- break;
- default:
- /* extalr */
- parent_name = of_clk_get_parent_name(np, 2);
- break;
- }
- } else if (!strcmp(name, "system")) {
- parent_name = of_clk_get_parent_name(np, 0);
- if (cpg_mode & BIT(1))
- div = 2;
- } else if (!strcmp(name, "pllc0")) {
- /* PLLC0/1 are configurable multiplier clocks. Register them as
- * fixed factor clocks for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
- */
- u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
- parent_name = "system";
- mult = ((value >> 24) & 0x7f) + 1;
- } else if (!strcmp(name, "pllc1")) {
- u32 value = clk_readl(cpg->reg + CPG_FRQCRA);
- parent_name = "system";
- mult = ((value >> 24) & 0x7f) + 1;
- div = 2;
- } else if (!strcmp(name, "pllc2")) {
- u32 value = clk_readl(cpg->reg + CPG_PLLC2CR);
- parent_name = "system";
- mult = ((value >> 24) & 0x3f) + 1;
- } else if (!strcmp(name, "usb24s")) {
- u32 value = clk_readl(cpg->reg + CPG_USBCKCR);
- if (value & BIT(7))
- /* extal2 */
- parent_name = of_clk_get_parent_name(np, 1);
- else
- parent_name = "system";
- if (!(value & BIT(6)))
- div = 2;
- } else {
- struct div4_clk *c;
- for (c = div4_clks; c->name; c++) {
- if (!strcmp(name, c->name)) {
- parent_name = "pllc1";
- table = div4_div_table;
- reg = c->reg;
- shift = c->shift;
- 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, 4, 0,
- table, &cpg->lock);
- }
-}
-
-static void __init r8a7740_cpg_clocks_init(struct device_node *np)
-{
- struct r8a7740_cpg *cpg;
- struct clk **clks;
- unsigned int i;
- int num_clks;
-
- if (of_property_read_u32(np, "renesas,mode", &cpg_mode))
- pr_warn("%s: missing renesas,mode property\n", __func__);
-
- 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 = kzalloc(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;
-
- 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 = r8a7740_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(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks",
- r8a7740_cpg_clocks_init);
+++ /dev/null
-/*
- * r8a7778 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/clk/shmobile.h>
-#include <linux/of_address.h>
-#include <linux/slab.h>
-
-struct r8a7778_cpg {
- struct clk_onecell_data data;
- spinlock_t lock;
- void __iomem *reg;
-};
-
-/* PLL multipliers per bits 11, 12, and 18 of MODEMR */
-static const struct {
- unsigned long plla_mult;
- unsigned long pllb_mult;
-} r8a7778_rates[] __initconst = {
- [0] = { 21, 21 },
- [1] = { 24, 24 },
- [2] = { 28, 28 },
- [3] = { 32, 32 },
- [5] = { 24, 21 },
- [6] = { 28, 21 },
- [7] = { 32, 24 },
-};
-
-/* Clock dividers per bits 1 and 2 of MODEMR */
-static const struct {
- const char *name;
- unsigned int div[4];
-} r8a7778_divs[6] __initconst = {
- { "b", { 12, 12, 16, 18 } },
- { "out", { 12, 12, 16, 18 } },
- { "p", { 16, 12, 16, 12 } },
- { "s", { 4, 3, 4, 3 } },
- { "s1", { 8, 6, 8, 6 } },
-};
-
-static u32 cpg_mode_rates __initdata;
-static u32 cpg_mode_divs __initdata;
-
-static struct clk * __init
-r8a7778_cpg_register_clock(struct device_node *np, struct r8a7778_cpg *cpg,
- const char *name)
-{
- if (!strcmp(name, "plla")) {
- return clk_register_fixed_factor(NULL, "plla",
- of_clk_get_parent_name(np, 0), 0,
- r8a7778_rates[cpg_mode_rates].plla_mult, 1);
- } else if (!strcmp(name, "pllb")) {
- return clk_register_fixed_factor(NULL, "pllb",
- of_clk_get_parent_name(np, 0), 0,
- r8a7778_rates[cpg_mode_rates].pllb_mult, 1);
- } else {
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(r8a7778_divs); i++) {
- if (!strcmp(name, r8a7778_divs[i].name)) {
- return clk_register_fixed_factor(NULL,
- r8a7778_divs[i].name,
- "plla", 0, 1,
- r8a7778_divs[i].div[cpg_mode_divs]);
- }
- }
- }
-
- return ERR_PTR(-EINVAL);
-}
-
-
-static void __init r8a7778_cpg_clocks_init(struct device_node *np)
-{
- struct r8a7778_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;
-
- 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 = r8a7778_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);
-
- cpg_mstp_add_clk_domain(np);
-}
-
-CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks",
- r8a7778_cpg_clocks_init);
-
-void __init r8a7778_clocks_init(u32 mode)
-{
- BUG_ON(!(mode & BIT(19)));
-
- cpg_mode_rates = (!!(mode & BIT(18)) << 2) |
- (!!(mode & BIT(12)) << 1) |
- (!!(mode & BIT(11)));
- cpg_mode_divs = (!!(mode & BIT(2)) << 1) |
- (!!(mode & BIT(1)));
-
- of_clk_init(NULL);
-}
+++ /dev/null
-/*
- * r8a7779 Core CPG Clocks
- *
- * Copyright (C) 2013, 2014 Horms Solutions Ltd.
- *
- * Contact: Simon Horman <horms@verge.net.au>
- *
- * 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/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>
-
-#define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1)
-
-struct r8a7779_cpg {
- struct clk_onecell_data data;
- spinlock_t lock;
- void __iomem *reg;
-};
-
-/* -----------------------------------------------------------------------------
- * CPG Clock Data
- */
-
-/*
- * MD1 = 1 MD1 = 0
- * (PLLA = 1500) (PLLA = 1600)
- * (MHz) (MHz)
- *------------------------------------------------+--------------------
- * clkz 1000 (2/3) 800 (1/2)
- * clkzs 250 (1/6) 200 (1/8)
- * clki 750 (1/2) 800 (1/2)
- * clks 250 (1/6) 200 (1/8)
- * clks1 125 (1/12) 100 (1/16)
- * clks3 187.5 (1/8) 200 (1/8)
- * clks4 93.7 (1/16) 100 (1/16)
- * clkp 62.5 (1/24) 50 (1/32)
- * clkg 62.5 (1/24) 66.6 (1/24)
- * clkb, CLKOUT
- * (MD2 = 0) 62.5 (1/24) 66.6 (1/24)
- * (MD2 = 1) 41.6 (1/36) 50 (1/32)
- */
-
-#define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1)
-
-struct cpg_clk_config {
- unsigned int z_mult;
- unsigned int z_div;
- unsigned int zs_and_s_div;
- unsigned int s1_div;
- unsigned int p_div;
- unsigned int b_and_out_div;
-};
-
-static const struct cpg_clk_config cpg_clk_configs[4] __initconst = {
- { 1, 2, 8, 16, 32, 24 },
- { 2, 3, 6, 12, 24, 24 },
- { 1, 2, 8, 16, 32, 32 },
- { 2, 3, 6, 12, 24, 36 },
-};
-
-/*
- * MD PLLA Ratio
- * 12 11
- *------------------------
- * 0 0 x42
- * 0 1 x48
- * 1 0 x56
- * 1 1 x64
- */
-
-#define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11)
-
-static const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 };
-
-/* -----------------------------------------------------------------------------
- * Initialization
- */
-
-static u32 cpg_mode __initdata;
-
-static struct clk * __init
-r8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg,
- const struct cpg_clk_config *config,
- unsigned int plla_mult, const char *name)
-{
- const char *parent_name = "plla";
- unsigned int mult = 1;
- unsigned int div = 1;
-
- if (!strcmp(name, "plla")) {
- parent_name = of_clk_get_parent_name(np, 0);
- mult = plla_mult;
- } else if (!strcmp(name, "z")) {
- div = config->z_div;
- mult = config->z_mult;
- } else if (!strcmp(name, "zs") || !strcmp(name, "s")) {
- div = config->zs_and_s_div;
- } else if (!strcmp(name, "s1")) {
- div = config->s1_div;
- } else if (!strcmp(name, "p")) {
- div = config->p_div;
- } else if (!strcmp(name, "b") || !strcmp(name, "out")) {
- div = config->b_and_out_div;
- } else {
- return ERR_PTR(-EINVAL);
- }
-
- return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div);
-}
-
-static void __init r8a7779_cpg_clocks_init(struct device_node *np)
-{
- const struct cpg_clk_config *config;
- struct r8a7779_cpg *cpg;
- struct clk **clks;
- unsigned int i, plla_mult;
- 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 = kzalloc(CPG_NUM_CLOCKS * 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;
-
- config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)];
- plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)];
-
- 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 = r8a7779_cpg_register_clock(np, cpg, config,
- plla_mult, 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);
-
- cpg_mstp_add_clk_domain(np);
-}
-CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
- r8a7779_cpg_clocks_init);
-
-void __init r8a7779_clocks_init(u32 mode)
-{
- cpg_mode = mode;
-
- of_clk_init(NULL);
-}
+++ /dev/null
-/*
- * rcar_gen2 Core CPG Clocks
- *
- * Copyright (C) 2013 Ideas On Board SPRL
- *
- * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License.
- */
-
-#include <linux/clk-provider.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 {
- struct clk_onecell_data data;
- spinlock_t lock;
- void __iomem *reg;
-};
-
-#define CPG_FRQCRB 0x00000004
-#define CPG_FRQCRB_KICK BIT(31)
-#define CPG_SDCKCR 0x00000074
-#define CPG_PLL0CR 0x000000d8
-#define CPG_FRQCRC 0x000000e0
-#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
-#define CPG_FRQCRC_ZFC_SHIFT 8
-#define CPG_ADSPCKCR 0x0000025c
-#define CPG_RCANCKCR 0x00000270
-
-/* -----------------------------------------------------------------------------
- * Z Clock
- *
- * Traits of this clock:
- * prepare - clk_prepare only ensures that parents are prepared
- * enable - clk_enable only ensures that parents are enabled
- * rate - rate is adjustable. clk->rate = parent->rate * mult / 32
- * parent - fixed parent. No clk_set_parent support
- */
-
-struct cpg_z_clk {
- struct clk_hw hw;
- void __iomem *reg;
- void __iomem *kick_reg;
-};
-
-#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
-
-static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct cpg_z_clk *zclk = to_z_clk(hw);
- unsigned int mult;
- unsigned int val;
-
- val = (clk_readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK)
- >> CPG_FRQCRC_ZFC_SHIFT;
- mult = 32 - val;
-
- return div_u64((u64)parent_rate * mult, 32);
-}
-
-static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
-{
- unsigned long prate = *parent_rate;
- unsigned int mult;
-
- if (!prate)
- prate = 1;
-
- mult = div_u64((u64)rate * 32, prate);
- mult = clamp(mult, 1U, 32U);
-
- return *parent_rate / 32 * mult;
-}
-
-static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct cpg_z_clk *zclk = to_z_clk(hw);
- unsigned int mult;
- u32 val, kick;
- unsigned int i;
-
- mult = div_u64((u64)rate * 32, parent_rate);
- mult = clamp(mult, 1U, 32U);
-
- if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
- return -EBUSY;
-
- val = clk_readl(zclk->reg);
- val &= ~CPG_FRQCRC_ZFC_MASK;
- val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
- clk_writel(val, zclk->reg);
-
- /*
- * Set KICK bit in FRQCRB to update hardware setting and wait for
- * clock change completion.
- */
- kick = clk_readl(zclk->kick_reg);
- kick |= CPG_FRQCRB_KICK;
- clk_writel(kick, zclk->kick_reg);
-
- /*
- * Note: There is no HW information about the worst case latency.
- *
- * Using experimental measurements, it seems that no more than
- * ~10 iterations are needed, independently of the CPU rate.
- * Since this value might be dependent on external xtal rate, pll1
- * rate or even the other emulation clocks rate, use 1000 as a
- * "super" safe value.
- */
- for (i = 1000; i; i--) {
- if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
- return 0;
-
- cpu_relax();
- }
-
- return -ETIMEDOUT;
-}
-
-static const struct clk_ops cpg_z_clk_ops = {
- .recalc_rate = cpg_z_clk_recalc_rate,
- .round_rate = cpg_z_clk_round_rate,
- .set_rate = cpg_z_clk_set_rate,
-};
-
-static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
-{
- static const char *parent_name = "pll0";
- struct clk_init_data init;
- struct cpg_z_clk *zclk;
- struct clk *clk;
-
- zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);
- if (!zclk)
- return ERR_PTR(-ENOMEM);
-
- init.name = "z";
- init.ops = &cpg_z_clk_ops;
- init.flags = 0;
- init.parent_names = &parent_name;
- init.num_parents = 1;
-
- zclk->reg = cpg->reg + CPG_FRQCRC;
- zclk->kick_reg = cpg->reg + CPG_FRQCRB;
- zclk->hw.init = &init;
-
- clk = clk_register(NULL, &zclk->hw);
- if (IS_ERR(clk))
- kfree(zclk);
-
- return clk;
-}
-
-static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
- struct device_node *np)
-{
- const char *parent_name = of_clk_get_parent_name(np, 1);
- struct clk_fixed_factor *fixed;
- struct clk_gate *gate;
- struct clk *clk;
-
- fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
- if (!fixed)
- return ERR_PTR(-ENOMEM);
-
- fixed->mult = 1;
- fixed->div = 6;
-
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
- if (!gate) {
- kfree(fixed);
- return ERR_PTR(-ENOMEM);
- }
-
- gate->reg = cpg->reg + CPG_RCANCKCR;
- gate->bit_idx = 8;
- gate->flags = CLK_GATE_SET_TO_DISABLE;
- gate->lock = &cpg->lock;
-
- clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
- &fixed->hw, &clk_fixed_factor_ops,
- &gate->hw, &clk_gate_ops, 0);
- if (IS_ERR(clk)) {
- kfree(gate);
- kfree(fixed);
- }
-
- return clk;
-}
-
-/* ADSP divisors */
-static const struct clk_div_table cpg_adsp_div_table[] = {
- { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 },
- { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
- { 10, 36 }, { 11, 48 }, { 0, 0 },
-};
-
-static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
-{
- const char *parent_name = "pll1";
- struct clk_divider *div;
- struct clk_gate *gate;
- struct clk *clk;
-
- div = kzalloc(sizeof(*div), GFP_KERNEL);
- if (!div)
- return ERR_PTR(-ENOMEM);
-
- div->reg = cpg->reg + CPG_ADSPCKCR;
- div->width = 4;
- div->table = cpg_adsp_div_table;
- div->lock = &cpg->lock;
-
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
- if (!gate) {
- kfree(div);
- return ERR_PTR(-ENOMEM);
- }
-
- gate->reg = cpg->reg + CPG_ADSPCKCR;
- gate->bit_idx = 8;
- gate->flags = CLK_GATE_SET_TO_DISABLE;
- gate->lock = &cpg->lock;
-
- clk = clk_register_composite(NULL, "adsp", &parent_name, 1, NULL, NULL,
- &div->hw, &clk_divider_ops,
- &gate->hw, &clk_gate_ops, 0);
- if (IS_ERR(clk)) {
- kfree(gate);
- kfree(div);
- }
-
- return clk;
-}
-
-/* -----------------------------------------------------------------------------
- * CPG Clock Data
- */
-
-/*
- * MD EXTAL PLL0 PLL1 PLL3
- * 14 13 19 (MHz) *1 *1
- *---------------------------------------------------
- * 0 0 0 15 x 1 x172/2 x208/2 x106
- * 0 0 1 15 x 1 x172/2 x208/2 x88
- * 0 1 0 20 x 1 x130/2 x156/2 x80
- * 0 1 1 20 x 1 x130/2 x156/2 x66
- * 1 0 0 26 / 2 x200/2 x240/2 x122
- * 1 0 1 26 / 2 x200/2 x240/2 x102
- * 1 1 0 30 / 2 x172/2 x208/2 x106
- * 1 1 1 30 / 2 x172/2 x208/2 x88
- *
- * *1 : Table 7.6 indicates VCO output (PLLx = VCO/2)
- */
-#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \
- (((md) & BIT(13)) >> 12) | \
- (((md) & BIT(19)) >> 19))
-struct cpg_pll_config {
- unsigned int extal_div;
- unsigned int pll1_mult;
- unsigned int pll3_mult;
-};
-
-static const struct cpg_pll_config cpg_pll_configs[8] __initconst = {
- { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 },
- { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 },
-};
-
-/* SDHI divisors */
-static const struct clk_div_table cpg_sdh_div_table[] = {
- { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 },
- { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 },
- { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 },
-};
-
-static const struct clk_div_table cpg_sd01_div_table[] = {
- { 4, 8 },
- { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
- { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 },
-};
-
-/* -----------------------------------------------------------------------------
- * Initialization
- */
-
-static u32 cpg_mode __initdata;
-
-static struct clk * __init
-rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
- const struct cpg_pll_config *config,
- const char *name)
-{
- const struct clk_div_table *table = NULL;
- const char *parent_name;
- unsigned int shift;
- unsigned int mult = 1;
- unsigned int div = 1;
-
- if (!strcmp(name, "main")) {
- parent_name = of_clk_get_parent_name(np, 0);
- div = config->extal_div;
- } else if (!strcmp(name, "pll0")) {
- /* PLL0 is a configurable multiplier clock. Register it as a
- * fixed factor clock for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
- */
- u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
- parent_name = "main";
- mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
- } else if (!strcmp(name, "pll1")) {
- parent_name = "main";
- mult = config->pll1_mult / 2;
- } else if (!strcmp(name, "pll3")) {
- parent_name = "main";
- mult = config->pll3_mult;
- } else if (!strcmp(name, "lb")) {
- parent_name = "pll1";
- div = cpg_mode & BIT(18) ? 36 : 24;
- } else if (!strcmp(name, "qspi")) {
- parent_name = "pll1_div2";
- div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
- ? 8 : 10;
- } else if (!strcmp(name, "sdh")) {
- parent_name = "pll1";
- table = cpg_sdh_div_table;
- shift = 8;
- } else if (!strcmp(name, "sd0")) {
- parent_name = "pll1";
- table = cpg_sd01_div_table;
- shift = 4;
- } else if (!strcmp(name, "sd1")) {
- parent_name = "pll1";
- table = cpg_sd01_div_table;
- shift = 0;
- } else if (!strcmp(name, "z")) {
- return cpg_z_clk_register(cpg);
- } else if (!strcmp(name, "rcan")) {
- return cpg_rcan_clk_register(cpg, np);
- } else if (!strcmp(name, "adsp")) {
- return cpg_adsp_clk_register(cpg);
- } else {
- 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 + CPG_SDCKCR, shift,
- 4, 0, table, &cpg->lock);
-}
-
-static void __init rcar_gen2_cpg_clocks_init(struct device_node *np)
-{
- const struct cpg_pll_config *config;
- struct rcar_gen2_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 = kzalloc(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.
- */
- pr_err("%s: failed to allocate cpg\n", __func__);
- 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;
-
- config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
-
- 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 = rcar_gen2_cpg_register_clock(np, cpg, config, 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);
-
- cpg_mstp_add_clk_domain(np);
-}
-CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks",
- rcar_gen2_cpg_clocks_init);
-
-void __init rcar_gen2_clocks_init(u32 mode)
-{
- cpg_mode = mode;
-
- of_clk_init(NULL);
-}
+++ /dev/null
-/*
- * rz Core CPG Clocks
- *
- * Copyright (C) 2013 Ideas On Board SPRL
- * Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.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; version 2 of the License.
- */
-
-#include <linux/clk-provider.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>
-
-struct rz_cpg {
- struct clk_onecell_data data;
- void __iomem *reg;
-};
-
-#define CPG_FRQCR 0x10
-#define CPG_FRQCR2 0x14
-
-/* -----------------------------------------------------------------------------
- * Initialization
- */
-
-static struct clk * __init
-rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name)
-{
- u32 val;
- unsigned mult;
- static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 };
-
- if (strcmp(name, "pll") == 0) {
- /* FIXME: cpg_mode should be read from GPIO. But no GPIO support yet */
- unsigned cpg_mode = 0; /* hardcoded to EXTAL for now */
- const char *parent_name = of_clk_get_parent_name(np, cpg_mode);
-
- mult = cpg_mode ? (32 / 4) : 30;
-
- return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, 1);
- }
-
- /* If mapping regs failed, skip non-pll clocks. System will boot anyhow */
- if (!cpg->reg)
- return ERR_PTR(-ENXIO);
-
- /* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3)
- * and the constraint that always g <= i. To get the rz platform started,
- * let them run at fixed current speed and implement the details later.
- */
- if (strcmp(name, "i") == 0)
- val = (clk_readl(cpg->reg + CPG_FRQCR) >> 8) & 3;
- else if (strcmp(name, "g") == 0)
- val = clk_readl(cpg->reg + CPG_FRQCR2) & 3;
- else
- return ERR_PTR(-EINVAL);
-
- mult = frqcr_tab[val];
- return clk_register_fixed_factor(NULL, name, "pll", 0, mult, 3);
-}
-
-static void __init rz_cpg_clocks_init(struct device_node *np)
-{
- struct rz_cpg *cpg;
- struct clk **clks;
- unsigned i;
- int num_clks;
-
- num_clks = of_property_count_strings(np, "clock-output-names");
- if (WARN(num_clks <= 0, "can't count CPG clocks\n"))
- return;
-
- cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
- clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
- BUG_ON(!cpg || !clks);
-
- cpg->data.clks = clks;
- cpg->data.clk_num = num_clks;
-
- cpg->reg = of_iomap(np, 0);
-
- 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 = rz_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);
-
- cpg_mstp_add_clk_domain(np);
-}
-CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init);
+++ /dev/null
-/*
- * 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/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 {
- 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);
+++ /dev/null
-/*
- * r8a7795 Clock Pulse Generator / Module Standby and Software Reset
- *
- * Copyright (C) 2015 Glider bvba
- *
- * Based on clk-rcar-gen3.c
- *
- * Copyright (C) 2015 Renesas Electronics Corp.
- *
- * 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/bug.h>
-#include <linux/clk-provider.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-
-#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
-
-#include "renesas-cpg-mssr.h"
-
-
-enum clk_ids {
- /* Core Clock Outputs exported to DT */
- LAST_DT_CORE_CLK = R8A7795_CLK_OSC,
-
- /* External Input Clocks */
- CLK_EXTAL,
- CLK_EXTALR,
-
- /* Internal Core Clocks */
- CLK_MAIN,
- CLK_PLL0,
- CLK_PLL1,
- CLK_PLL2,
- CLK_PLL3,
- CLK_PLL4,
- CLK_PLL1_DIV2,
- CLK_PLL1_DIV4,
- CLK_S0,
- CLK_S1,
- CLK_S2,
- CLK_S3,
- CLK_SDSRC,
- CLK_SSPSRC,
-
- /* Module Clocks */
- MOD_CLK_BASE
-};
-
-enum r8a7795_clk_types {
- CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM,
- CLK_TYPE_GEN3_PLL0,
- CLK_TYPE_GEN3_PLL1,
- CLK_TYPE_GEN3_PLL2,
- CLK_TYPE_GEN3_PLL3,
- CLK_TYPE_GEN3_PLL4,
- CLK_TYPE_GEN3_SD,
-};
-
-static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
- /* External Clock Inputs */
- DEF_INPUT("extal", CLK_EXTAL),
- DEF_INPUT("extalr", CLK_EXTALR),
-
- /* Internal Core Clocks */
- DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
- DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
- DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
- DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
- DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
- DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
-
- DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
- DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1),
- DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1),
- DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1),
- DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
- DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
-
- /* Core Clock Outputs */
- DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
- DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
- DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1),
- DEF_FIXED("zx", R8A7795_CLK_ZX, CLK_PLL1_DIV2, 2, 1),
- DEF_FIXED("s0d1", R8A7795_CLK_S0D1, CLK_S0, 1, 1),
- DEF_FIXED("s0d4", R8A7795_CLK_S0D4, CLK_S0, 4, 1),
- DEF_FIXED("s1d1", R8A7795_CLK_S1D1, CLK_S1, 1, 1),
- DEF_FIXED("s1d2", R8A7795_CLK_S1D2, CLK_S1, 2, 1),
- DEF_FIXED("s1d4", R8A7795_CLK_S1D4, CLK_S1, 4, 1),
- DEF_FIXED("s2d1", R8A7795_CLK_S2D1, CLK_S2, 1, 1),
- DEF_FIXED("s2d2", R8A7795_CLK_S2D2, CLK_S2, 2, 1),
- DEF_FIXED("s2d4", R8A7795_CLK_S2D4, CLK_S2, 4, 1),
- DEF_FIXED("s3d1", R8A7795_CLK_S3D1, CLK_S3, 1, 1),
- DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1),
- DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1),
-
- DEF_SD("sd0", R8A7795_CLK_SD0, CLK_PLL1_DIV2, 0x0074),
- DEF_SD("sd1", R8A7795_CLK_SD1, CLK_PLL1_DIV2, 0x0078),
- DEF_SD("sd2", R8A7795_CLK_SD2, CLK_PLL1_DIV2, 0x0268),
- DEF_SD("sd3", R8A7795_CLK_SD3, CLK_PLL1_DIV2, 0x026c),
-
- DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1),
- DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1),
-
- DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014),
- DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250),
- DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
-};
-
-static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
- DEF_MOD("scif5", 202, R8A7795_CLK_S3D4),
- DEF_MOD("scif4", 203, R8A7795_CLK_S3D4),
- DEF_MOD("scif3", 204, R8A7795_CLK_S3D4),
- DEF_MOD("scif1", 206, R8A7795_CLK_S3D4),
- DEF_MOD("scif0", 207, R8A7795_CLK_S3D4),
- DEF_MOD("msiof3", 208, R8A7795_CLK_MSO),
- DEF_MOD("msiof2", 209, R8A7795_CLK_MSO),
- DEF_MOD("msiof1", 210, R8A7795_CLK_MSO),
- DEF_MOD("msiof0", 211, R8A7795_CLK_MSO),
- DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S3D1),
- DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1),
- DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S3D1),
- DEF_MOD("scif2", 310, R8A7795_CLK_S3D4),
- DEF_MOD("sdif3", 311, R8A7795_CLK_SD3),
- DEF_MOD("sdif2", 312, R8A7795_CLK_SD2),
- DEF_MOD("sdif1", 313, R8A7795_CLK_SD1),
- DEF_MOD("sdif0", 314, R8A7795_CLK_SD0),
- DEF_MOD("pcie1", 318, R8A7795_CLK_S3D1),
- DEF_MOD("pcie0", 319, R8A7795_CLK_S3D1),
- DEF_MOD("usb3-if1", 327, R8A7795_CLK_S3D1),
- DEF_MOD("usb3-if0", 328, R8A7795_CLK_S3D1),
- DEF_MOD("usb-dmac0", 330, R8A7795_CLK_S3D1),
- DEF_MOD("usb-dmac1", 331, R8A7795_CLK_S3D1),
- DEF_MOD("intc-ex", 407, R8A7795_CLK_CP),
- DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1),
- DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4),
- DEF_MOD("audmac1", 501, R8A7795_CLK_S3D4),
- DEF_MOD("hscif4", 516, R8A7795_CLK_S3D1),
- DEF_MOD("hscif3", 517, R8A7795_CLK_S3D1),
- DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1),
- DEF_MOD("hscif1", 519, R8A7795_CLK_S3D1),
- DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1),
- DEF_MOD("fcpvd3", 600, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvd2", 601, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvd1", 602, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvd0", 603, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvb1", 606, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvb0", 607, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvi2", 609, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvi1", 610, R8A7795_CLK_S2D1),
- DEF_MOD("fcpvi0", 611, R8A7795_CLK_S2D1),
- DEF_MOD("fcpf2", 613, R8A7795_CLK_S2D1),
- DEF_MOD("fcpf1", 614, R8A7795_CLK_S2D1),
- DEF_MOD("fcpf0", 615, R8A7795_CLK_S2D1),
- DEF_MOD("fcpci1", 616, R8A7795_CLK_S2D1),
- DEF_MOD("fcpci0", 617, R8A7795_CLK_S2D1),
- DEF_MOD("fcpcs", 619, R8A7795_CLK_S2D1),
- DEF_MOD("vspd3", 620, R8A7795_CLK_S2D1),
- DEF_MOD("vspd2", 621, R8A7795_CLK_S2D1),
- DEF_MOD("vspd1", 622, R8A7795_CLK_S2D1),
- DEF_MOD("vspd0", 623, R8A7795_CLK_S2D1),
- DEF_MOD("vspbc", 624, R8A7795_CLK_S2D1),
- DEF_MOD("vspbd", 626, R8A7795_CLK_S2D1),
- DEF_MOD("vspi2", 629, R8A7795_CLK_S2D1),
- DEF_MOD("vspi1", 630, R8A7795_CLK_S2D1),
- DEF_MOD("vspi0", 631, R8A7795_CLK_S2D1),
- DEF_MOD("ehci2", 701, R8A7795_CLK_S3D4),
- DEF_MOD("ehci1", 702, R8A7795_CLK_S3D4),
- DEF_MOD("ehci0", 703, R8A7795_CLK_S3D4),
- DEF_MOD("hsusb", 704, R8A7795_CLK_S3D4),
- DEF_MOD("du3", 721, R8A7795_CLK_S2D1),
- DEF_MOD("du2", 722, R8A7795_CLK_S2D1),
- DEF_MOD("du1", 723, R8A7795_CLK_S2D1),
- DEF_MOD("du0", 724, R8A7795_CLK_S2D1),
- DEF_MOD("lvds", 727, R8A7795_CLK_S2D1),
- DEF_MOD("hdmi1", 728, R8A7795_CLK_HDMI),
- DEF_MOD("hdmi0", 729, R8A7795_CLK_HDMI),
- DEF_MOD("etheravb", 812, R8A7795_CLK_S3D2),
- DEF_MOD("sata0", 815, R8A7795_CLK_S3D2),
- DEF_MOD("gpio7", 905, R8A7795_CLK_CP),
- DEF_MOD("gpio6", 906, R8A7795_CLK_CP),
- DEF_MOD("gpio5", 907, R8A7795_CLK_CP),
- DEF_MOD("gpio4", 908, R8A7795_CLK_CP),
- DEF_MOD("gpio3", 909, R8A7795_CLK_CP),
- DEF_MOD("gpio2", 910, R8A7795_CLK_CP),
- DEF_MOD("gpio1", 911, R8A7795_CLK_CP),
- DEF_MOD("gpio0", 912, R8A7795_CLK_CP),
- DEF_MOD("can-fd", 914, R8A7795_CLK_S3D2),
- DEF_MOD("can-if1", 915, R8A7795_CLK_S3D4),
- DEF_MOD("can-if0", 916, R8A7795_CLK_S3D4),
- DEF_MOD("i2c6", 918, R8A7795_CLK_S3D2),
- DEF_MOD("i2c5", 919, R8A7795_CLK_S3D2),
- DEF_MOD("i2c4", 927, R8A7795_CLK_S3D2),
- DEF_MOD("i2c3", 928, R8A7795_CLK_S3D2),
- DEF_MOD("i2c2", 929, R8A7795_CLK_S3D2),
- DEF_MOD("i2c1", 930, R8A7795_CLK_S3D2),
- DEF_MOD("i2c0", 931, R8A7795_CLK_S3D2),
- DEF_MOD("ssi-all", 1005, R8A7795_CLK_S3D4),
- DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)),
- DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)),
- DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)),
- DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)),
- DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)),
- DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)),
- DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)),
- DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)),
- DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)),
- DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)),
- DEF_MOD("scu-all", 1017, R8A7795_CLK_S3D4),
- DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)),
- DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)),
- DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)),
- DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)),
- DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)),
-};
-
-static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
- MOD_CLK_ID(408), /* INTC-AP (GIC) */
-};
-
-/* -----------------------------------------------------------------------------
- * SDn Clock
- *
- */
-#define CPG_SD_STP_HCK BIT(9)
-#define CPG_SD_STP_CK BIT(8)
-
-#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
-#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
-
-#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
-{ \
- .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
- ((stp_ck) ? CPG_SD_STP_CK : 0) | \
- ((sd_srcfc) << 2) | \
- ((sd_fc) << 0), \
- .div = (sd_div), \
-}
-
-struct sd_div_table {
- u32 val;
- unsigned int div;
-};
-
-struct sd_clock {
- struct clk_hw hw;
- void __iomem *reg;
- const struct sd_div_table *div_table;
- unsigned int div_num;
- unsigned int div_min;
- unsigned int div_max;
-};
-
-/* SDn divider
- * sd_srcfc sd_fc div
- * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
- *-------------------------------------------------------------------
- * 0 0 0 (1) 1 (4) 4
- * 0 0 1 (2) 1 (4) 8
- * 1 0 2 (4) 1 (4) 16
- * 1 0 3 (8) 1 (4) 32
- * 1 0 4 (16) 1 (4) 64
- * 0 0 0 (1) 0 (2) 2
- * 0 0 1 (2) 0 (2) 4
- * 1 0 2 (4) 0 (2) 8
- * 1 0 3 (8) 0 (2) 16
- * 1 0 4 (16) 0 (2) 32
- */
-static const struct sd_div_table cpg_sd_div_table[] = {
-/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
- CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
- CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),
- CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16),
- CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32),
- CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64),
- CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2),
- CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4),
- CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8),
- CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16),
- CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32),
-};
-
-#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw)
-
-static int cpg_sd_clock_enable(struct clk_hw *hw)
-{
- struct sd_clock *clock = to_sd_clock(hw);
- u32 val, sd_fc;
- unsigned int i;
-
- val = clk_readl(clock->reg);
-
- sd_fc = val & CPG_SD_FC_MASK;
- for (i = 0; i < clock->div_num; i++)
- if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
- break;
-
- if (i >= clock->div_num)
- return -EINVAL;
-
- val &= ~(CPG_SD_STP_MASK);
- val |= clock->div_table[i].val & CPG_SD_STP_MASK;
-
- clk_writel(val, clock->reg);
-
- return 0;
-}
-
-static void cpg_sd_clock_disable(struct clk_hw *hw)
-{
- struct sd_clock *clock = to_sd_clock(hw);
-
- clk_writel(clk_readl(clock->reg) | CPG_SD_STP_MASK, clock->reg);
-}
-
-static int cpg_sd_clock_is_enabled(struct clk_hw *hw)
-{
- struct sd_clock *clock = to_sd_clock(hw);
-
- return !(clk_readl(clock->reg) & CPG_SD_STP_MASK);
-}
-
-static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct sd_clock *clock = to_sd_clock(hw);
- unsigned long rate = parent_rate;
- u32 val, sd_fc;
- unsigned int i;
-
- val = clk_readl(clock->reg);
-
- sd_fc = val & CPG_SD_FC_MASK;
- for (i = 0; i < clock->div_num; i++)
- if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
- break;
-
- if (i >= clock->div_num)
- return -EINVAL;
-
- return DIV_ROUND_CLOSEST(rate, clock->div_table[i].div);
-}
-
-static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock,
- unsigned long rate,
- unsigned long parent_rate)
-{
- unsigned int div;
-
- if (!rate)
- rate = 1;
-
- div = DIV_ROUND_CLOSEST(parent_rate, rate);
-
- return clamp_t(unsigned int, div, clock->div_min, clock->div_max);
-}
-
-static long cpg_sd_clock_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
-{
- struct sd_clock *clock = to_sd_clock(hw);
- unsigned int div = cpg_sd_clock_calc_div(clock, rate, *parent_rate);
-
- return DIV_ROUND_CLOSEST(*parent_rate, div);
-}
-
-static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct sd_clock *clock = to_sd_clock(hw);
- unsigned int div = cpg_sd_clock_calc_div(clock, rate, parent_rate);
- u32 val;
- unsigned int i;
-
- for (i = 0; i < clock->div_num; i++)
- if (div == clock->div_table[i].div)
- break;
-
- if (i >= clock->div_num)
- return -EINVAL;
-
- val = clk_readl(clock->reg);
- val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK);
- val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK);
- clk_writel(val, clock->reg);
-
- return 0;
-}
-
-static const struct clk_ops cpg_sd_clock_ops = {
- .enable = cpg_sd_clock_enable,
- .disable = cpg_sd_clock_disable,
- .is_enabled = cpg_sd_clock_is_enabled,
- .recalc_rate = cpg_sd_clock_recalc_rate,
- .round_rate = cpg_sd_clock_round_rate,
- .set_rate = cpg_sd_clock_set_rate,
-};
-
-static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
- void __iomem *base,
- const char *parent_name)
-{
- struct clk_init_data init;
- struct sd_clock *clock;
- struct clk *clk;
- unsigned int i;
-
- clock = kzalloc(sizeof(*clock), GFP_KERNEL);
- if (!clock)
- return ERR_PTR(-ENOMEM);
-
- init.name = core->name;
- init.ops = &cpg_sd_clock_ops;
- init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
- init.parent_names = &parent_name;
- init.num_parents = 1;
-
- clock->reg = base + core->offset;
- clock->hw.init = &init;
- clock->div_table = cpg_sd_div_table;
- clock->div_num = ARRAY_SIZE(cpg_sd_div_table);
-
- clock->div_max = clock->div_table[0].div;
- clock->div_min = clock->div_max;
- for (i = 1; i < clock->div_num; i++) {
- clock->div_max = max(clock->div_max, clock->div_table[i].div);
- clock->div_min = min(clock->div_min, clock->div_table[i].div);
- }
-
- clk = clk_register(NULL, &clock->hw);
- if (IS_ERR(clk))
- kfree(clock);
-
- return clk;
-}
-
-#define CPG_PLL0CR 0x00d8
-#define CPG_PLL2CR 0x002c
-#define CPG_PLL4CR 0x01f4
-
-/*
- * CPG Clock Data
- */
-
-/*
- * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4
- * 14 13 19 17 (MHz)
- *-------------------------------------------------------------------
- * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144
- * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144
- * 0 0 1 0 Prohibited setting
- * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144
- * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120
- * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120
- * 0 1 1 0 Prohibited setting
- * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120
- * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96
- * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96
- * 1 0 1 0 Prohibited setting
- * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96
- * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144
- * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144
- * 1 1 1 0 Prohibited setting
- * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144
- */
-#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
- (((md) & BIT(13)) >> 11) | \
- (((md) & BIT(19)) >> 18) | \
- (((md) & BIT(17)) >> 17))
-
-struct cpg_pll_config {
- unsigned int extal_div;
- unsigned int pll1_mult;
- unsigned int pll3_mult;
-};
-
-static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
- /* EXTAL div PLL1 mult PLL3 mult */
- { 1, 192, 192, },
- { 1, 192, 128, },
- { 0, /* Prohibited setting */ },
- { 1, 192, 192, },
- { 1, 160, 160, },
- { 1, 160, 106, },
- { 0, /* Prohibited setting */ },
- { 1, 160, 160, },
- { 1, 128, 128, },
- { 1, 128, 84, },
- { 0, /* Prohibited setting */ },
- { 1, 128, 128, },
- { 2, 192, 192, },
- { 2, 192, 128, },
- { 0, /* Prohibited setting */ },
- { 2, 192, 192, },
-};
-
-static const struct cpg_pll_config *cpg_pll_config __initdata;
-
-static
-struct clk * __init r8a7795_cpg_clk_register(struct device *dev,
- const struct cpg_core_clk *core,
- const struct cpg_mssr_info *info,
- struct clk **clks,
- void __iomem *base)
-{
- const struct clk *parent;
- unsigned int mult = 1;
- unsigned int div = 1;
- u32 value;
-
- parent = clks[core->parent];
- if (IS_ERR(parent))
- return ERR_CAST(parent);
-
- switch (core->type) {
- case CLK_TYPE_GEN3_MAIN:
- div = cpg_pll_config->extal_div;
- break;
-
- case CLK_TYPE_GEN3_PLL0:
- /*
- * PLL0 is a configurable multiplier clock. Register it as a
- * fixed factor clock for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
- */
- value = readl(base + CPG_PLL0CR);
- mult = (((value >> 24) & 0x7f) + 1) * 2;
- break;
-
- case CLK_TYPE_GEN3_PLL1:
- mult = cpg_pll_config->pll1_mult;
- break;
-
- case CLK_TYPE_GEN3_PLL2:
- /*
- * PLL2 is a configurable multiplier clock. Register it as a
- * fixed factor clock for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
- */
- value = readl(base + CPG_PLL2CR);
- mult = (((value >> 24) & 0x7f) + 1) * 2;
- break;
-
- case CLK_TYPE_GEN3_PLL3:
- mult = cpg_pll_config->pll3_mult;
- break;
-
- case CLK_TYPE_GEN3_PLL4:
- /*
- * PLL4 is a configurable multiplier clock. Register it as a
- * fixed factor clock for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
- */
- value = readl(base + CPG_PLL4CR);
- mult = (((value >> 24) & 0x7f) + 1) * 2;
- break;
-
- case CLK_TYPE_GEN3_SD:
- return cpg_sd_clk_register(core, base, __clk_get_name(parent));
-
- default:
- return ERR_PTR(-EINVAL);
- }
-
- return clk_register_fixed_factor(NULL, core->name,
- __clk_get_name(parent), 0, mult, div);
-}
-
-/*
- * Reset register definitions.
- */
-#define MODEMR 0xe6160060
-
-static u32 rcar_gen3_read_mode_pins(void)
-{
- void __iomem *modemr = ioremap_nocache(MODEMR, 4);
- u32 mode;
-
- BUG_ON(!modemr);
- mode = ioread32(modemr);
- iounmap(modemr);
-
- return mode;
-}
-
-static int __init r8a7795_cpg_mssr_init(struct device *dev)
-{
- u32 cpg_mode = rcar_gen3_read_mode_pins();
-
- cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
- if (!cpg_pll_config->extal_div) {
- dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
- return -EINVAL;
- }
-
- return 0;
-}
-
-const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
- /* Core Clocks */
- .core_clks = r8a7795_core_clks,
- .num_core_clks = ARRAY_SIZE(r8a7795_core_clks),
- .last_dt_core_clk = LAST_DT_CORE_CLK,
- .num_total_core_clks = MOD_CLK_BASE,
-
- /* Module Clocks */
- .mod_clks = r8a7795_mod_clks,
- .num_mod_clks = ARRAY_SIZE(r8a7795_mod_clks),
- .num_hw_mod_clks = 12 * 32,
-
- /* Critical Module Clocks */
- .crit_mod_clks = r8a7795_crit_mod_clks,
- .num_crit_mod_clks = ARRAY_SIZE(r8a7795_crit_mod_clks),
-
- /* Callbacks */
- .init = r8a7795_cpg_mssr_init,
- .cpg_clk_register = r8a7795_cpg_clk_register,
-};
+++ /dev/null
-/*
- * Renesas Clock Pulse Generator / Module Standby and Software Reset
- *
- * Copyright (C) 2015 Glider bvba
- *
- * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
- *
- * Copyright (C) 2013 Ideas On Board SPRL
- * Copyright (C) 2015 Renesas Electronics Corp.
- *
- * 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.h>
-#include <linux/clk-provider.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_clock.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-
-#include <dt-bindings/clock/renesas-cpg-mssr.h>
-
-#include "renesas-cpg-mssr.h"
-#include "clk-div6.h"
-
-#ifdef DEBUG
-#define WARN_DEBUG(x) do { } while (0)
-#else
-#define WARN_DEBUG(x) WARN_ON(x)
-#endif
-
-
-/*
- * Module Standby and Software Reset register offets.
- *
- * If the registers exist, these are valid for SH-Mobile, R-Mobile,
- * R-Car Gen 2, and R-Car Gen 3.
- * These are NOT valid for R-Car Gen1 and RZ/A1!
- */
-
-/*
- * Module Stop Status Register offsets
- */
-
-static const u16 mstpsr[] = {
- 0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4,
- 0x9A0, 0x9A4, 0x9A8, 0x9AC,
-};
-
-#define MSTPSR(i) mstpsr[i]
-
-
-/*
- * System Module Stop Control Register offsets
- */
-
-static const u16 smstpcr[] = {
- 0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C,
- 0x990, 0x994, 0x998, 0x99C,
-};
-
-#define SMSTPCR(i) smstpcr[i]
-
-
-/*
- * Software Reset Register offsets
- */
-
-static const u16 srcr[] = {
- 0x0A0, 0x0A8, 0x0B0, 0x0B8, 0x0BC, 0x0C4, 0x1C8, 0x1CC,
- 0x920, 0x924, 0x928, 0x92C,
-};
-
-#define SRCR(i) srcr[i]
-
-
-/* Realtime Module Stop Control Register offsets */
-#define RMSTPCR(i) (smstpcr[i] - 0x20)
-
-/* Modem Module Stop Control Register offsets (r8a73a4) */
-#define MMSTPCR(i) (smstpcr[i] + 0x20)
-
-/* Software Reset Clearing Register offsets */
-#define SRSTCLR(i) (0x940 + (i) * 4)
-
-
-/**
- * Clock Pulse Generator / Module Standby and Software Reset Private Data
- *
- * @dev: CPG/MSSR device
- * @base: CPG/MSSR register block base address
- * @mstp_lock: protects writes to SMSTPCR
- * @clks: Array containing all Core and Module Clocks
- * @num_core_clks: Number of Core Clocks in clks[]
- * @num_mod_clks: Number of Module Clocks in clks[]
- * @last_dt_core_clk: ID of the last Core Clock exported to DT
- */
-struct cpg_mssr_priv {
- struct device *dev;
- void __iomem *base;
- spinlock_t mstp_lock;
-
- struct clk **clks;
- unsigned int num_core_clks;
- unsigned int num_mod_clks;
- unsigned int last_dt_core_clk;
-};
-
-
-/**
- * struct mstp_clock - MSTP gating clock
- * @hw: handle between common and hardware-specific interfaces
- * @index: MSTP clock number
- * @priv: CPG/MSSR private data
- */
-struct mstp_clock {
- struct clk_hw hw;
- u32 index;
- struct cpg_mssr_priv *priv;
-};
-
-#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
-
-static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
-{
- struct mstp_clock *clock = to_mstp_clock(hw);
- struct cpg_mssr_priv *priv = clock->priv;
- unsigned int reg = clock->index / 32;
- unsigned int bit = clock->index % 32;
- struct device *dev = priv->dev;
- u32 bitmask = BIT(bit);
- unsigned long flags;
- unsigned int i;
- u32 value;
-
- dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
- enable ? "ON" : "OFF");
- spin_lock_irqsave(&priv->mstp_lock, flags);
-
- value = clk_readl(priv->base + SMSTPCR(reg));
- if (enable)
- value &= ~bitmask;
- else
- value |= bitmask;
- clk_writel(value, priv->base + SMSTPCR(reg));
-
- spin_unlock_irqrestore(&priv->mstp_lock, flags);
-
- if (!enable)
- return 0;
-
- for (i = 1000; i > 0; --i) {
- if (!(clk_readl(priv->base + MSTPSR(reg)) &
- bitmask))
- break;
- cpu_relax();
- }
-
- if (!i) {
- dev_err(dev, "Failed to enable SMSTP %p[%d]\n",
- priv->base + SMSTPCR(reg), bit);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int cpg_mstp_clock_enable(struct clk_hw *hw)
-{
- return cpg_mstp_clock_endisable(hw, true);
-}
-
-static void cpg_mstp_clock_disable(struct clk_hw *hw)
-{
- cpg_mstp_clock_endisable(hw, false);
-}
-
-static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
-{
- struct mstp_clock *clock = to_mstp_clock(hw);
- struct cpg_mssr_priv *priv = clock->priv;
- u32 value;
-
- value = clk_readl(priv->base + MSTPSR(clock->index / 32));
-
- return !(value & BIT(clock->index % 32));
-}
-
-static const struct clk_ops cpg_mstp_clock_ops = {
- .enable = cpg_mstp_clock_enable,
- .disable = cpg_mstp_clock_disable,
- .is_enabled = cpg_mstp_clock_is_enabled,
-};
-
-static
-struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
- void *data)
-{
- unsigned int clkidx = clkspec->args[1];
- struct cpg_mssr_priv *priv = data;
- struct device *dev = priv->dev;
- unsigned int idx;
- const char *type;
- struct clk *clk;
-
- switch (clkspec->args[0]) {
- case CPG_CORE:
- type = "core";
- if (clkidx > priv->last_dt_core_clk) {
- dev_err(dev, "Invalid %s clock index %u\n", type,
- clkidx);
- return ERR_PTR(-EINVAL);
- }
- clk = priv->clks[clkidx];
- break;
-
- case CPG_MOD:
- type = "module";
- idx = MOD_CLK_PACK(clkidx);
- if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
- dev_err(dev, "Invalid %s clock index %u\n", type,
- clkidx);
- return ERR_PTR(-EINVAL);
- }
- clk = priv->clks[priv->num_core_clks + idx];
- break;
-
- default:
- dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]);
- return ERR_PTR(-EINVAL);
- }
-
- if (IS_ERR(clk))
- dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx,
- PTR_ERR(clk));
- else
- dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n",
- clkspec->args[0], clkspec->args[1], clk, clk);
- return clk;
-}
-
-static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
- const struct cpg_mssr_info *info,
- struct cpg_mssr_priv *priv)
-{
- struct clk *clk = NULL, *parent;
- struct device *dev = priv->dev;
- unsigned int id = core->id;
- const char *parent_name;
-
- WARN_DEBUG(id >= priv->num_core_clks);
- WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
-
- switch (core->type) {
- case CLK_TYPE_IN:
- clk = of_clk_get_by_name(priv->dev->of_node, core->name);
- break;
-
- case CLK_TYPE_FF:
- case CLK_TYPE_DIV6P1:
- WARN_DEBUG(core->parent >= priv->num_core_clks);
- parent = priv->clks[core->parent];
- if (IS_ERR(parent)) {
- clk = parent;
- goto fail;
- }
-
- parent_name = __clk_get_name(parent);
- if (core->type == CLK_TYPE_FF) {
- clk = clk_register_fixed_factor(NULL, core->name,
- parent_name, 0,
- core->mult, core->div);
- } else {
- clk = cpg_div6_register(core->name, 1, &parent_name,
- priv->base + core->offset);
- }
- break;
-
- default:
- if (info->cpg_clk_register)
- clk = info->cpg_clk_register(dev, core, info,
- priv->clks, priv->base);
- else
- dev_err(dev, "%s has unsupported core clock type %u\n",
- core->name, core->type);
- break;
- }
-
- if (IS_ERR_OR_NULL(clk))
- goto fail;
-
- dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk);
- priv->clks[id] = clk;
- return;
-
-fail:
- dev_err(dev, "Failed to register %s clock %s: %ld\n", "core,",
- core->name, PTR_ERR(clk));
-}
-
-static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
- const struct cpg_mssr_info *info,
- struct cpg_mssr_priv *priv)
-{
- struct mstp_clock *clock = NULL;
- struct device *dev = priv->dev;
- unsigned int id = mod->id;
- struct clk_init_data init;
- struct clk *parent, *clk;
- const char *parent_name;
- unsigned int i;
-
- WARN_DEBUG(id < priv->num_core_clks);
- WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
- WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
- WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
-
- parent = priv->clks[mod->parent];
- if (IS_ERR(parent)) {
- clk = parent;
- goto fail;
- }
-
- clock = kzalloc(sizeof(*clock), GFP_KERNEL);
- if (!clock) {
- clk = ERR_PTR(-ENOMEM);
- goto fail;
- }
-
- init.name = mod->name;
- init.ops = &cpg_mstp_clock_ops;
- init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
- for (i = 0; i < info->num_crit_mod_clks; i++)
- if (id == info->crit_mod_clks[i]) {
-#ifdef CLK_ENABLE_HAND_OFF
- dev_dbg(dev, "MSTP %s setting CLK_ENABLE_HAND_OFF\n",
- mod->name);
- init.flags |= CLK_ENABLE_HAND_OFF;
- break;
-#else
- dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n",
- mod->name);
- kfree(clock);
- return;
-#endif
- }
-
- parent_name = __clk_get_name(parent);
- init.parent_names = &parent_name;
- init.num_parents = 1;
-
- clock->index = id - priv->num_core_clks;
- clock->priv = priv;
- clock->hw.init = &init;
-
- clk = clk_register(NULL, &clock->hw);
- if (IS_ERR(clk))
- goto fail;
-
- dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk);
- priv->clks[id] = clk;
- return;
-
-fail:
- dev_err(dev, "Failed to register %s clock %s: %ld\n", "module,",
- mod->name, PTR_ERR(clk));
- kfree(clock);
-}
-
-
-#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
-struct cpg_mssr_clk_domain {
- struct generic_pm_domain genpd;
- struct device_node *np;
- unsigned int num_core_pm_clks;
- unsigned int core_pm_clks[0];
-};
-
-static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
- struct cpg_mssr_clk_domain *pd)
-{
- unsigned int i;
-
- if (clkspec->np != pd->np || clkspec->args_count != 2)
- return false;
-
- switch (clkspec->args[0]) {
- case CPG_CORE:
- for (i = 0; i < pd->num_core_pm_clks; i++)
- if (clkspec->args[1] == pd->core_pm_clks[i])
- return true;
- return false;
-
- case CPG_MOD:
- return true;
-
- default:
- return false;
- }
-}
-
-static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd,
- struct device *dev)
-{
- struct cpg_mssr_clk_domain *pd =
- container_of(genpd, struct cpg_mssr_clk_domain, genpd);
- 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 (cpg_mssr_is_pm_clk(&clkspec, pd))
- 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;
-}
-
-static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd,
- struct device *dev)
-{
- if (!list_empty(&dev->power.subsys_data->clock_list))
- pm_clk_destroy(dev);
-}
-
-static int __init cpg_mssr_add_clk_domain(struct device *dev,
- const unsigned int *core_pm_clks,
- unsigned int num_core_pm_clks)
-{
- struct device_node *np = dev->of_node;
- struct generic_pm_domain *genpd;
- struct cpg_mssr_clk_domain *pd;
- size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]);
-
- pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
-
- pd->np = np;
- pd->num_core_pm_clks = num_core_pm_clks;
- memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
-
- genpd = &pd->genpd;
- genpd->name = np->name;
- genpd->flags = GENPD_FLAG_PM_CLK;
- pm_genpd_init(genpd, &simple_qos_governor, false);
- genpd->attach_dev = cpg_mssr_attach_dev;
- genpd->detach_dev = cpg_mssr_detach_dev;
-
- of_genpd_add_provider_simple(np, genpd);
- return 0;
-}
-#else
-static inline int cpg_mssr_add_clk_domain(struct device *dev,
- const unsigned int *core_pm_clks,
- unsigned int num_core_pm_clks)
-{
- return 0;
-}
-#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
-
-
-static const struct of_device_id cpg_mssr_match[] = {
-#ifdef CONFIG_ARCH_R8A7795
- {
- .compatible = "renesas,r8a7795-cpg-mssr",
- .data = &r8a7795_cpg_mssr_info,
- },
-#endif
- { /* sentinel */ }
-};
-
-static void cpg_mssr_del_clk_provider(void *data)
-{
- of_clk_del_provider(data);
-}
-
-static int __init cpg_mssr_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- const struct cpg_mssr_info *info;
- struct cpg_mssr_priv *priv;
- unsigned int nclks, i;
- struct resource *res;
- struct clk **clks;
- int error;
-
- info = of_match_node(cpg_mssr_match, np)->data;
- if (info->init) {
- error = info->init(dev);
- if (error)
- return error;
- }
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->dev = dev;
- spin_lock_init(&priv->mstp_lock);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->base))
- return PTR_ERR(priv->base);
-
- nclks = info->num_total_core_clks + info->num_hw_mod_clks;
- clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
- if (!clks)
- return -ENOMEM;
-
- priv->clks = clks;
- priv->num_core_clks = info->num_total_core_clks;
- priv->num_mod_clks = info->num_hw_mod_clks;
- priv->last_dt_core_clk = info->last_dt_core_clk;
-
- for (i = 0; i < nclks; i++)
- clks[i] = ERR_PTR(-ENOENT);
-
- for (i = 0; i < info->num_core_clks; i++)
- cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
-
- for (i = 0; i < info->num_mod_clks; i++)
- cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
-
- error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
- if (error)
- return error;
-
- error = devm_add_action_or_reset(dev,
- cpg_mssr_del_clk_provider,
- np);
- if (error)
- return error;
-
- error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks,
- info->num_core_pm_clks);
- if (error)
- return error;
-
- return 0;
-}
-
-static struct platform_driver cpg_mssr_driver = {
- .driver = {
- .name = "renesas-cpg-mssr",
- .of_match_table = cpg_mssr_match,
- },
-};
-
-static int __init cpg_mssr_init(void)
-{
- return platform_driver_probe(&cpg_mssr_driver, cpg_mssr_probe);
-}
-
-subsys_initcall(cpg_mssr_init);
-
-MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
-MODULE_LICENSE("GPL v2");
+++ /dev/null
-/*
- * Renesas Clock Pulse Generator / Module Standby and Software Reset
- *
- * Copyright (C) 2015 Glider bvba
- *
- * 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.
- */
-
-#ifndef __CLK_RENESAS_CPG_MSSR_H__
-#define __CLK_RENESAS_CPG_MSSR_H__
-
- /*
- * Definitions of CPG Core Clocks
- *
- * These include:
- * - Clock outputs exported to DT
- * - External input clocks
- * - Internal CPG clocks
- */
-
-struct cpg_core_clk {
- /* Common */
- const char *name;
- unsigned int id;
- unsigned int type;
- /* Depending on type */
- unsigned int parent; /* Core Clocks only */
- unsigned int div;
- unsigned int mult;
- unsigned int offset;
-};
-
-enum clk_types {
- /* Generic */
- CLK_TYPE_IN, /* External Clock Input */
- CLK_TYPE_FF, /* Fixed Factor Clock */
- CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */
-
- /* Custom definitions start here */
- CLK_TYPE_CUSTOM,
-};
-
-#define DEF_TYPE(_name, _id, _type...) \
- { .name = _name, .id = _id, .type = _type }
-#define DEF_BASE(_name, _id, _type, _parent...) \
- DEF_TYPE(_name, _id, _type, .parent = _parent)
-
-#define DEF_INPUT(_name, _id) \
- DEF_TYPE(_name, _id, CLK_TYPE_IN)
-#define DEF_FIXED(_name, _id, _parent, _div, _mult) \
- DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
-#define DEF_DIV6P1(_name, _id, _parent, _offset) \
- DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
-#define DEF_SD(_name, _id, _parent, _offset) \
- DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
-
-
- /*
- * Definitions of Module Clocks
- */
-
-struct mssr_mod_clk {
- const char *name;
- unsigned int id;
- unsigned int parent; /* Add MOD_CLK_BASE for Module Clocks */
-};
-
-/* Convert from sparse base-100 to packed index space */
-#define MOD_CLK_PACK(x) ((x) - ((x) / 100) * (100 - 32))
-
-#define MOD_CLK_ID(x) (MOD_CLK_BASE + MOD_CLK_PACK(x))
-
-#define DEF_MOD(_name, _mod, _parent...) \
- { .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent }
-
-
-struct device_node;
-
- /**
- * SoC-specific CPG/MSSR Description
- *
- * @core_clks: Array of Core Clock definitions
- * @num_core_clks: Number of entries in core_clks[]
- * @last_dt_core_clk: ID of the last Core Clock exported to DT
- * @num_total_core_clks: Total number of Core Clocks (exported + internal)
- *
- * @mod_clks: Array of Module Clock definitions
- * @num_mod_clks: Number of entries in mod_clks[]
- * @num_hw_mod_clks: Number of Module Clocks supported by the hardware
- *
- * @crit_mod_clks: Array with Module Clock IDs of critical clocks that
- * should not be disabled without a knowledgeable driver
- * @num_crit_mod_clks: Number of entries in crit_mod_clks[]
- *
- * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power
- * Management, in addition to Module Clocks
- * @num_core_pm_clks: Number of entries in core_pm_clks[]
- *
- * @init: Optional callback to perform SoC-specific initialization
- * @cpg_clk_register: Optional callback to handle special Core Clock types
- */
-
-struct cpg_mssr_info {
- /* Core Clocks */
- const struct cpg_core_clk *core_clks;
- unsigned int num_core_clks;
- unsigned int last_dt_core_clk;
- unsigned int num_total_core_clks;
-
- /* Module Clocks */
- const struct mssr_mod_clk *mod_clks;
- unsigned int num_mod_clks;
- unsigned int num_hw_mod_clks;
-
- /* Critical Module Clocks that should not be disabled */
- const unsigned int *crit_mod_clks;
- unsigned int num_crit_mod_clks;
-
- /* Core Clocks suitable for PM, in addition to the Module Clocks */
- const unsigned int *core_pm_clks;
- unsigned int num_core_pm_clks;
-
- /* Callbacks */
- int (*init)(struct device *dev);
- struct clk *(*cpg_clk_register)(struct device *dev,
- const struct cpg_core_clk *core,
- const struct cpg_mssr_info *info,
- struct clk **clks, void __iomem *base);
-};
-
-extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
-#endif