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
->charge_gpio
>= 0)
138 props
++; /* POWER_SUPPLY_PROP_STATUS */
139 if (info
->batt_tech
>= 0)
140 props
++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
141 if (info
->batt_I2C_reg
>= 0)
142 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
143 if (info
->max_voltage
>= 0)
144 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
145 if (info
->min_voltage
>= 0)
146 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
148 prop
= kzalloc(props
* sizeof(*prop
), GFP_KERNEL
);
152 prop
[i
++] = POWER_SUPPLY_PROP_PRESENT
;
153 if (info
->charge_gpio
>= 0)
154 prop
[i
++] = POWER_SUPPLY_PROP_STATUS
;
155 if (info
->batt_tech
>= 0)
156 prop
[i
++] = POWER_SUPPLY_PROP_TECHNOLOGY
;
157 if (info
->batt_I2C_reg
>= 0)
158 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_NOW
;
159 if (info
->max_voltage
>= 0)
160 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MAX
;
161 if (info
->min_voltage
>= 0)
162 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MIN
;
164 if (!info
->batt_name
) {
165 dev_info(&charger
->client
->dev
,
166 "Please consider setting proper battery "
167 "name in platform definition file, falling "
168 "back to name \" Z2_DEFAULT_NAME \"\n");
169 charger
->batt_ps
.name
= Z2_DEFAULT_NAME
;
171 charger
->batt_ps
.name
= info
->batt_name
;
173 charger
->batt_ps
.properties
= prop
;
174 charger
->batt_ps
.num_properties
= props
;
175 charger
->batt_ps
.type
= POWER_SUPPLY_TYPE_BATTERY
;
176 charger
->batt_ps
.get_property
= z2_batt_get_property
;
177 charger
->batt_ps
.external_power_changed
= z2_batt_ext_power_changed
;
178 charger
->batt_ps
.use_for_apm
= 1;
183 static int __devinit
z2_batt_probe(struct i2c_client
*client
,
184 const struct i2c_device_id
*id
)
187 int props
= 1; /* POWER_SUPPLY_PROP_PRESENT */
188 struct z2_charger
*charger
;
189 struct z2_battery_info
*info
= client
->dev
.platform_data
;
192 dev_err(&client
->dev
,
193 "Please set platform device platform_data"
194 " to a valid z2_battery_info pointer!\n");
198 charger
= kzalloc(sizeof(*charger
), GFP_KERNEL
);
202 charger
->bat_status
= POWER_SUPPLY_STATUS_UNKNOWN
;
203 charger
->info
= info
;
204 charger
->client
= client
;
205 i2c_set_clientdata(client
, charger
);
207 mutex_init(&charger
->work_lock
);
209 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
)) {
210 ret
= gpio_request(info
->charge_gpio
, "BATT CHRG");
214 ret
= gpio_direction_input(info
->charge_gpio
);
218 irq_set_irq_type(gpio_to_irq(info
->charge_gpio
),
220 ret
= request_irq(gpio_to_irq(info
->charge_gpio
),
221 z2_charge_switch_irq
, IRQF_DISABLED
,
222 "AC Detect", charger
);
227 ret
= z2_batt_ps_init(charger
, props
);
231 INIT_WORK(&charger
->bat_work
, z2_batt_work
);
233 ret
= power_supply_register(&client
->dev
, &charger
->batt_ps
);
237 schedule_work(&charger
->bat_work
);
242 kfree(charger
->batt_ps
.properties
);
244 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
245 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
247 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
248 gpio_free(info
->charge_gpio
);
254 static int __devexit
z2_batt_remove(struct i2c_client
*client
)
256 struct z2_charger
*charger
= i2c_get_clientdata(client
);
257 struct z2_battery_info
*info
= charger
->info
;
259 cancel_work_sync(&charger
->bat_work
);
260 power_supply_unregister(&charger
->batt_ps
);
262 kfree(charger
->batt_ps
.properties
);
263 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
)) {
264 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
265 gpio_free(info
->charge_gpio
);
274 static int z2_batt_suspend(struct device
*dev
)
276 struct i2c_client
*client
= to_i2c_client(dev
);
277 struct z2_charger
*charger
= i2c_get_clientdata(client
);
279 flush_work_sync(&charger
->bat_work
);
283 static int z2_batt_resume(struct device
*dev
)
285 struct i2c_client
*client
= to_i2c_client(dev
);
286 struct z2_charger
*charger
= i2c_get_clientdata(client
);
288 schedule_work(&charger
->bat_work
);
292 static const struct dev_pm_ops z2_battery_pm_ops
= {
293 .suspend
= z2_batt_suspend
,
294 .resume
= z2_batt_resume
,
297 #define Z2_BATTERY_PM_OPS (&z2_battery_pm_ops)
300 #define Z2_BATTERY_PM_OPS (NULL)
303 static const struct i2c_device_id z2_batt_id
[] = {
307 MODULE_DEVICE_TABLE(i2c
, z2_batt_id
);
309 static struct i2c_driver z2_batt_driver
= {
311 .name
= "z2-battery",
312 .owner
= THIS_MODULE
,
313 .pm
= Z2_BATTERY_PM_OPS
315 .probe
= z2_batt_probe
,
316 .remove
= z2_batt_remove
,
317 .id_table
= z2_batt_id
,
320 static int __init
z2_batt_init(void)
322 return i2c_add_driver(&z2_batt_driver
);
325 static void __exit
z2_batt_exit(void)
327 i2c_del_driver(&z2_batt_driver
);
330 module_init(z2_batt_init
);
331 module_exit(z2_batt_exit
);
333 MODULE_LICENSE("GPL");
334 MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
335 MODULE_DESCRIPTION("Zipit Z2 battery driver");