2 * linux/arch/arm/mach-sa1100/jornada56x.c
5 #include <linux/init.h>
6 #include <linux/kernel.h>
8 #include <linux/delay.h>
9 #include <linux/device.h>
10 #include <linux/ioport.h>
11 #include <linux/interrupt.h>
12 #include <linux/battery.h>
13 #include <linux/err.h>
14 #include <linux/mtd/mtd.h>
15 #include <linux/mtd/partitions.h>
17 #include <asm/hardware.h>
19 #include <asm/mach-types.h>
20 #include <asm/setup.h>
23 #include <asm/mach/arch.h>
24 #include <asm/mach/irq.h>
25 #include <asm/mach/map.h>
26 #include <asm/mach/serial_sa1100.h>
27 #include <asm/mach/flash.h>
28 #include <asm/arch/jornada56x.h>
29 #include <asm/arch/bitfield.h>
31 #include <linux/lcd.h>
32 #include <linux/backlight.h>
34 #include <../drivers/video/sa1100fb.h>
35 #include <linux/platform_device.h>
39 /***********************************************
41 * Jornada 56x LCD and backlight functions *
43 ***********************************************/
45 static struct lcd_device
*sa1100_lcd_device
;
46 static struct backlight_device
*sa1100_backlight_device
;
48 static void jornada56x_lcd_power(int on
)
57 static void jornada56x_backlight_power (int on
)
60 JORNADA_GPDPCR
= JORNADA_BACKLIGHT
;
62 JORNADA_GPDPSR
= JORNADA_BACKLIGHT
;
65 static int jornada56x_lcd_get_power(struct lcd_device
*ld
)
67 return (GPLR
& GPIO_GPIO24
) ? 0 : 4;
70 static int jornada56x_lcd_set_power(struct lcd_device
*ld
, int state
)
73 jornada56x_lcd_power(1);
75 jornada56x_lcd_power(0);
80 static int jornada56x_backlight_get_power(struct backlight_device
*bd
)
82 return (JORNADA_GPDPLR
& JORNADA_BACKLIGHT
) ? 4 : 0;
85 static int jornada56x_backlight_set_power(struct backlight_device
*bd
, int state
)
88 jornada56x_backlight_power(1);
90 jornada56x_backlight_power(0);
95 static int jornada56x_backlight_get_brightness (struct backlight_device
*bd
)
97 return (JORNADA_PWM1_DATA
- 0x40000000);
100 static int jornada56x_backlight_set_brightness (struct backlight_device
*bd
, int value
)
102 int brightness
= 190 - value
;
103 JORNADA_PWM1_CKDR
= 0;
104 JORNADA_PWM1_DATA
= brightness
; /* range is from 0 (brightest) to 255 (darkest) although values > 190 are no good */
105 JORNADA_PWM_CTRL
= 1; /* enable backlight control - 1=Enable ; 0=Disable */
110 static struct backlight_properties jornada56x_backlight_properties
= {
111 .owner
= THIS_MODULE
,
112 .get_power
= jornada56x_backlight_get_power
,
113 .set_power
= jornada56x_backlight_set_power
,
114 .get_brightness
= jornada56x_backlight_get_brightness
,
115 .set_brightness
= jornada56x_backlight_set_brightness
,
116 .max_brightness
= 190,
119 static struct lcd_properties jornada56x_lcd_properties
= {
120 .owner
= THIS_MODULE
,
121 .set_power
= jornada56x_lcd_set_power
,
122 .get_power
= jornada56x_lcd_get_power
,
126 /************************************
128 * Jornada 56x Microwire functions *
130 ************************************/
133 int microwire_data
[8];
136 #define ASIC_INT_DELAY 10 /* Poll every 10 milliseconds */
137 enum {PCR_GET_VALUE
=1, PCR_SET_VALUE
, PCR_BIT_SET
, PCR_BIT_CLEAR
};
141 void SetPMUPCRRegister(long arg_action
, long arg_value
)
145 /* Read PCR and remove the unwanted bit 6 */
146 this_pcr
= (((JORNADA_PCR
& 0xff80) >>1) | (JORNADA_PCR
& 0x3f));
148 this_pcr
&= ~(JORNADA_MUX_CLK0
| JORNADA_MUX_CLK1
);
149 if (this_pcr
& JORNADA_SM_CLK_EN
)
150 this_pcr
|= JORNADA_MUX_CLK1
;
151 else if (this_pcr
& JORNADA_MMC_CLK_EN
)
152 this_pcr
|= JORNADA_MUX_CLK0
;
153 switch (arg_action
) {
155 this_pcr
= arg_value
;
157 case PCR_BIT_SET
: /* enable controller */
158 if(arg_value
& JORNADA_SM_CLK_EN
) { /* smart card controller */
159 this_pcr
&= ~(JORNADA_MUX_CLK0
| JORNADA_MUX_CLK1
);
160 this_pcr
|= JORNADA_MUX_CLK1
;
162 else if(arg_value
& JORNADA_MMC_CLK_EN
) { /* mmc controller */
163 this_pcr
&= ~(JORNADA_MUX_CLK0
| JORNADA_MUX_CLK1
);
164 this_pcr
|= JORNADA_MUX_CLK0
;
166 this_pcr
|= arg_value
;
168 case PCR_BIT_CLEAR
: /* disable controller */
169 /* smart card or mmc controller */
170 if (arg_value
& (JORNADA_SM_CLK_EN
| JORNADA_MMC_CLK_EN
))
171 this_pcr
&= ~(JORNADA_MUX_CLK0
| JORNADA_MUX_CLK1
);
172 this_pcr
&= ~arg_value
;
178 JORNADA_PCR
= this_pcr
;
181 void jornada_microwire_init(void)
183 JORNADA_GPIOAFR
|= JORNADA_GP_MW
;
185 JORNADA_MWFTR
= (8 << JORNADA_MWFTR_V_TFT
)
186 | (8 << JORNADA_MWFTR_V_RFT
); /* 0x108 */
188 SetPMUPCRRegister(PCR_BIT_SET
, JORNADA_MW_CLK_EN
);
190 JORNADA_MWCR
= JORNADA_MW_EN
| JORNADA_DSS_16_BIT
191 | (8 << JORNADA_MWCR_V_SCR
) /* 0xa07 */
192 | JORNADA_FIFO_RST
; /* reset FIFO */
194 JORNADA_MWCR
&= ~JORNADA_FIFO_RST
;
195 /* set FIFO interrupt levels to 8 for each of Rx, Tx */
197 JORNADA_MWFTR
= (8 << JORNADA_MWFTR_V_TFT
)
198 | (8 << JORNADA_MWFTR_V_RFT
); /* 0x108 */
201 void jornada_microwire_start(void)
204 while(retry
-- && (JORNADA_MWFSR
& JORNADA_MW_RNE
)); /* empty out existing data */
207 void jornada_microwire_read(int *value1
, int *value2
)
209 int i
,retry
= 1000000;
210 while (retry
-- && !(JORNADA_MWFSR
& JORNADA_MW_RFS
));
212 for (i
= 0; i
< 8; i
++)
213 microwire_data
[i
] = (JORNADA_MWDR
& 0xffff) >> 4;
215 *value1
= (microwire_data
[0] + microwire_data
[1] + microwire_data
[2] + microwire_data
[3]) / 4;
216 *value2
= (microwire_data
[4] + microwire_data
[5] + microwire_data
[6] + microwire_data
[7]) / 4;
219 /***********************************
221 * Jornada 56x battery functions *
223 ***********************************/
225 typedef void (*apm_get_power_status_t
)(struct apm_power_info
*);
227 static void j56x_get_battery_info(void)
231 if ( !( (GPLR
& GPIO_JORNADA56X_TOUCH
) == 0)) {
232 jornada_microwire_start();
233 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
234 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
235 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
236 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
237 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
238 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
239 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
240 JORNADA_MWDR
= JORNADA_MW_MAIN_BATTERY
;
241 jornada_microwire_read(&a
,&b
);
246 static void j56x_apm_get_power_status(struct apm_power_info
* info
)
249 j56x_get_battery_info();
250 battery_life
= ((value
- 1428) * 8) / 19; /* well, sort of accuarate */
253 info
->battery_life
= -1;
254 info
->battery_status
= 0x04;
255 info
->ac_line_status
= 0x01;
258 info
->battery_life
= battery_life
;
260 if (JORNADA_LEDCR
& JORNADA_CHARGE_FULL
) /* This should check the current battery status */
261 info
->battery_status
= 3 - battery_life
/ 50;
263 info
->battery_status
= 3;
265 if (JORNADA_LEDCR
& JORNADA_AC_IN
) /* Check if the AC adapter is plugged in or not */
266 info
->ac_line_status
= 0x00;
268 info
->ac_line_status
= 0x01;
270 info
->time
= battery_life
* 3;
276 int set_apm_get_power_status( apm_get_power_status_t t
)
278 apm_get_power_status
= t
;
282 /***********************************
284 * Jornada 56x power management *
286 ***********************************/
288 static void jornada56x_asic_setup(void)
290 JORNADA_SCR
&= ~JORNADA_ASIC_SLEEP_EN
; /* wake up the ASIC */
292 JORNADA_GPIOAFR
= JORNADA_GP_PWM1
;
293 JORNADA_SCR
|= JORNADA_RCLK_EN
;
297 SetPMUPCRRegister(PCR_BIT_SET
,(JORNADA_GPIO_INT_CLK_EN
|JORNADA_PWM1CLK_EN
));
299 JORNADA_PWM1_CKDR
= 0;
300 JORNADA_PWM2_CKDR
= 0;
304 JORNADA_GPBPSR
= 0x001B;
305 JORNADA_GPCPSR
= 0x31C0;
306 JORNADA_GPDPSR
= 0xAD99;
308 JORNADA_GPBPCR
= 0x3E24;
309 JORNADA_GPCPCR
= 0x0002;
310 JORNADA_GPDPCR
= 0x5264;
311 JORNADA_GPDPSR
= JORNADA_RS232_ON
; /* enable rs232 transceiver */
312 JORNADA_GPDPSR
= JORNADA_CF_POWER_OFF
; /* turn power off to CF */
314 JORNADA_GPBPSDR
= 0x81FF;
315 JORNADA_GPCPSDR
= 0xB96F;
316 JORNADA_GPDPSDR
= 0xFBFF;
318 JORNADA_GPBPSLR
= 0x00D0;
319 JORNADA_GPCPSLR
= 0x0000;
320 JORNADA_GPDPSLR
= 0xA198;
322 JORNADA_GPBPFDR
= 0x81FF;
323 JORNADA_GPCPFDR
= 0xB96F;
324 JORNADA_GPDPFDR
= 0xFBFF;
326 JORNADA_GPBPFLR
= 0x01D0;
327 JORNADA_GPCPFLR
= 0x0000;
328 JORNADA_GPDPFLR
= 0xA198;
330 JORNADA_GPBPDR
= 0x01FF;
331 JORNADA_GPCPDR
= 0x37C2;
332 JORNADA_GPDPDR
= 0xFFFF;
334 JORNADA_GPBPCR
= 0x1c0; /* Buttons: row lines all output 0 */
335 JORNADA_GPBPDR
|= 0x1c0; /* Buttons: turn row lines into outputs */
337 mdelay(2); /* Delay 2 milliseconds. */
338 JORNADA_INT_EN
|= JORNADA_GPIO_B_INT
| JORNADA_GPIO_C_INT
;
340 jornada_microwire_init();
342 /* Clear screen here */
343 JORNADA_GPDPCR
= GPIO_GPIO5
;
344 JORNADA_GPDPCR
= GPIO_GPIO13
; /* Turn on power to panel */
345 JORNADA_GPDPSR
= GPIO_GPIO14
; /* force GPIO-D14 to high */
349 static int jornada56x_probe(struct device
*dev
)
360 jornada56x_asic_setup(); /* initialize default ASIC configuration */
362 JORNADA_GPDPSR
= JORNADA_BACKLIGHT
; /* Turn off the front light */
367 struct pm_save_data
{
374 static int jornada56x_suspend(struct device
*dev
, pm_message_t state
)
376 struct pm_save_data
*save
;
378 save
= kmalloc(sizeof(struct pm_save_data
), GFP_KERNEL
);
381 dev
->power
.saved_state
= save
;
383 /* save interrupt states */
384 disable_irq(GPIO_JORNADA56X_POWER_SWITCH_IRQ
);
385 save
->gpiob_re_en
= JORNADA_GPIOB_RE_EN
;
386 save
->gpiob_fe_en
= JORNADA_GPIOB_FE_EN
;
387 save
->gpioc_re_en
= JORNADA_GPIOC_RE_EN
;
388 save
->gpioc_fe_en
= JORNADA_GPIOC_FE_EN
;
390 /* disable all ASIC interrupts */
392 JORNADA_INT_STAT
= 0xffff;
394 JORNADA_INT_STAT2
= 0xffff;
395 JORNADA_GPIOB_FE_EN
= 0;
396 JORNADA_GPIOB_RE_EN
= 0;
397 JORNADA_GPIOB_STAT
= 0xffff;
398 JORNADA_GPIOC_FE_EN
= 0;
399 JORNADA_GPIOC_RE_EN
= 0;
400 JORNADA_GPIOC_STAT
= 0xffff;
402 JORNADA_GPDPCR
= GPIO_GPIO14
; /* clear the screen here */
404 JORNADA_PCR
= 0; /* disable everything */
405 JORNADA_SCR
= 0; /* disable everything */
406 JORNADA_SCR
|= JORNADA_ASIC_SLEEP_EN
; /* put the system ASIC into zZzZz */
411 static int jornada56x_resume(struct device
*dev
)
413 struct pm_save_data
*save
;
415 save
= (struct pm_save_data
*)dev
->power
.saved_state
;
419 jornada56x_asic_setup(); /* restore default ASIC configuration which gets lost during zZz */
421 /* restore saved ASIC irq configuration */
422 JORNADA_GPIOB_RE_EN
= save
->gpiob_re_en
;
423 JORNADA_GPIOB_FE_EN
= save
->gpiob_fe_en
;
424 JORNADA_GPIOC_RE_EN
= save
->gpioc_re_en
;
425 JORNADA_GPIOC_FE_EN
= save
->gpioc_fe_en
;
427 enable_irq(GPIO_JORNADA56X_POWER_SWITCH_IRQ
);
431 static struct device_driver jornada56x_driver
= {
432 .name
= "jornada56x",
433 .bus
= &platform_bus_type
,
434 .probe
= jornada56x_probe
,
435 .suspend
= jornada56x_suspend
,
436 .resume
= jornada56x_resume
,
439 /***********************************
441 * Jornada 56x system flash *
443 ***********************************/
445 static struct mtd_partition jornada56x_partitions
[] = {
450 .mask_flags
= MTD_WRITEABLE
,
453 .size
= MTDPART_SIZ_FULL
,
454 .offset
= MTDPART_OFS_APPEND
,
458 static void jornada56x_set_vpp(int vpp
)
467 static struct flash_platform_data jornada56x_flash_data
= {
468 .map_name
= "cfi_probe",
469 .parts
= jornada56x_partitions
,
470 .nr_parts
= ARRAY_SIZE(jornada56x_partitions
),
471 .set_vpp
= jornada56x_set_vpp
,
474 static struct resource jornada56x_flash_resource
= {
475 .start
= SA1100_CS0_PHYS
,
476 .end
= SA1100_CS0_PHYS
+ SZ_32M
- 1,
477 .flags
= IORESOURCE_MEM
,
480 /***********************************
482 * Jornada 56x system functions *
484 ***********************************/
486 static struct platform_device jornada56x_device
= {
487 .name
= "jornada56x",
491 static struct platform_device
*devices
[] __initdata
= {
495 static void irq_ack_low(unsigned int irq
)
497 JORNADA_INT_STAT
= (1 << (irq
- IRQ_JORNADA_MMC
));
500 static void irq_mask_low(unsigned int irq
)
502 JORNADA_INT_EN
&= ~(1 << (irq
- IRQ_JORNADA_MMC
));
505 static void irq_unmask_low(unsigned int irq
)
507 JORNADA_INT_EN
|= (1 << (irq
- IRQ_JORNADA_MMC
));
510 static struct irqchip irq_low
= {
512 .mask
= irq_mask_low
,
513 .unmask
= irq_unmask_low
,
516 static void irq_ack_high(unsigned int irq
)
518 JORNADA_INT_STAT2
= (1 << (irq
- IRQ_JORNADA_UART
));
521 static void irq_mask_high(unsigned int irq
)
523 JORNADA_INT_EN2
&= ~(1 << (irq
- IRQ_JORNADA_UART
));
526 static void irq_unmask_high(unsigned int irq
)
528 JORNADA_INT_EN2
|= (1 << (irq
- IRQ_JORNADA_UART
));
531 static struct irqchip irq_high
= {
533 .mask
= irq_mask_high
,
534 .unmask
= irq_unmask_high
,
537 static void irq_ack_gpiob(unsigned int irq
)
539 JORNADA_GPIOB_STAT
= (1 << (irq
- IRQ_JORNADA_GPIO_B0
));
542 static void irq_mask_gpiob(unsigned int irq
)
544 JORNADA_GPIOB_FE_EN
&= ~(1 << (irq
- IRQ_JORNADA_GPIO_B0
));
547 static void irq_unmask_gpiob(unsigned int irq
)
549 JORNADA_GPIOB_FE_EN
|= (1 << (irq
- IRQ_JORNADA_GPIO_B0
));
552 static struct irqchip irq_gpiob
= {
553 .ack
= irq_ack_gpiob
,
554 .mask
= irq_mask_gpiob
,
555 .unmask
= irq_unmask_gpiob
,
558 static void irq_ack_gpioc(unsigned int irq
)
560 JORNADA_GPIOC_STAT
= (1 << (irq
- IRQ_JORNADA_GPIO_C0
));
563 static void irq_mask_gpioc(unsigned int irq
)
565 JORNADA_GPIOC_FE_EN
&= ~(1 << (irq
- IRQ_JORNADA_GPIO_C0
));
568 static void irq_unmask_gpioc(unsigned int irq
)
570 JORNADA_GPIOC_FE_EN
|= (1 << (irq
- IRQ_JORNADA_GPIO_C0
));
573 static struct irqchip irq_gpioc
= {
574 .ack
= irq_ack_gpioc
,
575 .mask
= irq_mask_gpioc
,
576 .unmask
= irq_unmask_gpioc
,
579 extern asmlinkage
void asm_do_IRQ(int irq
, struct pt_regs
*regs
);
581 static void __init
jornada56x_init_irq(void)
590 JORNADA_INT_STAT
= 0xffff;
592 JORNADA_INT_STAT2
= 0xffff;
593 JORNADA_GPIOB_FE_EN
= 0;
594 JORNADA_GPIOB_RE_EN
= 0;
595 JORNADA_GPIOB_STAT
= 0xffff;
596 JORNADA_GPIOC_FE_EN
= 0;
597 JORNADA_GPIOC_RE_EN
= 0;
598 JORNADA_GPIOC_STAT
= 0xffff;
600 for (irq
= IRQ_JORNADA_MMC
; irq
<= IRQ_JORNADA_MMC
+ 15; irq
++) {
601 set_irq_chip(irq
, &irq_low
);
602 set_irq_handler(irq
, do_edge_IRQ
);
603 set_irq_flags(irq
, IRQF_VALID
| IRQF_PROBE
);
606 for (irq
= IRQ_JORNADA_UART
; irq
<= IRQ_JORNADA_UART
+ 15; irq
++) {
607 set_irq_chip(irq
, &irq_high
);
608 set_irq_handler(irq
, do_edge_IRQ
);
609 set_irq_flags(irq
, IRQF_VALID
| IRQF_PROBE
);
612 for (irq
= IRQ_JORNADA_GPIO_B0
; irq
<= IRQ_JORNADA_GPIO_B0
+ 15; irq
++) {
613 set_irq_chip(irq
, &irq_gpiob
);
614 set_irq_handler(irq
, do_edge_IRQ
);
615 set_irq_flags(irq
, IRQF_VALID
| IRQF_PROBE
);
618 for (irq
= IRQ_JORNADA_GPIO_C0
; irq
<= IRQ_JORNADA_GPIO_C0
+ 15; irq
++) {
619 set_irq_chip(irq
, &irq_gpioc
);
620 set_irq_handler(irq
, do_edge_IRQ
);
621 set_irq_flags(irq
, IRQF_VALID
| IRQF_PROBE
);
626 static irqreturn_t
jornada56x_IRQ_demux(int irq
, void *dev_id
, struct pt_regs
*regs
)
628 unsigned long stat0
, stat1
, statb
, statc
;
633 stat0
= JORNADA_INT_STAT
& 0xffff & JORNADA_INT_EN
634 & ~(JORNADA_GPIO_B_INT
| JORNADA_GPIO_C_INT
);
635 stat1
= JORNADA_INT_STAT2
& 0xffff & JORNADA_INT_EN2
;
636 statb
= JORNADA_GPIOB_STAT
& 0xffff & JORNADA_GPIOB_FE_EN
;
637 statc
= JORNADA_GPIOC_STAT
& 0xffff & JORNADA_GPIOC_FE_EN
;
638 #define CHECK_STAT(A,B) \
639 for (i = A; B; i++, B >>= 1) \
642 asm_do_IRQ(i, regs); \
644 CHECK_STAT(IRQ_JORNADA_MMC
, stat0
);
645 CHECK_STAT(IRQ_JORNADA_UART
, stat1
);
646 CHECK_STAT(IRQ_JORNADA_GPIO_B0
, statb
);
647 CHECK_STAT(IRQ_JORNADA_GPIO_C0
, statc
);
653 static void jornada56x_init(void)
655 platform_add_devices(devices
, ARRAY_SIZE(devices
));
656 driver_register(&jornada56x_driver
); /* initialize default GPIO states */
658 if (request_irq(GPIO_JORNADA56X_ASIC_IRQ
, jornada56x_IRQ_demux
,
659 SA_INTERRUPT
, "Jornada56x ASIC", NULL
)) {
660 printk("%s(): request_irq failed\n", __FUNCTION__
);
663 set_irq_type(GPIO_JORNADA56X_ASIC_IRQ
, IRQT_BOTHEDGE
);
665 /* initialise backlight and lcd */
666 sa1100_backlight_device
= backlight_device_register("sa1100fb", 0, &jornada56x_backlight_properties
);
667 sa1100_lcd_device
= lcd_device_register("sa1100fb", 0, &jornada56x_lcd_properties
);
668 sa1100fb_lcd_power
= jornada56x_lcd_power
;
669 sa1100fb_backlight_power
= jornada56x_backlight_power
;
671 set_apm_get_power_status(j56x_apm_get_power_status
); /* apm handler */
672 sa11x0_set_flash_data(&jornada56x_flash_data
, &jornada56x_flash_resource
, 1); /* set flash data */
675 static struct map_desc jornada56x_io_desc
[] __initdata
= {
677 .virtual = 0xf0000000, /* ASIC */
678 .pfn
= __phys_to_pfn(0x40000000),
679 .length
= 0x00100000,
684 static void __init
jornada56x_map_io(void)
687 iotable_init(jornada56x_io_desc
, ARRAY_SIZE(jornada56x_io_desc
));
689 sa1100_register_uart(0, 3);
690 sa1100_register_uart(1, 1);
692 /* configure suspend conditions */
698 PGSR
|= 0x0f5243fc; /* preserve vital GPIO */
699 PWER
|= GPIO_JORNADA56X_POWER_SWITCH
| PWER_RTC
;
703 MACHINE_START(JORNADA56X
, "HP Jornada 56x")
704 /* Maintainer: Alex Lange - chicken@handhelds.org */
705 .phys_ram
= 0xc0000000,
706 .phys_io
= 0x80000000,
707 .io_pg_offst
= ((0xf8000000) >> 18) & 0xfffc,
708 .boot_params
= 0xc0000100,
709 .map_io
= jornada56x_map_io
,
710 .init_irq
= jornada56x_init_irq
,
711 .timer
= &sa1100_timer
,
712 .init_machine
= jornada56x_init
,