Commit bef94596 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge branch 'depends/clk/clk-next' into next/clock

Mike Turquette <mturquette@ti.com> has asked me to take the clock
changes through the arm-soc tree while there are still so many
inderdependencies, so this is the entire branch.

* depends/clk/clk-next: (30 commits)
  clk: add a fixed factor clock
  clk: mux: assign init data
  clk: remove COMMON_CLK_DISABLE_UNUSED
  clk: prevent spurious parent rate propagation
  MAINTAINERS: add entry for common clk framework
  clk: clk_set_rate() must fail if CLK_SET_RATE_GATE is set and clk is enabled
  clk: Use a separate struct for holding init data.
  clk: constify parent name arrays in macros
  clk: remove trailing whitespace from clk.h
  clk: select CLKDEV_LOOKUP for COMMON_CLK
  clk: Don't set clk->new_rate twice
  clk: clk-private: Add DEFINE_CLK macro
  clk: clk-gate: Create clk_gate_endisable()
  clk: Fix typo in comment
  clk: propagate round_rate for CLK_SET_RATE_PARENT case
  clk: pass parent_rate into .set_rate
  clk: always pass parent_rate into .round_rate
  clk: basic: improve parent_names & return errors
  clk: core: copy parent_names & return error codes
  clk: Constify parent name arrays
  ...
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 66f75a5d f0948f59
......@@ -1882,6 +1882,16 @@ F: Documentation/filesystems/coda.txt
F: fs/coda/
F: include/linux/coda*.h
COMMON CLK FRAMEWORK
M: Mike Turquette <mturquette@ti.com>
M: Mike Turquette <mturquette@linaro.org>
L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV)
T: git git://git.linaro.org/people/mturquette/linux.git
S: Maintained
F: drivers/clk/clk.c
F: drivers/clk/clk-*
F: include/linux/clk-pr*
COMMON INTERNET FILE SYSTEM (CIFS)
M: Steve French <sfrench@samba.org>
L: linux-cifs@vger.kernel.org
......
......@@ -12,6 +12,7 @@ config HAVE_MACH_CLKDEV
config COMMON_CLK
bool
select HAVE_CLK_PREPARE
select CLKDEV_LOOKUP
---help---
The common clock framework is a single definition of struct
clk, useful across many platforms, as well as an
......@@ -22,17 +23,6 @@ config COMMON_CLK
menu "Common Clock Framework"
depends on COMMON_CLK
config COMMON_CLK_DISABLE_UNUSED
bool "Disabled unused clocks at boot"
depends on COMMON_CLK
---help---
Traverses the entire clock tree and disables any clocks that are
enabled in hardware but have not been enabled by any device drivers.
This saves power and keeps the software model of the clock in line
with reality.
If in doubt, say "N".
config COMMON_CLK_DEBUG
bool "DebugFS representation of clock tree"
depends on COMMON_CLK
......
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
clk-mux.o clk-divider.o
clk-mux.o clk-divider.o clk-fixed-factor.o
......@@ -45,7 +45,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
return parent_rate / div;
}
EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
/*
* The reverse of DIV_ROUND_UP: The maximum number which
......@@ -68,8 +67,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (divider->flags & CLK_DIVIDER_ONE_BASED)
maxdiv--;
if (!best_parent_rate) {
parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
bestdiv = DIV_ROUND_UP(parent_rate, rate);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
......@@ -109,24 +108,18 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
int div;
div = clk_divider_bestdiv(hw, rate, prate);
if (prate)
return *prate / div;
else {
unsigned long r;
r = __clk_get_rate(__clk_get_parent(hw->clk));
return r / div;
}
return *prate / div;
}
EXPORT_SYMBOL_GPL(clk_divider_round_rate);
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
unsigned int div;
unsigned long flags = 0;
u32 val;
div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate;
div = parent_rate / rate;
if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
div--;
......@@ -147,15 +140,26 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
return 0;
}
EXPORT_SYMBOL_GPL(clk_divider_set_rate);
struct clk_ops clk_divider_ops = {
const 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);
/**
* clk_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
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,
......@@ -163,38 +167,34 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
{
struct clk_divider *div;
struct clk *clk;
struct clk_init_data init;
/* allocate the divider */
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
if (!div) {
pr_err("%s: could not allocate divider clk\n", __func__);
return NULL;
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &clk_divider_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
/* struct clk_divider assignments */
div->reg = reg;
div->shift = shift;
div->width = width;
div->flags = clk_divider_flags;
div->lock = lock;
div->hw.init = &init;
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;
/* register the clock */
clk = clk_register(dev, &div->hw);
out:
kfree(div->parent[0]);
kfree(div);
if (IS_ERR(clk))
kfree(div);
return NULL;
return clk;
}
/*
* Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
*
* 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.
*
* Standard functionality for the common clock API.
*/
#include <linux/module.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/err.h>
/*
* DOC: basic fixed multiplier and 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 fixed. clk->rate = parent->rate / div * mult
* parent - fixed parent. No clk_set_parent support
*/
#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw)
static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
return parent_rate * fix->mult / fix->div;
}
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
unsigned long best_parent;
best_parent = (rate / fix->mult) * fix->div;
*prate = __clk_round_rate(__clk_get_parent(hw->clk),
best_parent);
}
return (*prate / fix->div) * fix->mult;
}
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
return 0;
}
struct clk_ops clk_fixed_factor_ops = {
.round_rate = clk_factor_round_rate,
.set_rate = clk_factor_set_rate,
.recalc_rate = clk_factor_recalc_rate,
};
EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
{
struct clk_fixed_factor *fix;
struct clk_init_data init;
struct clk *clk;
fix = kmalloc(sizeof(*fix), GFP_KERNEL);
if (!fix) {
pr_err("%s: could not allocate fixed factor clk\n", __func__);
return ERR_PTR(-ENOMEM);
}
/* struct clk_fixed_factor assignments */
fix->mult = mult;
fix->div = div;
fix->hw.init = &init;
init.name = name;
init.ops = &clk_fixed_factor_ops;
init.flags = flags;
init.parent_names = &parent_name;
init.num_parents = 1;
clk = clk_register(dev, &fix->hw);
if (IS_ERR(clk))
kfree(fix);
return clk;
}
......@@ -32,51 +32,50 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
{
return to_clk_fixed_rate(hw)->fixed_rate;
}
EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
struct clk_ops clk_fixed_rate_ops = {
const struct clk_ops clk_fixed_rate_ops = {
.recalc_rate = clk_fixed_rate_recalc_rate,
};
EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
/**
* clk_register_fixed_rate - register fixed-rate clock with the clock framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @fixed_rate: non-adjustable clock rate
*/
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;
struct clk *clk;
struct clk_init_data init;
/* allocate fixed-rate clock */
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);
}
init.name = name;
init.ops = &clk_fixed_rate_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
/* struct clk_fixed_rate assignments */
fixed->fixed_rate = fixed_rate;
fixed->hw.init = &init;
if (parent_name) {
parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
if (! parent_names)
goto out;
/* register the clock */
clk = clk_register(dev, &fixed->hw);
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);
}
if (IS_ERR(clk))
kfree(fixed);
out:
return clk_register(dev, name,
&clk_fixed_rate_ops, &fixed->hw,
parent_names,
(parent_name ? 1 : 0),
flags);
return clk;
}
......@@ -28,32 +28,38 @@
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
static void clk_gate_set_bit(struct clk_gate *gate)
/*
* It works on following logic:
*
* For enabling clock, enable = 1
* set2dis = 1 -> clear bit -> set = 0
* set2dis = 0 -> set bit -> set = 1
*
* For disabling clock, enable = 0
* set2dis = 1 -> set bit -> set = 1
* set2dis = 0 -> clear bit -> set = 0
*
* So, result is always: enable xor set2dis.
*/
static void clk_gate_endisable(struct clk_hw *hw, int enable)
{
u32 reg;
struct clk_gate *gate = to_clk_gate(hw);
int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
unsigned long flags = 0;
u32 reg;
set ^= enable;
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);
if (set)
reg |= BIT(gate->bit_idx);
else
reg &= ~BIT(gate->bit_idx);
reg = readl(gate->reg);
reg &= ~BIT(gate->bit_idx);
writel(reg, gate->reg);
if (gate->lock)
......@@ -62,27 +68,15 @@ static void clk_gate_clear_bit(struct clk_gate *gate)
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);
clk_gate_endisable(hw, 1);
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);
clk_gate_endisable(hw, 0);
}
EXPORT_SYMBOL_GPL(clk_gate_disable);
static int clk_gate_is_enabled(struct clk_hw *hw)
{
......@@ -99,15 +93,25 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
return reg ? 1 : 0;
}
EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
struct clk_ops clk_gate_ops = {
const 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);
/**
* clk_register_gate - register a gate clock with the clock framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of this clock's parent
* @flags: framework-specific flags for this clock
* @reg: register address to control gating of this clock
* @bit_idx: which bit in the register controls gating of this clock
* @clk_gate_flags: gate-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
......@@ -115,36 +119,32 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
{
struct clk_gate *gate;
struct clk *clk;
struct clk_init_data init;
/* allocate the gate */
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
if (!gate) {
pr_err("%s: could not allocate gated clk\n", __func__);
return NULL;
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &clk_gate_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
/* struct clk_gate assignments */
gate->reg = reg;
gate->bit_idx = bit_idx;
gate->flags = clk_gate_flags;
gate->lock = lock;
gate->hw.init = &init;
if (parent_name) {
gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
if (!gate->parent[0])
goto out;
}
clk = clk_register(dev, &gate->hw);
if (IS_ERR(clk))
kfree(gate);
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;
return clk;
}
......@@ -55,7 +55,6 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
return val;
}
EXPORT_SYMBOL_GPL(clk_mux_get_parent);
static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
......@@ -82,35 +81,47 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
return 0;
}
EXPORT_SYMBOL_GPL(clk_mux_set_parent);
struct clk_ops clk_mux_ops = {
const 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,
const 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;
struct clk *clk;
struct clk_init_data init;
mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
/* allocate the mux */
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
if (!mux) {
pr_err("%s: could not allocate mux clk\n", __func__);
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &clk_mux_ops;
init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
/* struct clk_mux assignments */
mux->reg = reg;
mux->shift = shift;
mux->width = width;
mux->flags = clk_mux_flags;
mux->lock = lock;
mux->hw.init = &init;
clk = clk_register(dev, &mux->hw);
if (IS_ERR(clk))
kfree(mux);
return clk_register(dev, name, &clk_mux_ops, &mux->hw,
parent_names, num_parents, flags);
return clk;
}
This diff is collapsed.
......@@ -30,7 +30,7 @@ struct clk {
const struct clk_ops *ops;
struct clk_hw *hw;
struct clk *parent;
char **parent_names;
const char **parent_names;
struct clk **parents;
u8 num_parents;
unsigned long rate;
......@@ -55,12 +55,22 @@ struct clk {
* alternative macro for static initialization
*/
extern struct clk_ops clk_fixed_rate_ops;
#define DEFINE_CLK(_name, _ops, _flags, _parent_names, \
_parents) \
static struct clk _name = { \
.name = #_name, \
.ops = &_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_names, \
.num_parents = ARRAY_SIZE(_parent_names), \
.parents = _parents, \
.flags = _flags, \
}
#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
_fixed_rate_flags) \
static struct clk _name; \
static char *_name##_parent_names[] = {}; \
static const char *_name##_parent_names[] = {}; \
static struct clk_fixed_rate _name##_hw = { \
.hw = { \
.clk = &_name, \
......@@ -68,23 +78,14 @@ extern struct clk_ops clk_fixed_rate_ops;
.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_CLK(_name, clk_fixed_rate_ops, _flags, \
_name##_parent_names, NULL);
#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[] = { \
static const char *_name##_parent_names[] = { \
_parent_name, \
}; \
static struct clk *_name##_parents[] = { \
......@@ -99,24 +100,14 @@ extern struct clk_ops clk_gate_ops;
.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_CLK(_name, clk_gate_ops, _flags, \
_name##_parent_names, _name##_parents);
#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[] = { \
static const char *_name##_parent_names[] = { \
_parent_name, \
}; \
static struct clk *_name##_parents[] = { \
......@@ -132,18 +123,8 @@ extern struct clk_ops clk_divider_ops;
.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_CLK(_name, clk_divider_ops, _flags, \
_name##_parent_names, _name##_parents);
#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
_reg, _shift, _width, \
......@@ -159,16 +140,28 @@ extern struct clk_ops clk_mux_ops;
.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, \
};
DEFINE_CLK(_name, clk_mux_ops, _flags, _parent_names, \
_parents);
#define DEFINE_CLK_FIXED_FACTOR(_name, _parent_name, \
_parent_ptr, _flags, \
_mult, _div) \
static struct clk _name; \
static const char *_name##_parent_names[] = { \
_parent_name, \
}; \
static struct clk *_name##_parents[] = { \
_parent_ptr, \
}; \
static struct clk_fixed_factor _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.mult = _mult, \
.div = _div, \
}; \
DEFINE_CLK(_name, clk_fixed_factor_ops, _flags, \
_name##_parent_names, _name##_parents);
/**
* __clk_init - initialize the data structures in a struct clk
......@@ -189,8 +182,12 @@ extern struct clk_ops clk_mux_ops;
*
* It is not necessary to call clk_register if __clk_init is used directly with
* statically initialized clock data.
*
* Returns 0 on success, otherwise an error code.
*/
void __clk_init(struct device *dev, struct clk *clk);
int __clk_init(struct device *dev, struct clk *clk);
struct clk *__clk_register(struct device *dev, struct clk_hw *hw);
#endif /* CONFIG_COMMON_CLK */
#endif /* CLK_PRIVATE_H */
......@@ -15,19 +15,6 @@
#ifdef CONFIG_COMMON_CLK
/**
* struct clk_hw - handle for traversing from a struct clk to its corresponding
* hardware-specific structure. struct clk_hw should be declared within struct
* clk_foo and then referenced by the struct clk instance that uses struct
* clk_foo's clk_ops
*
* clk: pointer to the struct clk instance that points back to this struct
* clk_hw instance
*/
struct clk_hw {
struct clk *clk;
};
/*
* flags used across common struct clk. these flags should only affect the
* top-level framework. custom flags for dealing with hardware specifics
......@@ -39,6 +26,8 @@ struct clk_hw {
#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
#define CLK_IS_ROOT BIT(4) /* root clk, has no parent */
struct clk_hw;
/**
* struct clk_ops - Callback operations for hardware clocks; these are to
* be provided by the clock implementation, and will be called by drivers
......@@ -88,19 +77,11 @@ struct clk_hw {
* array index into the value programmed into the hardware.
* Returns 0 on success, -EERROR otherwise.
*
* @set_rate: Change the rate of this clock. If this callback returns
* CLK_SET_RATE_PARENT, the rate change will be propagated to the
* parent clock (which may propagate again if the parent clock
* also sets this flag). The requested rate of the parent is
* passed back from the callback in the second 'unsigned long *'
* argument. Note that it is up to the hardware clock's set_rate
* implementation to insure that clocks do not run out of spec
* when propgating the call to set_rate up to the parent. One way
* to do this is to gate the clock (via clk_disable and/or
* clk_unprepare) before calling clk_set_rate, then ungating it
* afterward. If your clock also has the CLK_GATE_SET_RATE flag
* set then this will insure safety. Returns 0 on success,
* -EERROR otherwise.
* @set_rate: Change the rate of this clock. The requested rate is specified
* by the second argument, which should typically be the return
* of .round_rate call. The third argument gives the parent rate
* which is likely helpful for most .set_rate implementation.
* Returns 0 on success, -EERROR otherwise.
*
* The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
* implementations to split any work between atomic (enable) and sleepable
......@@ -125,10 +106,46 @@ struct clk_ops {
unsigned long *);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long);
int (*set_rate)(struct clk_hw *hw, unsigned long,
unsigned long);
void (*init)(struct clk_hw *hw);
};
/**
* struct clk_init_data - holds init data that's common to all clocks and is
* shared between the clock provider and the common clock framework.
*
* @name: clock name
* @ops: operations this clock supports
* @parent_names: array of string names for all possible parents
* @num_parents: number of possible parents
* @flags: framework-level hints and quirks
*/
struct clk_init_data {
const char *name;
const struct clk_ops *ops;
const char **parent_names;
u8 num_parents;
unsigned long flags;
};
/**
* struct clk_hw - handle for traversing from a struct clk to its corresponding
* hardware-specific structure. struct clk_hw should be declared within struct
* clk_foo and then referenced by the struct clk instance that uses struct
* clk_foo's clk_ops
*
* @clk: pointer to the struct clk instance that points back to this struct
* clk_hw instance
*
* @init: pointer to struct clk_init_data that contains the init data shared
* with the common clock framework.
*/
struct clk_hw {
struct clk *clk;
struct clk_init_data *init;
};
/*
* DOC: Basic clock implementations common to many platforms
*
......@@ -149,6 +166,7 @@ struct clk_fixed_rate {
u8 flags;
};
extern const struct clk_ops 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);
......@@ -165,7 +183,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
* 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
* CLK_GATE_SET_TO_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
*/
......@@ -175,11 +193,11 @@ struct clk_gate {
u8 bit_idx;
u8 flags;
spinlock_t *lock;
char *parent[1];
};
#define CLK_GATE_SET_TO_DISABLE BIT(0)
extern const struct clk_ops 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,
......@@ -212,12 +230,12 @@ struct clk_divider {
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)
extern const struct clk_ops 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,
......@@ -238,7 +256,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
*
* 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)
* CLK_MUX_INDEX_BIT - register index is a single bit (power of two)
*/
struct clk_mux {
struct clk_hw hw;
......@@ -252,29 +270,47 @@ struct clk_mux {
#define CLK_MUX_INDEX_ONE BIT(0)
#define CLK_MUX_INDEX_BIT BIT(1)
extern const struct clk_ops clk_mux_ops;
struct clk *clk_register_mux(struct device *dev, const char *name,
char **parent_names, u8 num_parents, unsigned long flags,
const 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_fixed_factor - fixed multiplier and divider clock
*
* @hw: handle between common and hardware-specific interfaces
* @mult: multiplier
* @div: divider
*
* Clock with a fixed multiplier and divider. The output frequency is the
* parent clock rate divided by div and multiplied by mult.
* Implements .recalc_rate, .set_rate and .round_rate
*/
struct clk_fixed_factor {
struct clk_hw hw;
unsigned int mult;
unsigned int div;
};
extern struct clk_ops clk_fixed_factor_ops;
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div);
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
* @name: clock name
* @ops: operations this clock supports
* @hw: link to hardware-specific clock data
* @parent_names: array of string names for all possible parents
* @num_parents: number of possible parents
* @flags: framework-level hints and quirks
*
* clk_register is the primary interface for populating the clock tree with new
* clock nodes. It returns a pointer to the newly allocated struct clk which
* cannot be dereferenced by driver code but may be used in conjuction with the
* rest of the clock API.
* rest of the clock API. In the event of an error clk_register will return an
* error code; drivers must test for an error code after calling clk_register.
*/
struct clk *clk_register(struct device *dev, const char *name,
const struct clk_ops *ops, struct clk_hw *hw,
char **parent_names, u8 num_parents, unsigned long flags);
struct clk *clk_register(struct device *dev, struct clk_hw *hw);
/* helper functions */
const char *__clk_get_name(struct clk *clk);
......
......@@ -81,7 +81,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
#endif /* !CONFIG_COMMON_CLK */
#endif
/**
* clk_get - lookup and obtain a reference to a clock producer.
......@@ -220,7 +220,7 @@ void clk_put(struct clk *clk);
* Returns rounded clock rate in Hz, or negative errno.
*/
long clk_round_rate(struct clk *clk, unsigned long rate);
/**
* clk_set_rate - set the clock rate for a clock source
* @clk: clock source
......@@ -229,7 +229,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate);
* Returns success (0) or negative errno.
*/
int clk_set_rate(struct clk *clk, unsigned long rate);
/**
* clk_set_parent - set the parent clock source for this clock
* @clk: clock source
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment