lkml.org 
[lkml]   [2012]   [Mar]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH v6 3/3] clk: basic clock hardware types
    On Fri, Mar 09, 2012 at 11:54:24PM -0800, Mike Turquette wrote:
    > Many platforms support simple gateable clocks, fixed-rate clocks,
    > adjustable divider clocks and multi-parent multiplexer clocks.
    >
    > This patch introduces basic clock types for the above-mentioned hardware
    > which share some common characteristics.
    >
    > Based on original work by Jeremy Kerr and contribution by Jamie Iles.
    > Dividers and multiplexor clocks originally contributed by Richard Zhao &
    > Sascha Hauer.
    >
    > Signed-off-by: Mike Turquette <mturquette@linaro.org>
    > Signed-off-by: Mike Turquette <mturquette@ti.com>
    > Cc: Russell King <linux@arm.linux.org.uk>
    > Cc: Jeremy Kerr <jeremy.kerr@canonical.com>
    > Cc: Thomas Gleixner <tglx@linutronix.de>
    > Cc: Arnd Bergman <arnd.bergmann@linaro.org>
    > Cc: Paul Walmsley <paul@pwsan.com>
    > Cc: Shawn Guo <shawn.guo@freescale.com>
    > Cc: Sascha Hauer <s.hauer@pengutronix.de>
    > Cc: Jamie Iles <jamie@jamieiles.com>
    > Cc: Richard Zhao <richard.zhao@linaro.org>
    > Cc: Saravana Kannan <skannan@codeaurora.org>
    > Cc: Magnus Damm <magnus.damm@gmail.com>
    > Cc: Rob Herring <rob.herring@calxeda.com>
    > Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
    > Cc: Linus Walleij <linus.walleij@stericsson.com>
    > Cc: Stephen Boyd <sboyd@codeaurora.org>
    > Cc: Amit Kucheria <amit.kucheria@linaro.org>
    > Cc: Deepak Saxena <dsaxena@linaro.org>
    > Cc: Grant Likely <grant.likely@secretlab.ca>
    > Cc: Andrew Lunn <andrew@lunn.ch>
    > ---
    > Changes since v5:
    > * standardized the hw-specific locking in the basic clock types
    > * export the individual ops for each basic clock type
    > * improve registration for single-parent basic clocks (thanks Sascha)
    > * fixed bugs in gate clock's static initializers (thanks Andrew)
    >
    > drivers/clk/Makefile | 3 +-
    > drivers/clk/clk-divider.c | 204 ++++++++++++++++++++++++++++++++++++++++++
    > drivers/clk/clk-fixed-rate.c | 82 +++++++++++++++++
    > drivers/clk/clk-gate.c | 157 ++++++++++++++++++++++++++++++++
    > drivers/clk/clk-mux.c | 123 +++++++++++++++++++++++++
    > include/linux/clk-private.h | 124 +++++++++++++++++++++++++
    > include/linux/clk-provider.h | 127 ++++++++++++++++++++++++++
    > 7 files changed, 819 insertions(+), 1 deletions(-)
    > create mode 100644 drivers/clk/clk-divider.c
    > create mode 100644 drivers/clk/clk-fixed-rate.c
    > create mode 100644 drivers/clk/clk-gate.c
    > create mode 100644 drivers/clk/clk-mux.c
    >
    > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
    > index ff362c4..1f736bc 100644
    > --- a/drivers/clk/Makefile
    > +++ b/drivers/clk/Makefile
    > @@ -1,3 +1,4 @@
    >
    > obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
    > -obj-$(CONFIG_COMMON_CLK) += clk.o
    > +obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
    > + clk-mux.o clk-divider.o
    > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
    > new file mode 100644
    > index 0000000..c0c4e0b
    > --- /dev/null
    > +++ b/drivers/clk/clk-divider.c
    > @@ -0,0 +1,204 @@
    > +/*
    > + * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
    > + * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
    > + * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
    > + *
    > + * This program is free software; you can redistribute it and/or modify
    > + * it under the terms of the GNU General Public License version 2 as
    > + * published by the Free Software Foundation.
    > + *
    > + * Adjustable divider clock implementation
    > + */
    > +
    > +#include <linux/clk-provider.h>
    > +#include <linux/module.h>
    > +#include <linux/slab.h>
    > +#include <linux/io.h>
    > +#include <linux/err.h>
    > +#include <linux/string.h>
    > +
    > +/*
    > + * DOC: basic adjustable divider clock that cannot gate
    > + *
    > + * 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
    > + */
    > +
    > +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
    > +
    > +static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
    > + unsigned long parent_rate)
    > +{
    > + struct clk_divider *divider = to_clk_divider(hw);
    > + unsigned int div;
    > + unsigned long flags = 0;
    > +
    > + if (divider->lock)
    > + spin_lock_irqsave(divider->lock, flags);
    > +
    > + div = readl(divider->reg) >> divider->shift;
    > + div &= (1 << divider->width) - 1;
    > +
    > + if (divider->lock)
    > + spin_unlock_irqrestore(divider->lock, flags);
    > +
    > + if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
    > + div++;
    > +
    > + return parent_rate / div;
    > +}
    > +EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
    > +
    > +static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
    > + unsigned long *best_parent_rate)
    > +{
    > + struct clk_divider *divider = to_clk_divider(hw);
    > + int i, bestdiv = 0;
    > + unsigned long parent_rate, best = 0, now, maxdiv;
    > +
    > + maxdiv = (1 << divider->width);

    We need a check for rate == 0 here:

    if (rate == 0)
    rate = 1;

    Otherwise we divide by zero below.

    > +
    > + if (divider->flags & CLK_DIVIDER_ONE_BASED)
    > + maxdiv--;
    > +
    > + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
    > + parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
    > + bestdiv = parent_rate / rate;

    It's a bit strange but due to integer maths you must use DIV_ROUND_UP
    in round_rate and div = parent_rate / rate in set_rate.

    Example:

    parent_rate = 100
    rate = 34

    Now the best divider would be 3 (100/3 = 33), but the above
    results in 2. With DIV_ROUND_UP round_rate correctly returns
    33. Now when you use DIV_ROUND_UP in set_rate the resulting
    divider would be 4 which is wrong whereas 100/33 returns the correct
    result.

    Sascha

    --
    Pengutronix e.K. | |
    Industrial Linux Solutions | http://www.pengutronix.de/ |
    Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
    Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |


    \
     
     \ /
      Last update: 2012-03-14 19:27    [W:0.052 / U:33.944 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site