Commit 32726d2d authored by Tomasz Figa's avatar Tomasz Figa Committed by Kukjin Kim

ARM: SAMSUNG: Remove legacy clock code

Since S5PV210 now has a complete clock driver using Common Clock
Framework, there is no reason to keep the old code. Remove it together
with the whole legacy Samsung-specific clock framework which no longer
has any users.
Signed-off-by: default avatarTomasz Figa <t.figa@samsung.com>
Signed-off-by: default avatarKukjin Kim <kgene.kim@samsung.com>
parent f73d4cb6
......@@ -765,6 +765,7 @@ config ARCH_S5PV210
select ATAGS
select CLKDEV_LOOKUP
select CLKSRC_SAMSUNG_PWM
select COMMON_CLK_SAMSUNG
select CPU_V7
select GENERIC_CLOCKEVENTS
select GPIO_SAMSUNG
......
......@@ -28,7 +28,6 @@
#include <asm/suspend.h>
#include <plat/pm-common.h>
#include <plat/pll.h>
#include <plat/regs-srom.h>
#include <mach/map.h>
......
......@@ -49,9 +49,7 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/clock.h>
#include <plat/cpu-freq.h>
#include <plat/pll.h>
#include <plat/pwm-core.h>
#include <plat/watchdog-reset.h>
......
......@@ -29,7 +29,6 @@
#include <plat/cpu.h>
#include <plat/cpu-freq-core.h>
#include <plat/clock.h>
#include <mach/s3c2412.h>
......
......@@ -60,7 +60,6 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/gpio-cfg.h>
#include <plat/pll.h>
#include <plat/pm.h>
#include <plat/samsung-time.h>
......@@ -73,6 +72,10 @@
#define H1940_LATCH_BIT(x) (1 << ((x) + 16 - S3C_GPIO_END))
#define S3C24XX_PLL_MDIV_SHIFT (12)
#define S3C24XX_PLL_PDIV_SHIFT (4)
#define S3C24XX_PLL_SDIV_SHIFT (0)
static struct map_desc h1940_iodesc[] __initdata = {
[0] = {
.virtual = (unsigned long)H1940_LATCH,
......
......@@ -48,7 +48,6 @@
#include <linux/mtd/partitions.h>
#include <plat/gpio-cfg.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/pm.h>
......
......@@ -43,7 +43,6 @@
#include <mach/gpio-samsung.h>
#include <mach/fb.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/samsung-time.h>
......
......@@ -44,7 +44,6 @@
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/gpio-cfg.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
......
......@@ -38,7 +38,6 @@
#include <mach/fb.h>
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/samsung-time.h>
......
......@@ -42,7 +42,6 @@
#include <linux/platform_data/i2c-s3c2410.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/samsung-time.h>
......
......@@ -41,8 +41,6 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/clock.h>
#include <plat/pll.h>
#include <plat/pm.h>
#include <plat/watchdog-reset.h>
......@@ -83,10 +81,6 @@ void __init s3c2410_map_io(void)
iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
}
void __init_or_cpufreq s3c2410_setup_clocks(void)
{
}
struct bus_type s3c2410_subsys = {
.name = "s3c2410-core",
.dev_name = "s3c2410-core",
......
......@@ -37,12 +37,10 @@
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/clock.h>
#include <plat/cpu.h>
#include <plat/cpu-freq.h>
#include <plat/devs.h>
#include <plat/nand-core.h>
#include <plat/pll.h>
#include <plat/pm.h>
#include <plat/regs-spi.h>
......@@ -171,10 +169,6 @@ void __init s3c2412_map_io(void)
iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
}
void __init_or_cpufreq s3c2412_setup_clocks(void)
{
}
/* need to register the subsystem before we actually register the device, and
* we also need to ensure that it has been initialised before any of the
* drivers even try to use it (even if not on an s3c2412 based system)
......
......@@ -43,7 +43,6 @@
#include <mach/regs-clock.h>
#include <plat/clock.h>
#include <plat/cpu.h>
#include <plat/pm.h>
......
......@@ -38,11 +38,9 @@
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/pm.h>
#include <plat/pll.h>
#include <plat/nand-core.h>
#include <plat/watchdog-reset.h>
......@@ -78,10 +76,6 @@ void __init s3c244x_map_io(void)
s3c2410_device_dclk.name = "s3c2440-dclk";
}
void __init_or_cpufreq s3c244x_setup_clocks(void)
{
}
/* Since the S3C2442 and S3C2440 share items, put both subsystems here */
struct bus_type s3c2440_subsys = {
......
......@@ -45,7 +45,6 @@
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/fb.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <mach/regs-gpio.h>
......
......@@ -58,7 +58,6 @@
#include <linux/platform_data/spi-s3c64xx.h>
#include <plat/keypad.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/adc.h>
......
......@@ -39,7 +39,6 @@
#include <plat/fb.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/samsung-time.h>
......
......@@ -40,7 +40,6 @@
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/fb.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/samsung-time.h>
......
......@@ -28,7 +28,6 @@
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
#include <plat/clock.h>
#include <plat/cpu.h>
#include <plat/devs.h>
#include <linux/platform_data/i2c-s3c2410.h>
......
......@@ -30,7 +30,6 @@
#include <mach/hardware.h>
#include <mach/map.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <linux/platform_data/i2c-s3c2410.h>
......
......@@ -63,7 +63,6 @@
#include <plat/fb.h>
#include <plat/gpio-cfg.h>
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/adc.h>
......
......@@ -39,7 +39,6 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/clock.h>
#include <plat/sdhci.h>
#include <plat/iic-core.h>
#include <plat/onenand-core.h>
......
......@@ -40,7 +40,6 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/clock.h>
#include <plat/sdhci.h>
#include <plat/ata-core.h>
#include <plat/adc-core.h>
......
......@@ -13,7 +13,6 @@ config CPU_S5PV210
bool
select ARM_AMBA
select PL330_DMA if DMADEVICES
select S5P_CLOCK if !COMMON_CLK
select S5P_EXT_INT
select S5P_PM if PM
select S5P_SLEEP if PM
......@@ -71,14 +70,6 @@ config S5PV210_SETUP_USB_PHY
help
Common setup code for USB PHY controller
config COMMON_CLK_S5PV210
bool "Common Clock Framework support"
default y
select COMMON_CLK_SAMSUNG
help
Enable this option to use new clock driver
based on Common Clock Framework.
menu "S5PC110 Machines"
config MACH_AQUILA
......
......@@ -13,7 +13,6 @@ obj- :=
# Core
obj-y += common.o
obj-$(CONFIG_S5P_CLOCK) += clock.o
obj-$(CONFIG_PM) += pm.o
obj-y += dma.o
......
/* linux/arch/arm/mach-s5pv210/clock.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* S5PV210 - Clock support
*
* 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/device.h>
#include <linux/io.h>
#include <mach/map.h>
#include <plat/cpu-freq.h>
#include <mach/regs-clock.h>
#include <plat/clock.h>
#include <plat/cpu.h>
#include <plat/pll.h>
#include <plat/s5p-clock.h>
#include <plat/clock-clksrc.h>
#include "common.h"
static unsigned long xtal;
static struct clksrc_clk clk_mout_apll = {
.clk = {
.name = "mout_apll",
},
.sources = &clk_src_apll,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
};
static struct clksrc_clk clk_mout_epll = {
.clk = {
.name = "mout_epll",
},
.sources = &clk_src_epll,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 8, .size = 1 },
};
static struct clksrc_clk clk_mout_mpll = {
.clk = {
.name = "mout_mpll",
},
.sources = &clk_src_mpll,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 4, .size = 1 },
};
static struct clk *clkset_armclk_list[] = {
[0] = &clk_mout_apll.clk,
[1] = &clk_mout_mpll.clk,
};
static struct clksrc_sources clkset_armclk = {
.sources = clkset_armclk_list,
.nr_sources = ARRAY_SIZE(clkset_armclk_list),
};
static struct clksrc_clk clk_armclk = {
.clk = {
.name = "armclk",
},
.sources = &clkset_armclk,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 16, .size = 1 },
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 3 },
};
static struct clksrc_clk clk_hclk_msys = {
.clk = {
.name = "hclk_msys",
.parent = &clk_armclk.clk,
},
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 8, .size = 3 },
};
static struct clksrc_clk clk_pclk_msys = {
.clk = {
.name = "pclk_msys",
.parent = &clk_hclk_msys.clk,
},
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 12, .size = 3 },
};
static struct clksrc_clk clk_sclk_a2m = {
.clk = {
.name = "sclk_a2m",
.parent = &clk_mout_apll.clk,
},
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 3 },
};
static struct clk *clkset_hclk_sys_list[] = {
[0] = &clk_mout_mpll.clk,
[1] = &clk_sclk_a2m.clk,
};
static struct clksrc_sources clkset_hclk_sys = {
.sources = clkset_hclk_sys_list,
.nr_sources = ARRAY_SIZE(clkset_hclk_sys_list),
};
static struct clksrc_clk clk_hclk_dsys = {
.clk = {
.name = "hclk_dsys",
},
.sources = &clkset_hclk_sys,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 20, .size = 1 },
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 16, .size = 4 },
};
static struct clksrc_clk clk_pclk_dsys = {
.clk = {
.name = "pclk_dsys",
.parent = &clk_hclk_dsys.clk,
},
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 20, .size = 3 },
};
static struct clksrc_clk clk_hclk_psys = {
.clk = {
.name = "hclk_psys",
},
.sources = &clkset_hclk_sys,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 24, .size = 1 },
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 24, .size = 4 },
};
static struct clksrc_clk clk_pclk_psys = {
.clk = {
.name = "pclk_psys",
.parent = &clk_hclk_psys.clk,
},
.reg_div = { .reg = S5P_CLK_DIV0, .shift = 28, .size = 3 },
};
static int s5pv210_clk_ip0_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP0, clk, enable);
}
static int s5pv210_clk_ip1_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP1, clk, enable);
}
static int s5pv210_clk_ip2_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP2, clk, enable);
}
static int s5pv210_clk_ip3_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable);
}
static int s5pv210_clk_mask0_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLK_SRC_MASK0, clk, enable);
}
static int s5pv210_clk_mask1_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLK_SRC_MASK1, clk, enable);
}
static int s5pv210_clk_hdmiphy_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable);
}
static int exynos4_clk_dac_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_DAC_PHY_CONTROL, clk, enable);
}
static struct clk clk_sclk_hdmi27m = {
.name = "sclk_hdmi27m",
.rate = 27000000,
};
static struct clk clk_sclk_hdmiphy = {
.name = "sclk_hdmiphy",
};
static struct clk clk_sclk_usbphy0 = {
.name = "sclk_usbphy0",
};
static struct clk clk_sclk_usbphy1 = {
.name = "sclk_usbphy1",
};
static struct clk clk_pcmcdclk0 = {
.name = "pcmcdclk",
};
static struct clk clk_pcmcdclk1 = {
.name = "pcmcdclk",
};
static struct clk clk_pcmcdclk2 = {
.name = "pcmcdclk",
};
static struct clk *clkset_vpllsrc_list[] = {
[0] = &clk_fin_vpll,
[1] = &clk_sclk_hdmi27m,
};
static struct clksrc_sources clkset_vpllsrc = {
.sources = clkset_vpllsrc_list,
.nr_sources = ARRAY_SIZE(clkset_vpllsrc_list),
};
static struct clksrc_clk clk_vpllsrc = {
.clk = {
.name = "vpll_src",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 7),
},
.sources = &clkset_vpllsrc,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 28, .size = 1 },
};
static struct clk *clkset_sclk_vpll_list[] = {
[0] = &clk_vpllsrc.clk,
[1] = &clk_fout_vpll,
};
static struct clksrc_sources clkset_sclk_vpll = {
.sources = clkset_sclk_vpll_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_vpll_list),
};
static struct clksrc_clk clk_sclk_vpll = {
.clk = {
.name = "sclk_vpll",
},
.sources = &clkset_sclk_vpll,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 12, .size = 1 },
};
static struct clk *clkset_moutdmc0src_list[] = {
[0] = &clk_sclk_a2m.clk,
[1] = &clk_mout_mpll.clk,
[2] = NULL,
[3] = NULL,
};
static struct clksrc_sources clkset_moutdmc0src = {
.sources = clkset_moutdmc0src_list,
.nr_sources = ARRAY_SIZE(clkset_moutdmc0src_list),
};
static struct clksrc_clk clk_mout_dmc0 = {
.clk = {
.name = "mout_dmc0",
},
.sources = &clkset_moutdmc0src,
.reg_src = { .reg = S5P_CLK_SRC6, .shift = 24, .size = 2 },
};
static struct clksrc_clk clk_sclk_dmc0 = {
.clk = {
.name = "sclk_dmc0",
.parent = &clk_mout_dmc0.clk,
},
.reg_div = { .reg = S5P_CLK_DIV6, .shift = 28, .size = 4 },
};
static unsigned long s5pv210_clk_imem_get_rate(struct clk *clk)
{
return clk_get_rate(clk->parent) / 2;
}
static struct clk_ops clk_hclk_imem_ops = {
.get_rate = s5pv210_clk_imem_get_rate,
};
static unsigned long s5pv210_clk_fout_apll_get_rate(struct clk *clk)
{
return s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
}
static struct clk_ops clk_fout_apll_ops = {
.get_rate = s5pv210_clk_fout_apll_get_rate,
};
static struct clk init_clocks_off[] = {
{
.name = "rot",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1<<29),
}, {
.name = "fimc",
.devname = "s5pv210-fimc.0",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 24),
}, {
.name = "fimc",
.devname = "s5pv210-fimc.1",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 25),
}, {
.name = "fimc",
.devname = "s5pv210-fimc.2",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 26),
}, {
.name = "jpeg",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 28),
}, {
.name = "mfc",
.devname = "s5p-mfc",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 16),
}, {
.name = "dac",
.devname = "s5p-sdo",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1 << 10),
}, {
.name = "mixer",
.devname = "s5p-mixer",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1 << 9),
}, {
.name = "vp",
.devname = "s5p-mixer",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1 << 8),
}, {
.name = "hdmi",
.devname = "s5pv210-hdmi",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1 << 11),
}, {
.name = "hdmiphy",
.devname = "s5pv210-hdmi",
.enable = s5pv210_clk_hdmiphy_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "dacphy",
.devname = "s5p-sdo",
.enable = exynos4_clk_dac_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "otg",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1<<16),
}, {
.name = "usb-host",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1<<17),
}, {
.name = "lcd",
.parent = &clk_hclk_dsys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1<<0),
}, {
.name = "cfcon",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1<<25),
}, {
.name = "systimer",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<16),
}, {
.name = "watchdog",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<22),
}, {
.name = "rtc",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<15),
}, {
.name = "i2c",
.devname = "s3c2440-i2c.0",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<7),
}, {
.name = "i2c",
.devname = "s3c2440-i2c.1",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 10),
}, {
.name = "i2c",
.devname = "s3c2440-i2c.2",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<9),
}, {
.name = "i2c",
.devname = "s3c2440-hdmiphy-i2c",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 11),
}, {
.name = "spi",
.devname = "s5pv210-spi.0",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<12),
}, {
.name = "spi",
.devname = "s5pv210-spi.1",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<13),
}, {
.name = "spi",
.devname = "s5pv210-spi.2",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<14),
}, {
.name = "timers",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<23),
}, {
.name = "adc",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<24),
}, {
.name = "keypad",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<21),
}, {
.name = "iis",
.devname = "samsung-i2s.0",
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<4),
}, {
.name = "iis",
.devname = "samsung-i2s.1",
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 5),
}, {
.name = "iis",
.devname = "samsung-i2s.2",
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 6),
}, {
.name = "spdif",
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 0),
},
};
static struct clk init_clocks[] = {
{
.name = "hclk_imem",
.parent = &clk_hclk_msys.clk,
.ctrlbit = (1 << 5),
.enable = s5pv210_clk_ip0_ctrl,
.ops = &clk_hclk_imem_ops,
}, {
.name = "uart",
.devname = "s5pv210-uart.0",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 17),
}, {
.name = "uart",
.devname = "s5pv210-uart.1",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 18),
}, {
.name = "uart",
.devname = "s5pv210-uart.2",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 19),
}, {
.name = "uart",
.devname = "s5pv210-uart.3",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 20),
}, {
.name = "sromc",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1 << 26),
},
};
static struct clk clk_hsmmc0 = {
.name = "hsmmc",
.devname = "s3c-sdhci.0",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip2_ctrl,
.ctrlbit = (1<<16),
};
static struct clk clk_hsmmc1 = {
.name = "hsmmc",
.devname = "s3c-sdhci.1",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip2_ctrl,
.ctrlbit = (1<<17),
};
static struct clk clk_hsmmc2 = {
.name = "hsmmc",
.devname = "s3c-sdhci.2",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip2_ctrl,
.ctrlbit = (1<<18),
};
static struct clk clk_hsmmc3 = {
.name = "hsmmc",
.devname = "s3c-sdhci.3",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip2_ctrl,
.ctrlbit = (1<<19),
};
static struct clk clk_pdma0 = {
.name = "pdma0",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 3),
};
static struct clk clk_pdma1 = {
.name = "pdma1",
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 4),
};
static struct clk *clkset_uart_list[] = {
[6] = &clk_mout_mpll.clk,
[7] = &clk_mout_epll.clk,
};
static struct clksrc_sources clkset_uart = {
.sources = clkset_uart_list,
.nr_sources = ARRAY_SIZE(clkset_uart_list),
};
static struct clk *clkset_group1_list[] = {
[0] = &clk_sclk_a2m.clk,
[1] = &clk_mout_mpll.clk,
[2] = &clk_mout_epll.clk,
[3] = &clk_sclk_vpll.clk,
};
static struct clksrc_sources clkset_group1 = {
.sources = clkset_group1_list,
.nr_sources = ARRAY_SIZE(clkset_group1_list),
};
static struct clk *clkset_sclk_onenand_list[] = {
[0] = &clk_hclk_psys.clk,
[1] = &clk_hclk_dsys.clk,
};
static struct clksrc_sources clkset_sclk_onenand = {
.sources = clkset_sclk_onenand_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_onenand_list),
};
static struct clk *clkset_sclk_dac_list[] = {
[0] = &clk_sclk_vpll.clk,
[1] = &clk_sclk_hdmiphy,
};
static struct clksrc_sources clkset_sclk_dac = {
.sources = clkset_sclk_dac_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_dac_list),
};
static struct clksrc_clk clk_sclk_dac = {
.clk = {
.name = "sclk_dac",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 2),
},
.sources = &clkset_sclk_dac,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 8, .size = 1 },
};
static struct clksrc_clk clk_sclk_pixel = {
.clk = {
.name = "sclk_pixel",
.parent = &clk_sclk_vpll.clk,
},
.reg_div = { .reg = S5P_CLK_DIV1, .shift = 0, .size = 4},
};
static struct clk *clkset_sclk_hdmi_list[] = {
[0] = &clk_sclk_pixel.clk,
[1] = &clk_sclk_hdmiphy,
};
static struct clksrc_sources clkset_sclk_hdmi = {
.sources = clkset_sclk_hdmi_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_hdmi_list),
};
static struct clksrc_clk clk_sclk_hdmi = {
.clk = {
.name = "sclk_hdmi",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 0),
},
.sources = &clkset_sclk_hdmi,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 0, .size = 1 },
};
static struct clk *clkset_sclk_mixer_list[] = {
[0] = &clk_sclk_dac.clk,
[1] = &clk_sclk_hdmi.clk,
};
static struct clksrc_sources clkset_sclk_mixer = {
.sources = clkset_sclk_mixer_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_mixer_list),
};
static struct clksrc_clk clk_sclk_mixer = {
.clk = {
.name = "sclk_mixer",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 1),
},
.sources = &clkset_sclk_mixer,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 1 },
};
static struct clksrc_clk *sclk_tv[] = {
&clk_sclk_dac,
&clk_sclk_pixel,
&clk_sclk_hdmi,
&clk_sclk_mixer,
};
static struct clk *clkset_sclk_audio0_list[] = {
[0] = &clk_ext_xtal_mux,
[1] = &clk_pcmcdclk0,
[2] = &clk_sclk_hdmi27m,
[3] = &clk_sclk_usbphy0,
[4] = &clk_sclk_usbphy1,
[5] = &clk_sclk_hdmiphy,
[6] = &clk_mout_mpll.clk,
[7] = &clk_mout_epll.clk,
[8] = &clk_sclk_vpll.clk,
};
static struct clksrc_sources clkset_sclk_audio0 = {
.sources = clkset_sclk_audio0_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_audio0_list),
};
static struct clksrc_clk clk_sclk_audio0 = {
.clk = {
.name = "sclk_audio",
.devname = "soc-audio.0",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 24),
},
.sources = &clkset_sclk_audio0,
.reg_src = { .reg = S5P_CLK_SRC6, .shift = 0, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV6, .shift = 0, .size = 4 },
};
static struct clk *clkset_sclk_audio1_list[] = {
[0] = &clk_ext_xtal_mux,
[1] = &clk_pcmcdclk1,
[2] = &clk_sclk_hdmi27m,
[3] = &clk_sclk_usbphy0,
[4] = &clk_sclk_usbphy1,
[5] = &clk_sclk_hdmiphy,
[6] = &clk_mout_mpll.clk,
[7] = &clk_mout_epll.clk,
[8] = &clk_sclk_vpll.clk,
};
static struct clksrc_sources clkset_sclk_audio1 = {
.sources = clkset_sclk_audio1_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_audio1_list),
};
static struct clksrc_clk clk_sclk_audio1 = {
.clk = {
.name = "sclk_audio",
.devname = "soc-audio.1",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 25),
},
.sources = &clkset_sclk_audio1,
.reg_src = { .reg = S5P_CLK_SRC6, .shift = 4, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV6, .shift = 4, .size = 4 },
};
static struct clk *clkset_sclk_audio2_list[] = {
[0] = &clk_ext_xtal_mux,
[1] = &clk_pcmcdclk0,
[2] = &clk_sclk_hdmi27m,
[3] = &clk_sclk_usbphy0,
[4] = &clk_sclk_usbphy1,
[5] = &clk_sclk_hdmiphy,
[6] = &clk_mout_mpll.clk,
[7] = &clk_mout_epll.clk,
[8] = &clk_sclk_vpll.clk,
};
static struct clksrc_sources clkset_sclk_audio2 = {
.sources = clkset_sclk_audio2_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_audio2_list),
};
static struct clksrc_clk clk_sclk_audio2 = {
.clk = {
.name = "sclk_audio",
.devname = "soc-audio.2",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 26),
},
.sources = &clkset_sclk_audio2,
.reg_src = { .reg = S5P_CLK_SRC6, .shift = 8, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV6, .shift = 8, .size = 4 },
};
static struct clk *clkset_sclk_spdif_list[] = {
[0] = &clk_sclk_audio0.clk,
[1] = &clk_sclk_audio1.clk,
[2] = &clk_sclk_audio2.clk,
};
static struct clksrc_sources clkset_sclk_spdif = {
.sources = clkset_sclk_spdif_list,
.nr_sources = ARRAY_SIZE(clkset_sclk_spdif_list),
};
static struct clksrc_clk clk_sclk_spdif = {
.clk = {
.name = "sclk_spdif",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 27),
.ops = &s5p_sclk_spdif_ops,
},
.sources = &clkset_sclk_spdif,
.reg_src = { .reg = S5P_CLK_SRC6, .shift = 12, .size = 2 },
};
static struct clk *clkset_group2_list[] = {
[0] = &clk_ext_xtal_mux,
[1] = &clk_xusbxti,
[2] = &clk_sclk_hdmi27m,
[3] = &clk_sclk_usbphy0,
[4] = &clk_sclk_usbphy1,
[5] = &clk_sclk_hdmiphy,
[6] = &clk_mout_mpll.clk,
[7] = &clk_mout_epll.clk,
[8] = &clk_sclk_vpll.clk,
};
static struct clksrc_sources clkset_group2 = {
.sources = clkset_group2_list,
.nr_sources = ARRAY_SIZE(clkset_group2_list),
};
static struct clksrc_clk clksrcs[] = {
{
.clk = {
.name = "sclk_dmc",
},
.sources = &clkset_group1,
.reg_src = { .reg = S5P_CLK_SRC6, .shift = 24, .size = 2 },
.reg_div = { .reg = S5P_CLK_DIV6, .shift = 28, .size = 4 },
}, {
.clk = {
.name = "sclk_onenand",
},
.sources = &clkset_sclk_onenand,
.reg_src = { .reg = S5P_CLK_SRC0, .shift = 28, .size = 1 },
.reg_div = { .reg = S5P_CLK_DIV6, .shift = 12, .size = 3 },
}, {
.clk = {
.name = "sclk_fimc",
.devname = "s5pv210-fimc.0",
.enable = s5pv210_clk_mask1_ctrl,
.ctrlbit = (1 << 2),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC3, .shift = 12, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV3, .shift = 12, .size = 4 },
}, {
.clk = {
.name = "sclk_fimc",
.devname = "s5pv210-fimc.1",
.enable = s5pv210_clk_mask1_ctrl,
.ctrlbit = (1 << 3),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC3, .shift = 16, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV3, .shift = 16, .size = 4 },
}, {
.clk = {
.name = "sclk_fimc",
.devname = "s5pv210-fimc.2",
.enable = s5pv210_clk_mask1_ctrl,
.ctrlbit = (1 << 4),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC3, .shift = 20, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV3, .shift = 20, .size = 4 },
}, {
.clk = {
.name = "sclk_cam0",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 3),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 12, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV1, .shift = 12, .size = 4 },
}, {
.clk = {
.name = "sclk_cam1",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 4),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 16, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV1, .shift = 16, .size = 4 },
}, {
.clk = {
.name = "sclk_fimd",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 5),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 20, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV1, .shift = 20, .size = 4 },
}, {
.clk = {
.name = "sclk_mfc",
.devname = "s5p-mfc",
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 16),
},
.sources = &clkset_group1,
.reg_src = { .reg = S5P_CLK_SRC2, .shift = 4, .size = 2 },
.reg_div = { .reg = S5P_CLK_DIV2, .shift = 4, .size = 4 },
}, {
.clk = {
.name = "sclk_g2d",
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 12),
},
.sources = &clkset_group1,
.reg_src = { .reg = S5P_CLK_SRC2, .shift = 8, .size = 2 },
.reg_div = { .reg = S5P_CLK_DIV2, .shift = 8, .size = 4 },
}, {
.clk = {
.name = "sclk_g3d",
.enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 8),
},
.sources = &clkset_group1,
.reg_src = { .reg = S5P_CLK_SRC2, .shift = 0, .size = 2 },
.reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 },
}, {
.clk = {
.name = "sclk_csis",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 6),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC1, .shift = 24, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV1, .shift = 28, .size = 4 },
}, {
.clk = {
.name = "sclk_pwi",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 29),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC6, .shift = 20, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV6, .shift = 24, .size = 4 },
}, {
.clk = {
.name = "sclk_pwm",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 19),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC5, .shift = 12, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV5, .shift = 12, .size = 4 },
},
};
static struct clksrc_clk clk_sclk_uart0 = {
.clk = {
.name = "uclk1",
.devname = "s5pv210-uart.0",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 12),
},
.sources = &clkset_uart,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 16, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 16, .size = 4 },
};
static struct clksrc_clk clk_sclk_uart1 = {
.clk = {
.name = "uclk1",
.devname = "s5pv210-uart.1",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 13),
},
.sources = &clkset_uart,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 20, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 20, .size = 4 },
};
static struct clksrc_clk clk_sclk_uart2 = {
.clk = {
.name = "uclk1",
.devname = "s5pv210-uart.2",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 14),
},
.sources = &clkset_uart,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 24, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 24, .size = 4 },
};
static struct clksrc_clk clk_sclk_uart3 = {
.clk = {
.name = "uclk1",
.devname = "s5pv210-uart.3",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 15),
},
.sources = &clkset_uart,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 28, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 28, .size = 4 },
};
static struct clksrc_clk clk_sclk_mmc0 = {
.clk = {
.name = "sclk_mmc",
.devname = "s3c-sdhci.0",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 8),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 0, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 0, .size = 4 },
};
static struct clksrc_clk clk_sclk_mmc1 = {
.clk = {
.name = "sclk_mmc",
.devname = "s3c-sdhci.1",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 9),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 4, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 4, .size = 4 },
};
static struct clksrc_clk clk_sclk_mmc2 = {
.clk = {
.name = "sclk_mmc",
.devname = "s3c-sdhci.2",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 10),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 8, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 8, .size = 4 },
};
static struct clksrc_clk clk_sclk_mmc3 = {
.clk = {
.name = "sclk_mmc",
.devname = "s3c-sdhci.3",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 11),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC4, .shift = 12, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 12, .size = 4 },
};
static struct clksrc_clk clk_sclk_spi0 = {
.clk = {
.name = "sclk_spi",
.devname = "s5pv210-spi.0",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 16),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC5, .shift = 0, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV5, .shift = 0, .size = 4 },
};
static struct clksrc_clk clk_sclk_spi1 = {
.clk = {
.name = "sclk_spi",
.devname = "s5pv210-spi.1",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 17),
},
.sources = &clkset_group2,
.reg_src = { .reg = S5P_CLK_SRC5, .shift = 4, .size = 4 },
.reg_div = { .reg = S5P_CLK_DIV5, .shift = 4, .size = 4 },
};
static struct clksrc_clk *clksrc_cdev[] = {
&clk_sclk_uart0,
&clk_sclk_uart1,
&clk_sclk_uart2,
&clk_sclk_uart3,
&clk_sclk_mmc0,
&clk_sclk_mmc1,
&clk_sclk_mmc2,
&clk_sclk_mmc3,
&clk_sclk_spi0,
&clk_sclk_spi1,
};
static struct clk *clk_cdev[] = {
&clk_hsmmc0,
&clk_hsmmc1,
&clk_hsmmc2,
&clk_hsmmc3,
&clk_pdma0,
&clk_pdma1,
};
/* Clock initialisation code */
static struct clksrc_clk *sysclks[] = {
&clk_mout_apll,
&clk_mout_epll,
&clk_mout_mpll,
&clk_armclk,
&clk_hclk_msys,
&clk_sclk_a2m,
&clk_hclk_dsys,
&clk_hclk_psys,
&clk_pclk_msys,
&clk_pclk_dsys,
&clk_pclk_psys,
&clk_vpllsrc,
&clk_sclk_vpll,
&clk_mout_dmc0,
&clk_sclk_dmc0,
&clk_sclk_audio0,
&clk_sclk_audio1,
&clk_sclk_audio2,
&clk_sclk_spdif,
};
static u32 epll_div[][6] = {
{ 48000000, 0, 48, 3, 3, 0 },
{ 96000000, 0, 48, 3, 2, 0 },
{ 144000000, 1, 72, 3, 2, 0 },
{ 192000000, 0, 48, 3, 1, 0 },
{ 288000000, 1, 72, 3, 1, 0 },
{ 32750000, 1, 65, 3, 4, 35127 },
{ 32768000, 1, 65, 3, 4, 35127 },
{ 45158400, 0, 45, 3, 3, 10355 },
{ 45000000, 0, 45, 3, 3, 10355 },
{ 45158000, 0, 45, 3, 3, 10355 },
{ 49125000, 0, 49, 3, 3, 9961 },
{ 49152000, 0, 49, 3, 3, 9961 },
{ 67737600, 1, 67, 3, 3, 48366 },
{ 67738000, 1, 67, 3, 3, 48366 },
{ 73800000, 1, 73, 3, 3, 47710 },
{ 73728000, 1, 73, 3, 3, 47710 },
{ 36000000, 1, 32, 3, 4, 0 },
{ 60000000, 1, 60, 3, 3, 0 },
{ 72000000, 1, 72, 3, 3, 0 },
{ 80000000, 1, 80, 3, 3, 0 },
{ 84000000, 0, 42, 3, 2, 0 },
{ 50000000, 0, 50, 3, 3, 0 },
};
static int s5pv210_epll_set_rate(struct clk *clk, unsigned long rate)
{
unsigned int epll_con, epll_con_k;
unsigned int i;
/* Return if nothing changed */
if (clk->rate == rate)
return 0;
epll_con = __raw_readl(S5P_EPLL_CON);
epll_con_k = __raw_readl(S5P_EPLL_CON1);
epll_con_k &= ~PLL46XX_KDIV_MASK;
epll_con &= ~(1 << 27 |
PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |
PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |
PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
if (epll_div[i][0] == rate) {
epll_con_k |= epll_div[i][5] << 0;
epll_con |= (epll_div[i][1] << 27 |
epll_div[i][2] << PLL46XX_MDIV_SHIFT |
epll_div[i][3] << PLL46XX_PDIV_SHIFT |
epll_div[i][4] << PLL46XX_SDIV_SHIFT);
break;
}
}
if (i == ARRAY_SIZE(epll_div)) {
printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n",
__func__);
return -EINVAL;
}
__raw_writel(epll_con, S5P_EPLL_CON);
__raw_writel(epll_con_k, S5P_EPLL_CON1);
printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
clk->rate, rate);
clk->rate = rate;
return 0;
}
static struct clk_ops s5pv210_epll_ops = {
.set_rate = s5pv210_epll_set_rate,
.get_rate = s5p_epll_get_rate,
};
static u32 vpll_div[][5] = {
{ 54000000, 3, 53, 3, 0 },
{ 108000000, 3, 53, 2, 0 },
};
static unsigned long s5pv210_vpll_get_rate(struct clk *clk)
{
return clk->rate;
}
static int s5pv210_vpll_set_rate(struct clk *clk, unsigned long rate)
{
unsigned int vpll_con;
unsigned int i;
/* Return if nothing changed */
if (clk->rate == rate)
return 0;
vpll_con = __raw_readl(S5P_VPLL_CON);
vpll_con &= ~(0x1 << 27 | \
PLL90XX_MDIV_MASK << PLL90XX_MDIV_SHIFT | \
PLL90XX_PDIV_MASK << PLL90XX_PDIV_SHIFT | \
PLL90XX_SDIV_MASK << PLL90XX_SDIV_SHIFT);
for (i = 0; i < ARRAY_SIZE(vpll_div); i++) {
if (vpll_div[i][0] == rate) {
vpll_con |= vpll_div[i][1] << PLL90XX_PDIV_SHIFT;
vpll_con |= vpll_div[i][2] << PLL90XX_MDIV_SHIFT;
vpll_con |= vpll_div[i][3] << PLL90XX_SDIV_SHIFT;
vpll_con |= vpll_div[i][4] << 27;
break;
}
}
if (i == ARRAY_SIZE(vpll_div)) {
printk(KERN_ERR "%s: Invalid Clock VPLL Frequency\n",
__func__);
return -EINVAL;
}
__raw_writel(vpll_con, S5P_VPLL_CON);
/* Wait for VPLL lock */
while (!(__raw_readl(S5P_VPLL_CON) & (1 << PLL90XX_LOCKED_SHIFT)))
continue;
clk->rate = rate;
return 0;
}
static struct clk_ops s5pv210_vpll_ops = {
.get_rate = s5pv210_vpll_get_rate,
.set_rate = s5pv210_vpll_set_rate,
};
void __init_or_cpufreq s5pv210_setup_clocks(void)
{
struct clk *xtal_clk;
unsigned long vpllsrc;
unsigned long armclk;
unsigned long hclk_msys;
unsigned long hclk_dsys;
unsigned long hclk_psys;
unsigned long pclk_msys;
unsigned long pclk_dsys;
unsigned long pclk_psys;
unsigned long apll;
unsigned long mpll;
unsigned long epll;
unsigned long vpll;
unsigned int ptr;
u32 clkdiv0, clkdiv1;
/* Set functions for clk_fout_epll */
clk_fout_epll.enable = s5p_epll_enable;
clk_fout_epll.ops = &s5pv210_epll_ops;
printk(KERN_DEBUG "%s: registering clocks\n", __func__);
clkdiv0 = __raw_readl(S5P_CLK_DIV0);
clkdiv1 = __raw_readl(S5P_CLK_DIV1);
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 = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON),
__raw_readl(S5P_EPLL_CON1), pll_4600);
vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502);
clk_fout_apll.ops = &clk_fout_apll_ops;
clk_fout_mpll.rate = mpll;
clk_fout_epll.rate = epll;
clk_fout_vpll.ops = &s5pv210_vpll_ops;
clk_fout_vpll.rate = vpll;
printk(KERN_INFO "S5PV210: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
apll, mpll, epll, vpll);
armclk = clk_get_rate(&clk_armclk.clk);
hclk_msys = clk_get_rate(&clk_hclk_msys.clk);
hclk_dsys = clk_get_rate(&clk_hclk_dsys.clk);
hclk_psys = clk_get_rate(&clk_hclk_psys.clk);
pclk_msys = clk_get_rate(&clk_pclk_msys.clk);
pclk_dsys = clk_get_rate(&clk_pclk_dsys.clk);
pclk_psys = clk_get_rate(&clk_pclk_psys.clk);
printk(KERN_INFO "S5PV210: ARMCLK=%ld, HCLKM=%ld, HCLKD=%ld\n"
"HCLKP=%ld, PCLKM=%ld, PCLKD=%ld, PCLKP=%ld\n",
armclk, hclk_msys, hclk_dsys, hclk_psys,
pclk_msys, pclk_dsys, pclk_psys);
clk_f.rate = armclk;
clk_h.rate = hclk_psys;
clk_p.rate = pclk_psys;
for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
s3c_set_clksrc(&clksrcs[ptr], true);
}
static struct clk *clks[] __initdata = {
&clk_sclk_hdmi27m,
&clk_sclk_hdmiphy,
&clk_sclk_usbphy0,
&clk_sclk_usbphy1,
&clk_pcmcdclk0,
&clk_pcmcdclk1,
&clk_pcmcdclk2,
};
static struct clk_lookup s5pv210_clk_lookup[] = {
CLKDEV_INIT(NULL, "clk_uart_baud0", &clk_p),
CLKDEV_INIT("s5pv210-uart.0", "clk_uart_baud1", &clk_sclk_uart0.clk),
CLKDEV_INIT("s5pv210-uart.1", "clk_uart_baud1", &clk_sclk_uart1.clk),
CLKDEV_INIT("s5pv210-uart.2", "clk_uart_baud1", &clk_sclk_uart2.clk),
CLKDEV_INIT("s5pv210-uart.3", "clk_uart_baud1", &clk_sclk_uart3.clk),
CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &clk_hsmmc0),
CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &clk_hsmmc1),
CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.0", &clk_hsmmc2),
CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.0", &clk_hsmmc3),
CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &clk_sclk_mmc3.clk),
CLKDEV_INIT(NULL, "spi_busclk0", &clk_p),
CLKDEV_INIT("s5pv210-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
CLKDEV_INIT("s5pv210-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
CLKDEV_INIT("dma-pl330.0", "apb_pclk", &clk_pdma0),
CLKDEV_INIT("dma-pl330.1", "apb_pclk", &clk_pdma1),
};
void __init s5pv210_register_clocks(void)
{
int ptr;
s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
s3c_register_clksrc(sysclks[ptr], 1);
for (ptr = 0; ptr < ARRAY_SIZE(sclk_tv); ptr++)
s3c_register_clksrc(sclk_tv[ptr], 1);
for (ptr = 0; ptr < ARRAY_SIZE(clksrc_cdev); ptr++)
s3c_register_clksrc(clksrc_cdev[ptr], 1);
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
clkdev_add_table(s5pv210_clk_lookup, ARRAY_SIZE(s5pv210_clk_lookup));
s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
for (ptr = 0; ptr < ARRAY_SIZE(clk_cdev); ptr++)
s3c_disable_clocks(clk_cdev[ptr], 1);
}
......@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/device.h>
#include <clocksource/samsung_pwm.h>
......@@ -37,12 +38,6 @@
#include <plat/cpu.h>
#ifdef CONFIG_S5P_CLOCK
#include <plat/clock.h>
#else
#include <linux/clk-provider.h>
#endif
#include <plat/devs.h>
#include <plat/sdhci.h>
#include <plat/adc-core.h>
......@@ -239,16 +234,7 @@ void __init s5pv210_map_io(void)
void __init s5pv210_init_clocks(int xtal)
{
#ifdef CONFIG_S5P_CLOCK
printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
s3c24xx_register_baseclocks(xtal);
s5p_register_clocks(xtal);
s5pv210_register_clocks();
s5pv210_setup_clocks();
#else
xusbxti_f = xtal;
#endif
}
void __init s5pv210_init_irq(void)
......
......@@ -14,14 +14,8 @@
#include <linux/reboot.h>
#ifdef CONFIG_COMMON_CLK_S5PV210
void s5pv210_clk_init(unsigned long xxti_f, unsigned long xusbxti_f,
void __iomem *reg_base);
#else
static inline void s5pv210_clk_init(unsigned long xxti_f,
unsigned long xusbxti_f,
void __iomem *reg_base) {}
#endif
void s5pv210_init_io(struct map_desc *mach_desc, int size);
void s5pv210_init_irq(void);
......
......@@ -46,7 +46,6 @@
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/keypad.h>
#include <plat/sdhci.h>
#include <plat/clock.h>
#include <plat/samsung-time.h>
#include <plat/mfc.h>
......
......@@ -47,7 +47,6 @@
#include <plat/samsung-time.h>
#include <plat/backlight.h>
#include <plat/mfc.h>
#include <plat/clock.h>
#include "common.h"
......
......@@ -26,55 +26,7 @@
#include <mach/regs-clock.h>
static struct sleep_save s5pv210_core_save[] = {
/* Clock source */
SAVE_ITEM(S5P_CLK_SRC0),
SAVE_ITEM(S5P_CLK_SRC1),
SAVE_ITEM(S5P_CLK_SRC2),
SAVE_ITEM(S5P_CLK_SRC3),
SAVE_ITEM(S5P_CLK_SRC4),
SAVE_ITEM(S5P_CLK_SRC5),
SAVE_ITEM(S5P_CLK_SRC6),
/* Clock source Mask */
SAVE_ITEM(S5P_CLK_SRC_MASK0),
SAVE_ITEM(S5P_CLK_SRC_MASK1),
/* Clock Divider */
SAVE_ITEM(S5P_CLK_DIV0),
SAVE_ITEM(S5P_CLK_DIV1),
SAVE_ITEM(S5P_CLK_DIV2),
SAVE_ITEM(S5P_CLK_DIV3),
SAVE_ITEM(S5P_CLK_DIV4),
SAVE_ITEM(S5P_CLK_DIV5),
SAVE_ITEM(S5P_CLK_DIV6),
SAVE_ITEM(S5P_CLK_DIV7),
/* Clock Main Gate */
SAVE_ITEM(S5P_CLKGATE_MAIN0),
SAVE_ITEM(S5P_CLKGATE_MAIN1),
SAVE_ITEM(S5P_CLKGATE_MAIN2),
/* Clock source Peri Gate */
SAVE_ITEM(S5P_CLKGATE_PERI0),
SAVE_ITEM(S5P_CLKGATE_PERI1),
/* Clock source SCLK Gate */
SAVE_ITEM(S5P_CLKGATE_SCLK0),
SAVE_ITEM(S5P_CLKGATE_SCLK1),
/* Clock IP Clock gate */
SAVE_ITEM(S5P_CLKGATE_IP0),
SAVE_ITEM(S5P_CLKGATE_IP1),
SAVE_ITEM(S5P_CLKGATE_IP2),
SAVE_ITEM(S5P_CLKGATE_IP3),
SAVE_ITEM(S5P_CLKGATE_IP4),
/* Clock Blcok and Bus gate */
SAVE_ITEM(S5P_CLKGATE_BLOCK),
SAVE_ITEM(S5P_CLKGATE_BUS0),
/* Clock ETC */
SAVE_ITEM(S5P_CLK_OUT),
SAVE_ITEM(S5P_MDNIE_SEL),
};
......
......@@ -23,7 +23,6 @@ config PLAT_S5P
select PLAT_SAMSUNG
select S3C_GPIO_TRACK
select S5P_GPIO_DRVSTR
select SAMSUNG_CLKSRC if !COMMON_CLK
help
Base platform code for Samsung's S5P series SoC.
......@@ -65,23 +64,6 @@ config SAMSUNG_ATAGS
if SAMSUNG_ATAGS
# clock options
config SAMSUNG_CLOCK
bool
default y if !COMMON_CLK
config SAMSUNG_CLKSRC
bool
help
Select the clock code for the clksrc implementation
used by newer systems such as the S3C64XX.
config S5P_CLOCK
bool
help
Support common clock part for ARCH_S5P and ARCH_EXYNOS SoCs
# options for IRQ support
config S5P_IRQ
......
......@@ -16,11 +16,6 @@ obj- :=
obj-y += init.o cpu.o
obj-$(CONFIG_SAMSUNG_CLOCK) += clock.o
obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o
obj-$(CONFIG_S5P_IRQ) += s5p-irq.o
obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o
obj-$(CONFIG_S5P_GPIO_INT) += s5p-irq-gpioint.o
......
/* linux/arch/arm/plat-samsung/clock-clksrc.c
*
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* 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/device.h>
#include <linux/io.h>
#include <plat/clock.h>
#include <plat/clock-clksrc.h>
#include <plat/cpu-freq.h>
static inline struct clksrc_clk *to_clksrc(struct clk *clk)
{
return container_of(clk, struct clksrc_clk, clk);
}
static inline u32 bit_mask(u32 shift, u32 nr_bits)
{
u32 mask = 0xffffffff >> (32 - nr_bits);
return mask << shift;
}
static unsigned long s3c_getrate_clksrc(struct clk *clk)
{
struct clksrc_clk *sclk = to_clksrc(clk);
unsigned long rate = clk_get_rate(clk->parent);
u32 clkdiv = __raw_readl(sclk->reg_div.reg);
u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
clkdiv &= mask;
clkdiv >>= sclk->reg_div.shift;
clkdiv++;
rate /= clkdiv;
return rate;
}
static int s3c_setrate_clksrc(struct clk *clk, unsigned long rate)
{
struct clksrc_clk *sclk = to_clksrc(clk);
void __iomem *reg = sclk->reg_div.reg;
unsigned int div;
u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
u32 val;
rate = clk_round_rate(clk, rate);
div = clk_get_rate(clk->parent) / rate;
if (div > (1 << sclk->reg_div.size))
return -EINVAL;
val = __raw_readl(reg);
val &= ~mask;
val |= (div - 1) << sclk->reg_div.shift;
__raw_writel(val, reg);
return 0;
}
static int s3c_setparent_clksrc(struct clk *clk, struct clk *parent)
{
struct clksrc_clk *sclk = to_clksrc(clk);
struct clksrc_sources *srcs = sclk->sources;
u32 clksrc = __raw_readl(sclk->reg_src.reg);
u32 mask = bit_mask(sclk->reg_src.shift, sclk->reg_src.size);
int src_nr = -1;
int ptr;
for (ptr = 0; ptr < srcs->nr_sources; ptr++)
if (srcs->sources[ptr] == parent) {
src_nr = ptr;
break;
}
if (src_nr >= 0) {
clk->parent = parent;
clksrc &= ~mask;
clksrc |= src_nr << sclk->reg_src.shift;
__raw_writel(clksrc, sclk->reg_src.reg);
return 0;
}
return -EINVAL;
}
static unsigned long s3c_roundrate_clksrc(struct clk *clk,
unsigned long rate)
{
struct clksrc_clk *sclk = to_clksrc(clk);
unsigned long parent_rate = clk_get_rate(clk->parent);
int max_div = 1 << sclk->reg_div.size;
int div;
if (rate >= parent_rate)
rate = parent_rate;
else {
div = parent_rate / rate;
if (parent_rate % rate)
div++;
if (div == 0)
div = 1;
if (div > max_div)
div = max_div;
rate = parent_rate / div;
}
return rate;
}
/* Clock initialisation code */
void __init_or_cpufreq s3c_set_clksrc(struct clksrc_clk *clk, bool announce)
{
struct clksrc_sources *srcs = clk->sources;
u32 mask = bit_mask(clk->reg_src.shift, clk->reg_src.size);
u32 clksrc;
if (!clk->reg_src.reg) {
if (!clk->clk.parent)
printk(KERN_ERR "%s: no parent clock specified\n",
clk->clk.name);
return;
}
clksrc = __raw_readl(clk->reg_src.reg);
clksrc &= mask;
clksrc >>= clk->reg_src.shift;
if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
printk(KERN_ERR "%s: bad source %d\n",
clk->clk.name, clksrc);
return;
}
clk->clk.parent = srcs->sources[clksrc];
if (announce)
printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
clk->clk.name, clk->clk.parent->name, clksrc,
clk_get_rate(&clk->clk));
}
static struct clk_ops clksrc_ops = {
.set_parent = s3c_setparent_clksrc,
.get_rate = s3c_getrate_clksrc,
.set_rate = s3c_setrate_clksrc,
.round_rate = s3c_roundrate_clksrc,
};
static struct clk_ops clksrc_ops_nodiv = {
.set_parent = s3c_setparent_clksrc,
};
static struct clk_ops clksrc_ops_nosrc = {
.get_rate = s3c_getrate_clksrc,
.set_rate = s3c_setrate_clksrc,
.round_rate = s3c_roundrate_clksrc,
};
void __init s3c_register_clksrc(struct clksrc_clk *clksrc, int size)
{
int ret;
for (; size > 0; size--, clksrc++) {
if (!clksrc->reg_div.reg && !clksrc->reg_src.reg)
printk(KERN_ERR "%s: clock %s has no registers set\n",
__func__, clksrc->clk.name);
/* fill in the default functions */
if (!clksrc->clk.ops) {
if (!clksrc->reg_div.reg)
clksrc->clk.ops = &clksrc_ops_nodiv;
else if (!clksrc->reg_src.reg)
clksrc->clk.ops = &clksrc_ops_nosrc;
else
clksrc->clk.ops = &clksrc_ops;
}
/* setup the clocksource, but do not announce it
* as it may be re-set by the setup routines
* called after the rest of the clocks have been
* registered
*/
s3c_set_clksrc(clksrc, false);
ret = s3c24xx_register_clock(&clksrc->clk);
if (ret < 0) {
printk(KERN_ERR "%s: failed to register %s (%d)\n",
__func__, clksrc->clk.name, ret);
}
}
}
/* linux/arch/arm/plat-s3c24xx/clock.c
*
* Copyright 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX Core clock control support
*
* Based on, and code from linux/arch/arm/mach-versatile/clock.c
**
** Copyright (C) 2004 ARM Limited.
** Written by Deep Blue Solutions Limited.
*
*
* 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/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#if defined(CONFIG_DEBUG_FS)
#include <linux/debugfs.h>
#endif
#include <asm/irq.h>
#include <plat/cpu-freq.h>
#include <plat/clock.h>
#include <plat/cpu.h>
#include <linux/serial_core.h>
#include <linux/serial_s3c.h> /* for s3c24xx_uart_devs */
/* clock information */
static LIST_HEAD(clocks);
/* We originally used an mutex here, but some contexts (see resume)
* are calling functions such as clk_set_parent() with IRQs disabled
* causing an BUG to be triggered.
*/
DEFINE_SPINLOCK(clocks_lock);
/* Global watchdog clock used by arch_wtd_reset() callback */
struct clk *s3c2410_wdtclk;
static int __init s3c_wdt_reset_init(void)
{
s3c2410_wdtclk = clk_get(NULL, "watchdog");
if (IS_ERR(s3c2410_wdtclk))
printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
return 0;
}
arch_initcall(s3c_wdt_reset_init);
/* enable and disable calls for use with the clk struct */
static int clk_null_enable(struct clk *clk, int enable)
{
return 0;
}
int clk_enable(struct clk *clk)
{
unsigned long flags;
if (IS_ERR(clk) || clk == NULL)
return -EINVAL;
clk_enable(clk->parent);
spin_lock_irqsave(&clocks_lock, flags);
if ((clk->usage++) == 0)
(clk->enable)(clk, 1);
spin_unlock_irqrestore(&clocks_lock, flags);
return 0;
}
void clk_disable(struct clk *clk)
{
unsigned long flags;
if (IS_ERR(clk) || clk == NULL)
return;
spin_lock_irqsave(&clocks_lock, flags);
if ((--clk->usage) == 0)
(clk->enable)(clk, 0);
spin_unlock_irqrestore(&clocks_lock, flags);
clk_disable(clk->parent);
}
unsigned long clk_get_rate(struct clk *clk)
{
if (IS_ERR_OR_NULL(clk))
return 0;
if (clk->rate != 0)
return clk->rate;
if (clk->ops != NULL && clk->ops->get_rate != NULL)
return (clk->ops->get_rate)(clk);
if (clk->parent != NULL)
return clk_get_rate(clk->parent);
return clk->rate;
}
long clk_round_rate(struct clk *clk, unsigned long rate)
{
if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->round_rate)
return (clk->ops->round_rate)(clk, rate);
return rate;
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
int ret;
if (IS_ERR_OR_NULL(clk))
return -EINVAL;
/* We do not default just do a clk->rate = rate as
* the clock may have been made this way by choice.
*/
WARN_ON(clk->ops == NULL);
WARN_ON(clk->ops && clk->ops->set_rate == NULL);
if (clk->ops == NULL || clk->ops->set_rate == NULL)
return -EINVAL;
spin_lock_irqsave(&clocks_lock, flags);
ret = (clk->ops->set_rate)(clk, rate);
spin_unlock_irqrestore(&clocks_lock, flags);
return ret;
}
struct clk *clk_get_parent(struct clk *clk)
{
return clk->parent;
}
int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
int ret = 0;
if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(parent))
return -EINVAL;
spin_lock_irqsave(&clocks_lock, flags);
if (clk->ops && clk->ops->set_parent)
ret = (clk->ops->set_parent)(clk, parent);
spin_unlock_irqrestore(&clocks_lock, flags);
return ret;
}
EXPORT_SYMBOL(clk_enable);
EXPORT_SYMBOL(clk_disable);
EXPORT_SYMBOL(clk_get_rate);
EXPORT_SYMBOL(clk_round_rate);
EXPORT_SYMBOL(clk_set_rate);
EXPORT_SYMBOL(clk_get_parent);
EXPORT_SYMBOL(clk_set_parent);
/* base clocks */
int clk_default_setrate(struct clk *clk, unsigned long rate)
{
clk->rate = rate;
return 0;
}
struct clk_ops clk_ops_def_setrate = {
.set_rate = clk_default_setrate,
};
struct clk clk_xtal = {
.name = "xtal",
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_ext = {
.name = "ext",
};
struct clk clk_epll = {
.name = "epll",
};
struct clk clk_mpll = {
.name = "mpll",
.ops = &clk_ops_def_setrate,
};
struct clk clk_upll = {
.name = "upll",
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_f = {
.name = "fclk",
.rate = 0,
.parent = &clk_mpll,
.ctrlbit = 0,
};
struct clk clk_h = {
.name = "hclk",
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
.ops = &clk_ops_def_setrate,
};
struct clk clk_p = {
.name = "pclk",
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
.ops = &clk_ops_def_setrate,
};
struct clk clk_usb_bus = {
.name = "usb-bus",
.rate = 0,
.parent = &clk_upll,
};
struct clk s3c24xx_uclk = {
.name = "uclk",
};
/* initialise the clock system */
/**
* s3c24xx_register_clock() - register a clock
* @clk: The clock to register
*
* Add the specified clock to the list of clocks known by the system.
*/
int s3c24xx_register_clock(struct clk *clk)
{
if (clk->enable == NULL)
clk->enable = clk_null_enable;
/* fill up the clk_lookup structure and register it*/
clk->lookup.dev_id = clk->devname;
clk->lookup.con_id = clk->name;
clk->lookup.clk = clk;
clkdev_add(&clk->lookup);
return 0;
}
/**
* s3c24xx_register_clocks() - register an array of clock pointers
* @clks: Pointer to an array of struct clk pointers
* @nr_clks: The number of clocks in the @clks array.
*
* Call s3c24xx_register_clock() for all the clock pointers contained
* in the @clks list. Returns the number of failures.
*/
int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
{
int fails = 0;
for (; nr_clks > 0; nr_clks--, clks++) {
if (s3c24xx_register_clock(*clks) < 0) {
struct clk *clk = *clks;
printk(KERN_ERR "%s: failed to register %p: %s\n",
__func__, clk, clk->name);
fails++;
}
}
return fails;
}
/**
* s3c_register_clocks() - register an array of clocks
* @clkp: Pointer to the first clock in the array.
* @nr_clks: Number of clocks to register.
*
* Call s3c24xx_register_clock() on the @clkp array given, printing an
* error if it fails to register the clock (unlikely).
*/
void __init s3c_register_clocks(struct clk *clkp, int nr_clks)
{
int ret;
for (; nr_clks > 0; nr_clks--, clkp++) {
ret = s3c24xx_register_clock(clkp);
if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
clkp->name, ret);
}
}
}
/**
* s3c_disable_clocks() - disable an array of clocks
* @clkp: Pointer to the first clock in the array.
* @nr_clks: Number of clocks to register.
*
* for internal use only at initialisation time. disable the clocks in the
* @clkp array.
*/
void __init s3c_disable_clocks(struct clk *clkp, int nr_clks)
{
for (; nr_clks > 0; nr_clks--, clkp++)
(clkp->enable)(clkp, 0);
}
/* initialise all the clocks */
int __init s3c24xx_register_baseclocks(unsigned long xtal)
{
printk(KERN_INFO "S3C24XX Clocks, Copyright 2004 Simtec Electronics\n");
clk_xtal.rate = xtal;
/* register our clocks */
if (s3c24xx_register_clock(&clk_xtal) < 0)
printk(KERN_ERR "failed to register master xtal\n");
if (s3c24xx_register_clock(&clk_mpll) < 0)
printk(KERN_ERR "failed to register mpll clock\n");
if (s3c24xx_register_clock(&clk_upll) < 0)
printk(KERN_ERR "failed to register upll clock\n");
if (s3c24xx_register_clock(&clk_f) < 0)
printk(KERN_ERR "failed to register cpu fclk\n");
if (s3c24xx_register_clock(&clk_h) < 0)
printk(KERN_ERR "failed to register cpu hclk\n");
if (s3c24xx_register_clock(&clk_p) < 0)
printk(KERN_ERR "failed to register cpu pclk\n");
return 0;
}
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
/* debugfs support to trace clock tree hierarchy and attributes */
static struct dentry *clk_debugfs_root;
static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
{
struct clk *child;
const char *state;
char buf[255] = { 0 };
int n = 0;
if (c->name)
n = snprintf(buf, sizeof(buf) - 1, "%s", c->name);
if (c->devname)
n += snprintf(buf + n, sizeof(buf) - 1 - n, ":%s", c->devname);
state = (c->usage > 0) ? "on" : "off";
seq_printf(s, "%*s%-*s %-6s %-3d %-10lu\n",
level * 3 + 1, "",
50 - level * 3, buf,
state, c->usage, clk_get_rate(c));
list_for_each_entry(child, &clocks, list) {
if (child->parent != c)
continue;
clock_tree_show_one(s, child, level + 1);
}
}
static int clock_tree_show(struct seq_file *s, void *data)
{
struct clk *c;
unsigned long flags;
seq_printf(s, " clock state ref rate\n");
seq_printf(s, "----------------------------------------------------\n");
spin_lock_irqsave(&clocks_lock, flags);
list_for_each_entry(c, &clocks, list)
if (c->parent == NULL)
clock_tree_show_one(s, c, 0);
spin_unlock_irqrestore(&clocks_lock, flags);
return 0;
}
static int clock_tree_open(struct inode *inode, struct file *file)
{
return single_open(file, clock_tree_show, inode->i_private);
}
static const struct file_operations clock_tree_fops = {
.open = clock_tree_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int clock_rate_show(void *data, u64 *val)
{
struct clk *c = data;
*val = clk_get_rate(c);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_rate_show, NULL, "%llu\n");
static int clk_debugfs_register_one(struct clk *c)
{
int err;
struct dentry *d;
struct clk *pa = c->parent;
char s[255];
char *p = s;
p += sprintf(p, "%s", c->devname);
d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
if (!d)
return -ENOMEM;
c->dent = d;
d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usage);
if (!d) {
err = -ENOMEM;
goto err_out;
}
d = debugfs_create_file("rate", S_IRUGO, c->dent, c, &clock_rate_fops);
if (!d) {
err = -ENOMEM;
goto err_out;
}
return 0;
err_out:
debugfs_remove_recursive(c->dent);
return err;
}
static int clk_debugfs_register(struct clk *c)
{
int err;
struct clk *pa = c->parent;
if (pa && !pa->dent) {
err = clk_debugfs_register(pa);
if (err)
return err;
}
if (!c->dent) {
err = clk_debugfs_register_one(c);
if (err)
return err;
}
return 0;
}
static int __init clk_debugfs_init(void)
{
struct clk *c;
struct dentry *d;
int err = -ENOMEM;
d = debugfs_create_dir("clock", NULL);
if (!d)
return -ENOMEM;
clk_debugfs_root = d;
d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
&clock_tree_fops);
if (!d)
goto err_out;
list_for_each_entry(c, &clocks, list) {
err = clk_debugfs_register(c);
if (err)
goto err_out;
}
return 0;
err_out:
debugfs_remove_recursive(clk_debugfs_root);
return err;
}
late_initcall(clk_debugfs_init);
#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
/* linux/arch/arm/plat-samsung/include/plat/clock-clksrc.h
*
* Parts taken from arch/arm/plat-s3c64xx/clock.c
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* Copyright 2009 Ben Dooks <ben-linux@fluff.org>
* Copyright 2009 Harald Welte
*
* 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 clksrc_sources - list of sources for a given clock
* @sources: array of pointers to clocks
* @nr_sources: The size of @sources
*/
struct clksrc_sources {
unsigned int nr_sources;
struct clk **sources;
};
/**
* struct clksrc_reg - register definition for clock control bits
* @reg: pointer to the register in virtual memory.
* @shift: the shift in bits to where the bitfield is.
* @size: the size in bits of the bitfield.
*
* This specifies the size and position of the bits we are interested
* in within the register specified by @reg.
*/
struct clksrc_reg {
void __iomem *reg;
unsigned short shift;
unsigned short size;
};
/**
* struct clksrc_clk - class of clock for newer style samsung devices.
* @clk: the standard clock representation
* @sources: the sources for this clock
* @reg_src: the register definition for selecting the clock's source
* @reg_div: the register definition for the clock's output divisor
*
* This clock implements the features required by the newer SoCs where
* the standard clock block provides an input mux and a post-mux divisor
* to provide the periperhal's clock.
*
* The array of @sources provides the mapping of mux position to the
* clock, and @reg_src shows the code where to modify to change the mux
* position. The @reg_div defines how to change the divider settings on
* the output.
*/
struct clksrc_clk {
struct clk clk;
struct clksrc_sources *sources;
struct clksrc_reg reg_src;
struct clksrc_reg reg_div;
};
/**
* s3c_set_clksrc() - setup the clock from the register settings
* @clk: The clock to setup.
* @announce: true to announce the setting to printk().
*
* Setup the clock from the current register settings, for when the
* kernel boots or if it is resuming from a possibly unknown state.
*/
extern void s3c_set_clksrc(struct clksrc_clk *clk, bool announce);
/**
* s3c_register_clksrc() register clocks from an array of clksrc clocks
* @srcs: The array of clocks to register
* @size: The size of the @srcs array.
*
* Initialise and register the array of clocks described by @srcs.
*/
extern void s3c_register_clksrc(struct clksrc_clk *srcs, int size);
/* linux/arch/arm/plat-s3c/include/plat/clock.h
*
* Copyright (c) 2004-2005 Simtec Electronics
* http://www.simtec.co.uk/products/SWLINUX/
* Written by Ben Dooks, <ben@simtec.co.uk>
*
* 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.
*/
#ifndef __ASM_PLAT_CLOCK_H
#define __ASM_PLAT_CLOCK_H __FILE__
#include <linux/spinlock.h>
#include <linux/clkdev.h>
struct clk;
/**
* struct clk_ops - standard clock operations
* @set_rate: set the clock rate, see clk_set_rate().
* @get_rate: get the clock rate, see clk_get_rate().
* @round_rate: round a given clock rate, see clk_round_rate().
* @set_parent: set the clock's parent, see clk_set_parent().
*
* Group the common clock implementations together so that we
* don't have to keep setting the same fields again. We leave
* enable in struct clk.
*
* Adding an extra layer of indirection into the process should
* not be a problem as it is unlikely these operations are going
* to need to be called quickly.
*/
struct clk_ops {
int (*set_rate)(struct clk *c, unsigned long rate);
unsigned long (*get_rate)(struct clk *c);
unsigned long (*round_rate)(struct clk *c, unsigned long rate);
int (*set_parent)(struct clk *c, struct clk *parent);
};
struct clk {
struct list_head list;
struct module *owner;
struct clk *parent;
const char *name;
const char *devname;
int id;
int usage;
unsigned long rate;
unsigned long ctrlbit;
struct clk_ops *ops;
int (*enable)(struct clk *, int enable);
struct clk_lookup lookup;
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
struct dentry *dent; /* For visible tree hierarchy */
#endif
};
/* other clocks which may be registered by board support */
extern struct clk s3c24xx_dclk0;
extern struct clk s3c24xx_dclk1;
extern struct clk s3c24xx_clkout0;
extern struct clk s3c24xx_clkout1;
extern struct clk s3c24xx_uclk;
extern struct clk clk_usb_bus;
/* core clock support */
extern struct clk clk_f;
extern struct clk clk_h;
extern struct clk clk_p;
extern struct clk clk_mpll;
extern struct clk clk_upll;
extern struct clk clk_epll;
extern struct clk clk_xtal;
extern struct clk clk_ext;
/* S3C2443/S3C2416 specific clocks */
extern struct clksrc_clk clk_epllref;
extern struct clksrc_clk clk_esysclk;
/* S3C24XX UART clocks */
extern struct clk s3c24xx_clk_uart0;
extern struct clk s3c24xx_clk_uart1;
extern struct clk s3c24xx_clk_uart2;
/* S3C64XX specific clocks */
extern struct clk clk_h2;
extern struct clk clk_27m;
extern struct clk clk_48m;
extern struct clk clk_xusbxti;
extern int clk_default_setrate(struct clk *clk, unsigned long rate);
extern struct clk_ops clk_ops_def_setrate;
/* exports for arch/arm/mach-s3c2410
*
* Please DO NOT use these outside of arch/arm/mach-s3c2410
*/
extern spinlock_t clocks_lock;
extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
extern int s3c24xx_register_clock(struct clk *clk);
extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
extern void s3c_register_clocks(struct clk *clk, int nr_clks);
extern void s3c_disable_clocks(struct clk *clkp, int nr_clks);
extern int s3c24xx_register_baseclocks(unsigned long xtal);
extern void s5p_register_clocks(unsigned long xtal_freq);
extern void s3c24xx_setup_clocks(unsigned long fclk,
unsigned long hclk,
unsigned long pclk);
extern void s3c2410_setup_clocks(void);
extern void s3c2412_setup_clocks(void);
extern void s3c244x_setup_clocks(void);
/* S3C2410 specific clock functions */
extern int s3c2410_baseclk_add(void);
/* S3C2443/S3C2416 specific clock functions */
typedef unsigned int (*pll_fn)(unsigned int reg, unsigned int base);
extern void s3c2443_common_setup_clocks(pll_fn get_mpll);
extern void s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
unsigned int *divs, int nr_divs,
int divmask);
extern int s3c2443_clkcon_enable_h(struct clk *clk, int enable);
extern int s3c2443_clkcon_enable_p(struct clk *clk, int enable);
extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable);
/* S3C64XX specific functions and clocks */
extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable);
/* Global watchdog clock used by arch_wtd_reset() callback */
extern struct clk *s3c2410_wdtclk;
#endif /* __ASM_PLAT_CLOCK_H */
......@@ -140,7 +140,6 @@ struct s3c_cpufreq_config {
* any frequency changes. This is really only need by devices like the
* S3C2410 where there is no or limited divider between the PLL and the
* ARMCLK.
* @resume_clocks: Update the clocks on resume.
* @get_iotiming: Get the current IO timing data, mainly for use at start.
* @set_iotiming: Update the IO timings from the cached copies calculated
* from the @calc_iotiming entry when changing the frequency.
......@@ -169,8 +168,6 @@ struct s3c_cpufreq_info {
/* driver routines */
void (*resume_clocks)(void);
int (*get_iotiming)(struct s3c_cpufreq_config *cfg,
struct s3c_iotimings *timings);
......
/* linux/arch/arm/plat-samsung/include/plat/pll.h
*
* Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* Samsung PLL codes
*
* 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 <asm/div64.h>
#define S3C24XX_PLL_MDIV_MASK (0xFF)
#define S3C24XX_PLL_PDIV_MASK (0x1F)
#define S3C24XX_PLL_SDIV_MASK (0x3)
#define S3C24XX_PLL_MDIV_SHIFT (12)
#define S3C24XX_PLL_PDIV_SHIFT (4)
#define S3C24XX_PLL_SDIV_SHIFT (0)
static inline unsigned int s3c24xx_get_pll(unsigned int pllval,
unsigned int baseclk)
{
unsigned int mdiv, pdiv, sdiv;
uint64_t fvco;
mdiv = (pllval >> S3C24XX_PLL_MDIV_SHIFT) & S3C24XX_PLL_MDIV_MASK;
pdiv = (pllval >> S3C24XX_PLL_PDIV_SHIFT) & S3C24XX_PLL_PDIV_MASK;
sdiv = (pllval >> S3C24XX_PLL_SDIV_SHIFT) & S3C24XX_PLL_SDIV_MASK;
fvco = (uint64_t)baseclk * (mdiv + 8);
do_div(fvco, (pdiv + 2) << sdiv);
return (unsigned int)fvco;
}
#define S3C2416_PLL_MDIV_MASK (0x3FF)
#define S3C2416_PLL_PDIV_MASK (0x3F)
#define S3C2416_PLL_SDIV_MASK (0x7)
#define S3C2416_PLL_MDIV_SHIFT (14)
#define S3C2416_PLL_PDIV_SHIFT (5)
#define S3C2416_PLL_SDIV_SHIFT (0)
static inline unsigned int s3c2416_get_pll(unsigned int pllval,
unsigned int baseclk)
{
unsigned int mdiv, pdiv, sdiv;
uint64_t fvco;
mdiv = (pllval >> S3C2416_PLL_MDIV_SHIFT) & S3C2416_PLL_MDIV_MASK;
pdiv = (pllval >> S3C2416_PLL_PDIV_SHIFT) & S3C2416_PLL_PDIV_MASK;
sdiv = (pllval >> S3C2416_PLL_SDIV_SHIFT) & S3C2416_PLL_SDIV_MASK;
fvco = (uint64_t)baseclk * mdiv;
do_div(fvco, (pdiv << sdiv));
return (unsigned int)fvco;
}
#define S3C6400_PLL_MDIV_MASK (0x3FF)
#define S3C6400_PLL_PDIV_MASK (0x3F)
#define S3C6400_PLL_SDIV_MASK (0x7)
#define S3C6400_PLL_MDIV_SHIFT (16)
#define S3C6400_PLL_PDIV_SHIFT (8)
#define S3C6400_PLL_SDIV_SHIFT (0)
static inline unsigned long s3c6400_get_pll(unsigned long baseclk,
u32 pllcon)
{
u32 mdiv, pdiv, sdiv;
u64 fvco = baseclk;
mdiv = (pllcon >> S3C6400_PLL_MDIV_SHIFT) & S3C6400_PLL_MDIV_MASK;
pdiv = (pllcon >> S3C6400_PLL_PDIV_SHIFT) & S3C6400_PLL_PDIV_MASK;
sdiv = (pllcon >> S3C6400_PLL_SDIV_SHIFT) & S3C6400_PLL_SDIV_MASK;
fvco *= mdiv;
do_div(fvco, (pdiv << sdiv));
return (unsigned long)fvco;
}
#define PLL6553X_MDIV_MASK (0x7F)
#define PLL6553X_PDIV_MASK (0x1F)
#define PLL6553X_SDIV_MASK (0x3)
#define PLL6553X_KDIV_MASK (0xFFFF)
#define PLL6553X_MDIV_SHIFT (16)
#define PLL6553X_PDIV_SHIFT (8)
#define PLL6553X_SDIV_SHIFT (0)
static inline unsigned long s3c_get_pll6553x(unsigned long baseclk,
u32 pll_con0, u32 pll_con1)
{
unsigned long result;
u32 mdiv, pdiv, sdiv, kdiv;
u64 tmp;
mdiv = (pll_con0 >> PLL6553X_MDIV_SHIFT) & PLL6553X_MDIV_MASK;
pdiv = (pll_con0 >> PLL6553X_PDIV_SHIFT) & PLL6553X_PDIV_MASK;
sdiv = (pll_con0 >> PLL6553X_SDIV_SHIFT) & PLL6553X_SDIV_MASK;
kdiv = pll_con1 & PLL6553X_KDIV_MASK;
/*
* We need to multiple baseclk by mdiv (the integer part) and kdiv
* which is in 2^16ths, so shift mdiv up (does not overflow) and
* add kdiv before multiplying. The use of tmp is to avoid any
* overflows before shifting bac down into result when multipling
* by the mdiv and kdiv pair.
*/
tmp = baseclk;
tmp *= (mdiv << 16) + kdiv;
do_div(tmp, (pdiv << sdiv));
result = tmp >> 16;
return result;
}
#define PLL35XX_MDIV_MASK (0x3FF)
#define PLL35XX_PDIV_MASK (0x3F)
#define PLL35XX_SDIV_MASK (0x7)
#define PLL35XX_MDIV_SHIFT (16)
#define PLL35XX_PDIV_SHIFT (8)
#define PLL35XX_SDIV_SHIFT (0)
static inline unsigned long s5p_get_pll35xx(unsigned long baseclk, u32 pll_con)
{
u32 mdiv, pdiv, sdiv;
u64 fvco = baseclk;
mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
fvco *= mdiv;
do_div(fvco, (pdiv << sdiv));
return (unsigned long)fvco;
}
#define PLL36XX_KDIV_MASK (0xFFFF)
#define PLL36XX_MDIV_MASK (0x1FF)
#define PLL36XX_PDIV_MASK (0x3F)
#define PLL36XX_SDIV_MASK (0x7)
#define PLL36XX_MDIV_SHIFT (16)
#define PLL36XX_PDIV_SHIFT (8)
#define PLL36XX_SDIV_SHIFT (0)
static inline unsigned long s5p_get_pll36xx(unsigned long baseclk,
u32 pll_con0, u32 pll_con1)
{
unsigned long result;
u32 mdiv, pdiv, sdiv, kdiv;
u64 tmp;
mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
kdiv = pll_con1 & PLL36XX_KDIV_MASK;
tmp = baseclk;
tmp *= (mdiv << 16) + kdiv;
do_div(tmp, (pdiv << sdiv));
result = tmp >> 16;
return result;
}
#define PLL45XX_MDIV_MASK (0x3FF)
#define PLL45XX_PDIV_MASK (0x3F)
#define PLL45XX_SDIV_MASK (0x7)
#define PLL45XX_MDIV_SHIFT (16)
#define PLL45XX_PDIV_SHIFT (8)
#define PLL45XX_SDIV_SHIFT (0)
enum pll45xx_type_t {
pll_4500,
pll_4502,
pll_4508
};
static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
enum pll45xx_type_t pll_type)
{
u32 mdiv, pdiv, sdiv;
u64 fvco = baseclk;
mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
if (pll_type == pll_4508)
sdiv = sdiv - 1;
fvco *= mdiv;
do_div(fvco, (pdiv << sdiv));
return (unsigned long)fvco;
}
/* CON0 bit-fields */
#define PLL46XX_MDIV_MASK (0x1FF)
#define PLL46XX_PDIV_MASK (0x3F)
#define PLL46XX_SDIV_MASK (0x7)
#define PLL46XX_LOCKED_SHIFT (29)
#define PLL46XX_MDIV_SHIFT (16)
#define PLL46XX_PDIV_SHIFT (8)
#define PLL46XX_SDIV_SHIFT (0)
/* CON1 bit-fields */
#define PLL46XX_MRR_MASK (0x1F)
#define PLL46XX_MFR_MASK (0x3F)
#define PLL46XX_KDIV_MASK (0xFFFF)
#define PLL4650C_KDIV_MASK (0xFFF)
#define PLL46XX_MRR_SHIFT (24)
#define PLL46XX_MFR_SHIFT (16)
#define PLL46XX_KDIV_SHIFT (0)
enum pll46xx_type_t {
pll_4600,
pll_4650,
pll_4650c,
};
static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
u32 pll_con0, u32 pll_con1,
enum pll46xx_type_t pll_type)
{
unsigned long result;
u32 mdiv, pdiv, sdiv, kdiv;
u64 tmp;
mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
kdiv = pll_con1 & PLL46XX_KDIV_MASK;
if (pll_type == pll_4650c)
kdiv = pll_con1 & PLL4650C_KDIV_MASK;
else
kdiv = pll_con1 & PLL46XX_KDIV_MASK;
tmp = baseclk;
if (pll_type == pll_4600) {
tmp *= (mdiv << 16) + kdiv;
do_div(tmp, (pdiv << sdiv));
result = tmp >> 16;
} else {
tmp *= (mdiv << 10) + kdiv;
do_div(tmp, (pdiv << sdiv));
result = tmp >> 10;
}
return result;
}
#define PLL90XX_MDIV_MASK (0xFF)
#define PLL90XX_PDIV_MASK (0x3F)
#define PLL90XX_SDIV_MASK (0x7)
#define PLL90XX_KDIV_MASK (0xffff)
#define PLL90XX_LOCKED_SHIFT (29)
#define PLL90XX_MDIV_SHIFT (16)
#define PLL90XX_PDIV_SHIFT (8)
#define PLL90XX_SDIV_SHIFT (0)
#define PLL90XX_KDIV_SHIFT (0)
static inline unsigned long s5p_get_pll90xx(unsigned long baseclk,
u32 pll_con, u32 pll_conk)
{
unsigned long result;
u32 mdiv, pdiv, sdiv, kdiv;
u64 tmp;
mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK;
pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK;
sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK;
kdiv = pll_conk & PLL90XX_KDIV_MASK;
/*
* We need to multiple baseclk by mdiv (the integer part) and kdiv
* which is in 2^16ths, so shift mdiv up (does not overflow) and
* add kdiv before multiplying. The use of tmp is to avoid any
* overflows before shifting bac down into result when multipling
* by the mdiv and kdiv pair.
*/
tmp = baseclk;
tmp *= (mdiv << 16) + kdiv;
do_div(tmp, (pdiv << sdiv));
result = tmp >> 16;
return result;
}
#define PLL65XX_MDIV_MASK (0x3FF)
#define PLL65XX_PDIV_MASK (0x3F)
#define PLL65XX_SDIV_MASK (0x7)
#define PLL65XX_MDIV_SHIFT (16)
#define PLL65XX_PDIV_SHIFT (8)
#define PLL65XX_SDIV_SHIFT (0)
static inline unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con)
{
u32 mdiv, pdiv, sdiv;
u64 fvco = baseclk;
mdiv = (pll_con >> PLL65XX_MDIV_SHIFT) & PLL65XX_MDIV_MASK;
pdiv = (pll_con >> PLL65XX_PDIV_SHIFT) & PLL65XX_PDIV_MASK;
sdiv = (pll_con >> PLL65XX_SDIV_SHIFT) & PLL65XX_SDIV_MASK;
fvco *= mdiv;
do_div(fvco, (pdiv << sdiv));
return (unsigned long)fvco;
}
/* linux/arch/arm/plat-samsung/include/plat/s5p-clock.h
*
* Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Header file for s5p clock support
*
* 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.
*/
#ifndef __ASM_PLAT_S5P_CLOCK_H
#define __ASM_PLAT_S5P_CLOCK_H __FILE__
#include <linux/clk.h>
#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
#define clk_fin_apll clk_ext_xtal_mux
#define clk_fin_bpll clk_ext_xtal_mux
#define clk_fin_cpll clk_ext_xtal_mux
#define clk_fin_mpll clk_ext_xtal_mux
#define clk_fin_epll clk_ext_xtal_mux
#define clk_fin_dpll clk_ext_xtal_mux
#define clk_fin_vpll clk_ext_xtal_mux
#define clk_fin_hpll clk_ext_xtal_mux
extern struct clk clk_ext_xtal_mux;
extern struct clk clk_xusbxti;
extern struct clk clk_48m;
extern struct clk s5p_clk_27m;
extern struct clk clk_fout_apll;
extern struct clk clk_fout_bpll;
extern struct clk clk_fout_bpll_div2;
extern struct clk clk_fout_cpll;
extern struct clk clk_fout_mpll;
extern struct clk clk_fout_mpll_div2;
extern struct clk clk_fout_epll;
extern struct clk clk_fout_dpll;
extern struct clk clk_fout_vpll;
extern struct clk clk_arm;
extern struct clk clk_vpll;
extern struct clksrc_sources clk_src_apll;
extern struct clksrc_sources clk_src_bpll;
extern struct clksrc_sources clk_src_bpll_fout;
extern struct clksrc_sources clk_src_cpll;
extern struct clksrc_sources clk_src_mpll;
extern struct clksrc_sources clk_src_mpll_fout;
extern struct clksrc_sources clk_src_epll;
extern struct clksrc_sources clk_src_dpll;
extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable);
/* Common EPLL operations for S5P platform */
extern int s5p_epll_enable(struct clk *clk, int enable);
extern unsigned long s5p_epll_get_rate(struct clk *clk);
/* SPDIF clk operations common for S5PV210/C110 and Exynos4 */
extern int s5p_spdif_set_rate(struct clk *clk, unsigned long rate);
extern unsigned long s5p_spdif_get_rate(struct clk *clk);
extern struct clk_ops s5p_sclk_spdif_ops;
#endif /* __ASM_PLAT_S5P_CLOCK_H */
......@@ -30,7 +30,6 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/clock.h>
static struct cpu_table *cpu;
......
/*
* Copyright 2009 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* S5P - Common clock support
*
* 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/device.h>
#include <linux/io.h>
#include <asm/div64.h>
#include <mach/regs-clock.h>
#include <plat/clock.h>
#include <plat/clock-clksrc.h>
#include <plat/s5p-clock.h>
/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
* clk_ext_xtal_mux.
*/
struct clk clk_ext_xtal_mux = {
.name = "ext_xtal",
.id = -1,
};
struct clk clk_xusbxti = {
.name = "xusbxti",
.id = -1,
.rate = 24000000,
};
struct clk s5p_clk_27m = {
.name = "clk_27m",
.id = -1,
.rate = 27000000,
};
/* 48MHz USB Phy clock output */
struct clk clk_48m = {
.name = "clk_48m",
.id = -1,
.rate = 48000000,
};
/* APLL clock output
* No need .ctrlbit, this is always on
*/
struct clk clk_fout_apll = {
.name = "fout_apll",
.id = -1,
};
/* BPLL clock output */
struct clk clk_fout_bpll = {
.name = "fout_bpll",
.id = -1,
};
struct clk clk_fout_bpll_div2 = {
.name = "fout_bpll_div2",
.id = -1,
};
/* CPLL clock output */
struct clk clk_fout_cpll = {
.name = "fout_cpll",
.id = -1,
};
/* MPLL clock output
* No need .ctrlbit, this is always on
*/
struct clk clk_fout_mpll = {
.name = "fout_mpll",
.id = -1,
};
struct clk clk_fout_mpll_div2 = {
.name = "fout_mpll_div2",
.id = -1,
};
/* EPLL clock output */
struct clk clk_fout_epll = {
.name = "fout_epll",
.id = -1,
.ctrlbit = (1 << 31),
};
/* DPLL clock output */
struct clk clk_fout_dpll = {
.name = "fout_dpll",
.id = -1,
.ctrlbit = (1 << 31),
};
/* VPLL clock output */
struct clk clk_fout_vpll = {
.name = "fout_vpll",
.id = -1,
.ctrlbit = (1 << 31),
};
/* Possible clock sources for APLL Mux */
static struct clk *clk_src_apll_list[] = {
[0] = &clk_fin_apll,
[1] = &clk_fout_apll,
};
struct clksrc_sources clk_src_apll = {
.sources = clk_src_apll_list,
.nr_sources = ARRAY_SIZE(clk_src_apll_list),
};
/* Possible clock sources for BPLL Mux */
static struct clk *clk_src_bpll_list[] = {
[0] = &clk_fin_bpll,
[1] = &clk_fout_bpll,
};
struct clksrc_sources clk_src_bpll = {
.sources = clk_src_bpll_list,
.nr_sources = ARRAY_SIZE(clk_src_bpll_list),
};
static struct clk *clk_src_bpll_fout_list[] = {
[0] = &clk_fout_bpll_div2,
[1] = &clk_fout_bpll,
};
struct clksrc_sources clk_src_bpll_fout = {
.sources = clk_src_bpll_fout_list,
.nr_sources = ARRAY_SIZE(clk_src_bpll_fout_list),
};
/* Possible clock sources for CPLL Mux */
static struct clk *clk_src_cpll_list[] = {
[0] = &clk_fin_cpll,
[1] = &clk_fout_cpll,
};
struct clksrc_sources clk_src_cpll = {
.sources = clk_src_cpll_list,
.nr_sources = ARRAY_SIZE(clk_src_cpll_list),
};
/* Possible clock sources for MPLL Mux */
static struct clk *clk_src_mpll_list[] = {
[0] = &clk_fin_mpll,
[1] = &clk_fout_mpll,
};
struct clksrc_sources clk_src_mpll = {
.sources = clk_src_mpll_list,
.nr_sources = ARRAY_SIZE(clk_src_mpll_list),
};
static struct clk *clk_src_mpll_fout_list[] = {
[0] = &clk_fout_mpll_div2,
[1] = &clk_fout_mpll,
};
struct clksrc_sources clk_src_mpll_fout = {
.sources = clk_src_mpll_fout_list,
.nr_sources = ARRAY_SIZE(clk_src_mpll_fout_list),
};
/* Possible clock sources for EPLL Mux */
static struct clk *clk_src_epll_list[] = {
[0] = &clk_fin_epll,
[1] = &clk_fout_epll,
};
struct clksrc_sources clk_src_epll = {
.sources = clk_src_epll_list,
.nr_sources = ARRAY_SIZE(clk_src_epll_list),
};
/* Possible clock sources for DPLL Mux */
static struct clk *clk_src_dpll_list[] = {
[0] = &clk_fin_dpll,
[1] = &clk_fout_dpll,
};
struct clksrc_sources clk_src_dpll = {
.sources = clk_src_dpll_list,
.nr_sources = ARRAY_SIZE(clk_src_dpll_list),
};
struct clk clk_vpll = {
.name = "vpll",
.id = -1,
};
int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable)
{
unsigned int ctrlbit = clk->ctrlbit;
u32 con;
con = __raw_readl(reg);
con = enable ? (con | ctrlbit) : (con & ~ctrlbit);
__raw_writel(con, reg);
return 0;
}
int s5p_epll_enable(struct clk *clk, int enable)
{
unsigned int ctrlbit = clk->ctrlbit;
unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
if (enable)
__raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
else
__raw_writel(epll_con, S5P_EPLL_CON);
return 0;
}
unsigned long s5p_epll_get_rate(struct clk *clk)
{
return clk->rate;
}
int s5p_spdif_set_rate(struct clk *clk, unsigned long rate)
{
struct clk *pclk;
int ret;
pclk = clk_get_parent(clk);
if (IS_ERR(pclk))
return -EINVAL;
ret = pclk->ops->set_rate(pclk, rate);
clk_put(pclk);
return ret;
}
unsigned long s5p_spdif_get_rate(struct clk *clk)
{
struct clk *pclk;
int rate;
pclk = clk_get_parent(clk);
if (IS_ERR(pclk))
return -EINVAL;
rate = pclk->ops->get_rate(pclk);
clk_put(pclk);
return rate;
}
struct clk_ops s5p_sclk_spdif_ops = {
.set_rate = s5p_spdif_set_rate,
.get_rate = s5p_spdif_get_rate,
};
static struct clk *s5p_clks[] __initdata = {
&clk_ext_xtal_mux,
&clk_48m,
&s5p_clk_27m,
&clk_fout_apll,
&clk_fout_mpll,
&clk_fout_epll,
&clk_fout_dpll,
&clk_fout_vpll,
&clk_vpll,
&clk_xusbxti,
};
void __init s5p_register_clocks(unsigned long xtal_freq)
{
int ret;
clk_ext_xtal_mux.rate = xtal_freq;
ret = s3c24xx_register_clocks(s5p_clks, ARRAY_SIZE(s5p_clks));
if (ret > 0)
printk(KERN_ERR "Failed to register s5p clocks\n");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment