[PATCH 11/12] clk: mmp: add device tree support for clocks.
Chao Xie
chao.xie at marvell.com
Mon Jun 9 18:27:47 PDT 2014
From: Chao Xie <chao.xie at marvell.com>
For MMP series SOC, it will use some types of clock.
Add the device tree support for these kind of clocks.
It includes mux/div/mix/gate/factor clock.
Signed-off-by: Chao Xie <chao.xie at marvell.com>
Conflicts:
drivers/clk/mmp/Makefile
---
.../devicetree/bindings/clock/mmp/clk-div | 28 +
.../devicetree/bindings/clock/mmp/clk-factor | 28 +
.../devicetree/bindings/clock/mmp/clk-gate | 41 ++
.../devicetree/bindings/clock/mmp/clk-mix | 38 ++
.../devicetree/bindings/clock/mmp/clk-mux | 20 +
drivers/clk/mmp/Makefile | 2 +-
drivers/clk/mmp/clk-of.c | 689 +++++++++++++++++++++
7 files changed, 845 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-div
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-factor
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-gate
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-mix
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-mux
create mode 100644 drivers/clk/mmp/clk-of.c
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-div b/Documentation/devicetree/bindings/clock/mmp/clk-div
new file mode 100644
index 0000000..62eb7d5
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-div
@@ -0,0 +1,28 @@
+Binding for div type clock
+
+The div clock is defined as common clock.
+
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-div".
+- clocks : The parents of the clock.
+- marvell,mmp-clk-bits-div : The width and shift of divider bits.
+
+Optional properties:
+- marvell,mmp-clk-div-power-of-two : The value of divider is a power of two.
+- marvell,mmp-clk-div-one-based : The value of divider starts from 1.
+- marvell,mmp-clk-div-table : The value of divider is not continous, and need
+ a table to record it.
+
+
+Examples
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ dsi_phy_slow_div: dsi_phy_slow_div {
+ compatible = "marvell,mmp-clk-div";
+ marvell,reg-offset = <0 0x44>;
+ clocks = <&vctcxo>;
+ marvell,mmp-clk-bits-div = <5 6>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-factor b/Documentation/devicetree/bindings/clock/mmp/clk-factor
new file mode 100644
index 0000000..9e1816c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-factor
@@ -0,0 +1,28 @@
+Binding for Marvell MMP series factor clock
+
+The factor clock is calculated by
+ Fout = (Fin * (den / num)) / factor;
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-factor";
+- clock: The parent of the clock.
+- marvell,mmp-clk-factor-factor : The "factor" of the clock.
+- marvell,mmp-clk-factor-bits-num : The width and shift of bits for "num".
+- marvell,mmp-clk-factor-bits-den : The width and shift of bits for "dev".
+- marvell,mmp-clk-factor-table : The table of (num, den) for the clock.
+
+Examples
+mpmu_clocks: mpmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4050000 0x1000>;
+ uart_pll: uart_pll {
+ compatible = "marvell,mmp-clk-factor";
+ clocks = <&pll1_4>;
+ marvell,reg-offset = <0 0x14>;
+ marvell,mmp-clk-factor-factor = <2>;
+ marvell,mmp-clk-factor-bits-den = <13 0>;
+ marvell,mmp-clk-factor-bits-num = <13 16>;
+ marvell,mmp-clk-factor-table = <8125 1536>;
+ };
+};
++
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-gate b/Documentation/devicetree/bindings/clock/mmp/clk-gate
new file mode 100644
index 0000000..5da6c63
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-gate
@@ -0,0 +1,41 @@
+Binding for Marvell MMP series gate clock and common gate clock
+
+There two type of gate clock used by Marvell MMP series SOC.
+The common gate clock and the gate clock defined for MMP series SOC.
+
+For common gate clock
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-general-gate";
+- clock : The parent of the clock.
+- marvell,mmp-clk-bit-gate : The offset of the bit control the gate.
+
+Examples
+apmu_clocks: apmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ pll1_416_gate: pll1_416_gate {
+ compatible = "marvell,mmp-clk-general-gate";
+ clocks = <&pll1_416m>;
+ marvell,reg-offset = <0 0x40>;
+ marvell,mmp-clk-bit-gate = <27>;
+ };
+};
+
+For MMP series gate clock
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-gate";
+- clock : The parent of the clock.
+- marvell,mmp-clk-mask : The (mask, val_enable, val_disable) for the clock.
+
+Examples
+apmu_clocks: apmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ usb_clock: usb_clock {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x9 0x9 0x1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-mix b/Documentation/devicetree/bindings/clock/mmp/clk-mix
new file mode 100644
index 0000000..8cf9b38
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-mix
@@ -0,0 +1,38 @@
+Binding for Marvell MMP series mix clock
+
+The mix clock is a combination of mux and div clock. It need to
+change the bits of mux and div together.
+
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-mix".
+- clocks : The parents of the clock.
+- marvell,mmp-clk-bits-div : The width and shift of divider bits.
+- marvell,mmp-clk-bits-mux : The width and shift of divider bits.
+- marvell,mmp-clk-bit-fc : The offset of the frequency change bit.
+- marvell,mmp-clk-mix-table : The array of (rate, parent_index). The rate
+ means the clock's rate, and parent_index means
+ the suggested parent index from user.
+
+Optional properties:
+- marvell,mmp-clk-div-power-of-two : The value of divider is a power of two.
+- marvell,mmp-clk-div-one-based : The value of divider starts from 1.
+- marvell,mmp-clk-div-table : The value of divider is not continous, and need
+ a table to record it.
+
+
+Exampels
+
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ lcd_clk {
+ compatible = "marvell,mmp-clk-mix";
+ clocks = <&pll1_416m &pll1_624 &pll2 &pll2p>;
+ marvell,reg-offset = <0 0x4c>;
+ marvell,mmp-clk-bits-mux = <2 17>;
+ marvell,mmp-clk-bits-div = <3 19>;
+ marvell,mmp-clk-bit-fc = <22>;
+ };
+};
+
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-mux b/Documentation/devicetree/bindings/clock/mmp/clk-mux
new file mode 100644
index 0000000..f5bb4dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-mux
@@ -0,0 +1,20 @@
+Binding for mux type clock
+
+The mux clock is defined as common clock.
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-mux".
+- clocks : The parents of the clock.
+- marvell,mmp-clk-bits-mux : The width and shift of mux bits.
+
+Examples
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ dsi_phy_esc_mux: dsi_phy_esc_mux {
+ compatible = "marvell,mmp-clk-mux";
+ marvell,reg-offset = <0 0x44>;
+ clocks = <&pll1_12 &pll1_13 &vctcxo &pll1_8>;
+ marvell,mmp-clk-bits-mux = <2 0>;
+ };
+};
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 84dce78..e29c6f1 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -6,7 +6,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o \
clk-mix-composite.o
ifneq ($(CONFIG_OF),)
-obj-y += clk-master-node.o lock.o clk-of-composite.o
+obj-y += clk-master-node.o lock.o clk-of-composite.o clk-of.o
endif
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
diff --git a/drivers/clk/mmp/clk-of.c b/drivers/clk/mmp/clk-of.c
new file mode 100644
index 0000000..2bba7ee
--- /dev/null
+++ b/drivers/clk/mmp/clk-of.c
@@ -0,0 +1,689 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <chao.xie at marvell.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+#include "clk.h"
+
+static int of_mmp_clk_get_flags(struct device_node *np,
+ unsigned long *flags)
+{
+ *flags = 0;
+
+ return 0;
+}
+
+static int of_mmp_clk_get_bits(struct device_node *np, const char *name,
+ u8 *width, u8 *shift)
+{
+ int ret;
+ u32 tmp[2];
+
+ ret = of_property_read_u32_array(np, name, tmp, 2);
+ if (ret) {
+ pr_err("%s:%s failed to read bits %s\n",
+ __func__, np->name, name);
+ return -EINVAL;
+ }
+
+ *width = tmp[0];
+ *shift = tmp[1];
+
+ return 0;
+}
+
+static int of_mmp_clk_div_dt_parse(struct device_node *np, u8 *shift,
+ u8 *width,
+ struct clk_div_table **ptable,
+ u8 *div_flags)
+{
+ int i, ret;
+ const __be32 *prop;
+ unsigned int proplen;
+ struct clk_div_table *table;
+ unsigned int size;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-bits-div",
+ width, shift);
+ if (ret)
+ return ret;
+
+ *div_flags = 0;
+ if (of_property_read_bool(np, "marvell,mmp-clk-div-power-of-two"))
+ *div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+ else if (of_property_read_bool(np, "marvell,mmp-clk-div-one-based"))
+ *div_flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (ptable)
+ *ptable = NULL;
+
+ prop = of_get_property(np, "marvell,mmp-clk-div-table", &proplen);
+ if (prop) {
+ if (!ptable)
+ return -EINVAL;
+
+ size = proplen / sizeof(u32);
+ if ((proplen % sizeof(u32)) || size % 2) {
+ pr_err("%s:%s marvell,mmp-clk-mix-table wrong value\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ table = kzalloc(sizeof(*table) * (size / 2 + 1), GFP_KERNEL);
+ if (!table) {
+ pr_err("%s:%s failed to allocate table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 2) {
+ table[i / 2].val = be32_to_cpup(prop + i);
+ table[i / 2].div = be32_to_cpup(prop + i + 1);
+ }
+ /* For safe. */
+ table[i / 2].val = 0;
+ table[i / 2].div = 0;
+
+ *ptable = table;
+ }
+
+ return 0;
+}
+
+static int of_mmp_clk_mux_dt_parse(struct device_node *np, u8 *shift,
+ u8 *width, u8 *mux_flags)
+{
+ int ret;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-bits-mux",
+ width, shift);
+ if (ret)
+ return ret;
+
+ *mux_flags = 0;
+
+ return 0;
+}
+
+static int of_mmp_clk_general_gate_dt_parse(struct device_node *np,
+ u8 *bit_idx, u8 *gate_flags)
+{
+ int ret;
+ u32 tmp;
+
+ ret = of_property_read_u32(np, "marvell,mmp-clk-bit-gate", &tmp);
+ if (ret) {
+ pr_err("%s:%s can not find marvell,mmp-clk-bit-gate\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ *bit_idx = tmp;
+
+ *gate_flags = 0;
+
+ return 0;
+}
+
+static int of_mmp_clk_gate_dt_parse(struct device_node *np,
+ u32 *mask, u32 *val_enable, u32 *val_disable,
+ unsigned int *gate_flags)
+{
+ int ret;
+ u32 tmp[3];
+
+ ret = of_property_read_u32_array(np, "marvell,mmp-clk-mask", tmp, 3);
+ if (ret) {
+ pr_err("%s:%s can not find marvell,mmp-clk-mask\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ *mask = tmp[0];
+ *val_enable = tmp[1];
+ *val_disable = tmp[2];
+
+ *gate_flags = 0;
+ if (of_property_read_bool(np, "marvell,mmp-clk-gate-need-delay"))
+ *gate_flags |= MMP_CLK_GATE_NEED_DELAY;
+
+ return 0;
+}
+
+
+static int of_mmp_clk_mix_dt_parse(struct device_node *np,
+ struct mmp_clk_mix_config *config,
+ spinlock_t **plock)
+{
+ struct mmp_clk_mix_reg_info *ri;
+ struct mmp_clk_mix_clk_table *table;
+ int i, ret, size;
+ u32 tmp;
+ spinlock_t *lock;
+ void __iomem *reg;
+ unsigned int reg_phys;
+ const __be32 *prop;
+ unsigned int proplen;
+
+ ri = &config->reg_info;
+ ret = of_mmp_clk_div_dt_parse(np, &ri->shift_div, &ri->width_div,
+ NULL, &config->div_flags);
+ if (ret)
+ return ret;
+
+ ret = of_mmp_clk_mux_dt_parse(np, &ri->shift_mux, &ri->width_mux,
+ &config->mux_flags);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "marvell,mmp-clk-bit-fc", &tmp);
+ if (ret)
+ ri->bit_fc = (u8)-1;
+ else
+ ri->bit_fc = tmp;
+
+ reg = of_mmp_clk_get_reg(np, 0, ®_phys);
+ if (!reg)
+ return -EINVAL;
+ ri->reg_clk_ctrl = reg;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return -EINVAL;
+
+ *plock = lock;
+ reg = of_mmp_clk_get_reg(np, 1, ®_phys);
+ if (reg)
+ ri->reg_clk_sel = reg;
+
+ prop = of_get_property(np, "marvell,mmp-clk-mix-table", &proplen);
+ if (prop) {
+ size = proplen / sizeof(u32);
+ if ((proplen % sizeof(u32)) || size % 2) {
+ pr_err("%s:%s marvell,mmp-clk-mix-table wrong value\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ table = kzalloc(sizeof(*table) * (size / 2), GFP_KERNEL);
+ if (!table) {
+ pr_err("%s:%s failed to allocate table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 2) {
+ table[i / 2].rate = be32_to_cpup(prop + i);
+ table[i / 2].parent_index = be32_to_cpup(prop + i + 1);
+ }
+ config->table = table;
+ config->table_size = size / 2;
+ } else {
+ config->table = NULL;
+ config->table_size = 0;
+ }
+
+ return 0;
+}
+
+static int of_mmp_clk_factor_dt_parse(struct device_node *np,
+ struct mmp_clk_factor_masks **pmasks,
+ struct mmp_clk_factor_tbl **pftbl,
+ unsigned int *pftbl_cnt)
+{
+ struct mmp_clk_factor_masks *masks;
+ struct mmp_clk_factor_tbl *table;
+ u8 width, shift;
+ int i, ret, size;
+ u32 tmp;
+ const __be32 *prop;
+ unsigned int proplen;
+
+ masks = kzalloc(sizeof(*masks), GFP_KERNEL);
+ if (!masks) {
+ pr_err("%s:%s failed to allocate factor masks\n",
+ __func__, np->name);
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32(np, "marvell,mmp-clk-factor-factor", &tmp);
+ if (ret) {
+ pr_err("%s:%s can not find marvell,mmp-clk-factor-num\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ masks->factor = tmp;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-factor-bits-num",
+ &width, &shift);
+ if (ret)
+ return ret;
+ masks->num_mask = BIT(width) - 1;
+ masks->num_shift = shift;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-factor-bits-den",
+ &width, &shift);
+ if (ret)
+ return ret;
+ masks->den_mask = BIT(width) - 1;
+ masks->den_shift = shift;
+ *pmasks = masks;
+
+ prop = of_get_property(np, "marvell,mmp-clk-factor-table", &proplen);
+ if (!prop) {
+ pr_err("%s:%s failed to get marvell,mmp-clk-factor-table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ size = proplen / sizeof(u32);
+ if ((proplen % sizeof(u32)) || size % 2) {
+ pr_err("%s:%s marvell,mmp-clk-factor-table wrong value\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ table = kzalloc(sizeof(*table) * (size / 2), GFP_KERNEL);
+ if (!table) {
+ pr_err("%s:%s failed to allocate table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 2) {
+ table[i / 2].num = be32_to_cpup(prop + i);
+ table[i / 2].den = be32_to_cpup(prop + i + 1);
+ }
+ *pftbl = table;
+ *pftbl_cnt = size / 2;
+
+ return 0;
+}
+
+static void of_mmp_clk_mix_setup(struct device_node *np)
+{
+ struct mmp_clk_mix *mix;
+ struct mmp_clk_mix_config config;
+ struct clk *clk;
+ spinlock_t *lock;
+ unsigned int num_parents;
+ const char **parent_names;
+ int i, ret;
+
+ ret = of_mmp_clk_mix_dt_parse(np, &config, &lock);
+ if (ret)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ mix = kzalloc(sizeof(*mix), GFP_KERNEL);
+ if (!mix) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+ memcpy(&mix->reg_info, &config.reg_info,
+ sizeof(config.reg_info));
+ mix->div_flags = config.div_flags;
+ mix->mux_flags = config.mux_flags;
+ mix->lock = lock;
+ if (config.table) {
+ mix->table = config.table;
+ mix->table_size = config.table_size;
+ }
+
+ of_mmp_clk_composite_add_member(np, &mix->hw, &mmp_clk_mix_ops,
+ MMP_CLK_COMPOSITE_TYPE_MUXMIX);
+ } else {
+ num_parents = of_clk_get_parent_count(np);
+ parent_names = kcalloc(num_parents, sizeof(char *),
+ GFP_KERNEL);
+ if (!parent_names) {
+ pr_err("%s:%s failed to allocate parent_names\n",
+ __func__, np->name);
+ return;
+ }
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ clk = mmp_clk_register_mix(NULL, np->name, num_parents,
+ parent_names, 0, &config, lock);
+
+ if (IS_ERR(clk)) {
+ kfree(parent_names);
+
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_mix, "marvell,mmp-clk-mix",
+ of_mmp_clk_mix_setup);
+
+static void of_mmp_clk_div_setup(struct device_node *np)
+{
+ struct clk_divider *div;
+ void __iomem *reg;
+ u8 width, shift, div_flags;
+ struct clk_div_table *table;
+ unsigned long flags;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ spinlock_t *lock;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, ®_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_div_dt_parse(np, &shift, &width, &table, &div_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+ div->shift = shift;
+ div->width = width;
+ div->table = table;
+ div->flags = div_flags;
+ div->lock = lock;
+ div->reg = reg;
+
+ of_mmp_clk_composite_add_member(np, &div->hw, &clk_divider_ops,
+ MMP_CLK_COMPOSITE_TYPE_DIV);
+ } else {
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ if (!table)
+ clk = clk_register_divider(NULL, np->name, parent_name,
+ flags, reg, shift, width, div_flags,
+ lock);
+ else
+ clk = clk_register_divider_table(NULL, np->name,
+ parent_name, flags, reg, shift, width,
+ div_flags, table, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_div, "marvell,mmp-clk-div",
+ of_mmp_clk_div_setup);
+
+static void of_mmp_clk_mux_setup(struct device_node *np)
+{
+ struct clk_mux *mux;
+ void __iomem *reg;
+ u8 width, shift, mux_flags;
+ unsigned long flags;
+ spinlock_t *lock;
+ unsigned int num_parents;
+ const char **parent_names;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int i, ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, ®_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_mux_dt_parse(np, &shift, &width, &mux_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ mux->reg = reg;
+ mux->mask = BIT(width) - 1;
+ mux->shift = shift;
+ mux->lock = lock;
+ mux->flags = mux_flags;
+ of_mmp_clk_composite_add_member(np, &mux->hw, &clk_mux_ops,
+ MMP_CLK_COMPOSITE_TYPE_MUXMIX);
+ } else {
+ num_parents = of_clk_get_parent_count(np);
+ parent_names = kcalloc(num_parents, sizeof(char *),
+ GFP_KERNEL);
+ if (!parent_names) {
+ pr_err("%s:%s failed to allocate parent_names\n",
+ __func__, np->name);
+ return;
+ }
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ clk = clk_register_mux(NULL, np->name, parent_names,
+ num_parents, flags,
+ reg, shift, width, mux_flags, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_mux, "marvell,mmp-clk-mux",
+ of_mmp_clk_mux_setup);
+
+static void of_mmp_clk_general_gate_setup(struct device_node *np)
+{
+ struct clk_gate *gate;
+ void __iomem *reg;
+ u8 bit_idx, gate_flags;
+ unsigned long flags;
+ spinlock_t *lock;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, ®_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_general_gate_dt_parse(np, &bit_idx, &gate_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+ gate->bit_idx = bit_idx;
+ gate->flags = gate_flags;
+ gate->reg = reg;
+ gate->lock = lock;
+ of_mmp_clk_composite_add_member(np, &gate->hw, &clk_gate_ops,
+ MMP_CLK_COMPOSITE_TYPE_GATE);
+ } else {
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ clk = clk_register_gate(NULL, np->name, parent_name, flags,
+ reg, bit_idx, gate_flags, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_general_gate, "marvell,mmp-clk-general-gate",
+ of_mmp_clk_general_gate_setup);
+
+static void of_mmp_clk_gate_setup(struct device_node *np)
+{
+ struct mmp_clk_gate *gate;
+ void __iomem *reg;
+ u32 mask, val_enable, val_disable;
+ unsigned int gate_flags;
+ unsigned long flags;
+ spinlock_t *lock;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, ®_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_gate_dt_parse(np, &mask, &val_enable, &val_disable,
+ &gate_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ gate->flags = gate_flags;
+ gate->mask = mask;
+ gate->val_enable = val_enable;
+ gate->val_disable = val_disable;
+ gate->reg = reg;
+ gate->lock = lock;
+ of_mmp_clk_composite_add_member(np, &gate->hw,
+ &mmp_clk_gate_ops,
+ MMP_CLK_COMPOSITE_TYPE_GATE);
+ } else {
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ clk = mmp_clk_register_gate(NULL, np->name, parent_name, flags,
+ reg, mask, val_enable, val_disable,
+ gate_flags, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_gate, "marvell,mmp-clk-gate",
+ of_mmp_clk_gate_setup);
+
+static void of_mmp_clk_factor_setup(struct device_node *np)
+{
+ void __iomem *reg;
+ struct mmp_clk_factor_masks *masks;
+ struct mmp_clk_factor_tbl *table;
+ unsigned int table_size;
+ unsigned long flags;
+ spinlock_t *lock;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, ®_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_factor_dt_parse(np, &masks, &table, &table_size);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ clk = mmp_clk_register_factor(np->name, parent_name, flags,
+ reg, masks, table, table_size,
+ lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n", __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+}
+CLK_OF_DECLARE(mmp_clk_factor,
+ "marvell,mmp-clk-factor",
+ of_mmp_clk_factor_setup);
+
+void mmp_clk_of_init(void)
+{
+ struct device_node *next;
+
+ next = NULL;
+ do {
+ next = of_mmp_clk_master_init(next);
+ } while (next);
+}
--
1.8.3.2
More information about the linux-arm-kernel
mailing list