diff options
53 files changed, 2273 insertions, 475 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e4b74fbdba0..80203dcb97f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -717,6 +717,7 @@ config ARCH_S5PC100 config ARCH_S5PV210 bool "Samsung S5PV210/S5PC110" select CPU_V7 + select ARCH_SPARSEMEM_ENABLE select GENERIC_GPIO select HAVE_CLK select ARM_L1_CACHE_SHIFT_6 @@ -730,9 +731,12 @@ config ARCH_S5PV210 config ARCH_S5PV310 bool "Samsung S5PV310/S5PC210" select CPU_V7 + select ARCH_SPARSEMEM_ENABLE select GENERIC_GPIO select HAVE_CLK select GENERIC_CLOCKEVENTS + select HAVE_S3C_RTC + select HAVE_S3C2410_WATCHDOG help Samsung S5PV310 series based systems diff --git a/arch/arm/mach-s3c64xx/gpiolib.c b/arch/arm/mach-s3c64xx/gpiolib.c index 300dee4a667..fd99a82e82c 100644 --- a/arch/arm/mach-s3c64xx/gpiolib.c +++ b/arch/arm/mach-s3c64xx/gpiolib.c @@ -195,11 +195,6 @@ static struct s3c_gpio_cfg gpio_2bit_cfg_eint11 = { .get_pull = s3c_gpio_getpull_updown, }; -int s3c64xx_gpio2int_gpn(struct gpio_chip *chip, unsigned pin) -{ - return IRQ_EINT(0) + pin; -} - static struct s3c_gpio_chip gpio_2bit[] = { { .base = S3C64XX_GPF_BASE, @@ -227,12 +222,13 @@ static struct s3c_gpio_chip gpio_2bit[] = { }, }, { .base = S3C64XX_GPN_BASE, + .irq_base = IRQ_EINT(0), .config = &gpio_2bit_cfg_eint10, .chip = { .base = S3C64XX_GPN(0), .ngpio = S3C64XX_GPIO_N_NR, .label = "GPN", - .to_irq = s3c64xx_gpio2int_gpn, + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = S3C64XX_GPO_BASE, diff --git a/arch/arm/mach-s5p6442/Kconfig b/arch/arm/mach-s5p6442/Kconfig index 0fda0a5df96..33569e4007c 100644 --- a/arch/arm/mach-s5p6442/Kconfig +++ b/arch/arm/mach-s5p6442/Kconfig @@ -11,7 +11,6 @@ if ARCH_S5P6442 config CPU_S5P6442 bool - select PLAT_S5P select S3C_PL330_DMA help Enable S5P6442 CPU support diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig index fbcae935202..164d2783d38 100644 --- a/arch/arm/mach-s5p64x0/Kconfig +++ b/arch/arm/mach-s5p64x0/Kconfig @@ -9,14 +9,12 @@ if ARCH_S5P64X0 config CPU_S5P6440 bool - select PLAT_S5P select S3C_PL330_DMA help Enable S5P6440 CPU support config CPU_S5P6450 bool - select PLAT_S5P select S3C_PL330_DMA help Enable S5P6450 CPU support diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig index 77ae4bfb74b..b8fbf2fcba6 100644 --- a/arch/arm/mach-s5pc100/Kconfig +++ b/arch/arm/mach-s5pc100/Kconfig @@ -9,7 +9,6 @@ if ARCH_S5PC100 config CPU_S5PC100 bool - select PLAT_S5P select S5P_EXT_INT select S3C_PL330_DMA help diff --git a/arch/arm/mach-s5pc100/Makefile b/arch/arm/mach-s5pc100/Makefile index a021ed1fb4b..eecab57d2e5 100644 --- a/arch/arm/mach-s5pc100/Makefile +++ b/arch/arm/mach-s5pc100/Makefile @@ -11,7 +11,7 @@ obj- := # Core support for S5PC100 system -obj-$(CONFIG_CPU_S5PC100) += cpu.o init.o clock.o gpiolib.o irq-gpio.o +obj-$(CONFIG_CPU_S5PC100) += cpu.o init.o clock.o gpiolib.o obj-$(CONFIG_CPU_S5PC100) += setup-i2c0.o obj-$(CONFIG_CPU_S5PC100) += dma.o diff --git a/arch/arm/mach-s5pc100/gpiolib.c b/arch/arm/mach-s5pc100/gpiolib.c index 0fab7f2cd8b..def4ff83e05 100644 --- a/arch/arm/mach-s5pc100/gpiolib.c +++ b/arch/arm/mach-s5pc100/gpiolib.c @@ -61,30 +61,6 @@ * L3 8 4Bit None */ -static int s5pc100_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - return S3C_IRQ_GPIO(chip->base + offset); -} - -static int s5pc100_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset) -{ - int base; - - base = chip->base - S5PC100_GPH0(0); - if (base == 0) - return IRQ_EINT(offset); - base = chip->base - S5PC100_GPH1(0); - if (base == 0) - return IRQ_EINT(8 + offset); - base = chip->base - S5PC100_GPH2(0); - if (base == 0) - return IRQ_EINT(16 + offset); - base = chip->base - S5PC100_GPH3(0); - if (base == 0) - return IRQ_EINT(24 + offset); - return -EINVAL; -} - static struct s3c_gpio_cfg gpio_cfg = { .set_config = s3c_gpio_setcfg_s3c64xx_4bit, .set_pull = s3c_gpio_setpull_updown, @@ -228,34 +204,42 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { }, { .base = S5PC100_GPH0_BASE, .config = &gpio_cfg_eint, + .irq_base = IRQ_EINT(0), .chip = { .base = S5PC100_GPH0(0), .ngpio = S5PC100_GPIO_H0_NR, .label = "GPH0", + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = S5PC100_GPH1_BASE, .config = &gpio_cfg_eint, + .irq_base = IRQ_EINT(8), .chip = { .base = S5PC100_GPH1(0), .ngpio = S5PC100_GPIO_H1_NR, .label = "GPH1", + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = S5PC100_GPH2_BASE, .config = &gpio_cfg_eint, + .irq_base = IRQ_EINT(16), .chip = { .base = S5PC100_GPH2(0), .ngpio = S5PC100_GPIO_H2_NR, .label = "GPH2", + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = S5PC100_GPH3_BASE, .config = &gpio_cfg_eint, + .irq_base = IRQ_EINT(24), .chip = { .base = S5PC100_GPH3(0), .ngpio = S5PC100_GPIO_H3_NR, .label = "GPH3", + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = S5PC100_GPI_BASE, @@ -380,47 +364,25 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { }, }; -/* FIXME move from irq-gpio.c */ -extern struct irq_chip s5pc100_gpioint; -extern void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc); - -static __init void s5pc100_gpiolib_link(struct s3c_gpio_chip *chip) -{ - /* Interrupt */ - if (chip->config == &gpio_cfg) { - int i, irq; - - chip->chip.to_irq = s5pc100_gpiolib_to_irq; - - for (i = 0; i < chip->chip.ngpio; i++) { - irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i; - set_irq_chip(irq, &s5pc100_gpioint); - set_irq_data(irq, &chip->chip); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } - } else if (chip->config == &gpio_cfg_eint) { - chip->chip.to_irq = s5pc100_gpiolib_to_eint; - } -} - static __init int s5pc100_gpiolib_init(void) { struct s3c_gpio_chip *chip; int nr_chips; + int gpioint_group = 0; chip = s5pc100_gpio_chips; nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); - for (; nr_chips > 0; nr_chips--, chip++) - s5pc100_gpiolib_link(chip); + for (; nr_chips > 0; nr_chips--, chip++) { + if (chip->config == &gpio_cfg) { + /* gpio interrupts */ + chip->group = gpioint_group++; + } + } samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, ARRAY_SIZE(s5pc100_gpio_chips)); - /* Interrupt */ - set_irq_chained_handler(IRQ_GPIOINT, s5pc100_irq_gpioint_handler); - return 0; } core_initcall(s5pc100_gpiolib_init); diff --git a/arch/arm/mach-s5pc100/include/mach/gpio.h b/arch/arm/mach-s5pc100/include/mach/gpio.h index 71ae1f52df1..29a8a12d9b4 100644 --- a/arch/arm/mach-s5pc100/include/mach/gpio.h +++ b/arch/arm/mach-s5pc100/include/mach/gpio.h @@ -146,13 +146,6 @@ enum s5p_gpio_number { /* define the number of gpios we need to the one after the MP04() range */ #define ARCH_NR_GPIOS (S5PC100_GPIO_END + 1) -#define EINT_MODE S3C_GPIO_SFN(0x2) - -#define EINT_GPIO_0(x) S5PC100_GPH0(x) -#define EINT_GPIO_1(x) S5PC100_GPH1(x) -#define EINT_GPIO_2(x) S5PC100_GPH2(x) -#define EINT_GPIO_3(x) S5PC100_GPH3(x) - #include <asm-generic/gpio.h> #endif /* __ASM_ARCH_GPIO_H */ diff --git a/arch/arm/mach-s5pc100/include/mach/irqs.h b/arch/arm/mach-s5pc100/include/mach/irqs.h index 06513e64724..e782dd6bcf6 100644 --- a/arch/arm/mach-s5pc100/include/mach/irqs.h +++ b/arch/arm/mach-s5pc100/include/mach/irqs.h @@ -100,11 +100,12 @@ #define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0)) #define S5P_EINT_BASE2 (IRQ_VIC_END + 1) -#define S3C_IRQ_GPIO_BASE (IRQ_EINT(31) + 1) -#define S3C_IRQ_GPIO(x) (S3C_IRQ_GPIO_BASE + (x)) +/* GPIO interrupt */ +#define S5P_GPIOINT_BASE (IRQ_EINT(31) + 1) +#define S5P_GPIOINT_GROUP_MAXNR 21 -/* Until MP04 Groups -> 40 (exactly 39) Groups * 8 ~= 320 GPIOs */ -#define NR_IRQS (S3C_IRQ_GPIO(320) + 1) +/* Set the default NR_IRQS */ +#define NR_IRQS (IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1) /* Compatibility */ #define IRQ_LCD_FIFO IRQ_LCD0 diff --git a/arch/arm/mach-s5pc100/include/mach/regs-gpio.h b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h index dd6295e1251..8c47536b117 100644 --- a/arch/arm/mach-s5pc100/include/mach/regs-gpio.h +++ b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h @@ -64,12 +64,12 @@ #define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7)) -/* values for S5P_EXTINT0 */ -#define S5P_EXTINT_LOWLEV (0x00) -#define S5P_EXTINT_HILEV (0x01) -#define S5P_EXTINT_FALLEDGE (0x02) -#define S5P_EXTINT_RISEEDGE (0x03) -#define S5P_EXTINT_BOTHEDGE (0x04) +#define EINT_MODE S3C_GPIO_SFN(0x2) + +#define EINT_GPIO_0(x) S5PC100_GPH0(x) +#define EINT_GPIO_1(x) S5PC100_GPH1(x) +#define EINT_GPIO_2(x) S5PC100_GPH2(x) +#define EINT_GPIO_3(x) S5PC100_GPH3(x) #endif /* __ASM_MACH_S5PC100_REGS_GPIO_H */ diff --git a/arch/arm/mach-s5pc100/irq-gpio.c b/arch/arm/mach-s5pc100/irq-gpio.c deleted file mode 100644 index 2bf86c18bc7..00000000000 --- a/arch/arm/mach-s5pc100/irq-gpio.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * arch/arm/mach-s5pc100/irq-gpio.c - * - * Copyright (C) 2009 Samsung Electronics - * - * S5PC100 - Interrupt handling for IRQ_GPIO${group}(x) - * - * 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/kernel.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> - -#include <mach/map.h> -#include <plat/gpio-cfg.h> - -#define S5P_GPIOREG(x) (S5P_VA_GPIO + (x)) - -#define CON_OFFSET 0x700 -#define MASK_OFFSET 0x900 -#define PEND_OFFSET 0xA00 -#define CON_OFFSET_2 0xE00 -#define MASK_OFFSET_2 0xF00 -#define PEND_OFFSET_2 0xF40 - -#define GPIOINT_LEVEL_LOW 0x0 -#define GPIOINT_LEVEL_HIGH 0x1 -#define GPIOINT_EDGE_FALLING 0x2 -#define GPIOINT_EDGE_RISING 0x3 -#define GPIOINT_EDGE_BOTH 0x4 - -static int group_to_con_offset(int group) -{ - return group << 2; -} - -static int group_to_mask_offset(int group) -{ - return group << 2; -} - -static int group_to_pend_offset(int group) -{ - return group << 2; -} - -static int s5pc100_get_start(unsigned int group) -{ - switch (group) { - case 0: return S5PC100_GPIO_A0_START; - case 1: return S5PC100_GPIO_A1_START; - case 2: return S5PC100_GPIO_B_START; - case 3: return S5PC100_GPIO_C_START; - case 4: return S5PC100_GPIO_D_START; - case 5: return S5PC100_GPIO_E0_START; - case 6: return S5PC100_GPIO_E1_START; - case 7: return S5PC100_GPIO_F0_START; - case 8: return S5PC100_GPIO_F1_START; - case 9: return S5PC100_GPIO_F2_START; - case 10: return S5PC100_GPIO_F3_START; - case 11: return S5PC100_GPIO_G0_START; - case 12: return S5PC100_GPIO_G1_START; - case 13: return S5PC100_GPIO_G2_START; - case 14: return S5PC100_GPIO_G3_START; - case 15: return S5PC100_GPIO_I_START; - case 16: return S5PC100_GPIO_J0_START; - case 17: return S5PC100_GPIO_J1_START; - case 18: return S5PC100_GPIO_J2_START; - case 19: return S5PC100_GPIO_J3_START; - case 20: return S5PC100_GPIO_J4_START; - default: - BUG(); - } - - return -EINVAL; -} - -static int s5pc100_get_group(unsigned int irq) -{ - irq -= S3C_IRQ_GPIO(0); - - switch (irq) { - case S5PC100_GPIO_A0_START ... S5PC100_GPIO_A1_START - 1: - return 0; - case S5PC100_GPIO_A1_START ... S5PC100_GPIO_B_START - 1: - return 1; - case S5PC100_GPIO_B_START ... S5PC100_GPIO_C_START - 1: - return 2; - case S5PC100_GPIO_C_START ... S5PC100_GPIO_D_START - 1: - return 3; - case S5PC100_GPIO_D_START ... S5PC100_GPIO_E0_START - 1: - return 4; - case S5PC100_GPIO_E0_START ... S5PC100_GPIO_E1_START - 1: - return 5; - case S5PC100_GPIO_E1_START ... S5PC100_GPIO_F0_START - 1: - return 6; - case S5PC100_GPIO_F0_START ... S5PC100_GPIO_F1_START - 1: - return 7; - case S5PC100_GPIO_F1_START ... S5PC100_GPIO_F2_START - 1: - return 8; - case S5PC100_GPIO_F2_START ... S5PC100_GPIO_F3_START - 1: - return 9; - case S5PC100_GPIO_F3_START ... S5PC100_GPIO_G0_START - 1: - return 10; - case S5PC100_GPIO_G0_START ... S5PC100_GPIO_G1_START - 1: - return 11; - case S5PC100_GPIO_G1_START ... S5PC100_GPIO_G2_START - 1: - return 12; - case S5PC100_GPIO_G2_START ... S5PC100_GPIO_G3_START - 1: - return 13; - case S5PC100_GPIO_G3_START ... S5PC100_GPIO_H0_START - 1: - return 14; - case S5PC100_GPIO_I_START ... S5PC100_GPIO_J0_START - 1: - return 15; - case S5PC100_GPIO_J0_START ... S5PC100_GPIO_J1_START - 1: - return 16; - case S5PC100_GPIO_J1_START ... S5PC100_GPIO_J2_START - 1: - return 17; - case S5PC100_GPIO_J2_START ... S5PC100_GPIO_J3_START - 1: - return 18; - case S5PC100_GPIO_J3_START ... S5PC100_GPIO_J4_START - 1: - return 19; - case S5PC100_GPIO_J4_START ... S5PC100_GPIO_K0_START - 1: - return 20; - default: - BUG(); - } - - return -EINVAL; -} - -static int s5pc100_get_offset(unsigned int irq) -{ - struct gpio_chip *chip = get_irq_data(irq); - return irq - S3C_IRQ_GPIO(chip->base); -} - -static void s5pc100_gpioint_ack(unsigned int irq) -{ - int group, offset, pend_offset; - unsigned int value; - - group = s5pc100_get_group(irq); - offset = s5pc100_get_offset(irq); - pend_offset = group_to_pend_offset(group); - - value = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset); - value |= 1 << offset; - __raw_writel(value, S5P_GPIOREG(PEND_OFFSET) + pend_offset); -} - -static void s5pc100_gpioint_mask(unsigned int irq) -{ - int group, offset, mask_offset; - unsigned int value; - - group = s5pc100_get_group(irq); - offset = s5pc100_get_offset(irq); - mask_offset = group_to_mask_offset(group); - - value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset); - value |= 1 << offset; - __raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset); -} - -static void s5pc100_gpioint_unmask(unsigned int irq) -{ - int group, offset, mask_offset; - unsigned int value; - - group = s5pc100_get_group(irq); - offset = s5pc100_get_offset(irq); - mask_offset = group_to_mask_offset(group); - - value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset); - value &= ~(1 << offset); - __raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset); -} - -static void s5pc100_gpioint_mask_ack(unsigned int irq) -{ - s5pc100_gpioint_mask(irq); - s5pc100_gpioint_ack(irq); -} - -static int s5pc100_gpioint_set_type(unsigned int irq, unsigned int type) -{ - int group, offset, con_offset; - unsigned int value; - - group = s5pc100_get_group(irq); - offset = s5pc100_get_offset(irq); - con_offset = group_to_con_offset(group); - - switch (type) { - case IRQ_TYPE_NONE: - printk(KERN_WARNING "No irq type\n"); - return -EINVAL; - case IRQ_TYPE_EDGE_RISING: - type = GPIOINT_EDGE_RISING; - break; - case IRQ_TYPE_EDGE_FALLING: - type = GPIOINT_EDGE_FALLING; - break; - case IRQ_TYPE_EDGE_BOTH: - type = GPIOINT_EDGE_BOTH; - break; - case IRQ_TYPE_LEVEL_HIGH: - type = GPIOINT_LEVEL_HIGH; - break; - case IRQ_TYPE_LEVEL_LOW: - type = GPIOINT_LEVEL_LOW; - break; - default: - BUG(); - } - - - value = __raw_readl(S5P_GPIOREG(CON_OFFSET) + con_offset); - value &= ~(0xf << (offset * 0x4)); - value |= (type << (offset * 0x4)); - __raw_writel(value, S5P_GPIOREG(CON_OFFSET) + con_offset); - - return 0; -} - -struct irq_chip s5pc100_gpioint = { - .name = "GPIO", - .ack = s5pc100_gpioint_ack, - .mask = s5pc100_gpioint_mask, - .mask_ack = s5pc100_gpioint_mask_ack, - .unmask = s5pc100_gpioint_unmask, - .set_type = s5pc100_gpioint_set_type, -}; - -void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc) -{ - int group, offset, pend_offset, mask_offset; - int real_irq, group_end; - unsigned int pend, mask; - - group_end = 21; - - for (group = 0; group < group_end; group++) { - pend_offset = group_to_pend_offset(group); - pend = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset); - if (!pend) - continue; - - mask_offset = group_to_mask_offset(group); - mask = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset); - pend &= ~mask; - - for (offset = 0; offset < 8; offset++) { - if (pend & (1 << offset)) { - real_irq = s5pc100_get_start(group) + offset; - generic_handle_irq(S3C_IRQ_GPIO(real_irq)); - } - } - } -} diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index 5315fec3db8..862f239a0fd 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig @@ -11,9 +11,9 @@ if ARCH_S5PV210 config CPU_S5PV210 bool - select PLAT_S5P select S3C_PL330_DMA select S5P_EXT_INT + select S5PV210_PM if PM help Enable S5PV210 CPU support @@ -58,7 +58,6 @@ menu "S5PC110 Machines" config MACH_AQUILA bool "Aquila" select CPU_S5PV210 - select ARCH_SPARSEMEM_ENABLE select S3C_DEV_FB select S5P_DEV_FIMC0 select S5P_DEV_FIMC1 @@ -75,7 +74,7 @@ config MACH_AQUILA config MACH_GONI bool "GONI" select CPU_S5PV210 - select ARCH_SPARSEMEM_ENABLE + select S5P_GPIO_INT select S3C_DEV_FB select S5P_DEV_FIMC0 select S5P_DEV_FIMC1 @@ -83,8 +82,15 @@ config MACH_GONI select S3C_DEV_HSMMC select S3C_DEV_HSMMC1 select S3C_DEV_HSMMC2 + select S3C_DEV_I2C1 + select S3C_DEV_I2C2 + select S3C_DEV_USB_HSOTG select S5P_DEV_ONENAND + select SAMSUNG_DEV_KEYPAD select S5PV210_SETUP_FB_24BPP + select S5PV210_SETUP_I2C1 + select S5PV210_SETUP_I2C2 + select S5PV210_SETUP_KEYPAD select S5PV210_SETUP_SDHCI help Machine support for Samsung GONI board @@ -93,7 +99,6 @@ config MACH_GONI config MACH_SMDKC110 bool "SMDKC110" select CPU_S5PV210 - select ARCH_SPARSEMEM_ENABLE select S3C_DEV_I2C1 select S3C_DEV_I2C2 select S3C_DEV_RTC @@ -113,7 +118,6 @@ menu "S5PV210 Machines" config MACH_SMDKV210 bool "SMDKV210" select CPU_S5PV210 - select ARCH_SPARSEMEM_ENABLE select S3C_DEV_HSMMC select S3C_DEV_HSMMC1 select S3C_DEV_HSMMC2 @@ -134,6 +138,29 @@ config MACH_SMDKV210 help Machine support for Samsung SMDKV210 +config MACH_TORBRECK + bool "Torbreck" + select CPU_S5PV210 + select ARCH_SPARSEMEM_ENABLE + select S3C_DEV_HSMMC + select S3C_DEV_HSMMC1 + select S3C_DEV_HSMMC2 + select S3C_DEV_HSMMC3 + select S3C_DEV_I2C1 + select S3C_DEV_I2C2 + select S3C_DEV_RTC + select S3C_DEV_WDT + select S5PV210_SETUP_I2C1 + select S5PV210_SETUP_I2C2 + select S5PV210_SETUP_SDHCI + help + Machine support for aESOP Torbreck + endmenu +config S5PV210_PM + bool + help + Power Management code common to S5PV210 + endif diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile index 70454891240..157754f0a91 100644 --- a/arch/arm/mach-s5pv210/Makefile +++ b/arch/arm/mach-s5pv210/Makefile @@ -14,6 +14,7 @@ obj- := obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o gpiolib.o obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o +obj-$(CONFIG_S5PV210_PM) += pm.o sleep.o # machine support @@ -21,6 +22,7 @@ obj-$(CONFIG_MACH_AQUILA) += mach-aquila.o obj-$(CONFIG_MACH_SMDKV210) += mach-smdkv210.o obj-$(CONFIG_MACH_SMDKC110) += mach-smdkc110.o obj-$(CONFIG_MACH_GONI) += mach-goni.o +obj-$(CONFIG_MACH_TORBRECK) += mach-torbreck.o # device support diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c index 2f16bfc0a11..8eb480e201b 100644 --- a/arch/arm/mach-s5pv210/cpu.c +++ b/arch/arm/mach-s5pv210/cpu.c @@ -85,6 +85,21 @@ static struct map_desc s5pv210_iodesc[] __initdata = { .pfn = __phys_to_pfn(S5PV210_PA_SROMC), .length = SZ_4K, .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S5P_VA_DMC0, + .pfn = __phys_to_pfn(S5PV210_PA_DMC0), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S5P_VA_DMC1, + .pfn = __phys_to_pfn(S5PV210_PA_DMC1), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_USB_HSPHY, + .pfn =__phys_to_pfn(S5PV210_PA_HSPHY), + .length = SZ_4K, + .type = MT_DEVICE, } }; diff --git a/arch/arm/mach-s5pv210/gpiolib.c b/arch/arm/mach-s5pv210/gpiolib.c index 0d459112d03..ab673effd76 100644 --- a/arch/arm/mach-s5pv210/gpiolib.c +++ b/arch/arm/mach-s5pv210/gpiolib.c @@ -150,6 +150,7 @@ static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { .label = "GPG3", }, }, { + .config = &gpio_cfg_noint, .chip = { .base = S5PV210_GPI(0), .ngpio = S5PV210_GPIO_I_NR, @@ -223,34 +224,42 @@ static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { }, { .base = (S5P_VA_GPIO + 0xC00), .config = &gpio_cfg_noint, + .irq_base = IRQ_EINT(0), .chip = { .base = S5PV210_GPH0(0), .ngpio = S5PV210_GPIO_H0_NR, .label = "GPH0", + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = (S5P_VA_GPIO + 0xC20), .config = &gpio_cfg_noint, + .irq_base = IRQ_EINT(8), .chip = { .base = S5PV210_GPH1(0), .ngpio = S5PV210_GPIO_H1_NR, .label = "GPH1", + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = (S5P_VA_GPIO + 0xC40), .config = &gpio_cfg_noint, + .irq_base = IRQ_EINT(16), .chip = { .base = S5PV210_GPH2(0), .ngpio = S5PV210_GPIO_H2_NR, .label = "GPH2", + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = (S5P_VA_GPIO + 0xC60), .config = &gpio_cfg_noint, + .irq_base = IRQ_EINT(24), .chip = { .base = S5PV210_GPH3(0), .ngpio = S5PV210_GPIO_H3_NR, .label = "GPH3", + .to_irq = samsung_gpiolib_to_irq, }, }, }; @@ -259,11 +268,14 @@ static __init int s5pv210_gpiolib_init(void) { struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); + int gpioint_group = 0; int i = 0; for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) + if (chip->config == NULL) { chip->config = &gpio_cfg; + chip->group = gpioint_group++; + } if (chip->base == NULL) chip->base = S5PV210_BANK_BASE(i); } diff --git a/arch/arm/mach-s5pv210/include/mach/irqs.h b/arch/arm/mach-s5pv210/include/mach/irqs.h index e1c020e5a49..bb7f277c1fa 100644 --- a/arch/arm/mach-s5pv210/include/mach/irqs.h +++ b/arch/arm/mach-s5pv210/include/mach/irqs.h @@ -109,7 +109,7 @@ #define IRQ_IPC S5P_IRQ_VIC3(0) #define IRQ_HOSTIF S5P_IRQ_VIC3(1) -#define IRQ_MMC3 S5P_IRQ_VIC3(2) +#define IRQ_HSMMC3 S5P_IRQ_VIC3(2) #define IRQ_CEC S5P_IRQ_VIC3(3) #define IRQ_TSI S5P_IRQ_VIC3(4) #define IRQ_MDNIE0 S5P_IRQ_VIC3(5) @@ -121,8 +121,12 @@ #define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0)) #define S5P_EINT_BASE2 (IRQ_VIC_END + 1) +/* GPIO interrupt */ +#define S5P_GPIOINT_BASE (IRQ_EINT(31) + 1) +#define S5P_GPIOINT_GROUP_MAXNR 22 + /* Set the default NR_IRQS */ -#define NR_IRQS (IRQ_EINT(31) + 1) +#define NR_IRQS (IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1) /* Compatibility */ #define IRQ_LCD_FIFO IRQ_LCD0 diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h index bd9afd52466..0e24ba14cd2 100644 --- a/arch/arm/mach-s5pv210/include/mach/map.h +++ b/arch/arm/mach-s5pv210/include/mach/map.h @@ -57,6 +57,8 @@ #define S5P_SZ_UART SZ_256 +#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) + #define S5PV210_PA_SROMC (0xE8000000) #define S5PV210_PA_CFCON (0xE8200000) @@ -73,6 +75,9 @@ #define S5PV210_PA_HSMMC(x) (0xEB000000 + ((x) * 0x100000)) +#define S5PV210_PA_HSOTG (0xEC000000) +#define S5PV210_PA_HSPHY (0xEC100000) + #define S5PV210_PA_VIC0 (0xF2000000) #define S5PV210_PA_VIC1 (0xF2100000) #define S5PV210_PA_VIC2 (0xF2200000) @@ -96,6 +101,9 @@ #define S5PV210_PA_ADC (0xE1700000) +#define S5PV210_PA_DMC0 (0xF0000000) +#define S5PV210_PA_DMC1 (0xF1400000) + /* compatibiltiy defines. */ #define S3C_PA_UART S5PV210_PA_UART #define S3C_PA_HSMMC0 S5PV210_PA_HSMMC(0) @@ -108,6 +116,7 @@ #define S3C_PA_FB S5PV210_PA_FB #define S3C_PA_RTC S5PV210_PA_RTC #define S3C_PA_WDT S5PV210_PA_WATCHDOG +#define S3C_PA_USB_HSOTG S5PV210_PA_HSOTG #define S5P_PA_FIMC0 S5PV210_PA_FIMC0 #define S5P_PA_FIMC1 S5PV210_PA_FIMC1 #define S5P_PA_FIMC2 S5PV210_PA_FIMC2 diff --git a/arch/arm/mach-s5pv210/include/mach/pm-core.h b/arch/arm/mach-s5pv210/include/mach/pm-core.h new file mode 100644 index 00000000000..e8d394f8b05 --- /dev/null +++ b/arch/arm/mach-s5pv210/include/mach/pm-core.h @@ -0,0 +1,43 @@ +/* linux/arch/arm/mach-s5pv210/include/mach/pm-core.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Based on arch/arm/mach-s3c2410/include/mach/pm-core.h, + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S5PV210 - PM core support for arch/arm/plat-s5p/pm.c + * + * 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. +*/ + +static inline void s3c_pm_debug_init_uart(void) +{ + /* nothing here yet */ +} + +static inline void s3c_pm_arch_prepare_irqs(void) +{ + __raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK); + __raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK); +} + +static inline void s3c_pm_arch_stop_clocks(void) +{ + /* nothing here yet */ +} + +static inline void s3c_pm_arch_show_resume_irqs(void) +{ + /* nothing here yet */ +} + +static inline void s3c_pm_arch_update_uart(void __iomem *regs, + struct pm_uart_save *save) +{ + /* nothing here yet */ +} diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h index 499aef73747..929fd3a33f8 100644 --- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h @@ -95,7 +95,7 @@ /* Registers related to power management */ #define S5P_PWR_CFG S5P_CLKREG(0xC000) #define S5P_EINT_WAKEUP_MASK S5P_CLKREG(0xC004) -#define S5P_WAKEUP_MASK S5P_CLKREG(0xC008) +#define S5P_WAKEUP_MASK S5P_CLKREG(0xC008) #define S5P_PWR_MODE S5P_CLKREG(0xC00C) #define S5P_NORMAL_CFG S5P_CLKREG(0xC010) #define S5P_IDLE_CFG S5P_CLKREG(0xC020) @@ -159,8 +159,11 @@ #define S5P_SLEEP_CFG_USBOSC_EN (1 << 1) /* OTHERS Resgister */ +#define S5P_OTHERS_RET_IO (1 << 31) +#define S5P_OTHERS_RET_CF (1 << 30) +#define S5P_OTHERS_RET_MMC (1 << 29) +#define S5P_OTHERS_RET_UART (1 << 28) #define S5P_OTHERS_USB_SIG_MASK (1 << 16) -#define S5P_OTHERS_MIPI_DPHY_EN (1 << 28) /* MIPI */ #define S5P_MIPI_DPHY_EN (3) diff --git a/arch/arm/mach-s5pv210/include/mach/regs-gpio.h b/arch/arm/mach-s5pv210/include/mach/regs-gpio.h index 49e029b4978..de0c8997607 100644 --- a/arch/arm/mach-s5pv210/include/mach/regs-gpio.h +++ b/arch/arm/mach-s5pv210/include/mach/regs-gpio.h @@ -31,13 +31,6 @@ #define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7)) -/* values for S5P_EXTINT0 */ -#define S5P_EXTINT_LOWLEV (0x00) -#define S5P_EXTINT_HILEV (0x01) -#define S5P_EXTINT_FALLEDGE (0x02) -#define S5P_EXTINT_RISEEDGE (0x03) -#define S5P_EXTINT_BOTHEDGE (0x04) - #define EINT_MODE S3C_GPIO_SFN(0xf) #define EINT_GPIO_0(x) S5PV210_GPH0(x) diff --git a/arch/arm/mach-s5pv210/include/mach/regs-sys.h b/arch/arm/mach-s5pv210/include/mach/regs-sys.h new file mode 100644 index 00000000000..26691d39d0f --- /dev/null +++ b/arch/arm/mach-s5pv210/include/mach/regs-sys.h @@ -0,0 +1,19 @@ +/* arch/arm/mach-s5pv210/include/mach/regs-sys.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5PV210 - System registers definitions + * + * 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. +*/ + +#define S5PV210_USB_PHY_CON (S3C_VA_SYS + 0xE80C) +#define S5PV210_USB_PHY0_EN (1 << 0) +#define S5PV210_USB_PHY1_EN (1 << 1) + +/* compatibility defines for s3c-hsotg driver */ +#define S3C64XX_OTHERS S5PV210_USB_PHY_CON +#define S3C64XX_OTHERS_USBMASK S5PV210_USB_PHY0_EN diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c index fdc5cca4eb4..1bae3f13f0a 100644 --- a/arch/arm/mach-s5pv210/mach-goni.c +++ b/arch/arm/mach-s5pv210/mach-goni.c @@ -15,7 +15,12 @@ #include <linux/fb.h> #include <linux/i2c.h> #include <linux/i2c-gpio.h> +#include <linux/i2c/qt602240_ts.h> #include <linux/mfd/max8998.h> +#include <linux/regulator/fixed.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_gpio.h> +#include <linux/lcd.h> #include <linux/gpio_keys.h> #include <linux/input.h> #include <linux/gpio.h> @@ -35,7 +40,10 @@ #include <plat/devs.h> #include <plat/cpu.h> #include <plat/fb.h> +#include <plat/iic.h> +#include <plat/keypad.h> #include <plat/sdhci.h> +#include <plat/clock.h> /* Following are default values for UCON, ULCON and UFCON UART registers */ #define GONI_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ @@ -87,13 +95,12 @@ static struct s3c2410_uartcfg goni_uartcfgs[] __initdata = { /* Frame Buffer */ static struct s3c_fb_pd_win goni_fb_win0 = { .win_mode = { - .pixclock = 1000000000000ULL / ((16+16+2+480)*(28+3+2+800)*55), .left_margin = 16, .right_margin = 16, - .upper_margin = 3, + .upper_margin = 2, .lower_margin = 28, .hsync_len = 2, - .vsync_len = 2, + .vsync_len = 1, .xres = 480, .yres = 800, .refresh = 55, @@ -111,9 +118,160 @@ static struct s3c_fb_platdata goni_lcd_pdata __initdata = { .setup_gpio = s5pv210_fb_gpio_setup_24bpp, }; +static int lcd_power_on(struct lcd_device *ld, int enable) +{ + return 1; +} + +static int reset_lcd(struct lcd_device *ld) +{ + static unsigned int first = 1; + int reset_gpio = -1; + + reset_gpio = S5PV210_MP05(5); + + if (first) { + gpio_request(reset_gpio, "MLCD_RST"); + first = 0; + } + + gpio_direction_output(reset_gpio, 1); + return 1; +} + +static struct lcd_platform_data goni_lcd_platform_data = { + .reset = reset_lcd, + .power_on = lcd_power_on, + .lcd_enabled = 0, + .reset_delay = 120, /* 120ms */ + .power_on_delay = 25, /* 25ms */ + .power_off_delay = 200, /* 200ms */ +}; + +#define LCD_BUS_NUM 3 +static struct spi_board_info spi_board_info[] __initdata = { + { + .modalias = "s6e63m0", + .platform_data = &goni_lcd_platform_data, + .max_speed_hz = 1200000, + .bus_num = LCD_BUS_NUM, + .chip_select = 0, + .mode = SPI_MODE_3, + .controller_data = (void *)S5PV210_MP01(1), /* DISPLAY_CS */ + }, +}; + +static struct spi_gpio_platform_data lcd_spi_gpio_data = { + .sck = S5PV210_MP04(1), /* DISPLAY_CLK */ + .mosi = S5PV210_MP04(3), /* DISPLAY_SI */ + .miso = SPI_GPIO_NO_MISO, + .num_chipselect = 1, +}; + +static struct platform_device goni_spi_gpio = { + .name = "spi_gpio", + .id = LCD_BUS_NUM, + .dev = { + .parent = &s3c_device_fb.dev, + .platform_data = &lcd_spi_gpio_data, + }, +}; + +/* KEYPAD */ +static uint32_t keymap[] __initdata = { + /* KEY(row, col, keycode) */ + KEY(0, 1, KEY_MENU), /* Send */ + KEY(0, 2, KEY_BACK), /* End */ + KEY(1, 1, KEY_CONFIG), /* Half shot */ + KEY(1, 2, KEY_VOLUMEUP), + KEY(2, 1, KEY_CAMERA), /* Full shot */ + KEY(2, 2, KEY_VOLUMEDOWN), +}; + +static struct matrix_keymap_data keymap_data __initdata = { + .keymap = keymap, + .keymap_size = ARRAY_SIZE(keymap), +}; + +static struct samsung_keypad_platdata keypad_data __initdata = { + .keymap_data = &keymap_data, + .rows = 3, + .cols = 3, +}; + +/* Radio */ +static struct i2c_board_info i2c1_devs[] __initdata = { + { + I2C_BOARD_INFO("si470x", 0x10), + }, +}; + +static void __init goni_radio_init(void) +{ + int gpio; + + gpio = S5PV210_GPJ2(4); /* XMSMDATA_4 */ + gpio_request(gpio, "FM_INT"); + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf)); + i2c1_devs[0].irq = gpio_to_irq(gpio); + + gpio = S5PV210_GPJ2(5); /* XMSMDATA_5 */ + gpio_request(gpio, "FM_RST"); + gpio_direction_output(gpio, 1); +} + +/* TSP */ +static struct qt602240_platform_data qt602240_platform_data = { + .x_line = 17, + .y_line = 11, + .x_size = 800, + .y_size = 480, + .blen = 0x21, + .threshold = 0x28, + .voltage = 2800000, /* 2.8V */ + .orient = QT602240_DIAGONAL, +}; + +static struct s3c2410_platform_i2c i2c2_data __initdata = { + .flags = 0, + .bus_num = 2, + .slave_addr = 0x10, + .frequency = 400 * 1000, + .sda_delay = 100, +}; + +static struct i2c_board_info i2c2_devs[] __initdata = { + { + I2C_BOARD_INFO("qt602240_ts", 0x4a), + .platform_data = &qt602240_platform_data, + }, +}; + +static void __init goni_tsp_init(void) +{ + int gpio; + + gpio = S5PV210_GPJ1(3); /* XMSMADDR_11 */ + gpio_request(gpio, "TSP_LDO_ON"); + gpio_direction_output(gpio, 1); + gpio_export(gpio, 0); + + gpio = S5PV210_GPJ0(5); /* XMSMADDR_5 */ + gpio_request(gpio, "TSP_INT"); + + s5p_register_gpio_interrupt(gpio); + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + i2c2_devs[0].irq = gpio_to_irq(gpio); +} + /* MAX8998 regulators */ #if defined(CONFIG_REGULATOR_MAX8998) || defined(CONFIG_REGULATOR_MAX8998_MODULE) +static struct regulator_consumer_supply goni_ldo5_consumers[] = { + REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"), +}; + static struct regulator_init_data goni_ldo2_data = { .constraints = { .name = "VALIVE_1.1V", @@ -153,6 +311,8 @@ static struct regulator_init_data goni_ldo5_data = { .max_uV = 2800000, .apply_uV = 1, }, + .num_consumer_supplies = ARRAY_SIZE(goni_ldo5_consumers), + .consumer_supplies = goni_ldo5_consumers, }; static struct regulator_init_data goni_ldo6_data = { @@ -444,11 +604,37 @@ static struct s3c_sdhci_platdata goni_hsmmc2_data __initdata = { .ext_cd_gpio_invert = 1, }; +static struct regulator_consumer_supply mmc2_supplies[] = { + REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"), +}; + +static struct regulator_init_data mmc2_fixed_voltage_init_data = { + .constraints = { + .name = "V_TF_2.8V", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(mmc2_supplies), + .consumer_supplies = mmc2_supplies, +}; + +static struct fixed_voltage_config mmc2_fixed_voltage_config = { + .supply_name = "EXT_FLASH_EN", + .microvolts = 2800000, + .gpio = GONI_EXT_FLASH_EN, + .enable_high = true, + .init_data = &mmc2_fixed_voltage_init_data, +}; + +static struct platform_device mmc2_fixed_voltage = { + .name = "reg-fixed-voltage", + .id = 2, + .dev = { + .platform_data = &mmc2_fixed_voltage_config, + }, +}; + static void goni_setup_sdhci(void) { - gpio_request(GONI_EXT_FLASH_EN, "FLASH_EN"); - gpio_direction_output(GONI_EXT_FLASH_EN, 1); - s3c_sdhci0_set_platdata(&goni_hsmmc0_data); s3c_sdhci1_set_platdata(&goni_hsmmc1_data); s3c_sdhci2_set_platdata(&goni_hsmmc2_data); @@ -457,7 +643,9 @@ static void goni_setup_sdhci(void) static struct platform_device *goni_devices[] __initdata = { &s3c_device_fb, &s5p_device_onenand, + &goni_spi_gpio, &goni_i2c_gpio_pmic, + &mmc2_fixed_voltage, &goni_device_gpiokeys, &s5p_device_fimc0, &s5p_device_fimc1, @@ -465,6 +653,10 @@ static struct platform_device *goni_devices[] __initdata = { &s3c_device_hsmmc0, &s3c_device_hsmmc1, &s3c_device_hsmmc2, + &s3c_device_usb_hsotg, + &samsung_device_keypad, + &s3c_device_i2c1, + &s3c_device_i2c2, }; static void __init goni_map_io(void) @@ -476,6 +668,20 @@ static void __init goni_map_io(void) static void __init goni_machine_init(void) { + /* Radio: call before I2C 1 registeration */ + goni_radio_init(); + + /* I2C1 */ + s3c_i2c1_set_platdata(NULL); + i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs)); + + /* TSP: call before I2C 2 registeration */ + goni_tsp_init(); + + /* I2C2 */ + s3c_i2c2_set_platdata(&i2c2_data); + i2c_register_board_info(2, i2c2_devs, ARRAY_SIZE(i2c2_devs)); + /* PMIC */ goni_pmic_init(); i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs, @@ -486,6 +692,14 @@ static void __init goni_machine_init(void) /* FB */ s3c_fb_set_platdata(&goni_lcd_pdata); + /* SPI */ + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); + + /* KEYPAD */ + samsung_keypad_set_platdata(&keypad_data); + + clk_xusbxti.rate = 24000000; + platform_add_devices(goni_devices, ARRAY_SIZE(goni_devices)); } diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c index 8211bb87c54..053b50ddcfa 100644 --- a/arch/arm/mach-s5pv210/mach-smdkc110.c +++ b/arch/arm/mach-s5pv210/mach-smdkc110.c @@ -28,6 +28,7 @@ #include <plat/cpu.h> #include <plat/ata.h> #include <plat/iic.h> +#include <plat/pm.h> /* Following are default values for UCON, ULCON and UFCON UART registers */ #define SMDKC110_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ @@ -110,6 +111,8 @@ static void __init smdkc110_map_io(void) static void __init smdkc110_machine_init(void) { + s3c_pm_init(); + s3c_i2c0_set_platdata(NULL); s3c_i2c1_set_platdata(NULL); s3c_i2c2_set_platdata(NULL); diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index fbbc0a3c373..5a9c79cb63b 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -31,6 +31,7 @@ #include <plat/ata.h> #include <plat/iic.h> #include <plat/keypad.h> +#include <plat/pm.h> /* Following are default values for UCON, ULCON and UFCON UART registers */ #define SMDKV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ @@ -145,6 +146,8 @@ static void __init smdkv210_map_io(void) static void __init smdkv210_machine_init(void) { + s3c_pm_init(); + samsung_keypad_set_platdata(&smdkv210_keypad_data); s3c24xx_ts_set_platdata(&s3c_ts_platform); diff --git a/arch/arm/mach-s5pv210/mach-torbreck.c b/arch/arm/mach-s5pv210/mach-torbreck.c new file mode 100644 index 00000000000..043c938806b --- /dev/null +++ b/arch/arm/mach-s5pv210/mach-torbreck.c @@ -0,0 +1,131 @@ +/* linux/arch/arm/mach-s5pv210/mach-torbreck.c + * + * Copyright (c) 2010 aESOP Community + * http://www.aesop.or.kr/ + * + * 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/kernel.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/serial_core.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/setup.h> +#include <asm/mach-types.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> + +#include <plat/regs-serial.h> +#include <plat/s5pv210.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/iic.h> + +/* Following are default values for UCON, ULCON and UFCON UART registers */ +#define TORBRECK_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ + S3C2410_UCON_RXILEVEL | \ + S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI | \ + S3C2443_UCON_RXERR_IRQEN) + +#define TORBRECK_ULCON_DEFAULT S3C2410_LCON_CS8 + +#define TORBRECK_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ + S5PV210_UFCON_TXTRIG4 | \ + S5PV210_UFCON_RXTRIG4) + +static struct s3c2410_uartcfg torbreck_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = TORBRECK_UCON_DEFAULT, + .ulcon = TORBRECK_ULCON_DEFAULT, + .ufcon = TORBRECK_UFCON_DEFAULT, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = TORBRECK_UCON_DEFAULT, + .ulcon = TORBRECK_ULCON_DEFAULT, + .ufcon = TORBRECK_UFCON_DEFAULT, + }, + [2] = { + .hwport = 2, + .flags = 0, + .ucon = TORBRECK_UCON_DEFAULT, + .ulcon = TORBRECK_ULCON_DEFAULT, + .ufcon = TORBRECK_UFCON_DEFAULT, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = TORBRECK_UCON_DEFAULT, + .ulcon = TORBRECK_ULCON_DEFAULT, + .ufcon = TORBRECK_UFCON_DEFAULT, + }, +}; + +static struct platform_device *torbreck_devices[] __initdata = { + &s5pv210_device_iis0, + &s3c_device_cfcon, + &s3c_device_hsmmc0, + &s3c_device_hsmmc1, + &s3c_device_hsmmc2, + &s3c_device_hsmmc3, + &s3c_device_i2c0, + &s3c_device_i2c1, + &s3c_device_i2c2, + &s3c_device_rtc, + &s3c_device_wdt, +}; + +static struct i2c_board_info torbreck_i2c_devs0[] __initdata = { + /* To Be Updated */ +}; + +static struct i2c_board_info torbreck_i2c_devs1[] __initdata = { + /* To Be Updated */ +}; + +static struct i2c_board_info torbreck_i2c_devs2[] __initdata = { + /* To Be Updated */ +}; + +static void __init torbreck_map_io(void) +{ + s5p_init_io(NULL, 0, S5P_VA_CHIPID); + s3c24xx_init_clocks(24000000); + s3c24xx_init_uarts(torbreck_uartcfgs, ARRAY_SIZE(torbreck_uartcfgs)); +} + +static void __init torbreck_machine_init(void) +{ + s3c_i2c0_set_platdata(NULL); + s3c_i2c1_set_platdata(NULL); + s3c_i2c2_set_platdata(NULL); + i2c_register_board_info(0, torbreck_i2c_devs0, + ARRAY_SIZE(torbreck_i2c_devs0)); + i2c_register_board_info(1, torbreck_i2c_devs1, + ARRAY_SIZE(torbreck_i2c_devs1)); + i2c_register_board_info(2, torbreck_i2c_devs2, + ARRAY_SIZE(torbreck_i2c_devs2)); + + platform_add_devices(torbreck_devices, ARRAY_SIZE(torbreck_devices)); +} + +MACHINE_START(TORBRECK, "TORBRECK") + /* Maintainer: Hyunchul Ko <ghcstop@gmail.com> */ + .boot_params = S5P_PA_SDRAM + 0x100, + .init_irq = s5pv210_init_irq, + .map_io = torbreck_map_io, + .init_machine = torbreck_machine_init, + .timer = &s3c24xx_timer, +MACHINE_END diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c new file mode 100644 index 00000000000..549d7924fd4 --- /dev/null +++ b/arch/arm/mach-s5pv210/pm.c @@ -0,0 +1,166 @@ +/* linux/arch/arm/mach-s5pv210/pm.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5PV210 - Power Management support + * + * Based on arch/arm/mach-s3c2410/pm.c + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/io.h> + +#include <plat/cpu.h> +#include <plat/pm.h> +#include <plat/regs-timer.h> + +#include <mach/regs-irq.h> +#include <mach/regs-clock.h> + +static struct sleep_save s5pv210_core_save[] = { + /* Clock source */ + SAVE_ITEM(S5P_CLK_SRC0), + SAVE_ITEM(S5P_CLK_SRC1), + SAVE_ITEM(S5P_CLK_SRC2), + SAVE_ITEM(S5P_CLK_SRC3), + SAVE_ITEM(S5P_CLK_SRC4), + SAVE_ITEM(S5P_CLK_SRC5), + SAVE_ITEM(S5P_CLK_SRC6), + + /* Clock source Mask */ + SAVE_ITEM(S5P_CLK_SRC_MASK0), + SAVE_ITEM(S5P_CLK_SRC_MASK1), + + /* Clock Divider */ + SAVE_ITEM(S5P_CLK_DIV0), + SAVE_ITEM(S5P_CLK_DIV1), + SAVE_ITEM(S5P_CLK_DIV2), + SAVE_ITEM(S5P_CLK_DIV3), + SAVE_ITEM(S5P_CLK_DIV4), + SAVE_ITEM(S5P_CLK_DIV5), + SAVE_ITEM(S5P_CLK_DIV6), + SAVE_ITEM(S5P_CLK_DIV7), + + /* Clock Main Gate */ + SAVE_ITEM(S5P_CLKGATE_MAIN0), + SAVE_ITEM(S5P_CLKGATE_MAIN1), + SAVE_ITEM(S5P_CLKGATE_MAIN2), + + /* Clock source Peri Gate */ + SAVE_ITEM(S5P_CLKGATE_PERI0), + SAVE_ITEM(S5P_CLKGATE_PERI1), + + /* Clock source SCLK Gate */ + SAVE_ITEM(S5P_CLKGATE_SCLK0), + SAVE_ITEM(S5P_CLKGATE_SCLK1), + + /* Clock IP Clock gate */ + SAVE_ITEM(S5P_CLKGATE_IP0), + SAVE_ITEM(S5P_CLKGATE_IP1), + SAVE_ITEM(S5P_CLKGATE_IP2), + SAVE_ITEM(S5P_CLKGATE_IP3), + SAVE_ITEM(S5P_CLKGATE_IP4), + + /* Clock Blcok and Bus gate */ + SAVE_ITEM(S5P_CLKGATE_BLOCK), + SAVE_ITEM(S5P_CLKGATE_BUS0), + + /* Clock ETC */ + SAVE_ITEM(S5P_CLK_OUT), + SAVE_ITEM(S5P_MDNIE_SEL), + + /* PWM Register */ + SAVE_ITEM(S3C2410_TCFG0), + SAVE_ITEM(S3C2410_TCFG1), + SAVE_ITEM(S3C64XX_TINT_CSTAT), + SAVE_ITEM(S3C2410_TCON), + SAVE_ITEM(S3C2410_TCNTB(0)), + SAVE_ITEM(S3C2410_TCMPB(0)), + SAVE_ITEM(S3C2410_TCNTO(0)), +}; + +void s5pv210_cpu_suspend(void) +{ + unsigned long tmp; + + /* issue the standby signal into the pm unit. Note, we + * issue a write-buffer drain just in case */ + + tmp = 0; + + asm("b 1f\n\t" + ".align 5\n\t" + "1:\n\t" + "mcr p15, 0, %0, c7, c10, 5\n\t" + "mcr p15, 0, %0, c7, c10, 4\n\t" + "wfi" : : "r" (tmp)); + + /* we should never get past here */ + panic("sleep resumed to originator?"); +} + +static void s5pv210_pm_prepare(void) +{ + unsigned int tmp; + + /* ensure at least INFORM0 has the resume address */ + __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0); + + tmp = __raw_readl(S5P_SLEEP_CFG); + tmp &= ~(S5P_SLEEP_CFG_OSC_EN | S5P_SLEEP_CFG_USBOSC_EN); + __raw_writel(tmp, S5P_SLEEP_CFG); + + /* WFI for SLEEP mode configuration by SYSCON */ + tmp = __raw_readl(S5P_PWR_CFG); + tmp &= S5P_CFG_WFI_CLEAN; + tmp |= S5P_CFG_WFI_SLEEP; + __raw_writel(tmp, S5P_PWR_CFG); + + /* SYSCON interrupt handling disable */ + tmp = __raw_readl(S5P_OTHERS); + tmp |= S5P_OTHER_SYSC_INTOFF; + __raw_writel(tmp, S5P_OTHERS); + + s3c_pm_do_save(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save)); +} + +static int s5pv210_pm_add(struct sys_device *sysdev) +{ + pm_cpu_prep = s5pv210_pm_prepare; + pm_cpu_sleep = s5pv210_cpu_suspend; + + return 0; +} + +static int s5pv210_pm_resume(struct sys_device *dev) +{ + u32 tmp; + + tmp = __raw_readl(S5P_OTHERS); + tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF |\ + S5P_OTHERS_RET_MMC | S5P_OTHERS_RET_UART); + __raw_writel(tmp , S5P_OTHERS); + + s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save)); + + return 0; +} + +static struct sysdev_driver s5pv210_pm_driver = { + .add = s5pv210_pm_add, + .resume = s5pv210_pm_resume, +}; + +static __init int s5pv210_pm_drvinit(void) +{ + return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver); +} +arch_initcall(s5pv210_pm_drvinit); diff --git a/arch/arm/mach-s5pv210/sleep.S b/arch/arm/mach-s5pv210/sleep.S new file mode 100644 index 00000000000..d4d222b716b --- /dev/null +++ b/arch/arm/mach-s5pv210/sleep.S @@ -0,0 +1,170 @@ +/* linux/arch/arm/plat-s5p/sleep.S + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5PV210 power Manager (Suspend-To-RAM) support + * Based on S3C2410 sleep code by: + * Ben Dooks, (c) 2004 Simtec Electronics + * + * Based on PXA/SA1100 sleep code by: + * Nicolas Pitre, (c) 2002 Monta Vista Software Inc + * Cliff Brake, (c) 2001 + * + * 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/linkage.h> +#include <asm/assembler.h> +#include <asm/memory.h> + + .text + + /* s3c_cpu_save + * + * entry: + * r0 = save address (virtual addr of s3c_sleep_save_phys) + */ + +ENTRY(s3c_cpu_save) + + stmfd sp!, { r3 - r12, lr } + + mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID + mrc p15, 0, r5, c3, c0, 0 @ Domain ID + mrc p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 + mrc p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 + mrc p15, 0, r8, c2, c0, 2 @ Translation Table Control + mrc p15, 0, r9, c1, c0, 0 @ Control register + mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register + mrc p15, 0, r11, c1, c0, 2 @ Co-processor access controls + mrc p15, 0, r12, c10, c2, 0 @ Read PRRR + mrc p15, 0, r3, c10, c2, 1 @ READ NMRR + + stmia r0, { r3 - r13 } + + bl s3c_pm_cb_flushcache + + ldr r0, =pm_cpu_sleep + ldr r0, [ r0 ] + mov pc, r0 + +resume_with_mmu: + /* + * After MMU is turned on, restore the previous MMU table. + */ + ldr r9 , =(PAGE_OFFSET - PHYS_OFFSET) + add r4, r4, r9 + str r12, [r4] + + ldmfd sp!, { r3 - r12, pc } + + .ltorg + + .data + + .global s3c_sleep_save_phys +s3c_sleep_save_phys: + .word 0 + + /* sleep magic, to allow the bootloader to check for an valid + * image to resume to. Must be the first word before the + * s3c_cpu_resume entry. + */ + + .word 0x2bedf00d + + /* s3c_cpu_resume + * + * resume code entry for bootloader to call + * + * we must put this code here in the data segment as we have no + * other way of restoring the stack pointer after sleep, and we + * must not write to the code segment (code is read-only) + */ + +ENTRY(s3c_cpu_resume) + mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE + msr cpsr_c, r0 + + mov r1, #0 + mcr p15, 0, r1, c8, c7, 0 @ invalidate TLBs + mcr p15, 0, r1, c7, c5, 0 @ invalidate I Cache + + ldr r0, s3c_sleep_save_phys @ address of restore block + ldmia r0, { r3 - r13 } + + mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID + mcr p15, 0, r5, c3, c0, 0 @ Domain ID + + mcr p15, 0, r8, c2, c0, 2 @ Translation Table Control + mcr p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 + mcr p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 + + mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register + + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ Invalidate I & D TLB + + mov r0, #0 @ restore copro access + mcr p15, 0, r11, c1, c0, 2 @ Co-processor access + mcr p15, 0, r0, c7, c5, 4 + + mcr p15, 0, r12, c10, c2, 0 @ write PRRR + mcr p15, 0, r3, c10, c2, 1 @ write NMRR + + /* + * In Cortex-A8, when MMU is turned on, the pipeline is flushed. + * And there are no valid entries in the MMU table at this point. + * So before turning on the MMU, the MMU entry for the DRAM address + * range is added. After the MMU is turned on, the other entries + * in the MMU table will be restored. + */ + + /* r6 = Translation Table BASE0 */ + mov r4, r6 + mov r4, r4, LSR #14 + mov r4, r4, LSL #14 + + /* Load address for adding to MMU table list */ + ldr r11, =0xE010F000 @ INFORM0 reg. + ldr r10, [r11, #0] + mov r10, r10, LSR #18 + bic r10, r10, #0x3 + orr r4, r4, r10 + + /* Calculate MMU table entry */ + mov r10, r10, LSL #18 + ldr r5, =0x40E + orr r10, r10, r5 + + /* Back up originally data */ + ldr r12, [r4] + + /* Add calculated MMU table entry into MMU table list */ + str r10, [r4] + + ldr r2, =resume_with_mmu + mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, etc + + nop + nop + nop + nop + nop @ second-to-last before mmu + + mov pc, r2 @ go back to virtual address + + .ltorg diff --git a/arch/arm/mach-s5pv310/Kconfig b/arch/arm/mach-s5pv310/Kconfig index 331b5bd97ab..9941852b7a0 100644 --- a/arch/arm/mach-s5pv310/Kconfig +++ b/arch/arm/mach-s5pv310/Kconfig @@ -11,7 +11,6 @@ if ARCH_S5PV310 config CPU_S5PV310 bool - select PLAT_S5P help Enable S5PV310 CPU support @@ -27,19 +26,36 @@ config S5PV310_SETUP_I2C2 # machine support -config MACH_SMDKV310 - bool "SMDKV310" +menu "S5PC210 Machines" + +config MACH_SMDKC210 + bool "SMDKC210" select CPU_S5PV310 - select ARCH_SPARSEMEM_ENABLE + select S3C_DEV_RTC + select S3C_DEV_WDT help - Machine support for Samsung SMDKV310 + Machine support for Samsung SMDKC210 + S5PC210(MCP) is one of package option of S5PV310 config MACH_UNIVERSAL_C210 bool "Mobile UNIVERSAL_C210 Board" select CPU_S5PV310 - select ARCH_SPARSEMEM_ENABLE help Machine support for Samsung Mobile Universal S5PC210 Reference Board. S5PC210(MCP) is one of package option of S5PV310 +endmenu + +menu "S5PV310 Machines" + +config MACH_SMDKV310 + bool "SMDKV310" + select CPU_S5PV310 + select S3C_DEV_RTC + select S3C_DEV_WDT + help + Machine support for Samsung SMDKV310 + +endmenu + endif diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile index d5b51c72340..aefb14f23b8 100644 --- a/arch/arm/mach-s5pv310/Makefile +++ b/arch/arm/mach-s5pv310/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o # machine support +obj-$(CONFIG_MACH_SMDKC210) += mach-smdkc210.o obj-$(CONFIG_MACH_SMDKV310) += mach-smdkv310.o obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index 26a0f03df8e..58c9d33f36f 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c @@ -30,16 +30,92 @@ static struct clk clk_sclk_hdmi27m = { .rate = 27000000, }; +static struct clk clk_sclk_hdmiphy = { + .name = "sclk_hdmiphy", + .id = -1, +}; + +static struct clk clk_sclk_usbphy0 = { + .name = "sclk_usbphy0", + .id = -1, + .rate = 27000000, +}; + +static struct clk clk_sclk_usbphy1 = { + .name = "sclk_usbphy1", + .id = -1, +}; + +static int s5pv310_clksrc_mask_top_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable); +} + +static int s5pv310_clksrc_mask_cam_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_CAM, clk, enable); +} + +static int s5pv310_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_LCD0, clk, enable); +} + +static int s5pv310_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable); +} + +static int s5pv310_clksrc_mask_fsys_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_FSYS, clk, enable); +} + static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable); } +static int s5pv310_clksrc_mask_peril1_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL1, clk, enable); +} + +static int s5pv310_clk_ip_cam_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_IP_CAM, clk, enable); +} + +static int s5pv310_clk_ip_image_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_IP_IMAGE, clk, enable); +} + +static int s5pv310_clk_ip_lcd0_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_IP_LCD0, clk, enable); +} + +static int s5pv310_clk_ip_lcd1_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_IP_LCD1, clk, enable); +} + +static int s5pv310_clk_ip_fsys_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_IP_FSYS, clk, enable); +} + static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable); } +static int s5pv310_clk_ip_perir_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable); +} + /* Core list of CMU_CPU side */ static struct clksrc_clk clk_mout_apll = { @@ -79,7 +155,7 @@ static struct clksrc_clk clk_mout_mpll = { }; static struct clk *clkset_moutcore_list[] = { - [0] = &clk_sclk_apll.clk, + [0] = &clk_mout_apll.clk, [1] = &clk_mout_mpll.clk, }; @@ -150,24 +226,6 @@ static struct clksrc_clk clk_periphclk = { .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 }, }; -static struct clksrc_clk clk_atclk = { - .clk = { - .name = "atclk", - .id = -1, - .parent = &clk_moutcore.clk, - }, - .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 16, .size = 3 }, -}; - -static struct clksrc_clk clk_pclk_dbg = { - .clk = { - .name = "pclk_dbg", - .id = -1, - .parent = &clk_atclk.clk, - }, - .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 20, .size = 3 }, -}; - /* Core list of CMU_CORE side */ static struct clk *clkset_corebus_list[] = { @@ -241,7 +299,7 @@ static struct clk *clkset_aclk_top_list[] = { [1] = &clk_sclk_apll.clk, }; -static struct clksrc_sources clkset_aclk_200 = { +static struct clksrc_sources clkset_aclk = { .sources = clkset_aclk_top_list, .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), }; @@ -251,52 +309,37 @@ static struct clksrc_clk clk_aclk_200 = { .name = "aclk_200", .id = -1, }, - .sources = &clkset_aclk_200, + .sources = &clkset_aclk, .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 }, .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 }, }; -static struct clksrc_sources clkset_aclk_100 = { - .sources = clkset_aclk_top_list, - .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), -}; - static struct clksrc_clk clk_aclk_100 = { .clk = { .name = "aclk_100", .id = -1, }, - .sources = &clkset_aclk_100, + .sources = &clkset_aclk, .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 }, .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 }, }; -static struct clksrc_sources clkset_aclk_160 = { - .sources = clkset_aclk_top_list, - .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), -}; - static struct clksrc_clk clk_aclk_160 = { .clk = { .name = "aclk_160", .id = -1, }, - .sources = &clkset_aclk_160, + .sources = &clkset_aclk, .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 }, .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 }, }; -static struct clksrc_sources clkset_aclk_133 = { - .sources = clkset_aclk_top_list, - .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), -}; - static struct clksrc_clk clk_aclk_133 = { .clk = { .name = "aclk_133", .id = -1, }, - .sources = &clkset_aclk_133, + .sources = &clkset_aclk, .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 }, .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 }, }; @@ -315,6 +358,8 @@ static struct clksrc_clk clk_vpllsrc = { .clk = { .name = "vpll_src", .id = -1, + .enable = s5pv310_clksrc_mask_top_ctrl, + .ctrlbit = (1 << 0), }, .sources = &clkset_vpllsrc, .reg_src = { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 }, @@ -346,7 +391,175 @@ static struct clk init_clocks_disable[] = { .parent = &clk_aclk_100.clk, .enable = s5pv310_clk_ip_peril_ctrl, .ctrlbit = (1<<24), - } + }, { + .name = "csis", + .id = 0, + .enable = s5pv310_clk_ip_cam_ctrl, + .ctrlbit = (1 << 4), + }, { + .name = "csis", + .id = 1, + .enable = s5pv310_clk_ip_cam_ctrl, + .ctrlbit = (1 << 5), + }, { + .name = "fimc", + .id = 0, + .enable = s5pv310_clk_ip_cam_ctrl, + .ctrlbit = (1 << 0), + }, { + .name = "fimc", + .id = 1, + .enable = s5pv310_clk_ip_cam_ctrl, + .ctrlbit = (1 << 1), + }, { + .name = "fimc", + .id = 2, + .enable = s5pv310_clk_ip_cam_ctrl, + .ctrlbit = (1 << 2), + }, { + .name = "fimc", + .id = 3, + .enable = s5pv310_clk_ip_cam_ctrl, + .ctrlbit = (1 << 3), + }, { + .name = "fimd", + .id = 0, + .enable = s5pv310_clk_ip_lcd0_ctrl, + .ctrlbit = (1 << 0), + }, { + .name = "fimd", + .id = 1, + .enable = s5pv310_clk_ip_lcd1_ctrl, + .ctrlbit = (1 << 0), + }, { + .name = "hsmmc", + .id = 0, + .parent = &clk_aclk_133.clk, + .enable = s5pv310_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 5), + }, { + .name = "hsmmc", + .id = 1, + .parent = &clk_aclk_133.clk, + .enable = s5pv310_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 6), + }, { + .name = "hsmmc", + .id = 2, + .parent = &clk_aclk_133.clk, + .enable = s5pv310_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 7), + }, { + .name = "hsmmc", + .id = 3, + .parent = &clk_aclk_133.clk, + .enable = s5pv310_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 8), + }, { + .name = "hsmmc", + .id = 4, + .parent = &clk_aclk_133.clk, + .enable = s5pv310_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 9), + }, { + .name = "sata", + .id = -1, + .enable = s5pv310_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 10), + }, { + .name = "adc", + .id = -1, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 15), + }, { + .name = "rtc", + .id = -1, + .enable = s5pv310_clk_ip_perir_ctrl, + .ctrlbit = (1 << 15), + }, { + .name = "watchdog", + .id = -1, + .enable = s5pv310_clk_ip_perir_ctrl, + .ctrlbit = (1 << 14), + }, { + .name = "usbhost", + .id = -1, + .enable = s5pv310_clk_ip_fsys_ctrl , + .ctrlbit = (1 << 12), + }, { + .name = "otg", + .id = -1, + .enable = s5pv310_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 13), + }, { + .name = "spi", + .id = 0, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 16), + }, { + .name = "spi", + .id = 1, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 17), + }, { + .name = "spi", + .id = 2, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 18), + }, { + .name = "fimg2d", + .id = -1, + .enable = s5pv310_clk_ip_image_ctrl, + .ctrlbit = (1 << 0), + }, { + .name = "i2c", + .id = 0, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 6), + }, { + .name = "i2c", + .id = 1, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 7), + }, { + .name = "i2c", + .id = 2, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 8), + }, { + .name = "i2c", + .id = 3, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 9), + }, { + .name = "i2c", + .id = 4, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 10), + }, { + .name = "i2c", + .id = 5, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 11), + }, { + .name = "i2c", + .id = 6, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 12), + }, { + .name = "i2c", + .id = 7, + .parent = &clk_aclk_100.clk, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 13), + }, }; static struct clk init_clocks[] = { @@ -387,6 +600,9 @@ static struct clk *clkset_group_list[] = { [0] = &clk_ext_xtal_mux, [1] = &clk_xusbxti, [2] = &clk_sclk_hdmi27m, + [3] = &clk_sclk_usbphy0, + [4] = &clk_sclk_usbphy1, + [5] = &clk_sclk_hdmiphy, [6] = &clk_mout_mpll.clk, [7] = &clk_mout_epll.clk, [8] = &clk_sclk_vpll.clk, @@ -397,6 +613,104 @@ static struct clksrc_sources clkset_group = { .nr_sources = ARRAY_SIZE(clkset_group_list), }; +static struct clk *clkset_mout_g2d0_list[] = { + [0] = &clk_mout_mpll.clk, + [1] = &clk_sclk_apll.clk, +}; + +static struct clksrc_sources clkset_mout_g2d0 = { + .sources = clkset_mout_g2d0_list, + .nr_sources = ARRAY_SIZE(clkset_mout_g2d0_list), +}; + +static struct clksrc_clk clk_mout_g2d0 = { + .clk = { + .name = "mout_g2d0", + .id = -1, + }, + .sources = &clkset_mout_g2d0, + .reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 0, .size = 1 }, +}; + +static struct clk *clkset_mout_g2d1_list[] = { + [0] = &clk_mout_epll.clk, + [1] = &clk_sclk_vpll.clk, +}; + +static struct clksrc_sources clkset_mout_g2d1 = { + .sources = clkset_mout_g2d1_list, + .nr_sources = ARRAY_SIZE(clkset_mout_g2d1_list), +}; + +static struct clksrc_clk clk_mout_g2d1 = { + .clk = { + .name = "mout_g2d1", + .id = -1, + }, + .sources = &clkset_mout_g2d1, + .reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 4, .size = 1 }, +}; + +static struct clk *clkset_mout_g2d_list[] = { + [0] = &clk_mout_g2d0.clk, + [1] = &clk_mout_g2d1.clk, +}; + +static struct clksrc_sources clkset_mout_g2d = { + .sources = clkset_mout_g2d_list, + .nr_sources = ARRAY_SIZE(clkset_mout_g2d_list), +}; + +static struct clksrc_clk clk_dout_mmc0 = { + .clk = { + .name = "dout_mmc0", + .id = -1, + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 0, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 0, .size = 4 }, +}; + +static struct clksrc_clk clk_dout_mmc1 = { + .clk = { + .name = "dout_mmc1", + .id = -1, + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 4, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 16, .size = 4 }, +}; + +static struct clksrc_clk clk_dout_mmc2 = { + .clk = { + .name = "dout_mmc2", + .id = -1, + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 8, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 0, .size = 4 }, +}; + +static struct clksrc_clk clk_dout_mmc3 = { + .clk = { + .name = "dout_mmc3", + .id = -1, + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 12, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 16, .size = 4 }, +}; + +static struct clksrc_clk clk_dout_mmc4 = { + .clk = { + .name = "dout_mmc4", + .id = -1, + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 16, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 0, .size = 4 }, +}; + static struct clksrc_clk clksrcs[] = { { .clk = { @@ -448,7 +762,200 @@ static struct clksrc_clk clksrcs[] = { .sources = &clkset_group, .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 }, .reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 }, - }, + }, { + .clk = { + .name = "sclk_csis", + .id = 0, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 24), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 24, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 24, .size = 4 }, + }, { + .clk = { + .name = "sclk_csis", + .id = 1, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 28), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 28, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 28, .size = 4 }, + }, { + .clk = { + .name = "sclk_cam", + .id = 0, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 16), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 16, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 16, .size = 4 }, + }, { + .clk = { + .name = "sclk_cam", + .id = 1, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 20), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 20, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 20, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimc", + .id = 0, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 0), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 0, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 0, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimc", + .id = 1, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 4), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 4, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 4, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimc", + .id = 2, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 8), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 8, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 8, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimc", + .id = 3, + .enable = s5pv310_clksrc_mask_cam_ctrl, + .ctrlbit = (1 << 12), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 12, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 12, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimd", + .id = 0, + .enable = s5pv310_clksrc_mask_lcd0_ctrl, + .ctrlbit = (1 << 0), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_LCD0, .shift = 0, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_LCD0, .shift = 0, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimd", + .id = 1, + .enable = s5pv310_clksrc_mask_lcd1_ctrl, + .ctrlbit = (1 << 0), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_LCD1, .shift = 0, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_LCD1, .shift = 0, .size = 4 }, + }, { + .clk = { + .name = "sclk_sata", + .id = -1, + .enable = s5pv310_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 24), + }, + .sources = &clkset_mout_corebus, + .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 24, .size = 1 }, + .reg_div = { .reg = S5P_CLKDIV_FSYS0, .shift = 20, .size = 4 }, + }, { + .clk = { + .name = "sclk_spi", + .id = 0, + .enable = s5pv310_clksrc_mask_peril1_ctrl, + .ctrlbit = (1 << 16), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 16, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 0, .size = 4 }, + }, { + .clk = { + .name = "sclk_spi", + .id = 1, + .enable = s5pv310_clksrc_mask_peril1_ctrl, + .ctrlbit = (1 << 20), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 20, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 16, .size = 4 }, + }, { + .clk = { + .name = "sclk_spi", + .id = 2, + .enable = s5pv310_clksrc_mask_peril1_ctrl, + .ctrlbit = (1 << 24), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 24, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_PERIL2, .shift = 0, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimg2d", + .id = -1, + }, + .sources = &clkset_mout_g2d, + .reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 8, .size = 1 }, + .reg_div = { .reg = S5P_CLKDIV_IMAGE, .shift = 0, .size = 4 }, + }, { + .clk = { + .name = "sclk_mmc", + .id = 0, + .parent = &clk_dout_mmc0.clk, + .enable = s5pv310_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 0), + }, + .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 }, + }, { + .clk = { + .name = "sclk_mmc", + .id = 1, + .parent = &clk_dout_mmc1.clk, + .enable = s5pv310_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 4), + }, + .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 }, + }, { + .clk = { + .name = "sclk_mmc", + .id = 2, + .parent = &clk_dout_mmc2.clk, + .enable = s5pv310_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 8), + }, + .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 }, + }, { + .clk = { + .name = "sclk_mmc", + .id = 3, + .parent = &clk_dout_mmc3.clk, + .enable = s5pv310_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 12), + }, + .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 }, + }, { + .clk = { + .name = "sclk_mmc", + .id = 4, + .parent = &clk_dout_mmc4.clk, + .enable = s5pv310_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 16), + }, + .reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 8, .size = 8 }, + } }; /* Clock initialization code */ @@ -464,8 +971,6 @@ static struct clksrc_clk *sysclks[] = { &clk_aclk_cores, &clk_aclk_corem1, &clk_periphclk, - &clk_atclk, - &clk_pclk_dbg, &clk_mout_corebus, &clk_sclk_dmc, &clk_aclk_cored, @@ -478,6 +983,11 @@ static struct clksrc_clk *sysclks[] = { &clk_aclk_100, &clk_aclk_160, &clk_aclk_133, + &clk_dout_mmc0, + &clk_dout_mmc1, + &clk_dout_mmc2, + &clk_dout_mmc3, + &clk_dout_mmc4, }; void __init_or_cpufreq s5pv310_setup_clocks(void) @@ -490,15 +1000,11 @@ void __init_or_cpufreq s5pv310_setup_clocks(void) unsigned long vpllsrc; unsigned long xtal; unsigned long armclk; - unsigned long aclk_corem0; - unsigned long aclk_cores; - unsigned long aclk_corem1; - unsigned long periphclk; unsigned long sclk_dmc; - unsigned long aclk_cored; - unsigned long aclk_corep; - unsigned long aclk_acp; - unsigned long pclk_acp; + unsigned long aclk_200; + unsigned long aclk_100; + unsigned long aclk_160; + unsigned long aclk_133; unsigned int ptr; printk(KERN_DEBUG "%s: registering clocks\n", __func__); @@ -529,26 +1035,21 @@ void __init_or_cpufreq s5pv310_setup_clocks(void) apll, mpll, epll, vpll); armclk = clk_get_rate(&clk_armclk.clk); - aclk_corem0 = clk_get_rate(&clk_aclk_corem0.clk); - aclk_cores = clk_get_rate(&clk_aclk_cores.clk); - aclk_corem1 = clk_get_rate(&clk_aclk_corem1.clk); - periphclk = clk_get_rate(&clk_periphclk.clk); sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk); - aclk_cored = clk_get_rate(&clk_aclk_cored.clk); - aclk_corep = clk_get_rate(&clk_aclk_corep.clk); - aclk_acp = clk_get_rate(&clk_aclk_acp.clk); - pclk_acp = clk_get_rate(&clk_pclk_acp.clk); - - printk(KERN_INFO "S5PV310: ARMCLK=%ld, COREM0=%ld, CORES=%ld\n" - "COREM1=%ld, PERI=%ld, DMC=%ld, CORED=%ld\n" - "COREP=%ld, ACLK_ACP=%ld, PCLK_ACP=%ld", - armclk, aclk_corem0, aclk_cores, aclk_corem1, - periphclk, sclk_dmc, aclk_cored, aclk_corep, - aclk_acp, pclk_acp); + + aclk_200 = clk_get_rate(&clk_aclk_200.clk); + aclk_100 = clk_get_rate(&clk_aclk_100.clk); + aclk_160 = clk_get_rate(&clk_aclk_160.clk); + aclk_133 = clk_get_rate(&clk_aclk_133.clk); + + printk(KERN_INFO "S5PV310: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n" + "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n", + armclk, sclk_dmc, aclk_200, + aclk_100, aclk_160, aclk_133); clk_f.rate = armclk; clk_h.rate = sclk_dmc; - clk_p.rate = periphclk; + clk_p.rate = aclk_100; for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) s3c_set_clksrc(&clksrcs[ptr], true); diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c new file mode 100644 index 00000000000..03652c3605f --- /dev/null +++ b/arch/arm/mach-s5pv310/hotplug.c @@ -0,0 +1,144 @@ +/* linux arch/arm/mach-s5pv310/hotplug.c + * + * Cloned from linux/arch/arm/mach-realview/hotplug.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <linux/completion.h> + +#include <asm/cacheflush.h> + +extern volatile int pen_release; + +static DECLARE_COMPLETION(cpu_killed); + +static inline void cpu_enter_lowpower(void) +{ + unsigned int v; + + flush_cache_all(); + asm volatile( + " mcr p15, 0, %1, c7, c5, 0\n" + " mcr p15, 0, %1, c7, c10, 4\n" + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" + " bic %0, %0, #0x20\n" + " mcr p15, 0, %0, c1, c0, 1\n" + " mrc p15, 0, %0, c1, c0, 0\n" + " bic %0, %0, #0x04\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "r" (0) + : "cc"); +} + +static inline void cpu_leave_lowpower(void) +{ + unsigned int v; + + asm volatile( + "mrc p15, 0, %0, c1, c0, 0\n" + " orr %0, %0, #0x04\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" + " orr %0, %0, #0x20\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : + : "cc"); +} + +static inline void platform_do_lowpower(unsigned int cpu) +{ + /* + * there is no power-control hardware on this platform, so all + * we can do is put the core into WFI; this is safe as the calling + * code will have already disabled interrupts + */ + for (;;) { + /* + * here's the WFI + */ + asm(".word 0xe320f003\n" + : + : + : "memory", "cc"); + + if (pen_release == cpu) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * The trouble is, letting people know about this is not really + * possible, since we are currently running incoherently, and + * therefore cannot safely call printk() or anything else + */ +#ifdef DEBUG + printk(KERN_WARN "CPU%u: spurious wakeup call\n", cpu); +#endif + } +} + +int platform_cpu_kill(unsigned int cpu) +{ + return wait_for_completion_timeout(&cpu_killed, 5000); +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ +#ifdef DEBUG + unsigned int this_cpu = hard_smp_processor_id(); + + if (cpu != this_cpu) { + printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", + this_cpu, cpu); + BUG(); + } +#endif + + printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); + complete(&cpu_killed); + + /* + * we're ready for shutdown now, so do it + */ + cpu_enter_lowpower(); + platform_do_lowpower(cpu); + + /* + * bring this CPU back into the world of cache + * coherency, and then restore interrupts + */ + cpu_leave_lowpower(); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h index 471fc3bb199..e81332f0330 100644 --- a/arch/arm/mach-s5pv310/include/mach/irqs.h +++ b/arch/arm/mach-s5pv310/include/mach/irqs.h @@ -60,6 +60,9 @@ #define IRQ_TIMER3_VIC COMBINER_IRQ(22, 3) #define IRQ_TIMER4_VIC COMBINER_IRQ(22, 4) +#define IRQ_RTC_ALARM COMBINER_IRQ(23, 0) +#define IRQ_RTC_TIC COMBINER_IRQ(23, 1) + #define IRQ_UART0 COMBINER_IRQ(26, 0) #define IRQ_UART1 COMBINER_IRQ(26, 1) #define IRQ_UART2 COMBINER_IRQ(26, 2) @@ -68,6 +71,11 @@ #define IRQ_IIC COMBINER_IRQ(27, 0) +#define IRQ_HSMMC0 COMBINER_IRQ(29, 0) +#define IRQ_HSMMC1 COMBINER_IRQ(29, 1) +#define IRQ_HSMMC2 COMBINER_IRQ(29, 2) +#define IRQ_HSMMC3 COMBINER_IRQ(29, 3) + #define IRQ_ONENAND_AUDI COMBINER_IRQ(34, 0) /* Set the default NR_IRQS */ diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h index aff6d23624b..8014c3a6dd5 100644 --- a/arch/arm/mach-s5pv310/include/mach/map.h +++ b/arch/arm/mach-s5pv310/include/mach/map.h @@ -34,12 +34,13 @@ #define S5PV310_PA_CHIPID (0x10000000) #define S5P_PA_CHIPID S5PV310_PA_CHIPID -#define S5PV310_PA_SYSCON (0x10020000) +#define S5PV310_PA_SYSCON (0x10010000) #define S5P_PA_SYSCON S5PV310_PA_SYSCON #define S5PV310_PA_CMU (0x10030000) #define S5PV310_PA_WATCHDOG (0x10060000) +#define S5PV310_PA_RTC (0x10070000) #define S5PV310_PA_COMBINER (0x10448000) @@ -81,6 +82,7 @@ #define S3C_PA_HSMMC2 S5PV310_PA_HSMMC(2) #define S3C_PA_HSMMC3 S5PV310_PA_HSMMC(3) #define S3C_PA_IIC S5PV310_PA_IIC0 +#define S3C_PA_RTC S5PV310_PA_RTC #define S3C_PA_WDT S5PV310_PA_WATCHDOG #endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h index 4013553cd9b..12e983c11ad 100644 --- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h @@ -26,11 +26,23 @@ #define S5P_CLKSRC_TOP0 S5P_CLKREG(0x0C210) #define S5P_CLKSRC_TOP1 S5P_CLKREG(0x0C214) - +#define S5P_CLKSRC_CAM S5P_CLKREG(0x0C220) +#define S5P_CLKSRC_IMAGE S5P_CLKREG(0x0C230) +#define S5P_CLKSRC_LCD0 S5P_CLKREG(0x0C234) +#define S5P_CLKSRC_LCD1 S5P_CLKREG(0x0C238) +#define S5P_CLKSRC_FSYS S5P_CLKREG(0x0C240) #define S5P_CLKSRC_PERIL0 S5P_CLKREG(0x0C250) +#define S5P_CLKSRC_PERIL1 S5P_CLKREG(0x0C254) #define S5P_CLKDIV_TOP S5P_CLKREG(0x0C510) - +#define S5P_CLKDIV_CAM S5P_CLKREG(0x0C520) +#define S5P_CLKDIV_IMAGE S5P_CLKREG(0x0C530) +#define S5P_CLKDIV_LCD0 S5P_CLKREG(0x0C534) +#define S5P_CLKDIV_LCD1 S5P_CLKREG(0x0C538) +#define S5P_CLKDIV_FSYS0 S5P_CLKREG(0x0C540) +#define S5P_CLKDIV_FSYS1 S5P_CLKREG(0x0C544) +#define S5P_CLKDIV_FSYS2 S5P_CLKREG(0x0C548) +#define S5P_CLKDIV_FSYS3 S5P_CLKREG(0x0C54C) #define S5P_CLKDIV_PERIL0 S5P_CLKREG(0x0C550) #define S5P_CLKDIV_PERIL1 S5P_CLKREG(0x0C554) #define S5P_CLKDIV_PERIL2 S5P_CLKREG(0x0C558) @@ -38,9 +50,21 @@ #define S5P_CLKDIV_PERIL4 S5P_CLKREG(0x0C560) #define S5P_CLKDIV_PERIL5 S5P_CLKREG(0x0C564) +#define S5P_CLKSRC_MASK_TOP S5P_CLKREG(0x0C310) +#define S5P_CLKSRC_MASK_CAM S5P_CLKREG(0x0C320) +#define S5P_CLKSRC_MASK_LCD0 S5P_CLKREG(0x0C334) +#define S5P_CLKSRC_MASK_LCD1 S5P_CLKREG(0x0C338) +#define S5P_CLKSRC_MASK_FSYS S5P_CLKREG(0x0C340) #define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) +#define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354) +#define S5P_CLKGATE_IP_CAM S5P_CLKREG(0x0C920) +#define S5P_CLKGATE_IP_IMAGE S5P_CLKREG(0x0C930) +#define S5P_CLKGATE_IP_LCD0 S5P_CLKREG(0x0C934) +#define S5P_CLKGATE_IP_LCD1 S5P_CLKREG(0x0C938) +#define S5P_CLKGATE_IP_FSYS S5P_CLKREG(0x0C940) #define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) +#define S5P_CLKGATE_IP_PERIR S5P_CLKREG(0x0C960) #define S5P_CLKSRC_CORE S5P_CLKREG(0x10200) #define S5P_CLKDIV_CORE0 S5P_CLKREG(0x10500) diff --git a/arch/arm/mach-s5pv310/irq-combiner.c b/arch/arm/mach-s5pv310/irq-combiner.c index 0f7052164f2..c3f88c3faf6 100644 --- a/arch/arm/mach-s5pv310/irq-combiner.c +++ b/arch/arm/mach-s5pv310/irq-combiner.c @@ -66,11 +66,7 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) if (status == 0) goto out; - for (combiner_irq = 0; combiner_irq < 32; combiner_irq++) { - if (status & 0x1) - break; - status >>= 1; - } + combiner_irq = __ffs(status); cascade_irq = combiner_irq + (chip_data->irq_offset & ~31); if (unlikely(cascade_irq >= NR_IRQS)) diff --git a/arch/arm/mach-s5pv310/mach-smdkc210.c b/arch/arm/mach-s5pv310/mach-smdkc210.c new file mode 100644 index 00000000000..b0623976b88 --- /dev/null +++ b/arch/arm/mach-s5pv310/mach-smdkc210.c @@ -0,0 +1,97 @@ +/* linux/arch/arm/mach-s5pv310/mach-smdkc210.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * 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/serial_core.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> +#include <asm/hardware/cache-l2x0.h> + +#include <plat/regs-serial.h> +#include <plat/s5pv310.h> +#include <plat/cpu.h> +#include <plat/devs.h> + +#include <mach/map.h> + +/* Following are default values for UCON, ULCON and UFCON UART registers */ +#define SMDKC210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ + S3C2410_UCON_RXILEVEL | \ + S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI | \ + S3C2443_UCON_RXERR_IRQEN) + +#define SMDKC210_ULCON_DEFAULT S3C2410_LCON_CS8 + +#define SMDKC210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ + S5PV210_UFCON_TXTRIG4 | \ + S5PV210_UFCON_RXTRIG4) + +static struct s3c2410_uartcfg smdkc210_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = SMDKC210_UCON_DEFAULT, + .ulcon = SMDKC210_ULCON_DEFAULT, + .ufcon = SMDKC210_UFCON_DEFAULT, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = SMDKC210_UCON_DEFAULT, + .ulcon = SMDKC210_ULCON_DEFAULT, + .ufcon = SMDKC210_UFCON_DEFAULT, + }, + [2] = { + .hwport = 2, + .flags = 0, + .ucon = SMDKC210_UCON_DEFAULT, + .ulcon = SMDKC210_ULCON_DEFAULT, + .ufcon = SMDKC210_UFCON_DEFAULT, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = SMDKC210_UCON_DEFAULT, + .ulcon = SMDKC210_ULCON_DEFAULT, + .ufcon = SMDKC210_UFCON_DEFAULT, + }, +}; + +static struct platform_device *smdkc210_devices[] __initdata = { + &s3c_device_rtc, + &s3c_device_wdt, +}; + +static void __init smdkc210_map_io(void) +{ + s5p_init_io(NULL, 0, S5P_VA_CHIPID); + s3c24xx_init_clocks(24000000); + s3c24xx_init_uarts(smdkc210_uartcfgs, ARRAY_SIZE(smdkc210_uartcfgs)); +} + +static void __init smdkc210_machine_init(void) +{ +#ifdef CONFIG_CACHE_L2X0 + l2x0_init(S5P_VA_L2CC, 1 << 28, 0xffffffff); +#endif + + platform_add_devices(smdkc210_devices, ARRAY_SIZE(smdkc210_devices)); +} + +MACHINE_START(SMDKC210, "SMDKC210") + /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ + .boot_params = S5P_PA_SDRAM + 0x100, + .init_irq = s5pv310_init_irq, + .map_io = smdkc210_map_io, + .init_machine = smdkc210_machine_init, + .timer = &s5pv310_timer, +MACHINE_END diff --git a/arch/arm/mach-s5pv310/mach-smdkv310.c b/arch/arm/mach-s5pv310/mach-smdkv310.c index 0d6ab77709d..9cb827da97f 100644 --- a/arch/arm/mach-s5pv310/mach-smdkv310.c +++ b/arch/arm/mach-s5pv310/mach-smdkv310.c @@ -17,6 +17,7 @@ #include <plat/regs-serial.h> #include <plat/s5pv310.h> #include <plat/cpu.h> +#include <plat/devs.h> #include <mach/map.h> @@ -65,6 +66,11 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = { }, }; +static struct platform_device *smdkv310_devices[] __initdata = { + &s3c_device_rtc, + &s3c_device_wdt, +}; + static void __init smdkv310_map_io(void) { s5p_init_io(NULL, 0, S5P_VA_CHIPID); @@ -77,6 +83,8 @@ static void __init smdkv310_machine_init(void) #ifdef CONFIG_CACHE_L2X0 l2x0_init(S5P_VA_L2CC, 1 << 28, 0xffffffff); #endif + + platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); } MACHINE_START(SMDKV310, "SMDKV310") diff --git a/arch/arm/mach-s5pv310/mach-universal_c210.c b/arch/arm/mach-s5pv310/mach-universal_c210.c index 2388cb94793..b57efaeb295 100644 --- a/arch/arm/mach-s5pv310/mach-universal_c210.c +++ b/arch/arm/mach-s5pv310/mach-universal_c210.c @@ -7,7 +7,11 @@ * published by the Free Software Foundation. */ +#include <linux/platform_device.h> #include <linux/serial_core.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/gpio.h> #include <asm/mach/arch.h> #include <asm/mach-types.h> @@ -60,6 +64,61 @@ static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = { }, }; +static struct gpio_keys_button universal_gpio_keys_tables[] = { + { + .code = KEY_VOLUMEUP, + .gpio = S5PV310_GPX2(0), /* XEINT16 */ + .desc = "gpio-keys: KEY_VOLUMEUP", + .type = EV_KEY, + .active_low = 1, + .debounce_interval = 1, + }, { + .code = KEY_VOLUMEDOWN, + .gpio = S5PV310_GPX2(1), /* XEINT17 */ + .desc = "gpio-keys: KEY_VOLUMEDOWN", + .type = EV_KEY, + .active_low = 1, + .debounce_interval = 1, + }, { + .code = KEY_CONFIG, + .gpio = S5PV310_GPX2(2), /* XEINT18 */ + .desc = "gpio-keys: KEY_CONFIG", + .type = EV_KEY, + .active_low = 1, + .debounce_interval = 1, + }, { + .code = KEY_CAMERA, + .gpio = S5PV310_GPX2(3), /* XEINT19 */ + .desc = "gpio-keys: KEY_CAMERA", + .type = EV_KEY, + .active_low = 1, + .debounce_interval = 1, + }, { + .code = KEY_OK, + .gpio = S5PV310_GPX3(5), /* XEINT29 */ + .desc = "gpio-keys: KEY_OK", + .type = EV_KEY, + .active_low = 1, + .debounce_interval = 1, + }, +}; + +static struct gpio_keys_platform_data universal_gpio_keys_data = { + .buttons = universal_gpio_keys_tables, + .nbuttons = ARRAY_SIZE(universal_gpio_keys_tables), +}; + +static struct platform_device universal_gpio_keys = { + .name = "gpio-keys", + .dev = { + .platform_data = &universal_gpio_keys_data, + }, +}; + +static struct platform_device *universal_devices[] __initdata = { + &universal_gpio_keys, +}; + static void __init universal_map_io(void) { s5p_init_io(NULL, 0, S5P_VA_CHIPID); @@ -72,6 +131,9 @@ static void __init universal_machine_init(void) #ifdef CONFIG_CACHE_L2X0 l2x0_init(S5P_VA_L2CC, 1 << 28, 0xffffffff); #endif + + /* Last */ + platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices)); } MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c index 4c0896f2572..243b6411050 100644 --- a/arch/arm/plat-s3c24xx/gpiolib.c +++ b/arch/arm/plat-s3c24xx/gpiolib.c @@ -74,11 +74,6 @@ static int s3c24xx_gpiolib_bankf_toirq(struct gpio_chip *chip, unsigned offset) return -EINVAL; } -static int s3c24xx_gpiolib_bankg_toirq(struct gpio_chip *chip, unsigned offset) -{ - return IRQ_EINT8 + offset; -} - static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = { .set_config = s3c_gpio_setcfg_s3c24xx_a, .get_config = s3c_gpio_getcfg_s3c24xx_a, @@ -157,12 +152,13 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { [6] = { .base = S3C2410_GPGCON, .pm = __gpio_pm(&s3c_gpio_pm_2bit), + .irq_base = IRQ_EINT8, .chip = { .base = S3C2410_GPG(0), .owner = THIS_MODULE, .label = "GPIOG", .ngpio = 16, - .to_irq = s3c24xx_gpiolib_bankg_toirq, + .to_irq = samsung_gpiolib_to_irq, }, }, { .base = S3C2410_GPHCON, diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 25960966af7..65dbfa8e0a8 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -32,6 +32,11 @@ config S5P_EXT_INT Use the external interrupts (other than GPIO interrupts.) Note: Do not choose this for S5P6440 and S5P6450. +config S5P_GPIO_INT + bool + help + Common code for the GPIO interrupts (other than external interrupts.) + config S5P_DEV_FIMC0 bool help diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile index f3e917e27da..de65238a7ae 100644 --- a/arch/arm/plat-s5p/Makefile +++ b/arch/arm/plat-s5p/Makefile @@ -18,6 +18,9 @@ obj-y += cpu.o obj-y += clock.o obj-y += irq.o obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o +obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o +obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PM) += irq-pm.o # devices diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c index 8aaf4e6b60c..81880096269 100644 --- a/arch/arm/plat-s5p/clock.c +++ b/arch/arm/plat-s5p/clock.c @@ -88,14 +88,6 @@ struct clk clk_fout_vpll = { .ctrlbit = (1 << 31), }; -/* ARM clock */ -struct clk clk_arm = { - .name = "armclk", - .id = -1, - .rate = 0, - .ctrlbit = 0, -}; - /* Possible clock sources for APLL Mux */ static struct clk *clk_src_apll_list[] = { [0] = &clk_fin_apll, @@ -165,7 +157,6 @@ static struct clk *s5p_clks[] __initdata = { &clk_fout_epll, &clk_fout_dpll, &clk_fout_vpll, - &clk_arm, &clk_vpll, &clk_xusbxti, }; diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-s5p/include/plat/irqs.h index 3fb3a3a1746..ba9121c60a2 100644 --- a/arch/arm/plat-s5p/include/plat/irqs.h +++ b/arch/arm/plat-s5p/include/plat/irqs.h @@ -94,4 +94,22 @@ ((irq) - S5P_EINT_BASE1) : \ ((irq) + 16 - S5P_EINT_BASE2)) +#define IRQ_EINT_BIT(x) EINT_OFFSET(x) + +/* Typically only a few gpio chips require gpio interrupt support. + To avoid memory waste irq descriptors are allocated only for + S5P_GPIOINT_GROUP_COUNT chips, each with total number of + S5P_GPIOINT_GROUP_SIZE pins/irqs. Each GPIOINT group can be assiged + to any gpio chip with the s5p_register_gpio_interrupt() function */ +#define S5P_GPIOINT_GROUP_COUNT 4 +#define S5P_GPIOINT_GROUP_SIZE 8 +#define S5P_GPIOINT_COUNT (S5P_GPIOINT_GROUP_COUNT * S5P_GPIOINT_GROUP_SIZE) + +/* IRQ types common for all s5p platforms */ +#define S5P_IRQ_TYPE_LEVEL_LOW (0x00) +#define S5P_IRQ_TYPE_LEVEL_HIGH (0x01) +#define S5P_IRQ_TYPE_EDGE_FALLING (0x02) +#define S5P_IRQ_TYPE_EDGE_RISING (0x03) +#define S5P_IRQ_TYPE_EDGE_BOTH (0x04) + #endif /* __ASM_PLAT_S5P_IRQS_H */ diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h index c4ff88bf647..c833f3f2181 100644 --- a/arch/arm/plat-s5p/include/plat/map-s5p.h +++ b/arch/arm/plat-s5p/include/plat/map-s5p.h @@ -18,6 +18,9 @@ #define S5P_VA_SYSTIMER S3C_ADDR(0x01200000) #define S5P_VA_SROMC S3C_ADDR(0x01100000) #define S5P_VA_SYSRAM S3C_ADDR(0x01180000) +#define S3C_VA_USB_HSPHY S3C_ADDR(0x02000000) +#define S5P_VA_DMC0 S3C_ADDR(0x00A00000) +#define S5P_VA_DMC1 S3C_ADDR(0x00A80000) #define S5P_VA_COMBINER_BASE S3C_ADDR(0x00600000) #define S5P_VA_COMBINER(x) (S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10) diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c index f36cd332702..752f1a645f9 100644 --- a/arch/arm/plat-s5p/irq-eint.c +++ b/arch/arm/plat-s5p/irq-eint.c @@ -67,23 +67,23 @@ static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type) switch (type) { case IRQ_TYPE_EDGE_RISING: - newvalue = S5P_EXTINT_RISEEDGE; + newvalue = S5P_IRQ_TYPE_EDGE_RISING; break; case IRQ_TYPE_EDGE_FALLING: - newvalue = S5P_EXTINT_FALLEDGE; + newvalue = S5P_IRQ_TYPE_EDGE_FALLING; break; case IRQ_TYPE_EDGE_BOTH: - newvalue = S5P_EXTINT_BOTHEDGE; + newvalue = S5P_IRQ_TYPE_EDGE_BOTH; break; case IRQ_TYPE_LEVEL_LOW: - newvalue = S5P_EXTINT_LOWLEV; + newvalue = S5P_IRQ_TYPE_LEVEL_LOW; break; case IRQ_TYPE_LEVEL_HIGH: - newvalue = S5P_EXTINT_HILEV; + newvalue = S5P_IRQ_TYPE_LEVEL_HIGH; break; default: diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c new file mode 100644 index 00000000000..0e5dc8cbf5e --- /dev/null +++ b/arch/arm/plat-s5p/irq-gpioint.c @@ -0,0 +1,237 @@ +/* linux/arch/arm/plat-s5p/irq-gpioint.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * Author: Kyungmin Park <kyungmin.park@samsung.com> + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * Author: Marek Szyprowski <m.szyprowski@samsung.com> + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <mach/map.h> +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> + +#define S5P_GPIOREG(x) (S5P_VA_GPIO + (x)) + +#define GPIOINT_CON_OFFSET 0x700 +#define GPIOINT_MASK_OFFSET 0x900 +#define GPIOINT_PEND_OFFSET 0xA00 + +static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR]; + +static int s5p_gpioint_get_group(unsigned int irq) +{ + struct gpio_chip *chip = get_irq_data(irq); + struct s3c_gpio_chip *s3c_chip = container_of(chip, + struct s3c_gpio_chip, chip); + int group; + + for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) + if (s3c_chip == irq_chips[group]) + break; + + return group; +} + +static int s5p_gpioint_get_offset(unsigned int irq) +{ + struct gpio_chip *chip = get_irq_data(irq); + struct s3c_gpio_chip *s3c_chip = container_of(chip, + struct s3c_gpio_chip, chip); + + return irq - s3c_chip->irq_base; +} + +static void s5p_gpioint_ack(unsigned int irq) +{ + int group, offset, pend_offset; + unsigned int value; + + group = s5p_gpioint_get_group(irq); + offset = s5p_gpioint_get_offset(irq); + pend_offset = group << 2; + + value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); + value |= 1 << offset; + __raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); +} + +static void s5p_gpioint_mask(unsigned int irq) +{ + int group, offset, mask_offset; + unsigned int value; + + group = s5p_gpioint_get_group(irq); + offset = s5p_gpioint_get_offset(irq); + mask_offset = group << 2; + + value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); + value |= 1 << offset; + __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); +} + +static void s5p_gpioint_unmask(unsigned int irq) +{ + int group, offset, mask_offset; + unsigned int value; + + group = s5p_gpioint_get_group(irq); + offset = s5p_gpioint_get_offset(irq); + mask_offset = group << 2; + + value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); + value &= ~(1 << offset); + __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); +} + +static void s5p_gpioint_mask_ack(unsigned int irq) +{ + s5p_gpioint_mask(irq); + s5p_gpioint_ack(irq); +} + +static int s5p_gpioint_set_type(unsigned int irq, unsigned int type) +{ + int group, offset, con_offset; + unsigned int value; + + group = s5p_gpioint_get_group(irq); + offset = s5p_gpioint_get_offset(irq); + con_offset = group << 2; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + type = S5P_IRQ_TYPE_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + type = S5P_IRQ_TYPE_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + type = S5P_IRQ_TYPE_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + type = S5P_IRQ_TYPE_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + type = S5P_IRQ_TYPE_LEVEL_LOW; + break; + case IRQ_TYPE_NONE: + default: + printk(KERN_WARNING "No irq type\n"); + return -EINVAL; + } + + value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); + value &= ~(0x7 << (offset * 0x4)); + value |= (type << (offset * 0x4)); + __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); + + return 0; +} + +struct irq_chip s5p_gpioint = { + .name = "s5p_gpioint", + .ack = s5p_gpioint_ack, + .mask = s5p_gpioint_mask, + .mask_ack = s5p_gpioint_mask_ack, + .unmask = s5p_gpioint_unmask, + .set_type = s5p_gpioint_set_type, +}; + +static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) +{ + int group, offset, pend_offset, mask_offset; + int real_irq; + unsigned int pend, mask; + + for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) { + pend_offset = group << 2; + pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + + pend_offset); + if (!pend) + continue; + + mask_offset = group << 2; + mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + + mask_offset); + pend &= ~mask; + + for (offset = 0; offset < 8; offset++) { + if (pend & (1 << offset)) { + struct s3c_gpio_chip *chip = irq_chips[group]; + if (chip) { + real_irq = chip->irq_base + offset; + generic_handle_irq(real_irq); + } + } + } + } +} + +static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) +{ + static int used_gpioint_groups = 0; + static bool handler_registered = 0; + int irq, group = chip->group; + int i; + + if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) + return -ENOMEM; + + chip->irq_base = S5P_GPIOINT_BASE + + used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; + used_gpioint_groups++; + + if (!handler_registered) { + set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler); + handler_registered = 1; + } + + irq_chips[group] = chip; + for (i = 0; i < chip->chip.ngpio; i++) { + irq = chip->irq_base + i; + set_irq_chip(irq, &s5p_gpioint); + set_irq_data(irq, &chip->chip); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + return 0; +} + +int __init s5p_register_gpio_interrupt(int pin) +{ + struct s3c_gpio_chip *my_chip = s3c_gpiolib_getchip(pin); + int offset, group; + int ret; + + if (!my_chip) + return -EINVAL; + + offset = pin - my_chip->chip.base; + group = my_chip->group; + + /* check if the group has been already registered */ + if (my_chip->irq_base) + return my_chip->irq_base + offset; + + /* register gpio group */ + ret = s5p_gpioint_add(my_chip); + if (ret == 0) { + my_chip->chip.to_irq = samsung_gpiolib_to_irq; + printk(KERN_INFO "Registered interrupt support for gpio group %d.\n", + group); + return my_chip->irq_base + offset; + } + return ret; +} diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-s5p/irq-pm.c new file mode 100644 index 00000000000..dc33b9ecda4 --- /dev/null +++ b/arch/arm/plat-s5p/irq-pm.c @@ -0,0 +1,93 @@ +/* linux/arch/arm/plat-s5p/irq-pm.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Based on arch/arm/plat-s3c24xx/irq-pm.c, + * Copyright (c) 2003,2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/sysdev.h> + +#include <plat/cpu.h> +#include <plat/irqs.h> +#include <plat/pm.h> +#include <mach/map.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-irq.h> + +/* state for IRQs over sleep */ + +/* default is to allow for EINT0..EINT31, and IRQ_RTC_TIC, IRQ_RTC_ALARM, + * as wakeup sources + * + * set bit to 1 in allow bitfield to enable the wakeup settings on it +*/ + +unsigned long s3c_irqwake_intallow = 0x00000006L; +unsigned long s3c_irqwake_eintallow = 0xffffffffL; + +int s3c_irq_wake(unsigned int irqno, unsigned int state) +{ + unsigned long irqbit; + + switch (irqno) { + case IRQ_RTC_TIC: + case IRQ_RTC_ALARM: + irqbit = 1 << (irqno + 1 - IRQ_RTC_ALARM); + if (!state) + s3c_irqwake_intmask |= irqbit; + else + s3c_irqwake_intmask &= ~irqbit; + break; + default: + return -ENOENT; + } + return 0; +} + +static struct sleep_save eint_save[] = { + SAVE_ITEM(S5P_EINT_CON(0)), + SAVE_ITEM(S5P_EINT_CON(1)), + SAVE_ITEM(S5P_EINT_CON(2)), + SAVE_ITEM(S5P_EINT_CON(3)), + + SAVE_ITEM(S5P_EINT_FLTCON(0)), + SAVE_ITEM(S5P_EINT_FLTCON(1)), + SAVE_ITEM(S5P_EINT_FLTCON(2)), + SAVE_ITEM(S5P_EINT_FLTCON(3)), + SAVE_ITEM(S5P_EINT_FLTCON(4)), + SAVE_ITEM(S5P_EINT_FLTCON(5)), + SAVE_ITEM(S5P_EINT_FLTCON(6)), + SAVE_ITEM(S5P_EINT_FLTCON(7)), + + SAVE_ITEM(S5P_EINT_MASK(0)), + SAVE_ITEM(S5P_EINT_MASK(1)), + SAVE_ITEM(S5P_EINT_MASK(2)), + SAVE_ITEM(S5P_EINT_MASK(3)), +}; + +int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) +{ + s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save)); + + return 0; +} + +int s3c24xx_irq_resume(struct sys_device *dev) +{ + s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save)); + + return 0; +} + diff --git a/arch/arm/plat-s5p/pm.c b/arch/arm/plat-s5p/pm.c new file mode 100644 index 00000000000..d592b6304b4 --- /dev/null +++ b/arch/arm/plat-s5p/pm.c @@ -0,0 +1,52 @@ +/* linux/arch/arm/plat-s5p/pm.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5P Power Manager (Suspend-To-RAM) support + * + * Based on arch/arm/plat-s3c24xx/pm.c + * Copyright (c) 2004,2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/suspend.h> +#include <plat/pm.h> + +#define PFX "s5p pm: " + +/* s3c_pm_check_resume_pin + * + * check to see if the pin is configured correctly for sleep mode, and + * make any necessary adjustments if it is not +*/ + +static void s3c_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) +{ + /* nothing here yet */ +} + +/* s3c_pm_configure_extint + * + * configure all external interrupt pins +*/ + +void s3c_pm_configure_extint(void) +{ + /* nothing here yet */ +} + +void s3c_pm_restore_core(void) +{ + /* nothing here yet */ +} + +void s3c_pm_save_core(void) +{ + /* nothing here yet */ +} + diff --git a/arch/arm/plat-samsung/dev-hsmmc3.c b/arch/arm/plat-samsung/dev-hsmmc3.c index 85aaf0f2842..335bc35044d 100644 --- a/arch/arm/plat-samsung/dev-hsmmc3.c +++ b/arch/arm/plat-samsung/dev-hsmmc3.c @@ -33,8 +33,8 @@ static struct resource s3c_hsmmc3_resource[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_MMC3, - .end = IRQ_MMC3, + .start = IRQ_HSMMC3, + .end = IRQ_HSMMC3, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/arm/plat-samsung/gpio.c b/arch/arm/plat-samsung/gpio.c index b83a83351ce..7743c4b8b2f 100644 --- a/arch/arm/plat-samsung/gpio.c +++ b/arch/arm/plat-samsung/gpio.c @@ -157,3 +157,11 @@ __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip) if (ret >= 0) s3c_gpiolib_track(chip); } + +int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct s3c_gpio_chip *s3c_chip = container_of(chip, + struct s3c_gpio_chip, chip); + + return s3c_chip->irq_base + offset; +} diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h index f684901b4b7..e4b5cf126fa 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h @@ -207,4 +207,22 @@ extern s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin); */ extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr); +/** + * s5p_register_gpio_interrupt() - register interrupt support for a gpio group + * @pin: The pin number from the group to be registered + * + * This function registers gpio interrupt support for the group that the + * specified pin belongs to. + * + * The total number of gpio pins is quite large ob s5p series. Registering + * irq support for all of them would be a resource waste. Because of that the + * interrupt support for standard gpio pins is registered dynamically. + * + * It will return the irq number of the interrupt that has been registered + * or -ENOMEM if no more gpio interrupts can be registered. It is allowed + * to call this function more than once for the same gpio group (the group + * will be registered only once). + */ +extern int s5p_register_gpio_interrupt(int pin); + #endif /* __PLAT_GPIO_CFG_H */ diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h index e358c7da848..13a22b8861e 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-core.h +++ b/arch/arm/plat-samsung/include/plat/gpio-core.h @@ -43,6 +43,8 @@ struct s3c_gpio_cfg; * struct s3c_gpio_chip - wrapper for specific implementation of gpio * @chip: The chip structure to be exported via gpiolib. * @base: The base pointer to the gpio configuration registers. + * @group: The group register number for gpio interrupt support. + * @irq_base: The base irq number. * @config: special function and pull-resistor control information. * @lock: Lock for exclusive access to this gpio bank. * @pm_save: Save information for suspend/resume support. @@ -63,6 +65,8 @@ struct s3c_gpio_chip { struct s3c_gpio_cfg *config; struct s3c_gpio_pm *pm; void __iomem *base; + int irq_base; + int group; spinlock_t lock; #ifdef CONFIG_PM u32 pm_save[4]; @@ -118,6 +122,17 @@ extern void samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip, extern void samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip); extern void samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip); + +/** + * samsung_gpiolib_to_irq - convert gpio pin to irq number + * @chip: The gpio chip that the pin belongs to. + * @offset: The offset of the pin in the chip. + * + * This helper returns the irq number calculated from the chip->irq_base and + * the provided offset. + */ +extern int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset); + /* exported for core SoC support to change */ extern struct s3c_gpio_cfg s3c24xx_gpiocfg_default; diff --git a/arch/arm/plat-samsung/pm-gpio.c b/arch/arm/plat-samsung/pm-gpio.c index 7df03f87fbf..96528200eb7 100644 --- a/arch/arm/plat-samsung/pm-gpio.c +++ b/arch/arm/plat-samsung/pm-gpio.c @@ -192,7 +192,7 @@ struct s3c_gpio_pm s3c_gpio_pm_2bit = { .resume = s3c_gpio_pm_2bit_resume, }; -#ifdef CONFIG_ARCH_S3C64XX +#if defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_PLAT_S5P) static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip) { chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON); @@ -302,7 +302,7 @@ struct s3c_gpio_pm s3c_gpio_pm_4bit = { .save = s3c_gpio_pm_4bit_save, .resume = s3c_gpio_pm_4bit_resume, }; -#endif /* CONFIG_ARCH_S3C64XX */ +#endif /* CONFIG_ARCH_S3C64XX || CONFIG_PLAT_S5P */ /** * s3c_pm_save_gpio() - save gpio chip data for suspend |