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: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
bef9459658
12 changed files with 536 additions and 322 deletions
10
MAINTAINERS
10
MAINTAINERS
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
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;
|
||||
}
|
||||
/* register the clock */
|
||||
clk = clk_register(dev, &div->hw);
|
||||
|
||||
clk = clk_register(dev, name,
|
||||
&clk_divider_ops, &div->hw,
|
||||
div->parent,
|
||||
(parent_name ? 1 : 0),
|
||||
flags);
|
||||
if (clk)
|
||||
return clk;
|
||||
if (IS_ERR(clk))
|
||||
kfree(div);
|
||||
|
||||
out:
|
||||
kfree(div->parent[0]);
|
||||
kfree(div);
|
||||
|
||||
return NULL;
|
||||
return clk;
|
||||
}
|
||||
|
|
95
drivers/clk/clk-fixed-factor.c
Normal file
95
drivers/clk/clk-fixed-factor.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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);
|
||||
/* register the clock */
|
||||
clk = clk_register(dev, &fixed->hw);
|
||||
|
||||
if (! parent_names)
|
||||
goto out;
|
||||
if (IS_ERR(clk))
|
||||
kfree(fixed);
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
if (set)
|
||||
reg |= BIT(gate->bit_idx);
|
||||
else
|
||||
reg &= ~BIT(gate->bit_idx);
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
|
||||
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);
|
||||
if (IS_ERR(clk))
|
||||
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;
|
||||
|
||||
return clk_register(dev, name, &clk_mux_ops, &mux->hw,
|
||||
parent_names, num_parents, flags);
|
||||
clk = clk_register(dev, &mux->hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(mux);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
|
|
@ -194,9 +194,8 @@ static int __init clk_debug_init(void)
|
|||
late_initcall(clk_debug_init);
|
||||
#else
|
||||
static inline int clk_debug_register(struct clk *clk) { return 0; }
|
||||
#endif /* CONFIG_COMMON_CLK_DEBUG */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED
|
||||
/* caller must hold prepare_lock */
|
||||
static void clk_disable_unused_subtree(struct clk *clk)
|
||||
{
|
||||
|
@ -246,9 +245,6 @@ static int clk_disable_unused(void)
|
|||
return 0;
|
||||
}
|
||||
late_initcall(clk_disable_unused);
|
||||
#else
|
||||
static inline int clk_disable_unused(struct clk *clk) { return 0; }
|
||||
#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */
|
||||
|
||||
/*** helper functions ***/
|
||||
|
||||
|
@ -287,7 +283,7 @@ unsigned long __clk_get_rate(struct clk *clk)
|
|||
unsigned long ret;
|
||||
|
||||
if (!clk) {
|
||||
ret = -EINVAL;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -297,7 +293,7 @@ unsigned long __clk_get_rate(struct clk *clk)
|
|||
goto out;
|
||||
|
||||
if (!clk->parent)
|
||||
ret = -ENODEV;
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -562,7 +558,7 @@ EXPORT_SYMBOL_GPL(clk_enable);
|
|||
* @clk: the clk whose rate is being returned
|
||||
*
|
||||
* Simply returns the cached rate of the clk. Does not query the hardware. If
|
||||
* clk is NULL then returns -EINVAL.
|
||||
* clk is NULL then returns 0.
|
||||
*/
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
|
@ -584,18 +580,22 @@ EXPORT_SYMBOL_GPL(clk_get_rate);
|
|||
*/
|
||||
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned long unused;
|
||||
unsigned long parent_rate = 0;
|
||||
|
||||
if (!clk)
|
||||
return -EINVAL;
|
||||
|
||||
if (!clk->ops->round_rate)
|
||||
return clk->rate;
|
||||
if (!clk->ops->round_rate) {
|
||||
if (clk->flags & CLK_SET_RATE_PARENT)
|
||||
return __clk_round_rate(clk->parent, rate);
|
||||
else
|
||||
return clk->rate;
|
||||
}
|
||||
|
||||
if (clk->flags & CLK_SET_RATE_PARENT)
|
||||
return clk->ops->round_rate(clk->hw, rate, &unused);
|
||||
else
|
||||
return clk->ops->round_rate(clk->hw, rate, NULL);
|
||||
if (clk->parent)
|
||||
parent_rate = clk->parent->rate;
|
||||
|
||||
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -765,25 +765,41 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
|
|||
static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
struct clk *top = clk;
|
||||
unsigned long best_parent_rate = clk->parent->rate;
|
||||
unsigned long best_parent_rate = 0;
|
||||
unsigned long new_rate;
|
||||
|
||||
if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) {
|
||||
clk->new_rate = clk->rate;
|
||||
/* sanity */
|
||||
if (IS_ERR_OR_NULL(clk))
|
||||
return NULL;
|
||||
|
||||
/* save parent rate, if it exists */
|
||||
if (clk->parent)
|
||||
best_parent_rate = clk->parent->rate;
|
||||
|
||||
/* never propagate up to the parent */
|
||||
if (!(clk->flags & CLK_SET_RATE_PARENT)) {
|
||||
if (!clk->ops->round_rate) {
|
||||
clk->new_rate = clk->rate;
|
||||
return NULL;
|
||||
}
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* need clk->parent from here on out */
|
||||
if (!clk->parent) {
|
||||
pr_debug("%s: %s has NULL parent\n", __func__, clk->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) {
|
||||
if (!clk->ops->round_rate) {
|
||||
top = clk_calc_new_rates(clk->parent, rate);
|
||||
new_rate = clk->new_rate = clk->parent->new_rate;
|
||||
new_rate = clk->parent->new_rate;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (clk->flags & CLK_SET_RATE_PARENT)
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
|
||||
else
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
|
||||
|
||||
if (best_parent_rate != clk->parent->rate) {
|
||||
top = clk_calc_new_rates(clk->parent, best_parent_rate);
|
||||
|
@ -839,7 +855,7 @@ static void clk_change_rate(struct clk *clk)
|
|||
old_rate = clk->rate;
|
||||
|
||||
if (clk->ops->set_rate)
|
||||
clk->ops->set_rate(clk->hw, clk->new_rate);
|
||||
clk->ops->set_rate(clk->hw, clk->new_rate, clk->parent->rate);
|
||||
|
||||
if (clk->ops->recalc_rate)
|
||||
clk->rate = clk->ops->recalc_rate(clk->hw,
|
||||
|
@ -859,38 +875,19 @@ static void clk_change_rate(struct clk *clk)
|
|||
* @clk: the clk whose rate is being changed
|
||||
* @rate: the new rate for clk
|
||||
*
|
||||
* In the simplest case clk_set_rate will only change the rate of clk.
|
||||
* In the simplest case clk_set_rate will only adjust the rate of clk.
|
||||
*
|
||||
* If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call
|
||||
* will fail; only when the clk is disabled will it be able to change
|
||||
* its rate.
|
||||
* Setting the CLK_SET_RATE_PARENT flag allows the rate change operation to
|
||||
* propagate up to clk's parent; whether or not this happens depends on the
|
||||
* outcome of clk's .round_rate implementation. If *parent_rate is unchanged
|
||||
* after calling .round_rate then upstream parent propagation is ignored. If
|
||||
* *parent_rate comes back with a new rate for clk's parent then we propagate
|
||||
* up to clk's parent and set it's rate. Upward propagation will continue
|
||||
* until either a clk does not support the CLK_SET_RATE_PARENT flag or
|
||||
* .round_rate stops requesting changes to clk's parent_rate.
|
||||
*
|
||||
* Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to
|
||||
* recursively propagate up to clk's parent; whether or not this happens
|
||||
* depends on the outcome of clk's .round_rate implementation. If
|
||||
* *parent_rate is 0 after calling .round_rate then upstream parent
|
||||
* propagation is ignored. If *parent_rate comes back with a new rate
|
||||
* for clk's parent then we propagate up to clk's parent and set it's
|
||||
* rate. Upward propagation will continue until either a clk does not
|
||||
* support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting
|
||||
* changes to clk's parent_rate. If there is a failure during upstream
|
||||
* propagation then clk_set_rate will unwind and restore each clk's rate
|
||||
* that had been successfully changed. Afterwards a rate change abort
|
||||
* notification will be propagated downstream, starting from the clk
|
||||
* that failed.
|
||||
*
|
||||
* At the end of all of the rate setting, clk_set_rate internally calls
|
||||
* __clk_recalc_rates and propagates the rate changes downstream,
|
||||
* starting from the highest clk whose rate was changed. This has the
|
||||
* added benefit of propagating post-rate change notifiers.
|
||||
*
|
||||
* Note that while post-rate change and rate change abort notifications
|
||||
* are guaranteed to be sent to a clk only once per call to
|
||||
* clk_set_rate, pre-change notifications will be sent for every clk
|
||||
* whose rate is changed. Stacking pre-change notifications is noisy
|
||||
* for the drivers subscribed to them, but this allows drivers to react
|
||||
* to intermediate clk rate changes up until the point where the final
|
||||
* rate is achieved at the end of upstream propagation.
|
||||
* Rate changes are accomplished via tree traversal that also recalculates the
|
||||
* rates for the clocks and fires off POST_RATE_CHANGE notifiers.
|
||||
*
|
||||
* Returns 0 on success, -EERROR otherwise.
|
||||
*/
|
||||
|
@ -906,6 +903,11 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
|||
if (rate == clk->rate)
|
||||
goto out;
|
||||
|
||||
if ((clk->flags & CLK_SET_RATE_GATE) && __clk_is_enabled(clk)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* calculate new rates and get the topmost changed clock */
|
||||
top = clk_calc_new_rates(clk, rate);
|
||||
if (!top) {
|
||||
|
@ -1175,40 +1177,41 @@ EXPORT_SYMBOL_GPL(clk_set_parent);
|
|||
*
|
||||
* Initializes the lists in struct clk, queries the hardware for the
|
||||
* parent and rate and sets them both.
|
||||
*
|
||||
* Any struct clk passed into __clk_init must have the following members
|
||||
* populated:
|
||||
* .name
|
||||
* .ops
|
||||
* .hw
|
||||
* .parent_names
|
||||
* .num_parents
|
||||
* .flags
|
||||
*
|
||||
* Essentially, everything that would normally be passed into clk_register is
|
||||
* assumed to be initialized already in __clk_init. The other members may be
|
||||
* populated, but are optional.
|
||||
*
|
||||
* __clk_init is only exposed via clk-private.h and is intended for use with
|
||||
* very large numbers of clocks that need to be statically initialized. It is
|
||||
* a layering violation to include clk-private.h from any code which implements
|
||||
* a clock's .ops; as such any statically initialized clock data MUST be in a
|
||||
* separate C file from the logic that implements it's operations.
|
||||
*/
|
||||
void __clk_init(struct device *dev, struct clk *clk)
|
||||
int __clk_init(struct device *dev, struct clk *clk)
|
||||
{
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
struct clk *orphan;
|
||||
struct hlist_node *tmp, *tmp2;
|
||||
|
||||
if (!clk)
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
|
||||
/* check to see if a clock with this name is already registered */
|
||||
if (__clk_lookup(clk->name))
|
||||
if (__clk_lookup(clk->name)) {
|
||||
pr_debug("%s: clk %s already initialized\n",
|
||||
__func__, clk->name);
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check that clk_ops are sane. See Documentation/clk.txt */
|
||||
if (clk->ops->set_rate &&
|
||||
!(clk->ops->round_rate && clk->ops->recalc_rate)) {
|
||||
pr_warning("%s: %s must implement .round_rate & .recalc_rate\n",
|
||||
__func__, clk->name);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (clk->ops->set_parent && !clk->ops->get_parent) {
|
||||
pr_warning("%s: %s must implement .get_parent & .set_parent\n",
|
||||
__func__, clk->name);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* throw a WARN if any entries in parent_names are NULL */
|
||||
for (i = 0; i < clk->num_parents; i++)
|
||||
|
@ -1302,45 +1305,118 @@ void __clk_init(struct device *dev, struct clk *clk)
|
|||
out:
|
||||
mutex_unlock(&prepare_lock);
|
||||
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* __clk_register - register a clock and return a cookie.
|
||||
*
|
||||
* Same as clk_register, except that the .clk field inside hw shall point to a
|
||||
* preallocated (generally statically allocated) struct clk. None of the fields
|
||||
* of the struct clk need to be initialized.
|
||||
*
|
||||
* The data pointed to by .init and .clk field shall NOT be marked as init
|
||||
* data.
|
||||
*
|
||||
* __clk_register is only exposed via clk-private.h and is intended for use with
|
||||
* very large numbers of clocks that need to be statically initialized. It is
|
||||
* a layering violation to include clk-private.h from any code which implements
|
||||
* a clock's .ops; as such any statically initialized clock data MUST be in a
|
||||
* separate C file from the logic that implements it's operations. Returns 0
|
||||
* on success, otherwise an error code.
|
||||
*/
|
||||
struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
|
||||
{
|
||||
int ret;
|
||||
struct clk *clk;
|
||||
|
||||
clk = hw->clk;
|
||||
clk->name = hw->init->name;
|
||||
clk->ops = hw->init->ops;
|
||||
clk->hw = hw;
|
||||
clk->flags = hw->init->flags;
|
||||
clk->parent_names = hw->init->parent_names;
|
||||
clk->num_parents = hw->init->num_parents;
|
||||
|
||||
ret = __clk_init(dev, clk);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_register);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
int i, ret;
|
||||
struct clk *clk;
|
||||
|
||||
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
|
||||
if (!clk)
|
||||
return NULL;
|
||||
if (!clk) {
|
||||
pr_err("%s: could not allocate clk\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto fail_out;
|
||||
}
|
||||
|
||||
clk->name = name;
|
||||
clk->ops = ops;
|
||||
clk->name = kstrdup(hw->init->name, GFP_KERNEL);
|
||||
if (!clk->name) {
|
||||
pr_err("%s: could not allocate clk->name\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto fail_name;
|
||||
}
|
||||
clk->ops = hw->init->ops;
|
||||
clk->hw = hw;
|
||||
clk->flags = flags;
|
||||
clk->parent_names = parent_names;
|
||||
clk->num_parents = num_parents;
|
||||
clk->flags = hw->init->flags;
|
||||
clk->num_parents = hw->init->num_parents;
|
||||
hw->clk = clk;
|
||||
|
||||
__clk_init(dev, clk);
|
||||
/* allocate local copy in case parent_names is __initdata */
|
||||
clk->parent_names = kzalloc((sizeof(char*) * clk->num_parents),
|
||||
GFP_KERNEL);
|
||||
|
||||
return clk;
|
||||
if (!clk->parent_names) {
|
||||
pr_err("%s: could not allocate clk->parent_names\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto fail_parent_names;
|
||||
}
|
||||
|
||||
|
||||
/* copy each string name in case parent_names is __initdata */
|
||||
for (i = 0; i < clk->num_parents; i++) {
|
||||
clk->parent_names[i] = kstrdup(hw->init->parent_names[i],
|
||||
GFP_KERNEL);
|
||||
if (!clk->parent_names[i]) {
|
||||
pr_err("%s: could not copy parent_names\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto fail_parent_names_copy;
|
||||
}
|
||||
}
|
||||
|
||||
ret = __clk_init(dev, clk);
|
||||
if (!ret)
|
||||
return clk;
|
||||
|
||||
fail_parent_names_copy:
|
||||
while (--i >= 0)
|
||||
kfree(clk->parent_names[i]);
|
||||
kfree(clk->parent_names);
|
||||
fail_parent_names:
|
||||
kfree(clk->name);
|
||||
fail_name:
|
||||
kfree(clk);
|
||||
fail_out:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue