aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-imx
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r--arch/arm/mach-imx/Kconfig10
-rw-r--r--arch/arm/mach-imx/Makefile19
-rw-r--r--arch/arm/mach-imx/Makefile.boot2
-rw-r--r--arch/arm/mach-imx/dma.c203
-rw-r--r--arch/arm/mach-imx/generic.c274
-rw-r--r--arch/arm/mach-imx/generic.h16
-rw-r--r--arch/arm/mach-imx/irq.c252
-rw-r--r--arch/arm/mach-imx/leds-mx1ads.c54
-rw-r--r--arch/arm/mach-imx/leds.c31
-rw-r--r--arch/arm/mach-imx/leds.h9
-rw-r--r--arch/arm/mach-imx/mx1ads.c88
-rw-r--r--arch/arm/mach-imx/time.c101
12 files changed, 1059 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
new file mode 100644
index 00000000000..ec85813ee5d
--- /dev/null
+++ b/arch/arm/mach-imx/Kconfig
@@ -0,0 +1,10 @@
1menu "IMX Implementations"
2 depends on ARCH_IMX
3
4config ARCH_MX1ADS
5 bool "mx1ads"
6 depends on ARCH_IMX
7 help
8 Say Y here if you are using the Motorola MX1ADS board
9
10endmenu
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
new file mode 100644
index 00000000000..0b27d79f2ef
--- /dev/null
+++ b/arch/arm/mach-imx/Makefile
@@ -0,0 +1,19 @@
1#
2# Makefile for the linux kernel.
3#
4# Note! Dependencies are done automagically by 'make dep', which also
5# removes any old dependencies. DON'T put your own dependencies here
6# unless it's something special (ie not a .c file).
7
8# Object file lists.
9
10obj-y += irq.o time.o dma.o generic.o
11
12# Specific board support
13obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
14
15# Support for blinky lights
16led-y := leds.o
17
18obj-$(CONFIG_LEDS) += $(led-y)
19led-$(CONFIG_ARCH_MX1ADS) += leds-mx1ads.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
new file mode 100644
index 00000000000..fd72ce5b808
--- /dev/null
+++ b/arch/arm/mach-imx/Makefile.boot
@@ -0,0 +1,2 @@
1 zreladdr-$(CONFIG_ARCH_MX1ADS) := 0x08008000
2
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
new file mode 100644
index 00000000000..71a59e19616
--- /dev/null
+++ b/arch/arm/mach-imx/dma.c
@@ -0,0 +1,203 @@
1/*
2 * linux/arch/arm/mach-imx/dma.c
3 *
4 * imx DMA registration and IRQ dispatching
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * 03/03/2004 Sascha Hauer <sascha@saschahauer.de>
11 * initial version heavily inspired by
12 * linux/arch/arm/mach-pxa/dma.c
13 */
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/interrupt.h>
19#include <linux/errno.h>
20
21#include <asm/system.h>
22#include <asm/irq.h>
23#include <asm/hardware.h>
24#include <asm/dma.h>
25
26static struct dma_channel {
27 char *name;
28 void (*irq_handler) (int, void *, struct pt_regs *);
29 void (*err_handler) (int, void *, struct pt_regs *);
30 void *data;
31} dma_channels[11];
32
33/* set err_handler to NULL to have the standard info-only error handler */
34int
35imx_request_dma(char *name, imx_dma_prio prio,
36 void (*irq_handler) (int, void *, struct pt_regs *),
37 void (*err_handler) (int, void *, struct pt_regs *), void *data)
38{
39 unsigned long flags;
40 int i, found = 0;
41
42 /* basic sanity checks */
43 if (!name || !irq_handler)
44 return -EINVAL;
45
46 local_irq_save(flags);
47
48 /* try grabbing a DMA channel with the requested priority */
49 for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
50 if (!dma_channels[i].name) {
51 found = 1;
52 break;
53 }
54 }
55
56 if (!found) {
57 /* requested prio group is full, try hier priorities */
58 for (i = prio - 1; i >= 0; i--) {
59 if (!dma_channels[i].name) {
60 found = 1;
61 break;
62 }
63 }
64 }
65
66 if (found) {
67 DIMR &= ~(1 << i);
68 dma_channels[i].name = name;
69 dma_channels[i].irq_handler = irq_handler;
70 dma_channels[i].err_handler = err_handler;
71 dma_channels[i].data = data;
72 } else {
73 printk(KERN_WARNING "No more available DMA channels for %s\n",
74 name);
75 i = -ENODEV;
76 }
77
78 local_irq_restore(flags);
79 return i;
80}
81
82void
83imx_free_dma(int dma_ch)
84{
85 unsigned long flags;
86
87 if (!dma_channels[dma_ch].name) {
88 printk(KERN_CRIT
89 "%s: trying to free channel %d which is already freed\n",
90 __FUNCTION__, dma_ch);
91 return;
92 }
93
94 local_irq_save(flags);
95 DIMR &= ~(1 << dma_ch);
96 dma_channels[dma_ch].name = NULL;
97 local_irq_restore(flags);
98}
99
100static irqreturn_t
101dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
102{
103 int i, disr = DISR;
104 struct dma_channel *channel;
105 unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
106
107 DISR = disr;
108 for (i = 0; i < 11; i++) {
109 channel = &dma_channels[i];
110
111 if ( (err_mask & 1<<i) && channel->name && channel->err_handler) {
112 channel->err_handler(i, channel->data, regs);
113 continue;
114 }
115
116 if (DBTOSR & (1 << i)) {
117 printk(KERN_WARNING
118 "Burst timeout on channel %d (%s)\n",
119 i, channel->name);
120 DBTOSR |= (1 << i);
121 }
122 if (DRTOSR & (1 << i)) {
123 printk(KERN_WARNING
124 "Request timeout on channel %d (%s)\n",
125 i, channel->name);
126 DRTOSR |= (1 << i);
127 }
128 if (DSESR & (1 << i)) {
129 printk(KERN_WARNING
130 "Transfer timeout on channel %d (%s)\n",
131 i, channel->name);
132 DSESR |= (1 << i);
133 }
134 if (DBOSR & (1 << i)) {
135 printk(KERN_WARNING
136 "Buffer overflow timeout on channel %d (%s)\n",
137 i, channel->name);
138 DBOSR |= (1 << i);
139 }
140 }
141 return IRQ_HANDLED;
142}
143
144static irqreturn_t
145dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
146{
147 int i, disr = DISR;
148
149 DISR = disr;
150 for (i = 0; i < 11; i++) {
151 if (disr & (1 << i)) {
152 struct dma_channel *channel = &dma_channels[i];
153 if (channel->name && channel->irq_handler) {
154 channel->irq_handler(i, channel->data, regs);
155 } else {
156 /*
157 * IRQ for an unregistered DMA channel:
158 * let's clear the interrupts and disable it.
159 */
160 printk(KERN_WARNING
161 "spurious IRQ for DMA channel %d\n", i);
162 }
163 }
164 }
165 return IRQ_HANDLED;
166}
167
168static int __init
169imx_dma_init(void)
170{
171 int ret;
172
173 /* reset DMA module */
174 DCR = DCR_DRST;
175
176 ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
177 if (ret) {
178 printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n");
179 return ret;
180 }
181
182 ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
183 if (ret) {
184 printk(KERN_CRIT "Wow! Can't register ERRIRQ for DMA\n");
185 free_irq(DMA_INT, NULL);
186 }
187
188 /* enable DMA module */
189 DCR = DCR_DEN;
190
191 /* clear all interrupts */
192 DISR = 0x3ff;
193
194 /* enable interrupts */
195 DIMR = 0;
196
197 return ret;
198}
199
200arch_initcall(imx_dma_init);
201
202EXPORT_SYMBOL(imx_request_dma);
203EXPORT_SYMBOL(imx_free_dma);
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
new file mode 100644
index 00000000000..54377d0f578
--- /dev/null
+++ b/arch/arm/mach-imx/generic.c
@@ -0,0 +1,274 @@
1/*
2 * arch/arm/mach-imx/generic.c
3 *
4 * author: Sascha Hauer
5 * Created: april 20th, 2004
6 * Copyright: Synertronixx GmbH
7 *
8 * Common code for i.MX machines
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25#include <linux/device.h>
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <asm/hardware.h>
30
31#include <asm/mach/map.h>
32
33void imx_gpio_mode(int gpio_mode)
34{
35 unsigned int pin = gpio_mode & GPIO_PIN_MASK;
36 unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> 5;
37 unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> 10;
38 unsigned int tmp;
39
40 /* Pullup enable */
41 if(gpio_mode & GPIO_PUEN)
42 PUEN(port) |= (1<<pin);
43 else
44 PUEN(port) &= ~(1<<pin);
45
46 /* Data direction */
47 if(gpio_mode & GPIO_OUT)
48 DDIR(port) |= 1<<pin;
49 else
50 DDIR(port) &= ~(1<<pin);
51
52 /* Primary / alternate function */
53 if(gpio_mode & GPIO_AF)
54 GPR(port) |= (1<<pin);
55 else
56 GPR(port) &= ~(1<<pin);
57
58 /* use as gpio? */
59 if( ocr == 3 )
60 GIUS(port) |= (1<<pin);
61 else
62 GIUS(port) &= ~(1<<pin);
63
64 /* Output / input configuration */
65 /* FIXME: I'm not very sure about OCR and ICONF, someone
66 * should have a look over it
67 */
68 if(pin<16) {
69 tmp = OCR1(port);
70 tmp &= ~( 3<<(pin*2));
71 tmp |= (ocr << (pin*2));
72 OCR1(port) = tmp;
73
74 if( gpio_mode & GPIO_AOUT )
75 ICONFA1(port) &= ~( 3<<(pin*2));
76 if( gpio_mode & GPIO_BOUT )
77 ICONFB1(port) &= ~( 3<<(pin*2));
78 } else {
79 tmp = OCR2(port);
80 tmp &= ~( 3<<((pin-16)*2));
81 tmp |= (ocr << ((pin-16)*2));
82 OCR2(port) = tmp;
83
84 if( gpio_mode & GPIO_AOUT )
85 ICONFA2(port) &= ~( 3<<((pin-16)*2));
86 if( gpio_mode & GPIO_BOUT )
87 ICONFB2(port) &= ~( 3<<((pin-16)*2));
88 }
89}
90
91EXPORT_SYMBOL(imx_gpio_mode);
92
93/*
94 * get the system pll clock in Hz
95 *
96 * mfi + mfn / (mfd +1)
97 * f = 2 * f_ref * --------------------
98 * pd + 1
99 */
100static unsigned int imx_decode_pll(unsigned int pll)
101{
102 u32 mfi = (pll >> 10) & 0xf;
103 u32 mfn = pll & 0x3ff;
104 u32 mfd = (pll >> 16) & 0x3ff;
105 u32 pd = (pll >> 26) & 0xf;
106 u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
107
108 mfi = mfi <= 5 ? 5 : mfi;
109
110 return (2 * (f_ref>>10) * ( (mfi<<10) + (mfn<<10) / (mfd+1) )) / (pd+1);
111}
112
113unsigned int imx_get_system_clk(void)
114{
115 return imx_decode_pll(SPCTL0);
116}
117EXPORT_SYMBOL(imx_get_system_clk);
118
119unsigned int imx_get_mcu_clk(void)
120{
121 return imx_decode_pll(MPCTL0);
122}
123EXPORT_SYMBOL(imx_get_mcu_clk);
124
125/*
126 * get peripheral clock 1 ( UART[12], Timer[12], PWM )
127 */
128unsigned int imx_get_perclk1(void)
129{
130 return imx_get_system_clk() / (((PCDR) & 0xf)+1);
131}
132EXPORT_SYMBOL(imx_get_perclk1);
133
134/*
135 * get peripheral clock 2 ( LCD, SD, SPI[12] )
136 */
137unsigned int imx_get_perclk2(void)
138{
139 return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
140}
141EXPORT_SYMBOL(imx_get_perclk2);
142
143/*
144 * get peripheral clock 3 ( SSI )
145 */
146unsigned int imx_get_perclk3(void)
147{
148 return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
149}
150EXPORT_SYMBOL(imx_get_perclk3);
151
152/*
153 * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
154 */
155unsigned int imx_get_hclk(void)
156{
157 return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
158}
159EXPORT_SYMBOL(imx_get_hclk);
160
161static struct resource imx_mmc_resources[] = {
162 [0] = {
163 .start = 0x00214000,
164 .end = 0x002140FF,
165 .flags = IORESOURCE_MEM,
166 },
167 [1] = {
168 .start = (SDHC_INT),
169 .end = (SDHC_INT),
170 .flags = IORESOURCE_IRQ,
171 },
172};
173
174static struct platform_device imx_mmc_device = {
175 .name = "imx-mmc",
176 .id = 0,
177 .num_resources = ARRAY_SIZE(imx_mmc_resources),
178 .resource = imx_mmc_resources,
179};
180
181static struct resource imx_uart1_resources[] = {
182 [0] = {
183 .start = 0x00206000,
184 .end = 0x002060FF,
185 .flags = IORESOURCE_MEM,
186 },
187 [1] = {
188 .start = (UART1_MINT_RX),
189 .end = (UART1_MINT_RX),
190 .flags = IORESOURCE_IRQ,
191 },
192 [2] = {
193 .start = (UART1_MINT_TX),
194 .end = (UART1_MINT_TX),
195 .flags = IORESOURCE_IRQ,
196 },
197};
198
199static struct platform_device imx_uart1_device = {
200 .name = "imx-uart",
201 .id = 0,
202 .num_resources = ARRAY_SIZE(imx_uart1_resources),
203 .resource = imx_uart1_resources,
204};
205
206static struct resource imx_uart2_resources[] = {
207 [0] = {
208 .start = 0x00207000,
209 .end = 0x002070FF,
210 .flags = IORESOURCE_MEM,
211 },
212 [1] = {
213 .start = (UART2_MINT_RX),
214 .end = (UART2_MINT_RX),
215 .flags = IORESOURCE_IRQ,
216 },
217 [2] = {
218 .start = (UART2_MINT_TX),
219 .end = (UART2_MINT_TX),
220 .flags = IORESOURCE_IRQ,
221 },
222};
223
224static struct platform_device imx_uart2_device = {
225 .name = "imx-uart",
226 .id = 1,
227 .num_resources = ARRAY_SIZE(imx_uart2_resources),
228 .resource = imx_uart2_resources,
229};
230
231static struct resource imxfb_resources[] = {
232 [0] = {
233 .start = 0x00205000,
234 .end = 0x002050FF,
235 .flags = IORESOURCE_MEM,
236 },
237 [1] = {
238 .start = LCDC_INT,
239 .end = LCDC_INT,
240 .flags = IORESOURCE_IRQ,
241 },
242};
243
244static struct platform_device imxfb_device = {
245 .name = "imx-fb",
246 .id = 0,
247 .num_resources = ARRAY_SIZE(imxfb_resources),
248 .resource = imxfb_resources,
249};
250
251static struct platform_device *devices[] __initdata = {
252 &imx_mmc_device,
253 &imxfb_device,
254 &imx_uart1_device,
255 &imx_uart2_device,
256};
257
258static struct map_desc imx_io_desc[] __initdata = {
259 /* virtual physical length type */
260 {IMX_IO_BASE, IMX_IO_PHYS, IMX_IO_SIZE, MT_DEVICE},
261};
262
263void __init
264imx_map_io(void)
265{
266 iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
267}
268
269static int __init imx_init(void)
270{
271 return platform_add_devices(devices, ARRAY_SIZE(devices));
272}
273
274subsys_initcall(imx_init);
diff --git a/arch/arm/mach-imx/generic.h b/arch/arm/mach-imx/generic.h
new file mode 100644
index 00000000000..e91003e4bef
--- /dev/null
+++ b/arch/arm/mach-imx/generic.h
@@ -0,0 +1,16 @@
1/*
2 * linux/arch/arm/mach-imx/generic.h
3 *
4 * Author: Sascha Hauer <sascha@saschahauer.de>
5 * Copyright: Synertronixx GmbH
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12extern void __init imx_map_io(void);
13extern void __init imx_init_irq(void);
14
15struct sys_timer;
16extern struct sys_timer imx_timer;
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
new file mode 100644
index 00000000000..0c2713426df
--- /dev/null
+++ b/arch/arm/mach-imx/irq.c
@@ -0,0 +1,252 @@
1/*
2 * linux/arch/arm/mach-imx/irq.c
3 *
4 * Copyright (C) 1999 ARM Limited
5 * Copyright (C) 2002 Shane Nay (shane@minirl.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * 03/03/2004 Sascha Hauer <sascha@saschahauer.de>
22 * Copied from the motorola bsp package and added gpio demux
23 * interrupt handler
24 */
25
26#include <linux/init.h>
27#include <linux/list.h>
28#include <linux/timer.h>
29
30#include <asm/hardware.h>
31#include <asm/irq.h>
32#include <asm/io.h>
33
34#include <asm/mach/irq.h>
35
36/*
37 *
38 * We simply use the ENABLE DISABLE registers inside of the IMX
39 * to turn on/off specific interrupts. FIXME- We should
40 * also add support for the accelerated interrupt controller
41 * by putting offets to irq jump code in the appropriate
42 * places.
43 *
44 */
45
46#define INTENNUM_OFF 0x8
47#define INTDISNUM_OFF 0xC
48
49#define VA_AITC_BASE IO_ADDRESS(IMX_AITC_BASE)
50#define IMX_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF)
51#define IMX_AITC_INTENNUM (VA_AITC_BASE + INTENNUM_OFF)
52
53#if 0
54#define DEBUG_IRQ(fmt...) printk(fmt)
55#else
56#define DEBUG_IRQ(fmt...) do { } while (0)
57#endif
58
59static void
60imx_mask_irq(unsigned int irq)
61{
62 __raw_writel(irq, IMX_AITC_INTDISNUM);
63}
64
65static void
66imx_unmask_irq(unsigned int irq)
67{
68 __raw_writel(irq, IMX_AITC_INTENNUM);
69}
70
71static int
72imx_gpio_irq_type(unsigned int _irq, unsigned int type)
73{
74 unsigned int irq_type = 0, irq, reg, bit;
75
76 irq = _irq - IRQ_GPIOA(0);
77 reg = irq >> 5;
78 bit = 1 << (irq % 32);
79
80 if (type == IRQT_PROBE) {
81 /* Don't mess with enabled GPIOs using preconfigured edges or
82 GPIOs set to alternate function during probe */
83 /* TODO: support probe */
84// if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
85// GPIO_bit(gpio))
86// return 0;
87// if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
88// return 0;
89// type = __IRQT_RISEDGE | __IRQT_FALEDGE;
90 }
91
92 GIUS(reg) |= bit;
93 DDIR(reg) &= ~(bit);
94
95 DEBUG_IRQ("setting type of irq %d to ", _irq);
96
97 if (type & __IRQT_RISEDGE) {
98 DEBUG_IRQ("rising edges\n");
99 irq_type = 0x0;
100 }
101 if (type & __IRQT_FALEDGE) {
102 DEBUG_IRQ("falling edges\n");
103 irq_type = 0x1;
104 }
105 if (type & __IRQT_LOWLVL) {
106 DEBUG_IRQ("low level\n");
107 irq_type = 0x3;
108 }
109 if (type & __IRQT_HIGHLVL) {
110 DEBUG_IRQ("high level\n");
111 irq_type = 0x2;
112 }
113
114 if (irq % 32 < 16) {
115 ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) |
116 (irq_type << ((irq % 16) * 2));
117 } else {
118 ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) |
119 (irq_type << ((irq % 16) * 2));
120 }
121
122 return 0;
123
124}
125
126static void
127imx_gpio_ack_irq(unsigned int irq)
128{
129 DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
130 ISR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
131}
132
133static void
134imx_gpio_mask_irq(unsigned int irq)
135{
136 DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
137 IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32));
138}
139
140static void
141imx_gpio_unmask_irq(unsigned int irq)
142{
143 DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
144 IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
145}
146
147static void
148imx_gpio_handler(unsigned int mask, unsigned int irq,
149 struct irqdesc *desc, struct pt_regs *regs)
150{
151 desc = irq_desc + irq;
152 while (mask) {
153 if (mask & 1) {
154 DEBUG_IRQ("handling irq %d\n", irq);
155 desc->handle(irq, desc, regs);
156 }
157 irq++;
158 desc++;
159 mask >>= 1;
160 }
161}
162
163static void
164imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
165 struct pt_regs *regs)
166{
167 unsigned int mask, irq;
168
169 mask = ISR(0);
170 irq = IRQ_GPIOA(0);
171 imx_gpio_handler(mask, irq, desc, regs);
172}
173
174static void
175imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
176 struct pt_regs *regs)
177{
178 unsigned int mask, irq;
179
180 mask = ISR(1);
181 irq = IRQ_GPIOB(0);
182 imx_gpio_handler(mask, irq, desc, regs);
183}
184
185static void
186imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
187 struct pt_regs *regs)
188{
189 unsigned int mask, irq;
190
191 mask = ISR(2);
192 irq = IRQ_GPIOC(0);
193 imx_gpio_handler(mask, irq, desc, regs);
194}
195
196static void
197imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
198 struct pt_regs *regs)
199{
200 unsigned int mask, irq;
201
202 mask = ISR(3);
203 irq = IRQ_GPIOD(0);
204 imx_gpio_handler(mask, irq, desc, regs);
205}
206
207static struct irqchip imx_internal_chip = {
208 .ack = imx_mask_irq,
209 .mask = imx_mask_irq,
210 .unmask = imx_unmask_irq,
211};
212
213static struct irqchip imx_gpio_chip = {
214 .ack = imx_gpio_ack_irq,
215 .mask = imx_gpio_mask_irq,
216 .unmask = imx_gpio_unmask_irq,
217 .type = imx_gpio_irq_type,
218};
219
220void __init
221imx_init_irq(void)
222{
223 unsigned int irq;
224
225 DEBUG_IRQ("Initializing imx interrupts\n");
226
227 /* Mask all interrupts initially */
228 IMR(0) = 0;
229 IMR(1) = 0;
230 IMR(2) = 0;
231 IMR(3) = 0;
232
233 for (irq = 0; irq < IMX_IRQS; irq++) {
234 set_irq_chip(irq, &imx_internal_chip);
235 set_irq_handler(irq, do_level_IRQ);
236 set_irq_flags(irq, IRQF_VALID);
237 }
238
239 for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) {
240 set_irq_chip(irq, &imx_gpio_chip);
241 set_irq_handler(irq, do_edge_IRQ);
242 set_irq_flags(irq, IRQF_VALID);
243 }
244
245 set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler);
246 set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler);
247 set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
248 set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
249
250 /* Disable all interrupts initially. */
251 /* In IMX this is done in the bootloader. */
252}
diff --git a/arch/arm/mach-imx/leds-mx1ads.c b/arch/arm/mach-imx/leds-mx1ads.c
new file mode 100644
index 00000000000..e6399b06e4a
--- /dev/null
+++ b/arch/arm/mach-imx/leds-mx1ads.c
@@ -0,0 +1,54 @@
1/*
2 * linux/arch/arm/mach-imx/leds-mx1ads.c
3 *
4 * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
5 *
6 * Original (leds-footbridge.c) by Russell King
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <asm/hardware.h>
17#include <asm/system.h>
18#include <asm/io.h>
19#include <asm/leds.h>
20#include <asm/mach-types.h>
21#include "leds.h"
22
23/*
24 * The MX1ADS Board has only one usable LED,
25 * so select only the timer led or the
26 * cpu usage led
27 */
28void
29mx1ads_leds_event(led_event_t ledevt)
30{
31 unsigned long flags;
32
33 local_irq_save(flags);
34
35 switch (ledevt) {
36#ifdef CONFIG_LEDS_CPU
37 case led_idle_start:
38 DR(0) &= ~(1<<2);
39 break;
40
41 case led_idle_end:
42 DR(0) |= 1<<2;
43 break;
44#endif
45
46#ifdef CONFIG_LEDS_TIMER
47 case led_timer:
48 DR(0) ^= 1<<2;
49#endif
50 default:
51 break;
52 }
53 local_irq_restore(flags);
54}
diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c
new file mode 100644
index 00000000000..471c1db7c57
--- /dev/null
+++ b/arch/arm/mach-imx/leds.c
@@ -0,0 +1,31 @@
1/*
2 * linux/arch/arm/mach-imx/leds.h
3 *
4 * Copyright (C) 2004 Sascha Hauer <sascha@saschahauer.de>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15
16#include <asm/leds.h>
17#include <asm/mach-types.h>
18
19#include "leds.h"
20
21static int __init
22leds_init(void)
23{
24 if (machine_is_mx1ads()) {
25 leds_event = mx1ads_leds_event;
26 }
27
28 return 0;
29}
30
31__initcall(leds_init);
diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h
new file mode 100644
index 00000000000..83fa21e795a
--- /dev/null
+++ b/arch/arm/mach-imx/leds.h
@@ -0,0 +1,9 @@
1/*
2 * include/asm-arm/arch-imx/leds.h
3 *
4 * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
5 *
6 * blinky lights for IMX-based systems
7 *
8 */
9extern void mx1ads_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
new file mode 100644
index 00000000000..625dd01c257
--- /dev/null
+++ b/arch/arm/mach-imx/mx1ads.c
@@ -0,0 +1,88 @@
1/*
2 * arch/arm/mach-imx/mx1ads.c
3 *
4 * Initially based on:
5 * linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c
6 * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
7 *
8 * 2004 (c) MontaVista Software, Inc.
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 */
14
15#include <linux/device.h>
16#include <linux/init.h>
17#include <asm/system.h>
18#include <asm/hardware.h>
19#include <asm/irq.h>
20#include <asm/pgtable.h>
21#include <asm/page.h>
22
23#include <asm/mach/map.h>
24#include <asm/mach-types.h>
25
26#include <asm/mach/arch.h>
27#include <linux/interrupt.h>
28#include "generic.h"
29#include <asm/serial.h>
30
31static struct resource mx1ads_resources[] = {
32 [0] = {
33 .start = IMX_CS4_VIRT,
34 .end = IMX_CS4_VIRT + 16,
35 .flags = IORESOURCE_MEM,
36 },
37 [1] = {
38 .start = 13,
39 .end = 13,
40 .flags = IORESOURCE_IRQ,
41 },
42};
43
44static struct platform_device mx1ads_device = {
45 .name = "mx1ads",
46 .num_resources = ARRAY_SIZE(mx1ads_resources),
47 .resource = mx1ads_resources,
48};
49
50static struct platform_device *devices[] __initdata = {
51 &mx1ads_device,
52};
53
54static void __init
55mx1ads_init(void)
56{
57#ifdef CONFIG_LEDS
58 imx_gpio_mode(GPIO_PORTA | GPIO_OUT | GPIO_GPIO | 2);
59#endif
60 platform_add_devices(devices, ARRAY_SIZE(devices));
61}
62
63static struct map_desc mx1ads_io_desc[] __initdata = {
64 /* virtual physical length type */
65 {IMX_CS0_VIRT, IMX_CS0_PHYS, IMX_CS0_SIZE, MT_DEVICE},
66 {IMX_CS1_VIRT, IMX_CS1_PHYS, IMX_CS1_SIZE, MT_DEVICE},
67 {IMX_CS2_VIRT, IMX_CS2_PHYS, IMX_CS2_SIZE, MT_DEVICE},
68 {IMX_CS3_VIRT, IMX_CS3_PHYS, IMX_CS3_SIZE, MT_DEVICE},
69 {IMX_CS4_VIRT, IMX_CS4_PHYS, IMX_CS4_SIZE, MT_DEVICE},
70 {IMX_CS5_VIRT, IMX_CS5_PHYS, IMX_CS5_SIZE, MT_DEVICE},
71};
72
73static void __init
74mx1ads_map_io(void)
75{
76 imx_map_io();
77 iotable_init(mx1ads_io_desc, ARRAY_SIZE(mx1ads_io_desc));
78}
79
80MACHINE_START(MX1ADS, "Motorola MX1ADS")
81 MAINTAINER("Sascha Hauer, Pengutronix")
82 BOOT_MEM(0x08000000, 0x00200000, 0xe0200000)
83 BOOT_PARAMS(0x08000100)
84 MAPIO(mx1ads_map_io)
85 INITIRQ(imx_init_irq)
86 .timer = &imx_timer,
87 INIT_MACHINE(mx1ads_init)
88MACHINE_END
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
new file mode 100644
index 00000000000..11f1e56c36b
--- /dev/null
+++ b/arch/arm/mach-imx/time.c
@@ -0,0 +1,101 @@
1/*
2 * linux/arch/arm/mach-imx/time.c
3 *
4 * Copyright (C) 2000-2001 Deep Blue Solutions
5 * Copyright (C) 2002 Shane Nay (shane@minirl.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/config.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/time.h>
17
18#include <asm/hardware.h>
19#include <asm/io.h>
20#include <asm/leds.h>
21#include <asm/irq.h>
22#include <asm/mach/time.h>
23
24/* Use timer 1 as system timer */
25#define TIMER_BASE IMX_TIM1_BASE
26
27/*
28 * Returns number of us since last clock interrupt. Note that interrupts
29 * will have been disabled by do_gettimeoffset()
30 */
31static unsigned long imx_gettimeoffset(void)
32{
33 unsigned long ticks;
34
35 /*
36 * Get the current number of ticks. Note that there is a race
37 * condition between us reading the timer and checking for
38 * an interrupt. We get around this by ensuring that the
39 * counter has not reloaded between our two reads.
40 */
41 ticks = IMX_TCN(TIMER_BASE);
42
43 /*
44 * Interrupt pending? If so, we've reloaded once already.
45 */
46 if (IMX_TSTAT(TIMER_BASE) & TSTAT_COMP)
47 ticks += LATCH;
48
49 /*
50 * Convert the ticks to usecs
51 */
52 return (1000000 / CLK32) * ticks;
53}
54
55/*
56 * IRQ handler for the timer
57 */
58static irqreturn_t
59imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
60{
61 write_seqlock(&xtime_lock);
62
63 /* clear the interrupt */
64 if (IMX_TSTAT(TIMER_BASE))
65 IMX_TSTAT(TIMER_BASE) = 0;
66
67 timer_tick(regs);
68 write_sequnlock(&xtime_lock);
69
70 return IRQ_HANDLED;
71}
72
73static struct irqaction imx_timer_irq = {
74 .name = "i.MX Timer Tick",
75 .flags = SA_INTERRUPT,
76 .handler = imx_timer_interrupt
77};
78
79/*
80 * Set up timer interrupt, and return the current time in seconds.
81 */
82static void __init imx_timer_init(void)
83{
84 /*
85 * Initialise to a known state (all timers off, and timing reset)
86 */
87 IMX_TCTL(TIMER_BASE) = 0;
88 IMX_TPRER(TIMER_BASE) = 0;
89 IMX_TCMP(TIMER_BASE) = LATCH - 1;
90 IMX_TCTL(TIMER_BASE) = TCTL_CLK_32 | TCTL_IRQEN | TCTL_TEN;
91
92 /*
93 * Make irqs happen for the system timer
94 */
95 setup_irq(TIM1_INT, &imx_timer_irq);
96}
97
98struct sys_timer imx_timer = {
99 .init = imx_timer_init,
100 .offset = imx_gettimeoffset,
101};