sync hh.org
[hh.org.git] / arch / arm / mach-sa1100 / jornada720.c
blob0133091c2ada7309dd34f848812fc86bb82d5ac2
1 /*
2 * linux/arch/arm/mach-sa1100/jornada720.c
3 */
5 #include <linux/init.h>
6 #include <linux/kernel.h>
7 #include <linux/tty.h>
8 #include <linux/delay.h>
9 #include <linux/platform_device.h>
10 #include <linux/ioport.h>
11 #include <linux/mtd/mtd.h>
12 #include <linux/mtd/partitions.h>
14 #include <asm/hardware.h>
15 #include <asm/hardware/sa1111.h>
16 #include <asm/irq.h>
17 #include <asm/mach-types.h>
18 #include <asm/setup.h>
19 #include <asm/arch/jornada720.h>
20 #include <asm/apm.h>
22 #include <asm/mach/arch.h>
23 #include <asm/mach/flash.h>
24 #include <asm/mach/map.h>
25 #include <asm/mach/serial_sa1100.h>
26 #include <asm/mach/flash.h>
27 #include <asm/mach/irda.h>
29 #include <linux/lcd.h>
30 #include <linux/backlight.h>
31 #include <linux/fb.h>
33 #include "generic.h"
35 #ifdef CONFIG_SA1100_JORNADA720_FLASH
36 static unsigned char *pRegs = REGISTER_OFFSET;
37 void e1356fb_init_hardware(void);
38 #endif
40 /***********************************
41 * *
42 * Jornada 720 mcu functions *
43 * *
44 ***********************************/
46 static char mcu_invert[256];
48 void jornada720_init_ser(void)
50 int i;
52 GPSR = GPIO_GPIO25;
53 Ser4SSCR0 = 0x0307;
54 Ser4MCCR0 = 0;
55 Ser4SSSR = 0;
56 Ser4SSCR1 = 0x18;
57 Ser4SSCR0 = 0x0387;
58 while (Ser4SSSR & SSSR_RNE)
59 i = Ser4SSDR;
62 int mcu_byte(int arg_data)
64 int i;
66 while ((Ser4SSSR & SSSR_TNF) == 0);
67 i = 0;
68 while ((GPLR & 0x400) && i++ < 400000)
69 ; /* wait for MCU */
70 if (i >= 400000) {
71 printk("mcu_byte: timed out\n");
72 return -1;
74 Ser4SSDR = mcu_invert[arg_data] << 8;
75 udelay(100);
76 while ((Ser4SSSR & SSSR_RNE) == 0);
77 i = Ser4SSDR;
78 if (i > 0xff)
79 printk("mcu_byte: read %x\n", i);
80 return mcu_invert[ i & 0xff ] & 0xff;
83 int mcu_start(int arg_data)
85 int i;
87 jornada720_mcu_init();
88 GPCR = GPIO_GPIO25; /* clear -> enable */
89 udelay(100);
90 i = mcu_byte(arg_data);
91 if (i != MCU_TxDummy)
93 printk("mcu_start: sent %x got %x\n", arg_data, i);
94 for (i = 0; i < 256; i++)
95 if (mcu_read() == -1)
96 break;
97 jornada720_init_ser();
98 return -1;
100 return 0;
103 void mcu_end(void)
105 udelay(100);
106 GPSR = GPIO_GPIO25; /* set */
109 void jornada720_mcu_init(void)
111 int i;
112 static int initialized = 0;
114 if (initialized)
115 return;
116 initialized = 1;
117 PPSR &= ~PPC_L_FCLK;
118 udelay(500);
119 PPDR |= PPC_L_FCLK;
120 udelay(500);
121 /* Take the MCU out of reset mode */
122 PPSR |= PPC_L_FCLK;
123 udelay(500);
124 for (i = 0; i <= 255; i++)
125 mcu_invert[i] = ( ((0x80 & i) >> 7) | ((0x40 & i) >> 5)
126 | ((0x20 & i) >> 3) | ((0x10 & i) >> 1) | ((0x08 & i) << 1)
127 | ((0x04 & i) << 3) | ((0x02 & i) << 5) | ((0x01 & i) << 7) );
129 GPSR = GPIO_GPIO25; /* set */
130 GPDR |= GPIO_GPIO25; /* GPIO(25) low -> enable MCU */
131 Ser4SSCR0 = 0x0307;
132 Ser4MCCR0 = 0;
133 Ser4SSSR = 0; /* remove any rcv overrun errors */
134 Ser4SSCR1 = 0x18;
135 Ser4SSCR0 = 0x0387;
137 while (Ser4SSSR & SSSR_RNE)
138 i = Ser4SSDR; /* drain any data already there */
141 /***********************************
143 * Jornada 720 screen controls *
145 ***********************************/
147 static int jornada720_lcd_set_power(struct lcd_device *ld, int state)
149 if ( state ) {
150 PPSR &= ~PPC_LDD1;
151 PPDR |= PPC_LDD1;
153 else {
154 PPSR |= PPC_LDD1;
156 return 0;
159 static int jornada720_lcd_get_contrast(struct lcd_device *ld)
161 int contrast;
162 mcu_start(MCU_GetContrast);
163 contrast = mcu_read();
164 mcu_end();
165 return contrast;
168 static int jornada720_lcd_set_contrast(struct lcd_device *ld, int contrast)
170 mcu_start(MCU_SetContrast);
171 mcu_byte(contrast);
172 mcu_end();
173 return 0;
176 static int jornada720_backlight_get_brightness (struct backlight_device *bd)
178 int brightness;
179 mcu_start(MCU_GetBrightness);
180 brightness = mcu_read();
181 mcu_end();
182 return brightness;
185 static int jornada720_backlight_set_brightness (struct backlight_device *bd, int value)
187 int brightness = 255 - value; /* brightness hack for the user environments */
188 mcu_start(MCU_SetBrightness);
189 mcu_byte(brightness); /* range is from 0 (brightest) to 255 (darkest) */
190 mcu_end();
191 return 0;
195 static struct backlight_properties jornada720_backlight_properties = {
196 .owner = THIS_MODULE,
197 .get_brightness = jornada720_backlight_get_brightness,
198 .set_brightness = jornada720_backlight_set_brightness,
199 .max_brightness = 255,
202 static struct lcd_properties jornada720_lcd_properties = {
203 .owner = THIS_MODULE,
204 .set_power = jornada720_lcd_set_power,
205 .set_contrast = jornada720_lcd_set_contrast,
206 .get_contrast = jornada720_lcd_get_contrast,
207 .max_contrast = 255,
210 /***********************************
212 * Jornada 720 IrDA *
214 ***********************************/
216 static int jornada720_irda_set_power(struct device *dev, unsigned int state)
218 if (state) {
219 PPSR &= ~PPC_L_BIAS;
220 PPDR |= PPC_L_BIAS;
222 else
223 PPSR |= PPC_L_BIAS;
225 return 0;
228 static struct irda_platform_data jornada720_irda_data = {
229 .set_power = jornada720_irda_set_power,
232 #ifdef CONFIG_SA1100_JORNADA720_FLASH
233 /***********************************
235 * Jornada 720 system flash *
237 ***********************************/
239 static struct mtd_partition jornada720_partitions[] = {
241 .name = "bootldr",
242 .size = 0x00040000,
243 .offset = 0,
244 .mask_flags = MTD_WRITEABLE,
245 }, {
246 .name = "rootfs",
247 .size = MTDPART_SIZ_FULL,
248 .offset = MTDPART_OFS_APPEND,
252 static void jornada720_set_vpp(int vpp)
254 if (vpp)
255 PPSR |= PPC_LDD7;
256 else
257 PPSR &= ~PPC_LDD7;
258 PPDR |= PPC_LDD7;
261 static struct flash_platform_data jornada720_flash_data = {
262 .map_name = "cfi_probe",
263 .parts = jornada720_partitions,
264 .nr_parts = ARRAY_SIZE(jornada720_partitions),
265 .set_vpp = jornada720_set_vpp,
268 static struct resource jornada720_flash_resource = {
269 .start = SA1100_CS0_PHYS,
270 .end = SA1100_CS0_PHYS + SZ_32M - 1,
271 .flags = IORESOURCE_MEM,
273 #endif
275 /***********************************
277 * Jornada 720 apm functions *
279 ***********************************/
281 typedef void (*apm_get_power_status_t)(struct apm_power_info*);
283 static void jornada720_apm_get_power_status(struct apm_power_info* info)
285 int value[2];
286 mcu_start(MCU_GetBatteryData);
287 value[0] = mcu_read();
288 value[1] = mcu_read();
289 value[2] = mcu_read();
290 mcu_end();
292 value[0] |= (value[2] & 3) << 8; /* main battery value */
293 value[1] |= (value[2] & 0xc) << 6; /* backup battery value, unused currently */
295 info->battery_life = ((value[0] - 430) * 10) / 23; /* to get an accurate 100% - 0% range */
297 if (GPLR & GPIO_GPIO4) /* AC line status connected to GPIO4; 1 == Battery, 0 == AC */
298 info->ac_line_status = APM_AC_OFFLINE;
299 else
300 info->ac_line_status = APM_AC_ONLINE;
302 if (!(GPLR & GPIO_GPIO26)) /* Battery status connected to GPIO26; 0 == charging, 1 == not charging */
303 info->battery_status = APM_BATTERY_STATUS_CHARGING;
304 else
305 info->battery_status = 2 - info->battery_life / 36; /* this fits quite well */
307 return;
310 int set_apm_get_power_status( apm_get_power_status_t t)
312 apm_get_power_status = t;
313 return 0;
316 static int jornada720_probe(struct device *dev)
318 #ifdef CONFIG_SA1100_JORNADA720_FLASH
319 sa11x0_set_flash_data(&jornada720_flash_data, &jornada720_flash_resource, 1); //set flash data
320 #endif
322 jornada720_mcu_init(); /* initialize the mcu... */
324 jornada720_lcd_set_contrast(0, 115); /* initial contrast setting */
326 backlight_device_register("e1356fb", 0, &jornada720_backlight_properties);
327 lcd_device_register("e1356fb", 0, &jornada720_lcd_properties);
329 set_apm_get_power_status(jornada720_apm_get_power_status); /* apm handler */
331 sa11x0_set_irda_data(&jornada720_irda_data);
333 return 0;
336 #ifdef CONFIG_SA1100_JORNADA720_FLASH
337 struct pm_save_data {
338 int contrast;
339 int brightness;
342 static int jornada720_suspend(struct device *dev, u32 state, u32 level)
344 struct pm_save_data *save;
346 if ( level != SUSPEND_DISABLE)
347 return 0;
349 save = kmalloc(sizeof(struct pm_save_data), GFP_KERNEL);
350 if (!save)
351 return -ENOMEM;
352 dev->power.saved_state = save;
354 /* disable keyboard and mouse irq as they would kill the whole suspend/resume cycle */
355 disable_irq(GPIO_JORNADA720_KEYBOARD_IRQ);
356 disable_irq(GPIO_JORNADA720_MOUSE_IRQ);
358 PPSR |= PPC_L_FCLK; /* make sure the mcu is not being reset */
360 /* save current contrast and brightness */
361 save->contrast = jornada720_lcd_get_contrast(0);
362 save->brightness = jornada720_backlight_get_brightness(0);
364 pRegs[0x1F0] = 1; /* put framebuffer into zZz */
366 return 0;
369 static int jornada720_resume(struct device *dev, u32 level)
371 struct pm_save_data *save;
373 if (level != RESUME_ENABLE)
374 return 0;
376 save = (struct pm_save_data *)dev->power.saved_state;
377 if (!save)
378 return 0;
380 GPSR = GPIO_GPIO8; /* reenable the rs232 receiver */
381 e1356fb_init_hardware(); /* wake up the framebuffer */
382 jornada720_init_ser(); /* reinitialize the mcu */
384 /* restore saved contrast and brightness */
385 jornada720_lcd_set_contrast(0,save->contrast);
386 jornada720_backlight_set_brightness(0,save->brightness);
388 TUCR = JORTUCR_VAL; /* this gets lost during zZz */
390 /* now reenable keyboard and mouse irq */
391 enable_irq(GPIO_JORNADA720_KEYBOARD_IRQ);
392 enable_irq(GPIO_JORNADA720_MOUSE_IRQ);
394 return 0;
396 #else
397 #define jornada720_suspend NULL
398 #define jornada720_resume NULL
399 #endif
401 static struct device_driver jornada720_driver = {
402 .name = "jornada720",
403 .bus = &platform_bus_type,
404 .probe = jornada720_probe,
405 .suspend = jornada720_suspend,
406 .resume = jornada720_resume,
409 /***********************************
411 * Jornada 720 system functions *
413 ***********************************/
415 static struct platform_device jornada720_device = {
416 .name = "jornada720",
417 .id = 0,
420 static struct resource sa1111_resources[] = {
421 [0] = {
422 .start = 0x40000000,
423 .end = 0x40001fff,
424 .flags = IORESOURCE_MEM,
426 [1] = {
427 .start = IRQ_GPIO1,
428 .end = IRQ_GPIO1,
429 .flags = IORESOURCE_IRQ,
433 static u64 sa1111_dmamask = 0xffffffffUL;
435 static struct platform_device sa1111_device = {
436 .name = "sa1111",
437 .id = 0,
438 .dev = {
439 .dma_mask = &sa1111_dmamask,
440 .coherent_dma_mask = 0xffffffff,
442 .num_resources = ARRAY_SIZE(sa1111_resources),
443 .resource = sa1111_resources,
446 static struct platform_device *devices[] __initdata = {
447 &sa1111_device,
448 &jornada720_device,
451 static void __init jornada720_init(void)
454 if (machine_is_jornada720()) {
455 GPDR |= GPIO_GPIO20;
456 TUCR = JORTUCR_VAL; /* set the oscillator out to the SA-1101 */
458 GPSR = GPIO_GPIO20;
459 udelay(1);
460 GPCR = GPIO_GPIO20;
461 udelay(1);
462 GPSR = GPIO_GPIO20;
463 udelay(20);
465 platform_add_devices(devices, ARRAY_SIZE(devices));
467 driver_register(&jornada720_driver);
471 static struct map_desc jornada720_io_desc[] __initdata = {
472 { /* Epson registers */
473 .virtual = 0xf0000000,
474 .pfn = __phys_to_pfn(0x48000000),
475 .length = 0x00100000,
476 .type = MT_DEVICE
477 }, { /* Epson frame buffer */
478 .virtual = 0xf1000000,
479 .pfn = __phys_to_pfn(0x48200000),
480 .length = 0x00100000,
481 .type = MT_DEVICE
482 }, { /* SA-1111 */
483 .virtual = 0xf4000000,
484 .pfn = __phys_to_pfn(0x40000000),
485 .length = 0x00100000,
486 .type = MT_DEVICE
490 static void __init jornada720_map_io(void)
492 sa1100_map_io();
493 iotable_init(jornada720_io_desc, ARRAY_SIZE(jornada720_io_desc));
495 sa1100_register_uart(0, 3);
496 sa1100_register_uart(1, 1);
498 /* configure suspend conditions */
499 PGSR = 0;
500 PWER = 0;
501 PCFR = 0;
502 PSDR = 0;
504 PGSR |= GPIO_GPIO20; /* preserve GPIO for the sa1111 */
505 PWER |= GPIO_JORNADA720_KEYBOARD | PWER_RTC;
506 PCFR |= PCFR_OPDE;
507 PSDR |= PPC_L_FCLK; /* make sure not to reset the mcu */
510 MACHINE_START(JORNADA720, "HP Jornada 720")
511 /* Maintainer: Alex Lange - chicken@handhelds.org */
512 .phys_ram = 0xc0000000,
513 .phys_io = 0x80000000,
514 .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
515 .boot_params = 0xc0000100,
516 .map_io = jornada720_map_io,
517 .init_irq = sa1100_init_irq,
518 .timer = &sa1100_timer,
519 .init_machine = jornada720_init,
520 MACHINE_END