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: fs/coda/
|
||||||
F: include/linux/coda*.h
|
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)
|
COMMON INTERNET FILE SYSTEM (CIFS)
|
||||||
M: Steve French <sfrench@samba.org>
|
M: Steve French <sfrench@samba.org>
|
||||||
L: linux-cifs@vger.kernel.org
|
L: linux-cifs@vger.kernel.org
|
||||||
|
|
|
@ -12,6 +12,7 @@ config HAVE_MACH_CLKDEV
|
||||||
config COMMON_CLK
|
config COMMON_CLK
|
||||||
bool
|
bool
|
||||||
select HAVE_CLK_PREPARE
|
select HAVE_CLK_PREPARE
|
||||||
|
select CLKDEV_LOOKUP
|
||||||
---help---
|
---help---
|
||||||
The common clock framework is a single definition of struct
|
The common clock framework is a single definition of struct
|
||||||
clk, useful across many platforms, as well as an
|
clk, useful across many platforms, as well as an
|
||||||
|
@ -22,17 +23,6 @@ config COMMON_CLK
|
||||||
menu "Common Clock Framework"
|
menu "Common Clock Framework"
|
||||||
depends on COMMON_CLK
|
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
|
config COMMON_CLK_DEBUG
|
||||||
bool "DebugFS representation of clock tree"
|
bool "DebugFS representation of clock tree"
|
||||||
depends on COMMON_CLK
|
depends on COMMON_CLK
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
|
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
|
||||||
obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.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;
|
return parent_rate / div;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The reverse of DIV_ROUND_UP: The maximum number which
|
* 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)
|
if (divider->flags & CLK_DIVIDER_ONE_BASED)
|
||||||
maxdiv--;
|
maxdiv--;
|
||||||
|
|
||||||
if (!best_parent_rate) {
|
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
|
||||||
parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
|
parent_rate = *best_parent_rate;
|
||||||
bestdiv = DIV_ROUND_UP(parent_rate, rate);
|
bestdiv = DIV_ROUND_UP(parent_rate, rate);
|
||||||
bestdiv = bestdiv == 0 ? 1 : bestdiv;
|
bestdiv = bestdiv == 0 ? 1 : bestdiv;
|
||||||
bestdiv = bestdiv > maxdiv ? maxdiv : 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;
|
int div;
|
||||||
div = clk_divider_bestdiv(hw, rate, prate);
|
div = clk_divider_bestdiv(hw, rate, prate);
|
||||||
|
|
||||||
if (prate)
|
return *prate / div;
|
||||||
return *prate / div;
|
|
||||||
else {
|
|
||||||
unsigned long r;
|
|
||||||
r = __clk_get_rate(__clk_get_parent(hw->clk));
|
|
||||||
return r / 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);
|
struct clk_divider *divider = to_clk_divider(hw);
|
||||||
unsigned int div;
|
unsigned int div;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate;
|
div = parent_rate / rate;
|
||||||
|
|
||||||
if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
|
if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
|
||||||
div--;
|
div--;
|
||||||
|
@ -147,15 +140,26 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
|
||||||
|
|
||||||
return 0;
|
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,
|
.recalc_rate = clk_divider_recalc_rate,
|
||||||
.round_rate = clk_divider_round_rate,
|
.round_rate = clk_divider_round_rate,
|
||||||
.set_rate = clk_divider_set_rate,
|
.set_rate = clk_divider_set_rate,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(clk_divider_ops);
|
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,
|
struct clk *clk_register_divider(struct device *dev, const char *name,
|
||||||
const char *parent_name, unsigned long flags,
|
const char *parent_name, unsigned long flags,
|
||||||
void __iomem *reg, u8 shift, u8 width,
|
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_divider *div;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
struct clk_init_data init;
|
||||||
|
|
||||||
|
/* allocate the divider */
|
||||||
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
|
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
|
||||||
|
|
||||||
if (!div) {
|
if (!div) {
|
||||||
pr_err("%s: could not allocate divider clk\n", __func__);
|
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 */
|
/* struct clk_divider assignments */
|
||||||
div->reg = reg;
|
div->reg = reg;
|
||||||
div->shift = shift;
|
div->shift = shift;
|
||||||
div->width = width;
|
div->width = width;
|
||||||
div->flags = clk_divider_flags;
|
div->flags = clk_divider_flags;
|
||||||
div->lock = lock;
|
div->lock = lock;
|
||||||
|
div->hw.init = &init;
|
||||||
|
|
||||||
if (parent_name) {
|
/* register the clock */
|
||||||
div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
|
clk = clk_register(dev, &div->hw);
|
||||||
if (!div->parent[0])
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
clk = clk_register(dev, name,
|
if (IS_ERR(clk))
|
||||||
&clk_divider_ops, &div->hw,
|
kfree(div);
|
||||||
div->parent,
|
|
||||||
(parent_name ? 1 : 0),
|
|
||||||
flags);
|
|
||||||
if (clk)
|
|
||||||
return clk;
|
|
||||||
|
|
||||||
out:
|
return clk;
|
||||||
kfree(div->parent[0]);
|
|
||||||
kfree(div);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
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;
|
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,
|
.recalc_rate = clk_fixed_rate_recalc_rate,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
|
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,
|
struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
|
||||||
const char *parent_name, unsigned long flags,
|
const char *parent_name, unsigned long flags,
|
||||||
unsigned long fixed_rate)
|
unsigned long fixed_rate)
|
||||||
{
|
{
|
||||||
struct clk_fixed_rate *fixed;
|
struct clk_fixed_rate *fixed;
|
||||||
char **parent_names = NULL;
|
struct clk *clk;
|
||||||
u8 len;
|
struct clk_init_data init;
|
||||||
|
|
||||||
|
/* allocate fixed-rate clock */
|
||||||
fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
|
fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
|
||||||
|
|
||||||
if (!fixed) {
|
if (!fixed) {
|
||||||
pr_err("%s: could not allocate fixed clk\n", __func__);
|
pr_err("%s: could not allocate fixed clk\n", __func__);
|
||||||
return ERR_PTR(-ENOMEM);
|
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 */
|
/* struct clk_fixed_rate assignments */
|
||||||
fixed->fixed_rate = fixed_rate;
|
fixed->fixed_rate = fixed_rate;
|
||||||
|
fixed->hw.init = &init;
|
||||||
|
|
||||||
if (parent_name) {
|
/* register the clock */
|
||||||
parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
|
clk = clk_register(dev, &fixed->hw);
|
||||||
|
|
||||||
if (! parent_names)
|
if (IS_ERR(clk))
|
||||||
goto out;
|
kfree(fixed);
|
||||||
|
|
||||||
len = sizeof(char) * strlen(parent_name);
|
return clk;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,32 +28,38 @@
|
||||||
|
|
||||||
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
|
#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;
|
unsigned long flags = 0;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
set ^= enable;
|
||||||
|
|
||||||
if (gate->lock)
|
if (gate->lock)
|
||||||
spin_lock_irqsave(gate->lock, flags);
|
spin_lock_irqsave(gate->lock, flags);
|
||||||
|
|
||||||
reg = readl(gate->reg);
|
reg = readl(gate->reg);
|
||||||
reg |= BIT(gate->bit_idx);
|
|
||||||
writel(reg, gate->reg);
|
|
||||||
|
|
||||||
if (gate->lock)
|
if (set)
|
||||||
spin_unlock_irqrestore(gate->lock, flags);
|
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);
|
writel(reg, gate->reg);
|
||||||
|
|
||||||
if (gate->lock)
|
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)
|
static int clk_gate_enable(struct clk_hw *hw)
|
||||||
{
|
{
|
||||||
struct clk_gate *gate = to_clk_gate(hw);
|
clk_gate_endisable(hw, 1);
|
||||||
|
|
||||||
if (gate->flags & CLK_GATE_SET_TO_DISABLE)
|
|
||||||
clk_gate_clear_bit(gate);
|
|
||||||
else
|
|
||||||
clk_gate_set_bit(gate);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clk_gate_enable);
|
|
||||||
|
|
||||||
static void clk_gate_disable(struct clk_hw *hw)
|
static void clk_gate_disable(struct clk_hw *hw)
|
||||||
{
|
{
|
||||||
struct clk_gate *gate = to_clk_gate(hw);
|
clk_gate_endisable(hw, 0);
|
||||||
|
|
||||||
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)
|
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;
|
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,
|
.enable = clk_gate_enable,
|
||||||
.disable = clk_gate_disable,
|
.disable = clk_gate_disable,
|
||||||
.is_enabled = clk_gate_is_enabled,
|
.is_enabled = clk_gate_is_enabled,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(clk_gate_ops);
|
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,
|
struct clk *clk_register_gate(struct device *dev, const char *name,
|
||||||
const char *parent_name, unsigned long flags,
|
const char *parent_name, unsigned long flags,
|
||||||
void __iomem *reg, u8 bit_idx,
|
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_gate *gate;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
struct clk_init_data init;
|
||||||
|
|
||||||
|
/* allocate the gate */
|
||||||
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
|
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
|
||||||
|
|
||||||
if (!gate) {
|
if (!gate) {
|
||||||
pr_err("%s: could not allocate gated clk\n", __func__);
|
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 */
|
/* struct clk_gate assignments */
|
||||||
gate->reg = reg;
|
gate->reg = reg;
|
||||||
gate->bit_idx = bit_idx;
|
gate->bit_idx = bit_idx;
|
||||||
gate->flags = clk_gate_flags;
|
gate->flags = clk_gate_flags;
|
||||||
gate->lock = lock;
|
gate->lock = lock;
|
||||||
|
gate->hw.init = &init;
|
||||||
|
|
||||||
if (parent_name) {
|
clk = clk_register(dev, &gate->hw);
|
||||||
gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
|
|
||||||
if (!gate->parent[0])
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
clk = clk_register(dev, name,
|
if (IS_ERR(clk))
|
||||||
&clk_gate_ops, &gate->hw,
|
kfree(gate);
|
||||||
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;
|
return val;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clk_mux_get_parent);
|
|
||||||
|
|
||||||
static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
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;
|
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,
|
.get_parent = clk_mux_get_parent,
|
||||||
.set_parent = clk_mux_set_parent,
|
.set_parent = clk_mux_set_parent,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(clk_mux_ops);
|
EXPORT_SYMBOL_GPL(clk_mux_ops);
|
||||||
|
|
||||||
struct clk *clk_register_mux(struct device *dev, const char *name,
|
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,
|
void __iomem *reg, u8 shift, u8 width,
|
||||||
u8 clk_mux_flags, spinlock_t *lock)
|
u8 clk_mux_flags, spinlock_t *lock)
|
||||||
{
|
{
|
||||||
struct clk_mux *mux;
|
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) {
|
if (!mux) {
|
||||||
pr_err("%s: could not allocate mux clk\n", __func__);
|
pr_err("%s: could not allocate mux clk\n", __func__);
|
||||||
return ERR_PTR(-ENOMEM);
|
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 */
|
/* struct clk_mux assignments */
|
||||||
mux->reg = reg;
|
mux->reg = reg;
|
||||||
mux->shift = shift;
|
mux->shift = shift;
|
||||||
mux->width = width;
|
mux->width = width;
|
||||||
mux->flags = clk_mux_flags;
|
mux->flags = clk_mux_flags;
|
||||||
mux->lock = lock;
|
mux->lock = lock;
|
||||||
|
mux->hw.init = &init;
|
||||||
|
|
||||||
return clk_register(dev, name, &clk_mux_ops, &mux->hw,
|
clk = clk_register(dev, &mux->hw);
|
||||||
parent_names, num_parents, flags);
|
|
||||||
|
if (IS_ERR(clk))
|
||||||
|
kfree(mux);
|
||||||
|
|
||||||
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,9 +194,8 @@ static int __init clk_debug_init(void)
|
||||||
late_initcall(clk_debug_init);
|
late_initcall(clk_debug_init);
|
||||||
#else
|
#else
|
||||||
static inline int clk_debug_register(struct clk *clk) { return 0; }
|
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 */
|
/* caller must hold prepare_lock */
|
||||||
static void clk_disable_unused_subtree(struct clk *clk)
|
static void clk_disable_unused_subtree(struct clk *clk)
|
||||||
{
|
{
|
||||||
|
@ -246,9 +245,6 @@ static int clk_disable_unused(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
late_initcall(clk_disable_unused);
|
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 ***/
|
/*** helper functions ***/
|
||||||
|
|
||||||
|
@ -287,7 +283,7 @@ unsigned long __clk_get_rate(struct clk *clk)
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
|
|
||||||
if (!clk) {
|
if (!clk) {
|
||||||
ret = -EINVAL;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +293,7 @@ unsigned long __clk_get_rate(struct clk *clk)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!clk->parent)
|
if (!clk->parent)
|
||||||
ret = -ENODEV;
|
ret = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -562,7 +558,7 @@ EXPORT_SYMBOL_GPL(clk_enable);
|
||||||
* @clk: the clk whose rate is being returned
|
* @clk: the clk whose rate is being returned
|
||||||
*
|
*
|
||||||
* Simply returns the cached rate of the clk. Does not query the hardware. If
|
* 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)
|
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 __clk_round_rate(struct clk *clk, unsigned long rate)
|
||||||
{
|
{
|
||||||
unsigned long unused;
|
unsigned long parent_rate = 0;
|
||||||
|
|
||||||
if (!clk)
|
if (!clk)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!clk->ops->round_rate)
|
if (!clk->ops->round_rate) {
|
||||||
return clk->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)
|
if (clk->parent)
|
||||||
return clk->ops->round_rate(clk->hw, rate, &unused);
|
parent_rate = clk->parent->rate;
|
||||||
else
|
|
||||||
return clk->ops->round_rate(clk->hw, rate, NULL);
|
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)
|
static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
|
||||||
{
|
{
|
||||||
struct clk *top = clk;
|
struct clk *top = clk;
|
||||||
unsigned long best_parent_rate = clk->parent->rate;
|
unsigned long best_parent_rate = 0;
|
||||||
unsigned long new_rate;
|
unsigned long new_rate;
|
||||||
|
|
||||||
if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) {
|
/* sanity */
|
||||||
clk->new_rate = clk->rate;
|
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;
|
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);
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clk->flags & CLK_SET_RATE_PARENT)
|
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
|
||||||
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
|
|
||||||
else
|
|
||||||
new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
|
|
||||||
|
|
||||||
if (best_parent_rate != clk->parent->rate) {
|
if (best_parent_rate != clk->parent->rate) {
|
||||||
top = clk_calc_new_rates(clk->parent, best_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;
|
old_rate = clk->rate;
|
||||||
|
|
||||||
if (clk->ops->set_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)
|
if (clk->ops->recalc_rate)
|
||||||
clk->rate = clk->ops->recalc_rate(clk->hw,
|
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
|
* @clk: the clk whose rate is being changed
|
||||||
* @rate: the new rate for clk
|
* @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
|
* Setting the CLK_SET_RATE_PARENT flag allows the rate change operation to
|
||||||
* will fail; only when the clk is disabled will it be able to change
|
* propagate up to clk's parent; whether or not this happens depends on the
|
||||||
* its rate.
|
* 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
|
* Rate changes are accomplished via tree traversal that also recalculates the
|
||||||
* recursively propagate up to clk's parent; whether or not this happens
|
* rates for the clocks and fires off POST_RATE_CHANGE notifiers.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -EERROR otherwise.
|
* Returns 0 on success, -EERROR otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -906,6 +903,11 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||||
if (rate == clk->rate)
|
if (rate == clk->rate)
|
||||||
goto out;
|
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 */
|
/* calculate new rates and get the topmost changed clock */
|
||||||
top = clk_calc_new_rates(clk, rate);
|
top = clk_calc_new_rates(clk, rate);
|
||||||
if (!top) {
|
if (!top) {
|
||||||
|
@ -1175,40 +1177,41 @@ EXPORT_SYMBOL_GPL(clk_set_parent);
|
||||||
*
|
*
|
||||||
* Initializes the lists in struct clk, queries the hardware for the
|
* Initializes the lists in struct clk, queries the hardware for the
|
||||||
* parent and rate and sets them both.
|
* 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 clk *orphan;
|
||||||
struct hlist_node *tmp, *tmp2;
|
struct hlist_node *tmp, *tmp2;
|
||||||
|
|
||||||
if (!clk)
|
if (!clk)
|
||||||
return;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&prepare_lock);
|
mutex_lock(&prepare_lock);
|
||||||
|
|
||||||
/* check to see if a clock with this name is already registered */
|
/* 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;
|
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 */
|
/* throw a WARN if any entries in parent_names are NULL */
|
||||||
for (i = 0; i < clk->num_parents; i++)
|
for (i = 0; i < clk->num_parents; i++)
|
||||||
|
@ -1302,45 +1305,118 @@ void __clk_init(struct device *dev, struct clk *clk)
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&prepare_lock);
|
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
|
* clk_register - allocate a new clock, register it and return an opaque cookie
|
||||||
* @dev: device that is registering this clock
|
* @dev: device that is registering this clock
|
||||||
* @name: clock name
|
|
||||||
* @ops: operations this clock supports
|
|
||||||
* @hw: link to hardware-specific clock data
|
* @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
|
* 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
|
* 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
|
* 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,
|
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||||
const struct clk_ops *ops, struct clk_hw *hw,
|
|
||||||
char **parent_names, u8 num_parents, unsigned long flags)
|
|
||||||
{
|
{
|
||||||
|
int i, ret;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
|
||||||
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
|
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
|
||||||
if (!clk)
|
if (!clk) {
|
||||||
return NULL;
|
pr_err("%s: could not allocate clk\n", __func__);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail_out;
|
||||||
|
}
|
||||||
|
|
||||||
clk->name = name;
|
clk->name = kstrdup(hw->init->name, GFP_KERNEL);
|
||||||
clk->ops = ops;
|
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->hw = hw;
|
||||||
clk->flags = flags;
|
clk->flags = hw->init->flags;
|
||||||
clk->parent_names = parent_names;
|
clk->num_parents = hw->init->num_parents;
|
||||||
clk->num_parents = num_parents;
|
|
||||||
hw->clk = clk;
|
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);
|
EXPORT_SYMBOL_GPL(clk_register);
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct clk {
|
||||||
const struct clk_ops *ops;
|
const struct clk_ops *ops;
|
||||||
struct clk_hw *hw;
|
struct clk_hw *hw;
|
||||||
struct clk *parent;
|
struct clk *parent;
|
||||||
char **parent_names;
|
const char **parent_names;
|
||||||
struct clk **parents;
|
struct clk **parents;
|
||||||
u8 num_parents;
|
u8 num_parents;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
|
@ -55,12 +55,22 @@ struct clk {
|
||||||
* alternative macro for static initialization
|
* 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, \
|
#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
|
||||||
_fixed_rate_flags) \
|
_fixed_rate_flags) \
|
||||||
static struct clk _name; \
|
static struct clk _name; \
|
||||||
static char *_name##_parent_names[] = {}; \
|
static const char *_name##_parent_names[] = {}; \
|
||||||
static struct clk_fixed_rate _name##_hw = { \
|
static struct clk_fixed_rate _name##_hw = { \
|
||||||
.hw = { \
|
.hw = { \
|
||||||
.clk = &_name, \
|
.clk = &_name, \
|
||||||
|
@ -68,23 +78,14 @@ extern struct clk_ops clk_fixed_rate_ops;
|
||||||
.fixed_rate = _rate, \
|
.fixed_rate = _rate, \
|
||||||
.flags = _fixed_rate_flags, \
|
.flags = _fixed_rate_flags, \
|
||||||
}; \
|
}; \
|
||||||
static struct clk _name = { \
|
DEFINE_CLK(_name, clk_fixed_rate_ops, _flags, \
|
||||||
.name = #_name, \
|
_name##_parent_names, NULL);
|
||||||
.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, \
|
#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \
|
||||||
_flags, _reg, _bit_idx, \
|
_flags, _reg, _bit_idx, \
|
||||||
_gate_flags, _lock) \
|
_gate_flags, _lock) \
|
||||||
static struct clk _name; \
|
static struct clk _name; \
|
||||||
static char *_name##_parent_names[] = { \
|
static const char *_name##_parent_names[] = { \
|
||||||
_parent_name, \
|
_parent_name, \
|
||||||
}; \
|
}; \
|
||||||
static struct clk *_name##_parents[] = { \
|
static struct clk *_name##_parents[] = { \
|
||||||
|
@ -99,24 +100,14 @@ extern struct clk_ops clk_gate_ops;
|
||||||
.flags = _gate_flags, \
|
.flags = _gate_flags, \
|
||||||
.lock = _lock, \
|
.lock = _lock, \
|
||||||
}; \
|
}; \
|
||||||
static struct clk _name = { \
|
DEFINE_CLK(_name, clk_gate_ops, _flags, \
|
||||||
.name = #_name, \
|
_name##_parent_names, _name##_parents);
|
||||||
.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, \
|
#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
|
||||||
_flags, _reg, _shift, _width, \
|
_flags, _reg, _shift, _width, \
|
||||||
_divider_flags, _lock) \
|
_divider_flags, _lock) \
|
||||||
static struct clk _name; \
|
static struct clk _name; \
|
||||||
static char *_name##_parent_names[] = { \
|
static const char *_name##_parent_names[] = { \
|
||||||
_parent_name, \
|
_parent_name, \
|
||||||
}; \
|
}; \
|
||||||
static struct clk *_name##_parents[] = { \
|
static struct clk *_name##_parents[] = { \
|
||||||
|
@ -132,18 +123,8 @@ extern struct clk_ops clk_divider_ops;
|
||||||
.flags = _divider_flags, \
|
.flags = _divider_flags, \
|
||||||
.lock = _lock, \
|
.lock = _lock, \
|
||||||
}; \
|
}; \
|
||||||
static struct clk _name = { \
|
DEFINE_CLK(_name, clk_divider_ops, _flags, \
|
||||||
.name = #_name, \
|
_name##_parent_names, _name##_parents);
|
||||||
.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, \
|
#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
|
||||||
_reg, _shift, _width, \
|
_reg, _shift, _width, \
|
||||||
|
@ -159,16 +140,28 @@ extern struct clk_ops clk_mux_ops;
|
||||||
.flags = _mux_flags, \
|
.flags = _mux_flags, \
|
||||||
.lock = _lock, \
|
.lock = _lock, \
|
||||||
}; \
|
}; \
|
||||||
static struct clk _name = { \
|
DEFINE_CLK(_name, clk_mux_ops, _flags, _parent_names, \
|
||||||
.name = #_name, \
|
_parents);
|
||||||
.ops = &clk_mux_ops, \
|
|
||||||
.hw = &_name##_hw.hw, \
|
#define DEFINE_CLK_FIXED_FACTOR(_name, _parent_name, \
|
||||||
.parent_names = _parent_names, \
|
_parent_ptr, _flags, \
|
||||||
.num_parents = \
|
_mult, _div) \
|
||||||
ARRAY_SIZE(_parent_names), \
|
static struct clk _name; \
|
||||||
.parents = _parents, \
|
static const char *_name##_parent_names[] = { \
|
||||||
.flags = _flags, \
|
_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
|
* __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
|
* It is not necessary to call clk_register if __clk_init is used directly with
|
||||||
* statically initialized clock data.
|
* 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 /* CONFIG_COMMON_CLK */
|
||||||
#endif /* CLK_PRIVATE_H */
|
#endif /* CLK_PRIVATE_H */
|
||||||
|
|
|
@ -15,19 +15,6 @@
|
||||||
|
|
||||||
#ifdef CONFIG_COMMON_CLK
|
#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
|
* flags used across common struct clk. these flags should only affect the
|
||||||
* top-level framework. custom flags for dealing with hardware specifics
|
* 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_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
|
||||||
#define CLK_IS_ROOT BIT(4) /* root clk, has no parent */
|
#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
|
* struct clk_ops - Callback operations for hardware clocks; these are to
|
||||||
* be provided by the clock implementation, and will be called by drivers
|
* 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.
|
* array index into the value programmed into the hardware.
|
||||||
* Returns 0 on success, -EERROR otherwise.
|
* Returns 0 on success, -EERROR otherwise.
|
||||||
*
|
*
|
||||||
* @set_rate: Change the rate of this clock. If this callback returns
|
* @set_rate: Change the rate of this clock. The requested rate is specified
|
||||||
* CLK_SET_RATE_PARENT, the rate change will be propagated to the
|
* by the second argument, which should typically be the return
|
||||||
* parent clock (which may propagate again if the parent clock
|
* of .round_rate call. The third argument gives the parent rate
|
||||||
* also sets this flag). The requested rate of the parent is
|
* which is likely helpful for most .set_rate implementation.
|
||||||
* passed back from the callback in the second 'unsigned long *'
|
* Returns 0 on success, -EERROR otherwise.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
|
* The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
|
||||||
* implementations to split any work between atomic (enable) and sleepable
|
* implementations to split any work between atomic (enable) and sleepable
|
||||||
|
@ -125,10 +106,46 @@ struct clk_ops {
|
||||||
unsigned long *);
|
unsigned long *);
|
||||||
int (*set_parent)(struct clk_hw *hw, u8 index);
|
int (*set_parent)(struct clk_hw *hw, u8 index);
|
||||||
u8 (*get_parent)(struct clk_hw *hw);
|
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);
|
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
|
* DOC: Basic clock implementations common to many platforms
|
||||||
*
|
*
|
||||||
|
@ -149,6 +166,7 @@ struct clk_fixed_rate {
|
||||||
u8 flags;
|
u8 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const struct clk_ops clk_fixed_rate_ops;
|
||||||
struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
|
struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
|
||||||
const char *parent_name, unsigned long flags,
|
const char *parent_name, unsigned long flags,
|
||||||
unsigned long fixed_rate);
|
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
|
* Clock which can gate its output. Implements .enable & .disable
|
||||||
*
|
*
|
||||||
* Flags:
|
* 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
|
* enable the clock. Setting this flag does the opposite: setting the bit
|
||||||
* disable the clock and clearing it enables the clock
|
* disable the clock and clearing it enables the clock
|
||||||
*/
|
*/
|
||||||
|
@ -175,11 +193,11 @@ struct clk_gate {
|
||||||
u8 bit_idx;
|
u8 bit_idx;
|
||||||
u8 flags;
|
u8 flags;
|
||||||
spinlock_t *lock;
|
spinlock_t *lock;
|
||||||
char *parent[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CLK_GATE_SET_TO_DISABLE BIT(0)
|
#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,
|
struct clk *clk_register_gate(struct device *dev, const char *name,
|
||||||
const char *parent_name, unsigned long flags,
|
const char *parent_name, unsigned long flags,
|
||||||
void __iomem *reg, u8 bit_idx,
|
void __iomem *reg, u8 bit_idx,
|
||||||
|
@ -212,12 +230,12 @@ struct clk_divider {
|
||||||
u8 width;
|
u8 width;
|
||||||
u8 flags;
|
u8 flags;
|
||||||
spinlock_t *lock;
|
spinlock_t *lock;
|
||||||
char *parent[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CLK_DIVIDER_ONE_BASED BIT(0)
|
#define CLK_DIVIDER_ONE_BASED BIT(0)
|
||||||
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
|
#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,
|
struct clk *clk_register_divider(struct device *dev, const char *name,
|
||||||
const char *parent_name, unsigned long flags,
|
const char *parent_name, unsigned long flags,
|
||||||
void __iomem *reg, u8 shift, u8 width,
|
void __iomem *reg, u8 shift, u8 width,
|
||||||
|
@ -238,7 +256,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
|
||||||
*
|
*
|
||||||
* Flags:
|
* Flags:
|
||||||
* CLK_MUX_INDEX_ONE - register index starts at 1, not 0
|
* 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_mux {
|
||||||
struct clk_hw hw;
|
struct clk_hw hw;
|
||||||
|
@ -252,29 +270,47 @@ struct clk_mux {
|
||||||
#define CLK_MUX_INDEX_ONE BIT(0)
|
#define CLK_MUX_INDEX_ONE BIT(0)
|
||||||
#define CLK_MUX_INDEX_BIT BIT(1)
|
#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,
|
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,
|
void __iomem *reg, u8 shift, u8 width,
|
||||||
u8 clk_mux_flags, spinlock_t *lock);
|
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
|
* clk_register - allocate a new clock, register it and return an opaque cookie
|
||||||
* @dev: device that is registering this clock
|
* @dev: device that is registering this clock
|
||||||
* @name: clock name
|
|
||||||
* @ops: operations this clock supports
|
|
||||||
* @hw: link to hardware-specific clock data
|
* @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
|
* 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
|
* 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
|
* 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,
|
struct clk *clk_register(struct device *dev, struct clk_hw *hw);
|
||||||
const struct clk_ops *ops, struct clk_hw *hw,
|
|
||||||
char **parent_names, u8 num_parents, unsigned long flags);
|
|
||||||
|
|
||||||
/* helper functions */
|
/* helper functions */
|
||||||
const char *__clk_get_name(struct clk *clk);
|
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);
|
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.
|
* 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.
|
* Returns rounded clock rate in Hz, or negative errno.
|
||||||
*/
|
*/
|
||||||
long clk_round_rate(struct clk *clk, unsigned long rate);
|
long clk_round_rate(struct clk *clk, unsigned long rate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clk_set_rate - set the clock rate for a clock source
|
* clk_set_rate - set the clock rate for a clock source
|
||||||
* @clk: 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.
|
* Returns success (0) or negative errno.
|
||||||
*/
|
*/
|
||||||
int clk_set_rate(struct clk *clk, unsigned long rate);
|
int clk_set_rate(struct clk *clk, unsigned long rate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clk_set_parent - set the parent clock source for this clock
|
* clk_set_parent - set the parent clock source for this clock
|
||||||
* @clk: clock source
|
* @clk: clock source
|
||||||
|
|
Loading…
Reference in a new issue