Release 4.7 drivers/sh/clk/cpg.c
/*
* Helper routines for SuperH Clock Pulse Generator blocks (CPG).
*
* Copyright (C) 2010 Magnus Damm
* Copyright (C) 2010 - 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/sh_clk.h>
#define CPG_CKSTP_BIT BIT(8)
static unsigned int sh_clk_read(struct clk *clk)
{
if (clk->flags & CLK_ENABLE_REG_8BIT)
return ioread8(clk->mapped_reg);
else if (clk->flags & CLK_ENABLE_REG_16BIT)
return ioread16(clk->mapped_reg);
return ioread32(clk->mapped_reg);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 36 | 67.92% | 2 | 50.00% |
magnus damm | magnus damm | 17 | 32.08% | 2 | 50.00% |
| Total | 53 | 100.00% | 4 | 100.00% |
static void sh_clk_write(int value, struct clk *clk)
{
if (clk->flags & CLK_ENABLE_REG_8BIT)
iowrite8(value, clk->mapped_reg);
else if (clk->flags & CLK_ENABLE_REG_16BIT)
iowrite16(value, clk->mapped_reg);
else
iowrite32(value, clk->mapped_reg);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 50 | 84.75% | 2 | 66.67% |
magnus damm | magnus damm | 9 | 15.25% | 1 | 33.33% |
| Total | 59 | 100.00% | 3 | 100.00% |
static unsigned int r8(const void __iomem *addr)
{
return ioread8(addr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
guennadi liakhovetski | guennadi liakhovetski | 19 | 100.00% | 1 | 100.00% |
| Total | 19 | 100.00% | 1 | 100.00% |
static unsigned int r16(const void __iomem *addr)
{
return ioread16(addr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
guennadi liakhovetski | guennadi liakhovetski | 19 | 100.00% | 1 | 100.00% |
| Total | 19 | 100.00% | 1 | 100.00% |
static unsigned int r32(const void __iomem *addr)
{
return ioread32(addr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
guennadi liakhovetski | guennadi liakhovetski | 19 | 100.00% | 1 | 100.00% |
| Total | 19 | 100.00% | 1 | 100.00% |
static int sh_clk_mstp_enable(struct clk *clk)
{
sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
if (clk->status_reg) {
unsigned int (*read)(const void __iomem *addr);
int i;
void __iomem *mapped_status = (phys_addr_t)clk->status_reg -
(phys_addr_t)clk->enable_reg + clk->mapped_reg;
if (clk->flags & CLK_ENABLE_REG_8BIT)
read = r8;
else if (clk->flags & CLK_ENABLE_REG_16BIT)
read = r16;
else
read = r32;
for (i = 1000;
(read(mapped_status) & (1 << clk->enable_bit)) && i;
i--)
cpu_relax();
if (!i) {
pr_err("cpg: failed to enable %p[%d]\n",
clk->enable_reg, clk->enable_bit);
return -ETIMEDOUT;
}
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
guennadi liakhovetski | guennadi liakhovetski | 131 | 79.88% | 1 | 33.33% |
paul mundt | paul mundt | 33 | 20.12% | 2 | 66.67% |
| Total | 164 | 100.00% | 3 | 100.00% |
static void sh_clk_mstp_disable(struct clk *clk)
{
sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
magnus damm | magnus damm | 17 | 58.62% | 1 | 50.00% |
paul mundt | paul mundt | 12 | 41.38% | 1 | 50.00% |
| Total | 29 | 100.00% | 2 | 100.00% |
static struct sh_clk_ops sh_clk_mstp_clk_ops = {
.enable = sh_clk_mstp_enable,
.disable = sh_clk_mstp_disable,
.recalc = followparent_recalc,
};
int __init sh_clk_mstp_register(struct clk *clks, int nr)
{
struct clk *clkp;
int ret = 0;
int k;
for (k = 0; !ret && (k < nr); k++) {
clkp = clks + k;
clkp->ops = &sh_clk_mstp_clk_ops;
ret |= clk_register(clkp);
}
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
magnus damm | magnus damm | 68 | 97.14% | 1 | 50.00% |
paul mundt | paul mundt | 2 | 2.86% | 1 | 50.00% |
| Total | 70 | 100.00% | 2 | 100.00% |
/*
* Div/mult table lookup helpers
*/
static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
{
return clk->priv;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 19 | 100.00% | 1 | 100.00% |
| Total | 19 | 100.00% | 1 | 100.00% |
static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
{
return clk_to_div_table(clk)->div_mult_table;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 22 | 100.00% | 1 | 100.00% |
| Total | 22 | 100.00% | 1 | 100.00% |
/*
* Common div ops
*/
static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
{
return clk_rate_table_round(clk, clk->freq_table, rate);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
magnus damm | magnus damm | 27 | 100.00% | 1 | 100.00% |
| Total | 27 | 100.00% | 1 | 100.00% |
static unsigned long sh_clk_div_recalc(struct clk *clk)
{
struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
unsigned int idx;
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, clk->arch_flags ? &clk->arch_flags : NULL);
idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask;
return clk->freq_table[idx].frequency;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 79 | 100.00% | 2 | 100.00% |
| Total | 79 | 100.00% | 2 | 100.00% |
static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
{
struct clk_div_table *dt = clk_to_div_table(clk);
unsigned long value;
int idx;
idx = clk_rate_table_find(clk, clk->freq_table, rate);
if (idx < 0)
return idx;
value = sh_clk_read(clk);
value &= ~(clk->div_mask << clk->enable_bit);
value |= (idx << clk->enable_bit);
sh_clk_write(value, clk);
/* XXX: Should use a post-change notifier */
if (dt->kick)
dt->kick(clk);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 108 | 100.00% | 1 | 100.00% |
| Total | 108 | 100.00% | 1 | 100.00% |
static int sh_clk_div_enable(struct clk *clk)
{
if (clk->div_mask == SH_CLK_DIV6_MSK) {
int ret = sh_clk_div_set_rate(clk, clk->rate);
if (ret < 0)
return ret;
}
sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kuninori morimoto | kuninori morimoto | 31 | 53.45% | 1 | 50.00% |
paul mundt | paul mundt | 27 | 46.55% | 1 | 50.00% |
| Total | 58 | 100.00% | 2 | 100.00% |
static void sh_clk_div_disable(struct clk *clk)
{
unsigned int val;
val = sh_clk_read(clk);
val |= CPG_CKSTP_BIT;
/*
* div6 clocks require the divisor field to be non-zero or the
* above CKSTP toggle silently fails. Ensure that the divisor
* array is reset to its initial state on disable.
*/
if (clk->flags & CLK_MASK_DIV_ON_DISABLE)
val |= clk->div_mask;
sh_clk_write(val, clk);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 48 | 100.00% | 1 | 100.00% |
| Total | 48 | 100.00% | 1 | 100.00% |
static struct sh_clk_ops sh_clk_div_clk_ops = {
.recalc = sh_clk_div_recalc,
.set_rate = sh_clk_div_set_rate,
.round_rate = sh_clk_div_round_rate,
};
static struct sh_clk_ops sh_clk_div_enable_clk_ops = {
.recalc = sh_clk_div_recalc,
.set_rate = sh_clk_div_set_rate,
.round_rate = sh_clk_div_round_rate,
.enable = sh_clk_div_enable,
.disable = sh_clk_div_disable,
};
static int __init sh_clk_init_parent(struct clk *clk)
{
u32 val;
if (clk->parent)
return 0;
if (!clk->parent_table || !clk->parent_num)
return 0;
if (!clk->src_width) {
pr_err("sh_clk_init_parent: cannot select parent clock\n");
return -EINVAL;
}
val = (sh_clk_read(clk) >> clk->src_shift);
val &= (1 << clk->src_width) - 1;
if (val >= clk->parent_num) {
pr_err("sh_clk_init_parent: parent table size failed\n");
return -EINVAL;
}
clk_reparent(clk, clk->parent_table[val]);
if (!clk->parent) {
pr_err("sh_clk_init_parent: unable to set parent");
return -EINVAL;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 69 | 51.49% | 2 | 66.67% |
guennadi liakhovetski | guennadi liakhovetski | 65 | 48.51% | 1 | 33.33% |
| Total | 134 | 100.00% | 3 | 100.00% |
static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
struct clk_div_table *table, struct sh_clk_ops *ops)
{
struct clk *clkp;
void *freq_table;
int nr_divs = table->div_mult_table->nr_divisors;
int freq_table_size = sizeof(struct cpufreq_frequency_table);
int ret = 0;
int k;
freq_table_size *= (nr_divs + 1);
freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
if (!freq_table) {
pr_err("%s: unable to alloc memory\n", __func__);
return -ENOMEM;
}
for (k = 0; !ret && (k < nr); k++) {
clkp = clks + k;
clkp->ops = ops;
clkp->priv = table;
clkp->freq_table = freq_table + (k * freq_table_size);
clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
ret = clk_register(clkp);
if (ret == 0)
ret = sh_clk_init_parent(clkp);
}
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 139 | 76.80% | 1 | 50.00% |
kuninori morimoto | kuninori morimoto | 42 | 23.20% | 1 | 50.00% |
| Total | 181 | 100.00% | 2 | 100.00% |
/*
* div6 support
*/
static int sh_clk_div6_divisors[64] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
};
static struct clk_div_mult_table div6_div_mult_table = {
.divisors = sh_clk_div6_divisors,
.nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
};
static struct clk_div_table sh_clk_div6_table = {
.div_mult_table = &div6_div_mult_table,
};
static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
{
struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
u32 value;
int ret, i;
if (!clk->parent_table || !clk->parent_num)
return -EINVAL;
/* Search the parent */
for (i = 0; i < clk->parent_num; i++)
if (clk->parent_table[i] == parent)
break;
if (i == clk->parent_num)
return -ENODEV;
ret = clk_reparent(clk, parent);
if (ret < 0)
return ret;
value = sh_clk_read(clk) &
~(((1 << clk->src_width) - 1) << clk->src_shift);
sh_clk_write(value | (i << clk->src_shift), clk);
/* Rebuild the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, NULL);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 121 | 71.18% | 2 | 40.00% |
magnus damm | magnus damm | 42 | 24.71% | 1 | 20.00% |
guennadi liakhovetski | guennadi liakhovetski | 4 | 2.35% | 1 | 20.00% |
kuninori morimoto | kuninori morimoto | 3 | 1.76% | 1 | 20.00% |
| Total | 170 | 100.00% | 5 | 100.00% |
static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
.recalc = sh_clk_div_recalc,
.round_rate = sh_clk_div_round_rate,
.set_rate = sh_clk_div_set_rate,
.enable = sh_clk_div_enable,
.disable = sh_clk_div_disable,
.set_parent = sh_clk_div6_set_parent,
};
int __init sh_clk_div6_register(struct clk *clks, int nr)
{
return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
&sh_clk_div_enable_clk_ops);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
guennadi liakhovetski | guennadi liakhovetski | 23 | 82.14% | 1 | 33.33% |
paul mundt | paul mundt | 5 | 17.86% | 2 | 66.67% |
| Total | 28 | 100.00% | 3 | 100.00% |
int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
{
return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
&sh_clk_div6_reparent_clk_ops);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
guennadi liakhovetski | guennadi liakhovetski | 24 | 85.71% | 1 | 50.00% |
paul mundt | paul mundt | 4 | 14.29% | 1 | 50.00% |
| Total | 28 | 100.00% | 2 | 100.00% |
/*
* div4 support
*/
static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
{
struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
u32 value;
int ret;
/* we really need a better way to determine parent index, but for
* now assume internal parent comes with CLK_ENABLE_ON_INIT set,
* no CLK_ENABLE_ON_INIT means external clock...
*/
if (parent->flags & CLK_ENABLE_ON_INIT)
value = sh_clk_read(clk) & ~(1 << 7);
else
value = sh_clk_read(clk) | (1 << 7);
ret = clk_reparent(clk, parent);
if (ret < 0)
return ret;
sh_clk_write(value, clk);
/* Rebiuld the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, &clk->arch_flags);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
magnus damm | magnus damm | 111 | 94.07% | 1 | 33.33% |
paul mundt | paul mundt | 7 | 5.93% | 2 | 66.67% |
| Total | 118 | 100.00% | 3 | 100.00% |
static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
.recalc = sh_clk_div_recalc,
.set_rate = sh_clk_div_set_rate,
.round_rate = sh_clk_div_round_rate,
.enable = sh_clk_div_enable,
.disable = sh_clk_div_disable,
.set_parent = sh_clk_div4_set_parent,
};
int __init sh_clk_div4_register(struct clk *clks, int nr,
struct clk_div4_table *table)
{
return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
magnus damm | magnus damm | 30 | 93.75% | 1 | 33.33% |
paul mundt | paul mundt | 2 | 6.25% | 2 | 66.67% |
| Total | 32 | 100.00% | 3 | 100.00% |
int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
struct clk_div4_table *table)
{
return sh_clk_div_register_ops(clks, nr, table,
&sh_clk_div_enable_clk_ops);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
magnus damm | magnus damm | 30 | 93.75% | 1 | 33.33% |
paul mundt | paul mundt | 2 | 6.25% | 2 | 66.67% |
| Total | 32 | 100.00% | 3 | 100.00% |
int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
struct clk_div4_table *table)
{
return sh_clk_div_register_ops(clks, nr, table,
&sh_clk_div4_reparent_clk_ops);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
magnus damm | magnus damm | 31 | 96.88% | 1 | 50.00% |
paul mundt | paul mundt | 1 | 3.12% | 1 | 50.00% |
| Total | 32 | 100.00% | 2 | 100.00% |
/* FSI-DIV */
static unsigned long fsidiv_recalc(struct clk *clk)
{
u32 value;
value = __raw_readl(clk->mapping->base);
value >>= 16;
if (value < 2)
return clk->parent->rate;
return clk->parent->rate / value;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kuninori morimoto | kuninori morimoto | 52 | 100.00% | 1 | 100.00% |
| Total | 52 | 100.00% | 1 | 100.00% |
static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
{
return clk_rate_div_range_round(clk, 1, 0xffff, rate);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kuninori morimoto | kuninori morimoto | 27 | 100.00% | 1 | 100.00% |
| Total | 27 | 100.00% | 1 | 100.00% |
static void fsidiv_disable(struct clk *clk)
{
__raw_writel(0, clk->mapping->base);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kuninori morimoto | kuninori morimoto | 22 | 100.00% | 1 | 100.00% |
| Total | 22 | 100.00% | 1 | 100.00% |
static int fsidiv_enable(struct clk *clk)
{
u32 value;
value = __raw_readl(clk->mapping->base) >> 16;
if (value < 2)
return 0;
__raw_writel((value << 16) | 0x3, clk->mapping->base);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kuninori morimoto | kuninori morimoto | 56 | 100.00% | 1 | 100.00% |
| Total | 56 | 100.00% | 1 | 100.00% |
static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
{
int idx;
idx = (clk->parent->rate / rate) & 0xffff;
if (idx < 2)
__raw_writel(0, clk->mapping->base);
else
__raw_writel(idx << 16, clk->mapping->base);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kuninori morimoto | kuninori morimoto | 66 | 100.00% | 1 | 100.00% |
| Total | 66 | 100.00% | 1 | 100.00% |
static struct sh_clk_ops fsidiv_clk_ops = {
.recalc = fsidiv_recalc,
.round_rate = fsidiv_round_rate,
.set_rate = fsidiv_set_rate,
.enable = fsidiv_enable,
.disable = fsidiv_disable,
};
int __init sh_clk_fsidiv_register(struct clk *clks, int nr)
{
struct clk_mapping *map;
int i;
for (i = 0; i < nr; i++) {
map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL);
if (!map) {
pr_err("%s: unable to alloc memory\n", __func__);
return -ENOMEM;
}
/* clks[i].enable_reg came from SH_CLK_FSIDIV() */
map->phys = (phys_addr_t)clks[i].enable_reg;
map->len = 8;
clks[i].enable_reg = 0; /* remove .enable_reg */
clks[i].ops = &fsidiv_clk_ops;
clks[i].mapping = map;
clk_register(&clks[i]);
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kuninori morimoto | kuninori morimoto | 130 | 100.00% | 1 | 100.00% |
| Total | 130 | 100.00% | 1 | 100.00% |
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
paul mundt | paul mundt | 1058 | 46.44% | 8 | 50.00% |
kuninori morimoto | kuninori morimoto | 467 | 20.50% | 3 | 18.75% |
magnus damm | magnus damm | 449 | 19.71% | 3 | 18.75% |
guennadi liakhovetski | guennadi liakhovetski | 304 | 13.35% | 2 | 12.50% |
| Total | 2278 | 100.00% | 16 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.