Commit 2c0c86d5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'clk-for-linus' of git://git.linaro.org/people/mturquette/linux

Pull clk framework update from Michael Turquette:
 "The common clk framework changes for 3.7 are dominated by ARM platform
  ports to the framework along with one MIPS port, one MFD port, one
  minor framework enhancement and one helper function for platforms
  expressing their clock data through device tree."

* tag 'clk-for-linus' 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
parents fdb2f9c2 494bfec9
......@@ -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.
......
obj-y := timer.o
obj-y += irq.o
obj-y += clock.o
obj-y += rstc.o
obj-y += prima2.o
obj-y += rtciobrg.o
......
/*
* 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,
};