1 | // SPDX-License-Identifier: GPL-2.0-only |
---|---|
2 | /* |
3 | * linux/arch/arm/mach-sa1100/assabet.c |
4 | * |
5 | * Author: Nicolas Pitre |
6 | * |
7 | * This file contains all Assabet-specific tweaks. |
8 | */ |
9 | #include <linux/init.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/errno.h> |
13 | #include <linux/gpio/driver.h> |
14 | #include <linux/gpio/gpio-reg.h> |
15 | #include <linux/gpio/machine.h> |
16 | #include <linux/gpio_keys.h> |
17 | #include <linux/ioport.h> |
18 | #include <linux/platform_data/sa11x0-serial.h> |
19 | #include <linux/regulator/fixed.h> |
20 | #include <linux/regulator/machine.h> |
21 | #include <linux/serial_core.h> |
22 | #include <linux/platform_device.h> |
23 | #include <linux/mfd/ucb1x00.h> |
24 | #include <linux/mtd/mtd.h> |
25 | #include <linux/mtd/partitions.h> |
26 | #include <linux/delay.h> |
27 | #include <linux/mm.h> |
28 | #include <linux/leds.h> |
29 | #include <linux/slab.h> |
30 | |
31 | #include <video/sa1100fb.h> |
32 | |
33 | #include <mach/hardware.h> |
34 | #include <asm/mach-types.h> |
35 | #include <asm/setup.h> |
36 | #include <asm/page.h> |
37 | #include <asm/pgtable-hwdef.h> |
38 | #include <asm/tlbflush.h> |
39 | |
40 | #include <asm/mach/arch.h> |
41 | #include <asm/mach/flash.h> |
42 | #include <asm/mach/map.h> |
43 | #include <mach/assabet.h> |
44 | #include <linux/platform_data/mfd-mcp-sa11x0.h> |
45 | #include <mach/irqs.h> |
46 | |
47 | #include "generic.h" |
48 | |
49 | #define ASSABET_BCR_DB1110 \ |
50 | (ASSABET_BCR_SPK_OFF | \ |
51 | ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ |
52 | ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ |
53 | ASSABET_BCR_IRDA_MD0) |
54 | |
55 | #define ASSABET_BCR_DB1111 \ |
56 | (ASSABET_BCR_SPK_OFF | \ |
57 | ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ |
58 | ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ |
59 | ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \ |
60 | ASSABET_BCR_IRDA_MD0 | ASSABET_BCR_CF_RST) |
61 | |
62 | unsigned long SCR_value = ASSABET_SCR_INIT; |
63 | EXPORT_SYMBOL(SCR_value); |
64 | |
65 | static struct gpio_chip *assabet_bcr_gc; |
66 | |
67 | static const char *assabet_names[] = { |
68 | "cf_pwr", "cf_gfx_reset", "nsoft_reset", "irda_fsel", |
69 | "irda_md0", "irda_md1", "stereo_loopback", "ncf_bus_on", |
70 | "audio_pwr_on", "light_pwr_on", "lcd16data", "lcd_pwr_on", |
71 | "rs232_on", "nred_led", "ngreen_led", "vib_on", |
72 | "com_dtr", "com_rts", "radio_wake_mod", "i2c_enab", |
73 | "tvir_enab", "qmute", "radio_pwr_on", "spkr_off", |
74 | "rs232_valid", "com_dcd", "com_cts", "com_dsr", |
75 | "radio_cts", "radio_dsr", "radio_dcd", "radio_ri", |
76 | }; |
77 | |
78 | /* The old deprecated interface */ |
79 | void ASSABET_BCR_frob(unsigned int mask, unsigned int val) |
80 | { |
81 | unsigned long m = mask, v = val; |
82 | |
83 | assabet_bcr_gc->set_multiple(assabet_bcr_gc, &m, &v); |
84 | } |
85 | EXPORT_SYMBOL(ASSABET_BCR_frob); |
86 | |
87 | static void __init assabet_init_gpio(void __iomem *reg, u32 def_val) |
88 | { |
89 | struct gpio_chip *gc; |
90 | |
91 | writel_relaxed(def_val, reg); |
92 | |
93 | gc = gpio_reg_init(NULL, reg, base: -1, num: 32, label: "assabet", direction: 0xff000000, def_out: def_val, |
94 | names: assabet_names, NULL, NULL); |
95 | |
96 | if (IS_ERR(ptr: gc)) |
97 | return; |
98 | |
99 | assabet_bcr_gc = gc; |
100 | } |
101 | |
102 | /* |
103 | * The codec reset goes to three devices, so we need to release |
104 | * the rest when any one of these requests it. However, that |
105 | * causes the ADV7171 to consume around 100mA - more than half |
106 | * the LCD-blanked power. |
107 | * |
108 | * With the ADV7171, LCD and backlight enabled, we go over |
109 | * budget on the MAX846 Li-Ion charger, and if no Li-Ion battery |
110 | * is connected, the Assabet crashes. |
111 | */ |
112 | #define RST_UCB1X00 (1 << 0) |
113 | #define RST_UDA1341 (1 << 1) |
114 | #define RST_ADV7171 (1 << 2) |
115 | |
116 | #define SDA GPIO_GPIO(15) |
117 | #define SCK GPIO_GPIO(18) |
118 | #define MOD GPIO_GPIO(17) |
119 | |
120 | static void adv7171_start(void) |
121 | { |
122 | GPSR = SCK; |
123 | udelay(1); |
124 | GPSR = SDA; |
125 | udelay(2); |
126 | GPCR = SDA; |
127 | } |
128 | |
129 | static void adv7171_stop(void) |
130 | { |
131 | GPSR = SCK; |
132 | udelay(2); |
133 | GPSR = SDA; |
134 | udelay(1); |
135 | } |
136 | |
137 | static void adv7171_send(unsigned byte) |
138 | { |
139 | unsigned i; |
140 | |
141 | for (i = 0; i < 8; i++, byte <<= 1) { |
142 | GPCR = SCK; |
143 | udelay(1); |
144 | if (byte & 0x80) |
145 | GPSR = SDA; |
146 | else |
147 | GPCR = SDA; |
148 | udelay(1); |
149 | GPSR = SCK; |
150 | udelay(1); |
151 | } |
152 | GPCR = SCK; |
153 | udelay(1); |
154 | GPSR = SDA; |
155 | udelay(1); |
156 | GPDR &= ~SDA; |
157 | GPSR = SCK; |
158 | udelay(1); |
159 | if (GPLR & SDA) |
160 | printk(KERN_WARNING "No ACK from ADV7171\n"); |
161 | udelay(1); |
162 | GPCR = SCK | SDA; |
163 | udelay(1); |
164 | GPDR |= SDA; |
165 | udelay(1); |
166 | } |
167 | |
168 | static void adv7171_write(unsigned reg, unsigned val) |
169 | { |
170 | unsigned gpdr = GPDR; |
171 | unsigned gplr = GPLR; |
172 | |
173 | ASSABET_BCR_frob(mask: ASSABET_BCR_AUDIO_ON, val: ASSABET_BCR_AUDIO_ON); |
174 | udelay(100); |
175 | |
176 | GPCR = SDA | SCK | MOD; /* clear L3 mode to ensure UDA1341 doesn't respond */ |
177 | GPDR = (GPDR | SCK | MOD) & ~SDA; |
178 | udelay(10); |
179 | if (!(GPLR & SDA)) |
180 | printk(KERN_WARNING "Something dragging SDA down?\n"); |
181 | GPDR |= SDA; |
182 | |
183 | adv7171_start(); |
184 | adv7171_send(byte: 0x54); |
185 | adv7171_send(byte: reg); |
186 | adv7171_send(byte: val); |
187 | adv7171_stop(); |
188 | |
189 | /* Restore GPIO state for L3 bus */ |
190 | GPSR = gplr & (SDA | SCK | MOD); |
191 | GPCR = (~gplr) & (SDA | SCK | MOD); |
192 | GPDR = gpdr; |
193 | } |
194 | |
195 | static void adv7171_sleep(void) |
196 | { |
197 | /* Put the ADV7171 into sleep mode */ |
198 | adv7171_write(reg: 0x04, val: 0x40); |
199 | } |
200 | |
201 | static unsigned codec_nreset; |
202 | |
203 | static void assabet_codec_reset(unsigned mask, int set) |
204 | { |
205 | unsigned long flags; |
206 | bool old; |
207 | |
208 | local_irq_save(flags); |
209 | old = !codec_nreset; |
210 | if (set) |
211 | codec_nreset &= ~mask; |
212 | else |
213 | codec_nreset |= mask; |
214 | |
215 | if (old != !codec_nreset) { |
216 | if (codec_nreset) { |
217 | ASSABET_BCR_set(ASSABET_BCR_NCODEC_RST); |
218 | adv7171_sleep(); |
219 | } else { |
220 | ASSABET_BCR_clear(ASSABET_BCR_NCODEC_RST); |
221 | } |
222 | } |
223 | local_irq_restore(flags); |
224 | } |
225 | |
226 | static void assabet_ucb1x00_reset(enum ucb1x00_reset state) |
227 | { |
228 | int set = state == UCB_RST_REMOVE || state == UCB_RST_SUSPEND || |
229 | state == UCB_RST_PROBE_FAIL; |
230 | assabet_codec_reset(RST_UCB1X00, set); |
231 | } |
232 | |
233 | void assabet_uda1341_reset(int set) |
234 | { |
235 | assabet_codec_reset(RST_UDA1341, set); |
236 | } |
237 | EXPORT_SYMBOL(assabet_uda1341_reset); |
238 | |
239 | |
240 | /* |
241 | * Assabet flash support code. |
242 | */ |
243 | |
244 | #ifdef ASSABET_REV_4 |
245 | /* |
246 | * Phase 4 Assabet has two 28F160B3 flash parts in bank 0: |
247 | */ |
248 | static struct mtd_partition assabet_partitions[] = { |
249 | { |
250 | .name = "bootloader", |
251 | .size = 0x00020000, |
252 | .offset = 0, |
253 | .mask_flags = MTD_WRITEABLE, |
254 | }, { |
255 | .name = "bootloader params", |
256 | .size = 0x00020000, |
257 | .offset = MTDPART_OFS_APPEND, |
258 | .mask_flags = MTD_WRITEABLE, |
259 | }, { |
260 | .name = "jffs", |
261 | .size = MTDPART_SIZ_FULL, |
262 | .offset = MTDPART_OFS_APPEND, |
263 | } |
264 | }; |
265 | #else |
266 | /* |
267 | * Phase 5 Assabet has two 28F128J3A flash parts in bank 0: |
268 | */ |
269 | static struct mtd_partition assabet_partitions[] = { |
270 | { |
271 | .name = "bootloader", |
272 | .size = 0x00040000, |
273 | .offset = 0, |
274 | .mask_flags = MTD_WRITEABLE, |
275 | }, { |
276 | .name = "bootloader params", |
277 | .size = 0x00040000, |
278 | .offset = MTDPART_OFS_APPEND, |
279 | .mask_flags = MTD_WRITEABLE, |
280 | }, { |
281 | .name = "jffs", |
282 | .size = MTDPART_SIZ_FULL, |
283 | .offset = MTDPART_OFS_APPEND, |
284 | } |
285 | }; |
286 | #endif |
287 | |
288 | static struct flash_platform_data assabet_flash_data = { |
289 | .map_name = "cfi_probe", |
290 | .parts = assabet_partitions, |
291 | .nr_parts = ARRAY_SIZE(assabet_partitions), |
292 | }; |
293 | |
294 | static struct resource assabet_flash_resources[] = { |
295 | DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M), |
296 | DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M), |
297 | }; |
298 | |
299 | |
300 | static struct ucb1x00_plat_data assabet_ucb1x00_data = { |
301 | .reset = assabet_ucb1x00_reset, |
302 | .gpio_base = -1, |
303 | .can_wakeup = 1, |
304 | }; |
305 | |
306 | static struct mcp_plat_data assabet_mcp_data = { |
307 | .mccr0 = MCCR0_ADM, |
308 | .sclk_rate = 11981000, |
309 | .codec_pdata = &assabet_ucb1x00_data, |
310 | }; |
311 | |
312 | static void assabet_lcd_set_visual(u32 visual) |
313 | { |
314 | u_int is_true_color = visual == FB_VISUAL_TRUECOLOR; |
315 | |
316 | if (machine_is_assabet()) { |
317 | #if 1 // phase 4 or newer Assabet's |
318 | if (is_true_color) |
319 | ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); |
320 | else |
321 | ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); |
322 | #else |
323 | // older Assabet's |
324 | if (is_true_color) |
325 | ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); |
326 | else |
327 | ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); |
328 | #endif |
329 | } |
330 | } |
331 | |
332 | #ifndef ASSABET_PAL_VIDEO |
333 | static void assabet_lcd_backlight_power(int on) |
334 | { |
335 | if (on) |
336 | ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON); |
337 | else |
338 | ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON); |
339 | } |
340 | |
341 | /* |
342 | * Turn on/off the backlight. When turning the backlight on, we wait |
343 | * 500us after turning it on so we don't cause the supplies to droop |
344 | * when we enable the LCD controller (and cause a hard reset.) |
345 | */ |
346 | static void assabet_lcd_power(int on) |
347 | { |
348 | if (on) { |
349 | ASSABET_BCR_set(ASSABET_BCR_LCD_ON); |
350 | udelay(500); |
351 | } else |
352 | ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); |
353 | } |
354 | |
355 | /* |
356 | * The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually |
357 | * takes an RGB666 signal, but we provide it with an RGB565 signal |
358 | * instead (def_rgb_16). |
359 | */ |
360 | static struct sa1100fb_mach_info lq039q2ds54_info = { |
361 | .pixclock = 171521, .bpp = 16, |
362 | .xres = 320, .yres = 240, |
363 | |
364 | .hsync_len = 5, .vsync_len = 1, |
365 | .left_margin = 61, .upper_margin = 3, |
366 | .right_margin = 9, .lower_margin = 0, |
367 | |
368 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
369 | |
370 | .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, |
371 | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), |
372 | |
373 | .backlight_power = assabet_lcd_backlight_power, |
374 | .lcd_power = assabet_lcd_power, |
375 | .set_visual = assabet_lcd_set_visual, |
376 | }; |
377 | #else |
378 | static void assabet_pal_backlight_power(int on) |
379 | { |
380 | ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON); |
381 | } |
382 | |
383 | static void assabet_pal_power(int on) |
384 | { |
385 | ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); |
386 | } |
387 | |
388 | static struct sa1100fb_mach_info pal_info = { |
389 | .pixclock = 67797, .bpp = 16, |
390 | .xres = 640, .yres = 512, |
391 | |
392 | .hsync_len = 64, .vsync_len = 6, |
393 | .left_margin = 125, .upper_margin = 70, |
394 | .right_margin = 115, .lower_margin = 36, |
395 | |
396 | .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, |
397 | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), |
398 | |
399 | .backlight_power = assabet_pal_backlight_power, |
400 | .lcd_power = assabet_pal_power, |
401 | .set_visual = assabet_lcd_set_visual, |
402 | }; |
403 | #endif |
404 | |
405 | #ifdef CONFIG_ASSABET_NEPONSET |
406 | static struct resource neponset_resources[] = { |
407 | DEFINE_RES_MEM(0x10000000, 0x08000000), |
408 | DEFINE_RES_MEM(0x18000000, 0x04000000), |
409 | DEFINE_RES_MEM(0x40000000, SZ_8K), |
410 | DEFINE_RES_IRQ(IRQ_GPIO25), |
411 | }; |
412 | #endif |
413 | |
414 | static struct gpiod_lookup_table assabet_cf_gpio_table = { |
415 | .dev_id = "sa11x0-pcmcia.1", |
416 | .table = { |
417 | GPIO_LOOKUP("gpio", 21, "ready", GPIO_ACTIVE_HIGH), |
418 | GPIO_LOOKUP("gpio", 22, "detect", GPIO_ACTIVE_LOW), |
419 | GPIO_LOOKUP("gpio", 24, "bvd2", GPIO_ACTIVE_HIGH), |
420 | GPIO_LOOKUP("gpio", 25, "bvd1", GPIO_ACTIVE_HIGH), |
421 | GPIO_LOOKUP("assabet", 1, "reset", GPIO_ACTIVE_HIGH), |
422 | GPIO_LOOKUP("assabet", 7, "bus-enable", GPIO_ACTIVE_LOW), |
423 | { }, |
424 | }, |
425 | }; |
426 | |
427 | static struct regulator_consumer_supply assabet_cf_vcc_consumers[] = { |
428 | REGULATOR_SUPPLY("vcc", "sa11x0-pcmcia.1"), |
429 | }; |
430 | |
431 | static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = { |
432 | .supply_name = "cf-power", |
433 | .microvolts = 3300000, |
434 | }; |
435 | |
436 | static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = { |
437 | .dev_id = "reg-fixed-voltage.0", |
438 | .table = { |
439 | GPIO_LOOKUP("assabet", 0, NULL, GPIO_ACTIVE_HIGH), |
440 | { }, |
441 | }, |
442 | }; |
443 | |
444 | static struct gpiod_lookup_table assabet_leds_gpio_table = { |
445 | .dev_id = "leds-gpio", |
446 | .table = { |
447 | GPIO_LOOKUP("assabet", 13, NULL, GPIO_ACTIVE_LOW), |
448 | GPIO_LOOKUP("assabet", 14, NULL, GPIO_ACTIVE_LOW), |
449 | { }, |
450 | }, |
451 | }; |
452 | |
453 | static struct gpio_led assabet_leds[] __initdata = { |
454 | { |
455 | .name = "assabet:red", |
456 | .default_trigger = "cpu0", |
457 | .default_state = LEDS_GPIO_DEFSTATE_KEEP, |
458 | }, { |
459 | .name = "assabet:green", |
460 | .default_trigger = "heartbeat", |
461 | .default_state = LEDS_GPIO_DEFSTATE_KEEP, |
462 | }, |
463 | }; |
464 | |
465 | static const struct gpio_led_platform_data assabet_leds_pdata __initconst = { |
466 | .num_leds = ARRAY_SIZE(assabet_leds), |
467 | .leds = assabet_leds, |
468 | }; |
469 | |
470 | static struct gpio_keys_button assabet_keys_buttons[] = { |
471 | { |
472 | .gpio = 0, |
473 | .irq = IRQ_GPIO0, |
474 | .desc = "gpio0", |
475 | .wakeup = 1, |
476 | .can_disable = 1, |
477 | .debounce_interval = 5, |
478 | }, { |
479 | .gpio = 1, |
480 | .irq = IRQ_GPIO1, |
481 | .desc = "gpio1", |
482 | .wakeup = 1, |
483 | .can_disable = 1, |
484 | .debounce_interval = 5, |
485 | }, |
486 | }; |
487 | |
488 | static const struct gpio_keys_platform_data assabet_keys_pdata = { |
489 | .buttons = assabet_keys_buttons, |
490 | .nbuttons = ARRAY_SIZE(assabet_keys_buttons), |
491 | .rep = 0, |
492 | }; |
493 | |
494 | static struct gpiod_lookup_table assabet_uart1_gpio_table = { |
495 | .dev_id = "sa11x0-uart.1", |
496 | .table = { |
497 | GPIO_LOOKUP("assabet", 16, "dtr", GPIO_ACTIVE_LOW), |
498 | GPIO_LOOKUP("assabet", 17, "rts", GPIO_ACTIVE_LOW), |
499 | GPIO_LOOKUP("assabet", 25, "dcd", GPIO_ACTIVE_LOW), |
500 | GPIO_LOOKUP("assabet", 26, "cts", GPIO_ACTIVE_LOW), |
501 | GPIO_LOOKUP("assabet", 27, "dsr", GPIO_ACTIVE_LOW), |
502 | { }, |
503 | }, |
504 | }; |
505 | |
506 | static struct gpiod_lookup_table assabet_uart3_gpio_table = { |
507 | .dev_id = "sa11x0-uart.3", |
508 | .table = { |
509 | GPIO_LOOKUP("assabet", 28, "cts", GPIO_ACTIVE_LOW), |
510 | GPIO_LOOKUP("assabet", 29, "dsr", GPIO_ACTIVE_LOW), |
511 | GPIO_LOOKUP("assabet", 30, "dcd", GPIO_ACTIVE_LOW), |
512 | GPIO_LOOKUP("assabet", 31, "rng", GPIO_ACTIVE_LOW), |
513 | { }, |
514 | }, |
515 | }; |
516 | |
517 | static void __init assabet_init(void) |
518 | { |
519 | /* |
520 | * Ensure that the power supply is in "high power" mode. |
521 | */ |
522 | GPSR = GPIO_GPIO16; |
523 | GPDR |= GPIO_GPIO16; |
524 | |
525 | /* |
526 | * Ensure that these pins are set as outputs and are driving |
527 | * logic 0. This ensures that we won't inadvertently toggle |
528 | * the WS latch in the CPLD, and we don't float causing |
529 | * excessive power drain. --rmk |
530 | */ |
531 | GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM; |
532 | GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM; |
533 | |
534 | /* |
535 | * Also set GPIO27 as an output; this is used to clock UART3 |
536 | * via the FPGA and as otherwise has no pullups or pulldowns, |
537 | * so stop it floating. |
538 | */ |
539 | GPCR = GPIO_GPIO27; |
540 | GPDR |= GPIO_GPIO27; |
541 | |
542 | /* |
543 | * Set up registers for sleep mode. |
544 | */ |
545 | PWER = PWER_GPIO0; |
546 | PGSR = 0; |
547 | PCFR = 0; |
548 | PSDR = 0; |
549 | PPDR |= PPC_TXD3 | PPC_TXD1; |
550 | PPSR |= PPC_TXD3 | PPC_TXD1; |
551 | |
552 | sa11x0_ppc_configure_mcp(); |
553 | |
554 | if (machine_has_neponset()) { |
555 | #ifndef CONFIG_ASSABET_NEPONSET |
556 | printk( "Warning: Neponset detected but full support " |
557 | "hasn't been configured in the kernel\n"); |
558 | #else |
559 | platform_device_register_simple("neponset", 0, |
560 | neponset_resources, ARRAY_SIZE(neponset_resources)); |
561 | #endif |
562 | } else { |
563 | gpiod_add_lookup_table(table: &assabet_uart1_gpio_table); |
564 | gpiod_add_lookup_table(table: &assabet_uart3_gpio_table); |
565 | gpiod_add_lookup_table(table: &assabet_cf_vcc_gpio_table); |
566 | |
567 | sa11x0_register_fixed_regulator(n: 0, cfg: &assabet_cf_vcc_pdata, |
568 | supplies: assabet_cf_vcc_consumers, |
569 | ARRAY_SIZE(assabet_cf_vcc_consumers), |
570 | uses_gpio: true); |
571 | |
572 | } |
573 | |
574 | platform_device_register_resndata(NULL, name: "gpio-keys", id: 0, |
575 | NULL, num: 0, |
576 | data: &assabet_keys_pdata, |
577 | size: sizeof(assabet_keys_pdata)); |
578 | |
579 | gpiod_add_lookup_table(table: &assabet_leds_gpio_table); |
580 | gpio_led_register_device(id: -1, pdata: &assabet_leds_pdata); |
581 | |
582 | #ifndef ASSABET_PAL_VIDEO |
583 | sa11x0_register_lcd(inf: &lq039q2ds54_info); |
584 | #else |
585 | sa11x0_register_lcd(&pal_video); |
586 | #endif |
587 | sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources, |
588 | ARRAY_SIZE(assabet_flash_resources)); |
589 | sa11x0_register_mcp(data: &assabet_mcp_data); |
590 | |
591 | if (!machine_has_neponset()) |
592 | sa11x0_register_pcmcia(socket: 1, &assabet_cf_gpio_table); |
593 | } |
594 | |
595 | /* |
596 | * On Assabet, we must probe for the Neponset board _before_ |
597 | * paging_init() has occurred to actually determine the amount |
598 | * of RAM available. To do so, we map the appropriate IO section |
599 | * in the page table here in order to access GPIO registers. |
600 | */ |
601 | static void __init map_sa1100_gpio_regs( void ) |
602 | { |
603 | unsigned long phys = __PREG(GPLR) & PMD_MASK; |
604 | unsigned long virt = (unsigned long)io_p2v(phys); |
605 | int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO); |
606 | pmd_t *pmd; |
607 | |
608 | pmd = pmd_off_k(va: virt); |
609 | *pmd = __pmd(val: phys | prot); |
610 | flush_pmd_entry(pmd); |
611 | } |
612 | |
613 | /* |
614 | * Read System Configuration "Register" |
615 | * (taken from "Intel StrongARM SA-1110 Microprocessor Development Board |
616 | * User's Guide", section 4.4.1) |
617 | * |
618 | * This same scan is performed in arch/arm/boot/compressed/head-sa1100.S |
619 | * to set up the serial port for decompression status messages. We |
620 | * repeat it here because the kernel may not be loaded as a zImage, and |
621 | * also because it's a hassle to communicate the SCR value to the kernel |
622 | * from the decompressor. |
623 | * |
624 | * Note that IRQs are guaranteed to be disabled. |
625 | */ |
626 | static void __init get_assabet_scr(void) |
627 | { |
628 | unsigned long scr, i; |
629 | |
630 | GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ |
631 | GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ |
632 | GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */ |
633 | for(i = 100; i--; ) /* Read GPIO 9:2 */ |
634 | scr = GPLR; |
635 | GPDR |= 0x3fc; /* restore correct pin direction */ |
636 | scr &= 0x3fc; /* save as system configuration byte. */ |
637 | SCR_value = scr; |
638 | } |
639 | |
640 | static void __init |
641 | fixup_assabet(struct tag *tags, char **cmdline) |
642 | { |
643 | /* This must be done before any call to machine_has_neponset() */ |
644 | map_sa1100_gpio_regs(); |
645 | get_assabet_scr(); |
646 | |
647 | if (machine_has_neponset()) |
648 | printk("Neponset expansion board detected\n"); |
649 | } |
650 | |
651 | |
652 | static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate) |
653 | { |
654 | if (port->mapbase == _Ser1UTCR0) { |
655 | if (state) |
656 | ASSABET_BCR_clear(ASSABET_BCR_RS232EN); |
657 | else |
658 | ASSABET_BCR_set(ASSABET_BCR_RS232EN); |
659 | } |
660 | } |
661 | |
662 | static struct sa1100_port_fns assabet_port_fns __initdata = { |
663 | .pm = assabet_uart_pm, |
664 | }; |
665 | |
666 | static struct map_desc assabet_io_desc[] __initdata = { |
667 | { /* Board Control Register */ |
668 | .virtual = 0xf1000000, |
669 | .pfn = __phys_to_pfn(0x12000000), |
670 | .length = 0x00100000, |
671 | .type = MT_DEVICE |
672 | }, { /* MQ200 */ |
673 | .virtual = 0xf2800000, |
674 | .pfn = __phys_to_pfn(0x4b800000), |
675 | .length = 0x00800000, |
676 | .type = MT_DEVICE |
677 | } |
678 | }; |
679 | |
680 | static void __init assabet_map_io(void) |
681 | { |
682 | sa1100_map_io(); |
683 | iotable_init(assabet_io_desc, ARRAY_SIZE(assabet_io_desc)); |
684 | |
685 | /* |
686 | * Set SUS bit in SDCR0 so serial port 1 functions. |
687 | * Its called GPCLKR0 in my SA1110 manual. |
688 | */ |
689 | Ser1SDCR0 |= SDCR0_SUS; |
690 | MSC1 = (MSC1 & ~0xffff) | |
691 | MSC_NonBrst | MSC_32BitStMem | |
692 | MSC_RdAcc(2) | MSC_WrAcc(2) | MSC_Rec(0); |
693 | |
694 | if (!machine_has_neponset()) |
695 | sa1100_register_uart_fns(fns: &assabet_port_fns); |
696 | |
697 | /* |
698 | * When Neponset is attached, the first UART should be |
699 | * UART3. That's what Angel is doing and many documents |
700 | * are stating this. |
701 | * |
702 | * We do the Neponset mapping even if Neponset support |
703 | * isn't compiled in so the user will still get something on |
704 | * the expected physical serial port. |
705 | * |
706 | * We no longer do this; not all boot loaders support it, |
707 | * and UART3 appears to be somewhat unreliable with blob. |
708 | */ |
709 | sa1100_register_uart(idx: 0, port: 1); |
710 | sa1100_register_uart(idx: 2, port: 3); |
711 | } |
712 | |
713 | static void __init assabet_init_irq(void) |
714 | { |
715 | u32 def_val; |
716 | |
717 | sa1100_init_irq(); |
718 | |
719 | if (machine_has_neponset()) |
720 | def_val = ASSABET_BCR_DB1111; |
721 | else |
722 | def_val = ASSABET_BCR_DB1110; |
723 | |
724 | /* |
725 | * Angel sets this, but other bootloaders may not. |
726 | * |
727 | * This must precede any driver calls to BCR_set() or BCR_clear(). |
728 | */ |
729 | assabet_init_gpio((void *)&ASSABET_BCR, def_val); |
730 | } |
731 | |
732 | MACHINE_START(ASSABET, "Intel-Assabet") |
733 | .atag_offset = 0x100, |
734 | .fixup = fixup_assabet, |
735 | .map_io = assabet_map_io, |
736 | .nr_irqs = SA1100_NR_IRQS, |
737 | .init_irq = assabet_init_irq, |
738 | .init_time = sa1100_timer_init, |
739 | .init_machine = assabet_init, |
740 | .init_late = sa11x0_init_late, |
741 | #ifdef CONFIG_SA1111 |
742 | .dma_zone_size = SZ_1M, |
743 | #endif |
744 | .restart = sa11x0_restart, |
745 | MACHINE_END |
746 |
Definitions
- SCR_value
- assabet_bcr_gc
- assabet_names
- ASSABET_BCR_frob
- assabet_init_gpio
- adv7171_start
- adv7171_stop
- adv7171_send
- adv7171_write
- adv7171_sleep
- codec_nreset
- assabet_codec_reset
- assabet_ucb1x00_reset
- assabet_uda1341_reset
- assabet_partitions
- assabet_flash_data
- assabet_flash_resources
- assabet_ucb1x00_data
- assabet_mcp_data
- assabet_lcd_set_visual
- assabet_lcd_backlight_power
- assabet_lcd_power
- lq039q2ds54_info
- assabet_cf_gpio_table
- assabet_cf_vcc_consumers
- assabet_cf_vcc_pdata
- assabet_cf_vcc_gpio_table
- assabet_leds_gpio_table
- assabet_leds
- assabet_leds_pdata
- assabet_keys_buttons
- assabet_keys_pdata
- assabet_uart1_gpio_table
- assabet_uart3_gpio_table
- assabet_init
- map_sa1100_gpio_regs
- get_assabet_scr
- fixup_assabet
- assabet_uart_pm
- assabet_port_fns
- assabet_io_desc
- assabet_map_io
Improve your Profiling and Debugging skills
Find out more