diff options
author | Mike Rapoport <mike@compulab.co.il> | 2007-07-18 06:31:46 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-07-20 12:45:15 -0400 |
commit | 3d50527bbf1b68e5206263ade414f0d966b00f74 (patch) | |
tree | e81f3439165bb4796c819f207fa857775ff69109 /arch/arm/mach-pxa/em-x270.c | |
parent | b750a09385d7c464113ae8915e63541a163fbac8 (diff) |
[ARM] 4475/2: EM-x270 board support
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-pxa/em-x270.c')
-rw-r--r-- | arch/arm/mach-pxa/em-x270.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c new file mode 100644 index 000000000000..3d0ad5065ee5 --- /dev/null +++ b/arch/arm/mach-pxa/em-x270.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * Support for CompuLab EM-x270 platform | ||
3 | * | ||
4 | * Copyright (C) 2007 CompuLab, Ltd. | ||
5 | * Author: Mike Rapoport <mike@compulab.co.il> | ||
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 | #include <linux/irq.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | |||
15 | #include <linux/dm9000.h> | ||
16 | #include <linux/rtc-v3020.h> | ||
17 | |||
18 | #include <linux/mtd/nand.h> | ||
19 | #include <linux/mtd/partitions.h> | ||
20 | |||
21 | #include <asm/mach-types.h> | ||
22 | |||
23 | #include <asm/mach/arch.h> | ||
24 | |||
25 | #include <asm/arch/pxa-regs.h> | ||
26 | #include <asm/arch/pxafb.h> | ||
27 | #include <asm/arch/ohci.h> | ||
28 | #include <asm/arch/mmc.h> | ||
29 | #include <asm/arch/bitfield.h> | ||
30 | |||
31 | #include "generic.h" | ||
32 | |||
33 | /* GPIO IRQ usage */ | ||
34 | #define EM_X270_MMC_PD (105) | ||
35 | #define EM_X270_ETHIRQ IRQ_GPIO(41) | ||
36 | #define EM_X270_MMC_IRQ IRQ_GPIO(13) | ||
37 | |||
38 | static struct resource em_x270_dm9k_resource[] = { | ||
39 | [0] = { | ||
40 | .start = PXA_CS2_PHYS, | ||
41 | .end = PXA_CS2_PHYS + 3, | ||
42 | .flags = IORESOURCE_MEM, | ||
43 | }, | ||
44 | [1] = { | ||
45 | .start = PXA_CS2_PHYS + 8, | ||
46 | .end = PXA_CS2_PHYS + 8 + 0x3f, | ||
47 | .flags = IORESOURCE_MEM, | ||
48 | }, | ||
49 | [2] = { | ||
50 | .start = EM_X270_ETHIRQ, | ||
51 | .end = EM_X270_ETHIRQ, | ||
52 | .flags = IORESOURCE_IRQ, | ||
53 | } | ||
54 | }; | ||
55 | |||
56 | /* for the moment we limit ourselves to 32bit IO until some | ||
57 | * better IO routines can be written and tested | ||
58 | */ | ||
59 | static struct dm9000_plat_data em_x270_dm9k_platdata = { | ||
60 | .flags = DM9000_PLATF_32BITONLY, | ||
61 | }; | ||
62 | |||
63 | /* Ethernet device */ | ||
64 | static struct platform_device em_x270_dm9k = { | ||
65 | .name = "dm9000", | ||
66 | .id = 0, | ||
67 | .num_resources = ARRAY_SIZE(em_x270_dm9k_resource), | ||
68 | .resource = em_x270_dm9k_resource, | ||
69 | .dev = { | ||
70 | .platform_data = &em_x270_dm9k_platdata, | ||
71 | } | ||
72 | }; | ||
73 | |||
74 | /* audio device */ | ||
75 | static struct platform_device em_x270_audio = { | ||
76 | .name = "pxa2xx-ac97", | ||
77 | .id = -1, | ||
78 | }; | ||
79 | |||
80 | /* WM9712 touchscreen controller. Hopefully the driver will make it to | ||
81 | * the mainstream sometime */ | ||
82 | static struct platform_device em_x270_ts = { | ||
83 | .name = "wm97xx-ts", | ||
84 | .id = -1, | ||
85 | }; | ||
86 | |||
87 | /* RTC */ | ||
88 | static struct resource em_x270_v3020_resource[] = { | ||
89 | [0] = { | ||
90 | .start = PXA_CS4_PHYS, | ||
91 | .end = PXA_CS4_PHYS + 3, | ||
92 | .flags = IORESOURCE_MEM, | ||
93 | }, | ||
94 | }; | ||
95 | |||
96 | static struct v3020_platform_data em_x270_v3020_platdata = { | ||
97 | .leftshift = 0, | ||
98 | }; | ||
99 | |||
100 | static struct platform_device em_x270_rtc = { | ||
101 | .name = "v3020", | ||
102 | .num_resources = ARRAY_SIZE(em_x270_v3020_resource), | ||
103 | .resource = em_x270_v3020_resource, | ||
104 | .id = -1, | ||
105 | .dev = { | ||
106 | .platform_data = &em_x270_v3020_platdata, | ||
107 | } | ||
108 | }; | ||
109 | |||
110 | /* NAND flash */ | ||
111 | #define GPIO_NAND_CS (11) | ||
112 | #define GPIO_NAND_RB (56) | ||
113 | |||
114 | static inline void nand_cs_on(void) | ||
115 | { | ||
116 | GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); | ||
117 | } | ||
118 | |||
119 | static void nand_cs_off(void) | ||
120 | { | ||
121 | dsb(); | ||
122 | |||
123 | GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); | ||
124 | } | ||
125 | |||
126 | /* hardware specific access to control-lines */ | ||
127 | static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat, | ||
128 | unsigned int ctrl) | ||
129 | { | ||
130 | struct nand_chip *this = mtd->priv; | ||
131 | unsigned long nandaddr = (unsigned long)this->IO_ADDR_W; | ||
132 | |||
133 | dsb(); | ||
134 | |||
135 | if (ctrl & NAND_CTRL_CHANGE) { | ||
136 | if (ctrl & NAND_ALE) | ||
137 | nandaddr |= (1 << 3); | ||
138 | else | ||
139 | nandaddr &= ~(1 << 3); | ||
140 | if (ctrl & NAND_CLE) | ||
141 | nandaddr |= (1 << 2); | ||
142 | else | ||
143 | nandaddr &= ~(1 << 2); | ||
144 | if (ctrl & NAND_NCE) | ||
145 | nand_cs_on(); | ||
146 | else | ||
147 | nand_cs_off(); | ||
148 | } | ||
149 | |||
150 | dsb(); | ||
151 | this->IO_ADDR_W = (void __iomem *)nandaddr; | ||
152 | if (dat != NAND_CMD_NONE) | ||
153 | writel(dat, this->IO_ADDR_W); | ||
154 | |||
155 | dsb(); | ||
156 | } | ||
157 | |||
158 | /* read device ready pin */ | ||
159 | static int em_x270_nand_device_ready(struct mtd_info *mtd) | ||
160 | { | ||
161 | dsb(); | ||
162 | |||
163 | return GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB); | ||
164 | } | ||
165 | |||
166 | static struct mtd_partition em_x270_partition_info[] = { | ||
167 | [0] = { | ||
168 | .name = "em_x270-0", | ||
169 | .offset = 0, | ||
170 | .size = SZ_4M, | ||
171 | }, | ||
172 | [1] = { | ||
173 | .name = "em_x270-1", | ||
174 | .offset = MTDPART_OFS_APPEND, | ||
175 | .size = MTDPART_SIZ_FULL | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static const char *em_x270_part_probes[] = { "cmdlinepart", NULL }; | ||
180 | |||
181 | struct platform_nand_data em_x270_nand_platdata = { | ||
182 | .chip = { | ||
183 | .nr_chips = 1, | ||
184 | .chip_offset = 0, | ||
185 | .nr_partitions = ARRAY_SIZE(em_x270_partition_info), | ||
186 | .partitions = em_x270_partition_info, | ||
187 | .chip_delay = 20, | ||
188 | .part_probe_types = em_x270_part_probes, | ||
189 | }, | ||
190 | .ctrl = { | ||
191 | .hwcontrol = 0, | ||
192 | .dev_ready = em_x270_nand_device_ready, | ||
193 | .select_chip = 0, | ||
194 | .cmd_ctrl = em_x270_nand_cmd_ctl, | ||
195 | }, | ||
196 | }; | ||
197 | |||
198 | static struct resource em_x270_nand_resource[] = { | ||
199 | [0] = { | ||
200 | .start = PXA_CS1_PHYS, | ||
201 | .end = PXA_CS1_PHYS + 12, | ||
202 | .flags = IORESOURCE_MEM, | ||
203 | }, | ||
204 | }; | ||
205 | |||
206 | static struct platform_device em_x270_nand = { | ||
207 | .name = "gen_nand", | ||
208 | .num_resources = ARRAY_SIZE(em_x270_nand_resource), | ||
209 | .resource = em_x270_nand_resource, | ||
210 | .id = -1, | ||
211 | .dev = { | ||
212 | .platform_data = &em_x270_nand_platdata, | ||
213 | } | ||
214 | }; | ||
215 | |||
216 | /* platform devices */ | ||
217 | static struct platform_device *platform_devices[] __initdata = { | ||
218 | &em_x270_dm9k, | ||
219 | &em_x270_audio, | ||
220 | &em_x270_ts, | ||
221 | &em_x270_rtc, | ||
222 | &em_x270_nand, | ||
223 | }; | ||
224 | |||
225 | |||
226 | /* PXA27x OHCI controller setup */ | ||
227 | static int em_x270_ohci_init(struct device *dev) | ||
228 | { | ||
229 | /* Set the Power Control Polarity Low */ | ||
230 | UHCHR = (UHCHR | UHCHR_PCPL) & | ||
231 | ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE); | ||
232 | |||
233 | /* enable port 2 transiever */ | ||
234 | UP2OCR = UP2OCR_HXS | UP2OCR_HXOE; | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static struct pxaohci_platform_data em_x270_ohci_platform_data = { | ||
240 | .port_mode = PMM_PERPORT_MODE, | ||
241 | .init = em_x270_ohci_init, | ||
242 | }; | ||
243 | |||
244 | |||
245 | static int em_x270_mci_init(struct device *dev, | ||
246 | irq_handler_t em_x270_detect_int, | ||
247 | void *data) | ||
248 | { | ||
249 | int err; | ||
250 | |||
251 | /* setup GPIO for PXA27x MMC controller */ | ||
252 | pxa_gpio_mode(GPIO32_MMCCLK_MD); | ||
253 | pxa_gpio_mode(GPIO112_MMCCMD_MD); | ||
254 | pxa_gpio_mode(GPIO92_MMCDAT0_MD); | ||
255 | pxa_gpio_mode(GPIO109_MMCDAT1_MD); | ||
256 | pxa_gpio_mode(GPIO110_MMCDAT2_MD); | ||
257 | pxa_gpio_mode(GPIO111_MMCDAT3_MD); | ||
258 | |||
259 | /* EM-X270 uses GPIO13 as SD power enable */ | ||
260 | pxa_gpio_mode(EM_X270_MMC_PD | GPIO_OUT); | ||
261 | |||
262 | err = request_irq(EM_X270_MMC_IRQ, em_x270_detect_int, | ||
263 | IRQF_DISABLED | IRQF_TRIGGER_FALLING, | ||
264 | "MMC card detect", data); | ||
265 | if (err) { | ||
266 | printk(KERN_ERR "%s: can't request MMC card detect IRQ: %d\n", | ||
267 | __FUNCTION__, err); | ||
268 | return err; | ||
269 | } | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static void em_x270_mci_setpower(struct device *dev, unsigned int vdd) | ||
275 | { | ||
276 | /* | ||
277 | FIXME: current hardware implementation does not allow to | ||
278 | enable/disable MMC power. This will be fixed in next HW releases, | ||
279 | and we'll need to add implmentation here. | ||
280 | */ | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | static void em_x270_mci_exit(struct device *dev, void *data) | ||
285 | { | ||
286 | free_irq(EM_X270_MMC_IRQ, data); | ||
287 | } | ||
288 | |||
289 | static struct pxamci_platform_data em_x270_mci_platform_data = { | ||
290 | .ocr_mask = MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31, | ||
291 | .init = em_x270_mci_init, | ||
292 | .setpower = em_x270_mci_setpower, | ||
293 | .exit = em_x270_mci_exit, | ||
294 | }; | ||
295 | |||
296 | /* LCD 480x640 */ | ||
297 | static struct pxafb_mode_info em_x270_lcd_mode = { | ||
298 | .pixclock = 50000, | ||
299 | .bpp = 16, | ||
300 | .xres = 480, | ||
301 | .yres = 640, | ||
302 | .hsync_len = 8, | ||
303 | .vsync_len = 2, | ||
304 | .left_margin = 8, | ||
305 | .upper_margin = 0, | ||
306 | .right_margin = 24, | ||
307 | .lower_margin = 4, | ||
308 | .cmap_greyscale = 0, | ||
309 | }; | ||
310 | |||
311 | static struct pxafb_mach_info em_x270_lcd = { | ||
312 | .modes = &em_x270_lcd_mode, | ||
313 | .num_modes = 1, | ||
314 | .cmap_inverse = 0, | ||
315 | .cmap_static = 0, | ||
316 | .lccr0 = LCCR0_PAS, | ||
317 | .lccr3 = LCCR3_PixClkDiv(0x01) | LCCR3_Acb(0xff), | ||
318 | }; | ||
319 | |||
320 | static void __init em_x270_init(void) | ||
321 | { | ||
322 | /* setup LCD */ | ||
323 | set_pxa_fb_info(&em_x270_lcd); | ||
324 | |||
325 | /* register EM-X270 platform devices */ | ||
326 | platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); | ||
327 | |||
328 | /* set MCI and OHCI platform parameters */ | ||
329 | pxa_set_mci_info(&em_x270_mci_platform_data); | ||
330 | pxa_set_ohci_info(&em_x270_ohci_platform_data); | ||
331 | |||
332 | /* setup STUART GPIOs */ | ||
333 | pxa_gpio_mode(GPIO46_STRXD_MD); | ||
334 | pxa_gpio_mode(GPIO47_STTXD_MD); | ||
335 | |||
336 | /* setup BTUART GPIOs */ | ||
337 | pxa_gpio_mode(GPIO42_BTRXD_MD); | ||
338 | pxa_gpio_mode(GPIO43_BTTXD_MD); | ||
339 | pxa_gpio_mode(GPIO44_BTCTS_MD); | ||
340 | pxa_gpio_mode(GPIO45_BTRTS_MD); | ||
341 | |||
342 | /* Setup interrupt for dm9000 */ | ||
343 | set_irq_type(EM_X270_ETHIRQ, IRQT_RISING); | ||
344 | } | ||
345 | |||
346 | MACHINE_START(EM_X270, "Compulab EM-x270") | ||
347 | .boot_params = 0xa0000100, | ||
348 | .phys_io = 0x40000000, | ||
349 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, | ||
350 | .map_io = pxa_map_io, | ||
351 | .init_irq = pxa27x_init_irq, | ||
352 | .timer = &pxa_timer, | ||
353 | .init_machine = em_x270_init, | ||
354 | MACHINE_END | ||