aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Beisert <j.beisert@pengutronix.de>2008-07-05 04:02:49 -0400
committerRobert Schwebel <r.schwebel@pengutronix.de>2008-07-05 04:02:49 -0400
commit07bd1a6cc7cbb3f373fbe49b204c6cde5e9155fc (patch)
tree94a09785b99feebe4c83e836a976fe7fbf146813
parente3d13ff4b9d3b05d7a969153e2c049548e25deea (diff)
MXC arch: Add gpio support for the whole platform
This patch bases on the one from Daniel Mack. The most important change to Daniel's patch is to be more generic. This gpio routine supports at least the i.MX27 and i.MX31 processors. Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de> Acked-by: Daniel Mack <daniel@caiaq.de>
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/mach-mx3/devices.c27
-rw-r--r--arch/arm/plat-mxc/Makefile2
-rw-r--r--arch/arm/plat-mxc/gpio.c253
-rw-r--r--arch/arm/plat-mxc/irq.c3
-rw-r--r--include/asm-arm/arch-mxc/common.h1
-rw-r--r--include/asm-arm/arch-mxc/gpio.h42
-rw-r--r--include/asm-arm/arch-mxc/mx31.h19
8 files changed, 348 insertions, 1 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b786e68914d4..5c8c1a89be73 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -368,6 +368,8 @@ config ARCH_NS9XXX
368config ARCH_MXC 368config ARCH_MXC
369 bool "Freescale MXC/iMX-based" 369 bool "Freescale MXC/iMX-based"
370 select ARCH_MTD_XIP 370 select ARCH_MTD_XIP
371 select GENERIC_GPIO
372 select HAVE_GPIO_LIB
371 help 373 help
372 Support for Freescale MXC/iMX-based family of processors 374 Support for Freescale MXC/iMX-based family of processors
373 375
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
index 1bc6d23a1d58..5c0320fce5b6 100644
--- a/arch/arm/mach-mx3/devices.c
+++ b/arch/arm/mach-mx3/devices.c
@@ -20,6 +20,7 @@
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/platform_device.h> 21#include <linux/platform_device.h>
22#include <linux/serial.h> 22#include <linux/serial.h>
23#include <linux/gpio.h>
23#include <asm/hardware.h> 24#include <asm/hardware.h>
24#include <asm/arch/imx-uart.h> 25#include <asm/arch/imx-uart.h>
25 26
@@ -151,3 +152,29 @@ int __init imx_init_uart(int uart_no, struct imxuart_platform_data *pdata)
151 return 0; 152 return 0;
152} 153}
153 154
155/* GPIO port description */
156static struct mxc_gpio_port imx_gpio_ports[] = {
157 [0] = {
158 .chip.label = "gpio-0",
159 .base = IO_ADDRESS(GPIO1_BASE_ADDR),
160 .irq = MXC_INT_GPIO1,
161 .virtual_irq_start = MXC_GPIO_INT_BASE
162 },
163 [1] = {
164 .chip.label = "gpio-1",
165 .base = IO_ADDRESS(GPIO2_BASE_ADDR),
166 .irq = MXC_INT_GPIO2,
167 .virtual_irq_start = MXC_GPIO_INT_BASE + GPIO_NUM_PIN
168 },
169 [2] = {
170 .chip.label = "gpio-2",
171 .base = IO_ADDRESS(GPIO3_BASE_ADDR),
172 .irq = MXC_INT_GPIO3,
173 .virtual_irq_start = MXC_GPIO_INT_BASE + GPIO_NUM_PIN * 2
174 }
175};
176
177int __init mxc_register_gpios(void)
178{
179 return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
180}
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 3eb181cb7afb..66272a6fc323 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -3,4 +3,4 @@
3# 3#
4 4
5# Common support 5# Common support
6obj-y := irq.o clock.o 6obj-y := irq.o clock.o gpio.o
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c
new file mode 100644
index 000000000000..4a7736717d86
--- /dev/null
+++ b/arch/arm/plat-mxc/gpio.c
@@ -0,0 +1,253 @@
1/*
2 * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
3 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
4 *
5 * Based on code from Freescale,
6 * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/irq.h>
25#include <linux/gpio.h>
26#include <asm/hardware.h>
27#include <asm-generic/bug.h>
28
29static struct mxc_gpio_port *mxc_gpio_ports;
30static int gpio_table_size;
31
32/* Note: This driver assumes 32 GPIOs are handled in one register */
33
34static void _clear_gpio_irqstatus(struct mxc_gpio_port *port, u32 index)
35{
36 __raw_writel(1 << index, port->base + GPIO_ISR);
37}
38
39static void _set_gpio_irqenable(struct mxc_gpio_port *port, u32 index,
40 int enable)
41{
42 u32 l;
43
44 l = __raw_readl(port->base + GPIO_IMR);
45 l = (l & (~(1 << index))) | (!!enable << index);
46 __raw_writel(l, port->base + GPIO_IMR);
47}
48
49static void gpio_ack_irq(u32 irq)
50{
51 u32 gpio = irq_to_gpio(irq);
52 _clear_gpio_irqstatus(&mxc_gpio_ports[gpio / 32], gpio & 0x1f);
53}
54
55static void gpio_mask_irq(u32 irq)
56{
57 u32 gpio = irq_to_gpio(irq);
58 _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 0);
59}
60
61static void gpio_unmask_irq(u32 irq)
62{
63 u32 gpio = irq_to_gpio(irq);
64 _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1);
65}
66
67static int gpio_set_irq_type(u32 irq, u32 type)
68{
69 u32 gpio = irq_to_gpio(irq);
70 struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32];
71 u32 bit, val;
72 int edge;
73 void __iomem *reg = port->base;
74
75 switch (type) {
76 case IRQT_RISING:
77 edge = GPIO_INT_RISE_EDGE;
78 break;
79 case IRQT_FALLING:
80 edge = GPIO_INT_FALL_EDGE;
81 break;
82 case IRQT_LOW:
83 edge = GPIO_INT_LOW_LEV;
84 break;
85 case IRQT_HIGH:
86 edge = GPIO_INT_HIGH_LEV;
87 break;
88 default: /* this includes IRQT_BOTHEDGE */
89 return -EINVAL;
90 }
91
92 reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
93 bit = gpio & 0xf;
94 val = __raw_readl(reg) & ~(0x3 << (bit << 1));
95 __raw_writel(val | (edge << (bit << 1)), reg);
96 _clear_gpio_irqstatus(port, gpio & 0x1f);
97
98 return 0;
99}
100
101/* handle n interrupts in one status register */
102static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)
103{
104 u32 gpio_irq_no;
105
106 gpio_irq_no = port->virtual_irq_start;
107 for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) {
108
109 if ((irq_stat & 1) == 0)
110 continue;
111
112 BUG_ON(!(irq_desc[gpio_irq_no].handle_irq));
113 irq_desc[gpio_irq_no].handle_irq(gpio_irq_no,
114 &irq_desc[gpio_irq_no]);
115 }
116}
117
118#ifdef CONFIG_ARCH_MX3
119/* MX3 has one interrupt *per* gpio port */
120static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc)
121{
122 u32 irq_stat;
123 struct mxc_gpio_port *port = (struct mxc_gpio_port *)get_irq_data(irq);
124
125 irq_stat = __raw_readl(port->base + GPIO_ISR) &
126 __raw_readl(port->base + GPIO_IMR);
127 BUG_ON(!irq_stat);
128 mxc_gpio_irq_handler(port, irq_stat);
129}
130#endif
131
132#ifdef CONFIG_ARCH_MX2
133/* MX2 has one interrupt *for all* gpio ports */
134static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc)
135{
136 int i;
137 u32 irq_msk, irq_stat;
138 struct mxc_gpio_port *port = (struct mxc_gpio_port *)get_irq_data(irq);
139
140 /* walk through all interrupt status registers */
141 for (i = 0; i < gpio_table_size; i++) {
142 irq_msk = __raw_readl(port[i].base + GPIO_IMR);
143 if (!irq_msk)
144 continue;
145
146 irq_stat = __raw_readl(port[i].base + GPIO_ISR) & irq_msk;
147 if (irq_stat)
148 mxc_gpio_irq_handler(&port[i], irq_stat);
149 }
150}
151#endif
152
153static struct irq_chip gpio_irq_chip = {
154 .ack = gpio_ack_irq,
155 .mask = gpio_mask_irq,
156 .unmask = gpio_unmask_irq,
157 .set_type = gpio_set_irq_type,
158};
159
160static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
161 int dir)
162{
163 struct mxc_gpio_port *port =
164 container_of(chip, struct mxc_gpio_port, chip);
165 u32 l;
166
167 l = __raw_readl(port->base + GPIO_GDIR);
168 if (dir)
169 l |= 1 << offset;
170 else
171 l &= ~(1 << offset);
172 __raw_writel(l, port->base + GPIO_GDIR);
173}
174
175static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
176{
177 struct mxc_gpio_port *port =
178 container_of(chip, struct mxc_gpio_port, chip);
179 void __iomem *reg = port->base + GPIO_DR;
180 u32 l;
181
182 l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset);
183 __raw_writel(l, reg);
184}
185
186static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset)
187{
188 struct mxc_gpio_port *port =
189 container_of(chip, struct mxc_gpio_port, chip);
190
191 return (__raw_readl(port->base + GPIO_DR) >> offset) & 1;
192}
193
194static int mxc_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
195{
196 _set_gpio_direction(chip, offset, 0);
197 return 0;
198}
199
200static int mxc_gpio_direction_output(struct gpio_chip *chip,
201 unsigned offset, int value)
202{
203 _set_gpio_direction(chip, offset, 1);
204 mxc_gpio_set(chip, offset, value);
205 return 0;
206}
207
208int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
209{
210 int i, j;
211
212 /* save for local usage */
213 mxc_gpio_ports = port;
214 gpio_table_size = cnt;
215
216 printk(KERN_INFO "MXC GPIO hardware\n");
217
218 for (i = 0; i < cnt; i++) {
219 /* disable the interrupt and clear the status */
220 __raw_writel(0, port[i].base + GPIO_IMR);
221 __raw_writel(~0, port[i].base + GPIO_ISR);
222 for (j = port[i].virtual_irq_start;
223 j < port[i].virtual_irq_start + 32; j++) {
224 set_irq_chip(j, &gpio_irq_chip);
225 set_irq_handler(j, handle_edge_irq);
226 set_irq_flags(j, IRQF_VALID);
227 }
228
229 /* register gpio chip */
230 port[i].chip.direction_input = mxc_gpio_direction_input;
231 port[i].chip.direction_output = mxc_gpio_direction_output;
232 port[i].chip.get = mxc_gpio_get;
233 port[i].chip.set = mxc_gpio_set;
234 port[i].chip.base = i * 32;
235 port[i].chip.ngpio = 32;
236
237 /* its a serious configuration bug when it fails */
238 BUG_ON( gpiochip_add(&port[i].chip) < 0 );
239
240#ifdef CONFIG_ARCH_MX3
241 /* setup one handler for each entry */
242 set_irq_chained_handler(port[i].irq, mx3_gpio_irq_handler);
243 set_irq_data(port[i].irq, &port[i]);
244#endif
245 }
246
247#ifdef CONFIG_ARCH_MX2
248 /* setup one handler for all GPIO interrupts */
249 set_irq_chained_handler(port[0].irq, mx2_gpio_irq_handler);
250 set_irq_data(port[0].irq, port);
251#endif
252 return 0;
253}
diff --git a/arch/arm/plat-mxc/irq.c b/arch/arm/plat-mxc/irq.c
index 2ad5a6917b3f..88f0cfababda 100644
--- a/arch/arm/plat-mxc/irq.c
+++ b/arch/arm/plat-mxc/irq.c
@@ -71,5 +71,8 @@ void __init mxc_init_irq(void)
71 reg |= (0xF << 28); 71 reg |= (0xF << 28);
72 __raw_writel(reg, AVIC_NIPRIORITY6); 72 __raw_writel(reg, AVIC_NIPRIORITY6);
73 73
74 /* init architectures chained interrupt handler */
75 mxc_register_gpios();
76
74 printk(KERN_INFO "MXC IRQ initialized\n"); 77 printk(KERN_INFO "MXC IRQ initialized\n");
75} 78}
diff --git a/include/asm-arm/arch-mxc/common.h b/include/asm-arm/arch-mxc/common.h
index c6d4aa360635..8774783ed984 100644
--- a/include/asm-arm/arch-mxc/common.h
+++ b/include/asm-arm/arch-mxc/common.h
@@ -17,5 +17,6 @@ extern void mxc_map_io(void);
17extern void mxc_init_irq(void); 17extern void mxc_init_irq(void);
18extern struct sys_timer mxc_timer; 18extern struct sys_timer mxc_timer;
19extern int mxc_clocks_init(unsigned long fref); 19extern int mxc_clocks_init(unsigned long fref);
20extern int mxc_register_gpios(void);
20 21
21#endif 22#endif
diff --git a/include/asm-arm/arch-mxc/gpio.h b/include/asm-arm/arch-mxc/gpio.h
new file mode 100644
index 000000000000..d393e15f5a6b
--- /dev/null
+++ b/include/asm-arm/arch-mxc/gpio.h
@@ -0,0 +1,42 @@
1/*
2 * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#ifndef __ASM_ARCH_MXC_GPIO_H__
20#define __ASM_ARCH_MXC_GPIO_H__
21
22#include <asm/hardware.h>
23#include <asm-generic/gpio.h>
24
25/* use gpiolib dispatchers */
26#define gpio_get_value __gpio_get_value
27#define gpio_set_value __gpio_set_value
28#define gpio_cansleep __gpio_cansleep
29
30#define gpio_to_irq(gpio) (MXC_MAX_INT_LINES + (gpio))
31#define irq_to_gpio(irq) ((irq) - MXC_MAX_INT_LINES)
32
33struct mxc_gpio_port {
34 void __iomem *base;
35 int irq;
36 int virtual_irq_start;
37 struct gpio_chip chip;
38};
39
40int mxc_gpio_init(struct mxc_gpio_port*, int);
41
42#endif
diff --git a/include/asm-arm/arch-mxc/mx31.h b/include/asm-arm/arch-mxc/mx31.h
index 36a1af495bb3..98e6a4cd1ea9 100644
--- a/include/asm-arm/arch-mxc/mx31.h
+++ b/include/asm-arm/arch-mxc/mx31.h
@@ -347,6 +347,25 @@
347#define SYSTEM_REV_MIN CHIP_REV_1_0 347#define SYSTEM_REV_MIN CHIP_REV_1_0
348#define SYSTEM_REV_NUM 3 348#define SYSTEM_REV_NUM 3
349 349
350/* gpio and gpio based interrupt handling */
351#define GPIO_DR 0x00
352#define GPIO_GDIR 0x04
353#define GPIO_PSR 0x08
354#define GPIO_ICR1 0x0C
355#define GPIO_ICR2 0x10
356#define GPIO_IMR 0x14
357#define GPIO_ISR 0x18
358#define GPIO_INT_LOW_LEV 0x0
359#define GPIO_INT_HIGH_LEV 0x1
360#define GPIO_INT_RISE_EDGE 0x2
361#define GPIO_INT_FALL_EDGE 0x3
362#define GPIO_INT_NONE 0x4
363
364/* Mandatory defines used globally */
365
366/* this CPU supports up to 96 GPIOs */
367#define ARCH_NR_GPIOS 96
368
350#if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS) 369#if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
351 370
352/* this is a i.MX31 CPU */ 371/* this is a i.MX31 CPU */