mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 17:01:14 +00:00
Merge branch 'next-s3c24xx' into next-merged
This commit is contained in:
commit
c6ad115876
50 changed files with 1800 additions and 765 deletions
|
@ -33,11 +33,6 @@ config S3C2410_GPIO
|
|||
help
|
||||
GPIO code for S3C2410 and similar processors
|
||||
|
||||
config S3C2410_CLOCK
|
||||
bool
|
||||
help
|
||||
Clock code for the S3C2410, and similar processors
|
||||
|
||||
config SIMTEC_NOR
|
||||
bool
|
||||
help
|
||||
|
@ -85,6 +80,7 @@ config ARCH_BAST
|
|||
select PM_SIMTEC if PM
|
||||
select SIMTEC_NOR
|
||||
select MACH_BAST_IDE
|
||||
select S3C24XX_DCLK
|
||||
select ISA
|
||||
help
|
||||
Say Y here if you are using the Simtec Electronics EB2410ITX
|
||||
|
@ -122,6 +118,7 @@ config MACH_TCT_HAMMER
|
|||
config MACH_VR1000
|
||||
bool "Thorcom VR1000"
|
||||
select PM_SIMTEC if PM
|
||||
select S3C24XX_DCLK
|
||||
select SIMTEC_NOR
|
||||
select MACH_BAST_IDE
|
||||
select CPU_S3C2410
|
||||
|
|
|
@ -15,7 +15,6 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
|
|||
obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
|
||||
obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
|
||||
obj-$(CONFIG_S3C2410_GPIO) += gpio.o
|
||||
obj-$(CONFIG_S3C2410_CLOCK) += clock.o
|
||||
|
||||
# Machine support
|
||||
|
||||
|
|
|
@ -42,13 +42,6 @@
|
|||
#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
|
||||
#define S3C2410_PLLCON_MDIVMASK ((1<<(1+(19-12)))-1)
|
||||
#define S3C2410_PLLCON_PDIVMASK ((1<<5)-1)
|
||||
#define S3C2410_PLLCON_SDIVMASK 3
|
||||
|
||||
/* DCLKCON register addresses in gpio.h */
|
||||
|
||||
#define S3C2410_DCLKCON_DCLK0EN (1<<0)
|
||||
|
@ -76,32 +69,6 @@
|
|||
#define S3C2410_CLKSLOW_SLOWVAL(x) (x)
|
||||
#define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
static inline unsigned int
|
||||
s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
|
||||
{
|
||||
unsigned int mdiv, pdiv, sdiv;
|
||||
uint64_t fvco;
|
||||
|
||||
mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT;
|
||||
pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT;
|
||||
sdiv = pllval >> S3C2410_PLLCON_SDIVSHIFT;
|
||||
|
||||
mdiv &= S3C2410_PLLCON_MDIVMASK;
|
||||
pdiv &= S3C2410_PLLCON_PDIVMASK;
|
||||
sdiv &= S3C2410_PLLCON_SDIVMASK;
|
||||
|
||||
fvco = (uint64_t)baseclk * (mdiv + 8);
|
||||
do_div(fvco, (pdiv + 2) << sdiv);
|
||||
|
||||
return (unsigned int)fvco;
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
|
||||
|
||||
/* extra registers */
|
||||
|
|
|
@ -1053,13 +1053,6 @@
|
|||
#define S3C24XX_EXTINT1 S3C24XX_GPIOREG2(0x8C)
|
||||
#define S3C24XX_EXTINT2 S3C24XX_GPIOREG2(0x90)
|
||||
|
||||
/* values for S3C2410_EXTINT0/1/2 */
|
||||
#define S3C2410_EXTINT_LOWLEV (0x00)
|
||||
#define S3C2410_EXTINT_HILEV (0x01)
|
||||
#define S3C2410_EXTINT_FALLEDGE (0x02)
|
||||
#define S3C2410_EXTINT_RISEEDGE (0x04)
|
||||
#define S3C2410_EXTINT_BOTHEDGE (0x06)
|
||||
|
||||
/* interrupt filtering conrrol for EINT16..EINT23 */
|
||||
#define S3C2410_EINFLT0 S3C2410_GPIOREG(0x94)
|
||||
#define S3C2410_EINFLT1 S3C2410_GPIOREG(0x98)
|
||||
|
|
|
@ -22,5 +22,12 @@ struct s3c2410_spi_info {
|
|||
void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
|
||||
};
|
||||
|
||||
/* Standard setup / suspend routines for SPI GPIO pins. */
|
||||
|
||||
extern void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
|
||||
int enable);
|
||||
|
||||
extern void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
|
||||
int enable);
|
||||
|
||||
#endif /* __ASM_ARCH_SPI_H */
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <plat/clock.h>
|
||||
#include <plat/devs.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/pll.h>
|
||||
#include <plat/pm.h>
|
||||
|
||||
static struct map_desc h1940_iodesc[] __initdata = {
|
||||
|
@ -223,10 +224,9 @@ static void __init h1940_init(void)
|
|||
S3C2410_MISCCR_USBSUSPND0 |
|
||||
S3C2410_MISCCR_USBSUSPND1, 0x0);
|
||||
|
||||
tmp = (
|
||||
0x78 << S3C2410_PLLCON_MDIVSHIFT)
|
||||
| (0x02 << S3C2410_PLLCON_PDIVSHIFT)
|
||||
| (0x03 << S3C2410_PLLCON_SDIVSHIFT);
|
||||
tmp = (0x78 << S3C24XX_PLLCON_MDIVSHIFT)
|
||||
| (0x02 << S3C24XX_PLLCON_PDIVSHIFT)
|
||||
| (0x03 << S3C24XX_PLLCON_SDIVSHIFT);
|
||||
writel(tmp, S3C2410_UPLLCON);
|
||||
|
||||
platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -28,6 +29,8 @@
|
|||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <plat/cpu-freq.h>
|
||||
|
||||
#include <mach/regs-clock.h>
|
||||
#include <plat/regs-serial.h>
|
||||
|
||||
|
@ -35,6 +38,7 @@
|
|||
#include <plat/cpu.h>
|
||||
#include <plat/devs.h>
|
||||
#include <plat/clock.h>
|
||||
#include <plat/pll.h>
|
||||
|
||||
/* Initial IO mappings */
|
||||
|
||||
|
@ -59,25 +63,28 @@ void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
|
|||
* machine specific initialisation.
|
||||
*/
|
||||
|
||||
void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)
|
||||
void __init s3c2410_map_io(void)
|
||||
{
|
||||
/* register our io-tables */
|
||||
|
||||
iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
|
||||
iotable_init(mach_desc, mach_size);
|
||||
}
|
||||
|
||||
void __init s3c2410_init_clocks(int xtal)
|
||||
void __init_or_cpufreq s3c2410_setup_clocks(void)
|
||||
{
|
||||
struct clk *xtal_clk;
|
||||
unsigned long tmp;
|
||||
unsigned long xtal;
|
||||
unsigned long fclk;
|
||||
unsigned long hclk;
|
||||
unsigned long pclk;
|
||||
|
||||
xtal_clk = clk_get(NULL, "xtal");
|
||||
xtal = clk_get_rate(xtal_clk);
|
||||
clk_put(xtal_clk);
|
||||
|
||||
/* now we've got our machine bits initialised, work out what
|
||||
* clocks we've got */
|
||||
|
||||
fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
|
||||
fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
|
||||
|
||||
tmp = __raw_readl(S3C2410_CLKDIVN);
|
||||
|
||||
|
@ -95,7 +102,13 @@ void __init s3c2410_init_clocks(int xtal)
|
|||
* console to use them
|
||||
*/
|
||||
|
||||
s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
|
||||
s3c24xx_setup_clocks(fclk, hclk, pclk);
|
||||
}
|
||||
|
||||
void __init s3c2410_init_clocks(int xtal)
|
||||
{
|
||||
s3c24xx_register_baseclocks(xtal);
|
||||
s3c2410_setup_clocks();
|
||||
s3c2410_baseclk_add();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
@ -33,6 +34,8 @@
|
|||
#include <mach/reset.h>
|
||||
#include <mach/idle.h>
|
||||
|
||||
#include <plat/cpu-freq.h>
|
||||
|
||||
#include <mach/regs-clock.h>
|
||||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-power.h>
|
||||
|
@ -47,6 +50,7 @@
|
|||
#include <plat/devs.h>
|
||||
#include <plat/clock.h>
|
||||
#include <plat/pm.h>
|
||||
#include <plat/pll.h>
|
||||
|
||||
#ifndef CONFIG_CPU_S3C2412_ONLY
|
||||
void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
|
||||
|
@ -136,7 +140,7 @@ static void s3c2412_hard_reset(void)
|
|||
* machine specific initialisation.
|
||||
*/
|
||||
|
||||
void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
|
||||
void __init s3c2412_map_io(void)
|
||||
{
|
||||
/* move base of IO */
|
||||
|
||||
|
@ -153,20 +157,25 @@ void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
|
|||
/* register our io-tables */
|
||||
|
||||
iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
|
||||
iotable_init(mach_desc, mach_size);
|
||||
}
|
||||
|
||||
void __init s3c2412_init_clocks(int xtal)
|
||||
void __init_or_cpufreq s3c2412_setup_clocks(void)
|
||||
{
|
||||
struct clk *xtal_clk;
|
||||
unsigned long tmp;
|
||||
unsigned long xtal;
|
||||
unsigned long fclk;
|
||||
unsigned long hclk;
|
||||
unsigned long pclk;
|
||||
|
||||
xtal_clk = clk_get(NULL, "xtal");
|
||||
xtal = clk_get_rate(xtal_clk);
|
||||
clk_put(xtal_clk);
|
||||
|
||||
/* now we've got our machine bits initialised, work out what
|
||||
* clocks we've got */
|
||||
|
||||
fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
|
||||
fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
|
||||
|
||||
clk_mpll.rate = fclk;
|
||||
|
||||
|
@ -183,11 +192,17 @@ void __init s3c2412_init_clocks(int xtal)
|
|||
printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
|
||||
print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
|
||||
|
||||
s3c24xx_setup_clocks(fclk, hclk, pclk);
|
||||
}
|
||||
|
||||
void __init s3c2412_init_clocks(int xtal)
|
||||
{
|
||||
/* initialise the clocks here, to allow other things like the
|
||||
* console to use them
|
||||
*/
|
||||
|
||||
s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
|
||||
s3c24xx_register_baseclocks(xtal);
|
||||
s3c2412_setup_clocks();
|
||||
s3c2412_baseclk_add();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ menu "S3C2440 Machines"
|
|||
config MACH_ANUBIS
|
||||
bool "Simtec Electronics ANUBIS"
|
||||
select CPU_S3C2440
|
||||
select S3C24XX_DCLK
|
||||
select PM_SIMTEC if PM
|
||||
select HAVE_PATA_PLATFORM
|
||||
select S3C24XX_GPIO_EXTRA64
|
||||
|
@ -39,6 +40,7 @@ config MACH_ANUBIS
|
|||
config MACH_OSIRIS
|
||||
bool "Simtec IM2440D20 (OSIRIS) module"
|
||||
select CPU_S3C2440
|
||||
select S3C24XX_DCLK
|
||||
select PM_SIMTEC if PM
|
||||
select S3C24XX_GPIO_EXTRA128
|
||||
help
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include <mach/regs-s3c2443-clock.h>
|
||||
|
||||
#include <plat/cpu-freq.h>
|
||||
|
||||
#include <plat/s3c2443.h>
|
||||
#include <plat/clock.h>
|
||||
#include <plat/cpu.h>
|
||||
|
@ -1011,22 +1013,20 @@ static struct clk *clks[] __initdata = {
|
|||
&clk_prediv,
|
||||
};
|
||||
|
||||
void __init s3c2443_init_clocks(int xtal)
|
||||
void __init_or_cpufreq s3c2443_setup_clocks(void)
|
||||
{
|
||||
unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
|
||||
unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
|
||||
unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
|
||||
struct clk *xtal_clk;
|
||||
unsigned long xtal;
|
||||
unsigned long pll;
|
||||
unsigned long fclk;
|
||||
unsigned long hclk;
|
||||
unsigned long pclk;
|
||||
struct clk *clkp;
|
||||
int ret;
|
||||
int ptr;
|
||||
|
||||
/* s3c2443 parents h and p clocks from prediv */
|
||||
clk_h.parent = &clk_prediv;
|
||||
clk_p.parent = &clk_prediv;
|
||||
xtal_clk = clk_get(NULL, "xtal");
|
||||
xtal = clk_get_rate(xtal_clk);
|
||||
clk_put(xtal_clk);
|
||||
|
||||
pll = s3c2443_get_mpll(mpllcon, xtal);
|
||||
clk_msysclk.rate = pll;
|
||||
|
@ -1036,13 +1036,29 @@ void __init s3c2443_init_clocks(int xtal)
|
|||
hclk /= s3c2443_get_hdiv(clkdiv0);
|
||||
pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
|
||||
|
||||
s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
|
||||
s3c24xx_setup_clocks(fclk, hclk, pclk);
|
||||
|
||||
printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
|
||||
(mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
|
||||
print_mhz(pll), print_mhz(fclk),
|
||||
print_mhz(hclk), print_mhz(pclk));
|
||||
|
||||
s3c24xx_setup_clocks(fclk, hclk, pclk);
|
||||
}
|
||||
|
||||
void __init s3c2443_init_clocks(int xtal)
|
||||
{
|
||||
struct clk *clkp;
|
||||
unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
|
||||
int ret;
|
||||
int ptr;
|
||||
|
||||
/* s3c2443 parents h and p clocks from prediv */
|
||||
clk_h.parent = &clk_prediv;
|
||||
clk_p.parent = &clk_prediv;
|
||||
|
||||
s3c24xx_register_baseclocks(xtal);
|
||||
s3c2443_setup_clocks();
|
||||
s3c2443_clk_initparents();
|
||||
|
||||
for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
|
||||
|
@ -1056,7 +1072,6 @@ void __init s3c2443_init_clocks(int xtal)
|
|||
}
|
||||
|
||||
clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
|
||||
|
||||
clk_usb_bus.parent = &clk_usb_bus_host;
|
||||
|
||||
/* ensure usb bus clock is within correct rate of 48MHz */
|
||||
|
|
|
@ -81,10 +81,9 @@ void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
|
|||
* machine specific initialisation.
|
||||
*/
|
||||
|
||||
void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size)
|
||||
void __init s3c2443_map_io(void)
|
||||
{
|
||||
iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
|
||||
iotable_init(mach_desc, mach_size);
|
||||
}
|
||||
|
||||
/* need to register class before we actually register the device, and
|
||||
|
|
|
@ -57,6 +57,14 @@ config S3C_BOOT_ERROR_RESET
|
|||
Say y here to use the watchdog to reset the system if the
|
||||
kernel decompressor detects an error during decompression.
|
||||
|
||||
config S3C_BOOT_UART_FORCE_FIFO
|
||||
bool "Force UART FIFO on during boot process"
|
||||
depends on PLAT_S3C
|
||||
default y
|
||||
help
|
||||
Say Y here to force the UART FIFOs on during the kernel
|
||||
uncompressor
|
||||
|
||||
comment "Power management"
|
||||
|
||||
config S3C2410_PM_DEBUG
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
# dummy makefile, currently just including asm/arm/plat-s3c/include/plat
|
||||
# arch/arm/plat-s3c/Makefile
|
||||
#
|
||||
# Copyright 2008 Simtec Electronics
|
||||
#
|
||||
# Licensed under GPLv2
|
||||
|
||||
obj-n := dummy.o
|
||||
obj-y :=
|
||||
obj-m :=
|
||||
obj-n :=
|
||||
obj- :=
|
||||
|
||||
# Core support for all Samsung SoCs
|
||||
|
||||
obj-y += init.o
|
||||
obj-y += time.o
|
||||
obj-y += clock.o
|
||||
obj-y += pwm-clock.o
|
359
arch/arm/plat-s3c/clock.c
Normal file
359
arch/arm/plat-s3c/clock.c
Normal file
|
@ -0,0 +1,359 @@
|
|||
/* linux/arch/arm/plat-s3c24xx/clock.c
|
||||
*
|
||||
* Copyright (c) 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/sysdev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <plat/cpu-freq.h>
|
||||
|
||||
#include <plat/clock.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
/* 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);
|
||||
|
||||
/* enable and disable calls for use with the clk struct */
|
||||
|
||||
static int clk_null_enable(struct clk *clk, int enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clock API calls */
|
||||
|
||||
struct clk *clk_get(struct device *dev, const char *id)
|
||||
{
|
||||
struct clk *p;
|
||||
struct clk *clk = ERR_PTR(-ENOENT);
|
||||
int idno;
|
||||
|
||||
if (dev == NULL || dev->bus != &platform_bus_type)
|
||||
idno = -1;
|
||||
else
|
||||
idno = to_platform_device(dev)->id;
|
||||
|
||||
spin_lock(&clocks_lock);
|
||||
|
||||
list_for_each_entry(p, &clocks, list) {
|
||||
if (p->id == idno &&
|
||||
strcmp(id, p->name) == 0 &&
|
||||
try_module_get(p->owner)) {
|
||||
clk = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for the case where a device was supplied, but the
|
||||
* clock that was being searched for is not device specific */
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
list_for_each_entry(p, &clocks, list) {
|
||||
if (p->id == -1 && strcmp(id, p->name) == 0 &&
|
||||
try_module_get(p->owner)) {
|
||||
clk = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&clocks_lock);
|
||||
return clk;
|
||||
}
|
||||
|
||||
void clk_put(struct clk *clk)
|
||||
{
|
||||
module_put(clk->owner);
|
||||
}
|
||||
|
||||
int clk_enable(struct clk *clk)
|
||||
{
|
||||
if (IS_ERR(clk) || clk == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
clk_enable(clk->parent);
|
||||
|
||||
spin_lock(&clocks_lock);
|
||||
|
||||
if ((clk->usage++) == 0)
|
||||
(clk->enable)(clk, 1);
|
||||
|
||||
spin_unlock(&clocks_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clk_disable(struct clk *clk)
|
||||
{
|
||||
if (IS_ERR(clk) || clk == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&clocks_lock);
|
||||
|
||||
if ((--clk->usage) == 0)
|
||||
(clk->enable)(clk, 0);
|
||||
|
||||
spin_unlock(&clocks_lock);
|
||||
clk_disable(clk->parent);
|
||||
}
|
||||
|
||||
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
if (IS_ERR(clk))
|
||||
return 0;
|
||||
|
||||
if (clk->rate != 0)
|
||||
return clk->rate;
|
||||
|
||||
if (clk->get_rate != NULL)
|
||||
return (clk->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(clk) && clk->round_rate)
|
||||
return (clk->round_rate)(clk, rate);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(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->set_rate == NULL);
|
||||
|
||||
if (clk->set_rate == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&clocks_lock);
|
||||
ret = (clk->set_rate)(clk, rate);
|
||||
spin_unlock(&clocks_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct clk *clk_get_parent(struct clk *clk)
|
||||
{
|
||||
return clk->parent;
|
||||
}
|
||||
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR(clk))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&clocks_lock);
|
||||
|
||||
if (clk->set_parent)
|
||||
ret = (clk->set_parent)(clk, parent);
|
||||
|
||||
spin_unlock(&clocks_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(clk_get);
|
||||
EXPORT_SYMBOL(clk_put);
|
||||
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 */
|
||||
|
||||
static int clk_default_setrate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
clk->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct clk clk_xtal = {
|
||||
.name = "xtal",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
};
|
||||
|
||||
struct clk clk_mpll = {
|
||||
.name = "mpll",
|
||||
.id = -1,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_upll = {
|
||||
.name = "upll",
|
||||
.id = -1,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
};
|
||||
|
||||
struct clk clk_f = {
|
||||
.name = "fclk",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = &clk_mpll,
|
||||
.ctrlbit = 0,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_h = {
|
||||
.name = "hclk",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_p = {
|
||||
.name = "pclk",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_usb_bus = {
|
||||
.name = "usb-bus",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = &clk_upll,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct clk s3c24xx_uclk = {
|
||||
.name = "uclk",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
/* initialise the clock system */
|
||||
|
||||
int s3c24xx_register_clock(struct clk *clk)
|
||||
{
|
||||
clk->owner = THIS_MODULE;
|
||||
|
||||
if (clk->enable == NULL)
|
||||
clk->enable = clk_null_enable;
|
||||
|
||||
/* add to the list of available clocks */
|
||||
|
||||
/* Quick check to see if this clock has already been registered. */
|
||||
BUG_ON(clk->list.prev != clk->list.next);
|
||||
|
||||
spin_lock(&clocks_lock);
|
||||
list_add(&clk->list, &clocks);
|
||||
spin_unlock(&clocks_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
fails++;
|
||||
}
|
||||
|
||||
return fails;
|
||||
}
|
||||
|
||||
/* initalise all the clocks */
|
||||
|
||||
int __init s3c24xx_register_baseclocks(unsigned long xtal)
|
||||
{
|
||||
printk(KERN_INFO "S3C24XX Clocks, (c) 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;
|
||||
}
|
||||
|
18
arch/arm/plat-s3c/include/mach/io.h
Normal file
18
arch/arm/plat-s3c/include/mach/io.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* arch/arm/plat-s3c/include/mach/io.h
|
||||
*
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* Ben Dooks <ben-linux@fluff.org>
|
||||
*
|
||||
* Default IO routines for plat-s3c based systems, such as S3C24A0
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARM_ARCH_IO_H
|
||||
#define __ASM_ARM_ARCH_IO_H
|
||||
|
||||
/* No current ISA/PCI bus support. */
|
||||
#define __io(a) ((void __iomem *)(a))
|
||||
#define __mem_pci(a) (a)
|
||||
|
||||
#define IO_SPACE_LIMIT (0xFFFFFFFF)
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
/* arch/arm/mach-s3c2410/include/mach/vmalloc.h
|
||||
/* arch/arm/plat-s3c/include/mach/vmalloc.h
|
||||
*
|
||||
* from arch/arm/mach-iop3xx/include/mach/vmalloc.h
|
||||
*
|
29
arch/arm/plat-s3c/include/plat/adc.h
Normal file
29
arch/arm/plat-s3c/include/plat/adc.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* arch/arm/plat-s3c/include/plat/adc.h
|
||||
*
|
||||
* Copyright (c) 2008 Simtec Electronics
|
||||
* http://armlinux.simnte.co.uk/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C24XX ADC driver information
|
||||
*
|
||||
* 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_ADC_H
|
||||
#define __ASM_PLAT_ADC_H __FILE__
|
||||
|
||||
struct s3c_adc_client;
|
||||
|
||||
extern int s3c_adc_start(struct s3c_adc_client *client,
|
||||
unsigned int channel, unsigned int nr_samples);
|
||||
|
||||
extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
|
||||
void (*select)(unsigned selected),
|
||||
void (*conv)(unsigned d0, unsigned d1),
|
||||
unsigned int is_ts);
|
||||
|
||||
extern void s3c_adc_release(struct s3c_adc_client *client);
|
||||
|
||||
#endif /* __ASM_PLAT_ADC_H */
|
|
@ -1,5 +1,4 @@
|
|||
/* linux/include/asm-arm/plat-s3c24xx/clock.h
|
||||
* linux/arch/arm/mach-s3c2410/clock.h
|
||||
/* linux/arch/arm/plat-s3c/include/plat/clock.h
|
||||
*
|
||||
* Copyright (c) 2004-2005 Simtec Electronics
|
||||
* http://www.simtec.co.uk/products/SWLINUX/
|
||||
|
@ -10,6 +9,8 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct clk {
|
||||
struct list_head list;
|
||||
struct module *owner;
|
||||
|
@ -51,14 +52,21 @@ extern struct clk clk_xtal;
|
|||
* Please DO NOT use these outside of arch/arm/mach-s3c2410
|
||||
*/
|
||||
|
||||
extern struct mutex clocks_mutex;
|
||||
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 int s3c24xx_setup_clocks(unsigned long xtal,
|
||||
unsigned long fclk,
|
||||
unsigned long hclk,
|
||||
unsigned long pclk);
|
||||
extern int s3c24xx_register_baseclocks(unsigned long xtal);
|
||||
|
||||
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);
|
||||
extern void s3c2443_setup_clocks(void);
|
||||
|
94
arch/arm/plat-s3c/include/plat/cpu-freq.h
Normal file
94
arch/arm/plat-s3c/include/plat/cpu-freq.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* arch/arm/plat-s3c/include/plat/cpu-freq.h
|
||||
*
|
||||
* Copyright (c) 2006,2007 Simtec Electronics
|
||||
* http://armlinux.simtec.co.uk/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C CPU frequency scaling support - driver and board
|
||||
*
|
||||
* 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/cpufreq.h>
|
||||
|
||||
struct s3c_cpufreq_info;
|
||||
struct s3c_cpufreq_board;
|
||||
struct s3c_iotimings;
|
||||
|
||||
struct s3c_freq {
|
||||
unsigned long fclk;
|
||||
unsigned long armclk;
|
||||
unsigned long hclk_tns; /* in 10ths of ns */
|
||||
unsigned long hclk;
|
||||
unsigned long pclk;
|
||||
};
|
||||
|
||||
/* wrapper 'struct cpufreq_freqs' so that any drivers receiving the
|
||||
* notification can use this information that is not provided by just
|
||||
* having the core frequency alone.
|
||||
*/
|
||||
|
||||
struct s3c_cpufreq_freqs {
|
||||
struct cpufreq_freqs freqs;
|
||||
struct s3c_freq old;
|
||||
struct s3c_freq new;
|
||||
};
|
||||
|
||||
#define to_s3c_cpufreq(_cf) container_of(_cf, struct s3c_cpufreq_freqs, freqs)
|
||||
|
||||
struct s3c_clkdivs {
|
||||
int p_divisor; /* fclk / pclk */
|
||||
int h_divisor; /* fclk / hclk */
|
||||
int arm_divisor; /* not all cpus have this. */
|
||||
unsigned char dvs; /* using dvs mode to arm. */
|
||||
};
|
||||
|
||||
#define PLLVAL(_m, _p, _s) (((_m) << 12) | ((_p) << 4) | (_s))
|
||||
|
||||
struct s3c_pllval {
|
||||
unsigned long freq;
|
||||
unsigned long pll_reg;
|
||||
};
|
||||
|
||||
struct s3c_cpufreq_config {
|
||||
struct s3c_freq freq;
|
||||
struct s3c_pllval pll;
|
||||
struct s3c_clkdivs divs;
|
||||
struct s3c_cpufreq_info *info; /* for core, not drivers */
|
||||
struct s3c_cpufreq_board *board;
|
||||
};
|
||||
|
||||
/* s3c_cpufreq_board
|
||||
*
|
||||
* per-board configuraton information, such as memory refresh and
|
||||
* how to initialise IO timings.
|
||||
*/
|
||||
struct s3c_cpufreq_board {
|
||||
unsigned int refresh; /* refresh period in ns */
|
||||
unsigned int auto_io:1; /* automatically init io timings. */
|
||||
unsigned int need_io:1; /* set if needs io timing support. */
|
||||
|
||||
/* any non-zero field in here is taken as an upper limit. */
|
||||
struct s3c_freq max; /* frequency limits */
|
||||
};
|
||||
|
||||
/* Things depending on frequency scaling. */
|
||||
#ifdef CONFIG_CPU_FREQ_S3C
|
||||
#define __init_or_cpufreq
|
||||
#else
|
||||
#define __init_or_cpufreq __init
|
||||
#endif
|
||||
|
||||
/* Board functions */
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_S3C
|
||||
extern int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board);
|
||||
#else
|
||||
|
||||
static inline int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_CPU_FREQ_S3C */
|
|
@ -1,4 +1,4 @@
|
|||
/* linux/include/asm-arm/plat-s3c24xx/cpu.h
|
||||
/* linux/arch/arm/plat-s3c/include/plat/cpu.h
|
||||
*
|
||||
* Copyright (c) 2004-2005 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
|
@ -18,7 +18,7 @@
|
|||
#define MHZ (1000*1000)
|
||||
#endif
|
||||
|
||||
#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000)
|
||||
#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000)
|
||||
|
||||
/* forward declaration */
|
||||
struct s3c24xx_uart_resources;
|
||||
|
@ -26,6 +26,21 @@ struct platform_device;
|
|||
struct s3c2410_uartcfg;
|
||||
struct map_desc;
|
||||
|
||||
/* per-cpu initialisation function table. */
|
||||
|
||||
struct cpu_table {
|
||||
unsigned long idcode;
|
||||
unsigned long idmask;
|
||||
void (*map_io)(void);
|
||||
void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
|
||||
void (*init_clocks)(int xtal);
|
||||
int (*init)(void);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern void s3c_init_cpu(unsigned long idcode,
|
||||
struct cpu_table *cpus, unsigned int cputab_size);
|
||||
|
||||
/* core initialisation functions */
|
||||
|
||||
extern void s3c24xx_init_irq(void);
|
21
arch/arm/plat-s3c/include/plat/regs-irqtype.h
Normal file
21
arch/arm/plat-s3c/include/plat/regs-irqtype.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* arch/arm/plat-s3c/include/plat/regs-irqtype.h
|
||||
*
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* S3C - IRQ detection types.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* values for S3C2410_EXTINT0/1/2 and other cpus in the series, including
|
||||
* the S3C64XX
|
||||
*/
|
||||
#define S3C2410_EXTINT_LOWLEV (0x00)
|
||||
#define S3C2410_EXTINT_HILEV (0x01)
|
||||
#define S3C2410_EXTINT_FALLEDGE (0x02)
|
||||
#define S3C2410_EXTINT_RISEEDGE (0x04)
|
||||
#define S3C2410_EXTINT_BOTHEDGE (0x06)
|
|
@ -139,6 +139,28 @@ static void arch_decomp_error(const char *x)
|
|||
|
||||
static void error(char *err);
|
||||
|
||||
#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
|
||||
static inline void arch_enable_uart_fifo(void)
|
||||
{
|
||||
u32 fifocon = uart_rd(S3C2410_UFCON);
|
||||
|
||||
if (!(fifocon & S3C2410_UFCON_FIFOMODE)) {
|
||||
fifocon |= S3C2410_UFCON_RESETBOTH;
|
||||
uart_wr(S3C2410_UFCON, fifocon);
|
||||
|
||||
/* wait for fifo reset to complete */
|
||||
while (1) {
|
||||
fifocon = uart_rd(S3C2410_UFCON);
|
||||
if (!(fifocon & S3C2410_UFCON_RESETBOTH))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define arch_enable_uart_fifo() do { } while(0)
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
arch_decomp_setup(void)
|
||||
{
|
||||
|
@ -149,6 +171,12 @@ arch_decomp_setup(void)
|
|||
|
||||
arch_detect_cpu();
|
||||
arch_decomp_wdog_start();
|
||||
|
||||
/* Enable the UART FIFOs if they where not enabled and our
|
||||
* configuration says we should turn them on.
|
||||
*/
|
||||
|
||||
arch_enable_uart_fifo();
|
||||
}
|
||||
|
||||
|
||||
|
|
161
arch/arm/plat-s3c/init.c
Normal file
161
arch/arm/plat-s3c/init.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/* linux/arch/arm/plat-s3c/init.c
|
||||
*
|
||||
* Copyright (c) 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* S3C series CPU initialisation
|
||||
*
|
||||
* 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/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/devs.h>
|
||||
#include <plat/clock.h>
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
|
||||
static struct cpu_table *cpu;
|
||||
|
||||
static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode,
|
||||
struct cpu_table *tab,
|
||||
unsigned int count)
|
||||
{
|
||||
for (; count != 0; count--, tab++) {
|
||||
if ((idcode & tab->idmask) == tab->idcode)
|
||||
return tab;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __init s3c_init_cpu(unsigned long idcode,
|
||||
struct cpu_table *cputab, unsigned int cputab_size)
|
||||
{
|
||||
cpu = s3c_lookup_cpu(idcode, cputab, cputab_size);
|
||||
|
||||
if (cpu == NULL) {
|
||||
printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
|
||||
panic("Unknown S3C24XX CPU");
|
||||
}
|
||||
|
||||
printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
|
||||
|
||||
if (cpu->map_io == NULL || cpu->init == NULL) {
|
||||
printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
|
||||
panic("Unsupported Samsung CPU");
|
||||
}
|
||||
|
||||
cpu->map_io();
|
||||
}
|
||||
|
||||
/* s3c24xx_init_clocks
|
||||
*
|
||||
* Initialise the clock subsystem and associated information from the
|
||||
* given master crystal value.
|
||||
*
|
||||
* xtal = 0 -> use default PLL crystal value (normally 12MHz)
|
||||
* != 0 -> PLL crystal value in Hz
|
||||
*/
|
||||
|
||||
void __init s3c24xx_init_clocks(int xtal)
|
||||
{
|
||||
if (xtal == 0)
|
||||
xtal = 12*1000*1000;
|
||||
|
||||
if (cpu == NULL)
|
||||
panic("s3c24xx_init_clocks: no cpu setup?\n");
|
||||
|
||||
if (cpu->init_clocks == NULL)
|
||||
panic("s3c24xx_init_clocks: cpu has no clock init\n");
|
||||
else
|
||||
(cpu->init_clocks)(xtal);
|
||||
}
|
||||
|
||||
/* uart management */
|
||||
|
||||
static int nr_uarts __initdata = 0;
|
||||
|
||||
static struct s3c2410_uartcfg uart_cfgs[3];
|
||||
|
||||
/* s3c24xx_init_uartdevs
|
||||
*
|
||||
* copy the specified platform data and configuration into our central
|
||||
* set of devices, before the data is thrown away after the init process.
|
||||
*
|
||||
* This also fills in the array passed to the serial driver for the
|
||||
* early initialisation of the console.
|
||||
*/
|
||||
|
||||
void __init s3c24xx_init_uartdevs(char *name,
|
||||
struct s3c24xx_uart_resources *res,
|
||||
struct s3c2410_uartcfg *cfg, int no)
|
||||
{
|
||||
struct platform_device *platdev;
|
||||
struct s3c2410_uartcfg *cfgptr = uart_cfgs;
|
||||
struct s3c24xx_uart_resources *resp;
|
||||
int uart;
|
||||
|
||||
memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
|
||||
|
||||
for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
|
||||
platdev = s3c24xx_uart_src[cfgptr->hwport];
|
||||
|
||||
resp = res + cfgptr->hwport;
|
||||
|
||||
s3c24xx_uart_devs[uart] = platdev;
|
||||
|
||||
platdev->name = name;
|
||||
platdev->resource = resp->resources;
|
||||
platdev->num_resources = resp->nr_resources;
|
||||
|
||||
platdev->dev.platform_data = cfgptr;
|
||||
}
|
||||
|
||||
nr_uarts = no;
|
||||
}
|
||||
|
||||
void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
|
||||
{
|
||||
if (cpu == NULL)
|
||||
return;
|
||||
|
||||
if (cpu->init_uarts == NULL) {
|
||||
printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
|
||||
} else
|
||||
(cpu->init_uarts)(cfg, no);
|
||||
}
|
||||
|
||||
static int __init s3c_arch_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// do the correct init for cpu
|
||||
|
||||
if (cpu == NULL)
|
||||
panic("s3c_arch_init: NULL cpu\n");
|
||||
|
||||
ret = (cpu->init)();
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
arch_initcall(s3c_arch_init);
|
|
@ -73,11 +73,13 @@
|
|||
* tclk -------------------------/
|
||||
*/
|
||||
|
||||
static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
|
||||
static struct clk clk_timer_scaler[];
|
||||
|
||||
static unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
|
||||
{
|
||||
unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
|
||||
|
||||
if (clk->id == 1) {
|
||||
if (clk == &clk_timer_scaler[1]) {
|
||||
tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
|
||||
tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
|
||||
} else {
|
||||
|
@ -87,18 +89,61 @@ static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
|
|||
return clk_get_rate(clk->parent) / (tcfg0 + 1);
|
||||
}
|
||||
|
||||
/* TODO - add set rate calls. */
|
||||
static unsigned long clk_pwm_scaler_round_rate(struct clk *clk,
|
||||
unsigned long rate)
|
||||
{
|
||||
unsigned long parent_rate = clk_get_rate(clk->parent);
|
||||
unsigned long divisor = parent_rate / rate;
|
||||
|
||||
if (divisor > 256)
|
||||
divisor = 256;
|
||||
else if (divisor < 2)
|
||||
divisor = 2;
|
||||
|
||||
return parent_rate / divisor;
|
||||
}
|
||||
|
||||
static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned long round = clk_pwm_scaler_round_rate(clk, rate);
|
||||
unsigned long tcfg0;
|
||||
unsigned long divisor;
|
||||
unsigned long flags;
|
||||
|
||||
divisor = clk_get_rate(clk->parent) / round;
|
||||
divisor--;
|
||||
|
||||
local_irq_save(flags);
|
||||
tcfg0 = __raw_readl(S3C2410_TCFG0);
|
||||
|
||||
if (clk == &clk_timer_scaler[1]) {
|
||||
tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
|
||||
tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
|
||||
} else {
|
||||
tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
|
||||
tcfg0 |= divisor;
|
||||
}
|
||||
|
||||
__raw_writel(tcfg0, S3C2410_TCFG0);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk clk_timer_scaler[] = {
|
||||
[0] = {
|
||||
.name = "pwm-scaler0",
|
||||
.id = -1,
|
||||
.get_rate = clk_pwm_scaler_getrate,
|
||||
.get_rate = clk_pwm_scaler_get_rate,
|
||||
.set_rate = clk_pwm_scaler_set_rate,
|
||||
.round_rate = clk_pwm_scaler_round_rate,
|
||||
},
|
||||
[1] = {
|
||||
.name = "pwm-scaler1",
|
||||
.id = -1,
|
||||
.get_rate = clk_pwm_scaler_getrate,
|
||||
.get_rate = clk_pwm_scaler_get_rate,
|
||||
.set_rate = clk_pwm_scaler_set_rate,
|
||||
.round_rate = clk_pwm_scaler_round_rate,
|
||||
},
|
||||
};
|
||||
|
|
@ -101,7 +101,7 @@ static unsigned long s3c2410_gettimeoffset (void)
|
|||
|
||||
/* work out how many ticks have gone since last timer interrupt */
|
||||
|
||||
tval = __raw_readl(S3C2410_TCNTO(4));
|
||||
tval = __raw_readl(S3C2410_TCNTO(4));
|
||||
tdone = timer_startval - tval;
|
||||
|
||||
/* check to see if there is an interrupt pending */
|
||||
|
@ -144,7 +144,7 @@ static struct irqaction s3c2410_timer_irq = {
|
|||
machine_is_bast() || \
|
||||
machine_is_vr1000() || \
|
||||
machine_is_anubis() || \
|
||||
machine_is_osiris() )
|
||||
machine_is_osiris())
|
||||
|
||||
/*
|
||||
* Set up timer interrupt, and return the current time in seconds.
|
||||
|
@ -216,7 +216,7 @@ static void s3c2410_timer_setup (void)
|
|||
|
||||
tcnt--;
|
||||
|
||||
printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
|
||||
printk(KERN_DEBUG "timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
|
||||
tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
|
||||
|
||||
/* check to see if timer is within 16bit range... */
|
||||
|
@ -247,7 +247,7 @@ static void s3c2410_timer_setup (void)
|
|||
__raw_writel(tcon, S3C2410_TCON);
|
||||
}
|
||||
|
||||
static void __init s3c2410_timer_init (void)
|
||||
static void __init s3c2410_timer_init(void)
|
||||
{
|
||||
s3c2410_timer_setup();
|
||||
setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
|
|
@ -15,6 +15,19 @@ config PLAT_S3C24XX
|
|||
|
||||
if PLAT_S3C24XX
|
||||
|
||||
# code that is shared between a number of the s3c24xx implementations
|
||||
|
||||
config S3C2410_CLOCK
|
||||
bool
|
||||
help
|
||||
Clock code for the S3C2410, and similar processors which
|
||||
is currently includes the S3C2410, S3C2440, S3C2442.
|
||||
|
||||
config S3C24XX_DCLK
|
||||
bool
|
||||
help
|
||||
Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
|
||||
|
||||
config CPU_S3C244X
|
||||
bool
|
||||
depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
|
||||
|
@ -70,6 +83,29 @@ config S3C2410_DMA_DEBUG
|
|||
Enable debugging output for the DMA code. This option sends info
|
||||
to the kernel log, at priority KERN_DEBUG.
|
||||
|
||||
config S3C24XX_ADC
|
||||
bool "ADC common driver support"
|
||||
help
|
||||
Core support for the ADC block found in the S3C24XX SoC systems
|
||||
for drivers such as the touchscreen and hwmon to use to share
|
||||
this resource.
|
||||
|
||||
# SPI default pin configuration code
|
||||
|
||||
config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
|
||||
bool
|
||||
help
|
||||
SPI GPIO configuration code for BUS0 when connected to
|
||||
GPE11, GPE12 and GPE13.
|
||||
|
||||
config S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7
|
||||
bool
|
||||
help
|
||||
SPI GPIO configuration code for BUS 1 when connected to
|
||||
GPG5, GPG6 and GPG7.
|
||||
|
||||
# common code for s3c24xx based machines, such as the SMDKs.
|
||||
|
||||
config MACH_SMDK
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -17,9 +17,8 @@ obj-y += irq.o
|
|||
obj-y += devs.o
|
||||
obj-y += gpio.o
|
||||
obj-y += gpiolib.o
|
||||
obj-y += time.o
|
||||
obj-y += clock.o
|
||||
obj-y += pwm-clock.o
|
||||
obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o
|
||||
|
||||
# Architecture dependant builds
|
||||
|
||||
|
@ -30,5 +29,15 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
|
|||
obj-$(CONFIG_PM) += pm.o
|
||||
obj-$(CONFIG_PM) += sleep.o
|
||||
obj-$(CONFIG_HAVE_PWM) += pwm.o
|
||||
obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
|
||||
obj-$(CONFIG_S3C2410_DMA) += dma.o
|
||||
obj-$(CONFIG_S3C24XX_ADC) += adc.o
|
||||
|
||||
# SPI gpio central GPIO functions
|
||||
|
||||
obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o
|
||||
obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7) += spi-bus1-gpg5_6_7.o
|
||||
|
||||
# machine common support
|
||||
|
||||
obj-$(CONFIG_MACH_SMDK) += common-smdk.o
|
||||
|
|
372
arch/arm/plat-s3c24xx/adc.c
Normal file
372
arch/arm/plat-s3c24xx/adc.c
Normal file
|
@ -0,0 +1,372 @@
|
|||
/* arch/arm/plat-s3c24xx/adc.c
|
||||
*
|
||||
* Copyright (c) 2008 Simtec Electronics
|
||||
* http://armlinux.simtec.co.uk/
|
||||
* Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
|
||||
*
|
||||
* S3C24XX ADC device core
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <plat/regs-adc.h>
|
||||
#include <plat/adc.h>
|
||||
|
||||
/* This driver is designed to control the usage of the ADC block between
|
||||
* the touchscreen and any other drivers that may need to use it, such as
|
||||
* the hwmon driver.
|
||||
*
|
||||
* Priority will be given to the touchscreen driver, but as this itself is
|
||||
* rate limited it should not starve other requests which are processed in
|
||||
* order that they are received.
|
||||
*
|
||||
* Each user registers to get a client block which uniquely identifies it
|
||||
* and stores information such as the necessary functions to callback when
|
||||
* action is required.
|
||||
*/
|
||||
|
||||
struct s3c_adc_client {
|
||||
struct platform_device *pdev;
|
||||
struct list_head pend;
|
||||
|
||||
unsigned int nr_samples;
|
||||
unsigned char is_ts;
|
||||
unsigned char channel;
|
||||
|
||||
void (*select_cb)(unsigned selected);
|
||||
void (*convert_cb)(unsigned val1, unsigned val2);
|
||||
};
|
||||
|
||||
struct adc_device {
|
||||
struct platform_device *pdev;
|
||||
struct platform_device *owner;
|
||||
struct clk *clk;
|
||||
struct s3c_adc_client *cur;
|
||||
struct s3c_adc_client *ts_pend;
|
||||
void __iomem *regs;
|
||||
|
||||
unsigned int prescale;
|
||||
|
||||
int irq;
|
||||
};
|
||||
|
||||
static struct adc_device *adc_dev;
|
||||
|
||||
static LIST_HEAD(adc_pending);
|
||||
|
||||
#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
|
||||
|
||||
static inline void s3c_adc_convert(struct adc_device *adc)
|
||||
{
|
||||
unsigned con = readl(adc->regs + S3C2410_ADCCON);
|
||||
|
||||
con |= S3C2410_ADCCON_ENABLE_START;
|
||||
writel(con, adc->regs + S3C2410_ADCCON);
|
||||
}
|
||||
|
||||
static inline void s3c_adc_select(struct adc_device *adc,
|
||||
struct s3c_adc_client *client)
|
||||
{
|
||||
unsigned con = readl(adc->regs + S3C2410_ADCCON);
|
||||
|
||||
client->select_cb(1);
|
||||
|
||||
con &= ~S3C2410_ADCCON_MUXMASK;
|
||||
con &= ~S3C2410_ADCCON_STDBM;
|
||||
con &= ~S3C2410_ADCCON_STARTMASK;
|
||||
|
||||
if (!client->is_ts)
|
||||
con |= S3C2410_ADCCON_SELMUX(client->channel);
|
||||
|
||||
writel(con, adc->regs + S3C2410_ADCCON);
|
||||
}
|
||||
|
||||
static void s3c_adc_dbgshow(struct adc_device *adc)
|
||||
{
|
||||
adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
|
||||
readl(adc->regs + S3C2410_ADCCON),
|
||||
readl(adc->regs + S3C2410_ADCTSC),
|
||||
readl(adc->regs + S3C2410_ADCDLY));
|
||||
}
|
||||
|
||||
void s3c_adc_try(struct adc_device *adc)
|
||||
{
|
||||
struct s3c_adc_client *next = adc->ts_pend;
|
||||
|
||||
if (!next && !list_empty(&adc_pending)) {
|
||||
next = list_first_entry(&adc_pending,
|
||||
struct s3c_adc_client, pend);
|
||||
list_del(&next->pend);
|
||||
} else
|
||||
adc->ts_pend = NULL;
|
||||
|
||||
if (next) {
|
||||
adc_dbg(adc, "new client is %p\n", next);
|
||||
adc->cur = next;
|
||||
s3c_adc_select(adc, next);
|
||||
s3c_adc_convert(adc);
|
||||
s3c_adc_dbgshow(adc);
|
||||
}
|
||||
}
|
||||
|
||||
int s3c_adc_start(struct s3c_adc_client *client,
|
||||
unsigned int channel, unsigned int nr_samples)
|
||||
{
|
||||
struct adc_device *adc = adc_dev;
|
||||
unsigned long flags;
|
||||
|
||||
if (!adc) {
|
||||
printk(KERN_ERR "%s: failed to find adc\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (client->is_ts && adc->ts_pend)
|
||||
return -EAGAIN;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
client->channel = channel;
|
||||
client->nr_samples = nr_samples;
|
||||
|
||||
if (client->is_ts)
|
||||
adc->ts_pend = client;
|
||||
else
|
||||
list_add_tail(&client->pend, &adc_pending);
|
||||
|
||||
if (!adc->cur)
|
||||
s3c_adc_try(adc);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s3c_adc_start);
|
||||
|
||||
static void s3c_adc_default_select(unsigned select)
|
||||
{
|
||||
}
|
||||
|
||||
struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
|
||||
void (*select)(unsigned int selected),
|
||||
void (*conv)(unsigned d0, unsigned d1),
|
||||
unsigned int is_ts)
|
||||
{
|
||||
struct s3c_adc_client *client;
|
||||
|
||||
WARN_ON(!pdev);
|
||||
WARN_ON(!conv);
|
||||
|
||||
if (!select)
|
||||
select = s3c_adc_default_select;
|
||||
|
||||
if (!conv || !pdev)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
|
||||
if (!client) {
|
||||
dev_err(&pdev->dev, "no memory for adc client\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
client->pdev = pdev;
|
||||
client->is_ts = is_ts;
|
||||
client->select_cb = select;
|
||||
client->convert_cb = conv;
|
||||
|
||||
return client;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s3c_adc_register);
|
||||
|
||||
void s3c_adc_release(struct s3c_adc_client *client)
|
||||
{
|
||||
/* We should really check that nothing is in progress. */
|
||||
kfree(client);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s3c_adc_release);
|
||||
|
||||
static irqreturn_t s3c_adc_irq(int irq, void *pw)
|
||||
{
|
||||
struct adc_device *adc = pw;
|
||||
struct s3c_adc_client *client = adc->cur;
|
||||
unsigned long flags;
|
||||
unsigned data0, data1;
|
||||
|
||||
if (!client) {
|
||||
dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
data0 = readl(adc->regs + S3C2410_ADCDAT0);
|
||||
data1 = readl(adc->regs + S3C2410_ADCDAT1);
|
||||
adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
|
||||
|
||||
(client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
|
||||
|
||||
if (--client->nr_samples > 0) {
|
||||
/* fire another conversion for this */
|
||||
|
||||
client->select_cb(1);
|
||||
s3c_adc_convert(adc);
|
||||
} else {
|
||||
local_irq_save(flags);
|
||||
(client->select_cb)(0);
|
||||
adc->cur = NULL;
|
||||
|
||||
s3c_adc_try(adc);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int s3c_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct adc_device *adc;
|
||||
struct resource *regs;
|
||||
int ret;
|
||||
|
||||
adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
|
||||
if (adc == NULL) {
|
||||
dev_err(dev, "failed to allocate adc_device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
adc->pdev = pdev;
|
||||
adc->prescale = S3C2410_ADCCON_PRSCVL(49);
|
||||
|
||||
adc->irq = platform_get_irq(pdev, 1);
|
||||
if (adc->irq <= 0) {
|
||||
dev_err(dev, "failed to get adc irq\n");
|
||||
ret = -ENOENT;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to attach adc irq\n");
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
adc->clk = clk_get(dev, "adc");
|
||||
if (IS_ERR(adc->clk)) {
|
||||
dev_err(dev, "failed to get adc clock\n");
|
||||
ret = PTR_ERR(adc->clk);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs) {
|
||||
dev_err(dev, "failed to find registers\n");
|
||||
ret = -ENXIO;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
adc->regs = ioremap(regs->start, resource_size(regs));
|
||||
if (!adc->regs) {
|
||||
dev_err(dev, "failed to map registers\n");
|
||||
ret = -ENXIO;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
clk_enable(adc->clk);
|
||||
|
||||
writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
|
||||
adc->regs + S3C2410_ADCCON);
|
||||
|
||||
dev_info(dev, "attached adc driver\n");
|
||||
|
||||
platform_set_drvdata(pdev, adc);
|
||||
adc_dev = adc;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
clk_put(adc->clk);
|
||||
|
||||
err_irq:
|
||||
free_irq(adc->irq, adc);
|
||||
|
||||
err_alloc:
|
||||
kfree(adc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s3c_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct adc_device *adc = platform_get_drvdata(pdev);
|
||||
|
||||
iounmap(adc->regs);
|
||||
free_irq(adc->irq, adc);
|
||||
clk_disable(adc->clk);
|
||||
clk_put(adc->clk);
|
||||
kfree(adc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct adc_device *adc = platform_get_drvdata(pdev);
|
||||
u32 con;
|
||||
|
||||
con = readl(adc->regs + S3C2410_ADCCON);
|
||||
con |= S3C2410_ADCCON_STDBM;
|
||||
writel(con, adc->regs + S3C2410_ADCCON);
|
||||
|
||||
clk_disable(adc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_adc_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct adc_device *adc = platform_get_drvdata(pdev);
|
||||
|
||||
clk_enable(adc->clk);
|
||||
|
||||
writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
|
||||
adc->regs + S3C2410_ADCCON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define s3c_adc_suspend NULL
|
||||
#define s3c_adc_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver s3c_adc_driver = {
|
||||
.driver = {
|
||||
.name = "s3c24xx-adc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = s3c_adc_probe,
|
||||
.remove = __devexit_p(s3c_adc_remove),
|
||||
.suspend = s3c_adc_suspend,
|
||||
.resume = s3c_adc_resume,
|
||||
};
|
||||
|
||||
static int __init adc_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&s3c_adc_driver);
|
||||
if (ret)
|
||||
printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
arch_initcall(adc_init);
|
194
arch/arm/plat-s3c24xx/clock-dclk.c
Normal file
194
arch/arm/plat-s3c24xx/clock-dclk.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/* 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,
|
||||
};
|
|
@ -27,18 +27,8 @@
|
|||
*/
|
||||
|
||||
#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/sysdev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
@ -47,490 +37,23 @@
|
|||
#include <mach/regs-clock.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
||||
#include <plat/cpu-freq.h>
|
||||
|
||||
#include <plat/clock.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
/* clock information */
|
||||
|
||||
static LIST_HEAD(clocks);
|
||||
|
||||
DEFINE_MUTEX(clocks_mutex);
|
||||
|
||||
/* enable and disable calls for use with the clk struct */
|
||||
|
||||
static int clk_null_enable(struct clk *clk, int enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clock API calls */
|
||||
|
||||
struct clk *clk_get(struct device *dev, const char *id)
|
||||
{
|
||||
struct clk *p;
|
||||
struct clk *clk = ERR_PTR(-ENOENT);
|
||||
int idno;
|
||||
|
||||
if (dev == NULL || dev->bus != &platform_bus_type)
|
||||
idno = -1;
|
||||
else
|
||||
idno = to_platform_device(dev)->id;
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
|
||||
list_for_each_entry(p, &clocks, list) {
|
||||
if (p->id == idno &&
|
||||
strcmp(id, p->name) == 0 &&
|
||||
try_module_get(p->owner)) {
|
||||
clk = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for the case where a device was supplied, but the
|
||||
* clock that was being searched for is not device specific */
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
list_for_each_entry(p, &clocks, list) {
|
||||
if (p->id == -1 && strcmp(id, p->name) == 0 &&
|
||||
try_module_get(p->owner)) {
|
||||
clk = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&clocks_mutex);
|
||||
return clk;
|
||||
}
|
||||
|
||||
void clk_put(struct clk *clk)
|
||||
{
|
||||
module_put(clk->owner);
|
||||
}
|
||||
|
||||
int clk_enable(struct clk *clk)
|
||||
{
|
||||
if (IS_ERR(clk) || clk == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
clk_enable(clk->parent);
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
|
||||
if ((clk->usage++) == 0)
|
||||
(clk->enable)(clk, 1);
|
||||
|
||||
mutex_unlock(&clocks_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clk_disable(struct clk *clk)
|
||||
{
|
||||
if (IS_ERR(clk) || clk == NULL)
|
||||
return;
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
|
||||
if ((--clk->usage) == 0)
|
||||
(clk->enable)(clk, 0);
|
||||
|
||||
mutex_unlock(&clocks_mutex);
|
||||
clk_disable(clk->parent);
|
||||
}
|
||||
|
||||
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
if (IS_ERR(clk))
|
||||
return 0;
|
||||
|
||||
if (clk->rate != 0)
|
||||
return clk->rate;
|
||||
|
||||
if (clk->get_rate != NULL)
|
||||
return (clk->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(clk) && clk->round_rate)
|
||||
return (clk->round_rate)(clk, rate);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(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->set_rate == NULL);
|
||||
|
||||
if (clk->set_rate == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
ret = (clk->set_rate)(clk, rate);
|
||||
mutex_unlock(&clocks_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct clk *clk_get_parent(struct clk *clk)
|
||||
{
|
||||
return clk->parent;
|
||||
}
|
||||
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR(clk))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
|
||||
if (clk->set_parent)
|
||||
ret = (clk->set_parent)(clk, parent);
|
||||
|
||||
mutex_unlock(&clocks_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(clk_get);
|
||||
EXPORT_SYMBOL(clk_put);
|
||||
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 */
|
||||
|
||||
static int clk_default_setrate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
clk->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct clk clk_xtal = {
|
||||
.name = "xtal",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
};
|
||||
|
||||
struct clk clk_mpll = {
|
||||
.name = "mpll",
|
||||
.id = -1,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_upll = {
|
||||
.name = "upll",
|
||||
.id = -1,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
};
|
||||
|
||||
struct clk clk_f = {
|
||||
.name = "fclk",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = &clk_mpll,
|
||||
.ctrlbit = 0,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_h = {
|
||||
.name = "hclk",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_p = {
|
||||
.name = "pclk",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.parent = NULL,
|
||||
.ctrlbit = 0,
|
||||
.set_rate = clk_default_setrate,
|
||||
};
|
||||
|
||||
struct clk clk_usb_bus = {
|
||||
.name = "usb-bus",
|
||||
.id = -1,
|
||||
.rate = 0,
|
||||
.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 = {
|
||||
.name = "uclk",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
/* initialise the clock system */
|
||||
|
||||
int s3c24xx_register_clock(struct clk *clk)
|
||||
{
|
||||
clk->owner = THIS_MODULE;
|
||||
|
||||
if (clk->enable == NULL)
|
||||
clk->enable = clk_null_enable;
|
||||
|
||||
/* add to the list of available clocks */
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
list_add(&clk->list, &clocks);
|
||||
mutex_unlock(&clocks_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
fails++;
|
||||
}
|
||||
|
||||
return fails;
|
||||
}
|
||||
#include <plat/pll.h>
|
||||
|
||||
/* initalise all the clocks */
|
||||
|
||||
int __init s3c24xx_setup_clocks(unsigned long xtal,
|
||||
unsigned long fclk,
|
||||
unsigned long hclk,
|
||||
unsigned long pclk)
|
||||
void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
|
||||
unsigned long hclk,
|
||||
unsigned long pclk)
|
||||
{
|
||||
printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
|
||||
|
||||
/* initialise the main system clocks */
|
||||
|
||||
clk_xtal.rate = xtal;
|
||||
clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
|
||||
clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON),
|
||||
clk_xtal.rate);
|
||||
|
||||
clk_mpll.rate = fclk;
|
||||
clk_h.rate = hclk;
|
||||
clk_p.rate = pclk;
|
||||
clk_f.rate = fclk;
|
||||
|
||||
/* assume uart clocks are correctly setup */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -55,16 +55,6 @@
|
|||
#include <plat/s3c2442.h>
|
||||
#include <plat/s3c2443.h>
|
||||
|
||||
struct cpu_table {
|
||||
unsigned long idcode;
|
||||
unsigned long idmask;
|
||||
void (*map_io)(struct map_desc *mach_desc, int size);
|
||||
void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
|
||||
void (*init_clocks)(int xtal);
|
||||
int (*init)(void);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* table of supported CPUs */
|
||||
|
||||
static const char name_s3c2400[] = "S3C2400";
|
||||
|
@ -169,23 +159,7 @@ static struct map_desc s3c_iodesc[] __initdata = {
|
|||
IODESC_ENT(UART)
|
||||
};
|
||||
|
||||
static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode)
|
||||
{
|
||||
struct cpu_table *tab;
|
||||
int count;
|
||||
|
||||
tab = cpu_ids;
|
||||
for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
|
||||
if ((idcode & tab->idmask) == tab->idcode)
|
||||
return tab;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* cpu information */
|
||||
|
||||
static struct cpu_table *cpu;
|
||||
/* read cpu identificaiton code */
|
||||
|
||||
static unsigned long s3c24xx_read_idcode_v5(void)
|
||||
{
|
||||
|
@ -231,6 +205,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
|
|||
unsigned long idcode = 0x0;
|
||||
|
||||
/* initialise the io descriptors we need for initialisation */
|
||||
iotable_init(mach_desc, size);
|
||||
iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
|
||||
|
||||
if (cpu_architecture() >= CPU_ARCH_ARMv5) {
|
||||
|
@ -239,117 +214,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
|
|||
idcode = s3c24xx_read_idcode_v4();
|
||||
}
|
||||
|
||||
cpu = s3c_lookup_cpu(idcode);
|
||||
|
||||
if (cpu == NULL) {
|
||||
printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
|
||||
panic("Unknown S3C24XX CPU");
|
||||
}
|
||||
|
||||
printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
|
||||
|
||||
if (cpu->map_io == NULL || cpu->init == NULL) {
|
||||
printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
|
||||
panic("Unsupported S3C24XX CPU");
|
||||
}
|
||||
|
||||
arm_pm_restart = s3c24xx_pm_restart;
|
||||
|
||||
(cpu->map_io)(mach_desc, size);
|
||||
s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
|
||||
}
|
||||
|
||||
/* s3c24xx_init_clocks
|
||||
*
|
||||
* Initialise the clock subsystem and associated information from the
|
||||
* given master crystal value.
|
||||
*
|
||||
* xtal = 0 -> use default PLL crystal value (normally 12MHz)
|
||||
* != 0 -> PLL crystal value in Hz
|
||||
*/
|
||||
|
||||
void __init s3c24xx_init_clocks(int xtal)
|
||||
{
|
||||
if (xtal == 0)
|
||||
xtal = 12*1000*1000;
|
||||
|
||||
if (cpu == NULL)
|
||||
panic("s3c24xx_init_clocks: no cpu setup?\n");
|
||||
|
||||
if (cpu->init_clocks == NULL)
|
||||
panic("s3c24xx_init_clocks: cpu has no clock init\n");
|
||||
else
|
||||
(cpu->init_clocks)(xtal);
|
||||
}
|
||||
|
||||
/* uart management */
|
||||
|
||||
static int nr_uarts __initdata = 0;
|
||||
|
||||
static struct s3c2410_uartcfg uart_cfgs[3];
|
||||
|
||||
/* s3c24xx_init_uartdevs
|
||||
*
|
||||
* copy the specified platform data and configuration into our central
|
||||
* set of devices, before the data is thrown away after the init process.
|
||||
*
|
||||
* This also fills in the array passed to the serial driver for the
|
||||
* early initialisation of the console.
|
||||
*/
|
||||
|
||||
void __init s3c24xx_init_uartdevs(char *name,
|
||||
struct s3c24xx_uart_resources *res,
|
||||
struct s3c2410_uartcfg *cfg, int no)
|
||||
{
|
||||
struct platform_device *platdev;
|
||||
struct s3c2410_uartcfg *cfgptr = uart_cfgs;
|
||||
struct s3c24xx_uart_resources *resp;
|
||||
int uart;
|
||||
|
||||
memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
|
||||
|
||||
for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
|
||||
platdev = s3c24xx_uart_src[cfgptr->hwport];
|
||||
|
||||
resp = res + cfgptr->hwport;
|
||||
|
||||
s3c24xx_uart_devs[uart] = platdev;
|
||||
|
||||
platdev->name = name;
|
||||
platdev->resource = resp->resources;
|
||||
platdev->num_resources = resp->nr_resources;
|
||||
|
||||
platdev->dev.platform_data = cfgptr;
|
||||
}
|
||||
|
||||
nr_uarts = no;
|
||||
}
|
||||
|
||||
void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
|
||||
{
|
||||
if (cpu == NULL)
|
||||
return;
|
||||
|
||||
if (cpu->init_uarts == NULL) {
|
||||
printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
|
||||
} else
|
||||
(cpu->init_uarts)(cfg, no);
|
||||
}
|
||||
|
||||
static int __init s3c_arch_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// do the correct init for cpu
|
||||
|
||||
if (cpu == NULL)
|
||||
panic("s3c_arch_init: NULL cpu\n");
|
||||
|
||||
ret = (cpu->init)();
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
arch_initcall(s3c_arch_init);
|
||||
|
|
|
@ -372,12 +372,20 @@ static struct resource s3c_adc_resource[] = {
|
|||
};
|
||||
|
||||
struct platform_device s3c_device_adc = {
|
||||
.name = "s3c2410-adc",
|
||||
.name = "s3c24xx-adc",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s3c_adc_resource),
|
||||
.resource = s3c_adc_resource,
|
||||
};
|
||||
|
||||
/* HWMON */
|
||||
|
||||
struct platform_device s3c_device_hwmon = {
|
||||
.name = "s3c24xx-hwmon",
|
||||
.id = -1,
|
||||
.dev.parent = &s3c_device_adc.dev,
|
||||
};
|
||||
|
||||
/* SDI */
|
||||
|
||||
static struct resource s3c_sdi_resource[] = {
|
||||
|
|
|
@ -161,8 +161,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
|
|||
.ngpio = 24,
|
||||
.direction_input = s3c24xx_gpiolib_banka_input,
|
||||
.direction_output = s3c24xx_gpiolib_banka_output,
|
||||
.set = s3c24xx_gpiolib_set,
|
||||
.get = s3c24xx_gpiolib_get,
|
||||
},
|
||||
},
|
||||
[1] = {
|
||||
|
@ -172,10 +170,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
|
|||
.owner = THIS_MODULE,
|
||||
.label = "GPIOB",
|
||||
.ngpio = 16,
|
||||
.direction_input = s3c24xx_gpiolib_input,
|
||||
.direction_output = s3c24xx_gpiolib_output,
|
||||
.set = s3c24xx_gpiolib_set,
|
||||
.get = s3c24xx_gpiolib_get,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
|
@ -185,10 +179,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
|
|||
.owner = THIS_MODULE,
|
||||
.label = "GPIOC",
|
||||
.ngpio = 16,
|
||||
.direction_input = s3c24xx_gpiolib_input,
|
||||
.direction_output = s3c24xx_gpiolib_output,
|
||||
.set = s3c24xx_gpiolib_set,
|
||||
.get = s3c24xx_gpiolib_get,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
|
@ -198,10 +188,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
|
|||
.owner = THIS_MODULE,
|
||||
.label = "GPIOD",
|
||||
.ngpio = 16,
|
||||
.direction_input = s3c24xx_gpiolib_input,
|
||||
.direction_output = s3c24xx_gpiolib_output,
|
||||
.set = s3c24xx_gpiolib_set,
|
||||
.get = s3c24xx_gpiolib_get,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
|
@ -211,10 +197,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
|
|||
.label = "GPIOE",
|
||||
.owner = THIS_MODULE,
|
||||
.ngpio = 16,
|
||||
.direction_input = s3c24xx_gpiolib_input,
|
||||
.direction_output = s3c24xx_gpiolib_output,
|
||||
.set = s3c24xx_gpiolib_set,
|
||||
.get = s3c24xx_gpiolib_get,
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
|
@ -224,10 +206,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
|
|||
.owner = THIS_MODULE,
|
||||
.label = "GPIOF",
|
||||
.ngpio = 8,
|
||||
.direction_input = s3c24xx_gpiolib_input,
|
||||
.direction_output = s3c24xx_gpiolib_output,
|
||||
.set = s3c24xx_gpiolib_set,
|
||||
.get = s3c24xx_gpiolib_get,
|
||||
},
|
||||
},
|
||||
[6] = {
|
||||
|
@ -237,21 +215,38 @@ static struct s3c24xx_gpio_chip gpios[] = {
|
|||
.owner = THIS_MODULE,
|
||||
.label = "GPIOG",
|
||||
.ngpio = 10,
|
||||
.direction_input = s3c24xx_gpiolib_input,
|
||||
.direction_output = s3c24xx_gpiolib_output,
|
||||
.set = s3c24xx_gpiolib_set,
|
||||
.get = s3c24xx_gpiolib_get,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static __init void s3c24xx_gpiolib_add(struct s3c24xx_gpio_chip *chip)
|
||||
{
|
||||
struct gpio_chip *gc = &chip->chip;
|
||||
|
||||
BUG_ON(!chip->base);
|
||||
BUG_ON(!gc->label);
|
||||
BUG_ON(!gc->ngpio);
|
||||
|
||||
if (!gc->direction_input)
|
||||
gc->direction_input = s3c24xx_gpiolib_input;
|
||||
if (!gc->direction_output)
|
||||
gc->direction_output = s3c24xx_gpiolib_output;
|
||||
if (!gc->set)
|
||||
gc->set = s3c24xx_gpiolib_set;
|
||||
if (!gc->get)
|
||||
gc->get = s3c24xx_gpiolib_get;
|
||||
|
||||
/* gpiochip_add() prints own failure message on error. */
|
||||
gpiochip_add(gc);
|
||||
}
|
||||
|
||||
static __init int s3c24xx_gpiolib_init(void)
|
||||
{
|
||||
struct s3c24xx_gpio_chip *chip = gpios;
|
||||
int gpn;
|
||||
|
||||
for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++)
|
||||
gpiochip_add(&chip->chip);
|
||||
s3c24xx_gpiolib_add(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
37
arch/arm/plat-s3c24xx/include/plat/pll.h
Normal file
37
arch/arm/plat-s3c24xx/include/plat/pll.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* linux/arch/arm/plat-s3c24xx/include/plat/pll.h
|
||||
*
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* S3C24xx - common pll registers and code
|
||||
*/
|
||||
|
||||
#define S3C24XX_PLLCON_MDIVSHIFT 12
|
||||
#define S3C24XX_PLLCON_PDIVSHIFT 4
|
||||
#define S3C24XX_PLLCON_SDIVSHIFT 0
|
||||
#define S3C24XX_PLLCON_MDIVMASK ((1<<(1+(19-12)))-1)
|
||||
#define S3C24XX_PLLCON_PDIVMASK ((1<<5)-1)
|
||||
#define S3C24XX_PLLCON_SDIVMASK 3
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
static inline unsigned int
|
||||
s3c24xx_get_pll(unsigned int pllval, unsigned int baseclk)
|
||||
{
|
||||
unsigned int mdiv, pdiv, sdiv;
|
||||
uint64_t fvco;
|
||||
|
||||
mdiv = pllval >> S3C24XX_PLLCON_MDIVSHIFT;
|
||||
pdiv = pllval >> S3C24XX_PLLCON_PDIVSHIFT;
|
||||
sdiv = pllval >> S3C24XX_PLLCON_SDIVSHIFT;
|
||||
|
||||
mdiv &= S3C24XX_PLLCON_MDIVMASK;
|
||||
pdiv &= S3C24XX_PLLCON_PDIVMASK;
|
||||
sdiv &= S3C24XX_PLLCON_SDIVMASK;
|
||||
|
||||
fvco = (uint64_t)baseclk * (mdiv + 8);
|
||||
do_div(fvco, (pdiv + 2) << sdiv);
|
||||
|
||||
return (unsigned int)fvco;
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
extern int s3c2400_init(void);
|
||||
|
||||
extern void s3c2400_map_io(struct map_desc *mach_desc, int size);
|
||||
extern void s3c2400_map_io(void);
|
||||
|
||||
extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
extern int s3c2410_init(void);
|
||||
|
||||
extern void s3c2410_map_io(struct map_desc *mach_desc, int size);
|
||||
extern void s3c2410_map_io(void);
|
||||
|
||||
extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
extern int s3c2412_init(void);
|
||||
|
||||
extern void s3c2412_map_io(struct map_desc *mach_desc, int size);
|
||||
extern void s3c2412_map_io(void);
|
||||
|
||||
extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ struct s3c2410_uartcfg;
|
|||
|
||||
extern int s3c2443_init(void);
|
||||
|
||||
extern void s3c2443_map_io(struct map_desc *mach_desc, int size);
|
||||
extern void s3c2443_map_io(void);
|
||||
|
||||
extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no);
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <plat/regs-irqtype.h>
|
||||
#include <mach/regs-irq.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
||||
|
|
|
@ -76,11 +76,13 @@ static struct sleep_save core_save[] = {
|
|||
SAVE_ITEM(S3C2410_BANKCON4),
|
||||
SAVE_ITEM(S3C2410_BANKCON5),
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ
|
||||
SAVE_ITEM(S3C2410_CLKDIVN),
|
||||
SAVE_ITEM(S3C2410_MPLLCON),
|
||||
SAVE_ITEM(S3C2410_REFRESH),
|
||||
#endif
|
||||
SAVE_ITEM(S3C2410_UPLLCON),
|
||||
SAVE_ITEM(S3C2410_CLKSLOW),
|
||||
SAVE_ITEM(S3C2410_REFRESH),
|
||||
};
|
||||
|
||||
static struct gpio_sleep {
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <linux/sysdev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
|
@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev)
|
|||
if (clk_get_rate(clock_upll) > (94 * MHZ)) {
|
||||
clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
spin_lock(&clocks_lock);
|
||||
|
||||
clkdivn = __raw_readl(S3C2410_CLKDIVN);
|
||||
clkdivn |= S3C2440_CLKDIVN_UCLK;
|
||||
__raw_writel(clkdivn, S3C2410_CLKDIVN);
|
||||
|
||||
mutex_unlock(&clocks_mutex);
|
||||
spin_unlock(&clocks_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <plat/cpu-freq.h>
|
||||
|
||||
#include <mach/regs-clock.h>
|
||||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
@ -42,6 +44,7 @@
|
|||
#include <plat/devs.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/pm.h>
|
||||
#include <plat/pll.h>
|
||||
|
||||
static struct map_desc s3c244x_iodesc[] __initdata = {
|
||||
IODESC_ENT(CLKPWR),
|
||||
|
@ -56,12 +59,11 @@ void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
|
|||
s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
|
||||
}
|
||||
|
||||
void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
|
||||
void __init s3c244x_map_io(void)
|
||||
{
|
||||
/* register our io-tables */
|
||||
|
||||
iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
|
||||
iotable_init(mach_desc, size);
|
||||
|
||||
/* rename any peripherals used differing from the s3c2410 */
|
||||
|
||||
|
@ -71,17 +73,20 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
|
|||
s3c_device_usbgadget.name = "s3c2440-usbgadget";
|
||||
}
|
||||
|
||||
void __init s3c244x_init_clocks(int xtal)
|
||||
void __init_or_cpufreq s3c244x_setup_clocks(void)
|
||||
{
|
||||
struct clk *xtal_clk;
|
||||
unsigned long clkdiv;
|
||||
unsigned long camdiv;
|
||||
unsigned long xtal;
|
||||
unsigned long hclk, fclk, pclk;
|
||||
int hdiv = 1;
|
||||
|
||||
/* now we've got our machine bits initialised, work out what
|
||||
* clocks we've got */
|
||||
xtal_clk = clk_get(NULL, "xtal");
|
||||
xtal = clk_get_rate(xtal_clk);
|
||||
clk_put(xtal_clk);
|
||||
|
||||
fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
|
||||
fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
|
||||
|
||||
clkdiv = __raw_readl(S3C2410_CLKDIVN);
|
||||
camdiv = __raw_readl(S3C2440_CAMDIVN);
|
||||
|
@ -107,18 +112,24 @@ void __init s3c244x_init_clocks(int xtal)
|
|||
}
|
||||
|
||||
hclk = fclk / hdiv;
|
||||
pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
|
||||
pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
|
||||
|
||||
/* print brief summary of clocks, etc */
|
||||
|
||||
printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
|
||||
print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
|
||||
|
||||
s3c24xx_setup_clocks(fclk, hclk, pclk);
|
||||
}
|
||||
|
||||
void __init s3c244x_init_clocks(int xtal)
|
||||
{
|
||||
/* initialise the clocks here, to allow other things like the
|
||||
* console to use them, and to add new ones after the initialisation
|
||||
*/
|
||||
|
||||
s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
|
||||
s3c24xx_register_baseclocks(xtal);
|
||||
s3c244x_setup_clocks();
|
||||
s3c2410_baseclk_add();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
|
||||
|
||||
extern void s3c244x_map_io(struct map_desc *mach_desc, int size);
|
||||
extern void s3c244x_map_io(void);
|
||||
|
||||
extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
|
||||
|
||||
|
|
37
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
Normal file
37
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
|
||||
*
|
||||
* Copyright (c) 2008 Simtec Electronics
|
||||
* http://armlinux.simtec.co.uk/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C24XX SPI - gpio configuration for bus 0 on gpe11,12,13
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include <mach/spi.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
||||
void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
|
||||
int enable)
|
||||
{
|
||||
if (enable) {
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
|
||||
s3c2410_gpio_pullup(S3C2410_GPE11, 0);
|
||||
s3c2410_gpio_pullup(S3C2410_GPE13, 0);
|
||||
} else {
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPIO_INPUT);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPIO_INPUT);
|
||||
s3c2410_gpio_pullup(S3C2410_GPE11, 1);
|
||||
s3c2410_gpio_pullup(S3C2410_GPE12, 1);
|
||||
s3c2410_gpio_pullup(S3C2410_GPE13, 1);
|
||||
}
|
||||
}
|
37
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
Normal file
37
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpg5_6_7.c
|
||||
*
|
||||
* Copyright (c) 2008 Simtec Electronics
|
||||
* http://armlinux.simtec.co.uk/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C24XX SPI - gpio configuration for bus 1 on gpg5,6,7
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include <mach/spi.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
||||
void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
|
||||
int enable)
|
||||
{
|
||||
if (enable) {
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
|
||||
s3c2410_gpio_pullup(S3C2410_GPG5, 0);
|
||||
s3c2410_gpio_pullup(S3C2410_GPG6, 0);
|
||||
} else {
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPIO_INPUT);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPIO_INPUT);
|
||||
s3c2410_gpio_pullup(S3C2410_GPG5, 1);
|
||||
s3c2410_gpio_pullup(S3C2410_GPG6, 1);
|
||||
s3c2410_gpio_pullup(S3C2410_GPG7, 1);
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
|
||||
|
@ -452,6 +453,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
|
|||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
|
||||
ourport->pm_level = level;
|
||||
|
||||
switch (level) {
|
||||
case 3:
|
||||
if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
|
||||
|
@ -661,6 +664,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|||
|
||||
ourport->clksrc = clksrc;
|
||||
ourport->baudclk = clk;
|
||||
ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
|
||||
}
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
|
@ -890,6 +894,93 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port,
|
|||
return (info->reset_port)(port, cfg);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
|
||||
static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
struct s3c24xx_uart_port *port;
|
||||
struct uart_port *uport;
|
||||
|
||||
port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
|
||||
uport = &port->port;
|
||||
|
||||
/* check to see if port is enabled */
|
||||
|
||||
if (port->pm_level != 0)
|
||||
return 0;
|
||||
|
||||
/* try and work out if the baudrate is changing, we can detect
|
||||
* a change in rate, but we do not have support for detecting
|
||||
* a disturbance in the clock-rate over the change.
|
||||
*/
|
||||
|
||||
if (IS_ERR(port->clk))
|
||||
goto exit;
|
||||
|
||||
if (port->baudclk_rate == clk_get_rate(port->clk))
|
||||
goto exit;
|
||||
|
||||
if (val == CPUFREQ_PRECHANGE) {
|
||||
/* we should really shut the port down whilst the
|
||||
* frequency change is in progress. */
|
||||
|
||||
} else if (val == CPUFREQ_POSTCHANGE) {
|
||||
struct ktermios *termios;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (uport->info == NULL) {
|
||||
printk(KERN_WARNING "%s: info NULL\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
tty = uport->info->port.tty;
|
||||
|
||||
if (tty == NULL) {
|
||||
printk(KERN_WARNING "%s: tty is NULL\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
termios = tty->termios;
|
||||
|
||||
if (termios == NULL) {
|
||||
printk(KERN_WARNING "%s: no termios?\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s3c24xx_serial_set_termios(uport, termios, NULL);
|
||||
}
|
||||
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
|
||||
|
||||
return cpufreq_register_notifier(&port->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
cpufreq_unregister_notifier(&port->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* s3c24xx_serial_init_port
|
||||
*
|
||||
* initialise a single serial port from the platform device given
|
||||
|
@ -1002,6 +1093,10 @@ int s3c24xx_serial_probe(struct platform_device *dev,
|
|||
if (ret < 0)
|
||||
printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
|
||||
|
||||
ret = s3c24xx_serial_cpufreq_register(ourport);
|
||||
if (ret < 0)
|
||||
dev_err(&dev->dev, "failed to add cpufreq notifier\n");
|
||||
|
||||
return 0;
|
||||
|
||||
probe_err:
|
||||
|
@ -1015,6 +1110,7 @@ int s3c24xx_serial_remove(struct platform_device *dev)
|
|||
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
|
||||
|
||||
if (port) {
|
||||
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
|
||||
device_remove_file(&dev->dev, &dev_attr_clock_source);
|
||||
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
||||
}
|
||||
|
|
|
@ -33,12 +33,18 @@ struct s3c24xx_uart_info {
|
|||
struct s3c24xx_uart_port {
|
||||
unsigned char rx_claimed;
|
||||
unsigned char tx_claimed;
|
||||
unsigned int pm_level;
|
||||
unsigned long baudclk_rate;
|
||||
|
||||
struct s3c24xx_uart_info *info;
|
||||
struct s3c24xx_uart_clksrc *clksrc;
|
||||
struct clk *clk;
|
||||
struct clk *baudclk;
|
||||
struct uart_port port;
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
struct notifier_block freq_transition;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* conversion functions */
|
||||
|
|
Loading…
Reference in a new issue