diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-pxa |
Linux-2.6.12-rc2v2.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-pxa')
-rw-r--r-- | arch/arm/mach-pxa/Kconfig | 77 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Makefile | 26 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Makefile.boot | 2 | ||||
-rw-r--r-- | arch/arm/mach-pxa/corgi.c | 320 | ||||
-rw-r--r-- | arch/arm/mach-pxa/corgi_ssp.c | 248 | ||||
-rw-r--r-- | arch/arm/mach-pxa/dma.c | 133 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.c | 237 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.h | 24 | ||||
-rw-r--r-- | arch/arm/mach-pxa/idp.c | 190 | ||||
-rw-r--r-- | arch/arm/mach-pxa/irq.c | 313 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds-idp.c | 117 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds-lubbock.c | 126 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds-mainstone.c | 121 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-pxa/leds.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-pxa/lubbock.c | 247 | ||||
-rw-r--r-- | arch/arm/mach-pxa/mainstone.c | 316 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pm.c | 227 | ||||
-rw-r--r-- | arch/arm/mach-pxa/poodle.c | 189 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa25x.c | 104 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa27x.c | 163 | ||||
-rw-r--r-- | arch/arm/mach-pxa/sleep.S | 194 | ||||
-rw-r--r-- | arch/arm/mach-pxa/ssp.c | 363 | ||||
-rw-r--r-- | arch/arm/mach-pxa/time.c | 164 |
24 files changed, 3945 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig new file mode 100644 index 000000000000..405a55f2287c --- /dev/null +++ b/arch/arm/mach-pxa/Kconfig | |||
@@ -0,0 +1,77 @@ | |||
1 | if ARCH_PXA | ||
2 | |||
3 | menu "Intel PXA2xx Implementations" | ||
4 | |||
5 | choice | ||
6 | prompt "Select target board" | ||
7 | |||
8 | config ARCH_LUBBOCK | ||
9 | bool "Intel DBPXA250 Development Platform" | ||
10 | select PXA25x | ||
11 | select SA1111 | ||
12 | |||
13 | config MACH_MAINSTONE | ||
14 | bool "Intel HCDDBBVA0 Development Platform" | ||
15 | select PXA27x | ||
16 | select IWMMXT | ||
17 | |||
18 | config ARCH_PXA_IDP | ||
19 | bool "Accelent Xscale IDP" | ||
20 | select PXA25x | ||
21 | |||
22 | config PXA_SHARPSL | ||
23 | bool "SHARP SL-5600 and SL-C7xx Models" | ||
24 | select PXA25x | ||
25 | select SHARP_SCOOP | ||
26 | select SHARP_PARAM | ||
27 | help | ||
28 | Say Y here if you intend to run this kernel on a | ||
29 | Sharp SL-5600 (Poodle), Sharp SL-C700 (Corgi), | ||
30 | SL-C750 (Shepherd) or a Sharp SL-C760 (Husky) | ||
31 | handheld computer. | ||
32 | |||
33 | endchoice | ||
34 | |||
35 | endmenu | ||
36 | |||
37 | config MACH_POODLE | ||
38 | bool "Enable Sharp SL-5600 (Poodle) Support" | ||
39 | depends PXA_SHARPSL | ||
40 | select SHARP_LOCOMO | ||
41 | |||
42 | config MACH_CORGI | ||
43 | bool "Enable Sharp SL-C700 (Corgi) Support" | ||
44 | depends PXA_SHARPSL | ||
45 | select PXA_SHARP_C7xx | ||
46 | |||
47 | config MACH_SHEPHERD | ||
48 | bool "Enable Sharp SL-C750 (Shepherd) Support" | ||
49 | depends PXA_SHARPSL | ||
50 | select PXA_SHARP_C7xx | ||
51 | |||
52 | config MACH_HUSKY | ||
53 | bool "Enable Sharp SL-C760 (Husky) Support" | ||
54 | depends PXA_SHARPSL | ||
55 | select PXA_SHARP_C7xx | ||
56 | |||
57 | config PXA25x | ||
58 | bool | ||
59 | help | ||
60 | Select code specific to PXA21x/25x/26x variants | ||
61 | |||
62 | config PXA27x | ||
63 | bool | ||
64 | help | ||
65 | Select code specific to PXA27x variants | ||
66 | |||
67 | config IWMMXT | ||
68 | bool | ||
69 | help | ||
70 | Enable support for iWMMXt | ||
71 | |||
72 | config PXA_SHARP_C7xx | ||
73 | bool | ||
74 | help | ||
75 | Enable support for all Sharp C7xx models | ||
76 | |||
77 | endif | ||
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile new file mode 100644 index 000000000000..c4e6d2523585 --- /dev/null +++ b/arch/arm/mach-pxa/Makefile | |||
@@ -0,0 +1,26 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | # Common support (must be linked before board specific support) | ||
6 | obj-y += generic.o irq.o dma.o time.o | ||
7 | obj-$(CONFIG_PXA25x) += pxa25x.o | ||
8 | obj-$(CONFIG_PXA27x) += pxa27x.o | ||
9 | |||
10 | # Specific board support | ||
11 | obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o | ||
12 | obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o | ||
13 | obj-$(CONFIG_ARCH_PXA_IDP) += idp.o | ||
14 | obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o ssp.o | ||
15 | obj-$(CONFIG_MACH_POODLE) += poodle.o | ||
16 | |||
17 | # Support for blinky lights | ||
18 | led-y := leds.o | ||
19 | led-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o | ||
20 | led-$(CONFIG_MACH_MAINSTONE) += leds-mainstone.o | ||
21 | led-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o | ||
22 | |||
23 | obj-$(CONFIG_LEDS) += $(led-y) | ||
24 | |||
25 | # Misc features | ||
26 | obj-$(CONFIG_PM) += pm.o sleep.o | ||
diff --git a/arch/arm/mach-pxa/Makefile.boot b/arch/arm/mach-pxa/Makefile.boot new file mode 100644 index 000000000000..1ead67178eca --- /dev/null +++ b/arch/arm/mach-pxa/Makefile.boot | |||
@@ -0,0 +1,2 @@ | |||
1 | zreladdr-y := 0xa0008000 | ||
2 | |||
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c new file mode 100644 index 000000000000..f691cf77d390 --- /dev/null +++ b/arch/arm/mach-pxa/corgi.c | |||
@@ -0,0 +1,320 @@ | |||
1 | /* | ||
2 | * Support for Sharp SL-C7xx PDAs | ||
3 | * Models: SL-C700 (Corgi), SL-C750 (Shepherd), SL-C760 (Husky) | ||
4 | * | ||
5 | * Copyright (c) 2004-2005 Richard Purdie | ||
6 | * | ||
7 | * Based on Sharp's 2.4 kernel patches/lubbock.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/major.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/mmc/host.h> | ||
22 | |||
23 | #include <asm/setup.h> | ||
24 | #include <asm/memory.h> | ||
25 | #include <asm/mach-types.h> | ||
26 | #include <asm/hardware.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/io.h> | ||
29 | |||
30 | #include <asm/mach/arch.h> | ||
31 | #include <asm/mach/map.h> | ||
32 | #include <asm/mach/irq.h> | ||
33 | |||
34 | #include <asm/arch/pxa-regs.h> | ||
35 | #include <asm/arch/irq.h> | ||
36 | #include <asm/arch/mmc.h> | ||
37 | #include <asm/arch/udc.h> | ||
38 | #include <asm/arch/corgi.h> | ||
39 | |||
40 | #include <asm/mach/sharpsl_param.h> | ||
41 | #include <asm/hardware/scoop.h> | ||
42 | #include <video/w100fb.h> | ||
43 | |||
44 | #include "generic.h" | ||
45 | |||
46 | |||
47 | /* | ||
48 | * Corgi SCOOP Device | ||
49 | */ | ||
50 | static struct resource corgi_scoop_resources[] = { | ||
51 | [0] = { | ||
52 | .start = 0x10800000, | ||
53 | .end = 0x10800fff, | ||
54 | .flags = IORESOURCE_MEM, | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | static struct scoop_config corgi_scoop_setup = { | ||
59 | .io_dir = CORGI_SCOOP_IO_DIR, | ||
60 | .io_out = CORGI_SCOOP_IO_OUT, | ||
61 | }; | ||
62 | |||
63 | struct platform_device corgiscoop_device = { | ||
64 | .name = "sharp-scoop", | ||
65 | .id = -1, | ||
66 | .dev = { | ||
67 | .platform_data = &corgi_scoop_setup, | ||
68 | }, | ||
69 | .num_resources = ARRAY_SIZE(corgi_scoop_resources), | ||
70 | .resource = corgi_scoop_resources, | ||
71 | }; | ||
72 | |||
73 | |||
74 | /* | ||
75 | * Corgi SSP Device | ||
76 | * | ||
77 | * Set the parent as the scoop device because a lot of SSP devices | ||
78 | * also use scoop functions and this makes the power up/down order | ||
79 | * work correctly. | ||
80 | */ | ||
81 | static struct platform_device corgissp_device = { | ||
82 | .name = "corgi-ssp", | ||
83 | .dev = { | ||
84 | .parent = &corgiscoop_device.dev, | ||
85 | }, | ||
86 | .id = -1, | ||
87 | }; | ||
88 | |||
89 | |||
90 | /* | ||
91 | * Corgi w100 Frame Buffer Device | ||
92 | */ | ||
93 | static struct w100fb_mach_info corgi_fb_info = { | ||
94 | .w100fb_ssp_send = corgi_ssp_lcdtg_send, | ||
95 | .comadj = -1, | ||
96 | .phadadj = -1, | ||
97 | }; | ||
98 | |||
99 | static struct resource corgi_fb_resources[] = { | ||
100 | [0] = { | ||
101 | .start = 0x08000000, | ||
102 | .end = 0x08ffffff, | ||
103 | .flags = IORESOURCE_MEM, | ||
104 | }, | ||
105 | }; | ||
106 | |||
107 | static struct platform_device corgifb_device = { | ||
108 | .name = "w100fb", | ||
109 | .id = -1, | ||
110 | .dev = { | ||
111 | .platform_data = &corgi_fb_info, | ||
112 | .parent = &corgissp_device.dev, | ||
113 | }, | ||
114 | .num_resources = ARRAY_SIZE(corgi_fb_resources), | ||
115 | .resource = corgi_fb_resources, | ||
116 | }; | ||
117 | |||
118 | |||
119 | /* | ||
120 | * Corgi Backlight Device | ||
121 | */ | ||
122 | static struct platform_device corgibl_device = { | ||
123 | .name = "corgi-bl", | ||
124 | .dev = { | ||
125 | .parent = &corgifb_device.dev, | ||
126 | }, | ||
127 | .id = -1, | ||
128 | }; | ||
129 | |||
130 | |||
131 | /* | ||
132 | * MMC/SD Device | ||
133 | * | ||
134 | * The card detect interrupt isn't debounced so we delay it by HZ/4 | ||
135 | * to give the card a chance to fully insert/eject. | ||
136 | */ | ||
137 | static struct mmc_detect { | ||
138 | struct timer_list detect_timer; | ||
139 | void *devid; | ||
140 | } mmc_detect; | ||
141 | |||
142 | static void mmc_detect_callback(unsigned long data) | ||
143 | { | ||
144 | mmc_detect_change(mmc_detect.devid); | ||
145 | } | ||
146 | |||
147 | static irqreturn_t corgi_mmc_detect_int(int irq, void *devid, struct pt_regs *regs) | ||
148 | { | ||
149 | mmc_detect.devid=devid; | ||
150 | mod_timer(&mmc_detect.detect_timer, jiffies + HZ/4); | ||
151 | return IRQ_HANDLED; | ||
152 | } | ||
153 | |||
154 | static int corgi_mci_init(struct device *dev, irqreturn_t (*unused_detect_int)(int, void *, struct pt_regs *), void *data) | ||
155 | { | ||
156 | int err; | ||
157 | |||
158 | /* setup GPIO for PXA25x MMC controller */ | ||
159 | pxa_gpio_mode(GPIO6_MMCCLK_MD); | ||
160 | pxa_gpio_mode(GPIO8_MMCCS0_MD); | ||
161 | pxa_gpio_mode(CORGI_GPIO_nSD_DETECT | GPIO_IN); | ||
162 | pxa_gpio_mode(CORGI_GPIO_SD_PWR | GPIO_OUT); | ||
163 | |||
164 | init_timer(&mmc_detect.detect_timer); | ||
165 | mmc_detect.detect_timer.function = mmc_detect_callback; | ||
166 | mmc_detect.detect_timer.data = (unsigned long) &mmc_detect; | ||
167 | |||
168 | err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_mmc_detect_int, SA_INTERRUPT, | ||
169 | "MMC card detect", data); | ||
170 | if (err) { | ||
171 | printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); | ||
172 | return -1; | ||
173 | } | ||
174 | |||
175 | set_irq_type(CORGI_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static void corgi_mci_setpower(struct device *dev, unsigned int vdd) | ||
181 | { | ||
182 | struct pxamci_platform_data* p_d = dev->platform_data; | ||
183 | |||
184 | if (( 1 << vdd) & p_d->ocr_mask) { | ||
185 | printk(KERN_DEBUG "%s: on\n", __FUNCTION__); | ||
186 | GPSR1 = GPIO_bit(CORGI_GPIO_SD_PWR); | ||
187 | } else { | ||
188 | printk(KERN_DEBUG "%s: off\n", __FUNCTION__); | ||
189 | GPCR1 = GPIO_bit(CORGI_GPIO_SD_PWR); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | static void corgi_mci_exit(struct device *dev, void *data) | ||
194 | { | ||
195 | free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data); | ||
196 | del_timer(&mmc_detect.detect_timer); | ||
197 | } | ||
198 | |||
199 | static struct pxamci_platform_data corgi_mci_platform_data = { | ||
200 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
201 | .init = corgi_mci_init, | ||
202 | .setpower = corgi_mci_setpower, | ||
203 | .exit = corgi_mci_exit, | ||
204 | }; | ||
205 | |||
206 | |||
207 | /* | ||
208 | * USB Device Controller | ||
209 | */ | ||
210 | static void corgi_udc_command(int cmd) | ||
211 | { | ||
212 | switch(cmd) { | ||
213 | case PXA2XX_UDC_CMD_CONNECT: | ||
214 | GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP); | ||
215 | break; | ||
216 | case PXA2XX_UDC_CMD_DISCONNECT: | ||
217 | GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP); | ||
218 | break; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static struct pxa2xx_udc_mach_info udc_info __initdata = { | ||
223 | /* no connect GPIO; corgi can't tell connection status */ | ||
224 | .udc_command = corgi_udc_command, | ||
225 | }; | ||
226 | |||
227 | |||
228 | static struct platform_device *devices[] __initdata = { | ||
229 | &corgiscoop_device, | ||
230 | &corgissp_device, | ||
231 | &corgifb_device, | ||
232 | &corgibl_device, | ||
233 | }; | ||
234 | |||
235 | static void __init corgi_init(void) | ||
236 | { | ||
237 | corgi_fb_info.comadj=sharpsl_param.comadj; | ||
238 | corgi_fb_info.phadadj=sharpsl_param.phadadj; | ||
239 | |||
240 | pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT); | ||
241 | pxa_set_udc_info(&udc_info); | ||
242 | pxa_set_mci_info(&corgi_mci_platform_data); | ||
243 | |||
244 | platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
245 | } | ||
246 | |||
247 | static void __init fixup_corgi(struct machine_desc *desc, | ||
248 | struct tag *tags, char **cmdline, struct meminfo *mi) | ||
249 | { | ||
250 | sharpsl_save_param(); | ||
251 | mi->nr_banks=1; | ||
252 | mi->bank[0].start = 0xa0000000; | ||
253 | mi->bank[0].node = 0; | ||
254 | if (machine_is_corgi()) | ||
255 | mi->bank[0].size = (32*1024*1024); | ||
256 | else | ||
257 | mi->bank[0].size = (64*1024*1024); | ||
258 | } | ||
259 | |||
260 | static void __init corgi_init_irq(void) | ||
261 | { | ||
262 | pxa_init_irq(); | ||
263 | } | ||
264 | |||
265 | static struct map_desc corgi_io_desc[] __initdata = { | ||
266 | /* virtual physical length */ | ||
267 | /* { 0xf1000000, 0x08000000, 0x01000000, MT_DEVICE },*/ /* LCDC (readable for Qt driver) */ | ||
268 | /* { 0xef700000, 0x10800000, 0x00001000, MT_DEVICE },*/ /* SCOOP */ | ||
269 | { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */ | ||
270 | }; | ||
271 | |||
272 | static void __init corgi_map_io(void) | ||
273 | { | ||
274 | pxa_map_io(); | ||
275 | iotable_init(corgi_io_desc,ARRAY_SIZE(corgi_io_desc)); | ||
276 | |||
277 | /* setup sleep mode values */ | ||
278 | PWER = 0x00000002; | ||
279 | PFER = 0x00000000; | ||
280 | PRER = 0x00000002; | ||
281 | PGSR0 = 0x0158C000; | ||
282 | PGSR1 = 0x00FF0080; | ||
283 | PGSR2 = 0x0001C004; | ||
284 | /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */ | ||
285 | PCFR |= PCFR_OPDE; | ||
286 | } | ||
287 | |||
288 | #ifdef CONFIG_MACH_CORGI | ||
289 | MACHINE_START(CORGI, "SHARP Corgi") | ||
290 | BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) | ||
291 | FIXUP(fixup_corgi) | ||
292 | MAPIO(corgi_map_io) | ||
293 | INITIRQ(corgi_init_irq) | ||
294 | .init_machine = corgi_init, | ||
295 | .timer = &pxa_timer, | ||
296 | MACHINE_END | ||
297 | #endif | ||
298 | |||
299 | #ifdef CONFIG_MACH_SHEPHERD | ||
300 | MACHINE_START(SHEPHERD, "SHARP Shepherd") | ||
301 | BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) | ||
302 | FIXUP(fixup_corgi) | ||
303 | MAPIO(corgi_map_io) | ||
304 | INITIRQ(corgi_init_irq) | ||
305 | .init_machine = corgi_init, | ||
306 | .timer = &pxa_timer, | ||
307 | MACHINE_END | ||
308 | #endif | ||
309 | |||
310 | #ifdef CONFIG_MACH_HUSKY | ||
311 | MACHINE_START(HUSKY, "SHARP Husky") | ||
312 | BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) | ||
313 | FIXUP(fixup_corgi) | ||
314 | MAPIO(corgi_map_io) | ||
315 | INITIRQ(corgi_init_irq) | ||
316 | .init_machine = corgi_init, | ||
317 | .timer = &pxa_timer, | ||
318 | MACHINE_END | ||
319 | #endif | ||
320 | |||
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c new file mode 100644 index 000000000000..8ccffba0018f --- /dev/null +++ b/arch/arm/mach-pxa/corgi_ssp.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * SSP control code for Sharp Corgi devices | ||
3 | * | ||
4 | * Copyright (c) 2004 Richard Purdie | ||
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 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <asm/hardware.h> | ||
20 | |||
21 | #include <asm/arch/ssp.h> | ||
22 | #include <asm/arch/corgi.h> | ||
23 | #include <asm/arch/pxa-regs.h> | ||
24 | |||
25 | static spinlock_t corgi_ssp_lock = SPIN_LOCK_UNLOCKED; | ||
26 | static struct ssp_dev corgi_ssp_dev; | ||
27 | static struct ssp_state corgi_ssp_state; | ||
28 | |||
29 | /* | ||
30 | * There are three devices connected to the SSP interface: | ||
31 | * 1. A touchscreen controller (TI ADS7846 compatible) | ||
32 | * 2. An LCD contoller (with some Backlight functionality) | ||
33 | * 3. A battery moinitoring IC (Maxim MAX1111) | ||
34 | * | ||
35 | * Each device uses a different speed/mode of communication. | ||
36 | * | ||
37 | * The touchscreen is very sensitive and the most frequently used | ||
38 | * so the port is left configured for this. | ||
39 | * | ||
40 | * Devices are selected using Chip Selects on GPIOs. | ||
41 | */ | ||
42 | |||
43 | /* | ||
44 | * ADS7846 Routines | ||
45 | */ | ||
46 | unsigned long corgi_ssp_ads7846_putget(ulong data) | ||
47 | { | ||
48 | unsigned long ret,flag; | ||
49 | |||
50 | spin_lock_irqsave(&corgi_ssp_lock, flag); | ||
51 | GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); | ||
52 | |||
53 | ssp_write_word(&corgi_ssp_dev,data); | ||
54 | ret = ssp_read_word(&corgi_ssp_dev); | ||
55 | |||
56 | GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); | ||
57 | spin_unlock_irqrestore(&corgi_ssp_lock, flag); | ||
58 | |||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * NOTE: These functions should always be called in interrupt context | ||
64 | * and use the _lock and _unlock functions. They are very time sensitive. | ||
65 | */ | ||
66 | void corgi_ssp_ads7846_lock(void) | ||
67 | { | ||
68 | spin_lock(&corgi_ssp_lock); | ||
69 | GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); | ||
70 | } | ||
71 | |||
72 | void corgi_ssp_ads7846_unlock(void) | ||
73 | { | ||
74 | GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); | ||
75 | spin_unlock(&corgi_ssp_lock); | ||
76 | } | ||
77 | |||
78 | void corgi_ssp_ads7846_put(ulong data) | ||
79 | { | ||
80 | ssp_write_word(&corgi_ssp_dev,data); | ||
81 | } | ||
82 | |||
83 | unsigned long corgi_ssp_ads7846_get(void) | ||
84 | { | ||
85 | return ssp_read_word(&corgi_ssp_dev); | ||
86 | } | ||
87 | |||
88 | EXPORT_SYMBOL(corgi_ssp_ads7846_putget); | ||
89 | EXPORT_SYMBOL(corgi_ssp_ads7846_lock); | ||
90 | EXPORT_SYMBOL(corgi_ssp_ads7846_unlock); | ||
91 | EXPORT_SYMBOL(corgi_ssp_ads7846_put); | ||
92 | EXPORT_SYMBOL(corgi_ssp_ads7846_get); | ||
93 | |||
94 | |||
95 | /* | ||
96 | * LCD/Backlight Routines | ||
97 | */ | ||
98 | unsigned long corgi_ssp_dac_put(ulong data) | ||
99 | { | ||
100 | unsigned long flag; | ||
101 | |||
102 | spin_lock_irqsave(&corgi_ssp_lock, flag); | ||
103 | GPCR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); | ||
104 | |||
105 | ssp_disable(&corgi_ssp_dev); | ||
106 | ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPH, 0, SSCR0_SerClkDiv(76)); | ||
107 | ssp_enable(&corgi_ssp_dev); | ||
108 | |||
109 | ssp_write_word(&corgi_ssp_dev,data); | ||
110 | /* Read null data back from device to prevent SSP overflow */ | ||
111 | ssp_read_word(&corgi_ssp_dev); | ||
112 | |||
113 | ssp_disable(&corgi_ssp_dev); | ||
114 | ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2)); | ||
115 | ssp_enable(&corgi_ssp_dev); | ||
116 | GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); | ||
117 | spin_unlock_irqrestore(&corgi_ssp_lock, flag); | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | void corgi_ssp_lcdtg_send(u8 adrs, u8 data) | ||
123 | { | ||
124 | corgi_ssp_dac_put(((adrs & 0x07) << 5) | (data & 0x1f)); | ||
125 | } | ||
126 | |||
127 | void corgi_ssp_blduty_set(int duty) | ||
128 | { | ||
129 | corgi_ssp_lcdtg_send(0x02,duty); | ||
130 | } | ||
131 | |||
132 | EXPORT_SYMBOL(corgi_ssp_lcdtg_send); | ||
133 | EXPORT_SYMBOL(corgi_ssp_blduty_set); | ||
134 | |||
135 | /* | ||
136 | * Max1111 Routines | ||
137 | */ | ||
138 | int corgi_ssp_max1111_get(ulong data) | ||
139 | { | ||
140 | unsigned long flag; | ||
141 | int voltage,voltage1,voltage2; | ||
142 | |||
143 | spin_lock_irqsave(&corgi_ssp_lock, flag); | ||
144 | GPCR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); | ||
145 | ssp_disable(&corgi_ssp_dev); | ||
146 | ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(8)); | ||
147 | ssp_enable(&corgi_ssp_dev); | ||
148 | |||
149 | udelay(1); | ||
150 | |||
151 | /* TB1/RB1 */ | ||
152 | ssp_write_word(&corgi_ssp_dev,data); | ||
153 | ssp_read_word(&corgi_ssp_dev); /* null read */ | ||
154 | |||
155 | /* TB12/RB2 */ | ||
156 | ssp_write_word(&corgi_ssp_dev,0); | ||
157 | voltage1=ssp_read_word(&corgi_ssp_dev); | ||
158 | |||
159 | /* TB13/RB3*/ | ||
160 | ssp_write_word(&corgi_ssp_dev,0); | ||
161 | voltage2=ssp_read_word(&corgi_ssp_dev); | ||
162 | |||
163 | ssp_disable(&corgi_ssp_dev); | ||
164 | ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2)); | ||
165 | ssp_enable(&corgi_ssp_dev); | ||
166 | GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); | ||
167 | spin_unlock_irqrestore(&corgi_ssp_lock, flag); | ||
168 | |||
169 | if (voltage1 & 0xc0 || voltage2 & 0x3f) | ||
170 | voltage = -1; | ||
171 | else | ||
172 | voltage = ((voltage1 << 2) & 0xfc) | ((voltage2 >> 6) & 0x03); | ||
173 | |||
174 | return voltage; | ||
175 | } | ||
176 | |||
177 | EXPORT_SYMBOL(corgi_ssp_max1111_get); | ||
178 | |||
179 | /* | ||
180 | * Support Routines | ||
181 | */ | ||
182 | int __init corgi_ssp_probe(struct device *dev) | ||
183 | { | ||
184 | int ret; | ||
185 | |||
186 | /* Chip Select - Disable All */ | ||
187 | GPDR0 |= GPIO_bit(CORGI_GPIO_LCDCON_CS); /* output */ | ||
188 | GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); /* High - Disable LCD Control/Timing Gen */ | ||
189 | GPDR0 |= GPIO_bit(CORGI_GPIO_MAX1111_CS); /* output */ | ||
190 | GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/ | ||
191 | GPDR0 |= GPIO_bit(CORGI_GPIO_ADS7846_CS); /* output */ | ||
192 | GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/ | ||
193 | |||
194 | ret=ssp_init(&corgi_ssp_dev,1); | ||
195 | |||
196 | if (ret) | ||
197 | printk(KERN_ERR "Unable to register SSP handler!\n"); | ||
198 | else { | ||
199 | ssp_disable(&corgi_ssp_dev); | ||
200 | ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2)); | ||
201 | ssp_enable(&corgi_ssp_dev); | ||
202 | } | ||
203 | |||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static int corgi_ssp_remove(struct device *dev) | ||
208 | { | ||
209 | ssp_exit(&corgi_ssp_dev); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level) | ||
214 | { | ||
215 | if (level == SUSPEND_POWER_DOWN) { | ||
216 | ssp_flush(&corgi_ssp_dev); | ||
217 | ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state); | ||
218 | } | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int corgi_ssp_resume(struct device *dev, u32 level) | ||
223 | { | ||
224 | if (level == RESUME_POWER_ON) { | ||
225 | GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); /* High - Disable LCD Control/Timing Gen */ | ||
226 | GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/ | ||
227 | GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/ | ||
228 | ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state); | ||
229 | ssp_enable(&corgi_ssp_dev); | ||
230 | } | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static struct device_driver corgissp_driver = { | ||
235 | .name = "corgi-ssp", | ||
236 | .bus = &platform_bus_type, | ||
237 | .probe = corgi_ssp_probe, | ||
238 | .remove = corgi_ssp_remove, | ||
239 | .suspend = corgi_ssp_suspend, | ||
240 | .resume = corgi_ssp_resume, | ||
241 | }; | ||
242 | |||
243 | int __init corgi_ssp_init(void) | ||
244 | { | ||
245 | return driver_register(&corgissp_driver); | ||
246 | } | ||
247 | |||
248 | arch_initcall(corgi_ssp_init); | ||
diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c new file mode 100644 index 000000000000..458112b21e25 --- /dev/null +++ b/arch/arm/mach-pxa/dma.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/dma.c | ||
3 | * | ||
4 | * PXA DMA registration and IRQ dispatching | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Nov 15, 2001 | ||
8 | * Copyright: MontaVista Software Inc. | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
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 | |||
26 | #include <asm/arch/pxa-regs.h> | ||
27 | |||
28 | static struct dma_channel { | ||
29 | char *name; | ||
30 | void (*irq_handler)(int, void *, struct pt_regs *); | ||
31 | void *data; | ||
32 | } dma_channels[PXA_DMA_CHANNELS]; | ||
33 | |||
34 | |||
35 | int pxa_request_dma (char *name, pxa_dma_prio prio, | ||
36 | void (*irq_handler)(int, void *, struct pt_regs *), | ||
37 | 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 + PXA_DMA_NBCH(prio); 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 | DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; | ||
68 | dma_channels[i].name = name; | ||
69 | dma_channels[i].irq_handler = irq_handler; | ||
70 | dma_channels[i].data = data; | ||
71 | } else { | ||
72 | printk (KERN_WARNING "No more available DMA channels for %s\n", name); | ||
73 | i = -ENODEV; | ||
74 | } | ||
75 | |||
76 | local_irq_restore(flags); | ||
77 | return i; | ||
78 | } | ||
79 | |||
80 | void pxa_free_dma (int dma_ch) | ||
81 | { | ||
82 | unsigned long flags; | ||
83 | |||
84 | if (!dma_channels[dma_ch].name) { | ||
85 | printk (KERN_CRIT | ||
86 | "%s: trying to free channel %d which is already freed\n", | ||
87 | __FUNCTION__, dma_ch); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | local_irq_save(flags); | ||
92 | DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; | ||
93 | dma_channels[dma_ch].name = NULL; | ||
94 | local_irq_restore(flags); | ||
95 | } | ||
96 | |||
97 | static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
98 | { | ||
99 | int i, dint = DINT; | ||
100 | |||
101 | for (i = 0; i < PXA_DMA_CHANNELS; i++) { | ||
102 | if (dint & (1 << i)) { | ||
103 | struct dma_channel *channel = &dma_channels[i]; | ||
104 | if (channel->name && channel->irq_handler) { | ||
105 | channel->irq_handler(i, channel->data, regs); | ||
106 | } else { | ||
107 | /* | ||
108 | * IRQ for an unregistered DMA channel: | ||
109 | * let's clear the interrupts and disable it. | ||
110 | */ | ||
111 | printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i); | ||
112 | DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | return IRQ_HANDLED; | ||
117 | } | ||
118 | |||
119 | static int __init pxa_dma_init (void) | ||
120 | { | ||
121 | int ret; | ||
122 | |||
123 | ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); | ||
124 | if (ret) | ||
125 | printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | arch_initcall(pxa_dma_init); | ||
130 | |||
131 | EXPORT_SYMBOL(pxa_request_dma); | ||
132 | EXPORT_SYMBOL(pxa_free_dma); | ||
133 | |||
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c new file mode 100644 index 000000000000..b1575b8dc1cd --- /dev/null +++ b/arch/arm/mach-pxa/generic.c | |||
@@ -0,0 +1,237 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/generic.c | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Jun 15, 2001 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * Code common to all PXA 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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * Since this file should be linked before any other machine specific file, | ||
15 | * the __initcall() here will be executed first. This serves as default | ||
16 | * initialization stuff for PXA machines which can be overridden later if | ||
17 | * need be. | ||
18 | */ | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/ioport.h> | ||
25 | #include <linux/pm.h> | ||
26 | |||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/system.h> | ||
30 | #include <asm/pgtable.h> | ||
31 | #include <asm/mach/map.h> | ||
32 | |||
33 | #include <asm/arch/pxa-regs.h> | ||
34 | #include <asm/arch/udc.h> | ||
35 | #include <asm/arch/pxafb.h> | ||
36 | #include <asm/arch/mmc.h> | ||
37 | |||
38 | #include "generic.h" | ||
39 | |||
40 | /* | ||
41 | * Handy function to set GPIO alternate functions | ||
42 | */ | ||
43 | |||
44 | void pxa_gpio_mode(int gpio_mode) | ||
45 | { | ||
46 | unsigned long flags; | ||
47 | int gpio = gpio_mode & GPIO_MD_MASK_NR; | ||
48 | int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; | ||
49 | int gafr; | ||
50 | |||
51 | local_irq_save(flags); | ||
52 | if (gpio_mode & GPIO_DFLT_LOW) | ||
53 | GPCR(gpio) = GPIO_bit(gpio); | ||
54 | else if (gpio_mode & GPIO_DFLT_HIGH) | ||
55 | GPSR(gpio) = GPIO_bit(gpio); | ||
56 | if (gpio_mode & GPIO_MD_MASK_DIR) | ||
57 | GPDR(gpio) |= GPIO_bit(gpio); | ||
58 | else | ||
59 | GPDR(gpio) &= ~GPIO_bit(gpio); | ||
60 | gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); | ||
61 | GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); | ||
62 | local_irq_restore(flags); | ||
63 | } | ||
64 | |||
65 | EXPORT_SYMBOL(pxa_gpio_mode); | ||
66 | |||
67 | /* | ||
68 | * Routine to safely enable or disable a clock in the CKEN | ||
69 | */ | ||
70 | void pxa_set_cken(int clock, int enable) | ||
71 | { | ||
72 | unsigned long flags; | ||
73 | local_irq_save(flags); | ||
74 | |||
75 | if (enable) | ||
76 | CKEN |= clock; | ||
77 | else | ||
78 | CKEN &= ~clock; | ||
79 | |||
80 | local_irq_restore(flags); | ||
81 | } | ||
82 | |||
83 | EXPORT_SYMBOL(pxa_set_cken); | ||
84 | |||
85 | /* | ||
86 | * Intel PXA2xx internal register mapping. | ||
87 | * | ||
88 | * Note 1: not all PXA2xx variants implement all those addresses. | ||
89 | * | ||
90 | * Note 2: virtual 0xfffe0000-0xffffffff is reserved for the vector table | ||
91 | * and cache flush area. | ||
92 | */ | ||
93 | static struct map_desc standard_io_desc[] __initdata = { | ||
94 | /* virtual physical length type */ | ||
95 | { 0xf2000000, 0x40000000, 0x02000000, MT_DEVICE }, /* Devs */ | ||
96 | { 0xf4000000, 0x44000000, 0x00100000, MT_DEVICE }, /* LCD */ | ||
97 | { 0xf6000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Mem Ctl */ | ||
98 | { 0xf8000000, 0x4c000000, 0x00100000, MT_DEVICE }, /* USB host */ | ||
99 | { 0xfa000000, 0x50000000, 0x00100000, MT_DEVICE }, /* Camera */ | ||
100 | { 0xfe000000, 0x58000000, 0x00100000, MT_DEVICE }, /* IMem ctl */ | ||
101 | { 0xff000000, 0x00000000, 0x00100000, MT_DEVICE } /* UNCACHED_PHYS_0 */ | ||
102 | }; | ||
103 | |||
104 | void __init pxa_map_io(void) | ||
105 | { | ||
106 | iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); | ||
107 | get_clk_frequency_khz(1); | ||
108 | } | ||
109 | |||
110 | |||
111 | static struct resource pxamci_resources[] = { | ||
112 | [0] = { | ||
113 | .start = 0x41100000, | ||
114 | .end = 0x41100fff, | ||
115 | .flags = IORESOURCE_MEM, | ||
116 | }, | ||
117 | [1] = { | ||
118 | .start = IRQ_MMC, | ||
119 | .end = IRQ_MMC, | ||
120 | .flags = IORESOURCE_IRQ, | ||
121 | }, | ||
122 | }; | ||
123 | |||
124 | static u64 pxamci_dmamask = 0xffffffffUL; | ||
125 | |||
126 | static struct platform_device pxamci_device = { | ||
127 | .name = "pxa2xx-mci", | ||
128 | .id = -1, | ||
129 | .dev = { | ||
130 | .dma_mask = &pxamci_dmamask, | ||
131 | .coherent_dma_mask = 0xffffffff, | ||
132 | }, | ||
133 | .num_resources = ARRAY_SIZE(pxamci_resources), | ||
134 | .resource = pxamci_resources, | ||
135 | }; | ||
136 | |||
137 | void __init pxa_set_mci_info(struct pxamci_platform_data *info) | ||
138 | { | ||
139 | pxamci_device.dev.platform_data = info; | ||
140 | } | ||
141 | |||
142 | |||
143 | static struct pxa2xx_udc_mach_info pxa_udc_info; | ||
144 | |||
145 | void __init pxa_set_udc_info(struct pxa2xx_udc_mach_info *info) | ||
146 | { | ||
147 | memcpy(&pxa_udc_info, info, sizeof *info); | ||
148 | } | ||
149 | |||
150 | static struct resource pxa2xx_udc_resources[] = { | ||
151 | [0] = { | ||
152 | .start = 0x40600000, | ||
153 | .end = 0x4060ffff, | ||
154 | .flags = IORESOURCE_MEM, | ||
155 | }, | ||
156 | [1] = { | ||
157 | .start = IRQ_USB, | ||
158 | .end = IRQ_USB, | ||
159 | .flags = IORESOURCE_IRQ, | ||
160 | }, | ||
161 | }; | ||
162 | |||
163 | static u64 udc_dma_mask = ~(u32)0; | ||
164 | |||
165 | static struct platform_device udc_device = { | ||
166 | .name = "pxa2xx-udc", | ||
167 | .id = -1, | ||
168 | .resource = pxa2xx_udc_resources, | ||
169 | .num_resources = ARRAY_SIZE(pxa2xx_udc_resources), | ||
170 | .dev = { | ||
171 | .platform_data = &pxa_udc_info, | ||
172 | .dma_mask = &udc_dma_mask, | ||
173 | } | ||
174 | }; | ||
175 | |||
176 | static struct pxafb_mach_info pxa_fb_info; | ||
177 | |||
178 | void __init set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info) | ||
179 | { | ||
180 | memcpy(&pxa_fb_info,hard_pxa_fb_info,sizeof(struct pxafb_mach_info)); | ||
181 | } | ||
182 | |||
183 | static struct resource pxafb_resources[] = { | ||
184 | [0] = { | ||
185 | .start = 0x44000000, | ||
186 | .end = 0x4400ffff, | ||
187 | .flags = IORESOURCE_MEM, | ||
188 | }, | ||
189 | [1] = { | ||
190 | .start = IRQ_LCD, | ||
191 | .end = IRQ_LCD, | ||
192 | .flags = IORESOURCE_IRQ, | ||
193 | }, | ||
194 | }; | ||
195 | |||
196 | static u64 fb_dma_mask = ~(u64)0; | ||
197 | |||
198 | static struct platform_device pxafb_device = { | ||
199 | .name = "pxa2xx-fb", | ||
200 | .id = -1, | ||
201 | .dev = { | ||
202 | .platform_data = &pxa_fb_info, | ||
203 | .dma_mask = &fb_dma_mask, | ||
204 | .coherent_dma_mask = 0xffffffff, | ||
205 | }, | ||
206 | .num_resources = ARRAY_SIZE(pxafb_resources), | ||
207 | .resource = pxafb_resources, | ||
208 | }; | ||
209 | |||
210 | static struct platform_device ffuart_device = { | ||
211 | .name = "pxa2xx-uart", | ||
212 | .id = 0, | ||
213 | }; | ||
214 | static struct platform_device btuart_device = { | ||
215 | .name = "pxa2xx-uart", | ||
216 | .id = 1, | ||
217 | }; | ||
218 | static struct platform_device stuart_device = { | ||
219 | .name = "pxa2xx-uart", | ||
220 | .id = 2, | ||
221 | }; | ||
222 | |||
223 | static struct platform_device *devices[] __initdata = { | ||
224 | &pxamci_device, | ||
225 | &udc_device, | ||
226 | &pxafb_device, | ||
227 | &ffuart_device, | ||
228 | &btuart_device, | ||
229 | &stuart_device, | ||
230 | }; | ||
231 | |||
232 | static int __init pxa_init(void) | ||
233 | { | ||
234 | return platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
235 | } | ||
236 | |||
237 | subsys_initcall(pxa_init); | ||
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h new file mode 100644 index 000000000000..e54a8dd63c17 --- /dev/null +++ b/arch/arm/mach-pxa/generic.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/generic.h | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Copyright: MontaVista Software Inc. | ||
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 | struct sys_timer; | ||
13 | |||
14 | extern struct sys_timer pxa_timer; | ||
15 | extern void __init pxa_map_io(void); | ||
16 | extern void __init pxa_init_irq(void); | ||
17 | |||
18 | extern unsigned int get_clk_frequency_khz(int info); | ||
19 | |||
20 | #define SET_BANK(__nr,__start,__size) \ | ||
21 | mi->bank[__nr].start = (__start), \ | ||
22 | mi->bank[__nr].size = (__size), \ | ||
23 | mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) | ||
24 | |||
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c new file mode 100644 index 000000000000..c5a66bf4d3d5 --- /dev/null +++ b/arch/arm/mach-pxa/idp.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/idp.c | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc. | ||
9 | * | ||
10 | * 2001-09-13: Cliff Brake <cbrake@accelent.com> | ||
11 | * Initial code | ||
12 | * | ||
13 | * 2005-02-15: Cliff Brake <cliff.brake@gmail.com> | ||
14 | * <http://www.vibren.com> <http://bec-systems.com> | ||
15 | * Updated for 2.6 kernel | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/fb.h> | ||
23 | |||
24 | #include <asm/setup.h> | ||
25 | #include <asm/memory.h> | ||
26 | #include <asm/mach-types.h> | ||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/irq.h> | ||
29 | |||
30 | #include <asm/mach/arch.h> | ||
31 | #include <asm/mach/map.h> | ||
32 | |||
33 | #include <asm/arch/pxa-regs.h> | ||
34 | #include <asm/arch/idp.h> | ||
35 | #include <asm/arch/pxafb.h> | ||
36 | #include <asm/arch/bitfield.h> | ||
37 | #include <asm/arch/mmc.h> | ||
38 | |||
39 | #include "generic.h" | ||
40 | |||
41 | /* TODO: | ||
42 | * - add pxa2xx_audio_ops_t device structure | ||
43 | * - Ethernet interrupt | ||
44 | */ | ||
45 | |||
46 | static struct resource smc91x_resources[] = { | ||
47 | [0] = { | ||
48 | .start = (IDP_ETH_PHYS + 0x300), | ||
49 | .end = (IDP_ETH_PHYS + 0xfffff), | ||
50 | .flags = IORESOURCE_MEM, | ||
51 | }, | ||
52 | [1] = { | ||
53 | .start = IRQ_GPIO(4), | ||
54 | .end = IRQ_GPIO(4), | ||
55 | .flags = IORESOURCE_IRQ, | ||
56 | } | ||
57 | }; | ||
58 | |||
59 | static struct platform_device smc91x_device = { | ||
60 | .name = "smc91x", | ||
61 | .id = 0, | ||
62 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
63 | .resource = smc91x_resources, | ||
64 | }; | ||
65 | |||
66 | static void idp_backlight_power(int on) | ||
67 | { | ||
68 | if (on) { | ||
69 | IDP_CPLD_LCD |= (1<<1); | ||
70 | } else { | ||
71 | IDP_CPLD_LCD &= ~(1<<1); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | static void idp_vlcd(int on) | ||
76 | { | ||
77 | if (on) { | ||
78 | IDP_CPLD_LCD |= (1<<2); | ||
79 | } else { | ||
80 | IDP_CPLD_LCD &= ~(1<<2); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | static void idp_lcd_power(int on) | ||
85 | { | ||
86 | if (on) { | ||
87 | IDP_CPLD_LCD |= (1<<0); | ||
88 | } else { | ||
89 | IDP_CPLD_LCD &= ~(1<<0); | ||
90 | } | ||
91 | |||
92 | /* call idp_vlcd for now as core driver does not support | ||
93 | * both power and vlcd hooks. Note, this is not technically | ||
94 | * the correct sequence, but seems to work. Disclaimer: | ||
95 | * this may eventually damage the display. | ||
96 | */ | ||
97 | |||
98 | idp_vlcd(on); | ||
99 | } | ||
100 | |||
101 | static struct pxafb_mach_info sharp_lm8v31 __initdata = { | ||
102 | .pixclock = 270000, | ||
103 | .xres = 640, | ||
104 | .yres = 480, | ||
105 | .bpp = 16, | ||
106 | .hsync_len = 1, | ||
107 | .left_margin = 3, | ||
108 | .right_margin = 3, | ||
109 | .vsync_len = 1, | ||
110 | .upper_margin = 0, | ||
111 | .lower_margin = 0, | ||
112 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
113 | .cmap_greyscale = 0, | ||
114 | .cmap_inverse = 0, | ||
115 | .cmap_static = 0, | ||
116 | .lccr0 = LCCR0_SDS, | ||
117 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), | ||
118 | .pxafb_backlight_power = &idp_backlight_power, | ||
119 | .pxafb_lcd_power = &idp_lcd_power | ||
120 | }; | ||
121 | |||
122 | static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *, struct pt_regs *), void *data) | ||
123 | { | ||
124 | /* setup GPIO for PXA25x MMC controller */ | ||
125 | pxa_gpio_mode(GPIO6_MMCCLK_MD); | ||
126 | pxa_gpio_mode(GPIO8_MMCCS0_MD); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static struct pxamci_platform_data idp_mci_platform_data = { | ||
132 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
133 | .init = idp_mci_init, | ||
134 | }; | ||
135 | |||
136 | static void __init idp_init(void) | ||
137 | { | ||
138 | printk("idp_init()\n"); | ||
139 | |||
140 | platform_device_register(&smc91x_device); | ||
141 | //platform_device_register(&mst_audio_device); | ||
142 | set_pxa_fb_info(&sharp_lm8v31); | ||
143 | pxa_set_mci_info(&idp_mci_platform_data); | ||
144 | } | ||
145 | |||
146 | static void __init idp_init_irq(void) | ||
147 | { | ||
148 | |||
149 | pxa_init_irq(); | ||
150 | |||
151 | set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE); | ||
152 | } | ||
153 | |||
154 | static struct map_desc idp_io_desc[] __initdata = { | ||
155 | /* virtual physical length type */ | ||
156 | |||
157 | { IDP_COREVOLT_VIRT, | ||
158 | IDP_COREVOLT_PHYS, | ||
159 | IDP_COREVOLT_SIZE, | ||
160 | MT_DEVICE }, | ||
161 | { IDP_CPLD_VIRT, | ||
162 | IDP_CPLD_PHYS, | ||
163 | IDP_CPLD_SIZE, | ||
164 | MT_DEVICE } | ||
165 | }; | ||
166 | |||
167 | static void __init idp_map_io(void) | ||
168 | { | ||
169 | pxa_map_io(); | ||
170 | iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc)); | ||
171 | |||
172 | // serial ports 2 & 3 | ||
173 | pxa_gpio_mode(GPIO42_BTRXD_MD); | ||
174 | pxa_gpio_mode(GPIO43_BTTXD_MD); | ||
175 | pxa_gpio_mode(GPIO44_BTCTS_MD); | ||
176 | pxa_gpio_mode(GPIO45_BTRTS_MD); | ||
177 | pxa_gpio_mode(GPIO46_STRXD_MD); | ||
178 | pxa_gpio_mode(GPIO47_STTXD_MD); | ||
179 | |||
180 | } | ||
181 | |||
182 | |||
183 | MACHINE_START(PXA_IDP, "Vibren PXA255 IDP") | ||
184 | MAINTAINER("Vibren Technologies") | ||
185 | BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) | ||
186 | MAPIO(idp_map_io) | ||
187 | INITIRQ(idp_init_irq) | ||
188 | .timer = &pxa_timer, | ||
189 | INIT_MACHINE(idp_init) | ||
190 | MACHINE_END | ||
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c new file mode 100644 index 000000000000..f3cac43124a5 --- /dev/null +++ b/arch/arm/mach-pxa/irq.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/irq.c | ||
3 | * | ||
4 | * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc. | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Jun 15, 2001 | ||
8 | * Copyright: MontaVista Software Inc. | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/ptrace.h> | ||
19 | |||
20 | #include <asm/hardware.h> | ||
21 | #include <asm/irq.h> | ||
22 | #include <asm/mach/irq.h> | ||
23 | #include <asm/arch/pxa-regs.h> | ||
24 | |||
25 | #include "generic.h" | ||
26 | |||
27 | |||
28 | /* | ||
29 | * This is for peripheral IRQs internal to the PXA chip. | ||
30 | */ | ||
31 | |||
32 | static void pxa_mask_low_irq(unsigned int irq) | ||
33 | { | ||
34 | ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); | ||
35 | } | ||
36 | |||
37 | static void pxa_unmask_low_irq(unsigned int irq) | ||
38 | { | ||
39 | ICMR |= (1 << (irq + PXA_IRQ_SKIP)); | ||
40 | } | ||
41 | |||
42 | static struct irqchip pxa_internal_chip_low = { | ||
43 | .ack = pxa_mask_low_irq, | ||
44 | .mask = pxa_mask_low_irq, | ||
45 | .unmask = pxa_unmask_low_irq, | ||
46 | }; | ||
47 | |||
48 | #if PXA_INTERNAL_IRQS > 32 | ||
49 | |||
50 | /* | ||
51 | * This is for the second set of internal IRQs as found on the PXA27x. | ||
52 | */ | ||
53 | |||
54 | static void pxa_mask_high_irq(unsigned int irq) | ||
55 | { | ||
56 | ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); | ||
57 | } | ||
58 | |||
59 | static void pxa_unmask_high_irq(unsigned int irq) | ||
60 | { | ||
61 | ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); | ||
62 | } | ||
63 | |||
64 | static struct irqchip pxa_internal_chip_high = { | ||
65 | .ack = pxa_mask_high_irq, | ||
66 | .mask = pxa_mask_high_irq, | ||
67 | .unmask = pxa_unmask_high_irq, | ||
68 | }; | ||
69 | |||
70 | #endif | ||
71 | |||
72 | /* | ||
73 | * PXA GPIO edge detection for IRQs: | ||
74 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. | ||
75 | * Use this instead of directly setting GRER/GFER. | ||
76 | */ | ||
77 | |||
78 | static long GPIO_IRQ_rising_edge[4]; | ||
79 | static long GPIO_IRQ_falling_edge[4]; | ||
80 | static long GPIO_IRQ_mask[4]; | ||
81 | |||
82 | static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) | ||
83 | { | ||
84 | int gpio, idx; | ||
85 | |||
86 | gpio = IRQ_TO_GPIO(irq); | ||
87 | idx = gpio >> 5; | ||
88 | |||
89 | if (type == IRQT_PROBE) { | ||
90 | /* Don't mess with enabled GPIOs using preconfigured edges or | ||
91 | GPIOs set to alternate function during probe */ | ||
92 | if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & | ||
93 | GPIO_bit(gpio)) | ||
94 | return 0; | ||
95 | if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) | ||
96 | return 0; | ||
97 | type = __IRQT_RISEDGE | __IRQT_FALEDGE; | ||
98 | } | ||
99 | |||
100 | /* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */ | ||
101 | |||
102 | pxa_gpio_mode(gpio | GPIO_IN); | ||
103 | |||
104 | if (type & __IRQT_RISEDGE) { | ||
105 | /* printk("rising "); */ | ||
106 | __set_bit (gpio, GPIO_IRQ_rising_edge); | ||
107 | } else | ||
108 | __clear_bit (gpio, GPIO_IRQ_rising_edge); | ||
109 | |||
110 | if (type & __IRQT_FALEDGE) { | ||
111 | /* printk("falling "); */ | ||
112 | __set_bit (gpio, GPIO_IRQ_falling_edge); | ||
113 | } else | ||
114 | __clear_bit (gpio, GPIO_IRQ_falling_edge); | ||
115 | |||
116 | /* printk("edges\n"); */ | ||
117 | |||
118 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | ||
119 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * GPIO IRQs must be acknowledged. This is for GPIO 0 and 1. | ||
125 | */ | ||
126 | |||
127 | static void pxa_ack_low_gpio(unsigned int irq) | ||
128 | { | ||
129 | GEDR0 = (1 << (irq - IRQ_GPIO0)); | ||
130 | } | ||
131 | |||
132 | static struct irqchip pxa_low_gpio_chip = { | ||
133 | .ack = pxa_ack_low_gpio, | ||
134 | .mask = pxa_mask_low_irq, | ||
135 | .unmask = pxa_unmask_low_irq, | ||
136 | .type = pxa_gpio_irq_type, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Demux handler for GPIO>=2 edge detect interrupts | ||
141 | */ | ||
142 | |||
143 | static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, | ||
144 | struct pt_regs *regs) | ||
145 | { | ||
146 | unsigned int mask; | ||
147 | int loop; | ||
148 | |||
149 | do { | ||
150 | loop = 0; | ||
151 | |||
152 | mask = GEDR0 & ~3; | ||
153 | if (mask) { | ||
154 | GEDR0 = mask; | ||
155 | irq = IRQ_GPIO(2); | ||
156 | desc = irq_desc + irq; | ||
157 | mask >>= 2; | ||
158 | do { | ||
159 | if (mask & 1) | ||
160 | desc->handle(irq, desc, regs); | ||
161 | irq++; | ||
162 | desc++; | ||
163 | mask >>= 1; | ||
164 | } while (mask); | ||
165 | loop = 1; | ||
166 | } | ||
167 | |||
168 | mask = GEDR1; | ||
169 | if (mask) { | ||
170 | GEDR1 = mask; | ||
171 | irq = IRQ_GPIO(32); | ||
172 | desc = irq_desc + irq; | ||
173 | do { | ||
174 | if (mask & 1) | ||
175 | desc->handle(irq, desc, regs); | ||
176 | irq++; | ||
177 | desc++; | ||
178 | mask >>= 1; | ||
179 | } while (mask); | ||
180 | loop = 1; | ||
181 | } | ||
182 | |||
183 | mask = GEDR2; | ||
184 | if (mask) { | ||
185 | GEDR2 = mask; | ||
186 | irq = IRQ_GPIO(64); | ||
187 | desc = irq_desc + irq; | ||
188 | do { | ||
189 | if (mask & 1) | ||
190 | desc->handle(irq, desc, regs); | ||
191 | irq++; | ||
192 | desc++; | ||
193 | mask >>= 1; | ||
194 | } while (mask); | ||
195 | loop = 1; | ||
196 | } | ||
197 | |||
198 | #if PXA_LAST_GPIO >= 96 | ||
199 | mask = GEDR3; | ||
200 | if (mask) { | ||
201 | GEDR3 = mask; | ||
202 | irq = IRQ_GPIO(96); | ||
203 | desc = irq_desc + irq; | ||
204 | do { | ||
205 | if (mask & 1) | ||
206 | desc->handle(irq, desc, regs); | ||
207 | irq++; | ||
208 | desc++; | ||
209 | mask >>= 1; | ||
210 | } while (mask); | ||
211 | loop = 1; | ||
212 | } | ||
213 | #endif | ||
214 | } while (loop); | ||
215 | } | ||
216 | |||
217 | static void pxa_ack_muxed_gpio(unsigned int irq) | ||
218 | { | ||
219 | int gpio = irq - IRQ_GPIO(2) + 2; | ||
220 | GEDR(gpio) = GPIO_bit(gpio); | ||
221 | } | ||
222 | |||
223 | static void pxa_mask_muxed_gpio(unsigned int irq) | ||
224 | { | ||
225 | int gpio = irq - IRQ_GPIO(2) + 2; | ||
226 | __clear_bit(gpio, GPIO_IRQ_mask); | ||
227 | GRER(gpio) &= ~GPIO_bit(gpio); | ||
228 | GFER(gpio) &= ~GPIO_bit(gpio); | ||
229 | } | ||
230 | |||
231 | static void pxa_unmask_muxed_gpio(unsigned int irq) | ||
232 | { | ||
233 | int gpio = irq - IRQ_GPIO(2) + 2; | ||
234 | int idx = gpio >> 5; | ||
235 | __set_bit(gpio, GPIO_IRQ_mask); | ||
236 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | ||
237 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | ||
238 | } | ||
239 | |||
240 | static struct irqchip pxa_muxed_gpio_chip = { | ||
241 | .ack = pxa_ack_muxed_gpio, | ||
242 | .mask = pxa_mask_muxed_gpio, | ||
243 | .unmask = pxa_unmask_muxed_gpio, | ||
244 | .type = pxa_gpio_irq_type, | ||
245 | }; | ||
246 | |||
247 | |||
248 | void __init pxa_init_irq(void) | ||
249 | { | ||
250 | int irq; | ||
251 | |||
252 | /* disable all IRQs */ | ||
253 | ICMR = 0; | ||
254 | |||
255 | /* all IRQs are IRQ, not FIQ */ | ||
256 | ICLR = 0; | ||
257 | |||
258 | /* clear all GPIO edge detects */ | ||
259 | GFER0 = 0; | ||
260 | GFER1 = 0; | ||
261 | GFER2 = 0; | ||
262 | GRER0 = 0; | ||
263 | GRER1 = 0; | ||
264 | GRER2 = 0; | ||
265 | GEDR0 = GEDR0; | ||
266 | GEDR1 = GEDR1; | ||
267 | GEDR2 = GEDR2; | ||
268 | |||
269 | #ifdef CONFIG_PXA27x | ||
270 | /* And similarly for the extra regs on the PXA27x */ | ||
271 | ICMR2 = 0; | ||
272 | ICLR2 = 0; | ||
273 | GFER3 = 0; | ||
274 | GRER3 = 0; | ||
275 | GEDR3 = GEDR3; | ||
276 | #endif | ||
277 | |||
278 | /* only unmasked interrupts kick us out of idle */ | ||
279 | ICCR = 1; | ||
280 | |||
281 | /* GPIO 0 and 1 must have their mask bit always set */ | ||
282 | GPIO_IRQ_mask[0] = 3; | ||
283 | |||
284 | for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { | ||
285 | set_irq_chip(irq, &pxa_internal_chip_low); | ||
286 | set_irq_handler(irq, do_level_IRQ); | ||
287 | set_irq_flags(irq, IRQF_VALID); | ||
288 | } | ||
289 | |||
290 | #if PXA_INTERNAL_IRQS > 32 | ||
291 | for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { | ||
292 | set_irq_chip(irq, &pxa_internal_chip_high); | ||
293 | set_irq_handler(irq, do_level_IRQ); | ||
294 | set_irq_flags(irq, IRQF_VALID); | ||
295 | } | ||
296 | #endif | ||
297 | |||
298 | for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { | ||
299 | set_irq_chip(irq, &pxa_low_gpio_chip); | ||
300 | set_irq_handler(irq, do_edge_IRQ); | ||
301 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
302 | } | ||
303 | |||
304 | for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { | ||
305 | set_irq_chip(irq, &pxa_muxed_gpio_chip); | ||
306 | set_irq_handler(irq, do_edge_IRQ); | ||
307 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
308 | } | ||
309 | |||
310 | /* Install handler for GPIO>=2 edge detect interrupts */ | ||
311 | set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); | ||
312 | set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); | ||
313 | } | ||
diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c new file mode 100644 index 000000000000..5eba6ea0b0f7 --- /dev/null +++ b/arch/arm/mach-pxa/leds-idp.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/leds-idp.c | ||
3 | * | ||
4 | * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> | ||
5 | * | ||
6 | * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> | ||
7 | * | ||
8 | * Original (leds-footbridge.c) by Russell King | ||
9 | * | ||
10 | * Macros for actual LED manipulation should be in machine specific | ||
11 | * files in this 'mach' directory. | ||
12 | */ | ||
13 | |||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/init.h> | ||
17 | |||
18 | #include <asm/hardware.h> | ||
19 | #include <asm/leds.h> | ||
20 | #include <asm/system.h> | ||
21 | |||
22 | #include <asm/arch/pxa-regs.h> | ||
23 | #include <asm/arch/idp.h> | ||
24 | |||
25 | #include "leds.h" | ||
26 | |||
27 | #define LED_STATE_ENABLED 1 | ||
28 | #define LED_STATE_CLAIMED 2 | ||
29 | |||
30 | static unsigned int led_state; | ||
31 | static unsigned int hw_led_state; | ||
32 | |||
33 | void idp_leds_event(led_event_t evt) | ||
34 | { | ||
35 | unsigned long flags; | ||
36 | |||
37 | local_irq_save(flags); | ||
38 | |||
39 | switch (evt) { | ||
40 | case led_start: | ||
41 | hw_led_state = IDP_HB_LED | IDP_BUSY_LED; | ||
42 | led_state = LED_STATE_ENABLED; | ||
43 | break; | ||
44 | |||
45 | case led_stop: | ||
46 | led_state &= ~LED_STATE_ENABLED; | ||
47 | break; | ||
48 | |||
49 | case led_claim: | ||
50 | led_state |= LED_STATE_CLAIMED; | ||
51 | hw_led_state = IDP_HB_LED | IDP_BUSY_LED; | ||
52 | break; | ||
53 | |||
54 | case led_release: | ||
55 | led_state &= ~LED_STATE_CLAIMED; | ||
56 | hw_led_state = IDP_HB_LED | IDP_BUSY_LED; | ||
57 | break; | ||
58 | |||
59 | #ifdef CONFIG_LEDS_TIMER | ||
60 | case led_timer: | ||
61 | if (!(led_state & LED_STATE_CLAIMED)) | ||
62 | hw_led_state ^= IDP_HB_LED; | ||
63 | break; | ||
64 | #endif | ||
65 | |||
66 | #ifdef CONFIG_LEDS_CPU | ||
67 | case led_idle_start: | ||
68 | if (!(led_state & LED_STATE_CLAIMED)) | ||
69 | hw_led_state &= ~IDP_BUSY_LED; | ||
70 | break; | ||
71 | |||
72 | case led_idle_end: | ||
73 | if (!(led_state & LED_STATE_CLAIMED)) | ||
74 | hw_led_state |= IDP_BUSY_LED; | ||
75 | break; | ||
76 | #endif | ||
77 | |||
78 | case led_halted: | ||
79 | break; | ||
80 | |||
81 | case led_green_on: | ||
82 | if (led_state & LED_STATE_CLAIMED) | ||
83 | hw_led_state |= IDP_HB_LED; | ||
84 | break; | ||
85 | |||
86 | case led_green_off: | ||
87 | if (led_state & LED_STATE_CLAIMED) | ||
88 | hw_led_state &= ~IDP_HB_LED; | ||
89 | break; | ||
90 | |||
91 | case led_amber_on: | ||
92 | break; | ||
93 | |||
94 | case led_amber_off: | ||
95 | break; | ||
96 | |||
97 | case led_red_on: | ||
98 | if (led_state & LED_STATE_CLAIMED) | ||
99 | hw_led_state |= IDP_BUSY_LED; | ||
100 | break; | ||
101 | |||
102 | case led_red_off: | ||
103 | if (led_state & LED_STATE_CLAIMED) | ||
104 | hw_led_state &= ~IDP_BUSY_LED; | ||
105 | break; | ||
106 | |||
107 | default: | ||
108 | break; | ||
109 | } | ||
110 | |||
111 | if (led_state & LED_STATE_ENABLED) | ||
112 | IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state); | ||
113 | else | ||
114 | IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK; | ||
115 | |||
116 | local_irq_restore(flags); | ||
117 | } | ||
diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c new file mode 100644 index 000000000000..05cf56059a0f --- /dev/null +++ b/arch/arm/mach-pxa/leds-lubbock.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/leds-lubbock.c | ||
3 | * | ||
4 | * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> | ||
5 | * | ||
6 | * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> | ||
7 | * | ||
8 | * Original (leds-footbridge.c) by Russell King | ||
9 | * | ||
10 | * Major surgery on April 2004 by Nicolas Pitre for less global | ||
11 | * namespace collision. Mostly adapted the Mainstone version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | |||
17 | #include <asm/hardware.h> | ||
18 | #include <asm/leds.h> | ||
19 | #include <asm/system.h> | ||
20 | #include <asm/arch/pxa-regs.h> | ||
21 | #include <asm/arch/lubbock.h> | ||
22 | |||
23 | #include "leds.h" | ||
24 | |||
25 | /* | ||
26 | * 8 discrete leds available for general use: | ||
27 | * | ||
28 | * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays | ||
29 | * so be sure to not monkey with them here. | ||
30 | */ | ||
31 | |||
32 | #define D28 (1 << 0) | ||
33 | #define D27 (1 << 1) | ||
34 | #define D26 (1 << 2) | ||
35 | #define D25 (1 << 3) | ||
36 | #define D24 (1 << 4) | ||
37 | #define D23 (1 << 5) | ||
38 | #define D22 (1 << 6) | ||
39 | #define D21 (1 << 7) | ||
40 | |||
41 | #define LED_STATE_ENABLED 1 | ||
42 | #define LED_STATE_CLAIMED 2 | ||
43 | |||
44 | static unsigned int led_state; | ||
45 | static unsigned int hw_led_state; | ||
46 | |||
47 | void lubbock_leds_event(led_event_t evt) | ||
48 | { | ||
49 | unsigned long flags; | ||
50 | |||
51 | local_irq_save(flags); | ||
52 | |||
53 | switch (evt) { | ||
54 | case led_start: | ||
55 | hw_led_state = 0; | ||
56 | led_state = LED_STATE_ENABLED; | ||
57 | break; | ||
58 | |||
59 | case led_stop: | ||
60 | led_state &= ~LED_STATE_ENABLED; | ||
61 | break; | ||
62 | |||
63 | case led_claim: | ||
64 | led_state |= LED_STATE_CLAIMED; | ||
65 | hw_led_state = 0; | ||
66 | break; | ||
67 | |||
68 | case led_release: | ||
69 | led_state &= ~LED_STATE_CLAIMED; | ||
70 | hw_led_state = 0; | ||
71 | break; | ||
72 | |||
73 | #ifdef CONFIG_LEDS_TIMER | ||
74 | case led_timer: | ||
75 | hw_led_state ^= D26; | ||
76 | break; | ||
77 | #endif | ||
78 | |||
79 | #ifdef CONFIG_LEDS_CPU | ||
80 | case led_idle_start: | ||
81 | hw_led_state &= ~D27; | ||
82 | break; | ||
83 | |||
84 | case led_idle_end: | ||
85 | hw_led_state |= D27; | ||
86 | break; | ||
87 | #endif | ||
88 | |||
89 | case led_halted: | ||
90 | break; | ||
91 | |||
92 | case led_green_on: | ||
93 | hw_led_state |= D21; | ||
94 | break; | ||
95 | |||
96 | case led_green_off: | ||
97 | hw_led_state &= ~D21; | ||
98 | break; | ||
99 | |||
100 | case led_amber_on: | ||
101 | hw_led_state |= D22; | ||
102 | break; | ||
103 | |||
104 | case led_amber_off: | ||
105 | hw_led_state &= ~D22; | ||
106 | break; | ||
107 | |||
108 | case led_red_on: | ||
109 | hw_led_state |= D23; | ||
110 | break; | ||
111 | |||
112 | case led_red_off: | ||
113 | hw_led_state &= ~D23; | ||
114 | break; | ||
115 | |||
116 | default: | ||
117 | break; | ||
118 | } | ||
119 | |||
120 | if (led_state & LED_STATE_ENABLED) | ||
121 | LUB_DISC_BLNK_LED = (LUB_DISC_BLNK_LED | 0xff) & ~hw_led_state; | ||
122 | else | ||
123 | LUB_DISC_BLNK_LED |= 0xff; | ||
124 | |||
125 | local_irq_restore(flags); | ||
126 | } | ||
diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c new file mode 100644 index 000000000000..bbd3f87a9fc2 --- /dev/null +++ b/arch/arm/mach-pxa/leds-mainstone.c | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/leds-mainstone.c | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Nov 05, 2002 | ||
6 | * Copyright: MontaVista Software Inc. | ||
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 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | |||
16 | #include <asm/hardware.h> | ||
17 | #include <asm/leds.h> | ||
18 | #include <asm/system.h> | ||
19 | |||
20 | #include <asm/arch/pxa-regs.h> | ||
21 | #include <asm/arch/mainstone.h> | ||
22 | |||
23 | #include "leds.h" | ||
24 | |||
25 | |||
26 | /* 8 discrete leds available for general use: */ | ||
27 | #define D28 (1 << 0) | ||
28 | #define D27 (1 << 1) | ||
29 | #define D26 (1 << 2) | ||
30 | #define D25 (1 << 3) | ||
31 | #define D24 (1 << 4) | ||
32 | #define D23 (1 << 5) | ||
33 | #define D22 (1 << 6) | ||
34 | #define D21 (1 << 7) | ||
35 | |||
36 | #define LED_STATE_ENABLED 1 | ||
37 | #define LED_STATE_CLAIMED 2 | ||
38 | |||
39 | static unsigned int led_state; | ||
40 | static unsigned int hw_led_state; | ||
41 | |||
42 | void mainstone_leds_event(led_event_t evt) | ||
43 | { | ||
44 | unsigned long flags; | ||
45 | |||
46 | local_irq_save(flags); | ||
47 | |||
48 | switch (evt) { | ||
49 | case led_start: | ||
50 | hw_led_state = 0; | ||
51 | led_state = LED_STATE_ENABLED; | ||
52 | break; | ||
53 | |||
54 | case led_stop: | ||
55 | led_state &= ~LED_STATE_ENABLED; | ||
56 | break; | ||
57 | |||
58 | case led_claim: | ||
59 | led_state |= LED_STATE_CLAIMED; | ||
60 | hw_led_state = 0; | ||
61 | break; | ||
62 | |||
63 | case led_release: | ||
64 | led_state &= ~LED_STATE_CLAIMED; | ||
65 | hw_led_state = 0; | ||
66 | break; | ||
67 | |||
68 | #ifdef CONFIG_LEDS_TIMER | ||
69 | case led_timer: | ||
70 | hw_led_state ^= D26; | ||
71 | break; | ||
72 | #endif | ||
73 | |||
74 | #ifdef CONFIG_LEDS_CPU | ||
75 | case led_idle_start: | ||
76 | hw_led_state &= ~D27; | ||
77 | break; | ||
78 | |||
79 | case led_idle_end: | ||
80 | hw_led_state |= D27; | ||
81 | break; | ||
82 | #endif | ||
83 | |||
84 | case led_halted: | ||
85 | break; | ||
86 | |||
87 | case led_green_on: | ||
88 | hw_led_state |= D21;; | ||
89 | break; | ||
90 | |||
91 | case led_green_off: | ||
92 | hw_led_state &= ~D21; | ||
93 | break; | ||
94 | |||
95 | case led_amber_on: | ||
96 | hw_led_state |= D22;; | ||
97 | break; | ||
98 | |||
99 | case led_amber_off: | ||
100 | hw_led_state &= ~D22; | ||
101 | break; | ||
102 | |||
103 | case led_red_on: | ||
104 | hw_led_state |= D23;; | ||
105 | break; | ||
106 | |||
107 | case led_red_off: | ||
108 | hw_led_state &= ~D23; | ||
109 | break; | ||
110 | |||
111 | default: | ||
112 | break; | ||
113 | } | ||
114 | |||
115 | if (led_state & LED_STATE_ENABLED) | ||
116 | MST_LEDCTRL = (MST_LEDCTRL | 0xff) & ~hw_led_state; | ||
117 | else | ||
118 | MST_LEDCTRL |= 0xff; | ||
119 | |||
120 | local_irq_restore(flags); | ||
121 | } | ||
diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c new file mode 100644 index 000000000000..bbe4d5f6afaa --- /dev/null +++ b/arch/arm/mach-pxa/leds.c | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/leds.c | ||
3 | * | ||
4 | * xscale LEDs dispatcher | ||
5 | * | ||
6 | * Copyright (C) 2001 Nicolas Pitre | ||
7 | * | ||
8 | * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. | ||
9 | */ | ||
10 | #include <linux/compiler.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <asm/leds.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | |||
16 | #include "leds.h" | ||
17 | |||
18 | static int __init | ||
19 | pxa_leds_init(void) | ||
20 | { | ||
21 | if (machine_is_lubbock()) | ||
22 | leds_event = lubbock_leds_event; | ||
23 | if (machine_is_mainstone()) | ||
24 | leds_event = mainstone_leds_event; | ||
25 | if (machine_is_pxa_idp()) | ||
26 | leds_event = idp_leds_event; | ||
27 | |||
28 | leds_event(led_start); | ||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | core_initcall(pxa_leds_init); | ||
diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h new file mode 100644 index 000000000000..d98f6e93c12b --- /dev/null +++ b/arch/arm/mach-pxa/leds.h | |||
@@ -0,0 +1,12 @@ | |||
1 | /* | ||
2 | * include/asm-arm/arch-pxa/leds.h | ||
3 | * | ||
4 | * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. | ||
5 | * | ||
6 | * blinky lights for various PXA-based systems: | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | extern void idp_leds_event(led_event_t evt); | ||
11 | extern void lubbock_leds_event(led_event_t evt); | ||
12 | extern void mainstone_leds_event(led_event_t evt); | ||
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c new file mode 100644 index 000000000000..dd012d6e2f5c --- /dev/null +++ b/arch/arm/mach-pxa/lubbock.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/lubbock.c | ||
3 | * | ||
4 | * Support for the Intel DBPXA250 Development Platform. | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Jun 15, 2001 | ||
8 | * Copyright: MontaVista Software Inc. | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/major.h> | ||
19 | #include <linux/fb.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | |||
22 | #include <asm/setup.h> | ||
23 | #include <asm/memory.h> | ||
24 | #include <asm/mach-types.h> | ||
25 | #include <asm/hardware.h> | ||
26 | #include <asm/irq.h> | ||
27 | |||
28 | #include <asm/mach/arch.h> | ||
29 | #include <asm/mach/map.h> | ||
30 | #include <asm/mach/irq.h> | ||
31 | |||
32 | #include <asm/hardware/sa1111.h> | ||
33 | |||
34 | #include <asm/arch/pxa-regs.h> | ||
35 | #include <asm/arch/lubbock.h> | ||
36 | #include <asm/arch/udc.h> | ||
37 | #include <asm/arch/pxafb.h> | ||
38 | #include <asm/arch/mmc.h> | ||
39 | |||
40 | #include "generic.h" | ||
41 | |||
42 | |||
43 | #define LUB_MISC_WR __LUB_REG(LUBBOCK_FPGA_PHYS + 0x080) | ||
44 | |||
45 | void lubbock_set_misc_wr(unsigned int mask, unsigned int set) | ||
46 | { | ||
47 | unsigned long flags; | ||
48 | |||
49 | local_irq_save(flags); | ||
50 | LUB_MISC_WR = (LUB_MISC_WR & ~mask) | (set & mask); | ||
51 | local_irq_restore(flags); | ||
52 | } | ||
53 | EXPORT_SYMBOL(lubbock_set_misc_wr); | ||
54 | |||
55 | static unsigned long lubbock_irq_enabled; | ||
56 | |||
57 | static void lubbock_mask_irq(unsigned int irq) | ||
58 | { | ||
59 | int lubbock_irq = (irq - LUBBOCK_IRQ(0)); | ||
60 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq)); | ||
61 | } | ||
62 | |||
63 | static void lubbock_unmask_irq(unsigned int irq) | ||
64 | { | ||
65 | int lubbock_irq = (irq - LUBBOCK_IRQ(0)); | ||
66 | /* the irq can be acknowledged only if deasserted, so it's done here */ | ||
67 | LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq); | ||
68 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq)); | ||
69 | } | ||
70 | |||
71 | static struct irqchip lubbock_irq_chip = { | ||
72 | .ack = lubbock_mask_irq, | ||
73 | .mask = lubbock_mask_irq, | ||
74 | .unmask = lubbock_unmask_irq, | ||
75 | }; | ||
76 | |||
77 | static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc, | ||
78 | struct pt_regs *regs) | ||
79 | { | ||
80 | unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; | ||
81 | do { | ||
82 | GEDR(0) = GPIO_bit(0); /* clear our parent irq */ | ||
83 | if (likely(pending)) { | ||
84 | irq = LUBBOCK_IRQ(0) + __ffs(pending); | ||
85 | desc = irq_desc + irq; | ||
86 | desc->handle(irq, desc, regs); | ||
87 | } | ||
88 | pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; | ||
89 | } while (pending); | ||
90 | } | ||
91 | |||
92 | static void __init lubbock_init_irq(void) | ||
93 | { | ||
94 | int irq; | ||
95 | |||
96 | pxa_init_irq(); | ||
97 | |||
98 | /* setup extra lubbock irqs */ | ||
99 | for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { | ||
100 | set_irq_chip(irq, &lubbock_irq_chip); | ||
101 | set_irq_handler(irq, do_level_IRQ); | ||
102 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
103 | } | ||
104 | |||
105 | set_irq_chained_handler(IRQ_GPIO(0), lubbock_irq_handler); | ||
106 | set_irq_type(IRQ_GPIO(0), IRQT_FALLING); | ||
107 | } | ||
108 | |||
109 | static int lubbock_udc_is_connected(void) | ||
110 | { | ||
111 | return (LUB_MISC_RD & (1 << 9)) == 0; | ||
112 | } | ||
113 | |||
114 | static struct pxa2xx_udc_mach_info udc_info __initdata = { | ||
115 | .udc_is_connected = lubbock_udc_is_connected, | ||
116 | // no D+ pullup; lubbock can't connect/disconnect in software | ||
117 | }; | ||
118 | |||
119 | static struct resource sa1111_resources[] = { | ||
120 | [0] = { | ||
121 | .start = 0x10000000, | ||
122 | .end = 0x10001fff, | ||
123 | .flags = IORESOURCE_MEM, | ||
124 | }, | ||
125 | [1] = { | ||
126 | .start = LUBBOCK_SA1111_IRQ, | ||
127 | .end = LUBBOCK_SA1111_IRQ, | ||
128 | .flags = IORESOURCE_IRQ, | ||
129 | }, | ||
130 | }; | ||
131 | |||
132 | static struct platform_device sa1111_device = { | ||
133 | .name = "sa1111", | ||
134 | .id = -1, | ||
135 | .num_resources = ARRAY_SIZE(sa1111_resources), | ||
136 | .resource = sa1111_resources, | ||
137 | }; | ||
138 | |||
139 | static struct resource smc91x_resources[] = { | ||
140 | [0] = { | ||
141 | .name = "smc91x-regs", | ||
142 | .start = 0x0c000000, | ||
143 | .end = 0x0c0fffff, | ||
144 | .flags = IORESOURCE_MEM, | ||
145 | }, | ||
146 | [1] = { | ||
147 | .start = LUBBOCK_ETH_IRQ, | ||
148 | .end = LUBBOCK_ETH_IRQ, | ||
149 | .flags = IORESOURCE_IRQ, | ||
150 | }, | ||
151 | [2] = { | ||
152 | .name = "smc91x-attrib", | ||
153 | .start = 0x0e000000, | ||
154 | .end = 0x0e0fffff, | ||
155 | .flags = IORESOURCE_MEM, | ||
156 | }, | ||
157 | }; | ||
158 | |||
159 | static struct platform_device smc91x_device = { | ||
160 | .name = "smc91x", | ||
161 | .id = -1, | ||
162 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
163 | .resource = smc91x_resources, | ||
164 | }; | ||
165 | |||
166 | static struct platform_device *devices[] __initdata = { | ||
167 | &sa1111_device, | ||
168 | &smc91x_device, | ||
169 | }; | ||
170 | |||
171 | static struct pxafb_mach_info sharp_lm8v31 __initdata = { | ||
172 | .pixclock = 270000, | ||
173 | .xres = 640, | ||
174 | .yres = 480, | ||
175 | .bpp = 16, | ||
176 | .hsync_len = 1, | ||
177 | .left_margin = 3, | ||
178 | .right_margin = 3, | ||
179 | .vsync_len = 1, | ||
180 | .upper_margin = 0, | ||
181 | .lower_margin = 0, | ||
182 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
183 | .cmap_greyscale = 0, | ||
184 | .cmap_inverse = 0, | ||
185 | .cmap_static = 0, | ||
186 | .lccr0 = LCCR0_SDS, | ||
187 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), | ||
188 | }; | ||
189 | |||
190 | static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data) | ||
191 | { | ||
192 | /* setup GPIO for PXA25x MMC controller */ | ||
193 | pxa_gpio_mode(GPIO6_MMCCLK_MD); | ||
194 | pxa_gpio_mode(GPIO8_MMCCS0_MD); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static struct pxamci_platform_data lubbock_mci_platform_data = { | ||
200 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
201 | .init = lubbock_mci_init, | ||
202 | }; | ||
203 | |||
204 | static void __init lubbock_init(void) | ||
205 | { | ||
206 | pxa_set_udc_info(&udc_info); | ||
207 | set_pxa_fb_info(&sharp_lm8v31); | ||
208 | pxa_set_mci_info(&lubbock_mci_platform_data); | ||
209 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
210 | } | ||
211 | |||
212 | static struct map_desc lubbock_io_desc[] __initdata = { | ||
213 | { LUBBOCK_FPGA_VIRT, LUBBOCK_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ | ||
214 | }; | ||
215 | |||
216 | static void __init lubbock_map_io(void) | ||
217 | { | ||
218 | pxa_map_io(); | ||
219 | iotable_init(lubbock_io_desc, ARRAY_SIZE(lubbock_io_desc)); | ||
220 | |||
221 | /* This enables the BTUART */ | ||
222 | pxa_gpio_mode(GPIO42_BTRXD_MD); | ||
223 | pxa_gpio_mode(GPIO43_BTTXD_MD); | ||
224 | pxa_gpio_mode(GPIO44_BTCTS_MD); | ||
225 | pxa_gpio_mode(GPIO45_BTRTS_MD); | ||
226 | |||
227 | /* This is for the SMC chip select */ | ||
228 | pxa_gpio_mode(GPIO79_nCS_3_MD); | ||
229 | |||
230 | /* setup sleep mode values */ | ||
231 | PWER = 0x00000002; | ||
232 | PFER = 0x00000000; | ||
233 | PRER = 0x00000002; | ||
234 | PGSR0 = 0x00008000; | ||
235 | PGSR1 = 0x003F0202; | ||
236 | PGSR2 = 0x0001C000; | ||
237 | PCFR |= PCFR_OPDE; | ||
238 | } | ||
239 | |||
240 | MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") | ||
241 | MAINTAINER("MontaVista Software Inc.") | ||
242 | BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) | ||
243 | MAPIO(lubbock_map_io) | ||
244 | INITIRQ(lubbock_init_irq) | ||
245 | .timer = &pxa_timer, | ||
246 | INIT_MACHINE(lubbock_init) | ||
247 | MACHINE_END | ||
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c new file mode 100644 index 000000000000..3f952237ae3d --- /dev/null +++ b/arch/arm/mach-pxa/mainstone.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/mainstone.c | ||
3 | * | ||
4 | * Support for the Intel HCDDBBVA0 Development Platform. | ||
5 | * (go figure how they came up with such name...) | ||
6 | * | ||
7 | * Author: Nicolas Pitre | ||
8 | * Created: Nov 05, 2002 | ||
9 | * Copyright: MontaVista Software Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/bitops.h> | ||
21 | #include <linux/fb.h> | ||
22 | |||
23 | #include <asm/types.h> | ||
24 | #include <asm/setup.h> | ||
25 | #include <asm/memory.h> | ||
26 | #include <asm/mach-types.h> | ||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/irq.h> | ||
29 | |||
30 | #include <asm/mach/arch.h> | ||
31 | #include <asm/mach/map.h> | ||
32 | #include <asm/mach/irq.h> | ||
33 | |||
34 | #include <asm/arch/pxa-regs.h> | ||
35 | #include <asm/arch/mainstone.h> | ||
36 | #include <asm/arch/audio.h> | ||
37 | #include <asm/arch/pxafb.h> | ||
38 | #include <asm/arch/mmc.h> | ||
39 | |||
40 | #include "generic.h" | ||
41 | |||
42 | |||
43 | static unsigned long mainstone_irq_enabled; | ||
44 | |||
45 | static void mainstone_mask_irq(unsigned int irq) | ||
46 | { | ||
47 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); | ||
48 | MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq)); | ||
49 | } | ||
50 | |||
51 | static void mainstone_unmask_irq(unsigned int irq) | ||
52 | { | ||
53 | int mainstone_irq = (irq - MAINSTONE_IRQ(0)); | ||
54 | /* the irq can be acknowledged only if deasserted, so it's done here */ | ||
55 | MST_INTSETCLR &= ~(1 << mainstone_irq); | ||
56 | MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq)); | ||
57 | } | ||
58 | |||
59 | static struct irqchip mainstone_irq_chip = { | ||
60 | .ack = mainstone_mask_irq, | ||
61 | .mask = mainstone_mask_irq, | ||
62 | .unmask = mainstone_unmask_irq, | ||
63 | }; | ||
64 | |||
65 | |||
66 | static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc, | ||
67 | struct pt_regs *regs) | ||
68 | { | ||
69 | unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled; | ||
70 | do { | ||
71 | GEDR(0) = GPIO_bit(0); /* clear useless edge notification */ | ||
72 | if (likely(pending)) { | ||
73 | irq = MAINSTONE_IRQ(0) + __ffs(pending); | ||
74 | desc = irq_desc + irq; | ||
75 | desc->handle(irq, desc, regs); | ||
76 | } | ||
77 | pending = MST_INTSETCLR & mainstone_irq_enabled; | ||
78 | } while (pending); | ||
79 | } | ||
80 | |||
81 | static void __init mainstone_init_irq(void) | ||
82 | { | ||
83 | int irq; | ||
84 | |||
85 | pxa_init_irq(); | ||
86 | |||
87 | /* setup extra Mainstone irqs */ | ||
88 | for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { | ||
89 | set_irq_chip(irq, &mainstone_irq_chip); | ||
90 | set_irq_handler(irq, do_level_IRQ); | ||
91 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
92 | } | ||
93 | set_irq_flags(MAINSTONE_IRQ(8), 0); | ||
94 | set_irq_flags(MAINSTONE_IRQ(12), 0); | ||
95 | |||
96 | MST_INTMSKENA = 0; | ||
97 | MST_INTSETCLR = 0; | ||
98 | |||
99 | set_irq_chained_handler(IRQ_GPIO(0), mainstone_irq_handler); | ||
100 | set_irq_type(IRQ_GPIO(0), IRQT_FALLING); | ||
101 | } | ||
102 | |||
103 | |||
104 | static struct resource smc91x_resources[] = { | ||
105 | [0] = { | ||
106 | .start = (MST_ETH_PHYS + 0x300), | ||
107 | .end = (MST_ETH_PHYS + 0xfffff), | ||
108 | .flags = IORESOURCE_MEM, | ||
109 | }, | ||
110 | [1] = { | ||
111 | .start = MAINSTONE_IRQ(3), | ||
112 | .end = MAINSTONE_IRQ(3), | ||
113 | .flags = IORESOURCE_IRQ, | ||
114 | } | ||
115 | }; | ||
116 | |||
117 | static struct platform_device smc91x_device = { | ||
118 | .name = "smc91x", | ||
119 | .id = 0, | ||
120 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
121 | .resource = smc91x_resources, | ||
122 | }; | ||
123 | |||
124 | static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv) | ||
125 | { | ||
126 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
127 | MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv) | ||
132 | { | ||
133 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
134 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; | ||
135 | } | ||
136 | |||
137 | static long mst_audio_suspend_mask; | ||
138 | |||
139 | static void mst_audio_suspend(void *priv) | ||
140 | { | ||
141 | mst_audio_suspend_mask = MST_MSCWR2; | ||
142 | MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF; | ||
143 | } | ||
144 | |||
145 | static void mst_audio_resume(void *priv) | ||
146 | { | ||
147 | MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF; | ||
148 | } | ||
149 | |||
150 | static pxa2xx_audio_ops_t mst_audio_ops = { | ||
151 | .startup = mst_audio_startup, | ||
152 | .shutdown = mst_audio_shutdown, | ||
153 | .suspend = mst_audio_suspend, | ||
154 | .resume = mst_audio_resume, | ||
155 | }; | ||
156 | |||
157 | static struct platform_device mst_audio_device = { | ||
158 | .name = "pxa2xx-ac97", | ||
159 | .id = -1, | ||
160 | .dev = { .platform_data = &mst_audio_ops }, | ||
161 | }; | ||
162 | |||
163 | static void mainstone_backlight_power(int on) | ||
164 | { | ||
165 | if (on) { | ||
166 | pxa_gpio_mode(GPIO16_PWM0_MD); | ||
167 | pxa_set_cken(CKEN0_PWM0, 1); | ||
168 | PWM_CTRL0 = 0; | ||
169 | PWM_PWDUTY0 = 0x3ff; | ||
170 | PWM_PERVAL0 = 0x3ff; | ||
171 | } else { | ||
172 | PWM_CTRL0 = 0; | ||
173 | PWM_PWDUTY0 = 0x0; | ||
174 | PWM_PERVAL0 = 0x3FF; | ||
175 | pxa_set_cken(CKEN0_PWM0, 0); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static struct pxafb_mach_info toshiba_ltm04c380k __initdata = { | ||
180 | .pixclock = 50000, | ||
181 | .xres = 640, | ||
182 | .yres = 480, | ||
183 | .bpp = 16, | ||
184 | .hsync_len = 1, | ||
185 | .left_margin = 0x9f, | ||
186 | .right_margin = 1, | ||
187 | .vsync_len = 44, | ||
188 | .upper_margin = 0, | ||
189 | .lower_margin = 0, | ||
190 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, | ||
191 | .lccr0 = LCCR0_Act, | ||
192 | .lccr3 = LCCR3_PCP, | ||
193 | .pxafb_backlight_power = mainstone_backlight_power, | ||
194 | }; | ||
195 | |||
196 | static struct pxafb_mach_info toshiba_ltm035a776c __initdata = { | ||
197 | .pixclock = 110000, | ||
198 | .xres = 240, | ||
199 | .yres = 320, | ||
200 | .bpp = 16, | ||
201 | .hsync_len = 4, | ||
202 | .left_margin = 8, | ||
203 | .right_margin = 20, | ||
204 | .vsync_len = 3, | ||
205 | .upper_margin = 1, | ||
206 | .lower_margin = 10, | ||
207 | .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, | ||
208 | .lccr0 = LCCR0_Act, | ||
209 | .lccr3 = LCCR3_PCP, | ||
210 | .pxafb_backlight_power = mainstone_backlight_power, | ||
211 | }; | ||
212 | |||
213 | static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data) | ||
214 | { | ||
215 | int err; | ||
216 | |||
217 | /* | ||
218 | * setup GPIO for PXA27x MMC controller | ||
219 | */ | ||
220 | pxa_gpio_mode(GPIO32_MMCCLK_MD); | ||
221 | pxa_gpio_mode(GPIO112_MMCCMD_MD); | ||
222 | pxa_gpio_mode(GPIO92_MMCDAT0_MD); | ||
223 | pxa_gpio_mode(GPIO109_MMCDAT1_MD); | ||
224 | pxa_gpio_mode(GPIO110_MMCDAT2_MD); | ||
225 | pxa_gpio_mode(GPIO111_MMCDAT3_MD); | ||
226 | |||
227 | /* make sure SD/Memory Stick multiplexer's signals | ||
228 | * are routed to MMC controller | ||
229 | */ | ||
230 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; | ||
231 | |||
232 | err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, SA_INTERRUPT, | ||
233 | "MMC card detect", data); | ||
234 | if (err) { | ||
235 | printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void mainstone_mci_setpower(struct device *dev, unsigned int vdd) | ||
243 | { | ||
244 | struct pxamci_platform_data* p_d = dev->platform_data; | ||
245 | |||
246 | if (( 1 << vdd) & p_d->ocr_mask) { | ||
247 | printk(KERN_DEBUG "%s: on\n", __FUNCTION__); | ||
248 | MST_MSCWR1 |= MST_MSCWR1_MMC_ON; | ||
249 | MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; | ||
250 | } else { | ||
251 | printk(KERN_DEBUG "%s: off\n", __FUNCTION__); | ||
252 | MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | static void mainstone_mci_exit(struct device *dev, void *data) | ||
257 | { | ||
258 | free_irq(MAINSTONE_MMC_IRQ, data); | ||
259 | } | ||
260 | |||
261 | static struct pxamci_platform_data mainstone_mci_platform_data = { | ||
262 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
263 | .init = mainstone_mci_init, | ||
264 | .setpower = mainstone_mci_setpower, | ||
265 | .exit = mainstone_mci_exit, | ||
266 | }; | ||
267 | |||
268 | static void __init mainstone_init(void) | ||
269 | { | ||
270 | /* | ||
271 | * On Mainstone, we route AC97_SYSCLK via GPIO45 to | ||
272 | * the audio daughter card | ||
273 | */ | ||
274 | pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD); | ||
275 | |||
276 | platform_device_register(&smc91x_device); | ||
277 | platform_device_register(&mst_audio_device); | ||
278 | |||
279 | /* reading Mainstone's "Virtual Configuration Register" | ||
280 | might be handy to select LCD type here */ | ||
281 | if (0) | ||
282 | set_pxa_fb_info(&toshiba_ltm04c380k); | ||
283 | else | ||
284 | set_pxa_fb_info(&toshiba_ltm035a776c); | ||
285 | |||
286 | pxa_set_mci_info(&mainstone_mci_platform_data); | ||
287 | } | ||
288 | |||
289 | |||
290 | static struct map_desc mainstone_io_desc[] __initdata = { | ||
291 | { MST_FPGA_VIRT, MST_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ | ||
292 | }; | ||
293 | |||
294 | static void __init mainstone_map_io(void) | ||
295 | { | ||
296 | pxa_map_io(); | ||
297 | iotable_init(mainstone_io_desc, ARRAY_SIZE(mainstone_io_desc)); | ||
298 | |||
299 | /* initialize sleep mode regs (wake-up sources, etc) */ | ||
300 | PGSR0 = 0x00008800; | ||
301 | PGSR1 = 0x00000002; | ||
302 | PGSR2 = 0x0001FC00; | ||
303 | PGSR3 = 0x00001F81; | ||
304 | PWER = 0xC0000002; | ||
305 | PRER = 0x00000002; | ||
306 | PFER = 0x00000002; | ||
307 | } | ||
308 | |||
309 | MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") | ||
310 | MAINTAINER("MontaVista Software Inc.") | ||
311 | BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) | ||
312 | MAPIO(mainstone_map_io) | ||
313 | INITIRQ(mainstone_init_irq) | ||
314 | .timer = &pxa_timer, | ||
315 | INIT_MACHINE(mainstone_init) | ||
316 | MACHINE_END | ||
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c new file mode 100644 index 000000000000..82a4bf34c251 --- /dev/null +++ b/arch/arm/mach-pxa/pm.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* | ||
2 | * PXA250/210 Power Management Routines | ||
3 | * | ||
4 | * Original code for the SA11x0: | ||
5 | * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> | ||
6 | * | ||
7 | * Modified for the PXA250 by Nicolas Pitre: | ||
8 | * Copyright (c) 2002 Monta Vista Software, Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License. | ||
12 | */ | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/suspend.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/time.h> | ||
18 | |||
19 | #include <asm/hardware.h> | ||
20 | #include <asm/memory.h> | ||
21 | #include <asm/system.h> | ||
22 | #include <asm/arch/pxa-regs.h> | ||
23 | #include <asm/arch/lubbock.h> | ||
24 | #include <asm/mach/time.h> | ||
25 | |||
26 | |||
27 | /* | ||
28 | * Debug macros | ||
29 | */ | ||
30 | #undef DEBUG | ||
31 | |||
32 | extern void pxa_cpu_suspend(void); | ||
33 | extern void pxa_cpu_resume(void); | ||
34 | |||
35 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x | ||
36 | #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] | ||
37 | |||
38 | #define RESTORE_GPLEVEL(n) do { \ | ||
39 | GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
40 | GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
41 | } while (0) | ||
42 | |||
43 | /* | ||
44 | * List of global PXA peripheral registers to preserve. | ||
45 | * More ones like CP and general purpose register values are preserved | ||
46 | * with the stack pointer in sleep.S. | ||
47 | */ | ||
48 | enum { SLEEP_SAVE_START = 0, | ||
49 | |||
50 | SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3, | ||
51 | SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3, | ||
52 | SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3, | ||
53 | SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3, | ||
54 | SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, | ||
55 | |||
56 | SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, | ||
57 | SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, | ||
58 | SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, | ||
59 | SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, | ||
60 | |||
61 | SLEEP_SAVE_PSTR, | ||
62 | |||
63 | SLEEP_SAVE_ICMR, | ||
64 | SLEEP_SAVE_CKEN, | ||
65 | |||
66 | SLEEP_SAVE_CKSUM, | ||
67 | |||
68 | SLEEP_SAVE_SIZE | ||
69 | }; | ||
70 | |||
71 | |||
72 | static int pxa_pm_enter(suspend_state_t state) | ||
73 | { | ||
74 | unsigned long sleep_save[SLEEP_SAVE_SIZE]; | ||
75 | unsigned long checksum = 0; | ||
76 | struct timespec delta, rtc; | ||
77 | int i; | ||
78 | |||
79 | if (state != PM_SUSPEND_MEM) | ||
80 | return -EINVAL; | ||
81 | |||
82 | #ifdef CONFIG_IWMMXT | ||
83 | /* force any iWMMXt context to ram **/ | ||
84 | iwmmxt_task_disable(NULL); | ||
85 | #endif | ||
86 | |||
87 | /* preserve current time */ | ||
88 | rtc.tv_sec = RCNR; | ||
89 | rtc.tv_nsec = 0; | ||
90 | save_time_delta(&delta, &rtc); | ||
91 | |||
92 | SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); | ||
93 | SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); | ||
94 | SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); | ||
95 | SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); | ||
96 | SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); | ||
97 | |||
98 | SAVE(GAFR0_L); SAVE(GAFR0_U); | ||
99 | SAVE(GAFR1_L); SAVE(GAFR1_U); | ||
100 | SAVE(GAFR2_L); SAVE(GAFR2_U); | ||
101 | |||
102 | #ifdef CONFIG_PXA27x | ||
103 | SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3); | ||
104 | SAVE(GAFR3_L); SAVE(GAFR3_U); | ||
105 | #endif | ||
106 | |||
107 | SAVE(ICMR); | ||
108 | ICMR = 0; | ||
109 | |||
110 | SAVE(CKEN); | ||
111 | CKEN = 0; | ||
112 | |||
113 | SAVE(PSTR); | ||
114 | |||
115 | /* Note: wake up source are set up in each machine specific files */ | ||
116 | |||
117 | /* clear GPIO transition detect bits */ | ||
118 | GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; | ||
119 | #ifdef CONFIG_PXA27x | ||
120 | GEDR3 = GEDR3; | ||
121 | #endif | ||
122 | |||
123 | /* Clear sleep reset status */ | ||
124 | RCSR = RCSR_SMR; | ||
125 | |||
126 | /* set resume return address */ | ||
127 | PSPR = virt_to_phys(pxa_cpu_resume); | ||
128 | |||
129 | /* before sleeping, calculate and save a checksum */ | ||
130 | for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) | ||
131 | checksum += sleep_save[i]; | ||
132 | sleep_save[SLEEP_SAVE_CKSUM] = checksum; | ||
133 | |||
134 | /* *** go zzz *** */ | ||
135 | pxa_cpu_suspend(); | ||
136 | |||
137 | /* after sleeping, validate the checksum */ | ||
138 | checksum = 0; | ||
139 | for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) | ||
140 | checksum += sleep_save[i]; | ||
141 | |||
142 | /* if invalid, display message and wait for a hardware reset */ | ||
143 | if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { | ||
144 | #ifdef CONFIG_ARCH_LUBBOCK | ||
145 | LUB_HEXLED = 0xbadbadc5; | ||
146 | #endif | ||
147 | while (1) | ||
148 | pxa_cpu_suspend(); | ||
149 | } | ||
150 | |||
151 | /* ensure not to come back here if it wasn't intended */ | ||
152 | PSPR = 0; | ||
153 | |||
154 | /* restore registers */ | ||
155 | RESTORE(GAFR0_L); RESTORE(GAFR0_U); | ||
156 | RESTORE(GAFR1_L); RESTORE(GAFR1_U); | ||
157 | RESTORE(GAFR2_L); RESTORE(GAFR2_U); | ||
158 | RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); | ||
159 | RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); | ||
160 | RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); | ||
161 | RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); | ||
162 | RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); | ||
163 | |||
164 | #ifdef CONFIG_PXA27x | ||
165 | RESTORE(GAFR3_L); RESTORE(GAFR3_U); RESTORE_GPLEVEL(3); | ||
166 | RESTORE(GPDR3); RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3); | ||
167 | #endif | ||
168 | |||
169 | PSSR = PSSR_RDH | PSSR_PH; | ||
170 | |||
171 | RESTORE(CKEN); | ||
172 | |||
173 | ICLR = 0; | ||
174 | ICCR = 1; | ||
175 | RESTORE(ICMR); | ||
176 | |||
177 | RESTORE(PSTR); | ||
178 | |||
179 | /* restore current time */ | ||
180 | rtc.tv_sec = RCNR; | ||
181 | restore_time_delta(&delta, &rtc); | ||
182 | |||
183 | #ifdef DEBUG | ||
184 | printk(KERN_DEBUG "*** made it back from resume\n"); | ||
185 | #endif | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | unsigned long sleep_phys_sp(void *sp) | ||
191 | { | ||
192 | return virt_to_phys(sp); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Called after processes are frozen, but before we shut down devices. | ||
197 | */ | ||
198 | static int pxa_pm_prepare(suspend_state_t state) | ||
199 | { | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Called after devices are re-setup, but before processes are thawed. | ||
205 | */ | ||
206 | static int pxa_pm_finish(suspend_state_t state) | ||
207 | { | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. | ||
213 | */ | ||
214 | static struct pm_ops pxa_pm_ops = { | ||
215 | .pm_disk_mode = PM_DISK_FIRMWARE, | ||
216 | .prepare = pxa_pm_prepare, | ||
217 | .enter = pxa_pm_enter, | ||
218 | .finish = pxa_pm_finish, | ||
219 | }; | ||
220 | |||
221 | static int __init pxa_pm_init(void) | ||
222 | { | ||
223 | pm_set_ops(&pxa_pm_ops); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | late_initcall(pxa_pm_init); | ||
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c new file mode 100644 index 000000000000..b6c746ea3830 --- /dev/null +++ b/arch/arm/mach-pxa/poodle.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/poodle.c | ||
3 | * | ||
4 | * Support for the SHARP Poodle Board. | ||
5 | * | ||
6 | * Based on: | ||
7 | * linux/arch/arm/mach-pxa/lubbock.c Author: Nicolas Pitre | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Change Log | ||
14 | * 12-Dec-2002 Sharp Corporation for Poodle | ||
15 | * John Lenz <lenz@cs.wisc.edu> updates to 2.6 | ||
16 | */ | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/fb.h> | ||
21 | |||
22 | #include <asm/hardware.h> | ||
23 | #include <asm/mach-types.h> | ||
24 | #include <asm/irq.h> | ||
25 | #include <asm/setup.h> | ||
26 | |||
27 | #include <asm/mach/arch.h> | ||
28 | #include <asm/mach/map.h> | ||
29 | #include <asm/mach/irq.h> | ||
30 | |||
31 | #include <asm/arch/pxa-regs.h> | ||
32 | #include <asm/arch/irq.h> | ||
33 | #include <asm/arch/poodle.h> | ||
34 | #include <asm/arch/pxafb.h> | ||
35 | |||
36 | #include <asm/hardware/scoop.h> | ||
37 | #include <asm/hardware/locomo.h> | ||
38 | #include <asm/mach/sharpsl_param.h> | ||
39 | |||
40 | #include "generic.h" | ||
41 | |||
42 | static struct resource poodle_scoop_resources[] = { | ||
43 | [0] = { | ||
44 | .start = 0x10800000, | ||
45 | .end = 0x10800fff, | ||
46 | .flags = IORESOURCE_MEM, | ||
47 | }, | ||
48 | }; | ||
49 | |||
50 | static struct scoop_config poodle_scoop_setup = { | ||
51 | .io_dir = POODLE_SCOOP_IO_DIR, | ||
52 | .io_out = POODLE_SCOOP_IO_OUT, | ||
53 | }; | ||
54 | |||
55 | struct platform_device poodle_scoop_device = { | ||
56 | .name = "sharp-scoop", | ||
57 | .id = -1, | ||
58 | .dev = { | ||
59 | .platform_data = &poodle_scoop_setup, | ||
60 | }, | ||
61 | .num_resources = ARRAY_SIZE(poodle_scoop_resources), | ||
62 | .resource = poodle_scoop_resources, | ||
63 | }; | ||
64 | |||
65 | |||
66 | /* LoCoMo device */ | ||
67 | static struct resource locomo_resources[] = { | ||
68 | [0] = { | ||
69 | .start = 0x10000000, | ||
70 | .end = 0x10001fff, | ||
71 | .flags = IORESOURCE_MEM, | ||
72 | }, | ||
73 | [1] = { | ||
74 | .start = IRQ_GPIO(10), | ||
75 | .end = IRQ_GPIO(10), | ||
76 | .flags = IORESOURCE_IRQ, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | static struct platform_device locomo_device = { | ||
81 | .name = "locomo", | ||
82 | .id = 0, | ||
83 | .num_resources = ARRAY_SIZE(locomo_resources), | ||
84 | .resource = locomo_resources, | ||
85 | }; | ||
86 | |||
87 | /* PXAFB device */ | ||
88 | static struct pxafb_mach_info poodle_fb_info __initdata = { | ||
89 | .pixclock = 144700, | ||
90 | |||
91 | .xres = 320, | ||
92 | .yres = 240, | ||
93 | .bpp = 16, | ||
94 | |||
95 | .hsync_len = 7, | ||
96 | .left_margin = 11, | ||
97 | .right_margin = 30, | ||
98 | |||
99 | .vsync_len = 2, | ||
100 | .upper_margin = 2, | ||
101 | .lower_margin = 0, | ||
102 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
103 | |||
104 | .lccr0 = LCCR0_Act | LCCR0_Sngl | LCCR0_Color, | ||
105 | .lccr3 = 0, | ||
106 | |||
107 | .pxafb_backlight_power = NULL, | ||
108 | .pxafb_lcd_power = NULL, | ||
109 | }; | ||
110 | |||
111 | static struct platform_device *devices[] __initdata = { | ||
112 | &locomo_device, | ||
113 | &poodle_scoop_device, | ||
114 | }; | ||
115 | |||
116 | static void __init poodle_init(void) | ||
117 | { | ||
118 | int ret = 0; | ||
119 | |||
120 | /* cpu initialize */ | ||
121 | /* Pgsr Register */ | ||
122 | PGSR0 = 0x0146dd80; | ||
123 | PGSR1 = 0x03bf0890; | ||
124 | PGSR2 = 0x0001c000; | ||
125 | |||
126 | /* Alternate Register */ | ||
127 | GAFR0_L = 0x01001000; | ||
128 | GAFR0_U = 0x591a8010; | ||
129 | GAFR1_L = 0x900a8451; | ||
130 | GAFR1_U = 0xaaa5aaaa; | ||
131 | GAFR2_L = 0x8aaaaaaa; | ||
132 | GAFR2_U = 0x00000002; | ||
133 | |||
134 | /* Direction Register */ | ||
135 | GPDR0 = 0xd3f0904c; | ||
136 | GPDR1 = 0xfcffb7d3; | ||
137 | GPDR2 = 0x0001ffff; | ||
138 | |||
139 | /* Output Register */ | ||
140 | GPCR0 = 0x00000000; | ||
141 | GPCR1 = 0x00000000; | ||
142 | GPCR2 = 0x00000000; | ||
143 | |||
144 | GPSR0 = 0x00400000; | ||
145 | GPSR1 = 0x00000000; | ||
146 | GPSR2 = 0x00000000; | ||
147 | |||
148 | set_pxa_fb_info(&poodle_fb_info); | ||
149 | |||
150 | ret = platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
151 | if (ret) { | ||
152 | printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n"); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | static void __init fixup_poodle(struct machine_desc *desc, | ||
157 | struct tag *tags, char **cmdline, struct meminfo *mi) | ||
158 | { | ||
159 | sharpsl_save_param(); | ||
160 | } | ||
161 | |||
162 | static struct map_desc poodle_io_desc[] __initdata = { | ||
163 | /* virtual physical length */ | ||
164 | { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */ | ||
165 | }; | ||
166 | |||
167 | static void __init poodle_map_io(void) | ||
168 | { | ||
169 | pxa_map_io(); | ||
170 | iotable_init(poodle_io_desc, ARRAY_SIZE(poodle_io_desc)); | ||
171 | |||
172 | /* setup sleep mode values */ | ||
173 | PWER = 0x00000002; | ||
174 | PFER = 0x00000000; | ||
175 | PRER = 0x00000002; | ||
176 | PGSR0 = 0x00008000; | ||
177 | PGSR1 = 0x003F0202; | ||
178 | PGSR2 = 0x0001C000; | ||
179 | PCFR |= PCFR_OPDE; | ||
180 | } | ||
181 | |||
182 | MACHINE_START(POODLE, "SHARP Poodle") | ||
183 | BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) | ||
184 | FIXUP(fixup_poodle) | ||
185 | MAPIO(poodle_map_io) | ||
186 | INITIRQ(pxa_init_irq) | ||
187 | .timer = &pxa_timer, | ||
188 | .init_machine = poodle_init, | ||
189 | MACHINE_END | ||
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c new file mode 100644 index 000000000000..e887b7175ef3 --- /dev/null +++ b/arch/arm/mach-pxa/pxa25x.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/pxa25x.c | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Jun 15, 2001 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * Code specific to PXA21x/25x/26x variants. | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * Since this file should be linked before any other machine specific file, | ||
15 | * the __initcall() here will be executed first. This serves as default | ||
16 | * initialization stuff for PXA machines which can be overridden later if | ||
17 | * need be. | ||
18 | */ | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/pm.h> | ||
23 | |||
24 | #include <asm/hardware.h> | ||
25 | #include <asm/arch/pxa-regs.h> | ||
26 | |||
27 | #include "generic.h" | ||
28 | |||
29 | /* | ||
30 | * Various clock factors driven by the CCCR register. | ||
31 | */ | ||
32 | |||
33 | /* Crystal Frequency to Memory Frequency Multiplier (L) */ | ||
34 | static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, }; | ||
35 | |||
36 | /* Memory Frequency to Run Mode Frequency Multiplier (M) */ | ||
37 | static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 }; | ||
38 | |||
39 | /* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */ | ||
40 | /* Note: we store the value N * 2 here. */ | ||
41 | static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; | ||
42 | |||
43 | /* Crystal clock */ | ||
44 | #define BASE_CLK 3686400 | ||
45 | |||
46 | /* | ||
47 | * Get the clock frequency as reflected by CCCR and the turbo flag. | ||
48 | * We assume these values have been applied via a fcs. | ||
49 | * If info is not 0 we also display the current settings. | ||
50 | */ | ||
51 | unsigned int get_clk_frequency_khz(int info) | ||
52 | { | ||
53 | unsigned long cccr, turbo; | ||
54 | unsigned int l, L, m, M, n2, N; | ||
55 | |||
56 | cccr = CCCR; | ||
57 | asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) ); | ||
58 | |||
59 | l = L_clk_mult[(cccr >> 0) & 0x1f]; | ||
60 | m = M_clk_mult[(cccr >> 5) & 0x03]; | ||
61 | n2 = N2_clk_mult[(cccr >> 7) & 0x07]; | ||
62 | |||
63 | L = l * BASE_CLK; | ||
64 | M = m * L; | ||
65 | N = n2 * M / 2; | ||
66 | |||
67 | if(info) | ||
68 | { | ||
69 | L += 5000; | ||
70 | printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n", | ||
71 | L / 1000000, (L % 1000000) / 10000, l ); | ||
72 | M += 5000; | ||
73 | printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n", | ||
74 | M / 1000000, (M % 1000000) / 10000, m ); | ||
75 | N += 5000; | ||
76 | printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n", | ||
77 | N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5, | ||
78 | (turbo & 1) ? "" : "in" ); | ||
79 | } | ||
80 | |||
81 | return (turbo & 1) ? (N/1000) : (M/1000); | ||
82 | } | ||
83 | |||
84 | EXPORT_SYMBOL(get_clk_frequency_khz); | ||
85 | |||
86 | /* | ||
87 | * Return the current memory clock frequency in units of 10kHz | ||
88 | */ | ||
89 | unsigned int get_memclk_frequency_10khz(void) | ||
90 | { | ||
91 | return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; | ||
92 | } | ||
93 | |||
94 | EXPORT_SYMBOL(get_memclk_frequency_10khz); | ||
95 | |||
96 | /* | ||
97 | * Return the current LCD clock frequency in units of 10kHz | ||
98 | */ | ||
99 | unsigned int get_lcdclk_frequency_10khz(void) | ||
100 | { | ||
101 | return get_memclk_frequency_10khz(); | ||
102 | } | ||
103 | |||
104 | EXPORT_SYMBOL(get_lcdclk_frequency_10khz); | ||
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c new file mode 100644 index 000000000000..7e863afefb53 --- /dev/null +++ b/arch/arm/mach-pxa/pxa27x.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/pxa27x.c | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Nov 05, 2002 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * Code specific to PXA27x aka Bulverde. | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/device.h> | ||
20 | |||
21 | #include <asm/hardware.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <asm/arch/pxa-regs.h> | ||
24 | |||
25 | #include "generic.h" | ||
26 | |||
27 | /* Crystal clock: 13MHz */ | ||
28 | #define BASE_CLK 13000000 | ||
29 | |||
30 | /* | ||
31 | * Get the clock frequency as reflected by CCSR and the turbo flag. | ||
32 | * We assume these values have been applied via a fcs. | ||
33 | * If info is not 0 we also display the current settings. | ||
34 | */ | ||
35 | unsigned int get_clk_frequency_khz( int info) | ||
36 | { | ||
37 | unsigned long ccsr, clkcfg; | ||
38 | unsigned int l, L, m, M, n2, N, S; | ||
39 | int cccr_a, t, ht, b; | ||
40 | |||
41 | ccsr = CCSR; | ||
42 | cccr_a = CCCR & (1 << 25); | ||
43 | |||
44 | /* Read clkcfg register: it has turbo, b, half-turbo (and f) */ | ||
45 | asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) ); | ||
46 | t = clkcfg & (1 << 1); | ||
47 | ht = clkcfg & (1 << 2); | ||
48 | b = clkcfg & (1 << 3); | ||
49 | |||
50 | l = ccsr & 0x1f; | ||
51 | n2 = (ccsr>>7) & 0xf; | ||
52 | m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4; | ||
53 | |||
54 | L = l * BASE_CLK; | ||
55 | N = (L * n2) / 2; | ||
56 | M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2)); | ||
57 | S = (b) ? L : (L/2); | ||
58 | |||
59 | if (info) { | ||
60 | printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n", | ||
61 | L / 1000000, (L % 1000000) / 10000, l ); | ||
62 | printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n", | ||
63 | N / 1000000, (N % 1000000)/10000, n2 / 2, (n2 % 2)*5, | ||
64 | (t) ? "" : "in" ); | ||
65 | printk( KERN_INFO "Memory clock: %d.%02dMHz (/%d)\n", | ||
66 | M / 1000000, (M % 1000000) / 10000, m ); | ||
67 | printk( KERN_INFO "System bus clock: %d.%02dMHz \n", | ||
68 | S / 1000000, (S % 1000000) / 10000 ); | ||
69 | } | ||
70 | |||
71 | return (t) ? (N/1000) : (L/1000); | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Return the current mem clock frequency in units of 10kHz as | ||
76 | * reflected by CCCR[A], B, and L | ||
77 | */ | ||
78 | unsigned int get_memclk_frequency_10khz(void) | ||
79 | { | ||
80 | unsigned long ccsr, clkcfg; | ||
81 | unsigned int l, L, m, M; | ||
82 | int cccr_a, b; | ||
83 | |||
84 | ccsr = CCSR; | ||
85 | cccr_a = CCCR & (1 << 25); | ||
86 | |||
87 | /* Read clkcfg register: it has turbo, b, half-turbo (and f) */ | ||
88 | asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) ); | ||
89 | b = clkcfg & (1 << 3); | ||
90 | |||
91 | l = ccsr & 0x1f; | ||
92 | m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4; | ||
93 | |||
94 | L = l * BASE_CLK; | ||
95 | M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2)); | ||
96 | |||
97 | return (M / 10000); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Return the current LCD clock frequency in units of 10kHz as | ||
102 | */ | ||
103 | unsigned int get_lcdclk_frequency_10khz(void) | ||
104 | { | ||
105 | unsigned long ccsr; | ||
106 | unsigned int l, L, k, K; | ||
107 | |||
108 | ccsr = CCSR; | ||
109 | |||
110 | l = ccsr & 0x1f; | ||
111 | k = (l <= 7) ? 1 : (l <= 16) ? 2 : 4; | ||
112 | |||
113 | L = l * BASE_CLK; | ||
114 | K = L / k; | ||
115 | |||
116 | return (K / 10000); | ||
117 | } | ||
118 | |||
119 | EXPORT_SYMBOL(get_clk_frequency_khz); | ||
120 | EXPORT_SYMBOL(get_memclk_frequency_10khz); | ||
121 | EXPORT_SYMBOL(get_lcdclk_frequency_10khz); | ||
122 | |||
123 | |||
124 | /* | ||
125 | * device registration specific to PXA27x. | ||
126 | */ | ||
127 | |||
128 | static u64 pxa27x_dmamask = 0xffffffffUL; | ||
129 | |||
130 | static struct resource pxa27x_ohci_resources[] = { | ||
131 | [0] = { | ||
132 | .start = 0x4C000000, | ||
133 | .end = 0x4C00ff6f, | ||
134 | .flags = IORESOURCE_MEM, | ||
135 | }, | ||
136 | [1] = { | ||
137 | .start = IRQ_USBH1, | ||
138 | .end = IRQ_USBH1, | ||
139 | .flags = IORESOURCE_IRQ, | ||
140 | }, | ||
141 | }; | ||
142 | |||
143 | static struct platform_device ohci_device = { | ||
144 | .name = "pxa27x-ohci", | ||
145 | .id = -1, | ||
146 | .dev = { | ||
147 | .dma_mask = &pxa27x_dmamask, | ||
148 | .coherent_dma_mask = 0xffffffff, | ||
149 | }, | ||
150 | .num_resources = ARRAY_SIZE(pxa27x_ohci_resources), | ||
151 | .resource = pxa27x_ohci_resources, | ||
152 | }; | ||
153 | |||
154 | static struct platform_device *devices[] __initdata = { | ||
155 | &ohci_device, | ||
156 | }; | ||
157 | |||
158 | static int __init pxa27x_init(void) | ||
159 | { | ||
160 | return platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
161 | } | ||
162 | |||
163 | subsys_initcall(pxa27x_init); | ||
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S new file mode 100644 index 000000000000..16cad2c2497c --- /dev/null +++ b/arch/arm/mach-pxa/sleep.S | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * Low-level PXA250/210 sleep/wakeUp support | ||
3 | * | ||
4 | * Initial SA1110 code: | ||
5 | * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> | ||
6 | * | ||
7 | * Adapted for PXA by Nicolas Pitre: | ||
8 | * Copyright (c) 2002 Monta Vista Software, Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/linkage.h> | ||
16 | #include <asm/assembler.h> | ||
17 | #include <asm/hardware.h> | ||
18 | |||
19 | #include <asm/arch/pxa-regs.h> | ||
20 | |||
21 | .text | ||
22 | |||
23 | /* | ||
24 | * pxa_cpu_suspend() | ||
25 | * | ||
26 | * Forces CPU into sleep state | ||
27 | */ | ||
28 | |||
29 | ENTRY(pxa_cpu_suspend) | ||
30 | |||
31 | mra r2, r3, acc0 | ||
32 | stmfd sp!, {r2 - r12, lr} @ save registers on stack | ||
33 | |||
34 | @ get coprocessor registers | ||
35 | mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode | ||
36 | mrc p15, 0, r4, c15, c1, 0 @ CP access reg | ||
37 | mrc p15, 0, r5, c13, c0, 0 @ PID | ||
38 | mrc p15, 0, r6, c3, c0, 0 @ domain ID | ||
39 | mrc p15, 0, r7, c2, c0, 0 @ translation table base addr | ||
40 | mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg | ||
41 | mrc p15, 0, r9, c1, c0, 0 @ control reg | ||
42 | |||
43 | bic r3, r3, #2 @ clear frequency change bit | ||
44 | |||
45 | @ store them plus current virtual stack ptr on stack | ||
46 | mov r10, sp | ||
47 | stmfd sp!, {r3 - r10} | ||
48 | |||
49 | @ preserve phys address of stack | ||
50 | mov r0, sp | ||
51 | bl sleep_phys_sp | ||
52 | ldr r1, =sleep_save_sp | ||
53 | str r0, [r1] | ||
54 | |||
55 | @ clean data cache | ||
56 | bl xscale_flush_kern_cache_all | ||
57 | |||
58 | @ Put the processor to sleep | ||
59 | @ (also workaround for sighting 28071) | ||
60 | |||
61 | @ prepare value for sleep mode | ||
62 | mov r1, #3 @ sleep mode | ||
63 | |||
64 | @ prepare to put SDRAM into self-refresh manually | ||
65 | ldr r4, =MDREFR | ||
66 | ldr r5, [r4] | ||
67 | orr r5, r5, #MDREFR_SLFRSH | ||
68 | |||
69 | @ prepare pointer to physical address 0 (virtual mapping in generic.c) | ||
70 | mov r2, #UNCACHED_PHYS_0 | ||
71 | |||
72 | @ Intel PXA255 Specification Update notes problems | ||
73 | @ about suspending with PXBus operating above 133MHz | ||
74 | @ (see Errata 31, GPIO output signals, ... unpredictable in sleep | ||
75 | @ | ||
76 | @ We keep the change-down close to the actual suspend on SDRAM | ||
77 | @ as possible to eliminate messing about with the refresh clock | ||
78 | @ as the system will restore with the original speed settings | ||
79 | @ | ||
80 | @ Ben Dooks, 13-Sep-2004 | ||
81 | |||
82 | ldr r6, =CCCR | ||
83 | ldr r8, [r6] @ keep original value for resume | ||
84 | |||
85 | @ ensure x1 for run and turbo mode with memory clock | ||
86 | bic r7, r8, #CCCR_M_MASK | CCCR_N_MASK | ||
87 | orr r7, r7, #(1<<5) | (2<<7) | ||
88 | |||
89 | @ check that the memory frequency is within limits | ||
90 | and r14, r7, #CCCR_L_MASK | ||
91 | teq r14, #1 | ||
92 | bicne r7, r7, #CCCR_L_MASK | ||
93 | orrne r7, r7, #1 @@ 99.53MHz | ||
94 | |||
95 | @ get ready for the change | ||
96 | |||
97 | @ note, turbo is not preserved over sleep so there is no | ||
98 | @ point in preserving it here. we save it on the stack with the | ||
99 | @ other CP registers instead. | ||
100 | mov r0, #0 | ||
101 | mcr p14, 0, r0, c6, c0, 0 | ||
102 | orr r0, r0, #2 @ initiate change bit | ||
103 | |||
104 | @ align execution to a cache line | ||
105 | b 1f | ||
106 | |||
107 | .ltorg | ||
108 | .align 5 | ||
109 | 1: | ||
110 | |||
111 | @ All needed values are now in registers. | ||
112 | @ These last instructions should be in cache | ||
113 | |||
114 | @ initiate the frequency change... | ||
115 | str r7, [r6] | ||
116 | mcr p14, 0, r0, c6, c0, 0 | ||
117 | |||
118 | @ restore the original cpu speed value for resume | ||
119 | str r8, [r6] | ||
120 | |||
121 | @ put SDRAM into self-refresh | ||
122 | str r5, [r4] | ||
123 | |||
124 | @ force address lines low by reading at physical address 0 | ||
125 | ldr r3, [r2] | ||
126 | |||
127 | @ enter sleep mode | ||
128 | mcr p14, 0, r1, c7, c0, 0 | ||
129 | |||
130 | 20: b 20b @ loop waiting for sleep | ||
131 | |||
132 | /* | ||
133 | * cpu_pxa_resume() | ||
134 | * | ||
135 | * entry point from bootloader into kernel during resume | ||
136 | * | ||
137 | * Note: Yes, part of the following code is located into the .data section. | ||
138 | * This is to allow sleep_save_sp to be accessed with a relative load | ||
139 | * while we can't rely on any MMU translation. We could have put | ||
140 | * sleep_save_sp in the .text section as well, but some setups might | ||
141 | * insist on it to be truly read-only. | ||
142 | */ | ||
143 | |||
144 | .data | ||
145 | .align 5 | ||
146 | ENTRY(pxa_cpu_resume) | ||
147 | mov r0, #PSR_I_BIT | PSR_F_BIT | MODE_SVC @ set SVC, irqs off | ||
148 | msr cpsr_c, r0 | ||
149 | |||
150 | ldr r0, sleep_save_sp @ stack phys addr | ||
151 | ldr r2, =resume_after_mmu @ its absolute virtual address | ||
152 | ldmfd r0, {r3 - r9, sp} @ CP regs + virt stack ptr | ||
153 | |||
154 | mov r1, #0 | ||
155 | mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs | ||
156 | mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB | ||
157 | |||
158 | #ifdef CONFIG_XSCALE_CACHE_ERRATA | ||
159 | bic r9, r9, #0x0004 @ see cpu_xscale_proc_init | ||
160 | #endif | ||
161 | |||
162 | mcr p14, 0, r3, c6, c0, 0 @ clock configuration, turbo mode. | ||
163 | mcr p15, 0, r4, c15, c1, 0 @ CP access reg | ||
164 | mcr p15, 0, r5, c13, c0, 0 @ PID | ||
165 | mcr p15, 0, r6, c3, c0, 0 @ domain ID | ||
166 | mcr p15, 0, r7, c2, c0, 0 @ translation table base addr | ||
167 | mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg | ||
168 | b resume_turn_on_mmu @ cache align execution | ||
169 | |||
170 | .align 5 | ||
171 | resume_turn_on_mmu: | ||
172 | mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, caches, etc. | ||
173 | |||
174 | @ Let us ensure we jump to resume_after_mmu only when the mcr above | ||
175 | @ actually took effect. They call it the "cpwait" operation. | ||
176 | mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15 | ||
177 | sub pc, r2, r1, lsr #32 @ jump to virtual addr | ||
178 | nop | ||
179 | nop | ||
180 | nop | ||
181 | |||
182 | sleep_save_sp: | ||
183 | .word 0 @ preserve stack phys ptr here | ||
184 | |||
185 | .text | ||
186 | resume_after_mmu: | ||
187 | #ifdef CONFIG_XSCALE_CACHE_ERRATA | ||
188 | bl cpu_xscale_proc_init | ||
189 | #endif | ||
190 | ldmfd sp!, {r2, r3} | ||
191 | mar acc0, r2, r3 | ||
192 | ldmfd sp!, {r4 - r12, pc} @ return to caller | ||
193 | |||
194 | |||
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c new file mode 100644 index 000000000000..4d826c021315 --- /dev/null +++ b/arch/arm/mach-pxa/ssp.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/ssp.c | ||
3 | * | ||
4 | * based on linux/arch/arm/mach-sa1100/ssp.c by Russell King | ||
5 | * | ||
6 | * Copyright (C) 2003 Russell King. | ||
7 | * Copyright (C) 2003 Wolfson Microelectronics PLC | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * PXA2xx SSP driver. This provides the generic core for simple | ||
14 | * IO-based SSP applications and allows easy port setup for DMA access. | ||
15 | * | ||
16 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
17 | * | ||
18 | * Revision history: | ||
19 | * 22nd Aug 2003 Initial version. | ||
20 | * 20th Dec 2004 Added ssp_config for changing port config without | ||
21 | * closing the port. | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/irq.h> | ||
34 | #include <asm/hardware.h> | ||
35 | #include <asm/arch/ssp.h> | ||
36 | #include <asm/arch/pxa-regs.h> | ||
37 | |||
38 | #define PXA_SSP_PORTS 3 | ||
39 | |||
40 | static DECLARE_MUTEX(sem); | ||
41 | static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; | ||
42 | |||
43 | static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
44 | { | ||
45 | struct ssp_dev *dev = (struct ssp_dev*) dev_id; | ||
46 | unsigned int status = SSSR_P(dev->port); | ||
47 | |||
48 | SSSR_P(dev->port) = status; /* clear status bits */ | ||
49 | |||
50 | if (status & SSSR_ROR) | ||
51 | printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port); | ||
52 | |||
53 | if (status & SSSR_TUR) | ||
54 | printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port); | ||
55 | |||
56 | if (status & SSSR_BCE) | ||
57 | printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port); | ||
58 | |||
59 | return IRQ_HANDLED; | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * ssp_write_word - write a word to the SSP port | ||
64 | * @data: 32-bit, MSB justified data to write. | ||
65 | * | ||
66 | * Wait for a free entry in the SSP transmit FIFO, and write a data | ||
67 | * word to the SSP port. | ||
68 | * | ||
69 | * The caller is expected to perform the necessary locking. | ||
70 | * | ||
71 | * Returns: | ||
72 | * %-ETIMEDOUT timeout occurred (for future) | ||
73 | * 0 success | ||
74 | */ | ||
75 | int ssp_write_word(struct ssp_dev *dev, u32 data) | ||
76 | { | ||
77 | while (!(SSSR_P(dev->port) & SSSR_TNF)) | ||
78 | cpu_relax(); | ||
79 | |||
80 | SSDR_P(dev->port) = data; | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * ssp_read_word - read a word from the SSP port | ||
87 | * | ||
88 | * Wait for a data word in the SSP receive FIFO, and return the | ||
89 | * received data. Data is LSB justified. | ||
90 | * | ||
91 | * Note: Currently, if data is not expected to be received, this | ||
92 | * function will wait for ever. | ||
93 | * | ||
94 | * The caller is expected to perform the necessary locking. | ||
95 | * | ||
96 | * Returns: | ||
97 | * %-ETIMEDOUT timeout occurred (for future) | ||
98 | * 32-bit data success | ||
99 | */ | ||
100 | int ssp_read_word(struct ssp_dev *dev) | ||
101 | { | ||
102 | while (!(SSSR_P(dev->port) & SSSR_RNE)) | ||
103 | cpu_relax(); | ||
104 | |||
105 | return SSDR_P(dev->port); | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * ssp_flush - flush the transmit and receive FIFOs | ||
110 | * | ||
111 | * Wait for the SSP to idle, and ensure that the receive FIFO | ||
112 | * is empty. | ||
113 | * | ||
114 | * The caller is expected to perform the necessary locking. | ||
115 | */ | ||
116 | void ssp_flush(struct ssp_dev *dev) | ||
117 | { | ||
118 | do { | ||
119 | while (SSSR_P(dev->port) & SSSR_RNE) { | ||
120 | (void) SSDR_P(dev->port); | ||
121 | } | ||
122 | } while (SSSR_P(dev->port) & SSSR_BSY); | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * ssp_enable - enable the SSP port | ||
127 | * | ||
128 | * Turn on the SSP port. | ||
129 | */ | ||
130 | void ssp_enable(struct ssp_dev *dev) | ||
131 | { | ||
132 | SSCR0_P(dev->port) |= SSCR0_SSE; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * ssp_disable - shut down the SSP port | ||
137 | * | ||
138 | * Turn off the SSP port, optionally powering it down. | ||
139 | */ | ||
140 | void ssp_disable(struct ssp_dev *dev) | ||
141 | { | ||
142 | SSCR0_P(dev->port) &= ~SSCR0_SSE; | ||
143 | } | ||
144 | |||
145 | /** | ||
146 | * ssp_save_state - save the SSP configuration | ||
147 | * @ssp: pointer to structure to save SSP configuration | ||
148 | * | ||
149 | * Save the configured SSP state for suspend. | ||
150 | */ | ||
151 | void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp) | ||
152 | { | ||
153 | ssp->cr0 = SSCR0_P(dev->port); | ||
154 | ssp->cr1 = SSCR1_P(dev->port); | ||
155 | ssp->to = SSTO_P(dev->port); | ||
156 | ssp->psp = SSPSP_P(dev->port); | ||
157 | |||
158 | SSCR0_P(dev->port) &= ~SSCR0_SSE; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * ssp_restore_state - restore a previously saved SSP configuration | ||
163 | * @ssp: pointer to configuration saved by ssp_save_state | ||
164 | * | ||
165 | * Restore the SSP configuration saved previously by ssp_save_state. | ||
166 | */ | ||
167 | void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp) | ||
168 | { | ||
169 | SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE; | ||
170 | |||
171 | SSCR0_P(dev->port) = ssp->cr0 & ~SSCR0_SSE; | ||
172 | SSCR1_P(dev->port) = ssp->cr1; | ||
173 | SSTO_P(dev->port) = ssp->to; | ||
174 | SSPSP_P(dev->port) = ssp->psp; | ||
175 | |||
176 | SSCR0_P(dev->port) = ssp->cr0; | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * ssp_config - configure SSP port settings | ||
181 | * @mode: port operating mode | ||
182 | * @flags: port config flags | ||
183 | * @psp_flags: port PSP config flags | ||
184 | * @speed: port speed | ||
185 | * | ||
186 | * Port MUST be disabled by ssp_disable before making any config changes. | ||
187 | */ | ||
188 | int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed) | ||
189 | { | ||
190 | dev->mode = mode; | ||
191 | dev->flags = flags; | ||
192 | dev->psp_flags = psp_flags; | ||
193 | dev->speed = speed; | ||
194 | |||
195 | /* set up port type, speed, port settings */ | ||
196 | SSCR0_P(dev->port) = (dev->speed | dev->mode); | ||
197 | SSCR1_P(dev->port) = dev->flags; | ||
198 | SSPSP_P(dev->port) = dev->psp_flags; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * ssp_init - setup the SSP port | ||
205 | * | ||
206 | * initialise and claim resources for the SSP port. | ||
207 | * | ||
208 | * Returns: | ||
209 | * %-ENODEV if the SSP port is unavailable | ||
210 | * %-EBUSY if the resources are already in use | ||
211 | * %0 on success | ||
212 | */ | ||
213 | int ssp_init(struct ssp_dev *dev, u32 port) | ||
214 | { | ||
215 | int ret, irq; | ||
216 | |||
217 | if (port > PXA_SSP_PORTS || port == 0) | ||
218 | return -ENODEV; | ||
219 | |||
220 | down(&sem); | ||
221 | if (use_count[port - 1]) { | ||
222 | up(&sem); | ||
223 | return -EBUSY; | ||
224 | } | ||
225 | use_count[port - 1]++; | ||
226 | |||
227 | if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) { | ||
228 | use_count[port - 1]--; | ||
229 | up(&sem); | ||
230 | return -EBUSY; | ||
231 | } | ||
232 | |||
233 | switch (port) { | ||
234 | case 1: | ||
235 | irq = IRQ_SSP; | ||
236 | break; | ||
237 | #if defined (CONFIG_PXA27x) | ||
238 | case 2: | ||
239 | irq = IRQ_SSP2; | ||
240 | break; | ||
241 | case 3: | ||
242 | irq = IRQ_SSP3; | ||
243 | break; | ||
244 | #else | ||
245 | case 2: | ||
246 | irq = IRQ_NSSP; | ||
247 | break; | ||
248 | case 3: | ||
249 | irq = IRQ_ASSP; | ||
250 | break; | ||
251 | #endif | ||
252 | default: | ||
253 | return -ENODEV; | ||
254 | } | ||
255 | |||
256 | dev->port = port; | ||
257 | |||
258 | ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev); | ||
259 | if (ret) | ||
260 | goto out_region; | ||
261 | |||
262 | /* turn on SSP port clock */ | ||
263 | switch (dev->port) { | ||
264 | #if defined (CONFIG_PXA27x) | ||
265 | case 1: | ||
266 | pxa_set_cken(CKEN23_SSP1, 1); | ||
267 | break; | ||
268 | case 2: | ||
269 | pxa_set_cken(CKEN3_SSP2, 1); | ||
270 | break; | ||
271 | case 3: | ||
272 | pxa_set_cken(CKEN4_SSP3, 1); | ||
273 | break; | ||
274 | #else | ||
275 | case 1: | ||
276 | pxa_set_cken(CKEN3_SSP, 1); | ||
277 | break; | ||
278 | case 2: | ||
279 | pxa_set_cken(CKEN9_NSSP, 1); | ||
280 | break; | ||
281 | case 3: | ||
282 | pxa_set_cken(CKEN10_ASSP, 1); | ||
283 | break; | ||
284 | #endif | ||
285 | } | ||
286 | |||
287 | up(&sem); | ||
288 | return 0; | ||
289 | |||
290 | out_region: | ||
291 | release_mem_region(__PREG(SSCR0_P(port)), 0x2c); | ||
292 | use_count[port - 1]--; | ||
293 | up(&sem); | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * ssp_exit - undo the effects of ssp_init | ||
299 | * | ||
300 | * release and free resources for the SSP port. | ||
301 | */ | ||
302 | void ssp_exit(struct ssp_dev *dev) | ||
303 | { | ||
304 | int irq; | ||
305 | |||
306 | down(&sem); | ||
307 | SSCR0_P(dev->port) &= ~SSCR0_SSE; | ||
308 | |||
309 | /* find irq, save power and turn off SSP port clock */ | ||
310 | switch (dev->port) { | ||
311 | #if defined (CONFIG_PXA27x) | ||
312 | case 1: | ||
313 | irq = IRQ_SSP; | ||
314 | pxa_set_cken(CKEN23_SSP1, 0); | ||
315 | break; | ||
316 | case 2: | ||
317 | irq = IRQ_SSP2; | ||
318 | pxa_set_cken(CKEN3_SSP2, 0); | ||
319 | break; | ||
320 | case 3: | ||
321 | irq = IRQ_SSP3; | ||
322 | pxa_set_cken(CKEN4_SSP3, 0); | ||
323 | break; | ||
324 | #else | ||
325 | case 1: | ||
326 | irq = IRQ_SSP; | ||
327 | pxa_set_cken(CKEN3_SSP, 0); | ||
328 | break; | ||
329 | case 2: | ||
330 | irq = IRQ_NSSP; | ||
331 | pxa_set_cken(CKEN9_NSSP, 0); | ||
332 | break; | ||
333 | case 3: | ||
334 | irq = IRQ_ASSP; | ||
335 | pxa_set_cken(CKEN10_ASSP, 0); | ||
336 | break; | ||
337 | #endif | ||
338 | default: | ||
339 | printk(KERN_WARNING "SSP: tried to close invalid port\n"); | ||
340 | return; | ||
341 | } | ||
342 | |||
343 | free_irq(irq, dev); | ||
344 | release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); | ||
345 | use_count[dev->port - 1]--; | ||
346 | up(&sem); | ||
347 | } | ||
348 | |||
349 | EXPORT_SYMBOL(ssp_write_word); | ||
350 | EXPORT_SYMBOL(ssp_read_word); | ||
351 | EXPORT_SYMBOL(ssp_flush); | ||
352 | EXPORT_SYMBOL(ssp_enable); | ||
353 | EXPORT_SYMBOL(ssp_disable); | ||
354 | EXPORT_SYMBOL(ssp_save_state); | ||
355 | EXPORT_SYMBOL(ssp_restore_state); | ||
356 | EXPORT_SYMBOL(ssp_init); | ||
357 | EXPORT_SYMBOL(ssp_exit); | ||
358 | EXPORT_SYMBOL(ssp_config); | ||
359 | |||
360 | MODULE_DESCRIPTION("PXA SSP driver"); | ||
361 | MODULE_AUTHOR("Liam Girdwood"); | ||
362 | MODULE_LICENSE("GPL"); | ||
363 | |||
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c new file mode 100644 index 000000000000..473fb6173f72 --- /dev/null +++ b/arch/arm/mach-pxa/time.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-pxa/time.c | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Jun 15, 2001 | ||
6 | * Copyright: MontaVista Software Inc. | ||
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 | #include <linux/config.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/time.h> | ||
19 | #include <linux/signal.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/sched.h> | ||
22 | |||
23 | #include <asm/system.h> | ||
24 | #include <asm/hardware.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/leds.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/mach/irq.h> | ||
29 | #include <asm/mach/time.h> | ||
30 | #include <asm/arch/pxa-regs.h> | ||
31 | |||
32 | |||
33 | static inline unsigned long pxa_get_rtc_time(void) | ||
34 | { | ||
35 | return RCNR; | ||
36 | } | ||
37 | |||
38 | static int pxa_set_rtc(void) | ||
39 | { | ||
40 | unsigned long current_time = xtime.tv_sec; | ||
41 | |||
42 | if (RTSR & RTSR_ALE) { | ||
43 | /* make sure not to forward the clock over an alarm */ | ||
44 | unsigned long alarm = RTAR; | ||
45 | if (current_time >= alarm && alarm >= RCNR) | ||
46 | return -ERESTARTSYS; | ||
47 | } | ||
48 | RCNR = current_time; | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | /* IRQs are disabled before entering here from do_gettimeofday() */ | ||
53 | static unsigned long pxa_gettimeoffset (void) | ||
54 | { | ||
55 | long ticks_to_match, elapsed, usec; | ||
56 | |||
57 | /* Get ticks before next timer match */ | ||
58 | ticks_to_match = OSMR0 - OSCR; | ||
59 | |||
60 | /* We need elapsed ticks since last match */ | ||
61 | elapsed = LATCH - ticks_to_match; | ||
62 | |||
63 | /* don't get fooled by the workaround in pxa_timer_interrupt() */ | ||
64 | if (elapsed <= 0) | ||
65 | return 0; | ||
66 | |||
67 | /* Now convert them to usec */ | ||
68 | usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; | ||
69 | |||
70 | return usec; | ||
71 | } | ||
72 | |||
73 | static irqreturn_t | ||
74 | pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
75 | { | ||
76 | int next_match; | ||
77 | |||
78 | write_seqlock(&xtime_lock); | ||
79 | |||
80 | /* Loop until we get ahead of the free running timer. | ||
81 | * This ensures an exact clock tick count and time accuracy. | ||
82 | * IRQs are disabled inside the loop to ensure coherence between | ||
83 | * lost_ticks (updated in do_timer()) and the match reg value, so we | ||
84 | * can use do_gettimeofday() from interrupt handlers. | ||
85 | * | ||
86 | * HACK ALERT: it seems that the PXA timer regs aren't updated right | ||
87 | * away in all cases when a write occurs. We therefore compare with | ||
88 | * 8 instead of 0 in the while() condition below to avoid missing a | ||
89 | * match if OSCR has already reached the next OSMR value. | ||
90 | * Experience has shown that up to 6 ticks are needed to work around | ||
91 | * this problem, but let's use 8 to be conservative. Note that this | ||
92 | * affect things only when the timer IRQ has been delayed by nearly | ||
93 | * exactly one tick period which should be a pretty rare event. | ||
94 | */ | ||
95 | do { | ||
96 | timer_tick(regs); | ||
97 | OSSR = OSSR_M0; /* Clear match on timer 0 */ | ||
98 | next_match = (OSMR0 += LATCH); | ||
99 | } while( (signed long)(next_match - OSCR) <= 8 ); | ||
100 | |||
101 | write_sequnlock(&xtime_lock); | ||
102 | |||
103 | return IRQ_HANDLED; | ||
104 | } | ||
105 | |||
106 | static struct irqaction pxa_timer_irq = { | ||
107 | .name = "PXA Timer Tick", | ||
108 | .flags = SA_INTERRUPT, | ||
109 | .handler = pxa_timer_interrupt | ||
110 | }; | ||
111 | |||
112 | static void __init pxa_timer_init(void) | ||
113 | { | ||
114 | struct timespec tv; | ||
115 | |||
116 | set_rtc = pxa_set_rtc; | ||
117 | |||
118 | tv.tv_nsec = 0; | ||
119 | tv.tv_sec = pxa_get_rtc_time(); | ||
120 | do_settimeofday(&tv); | ||
121 | |||
122 | OSMR0 = 0; /* set initial match at 0 */ | ||
123 | OSSR = 0xf; /* clear status on all timers */ | ||
124 | setup_irq(IRQ_OST0, &pxa_timer_irq); | ||
125 | OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ | ||
126 | OSCR = 0; /* initialize free-running timer, force first match */ | ||
127 | } | ||
128 | |||
129 | #ifdef CONFIG_PM | ||
130 | static unsigned long osmr[4], oier; | ||
131 | |||
132 | static void pxa_timer_suspend(void) | ||
133 | { | ||
134 | osmr[0] = OSMR0; | ||
135 | osmr[1] = OSMR1; | ||
136 | osmr[2] = OSMR2; | ||
137 | osmr[3] = OSMR3; | ||
138 | oier = OIER; | ||
139 | } | ||
140 | |||
141 | static void pxa_timer_resume(void) | ||
142 | { | ||
143 | OSMR0 = osmr[0]; | ||
144 | OSMR1 = osmr[1]; | ||
145 | OSMR2 = osmr[2]; | ||
146 | OSMR3 = osmr[3]; | ||
147 | OIER = oier; | ||
148 | |||
149 | /* | ||
150 | * OSMR0 is the system timer: make sure OSCR is sufficiently behind | ||
151 | */ | ||
152 | OSCR = OSMR0 - LATCH; | ||
153 | } | ||
154 | #else | ||
155 | #define pxa_timer_suspend NULL | ||
156 | #define pxa_timer_resume NULL | ||
157 | #endif | ||
158 | |||
159 | struct sys_timer pxa_timer = { | ||
160 | .init = pxa_timer_init, | ||
161 | .suspend = pxa_timer_suspend, | ||
162 | .resume = pxa_timer_resume, | ||
163 | .offset = pxa_gettimeoffset, | ||
164 | }; | ||