Commit 10c37e7c authored by Ben Dooks's avatar Ben Dooks Committed by Russell King

[ARM PATCH] 1995/1: S3C2410 - Clock controls

Patch from Ben Dooks

Code to deal with controlling the clock sources
on the s3c2410, using the <arch/hardware/clocks.h>
interface

Includes Herbert Potzl's patch for the clock register
include file
parent 9c496bde
......@@ -4,7 +4,7 @@
# Object file lists.
obj-y := s3c2410.o irq.o time.o gpio.o
obj-y := s3c2410.o irq.o time.o gpio.o clock.o
obj-m :=
obj-n :=
obj- :=
......
/* linux/arch/arm/mach-s3c2410/gpio.c
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 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/interrupt.h>
#include <linux/ioport.h>
#include <asm/hardware.h>
#include <asm/atomic.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/hardware/clock.h>
#include <asm/arch/regs-clock.h>
#include "clock.h"
static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
/* old functions */
void s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
{
unsigned long clkcon;
unsigned long flags;
local_irq_save(flags);
clkcon = __raw_readl(S3C2410_CLKCON);
clkcon &= ~clocks;
if (enable)
clkcon |= clocks;
__raw_writel(clkcon, S3C2410_CLKCON);
local_irq_restore(flags);
}
/* Clock API calls */
struct clk *clk_get(struct device *dev, const char *id)
{
struct clk *p;
struct clk *clk = ERR_PTR(-ENOENT);
down(&clocks_sem);
list_for_each_entry(p, &clocks, list) {
if (strcmp(id, p->name) == 0 &&
try_module_get(p->owner)) {
clk = p;
break;
}
}
up(&clocks_sem);
return clk;
}
void clk_put(struct clk *clk)
{
module_put(clk->owner);
}
int clk_enable(struct clk *clk)
{
s3c2410_clk_enable(clk->ctrlbit, 1);
return 0;
}
void clk_disable(struct clk *clk)
{
s3c2410_clk_enable(clk->ctrlbit, 0);
}
int clk_use(struct clk *clk)
{
atomic_inc(&clk->used);
return 0;
}
void clk_unuse(struct clk *clk)
{
atomic_dec(&clk->used);
}
unsigned long clk_get_rate(struct clk *clk)
{
if (clk->parent != NULL)
return clk->parent->rate;
return clk->rate;
}
long clk_round_rate(struct clk *clk, unsigned long rate)
{
return rate;
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
return -EINVAL;
}
struct clk *clk_get_parent(struct clk *clk)
{
return clk->parent;
}
EXPORT_SYMBOL(clk_get);
EXPORT_SYMBOL(clk_put);
EXPORT_SYMBOL(clk_enable);
EXPORT_SYMBOL(clk_disable);
EXPORT_SYMBOL(clk_use);
EXPORT_SYMBOL(clk_unuse);
EXPORT_SYMBOL(clk_get_rate);
EXPORT_SYMBOL(clk_round_rate);
EXPORT_SYMBOL(clk_set_rate);
EXPORT_SYMBOL(clk_get_parent);
/* base clocks */
static struct clk clk_f = {
.name = "fclk",
.rate = 0,
.parent = NULL,
.ctrlbit = 0
};
static struct clk clk_h = {
.name = "hclk",
.rate = 0,
.parent = NULL,
.ctrlbit = 0
};
static struct clk clk_p = {
.name = "pclk",
.rate = 0,
.parent = NULL,
.ctrlbit = 0
};
/* clock definitions */
static struct clk init_clocks[] = {
{ .name = "nand",
.parent = &clk_h,
.ctrlbit = S3C2410_CLKCON_NAND
},
{ .name = "lcd",
.parent = &clk_h,
.ctrlbit = S3C2410_CLKCON_LCDC
},
{ .name = "usb-host",
.parent = &clk_h,
.ctrlbit = S3C2410_CLKCON_USBH
},
{ .name = "usb-device",
.parent = &clk_h,
.ctrlbit = S3C2410_CLKCON_USBD
},
{ .name = "timers",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_PWMT
},
{ .name = "sdi",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_SDI
},
{ .name = "uart0",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_UART0
},
{ .name = "uart1",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_UART1
},
{ .name = "uart2",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_UART2
},
{ .name = "gpio",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_GPIO
},
{ .name = "rtc",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_RTC
},
{ .name = "adc",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_ADC
},
{ .name = "i2c",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_IIC
},
{ .name = "iis",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_IIS
},
{ .name = "spi",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_SPI
}
};
/* initialise the clock system */
int s3c2410_register_clock(struct clk *clk)
{
clk->owner = THIS_MODULE;
atomic_set(&clk->used, 0);
/* add to the list of available clocks */
down(&clocks_sem);
list_add(&clk->list, &clocks);
up(&clocks_sem);
return 0;
}
/* initalise all the clocks */
static int __init s3c2410_init_clocks(void)
{
struct clk *clkp = init_clocks;
int ptr;
int ret;
printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n");
/* initialise the main system clocks */
clk_h.rate = s3c2410_hclk;
clk_p.rate = s3c2410_pclk;
clk_f.rate = s3c2410_fclk;
/* set the enabled clocks to a minimal (known) state */
__raw_writel(S3C2410_CLKCON_PWMT | S3C2410_CLKCON_UART0 | S3C2410_CLKCON_UART1 | S3C2410_CLKCON_UART2 | S3C2410_CLKCON_GPIO | S3C2410_CLKCON_RTC, S3C2410_CLKCON);
/* register our clocks */
if (s3c2410_register_clock(&clk_f) < 0)
printk(KERN_ERR "failed to register cpu fclk\n");
if (s3c2410_register_clock(&clk_h) < 0)
printk(KERN_ERR "failed to register cpu fclk\n");
if (s3c2410_register_clock(&clk_p) < 0)
printk(KERN_ERR "failed to register cpu fclk\n");
for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
ret = s3c2410_register_clock(clkp);
if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
clkp->name, ret);
}
}
return 0;
}
arch_initcall(s3c2410_init_clocks);
/*
* linux/arch/arm/mach-s3c2410/clock.h
*
* Copyright (c) 2004 Simtec Electronics
* 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.
*/
struct clk {
struct list_head list;
struct module *owner;
struct clk *parent;
const char *name;
atomic_t used;
unsigned long rate;
unsigned long ctrlbit;
};
/* linux/include/asm/arch-s3c2410/regs-clock.h
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* Copyright (c) 2003,2004 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
*
* This program is free software; you can redistribute it and/or modify
......@@ -10,8 +10,9 @@
* S3C2410 clock register definitions
*
* Changelog:
* 19-06-2003 BJD Created file
* 12-03-2004 BJD Updated include protection
* 08-Aug-2004 Herbert Ptzl Added CLKCON definitions
* 19-06-2003 Ben Dooks Created file
* 12-03-2004 Ben Dooks Updated include protection
*/
......@@ -30,6 +31,24 @@
#define S3C2410_CLKSLOW S3C2410_CLKREG(0x10)
#define S3C2410_CLKDIVN S3C2410_CLKREG(0x14)
#define S3C2410_CLKCON_IDLE (1<<2)
#define S3C2410_CLKCON_POWER (1<<3)
#define S3C2410_CLKCON_NAND (1<<4)
#define S3C2410_CLKCON_LCDC (1<<5)
#define S3C2410_CLKCON_USBH (1<<6)
#define S3C2410_CLKCON_USBD (1<<7)
#define S3C2410_CLKCON_PWMT (1<<8)
#define S3C2410_CLKCON_SDI (1<<9)
#define S3C2410_CLKCON_UART0 (1<<10)
#define S3C2410_CLKCON_UART1 (1<<11)
#define S3C2410_CLKCON_UART2 (1<<12)
#define S3C2410_CLKCON_GPIO (1<<13)
#define S3C2410_CLKCON_RTC (1<<14)
#define S3C2410_CLKCON_ADC (1<<15)
#define S3C2410_CLKCON_IIC (1<<16)
#define S3C2410_CLKCON_IIS (1<<17)
#define S3C2410_CLKCON_SPI (1<<18)
#define S3C2410_PLLCON_MDIVSHIFT 12
#define S3C2410_PLLCON_PDIVSHIFT 4
#define S3C2410_PLLCON_SDIVSHIFT 0
......
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