> Subject: [RFC 04/11] clk: imx: Add gate shared for i.MX8MP audiomix > > The newer i.MX platform use some gates that have a shared control bit > between them. Could the existing clk_hw_register_gate2 handle your case? Thanks, Peng. > > Signed-off-by: Abel Vesa <abel.vesa@xxxxxxx> > --- > drivers/clk/imx/Makefile | 2 +- > drivers/clk/imx/clk-gate-shared.c | 111 > ++++++++++++++++++++++++++++++++++++++ > drivers/clk/imx/clk.h | 4 ++ > 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 > drivers/clk/imx/clk-gate-shared.c > > diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index > 928f874c..799a8ef 100644 > --- a/drivers/clk/imx/Makefile > +++ b/drivers/clk/imx/Makefile > @@ -27,7 +27,7 @@ obj-$(CONFIG_MXC_CLK_SCU) += \ > > obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o > obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o > -obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o > +obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o clk-gate-shared.o > obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o > obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o > > diff --git a/drivers/clk/imx/clk-gate-shared.c > b/drivers/clk/imx/clk-gate-shared.c > new file mode 100644 > index 00000000..961a0e3 > --- /dev/null > +++ b/drivers/clk/imx/clk-gate-shared.c > @@ -0,0 +1,111 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright 2019 NXP. > + */ > + > +#include <linux/clk-provider.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/slab.h> > +#include "clk.h" > + > +/** > + * struct clk_gate_shared - i.MX specific gate clock having the gate > +flag > + * shared with other gate clocks > + */ > +struct clk_gate_shared { > + struct clk_gate gate; > + spinlock_t *lock; > + unsigned int *share_count; > +}; > + > +static int clk_gate_shared_enable(struct clk_hw *hw) { > + struct clk_gate *gate = to_clk_gate(hw); > + struct clk_gate_shared *shgate = container_of(gate, > + struct clk_gate_shared, gate); > + unsigned long flags = 0; > + int ret = 0; > + > + spin_lock_irqsave(shgate->lock, flags); > + > + if (shgate->share_count && (*shgate->share_count)++ > 0) > + goto out; > + > + ret = clk_gate_ops.enable(hw); > +out: > + spin_unlock_irqrestore(shgate->lock, flags); > + > + return ret; > +} > + > +static void clk_gate_shared_disable(struct clk_hw *hw) { > + struct clk_gate *gate = to_clk_gate(hw); > + struct clk_gate_shared *shgate = container_of(gate, > + struct clk_gate_shared, gate); > + unsigned long flags = 0; > + > + spin_lock_irqsave(shgate->lock, flags); > + > + if (shgate->share_count) { > + if (WARN_ON(*shgate->share_count == 0)) > + goto out; > + else if (--(*shgate->share_count) > 0) > + goto out; > + } > + > + clk_gate_ops.disable(hw); > +out: > + spin_unlock_irqrestore(shgate->lock, flags); } > + > +static int clk_gate_shared_is_enabled(struct clk_hw *hw) { > + return clk_gate_ops.is_enabled(hw); > +} > + > +static const struct clk_ops clk_gate_shared_ops = { > + .enable = clk_gate_shared_enable, > + .disable = clk_gate_shared_disable, > + .is_enabled = clk_gate_shared_is_enabled, }; > + > +struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev, const char > *name, > + const char *parent, void __iomem *reg, > + u8 shift, unsigned int *share_count) { > + struct clk_gate_shared *shgate; > + struct clk_gate *gate; > + struct clk_hw *hw; > + struct clk_init_data init; > + int ret; > + > + shgate = kzalloc(sizeof(*shgate), GFP_KERNEL); > + if (!shgate) > + return ERR_PTR(-ENOMEM); > + gate = &shgate->gate; > + > + init.name = name; > + init.ops = &clk_gate_shared_ops; > + init.flags = CLK_OPS_PARENT_ENABLE; > + init.parent_names = parent ? &parent : NULL; > + init.num_parents = parent ? 1 : 0; > + > + gate->reg = reg; > + gate->bit_idx = shift; > + gate->lock = NULL; > + gate->hw.init = &init; > + shgate->lock = &imx_ccm_lock; > + shgate->share_count = share_count; > + > + hw = &gate->hw; > + > + ret = clk_hw_register(NULL, hw); > + if (ret) { > + kfree(shgate); > + return ERR_PTR(ret); > + } > + > + return hw; > +} > diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index > f074dd8..51d6c26 100644 > --- a/drivers/clk/imx/clk.h > +++ b/drivers/clk/imx/clk.h > @@ -151,6 +151,10 @@ struct clk_hw *imx_clk_hw_sscg_pll(const char > *name, > void __iomem *base, > unsigned long flags); > > +struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev, const char > *name, > + const char *parent, void __iomem *reg, > + u8 shift, unsigned int *share_count); > + > enum imx_pllv3_type { > IMX_PLLV3_GENERIC, > IMX_PLLV3_SYS, > -- > 2.7.4