2 * Battery measurement code for Zipit Z2
4 * Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/power_supply.h>
17 #include <linux/i2c.h>
18 #include <linux/spinlock.h>
19 #include <linux/interrupt.h>
20 #include <linux/gpio.h>
21 #include <linux/interrupt.h>
22 #include <linux/irq.h>
24 #include <asm/mach/irq.h>
25 #include <linux/z2_battery.h>
27 #define Z2_DEFAULT_NAME "Z2"
30 struct z2_battery_info
*info
;
32 struct i2c_client
*client
;
33 struct power_supply batt_ps
;
34 struct mutex work_lock
;
35 struct work_struct bat_work
;
38 static unsigned long z2_read_bat(struct z2_charger
*charger
)
41 data
= i2c_smbus_read_byte_data(charger
->client
,
42 charger
->info
->batt_I2C_reg
);
46 return data
* charger
->info
->batt_mult
/ charger
->info
->batt_div
;
49 static int z2_batt_get_property(struct power_supply
*batt_ps
,
50 enum power_supply_property psp
,
51 union power_supply_propval
*val
)
53 struct z2_charger
*charger
= container_of(batt_ps
, struct z2_charger
,
55 struct z2_battery_info
*info
= charger
->info
;
58 case POWER_SUPPLY_PROP_STATUS
:
59 val
->intval
= charger
->bat_status
;
61 case POWER_SUPPLY_PROP_TECHNOLOGY
:
62 val
->intval
= info
->batt_tech
;
64 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
65 if (info
->batt_I2C_reg
>= 0)
66 val
->intval
= z2_read_bat(charger
);
70 case POWER_SUPPLY_PROP_VOLTAGE_MAX
:
71 if (info
->max_voltage
>= 0)
72 val
->intval
= info
->max_voltage
;
76 case POWER_SUPPLY_PROP_VOLTAGE_MIN
:
77 if (info
->min_voltage
>= 0)
78 val
->intval
= info
->min_voltage
;
82 case POWER_SUPPLY_PROP_PRESENT
:
92 static void z2_batt_ext_power_changed(struct power_supply
*batt_ps
)
94 struct z2_charger
*charger
= container_of(batt_ps
, struct z2_charger
,
96 schedule_work(&charger
->bat_work
);
99 static void z2_batt_update(struct z2_charger
*charger
)
101 int old_status
= charger
->bat_status
;
102 struct z2_battery_info
*info
;
104 info
= charger
->info
;
106 mutex_lock(&charger
->work_lock
);
108 charger
->bat_status
= (info
->charge_gpio
>= 0) ?
109 (gpio_get_value(info
->charge_gpio
) ?
110 POWER_SUPPLY_STATUS_CHARGING
:
111 POWER_SUPPLY_STATUS_DISCHARGING
) :
112 POWER_SUPPLY_STATUS_UNKNOWN
;
114 if (old_status
!= charger
->bat_status
) {
115 pr_debug("%s: %i -> %i\n", charger
->batt_ps
.name
, old_status
,
116 charger
->bat_status
);
117 power_supply_changed(&charger
->batt_ps
);
120 mutex_unlock(&charger
->work_lock
);
123 static void z2_batt_work(struct work_struct
*work
)
125 struct z2_charger
*charger
;
126 charger
= container_of(work
, struct z2_charger
, bat_work
);
127 z2_batt_update(charger
);
130 static irqreturn_t
z2_charge_switch_irq(int irq
, void *devid
)
132 struct z2_charger
*charger
= devid
;
133 schedule_work(&charger
->bat_work
);
137 static int z2_batt_ps_init(struct z2_charger
*charger
, int props
)
140 enum power_supply_property
*prop
;
141 struct z2_battery_info
*info
= charger
->info
;
143 if (info
->batt_tech
>= 0)
144 props
++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
145 if (info
->batt_I2C_reg
>= 0)
146 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
147 if (info
->max_voltage
>= 0)
148 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
149 if (info
->min_voltage
>= 0)
150 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
152 prop
= kzalloc(props
* sizeof(*prop
), GFP_KERNEL
);
156 prop
[i
++] = POWER_SUPPLY_PROP_PRESENT
;
157 if (info
->charge_gpio
>= 0)
158 prop
[i
++] = POWER_SUPPLY_PROP_STATUS
;
159 if (info
->batt_tech
>= 0)
160 prop
[i
++] = POWER_SUPPLY_PROP_TECHNOLOGY
;
161 if (info
->batt_I2C_reg
>= 0)
162 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_NOW
;
163 if (info
->max_voltage
>= 0)
164 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MAX
;
165 if (info
->min_voltage
>= 0)
166 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MIN
;
168 if (!info
->batt_name
) {
169 dev_info(&charger
->client
->dev
,
170 "Please consider setting proper battery "
171 "name in platform definition file, falling "
172 "back to name \" Z2_DEFAULT_NAME \"\n");
173 charger
->batt_ps
.name
= Z2_DEFAULT_NAME
;
175 charger
->batt_ps
.name
= info
->batt_name
;
177 charger
->batt_ps
.properties
= prop
;
178 charger
->batt_ps
.num_properties
= props
;
179 charger
->batt_ps
.type
= POWER_SUPPLY_TYPE_BATTERY
;
180 charger
->batt_ps
.get_property
= z2_batt_get_property
;
181 charger
->batt_ps
.external_power_changed
= z2_batt_ext_power_changed
;
182 charger
->batt_ps
.use_for_apm
= 1;
187 static int __devinit
z2_batt_probe(struct i2c_client
*client
,
188 const struct i2c_device_id
*id
)
191 int props
= 1; /* POWER_SUPPLY_PROP_PRESENT */
192 struct z2_charger
*charger
;
193 struct z2_battery_info
*info
= client
->dev
.platform_data
;
196 dev_err(&client
->dev
,
197 "Please set platform device platform_data"
198 " to a valid z2_battery_info pointer!\n");
202 charger
= kzalloc(sizeof(*charger
), GFP_KERNEL
);
206 charger
->bat_status
= POWER_SUPPLY_STATUS_UNKNOWN
;
207 charger
->info
= info
;
208 charger
->client
= client
;
209 i2c_set_clientdata(client
, charger
);
211 mutex_init(&charger
->work_lock
);
213 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
)) {
214 ret
= gpio_request(info
->charge_gpio
, "BATT CHRG");
218 ret
= gpio_direction_input(info
->charge_gpio
);
222 set_irq_type(gpio_to_irq(info
->charge_gpio
),
224 ret
= request_irq(gpio_to_irq(info
->charge_gpio
),
225 z2_charge_switch_irq
, IRQF_DISABLED
,
226 "AC Detect", charger
);
231 ret
= z2_batt_ps_init(charger
, props
);
235 INIT_WORK(&charger
->bat_work
, z2_batt_work
);
237 ret
= power_supply_register(&client
->dev
, &charger
->batt_ps
);
241 schedule_work(&charger
->bat_work
);
246 kfree(charger
->batt_ps
.properties
);
248 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
249 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
251 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
252 gpio_free(info
->charge_gpio
);
258 static int __devexit
z2_batt_remove(struct i2c_client
*client
)
260 struct z2_charger
*charger
= i2c_get_clientdata(client
);
261 struct z2_battery_info
*info
= charger
->info
;
263 flush_scheduled_work();
264 power_supply_unregister(&charger
->batt_ps
);
266 kfree(charger
->batt_ps
.properties
);
267 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
)) {
268 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
269 gpio_free(info
->charge_gpio
);
278 static int z2_batt_suspend(struct i2c_client
*client
, pm_message_t state
)
280 flush_scheduled_work();
284 static int z2_batt_resume(struct i2c_client
*client
)
286 struct z2_charger
*charger
= i2c_get_clientdata(client
);
288 schedule_work(&charger
->bat_work
);
292 #define z2_batt_suspend NULL
293 #define z2_batt_resume NULL
296 static const struct i2c_device_id z2_batt_id
[] = {
301 static struct i2c_driver z2_batt_driver
= {
303 .name
= "z2-battery",
304 .owner
= THIS_MODULE
,
306 .probe
= z2_batt_probe
,
307 .remove
= z2_batt_remove
,
308 .suspend
= z2_batt_suspend
,
309 .resume
= z2_batt_resume
,
310 .id_table
= z2_batt_id
,
313 static int __init
z2_batt_init(void)
315 return i2c_add_driver(&z2_batt_driver
);
318 static void __exit
z2_batt_exit(void)
320 i2c_del_driver(&z2_batt_driver
);
323 module_init(z2_batt_init
);
324 module_exit(z2_batt_exit
);
326 MODULE_LICENSE("GPL");
327 MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
328 MODULE_DESCRIPTION("Zipit Z2 battery driver");