Commit | Line | Data |
---|---|---|
64cd04d0 ML |
1 | /* |
2 | * DBAu1300 init and platform device setup. | |
3 | * | |
4 | * (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com> | |
5 | */ | |
6 | ||
415e0fec | 7 | #include <linux/clk.h> |
64cd04d0 ML |
8 | #include <linux/dma-mapping.h> |
9 | #include <linux/gpio.h> | |
10 | #include <linux/gpio_keys.h> | |
11 | #include <linux/init.h> | |
12 | #include <linux/input.h> /* KEY_* codes */ | |
13 | #include <linux/i2c.h> | |
14 | #include <linux/io.h> | |
15 | #include <linux/leds.h> | |
16 | #include <linux/ata_platform.h> | |
17 | #include <linux/mmc/host.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/mtd/mtd.h> | |
20 | #include <linux/mtd/nand.h> | |
21 | #include <linux/mtd/partitions.h> | |
22 | #include <linux/platform_device.h> | |
23 | #include <linux/smsc911x.h> | |
c64bb5f0 | 24 | #include <linux/wm97xx.h> |
64cd04d0 ML |
25 | |
26 | #include <asm/mach-au1x00/au1000.h> | |
832f5dac | 27 | #include <asm/mach-au1x00/gpio-au1300.h> |
64cd04d0 | 28 | #include <asm/mach-au1x00/au1100_mmc.h> |
a9b71a8f | 29 | #include <asm/mach-au1x00/au1200fb.h> |
64cd04d0 ML |
30 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
31 | #include <asm/mach-au1x00/au1xxx_psc.h> | |
64cd04d0 ML |
32 | #include <asm/mach-db1x00/bcsr.h> |
33 | #include <asm/mach-au1x00/prom.h> | |
34 | ||
35 | #include "platform.h" | |
36 | ||
a16afa53 ML |
37 | /* FPGA (external mux) interrupt sources */ |
38 | #define DB1300_FIRST_INT (ALCHEMY_GPIC_INT_LAST + 1) | |
39 | #define DB1300_IDE_INT (DB1300_FIRST_INT + 0) | |
40 | #define DB1300_ETH_INT (DB1300_FIRST_INT + 1) | |
41 | #define DB1300_CF_INT (DB1300_FIRST_INT + 2) | |
42 | #define DB1300_VIDEO_INT (DB1300_FIRST_INT + 4) | |
43 | #define DB1300_HDMI_INT (DB1300_FIRST_INT + 5) | |
44 | #define DB1300_DC_INT (DB1300_FIRST_INT + 6) | |
45 | #define DB1300_FLASH_INT (DB1300_FIRST_INT + 7) | |
46 | #define DB1300_CF_INSERT_INT (DB1300_FIRST_INT + 8) | |
47 | #define DB1300_CF_EJECT_INT (DB1300_FIRST_INT + 9) | |
48 | #define DB1300_AC97_INT (DB1300_FIRST_INT + 10) | |
49 | #define DB1300_AC97_PEN_INT (DB1300_FIRST_INT + 11) | |
50 | #define DB1300_SD1_INSERT_INT (DB1300_FIRST_INT + 12) | |
51 | #define DB1300_SD1_EJECT_INT (DB1300_FIRST_INT + 13) | |
52 | #define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14) | |
53 | #define DB1300_HOST_VBUS_OC_INT (DB1300_FIRST_INT + 15) | |
54 | #define DB1300_LAST_INT (DB1300_FIRST_INT + 15) | |
55 | ||
56 | /* SMSC9210 CS */ | |
57 | #define DB1300_ETH_PHYS_ADDR 0x19000000 | |
58 | #define DB1300_ETH_PHYS_END 0x197fffff | |
59 | ||
60 | /* ATA CS */ | |
61 | #define DB1300_IDE_PHYS_ADDR 0x18800000 | |
62 | #define DB1300_IDE_REG_SHIFT 5 | |
63 | #define DB1300_IDE_PHYS_LEN (16 << DB1300_IDE_REG_SHIFT) | |
64 | ||
65 | /* NAND CS */ | |
66 | #define DB1300_NAND_PHYS_ADDR 0x20000000 | |
67 | #define DB1300_NAND_PHYS_END 0x20000fff | |
68 | ||
69 | ||
64cd04d0 ML |
70 | static struct i2c_board_info db1300_i2c_devs[] __initdata = { |
71 | { I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec */ | |
72 | { I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */ | |
73 | }; | |
74 | ||
75 | /* multifunction pins to assign to GPIO controller */ | |
76 | static int db1300_gpio_pins[] __initdata = { | |
77 | AU1300_PIN_LCDPWM0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_WAKE1, | |
78 | AU1300_PIN_WAKE2, AU1300_PIN_WAKE3, AU1300_PIN_FG3AUX, | |
79 | AU1300_PIN_EXTCLK1, | |
80 | -1, /* terminator */ | |
81 | }; | |
82 | ||
83 | /* multifunction pins to assign to device functions */ | |
84 | static int db1300_dev_pins[] __initdata = { | |
85 | /* wake-from-str pins 0-3 */ | |
86 | AU1300_PIN_WAKE0, | |
87 | /* external clock sources for PSC0 */ | |
88 | AU1300_PIN_EXTCLK0, | |
89 | /* 8bit MMC interface on SD0: 6-9 */ | |
90 | AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6, | |
91 | AU1300_PIN_SD0DAT7, | |
92 | /* UART1 pins: 11-18 */ | |
93 | AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR, | |
94 | AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR, | |
95 | AU1300_PIN_U1RX, AU1300_PIN_U1TX, | |
96 | /* UART0 pins: 19-24 */ | |
97 | AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR, | |
98 | AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR, | |
99 | /* UART2: 25-26 */ | |
100 | AU1300_PIN_U2RX, AU1300_PIN_U2TX, | |
101 | /* UART3: 27-28 */ | |
102 | AU1300_PIN_U3RX, AU1300_PIN_U3TX, | |
103 | /* LCD controller PWMs, ext pixclock: 30-31 */ | |
104 | AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN, | |
105 | /* SD1 interface: 32-37 */ | |
106 | AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2, | |
107 | AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK, | |
108 | /* SD2 interface: 38-43 */ | |
109 | AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2, | |
110 | AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK, | |
111 | /* PSC0/1 clocks: 44-45 */ | |
112 | AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK, | |
113 | /* PSCs: 46-49/50-53/54-57/58-61 */ | |
114 | AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0, | |
115 | AU1300_PIN_PSC0D1, | |
116 | AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0, | |
117 | AU1300_PIN_PSC1D1, | |
70342287 | 118 | AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2D0, |
64cd04d0 ML |
119 | AU1300_PIN_PSC2D1, |
120 | AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0, | |
121 | AU1300_PIN_PSC3D1, | |
122 | /* PCMCIA interface: 62-70 */ | |
123 | AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16, | |
124 | AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT, | |
125 | AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW, | |
126 | /* camera interface H/V sync inputs: 71-72 */ | |
127 | AU1300_PIN_CIMLS, AU1300_PIN_CIMFS, | |
128 | /* PSC2/3 clocks: 73-74 */ | |
129 | AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK, | |
130 | -1, /* terminator */ | |
131 | }; | |
132 | ||
133 | static void __init db1300_gpio_config(void) | |
134 | { | |
135 | int *i; | |
136 | ||
137 | i = &db1300_dev_pins[0]; | |
138 | while (*i != -1) | |
139 | au1300_pinfunc_to_dev(*i++); | |
140 | ||
141 | i = &db1300_gpio_pins[0]; | |
142 | while (*i != -1) | |
143 | au1300_gpio_direction_input(*i++);/* implies pin_to_gpio */ | |
144 | ||
145 | au1300_set_dbdma_gpio(1, AU1300_PIN_FG3AUX); | |
146 | } | |
147 | ||
64cd04d0 ML |
148 | /**********************************************************************/ |
149 | ||
150 | static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, | |
151 | unsigned int ctrl) | |
152 | { | |
b1afda0e | 153 | struct nand_chip *this = mtd_to_nand(mtd); |
64cd04d0 ML |
154 | unsigned long ioaddr = (unsigned long)this->IO_ADDR_W; |
155 | ||
156 | ioaddr &= 0xffffff00; | |
157 | ||
158 | if (ctrl & NAND_CLE) { | |
159 | ioaddr += MEM_STNAND_CMD; | |
160 | } else if (ctrl & NAND_ALE) { | |
161 | ioaddr += MEM_STNAND_ADDR; | |
162 | } else { | |
163 | /* assume we want to r/w real data by default */ | |
164 | ioaddr += MEM_STNAND_DATA; | |
165 | } | |
166 | this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr; | |
167 | if (cmd != NAND_CMD_NONE) { | |
168 | __raw_writeb(cmd, this->IO_ADDR_W); | |
169 | wmb(); | |
170 | } | |
171 | } | |
172 | ||
173 | static int au1300_nand_device_ready(struct mtd_info *mtd) | |
174 | { | |
9cf12167 | 175 | return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1; |
64cd04d0 ML |
176 | } |
177 | ||
64cd04d0 ML |
178 | static struct mtd_partition db1300_nand_parts[] = { |
179 | { | |
180 | .name = "NAND FS 0", | |
70342287 | 181 | .offset = 0, |
64cd04d0 ML |
182 | .size = 8 * 1024 * 1024, |
183 | }, | |
184 | { | |
185 | .name = "NAND FS 1", | |
70342287 | 186 | .offset = MTDPART_OFS_APPEND, |
64cd04d0 ML |
187 | .size = MTDPART_SIZ_FULL |
188 | }, | |
189 | }; | |
190 | ||
191 | struct platform_nand_data db1300_nand_platdata = { | |
192 | .chip = { | |
193 | .nr_chips = 1, | |
194 | .chip_offset = 0, | |
195 | .nr_partitions = ARRAY_SIZE(db1300_nand_parts), | |
196 | .partitions = db1300_nand_parts, | |
197 | .chip_delay = 20, | |
64cd04d0 ML |
198 | }, |
199 | .ctrl = { | |
200 | .dev_ready = au1300_nand_device_ready, | |
201 | .cmd_ctrl = au1300_nand_cmd_ctrl, | |
202 | }, | |
203 | }; | |
204 | ||
205 | static struct resource db1300_nand_res[] = { | |
206 | [0] = { | |
207 | .start = DB1300_NAND_PHYS_ADDR, | |
208 | .end = DB1300_NAND_PHYS_ADDR + 0xff, | |
209 | .flags = IORESOURCE_MEM, | |
210 | }, | |
211 | }; | |
212 | ||
213 | static struct platform_device db1300_nand_dev = { | |
214 | .name = "gen_nand", | |
215 | .num_resources = ARRAY_SIZE(db1300_nand_res), | |
216 | .resource = db1300_nand_res, | |
217 | .id = -1, | |
218 | .dev = { | |
219 | .platform_data = &db1300_nand_platdata, | |
220 | } | |
221 | }; | |
222 | ||
223 | /**********************************************************************/ | |
224 | ||
225 | static struct resource db1300_eth_res[] = { | |
226 | [0] = { | |
227 | .start = DB1300_ETH_PHYS_ADDR, | |
228 | .end = DB1300_ETH_PHYS_END, | |
229 | .flags = IORESOURCE_MEM, | |
230 | }, | |
231 | [1] = { | |
232 | .start = DB1300_ETH_INT, | |
233 | .end = DB1300_ETH_INT, | |
234 | .flags = IORESOURCE_IRQ, | |
235 | }, | |
236 | }; | |
237 | ||
238 | static struct smsc911x_platform_config db1300_eth_config = { | |
239 | .phy_interface = PHY_INTERFACE_MODE_MII, | |
240 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, | |
241 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, | |
242 | .flags = SMSC911X_USE_32BIT, | |
243 | }; | |
244 | ||
245 | static struct platform_device db1300_eth_dev = { | |
246 | .name = "smsc911x", | |
247 | .id = -1, | |
248 | .num_resources = ARRAY_SIZE(db1300_eth_res), | |
249 | .resource = db1300_eth_res, | |
250 | .dev = { | |
251 | .platform_data = &db1300_eth_config, | |
252 | }, | |
253 | }; | |
254 | ||
255 | /**********************************************************************/ | |
256 | ||
257 | static struct resource au1300_psc1_res[] = { | |
258 | [0] = { | |
259 | .start = AU1300_PSC1_PHYS_ADDR, | |
260 | .end = AU1300_PSC1_PHYS_ADDR + 0x0fff, | |
261 | .flags = IORESOURCE_MEM, | |
262 | }, | |
263 | [1] = { | |
264 | .start = AU1300_PSC1_INT, | |
265 | .end = AU1300_PSC1_INT, | |
266 | .flags = IORESOURCE_IRQ, | |
267 | }, | |
268 | [2] = { | |
269 | .start = AU1300_DSCR_CMD0_PSC1_TX, | |
270 | .end = AU1300_DSCR_CMD0_PSC1_TX, | |
271 | .flags = IORESOURCE_DMA, | |
272 | }, | |
273 | [3] = { | |
274 | .start = AU1300_DSCR_CMD0_PSC1_RX, | |
275 | .end = AU1300_DSCR_CMD0_PSC1_RX, | |
276 | .flags = IORESOURCE_DMA, | |
277 | }, | |
278 | }; | |
279 | ||
280 | static struct platform_device db1300_ac97_dev = { | |
281 | .name = "au1xpsc_ac97", | |
282 | .id = 1, /* PSC ID. match with AC97 codec ID! */ | |
283 | .num_resources = ARRAY_SIZE(au1300_psc1_res), | |
284 | .resource = au1300_psc1_res, | |
285 | }; | |
286 | ||
287 | /**********************************************************************/ | |
288 | ||
289 | static struct resource au1300_psc2_res[] = { | |
290 | [0] = { | |
291 | .start = AU1300_PSC2_PHYS_ADDR, | |
292 | .end = AU1300_PSC2_PHYS_ADDR + 0x0fff, | |
293 | .flags = IORESOURCE_MEM, | |
294 | }, | |
295 | [1] = { | |
296 | .start = AU1300_PSC2_INT, | |
297 | .end = AU1300_PSC2_INT, | |
298 | .flags = IORESOURCE_IRQ, | |
299 | }, | |
300 | [2] = { | |
301 | .start = AU1300_DSCR_CMD0_PSC2_TX, | |
302 | .end = AU1300_DSCR_CMD0_PSC2_TX, | |
303 | .flags = IORESOURCE_DMA, | |
304 | }, | |
305 | [3] = { | |
306 | .start = AU1300_DSCR_CMD0_PSC2_RX, | |
307 | .end = AU1300_DSCR_CMD0_PSC2_RX, | |
308 | .flags = IORESOURCE_DMA, | |
309 | }, | |
310 | }; | |
311 | ||
312 | static struct platform_device db1300_i2s_dev = { | |
313 | .name = "au1xpsc_i2s", | |
314 | .id = 2, /* PSC ID */ | |
315 | .num_resources = ARRAY_SIZE(au1300_psc2_res), | |
316 | .resource = au1300_psc2_res, | |
317 | }; | |
318 | ||
319 | /**********************************************************************/ | |
320 | ||
321 | static struct resource au1300_psc3_res[] = { | |
322 | [0] = { | |
323 | .start = AU1300_PSC3_PHYS_ADDR, | |
324 | .end = AU1300_PSC3_PHYS_ADDR + 0x0fff, | |
325 | .flags = IORESOURCE_MEM, | |
326 | }, | |
327 | [1] = { | |
328 | .start = AU1300_PSC3_INT, | |
329 | .end = AU1300_PSC3_INT, | |
330 | .flags = IORESOURCE_IRQ, | |
331 | }, | |
332 | [2] = { | |
333 | .start = AU1300_DSCR_CMD0_PSC3_TX, | |
334 | .end = AU1300_DSCR_CMD0_PSC3_TX, | |
335 | .flags = IORESOURCE_DMA, | |
336 | }, | |
337 | [3] = { | |
338 | .start = AU1300_DSCR_CMD0_PSC3_RX, | |
339 | .end = AU1300_DSCR_CMD0_PSC3_RX, | |
340 | .flags = IORESOURCE_DMA, | |
341 | }, | |
342 | }; | |
343 | ||
344 | static struct platform_device db1300_i2c_dev = { | |
345 | .name = "au1xpsc_smbus", | |
346 | .id = 0, /* bus number */ | |
347 | .num_resources = ARRAY_SIZE(au1300_psc3_res), | |
348 | .resource = au1300_psc3_res, | |
349 | }; | |
350 | ||
351 | /**********************************************************************/ | |
352 | ||
353 | /* proper key assignments when facing the LCD panel. For key assignments | |
354 | * according to the schematics swap up with down and left with right. | |
355 | * I chose to use it to emulate the arrow keys of a keyboard. | |
356 | */ | |
357 | static struct gpio_keys_button db1300_5waysw_arrowkeys[] = { | |
358 | { | |
359 | .code = KEY_DOWN, | |
360 | .gpio = AU1300_PIN_LCDPWM0, | |
361 | .type = EV_KEY, | |
362 | .debounce_interval = 1, | |
363 | .active_low = 1, | |
364 | .desc = "5waysw-down", | |
365 | }, | |
366 | { | |
367 | .code = KEY_UP, | |
368 | .gpio = AU1300_PIN_PSC2SYNC1, | |
369 | .type = EV_KEY, | |
370 | .debounce_interval = 1, | |
371 | .active_low = 1, | |
372 | .desc = "5waysw-up", | |
373 | }, | |
374 | { | |
375 | .code = KEY_RIGHT, | |
376 | .gpio = AU1300_PIN_WAKE3, | |
377 | .type = EV_KEY, | |
378 | .debounce_interval = 1, | |
379 | .active_low = 1, | |
380 | .desc = "5waysw-right", | |
381 | }, | |
382 | { | |
383 | .code = KEY_LEFT, | |
384 | .gpio = AU1300_PIN_WAKE2, | |
385 | .type = EV_KEY, | |
386 | .debounce_interval = 1, | |
387 | .active_low = 1, | |
388 | .desc = "5waysw-left", | |
389 | }, | |
390 | { | |
391 | .code = KEY_ENTER, | |
392 | .gpio = AU1300_PIN_WAKE1, | |
393 | .type = EV_KEY, | |
394 | .debounce_interval = 1, | |
395 | .active_low = 1, | |
396 | .desc = "5waysw-push", | |
397 | }, | |
398 | }; | |
399 | ||
400 | static struct gpio_keys_platform_data db1300_5waysw_data = { | |
401 | .buttons = db1300_5waysw_arrowkeys, | |
402 | .nbuttons = ARRAY_SIZE(db1300_5waysw_arrowkeys), | |
403 | .rep = 1, | |
404 | .name = "db1300-5wayswitch", | |
405 | }; | |
406 | ||
407 | static struct platform_device db1300_5waysw_dev = { | |
408 | .name = "gpio-keys", | |
409 | .dev = { | |
410 | .platform_data = &db1300_5waysw_data, | |
411 | }, | |
412 | }; | |
413 | ||
414 | /**********************************************************************/ | |
415 | ||
64cd04d0 ML |
416 | static struct pata_platform_info db1300_ide_info = { |
417 | .ioport_shift = DB1300_IDE_REG_SHIFT, | |
418 | }; | |
419 | ||
420 | #define IDE_ALT_START (14 << DB1300_IDE_REG_SHIFT) | |
421 | static struct resource db1300_ide_res[] = { | |
422 | [0] = { | |
423 | .start = DB1300_IDE_PHYS_ADDR, | |
424 | .end = DB1300_IDE_PHYS_ADDR + IDE_ALT_START - 1, | |
425 | .flags = IORESOURCE_MEM, | |
426 | }, | |
427 | [1] = { | |
428 | .start = DB1300_IDE_PHYS_ADDR + IDE_ALT_START, | |
429 | .end = DB1300_IDE_PHYS_ADDR + DB1300_IDE_PHYS_LEN - 1, | |
430 | .flags = IORESOURCE_MEM, | |
431 | }, | |
432 | [2] = { | |
433 | .start = DB1300_IDE_INT, | |
434 | .end = DB1300_IDE_INT, | |
435 | .flags = IORESOURCE_IRQ, | |
436 | }, | |
437 | }; | |
438 | ||
439 | static struct platform_device db1300_ide_dev = { | |
440 | .dev = { | |
441 | .platform_data = &db1300_ide_info, | |
442 | }, | |
443 | .name = "pata_platform", | |
444 | .resource = db1300_ide_res, | |
445 | .num_resources = ARRAY_SIZE(db1300_ide_res), | |
446 | }; | |
447 | ||
448 | /**********************************************************************/ | |
449 | ||
450 | static irqreturn_t db1300_mmc_cd(int irq, void *ptr) | |
451 | { | |
452 | void(*mmc_cd)(struct mmc_host *, unsigned long); | |
453 | ||
454 | /* disable the one currently screaming. No other way to shut it up */ | |
455 | if (irq == DB1300_SD1_INSERT_INT) { | |
456 | disable_irq_nosync(DB1300_SD1_INSERT_INT); | |
457 | enable_irq(DB1300_SD1_EJECT_INT); | |
458 | } else { | |
459 | disable_irq_nosync(DB1300_SD1_EJECT_INT); | |
460 | enable_irq(DB1300_SD1_INSERT_INT); | |
461 | } | |
462 | ||
463 | /* link against CONFIG_MMC=m. We can only be called once MMC core has | |
464 | * initialized the controller, so symbol_get() should always succeed. | |
465 | */ | |
466 | mmc_cd = symbol_get(mmc_detect_change); | |
467 | mmc_cd(ptr, msecs_to_jiffies(500)); | |
468 | symbol_put(mmc_detect_change); | |
469 | ||
470 | return IRQ_HANDLED; | |
471 | } | |
472 | ||
473 | static int db1300_mmc_card_readonly(void *mmc_host) | |
474 | { | |
475 | /* it uses SD1 interface, but the DB1200's SD0 bit in the CPLD */ | |
476 | return bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP; | |
477 | } | |
478 | ||
479 | static int db1300_mmc_card_inserted(void *mmc_host) | |
480 | { | |
481 | return bcsr_read(BCSR_SIGSTAT) & (1 << 12); /* insertion irq signal */ | |
482 | } | |
483 | ||
484 | static int db1300_mmc_cd_setup(void *mmc_host, int en) | |
485 | { | |
486 | int ret; | |
487 | ||
488 | if (en) { | |
489 | ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0, | |
490 | "sd_insert", mmc_host); | |
491 | if (ret) | |
492 | goto out; | |
493 | ||
494 | ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0, | |
495 | "sd_eject", mmc_host); | |
496 | if (ret) { | |
497 | free_irq(DB1300_SD1_INSERT_INT, mmc_host); | |
498 | goto out; | |
499 | } | |
500 | ||
501 | if (db1300_mmc_card_inserted(mmc_host)) | |
502 | enable_irq(DB1300_SD1_EJECT_INT); | |
503 | else | |
504 | enable_irq(DB1300_SD1_INSERT_INT); | |
505 | ||
506 | } else { | |
507 | free_irq(DB1300_SD1_INSERT_INT, mmc_host); | |
508 | free_irq(DB1300_SD1_EJECT_INT, mmc_host); | |
509 | } | |
510 | ret = 0; | |
511 | out: | |
512 | return ret; | |
513 | } | |
514 | ||
515 | static void db1300_mmcled_set(struct led_classdev *led, | |
516 | enum led_brightness brightness) | |
517 | { | |
518 | if (brightness != LED_OFF) | |
519 | bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0); | |
520 | else | |
521 | bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0); | |
522 | } | |
523 | ||
524 | static struct led_classdev db1300_mmc_led = { | |
70342287 | 525 | .brightness_set = db1300_mmcled_set, |
64cd04d0 ML |
526 | }; |
527 | ||
528 | struct au1xmmc_platform_data db1300_sd1_platdata = { | |
529 | .cd_setup = db1300_mmc_cd_setup, | |
530 | .card_inserted = db1300_mmc_card_inserted, | |
531 | .card_readonly = db1300_mmc_card_readonly, | |
532 | .led = &db1300_mmc_led, | |
533 | }; | |
534 | ||
535 | static struct resource au1300_sd1_res[] = { | |
536 | [0] = { | |
537 | .start = AU1300_SD1_PHYS_ADDR, | |
538 | .end = AU1300_SD1_PHYS_ADDR, | |
539 | .flags = IORESOURCE_MEM, | |
540 | }, | |
541 | [1] = { | |
542 | .start = AU1300_SD1_INT, | |
543 | .end = AU1300_SD1_INT, | |
544 | .flags = IORESOURCE_IRQ, | |
545 | }, | |
546 | [2] = { | |
547 | .start = AU1300_DSCR_CMD0_SDMS_TX1, | |
548 | .end = AU1300_DSCR_CMD0_SDMS_TX1, | |
549 | .flags = IORESOURCE_DMA, | |
550 | }, | |
551 | [3] = { | |
552 | .start = AU1300_DSCR_CMD0_SDMS_RX1, | |
553 | .end = AU1300_DSCR_CMD0_SDMS_RX1, | |
554 | .flags = IORESOURCE_DMA, | |
555 | }, | |
556 | }; | |
557 | ||
558 | static struct platform_device db1300_sd1_dev = { | |
559 | .dev = { | |
560 | .platform_data = &db1300_sd1_platdata, | |
561 | }, | |
562 | .name = "au1xxx-mmc", | |
563 | .id = 1, | |
564 | .resource = au1300_sd1_res, | |
565 | .num_resources = ARRAY_SIZE(au1300_sd1_res), | |
566 | }; | |
567 | ||
568 | /**********************************************************************/ | |
569 | ||
570 | static int db1300_movinand_inserted(void *mmc_host) | |
571 | { | |
572 | return 0; /* disable for now, it doesn't work yet */ | |
573 | } | |
574 | ||
575 | static int db1300_movinand_readonly(void *mmc_host) | |
576 | { | |
577 | return 0; | |
578 | } | |
579 | ||
580 | static void db1300_movinand_led_set(struct led_classdev *led, | |
581 | enum led_brightness brightness) | |
582 | { | |
583 | if (brightness != LED_OFF) | |
584 | bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0); | |
585 | else | |
586 | bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1); | |
587 | } | |
588 | ||
589 | static struct led_classdev db1300_movinand_led = { | |
590 | .brightness_set = db1300_movinand_led_set, | |
591 | }; | |
592 | ||
593 | struct au1xmmc_platform_data db1300_sd0_platdata = { | |
594 | .card_inserted = db1300_movinand_inserted, | |
595 | .card_readonly = db1300_movinand_readonly, | |
596 | .led = &db1300_movinand_led, | |
597 | .mask_host_caps = MMC_CAP_NEEDS_POLL, | |
598 | }; | |
599 | ||
600 | static struct resource au1300_sd0_res[] = { | |
601 | [0] = { | |
602 | .start = AU1100_SD0_PHYS_ADDR, | |
603 | .end = AU1100_SD0_PHYS_ADDR, | |
604 | .flags = IORESOURCE_MEM, | |
605 | }, | |
606 | [1] = { | |
607 | .start = AU1300_SD0_INT, | |
608 | .end = AU1300_SD0_INT, | |
609 | .flags = IORESOURCE_IRQ, | |
610 | }, | |
611 | [2] = { | |
612 | .start = AU1300_DSCR_CMD0_SDMS_TX0, | |
613 | .end = AU1300_DSCR_CMD0_SDMS_TX0, | |
614 | .flags = IORESOURCE_DMA, | |
615 | }, | |
616 | [3] = { | |
617 | .start = AU1300_DSCR_CMD0_SDMS_RX0, | |
618 | .end = AU1300_DSCR_CMD0_SDMS_RX0, | |
619 | .flags = IORESOURCE_DMA, | |
620 | }, | |
621 | }; | |
622 | ||
623 | static struct platform_device db1300_sd0_dev = { | |
624 | .dev = { | |
625 | .platform_data = &db1300_sd0_platdata, | |
626 | }, | |
627 | .name = "au1xxx-mmc", | |
628 | .id = 0, | |
629 | .resource = au1300_sd0_res, | |
630 | .num_resources = ARRAY_SIZE(au1300_sd0_res), | |
631 | }; | |
632 | ||
633 | /**********************************************************************/ | |
634 | ||
635 | static struct platform_device db1300_wm9715_dev = { | |
636 | .name = "wm9712-codec", | |
637 | .id = 1, /* ID of PSC for AC97 audio, see asoc glue! */ | |
638 | }; | |
639 | ||
640 | static struct platform_device db1300_ac97dma_dev = { | |
641 | .name = "au1xpsc-pcm", | |
642 | .id = 1, /* PSC ID */ | |
643 | }; | |
644 | ||
645 | static struct platform_device db1300_i2sdma_dev = { | |
646 | .name = "au1xpsc-pcm", | |
647 | .id = 2, /* PSC ID */ | |
648 | }; | |
649 | ||
650 | static struct platform_device db1300_sndac97_dev = { | |
651 | .name = "db1300-ac97", | |
652 | }; | |
653 | ||
654 | static struct platform_device db1300_sndi2s_dev = { | |
655 | .name = "db1300-i2s", | |
656 | }; | |
657 | ||
658 | /**********************************************************************/ | |
659 | ||
a9b71a8f ML |
660 | static int db1300fb_panel_index(void) |
661 | { | |
662 | return 9; /* DB1300_800x480 */ | |
663 | } | |
664 | ||
665 | static int db1300fb_panel_init(void) | |
666 | { | |
667 | /* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */ | |
668 | bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD, | |
669 | BCSR_BOARD_LCDBL); | |
670 | return 0; | |
671 | } | |
672 | ||
673 | static int db1300fb_panel_shutdown(void) | |
674 | { | |
675 | /* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */ | |
676 | bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL, | |
677 | BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD); | |
678 | return 0; | |
679 | } | |
680 | ||
681 | static struct au1200fb_platdata db1300fb_pd = { | |
682 | .panel_index = db1300fb_panel_index, | |
683 | .panel_init = db1300fb_panel_init, | |
70342287 | 684 | .panel_shutdown = db1300fb_panel_shutdown, |
a9b71a8f ML |
685 | }; |
686 | ||
64cd04d0 ML |
687 | static struct resource au1300_lcd_res[] = { |
688 | [0] = { | |
689 | .start = AU1200_LCD_PHYS_ADDR, | |
690 | .end = AU1200_LCD_PHYS_ADDR + 0x800 - 1, | |
691 | .flags = IORESOURCE_MEM, | |
692 | }, | |
693 | [1] = { | |
694 | .start = AU1300_LCD_INT, | |
695 | .end = AU1300_LCD_INT, | |
696 | .flags = IORESOURCE_IRQ, | |
697 | } | |
698 | }; | |
699 | ||
700 | static u64 au1300_lcd_dmamask = DMA_BIT_MASK(32); | |
701 | ||
702 | static struct platform_device db1300_lcd_dev = { | |
703 | .name = "au1200-lcd", | |
704 | .id = 0, | |
705 | .dev = { | |
706 | .dma_mask = &au1300_lcd_dmamask, | |
707 | .coherent_dma_mask = DMA_BIT_MASK(32), | |
a9b71a8f | 708 | .platform_data = &db1300fb_pd, |
64cd04d0 ML |
709 | }, |
710 | .num_resources = ARRAY_SIZE(au1300_lcd_res), | |
711 | .resource = au1300_lcd_res, | |
712 | }; | |
713 | ||
714 | /**********************************************************************/ | |
715 | ||
c64bb5f0 ML |
716 | static void db1300_wm97xx_irqen(struct wm97xx *wm, int enable) |
717 | { | |
718 | if (enable) | |
719 | enable_irq(DB1300_AC97_PEN_INT); | |
720 | else | |
721 | disable_irq_nosync(DB1300_AC97_PEN_INT); | |
722 | } | |
723 | ||
724 | static struct wm97xx_mach_ops db1300_wm97xx_ops = { | |
725 | .irq_enable = db1300_wm97xx_irqen, | |
726 | .irq_gpio = WM97XX_GPIO_3, | |
727 | }; | |
728 | ||
729 | static int db1300_wm97xx_probe(struct platform_device *pdev) | |
730 | { | |
731 | struct wm97xx *wm = platform_get_drvdata(pdev); | |
732 | ||
733 | /* external pendown indicator */ | |
734 | wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, | |
735 | WM97XX_GPIO_POL_LOW, WM97XX_GPIO_STICKY, | |
736 | WM97XX_GPIO_WAKE); | |
737 | ||
738 | /* internal "virtual" pendown gpio */ | |
739 | wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT, | |
740 | WM97XX_GPIO_POL_LOW, WM97XX_GPIO_NOTSTICKY, | |
741 | WM97XX_GPIO_NOWAKE); | |
742 | ||
743 | wm->pen_irq = DB1300_AC97_PEN_INT; | |
744 | ||
745 | return wm97xx_register_mach_ops(wm, &db1300_wm97xx_ops); | |
746 | } | |
747 | ||
748 | static struct platform_driver db1300_wm97xx_driver = { | |
749 | .driver.name = "wm97xx-touch", | |
750 | .driver.owner = THIS_MODULE, | |
751 | .probe = db1300_wm97xx_probe, | |
752 | }; | |
753 | ||
754 | /**********************************************************************/ | |
755 | ||
64cd04d0 ML |
756 | static struct platform_device *db1300_dev[] __initdata = { |
757 | &db1300_eth_dev, | |
758 | &db1300_i2c_dev, | |
759 | &db1300_5waysw_dev, | |
64cd04d0 ML |
760 | &db1300_nand_dev, |
761 | &db1300_ide_dev, | |
762 | &db1300_sd0_dev, | |
763 | &db1300_sd1_dev, | |
764 | &db1300_lcd_dev, | |
765 | &db1300_ac97_dev, | |
766 | &db1300_i2s_dev, | |
767 | &db1300_wm9715_dev, | |
768 | &db1300_ac97dma_dev, | |
769 | &db1300_i2sdma_dev, | |
770 | &db1300_sndac97_dev, | |
771 | &db1300_sndi2s_dev, | |
772 | }; | |
773 | ||
bd8510df | 774 | int __init db1300_dev_setup(void) |
64cd04d0 ML |
775 | { |
776 | int swapped, cpldirq; | |
415e0fec | 777 | struct clk *c; |
64cd04d0 ML |
778 | |
779 | /* setup CPLD IRQ muxer */ | |
780 | cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1); | |
781 | irq_set_irq_type(cpldirq, IRQ_TYPE_LEVEL_HIGH); | |
782 | bcsr_init_irq(DB1300_FIRST_INT, DB1300_LAST_INT, cpldirq); | |
783 | ||
784 | /* insert/eject IRQs: one always triggers so don't enable them | |
785 | * when doing request_irq() on them. DB1200 has this bug too. | |
786 | */ | |
787 | irq_set_status_flags(DB1300_SD1_INSERT_INT, IRQ_NOAUTOEN); | |
788 | irq_set_status_flags(DB1300_SD1_EJECT_INT, IRQ_NOAUTOEN); | |
789 | irq_set_status_flags(DB1300_CF_INSERT_INT, IRQ_NOAUTOEN); | |
790 | irq_set_status_flags(DB1300_CF_EJECT_INT, IRQ_NOAUTOEN); | |
791 | ||
792 | /* | |
793 | * setup board | |
794 | */ | |
795 | prom_get_ethernet_addr(&db1300_eth_config.mac[0]); | |
796 | ||
797 | i2c_register_board_info(0, db1300_i2c_devs, | |
798 | ARRAY_SIZE(db1300_i2c_devs)); | |
799 | ||
c64bb5f0 ML |
800 | if (platform_driver_register(&db1300_wm97xx_driver)) |
801 | pr_warn("DB1300: failed to init touch pen irq support!\n"); | |
802 | ||
64cd04d0 ML |
803 | /* Audio PSC clock is supplied by codecs (PSC1, 2) */ |
804 | __raw_writel(PSC_SEL_CLK_SERCLK, | |
805 | (void __iomem *)KSEG1ADDR(AU1300_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); | |
806 | wmb(); | |
807 | __raw_writel(PSC_SEL_CLK_SERCLK, | |
808 | (void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET); | |
809 | wmb(); | |
c02a505e | 810 | /* I2C driver wants 50MHz, get as close as possible */ |
415e0fec ML |
811 | c = clk_get(NULL, "psc3_intclk"); |
812 | if (!IS_ERR(c)) { | |
c02a505e | 813 | clk_set_rate(c, 50000000); |
415e0fec ML |
814 | clk_prepare_enable(c); |
815 | clk_put(c); | |
816 | } | |
64cd04d0 ML |
817 | __raw_writel(PSC_SEL_CLK_INTCLK, |
818 | (void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET); | |
819 | wmb(); | |
820 | ||
821 | /* enable power to USB ports */ | |
822 | bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_USBHPWR | BCSR_RESETS_OTGPWR); | |
823 | ||
824 | /* although it is socket #0, it uses the CPLD bits which previous boards | |
825 | * have used for socket #1. | |
826 | */ | |
827 | db1x_register_pcmcia_socket( | |
828 | AU1000_PCMCIA_ATTR_PHYS_ADDR, | |
829 | AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x00400000 - 1, | |
830 | AU1000_PCMCIA_MEM_PHYS_ADDR, | |
831 | AU1000_PCMCIA_MEM_PHYS_ADDR + 0x00400000 - 1, | |
832 | AU1000_PCMCIA_IO_PHYS_ADDR, | |
833 | AU1000_PCMCIA_IO_PHYS_ADDR + 0x00010000 - 1, | |
834 | DB1300_CF_INT, DB1300_CF_INSERT_INT, 0, DB1300_CF_EJECT_INT, 1); | |
835 | ||
836 | swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT; | |
837 | db1x_register_norflash(64 << 20, 2, swapped); | |
838 | ||
839 | return platform_add_devices(db1300_dev, ARRAY_SIZE(db1300_dev)); | |
840 | } | |
64cd04d0 ML |
841 | |
842 | ||
bd8510df | 843 | int __init db1300_board_setup(void) |
64cd04d0 ML |
844 | { |
845 | unsigned short whoami; | |
846 | ||
64cd04d0 ML |
847 | bcsr_init(DB1300_BCSR_PHYS_ADDR, |
848 | DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS); | |
849 | ||
850 | whoami = bcsr_read(BCSR_WHOAMI); | |
970e268d ML |
851 | if (BCSR_WHOAMI_BOARD(whoami) != BCSR_WHOAMI_DB1300) |
852 | return -ENODEV; | |
853 | ||
854 | db1300_gpio_config(); | |
855 | ||
64cd04d0 ML |
856 | printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t" |
857 | "BoardID %d CPLD Rev %d DaughtercardID %d\n", | |
858 | BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami), | |
859 | BCSR_WHOAMI_DCID(whoami)); | |
860 | ||
861 | /* enable UARTs, YAMON only enables #2 */ | |
862 | alchemy_uart_enable(AU1300_UART0_PHYS_ADDR); | |
863 | alchemy_uart_enable(AU1300_UART1_PHYS_ADDR); | |
864 | alchemy_uart_enable(AU1300_UART3_PHYS_ADDR); | |
bd8510df ML |
865 | |
866 | return 0; | |
64cd04d0 | 867 | } |