diff options
Diffstat (limited to 'arch/arm/plat-s5p')
-rw-r--r-- | arch/arm/plat-s5p/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/plat-s5p/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/plat-s5p/clock.c | 1 | ||||
-rw-r--r-- | arch/arm/plat-s5p/cpu.c | 10 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/irqs.h | 7 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/s5pc100.h | 33 | ||||
-rw-r--r-- | arch/arm/plat-s5p/irq-eint.c | 218 |
7 files changed, 278 insertions, 1 deletions
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 92bd75607b4..11d6a1bbd90 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -7,7 +7,7 @@ config PLAT_S5P bool - depends on (ARCH_S5P6440 || ARCH_S5P6442 || ARCH_S5PV210) + depends on (ARCH_S5P6440 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210) default y select ARM_VIC select NO_IOPORT @@ -24,3 +24,9 @@ config PLAT_S5P select SAMSUNG_IRQ_UART help Base platform code for Samsung's S5P series SoC. + +config S5P_EXT_INT + bool + help + Use the external interrupts (other than GPIO interrupts.) + Note: Do not choose this for S5P6440. diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile index 0ec09a9c36b..39c242bb9d5 100644 --- a/arch/arm/plat-s5p/Makefile +++ b/arch/arm/plat-s5p/Makefile @@ -16,3 +16,5 @@ obj-y += dev-uart.o obj-y += cpu.o obj-y += clock.o obj-y += irq.o +obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o + diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c index 24a931fd8d3..b5e255265f2 100644 --- a/arch/arm/plat-s5p/clock.c +++ b/arch/arm/plat-s5p/clock.c @@ -148,6 +148,7 @@ static struct clk *s5p_clks[] __initdata = { &clk_fout_vpll, &clk_arm, &clk_vpll, + &clk_xusbxti, }; void __init s5p_register_clocks(unsigned long xtal_freq) diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c index f92e5de3a75..75cb8c37ca2 100644 --- a/arch/arm/plat-s5p/cpu.c +++ b/arch/arm/plat-s5p/cpu.c @@ -19,12 +19,14 @@ #include <plat/cpu.h> #include <plat/s5p6440.h> #include <plat/s5p6442.h> +#include <plat/s5pc100.h> #include <plat/s5pv210.h> /* table of supported CPUs */ static const char name_s5p6440[] = "S5P6440"; static const char name_s5p6442[] = "S5P6442"; +static const char name_s5pc100[] = "S5PC100"; static const char name_s5pv210[] = "S5PV210/S5PC110"; static struct cpu_table cpu_ids[] __initdata = { @@ -45,6 +47,14 @@ static struct cpu_table cpu_ids[] __initdata = { .init = s5p6442_init, .name = name_s5p6442, }, { + .idcode = 0x43100000, + .idmask = 0xfffff000, + .map_io = s5pc100_map_io, + .init_clocks = s5pc100_init_clocks, + .init_uarts = s5pc100_init_uarts, + .init = s5pc100_init, + .name = name_s5pc100, + }, { .idcode = 0x43110000, .idmask = 0xfffff000, .map_io = s5pv210_map_io, diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-s5p/include/plat/irqs.h index 9ff3d718be3..3fb3a3a1746 100644 --- a/arch/arm/plat-s5p/include/plat/irqs.h +++ b/arch/arm/plat-s5p/include/plat/irqs.h @@ -87,4 +87,11 @@ #define IRQ_TIMER3 S5P_TIMER_IRQ(3) #define IRQ_TIMER4 S5P_TIMER_IRQ(4) +#define IRQ_EINT(x) ((x) < 16 ? ((x) + S5P_EINT_BASE1) \ + : ((x) - 16 + S5P_EINT_BASE2)) + +#define EINT_OFFSET(irq) ((irq) < S5P_EINT_BASE2 ? \ + ((irq) - S5P_EINT_BASE1) : \ + ((irq) + 16 - S5P_EINT_BASE2)) + #endif /* __ASM_PLAT_S5P_IRQS_H */ diff --git a/arch/arm/plat-s5p/include/plat/s5pc100.h b/arch/arm/plat-s5p/include/plat/s5pc100.h new file mode 100644 index 00000000000..5f6099dd7ca --- /dev/null +++ b/arch/arm/plat-s5p/include/plat/s5pc100.h @@ -0,0 +1,33 @@ +/* arch/arm/plat-s5p/include/plat/s5pc100.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Header file for s5pc100 cpu support + * + * 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. +*/ + +/* Common init code for S5PC100 related SoCs */ + +extern void s5pc100_common_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s5pc100_register_clocks(void); +extern void s5pc100_setup_clocks(void); + +#ifdef CONFIG_CPU_S5PC100 + +extern int s5pc100_init(void); +extern void s5pc100_init_irq(void); +extern void s5pc100_map_io(void); +extern void s5pc100_init_clocks(int xtal); + +#define s5pc100_init_uarts s5pc100_common_init_uarts + +#else +#define s5pc100_init_clocks NULL +#define s5pc100_init_uarts NULL +#define s5pc100_map_io NULL +#define s5pc100_init NULL +#endif diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c new file mode 100644 index 00000000000..e56c8075df9 --- /dev/null +++ b/arch/arm/plat-s5p/irq-eint.c @@ -0,0 +1,218 @@ +/* linux/arch/arm/plat-s5p/irq-eint.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5P - IRQ EINT support + * + * 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/sysdev.h> +#include <linux/gpio.h> + +#include <asm/hardware/vic.h> + +#include <plat/regs-irqtype.h> + +#include <mach/map.h> +#include <plat/cpu.h> +#include <plat/pm.h> + +#include <plat/gpio-cfg.h> +#include <mach/regs-gpio.h> + +static inline void s5p_irq_eint_mask(unsigned int irq) +{ + u32 mask; + + mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq))); + mask |= eint_irq_to_bit(irq); + __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq))); +} + +static void s5p_irq_eint_unmask(unsigned int irq) +{ + u32 mask; + + mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq))); + mask &= ~(eint_irq_to_bit(irq)); + __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq))); +} + +static inline void s5p_irq_eint_ack(unsigned int irq) +{ + __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq))); +} + +static void s5p_irq_eint_maskack(unsigned int irq) +{ + /* compiler should in-line these */ + s5p_irq_eint_mask(irq); + s5p_irq_eint_ack(irq); +} + +static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type) +{ + int offs = EINT_OFFSET(irq); + int shift; + u32 ctrl, mask; + u32 newvalue = 0; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + newvalue = S5P_EXTINT_RISEEDGE; + break; + + case IRQ_TYPE_EDGE_FALLING: + newvalue = S5P_EXTINT_RISEEDGE; + break; + + case IRQ_TYPE_EDGE_BOTH: + newvalue = S5P_EXTINT_BOTHEDGE; + break; + + case IRQ_TYPE_LEVEL_LOW: + newvalue = S5P_EXTINT_LOWLEV; + break; + + case IRQ_TYPE_LEVEL_HIGH: + newvalue = S5P_EXTINT_HILEV; + break; + + default: + printk(KERN_ERR "No such irq type %d", type); + return -EINVAL; + } + + shift = (offs & 0x7) * 4; + mask = 0x7 << shift; + + ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(irq))); + ctrl &= ~mask; + ctrl |= newvalue << shift; + __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(irq))); + + if ((0 <= offs) && (offs < 8)) + s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE); + + else if ((8 <= offs) && (offs < 16)) + s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE); + + else if ((16 <= offs) && (offs < 24)) + s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE); + + else if ((24 <= offs) && (offs < 32)) + s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE); + + else + printk(KERN_ERR "No such irq number %d", offs); + + return 0; +} + +static struct irq_chip s5p_irq_eint = { + .name = "s5p-eint", + .mask = s5p_irq_eint_mask, + .unmask = s5p_irq_eint_unmask, + .mask_ack = s5p_irq_eint_maskack, + .ack = s5p_irq_eint_ack, + .set_type = s5p_irq_eint_set_type, +#ifdef CONFIG_PM + .set_wake = s3c_irqext_wake, +#endif +}; + +/* s5p_irq_demux_eint + * + * This function demuxes the IRQ from the group0 external interrupts, + * from EINTs 16 to 31. It is designed to be inlined into the specific + * handler s5p_irq_demux_eintX_Y. + * + * Each EINT pend/mask registers handle eight of them. + */ +static inline void s5p_irq_demux_eint(unsigned int start) +{ + u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start))); + u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start))); + unsigned int irq; + + status &= ~mask; + status &= 0xff; + + while (status) { + irq = fls(status) - 1; + generic_handle_irq(irq + start); + status &= ~(1 << irq); + } +} + +static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) +{ + s5p_irq_demux_eint(IRQ_EINT(16)); + s5p_irq_demux_eint(IRQ_EINT(24)); +} + +static inline void s5p_irq_vic_eint_mask(unsigned int irq) +{ + void __iomem *base = get_irq_chip_data(irq); + + s5p_irq_eint_mask(irq); + writel(1 << EINT_OFFSET(irq), base + VIC_INT_ENABLE_CLEAR); +} + +static void s5p_irq_vic_eint_unmask(unsigned int irq) +{ + void __iomem *base = get_irq_chip_data(irq); + + s5p_irq_eint_unmask(irq); + writel(1 << EINT_OFFSET(irq), base + VIC_INT_ENABLE); +} + +static inline void s5p_irq_vic_eint_ack(unsigned int irq) +{ + __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq))); +} + +static void s5p_irq_vic_eint_maskack(unsigned int irq) +{ + s5p_irq_vic_eint_mask(irq); + s5p_irq_vic_eint_ack(irq); +} + +static struct irq_chip s5p_irq_vic_eint = { + .name = "s5p_vic_eint", + .mask = s5p_irq_vic_eint_mask, + .unmask = s5p_irq_vic_eint_unmask, + .mask_ack = s5p_irq_vic_eint_maskack, + .ack = s5p_irq_vic_eint_ack, + .set_type = s5p_irq_eint_set_type, +#ifdef CONFIG_PM + .set_wake = s3c_irqext_wake, +#endif +}; + +int __init s5p_init_irq_eint(void) +{ + int irq; + + for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++) + set_irq_chip(irq, &s5p_irq_vic_eint); + + for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) { + set_irq_chip(irq, &s5p_irq_eint); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + + set_irq_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31); + return 0; +} + +arch_initcall(s5p_init_irq_eint); |