Commit 1929cb34 authored by dmitry pervushin's avatar dmitry pervushin Committed by Paul Mundt

sh: SH7722 clock framework support.

This adds support for the SH7722 (MobileR) to the clock framework.
Signed-off-by: default avatardmitry pervushin <dimka@nomadgs.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 34a780a0
Clock framework on SuperH architecture
The framework on SH extends existing API by the function clk_set_rate_ex,
which prototype is as follows:
clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id)
The algo_id parameter is used to specify algorithm used to recalculate clocks,
adjanced to clock, specified as first argument. It is assumed that algo_id==0
means no changes to adjanced clock
Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method,
if it is present in ops structure. The method should set the clock rate and adjust
all needed clocks according to the passed algo_id.
Exact values for algo_id are machine-dependend. For the sh7722, the following
values are defined:
NO_CHANGE = 0,
IUS_N1_N1, /* I:U = N:1, U:Sh = N:1 */
IUS_322, /* I:U:Sh = 3:2:2 */
IUS_522, /* I:U:Sh = 5:2:2 */
IUS_N11, /* I:U:Sh = N:1:1 */
SB_N1, /* Sh:B = N:1 */
SB3_N1, /* Sh:B3 = N:1 */
SB3_32, /* Sh:B3 = 3:2 */
SB3_43, /* Sh:B3 = 4:3 */
SB3_54, /* Sh:B3 = 5:4 */
BP_N1, /* B:P = N:1 */
IP_N1 /* I:P = N:1 */
Each of these constants means relation between clocks that can be set via the FRQCR
register
......@@ -98,13 +98,14 @@ int __clk_enable(struct clk *clk)
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
kref_get(&clk->kref);
if (clk->flags & CLK_ALWAYS_ENABLED)
return 0;
if (likely(clk->ops && clk->ops->enable))
clk->ops->enable(clk);
kref_get(&clk->kref);
return 0;
}
......@@ -127,10 +128,15 @@ static void clk_kref_release(struct kref *kref)
void __clk_disable(struct clk *clk)
{
int count = kref_put(&clk->kref, clk_kref_release);
if (clk->flags & CLK_ALWAYS_ENABLED)
return;
kref_put(&clk->kref, clk_kref_release);
if (!count) { /* count reaches zero, disable the clock */
if (likely(clk->ops && clk->ops->disable))
clk->ops->disable(clk);
}
}
void clk_disable(struct clk *clk)
......@@ -151,6 +157,15 @@ int clk_register(struct clk *clk)
mutex_unlock(&clock_list_sem);
if (clk->flags & CLK_ALWAYS_ENABLED) {
pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
if (clk->ops && clk->ops->enable)
clk->ops->enable(clk);
pr_debug( "Enabled.");
}
return 0;
}
......@@ -167,6 +182,11 @@ inline unsigned long clk_get_rate(struct clk *clk)
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
return clk_set_rate_ex(clk, rate, 0);
}
int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
{
int ret = -EOPNOTSUPP;
......@@ -174,7 +194,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
unsigned long flags;
spin_lock_irqsave(&clock_lock, flags);
ret = clk->ops->set_rate(clk, rate);
ret = clk->ops->set_rate(clk, rate, algo_id);
spin_unlock_irqrestore(&clock_lock, flags);
}
......@@ -256,7 +276,6 @@ int __init clk_init(void)
arch_init_clk_ops(&clk->ops, i);
ret |= clk_register(clk);
clk_enable(clk);
}
/* Kick the child clocks.. */
......@@ -298,3 +317,4 @@ EXPORT_SYMBOL_GPL(__clk_disable);
EXPORT_SYMBOL_GPL(clk_get_rate);
EXPORT_SYMBOL_GPL(clk_set_rate);
EXPORT_SYMBOL_GPL(clk_recalc_rate);
EXPORT_SYMBOL_GPL(clk_set_rate_ex);
......@@ -82,7 +82,8 @@ static void shoc_clk_init(struct clk *clk)
for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
int divisor = frqcr3_divisors[i];
if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0)
if (clk->ops->set_rate(clk, clk->parent->rate /
divisor, 0) == 0)
break;
}
......
......@@ -16,6 +16,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
obj-y += $(clock-y)
This diff is collapsed.
......@@ -13,7 +13,7 @@ struct clk_ops {
void (*enable)(struct clk *clk);
void (*disable)(struct clk *clk);
void (*recalc)(struct clk *clk);
int (*set_rate)(struct clk *clk, unsigned long rate);
int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
};
struct clk {
......@@ -50,4 +50,34 @@ void clk_unregister(struct clk *);
int show_clocks(struct seq_file *m);
/* the exported API, in addition to clk_set_rate */
/**
* clk_set_rate_ex - set the clock rate for a clock source, with additional parameter
* @clk: clock source
* @rate: desired clock rate in Hz
* @algo_id: algorithm id to be passed down to ops->set_rate
*
* Returns success (0) or negative errno.
*/
int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id);
enum clk_sh_algo_id {
NO_CHANGE = 0,
IUS_N1_N1,
IUS_322,
IUS_522,
IUS_N11,
SB_N1,
SB3_N1,
SB3_32,
SB3_43,
SB3_54,
BP_N1,
IP_N1,
};
#endif /* __ASM_SH_CLOCK_H */
......@@ -12,6 +12,10 @@
#if defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7722)
#define FRQCR 0xa4150000
#define VCLKCR 0xa4150004
#define SCLKACR 0xa4150008
#define SCLKBCR 0xa415000c
#define IrDACLKCR 0xa4150010
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
#define FRQCR 0xffc80000
#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment