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 power_supply_desc batt_ps_desc
;
29 struct mutex work_lock
;
30 struct work_struct bat_work
;
33 static unsigned long z2_read_bat(struct z2_charger
*charger
)
36 data
= i2c_smbus_read_byte_data(charger
->client
,
37 charger
->info
->batt_I2C_reg
);
41 return data
* charger
->info
->batt_mult
/ charger
->info
->batt_div
;
44 static int z2_batt_get_property(struct power_supply
*batt_ps
,
45 enum power_supply_property psp
,
46 union power_supply_propval
*val
)
48 struct z2_charger
*charger
= power_supply_get_drvdata(batt_ps
);
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
= power_supply_get_drvdata(batt_ps
);
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
->desc
->name
,
111 charger
->bat_status
);
112 power_supply_changed(charger
->batt_ps
);
115 mutex_unlock(&charger
->work_lock
);
118 static void z2_batt_work(struct work_struct
*work
)
120 struct z2_charger
*charger
;
121 charger
= container_of(work
, struct z2_charger
, bat_work
);
122 z2_batt_update(charger
);
125 static irqreturn_t
z2_charge_switch_irq(int irq
, void *devid
)
127 struct z2_charger
*charger
= devid
;
128 schedule_work(&charger
->bat_work
);
132 static int z2_batt_ps_init(struct z2_charger
*charger
, int props
)
135 enum power_supply_property
*prop
;
136 struct z2_battery_info
*info
= charger
->info
;
138 if (info
->charge_gpio
>= 0)
139 props
++; /* POWER_SUPPLY_PROP_STATUS */
140 if (info
->batt_tech
>= 0)
141 props
++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
142 if (info
->batt_I2C_reg
>= 0)
143 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
144 if (info
->max_voltage
>= 0)
145 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
146 if (info
->min_voltage
>= 0)
147 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
149 prop
= kzalloc(props
* sizeof(*prop
), GFP_KERNEL
);
153 prop
[i
++] = POWER_SUPPLY_PROP_PRESENT
;
154 if (info
->charge_gpio
>= 0)
155 prop
[i
++] = POWER_SUPPLY_PROP_STATUS
;
156 if (info
->batt_tech
>= 0)
157 prop
[i
++] = POWER_SUPPLY_PROP_TECHNOLOGY
;
158 if (info
->batt_I2C_reg
>= 0)
159 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_NOW
;
160 if (info
->max_voltage
>= 0)
161 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MAX
;
162 if (info
->min_voltage
>= 0)
163 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MIN
;
165 if (!info
->batt_name
) {
166 dev_info(&charger
->client
->dev
,
167 "Please consider setting proper battery "
168 "name in platform definition file, falling "
169 "back to name \" Z2_DEFAULT_NAME \"\n");
170 charger
->batt_ps_desc
.name
= Z2_DEFAULT_NAME
;
172 charger
->batt_ps_desc
.name
= info
->batt_name
;
174 charger
->batt_ps_desc
.properties
= prop
;
175 charger
->batt_ps_desc
.num_properties
= props
;
176 charger
->batt_ps_desc
.type
= POWER_SUPPLY_TYPE_BATTERY
;
177 charger
->batt_ps_desc
.get_property
= z2_batt_get_property
;
178 charger
->batt_ps_desc
.external_power_changed
=
179 z2_batt_ext_power_changed
;
180 charger
->batt_ps_desc
.use_for_apm
= 1;
185 static int z2_batt_probe(struct i2c_client
*client
,
186 const struct i2c_device_id
*id
)
189 int props
= 1; /* POWER_SUPPLY_PROP_PRESENT */
190 struct z2_charger
*charger
;
191 struct z2_battery_info
*info
= client
->dev
.platform_data
;
192 struct power_supply_config psy_cfg
= {};
195 dev_err(&client
->dev
,
196 "Please set platform device platform_data"
197 " to a valid z2_battery_info pointer!\n");
201 charger
= kzalloc(sizeof(*charger
), GFP_KERNEL
);
205 charger
->bat_status
= POWER_SUPPLY_STATUS_UNKNOWN
;
206 charger
->info
= info
;
207 charger
->client
= client
;
208 i2c_set_clientdata(client
, charger
);
209 psy_cfg
.drv_data
= 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 irq_set_irq_type(gpio_to_irq(info
->charge_gpio
),
224 ret
= request_irq(gpio_to_irq(info
->charge_gpio
),
225 z2_charge_switch_irq
, 0,
226 "AC Detect", charger
);
231 ret
= z2_batt_ps_init(charger
, props
);
235 INIT_WORK(&charger
->bat_work
, z2_batt_work
);
237 charger
->batt_ps
= power_supply_register(&client
->dev
,
238 &charger
->batt_ps_desc
,
240 if (IS_ERR(charger
->batt_ps
)) {
241 ret
= PTR_ERR(charger
->batt_ps
);
245 schedule_work(&charger
->bat_work
);
250 kfree(charger
->batt_ps_desc
.properties
);
252 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
253 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
255 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
))
256 gpio_free(info
->charge_gpio
);
262 static int z2_batt_remove(struct i2c_client
*client
)
264 struct z2_charger
*charger
= i2c_get_clientdata(client
);
265 struct z2_battery_info
*info
= charger
->info
;
267 cancel_work_sync(&charger
->bat_work
);
268 power_supply_unregister(charger
->batt_ps
);
270 kfree(charger
->batt_ps_desc
.properties
);
271 if (info
->charge_gpio
>= 0 && gpio_is_valid(info
->charge_gpio
)) {
272 free_irq(gpio_to_irq(info
->charge_gpio
), charger
);
273 gpio_free(info
->charge_gpio
);
282 static int z2_batt_suspend(struct device
*dev
)
284 struct i2c_client
*client
= to_i2c_client(dev
);
285 struct z2_charger
*charger
= i2c_get_clientdata(client
);
287 flush_work(&charger
->bat_work
);
291 static int z2_batt_resume(struct device
*dev
)
293 struct i2c_client
*client
= to_i2c_client(dev
);
294 struct z2_charger
*charger
= i2c_get_clientdata(client
);
296 schedule_work(&charger
->bat_work
);
300 static const struct dev_pm_ops z2_battery_pm_ops
= {
301 .suspend
= z2_batt_suspend
,
302 .resume
= z2_batt_resume
,
305 #define Z2_BATTERY_PM_OPS (&z2_battery_pm_ops)
308 #define Z2_BATTERY_PM_OPS (NULL)
311 static const struct i2c_device_id z2_batt_id
[] = {
315 MODULE_DEVICE_TABLE(i2c
, z2_batt_id
);
317 static struct i2c_driver z2_batt_driver
= {
319 .name
= "z2-battery",
320 .owner
= THIS_MODULE
,
321 .pm
= Z2_BATTERY_PM_OPS
323 .probe
= z2_batt_probe
,
324 .remove
= z2_batt_remove
,
325 .id_table
= z2_batt_id
,
327 module_i2c_driver(z2_batt_driver
);
329 MODULE_LICENSE("GPL");
330 MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
331 MODULE_DESCRIPTION("Zipit Z2 battery driver");