[PATCH] clk: let mxs specific clk-div clock type be a generic clock type
Shawn Guo
shawn.guo at linaro.org
Mon Mar 18 04:42:21 EDT 2013
On Sat, Mar 16, 2013 at 06:20:01PM +0530, Thomas Abraham wrote:
> The mxs platform specific clk-div clock is an extended version of the
> basic integer divider clock type that supports checking the stability
> status of the divider clock output. This type of clock is found on
> some of the Samsung platforms as well. So let the mxs specfic clk-div
> clock type be a generic clock type that all platforms can utilize.
>
> Cc: Shawn Guo <shawn.guo at linaro.org>
> Cc: Mike Turquette <mturquette at linaro.org>
> Signed-off-by: Thomas Abraham <thomas.abraham at linaro.org>
> ---
> drivers/clk/Makefile | 1 +
> drivers/clk/clk-divider-status.c | 119 ++++++++++++++++++++++++++++++++++++++
> drivers/clk/mxs/Makefile | 2 +-
> drivers/clk/mxs/clk-div.c | 110 -----------------------------------
> drivers/clk/mxs/clk.h | 12 +++-
> include/linux/clk-provider.h | 21 +++++++
> 6 files changed, 151 insertions(+), 114 deletions(-)
> create mode 100644 drivers/clk/clk-divider-status.c
> delete mode 100644 drivers/clk/mxs/clk-div.c
>From my quick testing, it seems working for mxs platform. But it's hard
to review the changes. Making it two steps might be helpful for
reviewer:
1) git mv drivers/clk/mxs/clk-div.c drivers/clk/clk-divider-status.c
2) make changes on drivers/clk/clk-divider-status.c
Shawn
>
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 0147022..0ac851a 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
> obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
> obj-$(CONFIG_COMMON_CLK) += clk-gate.o
> obj-$(CONFIG_COMMON_CLK) += clk-mux.o
> +obj-$(CONFIG_COMMON_CLK) += clk-divider-status.o
>
> # SoCs specific
> obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
> diff --git a/drivers/clk/clk-divider-status.c b/drivers/clk/clk-divider-status.c
> new file mode 100644
> index 0000000..1d66059
> --- /dev/null
> +++ b/drivers/clk/clk-divider-status.c
> @@ -0,0 +1,119 @@
> +/*
> + * Copyright 2012 Freescale Semiconductor, Inc.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + *
> + * Extension to the adjustable divider clock implementation with support for
> + * divider clock stability checks.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/jiffies.h>
> +
> +/*
> + * DOC: Adjustable divider clock with support for divider stability check
> + *
> + * 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 / divisor
> + * parent - fixed parent. No clk_set_parent support
> + */
> +
> +static inline struct clk_divider_status *to_clk_div(struct clk_hw *hw)
> +{
> + struct clk_divider *divider = container_of(hw, struct clk_divider, hw);
> +
> + return container_of(divider, struct clk_divider_status, divider);
> +}
> +
> +static unsigned long clk_divider_status_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_divider_status *div = to_clk_div(hw);
> +
> + return div->ops->recalc_rate(&div->divider.hw, parent_rate);
> +}
> +
> +static long clk_divider_status_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + struct clk_divider_status *div = to_clk_div(hw);
> +
> + return div->ops->round_rate(&div->divider.hw, rate, prate);
> +}
> +
> +static int clk_divider_status_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_divider_status *div = to_clk_div(hw);
> + int ret;
> +
> + ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate);
> + if (!ret) {
> + unsigned long timeout = jiffies + msecs_to_jiffies(10);
> +
> + while (readl_relaxed(div->reg) & (1 << div->busy)) {
> + if (time_after(jiffies, timeout))
> + return -ETIMEDOUT;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static struct clk_ops clk_divider_status_ops = {
> + .recalc_rate = clk_divider_status_recalc_rate,
> + .round_rate = clk_divider_status_round_rate,
> + .set_rate = clk_divider_status_set_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_divider_status_ops);
> +
> +struct clk *clk_register_divider_status(struct device *dev, const char *name,
> + const char *parent_name, unsigned long flags, void __iomem *reg,
> + u8 shift, u8 width, u8 clk_divider_flags,
> + void __iomem *reg_status, u8 shift_status, spinlock_t *lock)
> +{
> + struct clk_divider_status *div;
> + struct clk *clk;
> + struct clk_init_data init;
> +
> + div = kzalloc(sizeof(*div), GFP_KERNEL);
> + if (!div) {
> + pr_err("%s: could not allocate divider-status clk\n", __func__);
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + init.name = name;
> + init.ops = &clk_divider_status_ops;
> + init.flags = flags;
> + init.parent_names = (parent_name ? &parent_name : NULL);
> + init.num_parents = (parent_name ? 1 : 0);
> +
> + div->reg = reg_status;
> + div->busy = shift_status;
> + div->ops = &clk_divider_ops;
> +
> + div->divider.reg = reg;
> + div->divider.shift = shift;
> + div->divider.width = width;
> + div->divider.flags = clk_divider_flags;
> + div->divider.lock = lock;
> + div->divider.hw.init = &init;
> +
> + clk = clk_register(NULL, &div->divider.hw);
> + if (IS_ERR(clk))
> + kfree(div);
> +
> + return clk;
> +}
> diff --git a/drivers/clk/mxs/Makefile b/drivers/clk/mxs/Makefile
> index a6a2223..8f8f1b3 100644
> --- a/drivers/clk/mxs/Makefile
> +++ b/drivers/clk/mxs/Makefile
> @@ -2,7 +2,7 @@
> # Makefile for mxs specific clk
> #
>
> -obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o clk-ssp.o
> +obj-y += clk.o clk-pll.o clk-ref.o clk-frac.o clk-ssp.o
>
> obj-$(CONFIG_SOC_IMX23) += clk-imx23.o
> obj-$(CONFIG_SOC_IMX28) += clk-imx28.o
> diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c
> deleted file mode 100644
> index 90e1da9..0000000
> --- a/drivers/clk/mxs/clk-div.c
> +++ /dev/null
> @@ -1,110 +0,0 @@
> -/*
> - * Copyright 2012 Freescale Semiconductor, Inc.
> - *
> - * The code contained herein is licensed under the GNU General Public
> - * License. You may obtain a copy of the GNU General Public License
> - * Version 2 or later at the following locations:
> - *
> - * http://www.opensource.org/licenses/gpl-license.html
> - * http://www.gnu.org/copyleft/gpl.html
> - */
> -
> -#include <linux/clk.h>
> -#include <linux/clk-provider.h>
> -#include <linux/err.h>
> -#include <linux/slab.h>
> -#include "clk.h"
> -
> -/**
> - * struct clk_div - mxs integer divider clock
> - * @divider: the parent class
> - * @ops: pointer to clk_ops of parent class
> - * @reg: register address
> - * @busy: busy bit shift
> - *
> - * The mxs divider clock is a subclass of basic clk_divider with an
> - * addtional busy bit.
> - */
> -struct clk_div {
> - struct clk_divider divider;
> - const struct clk_ops *ops;
> - void __iomem *reg;
> - u8 busy;
> -};
> -
> -static inline struct clk_div *to_clk_div(struct clk_hw *hw)
> -{
> - struct clk_divider *divider = container_of(hw, struct clk_divider, hw);
> -
> - return container_of(divider, struct clk_div, divider);
> -}
> -
> -static unsigned long clk_div_recalc_rate(struct clk_hw *hw,
> - unsigned long parent_rate)
> -{
> - struct clk_div *div = to_clk_div(hw);
> -
> - return div->ops->recalc_rate(&div->divider.hw, parent_rate);
> -}
> -
> -static long clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
> - unsigned long *prate)
> -{
> - struct clk_div *div = to_clk_div(hw);
> -
> - return div->ops->round_rate(&div->divider.hw, rate, prate);
> -}
> -
> -static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
> - unsigned long parent_rate)
> -{
> - struct clk_div *div = to_clk_div(hw);
> - int ret;
> -
> - ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate);
> - if (!ret)
> - ret = mxs_clk_wait(div->reg, div->busy);
> -
> - return ret;
> -}
> -
> -static struct clk_ops clk_div_ops = {
> - .recalc_rate = clk_div_recalc_rate,
> - .round_rate = clk_div_round_rate,
> - .set_rate = clk_div_set_rate,
> -};
> -
> -struct clk *mxs_clk_div(const char *name, const char *parent_name,
> - void __iomem *reg, u8 shift, u8 width, u8 busy)
> -{
> - struct clk_div *div;
> - struct clk *clk;
> - struct clk_init_data init;
> -
> - div = kzalloc(sizeof(*div), GFP_KERNEL);
> - if (!div)
> - return ERR_PTR(-ENOMEM);
> -
> - init.name = name;
> - init.ops = &clk_div_ops;
> - init.flags = CLK_SET_RATE_PARENT;
> - init.parent_names = (parent_name ? &parent_name: NULL);
> - init.num_parents = (parent_name ? 1 : 0);
> -
> - div->reg = reg;
> - div->busy = busy;
> -
> - div->divider.reg = reg;
> - div->divider.shift = shift;
> - div->divider.width = width;
> - div->divider.flags = CLK_DIVIDER_ONE_BASED;
> - div->divider.lock = &mxs_lock;
> - div->divider.hw.init = &init;
> - div->ops = &clk_divider_ops;
> -
> - clk = clk_register(NULL, &div->divider.hw);
> - if (IS_ERR(clk))
> - kfree(div);
> -
> - return clk;
> -}
> diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h
> index 81421e2..865f495 100644
> --- a/drivers/clk/mxs/clk.h
> +++ b/drivers/clk/mxs/clk.h
> @@ -29,9 +29,6 @@ struct clk *mxs_clk_pll(const char *name, const char *parent_name,
> struct clk *mxs_clk_ref(const char *name, const char *parent_name,
> void __iomem *reg, u8 idx);
>
> -struct clk *mxs_clk_div(const char *name, const char *parent_name,
> - void __iomem *reg, u8 shift, u8 width, u8 busy);
> -
> struct clk *mxs_clk_frac(const char *name, const char *parent_name,
> void __iomem *reg, u8 shift, u8 width, u8 busy);
>
> @@ -63,4 +60,13 @@ static inline struct clk *mxs_clk_fixed_factor(const char *name,
> CLK_SET_RATE_PARENT, mult, div);
> }
>
> +static inline struct clk *mxs_clk_div(const char *name,
> + const char *parent_name, void __iomem *reg, u8 shift,
> + u8 width, u8 busy)
> +{
> + return clk_register_divider_status(NULL, name, parent_name,
> + CLK_SET_RATE_PARENT, reg, shift, width,
> + CLK_DIVIDER_ONE_BASED, reg, busy, &mxs_lock);
> +}
> +
> #endif /* __MXS_CLK_H */
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 7f197d7..6309335 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -268,6 +268,27 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
> spinlock_t *lock);
>
> /**
> + * struct clk_divider_status - integer divider clock with additional status bit
> + * @divider: the parent class
> + * @ops: pointer to clk_ops of parent class
> + * @reg: register containing the divider status bit
> + * @busy: divider busy bit shift
> + *
> + * This clock is a subclass of basic clk_divider with an addtional busy bit.
> + */
> +struct clk_divider_status {
> + struct clk_divider divider;
> + const struct clk_ops *ops;
> + void __iomem *reg;
> + u8 busy;
> +};
> +
> +struct clk *clk_register_divider_status(struct device *dev, const char *name,
> + const char *parent_name, unsigned long flags, void __iomem *reg,
> + u8 shift, u8 width, u8 clk_divider_flags,
> + void __iomem *reg_status, u8 shift_status, spinlock_t *lock);
> +
> +/**
> * struct clk_mux - multiplexer clock
> *
> * @hw: handle between common and hardware-specific interfaces
> --
> 1.7.5.4
>
More information about the linux-arm-kernel
mailing list