[PATCH] clk: let mxs specific clk-div clock type be a generic clock type

Thomas Abraham thomas.abraham at linaro.org
Mon Mar 18 06:18:24 EDT 2013


On 18 March 2013 14:12, Shawn Guo <shawn.guo at linaro.org> wrote:
> 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

Thanks Shawn for your comments. I will split this patch as you
suggested and post again.

Thomas.

>
> 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