c837e88cf9
Remove the individual 'struct clksrc_clks' and place them into an array so that we can simply use s3c_register_clksrcs to register tham all in one go. Since the spdif clock relies on the audio clock, move the audio clocks into their own arrary. Thanks to Marek Szyprowski for testing and pointing out the four clocks what where missed from the clock list. Signed-off-by: Ben Dooks <ben-linux@fluff.org>
876 lines
20 KiB
C
876 lines
20 KiB
C
/* linux/arch/arm/plat-s5pc1xx/s5pc100-clock.c
|
|
*
|
|
* Copyright 2009 Samsung Electronics, Co.
|
|
* Byungho Min <bhmin@samsung.com>
|
|
*
|
|
* S5PC100 based common clock support
|
|
*
|
|
* Based on plat-s3c64xx/s3c6400-clock.c
|
|
*
|
|
* 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/init.h>
|
|
#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/sysdev.h>
|
|
#include <linux/io.h>
|
|
|
|
#include <mach/hardware.h>
|
|
#include <mach/map.h>
|
|
|
|
#include <plat/cpu-freq.h>
|
|
|
|
#include <plat/regs-clock.h>
|
|
#include <plat/clock.h>
|
|
#include <plat/clock-clksrc.h>
|
|
#include <plat/cpu.h>
|
|
#include <plat/pll.h>
|
|
#include <plat/devs.h>
|
|
#include <plat/s5pc100.h>
|
|
|
|
/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
|
|
* ext_xtal_mux for want of an actual name from the manual.
|
|
*/
|
|
|
|
static struct clk clk_ext_xtal_mux = {
|
|
.name = "ext_xtal",
|
|
.id = -1,
|
|
};
|
|
|
|
#define clk_fin_apll clk_ext_xtal_mux
|
|
#define clk_fin_mpll clk_ext_xtal_mux
|
|
#define clk_fin_epll clk_ext_xtal_mux
|
|
#define clk_fin_hpll clk_ext_xtal_mux
|
|
|
|
#define clk_fout_mpll clk_mpll
|
|
#define clk_vclk_54m clk_54m
|
|
|
|
/* APLL */
|
|
static struct clk clk_fout_apll = {
|
|
.name = "fout_apll",
|
|
.id = -1,
|
|
.rate = 27000000,
|
|
};
|
|
|
|
static struct clk *clk_src_apll_list[] = {
|
|
[0] = &clk_fin_apll,
|
|
[1] = &clk_fout_apll,
|
|
};
|
|
|
|
static struct clksrc_sources clk_src_apll = {
|
|
.sources = clk_src_apll_list,
|
|
.nr_sources = ARRAY_SIZE(clk_src_apll_list),
|
|
};
|
|
|
|
static struct clksrc_clk clk_mout_apll = {
|
|
.clk = {
|
|
.name = "mout_apll",
|
|
.id = -1,
|
|
},
|
|
.sources = &clk_src_apll,
|
|
.reg_src = { .reg = S5PC100_CLKSRC0, .shift = 0, .size = 1, },
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_apll_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_APLL_MASK;
|
|
ratio >>= S5PC100_CLKDIV0_APLL_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_apll = {
|
|
.name = "dout_apll",
|
|
.id = -1,
|
|
.parent = &clk_mout_apll.clk,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_apll_get_rate,
|
|
},
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_ARM_MASK;
|
|
ratio >>= S5PC100_CLKDIV0_ARM_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static unsigned long s5pc100_clk_arm_round_rate(struct clk *clk,
|
|
unsigned long rate)
|
|
{
|
|
unsigned long parent = clk_get_rate(clk->parent);
|
|
u32 div;
|
|
|
|
if (parent < rate)
|
|
return rate;
|
|
|
|
div = (parent / rate) - 1;
|
|
if (div > S5PC100_CLKDIV0_ARM_MASK)
|
|
div = S5PC100_CLKDIV0_ARM_MASK;
|
|
|
|
return parent / (div + 1);
|
|
}
|
|
|
|
static int s5pc100_clk_arm_set_rate(struct clk *clk, unsigned long rate)
|
|
{
|
|
unsigned long parent = clk_get_rate(clk->parent);
|
|
u32 div;
|
|
u32 val;
|
|
|
|
if (rate < parent / (S5PC100_CLKDIV0_ARM_MASK + 1))
|
|
return -EINVAL;
|
|
|
|
rate = clk_round_rate(clk, rate);
|
|
div = clk_get_rate(clk->parent) / rate;
|
|
|
|
val = __raw_readl(S5PC100_CLKDIV0);
|
|
val &= S5PC100_CLKDIV0_ARM_MASK;
|
|
val |= (div - 1);
|
|
__raw_writel(val, S5PC100_CLKDIV0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct clk clk_arm = {
|
|
.name = "armclk",
|
|
.id = -1,
|
|
.parent = &clk_dout_apll,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_arm_get_rate,
|
|
.set_rate = s5pc100_clk_arm_set_rate,
|
|
.round_rate = s5pc100_clk_arm_round_rate,
|
|
},
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_D0_MASK;
|
|
ratio >>= S5PC100_CLKDIV0_D0_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_d0_bus = {
|
|
.name = "dout_d0_bus",
|
|
.id = -1,
|
|
.parent = &clk_arm,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_d0_bus_get_rate,
|
|
},
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_PCLKD0_MASK;
|
|
ratio >>= S5PC100_CLKDIV0_PCLKD0_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_pclkd0 = {
|
|
.name = "dout_pclkd0",
|
|
.id = -1,
|
|
.parent = &clk_dout_d0_bus,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_pclkd0_get_rate,
|
|
},
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_APLL2_MASK;
|
|
ratio >>= S5PC100_CLKDIV1_APLL2_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_apll2 = {
|
|
.name = "dout_apll2",
|
|
.id = -1,
|
|
.parent = &clk_mout_apll.clk,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_apll2_get_rate,
|
|
},
|
|
};
|
|
|
|
/* MPLL */
|
|
static struct clk *clk_src_mpll_list[] = {
|
|
[0] = &clk_fin_mpll,
|
|
[1] = &clk_fout_mpll,
|
|
};
|
|
|
|
static struct clksrc_sources clk_src_mpll = {
|
|
.sources = clk_src_mpll_list,
|
|
.nr_sources = ARRAY_SIZE(clk_src_mpll_list),
|
|
};
|
|
|
|
static struct clksrc_clk clk_mout_mpll = {
|
|
.clk = {
|
|
.name = "mout_mpll",
|
|
.id = -1,
|
|
},
|
|
.sources = &clk_src_mpll,
|
|
.reg_src = { .reg = S5PC100_CLKSRC0, .shift = 4, .size = 1, },
|
|
};
|
|
|
|
static struct clk *clkset_am_list[] = {
|
|
[0] = &clk_mout_mpll.clk,
|
|
[1] = &clk_dout_apll2,
|
|
};
|
|
|
|
static struct clksrc_sources clk_src_am = {
|
|
.sources = clkset_am_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_am_list),
|
|
};
|
|
|
|
static struct clksrc_clk clk_mout_am = {
|
|
.clk = {
|
|
.name = "mout_am",
|
|
.id = -1,
|
|
},
|
|
.sources = &clk_src_am,
|
|
.reg_src = { .reg = S5PC100_CLKSRC0, .shift = 16, .size = 1, },
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_d1_bus_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_D1_MASK;
|
|
ratio >>= S5PC100_CLKDIV1_D1_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_d1_bus = {
|
|
.name = "dout_d1_bus",
|
|
.id = -1,
|
|
.parent = &clk_mout_am.clk,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_d1_bus_get_rate,
|
|
},
|
|
};
|
|
|
|
static struct clk *clkset_onenand_list[] = {
|
|
[0] = &clk_dout_d0_bus,
|
|
[1] = &clk_dout_d1_bus,
|
|
};
|
|
|
|
static struct clksrc_sources clk_src_onenand = {
|
|
.sources = clkset_onenand_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_onenand_list),
|
|
};
|
|
|
|
static struct clksrc_clk clk_mout_onenand = {
|
|
.clk = {
|
|
.name = "mout_onenand",
|
|
.id = -1,
|
|
},
|
|
.sources = &clk_src_onenand,
|
|
.reg_src = { .reg = S5PC100_CLKSRC0, .shift = 24, .size = 1, },
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_pclkd1_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_PCLKD1_MASK;
|
|
ratio >>= S5PC100_CLKDIV1_PCLKD1_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_pclkd1 = {
|
|
.name = "dout_pclkd1",
|
|
.id = -1,
|
|
.parent = &clk_dout_d1_bus,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_pclkd1_get_rate,
|
|
},
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
|
|
ratio >>= S5PC100_CLKDIV1_MPLL2_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_mpll2 = {
|
|
.name = "dout_mpll2",
|
|
.id = -1,
|
|
.parent = &clk_mout_am.clk,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_mpll2_get_rate,
|
|
},
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_CAM_MASK;
|
|
ratio >>= S5PC100_CLKDIV1_CAM_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_cam = {
|
|
.name = "dout_cam",
|
|
.id = -1,
|
|
.parent = &clk_dout_mpll2,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_cam_get_rate,
|
|
},
|
|
};
|
|
|
|
static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk)
|
|
{
|
|
unsigned long rate = clk_get_rate(clk->parent);
|
|
unsigned int ratio;
|
|
|
|
printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
|
|
|
|
ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL_MASK;
|
|
ratio >>= S5PC100_CLKDIV1_MPLL_SHIFT;
|
|
|
|
return rate / (ratio + 1);
|
|
}
|
|
|
|
static struct clk clk_dout_mpll = {
|
|
.name = "dout_mpll",
|
|
.id = -1,
|
|
.parent = &clk_mout_am.clk,
|
|
.ops = &(struct clk_ops) {
|
|
.get_rate = s5pc100_clk_dout_mpll_get_rate,
|
|
},
|
|
};
|
|
|
|
/* EPLL */
|
|
static struct clk clk_fout_epll = {
|
|
.name = "fout_epll",
|
|
.id = -1,
|
|
};
|
|
|
|
static struct clk *clk_src_epll_list[] = {
|
|
[0] = &clk_fin_epll,
|
|
[1] = &clk_fout_epll,
|
|
};
|
|
|
|
static struct clksrc_sources clk_src_epll = {
|
|
.sources = clk_src_epll_list,
|
|
.nr_sources = ARRAY_SIZE(clk_src_epll_list),
|
|
};
|
|
|
|
static struct clksrc_clk clk_mout_epll = {
|
|
.clk = {
|
|
.name = "mout_epll",
|
|
.id = -1,
|
|
},
|
|
.sources = &clk_src_epll,
|
|
.reg_src = { .reg = S5PC100_CLKSRC0, .shift = 8, .size = 1, },
|
|
};
|
|
|
|
/* HPLL */
|
|
static struct clk clk_fout_hpll = {
|
|
.name = "fout_hpll",
|
|
.id = -1,
|
|
};
|
|
|
|
static struct clk *clk_src_hpll_list[] = {
|
|
[0] = &clk_27m,
|
|
[1] = &clk_fout_hpll,
|
|
};
|
|
|
|
static struct clksrc_sources clk_src_hpll = {
|
|
.sources = clk_src_hpll_list,
|
|
.nr_sources = ARRAY_SIZE(clk_src_hpll_list),
|
|
};
|
|
|
|
static struct clksrc_clk clk_mout_hpll = {
|
|
.clk = {
|
|
.name = "mout_hpll",
|
|
.id = -1,
|
|
},
|
|
.sources = &clk_src_hpll,
|
|
.reg_src = { .reg = S5PC100_CLKSRC0, .shift = 12, .size = 1, },
|
|
};
|
|
|
|
/* Peripherals */
|
|
/*
|
|
* The peripheral clocks are all controlled via clocksource followed
|
|
* by an optional divider and gate stage. We currently roll this into
|
|
* one clock which hides the intermediate clock from the mux.
|
|
*
|
|
* Note, the JPEG clock can only be an even divider...
|
|
*
|
|
* The scaler and LCD clocks depend on the S5PC100 version, and also
|
|
* have a common parent divisor so are not included here.
|
|
*/
|
|
|
|
static struct clk clk_iis_cd0 = {
|
|
.name = "iis_cdclk0",
|
|
.id = -1,
|
|
};
|
|
|
|
static struct clk clk_iis_cd1 = {
|
|
.name = "iis_cdclk1",
|
|
.id = -1,
|
|
};
|
|
|
|
static struct clk clk_iis_cd2 = {
|
|
.name = "iis_cdclk2",
|
|
.id = -1,
|
|
};
|
|
|
|
static struct clk clk_pcm_cd0 = {
|
|
.name = "pcm_cdclk0",
|
|
.id = -1,
|
|
};
|
|
|
|
static struct clk clk_pcm_cd1 = {
|
|
.name = "pcm_cdclk1",
|
|
.id = -1,
|
|
};
|
|
|
|
static struct clk *clkset_audio0_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll,
|
|
&clk_fin_epll,
|
|
&clk_iis_cd0,
|
|
&clk_pcm_cd0,
|
|
&clk_mout_hpll.clk,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_audio0 = {
|
|
.sources = clkset_audio0_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_audio0_list),
|
|
};
|
|
|
|
static struct clk *clkset_spi_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll2,
|
|
&clk_fin_epll,
|
|
&clk_mout_hpll.clk,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_spi = {
|
|
.sources = clkset_spi_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_spi_list),
|
|
};
|
|
|
|
static struct clk *clkset_uart_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_uart = {
|
|
.sources = clkset_uart_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_uart_list),
|
|
};
|
|
|
|
static struct clk *clkset_audio1_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll,
|
|
&clk_fin_epll,
|
|
&clk_iis_cd1,
|
|
&clk_pcm_cd1,
|
|
&clk_mout_hpll.clk,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_audio1 = {
|
|
.sources = clkset_audio1_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_audio1_list),
|
|
};
|
|
|
|
static struct clk *clkset_audio2_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll,
|
|
&clk_fin_epll,
|
|
&clk_iis_cd2,
|
|
&clk_mout_hpll.clk,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_audio2 = {
|
|
.sources = clkset_audio2_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_audio2_list),
|
|
};
|
|
|
|
static struct clksrc_clk clksrc_audio[] = {
|
|
{
|
|
.clk = {
|
|
.name = "audio-bus",
|
|
.id = 0,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0,
|
|
.enable = s5pc100_sclk1_ctrl,
|
|
},
|
|
.sources = &clkset_audio0,
|
|
.reg_div = { .reg = S5PC100_CLKDIV4, .shift = 12, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC3, .shift = 12, .size = 3, },
|
|
}, {
|
|
.clk = {
|
|
.name = "audio-bus",
|
|
.id = 1,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1,
|
|
.enable = s5pc100_sclk1_ctrl,
|
|
},
|
|
.sources = &clkset_audio1,
|
|
.reg_div = { .reg = S5PC100_CLKDIV4, .shift = 16, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC3, .shift = 16, .size = 3, },
|
|
}, {
|
|
.clk = {
|
|
.name = "audio-bus",
|
|
.id = 2,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2,
|
|
.enable = s5pc100_sclk1_ctrl,
|
|
},
|
|
.sources = &clkset_audio2,
|
|
.reg_div = { .reg = S5PC100_CLKDIV4, .shift = 20, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC3, .shift = 20, .size = 3, },
|
|
},
|
|
};
|
|
|
|
static struct clk *clkset_spdif_list[] = {
|
|
&clksrc_audio[0].clk,
|
|
&clksrc_audio[1].clk,
|
|
&clksrc_audio[2].clk,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_spdif = {
|
|
.sources = clkset_spdif_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_spdif_list),
|
|
};
|
|
|
|
static struct clk *clkset_lcd_fimc_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll,
|
|
&clk_mout_hpll.clk,
|
|
&clk_vclk_54m,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_lcd_fimc = {
|
|
.sources = clkset_lcd_fimc_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_lcd_fimc_list),
|
|
};
|
|
|
|
static struct clk *clkset_mmc_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll,
|
|
&clk_fin_epll,
|
|
&clk_mout_hpll.clk ,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_mmc = {
|
|
.sources = clkset_mmc_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_mmc_list),
|
|
};
|
|
|
|
static struct clk *clkset_usbhost_list[] = {
|
|
&clk_mout_epll.clk,
|
|
&clk_dout_mpll,
|
|
&clk_mout_hpll.clk,
|
|
&clk_48m,
|
|
};
|
|
|
|
static struct clksrc_sources clkset_usbhost = {
|
|
.sources = clkset_usbhost_list,
|
|
.nr_sources = ARRAY_SIZE(clkset_usbhost_list),
|
|
};
|
|
|
|
static struct clksrc_clk clksrc_clks[] = {
|
|
{
|
|
.clk = {
|
|
.name = "spi_bus",
|
|
.id = 0,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
|
|
},
|
|
.sources = &clkset_spi,
|
|
.reg_div = { .reg = S5PC100_CLKDIV2, .shift = 4, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC1, .shift = 4, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "spi_bus",
|
|
.id = 1,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
},
|
|
.sources = &clkset_spi,
|
|
.reg_div = { .reg = S5PC100_CLKDIV2, .shift = 8, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC1, .shift = 8, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "spi_bus",
|
|
.id = 2,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
},
|
|
.sources = &clkset_spi,
|
|
.reg_div = { .reg = S5PC100_CLKDIV2, .shift = 12, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC1, .shift = 12, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "uclk1",
|
|
.id = -1,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_UART,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
},
|
|
.sources = &clkset_uart,
|
|
.reg_div = { .reg = S5PC100_CLKDIV2, .shift = 0, .size = 3, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC1, .shift = 0, .size = 1, },
|
|
}, {
|
|
.clk = {
|
|
.name = "spdif",
|
|
.id = -1,
|
|
},
|
|
.sources = &clkset_spdif,
|
|
.reg_src = { .reg = S5PC100_CLKSRC3, .shift = 24, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "lcd",
|
|
.id = -1,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK1_LCD,
|
|
.enable = s5pc100_sclk1_ctrl,
|
|
},
|
|
.sources = &clkset_lcd_fimc,
|
|
.reg_div = { .reg = S5PC100_CLKDIV3, .shift = 12, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC2, .shift = 12, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "fimc",
|
|
.id = 0,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0,
|
|
.enable = s5pc100_sclk1_ctrl,
|
|
},
|
|
.sources = &clkset_lcd_fimc,
|
|
.reg_div = { .reg = S5PC100_CLKDIV3, .shift = 16, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC2, .shift = 16, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "fimc",
|
|
.id = 1,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1,
|
|
.enable = s5pc100_sclk1_ctrl,
|
|
},
|
|
.sources = &clkset_lcd_fimc,
|
|
.reg_div = { .reg = S5PC100_CLKDIV3, .shift = 20, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC2, .shift = 20, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "fimc",
|
|
.id = 2,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2,
|
|
.enable = s5pc100_sclk1_ctrl,
|
|
},
|
|
.sources = &clkset_lcd_fimc,
|
|
.reg_div = { .reg = S5PC100_CLKDIV3, .shift = 24, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC2, .shift = 24, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "mmc_bus",
|
|
.id = 0,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
},
|
|
.sources = &clkset_mmc,
|
|
.reg_div = { .reg = S5PC100_CLKDIV3, .shift = 0, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC2, .shift = 0, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "mmc_bus",
|
|
.id = 1,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
},
|
|
.sources = &clkset_mmc,
|
|
.reg_div = { .reg = S5PC100_CLKDIV3, .shift = 4, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC2, .shift = 4, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "mmc_bus",
|
|
.id = 2,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
},
|
|
.sources = &clkset_mmc,
|
|
.reg_div = { .reg = S5PC100_CLKDIV3, .shift = 8, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC2, .shift = 8, .size = 2, },
|
|
}, {
|
|
.clk = {
|
|
.name = "usbhost",
|
|
.id = -1,
|
|
.ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST,
|
|
.enable = s5pc100_sclk0_ctrl,
|
|
},
|
|
.sources = &clkset_usbhost,
|
|
.reg_div = { .reg = S5PC100_CLKDIV2, .shift = 20, .size = 4, },
|
|
.reg_src = { .reg = S5PC100_CLKSRC1, .shift = 20, .size = 2, },
|
|
}
|
|
};
|
|
|
|
/* Clock initialisation code */
|
|
|
|
static struct clksrc_clk *init_parents[] = {
|
|
&clk_mout_apll,
|
|
&clk_mout_mpll,
|
|
&clk_mout_am,
|
|
&clk_mout_onenand,
|
|
&clk_mout_epll,
|
|
&clk_mout_hpll,
|
|
};
|
|
|
|
#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
|
|
|
|
void __init_or_cpufreq s5pc100_setup_clocks(void)
|
|
{
|
|
struct clk *xtal_clk;
|
|
unsigned long xtal;
|
|
unsigned long armclk;
|
|
unsigned long hclkd0;
|
|
unsigned long hclk;
|
|
unsigned long pclkd0;
|
|
unsigned long pclk;
|
|
unsigned long apll, mpll, epll, hpll;
|
|
unsigned int ptr;
|
|
u32 clkdiv0, clkdiv1;
|
|
|
|
printk(KERN_DEBUG "%s: registering clocks\n", __func__);
|
|
|
|
clkdiv0 = __raw_readl(S5PC100_CLKDIV0);
|
|
clkdiv1 = __raw_readl(S5PC100_CLKDIV1);
|
|
|
|
printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1);
|
|
|
|
xtal_clk = clk_get(NULL, "xtal");
|
|
BUG_ON(IS_ERR(xtal_clk));
|
|
|
|
xtal = clk_get_rate(xtal_clk);
|
|
clk_put(xtal_clk);
|
|
|
|
printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
|
|
|
|
apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON));
|
|
mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON));
|
|
epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON));
|
|
hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
|
|
|
|
printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz"
|
|
", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n",
|
|
print_mhz(apll), print_mhz(mpll),
|
|
print_mhz(epll), print_mhz(hpll));
|
|
|
|
armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL);
|
|
armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
|
|
hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
|
|
pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
|
|
hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
|
|
pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
|
|
|
|
printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz,"
|
|
" PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz,"
|
|
" PCLK=%ld.%03ld MHz\n",
|
|
print_mhz(armclk), print_mhz(hclkd0),
|
|
print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk));
|
|
|
|
clk_fout_apll.rate = apll;
|
|
clk_fout_mpll.rate = mpll;
|
|
clk_fout_epll.rate = epll;
|
|
clk_fout_hpll.rate = hpll;
|
|
|
|
clk_h.rate = hclk;
|
|
clk_p.rate = pclk;
|
|
clk_f.rate = armclk;
|
|
|
|
for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
|
|
s3c_set_clksrc(init_parents[ptr], true);
|
|
|
|
for (ptr = 0; ptr < ARRAY_SIZE(clksrc_audio); ptr++)
|
|
s3c_set_clksrc(clksrc_audio + ptr, true);
|
|
|
|
for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
|
|
s3c_set_clksrc(clksrc_clks + ptr, true);
|
|
}
|
|
|
|
static struct clk *clks[] __initdata = {
|
|
&clk_ext_xtal_mux,
|
|
&clk_dout_apll,
|
|
&clk_dout_d0_bus,
|
|
&clk_dout_pclkd0,
|
|
&clk_dout_apll2,
|
|
&clk_mout_apll.clk,
|
|
&clk_mout_mpll.clk,
|
|
&clk_mout_epll.clk,
|
|
&clk_mout_hpll.clk,
|
|
&clk_mout_am.clk,
|
|
&clk_dout_d1_bus,
|
|
&clk_mout_onenand.clk,
|
|
&clk_dout_pclkd1,
|
|
&clk_dout_mpll2,
|
|
&clk_dout_cam,
|
|
&clk_dout_mpll,
|
|
&clk_fout_epll,
|
|
&clk_iis_cd0,
|
|
&clk_iis_cd1,
|
|
&clk_iis_cd2,
|
|
&clk_pcm_cd0,
|
|
&clk_pcm_cd1,
|
|
&clk_arm,
|
|
};
|
|
|
|
void __init s5pc100_register_clocks(void)
|
|
{
|
|
struct clk *clkp;
|
|
int ret;
|
|
int ptr;
|
|
|
|
for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
|
|
clkp = clks[ptr];
|
|
ret = s3c24xx_register_clock(clkp);
|
|
if (ret < 0) {
|
|
printk(KERN_ERR "Failed to register clock %s (%d)\n",
|
|
clkp->name, ret);
|
|
}
|
|
}
|
|
|
|
s3c_register_clksrc(clksrc_audio, ARRAY_SIZE(clksrc_audio));
|
|
s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
|
|
}
|