* [PATCH v3] ARM: S5P: Add support for gpio interrupts
@ 2010-09-06 9:12 Marek Szyprowski
2010-09-06 9:12 ` [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support Marek Szyprowski
` (6 more replies)
0 siblings, 7 replies; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-06 9:12 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
This patch series adds support for gpio interrupts on Samsung S5P SoC
series (S5PC100 and S5PC110/S5PV210). It is based on the previous
version created by Joonyoung Shim (which is available from the
"[PATCH v2 0/4] ARM: S5P: Support gpio interrupts" thread:
http://comments.gmane.org/gmane.linux.kernel.samsung-soc/1662 ).
This version has been redesigned to assign irq numbers dynamically to
reduce resource waste. Such idea has proposed by Ben Dooks some time ago
(see "[PATCH] ARM: S5P: Dynamicly numbered GPIO interrupt support"
thread: http://comments.gmane.org/gmane.linux.kernel.samsung-soc/1198 ).
The last patch in this series is an example how to use the dynamically
registered gpio interrupt. The QT602240 touch screen device on Goni
machine requires it.
The patch series has been rebased onto latest kgene/for-next kernel
tree.
The complete list of patches:
[PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support
[PATCH 2/6] ARM: S5PC110: add support for gpio interrupts
[PATCH 3/6] ARM: S5PC100: Use generic S5P gpio interrupts interface
[PATCH 4/6] ARM: S5PC100: Move external interrupt defines
[PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function
[PATCH 6/6] ARM: S5PC110: GONI: Add support for QT602240 TS driver
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
@ 2010-09-06 9:12 ` Marek Szyprowski
2010-09-28 14:03 ` Kukjin Kim
2010-09-06 9:12 ` [PATCH 2/6] ARM: S5PC110: add support for gpio interrupts Marek Szyprowski
` (5 subsequent siblings)
6 siblings, 1 reply; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-06 9:12 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds common code to enable support of gpio interrupts on s5p
series.
The total number of gpio pins is quite large on 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
by the s5p_register_gpio_interrupt() function.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
arch/arm/plat-s5p/Kconfig | 5 +
arch/arm/plat-s5p/Makefile | 1 +
arch/arm/plat-s5p/include/plat/irqs.h | 5 +
arch/arm/plat-s5p/irq-gpioint.c | 243 ++++++++++++++++++++++++
arch/arm/plat-samsung/include/plat/gpio-cfg.h | 18 ++
arch/arm/plat-samsung/include/plat/gpio-core.h | 4 +
6 files changed, 276 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/plat-s5p/irq-gpioint.c
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 407e323..d77d518 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.
+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 f3e917e..e0823be 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -18,6 +18,7 @@ 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
# devices
diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-s5p/include/plat/irqs.h
index 3fb3a3a..50bcf1e 100644
--- a/arch/arm/plat-s5p/include/plat/irqs.h
+++ b/arch/arm/plat-s5p/include/plat/irqs.h
@@ -94,4 +94,9 @@
((irq) - S5P_EINT_BASE1) : \
((irq) + 16 - S5P_EINT_BASE2))
+/* GPIO interrupt (registered by s5p_register_gpio_interrupt) */
+#define S5P_GPIOINT_GROUP_COUNT 4
+#define S5P_GPIOINT_GROUP_SIZE 8
+#define S5P_GPIOINT_COUNT (S5P_GPIOINT_GROUP_COUNT * S5P_GPIOINT_GROUP_SIZE)
+
#endif /* __ASM_PLAT_S5P_IRQS_H */
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
new file mode 100644
index 0000000..7409ae0
--- /dev/null
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -0,0 +1,243 @@
+/* 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
+
+#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 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_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(GPIOINT_CON_OFFSET) + con_offset);
+ value &= ~(0xf << (offset * 0x4));
+ value |= (type << (offset * 0x4));
+ __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset);
+
+ return 0;
+}
+
+struct irq_chip s5p_gpioint = {
+ .name = "GPIO",
+ .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) {
+ 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-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
index db4112c..41479a0 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
@@ -169,4 +169,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 e358c7d..c22c27c 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];
--
1.7.2.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 2/6] ARM: S5PC110: add support for gpio interrupts
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
2010-09-06 9:12 ` [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support Marek Szyprowski
@ 2010-09-06 9:12 ` Marek Szyprowski
2010-09-06 9:12 ` [PATCH 3/6] ARM: S5PC100: Use generic S5P gpio interrupts interface Marek Szyprowski
` (4 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-06 9:12 UTC (permalink / raw)
To: linux-arm-kernel
S5PV210/S5PC110 series can use common s5p gpio interrupt code. This
patch adds required defines and code to make use of it.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
arch/arm/mach-s5pv210/gpiolib.c | 6 +++++-
arch/arm/mach-s5pv210/include/mach/irqs.h | 6 +++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-s5pv210/gpiolib.c b/arch/arm/mach-s5pv210/gpiolib.c
index 0d45911..29dfb89 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,
@@ -259,11 +260,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 cdb8ae4..bb7f277 100644
--- a/arch/arm/mach-s5pv210/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv210/include/mach/irqs.h
@@ -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
--
1.7.2.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 3/6] ARM: S5PC100: Use generic S5P gpio interrupts interface
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
2010-09-06 9:12 ` [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support Marek Szyprowski
2010-09-06 9:12 ` [PATCH 2/6] ARM: S5PC110: add support for gpio interrupts Marek Szyprowski
@ 2010-09-06 9:12 ` Marek Szyprowski
2010-09-06 9:12 ` [PATCH 4/6] ARM: S5PC100: Move external interrupt defines Marek Szyprowski
` (3 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-06 9:12 UTC (permalink / raw)
To: linux-arm-kernel
From: Joonyoung Shim <jy0922.shim@samsung.com>
S5PC100 series can use common s5p gpio interrupt code. This patch
removes specific s5pc100 gpio interrupts code and adds required defines
and code to make use of common s5p code.
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
arch/arm/mach-s5pc100/Makefile | 2 +-
arch/arm/mach-s5pc100/gpiolib.c | 45 ++----
arch/arm/mach-s5pc100/include/mach/irqs.h | 9 +-
arch/arm/mach-s5pc100/irq-gpio.c | 266 -----------------------------
4 files changed, 17 insertions(+), 305 deletions(-)
delete mode 100644 arch/arm/mach-s5pc100/irq-gpio.c
diff --git a/arch/arm/mach-s5pc100/Makefile b/arch/arm/mach-s5pc100/Makefile
index a021ed1..eecab57 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 0fab7f2..5811578 100644
--- a/arch/arm/mach-s5pc100/gpiolib.c
+++ b/arch/arm/mach-s5pc100/gpiolib.c
@@ -61,11 +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;
@@ -232,6 +227,7 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
.base = S5PC100_GPH0(0),
.ngpio = S5PC100_GPIO_H0_NR,
.label = "GPH0",
+ .to_irq = s5pc100_gpiolib_to_eint,
},
}, {
.base = S5PC100_GPH1_BASE,
@@ -240,6 +236,7 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
.base = S5PC100_GPH1(0),
.ngpio = S5PC100_GPIO_H1_NR,
.label = "GPH1",
+ .to_irq = s5pc100_gpiolib_to_eint,
},
}, {
.base = S5PC100_GPH2_BASE,
@@ -248,6 +245,7 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
.base = S5PC100_GPH2(0),
.ngpio = S5PC100_GPIO_H2_NR,
.label = "GPH2",
+ .to_irq = s5pc100_gpiolib_to_eint,
},
}, {
.base = S5PC100_GPH3_BASE,
@@ -256,6 +254,7 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
.base = S5PC100_GPH3(0),
.ngpio = S5PC100_GPIO_H3_NR,
.label = "GPH3",
+ .to_irq = s5pc100_gpiolib_to_eint,
},
}, {
.base = S5PC100_GPI_BASE,
@@ -380,47 +379,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/irqs.h b/arch/arm/mach-s5pc100/include/mach/irqs.h
index 06513e6..e782dd6 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/irq-gpio.c b/arch/arm/mach-s5pc100/irq-gpio.c
deleted file mode 100644
index 2bf86c1..0000000
--- 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));
- }
- }
- }
-}
--
1.7.2.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 4/6] ARM: S5PC100: Move external interrupt defines
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
` (2 preceding siblings ...)
2010-09-06 9:12 ` [PATCH 3/6] ARM: S5PC100: Use generic S5P gpio interrupts interface Marek Szyprowski
@ 2010-09-06 9:12 ` Marek Szyprowski
2010-09-10 12:00 ` Kukjin Kim
2010-09-06 9:12 ` [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function Marek Szyprowski
` (2 subsequent siblings)
6 siblings, 1 reply; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-06 9:12 UTC (permalink / raw)
To: linux-arm-kernel
From: Joonyoung Shim <jy0922.shim@samsung.com>
This patch moves external interrupt defines from gpio.h to regs-gpio.h
for consistency with s5pv210.
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
arch/arm/mach-s5pc100/include/mach/gpio.h | 7 -------
arch/arm/mach-s5pc100/include/mach/regs-gpio.h | 7 +++++++
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-s5pc100/include/mach/gpio.h b/arch/arm/mach-s5pc100/include/mach/gpio.h
index 71ae1f5..29a8a12 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/regs-gpio.h b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
index dd6295e..6abe481 100644
--- a/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
+++ b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
@@ -71,5 +71,12 @@
#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 */
--
1.7.2.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
` (3 preceding siblings ...)
2010-09-06 9:12 ` [PATCH 4/6] ARM: S5PC100: Move external interrupt defines Marek Szyprowski
@ 2010-09-06 9:12 ` Marek Szyprowski
2010-10-01 4:49 ` Kukjin Kim
2010-09-06 9:12 ` [PATCH 6/6] ARM: S5PC110: GONI: Add support for QT602240 TS driver Marek Szyprowski
2010-09-29 6:49 ` [PATCH v3] ARM: S5P: Add support for gpio interrupts Kukjin Kim
6 siblings, 1 reply; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-06 9:12 UTC (permalink / raw)
To: linux-arm-kernel
From: Joonyoung Shim <jy0922.shim@samsung.com>
This patch adds a common callback for gpio_to_irq() for external and
gpio interrupts for Samsung SoCs.
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
arch/arm/mach-s3c64xx/gpiolib.c | 8 +----
arch/arm/mach-s5pc100/gpiolib.c | 31 ++++++-----------------
arch/arm/mach-s5pv210/gpiolib.c | 8 ++++++
arch/arm/plat-s3c24xx/gpiolib.c | 8 +----
arch/arm/plat-s5p/irq-gpioint.c | 1 +
arch/arm/plat-samsung/gpiolib.c | 8 ++++++
arch/arm/plat-samsung/include/plat/gpio-core.h | 11 ++++++++
7 files changed, 40 insertions(+), 35 deletions(-)
diff --git a/arch/arm/mach-s3c64xx/gpiolib.c b/arch/arm/mach-s3c64xx/gpiolib.c
index 300dee4..fd99a82 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-s5pc100/gpiolib.c b/arch/arm/mach-s5pc100/gpiolib.c
index 5811578..def4ff8 100644
--- a/arch/arm/mach-s5pc100/gpiolib.c
+++ b/arch/arm/mach-s5pc100/gpiolib.c
@@ -61,25 +61,6 @@
* L3 8 4Bit None
*/
-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,
@@ -223,38 +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 = s5pc100_gpiolib_to_eint,
+ .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 = s5pc100_gpiolib_to_eint,
+ .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 = s5pc100_gpiolib_to_eint,
+ .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 = s5pc100_gpiolib_to_eint,
+ .to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = S5PC100_GPI_BASE,
diff --git a/arch/arm/mach-s5pv210/gpiolib.c b/arch/arm/mach-s5pv210/gpiolib.c
index 29dfb89..ab673ef 100644
--- a/arch/arm/mach-s5pv210/gpiolib.c
+++ b/arch/arm/mach-s5pv210/gpiolib.c
@@ -224,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,
},
},
};
diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c
index 4c0896f..243b641 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/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 7409ae0..5b735b1 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -235,6 +235,7 @@ int __init s5p_register_gpio_interrupt(int pin)
/* 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;
diff --git a/arch/arm/plat-samsung/gpiolib.c b/arch/arm/plat-samsung/gpiolib.c
index c354089..f2dc389 100644
--- a/arch/arm/plat-samsung/gpiolib.c
+++ b/arch/arm/plat-samsung/gpiolib.c
@@ -197,3 +197,11 @@ void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip,
s3c_gpiolib_add(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-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h
index c22c27c..13a22b8 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-core.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-core.h
@@ -122,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;
--
1.7.2.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 6/6] ARM: S5PC110: GONI: Add support for QT602240 TS driver
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
` (4 preceding siblings ...)
2010-09-06 9:12 ` [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function Marek Szyprowski
@ 2010-09-06 9:12 ` Marek Szyprowski
2010-10-04 9:22 ` [PATCH RESEND] " Marek Szyprowski
2010-09-29 6:49 ` [PATCH v3] ARM: S5P: Add support for gpio interrupts Kukjin Kim
6 siblings, 1 reply; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-06 9:12 UTC (permalink / raw)
To: linux-arm-kernel
From: Kyungmin Park <kyungmin.park@samsung.com>
Add required platform definitions for QT602240 touchscreen on I2C2 bus.
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
arch/arm/mach-s5pv210/Kconfig | 3 ++
arch/arm/mach-s5pv210/mach-goni.c | 56 +++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 5315fec..2f4025d 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -76,6 +76,7 @@ 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 +84,10 @@ config MACH_GONI
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1
select S3C_DEV_HSMMC2
+ select S3C_DEV_I2C2
select S5P_DEV_ONENAND
select S5PV210_SETUP_FB_24BPP
+ select S5PV210_SETUP_I2C2
select S5PV210_SETUP_SDHCI
help
Machine support for Samsung GONI board
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index fdc5cca..bc9c5af 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -15,6 +15,7 @@
#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/gpio_keys.h>
#include <linux/input.h>
@@ -35,6 +36,7 @@
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/fb.h>
+#include <plat/iic.h>
#include <plat/sdhci.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
@@ -111,6 +113,52 @@ static struct s3c_fb_platdata goni_lcd_pdata __initdata = {
.setup_gpio = s5pv210_fb_gpio_setup_24bpp,
};
+/* 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, irq;
+
+ 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);
+ irq = gpio_to_irq(gpio);
+ i2c2_devs[0].irq = irq;
+}
+
/* MAX8998 regulators */
#if defined(CONFIG_REGULATOR_MAX8998) || defined(CONFIG_REGULATOR_MAX8998_MODULE)
@@ -465,6 +513,7 @@ static struct platform_device *goni_devices[] __initdata = {
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
+ &s3c_device_i2c2,
};
static void __init goni_map_io(void)
@@ -476,6 +525,13 @@ static void __init goni_map_io(void)
static void __init goni_machine_init(void)
{
+ /* 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,
--
1.7.2.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 4/6] ARM: S5PC100: Move external interrupt defines
2010-09-06 9:12 ` [PATCH 4/6] ARM: S5PC100: Move external interrupt defines Marek Szyprowski
@ 2010-09-10 12:00 ` Kukjin Kim
2010-09-21 5:16 ` Marek Szyprowski
0 siblings, 1 reply; 20+ messages in thread
From: Kukjin Kim @ 2010-09-10 12:00 UTC (permalink / raw)
To: linux-arm-kernel
Marek Szyprowski wrote:
>
> From: Joonyoung Shim <jy0922.shim@samsung.com>
>
> This patch moves external interrupt defines from gpio.h to regs-gpio.h
> for consistency with s5pv210.
>
> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> arch/arm/mach-s5pc100/include/mach/gpio.h | 7 -------
> arch/arm/mach-s5pc100/include/mach/regs-gpio.h | 7 +++++++
> 2 files changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm/mach-s5pc100/include/mach/gpio.h b/arch/arm/mach-
> s5pc100/include/mach/gpio.h
> index 71ae1f5..29a8a12 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/regs-gpio.h
b/arch/arm/mach-
> s5pc100/include/mach/regs-gpio.h
> index dd6295e..6abe481 100644
> --- a/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
> +++ b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
> @@ -71,5 +71,12 @@
> #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 */
>
> --
This is ok to me, will apply.
And will check other regarding gpio interrupt in this weekend ;-)
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 4/6] ARM: S5PC100: Move external interrupt defines
2010-09-10 12:00 ` Kukjin Kim
@ 2010-09-21 5:16 ` Marek Szyprowski
0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-21 5:16 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
On Friday, September 10, 2010 2:00 PM Kukjin Kim wrote:
> Marek Szyprowski wrote:
> >
> > From: Joonyoung Shim <jy0922.shim@samsung.com>
> >
> > This patch moves external interrupt defines from gpio.h to regs-gpio.h
> > for consistency with s5pv210.
> >
> > Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > ---
> > arch/arm/mach-s5pc100/include/mach/gpio.h | 7 -------
> > arch/arm/mach-s5pc100/include/mach/regs-gpio.h | 7 +++++++
> > 2 files changed, 7 insertions(+), 7 deletions(-)
> >
> > diff --git a/arch/arm/mach-s5pc100/include/mach/gpio.h b/arch/arm/mach-
> > s5pc100/include/mach/gpio.h
> > index 71ae1f5..29a8a12 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/regs-gpio.h
> b/arch/arm/mach-
> > s5pc100/include/mach/regs-gpio.h
> > index dd6295e..6abe481 100644
> > --- a/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
> > +++ b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
> > @@ -71,5 +71,12 @@
> > #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 */
> >
> > --
>
> This is ok to me, will apply.
>
> And will check other regarding gpio interrupt in this weekend ;-)
Is there any progress on gpio interrupts? Over 2 weeks passed since I
posted the patches...
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support
2010-09-06 9:12 ` [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support Marek Szyprowski
@ 2010-09-28 14:03 ` Kukjin Kim
2010-09-28 14:24 ` Marek Szyprowski
0 siblings, 1 reply; 20+ messages in thread
From: Kukjin Kim @ 2010-09-28 14:03 UTC (permalink / raw)
To: linux-arm-kernel
Marek Szyprowski wrote:
>
> This patch adds common code to enable support of gpio interrupts on s5p
> series.
>
> The total number of gpio pins is quite large on 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
> by the s5p_register_gpio_interrupt() function.
Hi,
I checked only S5PV210/S5PC110 GPIO interrupt.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> arch/arm/plat-s5p/Kconfig | 5 +
> arch/arm/plat-s5p/Makefile | 1 +
> arch/arm/plat-s5p/include/plat/irqs.h | 5 +
> arch/arm/plat-s5p/irq-gpioint.c | 243
> ++++++++++++++++++++++++
> arch/arm/plat-samsung/include/plat/gpio-cfg.h | 18 ++
> arch/arm/plat-samsung/include/plat/gpio-core.h | 4 +
> 6 files changed, 276 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/plat-s5p/irq-gpioint.c
>
> diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
> index 407e323..d77d518 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.
>
> +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 f3e917e..e0823be 100644
> --- a/arch/arm/plat-s5p/Makefile
> +++ b/arch/arm/plat-s5p/Makefile
> @@ -18,6 +18,7 @@ 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
>
> # devices
>
> diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-
> s5p/include/plat/irqs.h
> index 3fb3a3a..50bcf1e 100644
> --- a/arch/arm/plat-s5p/include/plat/irqs.h
> +++ b/arch/arm/plat-s5p/include/plat/irqs.h
> @@ -94,4 +94,9 @@
> ((irq) - S5P_EINT_BASE1) : \
> ((irq) + 16 -
> S5P_EINT_BASE2))
>
> +/* GPIO interrupt (registered by s5p_register_gpio_interrupt) */
> +#define S5P_GPIOINT_GROUP_COUNT 4
> +#define S5P_GPIOINT_GROUP_SIZE 8
Is it possible to support S5P SoCs GPIO interrupt with only 4-GROUPs?
> +#define S5P_GPIOINT_COUNT (S5P_GPIOINT_GROUP_COUNT *
> S5P_GPIOINT_GROUP_SIZE)
> +
> #endif /* __ASM_PLAT_S5P_IRQS_H */
> diff --git a/arch/arm/plat-s5p/irq-gpioint.c
b/arch/arm/plat-s5p/irq-gpioint.c
> new file mode 100644
> index 0000000..7409ae0
> --- /dev/null
> +++ b/arch/arm/plat-s5p/irq-gpioint.c
> @@ -0,0 +1,243 @@
> +/* 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
> +
> +#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
I remember Kyungmin's patch about interrupt polarity of GPIO Interrupt and
GPIO External Interrupt.
How about merging them into plat-s5p/include
Hmm...let's think the proper name...
> +
> +static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR];
Where is the definition of 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_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();
how about merging IRQ_TYPE_NONE and 'default'?
And basically, rerely happened exception case, so it's better move
IRQ_TYPE_NONE to later in switch case.
> + }
> +
> + value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) +
> con_offset);
> + value &= ~(0xf << (offset * 0x4));
0x7 is enough on S5PV210...but need to check another S5P SoCs.
> + value |= (type << (offset * 0x4));
> + __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) +
> con_offset);
> +
> + return 0;
> +}
> +
> +struct irq_chip s5p_gpioint = {
> + .name = "GPIO",
how about 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;
Where is S5P_GPIOINT_BASE?
> + used_gpioint_groups++;
> +
> + if (!handler_registered) {
> + set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler);
As you know, IRQ_GPIOINT defined only in the mach-s5p6442, mach-s5pc100 and
mach-s5pv210.
It means can be happend build error with mach-s5p64x0 or mach-s5pv310.
> + 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);
Do we really need set_irq_data?
> + 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) {
> + 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-samsung/include/plat/gpio-cfg.h
b/arch/arm/plat-
> samsung/include/plat/gpio-cfg.h
> index db4112c..41479a0 100644
> --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
> +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
> @@ -169,4 +169,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 e358c7d..c22c27c 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];
> --
I need sleeping :-)
Will continue tomorrow.
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support
2010-09-28 14:03 ` Kukjin Kim
@ 2010-09-28 14:24 ` Marek Szyprowski
2010-09-28 14:43 ` Kyungmin Park
2010-09-30 7:12 ` [PATCH v4] " Marek Szyprowski
0 siblings, 2 replies; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-28 14:24 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
On Tuesday, September 28, 2010 4:04 PM Kukjin Kim wrote:
> Marek Szyprowski wrote:
> >
> > This patch adds common code to enable support of gpio interrupts on s5p
> > series.
> >
> > The total number of gpio pins is quite large on 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
> > by the s5p_register_gpio_interrupt() function.
>
> Hi,
>
> I checked only S5PV210/S5PC110 GPIO interrupt.
>
> >
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > ---
> > arch/arm/plat-s5p/Kconfig | 5 +
> > arch/arm/plat-s5p/Makefile | 1 +
> > arch/arm/plat-s5p/include/plat/irqs.h | 5 +
> > arch/arm/plat-s5p/irq-gpioint.c | 243
> > ++++++++++++++++++++++++
> > arch/arm/plat-samsung/include/plat/gpio-cfg.h | 18 ++
> > arch/arm/plat-samsung/include/plat/gpio-core.h | 4 +
> > 6 files changed, 276 insertions(+), 0 deletions(-)
> > create mode 100644 arch/arm/plat-s5p/irq-gpioint.c
> >
> > diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
> > index 407e323..d77d518 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.
> >
> > +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 f3e917e..e0823be 100644
> > --- a/arch/arm/plat-s5p/Makefile
> > +++ b/arch/arm/plat-s5p/Makefile
> > @@ -18,6 +18,7 @@ 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
> >
> > # devices
> >
> > diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-
> > s5p/include/plat/irqs.h
> > index 3fb3a3a..50bcf1e 100644
> > --- a/arch/arm/plat-s5p/include/plat/irqs.h
> > +++ b/arch/arm/plat-s5p/include/plat/irqs.h
> > @@ -94,4 +94,9 @@
> > ((irq) - S5P_EINT_BASE1) : \
> > ((irq) + 16 -
> > S5P_EINT_BASE2))
> >
> > +/* GPIO interrupt (registered by s5p_register_gpio_interrupt) */
> > +#define S5P_GPIOINT_GROUP_COUNT 4
> > +#define S5P_GPIOINT_GROUP_SIZE 8
>
> Is it possible to support S5P SoCs GPIO interrupt with only 4-GROUPs?
Yes, it won't be a problem. Just 4 interrupt slots will be wasted. Not a bit problem
imho.
>
> > +#define S5P_GPIOINT_COUNT (S5P_GPIOINT_GROUP_COUNT *
> > S5P_GPIOINT_GROUP_SIZE)
> > +
> > #endif /* __ASM_PLAT_S5P_IRQS_H */
> > diff --git a/arch/arm/plat-s5p/irq-gpioint.c
> b/arch/arm/plat-s5p/irq-gpioint.c
> > new file mode 100644
> > index 0000000..7409ae0
> > --- /dev/null
> > +++ b/arch/arm/plat-s5p/irq-gpioint.c
> > @@ -0,0 +1,243 @@
> > +/* 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
> > +
> > +#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
>
> I remember Kyungmin's patch about interrupt polarity of GPIO Interrupt and
> GPIO External Interrupt.
> How about merging them into plat-s5p/include
I'm ok with this.
> Hmm...let's think the proper name...
>
> > +
> > +static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR];
>
> Where is the definition of S5P_GPIOINT_GROUP_MAXNR?
It will be defined by the proper user of the common irq-gpioint.c code. See the
next commit ("ARM: S5PC110: add support for gpio interrupts"). To avoid any
build breaks irq-gpioint.c code is compiled conditionally if selected by the
machine that requires/uses it.
> > +
> > +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_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();
>
> how about merging IRQ_TYPE_NONE and 'default'?
> And basically, rerely happened exception case, so it's better move
> IRQ_TYPE_NONE to later in switch case.
Ok, I can change this.
> > + }
> > +
> > + value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) +
> > con_offset);
> > + value &= ~(0xf << (offset * 0x4));
>
> 0x7 is enough on S5PV210...but need to check another S5P SoCs.
>
> > + value |= (type << (offset * 0x4));
> > + __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) +
> > con_offset);
> > +
> > + return 0;
> > +}
> > +
> > +struct irq_chip s5p_gpioint = {
> > + .name = "GPIO",
>
> how about s5p-gpioint?
ok, no problem.
>
> > + .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;
>
> Where is S5P_GPIOINT_BASE?
see the next commit...
>
> > + used_gpioint_groups++;
> > +
> > + if (!handler_registered) {
> > + set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler);
>
> As you know, IRQ_GPIOINT defined only in the mach-s5p6442, mach-s5pc100 and
> mach-s5pv210.
> It means can be happend build error with mach-s5p64x0 or mach-s5pv310.
Nope, this code is compiled conditionally only if the platform requires/supports
it.
>
> > + 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);
>
> Do we really need set_irq_data?
Yes, to get the gpio bank group number in s5p_gpioint_get_group() function.
>
> > + 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) {
> > + 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-samsung/include/plat/gpio-cfg.h
> b/arch/arm/plat-
> > samsung/include/plat/gpio-cfg.h
> > index db4112c..41479a0 100644
> > --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
> > +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
> > @@ -169,4 +169,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 e358c7d..c22c27c 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];
> > --
>
> I need sleeping :-)
> Will continue tomorrow.
Ok.
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support
2010-09-28 14:24 ` Marek Szyprowski
@ 2010-09-28 14:43 ` Kyungmin Park
2010-09-30 7:12 ` [PATCH v4] " Marek Szyprowski
1 sibling, 0 replies; 20+ messages in thread
From: Kyungmin Park @ 2010-09-28 14:43 UTC (permalink / raw)
To: linux-arm-kernel
Hi Marek,
On Sep 28, 2010 11:24 PM, "Marek Szyprowski"
<m.szyprowski@samsung.com> wrote:> Hello,
>
> On Tuesday, September 28, 2010 4:04 PM Kukjin Kim wrote:
>
>> Marek Szyprowski wrote:
>> >
>> > This patch adds common code to enable support of gpio interrupts on s5p
>> > series.
>> >
>> > The total number of gpio pins is quite large on 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
>> > by the s5p_register_gpio_interrupt() function.
>>
>> Hi,
>>
>> I checked only S5PV210/S5PC110 GPIO interrupt.
>>
>> >
>> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> > Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
>> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> > ---
>> > arch/arm/plat-s5p/Kconfig | 5 +
>> > arch/arm/plat-s5p/Makefile | 1 +
>> > arch/arm/plat-s5p/include/plat/irqs.h | 5 +
>> > arch/arm/plat-s5p/irq-gpioint.c | 243
>> > ++++++++++++++++++++++++
>> > arch/arm/plat-samsung/include/plat/gpio-cfg.h | 18 ++
>> > arch/arm/plat-samsung/include/plat/gpio-core.h | 4 +
>> > 6 files changed, 276 insertions(+), 0 deletions(-)
>> > create mode 100644 arch/arm/plat-s5p/irq-gpioint.c
>> >
>> > diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
>> > index 407e323..d77d518 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.
>> >
>> > +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 f3e917e..e0823be 100644
>> > --- a/arch/arm/plat-s5p/Makefile
>> > +++ b/arch/arm/plat-s5p/Makefile
>> > @@ -18,6 +18,7 @@ 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
>> >
>> > # devices
>> >
>> > diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-
>> > s5p/include/plat/irqs.h
>> > index 3fb3a3a..50bcf1e 100644
>> > --- a/arch/arm/plat-s5p/include/plat/irqs.h
>> > +++ b/arch/arm/plat-s5p/include/plat/irqs.h
>> > @@ -94,4 +94,9 @@
>> > ((irq) - S5P_EINT_BASE1) : \
>> > ((irq) + 16 -
>> > S5P_EINT_BASE2))
>> >
>> > +/* GPIO interrupt (registered by s5p_register_gpio_interrupt) */
>> > +#define S5P_GPIOINT_GROUP_COUNT 4
>> > +#define S5P_GPIOINT_GROUP_SIZE 8
>>
>> Is it possible to support S5P SoCs GPIO interrupt with only 4-GROUPs?
>
> Yes, it won't be a problem. Just 4 interrupt slots will be wasted. Not a bit problem
> imho.
>
>>
>> > +#define S5P_GPIOINT_COUNT (S5P_GPIOINT_GROUP_COUNT *
>> > S5P_GPIOINT_GROUP_SIZE)
>> > +
>> > #endif /* __ASM_PLAT_S5P_IRQS_H */
>> > diff --git a/arch/arm/plat-s5p/irq-gpioint.c
>> b/arch/arm/plat-s5p/irq-gpioint.c
>> > new file mode 100644
>> > index 0000000..7409ae0
>> > --- /dev/null
>> > +++ b/arch/arm/plat-s5p/irq-gpioint.c
>> > @@ -0,0 +1,243 @@
>> > +/* 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
>> > +
>> > +#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
>>
>> I remember Kyungmin's patch about interrupt polarity of GPIO Interrupt and
>> GPIO External Interrupt.
>> How about merging them into plat-s5p/include
>
> I'm ok with this.
>
>> Hmm...let's think the proper name...
>>
>> > +
>> > +static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR];
>>
>> Where is the definition of S5P_GPIOINT_GROUP_MAXNR?
>
> It will be defined by the proper user of the common irq-gpioint.c code. See the
> next commit ("ARM: S5PC110: add support for gpio interrupts"). To avoid any
> build breaks irq-gpioint.c code is compiled conditionally if selected by the
> machine that requires/uses it.
>
>> > +
>> > +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_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();
>>
>> how about merging IRQ_TYPE_NONE and 'default'?
>> And basically, rerely happened exception case, so it's better move
>> IRQ_TYPE_NONE to later in switch case.
>
> Ok, I can change this.
>
>> > + }
>> > +
>> > + value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) +
>> > con_offset);
>> > + value &= ~(0xf << (offset * 0x4));
>>
>> 0x7 is enough on S5PV210...but need to check another S5P SoCs.
>>
>> > + value |= (type << (offset * 0x4));
>> > + __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) +
>> > con_offset);
>> > +
>> > + return 0;
>> > +}
>> > +
>> > +struct irq_chip s5p_gpioint = {
>> > + .name = "GPIO",
>>
>> how about s5p-gpioint?
>
> ok, no problem.
Please use the GPIO as is, I don't like s5p- prefix.
It's not major issue. I want to use normal way like VIC, GIC, PIC and so on.
It's displayed at /proc/interrupts so no need to add *int suffix.
Thank you
Kyungmin Park
>
>>
>> > + .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;
>>
>> Where is S5P_GPIOINT_BASE?
>
> see the next commit...
>
>>
>> > + used_gpioint_groups++;
>> > +
>> > + if (!handler_registered) {
>> > + set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler);
>>
>> As you know, IRQ_GPIOINT defined only in the mach-s5p6442, mach-s5pc100 and
>> mach-s5pv210.
>> It means can be happend build error with mach-s5p64x0 or mach-s5pv310.
>
> Nope, this code is compiled conditionally only if the platform requires/supports
> it.
>
>>
>> > + 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);
>>
>> Do we really need set_irq_data?
>
> Yes, to get the gpio bank group number in s5p_gpioint_get_group() function.
>
>>
>> > + 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) {
>> > + 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-samsung/include/plat/gpio-cfg.h
>> b/arch/arm/plat-
>> > samsung/include/plat/gpio-cfg.h
>> > index db4112c..41479a0 100644
>> > --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
>> > +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
>> > @@ -169,4 +169,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 e358c7d..c22c27c 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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v3] ARM: S5P: Add support for gpio interrupts
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
` (5 preceding siblings ...)
2010-09-06 9:12 ` [PATCH 6/6] ARM: S5PC110: GONI: Add support for QT602240 TS driver Marek Szyprowski
@ 2010-09-29 6:49 ` Kukjin Kim
6 siblings, 0 replies; 20+ messages in thread
From: Kukjin Kim @ 2010-09-29 6:49 UTC (permalink / raw)
To: linux-arm-kernel
Marek Szyprowski wrote:
>
> Hello,
>
Hi :-)
> This patch series adds support for gpio interrupts on Samsung S5P SoC
> series (S5PC100 and S5PC110/S5PV210). It is based on the previous
> version created by Joonyoung Shim (which is available from the
> "[PATCH v2 0/4] ARM: S5P: Support gpio interrupts" thread:
> http://comments.gmane.org/gmane.linux.kernel.samsung-soc/1662 ).
>
> This version has been redesigned to assign irq numbers dynamically to
> reduce resource waste. Such idea has proposed by Ben Dooks some time ago
> (see "[PATCH] ARM: S5P: Dynamicly numbered GPIO interrupt support"
> thread: http://comments.gmane.org/gmane.linux.kernel.samsung-soc/1198 ).
>
> The last patch in this series is an example how to use the dynamically
> registered gpio interrupt. The QT602240 touch screen device on Goni
> machine requires it.
>
> The patch series has been rebased onto latest kgene/for-next kernel
> tree.
>
> The complete list of patches:
>
> [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support
> [PATCH 2/6] ARM: S5PC110: add support for gpio interrupts
> [PATCH 3/6] ARM: S5PC100: Use generic S5P gpio interrupts interface
> [PATCH 4/6] ARM: S5PC100: Move external interrupt defines
> [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function
> [PATCH 6/6] ARM: S5PC110: GONI: Add support for QT602240 TS driver
>
Ok...initial reading your 2nd to 5th patches, looks ok to me...will apply.
Others, will check/review soon.
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v4] ARM: Samsung: Add common s5p gpio interrupt support
2010-09-28 14:24 ` Marek Szyprowski
2010-09-28 14:43 ` Kyungmin Park
@ 2010-09-30 7:12 ` Marek Szyprowski
2010-09-30 13:29 ` Kukjin Kim
1 sibling, 1 reply; 20+ messages in thread
From: Marek Szyprowski @ 2010-09-30 7:12 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds common code to enable support of gpio interrupts on s5p
series.
The total number of gpio pins is quite large on 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
by the s5p_register_gpio_interrupt() function.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
Changes since v3:
- merged default and IRQ_TYPE_NONE cases in s5p_gpioint_set_type function
- fixed mask in GPIOINT_CON_OFFSET register from 0xf to 0x7
- renamed the chip to s5p_gpioint to match the s5p_extint style
- extended comments in plat/irqs.h
---
arch/arm/plat-s5p/Kconfig | 5 +
arch/arm/plat-s5p/Makefile | 1 +
arch/arm/plat-s5p/include/plat/irqs.h | 9 +
arch/arm/plat-s5p/irq-gpioint.c | 242 ++++++++++++++++++++++++
arch/arm/plat-samsung/include/plat/gpio-cfg.h | 18 ++
arch/arm/plat-samsung/include/plat/gpio-core.h | 4 +
6 files changed, 279 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/plat-s5p/irq-gpioint.c
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 2596096..65dbfa8 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 f3e917e..e0823be 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -18,6 +18,7 @@ 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
# devices
diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-s5p/include/plat/irqs.h
index 3fb3a3a..5a7bf96 100644
--- a/arch/arm/plat-s5p/include/plat/irqs.h
+++ b/arch/arm/plat-s5p/include/plat/irqs.h
@@ -94,4 +94,13 @@
((irq) - S5P_EINT_BASE1) : \
((irq) + 16 - S5P_EINT_BASE2))
+/* 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)
+
#endif /* __ASM_PLAT_S5P_IRQS_H */
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
new file mode 100644
index 0000000..32263a3
--- /dev/null
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -0,0 +1,242 @@
+/* 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
+
+#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 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 = 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;
+ 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) {
+ 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-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
index 1c6b929..5b43b95 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
@@ -169,4 +169,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 e358c7d..c22c27c 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];
--
1.7.1.569.g6f426
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v4] ARM: Samsung: Add common s5p gpio interrupt support
2010-09-30 7:12 ` [PATCH v4] " Marek Szyprowski
@ 2010-09-30 13:29 ` Kukjin Kim
2010-09-30 13:47 ` Kyungmin Park
0 siblings, 1 reply; 20+ messages in thread
From: Kukjin Kim @ 2010-09-30 13:29 UTC (permalink / raw)
To: linux-arm-kernel
Marek Szyprowski wrote:
>
> This patch adds common code to enable support of gpio interrupts on s5p
> series.
>
> The total number of gpio pins is quite large on 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
> by the s5p_register_gpio_interrupt() function.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>
> ---
>
> Changes since v3:
> - merged default and IRQ_TYPE_NONE cases in s5p_gpioint_set_type function
> - fixed mask in GPIOINT_CON_OFFSET register from 0xf to 0x7
> - renamed the chip to s5p_gpioint to match the s5p_extint style
> - extended comments in plat/irqs.h
>
> ---
> arch/arm/plat-s5p/Kconfig | 5 +
> arch/arm/plat-s5p/Makefile | 1 +
> arch/arm/plat-s5p/include/plat/irqs.h | 9 +
> arch/arm/plat-s5p/irq-gpioint.c | 242
> ++++++++++++++++++++++++
> arch/arm/plat-samsung/include/plat/gpio-cfg.h | 18 ++
> arch/arm/plat-samsung/include/plat/gpio-core.h | 4 +
> 6 files changed, 279 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/plat-s5p/irq-gpioint.c
>
> diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
> index 2596096..65dbfa8 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 f3e917e..e0823be 100644
> --- a/arch/arm/plat-s5p/Makefile
> +++ b/arch/arm/plat-s5p/Makefile
> @@ -18,6 +18,7 @@ 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
>
> # devices
>
> diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-
> s5p/include/plat/irqs.h
> index 3fb3a3a..5a7bf96 100644
> --- a/arch/arm/plat-s5p/include/plat/irqs.h
> +++ b/arch/arm/plat-s5p/include/plat/irqs.h
> @@ -94,4 +94,13 @@
> ((irq) - S5P_EINT_BASE1) : \
> ((irq) + 16 -
> S5P_EINT_BASE2))
>
> +/* 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)
> +
> #endif /* __ASM_PLAT_S5P_IRQS_H */
> diff --git a/arch/arm/plat-s5p/irq-gpioint.c
b/arch/arm/plat-s5p/irq-gpioint.c
> new file mode 100644
> index 0000000..32263a3
> --- /dev/null
> +++ b/arch/arm/plat-s5p/irq-gpioint.c
> @@ -0,0 +1,242 @@
> +/* 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
> +
> +#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 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 = 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;
> + 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) {
> + 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-samsung/include/plat/gpio-cfg.h
b/arch/arm/plat-
> samsung/include/plat/gpio-cfg.h
> index 1c6b929..5b43b95 100644
> --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
> +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
> @@ -169,4 +169,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 e358c7d..c22c27c 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];
> --
Looks ok to me...will apply.
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v4] ARM: Samsung: Add common s5p gpio interrupt support
2010-09-30 13:29 ` Kukjin Kim
@ 2010-09-30 13:47 ` Kyungmin Park
0 siblings, 0 replies; 20+ messages in thread
From: Kyungmin Park @ 2010-09-30 13:47 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Sep 30, 2010 at 10:29 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
> Marek Szyprowski wrote:
>>
>> This patch adds common code to enable support of gpio interrupts on s5p
>> series.
>>
>> The total number of gpio pins is quite large on 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
>> by the s5p_register_gpio_interrupt() function.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>>
>> ---
>>
>> Changes since v3:
>> - merged default and IRQ_TYPE_NONE cases in s5p_gpioint_set_type function
>> - fixed mask in GPIOINT_CON_OFFSET register from 0xf to 0x7
>> - renamed the chip to s5p_gpioint to match the s5p_extint style
>> - extended comments in plat/irqs.h
>>
>> ---
>> ?arch/arm/plat-s5p/Kconfig ? ? ? ? ? ? ? ? ? ? ?| ? ?5 +
>> ?arch/arm/plat-s5p/Makefile ? ? ? ? ? ? ? ? ? ? | ? ?1 +
>> ?arch/arm/plat-s5p/include/plat/irqs.h ? ? ? ? ?| ? ?9 +
>> ?arch/arm/plat-s5p/irq-gpioint.c ? ? ? ? ? ? ? ?| ?242
>> ++++++++++++++++++++++++
>> ?arch/arm/plat-samsung/include/plat/gpio-cfg.h ?| ? 18 ++
>> ?arch/arm/plat-samsung/include/plat/gpio-core.h | ? ?4 +
>> ?6 files changed, 279 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/plat-s5p/irq-gpioint.c
>>
>> diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
>> index 2596096..65dbfa8 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 f3e917e..e0823be 100644
>> --- a/arch/arm/plat-s5p/Makefile
>> +++ b/arch/arm/plat-s5p/Makefile
>> @@ -18,6 +18,7 @@ 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
>>
>> ?# devices
>>
>> diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-
>> s5p/include/plat/irqs.h
>> index 3fb3a3a..5a7bf96 100644
>> --- a/arch/arm/plat-s5p/include/plat/irqs.h
>> +++ b/arch/arm/plat-s5p/include/plat/irqs.h
>> @@ -94,4 +94,13 @@
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ((irq) - S5P_EINT_BASE1) : \
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ((irq) + 16 -
>> S5P_EINT_BASE2))
>>
>> +/* 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)
>> +
>> ?#endif /* __ASM_PLAT_S5P_IRQS_H */
>> diff --git a/arch/arm/plat-s5p/irq-gpioint.c
> b/arch/arm/plat-s5p/irq-gpioint.c
>> new file mode 100644
>> index 0000000..32263a3
>> --- /dev/null
>> +++ b/arch/arm/plat-s5p/irq-gpioint.c
>> @@ -0,0 +1,242 @@
>> +/* 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
>> +
>> +#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 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 = 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;
>> + ? ? 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) {
>> + ? ? ? ? ? ? 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-samsung/include/plat/gpio-cfg.h
> b/arch/arm/plat-
>> samsung/include/plat/gpio-cfg.h
>> index 1c6b929..5b43b95 100644
>> --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
>> +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
>> @@ -169,4 +169,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 e358c7d..c22c27c 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];
>> --
>
> Looks ok to me...will apply.
I hope I want to see the applied patches tomorrow since there are more patches.
One more, what's going on s5pc110 features. especially suspend &
resume. If you need I'll add Ack-by that patches.
Thank you,
Kyungmin Park
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function
2010-09-06 9:12 ` [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function Marek Szyprowski
@ 2010-10-01 4:49 ` Kukjin Kim
2010-10-01 5:19 ` Marek Szyprowski
0 siblings, 1 reply; 20+ messages in thread
From: Kukjin Kim @ 2010-10-01 4:49 UTC (permalink / raw)
To: linux-arm-kernel
Marek Szyprowski wrote:
>
> From: Joonyoung Shim <jy0922.shim@samsung.com>
>
> This patch adds a common callback for gpio_to_irq() for external and
> gpio interrupts for Samsung SoCs.
>
> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> arch/arm/mach-s3c64xx/gpiolib.c | 8 +----
> arch/arm/mach-s5pc100/gpiolib.c | 31
++++++-----------------
> arch/arm/mach-s5pv210/gpiolib.c | 8 ++++++
> arch/arm/plat-s3c24xx/gpiolib.c | 8 +----
> arch/arm/plat-s5p/irq-gpioint.c | 1 +
> arch/arm/plat-samsung/gpiolib.c | 8 ++++++
> arch/arm/plat-samsung/include/plat/gpio-core.h | 11 ++++++++
> 7 files changed, 40 insertions(+), 35 deletions(-)
>
> diff --git a/arch/arm/mach-s3c64xx/gpiolib.c
b/arch/arm/mach-s3c64xx/gpiolib.c
> index 300dee4..fd99a82 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-s5pc100/gpiolib.c
b/arch/arm/mach-s5pc100/gpiolib.c
> index 5811578..def4ff8 100644
> --- a/arch/arm/mach-s5pc100/gpiolib.c
> +++ b/arch/arm/mach-s5pc100/gpiolib.c
> @@ -61,25 +61,6 @@
> * L3 8 4Bit None
> */
>
> -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,
> @@ -223,38 +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 = s5pc100_gpiolib_to_eint,
> + .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 = s5pc100_gpiolib_to_eint,
> + .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 = s5pc100_gpiolib_to_eint,
> + .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 = s5pc100_gpiolib_to_eint,
> + .to_irq = samsung_gpiolib_to_irq,
> },
> }, {
> .base = S5PC100_GPI_BASE,
> diff --git a/arch/arm/mach-s5pv210/gpiolib.c
b/arch/arm/mach-s5pv210/gpiolib.c
> index 29dfb89..ab673ef 100644
> --- a/arch/arm/mach-s5pv210/gpiolib.c
> +++ b/arch/arm/mach-s5pv210/gpiolib.c
> @@ -224,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,
> },
> },
> };
> diff --git a/arch/arm/plat-s3c24xx/gpiolib.c
b/arch/arm/plat-s3c24xx/gpiolib.c
> index 4c0896f..243b641 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/irq-gpioint.c
b/arch/arm/plat-s5p/irq-gpioint.c
> index 7409ae0..5b735b1 100644
> --- a/arch/arm/plat-s5p/irq-gpioint.c
> +++ b/arch/arm/plat-s5p/irq-gpioint.c
> @@ -235,6 +235,7 @@ int __init s5p_register_gpio_interrupt(int pin)
> /* 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;
> diff --git a/arch/arm/plat-samsung/gpiolib.c
b/arch/arm/plat-samsung/gpiolib.c
> index c354089..f2dc389 100644
> --- a/arch/arm/plat-samsung/gpiolib.c
> +++ b/arch/arm/plat-samsung/gpiolib.c
> @@ -197,3 +197,11 @@ void __init samsung_gpiolib_add_4bit2_chips(struct
> s3c_gpio_chip *chip,
> s3c_gpiolib_add(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;
> +}
Hi,
Following is for your information...
Moved samsung_gpiolib_to_irq() into plat-samsung/gpio.c because happened
build error like following after applying this.
arch/arm/plat-s3c24xx/built-in.o:(.data+0x11c4): undefined reference to
`samsung_gpiolib_to_irq'
The reason is that plat-samsung/gpiolib.c is not required for
s3c24xx...applied anyway with modifying.
> diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h
b/arch/arm/plat-
> samsung/include/plat/gpio-core.h
> index c22c27c..13a22b8 100644
> --- a/arch/arm/plat-samsung/include/plat/gpio-core.h
> +++ b/arch/arm/plat-samsung/include/plat/gpio-core.h
> @@ -122,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;
>
> --
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function
2010-10-01 4:49 ` Kukjin Kim
@ 2010-10-01 5:19 ` Marek Szyprowski
0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2010-10-01 5:19 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
On Friday, October 01, 2010 6:49 AM Kukjin Kim wrote:
...
> > diff --git a/arch/arm/plat-samsung/gpiolib.c
> b/arch/arm/plat-samsung/gpiolib.c
> > index c354089..f2dc389 100644
> > --- a/arch/arm/plat-samsung/gpiolib.c
> > +++ b/arch/arm/plat-samsung/gpiolib.c
> > @@ -197,3 +197,11 @@ void __init samsung_gpiolib_add_4bit2_chips(struct
> > s3c_gpio_chip *chip,
> > s3c_gpiolib_add(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;
> > +}
>
> Hi,
>
> Following is for your information...
>
> Moved samsung_gpiolib_to_irq() into plat-samsung/gpio.c because happened
> build error like following after applying this.
>
> arch/arm/plat-s3c24xx/built-in.o:(.data+0x11c4): undefined reference to
> `samsung_gpiolib_to_irq'
>
> The reason is that plat-samsung/gpiolib.c is not required for
> s3c24xx...applied anyway with modifying.
I must have missed that plat-samsung/gpiolib.c is not used for s3c-24xx. Thank
You for the fix!
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH RESEND] ARM: S5PC110: GONI: Add support for QT602240 TS driver
2010-09-06 9:12 ` [PATCH 6/6] ARM: S5PC110: GONI: Add support for QT602240 TS driver Marek Szyprowski
@ 2010-10-04 9:22 ` Marek Szyprowski
2010-10-04 9:40 ` Kukjin Kim
0 siblings, 1 reply; 20+ messages in thread
From: Marek Szyprowski @ 2010-10-04 9:22 UTC (permalink / raw)
To: linux-arm-kernel
Add required platform definitions for QT602240 touchscreen on I2C2 bus.
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
Hello,
This is just a resend of the previous version rebased onto the latest
kgene/for-next branch.
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
---
arch/arm/mach-s5pv210/Kconfig | 3 ++
arch/arm/mach-s5pv210/mach-goni.c | 54 +++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index af2a813..0509fd5 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -73,6 +73,7 @@ config MACH_AQUILA
config MACH_GONI
bool "GONI"
select CPU_S5PV210
+ select S5P_GPIO_INT
select S3C_DEV_FB
select S5P_DEV_FIMC0
select S5P_DEV_FIMC1
@@ -80,10 +81,12 @@ config MACH_GONI
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1
select S3C_DEV_HSMMC2
+ 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_I2C2
select S5PV210_SETUP_KEYPAD
select S5PV210_SETUP_SDHCI
help
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 30ad59f..aa20875 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -15,6 +15,7 @@
#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/gpio_keys.h>
@@ -135,6 +136,51 @@ static struct samsung_keypad_platdata keypad_data __initdata = {
.cols = 3,
};
+/* 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)
@@ -524,6 +570,7 @@ static struct platform_device *goni_devices[] __initdata = {
&s3c_device_hsmmc2,
&s3c_device_usb_hsotg,
&samsung_device_keypad,
+ &s3c_device_i2c2,
};
static void __init goni_map_io(void)
@@ -535,6 +582,13 @@ static void __init goni_map_io(void)
static void __init goni_machine_init(void)
{
+ /* 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,
--
1.7.1.569.g6f426
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH RESEND] ARM: S5PC110: GONI: Add support for QT602240 TS driver
2010-10-04 9:22 ` [PATCH RESEND] " Marek Szyprowski
@ 2010-10-04 9:40 ` Kukjin Kim
0 siblings, 0 replies; 20+ messages in thread
From: Kukjin Kim @ 2010-10-04 9:40 UTC (permalink / raw)
To: linux-arm-kernel
Marek Szyprowski wrote:
>
> Add required platform definitions for QT602240 touchscreen on I2C2 bus.
>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>
> Hello,
>
> This is just a resend of the previous version rebased onto the latest
> kgene/for-next branch.
>
> Best regards
> --
> Marek Szyprowski
> Samsung Poland R&D Center
>
> ---
> arch/arm/mach-s5pv210/Kconfig | 3 ++
> arch/arm/mach-s5pv210/mach-goni.c | 54
> +++++++++++++++++++++++++++++++++++++
> 2 files changed, 57 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
> index af2a813..0509fd5 100644
> --- a/arch/arm/mach-s5pv210/Kconfig
> +++ b/arch/arm/mach-s5pv210/Kconfig
> @@ -73,6 +73,7 @@ config MACH_AQUILA
> config MACH_GONI
> bool "GONI"
> select CPU_S5PV210
> + select S5P_GPIO_INT
> select S3C_DEV_FB
> select S5P_DEV_FIMC0
> select S5P_DEV_FIMC1
> @@ -80,10 +81,12 @@ config MACH_GONI
> select S3C_DEV_HSMMC
> select S3C_DEV_HSMMC1
> select S3C_DEV_HSMMC2
> + 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_I2C2
> select S5PV210_SETUP_KEYPAD
> select S5PV210_SETUP_SDHCI
> help
> diff --git a/arch/arm/mach-s5pv210/mach-goni.c
b/arch/arm/mach-s5pv210/mach-
> goni.c
> index 30ad59f..aa20875 100644
> --- a/arch/arm/mach-s5pv210/mach-goni.c
> +++ b/arch/arm/mach-s5pv210/mach-goni.c
> @@ -15,6 +15,7 @@
> #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/gpio_keys.h>
> @@ -135,6 +136,51 @@ static struct samsung_keypad_platdata keypad_data
> __initdata = {
> .cols = 3,
> };
>
> +/* 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)
>
> @@ -524,6 +570,7 @@ static struct platform_device *goni_devices[]
__initdata = {
> &s3c_device_hsmmc2,
> &s3c_device_usb_hsotg,
> &samsung_device_keypad,
> + &s3c_device_i2c2,
> };
>
> static void __init goni_map_io(void)
> @@ -535,6 +582,13 @@ static void __init goni_map_io(void)
>
> static void __init goni_machine_init(void)
> {
> + /* 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,
> --
Looks ok...will apply.
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2010-10-04 9:40 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-09-06 9:12 [PATCH v3] ARM: S5P: Add support for gpio interrupts Marek Szyprowski
2010-09-06 9:12 ` [PATCH 1/6] ARM: Samsung: Add common s5p gpio interrupt support Marek Szyprowski
2010-09-28 14:03 ` Kukjin Kim
2010-09-28 14:24 ` Marek Szyprowski
2010-09-28 14:43 ` Kyungmin Park
2010-09-30 7:12 ` [PATCH v4] " Marek Szyprowski
2010-09-30 13:29 ` Kukjin Kim
2010-09-30 13:47 ` Kyungmin Park
2010-09-06 9:12 ` [PATCH 2/6] ARM: S5PC110: add support for gpio interrupts Marek Szyprowski
2010-09-06 9:12 ` [PATCH 3/6] ARM: S5PC100: Use generic S5P gpio interrupts interface Marek Szyprowski
2010-09-06 9:12 ` [PATCH 4/6] ARM: S5PC100: Move external interrupt defines Marek Szyprowski
2010-09-10 12:00 ` Kukjin Kim
2010-09-21 5:16 ` Marek Szyprowski
2010-09-06 9:12 ` [PATCH 5/6] ARM: Samsung: Add common samsung_gpiolib_to_irq function Marek Szyprowski
2010-10-01 4:49 ` Kukjin Kim
2010-10-01 5:19 ` Marek Szyprowski
2010-09-06 9:12 ` [PATCH 6/6] ARM: S5PC110: GONI: Add support for QT602240 TS driver Marek Szyprowski
2010-10-04 9:22 ` [PATCH RESEND] " Marek Szyprowski
2010-10-04 9:40 ` Kukjin Kim
2010-09-29 6:49 ` [PATCH v3] ARM: S5P: Add support for gpio interrupts Kukjin Kim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).