On 03/10/2012 01:54 AM, 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
One issue with spinlocks below, but otherwise:
Reviewed-by: Rob Herring rob.herring@calxeda.com
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);
What are you locking against? You are only reading the register.
- 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);
- 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;
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
goto out;
- }
- /*
* The maximum divider we can use without overflowing
* unsigned long in rate * i below
*/
- maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i++) {
int div;
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
rate * i);
div = parent_rate / rate;
div = div > maxdiv ? maxdiv : div;
div = div < 1 ? 1 : div;
now = parent_rate / div;
if (now <= rate && now >= best) {
bestdiv = div;
best = now;
*best_parent_rate = parent_rate;
}
- }
- if (!bestdiv) {
bestdiv = (1 << divider->width);
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
- } else {
parent_rate = best * bestdiv;
- }
+out:
- if (best_parent_rate)
*best_parent_rate = parent_rate;
- return bestdiv;
+}
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
+{
- unsigned long best_parent_rate;
- int div = clk_divider_bestdiv(hw, rate, &best_parent_rate);
- if (prate) {
if (best_parent_rate == __clk_get_rate(
__clk_get_parent(hw->clk)))
*prate = 0;
else
*prate = best_parent_rate;
- }
- return best_parent_rate / div;
+} +EXPORT_SYMBOL_GPL(clk_divider_round_rate);
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) +{
- unsigned long best_parent_rate;
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div;
- unsigned long flags = 0;
- u32 val;
- div = clk_divider_bestdiv(hw, rate, &best_parent_rate);
- if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
div--;
- val = readl(divider->reg);
- val &= ~(((1 << divider->width) - 1) << divider->shift);
- val |= div << divider->shift;
- writel(val, divider->reg);
- if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_divider_set_rate);
+struct clk_ops clk_divider_ops = {
- .recalc_rate = clk_divider_recalc_rate,
- .round_rate = clk_divider_round_rate,
- .set_rate = clk_divider_set_rate,
+}; +EXPORT_SYMBOL_GPL(clk_divider_ops);
+struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
+{
- struct clk_divider *div;
- struct clk *clk;
- div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
- if (!div) {
pr_err("%s: could not allocate divider clk\n", __func__);
return NULL;
- }
- /* struct clk_divider assignments */
- div->reg = reg;
- div->shift = shift;
- div->width = width;
- div->flags = clk_divider_flags;
- div->lock = lock;
- if (parent_name) {
div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
if (!div->parent[0])
goto out;
- }
- clk = clk_register(dev, name,
&clk_divider_ops, &div->hw,
div->parent,
(parent_name ? 1 : 0),
flags);
- if (clk)
return clk;
+out:
- kfree(div->parent[0]);
- kfree(div);
- return NULL;
+} diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c new file mode 100644 index 0000000..90c79fb --- /dev/null +++ b/drivers/clk/clk-fixed-rate.c @@ -0,0 +1,82 @@ +/*
- Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com
- 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.
- Fixed rate clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h>
+/*
- DOC: basic fixed-rate clock that cannot gate
- Traits of this clock:
- prepare - clk_(un)prepare only ensures parents are prepared
- enable - clk_enable only ensures parents are enabled
- rate - rate is always a fixed value. No clk_set_rate support
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
+static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- return to_clk_fixed_rate(hw)->fixed_rate;
+} +EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
+struct clk_ops clk_fixed_rate_ops = {
- .recalc_rate = clk_fixed_rate_recalc_rate,
+}; +EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate)
+{
- struct clk_fixed_rate *fixed;
- char **parent_names = NULL;
- u8 len;
- fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
- if (!fixed) {
pr_err("%s: could not allocate fixed clk\n", __func__);
return ERR_PTR(-ENOMEM);
- }
- /* struct clk_fixed_rate assignments */
- fixed->fixed_rate = fixed_rate;
- if (parent_name) {
parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
if (! parent_names)
goto out;
len = sizeof(char) * strlen(parent_name);
parent_names[0] = kmalloc(len, GFP_KERNEL);
if (!parent_names[0])
goto out;
strncpy(parent_names[0], parent_name, len);
- }
+out:
- return clk_register(dev, name,
&clk_fixed_rate_ops, &fixed->hw,
parent_names,
(parent_name ? 1 : 0),
flags);
+} diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c new file mode 100644 index 0000000..5d50efa --- /dev/null +++ b/drivers/clk/clk-gate.c @@ -0,0 +1,157 @@ +/*
- Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com
- 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.
- Gated 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 gatable clock which can gate and ungate it's ouput
- Traits of this clock:
- prepare - clk_(un)prepare only ensures parent is (un)prepared
- enable - clk_enable and clk_disable are functional & control gating
- rate - inherits rate from parent. No clk_set_rate support
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+static void clk_gate_set_bit(struct clk_gate *gate) +{
- u32 reg;
- unsigned long flags = 0;
- if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- reg |= BIT(gate->bit_idx);
- writel(reg, gate->reg);
- if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
+}
+static void clk_gate_clear_bit(struct clk_gate *gate) +{
- u32 reg;
- unsigned long flags = 0;
- if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- reg &= ~BIT(gate->bit_idx);
- writel(reg, gate->reg);
- if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
+}
+static int clk_gate_enable(struct clk_hw *hw) +{
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
clk_gate_clear_bit(gate);
- else
clk_gate_set_bit(gate);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_gate_enable);
+static void clk_gate_disable(struct clk_hw *hw) +{
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
clk_gate_set_bit(gate);
- else
clk_gate_clear_bit(gate);
+} +EXPORT_SYMBOL_GPL(clk_gate_disable);
+static int clk_gate_is_enabled(struct clk_hw *hw) +{
- u32 reg;
- unsigned long flags = 0;
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
ditto.
- /* if a set bit disables this clk, flip it before masking */
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
reg ^= BIT(gate->bit_idx);
- reg &= BIT(gate->bit_idx);
- return reg ? 1 : 0;
+} +EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
+struct clk_ops clk_gate_ops = {
- .enable = clk_gate_enable,
- .disable = clk_gate_disable,
- .is_enabled = clk_gate_is_enabled,
+}; +EXPORT_SYMBOL_GPL(clk_gate_ops);
+struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock)
+{
- struct clk_gate *gate;
- struct clk *clk;
- gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
- if (!gate) {
pr_err("%s: could not allocate gated clk\n", __func__);
return NULL;
- }
- /* struct clk_gate assignments */
- gate->reg = reg;
- gate->bit_idx = bit_idx;
- gate->flags = clk_gate_flags;
- gate->lock = lock;
- if (parent_name) {
gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
if (!gate->parent[0])
goto out;
- }
- clk = clk_register(dev, name,
&clk_gate_ops, &gate->hw,
gate->parent,
(parent_name ? 1 : 0),
flags);
- if (clk)
return clk;
+out:
- kfree(gate->parent[0]);
- kfree(gate);
- return NULL;
+} diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c new file mode 100644 index 0000000..6fc0878 --- /dev/null +++ b/drivers/clk/clk-mux.c @@ -0,0 +1,123 @@ +/*
- 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.
- Simple multiplexer clock implementation
- */
+#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h>
+/*
- DOC: basic adjustable multiplexer 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 only affected by parent switching. No clk_set_rate support
- parent - parent is adjustable through clk_set_parent
- */
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+static u8 clk_mux_get_parent(struct clk_hw *hw) +{
- struct clk_mux *mux = to_clk_mux(hw);
- u32 val;
- unsigned long flags = 0;
- if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
- /*
* FIXME need a mux-specific flag to determine if val is bitwise or numeric
* e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
* to 0x7 (index starts at one)
* OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
* val = 0x4 really means "bit 2, index starts at bit 0"
*/
- val = readl(mux->reg) >> mux->shift;
- val &= (1 << mux->width) - 1;
- if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
ditto
- if (val && (mux->flags & CLK_MUX_INDEX_BIT))
val = ffs(val) - 1;
- if (val && (mux->flags & CLK_MUX_INDEX_ONE))
val--;
- if (val >= __clk_get_num_parents(hw->clk))
return -EINVAL;
- return val;
+} +EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +{
- struct clk_mux *mux = to_clk_mux(hw);
- u32 val;
- unsigned long flags = 0;
- if (mux->flags & CLK_MUX_INDEX_BIT)
index = (1 << ffs(index));
- if (mux->flags & CLK_MUX_INDEX_ONE)
index++;
- if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
- val = readl(mux->reg);
- val &= ~(((1 << mux->width) - 1) << mux->shift);
- val |= index << mux->shift;
- writel(val, mux->reg);
- if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_mux_set_parent);
+struct clk_ops clk_mux_ops = {
- .get_parent = clk_mux_get_parent,
- .set_parent = clk_mux_set_parent,
+}; +EXPORT_SYMBOL_GPL(clk_mux_ops);
+struct clk *clk_register_mux(struct device *dev, const char *name,
char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock)
+{
- struct clk_mux *mux;
- mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
- if (!mux) {
pr_err("%s: could not allocate mux clk\n", __func__);
return ERR_PTR(-ENOMEM);
- }
- /* struct clk_mux assignments */
- mux->reg = reg;
- mux->shift = shift;
- mux->width = width;
- mux->flags = clk_mux_flags;
- mux->lock = lock;
- return clk_register(dev, name, &clk_mux_ops, &mux->hw,
parent_names, num_parents, flags);
+} diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 33bf6a7..9d5c4b1 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -45,6 +45,130 @@ struct clk { #endif }; +/*
- DOC: Basic clock implementations common to many platforms
- Each basic clock hardware type is comprised of a structure describing the
- clock hardware, implementations of the relevant callbacks in struct clk_ops,
- unique flags for that hardware type, a registration function and an
- alternative macro for static initialization
- */
+extern struct clk_ops clk_fixed_rate_ops;
+#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
_fixed_rate_flags) \
- static struct clk _name; \
- static char *_name##_parent_names[] = {}; \
- static struct clk_fixed_rate _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.fixed_rate = _rate, \
.flags = _fixed_rate_flags, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_fixed_rate_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _name##_parent_names, \
.num_parents = \
ARRAY_SIZE(_name##_parent_names), \
.flags = _flags, \
- };
+extern struct clk_ops clk_gate_ops;
+#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \
_flags, _reg, _bit_idx, \
_gate_flags, _lock) \
- static struct clk _name; \
- static char *_name##_parent_names[] = { \
_parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
_parent_ptr, \
- }; \
- static struct clk_gate _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.reg = _reg, \
.bit_idx = _bit_idx, \
.flags = _gate_flags, \
.lock = _lock, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_gate_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _name##_parent_names, \
.num_parents = \
ARRAY_SIZE(_name##_parent_names), \
.parents = _name##_parents, \
.flags = _flags, \
- };
+extern struct clk_ops clk_divider_ops;
+#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, _lock) \
- static struct clk _name; \
- static char *_name##_parent_names[] = { \
_parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
_parent_ptr, \
- }; \
- static struct clk_divider _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.reg = _reg, \
.shift = _shift, \
.width = _width, \
.flags = _divider_flags, \
.lock = _lock, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_divider_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _name##_parent_names, \
.num_parents = \
ARRAY_SIZE(_name##_parent_names), \
.parents = _name##_parents, \
.flags = _flags, \
- };
+extern struct clk_ops clk_mux_ops;
+#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
_reg, _shift, _width, \
_mux_flags, _lock) \
- static struct clk _name; \
- static struct clk_mux _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.reg = _reg, \
.shift = _shift, \
.width = _width, \
.flags = _mux_flags, \
.lock = _lock, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_mux_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_names, \
.num_parents = \
ARRAY_SIZE(_parent_names), \
.parents = _parents, \
.flags = _flags, \
- };
/**
- __clk_init - initialize the data structures in a struct clk
- @dev: device initializing this clk, placeholder for now
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 09dea1f..853d526 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -129,6 +129,133 @@ struct clk_ops { void (*init)(struct clk_hw *hw); }; +/*
- DOC: Basic clock implementations common to many platforms
- Each basic clock hardware type is comprised of a structure describing the
- clock hardware, implementations of the relevant callbacks in struct clk_ops,
- unique flags for that hardware type, a registration function and an
- alternative macro for static initialization
- */
+/**
- struct clk_fixed_rate - fixed-rate clock
- @hw: handle between common and hardware-specific interfaces
- @fixed_rate: constant frequency of clock
- */
+struct clk_fixed_rate {
- struct clk_hw hw;
- unsigned long fixed_rate;
- u8 flags;
+};
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate);
+/**
- struct clk_gate - gating clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register controlling gate
- @bit_idx: single bit controlling gate
- @flags: hardware-specific flags
- @lock: register lock
- Clock which can gate its output. Implements .enable & .disable
- Flags:
- CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to
- enable the clock. Setting this flag does the opposite: setting the bit
- disable the clock and clearing it enables the clock
- */
+struct clk_gate {
- struct clk_hw hw;
- void __iomem *reg;
- u8 bit_idx;
- u8 flags;
- spinlock_t *lock;
- char *parent[1];
+};
+#define CLK_GATE_SET_TO_DISABLE BIT(0)
+struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock);
+/**
- struct clk_divider - adjustable divider clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register containing the divider
- @shift: shift to the divider bit field
- @width: width of the divider bit field
- @lock: register lock
- Clock with an adjustable divider affecting its output frequency. Implements
- .recalc_rate, .set_rate and .round_rate
- Flags:
- CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
- register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is
- the raw value read from the register, with the value of zero considered
- invalid
- CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
- the hardware register
- */
+struct clk_divider {
- struct clk_hw hw;
- void __iomem *reg;
- u8 shift;
- u8 width;
- u8 flags;
- spinlock_t *lock;
- char *parent[1];
+};
+#define CLK_DIVIDER_ONE_BASED BIT(0) +#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
+struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock);
+/**
- struct clk_mux - multiplexer clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register controlling multiplexer
- @shift: shift to multiplexer bit field
- @width: width of mutliplexer bit field
- @num_clks: number of parent clocks
- @lock: register lock
- Clock with multiple selectable parents. Implements .get_parent, .set_parent
- and .recalc_rate
- Flags:
- CLK_MUX_INDEX_ONE - register index starts at 1, not 0
- CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two)
- */
+struct clk_mux {
- struct clk_hw hw;
- void __iomem *reg;
- u8 shift;
- u8 width;
- u8 flags;
- spinlock_t *lock;
+};
+#define CLK_MUX_INDEX_ONE BIT(0) +#define CLK_MUX_INDEX_BIT BIT(1)
+struct clk *clk_register_mux(struct device *dev, const char *name,
char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock);
/**
- clk_register - allocate a new clock, register it and return an opaque cookie