Commit 93bc6b63 authored by Ben Dooks's avatar Ben Dooks

[ARM] S3C24XX: Split DCLK/CLKOUT definitions out of clock.c

Only certain boards need these clocks, and they are not
available on some CPUs (such as the S3C24A0) so remove
them from arch/arm/plat-s3c24xx/clock.c and into their
own file with appropriate Kconfig entries.
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
parent 74b265d4
...@@ -80,6 +80,7 @@ config ARCH_BAST ...@@ -80,6 +80,7 @@ config ARCH_BAST
select PM_SIMTEC if PM select PM_SIMTEC if PM
select SIMTEC_NOR select SIMTEC_NOR
select MACH_BAST_IDE select MACH_BAST_IDE
select S3C24XX_DCLK
select ISA select ISA
help help
Say Y here if you are using the Simtec Electronics EB2410ITX Say Y here if you are using the Simtec Electronics EB2410ITX
...@@ -117,6 +118,7 @@ config MACH_TCT_HAMMER ...@@ -117,6 +118,7 @@ config MACH_TCT_HAMMER
config MACH_VR1000 config MACH_VR1000
bool "Thorcom VR1000" bool "Thorcom VR1000"
select PM_SIMTEC if PM select PM_SIMTEC if PM
select S3C24XX_DCLK
select SIMTEC_NOR select SIMTEC_NOR
select MACH_BAST_IDE select MACH_BAST_IDE
select CPU_S3C2410 select CPU_S3C2410
......
...@@ -29,6 +29,7 @@ menu "S3C2440 Machines" ...@@ -29,6 +29,7 @@ menu "S3C2440 Machines"
config MACH_ANUBIS config MACH_ANUBIS
bool "Simtec Electronics ANUBIS" bool "Simtec Electronics ANUBIS"
select CPU_S3C2440 select CPU_S3C2440
select S3C24XX_DCLK
select PM_SIMTEC if PM select PM_SIMTEC if PM
select HAVE_PATA_PLATFORM select HAVE_PATA_PLATFORM
help help
...@@ -38,6 +39,7 @@ config MACH_ANUBIS ...@@ -38,6 +39,7 @@ config MACH_ANUBIS
config MACH_OSIRIS config MACH_OSIRIS
bool "Simtec IM2440D20 (OSIRIS) module" bool "Simtec IM2440D20 (OSIRIS) module"
select CPU_S3C2440 select CPU_S3C2440
select S3C24XX_DCLK
select PM_SIMTEC if PM select PM_SIMTEC if PM
help help
Say Y here if you are using the Simtec IM2440D20 module, also Say Y here if you are using the Simtec IM2440D20 module, also
......
...@@ -23,6 +23,11 @@ config S3C2410_CLOCK ...@@ -23,6 +23,11 @@ config S3C2410_CLOCK
Clock code for the S3C2410, and similar processors which Clock code for the S3C2410, and similar processors which
is currently includes the S3C2410, S3C2440, S3C2442. is currently includes the S3C2410, S3C2440, S3C2442.
config S3C24XX_DCLK
bool
help
Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
config CPU_S3C244X config CPU_S3C244X
bool bool
depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
......
...@@ -20,6 +20,7 @@ obj-y += gpiolib.o ...@@ -20,6 +20,7 @@ obj-y += gpiolib.o
obj-y += time.o obj-y += time.o
obj-y += clock.o obj-y += clock.o
obj-y += pwm-clock.o obj-y += pwm-clock.o
obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o
# Architecture dependant builds # Architecture dependant builds
......
/* linux/arch/arm/plat-s3c24xx/clock-dclk.c
*
* Copyright (c) 2004,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.
*
* S3C24XX - definitions for DCLK and CLKOUT registers
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/clock.h>
#include <plat/cpu.h>
/* clocks that could be registered by external code */
static int s3c24xx_dclk_enable(struct clk *clk, int enable)
{
unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (enable)
dclkcon |= clk->ctrlbit;
else
dclkcon &= ~clk->ctrlbit;
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
{
unsigned long dclkcon;
unsigned int uclk;
if (parent == &clk_upll)
uclk = 1;
else if (parent == &clk_p)
uclk = 0;
else
return -EINVAL;
clk->parent = parent;
dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
if (uclk)
dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
else
dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
} else {
if (uclk)
dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
else
dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
}
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
{
unsigned long div;
if ((rate == 0) || !clk->parent)
return 0;
div = clk_get_rate(clk->parent) / rate;
if (div < 2)
div = 2;
else if (div > 16)
div = 16;
return div;
}
static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
unsigned long rate)
{
unsigned long div = s3c24xx_calc_div(clk, rate);
if (div == 0)
return 0;
return clk_get_rate(clk->parent) / div;
}
static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
{
unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
if (div == 0)
return -EINVAL;
if (clk == &s3c24xx_dclk0) {
mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
S3C2410_DCLKCON_DCLK0_CMP_MASK;
data = S3C2410_DCLKCON_DCLK0_DIV(div) |
S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
} else if (clk == &s3c24xx_dclk1) {
mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
S3C2410_DCLKCON_DCLK1_CMP_MASK;
data = S3C2410_DCLKCON_DCLK1_DIV(div) |
S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
} else
return -EINVAL;
clk->rate = clk_get_rate(clk->parent) / div;
__raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
S3C24XX_DCLKCON);
return clk->rate;
}
static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
{
unsigned long mask;
unsigned long source;
/* calculate the MISCCR setting for the clock */
if (parent == &clk_xtal)
source = S3C2410_MISCCR_CLK0_MPLL;
else if (parent == &clk_upll)
source = S3C2410_MISCCR_CLK0_UPLL;
else if (parent == &clk_f)
source = S3C2410_MISCCR_CLK0_FCLK;
else if (parent == &clk_h)
source = S3C2410_MISCCR_CLK0_HCLK;
else if (parent == &clk_p)
source = S3C2410_MISCCR_CLK0_PCLK;
else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
source = S3C2410_MISCCR_CLK0_DCLK0;
else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
source = S3C2410_MISCCR_CLK0_DCLK0;
else
return -EINVAL;
clk->parent = parent;
if (clk == &s3c24xx_clkout0)
mask = S3C2410_MISCCR_CLK0_MASK;
else {
source <<= 4;
mask = S3C2410_MISCCR_CLK1_MASK;
}
s3c2410_modify_misccr(mask, source);
return 0;
}
/* external clock definitions */
struct clk s3c24xx_dclk0 = {
.name = "dclk0",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK0EN,
.enable = s3c24xx_dclk_enable,
.set_parent = s3c24xx_dclk_setparent,
.set_rate = s3c24xx_set_dclk_rate,
.round_rate = s3c24xx_round_dclk_rate,
};
struct clk s3c24xx_dclk1 = {
.name = "dclk1",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK1EN,
.enable = s3c24xx_dclk_enable,
.set_parent = s3c24xx_dclk_setparent,
.set_rate = s3c24xx_set_dclk_rate,
.round_rate = s3c24xx_round_dclk_rate,
};
struct clk s3c24xx_clkout0 = {
.name = "clkout0",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_clkout1 = {
.name = "clkout1",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
...@@ -283,178 +283,7 @@ struct clk clk_usb_bus = { ...@@ -283,178 +283,7 @@ struct clk clk_usb_bus = {
.parent = &clk_upll, .parent = &clk_upll,
}; };
/* clocks that could be registered by external code */
static int s3c24xx_dclk_enable(struct clk *clk, int enable)
{
unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (enable)
dclkcon |= clk->ctrlbit;
else
dclkcon &= ~clk->ctrlbit;
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
{
unsigned long dclkcon;
unsigned int uclk;
if (parent == &clk_upll)
uclk = 1;
else if (parent == &clk_p)
uclk = 0;
else
return -EINVAL;
clk->parent = parent;
dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
if (uclk)
dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
else
dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
} else {
if (uclk)
dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
else
dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
}
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
{
unsigned long div;
if ((rate == 0) || !clk->parent)
return 0;
div = clk_get_rate(clk->parent) / rate;
if (div < 2)
div = 2;
else if (div > 16)
div = 16;
return div;
}
static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
unsigned long rate)
{
unsigned long div = s3c24xx_calc_div(clk, rate);
if (div == 0)
return 0;
return clk_get_rate(clk->parent) / div;
}
static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
{
unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
if (div == 0)
return -EINVAL;
if (clk == &s3c24xx_dclk0) {
mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
S3C2410_DCLKCON_DCLK0_CMP_MASK;
data = S3C2410_DCLKCON_DCLK0_DIV(div) |
S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
} else if (clk == &s3c24xx_dclk1) {
mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
S3C2410_DCLKCON_DCLK1_CMP_MASK;
data = S3C2410_DCLKCON_DCLK1_DIV(div) |
S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
} else
return -EINVAL;
clk->rate = clk_get_rate(clk->parent) / div;
__raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
S3C24XX_DCLKCON);
return clk->rate;
}
static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
{
unsigned long mask;
unsigned long source;
/* calculate the MISCCR setting for the clock */
if (parent == &clk_xtal)
source = S3C2410_MISCCR_CLK0_MPLL;
else if (parent == &clk_upll)
source = S3C2410_MISCCR_CLK0_UPLL;
else if (parent == &clk_f)
source = S3C2410_MISCCR_CLK0_FCLK;
else if (parent == &clk_h)
source = S3C2410_MISCCR_CLK0_HCLK;
else if (parent == &clk_p)
source = S3C2410_MISCCR_CLK0_PCLK;
else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
source = S3C2410_MISCCR_CLK0_DCLK0;
else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
source = S3C2410_MISCCR_CLK0_DCLK0;
else
return -EINVAL;
clk->parent = parent;
if (clk == &s3c24xx_clkout0)
mask = S3C2410_MISCCR_CLK0_MASK;
else {
source <<= 4;
mask = S3C2410_MISCCR_CLK1_MASK;
}
s3c2410_modify_misccr(mask, source);
return 0;
}
/* external clock definitions */
struct clk s3c24xx_dclk0 = {
.name = "dclk0",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK0EN,
.enable = s3c24xx_dclk_enable,
.set_parent = s3c24xx_dclk_setparent,
.set_rate = s3c24xx_set_dclk_rate,
.round_rate = s3c24xx_round_dclk_rate,
};
struct clk s3c24xx_dclk1 = {
.name = "dclk1",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK1EN,
.enable = s3c24xx_dclk_enable,
.set_parent = s3c24xx_dclk_setparent,
.set_rate = s3c24xx_set_dclk_rate,
.round_rate = s3c24xx_round_dclk_rate,
};
struct clk s3c24xx_clkout0 = {
.name = "clkout0",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_clkout1 = {
.name = "clkout1",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_uclk = { struct clk s3c24xx_uclk = {
.name = "uclk", .name = "uclk",
......
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