forked from Minki/linux
Merge branch 'clk-3.7' of git://git.linaro.org/people/mturquette/linux into next/dt
* 'clk-3.7' of git://git.linaro.org/people/mturquette/linux: clk: add of_clk_src_onecell_get() support clk: ux500: Define smp_twd clock for u8500 mfd: dbx500: Provide a more accurate smp_twd clock clk: ux500: Support for prmcu_rate clock clk: Provide option for clk_get_rate to issue hw for new rate clock: max77686: Add driver for Maxim 77686 32Khz crystal oscillator. ARM: ux500: Switch to use common clock framework clk: ux500: Clock definitions for u8500 clk: ux500: First version of clock definitions for ux500 clk: ux500: Adapt PRCMU and PRCC clocks for common clk clk: versatile: make config option boolean clk: add Loongson1B clock support arm: mmp: make all SOCs use common clock by default clk: mmp: add clock definition for mmp2 clk: mmp: add clock definition for pxa910 clk: mmp: add clock definition for pxa168 clk: mmp: add mmp specific clocks clk: convert ARM RealView to common clk clk: prima2: move from arch/arm/mach to drivers/clk ARM: PRIMA2: convert to common clk and finish full clk tree
This commit is contained in:
commit
77ea4a300d
@ -273,7 +273,7 @@ config ARCH_INTEGRATOR
|
||||
select ARM_AMBA
|
||||
select ARCH_HAS_CPUFREQ
|
||||
select COMMON_CLK
|
||||
select CLK_VERSATILE
|
||||
select COMMON_CLK_VERSATILE
|
||||
select HAVE_TCM
|
||||
select ICST
|
||||
select GENERIC_CLOCKEVENTS
|
||||
@ -289,13 +289,12 @@ config ARCH_INTEGRATOR
|
||||
config ARCH_REALVIEW
|
||||
bool "ARM Ltd. RealView family"
|
||||
select ARM_AMBA
|
||||
select CLKDEV_LOOKUP
|
||||
select HAVE_MACH_CLKDEV
|
||||
select COMMON_CLK
|
||||
select COMMON_CLK_VERSATILE
|
||||
select ICST
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select PLAT_VERSATILE
|
||||
select PLAT_VERSATILE_CLOCK
|
||||
select PLAT_VERSATILE_CLCD
|
||||
select ARM_TIMER_SP804
|
||||
select GPIO_PL061 if GPIOLIB
|
||||
@ -413,7 +412,7 @@ config ARCH_PRIMA2
|
||||
select NO_IOPORT
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select CLKDEV_LOOKUP
|
||||
select COMMON_CLK
|
||||
select GENERIC_IRQ_CHIP
|
||||
select MIGHT_HAVE_CACHE_L2X0
|
||||
select PINCTRL
|
||||
|
@ -108,18 +108,21 @@ endmenu
|
||||
config CPU_PXA168
|
||||
bool
|
||||
select CPU_MOHAWK
|
||||
select COMMON_CLK
|
||||
help
|
||||
Select code specific to PXA168
|
||||
|
||||
config CPU_PXA910
|
||||
bool
|
||||
select CPU_MOHAWK
|
||||
select COMMON_CLK
|
||||
help
|
||||
Select code specific to PXA910
|
||||
|
||||
config CPU_MMP2
|
||||
bool
|
||||
select CPU_PJ4
|
||||
select COMMON_CLK
|
||||
help
|
||||
Select code specific to MMP2. MMP2 is ARMv7 compatible.
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
obj-y := timer.o
|
||||
obj-y += irq.o
|
||||
obj-y += clock.o
|
||||
obj-y += rstc.o
|
||||
obj-y += prima2.o
|
||||
obj-y += rtciobrg.o
|
||||
|
@ -1,510 +0,0 @@
|
||||
/*
|
||||
* Clock tree for CSR SiRFprimaII
|
||||
*
|
||||
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
|
||||
*
|
||||
* Licensed under GPLv2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
#define SIRFSOC_CLKC_CLK_EN0 0x0000
|
||||
#define SIRFSOC_CLKC_CLK_EN1 0x0004
|
||||
#define SIRFSOC_CLKC_REF_CFG 0x0014
|
||||
#define SIRFSOC_CLKC_CPU_CFG 0x0018
|
||||
#define SIRFSOC_CLKC_MEM_CFG 0x001c
|
||||
#define SIRFSOC_CLKC_SYS_CFG 0x0020
|
||||
#define SIRFSOC_CLKC_IO_CFG 0x0024
|
||||
#define SIRFSOC_CLKC_DSP_CFG 0x0028
|
||||
#define SIRFSOC_CLKC_GFX_CFG 0x002c
|
||||
#define SIRFSOC_CLKC_MM_CFG 0x0030
|
||||
#define SIRFSOC_LKC_LCD_CFG 0x0034
|
||||
#define SIRFSOC_CLKC_MMC_CFG 0x0038
|
||||
#define SIRFSOC_CLKC_PLL1_CFG0 0x0040
|
||||
#define SIRFSOC_CLKC_PLL2_CFG0 0x0044
|
||||
#define SIRFSOC_CLKC_PLL3_CFG0 0x0048
|
||||
#define SIRFSOC_CLKC_PLL1_CFG1 0x004c
|
||||
#define SIRFSOC_CLKC_PLL2_CFG1 0x0050
|
||||
#define SIRFSOC_CLKC_PLL3_CFG1 0x0054
|
||||
#define SIRFSOC_CLKC_PLL1_CFG2 0x0058
|
||||
#define SIRFSOC_CLKC_PLL2_CFG2 0x005c
|
||||
#define SIRFSOC_CLKC_PLL3_CFG2 0x0060
|
||||
|
||||
#define SIRFSOC_CLOCK_VA_BASE SIRFSOC_VA(0x005000)
|
||||
|
||||
#define KHZ 1000
|
||||
#define MHZ (KHZ * KHZ)
|
||||
|
||||
struct clk_ops {
|
||||
unsigned long (*get_rate)(struct clk *clk);
|
||||
long (*round_rate)(struct clk *clk, unsigned long rate);
|
||||
int (*set_rate)(struct clk *clk, unsigned long rate);
|
||||
int (*enable)(struct clk *clk);
|
||||
int (*disable)(struct clk *clk);
|
||||
struct clk *(*get_parent)(struct clk *clk);
|
||||
int (*set_parent)(struct clk *clk, struct clk *parent);
|
||||
};
|
||||
|
||||
struct clk {
|
||||
struct clk *parent; /* parent clk */
|
||||
unsigned long rate; /* clock rate in Hz */
|
||||
signed char usage; /* clock enable count */
|
||||
signed char enable_bit; /* enable bit: 0 ~ 63 */
|
||||
unsigned short regofs; /* register offset */
|
||||
struct clk_ops *ops; /* clock operation */
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(clocks_lock);
|
||||
|
||||
static inline unsigned long clkc_readl(unsigned reg)
|
||||
{
|
||||
return readl(SIRFSOC_CLOCK_VA_BASE + reg);
|
||||
}
|
||||
|
||||
static inline void clkc_writel(u32 val, unsigned reg)
|
||||
{
|
||||
writel(val, SIRFSOC_CLOCK_VA_BASE + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* osc_rtc - real time oscillator - 32.768KHz
|
||||
* osc_sys - high speed oscillator - 26MHz
|
||||
*/
|
||||
|
||||
static struct clk clk_rtc = {
|
||||
.rate = 32768,
|
||||
};
|
||||
|
||||
static struct clk clk_osc = {
|
||||
.rate = 26 * MHZ,
|
||||
};
|
||||
|
||||
/*
|
||||
* std pll
|
||||
*/
|
||||
static unsigned long std_pll_get_rate(struct clk *clk)
|
||||
{
|
||||
unsigned long fin = clk_get_rate(clk->parent);
|
||||
u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 -
|
||||
SIRFSOC_CLKC_PLL1_CFG0;
|
||||
|
||||
if (clkc_readl(regcfg2) & BIT(2)) {
|
||||
/* pll bypass mode */
|
||||
clk->rate = fin;
|
||||
} else {
|
||||
/* fout = fin * nf / nr / od */
|
||||
u32 cfg0 = clkc_readl(clk->regofs);
|
||||
u32 nf = (cfg0 & (BIT(13) - 1)) + 1;
|
||||
u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1;
|
||||
u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1;
|
||||
WARN_ON(fin % MHZ);
|
||||
clk->rate = fin / MHZ * nf / nr / od * MHZ;
|
||||
}
|
||||
|
||||
return clk->rate;
|
||||
}
|
||||
|
||||
static int std_pll_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned long fin, nf, nr, od, reg;
|
||||
|
||||
/*
|
||||
* fout = fin * nf / (nr * od);
|
||||
* set od = 1, nr = fin/MHz, so fout = nf * MHz
|
||||
*/
|
||||
|
||||
nf = rate / MHZ;
|
||||
if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1))
|
||||
return -EINVAL;
|
||||
|
||||
fin = clk_get_rate(clk->parent);
|
||||
BUG_ON(fin < MHZ);
|
||||
|
||||
nr = fin / MHZ;
|
||||
BUG_ON((fin % MHZ) || nr > BIT(6));
|
||||
|
||||
od = 1;
|
||||
|
||||
reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19);
|
||||
clkc_writel(reg, clk->regofs);
|
||||
|
||||
reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0;
|
||||
clkc_writel((nf >> 1) - 1, reg);
|
||||
|
||||
reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0;
|
||||
while (!(clkc_readl(reg) & BIT(6)))
|
||||
cpu_relax();
|
||||
|
||||
clk->rate = 0; /* set to zero will force recalculation */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops std_pll_ops = {
|
||||
.get_rate = std_pll_get_rate,
|
||||
.set_rate = std_pll_set_rate,
|
||||
};
|
||||
|
||||
static struct clk clk_pll1 = {
|
||||
.parent = &clk_osc,
|
||||
.regofs = SIRFSOC_CLKC_PLL1_CFG0,
|
||||
.ops = &std_pll_ops,
|
||||
};
|
||||
|
||||
static struct clk clk_pll2 = {
|
||||
.parent = &clk_osc,
|
||||
.regofs = SIRFSOC_CLKC_PLL2_CFG0,
|
||||
.ops = &std_pll_ops,
|
||||
};
|
||||
|
||||
static struct clk clk_pll3 = {
|
||||
.parent = &clk_osc,
|
||||
.regofs = SIRFSOC_CLKC_PLL3_CFG0,
|
||||
.ops = &std_pll_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
* clock domains - cpu, mem, sys/io
|
||||
*/
|
||||
|
||||
static struct clk clk_mem;
|
||||
|
||||
static struct clk *dmn_get_parent(struct clk *clk)
|
||||
{
|
||||
struct clk *clks[] = {
|
||||
&clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
|
||||
};
|
||||
u32 cfg = clkc_readl(clk->regofs);
|
||||
WARN_ON((cfg & (BIT(3) - 1)) > 4);
|
||||
return clks[cfg & (BIT(3) - 1)];
|
||||
}
|
||||
|
||||
static int dmn_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
const struct clk *clks[] = {
|
||||
&clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
|
||||
};
|
||||
u32 cfg = clkc_readl(clk->regofs);
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(clks); i++) {
|
||||
if (clks[i] == parent) {
|
||||
cfg &= ~(BIT(3) - 1);
|
||||
clkc_writel(cfg | i, clk->regofs);
|
||||
/* BIT(3) - switching status: 1 - busy, 0 - done */
|
||||
while (clkc_readl(clk->regofs) & BIT(3))
|
||||
cpu_relax();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static unsigned long dmn_get_rate(struct clk *clk)
|
||||
{
|
||||
unsigned long fin = clk_get_rate(clk->parent);
|
||||
u32 cfg = clkc_readl(clk->regofs);
|
||||
if (cfg & BIT(24)) {
|
||||
/* fcd bypass mode */
|
||||
clk->rate = fin;
|
||||
} else {
|
||||
/*
|
||||
* wait count: bit[19:16], hold count: bit[23:20]
|
||||
*/
|
||||
u32 wait = (cfg >> 16) & (BIT(4) - 1);
|
||||
u32 hold = (cfg >> 20) & (BIT(4) - 1);
|
||||
|
||||
clk->rate = fin / (wait + hold + 2);
|
||||
}
|
||||
|
||||
return clk->rate;
|
||||
}
|
||||
|
||||
static int dmn_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned long fin;
|
||||
unsigned ratio, wait, hold, reg;
|
||||
unsigned bits = (clk == &clk_mem) ? 3 : 4;
|
||||
|
||||
fin = clk_get_rate(clk->parent);
|
||||
ratio = fin / rate;
|
||||
|
||||
if (unlikely(ratio < 2 || ratio > BIT(bits + 1)))
|
||||
return -EINVAL;
|
||||
|
||||
WARN_ON(fin % rate);
|
||||
|
||||
wait = (ratio >> 1) - 1;
|
||||
hold = ratio - wait - 2;
|
||||
|
||||
reg = clkc_readl(clk->regofs);
|
||||
reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20));
|
||||
reg |= (wait << 16) | (hold << 20) | BIT(25);
|
||||
clkc_writel(reg, clk->regofs);
|
||||
|
||||
/* waiting FCD been effective */
|
||||
while (clkc_readl(clk->regofs) & BIT(25))
|
||||
cpu_relax();
|
||||
|
||||
clk->rate = 0; /* set to zero will force recalculation */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cpu clock has no FCD register in Prima2, can only change pll
|
||||
*/
|
||||
static int cpu_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
int ret1, ret2;
|
||||
struct clk *cur_parent, *tmp_parent;
|
||||
|
||||
cur_parent = dmn_get_parent(clk);
|
||||
BUG_ON(cur_parent == NULL || cur_parent->usage > 1);
|
||||
|
||||
/* switch to tmp pll before setting parent clock's rate */
|
||||
tmp_parent = cur_parent == &clk_pll1 ? &clk_pll2 : &clk_pll1;
|
||||
ret1 = dmn_set_parent(clk, tmp_parent);
|
||||
BUG_ON(ret1);
|
||||
|
||||
ret2 = clk_set_rate(cur_parent, rate);
|
||||
|
||||
ret1 = dmn_set_parent(clk, cur_parent);
|
||||
|
||||
clk->rate = 0; /* set to zero will force recalculation */
|
||||
|
||||
return ret2 ? ret2 : ret1;
|
||||
}
|
||||
|
||||
static struct clk_ops cpu_ops = {
|
||||
.get_parent = dmn_get_parent,
|
||||
.set_parent = dmn_set_parent,
|
||||
.set_rate = cpu_set_rate,
|
||||
};
|
||||
|
||||
static struct clk clk_cpu = {
|
||||
.parent = &clk_pll1,
|
||||
.regofs = SIRFSOC_CLKC_CPU_CFG,
|
||||
.ops = &cpu_ops,
|
||||
};
|
||||
|
||||
|
||||
static struct clk_ops msi_ops = {
|
||||
.set_rate = dmn_set_rate,
|
||||
.get_rate = dmn_get_rate,
|
||||
.set_parent = dmn_set_parent,
|
||||
.get_parent = dmn_get_parent,
|
||||
};
|
||||
|
||||
static struct clk clk_mem = {
|
||||
.parent = &clk_pll2,
|
||||
.regofs = SIRFSOC_CLKC_MEM_CFG,
|
||||
.ops = &msi_ops,
|
||||
};
|
||||
|
||||
static struct clk clk_sys = {
|
||||
.parent = &clk_pll3,
|
||||
.regofs = SIRFSOC_CLKC_SYS_CFG,
|
||||
.ops = &msi_ops,
|
||||
};
|
||||
|
||||
static struct clk clk_io = {
|
||||
.parent = &clk_pll3,
|
||||
.regofs = SIRFSOC_CLKC_IO_CFG,
|
||||
.ops = &msi_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
* on-chip clock sets
|
||||
*/
|
||||
static struct clk_lookup onchip_clks[] = {
|
||||
{
|
||||
.dev_id = "rtc",
|
||||
.clk = &clk_rtc,
|
||||
}, {
|
||||
.dev_id = "osc",
|
||||
.clk = &clk_osc,
|
||||
}, {
|
||||
.dev_id = "pll1",
|
||||
.clk = &clk_pll1,
|
||||
}, {
|
||||
.dev_id = "pll2",
|
||||
.clk = &clk_pll2,
|
||||
}, {
|
||||
.dev_id = "pll3",
|
||||
.clk = &clk_pll3,
|
||||
}, {
|
||||
.dev_id = "cpu",
|
||||
.clk = &clk_cpu,
|
||||
}, {
|
||||
.dev_id = "mem",
|
||||
.clk = &clk_mem,
|
||||
}, {
|
||||
.dev_id = "sys",
|
||||
.clk = &clk_sys,
|
||||
}, {
|
||||
.dev_id = "io",
|
||||
.clk = &clk_io,
|
||||
},
|
||||
};
|
||||
|
||||
int clk_enable(struct clk *clk)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(IS_ERR_OR_NULL(clk)))
|
||||
return -EINVAL;
|
||||
|
||||
if (clk->parent)
|
||||
clk_enable(clk->parent);
|
||||
|
||||
spin_lock_irqsave(&clocks_lock, flags);
|
||||
if (!clk->usage++ && clk->ops && clk->ops->enable)
|
||||
clk->ops->enable(clk);
|
||||
spin_unlock_irqrestore(&clocks_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_enable);
|
||||
|
||||
void clk_disable(struct clk *clk)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(IS_ERR_OR_NULL(clk)))
|
||||
return;
|
||||
|
||||
WARN_ON(!clk->usage);
|
||||
|
||||
spin_lock_irqsave(&clocks_lock, flags);
|
||||
if (--clk->usage == 0 && clk->ops && clk->ops->disable)
|
||||
clk->ops->disable(clk);
|
||||
spin_unlock_irqrestore(&clocks_lock, flags);
|
||||
|
||||
if (clk->parent)
|
||||
clk_disable(clk->parent);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_disable);
|
||||
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
if (unlikely(IS_ERR_OR_NULL(clk)))
|
||||
return 0;
|
||||
|
||||
if (clk->rate)
|
||||
return clk->rate;
|
||||
|
||||
if (clk->ops && clk->ops->get_rate)
|
||||
return clk->ops->get_rate(clk);
|
||||
|
||||
return clk_get_rate(clk->parent);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_rate);
|
||||
|
||||
long clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
if (unlikely(IS_ERR_OR_NULL(clk)))
|
||||
return 0;
|
||||
|
||||
if (clk->ops && clk->ops->round_rate)
|
||||
return clk->ops->round_rate(clk, rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_round_rate);
|
||||
|
||||
int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
if (unlikely(IS_ERR_OR_NULL(clk)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!clk->ops || !clk->ops->set_rate)
|
||||
return -EINVAL;
|
||||
|
||||
return clk->ops->set_rate(clk, rate);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_rate);
|
||||
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(IS_ERR_OR_NULL(clk)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!clk->ops || !clk->ops->set_parent)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&clocks_lock, flags);
|
||||
ret = clk->ops->set_parent(clk, parent);
|
||||
if (!ret) {
|
||||
parent->usage += clk->usage;
|
||||
clk->parent->usage -= clk->usage;
|
||||
BUG_ON(clk->parent->usage < 0);
|
||||
clk->parent = parent;
|
||||
}
|
||||
spin_unlock_irqrestore(&clocks_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_parent);
|
||||
|
||||
struct clk *clk_get_parent(struct clk *clk)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(IS_ERR_OR_NULL(clk)))
|
||||
return NULL;
|
||||
|
||||
if (!clk->ops || !clk->ops->get_parent)
|
||||
return clk->parent;
|
||||
|
||||
spin_lock_irqsave(&clocks_lock, flags);
|
||||
clk->parent = clk->ops->get_parent(clk);
|
||||
spin_unlock_irqrestore(&clocks_lock, flags);
|
||||
return clk->parent;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_parent);
|
||||
|
||||
static void __init sirfsoc_clk_init(void)
|
||||
{
|
||||
clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks));
|
||||
}
|
||||
|
||||
static struct of_device_id clkc_ids[] = {
|
||||
{ .compatible = "sirf,prima2-clkc" },
|
||||
{},
|
||||
};
|
||||
|
||||
void __init sirfsoc_of_clk_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource res;
|
||||
struct map_desc sirfsoc_clkc_iodesc = {
|
||||
.virtual = SIRFSOC_CLOCK_VA_BASE,
|
||||
.type = MT_DEVICE,
|
||||
};
|
||||
|
||||
np = of_find_matching_node(NULL, clkc_ids);
|
||||
if (!np)
|
||||
panic("unable to find compatible clkc node in dtb\n");
|
||||
|
||||
if (of_address_to_resource(np, 0, &res))
|
||||
panic("unable to find clkc range in dtb");
|
||||
of_node_put(np);
|
||||
|
||||
sirfsoc_clkc_iodesc.pfn = __phys_to_pfn(res.start);
|
||||
sirfsoc_clkc_iodesc.length = 1 + res.end - res.start;
|
||||
|
||||
iotable_init(&sirfsoc_clkc_iodesc, 1);
|
||||
|
||||
sirfsoc_clk_init();
|
||||
}
|
@ -38,7 +38,6 @@ static const char *prima2cb_dt_match[] __initdata = {
|
||||
MACHINE_START(PRIMA2_EVB, "prima2cb")
|
||||
/* Maintainer: Barry Song <baohua.song@csr.com> */
|
||||
.atag_offset = 0x100,
|
||||
.init_early = sirfsoc_of_clk_init,
|
||||
.map_io = sirfsoc_map_lluart,
|
||||
.init_irq = sirfsoc_of_irq_init,
|
||||
.timer = &sirfsoc_timer,
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <asm/sched_clock.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SIRFSOC_TIMER_COUNTER_LO 0x0000
|
||||
#define SIRFSOC_TIMER_COUNTER_HI 0x0004
|
||||
#define SIRFSOC_TIMER_MATCH_0 0x0008
|
||||
@ -188,9 +190,13 @@ static void __init sirfsoc_clockevent_init(void)
|
||||
static void __init sirfsoc_timer_init(void)
|
||||
{
|
||||
unsigned long rate;
|
||||
struct clk *clk;
|
||||
|
||||
/* initialize clocking early, we want to set the OS timer */
|
||||
sirfsoc_of_clk_init();
|
||||
|
||||
/* timer's input clock is io clock */
|
||||
struct clk *clk = clk_get_sys("io", NULL);
|
||||
clk = clk_get_sys("io", NULL);
|
||||
|
||||
BUG_ON(IS_ERR(clk));
|
||||
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/amba/mmci.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
@ -226,115 +225,10 @@ struct mmci_platform_data realview_mmc1_plat_data = {
|
||||
.cd_invert = true,
|
||||
};
|
||||
|
||||
/*
|
||||
* Clock handling
|
||||
*/
|
||||
static const struct icst_params realview_oscvco_params = {
|
||||
.ref = 24000000,
|
||||
.vco_max = ICST307_VCO_MAX,
|
||||
.vco_min = ICST307_VCO_MIN,
|
||||
.vd_min = 4 + 8,
|
||||
.vd_max = 511 + 8,
|
||||
.rd_min = 1 + 2,
|
||||
.rd_max = 127 + 2,
|
||||
.s2div = icst307_s2div,
|
||||
.idx2s = icst307_idx2s,
|
||||
};
|
||||
|
||||
static void realview_oscvco_set(struct clk *clk, struct icst_vco vco)
|
||||
{
|
||||
void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET;
|
||||
u32 val;
|
||||
|
||||
val = readl(clk->vcoreg) & ~0x7ffff;
|
||||
val |= vco.v | (vco.r << 9) | (vco.s << 16);
|
||||
|
||||
writel(0xa05f, sys_lock);
|
||||
writel(val, clk->vcoreg);
|
||||
writel(0, sys_lock);
|
||||
}
|
||||
|
||||
static const struct clk_ops oscvco_clk_ops = {
|
||||
.round = icst_clk_round,
|
||||
.set = icst_clk_set,
|
||||
.setvco = realview_oscvco_set,
|
||||
};
|
||||
|
||||
static struct clk oscvco_clk = {
|
||||
.ops = &oscvco_clk_ops,
|
||||
.params = &realview_oscvco_params,
|
||||
};
|
||||
|
||||
/*
|
||||
* These are fixed clocks.
|
||||
*/
|
||||
static struct clk ref24_clk = {
|
||||
.rate = 24000000,
|
||||
};
|
||||
|
||||
static struct clk sp804_clk = {
|
||||
.rate = 1000000,
|
||||
};
|
||||
|
||||
static struct clk dummy_apb_pclk;
|
||||
|
||||
static struct clk_lookup lookups[] = {
|
||||
{ /* Bus clock */
|
||||
.con_id = "apb_pclk",
|
||||
.clk = &dummy_apb_pclk,
|
||||
}, { /* UART0 */
|
||||
.dev_id = "dev:uart0",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* UART1 */
|
||||
.dev_id = "dev:uart1",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* UART2 */
|
||||
.dev_id = "dev:uart2",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* UART3 */
|
||||
.dev_id = "fpga:uart3",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* UART3 is on the dev chip in PB1176 */
|
||||
.dev_id = "dev:uart3",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* UART4 only exists in PB1176 */
|
||||
.dev_id = "fpga:uart4",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* KMI0 */
|
||||
.dev_id = "fpga:kmi0",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* KMI1 */
|
||||
.dev_id = "fpga:kmi1",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* MMC0 */
|
||||
.dev_id = "fpga:mmc0",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* CLCD is in the PB1176 and EB DevChip */
|
||||
.dev_id = "dev:clcd",
|
||||
.clk = &oscvco_clk,
|
||||
}, { /* PB:CLCD */
|
||||
.dev_id = "issp:clcd",
|
||||
.clk = &oscvco_clk,
|
||||
}, { /* SSP */
|
||||
.dev_id = "dev:ssp0",
|
||||
.clk = &ref24_clk,
|
||||
}, { /* SP804 timers */
|
||||
.dev_id = "sp804",
|
||||
.clk = &sp804_clk,
|
||||
},
|
||||
};
|
||||
|
||||
void __init realview_init_early(void)
|
||||
{
|
||||
void __iomem *sys = __io_address(REALVIEW_SYS_BASE);
|
||||
|
||||
if (machine_is_realview_pb1176())
|
||||
oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC0_OFFSET;
|
||||
else
|
||||
oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC4_OFFSET;
|
||||
|
||||
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
|
||||
|
||||
versatile_sched_clock_init(sys + REALVIEW_SYS_24MHz_OFFSET, 24000000);
|
||||
}
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
#ifndef __ASM_MACH_CLKDEV_H
|
||||
#define __ASM_MACH_CLKDEV_H
|
||||
|
||||
#include <plat/clock.h>
|
||||
|
||||
struct clk {
|
||||
unsigned long rate;
|
||||
const struct clk_ops *ops;
|
||||
const struct icst_params *params;
|
||||
void __iomem *vcoreg;
|
||||
};
|
||||
|
||||
#define __clk_get(clk) ({ 1; })
|
||||
#define __clk_put(clk) do { } while (0)
|
||||
|
||||
#endif
|
@ -27,6 +27,7 @@
|
||||
#include <linux/amba/mmci.h>
|
||||
#include <linux/amba/pl022.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/clk-realview.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
@ -414,6 +415,7 @@ static void __init realview_eb_timer_init(void)
|
||||
else
|
||||
timer_irq = IRQ_EB_TIMER0_1;
|
||||
|
||||
realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
|
||||
realview_timer_init(timer_irq);
|
||||
realview_eb_twd_init();
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/clk-realview.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
@ -326,6 +327,7 @@ static void __init realview_pb1176_timer_init(void)
|
||||
timer2_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE);
|
||||
timer3_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE) + 0x20;
|
||||
|
||||
realview_clk_init(__io_address(REALVIEW_SYS_BASE), true);
|
||||
realview_timer_init(IRQ_DC1176_TIMER0);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/amba/mmci.h>
|
||||
#include <linux/amba/pl022.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/clk-realview.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
@ -312,6 +313,7 @@ static void __init realview_pb11mp_timer_init(void)
|
||||
timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE);
|
||||
timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
|
||||
|
||||
realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
|
||||
realview_timer_init(IRQ_TC11MP_TIMER0_1);
|
||||
realview_pb11mp_twd_init();
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/amba/mmci.h>
|
||||
#include <linux/amba/pl022.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/clk-realview.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/leds.h>
|
||||
@ -261,6 +262,7 @@ static void __init realview_pba8_timer_init(void)
|
||||
timer2_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE);
|
||||
timer3_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE) + 0x20;
|
||||
|
||||
realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
|
||||
realview_timer_init(IRQ_PBA8_TIMER0_1);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/amba/mmci.h>
|
||||
#include <linux/amba/pl022.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/clk-realview.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/leds.h>
|
||||
@ -320,6 +321,7 @@ static void __init realview_pbx_timer_init(void)
|
||||
timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
|
||||
timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
|
||||
|
||||
realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
|
||||
realview_timer_init(IRQ_PBX_TIMER0_1);
|
||||
realview_pbx_twd_init();
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ config UX500_SOC_COMMON
|
||||
select CACHE_L2X0
|
||||
select PINCTRL
|
||||
select PINCTRL_NOMADIK
|
||||
select COMMON_CLK
|
||||
|
||||
config UX500_SOC_DB8500
|
||||
bool
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Makefile for the linux kernel, U8500 machine.
|
||||
#
|
||||
|
||||
obj-y := clock.o cpu.o devices.o devices-common.o \
|
||||
obj-y := cpu.o devices.o devices-common.o \
|
||||
id.o usb.o timer.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
|
||||
|
@ -1,715 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 ST-Ericsson
|
||||
* Copyright (C) 2009 STMicroelectronics
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/cpufreq.h>
|
||||
|
||||
#include <plat/mtu.h>
|
||||
#include <mach/hardware.h>
|
||||
#include "clock.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h> /* for copy_from_user */
|
||||
static LIST_HEAD(clk_list);
|
||||
#endif
|
||||
|
||||
#define PRCC_PCKEN 0x00
|
||||
#define PRCC_PCKDIS 0x04
|
||||
#define PRCC_KCKEN 0x08
|
||||
#define PRCC_KCKDIS 0x0C
|
||||
|
||||
#define PRCM_YYCLKEN0_MGT_SET 0x510
|
||||
#define PRCM_YYCLKEN1_MGT_SET 0x514
|
||||
#define PRCM_YYCLKEN0_MGT_CLR 0x518
|
||||
#define PRCM_YYCLKEN1_MGT_CLR 0x51C
|
||||
#define PRCM_YYCLKEN0_MGT_VAL 0x520
|
||||
#define PRCM_YYCLKEN1_MGT_VAL 0x524
|
||||
|
||||
#define PRCM_SVAMMDSPCLK_MGT 0x008
|
||||
#define PRCM_SIAMMDSPCLK_MGT 0x00C
|
||||
#define PRCM_SGACLK_MGT 0x014
|
||||
#define PRCM_UARTCLK_MGT 0x018
|
||||
#define PRCM_MSP02CLK_MGT 0x01C
|
||||
#define PRCM_MSP1CLK_MGT 0x288
|
||||
#define PRCM_I2CCLK_MGT 0x020
|
||||
#define PRCM_SDMMCCLK_MGT 0x024
|
||||
#define PRCM_SLIMCLK_MGT 0x028
|
||||
#define PRCM_PER1CLK_MGT 0x02C
|
||||
#define PRCM_PER2CLK_MGT 0x030
|
||||
#define PRCM_PER3CLK_MGT 0x034
|
||||
#define PRCM_PER5CLK_MGT 0x038
|
||||
#define PRCM_PER6CLK_MGT 0x03C
|
||||
#define PRCM_PER7CLK_MGT 0x040
|
||||
#define PRCM_LCDCLK_MGT 0x044
|
||||
#define PRCM_BMLCLK_MGT 0x04C
|
||||
#define PRCM_HSITXCLK_MGT 0x050
|
||||
#define PRCM_HSIRXCLK_MGT 0x054
|
||||
#define PRCM_HDMICLK_MGT 0x058
|
||||
#define PRCM_APEATCLK_MGT 0x05C
|
||||
#define PRCM_APETRACECLK_MGT 0x060
|
||||
#define PRCM_MCDECLK_MGT 0x064
|
||||
#define PRCM_IPI2CCLK_MGT 0x068
|
||||
#define PRCM_DSIALTCLK_MGT 0x06C
|
||||
#define PRCM_DMACLK_MGT 0x074
|
||||
#define PRCM_B2R2CLK_MGT 0x078
|
||||
#define PRCM_TVCLK_MGT 0x07C
|
||||
#define PRCM_TCR 0x1C8
|
||||
#define PRCM_TCR_STOPPED (1 << 16)
|
||||
#define PRCM_TCR_DOZE_MODE (1 << 17)
|
||||
#define PRCM_UNIPROCLK_MGT 0x278
|
||||
#define PRCM_SSPCLK_MGT 0x280
|
||||
#define PRCM_RNGCLK_MGT 0x284
|
||||
#define PRCM_UICCCLK_MGT 0x27C
|
||||
|
||||
#define PRCM_MGT_ENABLE (1 << 8)
|
||||
|
||||
static DEFINE_SPINLOCK(clocks_lock);
|
||||
|
||||
static void __clk_enable(struct clk *clk)
|
||||
{
|
||||
if (clk->enabled++ == 0) {
|
||||
if (clk->parent_cluster)
|
||||
__clk_enable(clk->parent_cluster);
|
||||
|
||||
if (clk->parent_periph)
|
||||
__clk_enable(clk->parent_periph);
|
||||
|
||||
if (clk->ops && clk->ops->enable)
|
||||
clk->ops->enable(clk);
|
||||
}
|
||||
}
|
||||
|
||||
int clk_enable(struct clk *clk)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&clocks_lock, flags);
|
||||
__clk_enable(clk);
|
||||
spin_unlock_irqrestore(&clocks_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_enable);
|
||||
|
||||
static void __clk_disable(struct clk *clk)
|
||||
{
|
||||
if (--clk->enabled == 0) {
|
||||
if (clk->ops && clk->ops->disable)
|
||||
clk->ops->disable(clk);
|
||||
|
||||
if (clk->parent_periph)
|
||||
__clk_disable(clk->parent_periph);
|
||||
|
||||
if (clk->parent_cluster)
|
||||
__clk_disable(clk->parent_cluster);
|
||||
}
|
||||
}
|
||||
|
||||
void clk_disable(struct clk *clk)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(!clk->enabled);
|
||||
|
||||
spin_lock_irqsave(&clocks_lock, flags);
|
||||
__clk_disable(clk);
|
||||
spin_unlock_irqrestore(&clocks_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_disable);
|
||||
|
||||
/*
|
||||
* The MTU has a separate, rather complex muxing setup
|
||||
* with alternative parents (peripheral cluster or
|
||||
* ULP or fixed 32768 Hz) depending on settings
|
||||
*/
|
||||
static unsigned long clk_mtu_get_rate(struct clk *clk)
|
||||
{
|
||||
void __iomem *addr;
|
||||
u32 tcr;
|
||||
int mtu = (int) clk->data;
|
||||
/*
|
||||
* One of these is selected eventually
|
||||
* TODO: Replace the constant with a reference
|
||||
* to the ULP source once this is modeled.
|
||||
*/
|
||||
unsigned long clk32k = 32768;
|
||||
unsigned long mturate;
|
||||
unsigned long retclk;
|
||||
|
||||
if (cpu_is_u8500_family())
|
||||
addr = __io_address(U8500_PRCMU_BASE);
|
||||
else
|
||||
ux500_unknown_soc();
|
||||
|
||||
/*
|
||||
* On a startup, always conifgure the TCR to the doze mode;
|
||||
* bootloaders do it for us. Do this in the kernel too.
|
||||
*/
|
||||
writel(PRCM_TCR_DOZE_MODE, addr + PRCM_TCR);
|
||||
|
||||
tcr = readl(addr + PRCM_TCR);
|
||||
|
||||
/* Get the rate from the parent as a default */
|
||||
if (clk->parent_periph)
|
||||
mturate = clk_get_rate(clk->parent_periph);
|
||||
else if (clk->parent_cluster)
|
||||
mturate = clk_get_rate(clk->parent_cluster);
|
||||
else
|
||||
/* We need to be connected SOMEWHERE */
|
||||
BUG();
|
||||
|
||||
/* Return the clock selected for this MTU */
|
||||
if (tcr & (1 << mtu))
|
||||
retclk = clk32k;
|
||||
else
|
||||
retclk = mturate;
|
||||
|
||||
pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
|
||||
return retclk;
|
||||
}
|
||||
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
/*
|
||||
* If there is a custom getrate callback for this clock,
|
||||
* it will take precedence.
|
||||
*/
|
||||
if (clk->get_rate)
|
||||
return clk->get_rate(clk);
|
||||
|
||||
if (clk->ops && clk->ops->get_rate)
|
||||
return clk->ops->get_rate(clk);
|
||||
|
||||
rate = clk->rate;
|
||||
if (!rate) {
|
||||
if (clk->parent_periph)
|
||||
rate = clk_get_rate(clk->parent_periph);
|
||||
else if (clk->parent_cluster)
|
||||
rate = clk_get_rate(clk->parent_cluster);
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_rate);
|
||||
|
||||
long clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
/*TODO*/
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_round_rate);
|
||||
|
||||
int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
clk->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_rate);
|
||||
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
/*TODO*/
|
||||
return -ENOSYS;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_parent);
|
||||
|
||||
static void clk_prcmu_enable(struct clk *clk)
|
||||
{
|
||||
void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
|
||||
+ PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off;
|
||||
|
||||
writel(1 << clk->prcmu_cg_bit, cg_set_reg);
|
||||
}
|
||||
|
||||
static void clk_prcmu_disable(struct clk *clk)
|
||||
{
|
||||
void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE)
|
||||
+ PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off;
|
||||
|
||||
writel(1 << clk->prcmu_cg_bit, cg_clr_reg);
|
||||
}
|
||||
|
||||
static struct clkops clk_prcmu_ops = {
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
};
|
||||
|
||||
static unsigned int clkrst_base[] = {
|
||||
[1] = U8500_CLKRST1_BASE,
|
||||
[2] = U8500_CLKRST2_BASE,
|
||||
[3] = U8500_CLKRST3_BASE,
|
||||
[5] = U8500_CLKRST5_BASE,
|
||||
[6] = U8500_CLKRST6_BASE,
|
||||
};
|
||||
|
||||
static void clk_prcc_enable(struct clk *clk)
|
||||
{
|
||||
void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
|
||||
|
||||
if (clk->prcc_kernel != -1)
|
||||
writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN);
|
||||
|
||||
if (clk->prcc_bus != -1)
|
||||
writel(1 << clk->prcc_bus, addr + PRCC_PCKEN);
|
||||
}
|
||||
|
||||
static void clk_prcc_disable(struct clk *clk)
|
||||
{
|
||||
void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
|
||||
|
||||
if (clk->prcc_bus != -1)
|
||||
writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS);
|
||||
|
||||
if (clk->prcc_kernel != -1)
|
||||
writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS);
|
||||
}
|
||||
|
||||
static struct clkops clk_prcc_ops = {
|
||||
.enable = clk_prcc_enable,
|
||||
.disable = clk_prcc_disable,
|
||||
};
|
||||
|
||||
static struct clk clk_32khz = {
|
||||
.name = "clk_32khz",
|
||||
.rate = 32000,
|
||||
};
|
||||
|
||||
/*
|
||||
* PRCMU level clock gating
|
||||
*/
|
||||
|
||||
/* Bank 0 */
|
||||
static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK);
|
||||
static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK);
|
||||
static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK);
|
||||
static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000);
|
||||
static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK);
|
||||
static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */
|
||||
static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000);
|
||||
static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 100000000);
|
||||
static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK);
|
||||
static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK);
|
||||
static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK);
|
||||
static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK);
|
||||
static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK);
|
||||
static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000);
|
||||
static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK);
|
||||
static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK);
|
||||
static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK);
|
||||
static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK);
|
||||
static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK);
|
||||
static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK);
|
||||
static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK);
|
||||
static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK);
|
||||
static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK);
|
||||
static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */
|
||||
static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK);
|
||||
static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK);
|
||||
static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK);
|
||||
static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */
|
||||
static DEFINE_PRCMU_CLK_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* v1 */
|
||||
|
||||
/* Bank 1 */
|
||||
static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */
|
||||
static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */
|
||||
|
||||
/*
|
||||
* PRCC level clock gating
|
||||
* Format: per#, clk, PCKEN bit, KCKEN bit, parent
|
||||
*/
|
||||
|
||||
/* Peripheral Cluster #1 */
|
||||
static DEFINE_PRCC_CLK(1, msp3, 11, 10, &clk_msp1clk);
|
||||
static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
|
||||
static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
|
||||
static DEFINE_PRCC_CLK(1, spi3, 7, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk);
|
||||
static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk);
|
||||
static DEFINE_PRCC_CLK(1, msp1, 4, 4, &clk_msp1clk);
|
||||
static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk);
|
||||
static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk);
|
||||
static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk);
|
||||
static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk);
|
||||
|
||||
/* Peripheral Cluster #2 */
|
||||
static DEFINE_PRCC_CLK(2, gpio1, 11, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(2, ssitx, 10, 7, NULL);
|
||||
static DEFINE_PRCC_CLK(2, ssirx, 9, 6, NULL);
|
||||
static DEFINE_PRCC_CLK(2, spi0, 8, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(2, sdi3, 7, 5, &clk_sdmmcclk);
|
||||
static DEFINE_PRCC_CLK(2, sdi1, 6, 4, &clk_sdmmcclk);
|
||||
static DEFINE_PRCC_CLK(2, msp2, 5, 3, &clk_msp02clk);
|
||||
static DEFINE_PRCC_CLK(2, sdi4, 4, 2, &clk_sdmmcclk);
|
||||
static DEFINE_PRCC_CLK(2, pwl, 3, 1, NULL);
|
||||
static DEFINE_PRCC_CLK(2, spi1, 2, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(2, spi2, 1, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(2, i2c3, 0, 0, &clk_i2cclk);
|
||||
|
||||
/* Peripheral Cluster #3 */
|
||||
static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk);
|
||||
static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk);
|
||||
static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz);
|
||||
static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk);
|
||||
static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk);
|
||||
static DEFINE_PRCC_CLK(3, ssp1, 2, 2, &clk_sspclk);
|
||||
static DEFINE_PRCC_CLK(3, ssp0, 1, 1, &clk_sspclk);
|
||||
static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL);
|
||||
|
||||
/* Peripheral Cluster #4 is in the always on domain */
|
||||
|
||||
/* Peripheral Cluster #5 */
|
||||
static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(5, usb, 0, 0, NULL);
|
||||
|
||||
/* Peripheral Cluster #6 */
|
||||
|
||||
/* MTU ID in data */
|
||||
static DEFINE_PRCC_CLK_CUSTOM(6, mtu1, 9, -1, NULL, clk_mtu_get_rate, 1);
|
||||
static DEFINE_PRCC_CLK_CUSTOM(6, mtu0, 8, -1, NULL, clk_mtu_get_rate, 0);
|
||||
static DEFINE_PRCC_CLK(6, cfgreg, 7, 7, NULL);
|
||||
static DEFINE_PRCC_CLK(6, hash1, 6, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(6, unipro, 5, 1, &clk_uniproclk);
|
||||
static DEFINE_PRCC_CLK(6, pka, 4, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(6, hash0, 3, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(6, cryp0, 2, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(6, cryp1, 1, -1, NULL);
|
||||
static DEFINE_PRCC_CLK(6, rng, 0, 0, &clk_rngclk);
|
||||
|
||||
static struct clk clk_dummy_apb_pclk = {
|
||||
.name = "apb_pclk",
|
||||
};
|
||||
|
||||
static struct clk_lookup u8500_clks[] = {
|
||||
CLK(dummy_apb_pclk, NULL, "apb_pclk"),
|
||||
|
||||
/* Peripheral Cluster #1 */
|
||||
CLK(gpio0, "gpio.0", NULL),
|
||||
CLK(gpio0, "gpio.1", NULL),
|
||||
CLK(slimbus0, "slimbus0", NULL),
|
||||
CLK(i2c2, "nmk-i2c.2", NULL),
|
||||
CLK(sdi0, "sdi0", NULL),
|
||||
CLK(msp0, "ux500-msp-i2s.0", NULL),
|
||||
CLK(i2c1, "nmk-i2c.1", NULL),
|
||||
CLK(uart1, "uart1", NULL),
|
||||
CLK(uart0, "uart0", NULL),
|
||||
|
||||
/* Peripheral Cluster #3 */
|
||||
CLK(gpio2, "gpio.2", NULL),
|
||||
CLK(gpio2, "gpio.3", NULL),
|
||||
CLK(gpio2, "gpio.4", NULL),
|
||||
CLK(gpio2, "gpio.5", NULL),
|
||||
CLK(sdi5, "sdi5", NULL),
|
||||
CLK(uart2, "uart2", NULL),
|
||||
CLK(ske, "ske", NULL),
|
||||
CLK(ske, "nmk-ske-keypad", NULL),
|
||||
CLK(sdi2, "sdi2", NULL),
|
||||
CLK(i2c0, "nmk-i2c.0", NULL),
|
||||
CLK(fsmc, "fsmc", NULL),
|
||||
|
||||
/* Peripheral Cluster #5 */
|
||||
CLK(gpio3, "gpio.8", NULL),
|
||||
|
||||
/* Peripheral Cluster #6 */
|
||||
CLK(hash1, "hash1", NULL),
|
||||
CLK(pka, "pka", NULL),
|
||||
CLK(hash0, "hash0", NULL),
|
||||
CLK(cryp0, "cryp0", NULL),
|
||||
CLK(cryp1, "cryp1", NULL),
|
||||
|
||||
/* PRCMU level clock gating */
|
||||
|
||||
/* Bank 0 */
|
||||
CLK(svaclk, "sva", NULL),
|
||||
CLK(siaclk, "sia", NULL),
|
||||
CLK(sgaclk, "sga", NULL),
|
||||
CLK(slimclk, "slim", NULL),
|
||||
CLK(lcdclk, "lcd", NULL),
|
||||
CLK(bmlclk, "bml", NULL),
|
||||
CLK(hsitxclk, "stm-hsi.0", NULL),
|
||||
CLK(hsirxclk, "stm-hsi.1", NULL),
|
||||
CLK(hdmiclk, "hdmi", NULL),
|
||||
CLK(apeatclk, "apeat", NULL),
|
||||
CLK(apetraceclk, "apetrace", NULL),
|
||||
CLK(mcdeclk, "mcde", NULL),
|
||||
CLK(ipi2clk, "ipi2", NULL),
|
||||
CLK(dmaclk, "dma40.0", NULL),
|
||||
CLK(b2r2clk, "b2r2", NULL),
|
||||
CLK(tvclk, "tv", NULL),
|
||||
|
||||
/* Peripheral Cluster #1 */
|
||||
CLK(i2c4, "nmk-i2c.4", NULL),
|
||||
CLK(spi3, "spi3", NULL),
|
||||
CLK(msp1, "ux500-msp-i2s.1", NULL),
|
||||
CLK(msp3, "ux500-msp-i2s.3", NULL),
|
||||
|
||||
/* Peripheral Cluster #2 */
|
||||
CLK(gpio1, "gpio.6", NULL),
|
||||
CLK(gpio1, "gpio.7", NULL),
|
||||
CLK(ssitx, "ssitx", NULL),
|
||||
CLK(ssirx, "ssirx", NULL),
|
||||
CLK(spi0, "spi0", NULL),
|
||||
CLK(sdi3, "sdi3", NULL),
|
||||
CLK(sdi1, "sdi1", NULL),
|
||||
CLK(msp2, "ux500-msp-i2s.2", NULL),
|
||||
CLK(sdi4, "sdi4", NULL),
|
||||
CLK(pwl, "pwl", NULL),
|
||||
CLK(spi1, "spi1", NULL),
|
||||
CLK(spi2, "spi2", NULL),
|
||||
CLK(i2c3, "nmk-i2c.3", NULL),
|
||||
|
||||
/* Peripheral Cluster #3 */
|
||||
CLK(ssp1, "ssp1", NULL),
|
||||
CLK(ssp0, "ssp0", NULL),
|
||||
|
||||
/* Peripheral Cluster #5 */
|
||||
CLK(usb, "musb-ux500.0", "usb"),
|
||||
|
||||
/* Peripheral Cluster #6 */
|
||||
CLK(mtu1, "mtu1", NULL),
|
||||
CLK(mtu0, "mtu0", NULL),
|
||||
CLK(cfgreg, "cfgreg", NULL),
|
||||
CLK(hash1, "hash1", NULL),
|
||||
CLK(unipro, "unipro", NULL),
|
||||
CLK(rng, "rng", NULL),
|
||||
|
||||
/* PRCMU level clock gating */
|
||||
|
||||
/* Bank 0 */
|
||||
CLK(uniproclk, "uniproclk", NULL),
|
||||
CLK(dsialtclk, "dsialt", NULL),
|
||||
|
||||
/* Bank 1 */
|
||||
CLK(rngclk, "rng", NULL),
|
||||
CLK(uiccclk, "uicc", NULL),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
/*
|
||||
* debugfs support to trace clock tree hierarchy and attributes with
|
||||
* powerdebug
|
||||
*/
|
||||
static struct dentry *clk_debugfs_root;
|
||||
|
||||
void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num)
|
||||
{
|
||||
while (num--) {
|
||||
/* Check that the clock has not been already registered */
|
||||
if (!(cl->clk->list.prev != cl->clk->list.next))
|
||||
list_add_tail(&cl->clk->list, &clk_list);
|
||||
|
||||
cl++;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t usecount_dbg_read(struct file *file, char __user *buf,
|
||||
size_t size, loff_t *off)
|
||||
{
|
||||
struct clk *clk = file->f_dentry->d_inode->i_private;
|
||||
char cusecount[128];
|
||||
unsigned int len;
|
||||
|
||||
len = sprintf(cusecount, "%u\n", clk->enabled);
|
||||
return simple_read_from_buffer(buf, size, off, cusecount, len);
|
||||
}
|
||||
|
||||
static ssize_t rate_dbg_read(struct file *file, char __user *buf,
|
||||
size_t size, loff_t *off)
|
||||
{
|
||||
struct clk *clk = file->f_dentry->d_inode->i_private;
|
||||
char crate[128];
|
||||
unsigned int rate;
|
||||
unsigned int len;
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
len = sprintf(crate, "%u\n", rate);
|
||||
return simple_read_from_buffer(buf, size, off, crate, len);
|
||||
}
|
||||
|
||||
static const struct file_operations usecount_fops = {
|
||||
.read = usecount_dbg_read,
|
||||
};
|
||||
|
||||
static const struct file_operations set_rate_fops = {
|
||||
.read = rate_dbg_read,
|
||||
};
|
||||
|
||||
static struct dentry *clk_debugfs_register_dir(struct clk *c,
|
||||
struct dentry *p_dentry)
|
||||
{
|
||||
struct dentry *d, *clk_d;
|
||||
const char *p = c->name;
|
||||
|
||||
if (!p)
|
||||
p = "BUG";
|
||||
|
||||
clk_d = debugfs_create_dir(p, p_dentry);
|
||||
if (!clk_d)
|
||||
return NULL;
|
||||
|
||||
d = debugfs_create_file("usecount", S_IRUGO,
|
||||
clk_d, c, &usecount_fops);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
d = debugfs_create_file("rate", S_IRUGO,
|
||||
clk_d, c, &set_rate_fops);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
/*
|
||||
* TODO : not currently available in ux500
|
||||
* d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags);
|
||||
* if (!d)
|
||||
* goto err_out;
|
||||
*/
|
||||
|
||||
return clk_d;
|
||||
|
||||
err_out:
|
||||
debugfs_remove_recursive(clk_d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int clk_debugfs_register_one(struct clk *c)
|
||||
{
|
||||
struct clk *pa = c->parent_periph;
|
||||
struct clk *bpa = c->parent_cluster;
|
||||
|
||||
if (!(bpa && !pa)) {
|
||||
c->dent = clk_debugfs_register_dir(c,
|
||||
pa ? pa->dent : clk_debugfs_root);
|
||||
if (!c->dent)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (bpa) {
|
||||
c->dent_bus = clk_debugfs_register_dir(c,
|
||||
bpa->dent_bus ? bpa->dent_bus : bpa->dent);
|
||||
if ((!c->dent_bus) && (c->dent)) {
|
||||
debugfs_remove_recursive(c->dent);
|
||||
c->dent = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_debugfs_register(struct clk *c)
|
||||
{
|
||||
int err;
|
||||
struct clk *pa = c->parent_periph;
|
||||
struct clk *bpa = c->parent_cluster;
|
||||
|
||||
if (pa && (!pa->dent && !pa->dent_bus)) {
|
||||
err = clk_debugfs_register(pa);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (bpa && (!bpa->dent && !bpa->dent_bus)) {
|
||||
err = clk_debugfs_register(bpa);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((!c->dent) && (!c->dent_bus)) {
|
||||
err = clk_debugfs_register_one(c);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init clk_debugfs_init(void)
|
||||
{
|
||||
struct clk *c;
|
||||
struct dentry *d;
|
||||
int err;
|
||||
|
||||
d = debugfs_create_dir("clock", NULL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
clk_debugfs_root = d;
|
||||
|
||||
list_for_each_entry(c, &clk_list, list) {
|
||||
err = clk_debugfs_register(c);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
return 0;
|
||||
err_out:
|
||||
debugfs_remove_recursive(clk_debugfs_root);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_DEBUG_FS) */
|
||||
|
||||
unsigned long clk_smp_twd_rate = 500000000;
|
||||
|
||||
unsigned long clk_smp_twd_get_rate(struct clk *clk)
|
||||
{
|
||||
return clk_smp_twd_rate;
|
||||
}
|
||||
|
||||
static struct clk clk_smp_twd = {
|
||||
.get_rate = clk_smp_twd_get_rate,
|
||||
.name = "smp_twd",
|
||||
};
|
||||
|
||||
static struct clk_lookup clk_smp_twd_lookup = {
|
||||
.dev_id = "smp_twd",
|
||||
.clk = &clk_smp_twd,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
|
||||
static int clk_twd_cpufreq_transition(struct notifier_block *nb,
|
||||
unsigned long state, void *data)
|
||||
{
|
||||
struct cpufreq_freqs *f = data;
|
||||
|
||||
if (state == CPUFREQ_PRECHANGE) {
|
||||
/* Save frequency in simple Hz */
|
||||
clk_smp_twd_rate = (f->new * 1000) / 2;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block clk_twd_cpufreq_nb = {
|
||||
.notifier_call = clk_twd_cpufreq_transition,
|
||||
};
|
||||
|
||||
int clk_init_smp_twd_cpufreq(void)
|
||||
{
|
||||
return cpufreq_register_notifier(&clk_twd_cpufreq_nb,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int __init clk_init(void)
|
||||
{
|
||||
clkdev_add_table(u8500_clks, ARRAY_SIZE(u8500_clks));
|
||||
clkdev_add(&clk_smp_twd_lookup);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
clk_debugfs_add_table(u8500_clks, ARRAY_SIZE(u8500_clks));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 ST-Ericsson
|
||||
* Copyright (C) 2009 STMicroelectronics
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct clkops - ux500 clock operations
|
||||
* @enable: function to enable the clock
|
||||
* @disable: function to disable the clock
|
||||
* @get_rate: function to get the current clock rate
|
||||
*
|
||||
* This structure contains function pointers to functions that will be used to
|
||||
* control the clock. All of these functions are optional. If get_rate is
|
||||
* NULL, the rate in the struct clk will be used.
|
||||
*/
|
||||
struct clkops {
|
||||
void (*enable) (struct clk *);
|
||||
void (*disable) (struct clk *);
|
||||
unsigned long (*get_rate) (struct clk *);
|
||||
int (*set_parent)(struct clk *, struct clk *);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk - ux500 clock structure
|
||||
* @ops: pointer to clkops struct used to control this clock
|
||||
* @name: name, for debugging
|
||||
* @enabled: refcount. positive if enabled, zero if disabled
|
||||
* @get_rate: custom callback for getting the clock rate
|
||||
* @data: custom per-clock data for example for the get_rate
|
||||
* callback
|
||||
* @rate: fixed rate for clocks which don't implement
|
||||
* ops->getrate
|
||||
* @prcmu_cg_off: address offset of the combined enable/disable register
|
||||
* (used on u8500v1)
|
||||
* @prcmu_cg_bit: bit in the combined enable/disable register (used on
|
||||
* u8500v1)
|
||||
* @prcmu_cg_mgt: address of the enable/disable register (used on
|
||||
* u8500ed)
|
||||
* @cluster: peripheral cluster number
|
||||
* @prcc_bus: bit for the bus clock in the peripheral's CLKRST
|
||||
* @prcc_kernel: bit for the kernel clock in the peripheral's CLKRST.
|
||||
* -1 if no kernel clock exists.
|
||||
* @parent_cluster: pointer to parent's cluster clk struct
|
||||
* @parent_periph: pointer to parent's peripheral clk struct
|
||||
*
|
||||
* Peripherals are organised into clusters, and each cluster has an associated
|
||||
* bus clock. Some peripherals also have a parent peripheral clock.
|
||||
*
|
||||
* In order to enable a clock for a peripheral, we need to enable:
|
||||
* (1) the parent cluster (bus) clock at the PRCMU level
|
||||
* (2) the parent peripheral clock (if any) at the PRCMU level
|
||||
* (3) the peripheral's bus & kernel clock at the PRCC level
|
||||
*
|
||||
* (1) and (2) are handled by defining clk structs (DEFINE_PRCMU_CLK) for each
|
||||
* of the cluster and peripheral clocks, and hooking these as the parents of
|
||||
* the individual peripheral clocks.
|
||||
*
|
||||
* (3) is handled by specifying the bits in the PRCC control registers required
|
||||
* to enable these clocks and modifying them in the ->enable and
|
||||
* ->disable callbacks of the peripheral clocks (DEFINE_PRCC_CLK).
|
||||
*
|
||||
* This structure describes both the PRCMU-level clocks and PRCC-level clocks.
|
||||
* The prcmu_* fields are only used for the PRCMU clocks, and the cluster,
|
||||
* prcc, and parent pointers are only used for the PRCC-level clocks.
|
||||
*/
|
||||
struct clk {
|
||||
const struct clkops *ops;
|
||||
const char *name;
|
||||
unsigned int enabled;
|
||||
unsigned long (*get_rate)(struct clk *);
|
||||
void *data;
|
||||
|
||||
unsigned long rate;
|
||||
struct list_head list;
|
||||
|
||||
/* These three are only for PRCMU clks */
|
||||
|
||||
unsigned int prcmu_cg_off;
|
||||
unsigned int prcmu_cg_bit;
|
||||
unsigned int prcmu_cg_mgt;
|
||||
|
||||
/* The rest are only for PRCC clks */
|
||||
|
||||
int cluster;
|
||||
unsigned int prcc_bus;
|
||||
unsigned int prcc_kernel;
|
||||
|
||||
struct clk *parent_cluster;
|
||||
struct clk *parent_periph;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
struct dentry *dent; /* For visible tree hierarchy */
|
||||
struct dentry *dent_bus; /* For visible tree hierarchy */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \
|
||||
struct clk clk_##_name = { \
|
||||
.name = #_name, \
|
||||
.ops = &clk_prcmu_ops, \
|
||||
.prcmu_cg_off = _cg_off, \
|
||||
.prcmu_cg_bit = _cg_bit, \
|
||||
.prcmu_cg_mgt = PRCM_##_reg##_MGT \
|
||||
}
|
||||
|
||||
#define DEFINE_PRCMU_CLK_RATE(_name, _cg_off, _cg_bit, _reg, _rate) \
|
||||
struct clk clk_##_name = { \
|
||||
.name = #_name, \
|
||||
.ops = &clk_prcmu_ops, \
|
||||
.prcmu_cg_off = _cg_off, \
|
||||
.prcmu_cg_bit = _cg_bit, \
|
||||
.rate = _rate, \
|
||||
.prcmu_cg_mgt = PRCM_##_reg##_MGT \
|
||||
}
|
||||
|
||||
#define DEFINE_PRCC_CLK(_pclust, _name, _bus_en, _kernel_en, _kernclk) \
|
||||
struct clk clk_##_name = { \
|
||||
.name = #_name, \
|
||||
.ops = &clk_prcc_ops, \
|
||||
.cluster = _pclust, \
|
||||
.prcc_bus = _bus_en, \
|
||||
.prcc_kernel = _kernel_en, \
|
||||
.parent_cluster = &clk_per##_pclust##clk, \
|
||||
.parent_periph = _kernclk \
|
||||
}
|
||||
|
||||
#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \
|
||||
struct clk clk_##_name = { \
|
||||
.name = #_name, \
|
||||
.ops = &clk_prcc_ops, \
|
||||
.cluster = _pclust, \
|
||||
.prcc_bus = _bus_en, \
|
||||
.prcc_kernel = _kernel_en, \
|
||||
.parent_cluster = &clk_per##_pclust##clk, \
|
||||
.parent_periph = _kernclk, \
|
||||
.get_rate = _callback, \
|
||||
.data = (void *) _data \
|
||||
}
|
||||
|
||||
|
||||
#define CLK(_clk, _devname, _conname) \
|
||||
{ \
|
||||
.clk = &clk_##_clk, \
|
||||
.dev_id = _devname, \
|
||||
.con_id = _conname, \
|
||||
}
|
||||
|
||||
int __init clk_db8500_ed_fixup(void);
|
||||
int __init clk_init(void);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int clk_debugfs_init(void);
|
||||
#else
|
||||
static inline int clk_debugfs_init(void) { return 0; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
int clk_init_smp_twd_cpufreq(void);
|
||||
#else
|
||||
static inline int clk_init_smp_twd_cpufreq(void) { return 0; }
|
||||
#endif
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/db8500-prcmu.h>
|
||||
#include <linux/clksrc-dbx500-prcmu.h>
|
||||
#include <linux/sys_soc.h>
|
||||
@ -17,6 +16,7 @@
|
||||
#include <linux/stat.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_data/clk-ux500.h>
|
||||
|
||||
#include <asm/hardware/gic.h>
|
||||
#include <asm/mach/map.h>
|
||||
@ -25,8 +25,6 @@
|
||||
#include <mach/setup.h>
|
||||
#include <mach/devices.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
void __iomem *_PRCMU_BASE;
|
||||
|
||||
/*
|
||||
@ -70,13 +68,17 @@ void __init ux500_init_irq(void)
|
||||
*/
|
||||
if (cpu_is_u8500_family())
|
||||
db8500_prcmu_early_init();
|
||||
clk_init();
|
||||
|
||||
if (cpu_is_u8500_family())
|
||||
u8500_clk_init();
|
||||
else if (cpu_is_u9540())
|
||||
u9540_clk_init();
|
||||
else if (cpu_is_u8540())
|
||||
u8540_clk_init();
|
||||
}
|
||||
|
||||
void __init ux500_init_late(void)
|
||||
{
|
||||
clk_debugfs_init();
|
||||
clk_init_smp_twd_cpufreq();
|
||||
}
|
||||
|
||||
static const char * __init ux500_get_machine(void)
|
||||
|
@ -40,4 +40,17 @@ config COMMON_CLK_WM831X
|
||||
Supports the clocking subsystem of the WM831x/2x series of
|
||||
PMICs from Wolfson Microlectronics.
|
||||
|
||||
config COMMON_CLK_VERSATILE
|
||||
bool "Clock driver for ARM Reference designs"
|
||||
depends on ARCH_INTEGRATOR || ARCH_REALVIEW
|
||||
---help---
|
||||
Supports clocking on ARM Reference designs Integrator/AP,
|
||||
Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
|
||||
|
||||
config COMMON_CLK_MAX77686
|
||||
tristate "Clock driver for Maxim 77686 MFD"
|
||||
depends on MFD_MAX77686
|
||||
---help---
|
||||
This driver supports Maxim 77686 crystal oscillator clock.
|
||||
|
||||
endmenu
|
||||
|
@ -9,7 +9,14 @@ obj-$(CONFIG_ARCH_MXS) += mxs/
|
||||
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
|
||||
obj-$(CONFIG_PLAT_SPEAR) += spear/
|
||||
obj-$(CONFIG_ARCH_U300) += clk-u300.o
|
||||
obj-$(CONFIG_ARCH_INTEGRATOR) += versatile/
|
||||
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
|
||||
obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o
|
||||
ifeq ($(CONFIG_COMMON_CLK), y)
|
||||
obj-$(CONFIG_ARCH_MMP) += mmp/
|
||||
endif
|
||||
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
|
||||
obj-$(CONFIG_ARCH_U8500) += ux500/
|
||||
|
||||
# Chip specific
|
||||
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
|
111
drivers/clk/clk-ls1x.c
Normal file
111
drivers/clk/clk-ls1x.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <loongson1.h>
|
||||
|
||||
#define OSC 33
|
||||
|
||||
static DEFINE_SPINLOCK(_lock);
|
||||
|
||||
static int ls1x_pll_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ls1x_pll_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
}
|
||||
|
||||
static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 pll, rate;
|
||||
|
||||
pll = __raw_readl(LS1X_CLK_PLL_FREQ);
|
||||
rate = ((12 + (pll & 0x3f)) * 1000000) +
|
||||
((((pll >> 8) & 0x3ff) * 1000000) >> 10);
|
||||
rate *= OSC;
|
||||
rate >>= 1;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static const struct clk_ops ls1x_pll_clk_ops = {
|
||||
.enable = ls1x_pll_clk_enable,
|
||||
.disable = ls1x_pll_clk_disable,
|
||||
.recalc_rate = ls1x_pll_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init clk_register_pll(struct device *dev,
|
||||
const char *name, const char *parent_name, unsigned long flags)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
/* allocate the divider */
|
||||
hw = kzalloc(sizeof(struct clk_hw), GFP_KERNEL);
|
||||
if (!hw) {
|
||||
pr_err("%s: could not allocate clk_hw\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &ls1x_pll_clk_ops;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
hw->init = &init;
|
||||
|
||||
/* register the clock */
|
||||
clk = clk_register(dev, hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(hw);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void __init ls1x_clk_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_register_pll(NULL, "pll_clk", NULL, CLK_IS_ROOT);
|
||||
clk_prepare_enable(clk);
|
||||
|
||||
clk = clk_register_divider(NULL, "cpu_clk", "pll_clk",
|
||||
CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT,
|
||||
DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
|
||||
clk_prepare_enable(clk);
|
||||
clk_register_clkdev(clk, "cpu", NULL);
|
||||
|
||||
clk = clk_register_divider(NULL, "dc_clk", "pll_clk",
|
||||
CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT,
|
||||
DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
|
||||
clk_prepare_enable(clk);
|
||||
clk_register_clkdev(clk, "dc", NULL);
|
||||
|
||||
clk = clk_register_divider(NULL, "ahb_clk", "pll_clk",
|
||||
CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT,
|
||||
DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
|
||||
clk_prepare_enable(clk);
|
||||
clk_register_clkdev(clk, "ahb", NULL);
|
||||
clk_register_clkdev(clk, "stmmaceth", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 2);
|
||||
clk_prepare_enable(clk);
|
||||
clk_register_clkdev(clk, "apb", NULL);
|
||||
clk_register_clkdev(clk, "serial8250", NULL);
|
||||
}
|
244
drivers/clk/clk-max77686.c
Normal file
244
drivers/clk/clk-max77686.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* clk-max77686.c - Clock driver for Maxim 77686
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electornics
|
||||
* Jonghwa Lee <jonghwa3.lee@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/max77686.h>
|
||||
#include <linux/mfd/max77686-private.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
enum {
|
||||
MAX77686_CLK_AP = 0,
|
||||
MAX77686_CLK_CP,
|
||||
MAX77686_CLK_PMIC,
|
||||
MAX77686_CLKS_NUM,
|
||||
};
|
||||
|
||||
struct max77686_clk {
|
||||
struct max77686_dev *iodev;
|
||||
u32 mask;
|
||||
struct clk_hw hw;
|
||||
struct clk_lookup *lookup;
|
||||
};
|
||||
|
||||
static struct max77686_clk *get_max77686_clk(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct max77686_clk, hw);
|
||||
}
|
||||
|
||||
static int max77686_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max77686_clk *max77686;
|
||||
int ret;
|
||||
|
||||
max77686 = get_max77686_clk(hw);
|
||||
if (!max77686)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = regmap_update_bits(max77686->iodev->regmap,
|
||||
MAX77686_REG_32KHZ, max77686->mask, max77686->mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max77686_clk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max77686_clk *max77686;
|
||||
|
||||
max77686 = get_max77686_clk(hw);
|
||||
if (!max77686)
|
||||
return;
|
||||
|
||||
regmap_update_bits(max77686->iodev->regmap,
|
||||
MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
|
||||
}
|
||||
|
||||
static int max77686_clk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct max77686_clk *max77686;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
max77686 = get_max77686_clk(hw);
|
||||
if (!max77686)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = regmap_read(max77686->iodev->regmap,
|
||||
MAX77686_REG_32KHZ, &val);
|
||||
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return val & max77686->mask;
|
||||
}
|
||||
|
||||
static struct clk_ops max77686_clk_ops = {
|
||||
.prepare = max77686_clk_prepare,
|
||||
.unprepare = max77686_clk_unprepare,
|
||||
.is_enabled = max77686_clk_is_enabled,
|
||||
};
|
||||
|
||||
static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
|
||||
[MAX77686_CLK_AP] = {
|
||||
.name = "32khz_ap",
|
||||
.ops = &max77686_clk_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
[MAX77686_CLK_CP] = {
|
||||
.name = "32khz_cp",
|
||||
.ops = &max77686_clk_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
[MAX77686_CLK_PMIC] = {
|
||||
.name = "32khz_pmic",
|
||||
.ops = &max77686_clk_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
};
|
||||
|
||||
static int max77686_clk_register(struct device *dev,
|
||||
struct max77686_clk *max77686)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw = &max77686->hw;
|
||||
|
||||
clk = clk_register(dev, hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
return -ENOMEM;
|
||||
|
||||
max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup),
|
||||
GFP_KERNEL);
|
||||
if (IS_ERR(max77686->lookup))
|
||||
return -ENOMEM;
|
||||
|
||||
max77686->lookup->con_id = hw->init->name;
|
||||
max77686->lookup->clk = clk;
|
||||
|
||||
clkdev_add(max77686->lookup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __devinit int max77686_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max77686_clk **max77686_clks;
|
||||
int i, ret;
|
||||
|
||||
max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *)
|
||||
* MAX77686_CLKS_NUM, GFP_KERNEL);
|
||||
if (IS_ERR(max77686_clks))
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < MAX77686_CLKS_NUM; i++) {
|
||||
max77686_clks[i] = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct max77686_clk), GFP_KERNEL);
|
||||
if (IS_ERR(max77686_clks[i]))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX77686_CLKS_NUM; i++) {
|
||||
max77686_clks[i]->iodev = iodev;
|
||||
max77686_clks[i]->mask = 1 << i;
|
||||
max77686_clks[i]->hw.init = &max77686_clks_init[i];
|
||||
|
||||
ret = max77686_clk_register(&pdev->dev, max77686_clks[i]);
|
||||
if (ret) {
|
||||
switch (i) {
|
||||
case MAX77686_CLK_AP:
|
||||
dev_err(&pdev->dev, "Fail to register CLK_AP\n");
|
||||
goto err_clk_ap;
|
||||
break;
|
||||
case MAX77686_CLK_CP:
|
||||
dev_err(&pdev->dev, "Fail to register CLK_CP\n");
|
||||
goto err_clk_cp;
|
||||
break;
|
||||
case MAX77686_CLK_PMIC:
|
||||
dev_err(&pdev->dev, "Fail to register CLK_PMIC\n");
|
||||
goto err_clk_pmic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, max77686_clks);
|
||||
|
||||
goto out;
|
||||
|
||||
err_clk_pmic:
|
||||
clkdev_drop(max77686_clks[MAX77686_CLK_CP]->lookup);
|
||||
kfree(max77686_clks[MAX77686_CLK_CP]->hw.clk);
|
||||
err_clk_cp:
|
||||
clkdev_drop(max77686_clks[MAX77686_CLK_AP]->lookup);
|
||||
kfree(max77686_clks[MAX77686_CLK_AP]->hw.clk);
|
||||
err_clk_ap:
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit max77686_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max77686_clk **max77686_clks = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX77686_CLKS_NUM; i++) {
|
||||
clkdev_drop(max77686_clks[i]->lookup);
|
||||
kfree(max77686_clks[i]->hw.clk);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id max77686_clk_id[] = {
|
||||
{ "max77686-clk", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max77686_clk_id);
|
||||
|
||||
static struct platform_driver max77686_clk_driver = {
|
||||
.driver = {
|
||||
.name = "max77686-clk",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max77686_clk_probe,
|
||||
.remove = __devexit_p(max77686_clk_remove),
|
||||
.id_table = max77686_clk_id,
|
||||
};
|
||||
|
||||
static int __init max77686_clk_init(void)
|
||||
{
|
||||
return platform_driver_register(&max77686_clk_driver);
|
||||
}
|
||||
subsys_initcall(max77686_clk_init);
|
||||
|
||||
static void __init max77686_clk_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&max77686_clk_driver);
|
||||
}
|
||||
module_exit(max77686_clk_cleanup);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
|
||||
MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
1171
drivers/clk/clk-prima2.c
Normal file
1171
drivers/clk/clk-prima2.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -557,25 +557,6 @@ int clk_enable(struct clk *clk)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_enable);
|
||||
|
||||
/**
|
||||
* clk_get_rate - return the rate of clk
|
||||
* @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 0.
|
||||
*/
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
rate = __clk_get_rate(clk);
|
||||
mutex_unlock(&prepare_lock);
|
||||
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_get_rate);
|
||||
|
||||
/**
|
||||
* __clk_round_rate - round the given rate for a clk
|
||||
* @clk: round the rate of this clock
|
||||
@ -701,6 +682,30 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
|
||||
__clk_recalc_rates(child, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_get_rate - return the rate of clk
|
||||
* @clk: the clk whose rate is being returned
|
||||
*
|
||||
* Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
|
||||
* is set, which means a recalc_rate will be issued.
|
||||
* If clk is NULL then returns 0.
|
||||
*/
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
|
||||
if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
|
||||
__clk_recalc_rates(clk, 0);
|
||||
|
||||
rate = __clk_get_rate(clk);
|
||||
mutex_unlock(&prepare_lock);
|
||||
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_get_rate);
|
||||
|
||||
/**
|
||||
* __clk_speculate_rates
|
||||
* @clk: first clk in the subtree
|
||||
@ -1582,6 +1587,20 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
|
||||
|
||||
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct clk_onecell_data *clk_data = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= clk_data->clk_num) {
|
||||
pr_err("%s: invalid clock index %d\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return clk_data->clks[idx];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
|
||||
|
||||
/**
|
||||
* of_clk_add_provider() - Register a clock provider for a node
|
||||
* @np: Device node pointer associated with clock provider
|
||||
|
9
drivers/clk/mmp/Makefile
Normal file
9
drivers/clk/mmp/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for mmp specific clk
|
||||
#
|
||||
|
||||
obj-y += clk-apbc.o clk-apmu.o clk-frac.o
|
||||
|
||||
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
|
||||
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
|
||||
obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o
|
152
drivers/clk/mmp/clk-apbc.c
Normal file
152
drivers/clk/mmp/clk-apbc.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* mmp APB clock operation source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
/* Common APB clock register bit definitions */
|
||||
#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
|
||||
#define APBC_FNCLK (1 << 1) /* Functional Clock Enable */
|
||||
#define APBC_RST (1 << 2) /* Reset Generation */
|
||||
#define APBC_POWER (1 << 7) /* Reset Generation */
|
||||
|
||||
#define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
|
||||
struct clk_apbc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
unsigned int delay;
|
||||
unsigned int flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
static int clk_apbc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_apbc *apbc = to_clk_apbc(hw);
|
||||
unsigned int data;
|
||||
unsigned long flags = 0;
|
||||
|
||||
/*
|
||||
* It may share same register as MUX clock,
|
||||
* and it will impact FNCLK enable. Spinlock is needed
|
||||
*/
|
||||
if (apbc->lock)
|
||||
spin_lock_irqsave(apbc->lock, flags);
|
||||
|
||||
data = readl_relaxed(apbc->base);
|
||||
if (apbc->flags & APBC_POWER_CTRL)
|
||||
data |= APBC_POWER;
|
||||
data |= APBC_FNCLK;
|
||||
writel_relaxed(data, apbc->base);
|
||||
|
||||
if (apbc->lock)
|
||||
spin_unlock_irqrestore(apbc->lock, flags);
|
||||
|
||||
udelay(apbc->delay);
|
||||
|
||||
if (apbc->lock)
|
||||
spin_lock_irqsave(apbc->lock, flags);
|
||||
|
||||
data = readl_relaxed(apbc->base);
|
||||
data |= APBC_APBCLK;
|
||||
writel_relaxed(data, apbc->base);
|
||||
|
||||
if (apbc->lock)
|
||||
spin_unlock_irqrestore(apbc->lock, flags);
|
||||
|
||||
udelay(apbc->delay);
|
||||
|
||||
if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
|
||||
if (apbc->lock)
|
||||
spin_lock_irqsave(apbc->lock, flags);
|
||||
|
||||
data = readl_relaxed(apbc->base);
|
||||
data &= ~APBC_RST;
|
||||
writel_relaxed(data, apbc->base);
|
||||
|
||||
if (apbc->lock)
|
||||
spin_unlock_irqrestore(apbc->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_apbc_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_apbc *apbc = to_clk_apbc(hw);
|
||||
unsigned long data;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (apbc->lock)
|
||||
spin_lock_irqsave(apbc->lock, flags);
|
||||
|
||||
data = readl_relaxed(apbc->base);
|
||||
if (apbc->flags & APBC_POWER_CTRL)
|
||||
data &= ~APBC_POWER;
|
||||
data &= ~APBC_FNCLK;
|
||||
writel_relaxed(data, apbc->base);
|
||||
|
||||
if (apbc->lock)
|
||||
spin_unlock_irqrestore(apbc->lock, flags);
|
||||
|
||||
udelay(10);
|
||||
|
||||
if (apbc->lock)
|
||||
spin_lock_irqsave(apbc->lock, flags);
|
||||
|
||||
data = readl_relaxed(apbc->base);
|
||||
data &= ~APBC_APBCLK;
|
||||
writel_relaxed(data, apbc->base);
|
||||
|
||||
if (apbc->lock)
|
||||
spin_unlock_irqrestore(apbc->lock, flags);
|
||||
}
|
||||
|
||||
struct clk_ops clk_apbc_ops = {
|
||||
.prepare = clk_apbc_prepare,
|
||||
.unprepare = clk_apbc_unprepare,
|
||||
};
|
||||
|
||||
struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
|
||||
void __iomem *base, unsigned int delay,
|
||||
unsigned int apbc_flags, spinlock_t *lock)
|
||||
{
|
||||
struct clk_apbc *apbc;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
|
||||
if (!apbc)
|
||||
return NULL;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_apbc_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
apbc->base = base;
|
||||
apbc->delay = delay;
|
||||
apbc->flags = apbc_flags;
|
||||
apbc->lock = lock;
|
||||
apbc->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &apbc->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(apbc);
|
||||
|
||||
return clk;
|
||||
}
|
97
drivers/clk/mmp/clk-apmu.c
Normal file
97
drivers/clk/mmp/clk-apmu.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* mmp AXI peripharal clock operation source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk))
|
||||
struct clk_apmu {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
u32 rst_mask;
|
||||
u32 enable_mask;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
static int clk_apmu_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_apmu *apmu = to_clk_apmu(hw);
|
||||
unsigned long data;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (apmu->lock)
|
||||
spin_lock_irqsave(apmu->lock, flags);
|
||||
|
||||
data = readl_relaxed(apmu->base) | apmu->enable_mask;
|
||||
writel_relaxed(data, apmu->base);
|
||||
|
||||
if (apmu->lock)
|
||||
spin_unlock_irqrestore(apmu->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_apmu_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_apmu *apmu = to_clk_apmu(hw);
|
||||
unsigned long data;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (apmu->lock)
|
||||
spin_lock_irqsave(apmu->lock, flags);
|
||||
|
||||
data = readl_relaxed(apmu->base) & ~apmu->enable_mask;
|
||||
writel_relaxed(data, apmu->base);
|
||||
|
||||
if (apmu->lock)
|
||||
spin_unlock_irqrestore(apmu->lock, flags);
|
||||
}
|
||||
|
||||
struct clk_ops clk_apmu_ops = {
|
||||
.enable = clk_apmu_enable,
|
||||
.disable = clk_apmu_disable,
|
||||
};
|
||||
|
||||
struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name,
|
||||
void __iomem *base, u32 enable_mask, spinlock_t *lock)
|
||||
{
|
||||
struct clk_apmu *apmu;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
apmu = kzalloc(sizeof(*apmu), GFP_KERNEL);
|
||||
if (!apmu)
|
||||
return NULL;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_apmu_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
apmu->base = base;
|
||||
apmu->enable_mask = enable_mask;
|
||||
apmu->lock = lock;
|
||||
apmu->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &apmu->hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(apmu);
|
||||
|
||||
return clk;
|
||||
}
|
153
drivers/clk/mmp/clk-frac.c
Normal file
153
drivers/clk/mmp/clk-frac.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* mmp factor clock operation source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "clk.h"
|
||||
/*
|
||||
* It is M/N clock
|
||||
*
|
||||
* Fout from synthesizer can be given from two equations:
|
||||
* numerator/denominator = Fin / (Fout * factor)
|
||||
*/
|
||||
|
||||
#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw)
|
||||
struct clk_factor {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
struct clk_factor_masks *masks;
|
||||
struct clk_factor_tbl *ftbl;
|
||||
unsigned int ftbl_cnt;
|
||||
};
|
||||
|
||||
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_factor *factor = to_clk_factor(hw);
|
||||
unsigned long rate = 0, prev_rate;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < factor->ftbl_cnt; i++) {
|
||||
prev_rate = rate;
|
||||
rate = (((*prate / 10000) * factor->ftbl[i].num) /
|
||||
(factor->ftbl[i].den * factor->masks->factor)) * 10000;
|
||||
if (rate > drate)
|
||||
break;
|
||||
}
|
||||
if (i == 0)
|
||||
return rate;
|
||||
else
|
||||
return prev_rate;
|
||||
}
|
||||
|
||||
static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_factor *factor = to_clk_factor(hw);
|
||||
struct clk_factor_masks *masks = factor->masks;
|
||||
unsigned int val, num, den;
|
||||
|
||||
val = readl_relaxed(factor->base);
|
||||
|
||||
/* calculate numerator */
|
||||
num = (val >> masks->num_shift) & masks->num_mask;
|
||||
|
||||
/* calculate denominator */
|
||||
den = (val >> masks->den_shift) & masks->num_mask;
|
||||
|
||||
if (!den)
|
||||
return 0;
|
||||
|
||||
return (((parent_rate / 10000) * den) /
|
||||
(num * factor->masks->factor)) * 10000;
|
||||
}
|
||||
|
||||
/* Configures new clock rate*/
|
||||
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_factor *factor = to_clk_factor(hw);
|
||||
struct clk_factor_masks *masks = factor->masks;
|
||||
int i;
|
||||
unsigned long val;
|
||||
unsigned long prev_rate, rate = 0;
|
||||
|
||||
for (i = 0; i < factor->ftbl_cnt; i++) {
|
||||
prev_rate = rate;
|
||||
rate = (((prate / 10000) * factor->ftbl[i].num) /
|
||||
(factor->ftbl[i].den * factor->masks->factor)) * 10000;
|
||||
if (rate > drate)
|
||||
break;
|
||||
}
|
||||
if (i > 0)
|
||||
i--;
|
||||
|
||||
val = readl_relaxed(factor->base);
|
||||
|
||||
val &= ~(masks->num_mask << masks->num_shift);
|
||||
val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift;
|
||||
|
||||
val &= ~(masks->den_mask << masks->den_shift);
|
||||
val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift;
|
||||
|
||||
writel_relaxed(val, factor->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_factor_ops = {
|
||||
.recalc_rate = clk_factor_recalc_rate,
|
||||
.round_rate = clk_factor_round_rate,
|
||||
.set_rate = clk_factor_set_rate,
|
||||
};
|
||||
|
||||
struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
|
||||
unsigned long flags, void __iomem *base,
|
||||
struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl,
|
||||
unsigned int ftbl_cnt)
|
||||
{
|
||||
struct clk_factor *factor;
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
|
||||
if (!masks) {
|
||||
pr_err("%s: must pass a clk_factor_mask\n", __func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
factor = kzalloc(sizeof(*factor), GFP_KERNEL);
|
||||
if (!factor) {
|
||||
pr_err("%s: could not allocate factor clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* struct clk_aux assignments */
|
||||
factor->base = base;
|
||||
factor->masks = masks;
|
||||
factor->ftbl = ftbl;
|
||||
factor->ftbl_cnt = ftbl_cnt;
|
||||
factor->hw.init = &init;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_factor_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
clk = clk_register(NULL, &factor->hw);
|
||||
if (IS_ERR_OR_NULL(clk))
|
||||
kfree(factor);
|
||||
|
||||
return clk;
|
||||
}
|
449
drivers/clk/mmp/clk-mmp2.c
Normal file
449
drivers/clk/mmp/clk-mmp2.c
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* mmp2 clock framework source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <mach/addr-map.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define APBC_RTC 0x0
|
||||
#define APBC_TWSI0 0x4
|
||||
#define APBC_TWSI1 0x8
|
||||
#define APBC_TWSI2 0xc
|
||||
#define APBC_TWSI3 0x10
|
||||
#define APBC_TWSI4 0x7c
|
||||
#define APBC_TWSI5 0x80
|
||||
#define APBC_KPC 0x18
|
||||
#define APBC_UART0 0x2c
|
||||
#define APBC_UART1 0x30
|
||||
#define APBC_UART2 0x34
|
||||
#define APBC_UART3 0x88
|
||||
#define APBC_GPIO 0x38
|
||||
#define APBC_PWM0 0x3c
|
||||
#define APBC_PWM1 0x40
|
||||
#define APBC_PWM2 0x44
|
||||
#define APBC_PWM3 0x48
|
||||
#define APBC_SSP0 0x50
|
||||
#define APBC_SSP1 0x54
|
||||
#define APBC_SSP2 0x58
|
||||
#define APBC_SSP3 0x5c
|
||||
#define APMU_SDH0 0x54
|
||||
#define APMU_SDH1 0x58
|
||||
#define APMU_SDH2 0xe8
|
||||
#define APMU_SDH3 0xec
|
||||
#define APMU_USB 0x5c
|
||||
#define APMU_DISP0 0x4c
|
||||
#define APMU_DISP1 0x110
|
||||
#define APMU_CCIC0 0x50
|
||||
#define APMU_CCIC1 0xf4
|
||||
#define MPMU_UART_PLL 0x14
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static struct clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
.num_shift = 16,
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 14634, .den = 2165}, /*14.745MHZ */
|
||||
{.num = 3521, .den = 689}, /*19.23MHZ */
|
||||
{.num = 9679, .den = 5728}, /*58.9824MHZ */
|
||||
{.num = 15850, .den = 9451}, /*59.429MHZ */
|
||||
};
|
||||
|
||||
static const char *uart_parent[] = {"uart_pll", "vctcxo"};
|
||||
static const char *ssp_parent[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
|
||||
static const char *sdh_parent[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
|
||||
static const char *disp_parent[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
|
||||
static const char *ccic_parent[] = {"pll1_2", "pll1_16", "vctcxo"};
|
||||
|
||||
void __init mmp2_clk_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk *vctcxo;
|
||||
void __iomem *mpmu_base;
|
||||
void __iomem *apmu_base;
|
||||
void __iomem *apbc_base;
|
||||
|
||||
mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
|
||||
if (mpmu_base == NULL) {
|
||||
pr_err("error to ioremap MPMU base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
|
||||
if (apmu_base == NULL) {
|
||||
pr_err("error to ioremap APMU base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
|
||||
if (apbc_base == NULL) {
|
||||
pr_err("error to ioremap APBC base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
|
||||
clk_register_clkdev(clk, "clk32", NULL);
|
||||
|
||||
vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
|
||||
26000000);
|
||||
clk_register_clkdev(vctcxo, "vctcxo", NULL);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
|
||||
800000000);
|
||||
clk_register_clkdev(clk, "pll1", NULL);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, CLK_IS_ROOT,
|
||||
480000000);
|
||||
clk_register_clkdev(clk, "usb_pll", NULL);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "pll2", NULL, CLK_IS_ROOT,
|
||||
960000000);
|
||||
clk_register_clkdev(clk, "pll2", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_2", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_4", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_8", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_16", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_20", "pll1_4",
|
||||
CLK_SET_RATE_PARENT, 1, 5);
|
||||
clk_register_clkdev(clk, "pll1_20", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_3", "pll1",
|
||||
CLK_SET_RATE_PARENT, 1, 3);
|
||||
clk_register_clkdev(clk, "pll1_3", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_3",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_6", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_12", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll2_2", "pll2",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll2_2", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll2_4", "pll2_2",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll2_4", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll2_8", "pll2_4",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll2_8", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll2_16", "pll2_8",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll2_16", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll2_3", "pll2",
|
||||
CLK_SET_RATE_PARENT, 1, 3);
|
||||
clk_register_clkdev(clk, "pll2_3", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll2_6", "pll2_3",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll2_6", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll2_12", "pll2_6",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll2_12", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "vctcxo_2", "vctcxo",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "vctcxo_2", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "vctcxo_4", "vctcxo_2",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "vctcxo_4", NULL);
|
||||
|
||||
clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
|
||||
mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl));
|
||||
clk_set_rate(clk, 14745600);
|
||||
clk_register_clkdev(clk, "uart_pll", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi0", "vctcxo",
|
||||
apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi1", "vctcxo",
|
||||
apbc_base + APBC_TWSI1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi2", "vctcxo",
|
||||
apbc_base + APBC_TWSI2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.2");
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi3", "vctcxo",
|
||||
apbc_base + APBC_TWSI3, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.3");
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi4", "vctcxo",
|
||||
apbc_base + APBC_TWSI4, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.4");
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi5", "vctcxo",
|
||||
apbc_base + APBC_TWSI5, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.5");
|
||||
|
||||
clk = mmp_clk_register_apbc("gpio", "vctcxo",
|
||||
apbc_base + APBC_GPIO, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa-gpio");
|
||||
|
||||
clk = mmp_clk_register_apbc("kpc", "clk32",
|
||||
apbc_base + APBC_KPC, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa27x-keypad");
|
||||
|
||||
clk = mmp_clk_register_apbc("rtc", "clk32",
|
||||
apbc_base + APBC_RTC, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-rtc");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm0", "vctcxo",
|
||||
apbc_base + APBC_PWM0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp2-pwm.0");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm1", "vctcxo",
|
||||
apbc_base + APBC_PWM1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp2-pwm.1");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm2", "vctcxo",
|
||||
apbc_base + APBC_PWM2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp2-pwm.2");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm3", "vctcxo",
|
||||
apbc_base + APBC_PWM3, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp2-pwm.3");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, vctcxo);
|
||||
clk_register_clkdev(clk, "uart_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart0", "uart0_mux",
|
||||
apbc_base + APBC_UART0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, vctcxo);
|
||||
clk_register_clkdev(clk, "uart_mux.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart1", "uart1_mux",
|
||||
apbc_base + APBC_UART1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, vctcxo);
|
||||
clk_register_clkdev(clk, "uart_mux.2", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart2", "uart2_mux",
|
||||
apbc_base + APBC_UART2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart3_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART3, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, vctcxo);
|
||||
clk_register_clkdev(clk, "uart_mux.3", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart3", "uart3_mux",
|
||||
apbc_base + APBC_UART3, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.3");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "uart_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp0", "ssp0_mux",
|
||||
apbc_base + APBC_SSP0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp1", "ssp1_mux",
|
||||
apbc_base + APBC_SSP1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.1");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.2", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp2", "ssp2_mux",
|
||||
apbc_base + APBC_SSP2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.2");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.3", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp3", "ssp3_mux",
|
||||
apbc_base + APBC_SSP3, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.3");
|
||||
|
||||
clk = clk_register_mux(NULL, "sdh_mux", sdh_parent,
|
||||
ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_SDH0, 8, 2, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sdh_mux", NULL);
|
||||
|
||||
clk = clk_register_divider(NULL, "sdh_div", "sdh_mux",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_SDH0,
|
||||
10, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
|
||||
clk_register_clkdev(clk, "sdh_div", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh0", "sdh_div", apmu_base + APMU_SDH0,
|
||||
0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxav3.0");
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh1", "sdh_div", apmu_base + APMU_SDH1,
|
||||
0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxav3.1");
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh2", "sdh_div", apmu_base + APMU_SDH2,
|
||||
0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxav3.2");
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh3", "sdh_div", apmu_base + APMU_SDH3,
|
||||
0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxav3.3");
|
||||
|
||||
clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB,
|
||||
0x9, &clk_lock);
|
||||
clk_register_clkdev(clk, "usb_clk", NULL);
|
||||
|
||||
clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
|
||||
ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_DISP0, 6, 2, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_mux.0", NULL);
|
||||
|
||||
clk = clk_register_divider(NULL, "disp0_div", "disp0_mux",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_DISP0,
|
||||
8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_div.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("disp0", "disp0_div",
|
||||
apmu_base + APMU_DISP0, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-disp.0");
|
||||
|
||||
clk = clk_register_divider(NULL, "disp0_sphy_div", "disp0_mux", 0,
|
||||
apmu_base + APMU_DISP0, 15, 5, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_sphy_div.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("disp0_sphy", "disp0_sphy_div",
|
||||
apmu_base + APMU_DISP0, 0x1024, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_sphy.0", NULL);
|
||||
|
||||
clk = clk_register_mux(NULL, "disp1_mux", disp_parent,
|
||||
ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_DISP1, 6, 2, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_mux.1", NULL);
|
||||
|
||||
clk = clk_register_divider(NULL, "disp1_div", "disp1_mux",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_DISP1,
|
||||
8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_div.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("disp1", "disp1_div",
|
||||
apmu_base + APMU_DISP1, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-disp.1");
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic_arbiter", "vctcxo",
|
||||
apmu_base + APMU_CCIC0, 0x1800, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_arbiter", NULL);
|
||||
|
||||
clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
|
||||
ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_CCIC0, 6, 2, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_mux.0", NULL);
|
||||
|
||||
clk = clk_register_divider(NULL, "ccic0_div", "ccic0_mux",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
|
||||
17, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_div.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0", "ccic0_div",
|
||||
apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_div",
|
||||
apmu_base + APMU_CCIC0, 0x24, &clk_lock);
|
||||
clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
|
||||
|
||||
clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_div",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
|
||||
10, 5, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.0");
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
|
||||
apmu_base + APMU_CCIC0, 0x300, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ccic1_mux", ccic_parent,
|
||||
ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_CCIC1, 6, 2, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_mux.1", NULL);
|
||||
|
||||
clk = clk_register_divider(NULL, "ccic1_div", "ccic1_mux",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1,
|
||||
16, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_div.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic1", "ccic1_div",
|
||||
apmu_base + APMU_CCIC1, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, "fnclk", "mmp-ccic.1");
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic1_phy", "ccic1_div",
|
||||
apmu_base + APMU_CCIC1, 0x24, &clk_lock);
|
||||
clk_register_clkdev(clk, "phyclk", "mmp-ccic.1");
|
||||
|
||||
clk = clk_register_divider(NULL, "ccic1_sphy_div", "ccic1_div",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1,
|
||||
10, 5, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.1");
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic1_sphy", "ccic1_sphy_div",
|
||||
apmu_base + APMU_CCIC1, 0x300, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk", "mmp-ccic.1");
|
||||
}
|
346
drivers/clk/mmp/clk-pxa168.c
Normal file
346
drivers/clk/mmp/clk-pxa168.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* pxa168 clock framework source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <mach/addr-map.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define APBC_RTC 0x28
|
||||
#define APBC_TWSI0 0x2c
|
||||
#define APBC_KPC 0x30
|
||||
#define APBC_UART0 0x0
|
||||
#define APBC_UART1 0x4
|
||||
#define APBC_GPIO 0x8
|
||||
#define APBC_PWM0 0xc
|
||||
#define APBC_PWM1 0x10
|
||||
#define APBC_PWM2 0x14
|
||||
#define APBC_PWM3 0x18
|
||||
#define APBC_SSP0 0x81c
|
||||
#define APBC_SSP1 0x820
|
||||
#define APBC_SSP2 0x84c
|
||||
#define APBC_SSP3 0x858
|
||||
#define APBC_SSP4 0x85c
|
||||
#define APBC_TWSI1 0x6c
|
||||
#define APBC_UART2 0x70
|
||||
#define APMU_SDH0 0x54
|
||||
#define APMU_SDH1 0x58
|
||||
#define APMU_USB 0x5c
|
||||
#define APMU_DISP0 0x4c
|
||||
#define APMU_CCIC0 0x50
|
||||
#define APMU_DFC 0x60
|
||||
#define MPMU_UART_PLL 0x14
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static struct clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
.num_shift = 16,
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 8125, .den = 1536}, /*14.745MHZ */
|
||||
};
|
||||
|
||||
static const char *uart_parent[] = {"pll1_3_16", "uart_pll"};
|
||||
static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
|
||||
static const char *sdh_parent[] = {"pll1_12", "pll1_13"};
|
||||
static const char *disp_parent[] = {"pll1_2", "pll1_12"};
|
||||
static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
|
||||
static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
|
||||
|
||||
void __init pxa168_clk_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk *uart_pll;
|
||||
void __iomem *mpmu_base;
|
||||
void __iomem *apmu_base;
|
||||
void __iomem *apbc_base;
|
||||
|
||||
mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
|
||||
if (mpmu_base == NULL) {
|
||||
pr_err("error to ioremap MPMU base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
|
||||
if (apmu_base == NULL) {
|
||||
pr_err("error to ioremap APMU base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
|
||||
if (apbc_base == NULL) {
|
||||
pr_err("error to ioremap APBC base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
|
||||
clk_register_clkdev(clk, "clk32", NULL);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
|
||||
26000000);
|
||||
clk_register_clkdev(clk, "vctcxo", NULL);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
|
||||
624000000);
|
||||
clk_register_clkdev(clk, "pll1", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_2", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_4", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_8", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_16", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2",
|
||||
CLK_SET_RATE_PARENT, 1, 3);
|
||||
clk_register_clkdev(clk, "pll1_6", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_12", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_24", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_48", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_96", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1",
|
||||
CLK_SET_RATE_PARENT, 1, 13);
|
||||
clk_register_clkdev(clk, "pll1_13", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1",
|
||||
CLK_SET_RATE_PARENT, 2, 3);
|
||||
clk_register_clkdev(clk, "pll1_13_1_5", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1",
|
||||
CLK_SET_RATE_PARENT, 2, 3);
|
||||
clk_register_clkdev(clk, "pll1_2_1_5", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1",
|
||||
CLK_SET_RATE_PARENT, 3, 16);
|
||||
clk_register_clkdev(clk, "pll1_3_16", NULL);
|
||||
|
||||
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
|
||||
mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl));
|
||||
clk_set_rate(uart_pll, 14745600);
|
||||
clk_register_clkdev(uart_pll, "uart_pll", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5",
|
||||
apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5",
|
||||
apbc_base + APBC_TWSI1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
|
||||
|
||||
clk = mmp_clk_register_apbc("gpio", "vctcxo",
|
||||
apbc_base + APBC_GPIO, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa-gpio");
|
||||
|
||||
clk = mmp_clk_register_apbc("kpc", "clk32",
|
||||
apbc_base + APBC_KPC, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa27x-keypad");
|
||||
|
||||
clk = mmp_clk_register_apbc("rtc", "clk32",
|
||||
apbc_base + APBC_RTC, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sa1100-rtc");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm0", "pll1_48",
|
||||
apbc_base + APBC_PWM0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa168-pwm.0");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm1", "pll1_48",
|
||||
apbc_base + APBC_PWM1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa168-pwm.1");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm2", "pll1_48",
|
||||
apbc_base + APBC_PWM2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa168-pwm.2");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm3", "pll1_48",
|
||||
apbc_base + APBC_PWM3, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa168-pwm.3");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, uart_pll);
|
||||
clk_register_clkdev(clk, "uart_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart0", "uart0_mux",
|
||||
apbc_base + APBC_UART0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, uart_pll);
|
||||
clk_register_clkdev(clk, "uart_mux.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart1", "uart1_mux",
|
||||
apbc_base + APBC_UART1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, uart_pll);
|
||||
clk_register_clkdev(clk, "uart_mux.2", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart2", "uart2_mux",
|
||||
apbc_base + APBC_UART2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "uart_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", apbc_base + APBC_SSP0,
|
||||
10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", apbc_base + APBC_SSP1,
|
||||
10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.1");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.2", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp2", "ssp1_mux", apbc_base + APBC_SSP2,
|
||||
10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.2");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.3", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp3", "ssp1_mux", apbc_base + APBC_SSP3,
|
||||
10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.3");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp4_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP4, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.4", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp4", "ssp1_mux", apbc_base + APBC_SSP4,
|
||||
10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.4");
|
||||
|
||||
clk = mmp_clk_register_apmu("dfc", "pll1_4", apmu_base + APMU_DFC,
|
||||
0x19b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
|
||||
ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sdh0_mux", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh0", "sdh_mux", apmu_base + APMU_SDH0,
|
||||
0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
|
||||
ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sdh1_mux", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh1", "sdh1_mux", apmu_base + APMU_SDH1,
|
||||
0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxa.1");
|
||||
|
||||
clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB,
|
||||
0x9, &clk_lock);
|
||||
clk_register_clkdev(clk, "usb_clk", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("sph", "usb_pll", apmu_base + APMU_USB,
|
||||
0x12, &clk_lock);
|
||||
clk_register_clkdev(clk, "sph_clk", NULL);
|
||||
|
||||
clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
|
||||
ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("disp0", "disp0_mux",
|
||||
apmu_base + APMU_DISP0, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, "fnclk", "mmp-disp.0");
|
||||
|
||||
clk = mmp_clk_register_apmu("disp0_hclk", "disp0_mux",
|
||||
apmu_base + APMU_DISP0, 0x24, &clk_lock);
|
||||
clk_register_clkdev(clk, "hclk", "mmp-disp.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
|
||||
ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0", "ccic0_mux",
|
||||
apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
|
||||
ARRAY_SIZE(ccic_phy_parent),
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
|
||||
7, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
|
||||
apmu_base + APMU_CCIC0, 0x24, &clk_lock);
|
||||
clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
|
||||
|
||||
clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
|
||||
10, 5, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk_div", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
|
||||
apmu_base + APMU_CCIC0, 0x300, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
|
||||
}
|
320
drivers/clk/mmp/clk-pxa910.c
Normal file
320
drivers/clk/mmp/clk-pxa910.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* pxa910 clock framework source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <mach/addr-map.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define APBC_RTC 0x28
|
||||
#define APBC_TWSI0 0x2c
|
||||
#define APBC_KPC 0x18
|
||||
#define APBC_UART0 0x0
|
||||
#define APBC_UART1 0x4
|
||||
#define APBC_GPIO 0x8
|
||||
#define APBC_PWM0 0xc
|
||||
#define APBC_PWM1 0x10
|
||||
#define APBC_PWM2 0x14
|
||||
#define APBC_PWM3 0x18
|
||||
#define APBC_SSP0 0x1c
|
||||
#define APBC_SSP1 0x20
|
||||
#define APBC_SSP2 0x4c
|
||||
#define APBCP_TWSI1 0x28
|
||||
#define APBCP_UART2 0x1c
|
||||
#define APMU_SDH0 0x54
|
||||
#define APMU_SDH1 0x58
|
||||
#define APMU_USB 0x5c
|
||||
#define APMU_DISP0 0x4c
|
||||
#define APMU_CCIC0 0x50
|
||||
#define APMU_DFC 0x60
|
||||
#define MPMU_UART_PLL 0x14
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static struct clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
.num_shift = 16,
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 8125, .den = 1536}, /*14.745MHZ */
|
||||
};
|
||||
|
||||
static const char *uart_parent[] = {"pll1_3_16", "uart_pll"};
|
||||
static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
|
||||
static const char *sdh_parent[] = {"pll1_12", "pll1_13"};
|
||||
static const char *disp_parent[] = {"pll1_2", "pll1_12"};
|
||||
static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
|
||||
static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
|
||||
|
||||
void __init pxa910_clk_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk *uart_pll;
|
||||
void __iomem *mpmu_base;
|
||||
void __iomem *apmu_base;
|
||||
void __iomem *apbcp_base;
|
||||
void __iomem *apbc_base;
|
||||
|
||||
mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
|
||||
if (mpmu_base == NULL) {
|
||||
pr_err("error to ioremap MPMU base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
|
||||
if (apmu_base == NULL) {
|
||||
pr_err("error to ioremap APMU base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
apbcp_base = ioremap(APB_PHYS_BASE + 0x3b000, SZ_4K);
|
||||
if (apbcp_base == NULL) {
|
||||
pr_err("error to ioremap APBC extension base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
|
||||
if (apbc_base == NULL) {
|
||||
pr_err("error to ioremap APBC base\n");
|
||||
return;
|
||||
}
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
|
||||
clk_register_clkdev(clk, "clk32", NULL);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
|
||||
26000000);
|
||||
clk_register_clkdev(clk, "vctcxo", NULL);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
|
||||
624000000);
|
||||
clk_register_clkdev(clk, "pll1", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_2", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_4", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_8", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_16", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2",
|
||||
CLK_SET_RATE_PARENT, 1, 3);
|
||||
clk_register_clkdev(clk, "pll1_6", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_12", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_24", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_48", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48",
|
||||
CLK_SET_RATE_PARENT, 1, 2);
|
||||
clk_register_clkdev(clk, "pll1_96", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1",
|
||||
CLK_SET_RATE_PARENT, 1, 13);
|
||||
clk_register_clkdev(clk, "pll1_13", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1",
|
||||
CLK_SET_RATE_PARENT, 2, 3);
|
||||
clk_register_clkdev(clk, "pll1_13_1_5", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1",
|
||||
CLK_SET_RATE_PARENT, 2, 3);
|
||||
clk_register_clkdev(clk, "pll1_2_1_5", NULL);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1",
|
||||
CLK_SET_RATE_PARENT, 3, 16);
|
||||
clk_register_clkdev(clk, "pll1_3_16", NULL);
|
||||
|
||||
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
|
||||
mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl));
|
||||
clk_set_rate(uart_pll, 14745600);
|
||||
clk_register_clkdev(uart_pll, "uart_pll", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5",
|
||||
apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
|
||||
|
||||
clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5",
|
||||
apbcp_base + APBCP_TWSI1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
|
||||
|
||||
clk = mmp_clk_register_apbc("gpio", "vctcxo",
|
||||
apbc_base + APBC_GPIO, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa-gpio");
|
||||
|
||||
clk = mmp_clk_register_apbc("kpc", "clk32",
|
||||
apbc_base + APBC_KPC, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa27x-keypad");
|
||||
|
||||
clk = mmp_clk_register_apbc("rtc", "clk32",
|
||||
apbc_base + APBC_RTC, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sa1100-rtc");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm0", "pll1_48",
|
||||
apbc_base + APBC_PWM0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa910-pwm.0");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm1", "pll1_48",
|
||||
apbc_base + APBC_PWM1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa910-pwm.1");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm2", "pll1_48",
|
||||
apbc_base + APBC_PWM2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa910-pwm.2");
|
||||
|
||||
clk = mmp_clk_register_apbc("pwm3", "pll1_48",
|
||||
apbc_base + APBC_PWM3, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa910-pwm.3");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, uart_pll);
|
||||
clk_register_clkdev(clk, "uart_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart0", "uart0_mux",
|
||||
apbc_base + APBC_UART0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, uart_pll);
|
||||
clk_register_clkdev(clk, "uart_mux.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart1", "uart1_mux",
|
||||
apbc_base + APBC_UART1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
|
||||
|
||||
clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
|
||||
ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
|
||||
apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock);
|
||||
clk_set_parent(clk, uart_pll);
|
||||
clk_register_clkdev(clk, "uart_mux.2", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("uart2", "uart2_mux",
|
||||
apbcp_base + APBCP_UART2, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "uart_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp0", "ssp0_mux",
|
||||
apbc_base + APBC_SSP0, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
|
||||
ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
|
||||
apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ssp_mux.1", NULL);
|
||||
|
||||
clk = mmp_clk_register_apbc("ssp1", "ssp1_mux",
|
||||
apbc_base + APBC_SSP1, 10, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-ssp.1");
|
||||
|
||||
clk = mmp_clk_register_apmu("dfc", "pll1_4",
|
||||
apmu_base + APMU_DFC, 0x19b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
|
||||
ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sdh0_mux", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh0", "sdh_mux",
|
||||
apmu_base + APMU_SDH0, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
|
||||
ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sdh1_mux", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("sdh1", "sdh1_mux",
|
||||
apmu_base + APMU_SDH1, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "sdhci-pxa.1");
|
||||
|
||||
clk = mmp_clk_register_apmu("usb", "usb_pll",
|
||||
apmu_base + APMU_USB, 0x9, &clk_lock);
|
||||
clk_register_clkdev(clk, "usb_clk", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("sph", "usb_pll",
|
||||
apmu_base + APMU_USB, 0x12, &clk_lock);
|
||||
clk_register_clkdev(clk, "sph_clk", NULL);
|
||||
|
||||
clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
|
||||
ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "disp_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("disp0", "disp0_mux",
|
||||
apmu_base + APMU_DISP0, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, NULL, "mmp-disp.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
|
||||
ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
|
||||
apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0", "ccic0_mux",
|
||||
apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
|
||||
clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
|
||||
|
||||
clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
|
||||
ARRAY_SIZE(ccic_phy_parent),
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
|
||||
7, 1, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
|
||||
apmu_base + APMU_CCIC0, 0x24, &clk_lock);
|
||||
clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
|
||||
|
||||
clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux",
|
||||
CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
|
||||
10, 5, 0, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk_div", NULL);
|
||||
|
||||
clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
|
||||
apmu_base + APMU_CCIC0, 0x300, &clk_lock);
|
||||
clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
|
||||
}
|
35
drivers/clk/mmp/clk.h
Normal file
35
drivers/clk/mmp/clk.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __MACH_MMP_CLK_H
|
||||
#define __MACH_MMP_CLK_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
#define APBC_NO_BUS_CTRL BIT(0)
|
||||
#define APBC_POWER_CTRL BIT(1)
|
||||
|
||||
struct clk_factor_masks {
|
||||
unsigned int factor;
|
||||
unsigned int num_mask;
|
||||
unsigned int den_mask;
|
||||
unsigned int num_shift;
|
||||
unsigned int den_shift;
|
||||
};
|
||||
|
||||
struct clk_factor_tbl {
|
||||
unsigned int num;
|
||||
unsigned int den;
|
||||
};
|
||||
|
||||
extern struct clk *mmp_clk_register_pll2(const char *name,
|
||||
const char *parent_name, unsigned long flags);
|
||||
extern struct clk *mmp_clk_register_apbc(const char *name,
|
||||
const char *parent_name, void __iomem *base,
|
||||
unsigned int delay, unsigned int apbc_flags, spinlock_t *lock);
|
||||
extern struct clk *mmp_clk_register_apmu(const char *name,
|
||||
const char *parent_name, void __iomem *base, u32 enable_mask,
|
||||
spinlock_t *lock);
|
||||
extern struct clk *mmp_clk_register_factor(const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *base, struct clk_factor_masks *masks,
|
||||
struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt);
|
||||
#endif
|
12
drivers/clk/ux500/Makefile
Normal file
12
drivers/clk/ux500/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# Makefile for ux500 clocks
|
||||
#
|
||||
|
||||
# Clock types
|
||||
obj-y += clk-prcc.o
|
||||
obj-y += clk-prcmu.o
|
||||
|
||||
# Clock definitions
|
||||
obj-y += u8500_clk.o
|
||||
obj-y += u9540_clk.o
|
||||
obj-y += u8540_clk.o
|
164
drivers/clk/ux500/clk-prcc.c
Normal file
164
drivers/clk/ux500/clk-prcc.c
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* PRCC clock implementation for ux500 platform.
|
||||
*
|
||||
* Copyright (C) 2012 ST-Ericsson SA
|
||||
* Author: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/types.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define PRCC_PCKEN 0x000
|
||||
#define PRCC_PCKDIS 0x004
|
||||
#define PRCC_KCKEN 0x008
|
||||
#define PRCC_KCKDIS 0x00C
|
||||
#define PRCC_PCKSR 0x010
|
||||
#define PRCC_KCKSR 0x014
|
||||
|
||||
#define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw)
|
||||
|
||||
struct clk_prcc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
u32 cg_sel;
|
||||
int is_enabled;
|
||||
};
|
||||
|
||||
/* PRCC clock operations. */
|
||||
|
||||
static int clk_prcc_pclk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcc *clk = to_clk_prcc(hw);
|
||||
|
||||
writel(clk->cg_sel, (clk->base + PRCC_PCKEN));
|
||||
while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel))
|
||||
cpu_relax();
|
||||
|
||||
clk->is_enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_prcc_pclk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcc *clk = to_clk_prcc(hw);
|
||||
|
||||
writel(clk->cg_sel, (clk->base + PRCC_PCKDIS));
|
||||
clk->is_enabled = 0;
|
||||
}
|
||||
|
||||
static int clk_prcc_kclk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcc *clk = to_clk_prcc(hw);
|
||||
|
||||
writel(clk->cg_sel, (clk->base + PRCC_KCKEN));
|
||||
while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel))
|
||||
cpu_relax();
|
||||
|
||||
clk->is_enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_prcc_kclk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcc *clk = to_clk_prcc(hw);
|
||||
|
||||
writel(clk->cg_sel, (clk->base + PRCC_KCKDIS));
|
||||
clk->is_enabled = 0;
|
||||
}
|
||||
|
||||
static int clk_prcc_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcc *clk = to_clk_prcc(hw);
|
||||
return clk->is_enabled;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_prcc_pclk_ops = {
|
||||
.enable = clk_prcc_pclk_enable,
|
||||
.disable = clk_prcc_pclk_disable,
|
||||
.is_enabled = clk_prcc_is_enabled,
|
||||
};
|
||||
|
||||
static struct clk_ops clk_prcc_kclk_ops = {
|
||||
.enable = clk_prcc_kclk_enable,
|
||||
.disable = clk_prcc_kclk_disable,
|
||||
.is_enabled = clk_prcc_is_enabled,
|
||||
};
|
||||
|
||||
static struct clk *clk_reg_prcc(const char *name,
|
||||
const char *parent_name,
|
||||
resource_size_t phy_base,
|
||||
u32 cg_sel,
|
||||
unsigned long flags,
|
||||
struct clk_ops *clk_prcc_ops)
|
||||
{
|
||||
struct clk_prcc *clk;
|
||||
struct clk_init_data clk_prcc_init;
|
||||
struct clk *clk_reg;
|
||||
|
||||
if (!name) {
|
||||
pr_err("clk_prcc: %s invalid arguments passed\n", __func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL);
|
||||
if (!clk) {
|
||||
pr_err("clk_prcc: %s could not allocate clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
clk->base = ioremap(phy_base, SZ_4K);
|
||||
if (!clk->base)
|
||||
goto free_clk;
|
||||
|
||||
clk->cg_sel = cg_sel;
|
||||
clk->is_enabled = 1;
|
||||
|
||||
clk_prcc_init.name = name;
|
||||
clk_prcc_init.ops = clk_prcc_ops;
|
||||
clk_prcc_init.flags = flags;
|
||||
clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
clk_prcc_init.num_parents = (parent_name ? 1 : 0);
|
||||
clk->hw.init = &clk_prcc_init;
|
||||
|
||||
clk_reg = clk_register(NULL, &clk->hw);
|
||||
if (IS_ERR_OR_NULL(clk_reg))
|
||||
goto unmap_clk;
|
||||
|
||||
return clk_reg;
|
||||
|
||||
unmap_clk:
|
||||
iounmap(clk->base);
|
||||
free_clk:
|
||||
kfree(clk);
|
||||
pr_err("clk_prcc: %s failed to register clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
struct clk *clk_reg_prcc_pclk(const char *name,
|
||||
const char *parent_name,
|
||||
resource_size_t phy_base,
|
||||
u32 cg_sel,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
|
||||
&clk_prcc_pclk_ops);
|
||||
}
|
||||
|
||||
struct clk *clk_reg_prcc_kclk(const char *name,
|
||||
const char *parent_name,
|
||||
resource_size_t phy_base,
|
||||
u32 cg_sel,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
|
||||
&clk_prcc_kclk_ops);
|
||||
}
|
252
drivers/clk/ux500/clk-prcmu.c
Normal file
252
drivers/clk/ux500/clk-prcmu.c
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* PRCMU clock implementation for ux500 platform.
|
||||
*
|
||||
* Copyright (C) 2012 ST-Ericsson SA
|
||||
* Author: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include <linux/mfd/dbx500-prcmu.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include "clk.h"
|
||||
|
||||
#define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw)
|
||||
|
||||
struct clk_prcmu {
|
||||
struct clk_hw hw;
|
||||
u8 cg_sel;
|
||||
int is_enabled;
|
||||
};
|
||||
|
||||
/* PRCMU clock operations. */
|
||||
|
||||
static int clk_prcmu_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
return prcmu_request_clock(clk->cg_sel, true);
|
||||
}
|
||||
|
||||
static void clk_prcmu_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
if (prcmu_request_clock(clk->cg_sel, false))
|
||||
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
|
||||
hw->init->name);
|
||||
}
|
||||
|
||||
static int clk_prcmu_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
clk->is_enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_prcmu_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
clk->is_enabled = 0;
|
||||
}
|
||||
|
||||
static int clk_prcmu_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
return clk->is_enabled;
|
||||
}
|
||||
|
||||
static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
return prcmu_clock_rate(clk->cg_sel);
|
||||
}
|
||||
|
||||
static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
return prcmu_round_clock_rate(clk->cg_sel, rate);
|
||||
}
|
||||
|
||||
static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
return prcmu_set_clock_rate(clk->cg_sel, rate);
|
||||
}
|
||||
|
||||
static int request_ape_opp100(bool enable)
|
||||
{
|
||||
static int reqs;
|
||||
int err = 0;
|
||||
|
||||
if (enable) {
|
||||
if (!reqs)
|
||||
err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
|
||||
"clock", 100);
|
||||
if (!err)
|
||||
reqs++;
|
||||
} else {
|
||||
reqs--;
|
||||
if (!reqs)
|
||||
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
|
||||
"clock");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int clk_prcmu_opp_prepare(struct clk_hw *hw)
|
||||
{
|
||||
int err;
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
|
||||
err = request_ape_opp100(true);
|
||||
if (err) {
|
||||
pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n",
|
||||
__func__, hw->init->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = prcmu_request_clock(clk->cg_sel, true);
|
||||
if (err)
|
||||
request_ape_opp100(false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
|
||||
if (prcmu_request_clock(clk->cg_sel, false))
|
||||
goto out_error;
|
||||
if (request_ape_opp100(false))
|
||||
goto out_error;
|
||||
return;
|
||||
|
||||
out_error:
|
||||
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
|
||||
hw->init->name);
|
||||
}
|
||||
|
||||
static struct clk_ops clk_prcmu_scalable_ops = {
|
||||
.prepare = clk_prcmu_prepare,
|
||||
.unprepare = clk_prcmu_unprepare,
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
.recalc_rate = clk_prcmu_recalc_rate,
|
||||
.round_rate = clk_prcmu_round_rate,
|
||||
.set_rate = clk_prcmu_set_rate,
|
||||
};
|
||||
|
||||
static struct clk_ops clk_prcmu_gate_ops = {
|
||||
.prepare = clk_prcmu_prepare,
|
||||
.unprepare = clk_prcmu_unprepare,
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
.recalc_rate = clk_prcmu_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_ops clk_prcmu_rate_ops = {
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
.recalc_rate = clk_prcmu_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_ops clk_prcmu_opp_gate_ops = {
|
||||
.prepare = clk_prcmu_opp_prepare,
|
||||
.unprepare = clk_prcmu_opp_unprepare,
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
.recalc_rate = clk_prcmu_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk *clk_reg_prcmu(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long rate,
|
||||
unsigned long flags,
|
||||
struct clk_ops *clk_prcmu_ops)
|
||||
{
|
||||
struct clk_prcmu *clk;
|
||||
struct clk_init_data clk_prcmu_init;
|
||||
struct clk *clk_reg;
|
||||
|
||||
if (!name) {
|
||||
pr_err("clk_prcmu: %s invalid arguments passed\n", __func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL);
|
||||
if (!clk) {
|
||||
pr_err("clk_prcmu: %s could not allocate clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
clk->cg_sel = cg_sel;
|
||||
clk->is_enabled = 1;
|
||||
/* "rate" can be used for changing the initial frequency */
|
||||
if (rate)
|
||||
prcmu_set_clock_rate(cg_sel, rate);
|
||||
|
||||
clk_prcmu_init.name = name;
|
||||
clk_prcmu_init.ops = clk_prcmu_ops;
|
||||
clk_prcmu_init.flags = flags;
|
||||
clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
clk_prcmu_init.num_parents = (parent_name ? 1 : 0);
|
||||
clk->hw.init = &clk_prcmu_init;
|
||||
|
||||
clk_reg = clk_register(NULL, &clk->hw);
|
||||
if (IS_ERR_OR_NULL(clk_reg))
|
||||
goto free_clk;
|
||||
|
||||
return clk_reg;
|
||||
|
||||
free_clk:
|
||||
kfree(clk);
|
||||
pr_err("clk_prcmu: %s failed to register clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
struct clk *clk_reg_prcmu_scalable(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long rate,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
|
||||
&clk_prcmu_scalable_ops);
|
||||
}
|
||||
|
||||
struct clk *clk_reg_prcmu_gate(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
|
||||
&clk_prcmu_gate_ops);
|
||||
}
|
||||
|
||||
struct clk *clk_reg_prcmu_rate(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
|
||||
&clk_prcmu_rate_ops);
|
||||
}
|
||||
|
||||
struct clk *clk_reg_prcmu_opp_gate(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
|
||||
&clk_prcmu_opp_gate_ops);
|
||||
}
|
48
drivers/clk/ux500/clk.h
Normal file
48
drivers/clk/ux500/clk.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Clocks for ux500 platforms
|
||||
*
|
||||
* Copyright (C) 2012 ST-Ericsson SA
|
||||
* Author: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#ifndef __UX500_CLK_H
|
||||
#define __UX500_CLK_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
||||
struct clk *clk_reg_prcc_pclk(const char *name,
|
||||
const char *parent_name,
|
||||
unsigned int phy_base,
|
||||
u32 cg_sel,
|
||||
unsigned long flags);
|
||||
|
||||
struct clk *clk_reg_prcc_kclk(const char *name,
|
||||
const char *parent_name,
|
||||
unsigned int phy_base,
|
||||
u32 cg_sel,
|
||||
unsigned long flags);
|
||||
|
||||
struct clk *clk_reg_prcmu_scalable(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long rate,
|
||||
unsigned long flags);
|
||||
|
||||
struct clk *clk_reg_prcmu_gate(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long flags);
|
||||
|
||||
struct clk *clk_reg_prcmu_rate(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long flags);
|
||||
|
||||
struct clk *clk_reg_prcmu_opp_gate(const char *name,
|
||||
const char *parent_name,
|
||||
u8 cg_sel,
|
||||
unsigned long flags);
|
||||
|
||||
#endif /* __UX500_CLK_H */
|
477
drivers/clk/ux500/u8500_clk.c
Normal file
477
drivers/clk/ux500/u8500_clk.c
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Clock definitions for u8500 platform.
|
||||
*
|
||||
* Copyright (C) 2012 ST-Ericsson SA
|
||||
* Author: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/dbx500-prcmu.h>
|
||||
#include <linux/platform_data/clk-ux500.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
void u8500_clk_init(void)
|
||||
{
|
||||
struct prcmu_fw_version *fw_version;
|
||||
const char *sgaclk_parent = NULL;
|
||||
struct clk *clk;
|
||||
|
||||
/* Clock sources */
|
||||
clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
|
||||
CLK_IS_ROOT|CLK_IGNORE_UNUSED);
|
||||
clk_register_clkdev(clk, "soc0_pll", NULL);
|
||||
|
||||
clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1,
|
||||
CLK_IS_ROOT|CLK_IGNORE_UNUSED);
|
||||
clk_register_clkdev(clk, "soc1_pll", NULL);
|
||||
|
||||
clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR,
|
||||
CLK_IS_ROOT|CLK_IGNORE_UNUSED);
|
||||
clk_register_clkdev(clk, "ddr_pll", NULL);
|
||||
|
||||
/* FIXME: Add sys, ulp and int clocks here. */
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "rtc32k", "NULL",
|
||||
CLK_IS_ROOT|CLK_IGNORE_UNUSED,
|
||||
32768);
|
||||
clk_register_clkdev(clk, "clk32k", NULL);
|
||||
clk_register_clkdev(clk, NULL, "rtc-pl031");
|
||||
|
||||
/* PRCMU clocks */
|
||||
fw_version = prcmu_get_fw_version();
|
||||
if (fw_version != NULL) {
|
||||
switch (fw_version->project) {
|
||||
case PRCMU_FW_PROJECT_U8500_C2:
|
||||
case PRCMU_FW_PROJECT_U8520:
|
||||
case PRCMU_FW_PROJECT_U8420:
|
||||
sgaclk_parent = "soc0_pll";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sgaclk_parent)
|
||||
clk = clk_reg_prcmu_gate("sgclk", sgaclk_parent,
|
||||
PRCMU_SGACLK, 0);
|
||||
else
|
||||
clk = clk_reg_prcmu_gate("sgclk", NULL,
|
||||
PRCMU_SGACLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "mali");
|
||||
|
||||
clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "UART");
|
||||
|
||||
clk = clk_reg_prcmu_gate("msp02clk", NULL, PRCMU_MSP02CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "MSP02");
|
||||
|
||||
clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "MSP1");
|
||||
|
||||
clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "I2C");
|
||||
|
||||
clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "slim");
|
||||
|
||||
clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "PERIPH1");
|
||||
|
||||
clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "PERIPH2");
|
||||
|
||||
clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "PERIPH3");
|
||||
|
||||
clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "PERIPH5");
|
||||
|
||||
clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "PERIPH6");
|
||||
|
||||
clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "PERIPH7");
|
||||
|
||||
clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0,
|
||||
CLK_IS_ROOT|CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "lcd");
|
||||
clk_register_clkdev(clk, "lcd", "mcde");
|
||||
|
||||
clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BMLCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "bml");
|
||||
|
||||
clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0,
|
||||
CLK_IS_ROOT|CLK_SET_RATE_GATE);
|
||||
|
||||
clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0,
|
||||
CLK_IS_ROOT|CLK_SET_RATE_GATE);
|
||||
|
||||
clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0,
|
||||
CLK_IS_ROOT|CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "hdmi");
|
||||
clk_register_clkdev(clk, "hdmi", "mcde");
|
||||
|
||||
clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "apeat");
|
||||
|
||||
clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
|
||||
CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "apetrace");
|
||||
|
||||
clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "mcde");
|
||||
clk_register_clkdev(clk, "mcde", "mcde");
|
||||
clk_register_clkdev(clk, "dsisys", "dsilink.0");
|
||||
clk_register_clkdev(clk, "dsisys", "dsilink.1");
|
||||
clk_register_clkdev(clk, "dsisys", "dsilink.2");
|
||||
|
||||
clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK,
|
||||
CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "ipi2");
|
||||
|
||||
clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK,
|
||||
CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "dsialt");
|
||||
|
||||
clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "dma40.0");
|
||||
|
||||
clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "b2r2");
|
||||
clk_register_clkdev(clk, NULL, "b2r2_core");
|
||||
clk_register_clkdev(clk, NULL, "U8500-B2R2.0");
|
||||
|
||||
clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0,
|
||||
CLK_IS_ROOT|CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "tv");
|
||||
clk_register_clkdev(clk, "tv", "mcde");
|
||||
|
||||
clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "SSP");
|
||||
|
||||
clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "rngclk");
|
||||
|
||||
clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "uicc");
|
||||
|
||||
/*
|
||||
* FIXME: The MTU clocks might need some kind of "parent muxed join"
|
||||
* and these have no K-clocks. For now, we ignore the missing
|
||||
* connection to the corresponding P-clocks, p6_mtu0_clk and
|
||||
* p6_mtu1_clk. Instead timclk is used which is the valid parent.
|
||||
*/
|
||||
clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "mtu0");
|
||||
clk_register_clkdev(clk, NULL, "mtu1");
|
||||
|
||||
clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT);
|
||||
clk_register_clkdev(clk, NULL, "sdmmc");
|
||||
|
||||
|
||||
clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
|
||||
PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, "dsihs2", "mcde");
|
||||
clk_register_clkdev(clk, "dsihs2", "dsilink.2");
|
||||
|
||||
|
||||
clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll",
|
||||
PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, "dsihs0", "mcde");
|
||||
clk_register_clkdev(clk, "dsihs0", "dsilink.0");
|
||||
|
||||
clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll",
|
||||
PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, "dsihs1", "mcde");
|
||||
clk_register_clkdev(clk, "dsihs1", "dsilink.1");
|
||||
|
||||
clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk",
|
||||
PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, "dsilp0", "dsilink.0");
|
||||
clk_register_clkdev(clk, "dsilp0", "mcde");
|
||||
|
||||
clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk",
|
||||
PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, "dsilp1", "dsilink.1");
|
||||
clk_register_clkdev(clk, "dsilp1", "mcde");
|
||||
|
||||
clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk",
|
||||
PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, "dsilp2", "dsilink.2");
|
||||
clk_register_clkdev(clk, "dsilp2", "mcde");
|
||||
|
||||
clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS,
|
||||
CLK_IS_ROOT|CLK_GET_RATE_NOCACHE|
|
||||
CLK_IGNORE_UNUSED);
|
||||
clk_register_clkdev(clk, NULL, "smp_twd");
|
||||
|
||||
/*
|
||||
* FIXME: Add special handled PRCMU clocks here:
|
||||
* 1. clk_arm, use PRCMU_ARMCLK.
|
||||
* 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
|
||||
* 3. ab9540_clkout1yuv, see clkout0yuv
|
||||
*/
|
||||
|
||||
/* PRCC P-clocks */
|
||||
clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(0), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "uart0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(1), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "uart1");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(2), 0);
|
||||
clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(3), 0);
|
||||
clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(4), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(5), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "sdi0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(6), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(7), 0);
|
||||
clk_register_clkdev(clk, NULL, "spi3");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(8), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(9), 0);
|
||||
clk_register_clkdev(clk, NULL, "gpio.0");
|
||||
clk_register_clkdev(clk, NULL, "gpio.1");
|
||||
clk_register_clkdev(clk, NULL, "gpioblock0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(10), 0);
|
||||
clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", U8500_CLKRST1_BASE,
|
||||
BIT(11), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(0), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(1), 0);
|
||||
clk_register_clkdev(clk, NULL, "spi2");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(2), 0);
|
||||
clk_register_clkdev(clk, NULL, "spi1");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(3), 0);
|
||||
clk_register_clkdev(clk, NULL, "pwl");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(4), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "sdi4");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(5), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(6), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "sdi1");
|
||||
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(7), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "sdi3");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(8), 0);
|
||||
clk_register_clkdev(clk, NULL, "spi0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(9), 0);
|
||||
clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(10), 0);
|
||||
clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(11), 0);
|
||||
clk_register_clkdev(clk, NULL, "gpio.6");
|
||||
clk_register_clkdev(clk, NULL, "gpio.7");
|
||||
clk_register_clkdev(clk, NULL, "gpioblock1");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE,
|
||||
BIT(11), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(0), 0);
|
||||
clk_register_clkdev(clk, NULL, "fsmc");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(1), 0);
|
||||
clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(2), 0);
|
||||
clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(3), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(4), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "sdi2");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(5), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(6), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "uart2");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(7), 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", "sdi5");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", U8500_CLKRST3_BASE,
|
||||
BIT(8), 0);
|
||||
clk_register_clkdev(clk, NULL, "gpio.2");
|
||||
clk_register_clkdev(clk, NULL, "gpio.3");
|
||||
clk_register_clkdev(clk, NULL, "gpio.4");
|
||||
clk_register_clkdev(clk, NULL, "gpio.5");
|
||||
clk_register_clkdev(clk, NULL, "gpioblock2");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", U8500_CLKRST5_BASE,
|
||||
BIT(0), 0);
|
||||
clk_register_clkdev(clk, "usb", "musb-ux500.0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", U8500_CLKRST5_BASE,
|
||||
BIT(1), 0);
|
||||
clk_register_clkdev(clk, NULL, "gpio.8");
|
||||
clk_register_clkdev(clk, NULL, "gpioblock3");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(0), 0);
|
||||
|
||||
clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(1), 0);
|
||||
clk_register_clkdev(clk, NULL, "cryp0");
|
||||
clk_register_clkdev(clk, NULL, "cryp1");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(2), 0);
|
||||
clk_register_clkdev(clk, NULL, "hash0");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(3), 0);
|
||||
clk_register_clkdev(clk, NULL, "pka");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(4), 0);
|
||||
clk_register_clkdev(clk, NULL, "hash1");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(5), 0);
|
||||
clk_register_clkdev(clk, NULL, "cfgreg");
|
||||
|
||||
clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(6), 0);
|
||||
clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", U8500_CLKRST6_BASE,
|
||||
BIT(7), 0);
|
||||
|
||||
/* PRCC K-clocks
|
||||
*
|
||||
* FIXME: Some drivers requires PERPIH[n| to be automatically enabled
|
||||
* by enabling just the K-clock, even if it is not a valid parent to
|
||||
* the K-clock. Until drivers get fixed we might need some kind of
|
||||
* "parent muxed join".
|
||||
*/
|
||||
|
||||
/* Periph1 */
|
||||
clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
|
||||
U8500_CLKRST1_BASE, BIT(0), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "uart0");
|
||||
|
||||
clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
|
||||
U8500_CLKRST1_BASE, BIT(1), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "uart1");
|
||||
|
||||
clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
|
||||
U8500_CLKRST1_BASE, BIT(2), CLK_SET_RATE_GATE);
|
||||
clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
|
||||
U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
|
||||
clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
|
||||
U8500_CLKRST1_BASE, BIT(4), CLK_SET_RATE_GATE);
|
||||
|
||||
clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk",
|
||||
U8500_CLKRST1_BASE, BIT(5), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "sdi0");
|
||||
|
||||
clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
|
||||
U8500_CLKRST1_BASE, BIT(6), CLK_SET_RATE_GATE);
|
||||
clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
|
||||
U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
|
||||
/* FIXME: Redefinition of BIT(3). */
|
||||
clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
|
||||
U8500_CLKRST1_BASE, BIT(9), CLK_SET_RATE_GATE);
|
||||
clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
|
||||
U8500_CLKRST1_BASE, BIT(10), CLK_SET_RATE_GATE);
|
||||
|
||||
/* Periph2 */
|
||||
clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
|
||||
U8500_CLKRST2_BASE, BIT(0), CLK_SET_RATE_GATE);
|
||||
|
||||
clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk",
|
||||
U8500_CLKRST2_BASE, BIT(2), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "sdi4");
|
||||
|
||||
clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
|
||||
U8500_CLKRST2_BASE, BIT(3), CLK_SET_RATE_GATE);
|
||||
|
||||
clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk",
|
||||
U8500_CLKRST2_BASE, BIT(4), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "sdi1");
|
||||
|
||||
clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
|
||||
U8500_CLKRST2_BASE, BIT(5), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "sdi3");
|
||||
|
||||
/* Note that rate is received from parent. */
|
||||
clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
|
||||
U8500_CLKRST2_BASE, BIT(6),
|
||||
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
|
||||
clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
|
||||
U8500_CLKRST2_BASE, BIT(7),
|
||||
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
|
||||
|
||||
/* Periph3 */
|
||||
clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
|
||||
U8500_CLKRST3_BASE, BIT(1), CLK_SET_RATE_GATE);
|
||||
clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
|
||||
U8500_CLKRST3_BASE, BIT(2), CLK_SET_RATE_GATE);
|
||||
clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
|
||||
U8500_CLKRST3_BASE, BIT(3), CLK_SET_RATE_GATE);
|
||||
|
||||
clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk",
|
||||
U8500_CLKRST3_BASE, BIT(4), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "sdi2");
|
||||
|
||||
clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
|
||||
U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE);
|
||||
|
||||
clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
|
||||
U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "uart2");
|
||||
|
||||
clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
|
||||
U8500_CLKRST3_BASE, BIT(7), CLK_SET_RATE_GATE);
|
||||
clk_register_clkdev(clk, NULL, "sdi5");
|
||||
|
||||
/* Periph6 */
|
||||
clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
|
||||
U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE);
|
||||
|
||||
}
|
21
drivers/clk/ux500/u8540_clk.c
Normal file
21
drivers/clk/ux500/u8540_clk.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Clock definitions for u8540 platform.
|
||||
*
|
||||
* Copyright (C) 2012 ST-Ericsson SA
|
||||
* Author: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/dbx500-prcmu.h>
|
||||
#include <linux/platform_data/clk-ux500.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
void u8540_clk_init(void)
|
||||
{
|
||||
/* register clocks here */
|
||||
}
|
21
drivers/clk/ux500/u9540_clk.c
Normal file
21
drivers/clk/ux500/u9540_clk.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Clock definitions for u9540 platform.
|
||||
*
|
||||
* Copyright (C) 2012 ST-Ericsson SA
|
||||
* Author: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/dbx500-prcmu.h>
|
||||
#include <linux/platform_data/clk-ux500.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
void u9540_clk_init(void)
|
||||
{
|
||||
/* register clocks here */
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
# Makefile for Versatile-specific clocks
|
||||
obj-$(CONFIG_ICST) += clk-icst.o
|
||||
obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
|
||||
obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
|
||||
|
114
drivers/clk/versatile/clk-realview.c
Normal file
114
drivers/clk/versatile/clk-realview.c
Normal file
@ -0,0 +1,114 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/platform.h>
|
||||
|
||||
#include "clk-icst.h"
|
||||
|
||||
/*
|
||||
* Implementation of the ARM RealView clock trees.
|
||||
*/
|
||||
|
||||
static void __iomem *sys_lock;
|
||||
static void __iomem *sys_vcoreg;
|
||||
|
||||
/**
|
||||
* realview_oscvco_get() - get ICST OSC settings for the RealView
|
||||
*/
|
||||
static struct icst_vco realview_oscvco_get(void)
|
||||
{
|
||||
u32 val;
|
||||
struct icst_vco vco;
|
||||
|
||||
val = readl(sys_vcoreg);
|
||||
vco.v = val & 0x1ff;
|
||||
vco.r = (val >> 9) & 0x7f;
|
||||
vco.s = (val >> 16) & 03;
|
||||
return vco;
|
||||
}
|
||||
|
||||
static void realview_oscvco_set(struct icst_vco vco)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(sys_vcoreg) & ~0x7ffff;
|
||||
val |= vco.v | (vco.r << 9) | (vco.s << 16);
|
||||
|
||||
/* This magic unlocks the CM VCO so it can be controlled */
|
||||
writel(0xa05f, sys_lock);
|
||||
writel(val, sys_vcoreg);
|
||||
/* This locks the CM again */
|
||||
writel(0, sys_lock);
|
||||
}
|
||||
|
||||
static const struct icst_params realview_oscvco_params = {
|
||||
.ref = 24000000,
|
||||
.vco_max = ICST307_VCO_MAX,
|
||||
.vco_min = ICST307_VCO_MIN,
|
||||
.vd_min = 4 + 8,
|
||||
.vd_max = 511 + 8,
|
||||
.rd_min = 1 + 2,
|
||||
.rd_max = 127 + 2,
|
||||
.s2div = icst307_s2div,
|
||||
.idx2s = icst307_idx2s,
|
||||
};
|
||||
|
||||
static const struct clk_icst_desc __initdata realview_icst_desc = {
|
||||
.params = &realview_oscvco_params,
|
||||
.getvco = realview_oscvco_get,
|
||||
.setvco = realview_oscvco_set,
|
||||
};
|
||||
|
||||
/*
|
||||
* realview_clk_init() - set up the RealView clock tree
|
||||
*/
|
||||
void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
|
||||
if (is_pb1176)
|
||||
sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
|
||||
else
|
||||
sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;
|
||||
|
||||
|
||||
/* APB clock dummy */
|
||||
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", NULL);
|
||||
|
||||
/* 24 MHz clock */
|
||||
clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT,
|
||||
24000000);
|
||||
clk_register_clkdev(clk, NULL, "dev:uart0");
|
||||
clk_register_clkdev(clk, NULL, "dev:uart1");
|
||||
clk_register_clkdev(clk, NULL, "dev:uart2");
|
||||
clk_register_clkdev(clk, NULL, "fpga:kmi0");
|
||||
clk_register_clkdev(clk, NULL, "fpga:kmi1");
|
||||
clk_register_clkdev(clk, NULL, "fpga:mmc0");
|
||||
clk_register_clkdev(clk, NULL, "dev:ssp0");
|
||||
if (is_pb1176) {
|
||||
/*
|
||||
* UART3 is on the dev chip in PB1176
|
||||
* UART4 only exists in PB1176
|
||||
*/
|
||||
clk_register_clkdev(clk, NULL, "dev:uart3");
|
||||
clk_register_clkdev(clk, NULL, "dev:uart4");
|
||||
} else
|
||||
clk_register_clkdev(clk, NULL, "fpga:uart3");
|
||||
|
||||
|
||||
/* 1 MHz clock */
|
||||
clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT,
|
||||
1000000);
|
||||
clk_register_clkdev(clk, NULL, "sp804");
|
||||
|
||||
/* ICST VCO clock */
|
||||
clk = icst_clk_register(NULL, &realview_icst_desc);
|
||||
clk_register_clkdev(clk, NULL, "dev:clcd");
|
||||
clk_register_clkdev(clk, NULL, "issp:clcd");
|
||||
}
|
@ -418,6 +418,9 @@ static struct {
|
||||
|
||||
static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
|
||||
|
||||
/* Functions definition */
|
||||
static void compute_armss_rate(void);
|
||||
|
||||
/* Spinlocks */
|
||||
static DEFINE_SPINLOCK(prcmu_lock);
|
||||
static DEFINE_SPINLOCK(clkout_lock);
|
||||
@ -517,6 +520,7 @@ static struct dsiescclk dsiescclk[3] = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Used by MCDE to setup all necessary PRCMU registers
|
||||
*/
|
||||
@ -1013,6 +1017,7 @@ int db8500_prcmu_set_arm_opp(u8 opp)
|
||||
(mb1_transfer.ack.arm_opp != opp))
|
||||
r = -EIO;
|
||||
|
||||
compute_armss_rate();
|
||||
mutex_unlock(&mb1_transfer.lock);
|
||||
|
||||
return r;
|
||||
@ -1612,6 +1617,7 @@ static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
|
||||
if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
|
||||
(val & PRCM_PLL_FREQ_DIV2EN) &&
|
||||
((reg == PRCM_PLLSOC0_FREQ) ||
|
||||
(reg == PRCM_PLLARM_FREQ) ||
|
||||
(reg == PRCM_PLLDDR_FREQ))))
|
||||
div *= 2;
|
||||
|
||||
@ -1661,6 +1667,39 @@ static unsigned long clock_rate(u8 clock)
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static unsigned long latest_armss_rate;
|
||||
static unsigned long armss_rate(void)
|
||||
{
|
||||
return latest_armss_rate;
|
||||
}
|
||||
|
||||
static void compute_armss_rate(void)
|
||||
{
|
||||
u32 r;
|
||||
unsigned long rate;
|
||||
|
||||
r = readl(PRCM_ARM_CHGCLKREQ);
|
||||
|
||||
if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) {
|
||||
/* External ARMCLKFIX clock */
|
||||
|
||||
rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX);
|
||||
|
||||
/* Check PRCM_ARM_CHGCLKREQ divider */
|
||||
if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL))
|
||||
rate /= 2;
|
||||
|
||||
/* Check PRCM_ARMCLKFIX_MGT divider */
|
||||
r = readl(PRCM_ARMCLKFIX_MGT);
|
||||
r &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
|
||||
rate /= r;
|
||||
|
||||
} else {/* ARM PLL */
|
||||
rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV);
|
||||
}
|
||||
|
||||
latest_armss_rate = rate;
|
||||
}
|
||||
|
||||
static unsigned long dsiclk_rate(u8 n)
|
||||
{
|
||||
@ -1707,6 +1746,8 @@ unsigned long prcmu_clock_rate(u8 clock)
|
||||
return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
|
||||
else if (clock == PRCMU_PLLSOC1)
|
||||
return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
|
||||
else if (clock == PRCMU_ARMSS)
|
||||
return armss_rate();
|
||||
else if (clock == PRCMU_PLLDDR)
|
||||
return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
|
||||
else if (clock == PRCMU_PLLDSI)
|
||||
@ -2693,6 +2734,7 @@ void __init db8500_prcmu_early_init(void)
|
||||
handle_simple_irq);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
compute_armss_rate();
|
||||
}
|
||||
|
||||
static void __init init_prcm_registers(void)
|
||||
|
@ -61,7 +61,8 @@
|
||||
#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2
|
||||
|
||||
#define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114)
|
||||
#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1
|
||||
#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0)
|
||||
#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL BIT(16)
|
||||
|
||||
#define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98)
|
||||
#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1
|
||||
@ -140,6 +141,7 @@
|
||||
/* PRCMU clock/PLL/reset registers */
|
||||
#define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080)
|
||||
#define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084)
|
||||
#define PRCM_PLLARM_FREQ (_PRCMU_BASE + 0x088)
|
||||
#define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C)
|
||||
#define PRCM_PLL_FREQ_D_SHIFT 0
|
||||
#define PRCM_PLL_FREQ_D_MASK BITS(0, 7)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#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_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
|
||||
#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
|
||||
|
||||
struct clk_hw;
|
||||
|
||||
@ -360,6 +361,11 @@ int of_clk_add_provider(struct device_node *np,
|
||||
void of_clk_del_provider(struct device_node *np);
|
||||
struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
|
||||
void *data);
|
||||
struct clk_onecell_data {
|
||||
struct clk **clks;
|
||||
unsigned int clk_num;
|
||||
};
|
||||
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
|
||||
const char *of_clk_get_parent_name(struct device_node *np, int index);
|
||||
void of_clk_init(const struct of_device_id *matches);
|
||||
|
||||
|
@ -136,6 +136,7 @@ enum prcmu_clock {
|
||||
PRCMU_TIMCLK,
|
||||
PRCMU_PLLSOC0,
|
||||
PRCMU_PLLSOC1,
|
||||
PRCMU_ARMSS,
|
||||
PRCMU_PLLDDR,
|
||||
PRCMU_PLLDSI,
|
||||
PRCMU_DSI0CLK,
|
||||
|
1
include/linux/platform_data/clk-realview.h
Normal file
1
include/linux/platform_data/clk-realview.h
Normal file
@ -0,0 +1 @@
|
||||
void realview_clk_init(void __iomem *sysbase, bool is_pb1176);
|
17
include/linux/platform_data/clk-ux500.h
Normal file
17
include/linux/platform_data/clk-ux500.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Clock definitions for ux500 platforms
|
||||
*
|
||||
* Copyright (C) 2012 ST-Ericsson SA
|
||||
* Author: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#ifndef __CLK_UX500_H
|
||||
#define __CLK_UX500_H
|
||||
|
||||
void u8500_clk_init(void);
|
||||
void u9540_clk_init(void);
|
||||
void u8540_clk_init(void);
|
||||
|
||||
#endif /* __CLK_UX500_H */
|
Loading…
Reference in New Issue
Block a user