All of lore.kernel.org
 help / color / mirror / Atom feed
From: mturquette@linaro.org (Mike Turquette)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH V3 1/3] clk: ux500: Add support for sysctrl clocks
Date: Wed, 10 Apr 2013 11:29:10 -0700	[thread overview]
Message-ID: <20130410182910.14359.31168@quantum> (raw)
In-Reply-To: <CAPDyKFqM+638Q2FRFHu7pLw+MQSvT0yZp7v6dQeYN9gRY4c+aA@mail.gmail.com>

Quoting Ulf Hansson (2013-04-10 01:02:53)
> On 9 April 2013 03:14, Mike Turquette <mturquette@linaro.org> wrote:
> > Quoting Ulf Hansson (2013-04-03 05:26:57)
> >> From: Ulf Hansson <ulf.hansson@linaro.org>
> >>
> >> The abx500 sysctrl clocks are using the ab8500 sysctrl driver to
> >> modify the clock hardware. Sysctrl clocks are represented by a
> >> ab8500 sysctrl register and with a corresponding bitmask.
> >>
> >> The sysctrl clocks are slow path clocks, which means clk_prepare
> >> and clk_unprepare will be used to gate|ungate these clocks.
> >>
> >> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> >
> > Hi Ulf,
> >
> > Is there a V3 update for patches #2 & #3?  I can't seem to find them.
> 
> Hi Mike,
> 
> Only v3 exist for this patch. Sorry if it was a bit unclear.
> 

Taken into clk-next.

Regards,
Mike

> Kind regards
> Uffe
> 
> >
> > Regards,
> > Mike
> >
> >> ---
> >>
> >> Changes in v3:
> >>         - Fixed error check at clk registration.
> >> Changes in v2:
> >>         - Removed wrong header file.
> >> ---
> >>  drivers/clk/ux500/Makefile      |    1 +
> >>  drivers/clk/ux500/clk-sysctrl.c |  221 +++++++++++++++++++++++++++++++++++++++
> >>  drivers/clk/ux500/clk.h         |   29 +++++
> >>  3 files changed, 251 insertions(+)
> >>  create mode 100644 drivers/clk/ux500/clk-sysctrl.c
> >>
> >> diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile
> >> index bcc0c11..c6a806e 100644
> >> --- a/drivers/clk/ux500/Makefile
> >> +++ b/drivers/clk/ux500/Makefile
> >> @@ -5,6 +5,7 @@
> >>  # Clock types
> >>  obj-y += clk-prcc.o
> >>  obj-y += clk-prcmu.o
> >> +obj-y += clk-sysctrl.o
> >>
> >>  # Clock definitions
> >>  obj-y += u8500_clk.o
> >> diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c
> >> new file mode 100644
> >> index 0000000..bc7e9bd
> >> --- /dev/null
> >> +++ b/drivers/clk/ux500/clk-sysctrl.c
> >> @@ -0,0 +1,221 @@
> >> +/*
> >> + * Sysctrl clock implementation for ux500 platform.
> >> + *
> >> + * Copyright (C) 2013 ST-Ericsson SA
> >> + * Author: Ulf Hansson <ulf.hansson@linaro.org>
> >> + *
> >> + * License terms: GNU General Public License (GPL) version 2
> >> + */
> >> +
> >> +#include <linux/clk-provider.h>
> >> +#include <linux/mfd/abx500/ab8500-sysctrl.h>
> >> +#include <linux/device.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/delay.h>
> >> +#include <linux/io.h>
> >> +#include <linux/err.h>
> >> +#include "clk.h"
> >> +
> >> +#define SYSCTRL_MAX_NUM_PARENTS 4
> >> +
> >> +#define to_clk_sysctrl(_hw) container_of(_hw, struct clk_sysctrl, hw)
> >> +
> >> +struct clk_sysctrl {
> >> +       struct clk_hw hw;
> >> +       struct device *dev;
> >> +       u8 parent_index;
> >> +       u16 reg_sel[SYSCTRL_MAX_NUM_PARENTS];
> >> +       u8 reg_mask[SYSCTRL_MAX_NUM_PARENTS];
> >> +       u8 reg_bits[SYSCTRL_MAX_NUM_PARENTS];
> >> +       unsigned long rate;
> >> +       unsigned long enable_delay_us;
> >> +};
> >> +
> >> +/* Sysctrl clock operations. */
> >> +
> >> +static int clk_sysctrl_prepare(struct clk_hw *hw)
> >> +{
> >> +       int ret;
> >> +       struct clk_sysctrl *clk = to_clk_sysctrl(hw);
> >> +
> >> +       ret = ab8500_sysctrl_write(clk->reg_sel[0], clk->reg_mask[0],
> >> +                               clk->reg_bits[0]);
> >> +
> >> +       if (!ret && clk->enable_delay_us)
> >> +               usleep_range(clk->enable_delay_us, clk->enable_delay_us);
> >> +
> >> +       return ret;
> >> +}
> >> +
> >> +static void clk_sysctrl_unprepare(struct clk_hw *hw)
> >> +{
> >> +       struct clk_sysctrl *clk = to_clk_sysctrl(hw);
> >> +       if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0]))
> >> +               dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n",
> >> +                       __func__, __clk_get_name(hw->clk));
> >> +}
> >> +
> >> +static unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw,
> >> +                                       unsigned long parent_rate)
> >> +{
> >> +       struct clk_sysctrl *clk = to_clk_sysctrl(hw);
> >> +       return clk->rate;
> >> +}
> >> +
> >> +static int clk_sysctrl_set_parent(struct clk_hw *hw, u8 index)
> >> +{
> >> +       struct clk_sysctrl *clk = to_clk_sysctrl(hw);
> >> +       u8 old_index = clk->parent_index;
> >> +       int ret = 0;
> >> +
> >> +       if (clk->reg_sel[old_index]) {
> >> +               ret = ab8500_sysctrl_clear(clk->reg_sel[old_index],
> >> +                                       clk->reg_mask[old_index]);
> >> +               if (ret)
> >> +                       return ret;
> >> +       }
> >> +
> >> +       if (clk->reg_sel[index]) {
> >> +               ret = ab8500_sysctrl_write(clk->reg_sel[index],
> >> +                                       clk->reg_mask[index],
> >> +                                       clk->reg_bits[index]);
> >> +               if (ret) {
> >> +                       if (clk->reg_sel[old_index])
> >> +                               ab8500_sysctrl_write(clk->reg_sel[old_index],
> >> +                                               clk->reg_mask[old_index],
> >> +                                               clk->reg_bits[old_index]);
> >> +                       return ret;
> >> +               }
> >> +       }
> >> +       clk->parent_index = index;
> >> +
> >> +       return ret;
> >> +}
> >> +
> >> +static u8 clk_sysctrl_get_parent(struct clk_hw *hw)
> >> +{
> >> +       struct clk_sysctrl *clk = to_clk_sysctrl(hw);
> >> +       return clk->parent_index;
> >> +}
> >> +
> >> +static struct clk_ops clk_sysctrl_gate_ops = {
> >> +       .prepare = clk_sysctrl_prepare,
> >> +       .unprepare = clk_sysctrl_unprepare,
> >> +};
> >> +
> >> +static struct clk_ops clk_sysctrl_gate_fixed_rate_ops = {
> >> +       .prepare = clk_sysctrl_prepare,
> >> +       .unprepare = clk_sysctrl_unprepare,
> >> +       .recalc_rate = clk_sysctrl_recalc_rate,
> >> +};
> >> +
> >> +static struct clk_ops clk_sysctrl_set_parent_ops = {
> >> +       .set_parent = clk_sysctrl_set_parent,
> >> +       .get_parent = clk_sysctrl_get_parent,
> >> +};
> >> +
> >> +static struct clk *clk_reg_sysctrl(struct device *dev,
> >> +                               const char *name,
> >> +                               const char **parent_names,
> >> +                               u8 num_parents,
> >> +                               u16 *reg_sel,
> >> +                               u8 *reg_mask,
> >> +                               u8 *reg_bits,
> >> +                               unsigned long rate,
> >> +                               unsigned long enable_delay_us,
> >> +                               unsigned long flags,
> >> +                               struct clk_ops *clk_sysctrl_ops)
> >> +{
> >> +       struct clk_sysctrl *clk;
> >> +       struct clk_init_data clk_sysctrl_init;
> >> +       struct clk *clk_reg;
> >> +       int i;
> >> +
> >> +       if (!dev)
> >> +               return ERR_PTR(-EINVAL);
> >> +
> >> +       if (!name || (num_parents > SYSCTRL_MAX_NUM_PARENTS)) {
> >> +               dev_err(dev, "clk_sysctrl: invalid arguments passed\n");
> >> +               return ERR_PTR(-EINVAL);
> >> +       }
> >> +
> >> +       clk = devm_kzalloc(dev, sizeof(struct clk_sysctrl), GFP_KERNEL);
> >> +       if (!clk) {
> >> +               dev_err(dev, "clk_sysctrl: could not allocate clk\n");
> >> +               return ERR_PTR(-ENOMEM);
> >> +       }
> >> +
> >> +       for (i = 0; i < num_parents; i++) {
> >> +               clk->reg_sel[i] = reg_sel[i];
> >> +               clk->reg_bits[i] = reg_bits[i];
> >> +               clk->reg_mask[i] = reg_mask[i];
> >> +       }
> >> +
> >> +       clk->parent_index = 0;
> >> +       clk->rate = rate;
> >> +       clk->enable_delay_us = enable_delay_us;
> >> +       clk->dev = dev;
> >> +
> >> +       clk_sysctrl_init.name = name;
> >> +       clk_sysctrl_init.ops = clk_sysctrl_ops;
> >> +       clk_sysctrl_init.flags = flags;
> >> +       clk_sysctrl_init.parent_names = parent_names;
> >> +       clk_sysctrl_init.num_parents = num_parents;
> >> +       clk->hw.init = &clk_sysctrl_init;
> >> +
> >> +       clk_reg = devm_clk_register(clk->dev, &clk->hw);
> >> +       if (IS_ERR(clk_reg))
> >> +               dev_err(dev, "clk_sysctrl: clk_register failed\n");
> >> +
> >> +       return clk_reg;
> >> +}
> >> +
> >> +struct clk *clk_reg_sysctrl_gate(struct device *dev,
> >> +                               const char *name,
> >> +                               const char *parent_name,
> >> +                               u16 reg_sel,
> >> +                               u8 reg_mask,
> >> +                               u8 reg_bits,
> >> +                               unsigned long enable_delay_us,
> >> +                               unsigned long flags)
> >> +{
> >> +       const char **parent_names = (parent_name ? &parent_name : NULL);
> >> +       u8 num_parents = (parent_name ? 1 : 0);
> >> +
> >> +       return clk_reg_sysctrl(dev, name, parent_names, num_parents,
> >> +                       &reg_sel, &reg_mask, &reg_bits, 0, enable_delay_us,
> >> +                       flags, &clk_sysctrl_gate_ops);
> >> +}
> >> +
> >> +struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev,
> >> +                                       const char *name,
> >> +                                       const char *parent_name,
> >> +                                       u16 reg_sel,
> >> +                                       u8 reg_mask,
> >> +                                       u8 reg_bits,
> >> +                                       unsigned long rate,
> >> +                                       unsigned long enable_delay_us,
> >> +                                       unsigned long flags)
> >> +{
> >> +       const char **parent_names = (parent_name ? &parent_name : NULL);
> >> +       u8 num_parents = (parent_name ? 1 : 0);
> >> +
> >> +       return clk_reg_sysctrl(dev, name, parent_names, num_parents,
> >> +                       &reg_sel, &reg_mask, &reg_bits,
> >> +                       rate, enable_delay_us, flags,
> >> +                       &clk_sysctrl_gate_fixed_rate_ops);
> >> +}
> >> +
> >> +struct clk *clk_reg_sysctrl_set_parent(struct device *dev,
> >> +                               const char *name,
> >> +                               const char **parent_names,
> >> +                               u8 num_parents,
> >> +                               u16 *reg_sel,
> >> +                               u8 *reg_mask,
> >> +                               u8 *reg_bits,
> >> +                               unsigned long flags)
> >> +{
> >> +       return clk_reg_sysctrl(dev, name, parent_names, num_parents,
> >> +                       reg_sel, reg_mask, reg_bits, 0, 0, flags,
> >> +                       &clk_sysctrl_set_parent_ops);
> >> +}
> >> diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h
> >> index c3e4491..3d2dfdc 100644
> >> --- a/drivers/clk/ux500/clk.h
> >> +++ b/drivers/clk/ux500/clk.h
> >> @@ -11,6 +11,7 @@
> >>  #define __UX500_CLK_H
> >>
> >>  #include <linux/clk.h>
> >> +#include <linux/device.h>
> >>
> >>  struct clk *clk_reg_prcc_pclk(const char *name,
> >>                               const char *parent_name,
> >> @@ -57,4 +58,32 @@ struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
> >>                                             unsigned long rate,
> >>                                             unsigned long flags);
> >>
> >> +struct clk *clk_reg_sysctrl_gate(struct device *dev,
> >> +                                const char *name,
> >> +                                const char *parent_name,
> >> +                                u16 reg_sel,
> >> +                                u8 reg_mask,
> >> +                                u8 reg_bits,
> >> +                                unsigned long enable_delay_us,
> >> +                                unsigned long flags);
> >> +
> >> +struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev,
> >> +                                           const char *name,
> >> +                                           const char *parent_name,
> >> +                                           u16 reg_sel,
> >> +                                           u8 reg_mask,
> >> +                                           u8 reg_bits,
> >> +                                           unsigned long rate,
> >> +                                           unsigned long enable_delay_us,
> >> +                                           unsigned long flags);
> >> +
> >> +struct clk *clk_reg_sysctrl_set_parent(struct device *dev,
> >> +                                      const char *name,
> >> +                                      const char **parent_names,
> >> +                                      u8 num_parents,
> >> +                                      u16 *reg_sel,
> >> +                                      u8 *reg_mask,
> >> +                                      u8 *reg_bits,
> >> +                                      unsigned long flags);
> >> +
> >>  #endif /* __UX500_CLK_H */
> >> --
> >> 1.7.10

      reply	other threads:[~2013-04-10 18:29 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-03 12:26 [PATCH V3 1/3] clk: ux500: Add support for sysctrl clocks Ulf Hansson
2013-04-09  1:14 ` Mike Turquette
2013-04-10  8:02   ` Ulf Hansson
2013-04-10 18:29     ` Mike Turquette [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20130410182910.14359.31168@quantum \
    --to=mturquette@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.