2 * Power and APM status driver for iPAQ h1910/h1915
4 * Use consistent with the GNU GPL is permitted,
5 * provided that this copyright notice is
6 * preserved in its entirety in all copies and derived works.
8 * Copyright (C) 2005-2006 Pawel Kolodziejski
9 * Copyright (C) 2003 Joshua Wise
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/tty.h>
17 #include <linux/sched.h>
18 #include <linux/delay.h>
20 #include <linux/bootmem.h>
21 #include <linux/lcd.h>
22 #include <linux/backlight.h>
24 #include <linux/platform_device.h>
25 #include <linux/soc/asic3_base.h>
26 #include <linux/soc/tmio_mmc.h>
29 #include <asm/mach-types.h>
30 #include <asm/hardware.h>
31 #include <asm/setup.h>
34 #include <asm/mach/irq.h>
35 #include <asm/mach/arch.h>
36 #include <asm/mach/map.h>
37 #include <asm/mach/irda.h>
38 #include <asm/arch/h1900-asic.h>
39 #include <asm/arch/h1900-gpio.h>
40 #include <asm/arch/ipaq.h>
41 #include <asm/arch/udc.h>
42 #include <asm/arch/pxafb.h>
44 #include <asm/arch/pxa-regs.h>
45 #include <asm/arch/pxa-pm_ll.h>
46 #include <asm/arch/irq.h>
47 #include <asm/types.h>
50 #include "../generic.h"
53 extern struct platform_device h1900_asic3
;
54 #define asic3 &h1900_asic3.dev
59 unsigned long h1900_ssp_putget(ulong data
);
60 void h1900_set_led(int color
, int duty_time
, int cycle_time
);
62 static void h1900_pxa_ll_pm_suspend(unsigned long resume_addr
)
65 *addr_sig
= 0x4C494E42; // LINB signature for bootloader while resume
68 static void h1900_pxa_ll_pm_resume(void)
73 static struct pxa_ll_pm_ops h1900_ll_pm_ops
= {
74 .suspend
= h1900_pxa_ll_pm_suspend
,
75 .resume
= h1900_pxa_ll_pm_resume
,
78 void h1900_ll_pm_init(void)
80 addr_sig
= phys_to_virt(0xa0a00000);
81 pxa_pm_set_ll_ops(&h1900_ll_pm_ops
);
84 static irqreturn_t
h1900_charge(int irq
, void *dev_id
, struct pt_regs
*regs
)
88 if (!(GPLR(GPIO_NR_H1900_AC_IN_N
) & GPIO_bit(GPIO_NR_H1900_AC_IN_N
)) &&
89 (GPLR(GPIO_NR_H1900_MBAT_IN
) & GPIO_bit(GPIO_NR_H1900_MBAT_IN
)) )
97 if (GPLR(GPIO_NR_H1900_CHARGING
) & GPIO_bit(GPIO_NR_H1900_CHARGING
)) {
102 asic3_set_led(asic3
, 1, dtime
, 0x100);
103 asic3_set_led(asic3
, 0, dtime
, 0x100);
104 GPSR(GPIO_NR_H1900_CHARGER_EN
) = GPIO_bit(GPIO_NR_H1900_CHARGER_EN
);
106 asic3_set_led(asic3
, 1, 0, 0x100);
107 asic3_set_led(asic3
, 0, 0, 0x100);
108 GPCR(GPIO_NR_H1900_CHARGER_EN
) = GPIO_bit(GPIO_NR_H1900_CHARGER_EN
);
114 static struct irqaction h1900_charge_irq
= {
115 name
: "h1910/h1915 charge",
116 handler
: h1900_charge
,
122 #define CTRL_START 0x80
123 #define CTRL_AUX_N 0x64
124 #define CTRL_PD0 0x01
126 static void h1900_battery(void)
130 sample
= h1900_ssp_putget(CTRL_PD0
| CTRL_START
| CTRL_AUX_N
); // main battery: max - 4096, min - 3300
131 h1900_ssp_putget(CTRL_START
| CTRL_AUX_N
);
133 battery_power
= ((sample
- 3300) * 100) / 796;
135 if (!!(GPLR(GPIO_NR_H1900_AC_IN_N
) & GPIO_bit(GPIO_NR_H1900_AC_IN_N
))) {
136 if (battery_power
> 50) {
137 asic3_set_led(asic3
, 1, 0, 0x100);
138 asic3_set_led(asic3
, 0, 0, 0x100);
139 } else if ((battery_power
< 50) && (battery_power
> 10)) {
140 h1900_set_led(H1900_GREEN_LED
, 0x101, 0x100);
141 } else if (battery_power
< 10) {
142 h1900_set_led(H1900_RED_LED
, 0x101, 0x100);
146 //printk("bat: %d\n", battery_power);
149 typedef void (*apm_get_power_status_t
)(struct apm_power_info
*);
151 static void h1900_apm_get_power_status(struct apm_power_info
*info
)
155 info
->battery_life
= battery_power
;
157 if (!(GPLR(GPIO_NR_H1900_AC_IN_N
) & GPIO_bit(GPIO_NR_H1900_AC_IN_N
)))
158 info
->ac_line_status
= APM_AC_ONLINE
;
160 info
->ac_line_status
= APM_AC_OFFLINE
;
162 if (GPLR(GPIO_NR_H1900_CHARGING
) & GPIO_bit(GPIO_NR_H1900_CHARGING
))
163 info
->battery_status
= APM_BATTERY_STATUS_CHARGING
;
164 else if (!(GPLR(GPIO_NR_H1900_MBAT_IN
) & GPIO_bit(GPIO_NR_H1900_MBAT_IN
)))
165 info
->battery_status
= APM_BATTERY_STATUS_NOT_PRESENT
;
167 if (battery_power
> 50)
168 info
->battery_status
= APM_BATTERY_STATUS_HIGH
;
169 else if (battery_power
< 5)
170 info
->battery_status
= APM_BATTERY_STATUS_CRITICAL
;
172 info
->battery_status
= APM_BATTERY_STATUS_LOW
;
179 int set_apm_get_power_status(apm_get_power_status_t t
)
181 apm_get_power_status
= t
;
187 static int h1900_power_probe(struct device
*dev
)
189 h1900_charge(0, NULL
, NULL
);
191 set_irq_type(IRQ_GPIO(GPIO_NR_H1900_AC_IN_N
), IRQT_BOTHEDGE
);
192 set_irq_type(IRQ_GPIO(GPIO_NR_H1900_MBAT_IN
), IRQT_BOTHEDGE
);
193 set_irq_type(IRQ_GPIO(GPIO_NR_H1900_CHARGING
), IRQT_BOTHEDGE
);
194 setup_irq(IRQ_GPIO(GPIO_NR_H1900_AC_IN_N
), &h1900_charge_irq
);
195 setup_irq(IRQ_GPIO(GPIO_NR_H1900_MBAT_IN
), &h1900_charge_irq
);
196 setup_irq(IRQ_GPIO(GPIO_NR_H1900_CHARGING
), &h1900_charge_irq
);
199 set_apm_get_power_status(h1900_apm_get_power_status
);
206 static int h1900_power_suspend(struct device
*dev
, pm_message_t state
)
208 asic3_set_led(asic3
, 1, 0, 0x100);
209 asic3_set_led(asic3
, 0, 0, 0x100);
211 disable_irq(IRQ_GPIO(GPIO_NR_H1900_AC_IN_N
));
212 disable_irq(IRQ_GPIO(GPIO_NR_H1900_MBAT_IN
));
213 disable_irq(IRQ_GPIO(GPIO_NR_H1900_CHARGING
));
218 static int h1900_power_resume(struct device
*dev
)
220 enable_irq(IRQ_GPIO(GPIO_NR_H1900_AC_IN_N
));
221 enable_irq(IRQ_GPIO(GPIO_NR_H1900_MBAT_IN
));
222 enable_irq(IRQ_GPIO(GPIO_NR_H1900_CHARGING
));
228 static struct device_driver h1900_power_driver
= {
229 .name
= "h1900-power",
230 .bus
= &platform_bus_type
,
231 .probe
= h1900_power_probe
,
233 .suspend
= h1900_power_suspend
,
234 .resume
= h1900_power_resume
,
238 static int __init
h1900_power_init(void)
240 if (!machine_is_h1900())
243 return driver_register(&h1900_power_driver
);
246 static void __exit
h1900_power_exit(void)
248 driver_unregister(&h1900_power_driver
);
251 module_init(h1900_power_init
);
252 module_exit(h1900_power_exit
);
254 MODULE_AUTHOR("Joshua Wise, Pawel Kolodziejski");
255 MODULE_DESCRIPTION("HP iPAQ h1910/h1915 Power Driver");
256 MODULE_LICENSE("GPL");