2 * Copyright (C) 2003 Joshua Wise
3 * Copyright (c) 2002,2003 SHARP Corporation
4 * Copyright (C) 2005 Pawel Kolodziejski
6 * Use consistent with the GNU GPL is permitted,
7 * provided that this copyright notice is
8 * preserved in its entirety in all copies and derived works.
10 * HAL code based on h5400_asic_io.c, which is
11 * Copyright (C) 2003 Compaq Computer Corporation.
13 * Author: Joshua Wise <joshua at joshuawise.com>
18 #include <linux/module.h>
19 #include <linux/version.h>
20 #include <linux/init.h>
22 #include <linux/interrupt.h>
23 #include <linux/sched.h>
25 #include <linux/device.h>
26 #include <linux/sysctl.h>
27 #include <linux/delay.h>
28 #include <linux/input.h>
29 #include <linux/soc/asic3_base.h>
30 #include <linux/platform_device.h>
32 #include <asm/mach/map.h>
33 #include <asm/mach-types.h>
34 #include <asm/arch/hardware.h>
36 #include <asm/mach/irq.h>
37 #include <asm/arch/pxa-regs.h>
38 #include <asm/arch-pxa/h4000-gpio.h>
39 #include <asm/arch-pxa/h4000-asic.h>
40 #include <asm/hardware/ipaq-asic3.h>
43 /* Actually had battery fault at 3358 -pfalcon
44 Also, wince appears to shutdown at much higer
45 value, and using this one gives battery percentages
46 completely not matching wince. Anyway, way to solve
47 this is to figure out how to get battery *capacity*,
50 #define BATTERY_MIN 3400
51 #define BATTERY_MAX 3950
54 /* The ADS7846 has touchscreen and other sensors.
55 * Earlier ads784x chips are somewhat compatible.
57 #define ADS_START (1 << 7)
58 #define ADS_A2A1A0_d_y (1 << 4) /* differential */
59 #define ADS_A2A1A0_d_z1 (3 << 4) /* differential */
60 #define ADS_A2A1A0_d_z2 (4 << 4) /* differential */
61 #define ADS_A2A1A0_d_x (5 << 4) /* differential */
62 #define ADS_A2A1A0_temp0 (0 << 4) /* non-differential */
63 #define ADS_A2A1A0_vbatt (2 << 4) /* non-differential */
64 #define ADS_A2A1A0_vaux (6 << 4) /* non-differential */
65 #define ADS_A2A1A0_temp1 (7 << 4) /* non-differential */
66 #define ADS_8_BIT (1 << 3)
67 #define ADS_12_BIT (0 << 3)
68 #define ADS_SER (1 << 2) /* non-differential */
69 #define ADS_DFR (0 << 2) /* differential */
70 #define ADS_PD10_PDOWN (0 << 0) /* lowpower mode + penirq */
71 #define ADS_PD10_ADC_ON (1 << 0) /* ADC on */
72 #define ADS_PD10_REF_ON (2 << 0) /* vREF on + penirq */
73 #define ADS_PD10_ALL_ON (3 << 0) /* ADC + vREF on */
76 extern struct platform_device h4000_asic3
;
77 #define asic3 &h4000_asic3.dev
78 extern void h4000_set_led(int color
, int duty_time
, int cycle_time
);
79 extern unsigned long h4000_spi_putget(ulong data
);
81 static struct timer_list timer_bat
;
85 static void h4000_battery(unsigned long nr
)
89 /* Select main battery voltage source VS_MBAT */
90 asic3_set_gpio_out_d(asic3
, GPIOD_MUX_SEL1
|GPIOD_MUX_SEL0
, 0);
91 /* Likely not yet fully settled, by seems stable */
93 sample
= h4000_spi_putget(ADS_START
| ADS_A2A1A0_vaux
| ADS_12_BIT
| ADS_SER
| ADS_PD10_ADC_ON
);
94 //printk("sample vaux= %d\n", sample);
96 /* Throw away invalid samples, this does happen soon after resume for example. */
98 battery_power
= ((sample
- BATTERY_MIN
) * 100) / (BATTERY_MAX
- BATTERY_MIN
);
99 if (battery_power
< 0)
101 else if (battery_power
> 100)
106 if (!!(GPLR(GPIO_NR_H4000_AC_IN_N
) & GPIO_bit(GPIO_NR_H4000_AC_IN_N
))) {
107 if (battery_power
> 50) {
108 asic3_set_led(asic3
, 1, 0, 0x100);
109 asic3_set_led(asic3
, 0, 0, 0x100);
110 } else if ((battery_power
< 50) && (battery_power
> 10))
111 h4000_set_led(H4000_GREEN_LED
, 0x101, 0x100);
112 else if (battery_power
< 10)
113 h4000_set_led(H4000_RED_LED
, 0x101, 0x100);
116 //printk("bat: %d\n", battery_power);
118 mod_timer(&timer_bat
, jiffies
+ (1000 * HZ
) / 1000);
121 typedef void (*apm_get_power_status_t
)(struct apm_power_info
*);
123 static void h4000_apm_get_power_status(struct apm_power_info
*info
)
125 info
->battery_life
= battery_power
;
127 if (!(GPLR(GPIO_NR_H4000_AC_IN_N
) & GPIO_bit(GPIO_NR_H4000_AC_IN_N
)))
128 info
->ac_line_status
= APM_AC_ONLINE
;
130 info
->ac_line_status
= APM_AC_OFFLINE
;
132 if (GPLR(GPIO_NR_H4000_CHARGING
) & GPIO_bit(GPIO_NR_H4000_CHARGING
))
133 info
->battery_status
= APM_BATTERY_STATUS_CHARGING
;
134 /*else if (!(GPLR(GPIO_NR_H4000_MBAT_IN) & GPIO_bit(GPIO_NR_H4000_MBAT_IN)))
135 info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT;*/
137 if (battery_power
> 50)
138 info
->battery_status
= APM_BATTERY_STATUS_HIGH
;
139 else if (battery_power
< 5)
140 info
->battery_status
= APM_BATTERY_STATUS_CRITICAL
;
142 info
->battery_status
= APM_BATTERY_STATUS_LOW
;
145 /* Consider one "percent" per minute, which is shot in the sky. */
146 info
->time
= battery_power
;
147 info
->units
= APM_UNITS_MINS
;
150 int set_apm_get_power_status(apm_get_power_status_t t
)
152 apm_get_power_status
= t
;
159 static int h4000_batt_probe(struct platform_device
*dev
)
161 init_timer(&timer_bat
);
162 timer_bat
.function
= h4000_battery
;
163 timer_bat
.data
= (unsigned long)NULL
;
165 mod_timer(&timer_bat
, jiffies
+ (1000 * HZ
) / 1000);
168 set_apm_get_power_status(h4000_apm_get_power_status
);
175 static int h4000_batt_resume(struct platform_device
*pdev
)
180 #define h4000_batt_resume NULL
183 static struct platform_driver h4000_batt_driver
= {
185 .name
= "h4000_batt",
187 .probe
= h4000_batt_probe
,
190 .resume
= h4000_batt_resume
,
194 static int __init
h4000_batt_init(void)
196 if (!machine_is_h4000())
199 return platform_driver_register(&h4000_batt_driver
);
202 static void __exit
h4000_batt_exit(void)
204 del_timer_sync(&timer_bat
);
205 platform_driver_unregister(&h4000_batt_driver
);
208 module_init(h4000_batt_init
)
209 module_exit(h4000_batt_exit
)
211 MODULE_AUTHOR("Paul Sokolovsky");
212 MODULE_DESCRIPTION("Battery driver for the iPAQ h4xxx");
213 MODULE_LICENSE("GPL");