2 * Battery charger driver for Dialog Semiconductor DA9030
4 * Copyright (C) 2008 Compulab, Ltd.
5 * Mike Rapoport <mike@compulab.co.il>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/types.h>
15 #include <linux/device.h>
16 #include <linux/workqueue.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/power_supply.h>
20 #include <linux/mfd/da903x.h>
22 #include <linux/debugfs.h>
23 #include <linux/seq_file.h>
25 #define DA9030_STATUS_CHDET (1 << 3)
27 #define DA9030_FAULT_LOG 0x0a
28 #define DA9030_FAULT_LOG_OVER_TEMP (1 << 7)
29 #define DA9030_FAULT_LOG_VBAT_OVER (1 << 4)
31 #define DA9030_CHARGE_CONTROL 0x28
32 #define DA9030_CHRG_CHARGER_ENABLE (1 << 7)
34 #define DA9030_ADC_MAN_CONTROL 0x30
35 #define DA9030_ADC_TBATREF_ENABLE (1 << 5)
36 #define DA9030_ADC_LDO_INT_ENABLE (1 << 4)
38 #define DA9030_ADC_AUTO_CONTROL 0x31
39 #define DA9030_ADC_TBAT_ENABLE (1 << 5)
40 #define DA9030_ADC_VBAT_IN_TXON (1 << 4)
41 #define DA9030_ADC_VCH_ENABLE (1 << 3)
42 #define DA9030_ADC_ICH_ENABLE (1 << 2)
43 #define DA9030_ADC_VBAT_ENABLE (1 << 1)
44 #define DA9030_ADC_AUTO_SLEEP_ENABLE (1 << 0)
46 #define DA9030_VBATMON 0x32
47 #define DA9030_VBATMONTXON 0x33
48 #define DA9030_TBATHIGHP 0x34
49 #define DA9030_TBATHIGHN 0x35
50 #define DA9030_TBATLOW 0x36
52 #define DA9030_VBAT_RES 0x41
53 #define DA9030_VBATMIN_RES 0x42
54 #define DA9030_VBATMINTXON_RES 0x43
55 #define DA9030_ICHMAX_RES 0x44
56 #define DA9030_ICHMIN_RES 0x45
57 #define DA9030_ICHAVERAGE_RES 0x46
58 #define DA9030_VCHMAX_RES 0x47
59 #define DA9030_VCHMIN_RES 0x48
60 #define DA9030_TBAT_RES 0x49
62 struct da9030_adc_res
{
68 uint8_t ichaverage_res
;
76 struct da9030_battery_thresholds
{
83 int vbat_charge_start
;
85 int vbat_charge_restart
;
91 struct da9030_charger
{
92 struct power_supply psy
;
94 struct device
*master
;
96 struct da9030_adc_res adc
;
97 struct delayed_work work
;
98 unsigned int interval
;
100 struct power_supply_info
*battery_info
;
102 struct da9030_battery_thresholds thresholds
;
104 unsigned int charge_milliamp
;
105 unsigned int charge_millivolt
;
114 struct notifier_block nb
;
116 /* platform callbacks for battery low and critical events */
117 void (*battery_low
)(void);
118 void (*battery_critical
)(void);
120 struct dentry
*debug_file
;
123 static inline int da9030_reg_to_mV(int reg
)
125 return ((reg
* 2650) >> 8) + 2650;
128 static inline int da9030_millivolt_to_reg(int mV
)
130 return ((mV
- 2650) << 8) / 2650;
133 static inline int da9030_reg_to_mA(int reg
)
135 return ((reg
* 24000) >> 8) / 15;
138 #ifdef CONFIG_DEBUG_FS
139 static int bat_debug_show(struct seq_file
*s
, void *data
)
141 struct da9030_charger
*charger
= s
->private;
143 seq_printf(s
, "charger is %s\n", charger
->is_on
? "on" : "off");
144 if (charger
->chdet
) {
145 seq_printf(s
, "iset = %dmA, vset = %dmV\n",
146 charger
->mA
, charger
->mV
);
149 seq_printf(s
, "vbat_res = %d (%dmV)\n",
150 charger
->adc
.vbat_res
,
151 da9030_reg_to_mV(charger
->adc
.vbat_res
));
152 seq_printf(s
, "vbatmin_res = %d (%dmV)\n",
153 charger
->adc
.vbatmin_res
,
154 da9030_reg_to_mV(charger
->adc
.vbatmin_res
));
155 seq_printf(s
, "vbatmintxon = %d (%dmV)\n",
156 charger
->adc
.vbatmintxon
,
157 da9030_reg_to_mV(charger
->adc
.vbatmintxon
));
158 seq_printf(s
, "ichmax_res = %d (%dmA)\n",
159 charger
->adc
.ichmax_res
,
160 da9030_reg_to_mV(charger
->adc
.ichmax_res
));
161 seq_printf(s
, "ichmin_res = %d (%dmA)\n",
162 charger
->adc
.ichmin_res
,
163 da9030_reg_to_mA(charger
->adc
.ichmin_res
));
164 seq_printf(s
, "ichaverage_res = %d (%dmA)\n",
165 charger
->adc
.ichaverage_res
,
166 da9030_reg_to_mA(charger
->adc
.ichaverage_res
));
167 seq_printf(s
, "vchmax_res = %d (%dmV)\n",
168 charger
->adc
.vchmax_res
,
169 da9030_reg_to_mA(charger
->adc
.vchmax_res
));
170 seq_printf(s
, "vchmin_res = %d (%dmV)\n",
171 charger
->adc
.vchmin_res
,
172 da9030_reg_to_mV(charger
->adc
.vchmin_res
));
177 static int debug_open(struct inode
*inode
, struct file
*file
)
179 return single_open(file
, bat_debug_show
, inode
->i_private
);
182 static const struct file_operations bat_debug_fops
= {
186 .release
= single_release
,
189 static struct dentry
*da9030_bat_create_debugfs(struct da9030_charger
*charger
)
191 charger
->debug_file
= debugfs_create_file("charger", 0666, 0, charger
,
193 return charger
->debug_file
;
196 static void da9030_bat_remove_debugfs(struct da9030_charger
*charger
)
198 debugfs_remove(charger
->debug_file
);
201 static inline struct dentry
*da9030_bat_create_debugfs(struct da9030_charger
*charger
)
205 static inline void da9030_bat_remove_debugfs(struct da9030_charger
*charger
)
210 static inline void da9030_read_adc(struct da9030_charger
*charger
,
211 struct da9030_adc_res
*adc
)
213 da903x_reads(charger
->master
, DA9030_VBAT_RES
,
214 sizeof(*adc
), (uint8_t *)adc
);
217 static void da9030_charger_update_state(struct da9030_charger
*charger
)
221 da903x_read(charger
->master
, DA9030_CHARGE_CONTROL
, &val
);
222 charger
->is_on
= (val
& DA9030_CHRG_CHARGER_ENABLE
) ? 1 : 0;
223 charger
->mA
= ((val
>> 3) & 0xf) * 100;
224 charger
->mV
= (val
& 0x7) * 50 + 4000;
226 da9030_read_adc(charger
, &charger
->adc
);
227 da903x_read(charger
->master
, DA9030_FAULT_LOG
, &charger
->fault
);
228 charger
->chdet
= da903x_query_status(charger
->master
,
229 DA9030_STATUS_CHDET
);
232 static void da9030_set_charge(struct da9030_charger
*charger
, int on
)
237 val
= DA9030_CHRG_CHARGER_ENABLE
;
238 val
|= (charger
->charge_milliamp
/ 100) << 3;
239 val
|= (charger
->charge_millivolt
- 4000) / 50;
246 da903x_write(charger
->master
, DA9030_CHARGE_CONTROL
, val
);
249 static void da9030_charger_check_state(struct da9030_charger
*charger
)
251 da9030_charger_update_state(charger
);
253 /* we wake or boot with external power on */
254 if (!charger
->is_on
) {
255 if ((charger
->chdet
) &&
256 (charger
->adc
.vbat_res
<
257 charger
->thresholds
.vbat_charge_start
)) {
258 da9030_set_charge(charger
, 1);
261 if (charger
->adc
.vbat_res
>=
262 charger
->thresholds
.vbat_charge_stop
) {
263 da9030_set_charge(charger
, 0);
264 da903x_write(charger
->master
, DA9030_VBATMON
,
265 charger
->thresholds
.vbat_charge_restart
);
266 } else if (charger
->adc
.vbat_res
>
267 charger
->thresholds
.vbat_low
) {
268 /* we are charging and passed LOW_THRESH,
269 so upate DA9030 VBAT threshold
271 da903x_write(charger
->master
, DA9030_VBATMON
,
272 charger
->thresholds
.vbat_low
);
274 if (charger
->adc
.vchmax_res
> charger
->thresholds
.vcharge_max
||
275 charger
->adc
.vchmin_res
< charger
->thresholds
.vcharge_min
||
276 /* Tempreture readings are negative */
277 charger
->adc
.tbat_res
< charger
->thresholds
.tbat_high
||
278 charger
->adc
.tbat_res
> charger
->thresholds
.tbat_low
) {
279 /* disable charger */
280 da9030_set_charge(charger
, 0);
285 static void da9030_charging_monitor(struct work_struct
*work
)
287 struct da9030_charger
*charger
;
289 charger
= container_of(work
, struct da9030_charger
, work
.work
);
291 da9030_charger_check_state(charger
);
293 /* reschedule for the next time */
294 schedule_delayed_work(&charger
->work
, charger
->interval
);
297 static enum power_supply_property da9030_battery_props
[] = {
298 POWER_SUPPLY_PROP_MODEL_NAME
,
299 POWER_SUPPLY_PROP_STATUS
,
300 POWER_SUPPLY_PROP_HEALTH
,
301 POWER_SUPPLY_PROP_TECHNOLOGY
,
302 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
,
303 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
,
304 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
305 POWER_SUPPLY_PROP_CURRENT_AVG
,
308 static void da9030_battery_check_status(struct da9030_charger
*charger
,
309 union power_supply_propval
*val
)
311 if (charger
->chdet
) {
313 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
315 val
->intval
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
317 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
321 static void da9030_battery_check_health(struct da9030_charger
*charger
,
322 union power_supply_propval
*val
)
324 if (charger
->fault
& DA9030_FAULT_LOG_OVER_TEMP
)
325 val
->intval
= POWER_SUPPLY_HEALTH_OVERHEAT
;
326 else if (charger
->fault
& DA9030_FAULT_LOG_VBAT_OVER
)
327 val
->intval
= POWER_SUPPLY_HEALTH_OVERVOLTAGE
;
329 val
->intval
= POWER_SUPPLY_HEALTH_GOOD
;
332 static int da9030_battery_get_property(struct power_supply
*psy
,
333 enum power_supply_property psp
,
334 union power_supply_propval
*val
)
336 struct da9030_charger
*charger
;
337 charger
= container_of(psy
, struct da9030_charger
, psy
);
340 case POWER_SUPPLY_PROP_STATUS
:
341 da9030_battery_check_status(charger
, val
);
343 case POWER_SUPPLY_PROP_HEALTH
:
344 da9030_battery_check_health(charger
, val
);
346 case POWER_SUPPLY_PROP_TECHNOLOGY
:
347 val
->intval
= charger
->battery_info
->technology
;
349 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
:
350 val
->intval
= charger
->battery_info
->voltage_max_design
;
352 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
:
353 val
->intval
= charger
->battery_info
->voltage_min_design
;
355 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
356 val
->intval
= da9030_reg_to_mV(charger
->adc
.vbat_res
) * 1000;
358 case POWER_SUPPLY_PROP_CURRENT_AVG
:
360 da9030_reg_to_mA(charger
->adc
.ichaverage_res
) * 1000;
362 case POWER_SUPPLY_PROP_MODEL_NAME
:
363 val
->strval
= charger
->battery_info
->name
;
372 static void da9030_battery_vbat_event(struct da9030_charger
*charger
)
374 da9030_read_adc(charger
, &charger
->adc
);
379 if (charger
->adc
.vbat_res
< charger
->thresholds
.vbat_low
) {
380 /* set VBAT threshold for critical */
381 da903x_write(charger
->master
, DA9030_VBATMON
,
382 charger
->thresholds
.vbat_crit
);
383 if (charger
->battery_low
)
384 charger
->battery_low();
385 } else if (charger
->adc
.vbat_res
<
386 charger
->thresholds
.vbat_crit
) {
387 /* notify the system of battery critical */
388 if (charger
->battery_critical
)
389 charger
->battery_critical();
393 static int da9030_battery_event(struct notifier_block
*nb
, unsigned long event
,
396 struct da9030_charger
*charger
=
397 container_of(nb
, struct da9030_charger
, nb
);
401 case DA9030_EVENT_CHDET
:
402 status
= da903x_query_status(charger
->master
,
403 DA9030_STATUS_CHDET
);
404 da9030_set_charge(charger
, status
);
406 case DA9030_EVENT_VBATMON
:
407 da9030_battery_vbat_event(charger
);
409 case DA9030_EVENT_CHIOVER
:
410 case DA9030_EVENT_TBAT
:
411 da9030_set_charge(charger
, 0);
418 static void da9030_battery_convert_thresholds(struct da9030_charger
*charger
,
419 struct da9030_battery_info
*pdata
)
421 charger
->thresholds
.tbat_low
= pdata
->tbat_low
;
422 charger
->thresholds
.tbat_high
= pdata
->tbat_high
;
423 charger
->thresholds
.tbat_restart
= pdata
->tbat_restart
;
425 charger
->thresholds
.vbat_low
=
426 da9030_millivolt_to_reg(pdata
->vbat_low
);
427 charger
->thresholds
.vbat_crit
=
428 da9030_millivolt_to_reg(pdata
->vbat_crit
);
429 charger
->thresholds
.vbat_charge_start
=
430 da9030_millivolt_to_reg(pdata
->vbat_charge_start
);
431 charger
->thresholds
.vbat_charge_stop
=
432 da9030_millivolt_to_reg(pdata
->vbat_charge_stop
);
433 charger
->thresholds
.vbat_charge_restart
=
434 da9030_millivolt_to_reg(pdata
->vbat_charge_restart
);
436 charger
->thresholds
.vcharge_min
=
437 da9030_millivolt_to_reg(pdata
->vcharge_min
);
438 charger
->thresholds
.vcharge_max
=
439 da9030_millivolt_to_reg(pdata
->vcharge_max
);
442 static void da9030_battery_setup_psy(struct da9030_charger
*charger
)
444 struct power_supply
*psy
= &charger
->psy
;
445 struct power_supply_info
*info
= charger
->battery_info
;
447 psy
->name
= info
->name
;
448 psy
->use_for_apm
= info
->use_for_apm
;
449 psy
->type
= POWER_SUPPLY_TYPE_BATTERY
;
450 psy
->get_property
= da9030_battery_get_property
;
452 psy
->properties
= da9030_battery_props
;
453 psy
->num_properties
= ARRAY_SIZE(da9030_battery_props
);
456 static int da9030_battery_charger_init(struct da9030_charger
*charger
)
461 v
[0] = v
[1] = charger
->thresholds
.vbat_low
;
462 v
[2] = charger
->thresholds
.tbat_high
;
463 v
[3] = charger
->thresholds
.tbat_restart
;
464 v
[4] = charger
->thresholds
.tbat_low
;
466 ret
= da903x_writes(charger
->master
, DA9030_VBATMON
, 5, v
);
471 * Enable reference voltage supply for ADC from the LDO_INTERNAL
472 * regulator. Must be set before ADC measurements can be made.
474 ret
= da903x_write(charger
->master
, DA9030_ADC_MAN_CONTROL
,
475 DA9030_ADC_LDO_INT_ENABLE
|
476 DA9030_ADC_TBATREF_ENABLE
);
480 /* enable auto ADC measuremnts */
481 return da903x_write(charger
->master
, DA9030_ADC_AUTO_CONTROL
,
482 DA9030_ADC_TBAT_ENABLE
| DA9030_ADC_VBAT_IN_TXON
|
483 DA9030_ADC_VCH_ENABLE
| DA9030_ADC_ICH_ENABLE
|
484 DA9030_ADC_VBAT_ENABLE
|
485 DA9030_ADC_AUTO_SLEEP_ENABLE
);
488 static int da9030_battery_probe(struct platform_device
*pdev
)
490 struct da9030_charger
*charger
;
491 struct da9030_battery_info
*pdata
= pdev
->dev
.platform_data
;
497 if (pdata
->charge_milliamp
>= 1500 ||
498 pdata
->charge_millivolt
< 4000 ||
499 pdata
->charge_millivolt
> 4350)
502 charger
= kzalloc(sizeof(*charger
), GFP_KERNEL
);
506 charger
->master
= pdev
->dev
.parent
;
508 /* 10 seconds between monotor runs unless platfrom defines other
510 charger
->interval
= msecs_to_jiffies(
511 (pdata
->batmon_interval
? : 10) * 1000);
513 charger
->charge_milliamp
= pdata
->charge_milliamp
;
514 charger
->charge_millivolt
= pdata
->charge_millivolt
;
515 charger
->battery_info
= pdata
->battery_info
;
516 charger
->battery_low
= pdata
->battery_low
;
517 charger
->battery_critical
= pdata
->battery_critical
;
519 da9030_battery_convert_thresholds(charger
, pdata
);
521 ret
= da9030_battery_charger_init(charger
);
523 goto err_charger_init
;
525 INIT_DELAYED_WORK(&charger
->work
, da9030_charging_monitor
);
526 schedule_delayed_work(&charger
->work
, charger
->interval
);
528 charger
->nb
.notifier_call
= da9030_battery_event
;
529 ret
= da903x_register_notifier(charger
->master
, &charger
->nb
,
531 DA9030_EVENT_VBATMON
|
532 DA9030_EVENT_CHIOVER
|
537 da9030_battery_setup_psy(charger
);
538 ret
= power_supply_register(&pdev
->dev
, &charger
->psy
);
540 goto err_ps_register
;
542 charger
->debug_file
= da9030_bat_create_debugfs(charger
);
543 platform_set_drvdata(pdev
, charger
);
547 da903x_unregister_notifier(charger
->master
, &charger
->nb
,
548 DA9030_EVENT_CHDET
| DA9030_EVENT_VBATMON
|
549 DA9030_EVENT_CHIOVER
| DA9030_EVENT_TBAT
);
551 cancel_delayed_work(&charger
->work
);
559 static int da9030_battery_remove(struct platform_device
*dev
)
561 struct da9030_charger
*charger
= platform_get_drvdata(dev
);
563 da9030_bat_remove_debugfs(charger
);
565 da903x_unregister_notifier(charger
->master
, &charger
->nb
,
566 DA9030_EVENT_CHDET
| DA9030_EVENT_VBATMON
|
567 DA9030_EVENT_CHIOVER
| DA9030_EVENT_TBAT
);
568 cancel_delayed_work(&charger
->work
);
569 power_supply_unregister(&charger
->psy
);
576 static struct platform_driver da903x_battery_driver
= {
578 .name
= "da903x-battery",
579 .owner
= THIS_MODULE
,
581 .probe
= da9030_battery_probe
,
582 .remove
= da9030_battery_remove
,
585 static int da903x_battery_init(void)
587 return platform_driver_register(&da903x_battery_driver
);
590 static void da903x_battery_exit(void)
592 platform_driver_unregister(&da903x_battery_driver
);
595 module_init(da903x_battery_init
);
596 module_exit(da903x_battery_exit
);
598 MODULE_DESCRIPTION("DA9030 battery charger driver");
599 MODULE_AUTHOR("Mike Rapoport, CompuLab");
600 MODULE_LICENSE("GPL");