1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * DBAu1300 init and platform device setup. |
4 | * |
5 | * (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com> |
6 | */ |
7 | |
8 | #include <linux/clk.h> |
9 | #include <linux/dma-mapping.h> |
10 | #include <linux/gpio.h> |
11 | #include <linux/gpio_keys.h> |
12 | #include <linux/init.h> |
13 | #include <linux/input.h> /* KEY_* codes */ |
14 | #include <linux/i2c.h> |
15 | #include <linux/io.h> |
16 | #include <linux/leds.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/ata_platform.h> |
19 | #include <linux/mmc/host.h> |
20 | #include <linux/mtd/mtd.h> |
21 | #include <linux/mtd/platnand.h> |
22 | #include <linux/platform_device.h> |
23 | #include <linux/smsc911x.h> |
24 | #include <linux/wm97xx.h> |
25 | |
26 | #include <asm/mach-au1x00/au1000.h> |
27 | #include <asm/mach-au1x00/gpio-au1300.h> |
28 | #include <asm/mach-au1x00/au1100_mmc.h> |
29 | #include <asm/mach-au1x00/au1200fb.h> |
30 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
31 | #include <asm/mach-au1x00/au1xxx_psc.h> |
32 | #include <asm/mach-db1x00/bcsr.h> |
33 | #include <asm/mach-au1x00/prom.h> |
34 | |
35 | #include "platform.h" |
36 | |
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 | |
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, |
118 | AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2D0, |
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 | |
148 | /**********************************************************************/ |
149 | |
150 | static u64 au1300_all_dmamask = DMA_BIT_MASK(32); |
151 | |
152 | static void au1300_nand_cmd_ctrl(struct nand_chip *this, int cmd, |
153 | unsigned int ctrl) |
154 | { |
155 | unsigned long ioaddr = (unsigned long)this->legacy.IO_ADDR_W; |
156 | |
157 | ioaddr &= 0xffffff00; |
158 | |
159 | if (ctrl & NAND_CLE) { |
160 | ioaddr += MEM_STNAND_CMD; |
161 | } else if (ctrl & NAND_ALE) { |
162 | ioaddr += MEM_STNAND_ADDR; |
163 | } else { |
164 | /* assume we want to r/w real data by default */ |
165 | ioaddr += MEM_STNAND_DATA; |
166 | } |
167 | this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = (void __iomem *)ioaddr; |
168 | if (cmd != NAND_CMD_NONE) { |
169 | __raw_writeb(val: cmd, addr: this->legacy.IO_ADDR_W); |
170 | wmb(); |
171 | } |
172 | } |
173 | |
174 | static int au1300_nand_device_ready(struct nand_chip *this) |
175 | { |
176 | return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1; |
177 | } |
178 | |
179 | static struct mtd_partition db1300_nand_parts[] = { |
180 | { |
181 | .name = "NAND FS 0" , |
182 | .offset = 0, |
183 | .size = 8 * 1024 * 1024, |
184 | }, |
185 | { |
186 | .name = "NAND FS 1" , |
187 | .offset = MTDPART_OFS_APPEND, |
188 | .size = MTDPART_SIZ_FULL |
189 | }, |
190 | }; |
191 | |
192 | struct platform_nand_data db1300_nand_platdata = { |
193 | .chip = { |
194 | .nr_chips = 1, |
195 | .chip_offset = 0, |
196 | .nr_partitions = ARRAY_SIZE(db1300_nand_parts), |
197 | .partitions = db1300_nand_parts, |
198 | .chip_delay = 20, |
199 | }, |
200 | .ctrl = { |
201 | .dev_ready = au1300_nand_device_ready, |
202 | .cmd_ctrl = au1300_nand_cmd_ctrl, |
203 | }, |
204 | }; |
205 | |
206 | static struct resource db1300_nand_res[] = { |
207 | [0] = { |
208 | .start = DB1300_NAND_PHYS_ADDR, |
209 | .end = DB1300_NAND_PHYS_ADDR + 0xff, |
210 | .flags = IORESOURCE_MEM, |
211 | }, |
212 | }; |
213 | |
214 | static struct platform_device db1300_nand_dev = { |
215 | .name = "gen_nand" , |
216 | .num_resources = ARRAY_SIZE(db1300_nand_res), |
217 | .resource = db1300_nand_res, |
218 | .id = -1, |
219 | .dev = { |
220 | .platform_data = &db1300_nand_platdata, |
221 | } |
222 | }; |
223 | |
224 | /**********************************************************************/ |
225 | |
226 | static struct resource db1300_eth_res[] = { |
227 | [0] = { |
228 | .start = DB1300_ETH_PHYS_ADDR, |
229 | .end = DB1300_ETH_PHYS_END, |
230 | .flags = IORESOURCE_MEM, |
231 | }, |
232 | [1] = { |
233 | .start = DB1300_ETH_INT, |
234 | .end = DB1300_ETH_INT, |
235 | .flags = IORESOURCE_IRQ, |
236 | }, |
237 | }; |
238 | |
239 | static struct smsc911x_platform_config db1300_eth_config = { |
240 | .phy_interface = PHY_INTERFACE_MODE_MII, |
241 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, |
242 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, |
243 | .flags = SMSC911X_USE_32BIT, |
244 | }; |
245 | |
246 | static struct platform_device db1300_eth_dev = { |
247 | .name = "smsc911x" , |
248 | .id = -1, |
249 | .num_resources = ARRAY_SIZE(db1300_eth_res), |
250 | .resource = db1300_eth_res, |
251 | .dev = { |
252 | .platform_data = &db1300_eth_config, |
253 | }, |
254 | }; |
255 | |
256 | /**********************************************************************/ |
257 | |
258 | static struct resource au1300_psc1_res[] = { |
259 | [0] = { |
260 | .start = AU1300_PSC1_PHYS_ADDR, |
261 | .end = AU1300_PSC1_PHYS_ADDR + 0x0fff, |
262 | .flags = IORESOURCE_MEM, |
263 | }, |
264 | [1] = { |
265 | .start = AU1300_PSC1_INT, |
266 | .end = AU1300_PSC1_INT, |
267 | .flags = IORESOURCE_IRQ, |
268 | }, |
269 | [2] = { |
270 | .start = AU1300_DSCR_CMD0_PSC1_TX, |
271 | .end = AU1300_DSCR_CMD0_PSC1_TX, |
272 | .flags = IORESOURCE_DMA, |
273 | }, |
274 | [3] = { |
275 | .start = AU1300_DSCR_CMD0_PSC1_RX, |
276 | .end = AU1300_DSCR_CMD0_PSC1_RX, |
277 | .flags = IORESOURCE_DMA, |
278 | }, |
279 | }; |
280 | |
281 | static struct platform_device db1300_ac97_dev = { |
282 | .name = "au1xpsc_ac97" , |
283 | .id = 1, /* PSC ID. match with AC97 codec ID! */ |
284 | .num_resources = ARRAY_SIZE(au1300_psc1_res), |
285 | .resource = au1300_psc1_res, |
286 | }; |
287 | |
288 | /**********************************************************************/ |
289 | |
290 | static struct resource au1300_psc2_res[] = { |
291 | [0] = { |
292 | .start = AU1300_PSC2_PHYS_ADDR, |
293 | .end = AU1300_PSC2_PHYS_ADDR + 0x0fff, |
294 | .flags = IORESOURCE_MEM, |
295 | }, |
296 | [1] = { |
297 | .start = AU1300_PSC2_INT, |
298 | .end = AU1300_PSC2_INT, |
299 | .flags = IORESOURCE_IRQ, |
300 | }, |
301 | [2] = { |
302 | .start = AU1300_DSCR_CMD0_PSC2_TX, |
303 | .end = AU1300_DSCR_CMD0_PSC2_TX, |
304 | .flags = IORESOURCE_DMA, |
305 | }, |
306 | [3] = { |
307 | .start = AU1300_DSCR_CMD0_PSC2_RX, |
308 | .end = AU1300_DSCR_CMD0_PSC2_RX, |
309 | .flags = IORESOURCE_DMA, |
310 | }, |
311 | }; |
312 | |
313 | static struct platform_device db1300_i2s_dev = { |
314 | .name = "au1xpsc_i2s" , |
315 | .id = 2, /* PSC ID */ |
316 | .num_resources = ARRAY_SIZE(au1300_psc2_res), |
317 | .resource = au1300_psc2_res, |
318 | }; |
319 | |
320 | /**********************************************************************/ |
321 | |
322 | static struct resource au1300_psc3_res[] = { |
323 | [0] = { |
324 | .start = AU1300_PSC3_PHYS_ADDR, |
325 | .end = AU1300_PSC3_PHYS_ADDR + 0x0fff, |
326 | .flags = IORESOURCE_MEM, |
327 | }, |
328 | [1] = { |
329 | .start = AU1300_PSC3_INT, |
330 | .end = AU1300_PSC3_INT, |
331 | .flags = IORESOURCE_IRQ, |
332 | }, |
333 | [2] = { |
334 | .start = AU1300_DSCR_CMD0_PSC3_TX, |
335 | .end = AU1300_DSCR_CMD0_PSC3_TX, |
336 | .flags = IORESOURCE_DMA, |
337 | }, |
338 | [3] = { |
339 | .start = AU1300_DSCR_CMD0_PSC3_RX, |
340 | .end = AU1300_DSCR_CMD0_PSC3_RX, |
341 | .flags = IORESOURCE_DMA, |
342 | }, |
343 | }; |
344 | |
345 | static struct platform_device db1300_i2c_dev = { |
346 | .name = "au1xpsc_smbus" , |
347 | .id = 0, /* bus number */ |
348 | .num_resources = ARRAY_SIZE(au1300_psc3_res), |
349 | .resource = au1300_psc3_res, |
350 | }; |
351 | |
352 | /**********************************************************************/ |
353 | |
354 | /* proper key assignments when facing the LCD panel. For key assignments |
355 | * according to the schematics swap up with down and left with right. |
356 | * I chose to use it to emulate the arrow keys of a keyboard. |
357 | */ |
358 | static struct gpio_keys_button db1300_5waysw_arrowkeys[] = { |
359 | { |
360 | .code = KEY_DOWN, |
361 | .gpio = AU1300_PIN_LCDPWM0, |
362 | .type = EV_KEY, |
363 | .debounce_interval = 1, |
364 | .active_low = 1, |
365 | .desc = "5waysw-down" , |
366 | }, |
367 | { |
368 | .code = KEY_UP, |
369 | .gpio = AU1300_PIN_PSC2SYNC1, |
370 | .type = EV_KEY, |
371 | .debounce_interval = 1, |
372 | .active_low = 1, |
373 | .desc = "5waysw-up" , |
374 | }, |
375 | { |
376 | .code = KEY_RIGHT, |
377 | .gpio = AU1300_PIN_WAKE3, |
378 | .type = EV_KEY, |
379 | .debounce_interval = 1, |
380 | .active_low = 1, |
381 | .desc = "5waysw-right" , |
382 | }, |
383 | { |
384 | .code = KEY_LEFT, |
385 | .gpio = AU1300_PIN_WAKE2, |
386 | .type = EV_KEY, |
387 | .debounce_interval = 1, |
388 | .active_low = 1, |
389 | .desc = "5waysw-left" , |
390 | }, |
391 | { |
392 | .code = KEY_ENTER, |
393 | .gpio = AU1300_PIN_WAKE1, |
394 | .type = EV_KEY, |
395 | .debounce_interval = 1, |
396 | .active_low = 1, |
397 | .desc = "5waysw-push" , |
398 | }, |
399 | }; |
400 | |
401 | static struct gpio_keys_platform_data db1300_5waysw_data = { |
402 | .buttons = db1300_5waysw_arrowkeys, |
403 | .nbuttons = ARRAY_SIZE(db1300_5waysw_arrowkeys), |
404 | .rep = 1, |
405 | .name = "db1300-5wayswitch" , |
406 | }; |
407 | |
408 | static struct platform_device db1300_5waysw_dev = { |
409 | .name = "gpio-keys" , |
410 | .dev = { |
411 | .platform_data = &db1300_5waysw_data, |
412 | }, |
413 | }; |
414 | |
415 | /**********************************************************************/ |
416 | |
417 | static struct pata_platform_info db1300_ide_info = { |
418 | .ioport_shift = DB1300_IDE_REG_SHIFT, |
419 | }; |
420 | |
421 | #define IDE_ALT_START (14 << DB1300_IDE_REG_SHIFT) |
422 | static struct resource db1300_ide_res[] = { |
423 | [0] = { |
424 | .start = DB1300_IDE_PHYS_ADDR, |
425 | .end = DB1300_IDE_PHYS_ADDR + IDE_ALT_START - 1, |
426 | .flags = IORESOURCE_MEM, |
427 | }, |
428 | [1] = { |
429 | .start = DB1300_IDE_PHYS_ADDR + IDE_ALT_START, |
430 | .end = DB1300_IDE_PHYS_ADDR + DB1300_IDE_PHYS_LEN - 1, |
431 | .flags = IORESOURCE_MEM, |
432 | }, |
433 | [2] = { |
434 | .start = DB1300_IDE_INT, |
435 | .end = DB1300_IDE_INT, |
436 | .flags = IORESOURCE_IRQ, |
437 | }, |
438 | }; |
439 | |
440 | static struct platform_device db1300_ide_dev = { |
441 | .dev = { |
442 | .dma_mask = &au1300_all_dmamask, |
443 | .coherent_dma_mask = DMA_BIT_MASK(32), |
444 | .platform_data = &db1300_ide_info, |
445 | }, |
446 | .name = "pata_platform" , |
447 | .resource = db1300_ide_res, |
448 | .num_resources = ARRAY_SIZE(db1300_ide_res), |
449 | }; |
450 | |
451 | /**********************************************************************/ |
452 | |
453 | #ifdef CONFIG_MMC_AU1X |
454 | static irqreturn_t db1300_mmc_cd(int irq, void *ptr) |
455 | { |
456 | disable_irq_nosync(irq); |
457 | return IRQ_WAKE_THREAD; |
458 | } |
459 | |
460 | static irqreturn_t db1300_mmc_cdfn(int irq, void *ptr) |
461 | { |
462 | mmc_detect_change(ptr, msecs_to_jiffies(200)); |
463 | |
464 | msleep(100); /* debounce */ |
465 | if (irq == DB1300_SD1_INSERT_INT) |
466 | enable_irq(DB1300_SD1_EJECT_INT); |
467 | else |
468 | enable_irq(DB1300_SD1_INSERT_INT); |
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_threaded_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, |
490 | db1300_mmc_cdfn, 0, "sd_insert" , mmc_host); |
491 | if (ret) |
492 | goto out; |
493 | |
494 | ret = request_threaded_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, |
495 | db1300_mmc_cdfn, 0, "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 = { |
525 | .brightness_set = db1300_mmcled_set, |
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 | .dma_mask = &au1300_all_dmamask, |
561 | .coherent_dma_mask = DMA_BIT_MASK(32), |
562 | .platform_data = &db1300_sd1_platdata, |
563 | }, |
564 | .name = "au1xxx-mmc" , |
565 | .id = 1, |
566 | .resource = au1300_sd1_res, |
567 | .num_resources = ARRAY_SIZE(au1300_sd1_res), |
568 | }; |
569 | |
570 | /**********************************************************************/ |
571 | |
572 | static int db1300_movinand_inserted(void *mmc_host) |
573 | { |
574 | return 0; /* disable for now, it doesn't work yet */ |
575 | } |
576 | |
577 | static int db1300_movinand_readonly(void *mmc_host) |
578 | { |
579 | return 0; |
580 | } |
581 | |
582 | static void db1300_movinand_led_set(struct led_classdev *led, |
583 | enum led_brightness brightness) |
584 | { |
585 | if (brightness != LED_OFF) |
586 | bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0); |
587 | else |
588 | bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1); |
589 | } |
590 | |
591 | static struct led_classdev db1300_movinand_led = { |
592 | .brightness_set = db1300_movinand_led_set, |
593 | }; |
594 | |
595 | struct au1xmmc_platform_data db1300_sd0_platdata = { |
596 | .card_inserted = db1300_movinand_inserted, |
597 | .card_readonly = db1300_movinand_readonly, |
598 | .led = &db1300_movinand_led, |
599 | .mask_host_caps = MMC_CAP_NEEDS_POLL, |
600 | }; |
601 | |
602 | static struct resource au1300_sd0_res[] = { |
603 | [0] = { |
604 | .start = AU1100_SD0_PHYS_ADDR, |
605 | .end = AU1100_SD0_PHYS_ADDR, |
606 | .flags = IORESOURCE_MEM, |
607 | }, |
608 | [1] = { |
609 | .start = AU1300_SD0_INT, |
610 | .end = AU1300_SD0_INT, |
611 | .flags = IORESOURCE_IRQ, |
612 | }, |
613 | [2] = { |
614 | .start = AU1300_DSCR_CMD0_SDMS_TX0, |
615 | .end = AU1300_DSCR_CMD0_SDMS_TX0, |
616 | .flags = IORESOURCE_DMA, |
617 | }, |
618 | [3] = { |
619 | .start = AU1300_DSCR_CMD0_SDMS_RX0, |
620 | .end = AU1300_DSCR_CMD0_SDMS_RX0, |
621 | .flags = IORESOURCE_DMA, |
622 | }, |
623 | }; |
624 | |
625 | static struct platform_device db1300_sd0_dev = { |
626 | .dev = { |
627 | .dma_mask = &au1300_all_dmamask, |
628 | .coherent_dma_mask = DMA_BIT_MASK(32), |
629 | .platform_data = &db1300_sd0_platdata, |
630 | }, |
631 | .name = "au1xxx-mmc" , |
632 | .id = 0, |
633 | .resource = au1300_sd0_res, |
634 | .num_resources = ARRAY_SIZE(au1300_sd0_res), |
635 | }; |
636 | #endif /* CONFIG_MMC_AU1X */ |
637 | |
638 | /**********************************************************************/ |
639 | |
640 | static struct platform_device db1300_wm9715_dev = { |
641 | .name = "wm9712-codec" , |
642 | .id = 1, /* ID of PSC for AC97 audio, see asoc glue! */ |
643 | }; |
644 | |
645 | static struct platform_device db1300_ac97dma_dev = { |
646 | .name = "au1xpsc-pcm" , |
647 | .id = 1, /* PSC ID */ |
648 | }; |
649 | |
650 | static struct platform_device db1300_i2sdma_dev = { |
651 | .name = "au1xpsc-pcm" , |
652 | .id = 2, /* PSC ID */ |
653 | }; |
654 | |
655 | static struct platform_device db1300_sndac97_dev = { |
656 | .name = "db1300-ac97" , |
657 | .dev = { |
658 | .dma_mask = &au1300_all_dmamask, |
659 | .coherent_dma_mask = DMA_BIT_MASK(32), |
660 | }, |
661 | }; |
662 | |
663 | static struct platform_device db1300_sndi2s_dev = { |
664 | .name = "db1300-i2s" , |
665 | .dev = { |
666 | .dma_mask = &au1300_all_dmamask, |
667 | .coherent_dma_mask = DMA_BIT_MASK(32), |
668 | }, |
669 | }; |
670 | |
671 | /**********************************************************************/ |
672 | |
673 | static int db1300fb_panel_index(void) |
674 | { |
675 | return 9; /* DB1300_800x480 */ |
676 | } |
677 | |
678 | static int db1300fb_panel_init(void) |
679 | { |
680 | /* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */ |
681 | bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD, |
682 | BCSR_BOARD_LCDBL); |
683 | return 0; |
684 | } |
685 | |
686 | static int db1300fb_panel_shutdown(void) |
687 | { |
688 | /* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */ |
689 | bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL, |
690 | BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD); |
691 | return 0; |
692 | } |
693 | |
694 | static struct au1200fb_platdata db1300fb_pd = { |
695 | .panel_index = db1300fb_panel_index, |
696 | .panel_init = db1300fb_panel_init, |
697 | .panel_shutdown = db1300fb_panel_shutdown, |
698 | }; |
699 | |
700 | static struct resource au1300_lcd_res[] = { |
701 | [0] = { |
702 | .start = AU1200_LCD_PHYS_ADDR, |
703 | .end = AU1200_LCD_PHYS_ADDR + 0x800 - 1, |
704 | .flags = IORESOURCE_MEM, |
705 | }, |
706 | [1] = { |
707 | .start = AU1300_LCD_INT, |
708 | .end = AU1300_LCD_INT, |
709 | .flags = IORESOURCE_IRQ, |
710 | } |
711 | }; |
712 | |
713 | |
714 | static struct platform_device db1300_lcd_dev = { |
715 | .name = "au1200-lcd" , |
716 | .id = 0, |
717 | .dev = { |
718 | .dma_mask = &au1300_all_dmamask, |
719 | .coherent_dma_mask = DMA_BIT_MASK(32), |
720 | .platform_data = &db1300fb_pd, |
721 | }, |
722 | .num_resources = ARRAY_SIZE(au1300_lcd_res), |
723 | .resource = au1300_lcd_res, |
724 | }; |
725 | |
726 | /**********************************************************************/ |
727 | |
728 | #if IS_ENABLED(CONFIG_TOUCHSCREEN_WM97XX) |
729 | static struct wm97xx_mach_ops db1300_wm97xx_ops = { |
730 | .irq_gpio = WM97XX_GPIO_3, |
731 | }; |
732 | |
733 | static int db1300_wm97xx_probe(struct platform_device *pdev) |
734 | { |
735 | struct wm97xx *wm = platform_get_drvdata(pdev); |
736 | |
737 | /* external pendown indicator */ |
738 | wm97xx_config_gpio(wm, WM97XX_GPIO_13, dir: WM97XX_GPIO_IN, |
739 | pol: WM97XX_GPIO_POL_LOW, sticky: WM97XX_GPIO_STICKY, |
740 | wake: WM97XX_GPIO_WAKE); |
741 | |
742 | /* internal "virtual" pendown gpio */ |
743 | wm97xx_config_gpio(wm, WM97XX_GPIO_3, dir: WM97XX_GPIO_OUT, |
744 | pol: WM97XX_GPIO_POL_LOW, sticky: WM97XX_GPIO_NOTSTICKY, |
745 | wake: WM97XX_GPIO_NOWAKE); |
746 | |
747 | wm->pen_irq = DB1300_AC97_PEN_INT; |
748 | |
749 | return wm97xx_register_mach_ops(wm, &db1300_wm97xx_ops); |
750 | } |
751 | #else |
752 | static int db1300_wm97xx_probe(struct platform_device *pdev) |
753 | { |
754 | return -ENODEV; |
755 | } |
756 | #endif |
757 | |
758 | static struct platform_driver db1300_wm97xx_driver = { |
759 | .driver.name = "wm97xx-touch" , |
760 | .driver.owner = THIS_MODULE, |
761 | .probe = db1300_wm97xx_probe, |
762 | }; |
763 | |
764 | /**********************************************************************/ |
765 | |
766 | static struct platform_device *db1300_dev[] __initdata = { |
767 | &db1300_eth_dev, |
768 | &db1300_i2c_dev, |
769 | &db1300_5waysw_dev, |
770 | &db1300_nand_dev, |
771 | &db1300_ide_dev, |
772 | #ifdef CONFIG_MMC_AU1X |
773 | &db1300_sd0_dev, |
774 | &db1300_sd1_dev, |
775 | #endif |
776 | &db1300_lcd_dev, |
777 | &db1300_ac97_dev, |
778 | &db1300_i2s_dev, |
779 | &db1300_wm9715_dev, |
780 | &db1300_ac97dma_dev, |
781 | &db1300_i2sdma_dev, |
782 | &db1300_sndac97_dev, |
783 | &db1300_sndi2s_dev, |
784 | }; |
785 | |
786 | int __init db1300_dev_setup(void) |
787 | { |
788 | int swapped, cpldirq; |
789 | struct clk *c; |
790 | |
791 | /* setup CPLD IRQ muxer */ |
792 | cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1); |
793 | irq_set_irq_type(cpldirq, IRQ_TYPE_LEVEL_HIGH); |
794 | bcsr_init_irq(DB1300_FIRST_INT, DB1300_LAST_INT, cpldirq); |
795 | |
796 | /* insert/eject IRQs: one always triggers so don't enable them |
797 | * when doing request_irq() on them. DB1200 has this bug too. |
798 | */ |
799 | irq_set_status_flags(DB1300_SD1_INSERT_INT, IRQ_NOAUTOEN); |
800 | irq_set_status_flags(DB1300_SD1_EJECT_INT, IRQ_NOAUTOEN); |
801 | irq_set_status_flags(DB1300_CF_INSERT_INT, IRQ_NOAUTOEN); |
802 | irq_set_status_flags(DB1300_CF_EJECT_INT, IRQ_NOAUTOEN); |
803 | |
804 | /* |
805 | * setup board |
806 | */ |
807 | prom_get_ethernet_addr(&db1300_eth_config.mac[0]); |
808 | |
809 | i2c_register_board_info(busnum: 0, info: db1300_i2c_devs, |
810 | ARRAY_SIZE(db1300_i2c_devs)); |
811 | |
812 | if (platform_driver_register(&db1300_wm97xx_driver)) |
813 | pr_warn("DB1300: failed to init touch pen irq support!\n" ); |
814 | |
815 | /* Audio PSC clock is supplied by codecs (PSC1, 2) */ |
816 | __raw_writel(PSC_SEL_CLK_SERCLK, |
817 | (void __iomem *)KSEG1ADDR(AU1300_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); |
818 | wmb(); |
819 | __raw_writel(PSC_SEL_CLK_SERCLK, |
820 | (void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET); |
821 | wmb(); |
822 | /* I2C driver wants 50MHz, get as close as possible */ |
823 | c = clk_get(NULL, id: "psc3_intclk" ); |
824 | if (!IS_ERR(ptr: c)) { |
825 | clk_set_rate(clk: c, rate: 50000000); |
826 | clk_prepare_enable(clk: c); |
827 | clk_put(clk: c); |
828 | } |
829 | __raw_writel(PSC_SEL_CLK_INTCLK, |
830 | (void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET); |
831 | wmb(); |
832 | |
833 | /* enable power to USB ports */ |
834 | bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_USBHPWR | BCSR_RESETS_OTGPWR); |
835 | |
836 | /* although it is socket #0, it uses the CPLD bits which previous boards |
837 | * have used for socket #1. |
838 | */ |
839 | db1x_register_pcmcia_socket( |
840 | AU1000_PCMCIA_ATTR_PHYS_ADDR, |
841 | AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x00400000 - 1, |
842 | AU1000_PCMCIA_MEM_PHYS_ADDR, |
843 | AU1000_PCMCIA_MEM_PHYS_ADDR + 0x00400000 - 1, |
844 | AU1000_PCMCIA_IO_PHYS_ADDR, |
845 | AU1000_PCMCIA_IO_PHYS_ADDR + 0x00010000 - 1, |
846 | DB1300_CF_INT, DB1300_CF_INSERT_INT, 0, DB1300_CF_EJECT_INT, 1); |
847 | |
848 | swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT; |
849 | db1x_register_norflash(size: 64 << 20, width: 2, swapped); |
850 | |
851 | return platform_add_devices(db1300_dev, ARRAY_SIZE(db1300_dev)); |
852 | } |
853 | |
854 | |
855 | int __init db1300_board_setup(void) |
856 | { |
857 | unsigned short whoami; |
858 | |
859 | bcsr_init(DB1300_BCSR_PHYS_ADDR, |
860 | DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS); |
861 | |
862 | whoami = bcsr_read(BCSR_WHOAMI); |
863 | if (BCSR_WHOAMI_BOARD(whoami) != BCSR_WHOAMI_DB1300) |
864 | return -ENODEV; |
865 | |
866 | db1300_gpio_config(); |
867 | |
868 | printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t" |
869 | "BoardID %d CPLD Rev %d DaughtercardID %d\n" , |
870 | BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami), |
871 | BCSR_WHOAMI_DCID(whoami)); |
872 | |
873 | /* enable UARTs, YAMON only enables #2 */ |
874 | alchemy_uart_enable(AU1300_UART0_PHYS_ADDR); |
875 | alchemy_uart_enable(AU1300_UART1_PHYS_ADDR); |
876 | alchemy_uart_enable(AU1300_UART3_PHYS_ADDR); |
877 | |
878 | return 0; |
879 | } |
880 | |