# Core support for S5PC100 system
-obj-$(CONFIG_CPU_S5PC100) += cpu.o init.o clock.o gpiolib.o
+obj-$(CONFIG_CPU_S5PC100) += cpu.o init.o clock.o gpiolib.o irq-gpio.o
obj-$(CONFIG_CPU_S5PC100) += setup-i2c0.o
# Helper and device support
static __init void s5pc100_gpiolib_link(struct s3c_gpio_chip *chip)
{
-#if 0
/* Interrupt */
if (chip->config == &gpio_cfg) {
int i, irq;
set_irq_handler(irq, handle_level_irq);
set_irq_flags(irq, IRQF_VALID);
}
- } else if (chip->config == &gpio_cfg_eint)
+ } else if (chip->config == &gpio_cfg_eint) {
chip->chip.to_irq = s5pc100_gpiolib_to_eint;
-#endif
+ }
}
static __init int s5pc100_gpiolib_init(void)
samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips,
ARRAY_SIZE(s5pc100_gpio_chips));
-#if 0
+
/* Interrupt */
set_irq_chained_handler(IRQ_GPIOINT, s5pc100_irq_gpioint_handler);
-#endif
+
return 0;
}
core_initcall(s5pc100_gpiolib_init);
--- /dev/null
+/*
+ * 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));
+ }
+ }
+ }
+}
+++ /dev/null
-/*
- * arch/arm/plat-s5pc1xx/irq-gpio.c
- *
- * Copyright (C) 2009 Samsung Electronics
- *
- * S5PC1XX - 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 S5PC1XX_GPIOREG(x) (S5PC1XX_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 s5pc1xx_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 s5pc1xx_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 s5pc1xx_get_offset(unsigned int irq)
-{
- struct gpio_chip *chip = get_irq_data(irq);
- return irq - S3C_IRQ_GPIO(chip->base);
-}
-
-static void s5pc1xx_gpioint_ack(unsigned int irq)
-{
- int group, offset, pend_offset;
- unsigned int value;
-
- group = s5pc1xx_get_group(irq);
- offset = s5pc1xx_get_offset(irq);
- pend_offset = group_to_pend_offset(group);
-
- value = __raw_readl(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
- value |= 1 << offset;
- __raw_writel(value, S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
-}
-
-static void s5pc1xx_gpioint_mask(unsigned int irq)
-{
- int group, offset, mask_offset;
- unsigned int value;
-
- group = s5pc1xx_get_group(irq);
- offset = s5pc1xx_get_offset(irq);
- mask_offset = group_to_mask_offset(group);
-
- value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
- value |= 1 << offset;
- __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
-}
-
-static void s5pc1xx_gpioint_unmask(unsigned int irq)
-{
- int group, offset, mask_offset;
- unsigned int value;
-
- group = s5pc1xx_get_group(irq);
- offset = s5pc1xx_get_offset(irq);
- mask_offset = group_to_mask_offset(group);
-
- value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
- value &= ~(1 << offset);
- __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
-}
-
-static void s5pc1xx_gpioint_mask_ack(unsigned int irq)
-{
- s5pc1xx_gpioint_mask(irq);
- s5pc1xx_gpioint_ack(irq);
-}
-
-static int s5pc1xx_gpioint_set_type(unsigned int irq, unsigned int type)
-{
- int group, offset, con_offset;
- unsigned int value;
-
- group = s5pc1xx_get_group(irq);
- offset = s5pc1xx_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(S5PC1XX_GPIOREG(CON_OFFSET) + con_offset);
- value &= ~(0xf << (offset * 0x4));
- value |= (type << (offset * 0x4));
- __raw_writel(value, S5PC1XX_GPIOREG(CON_OFFSET) + con_offset);
-
- return 0;
-}
-
-struct irq_chip s5pc1xx_gpioint = {
- .name = "GPIO",
- .ack = s5pc1xx_gpioint_ack,
- .mask = s5pc1xx_gpioint_mask,
- .mask_ack = s5pc1xx_gpioint_mask_ack,
- .unmask = s5pc1xx_gpioint_unmask,
- .set_type = s5pc1xx_gpioint_set_type,
-};
-
-void s5pc1xx_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(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
- if (!pend)
- continue;
-
- mask_offset = group_to_mask_offset(group);
- mask = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
- pend &= ~mask;
-
- for (offset = 0; offset < 8; offset++) {
- if (pend & (1 << offset)) {
- real_irq = s5pc1xx_get_start(group) + offset;
- generic_handle_irq(S3C_IRQ_GPIO(real_irq));
- }
- }
- }
-}