Commit f25b6a27 authored by Ben Dooks's avatar Ben Dooks Committed by Russell King

[ARM PATCH] 2508/1: S3C2440 - timer and irq device updates

Patch from Ben Dooks

The patch does a number of updates, which are inter-dependant
on each other, for the s3c2440 support and some clean-ups for
all s3c24xx architecture in general.
1) Remove the s3c24xx_{fclk,hclk,pclk} variables, and pass
   these values to the clock core on initialisation. This
   removes the needless double copy, as only the timer code
   uses these directly (see point 4).
   Add an over-all xtal clock to the clock core
2) Add a sysdev driver to the clock code to ensure all the
   s3c2440 clocks are added if an s3c2440 is present.
3) Add the new IRQs to irq.c, and initialise them if the
   sysdev for the s3c2440 is present.
4) Change the timer code to request the timer clk and
   use it to get the frequency.
Depends on patch 2467/1
Thanks to Guillaume Gourat for the original patches that
prompted this re-write.

Signed-off-by: Ben Dooks
Signed-off-by: Russell King
parent cd4ad67d
/* linux/arch/arm/mach-s3c2410/clock.c /* linux/arch/arm/mach-s3c2410/clock.c
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
* S3C2410 Clock control support * S3C2410 Clock control support
* *
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -46,18 +47,13 @@ ...@@ -46,18 +47,13 @@
#include <asm/arch/regs-clock.h> #include <asm/arch/regs-clock.h>
#include "clock.h" #include "clock.h"
#include "cpu.h"
/* clock information */ /* clock information */
unsigned long s3c24xx_xtal = 12*1000*1000; /* default 12MHz */
unsigned long s3c24xx_fclk;
unsigned long s3c24xx_hclk;
unsigned long s3c24xx_pclk;
static LIST_HEAD(clocks); static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem); static DECLARE_MUTEX(clocks_sem);
/* old functions */ /* old functions */
void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable) void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
...@@ -206,6 +202,14 @@ EXPORT_SYMBOL(clk_get_parent); ...@@ -206,6 +202,14 @@ EXPORT_SYMBOL(clk_get_parent);
/* base clocks */ /* base clocks */
static struct clk clk_xtal = {
.name = "xtal",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
static struct clk clk_f = { static struct clk clk_f = {
.name = "fclk", .name = "fclk",
.id = -1, .id = -1,
...@@ -286,6 +290,7 @@ static struct clk init_clocks[] = { ...@@ -286,6 +290,7 @@ static struct clk init_clocks[] = {
.ctrlbit = S3C2410_CLKCON_USBD .ctrlbit = S3C2410_CLKCON_USBD
}, },
{ .name = "timers", { .name = "timers",
.id = -1,
.parent = &clk_p, .parent = &clk_p,
.enable = s3c24xx_clkcon_enable, .enable = s3c24xx_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_PWMT .ctrlbit = S3C2410_CLKCON_PWMT
...@@ -378,19 +383,24 @@ int s3c24xx_register_clock(struct clk *clk) ...@@ -378,19 +383,24 @@ int s3c24xx_register_clock(struct clk *clk)
/* initalise all the clocks */ /* initalise all the clocks */
int __init s3c24xx_setup_clocks(void) int __init s3c24xx_setup_clocks(unsigned long xtal,
unsigned long fclk,
unsigned long hclk,
unsigned long pclk)
{ {
struct clk *clkp = init_clocks; struct clk *clkp = init_clocks;
int ptr; int ptr;
int ret; int ret;
printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n"); printk(KERN_INFO "S3C2410 Clocks, (c) 2004 Simtec Electronics\n");
/* initialise the main system clocks */ /* initialise the main system clocks */
clk_h.rate = s3c24xx_hclk; clk_xtal.rate = xtal;
clk_p.rate = s3c24xx_pclk;
clk_f.rate = s3c24xx_fclk; clk_h.rate = hclk;
clk_p.rate = pclk;
clk_f.rate = fclk;
/* it looks like just setting the register here is not good /* it looks like just setting the register here is not good
* enough, and causes the odd hang at initial boot time, so * enough, and causes the odd hang at initial boot time, so
...@@ -414,6 +424,9 @@ int __init s3c24xx_setup_clocks(void) ...@@ -414,6 +424,9 @@ int __init s3c24xx_setup_clocks(void)
/* register our clocks */ /* register our clocks */
if (s3c24xx_register_clock(&clk_xtal) < 0)
printk(KERN_ERR "failed to register master xtal\n");
if (s3c24xx_register_clock(&clk_f) < 0) if (s3c24xx_register_clock(&clk_f) < 0)
printk(KERN_ERR "failed to register cpu fclk\n"); printk(KERN_ERR "failed to register cpu fclk\n");
...@@ -423,6 +436,8 @@ int __init s3c24xx_setup_clocks(void) ...@@ -423,6 +436,8 @@ int __init s3c24xx_setup_clocks(void)
if (s3c24xx_register_clock(&clk_p) < 0) if (s3c24xx_register_clock(&clk_p) < 0)
printk(KERN_ERR "failed to register cpu pclk\n"); printk(KERN_ERR "failed to register cpu pclk\n");
/* register clocks from clock array */
for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
ret = s3c24xx_register_clock(clkp); ret = s3c24xx_register_clock(clkp);
if (ret < 0) { if (ret < 0) {
...@@ -434,4 +449,59 @@ int __init s3c24xx_setup_clocks(void) ...@@ -434,4 +449,59 @@ int __init s3c24xx_setup_clocks(void)
return 0; return 0;
} }
/* S3C2440 extended clock support */
#ifdef CONFIG_CPU_S3C2440
static struct clk s3c2440_clk_upll = {
.name = "upll",
.id = -1,
};
static struct clk s3c2440_clk_cam = {
.name = "camif",
.parent = &clk_h,
.id = -1,
.enable = s3c24xx_clkcon_enable,
.ctrlbit = S3C2440_CLKCON_CAMERA,
};
static struct clk s3c2440_clk_ac97 = {
.name = "ac97",
.parent = &clk_p,
.id = -1,
.enable = s3c24xx_clkcon_enable,
.ctrlbit = S3C2440_CLKCON_CAMERA,
};
static int s3c2440_clk_add(struct sys_device *sysdev)
{
unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2;
printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
print_mhz(s3c2440_clk_upll.rate));
s3c24xx_register_clock(&s3c2440_clk_ac97);
s3c24xx_register_clock(&s3c2440_clk_cam);
s3c24xx_register_clock(&s3c2440_clk_upll);
clk_disable(&s3c2440_clk_ac97);
clk_disable(&s3c2440_clk_cam);
return 0;
}
static struct sysdev_driver s3c2440_clk_driver = {
.add = s3c2440_clk_add,
};
static int s3c24xx_clk_driver(void)
{
return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
}
arch_initcall(s3c24xx_clk_driver);
#endif /* CONFIG_CPU_S3C2440 */
/* /*
* linux/arch/arm/mach-s3c2410/clock.h * linux/arch/arm/mach-s3c2410/clock.h
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* http://www.simtec.co.uk/products/SWLINUX/
* Written by Ben Dooks, <ben@simtec.co.uk> * Written by Ben Dooks, <ben@simtec.co.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -29,13 +30,6 @@ extern struct clk s3c24xx_clkout0; ...@@ -29,13 +30,6 @@ extern struct clk s3c24xx_clkout0;
extern struct clk s3c24xx_clkout1; extern struct clk s3c24xx_clkout1;
extern struct clk s3c24xx_uclk; extern struct clk s3c24xx_uclk;
/* processor clock settings, in Hz */
extern unsigned long s3c24xx_xtal;
extern unsigned long s3c24xx_pclk;
extern unsigned long s3c24xx_hclk;
extern unsigned long s3c24xx_fclk;
/* exports for arch/arm/mach-s3c2410 /* exports for arch/arm/mach-s3c2410
* *
* Please DO NOT use these outside of arch/arm/mach-s3c2410 * Please DO NOT use these outside of arch/arm/mach-s3c2410
...@@ -44,4 +38,7 @@ extern unsigned long s3c24xx_fclk; ...@@ -44,4 +38,7 @@ extern unsigned long s3c24xx_fclk;
extern int s3c24xx_clkcon_enable(struct clk *clk, int enable); extern int s3c24xx_clkcon_enable(struct clk *clk, int enable);
extern int s3c24xx_register_clock(struct clk *clk); extern int s3c24xx_register_clock(struct clk *clk);
extern int s3c24xx_setup_clocks(void); extern int s3c24xx_setup_clocks(unsigned long xtal,
unsigned long fclk,
unsigned long hclk,
unsigned long pclk);
/* linux/arch/arm/mach-s3c2410/cpu.c /* linux/arch/arm/mach-s3c2410/cpu.c
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * http://www.simtec.co.uk/products/SWLINUX/
* Ben Dooks <ben@simtec.co.uk>
* *
* S3C24XX CPU Support * S3C24XX CPU Support
* *
...@@ -181,8 +182,8 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) ...@@ -181,8 +182,8 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
void __init s3c24xx_init_clocks(int xtal) void __init s3c24xx_init_clocks(int xtal)
{ {
if (xtal != 0) if (xtal == 0)
s3c24xx_xtal = xtal; xtal = 12*1000*1000;
if (cpu == NULL) if (cpu == NULL)
panic("s3c24xx_init_clocks: no cpu setup?\n"); panic("s3c24xx_init_clocks: no cpu setup?\n");
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
/* forward declaration */ /* forward declaration */
struct s3c2410_uartcfg; struct s3c2410_uartcfg;
struct map_desc;
/* core initialisation functions */ /* core initialisation functions */
...@@ -58,3 +59,7 @@ extern void s3c24xx_set_board(struct s3c24xx_board *board); ...@@ -58,3 +59,7 @@ extern void s3c24xx_set_board(struct s3c24xx_board *board);
struct sys_timer; struct sys_timer;
extern struct sys_timer s3c24xx_timer; extern struct sys_timer s3c24xx_timer;
/* system device classes */
extern struct sysdev_class s3c2440_sysclass;
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <asm/arch/regs-irq.h> #include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "cpu.h"
#include "pm.h" #include "pm.h"
#define irqdbf(x...) #define irqdbf(x...)
...@@ -628,6 +629,7 @@ s3c_irq_demux_uart2(unsigned int irq, ...@@ -628,6 +629,7 @@ s3c_irq_demux_uart2(unsigned int irq,
s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
} }
/* s3c24xx_init_irq /* s3c24xx_init_irq
* *
* Initialise S3C2410 IRQ system * Initialise S3C2410 IRQ system
...@@ -771,3 +773,174 @@ void __init s3c24xx_init_irq(void) ...@@ -771,3 +773,174 @@ void __init s3c24xx_init_irq(void)
irqdbf("s3c2410: registered interrupt handlers\n"); irqdbf("s3c2410: registered interrupt handlers\n");
} }
/* s3c2440 irq code
*/
#ifdef CONFIG_CPU_S3C2440
/* WDT/AC97 */
static void s3c_irq_demux_wdtac97(unsigned int irq,
struct irqdesc *desc,
struct pt_regs *regs)
{
unsigned int subsrc, submsk;
struct irqdesc *mydesc;
/* read the current pending interrupts, and the mask
* for what it is available */
subsrc = __raw_readl(S3C2410_SUBSRCPND);
submsk = __raw_readl(S3C2410_INTSUBMSK);
subsrc &= ~submsk;
subsrc >>= 13;
subsrc &= 3;
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_S3C2440_WDT;
mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_S3C2440_AC97;
mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
}
}
}
#define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0))
static void
s3c_irq_wdtac97_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13);
}
static void
s3c_irq_wdtac97_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_WDT);
}
static void
s3c_irq_wdtac97_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13);
}
static struct irqchip s3c_irq_wdtac97 = {
.mask = s3c_irq_wdtac97_mask,
.unmask = s3c_irq_wdtac97_unmask,
.ack = s3c_irq_wdtac97_ack,
};
/* camera irq */
static void s3c_irq_demux_cam(unsigned int irq,
struct irqdesc *desc,
struct pt_regs *regs)
{
unsigned int subsrc, submsk;
struct irqdesc *mydesc;
/* read the current pending interrupts, and the mask
* for what it is available */
subsrc = __raw_readl(S3C2410_SUBSRCPND);
submsk = __raw_readl(S3C2410_INTSUBMSK);
subsrc &= ~submsk;
subsrc >>= 11;
subsrc &= 3;
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_S3C2440_CAM_C;
mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_S3C2440_CAM_P;
mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
}
}
}
#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
static void
s3c_irq_cam_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
}
static void
s3c_irq_cam_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_CAM);
}
static void
s3c_irq_cam_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
}
static struct irqchip s3c_irq_cam = {
.mask = s3c_irq_cam_mask,
.unmask = s3c_irq_cam_unmask,
.ack = s3c_irq_cam_ack,
};
static int s3c2440_irq_add(struct sys_device *sysdev)
{
unsigned int irqno;
printk("S3C2440: IRQ Support\n");
set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
set_irq_handler(IRQ_NFCON, do_level_IRQ);
set_irq_flags(IRQ_NFCON, IRQF_VALID);
/* add new chained handler for wdt, ac7 */
set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
set_irq_handler(IRQ_WDT, do_level_IRQ);
set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97);
for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) {
set_irq_chip(irqno, &s3c_irq_wdtac97);
set_irq_handler(irqno, do_level_IRQ);
set_irq_flags(irqno, IRQF_VALID);
}
/* add chained handler for camera */
set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
set_irq_handler(IRQ_CAM, do_level_IRQ);
set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
set_irq_chip(irqno, &s3c_irq_cam);
set_irq_handler(irqno, do_level_IRQ);
set_irq_flags(irqno, IRQF_VALID);
}
return 0;
}
static struct sysdev_driver s3c2440_irq_driver = {
.add = s3c2440_irq_add,
};
static int s3c24xx_irq_driver(void)
{
return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
}
arch_initcall(s3c24xx_irq_driver);
#endif /* CONFIG_CPU_S3C2440 */
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* 21-Aug-2004 BJD Added new struct s3c2410_board handler * 21-Aug-2004 BJD Added new struct s3c2410_board handler
* 28-Sep-2004 BJD Updates for new serial port bits * 28-Sep-2004 BJD Updates for new serial port bits
* 04-Nov-2004 BJD Updated UART configuration process * 04-Nov-2004 BJD Updated UART configuration process
* 10-Jan-2004 BJD Removed s3c2410_clock_tick_rate * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -164,31 +164,32 @@ void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size) ...@@ -164,31 +164,32 @@ void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)
void __init s3c2410_init_clocks(int xtal) void __init s3c2410_init_clocks(int xtal)
{ {
unsigned long tmp; unsigned long tmp;
unsigned long fclk;
unsigned long hclk;
unsigned long pclk;
/* now we've got our machine bits initialised, work out what /* now we've got our machine bits initialised, work out what
* clocks we've got */ * clocks we've got */
s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
s3c24xx_xtal);
tmp = __raw_readl(S3C2410_CLKDIVN); tmp = __raw_readl(S3C2410_CLKDIVN);
/* work out clock scalings */ /* work out clock scalings */
s3c24xx_hclk = s3c24xx_fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1); hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
s3c24xx_pclk = s3c24xx_hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1); pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
/* print brieft summary of clocks, etc */ /* print brieft summary of clocks, etc */
printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk), print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
print_mhz(s3c24xx_pclk));
/* initialise the clocks here, to allow other things like the /* initialise the clocks here, to allow other things like the
* console to use them * console to use them
*/ */
s3c24xx_setup_clocks(); s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
} }
int __init s3c2410_init(void) int __init s3c2410_init(void)
......
...@@ -109,7 +109,6 @@ static struct platform_device s3c_uart0 = { ...@@ -109,7 +109,6 @@ static struct platform_device s3c_uart0 = {
.resource = s3c_uart0_resource, .resource = s3c_uart0_resource,
}; };
static struct platform_device s3c_uart1 = { static struct platform_device s3c_uart1 = {
.name = "s3c2440-uart", .name = "s3c2440-uart",
.id = 1, .id = 1,
...@@ -149,19 +148,6 @@ void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no) ...@@ -149,19 +148,6 @@ void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
s3c2440_uart_count = uart; s3c2440_uart_count = uart;
} }
/* s3c2440 specific clock sources */
static struct clk s3c2440_clk_cam = {
.name = "camera",
.enable = s3c24xx_clkcon_enable,
.ctrlbit = S3C2440_CLKCON_CAMERA
};
static struct clk s3c2440_clk_ac97 = {
.name = "ac97",
.enable = s3c24xx_clkcon_enable,
.ctrlbit = S3C2440_CLKCON_CAMERA
};
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -190,7 +176,7 @@ static int s3c2440_resume(struct sys_device *dev) ...@@ -190,7 +176,7 @@ static int s3c2440_resume(struct sys_device *dev)
#define s3c2440_resume NULL #define s3c2440_resume NULL
#endif #endif
static struct sysdev_class s3c2440_sysclass = { struct sysdev_class s3c2440_sysclass = {
set_kset_name("s3c2440-core"), set_kset_name("s3c2440-core"),
.suspend = s3c2440_suspend, .suspend = s3c2440_suspend,
.resume = s3c2440_resume .resume = s3c2440_resume
...@@ -209,19 +195,24 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size) ...@@ -209,19 +195,24 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
/* rename any peripherals used differing from the s3c2410 */ /* rename any peripherals used differing from the s3c2410 */
s3c_device_i2c.name = "s3c2440-i2c"; s3c_device_i2c.name = "s3c2440-i2c";
/* change irq for watchdog */
s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
} }
void __init s3c2440_init_clocks(int xtal) void __init s3c2440_init_clocks(int xtal)
{ {
unsigned long clkdiv; unsigned long clkdiv;
unsigned long camdiv; unsigned long camdiv;
int s3c2440_hdiv = 1; unsigned long hclk, fclk, pclk;
int hdiv = 1;
/* now we've got our machine bits initialised, work out what /* now we've got our machine bits initialised, work out what
* clocks we've got */ * clocks we've got */
s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
s3c24xx_xtal) * 2;
clkdiv = __raw_readl(S3C2410_CLKDIVN); clkdiv = __raw_readl(S3C2410_CLKDIVN);
camdiv = __raw_readl(S3C2440_CAMDIVN); camdiv = __raw_readl(S3C2440_CAMDIVN);
...@@ -230,63 +221,60 @@ void __init s3c2440_init_clocks(int xtal) ...@@ -230,63 +221,60 @@ void __init s3c2440_init_clocks(int xtal)
switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) { switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
case S3C2440_CLKDIVN_HDIVN_1: case S3C2440_CLKDIVN_HDIVN_1:
s3c2440_hdiv = 1; hdiv = 1;
break; break;
case S3C2440_CLKDIVN_HDIVN_2: case S3C2440_CLKDIVN_HDIVN_2:
s3c2440_hdiv = 1; hdiv = 1;
break; break;
case S3C2440_CLKDIVN_HDIVN_4_8: case S3C2440_CLKDIVN_HDIVN_4_8:
s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4; hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
break; break;
case S3C2440_CLKDIVN_HDIVN_3_6: case S3C2440_CLKDIVN_HDIVN_3_6:
s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3; hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
break; break;
} }
s3c24xx_hclk = s3c24xx_fclk / s3c2440_hdiv; hclk = fclk / hdiv;
s3c24xx_pclk = s3c24xx_hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1); pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
/* print brief summary of clocks, etc */ /* print brief summary of clocks, etc */
printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk), print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
print_mhz(s3c24xx_pclk));
/* initialise the clocks here, to allow other things like the /* initialise the clocks here, to allow other things like the
* console to use them, and to add new ones after the initialisation * console to use them, and to add new ones after the initialisation
*/ */
s3c24xx_setup_clocks(); s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
}
/* add s3c2440 specific clocks */
s3c2440_clk_cam.parent = clk_get(NULL, "hclk");
s3c2440_clk_ac97.parent = clk_get(NULL, "pclk");
s3c24xx_register_clock(&s3c2440_clk_ac97); /* need to register class before we actually register the device, and
s3c24xx_register_clock(&s3c2440_clk_cam); * 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 s3c2440 based system)
* as a driver which may support both 2410 and 2440 may try and use it.
*/
clk_disable(&s3c2440_clk_ac97); int __init s3c2440_core_init(void)
clk_disable(&s3c2440_clk_cam); {
return sysdev_class_register(&s3c2440_sysclass);
} }
core_initcall(s3c2440_core_init);
int __init s3c2440_init(void) int __init s3c2440_init(void)
{ {
int ret; int ret;
printk("S3C2440: Initialising architecture\n"); printk("S3C2440: Initialising architecture\n");
ret = sysdev_class_register(&s3c2440_sysclass); ret = sysdev_register(&s3c2440_sysdev);
if (ret == 0)
ret = sysdev_register(&s3c2440_sysdev);
if (ret != 0) if (ret != 0)
printk(KERN_ERR "failed to register sysdev for s3c2440\n"); printk(KERN_ERR "failed to register sysdev for s3c2440\n");
else
if (ret == 0)
ret = platform_add_devices(s3c24xx_uart_devs, s3c2440_uart_count); ret = platform_add_devices(s3c24xx_uart_devs, s3c2440_uart_count);
return ret; return ret;
......
/* linux/arch/arm/mach-s3c2410/time.c /* linux/arch/arm/mach-s3c2410/time.c
* *
* Copyright (C) 2003,2004 Simtec Electronics * Copyright (C) 2003-2005 Simtec Electronics
* Ben Dooks, <ben@simtec.co.uk> * Ben Dooks, <ben@simtec.co.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/err.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/leds.h> #include <asm/leds.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -33,6 +35,7 @@ ...@@ -33,6 +35,7 @@
#include <asm/arch/regs-timer.h> #include <asm/arch/regs-timer.h>
#include <asm/arch/regs-irq.h> #include <asm/arch/regs-irq.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/hardware/clock.h>
#include "clock.h" #include "clock.h"
...@@ -169,6 +172,9 @@ static void s3c2410_timer_setup (void) ...@@ -169,6 +172,9 @@ static void s3c2410_timer_setup (void)
tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
} else { } else {
unsigned long pclk;
struct clk *clk;
/* for the h1940 (and others), we use the pclk from the core /* for the h1940 (and others), we use the pclk from the core
* to generate the timer values. since values around 50 to * to generate the timer values. since values around 50 to
* 70MHz are not values we can directly generate the timer * 70MHz are not values we can directly generate the timer
...@@ -180,7 +186,18 @@ static void s3c2410_timer_setup (void) ...@@ -180,7 +186,18 @@ static void s3c2410_timer_setup (void)
/* this is used as default if no other timer can be found */ /* this is used as default if no other timer can be found */
timer_usec_ticks = timer_mask_usec_ticks(6, s3c24xx_pclk); clk = clk_get(NULL, "timers");
if (IS_ERR(clk))
panic("failed to get clock for system timer");
clk_use(clk);
clk_enable(clk);
pclk = clk_get_rate(clk);
/* configure clock tick */
timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
tcfg1 |= S3C2410_TCFG1_MUX4_DIV2; tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
...@@ -188,7 +205,7 @@ static void s3c2410_timer_setup (void) ...@@ -188,7 +205,7 @@ static void s3c2410_timer_setup (void)
tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
tcnt = (s3c24xx_pclk / 6) / HZ; tcnt = (pclk / 6) / HZ;
} }
/* timers reload after counting zero, so reduce the count by 1 */ /* timers reload after counting zero, so reduce the count by 1 */
......
/* linux/include/asm-arm/arch-s3c2410/irqs.h /* linux/include/asm-arm/arch-s3c2410/irqs.h
* *
* Copyright (c) 2003 Simtec Electronics * Copyright (c) 2003-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* 08-Jan-2003 BJD Linux 2.6.0 version, moved BAST bits out * 08-Jan-2003 BJD Linux 2.6.0 version, moved BAST bits out
* 12-Mar-2004 BJD Fixed bug in header protection * 12-Mar-2004 BJD Fixed bug in header protection
* 10-Feb-2005 BJD Added camera IRQ from guillaume.gourat@nexvision.tv * 10-Feb-2005 BJD Added camera IRQ from guillaume.gourat@nexvision.tv
* 28-Feb-2005 BJD Updated s3c2440 IRQs
*/ */
...@@ -36,8 +37,8 @@ ...@@ -36,8 +37,8 @@
#define IRQ_EINT3 S3C2410_IRQ(3) #define IRQ_EINT3 S3C2410_IRQ(3)
#define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */ #define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */
#define IRQ_EINT8t23 S3C2410_IRQ(5) #define IRQ_EINT8t23 S3C2410_IRQ(5)
#define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */ #define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */
#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440 */ #define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440 */
#define IRQ_BATT_FLT S3C2410_IRQ(7) #define IRQ_BATT_FLT S3C2410_IRQ(7)
#define IRQ_TICK S3C2410_IRQ(8) /* 24 */ #define IRQ_TICK S3C2410_IRQ(8) /* 24 */
#define IRQ_WDT S3C2410_IRQ(9) #define IRQ_WDT S3C2410_IRQ(9)
...@@ -56,6 +57,7 @@ ...@@ -56,6 +57,7 @@
#define IRQ_SPI0 S3C2410_IRQ(22) #define IRQ_SPI0 S3C2410_IRQ(22)
#define IRQ_UART1 S3C2410_IRQ(23) #define IRQ_UART1 S3C2410_IRQ(23)
#define IRQ_RESERVED24 S3C2410_IRQ(24) /* 40 */ #define IRQ_RESERVED24 S3C2410_IRQ(24) /* 40 */
#define IRQ_NFCON S3C2410_IRQ(24) /* for s3c2440 */
#define IRQ_USBD S3C2410_IRQ(25) #define IRQ_USBD S3C2410_IRQ(25)
#define IRQ_USBH S3C2410_IRQ(26) #define IRQ_USBH S3C2410_IRQ(26)
#define IRQ_IIC S3C2410_IRQ(27) #define IRQ_IIC S3C2410_IRQ(27)
...@@ -111,7 +113,14 @@ ...@@ -111,7 +113,14 @@
#define IRQ_TC S3C2410_IRQ(63) #define IRQ_TC S3C2410_IRQ(63)
#define IRQ_ADC S3C2410_IRQ(64) #define IRQ_ADC S3C2410_IRQ(64)
#define NR_IRQS (IRQ_ADC+1) /* extra irqs for s3c2440 */
#define IRQ_S3C2440_CAM_C S3C2410_IRQ(65)
#define IRQ_S3C2440_CAM_P S3C2410_IRQ(66)
#define IRQ_S3C2440_WDT S3C2410_IRQ(67)
#define IRQ_S3C2440_AC97 S3C2410_IRQ(68)
#define NR_IRQS (IRQ_S3C2440_AC97+1)
#endif /* __ASM_ARCH_IRQ_H */ #endif /* __ASM_ARCH_IRQ_H */
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