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