1 // SPDX-License-Identifier: GPL-2.0-only
3 * Battery measurement code for Zipit Z2
5 * Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.com>
8 #include <linux/module.h>
9 #include <linux/gpio.h>
10 #include <linux/i2c.h>
11 #include <linux/interrupt.h>
12 #include <linux/irq.h>
13 #include <linux/power_supply.h>
14 #include <linux/slab.h>
15 #include <linux/z2_battery.h>
17 #define Z2_DEFAULT_NAME "Z2"
20 struct z2_battery_info
*info
;
22 struct i2c_client
*client
;
23 struct power_supply
*batt_ps
;
24 struct power_supply_desc batt_ps_desc
;
25 struct mutex work_lock
;
26 struct work_struct bat_work
;
29 static unsigned long z2_read_bat(struct z2_charger
*charger
)
32 data
= i2c_smbus_read_byte_data(charger
->client
,
33 charger
->info
->batt_I2C_reg
);
37 return data
* charger
->info
->batt_mult
/ charger
->info
->batt_div
;
40 static int z2_batt_get_property(struct power_supply
*batt_ps
,
41 enum power_supply_property psp
,
42 union power_supply_propval
*val
)
44 struct z2_charger
*charger
= power_supply_get_drvdata(batt_ps
);
45 struct z2_battery_info
*info
= charger
->info
;
48 case POWER_SUPPLY_PROP_STATUS
:
49 val
->intval
= charger
->bat_status
;
51 case POWER_SUPPLY_PROP_TECHNOLOGY
:
52 val
->intval
= info
->batt_tech
;
54 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
55 if (info
->batt_I2C_reg
>= 0)
56 val
->intval
= z2_read_bat(charger
);
60 case POWER_SUPPLY_PROP_VOLTAGE_MAX
:
61 if (info
->max_voltage
>= 0)
62 val
->intval
= info
->max_voltage
;
66 case POWER_SUPPLY_PROP_VOLTAGE_MIN
:
67 if (info
->min_voltage
>= 0)
68 val
->intval
= info
->min_voltage
;
72 case POWER_SUPPLY_PROP_PRESENT
:
82 static void z2_batt_ext_power_changed(struct power_supply
*batt_ps
)
84 struct z2_charger
*charger
= power_supply_get_drvdata(batt_ps
);
86 schedule_work(&charger
->bat_work
);
89 static void z2_batt_update(struct z2_charger
*charger
)
91 int old_status
= charger
->bat_status
;
92 struct z2_battery_info
*info
;
96 mutex_lock(&charger
->work_lock
);
98 charger
->bat_status
= (info
->charge_gpio
>= 0) ?
99 (gpio_get_value(info
->charge_gpio
) ?
100 POWER_SUPPLY_STATUS_CHARGING
:
101 POWER_SUPPLY_STATUS_DISCHARGING
) :
102 POWER_SUPPLY_STATUS_UNKNOWN
;
104 if (old_status
!= charger
->bat_status
) {
105 pr_debug("%s: %i -> %i\n", charger
->batt_ps
->desc
->name
,
107 charger
->bat_status
);
108 power_supply_changed(charger
->batt_ps
);
111 mutex_unlock(&charger
->work_lock
);
114 static void z2_batt_work(struct work_struct
*work
)
116 struct z2_charger
*charger
;
117 charger
= container_of(work
, struct z2_charger
, bat_work
);
118 z2_batt_update(charger
);
121 static irqreturn_t
z2_charge_switch_irq(int irq
, void *devid
)
123 struct z2_charger
*charger
= devid
;
124 schedule_work(&charger
->bat_work
);
128 static int z2_batt_ps_init(struct z2_charger
*charger
, int props
)
131 enum power_supply_property
*prop
;
132 struct z2_battery_info
*info
= charger
->info
;
134 if (info
->charge_gpio
>= 0)
135 props
++; /* POWER_SUPPLY_PROP_STATUS */
136 if (info
->batt_tech
>= 0)
137 props
++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
138 if (info
->batt_I2C_reg
>= 0)
139 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
140 if (info
->max_voltage
>= 0)
141 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
142 if (info
->min_voltage
>= 0)
143 props
++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
145 prop
= kcalloc(props
, sizeof(*prop
), GFP_KERNEL
);
149 prop
[i
++] = POWER_SUPPLY_PROP_PRESENT
;
150 if (info
->charge_gpio
>= 0)
151 prop
[i
++] = POWER_SUPPLY_PROP_STATUS
;
152 if (info
->batt_tech
>= 0)
153 prop
[i
++] = POWER_SUPPLY_PROP_TECHNOLOGY
;
154 if (info
->batt_I2C_reg
>= 0)
155 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_NOW
;
156 if (info
->max_voltage
>= 0)
157 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MAX
;
158 if (info
->min_voltage
>= 0)
159 prop
[i
++] = POWER_SUPPLY_PROP_VOLTAGE_MIN
;
161 if (!info
->batt_name
) {
162 dev_info(&charger
->client
->dev
,
163 "Please consider setting proper battery "
164 "name in platform definition file, falling "
165 "back to name \" Z2_DEFAULT_NAME \"\n");
166 charger
->batt_ps_desc
.name
= Z2_DEFAULT_NAME
;
168 charger
->batt_ps_desc
.name
= info
->batt_name
;
170 charger
->batt_ps_desc
.properties
= prop
;
171 charger
->batt_ps_desc
.num_properties
= props
;
172 charger
->batt_ps_desc
.type
= POWER_SUPPLY_TYPE_BATTERY
;
173 charger
->batt_ps_desc
.get_property
= z2_batt_get_property
;
174 charger
->batt_ps_desc
.external_power_changed
=
175 z2_batt_ext_power_changed
;
176 charger
->batt_ps_desc
.use_for_apm
= 1;
181 static int 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
;
188 struct power_supply_config psy_cfg
= {};
191 dev_err(&client
->dev
,
192 "Please set platform device platform_data"
193 " to a valid z2_battery_info pointer!\n");
197 charger
= kzalloc(sizeof(*charger
), GFP_KERNEL
);
201 charger
->bat_status
= POWER_SUPPLY_STATUS_UNKNOWN
;
202 charger
->info
= info
;
203 charger
->client
= client
;
204 i2c_set_clientdata(client
, charger
);
205 psy_cfg
.drv_data
= 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
, 0,
222 "AC Detect", charger
);
227 ret
= z2_batt_ps_init(charger
, props
);
231 INIT_WORK(&charger
->bat_work
, z2_batt_work
);
233 charger
->batt_ps
= power_supply_register(&client
->dev
,
234 &charger
->batt_ps_desc
,
236 if (IS_ERR(charger
->batt_ps
)) {
237 ret
= PTR_ERR(charger
->batt_ps
);
241 schedule_work(&charger
->bat_work
);
246 kfree(charger
->batt_ps_desc
.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 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 cancel_work_sync(&charger
->bat_work
);
264 power_supply_unregister(charger
->batt_ps
);
266 kfree(charger
->batt_ps_desc
.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 device
*dev
)
280 struct i2c_client
*client
= to_i2c_client(dev
);
281 struct z2_charger
*charger
= i2c_get_clientdata(client
);
283 flush_work(&charger
->bat_work
);
287 static int z2_batt_resume(struct device
*dev
)
289 struct i2c_client
*client
= to_i2c_client(dev
);
290 struct z2_charger
*charger
= i2c_get_clientdata(client
);
292 schedule_work(&charger
->bat_work
);
296 static const struct dev_pm_ops z2_battery_pm_ops
= {
297 .suspend
= z2_batt_suspend
,
298 .resume
= z2_batt_resume
,
301 #define Z2_BATTERY_PM_OPS (&z2_battery_pm_ops)
304 #define Z2_BATTERY_PM_OPS (NULL)
307 static const struct i2c_device_id z2_batt_id
[] = {
311 MODULE_DEVICE_TABLE(i2c
, z2_batt_id
);
313 static struct i2c_driver z2_batt_driver
= {
315 .name
= "z2-battery",
316 .pm
= Z2_BATTERY_PM_OPS
318 .probe
= z2_batt_probe
,
319 .remove
= z2_batt_remove
,
320 .id_table
= z2_batt_id
,
322 module_i2c_driver(z2_batt_driver
);
324 MODULE_LICENSE("GPL");
325 MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
326 MODULE_DESCRIPTION("Zipit Z2 battery driver");