2 * Generic battery driver code using IIO
3 * Copyright (C) 2012, Anish Kumar <anish198519851985@gmail.com>
4 * based on jz4740-battery.c
5 * based on s3c_adc_battery.c
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
12 #include <linux/interrupt.h>
13 #include <linux/platform_device.h>
14 #include <linux/power_supply.h>
15 #include <linux/gpio.h>
16 #include <linux/err.h>
17 #include <linux/timer.h>
18 #include <linux/jiffies.h>
19 #include <linux/errno.h>
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/iio/consumer.h>
24 #include <linux/iio/types.h>
25 #include <linux/power/generic-adc-battery.h>
27 #define JITTER_DEFAULT 10 /* hope 10ms is enough */
37 * gab_chan_name suggests the standard channel names for commonly used
40 static const char *const gab_chan_name
[] = {
41 [GAB_VOLTAGE
] = "voltage",
42 [GAB_CURRENT
] = "current",
43 [GAB_POWER
] = "power",
47 struct power_supply
*psy
;
48 struct power_supply_desc psy_desc
;
49 struct iio_channel
*channel
[GAB_MAX_CHAN_TYPE
];
50 struct gab_platform_data
*pdata
;
51 struct delayed_work bat_work
;
57 static struct gab
*to_generic_bat(struct power_supply
*psy
)
59 return power_supply_get_drvdata(psy
);
62 static void gab_ext_power_changed(struct power_supply
*psy
)
64 struct gab
*adc_bat
= to_generic_bat(psy
);
66 schedule_delayed_work(&adc_bat
->bat_work
, msecs_to_jiffies(0));
69 static const enum power_supply_property gab_props
[] = {
70 POWER_SUPPLY_PROP_STATUS
,
71 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
72 POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN
,
73 POWER_SUPPLY_PROP_CHARGE_NOW
,
74 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
75 POWER_SUPPLY_PROP_CURRENT_NOW
,
76 POWER_SUPPLY_PROP_TECHNOLOGY
,
77 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
,
78 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
,
79 POWER_SUPPLY_PROP_MODEL_NAME
,
83 * This properties are set based on the received platform data and this
84 * should correspond one-to-one with enum chan_type.
86 static const enum power_supply_property gab_dyn_props
[] = {
87 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
88 POWER_SUPPLY_PROP_CURRENT_NOW
,
89 POWER_SUPPLY_PROP_POWER_NOW
,
92 static bool gab_charge_finished(struct gab
*adc_bat
)
94 struct gab_platform_data
*pdata
= adc_bat
->pdata
;
95 bool ret
= gpio_get_value(pdata
->gpio_charge_finished
);
96 bool inv
= pdata
->gpio_inverted
;
98 if (!gpio_is_valid(pdata
->gpio_charge_finished
))
103 static int gab_get_status(struct gab
*adc_bat
)
105 struct gab_platform_data
*pdata
= adc_bat
->pdata
;
106 struct power_supply_info
*bat_info
;
108 bat_info
= &pdata
->battery_info
;
109 if (adc_bat
->level
== bat_info
->charge_full_design
)
110 return POWER_SUPPLY_STATUS_FULL
;
111 return adc_bat
->status
;
114 static enum gab_chan_type
gab_prop_to_chan(enum power_supply_property psp
)
117 case POWER_SUPPLY_PROP_POWER_NOW
:
119 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
121 case POWER_SUPPLY_PROP_CURRENT_NOW
:
130 static int read_channel(struct gab
*adc_bat
, enum power_supply_property psp
,
136 chan_index
= gab_prop_to_chan(psp
);
137 ret
= iio_read_channel_processed(adc_bat
->channel
[chan_index
],
140 pr_err("read channel error\n");
144 static int gab_get_property(struct power_supply
*psy
,
145 enum power_supply_property psp
, union power_supply_propval
*val
)
148 struct gab_platform_data
*pdata
;
149 struct power_supply_info
*bat_info
;
153 adc_bat
= to_generic_bat(psy
);
155 dev_err(&psy
->dev
, "no battery infos ?!\n");
158 pdata
= adc_bat
->pdata
;
159 bat_info
= &pdata
->battery_info
;
162 case POWER_SUPPLY_PROP_STATUS
:
163 val
->intval
= gab_get_status(adc_bat
);
165 case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN
:
168 case POWER_SUPPLY_PROP_CHARGE_NOW
:
169 val
->intval
= pdata
->cal_charge(result
);
171 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
172 case POWER_SUPPLY_PROP_CURRENT_NOW
:
173 case POWER_SUPPLY_PROP_POWER_NOW
:
174 ret
= read_channel(adc_bat
, psp
, &result
);
177 val
->intval
= result
;
179 case POWER_SUPPLY_PROP_TECHNOLOGY
:
180 val
->intval
= bat_info
->technology
;
182 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
:
183 val
->intval
= bat_info
->voltage_min_design
;
185 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
:
186 val
->intval
= bat_info
->voltage_max_design
;
188 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
189 val
->intval
= bat_info
->charge_full_design
;
191 case POWER_SUPPLY_PROP_MODEL_NAME
:
192 val
->strval
= bat_info
->name
;
201 static void gab_work(struct work_struct
*work
)
204 struct delayed_work
*delayed_work
;
208 delayed_work
= to_delayed_work(work
);
209 adc_bat
= container_of(delayed_work
, struct gab
, bat_work
);
210 status
= adc_bat
->status
;
212 is_plugged
= power_supply_am_i_supplied(adc_bat
->psy
);
213 adc_bat
->cable_plugged
= is_plugged
;
216 adc_bat
->status
= POWER_SUPPLY_STATUS_DISCHARGING
;
217 else if (gab_charge_finished(adc_bat
))
218 adc_bat
->status
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
220 adc_bat
->status
= POWER_SUPPLY_STATUS_CHARGING
;
222 if (status
!= adc_bat
->status
)
223 power_supply_changed(adc_bat
->psy
);
226 static irqreturn_t
gab_charged(int irq
, void *dev_id
)
228 struct gab
*adc_bat
= dev_id
;
229 struct gab_platform_data
*pdata
= adc_bat
->pdata
;
232 delay
= pdata
->jitter_delay
? pdata
->jitter_delay
: JITTER_DEFAULT
;
233 schedule_delayed_work(&adc_bat
->bat_work
,
234 msecs_to_jiffies(delay
));
238 static int gab_probe(struct platform_device
*pdev
)
241 struct power_supply_desc
*psy_desc
;
242 struct power_supply_config psy_cfg
= {};
243 struct gab_platform_data
*pdata
= pdev
->dev
.platform_data
;
244 enum power_supply_property
*properties
;
249 adc_bat
= devm_kzalloc(&pdev
->dev
, sizeof(*adc_bat
), GFP_KERNEL
);
251 dev_err(&pdev
->dev
, "failed to allocate memory\n");
255 psy_cfg
.drv_data
= adc_bat
;
256 psy_desc
= &adc_bat
->psy_desc
;
257 psy_desc
->name
= pdata
->battery_info
.name
;
259 /* bootup default values for the battery */
260 adc_bat
->cable_plugged
= false;
261 adc_bat
->status
= POWER_SUPPLY_STATUS_DISCHARGING
;
262 psy_desc
->type
= POWER_SUPPLY_TYPE_BATTERY
;
263 psy_desc
->get_property
= gab_get_property
;
264 psy_desc
->external_power_changed
= gab_ext_power_changed
;
265 adc_bat
->pdata
= pdata
;
268 * copying the static properties and allocating extra memory for holding
269 * the extra configurable properties received from platform data.
271 psy_desc
->properties
= kcalloc(ARRAY_SIZE(gab_props
) +
272 ARRAY_SIZE(gab_chan_name
),
273 sizeof(*psy_desc
->properties
),
275 if (!psy_desc
->properties
) {
280 memcpy(psy_desc
->properties
, gab_props
, sizeof(gab_props
));
281 properties
= (enum power_supply_property
*)
282 ((char *)psy_desc
->properties
+ sizeof(gab_props
));
285 * getting channel from iio and copying the battery properties
286 * based on the channel supported by consumer device.
288 for (chan
= 0; chan
< ARRAY_SIZE(gab_chan_name
); chan
++) {
289 adc_bat
->channel
[chan
] = iio_channel_get(&pdev
->dev
,
290 gab_chan_name
[chan
]);
291 if (IS_ERR(adc_bat
->channel
[chan
])) {
292 ret
= PTR_ERR(adc_bat
->channel
[chan
]);
293 adc_bat
->channel
[chan
] = NULL
;
295 /* copying properties for supported channels only */
296 memcpy(properties
+ sizeof(*(psy_desc
->properties
)) * index
,
297 &gab_dyn_props
[chan
],
298 sizeof(gab_dyn_props
[chan
]));
303 /* none of the channels are supported so let's bail out */
306 goto second_mem_fail
;
310 * Total number of properties is equal to static properties
311 * plus the dynamic properties.Some properties may not be set
312 * as come channels may be not be supported by the device.So
313 * we need to take care of that.
315 psy_desc
->num_properties
= ARRAY_SIZE(gab_props
) + index
;
317 adc_bat
->psy
= power_supply_register(&pdev
->dev
, psy_desc
, &psy_cfg
);
318 if (IS_ERR(adc_bat
->psy
)) {
319 ret
= PTR_ERR(adc_bat
->psy
);
323 INIT_DELAYED_WORK(&adc_bat
->bat_work
, gab_work
);
325 if (gpio_is_valid(pdata
->gpio_charge_finished
)) {
327 ret
= gpio_request(pdata
->gpio_charge_finished
, "charged");
331 irq
= gpio_to_irq(pdata
->gpio_charge_finished
);
332 ret
= request_any_context_irq(irq
, gab_charged
,
333 IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING
,
334 "battery charged", adc_bat
);
339 platform_set_drvdata(pdev
, adc_bat
);
341 /* Schedule timer to check current status */
342 schedule_delayed_work(&adc_bat
->bat_work
,
343 msecs_to_jiffies(0));
347 gpio_free(pdata
->gpio_charge_finished
);
349 power_supply_unregister(adc_bat
->psy
);
351 for (chan
= 0; chan
< ARRAY_SIZE(gab_chan_name
); chan
++) {
352 if (adc_bat
->channel
[chan
])
353 iio_channel_release(adc_bat
->channel
[chan
]);
356 kfree(psy_desc
->properties
);
361 static int gab_remove(struct platform_device
*pdev
)
364 struct gab
*adc_bat
= platform_get_drvdata(pdev
);
365 struct gab_platform_data
*pdata
= adc_bat
->pdata
;
367 power_supply_unregister(adc_bat
->psy
);
369 if (gpio_is_valid(pdata
->gpio_charge_finished
)) {
370 free_irq(gpio_to_irq(pdata
->gpio_charge_finished
), adc_bat
);
371 gpio_free(pdata
->gpio_charge_finished
);
374 for (chan
= 0; chan
< ARRAY_SIZE(gab_chan_name
); chan
++) {
375 if (adc_bat
->channel
[chan
])
376 iio_channel_release(adc_bat
->channel
[chan
]);
379 kfree(adc_bat
->psy_desc
.properties
);
380 cancel_delayed_work(&adc_bat
->bat_work
);
384 static int __maybe_unused
gab_suspend(struct device
*dev
)
386 struct gab
*adc_bat
= dev_get_drvdata(dev
);
388 cancel_delayed_work_sync(&adc_bat
->bat_work
);
389 adc_bat
->status
= POWER_SUPPLY_STATUS_UNKNOWN
;
393 static int __maybe_unused
gab_resume(struct device
*dev
)
395 struct gab
*adc_bat
= dev_get_drvdata(dev
);
396 struct gab_platform_data
*pdata
= adc_bat
->pdata
;
399 delay
= pdata
->jitter_delay
? pdata
->jitter_delay
: JITTER_DEFAULT
;
401 /* Schedule timer to check current status */
402 schedule_delayed_work(&adc_bat
->bat_work
,
403 msecs_to_jiffies(delay
));
407 static SIMPLE_DEV_PM_OPS(gab_pm_ops
, gab_suspend
, gab_resume
);
409 static struct platform_driver gab_driver
= {
411 .name
= "generic-adc-battery",
415 .remove
= gab_remove
,
417 module_platform_driver(gab_driver
);
419 MODULE_AUTHOR("anish kumar <anish198519851985@gmail.com>");
420 MODULE_DESCRIPTION("generic battery driver using IIO");
421 MODULE_LICENSE("GPL");