1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) ST-Ericsson SA 2012 |
4 | * Copyright (c) 2012 Sony Mobile Communications AB |
5 | * |
6 | * Charging algorithm driver for AB8500 |
7 | * |
8 | * Authors: |
9 | * Johan Palsson <johan.palsson@stericsson.com> |
10 | * Karl Komierowski <karl.komierowski@stericsson.com> |
11 | * Arun R Murthy <arun.murthy@stericsson.com> |
12 | * Author: Imre Sunyi <imre.sunyi@sonymobile.com> |
13 | */ |
14 | |
15 | #include <linux/init.h> |
16 | #include <linux/module.h> |
17 | #include <linux/device.h> |
18 | #include <linux/component.h> |
19 | #include <linux/hrtimer.h> |
20 | #include <linux/interrupt.h> |
21 | #include <linux/delay.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/platform_device.h> |
24 | #include <linux/power_supply.h> |
25 | #include <linux/completion.h> |
26 | #include <linux/workqueue.h> |
27 | #include <linux/kobject.h> |
28 | #include <linux/of.h> |
29 | #include <linux/mfd/core.h> |
30 | #include <linux/mfd/abx500.h> |
31 | #include <linux/mfd/abx500/ab8500.h> |
32 | #include <linux/notifier.h> |
33 | |
34 | #include "ab8500-bm.h" |
35 | #include "ab8500-chargalg.h" |
36 | |
37 | /* Watchdog kick interval */ |
38 | #define CHG_WD_INTERVAL (6 * HZ) |
39 | |
40 | /* End-of-charge criteria counter */ |
41 | #define EOC_COND_CNT 10 |
42 | |
43 | /* One hour expressed in seconds */ |
44 | #define ONE_HOUR_IN_SECONDS 3600 |
45 | |
46 | /* Five minutes expressed in seconds */ |
47 | #define FIVE_MINUTES_IN_SECONDS 300 |
48 | |
49 | /* |
50 | * This is the battery capacity limit that will trigger a new |
51 | * full charging cycle in the case where maintenance charging |
52 | * has been disabled |
53 | */ |
54 | #define AB8500_RECHARGE_CAP 95 |
55 | |
56 | enum ab8500_chargers { |
57 | NO_CHG, |
58 | AC_CHG, |
59 | USB_CHG, |
60 | }; |
61 | |
62 | struct ab8500_chargalg_charger_info { |
63 | enum ab8500_chargers conn_chg; |
64 | enum ab8500_chargers prev_conn_chg; |
65 | enum ab8500_chargers online_chg; |
66 | enum ab8500_chargers prev_online_chg; |
67 | enum ab8500_chargers charger_type; |
68 | bool usb_chg_ok; |
69 | bool ac_chg_ok; |
70 | int usb_volt_uv; |
71 | int usb_curr_ua; |
72 | int ac_volt_uv; |
73 | int ac_curr_ua; |
74 | int usb_vset_uv; |
75 | int usb_iset_ua; |
76 | int ac_vset_uv; |
77 | int ac_iset_ua; |
78 | }; |
79 | |
80 | struct ab8500_chargalg_battery_data { |
81 | int temp; |
82 | int volt_uv; |
83 | int avg_curr_ua; |
84 | int inst_curr_ua; |
85 | int percent; |
86 | }; |
87 | |
88 | enum ab8500_chargalg_states { |
89 | STATE_HANDHELD_INIT, |
90 | STATE_HANDHELD, |
91 | STATE_CHG_NOT_OK_INIT, |
92 | STATE_CHG_NOT_OK, |
93 | STATE_HW_TEMP_PROTECT_INIT, |
94 | STATE_HW_TEMP_PROTECT, |
95 | STATE_NORMAL_INIT, |
96 | STATE_NORMAL, |
97 | STATE_WAIT_FOR_RECHARGE_INIT, |
98 | STATE_WAIT_FOR_RECHARGE, |
99 | STATE_MAINTENANCE_A_INIT, |
100 | STATE_MAINTENANCE_A, |
101 | STATE_MAINTENANCE_B_INIT, |
102 | STATE_MAINTENANCE_B, |
103 | STATE_TEMP_UNDEROVER_INIT, |
104 | STATE_TEMP_UNDEROVER, |
105 | STATE_TEMP_LOWHIGH_INIT, |
106 | STATE_TEMP_LOWHIGH, |
107 | STATE_OVV_PROTECT_INIT, |
108 | STATE_OVV_PROTECT, |
109 | STATE_SAFETY_TIMER_EXPIRED_INIT, |
110 | STATE_SAFETY_TIMER_EXPIRED, |
111 | STATE_BATT_REMOVED_INIT, |
112 | STATE_BATT_REMOVED, |
113 | STATE_WD_EXPIRED_INIT, |
114 | STATE_WD_EXPIRED, |
115 | }; |
116 | |
117 | static const char * const states[] = { |
118 | "HANDHELD_INIT" , |
119 | "HANDHELD" , |
120 | "CHG_NOT_OK_INIT" , |
121 | "CHG_NOT_OK" , |
122 | "HW_TEMP_PROTECT_INIT" , |
123 | "HW_TEMP_PROTECT" , |
124 | "NORMAL_INIT" , |
125 | "NORMAL" , |
126 | "WAIT_FOR_RECHARGE_INIT" , |
127 | "WAIT_FOR_RECHARGE" , |
128 | "MAINTENANCE_A_INIT" , |
129 | "MAINTENANCE_A" , |
130 | "MAINTENANCE_B_INIT" , |
131 | "MAINTENANCE_B" , |
132 | "TEMP_UNDEROVER_INIT" , |
133 | "TEMP_UNDEROVER" , |
134 | "TEMP_LOWHIGH_INIT" , |
135 | "TEMP_LOWHIGH" , |
136 | "OVV_PROTECT_INIT" , |
137 | "OVV_PROTECT" , |
138 | "SAFETY_TIMER_EXPIRED_INIT" , |
139 | "SAFETY_TIMER_EXPIRED" , |
140 | "BATT_REMOVED_INIT" , |
141 | "BATT_REMOVED" , |
142 | "WD_EXPIRED_INIT" , |
143 | "WD_EXPIRED" , |
144 | }; |
145 | |
146 | struct ab8500_chargalg_events { |
147 | bool batt_unknown; |
148 | bool mainextchnotok; |
149 | bool batt_ovv; |
150 | bool batt_rem; |
151 | bool btemp_underover; |
152 | bool btemp_low; |
153 | bool btemp_high; |
154 | bool main_thermal_prot; |
155 | bool usb_thermal_prot; |
156 | bool main_ovv; |
157 | bool vbus_ovv; |
158 | bool usbchargernotok; |
159 | bool safety_timer_expired; |
160 | bool maintenance_timer_expired; |
161 | bool ac_wd_expired; |
162 | bool usb_wd_expired; |
163 | bool ac_cv_active; |
164 | bool usb_cv_active; |
165 | bool vbus_collapsed; |
166 | }; |
167 | |
168 | /** |
169 | * struct ab8500_charge_curr_maximization - Charger maximization parameters |
170 | * @original_iset_ua: the non optimized/maximised charger current |
171 | * @current_iset_ua: the charging current used at this moment |
172 | * @condition_cnt: number of iterations needed before a new charger current |
173 | is set |
174 | * @max_current_ua: maximum charger current |
175 | * @wait_cnt: to avoid too fast current step down in case of charger |
176 | * voltage collapse, we insert this delay between step |
177 | * down |
178 | * @level: tells in how many steps the charging current has been |
179 | increased |
180 | */ |
181 | struct ab8500_charge_curr_maximization { |
182 | int original_iset_ua; |
183 | int current_iset_ua; |
184 | int condition_cnt; |
185 | int max_current_ua; |
186 | int wait_cnt; |
187 | u8 level; |
188 | }; |
189 | |
190 | enum maxim_ret { |
191 | MAXIM_RET_NOACTION, |
192 | MAXIM_RET_CHANGE, |
193 | MAXIM_RET_IBAT_TOO_HIGH, |
194 | }; |
195 | |
196 | /** |
197 | * struct ab8500_chargalg - ab8500 Charging algorithm device information |
198 | * @dev: pointer to the structure device |
199 | * @charge_status: battery operating status |
200 | * @eoc_cnt: counter used to determine end-of_charge |
201 | * @maintenance_chg: indicate if maintenance charge is active |
202 | * @t_hyst_norm temperature hysteresis when the temperature has been |
203 | * over or under normal limits |
204 | * @t_hyst_lowhigh temperature hysteresis when the temperature has been |
205 | * over or under the high or low limits |
206 | * @charge_state: current state of the charging algorithm |
207 | * @ccm charging current maximization parameters |
208 | * @chg_info: information about connected charger types |
209 | * @batt_data: data of the battery |
210 | * @bm: Platform specific battery management information |
211 | * @parent: pointer to the struct ab8500 |
212 | * @chargalg_psy: structure that holds the battery properties exposed by |
213 | * the charging algorithm |
214 | * @events: structure for information about events triggered |
215 | * @chargalg_wq: work queue for running the charging algorithm |
216 | * @chargalg_periodic_work: work to run the charging algorithm periodically |
217 | * @chargalg_wd_work: work to kick the charger watchdog periodically |
218 | * @chargalg_work: work to run the charging algorithm instantly |
219 | * @safety_timer: charging safety timer |
220 | * @maintenance_timer: maintenance charging timer |
221 | * @chargalg_kobject: structure of type kobject |
222 | */ |
223 | struct ab8500_chargalg { |
224 | struct device *dev; |
225 | int charge_status; |
226 | int eoc_cnt; |
227 | bool maintenance_chg; |
228 | int t_hyst_norm; |
229 | int t_hyst_lowhigh; |
230 | enum ab8500_chargalg_states charge_state; |
231 | struct ab8500_charge_curr_maximization ccm; |
232 | struct ab8500_chargalg_charger_info chg_info; |
233 | struct ab8500_chargalg_battery_data batt_data; |
234 | struct ab8500 *parent; |
235 | struct ab8500_bm_data *bm; |
236 | struct power_supply *chargalg_psy; |
237 | struct ux500_charger *ac_chg; |
238 | struct ux500_charger *usb_chg; |
239 | struct ab8500_chargalg_events events; |
240 | struct workqueue_struct *chargalg_wq; |
241 | struct delayed_work chargalg_periodic_work; |
242 | struct delayed_work chargalg_wd_work; |
243 | struct work_struct chargalg_work; |
244 | struct hrtimer safety_timer; |
245 | struct hrtimer maintenance_timer; |
246 | struct kobject chargalg_kobject; |
247 | }; |
248 | |
249 | /* Main battery properties */ |
250 | static enum power_supply_property ab8500_chargalg_props[] = { |
251 | POWER_SUPPLY_PROP_STATUS, |
252 | POWER_SUPPLY_PROP_HEALTH, |
253 | }; |
254 | |
255 | /** |
256 | * ab8500_chargalg_safety_timer_expired() - Expiration of the safety timer |
257 | * @timer: pointer to the hrtimer structure |
258 | * |
259 | * This function gets called when the safety timer for the charger |
260 | * expires |
261 | */ |
262 | static enum hrtimer_restart |
263 | ab8500_chargalg_safety_timer_expired(struct hrtimer *timer) |
264 | { |
265 | struct ab8500_chargalg *di = container_of(timer, struct ab8500_chargalg, |
266 | safety_timer); |
267 | dev_err(di->dev, "Safety timer expired\n" ); |
268 | di->events.safety_timer_expired = true; |
269 | |
270 | /* Trigger execution of the algorithm instantly */ |
271 | queue_work(wq: di->chargalg_wq, work: &di->chargalg_work); |
272 | |
273 | return HRTIMER_NORESTART; |
274 | } |
275 | |
276 | /** |
277 | * ab8500_chargalg_maintenance_timer_expired() - Expiration of |
278 | * the maintenance timer |
279 | * @timer: pointer to the timer structure |
280 | * |
281 | * This function gets called when the maintenance timer |
282 | * expires |
283 | */ |
284 | static enum hrtimer_restart |
285 | ab8500_chargalg_maintenance_timer_expired(struct hrtimer *timer) |
286 | { |
287 | |
288 | struct ab8500_chargalg *di = container_of(timer, struct ab8500_chargalg, |
289 | maintenance_timer); |
290 | |
291 | dev_dbg(di->dev, "Maintenance timer expired\n" ); |
292 | di->events.maintenance_timer_expired = true; |
293 | |
294 | /* Trigger execution of the algorithm instantly */ |
295 | queue_work(wq: di->chargalg_wq, work: &di->chargalg_work); |
296 | |
297 | return HRTIMER_NORESTART; |
298 | } |
299 | |
300 | /** |
301 | * ab8500_chargalg_state_to() - Change charge state |
302 | * @di: pointer to the ab8500_chargalg structure |
303 | * |
304 | * This function gets called when a charge state change should occur |
305 | */ |
306 | static void ab8500_chargalg_state_to(struct ab8500_chargalg *di, |
307 | enum ab8500_chargalg_states state) |
308 | { |
309 | dev_dbg(di->dev, |
310 | "State changed: %s (From state: [%d] %s =to=> [%d] %s )\n" , |
311 | di->charge_state == state ? "NO" : "YES" , |
312 | di->charge_state, |
313 | states[di->charge_state], |
314 | state, |
315 | states[state]); |
316 | |
317 | di->charge_state = state; |
318 | } |
319 | |
320 | static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) |
321 | { |
322 | struct power_supply_battery_info *bi = di->bm->bi; |
323 | |
324 | switch (di->charge_state) { |
325 | case STATE_NORMAL: |
326 | case STATE_MAINTENANCE_A: |
327 | case STATE_MAINTENANCE_B: |
328 | break; |
329 | default: |
330 | return 0; |
331 | } |
332 | |
333 | if (di->chg_info.charger_type & USB_CHG) { |
334 | return di->usb_chg->ops.check_enable(di->usb_chg, |
335 | bi->constant_charge_voltage_max_uv, |
336 | bi->constant_charge_current_max_ua); |
337 | } else if (di->chg_info.charger_type & AC_CHG) { |
338 | return di->ac_chg->ops.check_enable(di->ac_chg, |
339 | bi->constant_charge_voltage_max_uv, |
340 | bi->constant_charge_current_max_ua); |
341 | } |
342 | return 0; |
343 | } |
344 | |
345 | /** |
346 | * ab8500_chargalg_check_charger_connection() - Check charger connection change |
347 | * @di: pointer to the ab8500_chargalg structure |
348 | * |
349 | * This function will check if there is a change in the charger connection |
350 | * and change charge state accordingly. AC has precedence over USB. |
351 | */ |
352 | static int ab8500_chargalg_check_charger_connection(struct ab8500_chargalg *di) |
353 | { |
354 | if (di->chg_info.conn_chg != di->chg_info.prev_conn_chg) { |
355 | /* Charger state changed since last update */ |
356 | if (di->chg_info.conn_chg & AC_CHG) { |
357 | dev_info(di->dev, "Charging source is AC\n" ); |
358 | if (di->chg_info.charger_type != AC_CHG) { |
359 | di->chg_info.charger_type = AC_CHG; |
360 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
361 | } |
362 | } else if (di->chg_info.conn_chg & USB_CHG) { |
363 | dev_info(di->dev, "Charging source is USB\n" ); |
364 | di->chg_info.charger_type = USB_CHG; |
365 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
366 | } else { |
367 | dev_dbg(di->dev, "Charging source is OFF\n" ); |
368 | di->chg_info.charger_type = NO_CHG; |
369 | ab8500_chargalg_state_to(di, state: STATE_HANDHELD_INIT); |
370 | } |
371 | di->chg_info.prev_conn_chg = di->chg_info.conn_chg; |
372 | } |
373 | return di->chg_info.conn_chg; |
374 | } |
375 | |
376 | /** |
377 | * ab8500_chargalg_start_safety_timer() - Start charging safety timer |
378 | * @di: pointer to the ab8500_chargalg structure |
379 | * |
380 | * The safety timer is used to avoid overcharging of old or bad batteries. |
381 | * There are different timers for AC and USB |
382 | */ |
383 | static void ab8500_chargalg_start_safety_timer(struct ab8500_chargalg *di) |
384 | { |
385 | /* Charger-dependent expiration time in hours*/ |
386 | int timer_expiration = 0; |
387 | |
388 | switch (di->chg_info.charger_type) { |
389 | case AC_CHG: |
390 | timer_expiration = di->bm->main_safety_tmr_h; |
391 | break; |
392 | |
393 | case USB_CHG: |
394 | timer_expiration = di->bm->usb_safety_tmr_h; |
395 | break; |
396 | |
397 | default: |
398 | dev_err(di->dev, "Unknown charger to charge from\n" ); |
399 | break; |
400 | } |
401 | |
402 | di->events.safety_timer_expired = false; |
403 | hrtimer_set_expires_range(timer: &di->safety_timer, |
404 | time: ktime_set(secs: timer_expiration * ONE_HOUR_IN_SECONDS, nsecs: 0), |
405 | delta: ktime_set(FIVE_MINUTES_IN_SECONDS, nsecs: 0)); |
406 | hrtimer_start_expires(timer: &di->safety_timer, mode: HRTIMER_MODE_REL); |
407 | } |
408 | |
409 | /** |
410 | * ab8500_chargalg_stop_safety_timer() - Stop charging safety timer |
411 | * @di: pointer to the ab8500_chargalg structure |
412 | * |
413 | * The safety timer is stopped whenever the NORMAL state is exited |
414 | */ |
415 | static void ab8500_chargalg_stop_safety_timer(struct ab8500_chargalg *di) |
416 | { |
417 | if (hrtimer_try_to_cancel(timer: &di->safety_timer) >= 0) |
418 | di->events.safety_timer_expired = false; |
419 | } |
420 | |
421 | /** |
422 | * ab8500_chargalg_start_maintenance_timer() - Start charging maintenance timer |
423 | * @di: pointer to the ab8500_chargalg structure |
424 | * @duration: duration of the maintenance timer in minutes |
425 | * |
426 | * The maintenance timer is used to maintain the charge in the battery once |
427 | * the battery is considered full. These timers are chosen to match the |
428 | * discharge curve of the battery |
429 | */ |
430 | static void ab8500_chargalg_start_maintenance_timer(struct ab8500_chargalg *di, |
431 | int duration) |
432 | { |
433 | /* Set a timer in minutes with a 30 second range */ |
434 | hrtimer_set_expires_range(timer: &di->maintenance_timer, |
435 | time: ktime_set(secs: duration * 60, nsecs: 0), |
436 | delta: ktime_set(secs: 30, nsecs: 0)); |
437 | di->events.maintenance_timer_expired = false; |
438 | hrtimer_start_expires(timer: &di->maintenance_timer, mode: HRTIMER_MODE_REL); |
439 | } |
440 | |
441 | /** |
442 | * ab8500_chargalg_stop_maintenance_timer() - Stop maintenance timer |
443 | * @di: pointer to the ab8500_chargalg structure |
444 | * |
445 | * The maintenance timer is stopped whenever maintenance ends or when another |
446 | * state is entered |
447 | */ |
448 | static void ab8500_chargalg_stop_maintenance_timer(struct ab8500_chargalg *di) |
449 | { |
450 | if (hrtimer_try_to_cancel(timer: &di->maintenance_timer) >= 0) |
451 | di->events.maintenance_timer_expired = false; |
452 | } |
453 | |
454 | /** |
455 | * ab8500_chargalg_kick_watchdog() - Kick charger watchdog |
456 | * @di: pointer to the ab8500_chargalg structure |
457 | * |
458 | * The charger watchdog have to be kicked periodically whenever the charger is |
459 | * on, else the ABB will reset the system |
460 | */ |
461 | static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di) |
462 | { |
463 | /* Check if charger exists and kick watchdog if charging */ |
464 | if (di->ac_chg && di->ac_chg->ops.kick_wd && |
465 | di->chg_info.online_chg & AC_CHG) { |
466 | return di->ac_chg->ops.kick_wd(di->ac_chg); |
467 | } else if (di->usb_chg && di->usb_chg->ops.kick_wd && |
468 | di->chg_info.online_chg & USB_CHG) |
469 | return di->usb_chg->ops.kick_wd(di->usb_chg); |
470 | |
471 | return -ENXIO; |
472 | } |
473 | |
474 | /** |
475 | * ab8500_chargalg_ac_en() - Turn on/off the AC charger |
476 | * @di: pointer to the ab8500_chargalg structure |
477 | * @enable: charger on/off |
478 | * @vset_uv: requested charger output voltage in microvolt |
479 | * @iset_ua: requested charger output current in microampere |
480 | * |
481 | * The AC charger will be turned on/off with the requested charge voltage and |
482 | * current |
483 | */ |
484 | static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, |
485 | int vset_uv, int iset_ua) |
486 | { |
487 | if (!di->ac_chg || !di->ac_chg->ops.enable) |
488 | return -ENXIO; |
489 | |
490 | /* Select maximum of what both the charger and the battery supports */ |
491 | if (di->ac_chg->max_out_volt_uv) |
492 | vset_uv = min(vset_uv, di->ac_chg->max_out_volt_uv); |
493 | if (di->ac_chg->max_out_curr_ua) |
494 | iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); |
495 | |
496 | di->chg_info.ac_iset_ua = iset_ua; |
497 | di->chg_info.ac_vset_uv = vset_uv; |
498 | |
499 | return di->ac_chg->ops.enable(di->ac_chg, enable, vset_uv, iset_ua); |
500 | } |
501 | |
502 | /** |
503 | * ab8500_chargalg_usb_en() - Turn on/off the USB charger |
504 | * @di: pointer to the ab8500_chargalg structure |
505 | * @enable: charger on/off |
506 | * @vset_uv: requested charger output voltage in microvolt |
507 | * @iset_ua: requested charger output current in microampere |
508 | * |
509 | * The USB charger will be turned on/off with the requested charge voltage and |
510 | * current |
511 | */ |
512 | static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, |
513 | int vset_uv, int iset_ua) |
514 | { |
515 | if (!di->usb_chg || !di->usb_chg->ops.enable) |
516 | return -ENXIO; |
517 | |
518 | /* Select maximum of what both the charger and the battery supports */ |
519 | if (di->usb_chg->max_out_volt_uv) |
520 | vset_uv = min(vset_uv, di->usb_chg->max_out_volt_uv); |
521 | if (di->usb_chg->max_out_curr_ua) |
522 | iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); |
523 | |
524 | di->chg_info.usb_iset_ua = iset_ua; |
525 | di->chg_info.usb_vset_uv = vset_uv; |
526 | |
527 | return di->usb_chg->ops.enable(di->usb_chg, enable, vset_uv, iset_ua); |
528 | } |
529 | |
530 | /** |
531 | * ab8500_chargalg_update_chg_curr() - Update charger current |
532 | * @di: pointer to the ab8500_chargalg structure |
533 | * @iset_ua: requested charger output current in microampere |
534 | * |
535 | * The charger output current will be updated for the charger |
536 | * that is currently in use |
537 | */ |
538 | static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di, |
539 | int iset_ua) |
540 | { |
541 | /* Check if charger exists and update current if charging */ |
542 | if (di->ac_chg && di->ac_chg->ops.update_curr && |
543 | di->chg_info.charger_type & AC_CHG) { |
544 | /* |
545 | * Select maximum of what both the charger |
546 | * and the battery supports |
547 | */ |
548 | if (di->ac_chg->max_out_curr_ua) |
549 | iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); |
550 | |
551 | di->chg_info.ac_iset_ua = iset_ua; |
552 | |
553 | return di->ac_chg->ops.update_curr(di->ac_chg, iset_ua); |
554 | } else if (di->usb_chg && di->usb_chg->ops.update_curr && |
555 | di->chg_info.charger_type & USB_CHG) { |
556 | /* |
557 | * Select maximum of what both the charger |
558 | * and the battery supports |
559 | */ |
560 | if (di->usb_chg->max_out_curr_ua) |
561 | iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); |
562 | |
563 | di->chg_info.usb_iset_ua = iset_ua; |
564 | |
565 | return di->usb_chg->ops.update_curr(di->usb_chg, iset_ua); |
566 | } |
567 | |
568 | return -ENXIO; |
569 | } |
570 | |
571 | /** |
572 | * ab8500_chargalg_stop_charging() - Stop charging |
573 | * @di: pointer to the ab8500_chargalg structure |
574 | * |
575 | * This function is called from any state where charging should be stopped. |
576 | * All charging is disabled and all status parameters and timers are changed |
577 | * accordingly |
578 | */ |
579 | static void ab8500_chargalg_stop_charging(struct ab8500_chargalg *di) |
580 | { |
581 | ab8500_chargalg_ac_en(di, enable: false, vset_uv: 0, iset_ua: 0); |
582 | ab8500_chargalg_usb_en(di, enable: false, vset_uv: 0, iset_ua: 0); |
583 | ab8500_chargalg_stop_safety_timer(di); |
584 | ab8500_chargalg_stop_maintenance_timer(di); |
585 | di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING; |
586 | di->maintenance_chg = false; |
587 | cancel_delayed_work(dwork: &di->chargalg_wd_work); |
588 | power_supply_changed(psy: di->chargalg_psy); |
589 | } |
590 | |
591 | /** |
592 | * ab8500_chargalg_hold_charging() - Pauses charging |
593 | * @di: pointer to the ab8500_chargalg structure |
594 | * |
595 | * This function is called in the case where maintenance charging has been |
596 | * disabled and instead a battery voltage mode is entered to check when the |
597 | * battery voltage has reached a certain recharge voltage |
598 | */ |
599 | static void ab8500_chargalg_hold_charging(struct ab8500_chargalg *di) |
600 | { |
601 | ab8500_chargalg_ac_en(di, enable: false, vset_uv: 0, iset_ua: 0); |
602 | ab8500_chargalg_usb_en(di, enable: false, vset_uv: 0, iset_ua: 0); |
603 | ab8500_chargalg_stop_safety_timer(di); |
604 | ab8500_chargalg_stop_maintenance_timer(di); |
605 | di->charge_status = POWER_SUPPLY_STATUS_CHARGING; |
606 | di->maintenance_chg = false; |
607 | cancel_delayed_work(dwork: &di->chargalg_wd_work); |
608 | power_supply_changed(psy: di->chargalg_psy); |
609 | } |
610 | |
611 | /** |
612 | * ab8500_chargalg_start_charging() - Start the charger |
613 | * @di: pointer to the ab8500_chargalg structure |
614 | * @vset_uv: requested charger output voltage in microvolt |
615 | * @iset_ua: requested charger output current in microampere |
616 | * |
617 | * A charger will be enabled depending on the requested charger type that was |
618 | * detected previously. |
619 | */ |
620 | static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, |
621 | int vset_uv, int iset_ua) |
622 | { |
623 | switch (di->chg_info.charger_type) { |
624 | case AC_CHG: |
625 | dev_dbg(di->dev, |
626 | "AC parameters: Vset %d, Ich %d\n" , vset_uv, iset_ua); |
627 | ab8500_chargalg_usb_en(di, enable: false, vset_uv: 0, iset_ua: 0); |
628 | ab8500_chargalg_ac_en(di, enable: true, vset_uv, iset_ua); |
629 | break; |
630 | |
631 | case USB_CHG: |
632 | dev_dbg(di->dev, |
633 | "USB parameters: Vset %d, Ich %d\n" , vset_uv, iset_ua); |
634 | ab8500_chargalg_ac_en(di, enable: false, vset_uv: 0, iset_ua: 0); |
635 | ab8500_chargalg_usb_en(di, enable: true, vset_uv, iset_ua); |
636 | break; |
637 | |
638 | default: |
639 | dev_err(di->dev, "Unknown charger to charge from\n" ); |
640 | break; |
641 | } |
642 | } |
643 | |
644 | /** |
645 | * ab8500_chargalg_check_temp() - Check battery temperature ranges |
646 | * @di: pointer to the ab8500_chargalg structure |
647 | * |
648 | * The battery temperature is checked against the predefined limits and the |
649 | * charge state is changed accordingly |
650 | */ |
651 | static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di) |
652 | { |
653 | struct power_supply_battery_info *bi = di->bm->bi; |
654 | |
655 | if (di->batt_data.temp > (bi->temp_alert_min + di->t_hyst_norm) && |
656 | di->batt_data.temp < (bi->temp_alert_max - di->t_hyst_norm)) { |
657 | /* Temp OK! */ |
658 | di->events.btemp_underover = false; |
659 | di->events.btemp_low = false; |
660 | di->events.btemp_high = false; |
661 | di->t_hyst_norm = 0; |
662 | di->t_hyst_lowhigh = 0; |
663 | } else { |
664 | if ((di->batt_data.temp >= bi->temp_alert_max) && |
665 | (di->batt_data.temp < (bi->temp_max - di->t_hyst_lowhigh))) { |
666 | /* Alert zone for high temperature */ |
667 | di->events.btemp_underover = false; |
668 | di->events.btemp_high = true; |
669 | di->t_hyst_norm = di->bm->temp_hysteresis; |
670 | di->t_hyst_lowhigh = 0; |
671 | } else if ((di->batt_data.temp > (bi->temp_min + di->t_hyst_lowhigh)) && |
672 | (di->batt_data.temp <= bi->temp_alert_min)) { |
673 | /* Alert zone for low temperature */ |
674 | di->events.btemp_underover = false; |
675 | di->events.btemp_low = true; |
676 | di->t_hyst_norm = di->bm->temp_hysteresis; |
677 | di->t_hyst_lowhigh = 0; |
678 | } else if (di->batt_data.temp <= bi->temp_min || |
679 | di->batt_data.temp >= bi->temp_max) { |
680 | /* TEMP major!!!!! */ |
681 | di->events.btemp_underover = true; |
682 | di->events.btemp_low = false; |
683 | di->events.btemp_high = false; |
684 | di->t_hyst_norm = 0; |
685 | di->t_hyst_lowhigh = di->bm->temp_hysteresis; |
686 | } else { |
687 | /* Within hysteresis */ |
688 | dev_dbg(di->dev, "Within hysteresis limit temp: %d " |
689 | "hyst_lowhigh %d, hyst normal %d\n" , |
690 | di->batt_data.temp, di->t_hyst_lowhigh, |
691 | di->t_hyst_norm); |
692 | } |
693 | } |
694 | } |
695 | |
696 | /** |
697 | * ab8500_chargalg_check_charger_voltage() - Check charger voltage |
698 | * @di: pointer to the ab8500_chargalg structure |
699 | * |
700 | * Charger voltage is checked against maximum limit |
701 | */ |
702 | static void ab8500_chargalg_check_charger_voltage(struct ab8500_chargalg *di) |
703 | { |
704 | if (di->chg_info.usb_volt_uv > di->bm->chg_params->usb_volt_max_uv) |
705 | di->chg_info.usb_chg_ok = false; |
706 | else |
707 | di->chg_info.usb_chg_ok = true; |
708 | |
709 | if (di->chg_info.ac_volt_uv > di->bm->chg_params->ac_volt_max_uv) |
710 | di->chg_info.ac_chg_ok = false; |
711 | else |
712 | di->chg_info.ac_chg_ok = true; |
713 | |
714 | } |
715 | |
716 | /** |
717 | * ab8500_chargalg_end_of_charge() - Check if end-of-charge criteria is fulfilled |
718 | * @di: pointer to the ab8500_chargalg structure |
719 | * |
720 | * End-of-charge criteria is fulfilled when the battery voltage is above a |
721 | * certain limit and the battery current is below a certain limit for a |
722 | * predefined number of consecutive seconds. If true, the battery is full |
723 | */ |
724 | static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) |
725 | { |
726 | if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && |
727 | di->charge_state == STATE_NORMAL && |
728 | !di->maintenance_chg && (di->batt_data.volt_uv >= |
729 | di->bm->bi->voltage_max_design_uv || |
730 | di->events.usb_cv_active || di->events.ac_cv_active) && |
731 | di->batt_data.avg_curr_ua < |
732 | di->bm->bi->charge_term_current_ua && |
733 | di->batt_data.avg_curr_ua > 0) { |
734 | if (++di->eoc_cnt >= EOC_COND_CNT) { |
735 | di->eoc_cnt = 0; |
736 | di->charge_status = POWER_SUPPLY_STATUS_FULL; |
737 | di->maintenance_chg = true; |
738 | dev_dbg(di->dev, "EOC reached!\n" ); |
739 | power_supply_changed(psy: di->chargalg_psy); |
740 | } else { |
741 | dev_dbg(di->dev, |
742 | " EOC limit reached for the %d" |
743 | " time, out of %d before EOC\n" , |
744 | di->eoc_cnt, |
745 | EOC_COND_CNT); |
746 | } |
747 | } else { |
748 | di->eoc_cnt = 0; |
749 | } |
750 | } |
751 | |
752 | static void init_maxim_chg_curr(struct ab8500_chargalg *di) |
753 | { |
754 | struct power_supply_battery_info *bi = di->bm->bi; |
755 | |
756 | di->ccm.original_iset_ua = bi->constant_charge_current_max_ua; |
757 | di->ccm.current_iset_ua = bi->constant_charge_current_max_ua; |
758 | di->ccm.max_current_ua = di->bm->maxi->chg_curr_ua; |
759 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
760 | di->ccm.level = 0; |
761 | } |
762 | |
763 | /** |
764 | * ab8500_chargalg_chg_curr_maxim - increases the charger current to |
765 | * compensate for the system load |
766 | * @di pointer to the ab8500_chargalg structure |
767 | * |
768 | * This maximization function is used to raise the charger current to get the |
769 | * battery current as close to the optimal value as possible. The battery |
770 | * current during charging is affected by the system load |
771 | */ |
772 | static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) |
773 | { |
774 | |
775 | if (!di->bm->maxi->ena_maxi) |
776 | return MAXIM_RET_NOACTION; |
777 | |
778 | if (di->events.vbus_collapsed) { |
779 | dev_dbg(di->dev, "Charger voltage has collapsed %d\n" , |
780 | di->ccm.wait_cnt); |
781 | if (di->ccm.wait_cnt == 0) { |
782 | dev_dbg(di->dev, "lowering current\n" ); |
783 | di->ccm.wait_cnt++; |
784 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
785 | di->ccm.max_current_ua = di->ccm.current_iset_ua; |
786 | di->ccm.current_iset_ua = di->ccm.max_current_ua; |
787 | di->ccm.level--; |
788 | return MAXIM_RET_CHANGE; |
789 | } else { |
790 | dev_dbg(di->dev, "waiting\n" ); |
791 | /* Let's go in here twice before lowering curr again */ |
792 | di->ccm.wait_cnt = (di->ccm.wait_cnt + 1) % 3; |
793 | return MAXIM_RET_NOACTION; |
794 | } |
795 | } |
796 | |
797 | di->ccm.wait_cnt = 0; |
798 | |
799 | if (di->batt_data.inst_curr_ua > di->ccm.original_iset_ua) { |
800 | dev_dbg(di->dev, " Maximization Ibat (%duA) too high" |
801 | " (limit %duA) (current iset: %duA)!\n" , |
802 | di->batt_data.inst_curr_ua, di->ccm.original_iset_ua, |
803 | di->ccm.current_iset_ua); |
804 | |
805 | if (di->ccm.current_iset_ua == di->ccm.original_iset_ua) |
806 | return MAXIM_RET_NOACTION; |
807 | |
808 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
809 | di->ccm.current_iset_ua = di->ccm.original_iset_ua; |
810 | di->ccm.level = 0; |
811 | |
812 | return MAXIM_RET_IBAT_TOO_HIGH; |
813 | } |
814 | |
815 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
816 | return MAXIM_RET_NOACTION; |
817 | } |
818 | |
819 | static void handle_maxim_chg_curr(struct ab8500_chargalg *di) |
820 | { |
821 | struct power_supply_battery_info *bi = di->bm->bi; |
822 | enum maxim_ret ret; |
823 | int result; |
824 | |
825 | ret = ab8500_chargalg_chg_curr_maxim(di); |
826 | switch (ret) { |
827 | case MAXIM_RET_CHANGE: |
828 | result = ab8500_chargalg_update_chg_curr(di, |
829 | iset_ua: di->ccm.current_iset_ua); |
830 | if (result) |
831 | dev_err(di->dev, "failed to set chg curr\n" ); |
832 | break; |
833 | case MAXIM_RET_IBAT_TOO_HIGH: |
834 | result = ab8500_chargalg_update_chg_curr(di, |
835 | iset_ua: bi->constant_charge_current_max_ua); |
836 | if (result) |
837 | dev_err(di->dev, "failed to set chg curr\n" ); |
838 | break; |
839 | |
840 | case MAXIM_RET_NOACTION: |
841 | default: |
842 | /* Do nothing..*/ |
843 | break; |
844 | } |
845 | } |
846 | |
847 | static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) |
848 | { |
849 | struct power_supply *psy; |
850 | struct power_supply *ext = dev_get_drvdata(dev); |
851 | const char **supplicants = (const char **)ext->supplied_to; |
852 | struct ab8500_chargalg *di; |
853 | union power_supply_propval ret; |
854 | int j; |
855 | bool capacity_updated = false; |
856 | |
857 | psy = (struct power_supply *)data; |
858 | di = power_supply_get_drvdata(psy); |
859 | /* For all psy where the driver name appears in any supplied_to */ |
860 | j = match_string(array: supplicants, n: ext->num_supplicants, string: psy->desc->name); |
861 | if (j < 0) |
862 | return 0; |
863 | |
864 | /* |
865 | * If external is not registering 'POWER_SUPPLY_PROP_CAPACITY' to its |
866 | * property because of handling that sysfs entry on its own, this is |
867 | * the place to get the battery capacity. |
868 | */ |
869 | if (!power_supply_get_property(psy: ext, psp: POWER_SUPPLY_PROP_CAPACITY, val: &ret)) { |
870 | di->batt_data.percent = ret.intval; |
871 | capacity_updated = true; |
872 | } |
873 | |
874 | /* Go through all properties for the psy */ |
875 | for (j = 0; j < ext->desc->num_properties; j++) { |
876 | enum power_supply_property prop; |
877 | prop = ext->desc->properties[j]; |
878 | |
879 | /* |
880 | * Initialize chargers if not already done. |
881 | * The ab8500_charger*/ |
882 | if (!di->ac_chg && |
883 | ext->desc->type == POWER_SUPPLY_TYPE_MAINS) |
884 | di->ac_chg = psy_to_ux500_charger(ext); |
885 | else if (!di->usb_chg && |
886 | ext->desc->type == POWER_SUPPLY_TYPE_USB) |
887 | di->usb_chg = psy_to_ux500_charger(ext); |
888 | |
889 | if (power_supply_get_property(psy: ext, psp: prop, val: &ret)) |
890 | continue; |
891 | switch (prop) { |
892 | case POWER_SUPPLY_PROP_PRESENT: |
893 | switch (ext->desc->type) { |
894 | case POWER_SUPPLY_TYPE_BATTERY: |
895 | /* Battery present */ |
896 | if (ret.intval) |
897 | di->events.batt_rem = false; |
898 | /* Battery removed */ |
899 | else |
900 | di->events.batt_rem = true; |
901 | break; |
902 | case POWER_SUPPLY_TYPE_MAINS: |
903 | /* AC disconnected */ |
904 | if (!ret.intval && |
905 | (di->chg_info.conn_chg & AC_CHG)) { |
906 | di->chg_info.prev_conn_chg = |
907 | di->chg_info.conn_chg; |
908 | di->chg_info.conn_chg &= ~AC_CHG; |
909 | } |
910 | /* AC connected */ |
911 | else if (ret.intval && |
912 | !(di->chg_info.conn_chg & AC_CHG)) { |
913 | di->chg_info.prev_conn_chg = |
914 | di->chg_info.conn_chg; |
915 | di->chg_info.conn_chg |= AC_CHG; |
916 | } |
917 | break; |
918 | case POWER_SUPPLY_TYPE_USB: |
919 | /* USB disconnected */ |
920 | if (!ret.intval && |
921 | (di->chg_info.conn_chg & USB_CHG)) { |
922 | di->chg_info.prev_conn_chg = |
923 | di->chg_info.conn_chg; |
924 | di->chg_info.conn_chg &= ~USB_CHG; |
925 | } |
926 | /* USB connected */ |
927 | else if (ret.intval && |
928 | !(di->chg_info.conn_chg & USB_CHG)) { |
929 | di->chg_info.prev_conn_chg = |
930 | di->chg_info.conn_chg; |
931 | di->chg_info.conn_chg |= USB_CHG; |
932 | } |
933 | break; |
934 | default: |
935 | break; |
936 | } |
937 | break; |
938 | |
939 | case POWER_SUPPLY_PROP_ONLINE: |
940 | switch (ext->desc->type) { |
941 | case POWER_SUPPLY_TYPE_BATTERY: |
942 | break; |
943 | case POWER_SUPPLY_TYPE_MAINS: |
944 | /* AC offline */ |
945 | if (!ret.intval && |
946 | (di->chg_info.online_chg & AC_CHG)) { |
947 | di->chg_info.prev_online_chg = |
948 | di->chg_info.online_chg; |
949 | di->chg_info.online_chg &= ~AC_CHG; |
950 | } |
951 | /* AC online */ |
952 | else if (ret.intval && |
953 | !(di->chg_info.online_chg & AC_CHG)) { |
954 | di->chg_info.prev_online_chg = |
955 | di->chg_info.online_chg; |
956 | di->chg_info.online_chg |= AC_CHG; |
957 | queue_delayed_work(wq: di->chargalg_wq, |
958 | dwork: &di->chargalg_wd_work, delay: 0); |
959 | } |
960 | break; |
961 | case POWER_SUPPLY_TYPE_USB: |
962 | /* USB offline */ |
963 | if (!ret.intval && |
964 | (di->chg_info.online_chg & USB_CHG)) { |
965 | di->chg_info.prev_online_chg = |
966 | di->chg_info.online_chg; |
967 | di->chg_info.online_chg &= ~USB_CHG; |
968 | } |
969 | /* USB online */ |
970 | else if (ret.intval && |
971 | !(di->chg_info.online_chg & USB_CHG)) { |
972 | di->chg_info.prev_online_chg = |
973 | di->chg_info.online_chg; |
974 | di->chg_info.online_chg |= USB_CHG; |
975 | queue_delayed_work(wq: di->chargalg_wq, |
976 | dwork: &di->chargalg_wd_work, delay: 0); |
977 | } |
978 | break; |
979 | default: |
980 | break; |
981 | } |
982 | break; |
983 | |
984 | case POWER_SUPPLY_PROP_HEALTH: |
985 | switch (ext->desc->type) { |
986 | case POWER_SUPPLY_TYPE_BATTERY: |
987 | break; |
988 | case POWER_SUPPLY_TYPE_MAINS: |
989 | switch (ret.intval) { |
990 | case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: |
991 | di->events.mainextchnotok = true; |
992 | di->events.main_thermal_prot = false; |
993 | di->events.main_ovv = false; |
994 | di->events.ac_wd_expired = false; |
995 | break; |
996 | case POWER_SUPPLY_HEALTH_DEAD: |
997 | di->events.ac_wd_expired = true; |
998 | di->events.mainextchnotok = false; |
999 | di->events.main_ovv = false; |
1000 | di->events.main_thermal_prot = false; |
1001 | break; |
1002 | case POWER_SUPPLY_HEALTH_COLD: |
1003 | case POWER_SUPPLY_HEALTH_OVERHEAT: |
1004 | di->events.main_thermal_prot = true; |
1005 | di->events.mainextchnotok = false; |
1006 | di->events.main_ovv = false; |
1007 | di->events.ac_wd_expired = false; |
1008 | break; |
1009 | case POWER_SUPPLY_HEALTH_OVERVOLTAGE: |
1010 | di->events.main_ovv = true; |
1011 | di->events.mainextchnotok = false; |
1012 | di->events.main_thermal_prot = false; |
1013 | di->events.ac_wd_expired = false; |
1014 | break; |
1015 | case POWER_SUPPLY_HEALTH_GOOD: |
1016 | di->events.main_thermal_prot = false; |
1017 | di->events.mainextchnotok = false; |
1018 | di->events.main_ovv = false; |
1019 | di->events.ac_wd_expired = false; |
1020 | break; |
1021 | default: |
1022 | break; |
1023 | } |
1024 | break; |
1025 | |
1026 | case POWER_SUPPLY_TYPE_USB: |
1027 | switch (ret.intval) { |
1028 | case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: |
1029 | di->events.usbchargernotok = true; |
1030 | di->events.usb_thermal_prot = false; |
1031 | di->events.vbus_ovv = false; |
1032 | di->events.usb_wd_expired = false; |
1033 | break; |
1034 | case POWER_SUPPLY_HEALTH_DEAD: |
1035 | di->events.usb_wd_expired = true; |
1036 | di->events.usbchargernotok = false; |
1037 | di->events.usb_thermal_prot = false; |
1038 | di->events.vbus_ovv = false; |
1039 | break; |
1040 | case POWER_SUPPLY_HEALTH_COLD: |
1041 | case POWER_SUPPLY_HEALTH_OVERHEAT: |
1042 | di->events.usb_thermal_prot = true; |
1043 | di->events.usbchargernotok = false; |
1044 | di->events.vbus_ovv = false; |
1045 | di->events.usb_wd_expired = false; |
1046 | break; |
1047 | case POWER_SUPPLY_HEALTH_OVERVOLTAGE: |
1048 | di->events.vbus_ovv = true; |
1049 | di->events.usbchargernotok = false; |
1050 | di->events.usb_thermal_prot = false; |
1051 | di->events.usb_wd_expired = false; |
1052 | break; |
1053 | case POWER_SUPPLY_HEALTH_GOOD: |
1054 | di->events.usbchargernotok = false; |
1055 | di->events.usb_thermal_prot = false; |
1056 | di->events.vbus_ovv = false; |
1057 | di->events.usb_wd_expired = false; |
1058 | break; |
1059 | default: |
1060 | break; |
1061 | } |
1062 | break; |
1063 | default: |
1064 | break; |
1065 | } |
1066 | break; |
1067 | |
1068 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
1069 | switch (ext->desc->type) { |
1070 | case POWER_SUPPLY_TYPE_BATTERY: |
1071 | di->batt_data.volt_uv = ret.intval; |
1072 | break; |
1073 | case POWER_SUPPLY_TYPE_MAINS: |
1074 | di->chg_info.ac_volt_uv = ret.intval; |
1075 | break; |
1076 | case POWER_SUPPLY_TYPE_USB: |
1077 | di->chg_info.usb_volt_uv = ret.intval; |
1078 | break; |
1079 | default: |
1080 | break; |
1081 | } |
1082 | break; |
1083 | |
1084 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: |
1085 | switch (ext->desc->type) { |
1086 | case POWER_SUPPLY_TYPE_MAINS: |
1087 | /* AVG is used to indicate when we are |
1088 | * in CV mode */ |
1089 | if (ret.intval) |
1090 | di->events.ac_cv_active = true; |
1091 | else |
1092 | di->events.ac_cv_active = false; |
1093 | |
1094 | break; |
1095 | case POWER_SUPPLY_TYPE_USB: |
1096 | /* AVG is used to indicate when we are |
1097 | * in CV mode */ |
1098 | if (ret.intval) |
1099 | di->events.usb_cv_active = true; |
1100 | else |
1101 | di->events.usb_cv_active = false; |
1102 | |
1103 | break; |
1104 | default: |
1105 | break; |
1106 | } |
1107 | break; |
1108 | |
1109 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
1110 | switch (ext->desc->type) { |
1111 | case POWER_SUPPLY_TYPE_BATTERY: |
1112 | if (ret.intval) |
1113 | di->events.batt_unknown = false; |
1114 | else |
1115 | di->events.batt_unknown = true; |
1116 | |
1117 | break; |
1118 | default: |
1119 | break; |
1120 | } |
1121 | break; |
1122 | |
1123 | case POWER_SUPPLY_PROP_TEMP: |
1124 | di->batt_data.temp = ret.intval / 10; |
1125 | break; |
1126 | |
1127 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
1128 | switch (ext->desc->type) { |
1129 | case POWER_SUPPLY_TYPE_MAINS: |
1130 | di->chg_info.ac_curr_ua = ret.intval; |
1131 | break; |
1132 | case POWER_SUPPLY_TYPE_USB: |
1133 | di->chg_info.usb_curr_ua = ret.intval; |
1134 | break; |
1135 | case POWER_SUPPLY_TYPE_BATTERY: |
1136 | di->batt_data.inst_curr_ua = ret.intval; |
1137 | break; |
1138 | default: |
1139 | break; |
1140 | } |
1141 | break; |
1142 | |
1143 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
1144 | switch (ext->desc->type) { |
1145 | case POWER_SUPPLY_TYPE_BATTERY: |
1146 | di->batt_data.avg_curr_ua = ret.intval; |
1147 | break; |
1148 | case POWER_SUPPLY_TYPE_USB: |
1149 | if (ret.intval) |
1150 | di->events.vbus_collapsed = true; |
1151 | else |
1152 | di->events.vbus_collapsed = false; |
1153 | break; |
1154 | default: |
1155 | break; |
1156 | } |
1157 | break; |
1158 | case POWER_SUPPLY_PROP_CAPACITY: |
1159 | if (!capacity_updated) |
1160 | di->batt_data.percent = ret.intval; |
1161 | break; |
1162 | default: |
1163 | break; |
1164 | } |
1165 | } |
1166 | return 0; |
1167 | } |
1168 | |
1169 | /** |
1170 | * ab8500_chargalg_external_power_changed() - callback for power supply changes |
1171 | * @psy: pointer to the structure power_supply |
1172 | * |
1173 | * This function is the entry point of the pointer external_power_changed |
1174 | * of the structure power_supply. |
1175 | * This function gets executed when there is a change in any external power |
1176 | * supply that this driver needs to be notified of. |
1177 | */ |
1178 | static void ab8500_chargalg_external_power_changed(struct power_supply *psy) |
1179 | { |
1180 | struct ab8500_chargalg *di = power_supply_get_drvdata(psy); |
1181 | |
1182 | /* |
1183 | * Trigger execution of the algorithm instantly and read |
1184 | * all power_supply properties there instead |
1185 | */ |
1186 | if (di->chargalg_wq) |
1187 | queue_work(wq: di->chargalg_wq, work: &di->chargalg_work); |
1188 | } |
1189 | |
1190 | /** |
1191 | * ab8500_chargalg_time_to_restart() - time to restart CC/CV charging? |
1192 | * @di: charging algorithm state |
1193 | * |
1194 | * This checks if the voltage or capacity of the battery has fallen so |
1195 | * low that we need to restart the CC/CV charge cycle. |
1196 | */ |
1197 | static bool ab8500_chargalg_time_to_restart(struct ab8500_chargalg *di) |
1198 | { |
1199 | struct power_supply_battery_info *bi = di->bm->bi; |
1200 | |
1201 | /* Sanity check - these need to have some reasonable values */ |
1202 | if (!di->batt_data.volt_uv || !di->batt_data.percent) |
1203 | return false; |
1204 | |
1205 | /* Some batteries tell us at which voltage we should restart charging */ |
1206 | if (bi->charge_restart_voltage_uv > 0) { |
1207 | if (di->batt_data.volt_uv <= bi->charge_restart_voltage_uv) |
1208 | return true; |
1209 | /* Else we restart as we reach a certain capacity */ |
1210 | } else { |
1211 | if (di->batt_data.percent <= AB8500_RECHARGE_CAP) |
1212 | return true; |
1213 | } |
1214 | |
1215 | return false; |
1216 | } |
1217 | |
1218 | /** |
1219 | * ab8500_chargalg_algorithm() - Main function for the algorithm |
1220 | * @di: pointer to the ab8500_chargalg structure |
1221 | * |
1222 | * This is the main control function for the charging algorithm. |
1223 | * It is called periodically or when something happens that will |
1224 | * trigger a state change |
1225 | */ |
1226 | static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) |
1227 | { |
1228 | struct power_supply_battery_info *bi = di->bm->bi; |
1229 | struct power_supply_maintenance_charge_table *mt; |
1230 | int charger_status; |
1231 | int ret; |
1232 | |
1233 | /* Collect data from all power_supply class devices */ |
1234 | power_supply_for_each_device(data: di->chargalg_psy, fn: ab8500_chargalg_get_ext_psy_data); |
1235 | |
1236 | ab8500_chargalg_end_of_charge(di); |
1237 | ab8500_chargalg_check_temp(di); |
1238 | ab8500_chargalg_check_charger_voltage(di); |
1239 | |
1240 | charger_status = ab8500_chargalg_check_charger_connection(di); |
1241 | |
1242 | if (is_ab8500(ab: di->parent)) { |
1243 | ret = ab8500_chargalg_check_charger_enable(di); |
1244 | if (ret < 0) |
1245 | dev_err(di->dev, "Checking charger is enabled error" |
1246 | ": Returned Value %d\n" , ret); |
1247 | } |
1248 | |
1249 | /* |
1250 | * First check if we have a charger connected. |
1251 | * Also we don't allow charging of unknown batteries if configured |
1252 | * this way |
1253 | */ |
1254 | if (!charger_status || |
1255 | (di->events.batt_unknown && !di->bm->chg_unknown_bat)) { |
1256 | if (di->charge_state != STATE_HANDHELD) { |
1257 | di->events.safety_timer_expired = false; |
1258 | ab8500_chargalg_state_to(di, state: STATE_HANDHELD_INIT); |
1259 | } |
1260 | } |
1261 | |
1262 | /* Safety timer expiration */ |
1263 | else if (di->events.safety_timer_expired) { |
1264 | if (di->charge_state != STATE_SAFETY_TIMER_EXPIRED) |
1265 | ab8500_chargalg_state_to(di, |
1266 | state: STATE_SAFETY_TIMER_EXPIRED_INIT); |
1267 | } |
1268 | /* |
1269 | * Check if any interrupts has occurred |
1270 | * that will prevent us from charging |
1271 | */ |
1272 | |
1273 | /* Battery removed */ |
1274 | else if (di->events.batt_rem) { |
1275 | if (di->charge_state != STATE_BATT_REMOVED) |
1276 | ab8500_chargalg_state_to(di, state: STATE_BATT_REMOVED_INIT); |
1277 | } |
1278 | /* Main or USB charger not ok. */ |
1279 | else if (di->events.mainextchnotok || di->events.usbchargernotok) { |
1280 | /* |
1281 | * If vbus_collapsed is set, we have to lower the charger |
1282 | * current, which is done in the normal state below |
1283 | */ |
1284 | if (di->charge_state != STATE_CHG_NOT_OK && |
1285 | !di->events.vbus_collapsed) |
1286 | ab8500_chargalg_state_to(di, state: STATE_CHG_NOT_OK_INIT); |
1287 | } |
1288 | /* VBUS, Main or VBAT OVV. */ |
1289 | else if (di->events.vbus_ovv || |
1290 | di->events.main_ovv || |
1291 | di->events.batt_ovv || |
1292 | !di->chg_info.usb_chg_ok || |
1293 | !di->chg_info.ac_chg_ok) { |
1294 | if (di->charge_state != STATE_OVV_PROTECT) |
1295 | ab8500_chargalg_state_to(di, state: STATE_OVV_PROTECT_INIT); |
1296 | } |
1297 | /* USB Thermal, stop charging */ |
1298 | else if (di->events.main_thermal_prot || |
1299 | di->events.usb_thermal_prot) { |
1300 | if (di->charge_state != STATE_HW_TEMP_PROTECT) |
1301 | ab8500_chargalg_state_to(di, |
1302 | state: STATE_HW_TEMP_PROTECT_INIT); |
1303 | } |
1304 | /* Battery temp over/under */ |
1305 | else if (di->events.btemp_underover) { |
1306 | if (di->charge_state != STATE_TEMP_UNDEROVER) |
1307 | ab8500_chargalg_state_to(di, |
1308 | state: STATE_TEMP_UNDEROVER_INIT); |
1309 | } |
1310 | /* Watchdog expired */ |
1311 | else if (di->events.ac_wd_expired || |
1312 | di->events.usb_wd_expired) { |
1313 | if (di->charge_state != STATE_WD_EXPIRED) |
1314 | ab8500_chargalg_state_to(di, state: STATE_WD_EXPIRED_INIT); |
1315 | } |
1316 | /* Battery temp high/low */ |
1317 | else if (di->events.btemp_low || di->events.btemp_high) { |
1318 | if (di->charge_state != STATE_TEMP_LOWHIGH) |
1319 | ab8500_chargalg_state_to(di, state: STATE_TEMP_LOWHIGH_INIT); |
1320 | } |
1321 | |
1322 | dev_dbg(di->dev, |
1323 | "[CHARGALG] Vb %d Ib_avg %d Ib_inst %d Tb %d Cap %d Maint %d " |
1324 | "State %s Active_chg %d Chg_status %d AC %d USB %d " |
1325 | "AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d " |
1326 | "USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n" , |
1327 | di->batt_data.volt_uv, |
1328 | di->batt_data.avg_curr_ua, |
1329 | di->batt_data.inst_curr_ua, |
1330 | di->batt_data.temp, |
1331 | di->batt_data.percent, |
1332 | di->maintenance_chg, |
1333 | states[di->charge_state], |
1334 | di->chg_info.charger_type, |
1335 | di->charge_status, |
1336 | di->chg_info.conn_chg & AC_CHG, |
1337 | di->chg_info.conn_chg & USB_CHG, |
1338 | di->chg_info.online_chg & AC_CHG, |
1339 | di->chg_info.online_chg & USB_CHG, |
1340 | di->events.ac_cv_active, |
1341 | di->events.usb_cv_active, |
1342 | di->chg_info.ac_curr_ua, |
1343 | di->chg_info.usb_curr_ua, |
1344 | di->chg_info.ac_vset_uv, |
1345 | di->chg_info.ac_iset_ua, |
1346 | di->chg_info.usb_vset_uv, |
1347 | di->chg_info.usb_iset_ua); |
1348 | |
1349 | switch (di->charge_state) { |
1350 | case STATE_HANDHELD_INIT: |
1351 | ab8500_chargalg_stop_charging(di); |
1352 | di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING; |
1353 | ab8500_chargalg_state_to(di, state: STATE_HANDHELD); |
1354 | fallthrough; |
1355 | |
1356 | case STATE_HANDHELD: |
1357 | break; |
1358 | |
1359 | case STATE_BATT_REMOVED_INIT: |
1360 | ab8500_chargalg_stop_charging(di); |
1361 | ab8500_chargalg_state_to(di, state: STATE_BATT_REMOVED); |
1362 | fallthrough; |
1363 | |
1364 | case STATE_BATT_REMOVED: |
1365 | if (!di->events.batt_rem) |
1366 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1367 | break; |
1368 | |
1369 | case STATE_HW_TEMP_PROTECT_INIT: |
1370 | ab8500_chargalg_stop_charging(di); |
1371 | ab8500_chargalg_state_to(di, state: STATE_HW_TEMP_PROTECT); |
1372 | fallthrough; |
1373 | |
1374 | case STATE_HW_TEMP_PROTECT: |
1375 | if (!di->events.main_thermal_prot && |
1376 | !di->events.usb_thermal_prot) |
1377 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1378 | break; |
1379 | |
1380 | case STATE_OVV_PROTECT_INIT: |
1381 | ab8500_chargalg_stop_charging(di); |
1382 | ab8500_chargalg_state_to(di, state: STATE_OVV_PROTECT); |
1383 | fallthrough; |
1384 | |
1385 | case STATE_OVV_PROTECT: |
1386 | if (!di->events.vbus_ovv && |
1387 | !di->events.main_ovv && |
1388 | !di->events.batt_ovv && |
1389 | di->chg_info.usb_chg_ok && |
1390 | di->chg_info.ac_chg_ok) |
1391 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1392 | break; |
1393 | |
1394 | case STATE_CHG_NOT_OK_INIT: |
1395 | ab8500_chargalg_stop_charging(di); |
1396 | ab8500_chargalg_state_to(di, state: STATE_CHG_NOT_OK); |
1397 | fallthrough; |
1398 | |
1399 | case STATE_CHG_NOT_OK: |
1400 | if (!di->events.mainextchnotok && |
1401 | !di->events.usbchargernotok) |
1402 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1403 | break; |
1404 | |
1405 | case STATE_SAFETY_TIMER_EXPIRED_INIT: |
1406 | ab8500_chargalg_stop_charging(di); |
1407 | ab8500_chargalg_state_to(di, state: STATE_SAFETY_TIMER_EXPIRED); |
1408 | fallthrough; |
1409 | |
1410 | case STATE_SAFETY_TIMER_EXPIRED: |
1411 | /* We exit this state when charger is removed */ |
1412 | break; |
1413 | |
1414 | case STATE_NORMAL_INIT: |
1415 | if (bi->constant_charge_current_max_ua == 0) |
1416 | /* "charging" with 0 uA */ |
1417 | ab8500_chargalg_stop_charging(di); |
1418 | else { |
1419 | ab8500_chargalg_start_charging(di, |
1420 | vset_uv: bi->constant_charge_voltage_max_uv, |
1421 | iset_ua: bi->constant_charge_current_max_ua); |
1422 | } |
1423 | |
1424 | ab8500_chargalg_state_to(di, state: STATE_NORMAL); |
1425 | ab8500_chargalg_start_safety_timer(di); |
1426 | ab8500_chargalg_stop_maintenance_timer(di); |
1427 | init_maxim_chg_curr(di); |
1428 | di->charge_status = POWER_SUPPLY_STATUS_CHARGING; |
1429 | di->eoc_cnt = 0; |
1430 | di->maintenance_chg = false; |
1431 | power_supply_changed(psy: di->chargalg_psy); |
1432 | |
1433 | break; |
1434 | |
1435 | case STATE_NORMAL: |
1436 | handle_maxim_chg_curr(di); |
1437 | if (di->charge_status == POWER_SUPPLY_STATUS_FULL && |
1438 | di->maintenance_chg) { |
1439 | /* |
1440 | * The battery is fully charged, check if we support |
1441 | * maintenance charging else go back to waiting for |
1442 | * the recharge voltage limit. |
1443 | */ |
1444 | if (!power_supply_supports_maintenance_charging(info: bi)) |
1445 | ab8500_chargalg_state_to(di, |
1446 | state: STATE_WAIT_FOR_RECHARGE_INIT); |
1447 | else |
1448 | ab8500_chargalg_state_to(di, |
1449 | state: STATE_MAINTENANCE_A_INIT); |
1450 | } |
1451 | break; |
1452 | |
1453 | /* This state will be used when the maintenance state is disabled */ |
1454 | case STATE_WAIT_FOR_RECHARGE_INIT: |
1455 | ab8500_chargalg_hold_charging(di); |
1456 | ab8500_chargalg_state_to(di, state: STATE_WAIT_FOR_RECHARGE); |
1457 | fallthrough; |
1458 | |
1459 | case STATE_WAIT_FOR_RECHARGE: |
1460 | if (ab8500_chargalg_time_to_restart(di)) |
1461 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1462 | break; |
1463 | |
1464 | case STATE_MAINTENANCE_A_INIT: |
1465 | mt = power_supply_get_maintenance_charging_setting(info: bi, index: 0); |
1466 | if (!mt) { |
1467 | /* No maintenance A state, go back to normal */ |
1468 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1469 | power_supply_changed(psy: di->chargalg_psy); |
1470 | break; |
1471 | } |
1472 | ab8500_chargalg_stop_safety_timer(di); |
1473 | ab8500_chargalg_start_maintenance_timer(di, |
1474 | duration: mt->charge_safety_timer_minutes); |
1475 | ab8500_chargalg_start_charging(di, |
1476 | vset_uv: mt->charge_voltage_max_uv, |
1477 | iset_ua: mt->charge_current_max_ua); |
1478 | ab8500_chargalg_state_to(di, state: STATE_MAINTENANCE_A); |
1479 | power_supply_changed(psy: di->chargalg_psy); |
1480 | fallthrough; |
1481 | |
1482 | case STATE_MAINTENANCE_A: |
1483 | if (di->events.maintenance_timer_expired) { |
1484 | ab8500_chargalg_stop_maintenance_timer(di); |
1485 | ab8500_chargalg_state_to(di, state: STATE_MAINTENANCE_B_INIT); |
1486 | } |
1487 | /* |
1488 | * This happens if the voltage drops too quickly during |
1489 | * maintenance charging, especially in older batteries. |
1490 | */ |
1491 | if (ab8500_chargalg_time_to_restart(di)) { |
1492 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1493 | dev_info(di->dev, "restarted charging from maintenance state A - battery getting old?\n" ); |
1494 | } |
1495 | break; |
1496 | |
1497 | case STATE_MAINTENANCE_B_INIT: |
1498 | mt = power_supply_get_maintenance_charging_setting(info: bi, index: 1); |
1499 | if (!mt) { |
1500 | /* No maintenance B state, go back to normal */ |
1501 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1502 | power_supply_changed(psy: di->chargalg_psy); |
1503 | break; |
1504 | } |
1505 | ab8500_chargalg_start_maintenance_timer(di, |
1506 | duration: mt->charge_safety_timer_minutes); |
1507 | ab8500_chargalg_start_charging(di, |
1508 | vset_uv: mt->charge_voltage_max_uv, |
1509 | iset_ua: mt->charge_current_max_ua); |
1510 | ab8500_chargalg_state_to(di, state: STATE_MAINTENANCE_B); |
1511 | power_supply_changed(psy: di->chargalg_psy); |
1512 | fallthrough; |
1513 | |
1514 | case STATE_MAINTENANCE_B: |
1515 | if (di->events.maintenance_timer_expired) { |
1516 | ab8500_chargalg_stop_maintenance_timer(di); |
1517 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1518 | } |
1519 | /* |
1520 | * This happens if the voltage drops too quickly during |
1521 | * maintenance charging, especially in older batteries. |
1522 | */ |
1523 | if (ab8500_chargalg_time_to_restart(di)) { |
1524 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1525 | dev_info(di->dev, "restarted charging from maintenance state B - battery getting old?\n" ); |
1526 | } |
1527 | break; |
1528 | |
1529 | case STATE_TEMP_LOWHIGH_INIT: |
1530 | if (di->events.btemp_low) { |
1531 | ab8500_chargalg_start_charging(di, |
1532 | vset_uv: bi->alert_low_temp_charge_voltage_uv, |
1533 | iset_ua: bi->alert_low_temp_charge_current_ua); |
1534 | } else if (di->events.btemp_high) { |
1535 | ab8500_chargalg_start_charging(di, |
1536 | vset_uv: bi->alert_high_temp_charge_voltage_uv, |
1537 | iset_ua: bi->alert_high_temp_charge_current_ua); |
1538 | } else { |
1539 | dev_err(di->dev, "neither low or high temp event occurred\n" ); |
1540 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1541 | break; |
1542 | } |
1543 | ab8500_chargalg_stop_maintenance_timer(di); |
1544 | di->charge_status = POWER_SUPPLY_STATUS_CHARGING; |
1545 | ab8500_chargalg_state_to(di, state: STATE_TEMP_LOWHIGH); |
1546 | power_supply_changed(psy: di->chargalg_psy); |
1547 | fallthrough; |
1548 | |
1549 | case STATE_TEMP_LOWHIGH: |
1550 | if (!di->events.btemp_low && !di->events.btemp_high) |
1551 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1552 | break; |
1553 | |
1554 | case STATE_WD_EXPIRED_INIT: |
1555 | ab8500_chargalg_stop_charging(di); |
1556 | ab8500_chargalg_state_to(di, state: STATE_WD_EXPIRED); |
1557 | fallthrough; |
1558 | |
1559 | case STATE_WD_EXPIRED: |
1560 | if (!di->events.ac_wd_expired && |
1561 | !di->events.usb_wd_expired) |
1562 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1563 | break; |
1564 | |
1565 | case STATE_TEMP_UNDEROVER_INIT: |
1566 | ab8500_chargalg_stop_charging(di); |
1567 | ab8500_chargalg_state_to(di, state: STATE_TEMP_UNDEROVER); |
1568 | fallthrough; |
1569 | |
1570 | case STATE_TEMP_UNDEROVER: |
1571 | if (!di->events.btemp_underover) |
1572 | ab8500_chargalg_state_to(di, state: STATE_NORMAL_INIT); |
1573 | break; |
1574 | } |
1575 | |
1576 | /* Start charging directly if the new state is a charge state */ |
1577 | if (di->charge_state == STATE_NORMAL_INIT || |
1578 | di->charge_state == STATE_MAINTENANCE_A_INIT || |
1579 | di->charge_state == STATE_MAINTENANCE_B_INIT) |
1580 | queue_work(wq: di->chargalg_wq, work: &di->chargalg_work); |
1581 | } |
1582 | |
1583 | /** |
1584 | * ab8500_chargalg_periodic_work() - Periodic work for the algorithm |
1585 | * @work: pointer to the work_struct structure |
1586 | * |
1587 | * Work queue function for the charging algorithm |
1588 | */ |
1589 | static void ab8500_chargalg_periodic_work(struct work_struct *work) |
1590 | { |
1591 | struct ab8500_chargalg *di = container_of(work, |
1592 | struct ab8500_chargalg, chargalg_periodic_work.work); |
1593 | |
1594 | ab8500_chargalg_algorithm(di); |
1595 | |
1596 | /* |
1597 | * If a charger is connected then the battery has to be monitored |
1598 | * frequently, else the work can be delayed. |
1599 | */ |
1600 | if (di->chg_info.conn_chg) |
1601 | queue_delayed_work(wq: di->chargalg_wq, |
1602 | dwork: &di->chargalg_periodic_work, |
1603 | delay: di->bm->interval_charging * HZ); |
1604 | else |
1605 | queue_delayed_work(wq: di->chargalg_wq, |
1606 | dwork: &di->chargalg_periodic_work, |
1607 | delay: di->bm->interval_not_charging * HZ); |
1608 | } |
1609 | |
1610 | /** |
1611 | * ab8500_chargalg_wd_work() - periodic work to kick the charger watchdog |
1612 | * @work: pointer to the work_struct structure |
1613 | * |
1614 | * Work queue function for kicking the charger watchdog |
1615 | */ |
1616 | static void ab8500_chargalg_wd_work(struct work_struct *work) |
1617 | { |
1618 | int ret; |
1619 | struct ab8500_chargalg *di = container_of(work, |
1620 | struct ab8500_chargalg, chargalg_wd_work.work); |
1621 | |
1622 | ret = ab8500_chargalg_kick_watchdog(di); |
1623 | if (ret < 0) |
1624 | dev_err(di->dev, "failed to kick watchdog\n" ); |
1625 | |
1626 | queue_delayed_work(wq: di->chargalg_wq, |
1627 | dwork: &di->chargalg_wd_work, CHG_WD_INTERVAL); |
1628 | } |
1629 | |
1630 | /** |
1631 | * ab8500_chargalg_work() - Work to run the charging algorithm instantly |
1632 | * @work: pointer to the work_struct structure |
1633 | * |
1634 | * Work queue function for calling the charging algorithm |
1635 | */ |
1636 | static void ab8500_chargalg_work(struct work_struct *work) |
1637 | { |
1638 | struct ab8500_chargalg *di = container_of(work, |
1639 | struct ab8500_chargalg, chargalg_work); |
1640 | |
1641 | ab8500_chargalg_algorithm(di); |
1642 | } |
1643 | |
1644 | /** |
1645 | * ab8500_chargalg_get_property() - get the chargalg properties |
1646 | * @psy: pointer to the power_supply structure |
1647 | * @psp: pointer to the power_supply_property structure |
1648 | * @val: pointer to the power_supply_propval union |
1649 | * |
1650 | * This function gets called when an application tries to get the |
1651 | * chargalg properties by reading the sysfs files. |
1652 | * status: charging/discharging/full/unknown |
1653 | * health: health of the battery |
1654 | * Returns error code in case of failure else 0 on success |
1655 | */ |
1656 | static int ab8500_chargalg_get_property(struct power_supply *psy, |
1657 | enum power_supply_property psp, |
1658 | union power_supply_propval *val) |
1659 | { |
1660 | struct ab8500_chargalg *di = power_supply_get_drvdata(psy); |
1661 | |
1662 | switch (psp) { |
1663 | case POWER_SUPPLY_PROP_STATUS: |
1664 | val->intval = di->charge_status; |
1665 | break; |
1666 | case POWER_SUPPLY_PROP_HEALTH: |
1667 | if (di->events.batt_ovv) { |
1668 | val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; |
1669 | } else if (di->events.btemp_underover) { |
1670 | if (di->batt_data.temp <= di->bm->bi->temp_min) |
1671 | val->intval = POWER_SUPPLY_HEALTH_COLD; |
1672 | else |
1673 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; |
1674 | } else if (di->charge_state == STATE_SAFETY_TIMER_EXPIRED || |
1675 | di->charge_state == STATE_SAFETY_TIMER_EXPIRED_INIT) { |
1676 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; |
1677 | } else { |
1678 | val->intval = POWER_SUPPLY_HEALTH_GOOD; |
1679 | } |
1680 | break; |
1681 | default: |
1682 | return -EINVAL; |
1683 | } |
1684 | return 0; |
1685 | } |
1686 | |
1687 | static int __maybe_unused ab8500_chargalg_resume(struct device *dev) |
1688 | { |
1689 | struct ab8500_chargalg *di = dev_get_drvdata(dev); |
1690 | |
1691 | /* Kick charger watchdog if charging (any charger online) */ |
1692 | if (di->chg_info.online_chg) |
1693 | queue_delayed_work(wq: di->chargalg_wq, dwork: &di->chargalg_wd_work, delay: 0); |
1694 | |
1695 | /* |
1696 | * Run the charging algorithm directly to be sure we don't |
1697 | * do it too seldom |
1698 | */ |
1699 | queue_delayed_work(wq: di->chargalg_wq, dwork: &di->chargalg_periodic_work, delay: 0); |
1700 | |
1701 | return 0; |
1702 | } |
1703 | |
1704 | static int __maybe_unused ab8500_chargalg_suspend(struct device *dev) |
1705 | { |
1706 | struct ab8500_chargalg *di = dev_get_drvdata(dev); |
1707 | |
1708 | if (di->chg_info.online_chg) |
1709 | cancel_delayed_work_sync(dwork: &di->chargalg_wd_work); |
1710 | |
1711 | cancel_delayed_work_sync(dwork: &di->chargalg_periodic_work); |
1712 | |
1713 | return 0; |
1714 | } |
1715 | |
1716 | static char *supply_interface[] = { |
1717 | "ab8500_fg" , |
1718 | }; |
1719 | |
1720 | static const struct power_supply_desc ab8500_chargalg_desc = { |
1721 | .name = "ab8500_chargalg" , |
1722 | .type = POWER_SUPPLY_TYPE_UNKNOWN, |
1723 | .properties = ab8500_chargalg_props, |
1724 | .num_properties = ARRAY_SIZE(ab8500_chargalg_props), |
1725 | .get_property = ab8500_chargalg_get_property, |
1726 | .external_power_changed = ab8500_chargalg_external_power_changed, |
1727 | }; |
1728 | |
1729 | static int ab8500_chargalg_bind(struct device *dev, struct device *master, |
1730 | void *data) |
1731 | { |
1732 | struct ab8500_chargalg *di = dev_get_drvdata(dev); |
1733 | |
1734 | /* Create a work queue for the chargalg */ |
1735 | di->chargalg_wq = alloc_ordered_workqueue("ab8500_chargalg_wq" , |
1736 | WQ_MEM_RECLAIM); |
1737 | if (di->chargalg_wq == NULL) { |
1738 | dev_err(di->dev, "failed to create work queue\n" ); |
1739 | return -ENOMEM; |
1740 | } |
1741 | |
1742 | /* Run the charging algorithm */ |
1743 | queue_delayed_work(wq: di->chargalg_wq, dwork: &di->chargalg_periodic_work, delay: 0); |
1744 | |
1745 | return 0; |
1746 | } |
1747 | |
1748 | static void ab8500_chargalg_unbind(struct device *dev, struct device *master, |
1749 | void *data) |
1750 | { |
1751 | struct ab8500_chargalg *di = dev_get_drvdata(dev); |
1752 | |
1753 | /* Stop all timers and work */ |
1754 | hrtimer_cancel(timer: &di->safety_timer); |
1755 | hrtimer_cancel(timer: &di->maintenance_timer); |
1756 | |
1757 | cancel_delayed_work_sync(dwork: &di->chargalg_periodic_work); |
1758 | cancel_delayed_work_sync(dwork: &di->chargalg_wd_work); |
1759 | cancel_work_sync(work: &di->chargalg_work); |
1760 | |
1761 | /* Delete the work queue */ |
1762 | destroy_workqueue(wq: di->chargalg_wq); |
1763 | } |
1764 | |
1765 | static const struct component_ops ab8500_chargalg_component_ops = { |
1766 | .bind = ab8500_chargalg_bind, |
1767 | .unbind = ab8500_chargalg_unbind, |
1768 | }; |
1769 | |
1770 | static int ab8500_chargalg_probe(struct platform_device *pdev) |
1771 | { |
1772 | struct device *dev = &pdev->dev; |
1773 | struct power_supply_config psy_cfg = {}; |
1774 | struct ab8500_chargalg *di; |
1775 | |
1776 | di = devm_kzalloc(dev, size: sizeof(*di), GFP_KERNEL); |
1777 | if (!di) |
1778 | return -ENOMEM; |
1779 | |
1780 | di->bm = &ab8500_bm_data; |
1781 | |
1782 | /* get device struct and parent */ |
1783 | di->dev = dev; |
1784 | di->parent = dev_get_drvdata(dev: pdev->dev.parent); |
1785 | |
1786 | psy_cfg.supplied_to = supply_interface; |
1787 | psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); |
1788 | psy_cfg.drv_data = di; |
1789 | |
1790 | /* Initilialize safety timer */ |
1791 | hrtimer_init(timer: &di->safety_timer, CLOCK_MONOTONIC, mode: HRTIMER_MODE_REL); |
1792 | di->safety_timer.function = ab8500_chargalg_safety_timer_expired; |
1793 | |
1794 | /* Initilialize maintenance timer */ |
1795 | hrtimer_init(timer: &di->maintenance_timer, CLOCK_MONOTONIC, mode: HRTIMER_MODE_REL); |
1796 | di->maintenance_timer.function = |
1797 | ab8500_chargalg_maintenance_timer_expired; |
1798 | |
1799 | /* Init work for chargalg */ |
1800 | INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work, |
1801 | ab8500_chargalg_periodic_work); |
1802 | INIT_DEFERRABLE_WORK(&di->chargalg_wd_work, |
1803 | ab8500_chargalg_wd_work); |
1804 | |
1805 | /* Init work for chargalg */ |
1806 | INIT_WORK(&di->chargalg_work, ab8500_chargalg_work); |
1807 | |
1808 | /* To detect charger at startup */ |
1809 | di->chg_info.prev_conn_chg = -1; |
1810 | |
1811 | /* Register chargalg power supply class */ |
1812 | di->chargalg_psy = devm_power_supply_register(parent: di->dev, |
1813 | desc: &ab8500_chargalg_desc, |
1814 | cfg: &psy_cfg); |
1815 | if (IS_ERR(ptr: di->chargalg_psy)) { |
1816 | dev_err(di->dev, "failed to register chargalg psy\n" ); |
1817 | return PTR_ERR(ptr: di->chargalg_psy); |
1818 | } |
1819 | |
1820 | platform_set_drvdata(pdev, data: di); |
1821 | |
1822 | dev_info(di->dev, "probe success\n" ); |
1823 | return component_add(dev, &ab8500_chargalg_component_ops); |
1824 | } |
1825 | |
1826 | static void ab8500_chargalg_remove(struct platform_device *pdev) |
1827 | { |
1828 | component_del(&pdev->dev, &ab8500_chargalg_component_ops); |
1829 | } |
1830 | |
1831 | static SIMPLE_DEV_PM_OPS(ab8500_chargalg_pm_ops, ab8500_chargalg_suspend, ab8500_chargalg_resume); |
1832 | |
1833 | static const struct of_device_id ab8500_chargalg_match[] = { |
1834 | { .compatible = "stericsson,ab8500-chargalg" , }, |
1835 | { }, |
1836 | }; |
1837 | |
1838 | struct platform_driver ab8500_chargalg_driver = { |
1839 | .probe = ab8500_chargalg_probe, |
1840 | .remove_new = ab8500_chargalg_remove, |
1841 | .driver = { |
1842 | .name = "ab8500_chargalg" , |
1843 | .of_match_table = ab8500_chargalg_match, |
1844 | .pm = &ab8500_chargalg_pm_ops, |
1845 | }, |
1846 | }; |
1847 | MODULE_LICENSE("GPL v2" ); |
1848 | MODULE_AUTHOR("Johan Palsson, Karl Komierowski" ); |
1849 | MODULE_ALIAS("platform:ab8500-chargalg" ); |
1850 | MODULE_DESCRIPTION("ab8500 battery charging algorithm" ); |
1851 | |