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/module.h>
13 #include <linux/gpio.h>
14 #include <linux/i2c.h>
15 #include <linux/interrupt.h>
16 #include <linux/irq.h>
17 #include <linux/power_supply.h>
18 #include <linux/slab.h>
19 #include <linux/z2_battery.h>
21 #define Z2_DEFAULT_NAME "Z2"
24 struct z2_battery_info
*info
;
26 struct i2c_client
*client
;
27 struct power_supply batt_ps
;
28 struct mutex work_lock
;
29 struct work_struct bat_work
;
32 static unsigned long z2_read_bat(struct z2_charger
*charger
)
35 data
= i2c_smbus_read_byte_data(charger
->client
,
36 charger
->info
->batt_I2C_reg
);
40 return data
* charger
->info
->batt_mult
/ charger
->info
->batt_div
;
43 static int z2_batt_get_property(struct power_supply
*batt_ps
,
44 enum power_supply_property psp
,
45 union power_supply_propval
*val
)
47 struct z2_charger
*charger
= container_of(batt_ps
, struct z2_charger
,
49 struct z2_battery_info
*info
= charger
->info
;
52 case POWER_SUPPLY_PROP_STATUS
:
53 val
->intval
= charger
->bat_status
;
55 case POWER_SUPPLY_PROP_TECHNOLOGY
:
56 val
->intval
= info
->batt_tech
;
58 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
59 if (info
->batt_I2C_reg
>= 0)
60 val
->intval
= z2_read_bat(charger
);
64 case POWER_SUPPLY_PROP_VOLTAGE_MAX
:
65 if (info
->max_voltage
>= 0)
66 val
->intval
= info
->max_voltage
;
70 case POWER_SUPPLY_PROP_VOLTAGE_MIN
:
71 if (info
->min_voltage
>= 0)
72 val
->intval
= info
->min_voltage
;
76 case POWER_SUPPLY_PROP_PRESENT
:
86 static void z2_batt_ext_power_changed(struct power_supply
*batt_ps
)
88 struct z2_charger
*charger
= container_of(batt_ps
, struct z2_charger
,
90 schedule_work(&charger
->bat_work
);
93 static void z2_batt_update(struct z2_charger
*charger
)
95 int old_status
= charger
->bat_status
;
96 struct z2_battery_info
*info
;
100 mutex_lock(&charger
->work_lock
);
102 charger
->bat_status
= (info
->charge_gpio
>= 0) ?
103 (gpio_get_value(info
->charge_gpio
) ?
104 POWER_SUPPLY_STATUS_CHARGING
:
105 POWER_SUPPLY_STATUS_DISCHARGING
) :
106 POWER_SUPPLY_STATUS_UNKNOWN
;
108 if (old_status
!= charger
->bat_status
) {
109 pr_debug("%s: %i -> %i\n", charger
->batt_ps
.name
, old_status
,
110 charger
->bat_status
);
111 power_supply_changed(&charger
->batt_ps
);
114 mutex_unlock(&charger
->work_lock
);
117 static void z2_batt_work(struct work_struct
*work
)
119 struct z2_charger
*charger
;
120 charger
= container_of(work
, struct z2_charger
, bat_work
);
121 z2_batt_update(charger
);
124 static irqreturn_t
z2_charge_switch_irq(int irq
, void *devid
)
126 struct z2_charger
*charger
= devid
;
127 schedule_work(&charger
->bat_work
);
131 static int z2_batt_ps_init(struct z2_charger
*charger
, int props
)
134 enum power_supply_property
*prop
;
135 struct z2_battery_info
*info
= charger
->info
;
137 if (info
->batt_tech
>= 0)
138 props
++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
139 if (info
->batt_I2C_reg
>= 0)
140 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
141 if (info
->max_voltage
>= 0)
142 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
143 if (info
->min_voltage
>= 0)
144 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
146 prop
= kzalloc(props
* sizeof(*prop
), GFP_KERNEL
);
150 prop
[i
++] = POWER_SUPPLY_PROP_PRESENT
;
151 if (info
->charge_gpio
>= 0)
152 prop
[i
++] = POWER_SUPPLY_PROP_STATUS
;
153 if (info
->batt_tech
>= 0)
154 prop
[i
++] = POWER_SUPPLY_PROP_TECHNOLOGY
;
155 if (info
->batt_I2C_reg
>= 0)
156 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_NOW
;
157 if (info
->max_voltage
>= 0)
158 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MAX
;
159 if (info
->min_voltage
>= 0)
160 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MIN
;
162 if (!info
->batt_name
) {
163 dev_info(&charger
->client
->dev
,
164 "Please consider setting proper battery "
165 "name in platform definition file, falling "
166 "back to name \" Z2_DEFAULT_NAME \"\n");
167 charger
->batt_ps
.name
= Z2_DEFAULT_NAME
;
169 charger
->batt_ps
.name
= info
->batt_name
;
171 charger
->batt_ps
.properties
= prop
;
172 charger
->batt_ps
.num_properties
= props
;
173 charger
->batt_ps
.type
= POWER_SUPPLY_TYPE_BATTERY
;
174 charger
->batt_ps
.get_property
= z2_batt_get_property
;
175 charger
->batt_ps
.external_power_changed
= z2_batt_ext_power_changed
;
176 charger
->batt_ps
.use_for_apm
= 1;
181 static int __devinit
z2_batt_probe(struct i2c_client
*client
,
182 const struct i2c_device_id
*id
)
185 int props
= 1; /* POWER_SUPPLY_PROP_PRESENT */
186 struct z2_charger
*charger
;
187 struct z2_battery_info
*info
= client
->dev
.platform_data
;
190 dev_err(&client
->dev
,
191 "Please set platform device platform_data"
192 " to a valid z2_battery_info pointer!\n");
196 charger
= kzalloc(sizeof(*charger
), GFP_KERNEL
);
200 charger
->bat_status
= POWER_SUPPLY_STATUS_UNKNOWN
;
201 charger
->info
= info
;
202 charger
->client
= client
;
203 i2c_set_clientdata(client
, charger
);
205 mutex_init(&charger
->work_lock
);
207 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
)) {
208 ret
= gpio_request(info
->charge_gpio
, "BATT CHRG");
212 ret
= gpio_direction_input(info
->charge_gpio
);
216 set_irq_type(gpio_to_irq(info
->charge_gpio
),
218 ret
= request_irq(gpio_to_irq(info
->charge_gpio
),
219 z2_charge_switch_irq
, IRQF_DISABLED
,
220 "AC Detect", charger
);
225 ret
= z2_batt_ps_init(charger
, props
);
229 INIT_WORK(&charger
->bat_work
, z2_batt_work
);
231 ret
= power_supply_register(&client
->dev
, &charger
->batt_ps
);
235 schedule_work(&charger
->bat_work
);
240 kfree(charger
->batt_ps
.properties
);
242 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
243 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
245 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
246 gpio_free(info
->charge_gpio
);
252 static int __devexit
z2_batt_remove(struct i2c_client
*client
)
254 struct z2_charger
*charger
= i2c_get_clientdata(client
);
255 struct z2_battery_info
*info
= charger
->info
;
257 flush_scheduled_work();
258 power_supply_unregister(&charger
->batt_ps
);
260 kfree(charger
->batt_ps
.properties
);
261 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
)) {
262 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
263 gpio_free(info
->charge_gpio
);
272 static int z2_batt_suspend(struct i2c_client
*client
, pm_message_t state
)
274 flush_scheduled_work();
278 static int z2_batt_resume(struct i2c_client
*client
)
280 struct z2_charger
*charger
= i2c_get_clientdata(client
);
282 schedule_work(&charger
->bat_work
);
286 #define z2_batt_suspend NULL
287 #define z2_batt_resume NULL
290 static const struct i2c_device_id z2_batt_id
[] = {
295 static struct i2c_driver z2_batt_driver
= {
297 .name
= "z2-battery",
298 .owner
= THIS_MODULE
,
300 .probe
= z2_batt_probe
,
301 .remove
= z2_batt_remove
,
302 .suspend
= z2_batt_suspend
,
303 .resume
= z2_batt_resume
,
304 .id_table
= z2_batt_id
,
307 static int __init
z2_batt_init(void)
309 return i2c_add_driver(&z2_batt_driver
);
312 static void __exit
z2_batt_exit(void)
314 i2c_del_driver(&z2_batt_driver
);
317 module_init(z2_batt_init
);
318 module_exit(z2_batt_exit
);
320 MODULE_LICENSE("GPL");
321 MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
322 MODULE_DESCRIPTION("Zipit Z2 battery driver");