All of lore.kernel.org
 help / color / mirror / Atom feed
From: Johannes Weiner <jw@emlix.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: "Chris Zankel" <chris@zankel.net>,
	linux-kernel@vger.kernel.org, "Daniel Glöckner" <dg@emlix.com>
Subject: [patch 10/12] xtensa: support s6000 gpio irqs and alternate function selection
Date: Tue, 14 Apr 2009 11:41:18 +0200	[thread overview]
Message-ID: <1239702080-14355-11-git-send-email-jw@emlix.com> (raw)
In-Reply-To: <1239702080-14355-1-git-send-email-jw@emlix.com>

From: Daniel Glöckner <dg@emlix.com>

Implement an irq chip to handle interrupts via gpio.  The GPIO chip
initialization function now takes a bitmask denoting pins that should
be configured for their alternate function.

Signed-off-by: Daniel Glöckner <dg@emlix.com>
Signed-off-by: Johannes Weiner <jw@emlix.com>
---
 arch/xtensa/include/asm/gpio.h                    |    8 +-
 arch/xtensa/platforms/s6105/setup.c               |    2 +-
 arch/xtensa/variants/s6000/gpio.c                 |  163 ++++++++++++++++++++-
 arch/xtensa/variants/s6000/include/variant/gpio.h |    2 +-
 4 files changed, 168 insertions(+), 7 deletions(-)

diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h
index 0763b07..a8c9fc4 100644
--- a/arch/xtensa/include/asm/gpio.h
+++ b/arch/xtensa/include/asm/gpio.h
@@ -38,14 +38,14 @@ static inline int gpio_cansleep(unsigned int gpio)
 	return __gpio_cansleep(gpio);
 }
 
-/*
- * Not implemented, yet.
- */
 static inline int gpio_to_irq(unsigned int gpio)
 {
-	return -ENOSYS;
+	return __gpio_to_irq(gpio);
 }
 
+/*
+ * Not implemented, yet.
+ */
 static inline int irq_to_gpio(unsigned int irq)
 {
 	return -EINVAL;
diff --git a/arch/xtensa/platforms/s6105/setup.c b/arch/xtensa/platforms/s6105/setup.c
index 855ddea..95fa23c 100644
--- a/arch/xtensa/platforms/s6105/setup.c
+++ b/arch/xtensa/platforms/s6105/setup.c
@@ -49,7 +49,7 @@ void __init platform_setup(char **cmdline)
 
 void __init platform_init(bp_tag_t *first)
 {
-	s6_gpio_init();
+	s6_gpio_init(0);
 	gpio_request(GPIO_LED1_NGREEN, "led1_green");
 	gpio_request(GPIO_LED1_RED, "led1_red");
 	gpio_direction_output(GPIO_LED1_NGREEN, 1);
diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c
index 79317fd..5171e56 100644
--- a/arch/xtensa/variants/s6000/gpio.c
+++ b/arch/xtensa/variants/s6000/gpio.c
@@ -4,15 +4,20 @@
  * Copyright (c) 2009 emlix GmbH
  * Authors:	Oskar Schirmer <os@emlix.com>
  *		Johannes Weiner <jw@emlix.com>
+ *		Daniel Gloeckner <dg@emlix.com>
  */
+#include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/gpio.h>
 
 #include <variant/hardware.h>
 
+#define IRQ_BASE XTENSA_NR_IRQS
+
 #define S6_GPIO_DATA		0x000
 #define S6_GPIO_IS		0x404
 #define S6_GPIO_IBE		0x408
@@ -52,19 +57,175 @@ static void set(struct gpio_chip *chip, unsigned int off, int val)
 	writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off));
 }
 
+static int to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	if (offset < 8)
+		return offset + IRQ_BASE;
+	return -EINVAL;
+}
+
 static struct gpio_chip gpiochip = {
 	.owner = THIS_MODULE,
 	.direction_input = direction_input,
 	.get = get,
 	.direction_output = direction_output,
 	.set = set,
+	.to_irq = to_irq,
 	.base = 0,
 	.ngpio = 24,
 	.can_sleep = 0, /* no blocking io needed */
 	.exported = 0, /* no exporting to userspace */
 };
 
-int s6_gpio_init(void)
+int s6_gpio_init(u32 afsel)
 {
+	writeb(afsel, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL);
+	writeb(afsel >> 8, S6_REG_GPIO + S6_GPIO_BANK(1) + S6_GPIO_AFSEL);
+	writeb(afsel >> 16, S6_REG_GPIO + S6_GPIO_BANK(2) + S6_GPIO_AFSEL);
 	return gpiochip_add(&gpiochip);
 }
+
+static void ack(unsigned int irq)
+{
+	writeb(1 << (irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC);
+}
+
+static void mask(unsigned int irq)
+{
+	u8 r = readb(S6_REG_GPIO + S6_GPIO_IE);
+	r &= ~(1 << (irq - IRQ_BASE));
+	writeb(r, S6_REG_GPIO + S6_GPIO_IE);
+}
+
+static void unmask(unsigned int irq)
+{
+	u8 m = readb(S6_REG_GPIO + S6_GPIO_IE);
+	m |= 1 << (irq - IRQ_BASE);
+	writeb(m, S6_REG_GPIO + S6_GPIO_IE);
+}
+
+static int set_type(unsigned int irq, unsigned int type)
+{
+	const u8 m = 1 << (irq - IRQ_BASE);
+	irq_flow_handler_t handler;
+	struct irq_desc *desc;
+	u8 reg;
+
+	if (type == IRQ_TYPE_PROBE) {
+		if ((readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL) & m)
+		    || (readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE) & m)
+		    || readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_DIR
+			      + S6_GPIO_MASK(irq - IRQ_BASE)))
+			return 0;
+		type = IRQ_TYPE_EDGE_BOTH;
+	}
+
+	reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS);
+	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
+		reg |= m;
+		handler = handle_level_irq;
+	} else {
+		reg = ~m;
+		handler = handle_edge_irq;
+	}
+	writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS);
+	desc = irq_to_desc(irq);
+	desc->handle_irq = handler;
+
+	reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV);
+	if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING))
+		reg |= m;
+	else
+		reg &= ~m;
+	writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV);
+
+	reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE);
+	if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+		reg |= m;
+	else
+		reg &= ~m;
+	writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE);
+	return 0;
+}
+
+static struct irq_chip gpioirqs = {
+	.name = "GPIO",
+	.ack = ack,
+	.mask = mask,
+	.unmask = unmask,
+	.set_type = set_type,
+};
+
+static u8 demux_masks[4];
+
+static void demux_irqs(unsigned int irq, struct irq_desc *desc)
+{
+	u8 *mask = get_irq_desc_data(desc);
+	u8 pending;
+	int cirq;
+
+	desc->chip->mask(irq);
+	desc->chip->ack(irq);
+	pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask;
+	cirq = IRQ_BASE - 1;
+	while (pending) {
+		int n = ffs(pending);
+		cirq += n;
+		pending >>= n;
+		generic_handle_irq(cirq);
+	}
+	desc->chip->unmask(irq);
+}
+
+extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS];
+
+void __init variant_init_IRQ(void)
+{
+	int irq, n;
+	writeb(0, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE);
+	for (irq = n = 0; irq < XTENSA_NR_IRQS; irq++) {
+		const signed char *mapping = platform_irq_mappings[irq];
+		int alone = 1;
+		u8 mask;
+		if (!mapping)
+			continue;
+		for(mask = 0; *mapping != -1; mapping++)
+			switch (*mapping) {
+			case S6_INTC_GPIO(0):
+				mask |= 1 << 0;
+				break;
+			case S6_INTC_GPIO(1):
+				mask |= 1 << 1;
+				break;
+			case S6_INTC_GPIO(2):
+				mask |= 1 << 2;
+				break;
+			case S6_INTC_GPIO(3):
+				mask |= 0x1f << 3;
+				break;
+			default:
+				alone = 0;
+			}
+		if (mask) {
+			int cirq, i;
+			if (!alone) {
+				printk(KERN_ERR "chained irq chips can't share"
+					" parent irq %i\n", irq);
+				continue;
+			}
+			demux_masks[n] = mask;
+			cirq = IRQ_BASE - 1;
+			do {
+				i = ffs(mask);
+				cirq += i;
+				mask >>= i;
+				set_irq_chip(cirq, &gpioirqs);
+				set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+			} while (mask);
+			set_irq_data(irq, demux_masks + n);
+			set_irq_chained_handler(irq, demux_irqs);
+			if (++n == ARRAY_SIZE(demux_masks))
+				break;
+		}
+	}
+}
diff --git a/arch/xtensa/variants/s6000/include/variant/gpio.h b/arch/xtensa/variants/s6000/include/variant/gpio.h
index 8327f62..8484ab0 100644
--- a/arch/xtensa/variants/s6000/include/variant/gpio.h
+++ b/arch/xtensa/variants/s6000/include/variant/gpio.h
@@ -1,6 +1,6 @@
 #ifndef _XTENSA_VARIANT_S6000_GPIO_H
 #define _XTENSA_VARIANT_S6000_GPIO_H
 
-extern int s6_gpio_init(void);
+extern int s6_gpio_init(u32 afsel);
 
 #endif /* _XTENSA_VARIANT_S6000_GPIO_H */
-- 
1.6.2.107.ge47ee


  parent reply	other threads:[~2009-04-14  9:43 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-04-14  9:41 Johannes Weiner
2009-04-14  9:41 ` [patch 01/12] xtensa: always use correct stack pointer for stack traces Johannes Weiner
2009-04-14  9:41 ` [patch 02/12] xtensa: register gpio chip before use Johannes Weiner
2009-04-14  9:41 ` [patch 03/12] xtensa: fix wrong extern declaration renamed in code using it Johannes Weiner
2009-04-14  9:41 ` [patch 04/12] xtensa: implement ccount calibration for s6000 Johannes Weiner
2009-04-14  9:41 ` [patch 05/12] xtensa: update s6105_defconfig for ccount calibration Johannes Weiner
2009-04-14  9:41 ` [patch 06/12] xtensa: implement CLK API Johannes Weiner
2009-04-14  9:41 ` [patch 07/12] xtensa: implement PTRACE_PEEKUSER addresses for nommu Johannes Weiner
2009-04-14  9:41 ` [patch 08/12] xtensa: s6000 dma engine support Johannes Weiner
2009-04-14  9:41 ` [patch 09/12] xtensa: allow platform and variant to initialize own irq chips Johannes Weiner
2009-04-23  7:19   ` Chris Zankel
2009-04-23 16:16     ` Daniel Glöckner
2009-04-14  9:41 ` Johannes Weiner [this message]
2009-04-14  9:41 ` [patch 11/12] xtensa: s6105 specific configuration for s6gmac Johannes Weiner
2009-04-14  9:41 ` [patch 12/12] xtensa: enable s6gmac in s6105_defconfig Johannes Weiner
2009-04-16  7:42 ` Xtensa patches Chris Zankel
2009-04-16  8:24   ` Andrew Morton
2009-04-16  8:30     ` Paul Mundt
2009-04-16  8:56       ` Andrew Morton
2009-04-16  9:06         ` Paul Mundt
2009-04-16  8:35     ` Stephen Rothwell
2009-04-16  9:15       ` Chris Zankel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1239702080-14355-11-git-send-email-jw@emlix.com \
    --to=jw@emlix.com \
    --cc=akpm@linux-foundation.org \
    --cc=chris@zankel.net \
    --cc=dg@emlix.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.