From: Chao Xie <chao.xie@xxxxxxxxxxx> 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@xxxxxxxxxxx> 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@xxxxxxxxxxx> + * + * 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 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html