blob: 2dbc6290eb9b88b3bfc0517bf04e786a9d6d73ec [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/err.h>
17#include <linux/mfd/pmic8058.h>
18#include <linux/interrupt.h>
19#include <linux/power_supply.h>
20#include <linux/delay.h>
21#include <linux/bitops.h>
22#include <linux/debugfs.h>
23#include <linux/msm-charger.h>
24#include <linux/time.h>
25#include <linux/slab.h>
26#include <linux/wakelock.h>
27
28#include <asm/atomic.h>
29
30#include <mach/msm_hsusb.h>
31
32#define MSM_CHG_MAX_EVENTS 16
33#define CHARGING_TEOC_MS 9000000
34#define UPDATE_TIME_MS 60000
35#define RESUME_CHECK_PERIOD_MS 60000
36
37#define DEFAULT_BATT_MAX_V 4200
38#define DEFAULT_BATT_MIN_V 3200
39
40#define MSM_CHARGER_GAUGE_MISSING_VOLTS 3500
41#define MSM_CHARGER_GAUGE_MISSING_TEMP 35
42/**
43 * enum msm_battery_status
44 * @BATT_STATUS_ABSENT: battery not present
45 * @BATT_STATUS_ID_INVALID: battery present but the id is invalid
46 * @BATT_STATUS_DISCHARGING: battery is present and is discharging
47 * @BATT_STATUS_TRKL_CHARGING: battery is being trickle charged
48 * @BATT_STATUS_FAST_CHARGING: battery is being fast charged
49 * @BATT_STATUS_JUST_FINISHED_CHARGING: just finished charging,
50 * battery is fully charged. Do not begin charging untill the
51 * voltage falls below a threshold to avoid overcharging
52 * @BATT_STATUS_TEMPERATURE_OUT_OF_RANGE: battery present,
53 no charging, temp is hot/cold
54 */
55enum msm_battery_status {
56 BATT_STATUS_ABSENT,
57 BATT_STATUS_ID_INVALID,
58 BATT_STATUS_DISCHARGING,
59 BATT_STATUS_TRKL_CHARGING,
60 BATT_STATUS_FAST_CHARGING,
61 BATT_STATUS_JUST_FINISHED_CHARGING,
62 BATT_STATUS_TEMPERATURE_OUT_OF_RANGE,
63};
64
65struct msm_hardware_charger_priv {
66 struct list_head list;
67 struct msm_hardware_charger *hw_chg;
68 enum msm_hardware_charger_state hw_chg_state;
69 unsigned int max_source_current;
70 struct power_supply psy;
71};
72
73struct msm_charger_event {
74 enum msm_hardware_charger_event event;
75 struct msm_hardware_charger *hw_chg;
76};
77
78struct msm_charger_mux {
79 int inited;
80 struct list_head msm_hardware_chargers;
81 int count_chargers;
82 struct mutex msm_hardware_chargers_lock;
83
84 struct device *dev;
85
86 unsigned int max_voltage;
87 unsigned int min_voltage;
88
89 unsigned int safety_time;
90 struct delayed_work teoc_work;
91
92 unsigned int update_time;
93 int stop_update;
94 struct delayed_work update_heartbeat_work;
95
96 struct mutex status_lock;
97 enum msm_battery_status batt_status;
98 struct msm_hardware_charger_priv *current_chg_priv;
99 struct msm_hardware_charger_priv *current_mon_priv;
100
101 unsigned int (*get_batt_capacity_percent) (void);
102
103 struct msm_charger_event *queue;
104 int tail;
105 int head;
106 spinlock_t queue_lock;
107 int queue_count;
108 struct work_struct queue_work;
109 struct workqueue_struct *event_wq_thread;
110 struct wake_lock wl;
111};
112
113static struct msm_charger_mux msm_chg;
114
115static struct msm_battery_gauge *msm_batt_gauge;
116
117static int is_chg_capable_of_charging(struct msm_hardware_charger_priv *priv)
118{
119 if (priv->hw_chg_state == CHG_READY_STATE
120 || priv->hw_chg_state == CHG_CHARGING_STATE)
121 return 1;
122
123 return 0;
124}
125
126static int is_batt_status_capable_of_charging(void)
127{
128 if (msm_chg.batt_status == BATT_STATUS_ABSENT
129 || msm_chg.batt_status == BATT_STATUS_TEMPERATURE_OUT_OF_RANGE
130 || msm_chg.batt_status == BATT_STATUS_ID_INVALID
131 || msm_chg.batt_status == BATT_STATUS_JUST_FINISHED_CHARGING)
132 return 0;
133 return 1;
134}
135
136static int is_batt_status_charging(void)
137{
138 if (msm_chg.batt_status == BATT_STATUS_TRKL_CHARGING
139 || msm_chg.batt_status == BATT_STATUS_FAST_CHARGING)
140 return 1;
141 return 0;
142}
143
144static int is_battery_present(void)
145{
146 if (msm_batt_gauge && msm_batt_gauge->is_battery_present)
147 return msm_batt_gauge->is_battery_present();
148 else {
149 pr_err("msm-charger: no batt gauge batt=absent\n");
150 return 0;
151 }
152}
153
154static int is_battery_temp_within_range(void)
155{
156 if (msm_batt_gauge && msm_batt_gauge->is_battery_temp_within_range)
157 return msm_batt_gauge->is_battery_temp_within_range();
158 else {
159 pr_err("msm-charger no batt gauge batt=out_of_temperatur\n");
160 return 0;
161 }
162}
163
164static int is_battery_id_valid(void)
165{
166 if (msm_batt_gauge && msm_batt_gauge->is_battery_id_valid)
167 return msm_batt_gauge->is_battery_id_valid();
168 else {
169 pr_err("msm-charger no batt gauge batt=id_invalid\n");
170 return 0;
171 }
172}
173
174static int get_prop_battery_mvolts(void)
175{
176 if (msm_batt_gauge && msm_batt_gauge->get_battery_mvolts)
177 return msm_batt_gauge->get_battery_mvolts();
178 else {
179 pr_err("msm-charger no batt gauge assuming 3.5V\n");
180 return MSM_CHARGER_GAUGE_MISSING_VOLTS;
181 }
182}
183
184static int get_battery_temperature(void)
185{
186 if (msm_batt_gauge && msm_batt_gauge->get_battery_temperature)
187 return msm_batt_gauge->get_battery_temperature();
188 else {
189 pr_err("msm-charger no batt gauge assuming 35 deg G\n");
190 return MSM_CHARGER_GAUGE_MISSING_TEMP;
191 }
192}
193
194static int get_prop_batt_capacity(void)
195{
196 if (msm_batt_gauge && msm_batt_gauge->get_batt_remaining_capacity)
197 return msm_batt_gauge->get_batt_remaining_capacity();
198
199 return msm_chg.get_batt_capacity_percent();
200}
201
202static int get_prop_batt_health(void)
203{
204 int status = 0;
205
206 if (msm_chg.batt_status == BATT_STATUS_TEMPERATURE_OUT_OF_RANGE)
207 status = POWER_SUPPLY_HEALTH_OVERHEAT;
208 else
209 status = POWER_SUPPLY_HEALTH_GOOD;
210
211 return status;
212}
213
214static int get_prop_charge_type(void)
215{
216 int status = 0;
217
218 if (msm_chg.batt_status == BATT_STATUS_TRKL_CHARGING)
219 status = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
220 else if (msm_chg.batt_status == BATT_STATUS_FAST_CHARGING)
221 status = POWER_SUPPLY_CHARGE_TYPE_FAST;
222 else
223 status = POWER_SUPPLY_CHARGE_TYPE_NONE;
224
225 return status;
226}
227
228static int get_prop_batt_status(void)
229{
230 int status = 0;
231
232 if (msm_batt_gauge && msm_batt_gauge->get_battery_status) {
233 status = msm_batt_gauge->get_battery_status();
234 if (status == POWER_SUPPLY_STATUS_CHARGING ||
235 status == POWER_SUPPLY_STATUS_FULL ||
236 status == POWER_SUPPLY_STATUS_DISCHARGING)
237 return status;
238 }
239
240 if (is_batt_status_charging())
241 status = POWER_SUPPLY_STATUS_CHARGING;
242 else if (msm_chg.batt_status ==
243 BATT_STATUS_JUST_FINISHED_CHARGING
244 && msm_chg.current_chg_priv != NULL)
245 status = POWER_SUPPLY_STATUS_FULL;
246 else
247 status = POWER_SUPPLY_STATUS_DISCHARGING;
248
249 return status;
250}
251
252 /* This function should only be called within handle_event or resume */
253static void update_batt_status(void)
254{
255 if (is_battery_present()) {
256 if (is_battery_id_valid()) {
257 if (msm_chg.batt_status == BATT_STATUS_ABSENT
258 || msm_chg.batt_status
259 == BATT_STATUS_ID_INVALID) {
260 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
261 }
262 } else
263 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
264 } else
265 msm_chg.batt_status = BATT_STATUS_ABSENT;
266}
267
268static enum power_supply_property msm_power_props[] = {
269 POWER_SUPPLY_PROP_PRESENT,
270 POWER_SUPPLY_PROP_ONLINE,
271};
272
273static char *msm_power_supplied_to[] = {
274 "battery",
275};
276
277static int msm_power_get_property(struct power_supply *psy,
278 enum power_supply_property psp,
279 union power_supply_propval *val)
280{
281 struct msm_hardware_charger_priv *priv;
282
283 priv = container_of(psy, struct msm_hardware_charger_priv, psy);
284 switch (psp) {
285 case POWER_SUPPLY_PROP_PRESENT:
286 val->intval = !(priv->hw_chg_state == CHG_ABSENT_STATE);
287 break;
288 case POWER_SUPPLY_PROP_ONLINE:
289 val->intval = (priv->hw_chg_state == CHG_READY_STATE)
290 || (priv->hw_chg_state == CHG_CHARGING_STATE);
291 break;
292 default:
293 return -EINVAL;
294 }
295 return 0;
296}
297
298static enum power_supply_property msm_batt_power_props[] = {
299 POWER_SUPPLY_PROP_STATUS,
300 POWER_SUPPLY_PROP_CHARGE_TYPE,
301 POWER_SUPPLY_PROP_HEALTH,
302 POWER_SUPPLY_PROP_PRESENT,
303 POWER_SUPPLY_PROP_TECHNOLOGY,
304 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
305 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
306 POWER_SUPPLY_PROP_VOLTAGE_NOW,
307 POWER_SUPPLY_PROP_CAPACITY,
308};
309
310static int msm_batt_power_get_property(struct power_supply *psy,
311 enum power_supply_property psp,
312 union power_supply_propval *val)
313{
314 switch (psp) {
315 case POWER_SUPPLY_PROP_STATUS:
316 val->intval = get_prop_batt_status();
317 break;
318 case POWER_SUPPLY_PROP_CHARGE_TYPE:
319 val->intval = get_prop_charge_type();
320 break;
321 case POWER_SUPPLY_PROP_HEALTH:
322 val->intval = get_prop_batt_health();
323 break;
324 case POWER_SUPPLY_PROP_PRESENT:
325 val->intval = !(msm_chg.batt_status == BATT_STATUS_ABSENT);
326 break;
327 case POWER_SUPPLY_PROP_TECHNOLOGY:
328 val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
329 break;
330 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
331 val->intval = msm_chg.max_voltage * 1000;
332 break;
333 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
334 val->intval = msm_chg.min_voltage * 1000;
335 break;
336 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
337 val->intval = get_prop_battery_mvolts();
338 break;
339 case POWER_SUPPLY_PROP_CAPACITY:
340 val->intval = get_prop_batt_capacity();
341 break;
342 default:
343 return -EINVAL;
344 }
345 return 0;
346}
347
348static struct power_supply msm_psy_batt = {
349 .name = "battery",
350 .type = POWER_SUPPLY_TYPE_BATTERY,
351 .properties = msm_batt_power_props,
352 .num_properties = ARRAY_SIZE(msm_batt_power_props),
353 .get_property = msm_batt_power_get_property,
354};
355
356static int usb_chg_current;
357static struct msm_hardware_charger_priv *usb_hw_chg_priv;
358static void (*notify_vbus_state_func_ptr)(int);
359static int usb_notified_of_insertion;
360
361/* this is passed to the hsusb via platform_data msm_otg_pdata */
362int msm_charger_register_vbus_sn(void (*callback)(int))
363{
364 pr_debug(KERN_INFO "%s\n", __func__);
365 notify_vbus_state_func_ptr = callback;
366 return 0;
367}
368
369/* this is passed to the hsusb via platform_data msm_otg_pdata */
370void msm_charger_unregister_vbus_sn(void (*callback)(int))
371{
372 pr_debug(KERN_INFO "%s\n", __func__);
373 notify_vbus_state_func_ptr = NULL;
374}
375
376static void notify_usb_of_the_plugin_event(struct msm_hardware_charger_priv
377 *hw_chg, int plugin)
378{
379 plugin = !!plugin;
380 if (plugin == 1 && usb_notified_of_insertion == 0) {
381 usb_notified_of_insertion = 1;
382 if (notify_vbus_state_func_ptr) {
383 dev_dbg(msm_chg.dev, "%s notifying plugin\n", __func__);
384 (*notify_vbus_state_func_ptr) (plugin);
385 } else
386 dev_dbg(msm_chg.dev, "%s unable to notify plugin\n",
387 __func__);
388 usb_hw_chg_priv = hw_chg;
389 }
390 if (plugin == 0 && usb_notified_of_insertion == 1) {
391 if (notify_vbus_state_func_ptr) {
392 dev_dbg(msm_chg.dev, "%s notifying unplugin\n",
393 __func__);
394 (*notify_vbus_state_func_ptr) (plugin);
395 } else
396 dev_dbg(msm_chg.dev, "%s unable to notify unplugin\n",
397 __func__);
398 usb_notified_of_insertion = 0;
399 usb_hw_chg_priv = NULL;
400 }
401}
402
403static unsigned int msm_chg_get_batt_capacity_percent(void)
404{
405 unsigned int current_voltage = get_prop_battery_mvolts();
406 unsigned int low_voltage = msm_chg.min_voltage;
407 unsigned int high_voltage = msm_chg.max_voltage;
408
409 if (current_voltage <= low_voltage)
410 return 0;
411 else if (current_voltage >= high_voltage)
412 return 100;
413 else
414 return (current_voltage - low_voltage) * 100
415 / (high_voltage - low_voltage);
416}
417
418#ifdef DEBUG
419static inline void debug_print(const char *func,
420 struct msm_hardware_charger_priv *hw_chg_priv)
421{
422 dev_dbg(msm_chg.dev,
423 "%s current=(%s)(s=%d)(r=%d) new=(%s)(s=%d)(r=%d) batt=%d En\n",
424 func,
425 msm_chg.current_chg_priv ? msm_chg.current_chg_priv->
426 hw_chg->name : "none",
427 msm_chg.current_chg_priv ? msm_chg.
428 current_chg_priv->hw_chg_state : -1,
429 msm_chg.current_chg_priv ? msm_chg.current_chg_priv->
430 hw_chg->rating : -1,
431 hw_chg_priv ? hw_chg_priv->hw_chg->name : "none",
432 hw_chg_priv ? hw_chg_priv->hw_chg_state : -1,
433 hw_chg_priv ? hw_chg_priv->hw_chg->rating : -1,
434 msm_chg.batt_status);
435}
436#else
437static inline void debug_print(const char *func,
438 struct msm_hardware_charger_priv *hw_chg_priv)
439{
440}
441#endif
442
443static struct msm_hardware_charger_priv *find_best_charger(void)
444{
445 struct msm_hardware_charger_priv *hw_chg_priv;
446 struct msm_hardware_charger_priv *better;
447 int rating;
448
449 better = NULL;
450 rating = 0;
451
452 list_for_each_entry(hw_chg_priv, &msm_chg.msm_hardware_chargers, list) {
453 if (is_chg_capable_of_charging(hw_chg_priv)) {
454 if (hw_chg_priv->hw_chg->rating > rating) {
455 rating = hw_chg_priv->hw_chg->rating;
456 better = hw_chg_priv;
457 }
458 }
459 }
460
461 return better;
462}
463
464static int msm_charging_switched(struct msm_hardware_charger_priv *priv)
465{
466 int ret = 0;
467
468 if (priv->hw_chg->charging_switched)
469 ret = priv->hw_chg->charging_switched(priv->hw_chg);
470 return ret;
471}
472
473static int msm_stop_charging(struct msm_hardware_charger_priv *priv)
474{
475 int ret;
476
477 ret = priv->hw_chg->stop_charging(priv->hw_chg);
478 if (!ret)
479 wake_unlock(&msm_chg.wl);
480 return ret;
481}
482
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700483static void msm_enable_system_current(struct msm_hardware_charger_priv *priv)
484{
485 if (priv->hw_chg->start_system_current)
486 priv->hw_chg->start_system_current(priv->hw_chg,
487 priv->max_source_current);
488}
489
490static void msm_disable_system_current(struct msm_hardware_charger_priv *priv)
491{
492 if (priv->hw_chg->stop_system_current)
493 priv->hw_chg->stop_system_current(priv->hw_chg);
494}
495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496/* the best charger has been selected -start charging from current_chg_priv */
497static int msm_start_charging(void)
498{
499 int ret;
500 struct msm_hardware_charger_priv *priv;
501
502 priv = msm_chg.current_chg_priv;
503 wake_lock(&msm_chg.wl);
504 ret = priv->hw_chg->start_charging(priv->hw_chg, msm_chg.max_voltage,
505 priv->max_source_current);
506 if (ret) {
507 wake_unlock(&msm_chg.wl);
508 dev_err(msm_chg.dev, "%s couldnt start chg error = %d\n",
509 priv->hw_chg->name, ret);
510 } else
511 priv->hw_chg_state = CHG_CHARGING_STATE;
512
513 return ret;
514}
515
516static void handle_charging_done(struct msm_hardware_charger_priv *priv)
517{
518 if (msm_chg.current_chg_priv == priv) {
519 if (msm_chg.current_chg_priv->hw_chg_state ==
520 CHG_CHARGING_STATE)
521 if (msm_stop_charging(msm_chg.current_chg_priv)) {
522 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
523 msm_chg.current_chg_priv->hw_chg->name);
524 }
525 msm_chg.current_chg_priv->hw_chg_state = CHG_READY_STATE;
526
527 msm_chg.batt_status = BATT_STATUS_JUST_FINISHED_CHARGING;
528 dev_info(msm_chg.dev, "%s: stopping safety timer work\n",
529 __func__);
530 cancel_delayed_work(&msm_chg.teoc_work);
531
532 if (msm_batt_gauge && msm_batt_gauge->monitor_for_recharging)
533 msm_batt_gauge->monitor_for_recharging();
534 else
535 dev_err(msm_chg.dev,
536 "%s: no batt gauge recharge monitor\n", __func__);
537 }
538}
539
540static void teoc(struct work_struct *work)
541{
542 /* we have been charging too long - stop charging */
543 dev_info(msm_chg.dev, "%s: safety timer work expired\n", __func__);
544
545 mutex_lock(&msm_chg.status_lock);
546 if (msm_chg.current_chg_priv != NULL
547 && msm_chg.current_chg_priv->hw_chg_state == CHG_CHARGING_STATE) {
548 handle_charging_done(msm_chg.current_chg_priv);
549 }
550 mutex_unlock(&msm_chg.status_lock);
551}
552
553static void handle_battery_inserted(void)
554{
555 /* if a charger is already present start charging */
556 if (msm_chg.current_chg_priv != NULL &&
557 is_batt_status_capable_of_charging() &&
558 !is_batt_status_charging()) {
559 if (msm_start_charging()) {
560 dev_err(msm_chg.dev, "%s couldnt start chg\n",
561 msm_chg.current_chg_priv->hw_chg->name);
562 return;
563 }
564 msm_chg.batt_status = BATT_STATUS_TRKL_CHARGING;
565
566 dev_info(msm_chg.dev, "%s: starting safety timer work\n",
567 __func__);
568 queue_delayed_work(msm_chg.event_wq_thread,
569 &msm_chg.teoc_work,
570 round_jiffies_relative(msecs_to_jiffies
571 (msm_chg.
572 safety_time)));
573 }
574}
575
576static void handle_battery_removed(void)
577{
578 /* if a charger is charging the battery stop it */
579 if (msm_chg.current_chg_priv != NULL
580 && msm_chg.current_chg_priv->hw_chg_state == CHG_CHARGING_STATE) {
581 if (msm_stop_charging(msm_chg.current_chg_priv)) {
582 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
583 msm_chg.current_chg_priv->hw_chg->name);
584 }
585 msm_chg.current_chg_priv->hw_chg_state = CHG_READY_STATE;
586
587 dev_info(msm_chg.dev, "%s: stopping safety timer work\n",
588 __func__);
589 cancel_delayed_work(&msm_chg.teoc_work);
590 }
591}
592
593static void update_heartbeat(struct work_struct *work)
594{
595 int temperature;
596
597 if (msm_chg.batt_status == BATT_STATUS_ABSENT
598 || msm_chg.batt_status == BATT_STATUS_ID_INVALID) {
599 if (is_battery_present())
600 if (is_battery_id_valid()) {
601 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
602 handle_battery_inserted();
603 }
604 } else {
605 if (!is_battery_present()) {
606 msm_chg.batt_status = BATT_STATUS_ABSENT;
607 handle_battery_removed();
608 }
609 /*
610 * check battery id because a good battery could be removed
611 * and replaced with a invalid battery.
612 */
613 if (!is_battery_id_valid()) {
614 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
615 handle_battery_removed();
616 }
617 }
618 pr_debug("msm-charger %s batt_status= %d\n",
619 __func__, msm_chg.batt_status);
620
621 if (msm_chg.current_chg_priv
622 && msm_chg.current_chg_priv->hw_chg_state
623 == CHG_CHARGING_STATE) {
624 temperature = get_battery_temperature();
625 /* TODO implement JEITA SPEC*/
626 }
627
628 /* notify that the voltage has changed
629 * the read of the capacity will trigger a
630 * voltage read*/
631 power_supply_changed(&msm_psy_batt);
632
633 if (msm_chg.stop_update) {
634 msm_chg.stop_update = 0;
635 return;
636 }
637 queue_delayed_work(msm_chg.event_wq_thread,
638 &msm_chg.update_heartbeat_work,
639 round_jiffies_relative(msecs_to_jiffies
640 (msm_chg.update_time)));
641}
642
643/* set the charger state to READY before calling this */
644static void handle_charger_ready(struct msm_hardware_charger_priv *hw_chg_priv)
645{
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700646 struct msm_hardware_charger_priv *old_chg_priv = NULL;
647
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648 debug_print(__func__, hw_chg_priv);
649
650 if (msm_chg.current_chg_priv != NULL
651 && hw_chg_priv->hw_chg->rating >
652 msm_chg.current_chg_priv->hw_chg->rating) {
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700653 /*
654 * a better charger was found, ask the current charger
655 * to stop charging if it was charging
656 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 if (msm_chg.current_chg_priv->hw_chg_state ==
658 CHG_CHARGING_STATE) {
659 if (msm_stop_charging(msm_chg.current_chg_priv)) {
660 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
661 msm_chg.current_chg_priv->hw_chg->name);
662 return;
663 }
664 if (msm_charging_switched(msm_chg.current_chg_priv)) {
665 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
666 msm_chg.current_chg_priv->hw_chg->name);
667 return;
668 }
669 }
670 msm_chg.current_chg_priv->hw_chg_state = CHG_READY_STATE;
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700671 old_chg_priv = msm_chg.current_chg_priv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672 msm_chg.current_chg_priv = NULL;
673 }
674
675 if (msm_chg.current_chg_priv == NULL) {
676 msm_chg.current_chg_priv = hw_chg_priv;
677 dev_info(msm_chg.dev,
678 "%s: best charger = %s\n", __func__,
679 msm_chg.current_chg_priv->hw_chg->name);
680
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700681 msm_enable_system_current(msm_chg.current_chg_priv);
682 /*
683 * since a better charger was chosen, ask the old
684 * charger to stop providing system current
685 */
686 if (old_chg_priv != NULL)
687 msm_disable_system_current(old_chg_priv);
688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 if (!is_batt_status_capable_of_charging())
690 return;
691
692 /* start charging from the new charger */
693 if (!msm_start_charging()) {
694 /* if we simply switched chg continue with teoc timer
695 * else we update the batt state and set the teoc
696 * timer */
697 if (!is_batt_status_charging()) {
698 dev_info(msm_chg.dev,
699 "%s: starting safety timer\n", __func__);
700 queue_delayed_work(msm_chg.event_wq_thread,
701 &msm_chg.teoc_work,
702 round_jiffies_relative
703 (msecs_to_jiffies
704 (msm_chg.safety_time)));
705 msm_chg.batt_status = BATT_STATUS_TRKL_CHARGING;
706 }
707 } else {
708 /* we couldnt start charging from the new readied
709 * charger */
710 if (is_batt_status_charging())
711 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
712 }
713 }
714}
715
716static void handle_charger_removed(struct msm_hardware_charger_priv
717 *hw_chg_removed, int new_state)
718{
719 struct msm_hardware_charger_priv *hw_chg_priv;
720
721 debug_print(__func__, hw_chg_removed);
722
723 if (msm_chg.current_chg_priv == hw_chg_removed) {
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700724 msm_disable_system_current(hw_chg_removed);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725 if (msm_chg.current_chg_priv->hw_chg_state
726 == CHG_CHARGING_STATE) {
727 if (msm_stop_charging(hw_chg_removed)) {
728 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
729 msm_chg.current_chg_priv->hw_chg->name);
730 }
731 }
732 msm_chg.current_chg_priv = NULL;
733 }
734
735 hw_chg_removed->hw_chg_state = new_state;
736
737 if (msm_chg.current_chg_priv == NULL) {
738 hw_chg_priv = find_best_charger();
739 if (hw_chg_priv == NULL) {
740 dev_info(msm_chg.dev, "%s: no chargers\n", __func__);
741 /* if the battery was Just finished charging
742 * we keep that state as is so that we dont rush
743 * in to charging the battery when a charger is
744 * plugged in shortly. */
745 if (is_batt_status_charging())
746 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
747 } else {
748 msm_chg.current_chg_priv = hw_chg_priv;
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700749 msm_enable_system_current(hw_chg_priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 dev_info(msm_chg.dev,
751 "%s: best charger = %s\n", __func__,
752 msm_chg.current_chg_priv->hw_chg->name);
753
754 if (!is_batt_status_capable_of_charging())
755 return;
756
757 if (msm_start_charging()) {
758 /* we couldnt start charging for some reason */
759 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
760 }
761 }
762 }
763
764 /* if we arent charging stop the safety timer */
765 if (!is_batt_status_charging()) {
766 dev_info(msm_chg.dev, "%s: stopping safety timer work\n",
767 __func__);
768 cancel_delayed_work(&msm_chg.teoc_work);
769 }
770}
771
772static void handle_event(struct msm_hardware_charger *hw_chg, int event)
773{
774 struct msm_hardware_charger_priv *priv = NULL;
775
776 /*
777 * if hw_chg is NULL then this event comes from non-charger
778 * parties like battery gauge
779 */
780 if (hw_chg)
781 priv = hw_chg->charger_private;
782
783 mutex_lock(&msm_chg.status_lock);
784
785 switch (event) {
786 case CHG_INSERTED_EVENT:
787 if (priv->hw_chg_state != CHG_ABSENT_STATE) {
788 dev_info(msm_chg.dev,
789 "%s insertion detected when cbl present",
790 hw_chg->name);
791 break;
792 }
793 update_batt_status();
794 if (hw_chg->type == CHG_TYPE_USB) {
795 priv->hw_chg_state = CHG_PRESENT_STATE;
796 notify_usb_of_the_plugin_event(priv, 1);
797 if (usb_chg_current) {
798 priv->max_source_current = usb_chg_current;
799 usb_chg_current = 0;
800 /* usb has already indicated us to charge */
801 priv->hw_chg_state = CHG_READY_STATE;
802 handle_charger_ready(priv);
803 }
804 } else {
805 priv->hw_chg_state = CHG_READY_STATE;
806 handle_charger_ready(priv);
807 }
808 break;
809 case CHG_ENUMERATED_EVENT: /* only in USB types */
810 if (priv->hw_chg_state == CHG_ABSENT_STATE) {
811 dev_info(msm_chg.dev, "%s enum withuot presence\n",
812 hw_chg->name);
813 break;
814 }
815 update_batt_status();
816 dev_dbg(msm_chg.dev, "%s enum with %dmA to draw\n",
817 hw_chg->name, priv->max_source_current);
818 if (priv->max_source_current == 0) {
819 /* usb subsystem doesnt want us to draw
820 * charging current */
821 /* act as if the charge is removed */
822 if (priv->hw_chg_state != CHG_PRESENT_STATE)
823 handle_charger_removed(priv, CHG_PRESENT_STATE);
824 } else {
825 if (priv->hw_chg_state != CHG_READY_STATE) {
826 priv->hw_chg_state = CHG_READY_STATE;
827 handle_charger_ready(priv);
828 }
829 }
830 break;
831 case CHG_REMOVED_EVENT:
832 if (priv->hw_chg_state == CHG_ABSENT_STATE) {
833 dev_info(msm_chg.dev, "%s cable already removed\n",
834 hw_chg->name);
835 break;
836 }
837 update_batt_status();
838 if (hw_chg->type == CHG_TYPE_USB) {
839 usb_chg_current = 0;
840 notify_usb_of_the_plugin_event(priv, 0);
841 }
842 handle_charger_removed(priv, CHG_ABSENT_STATE);
843 break;
844 case CHG_DONE_EVENT:
845 if (priv->hw_chg_state == CHG_CHARGING_STATE)
846 handle_charging_done(priv);
847 break;
848 case CHG_BATT_BEGIN_FAST_CHARGING:
849 /* only update if we are TRKL charging */
850 if (msm_chg.batt_status == BATT_STATUS_TRKL_CHARGING)
851 msm_chg.batt_status = BATT_STATUS_FAST_CHARGING;
852 break;
853 case CHG_BATT_NEEDS_RECHARGING:
854 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
855 handle_battery_inserted();
856 priv = msm_chg.current_chg_priv;
857 break;
858 case CHG_BATT_TEMP_OUTOFRANGE:
859 /* the batt_temp out of range can trigger
860 * when the battery is absent */
861 if (!is_battery_present()
862 && msm_chg.batt_status != BATT_STATUS_ABSENT) {
863 msm_chg.batt_status = BATT_STATUS_ABSENT;
864 handle_battery_removed();
865 break;
866 }
867 if (msm_chg.batt_status == BATT_STATUS_TEMPERATURE_OUT_OF_RANGE)
868 break;
869 msm_chg.batt_status = BATT_STATUS_TEMPERATURE_OUT_OF_RANGE;
870 handle_battery_removed();
871 break;
872 case CHG_BATT_TEMP_INRANGE:
873 if (msm_chg.batt_status != BATT_STATUS_TEMPERATURE_OUT_OF_RANGE)
874 break;
875 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
876 /* check id */
877 if (!is_battery_id_valid())
878 break;
879 /* assume that we are discharging from the battery
880 * and act as if the battery was inserted
881 * if a charger is present charging will be resumed */
882 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
883 handle_battery_inserted();
884 break;
885 case CHG_BATT_INSERTED:
886 if (msm_chg.batt_status != BATT_STATUS_ABSENT)
887 break;
888 /* debounce */
889 if (!is_battery_present())
890 break;
891 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
892 if (!is_battery_id_valid())
893 break;
894 /* assume that we are discharging from the battery */
895 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
896 /* check if a charger is present */
897 handle_battery_inserted();
898 break;
899 case CHG_BATT_REMOVED:
900 if (msm_chg.batt_status == BATT_STATUS_ABSENT)
901 break;
902 /* debounce */
903 if (is_battery_present())
904 break;
905 msm_chg.batt_status = BATT_STATUS_ABSENT;
906 handle_battery_removed();
907 break;
908 case CHG_BATT_STATUS_CHANGE:
909 /* TODO battery SOC like battery-alarm/charging-full features
910 can be added here for future improvement */
911 break;
912 }
913 dev_dbg(msm_chg.dev, "%s %d done batt_status=%d\n", __func__,
914 event, msm_chg.batt_status);
915
916 /* update userspace */
917 if (msm_batt_gauge)
918 power_supply_changed(&msm_psy_batt);
919 if (priv)
920 power_supply_changed(&priv->psy);
921
922 mutex_unlock(&msm_chg.status_lock);
923}
924
925static int msm_chg_dequeue_event(struct msm_charger_event **event)
926{
927 unsigned long flags;
928
929 spin_lock_irqsave(&msm_chg.queue_lock, flags);
930 if (msm_chg.queue_count == 0) {
931 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
932 return -EINVAL;
933 }
934 *event = &msm_chg.queue[msm_chg.head];
935 msm_chg.head = (msm_chg.head + 1) % MSM_CHG_MAX_EVENTS;
936 pr_debug("%s dequeueing %d\n", __func__, (*event)->event);
937 msm_chg.queue_count--;
938 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
939 return 0;
940}
941
942static int msm_chg_enqueue_event(struct msm_hardware_charger *hw_chg,
943 enum msm_hardware_charger_event event)
944{
945 unsigned long flags;
946
947 spin_lock_irqsave(&msm_chg.queue_lock, flags);
948 if (msm_chg.queue_count == MSM_CHG_MAX_EVENTS) {
949 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
950 pr_err("%s: queue full cannot enqueue %d\n",
951 __func__, event);
952 return -EAGAIN;
953 }
954 pr_debug("%s queueing %d\n", __func__, event);
955 msm_chg.queue[msm_chg.tail].event = event;
956 msm_chg.queue[msm_chg.tail].hw_chg = hw_chg;
957 msm_chg.tail = (msm_chg.tail + 1)%MSM_CHG_MAX_EVENTS;
958 msm_chg.queue_count++;
959 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
960 return 0;
961}
962
963static void process_events(struct work_struct *work)
964{
965 struct msm_charger_event *event;
966 int rc;
967
968 do {
969 rc = msm_chg_dequeue_event(&event);
970 if (!rc)
971 handle_event(event->hw_chg, event->event);
972 } while (!rc);
973}
974
975/* USB calls these to tell us how much charging current we should draw */
976void msm_charger_vbus_draw(unsigned int mA)
977{
978 if (usb_hw_chg_priv) {
979 usb_hw_chg_priv->max_source_current = mA;
980 msm_charger_notify_event(usb_hw_chg_priv->hw_chg,
981 CHG_ENUMERATED_EVENT);
982 } else
983 /* remember the current, to be used when charger is ready */
984 usb_chg_current = mA;
985}
986
987static int __init determine_initial_batt_status(void)
988{
989 int rc;
990
991 if (is_battery_present())
992 if (is_battery_id_valid())
993 if (is_battery_temp_within_range())
994 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
995 else
996 msm_chg.batt_status
997 = BATT_STATUS_TEMPERATURE_OUT_OF_RANGE;
998 else
999 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
1000 else
1001 msm_chg.batt_status = BATT_STATUS_ABSENT;
1002
1003 if (is_batt_status_capable_of_charging())
1004 handle_battery_inserted();
1005
1006 rc = power_supply_register(msm_chg.dev, &msm_psy_batt);
1007 if (rc < 0) {
1008 dev_err(msm_chg.dev, "%s: power_supply_register failed"
1009 " rc=%d\n", __func__, rc);
1010 return rc;
1011 }
1012
1013 /* start updaing the battery powersupply every msm_chg.update_time
1014 * milliseconds */
1015 queue_delayed_work(msm_chg.event_wq_thread,
1016 &msm_chg.update_heartbeat_work,
1017 round_jiffies_relative(msecs_to_jiffies
1018 (msm_chg.update_time)));
1019
1020 pr_debug("%s:OK batt_status=%d\n", __func__, msm_chg.batt_status);
1021 return 0;
1022}
1023
1024static int __devinit msm_charger_probe(struct platform_device *pdev)
1025{
1026 msm_chg.dev = &pdev->dev;
1027 if (pdev->dev.platform_data) {
1028 unsigned int milli_secs;
1029
1030 struct msm_charger_platform_data *pdata
1031 =
1032 (struct msm_charger_platform_data *)pdev->dev.platform_data;
1033
1034 milli_secs = pdata->safety_time * 60 * MSEC_PER_SEC;
1035 if (milli_secs > jiffies_to_msecs(MAX_JIFFY_OFFSET)) {
1036 dev_warn(&pdev->dev, "%s: safety time too large"
1037 "%dms\n", __func__, milli_secs);
1038 milli_secs = jiffies_to_msecs(MAX_JIFFY_OFFSET);
1039 }
1040 msm_chg.safety_time = milli_secs;
1041
1042 milli_secs = pdata->update_time * 60 * MSEC_PER_SEC;
1043 if (milli_secs > jiffies_to_msecs(MAX_JIFFY_OFFSET)) {
1044 dev_warn(&pdev->dev, "%s: safety time too large"
1045 "%dms\n", __func__, milli_secs);
1046 milli_secs = jiffies_to_msecs(MAX_JIFFY_OFFSET);
1047 }
1048 msm_chg.update_time = milli_secs;
1049
1050 msm_chg.max_voltage = pdata->max_voltage;
1051 msm_chg.min_voltage = pdata->min_voltage;
1052 msm_chg.get_batt_capacity_percent =
1053 pdata->get_batt_capacity_percent;
1054 }
1055 if (msm_chg.safety_time == 0)
1056 msm_chg.safety_time = CHARGING_TEOC_MS;
1057 if (msm_chg.update_time == 0)
1058 msm_chg.update_time = UPDATE_TIME_MS;
1059 if (msm_chg.max_voltage == 0)
1060 msm_chg.max_voltage = DEFAULT_BATT_MAX_V;
1061 if (msm_chg.min_voltage == 0)
1062 msm_chg.min_voltage = DEFAULT_BATT_MIN_V;
1063 if (msm_chg.get_batt_capacity_percent == NULL)
1064 msm_chg.get_batt_capacity_percent =
1065 msm_chg_get_batt_capacity_percent;
1066
1067 mutex_init(&msm_chg.status_lock);
1068 INIT_DELAYED_WORK(&msm_chg.teoc_work, teoc);
1069 INIT_DELAYED_WORK(&msm_chg.update_heartbeat_work, update_heartbeat);
1070
1071 wake_lock_init(&msm_chg.wl, WAKE_LOCK_SUSPEND, "msm_charger");
1072 return 0;
1073}
1074
1075static int __devexit msm_charger_remove(struct platform_device *pdev)
1076{
Abhijeet Dharmapurikar0f828242011-07-11 12:12:25 -07001077 wake_lock_destroy(&msm_chg.wl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 mutex_destroy(&msm_chg.status_lock);
1079 power_supply_unregister(&msm_psy_batt);
1080 return 0;
1081}
1082
1083int msm_charger_notify_event(struct msm_hardware_charger *hw_chg,
1084 enum msm_hardware_charger_event event)
1085{
1086 msm_chg_enqueue_event(hw_chg, event);
1087 queue_work(msm_chg.event_wq_thread, &msm_chg.queue_work);
1088 return 0;
1089}
1090EXPORT_SYMBOL(msm_charger_notify_event);
1091
1092int msm_charger_register(struct msm_hardware_charger *hw_chg)
1093{
1094 struct msm_hardware_charger_priv *priv;
1095 int rc = 0;
1096
1097 if (!msm_chg.inited) {
1098 pr_err("%s: msm_chg is NULL,Too early to register\n", __func__);
1099 return -EAGAIN;
1100 }
1101
1102 if (hw_chg->start_charging == NULL
1103 || hw_chg->stop_charging == NULL
1104 || hw_chg->name == NULL
1105 || hw_chg->rating == 0) {
1106 pr_err("%s: invalid hw_chg\n", __func__);
1107 return -EINVAL;
1108 }
1109
1110 priv = kzalloc(sizeof *priv, GFP_KERNEL);
1111 if (priv == NULL) {
1112 dev_err(msm_chg.dev, "%s kzalloc failed\n", __func__);
1113 return -ENOMEM;
1114 }
1115
1116 priv->psy.name = hw_chg->name;
1117 if (hw_chg->type == CHG_TYPE_USB)
1118 priv->psy.type = POWER_SUPPLY_TYPE_USB;
1119 else
1120 priv->psy.type = POWER_SUPPLY_TYPE_MAINS;
1121
1122 priv->psy.supplied_to = msm_power_supplied_to;
1123 priv->psy.num_supplicants = ARRAY_SIZE(msm_power_supplied_to);
1124 priv->psy.properties = msm_power_props;
1125 priv->psy.num_properties = ARRAY_SIZE(msm_power_props);
1126 priv->psy.get_property = msm_power_get_property;
1127
1128 rc = power_supply_register(NULL, &priv->psy);
1129 if (rc) {
1130 dev_err(msm_chg.dev, "%s power_supply_register failed\n",
1131 __func__);
1132 goto out;
1133 }
1134
1135 priv->hw_chg = hw_chg;
1136 priv->hw_chg_state = CHG_ABSENT_STATE;
1137 INIT_LIST_HEAD(&priv->list);
1138 mutex_lock(&msm_chg.msm_hardware_chargers_lock);
1139 list_add_tail(&priv->list, &msm_chg.msm_hardware_chargers);
1140 mutex_unlock(&msm_chg.msm_hardware_chargers_lock);
1141 hw_chg->charger_private = (void *)priv;
1142 return 0;
1143
1144out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 kfree(priv);
1146 return rc;
1147}
1148EXPORT_SYMBOL(msm_charger_register);
1149
1150void msm_battery_gauge_register(struct msm_battery_gauge *batt_gauge)
1151{
1152 if (msm_batt_gauge) {
1153 msm_batt_gauge = batt_gauge;
1154 pr_err("msm-charger %s multiple battery gauge called\n",
1155 __func__);
1156 } else {
1157 msm_batt_gauge = batt_gauge;
1158 determine_initial_batt_status();
1159 }
1160}
1161EXPORT_SYMBOL(msm_battery_gauge_register);
1162
1163void msm_battery_gauge_unregister(struct msm_battery_gauge *batt_gauge)
1164{
1165 msm_batt_gauge = NULL;
1166}
1167EXPORT_SYMBOL(msm_battery_gauge_unregister);
1168
1169int msm_charger_unregister(struct msm_hardware_charger *hw_chg)
1170{
1171 struct msm_hardware_charger_priv *priv;
1172
1173 priv = (struct msm_hardware_charger_priv *)(hw_chg->charger_private);
1174 mutex_lock(&msm_chg.msm_hardware_chargers_lock);
1175 list_del(&priv->list);
1176 mutex_unlock(&msm_chg.msm_hardware_chargers_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 power_supply_unregister(&priv->psy);
1178 kfree(priv);
1179 return 0;
1180}
1181EXPORT_SYMBOL(msm_charger_unregister);
1182
1183static int msm_charger_suspend(struct device *dev)
1184{
1185 dev_dbg(msm_chg.dev, "%s suspended\n", __func__);
1186 msm_chg.stop_update = 1;
1187 cancel_delayed_work(&msm_chg.update_heartbeat_work);
1188 mutex_lock(&msm_chg.status_lock);
1189 handle_battery_removed();
1190 mutex_unlock(&msm_chg.status_lock);
1191 return 0;
1192}
1193
1194static int msm_charger_resume(struct device *dev)
1195{
1196 dev_dbg(msm_chg.dev, "%s resumed\n", __func__);
1197 msm_chg.stop_update = 0;
1198 /* start updaing the battery powersupply every msm_chg.update_time
1199 * milliseconds */
1200 queue_delayed_work(msm_chg.event_wq_thread,
1201 &msm_chg.update_heartbeat_work,
1202 round_jiffies_relative(msecs_to_jiffies
1203 (msm_chg.update_time)));
1204 mutex_lock(&msm_chg.status_lock);
1205 handle_battery_inserted();
1206 mutex_unlock(&msm_chg.status_lock);
1207 return 0;
1208}
1209
1210static SIMPLE_DEV_PM_OPS(msm_charger_pm_ops,
1211 msm_charger_suspend, msm_charger_resume);
1212
1213static struct platform_driver msm_charger_driver = {
1214 .probe = msm_charger_probe,
1215 .remove = __devexit_p(msm_charger_remove),
1216 .driver = {
1217 .name = "msm-charger",
1218 .owner = THIS_MODULE,
1219 .pm = &msm_charger_pm_ops,
1220 },
1221};
1222
1223static int __init msm_charger_init(void)
1224{
1225 int rc;
1226
1227 INIT_LIST_HEAD(&msm_chg.msm_hardware_chargers);
1228 msm_chg.count_chargers = 0;
1229 mutex_init(&msm_chg.msm_hardware_chargers_lock);
1230
1231 msm_chg.queue = kzalloc(sizeof(struct msm_charger_event)
1232 * MSM_CHG_MAX_EVENTS,
1233 GFP_KERNEL);
1234 if (!msm_chg.queue) {
1235 rc = -ENOMEM;
1236 goto out;
1237 }
1238 msm_chg.tail = 0;
1239 msm_chg.head = 0;
1240 spin_lock_init(&msm_chg.queue_lock);
1241 msm_chg.queue_count = 0;
1242 INIT_WORK(&msm_chg.queue_work, process_events);
1243 msm_chg.event_wq_thread = create_workqueue("msm_charger_eventd");
1244 if (!msm_chg.event_wq_thread) {
1245 rc = -ENOMEM;
1246 goto free_queue;
1247 }
1248 rc = platform_driver_register(&msm_charger_driver);
1249 if (rc < 0) {
1250 pr_err("%s: FAIL: platform_driver_register. rc = %d\n",
1251 __func__, rc);
1252 goto destroy_wq_thread;
1253 }
1254 msm_chg.inited = 1;
1255 return 0;
1256
1257destroy_wq_thread:
1258 destroy_workqueue(msm_chg.event_wq_thread);
1259free_queue:
1260 kfree(msm_chg.queue);
1261out:
1262 return rc;
1263}
1264
1265static void __exit msm_charger_exit(void)
1266{
1267 flush_workqueue(msm_chg.event_wq_thread);
1268 destroy_workqueue(msm_chg.event_wq_thread);
1269 kfree(msm_chg.queue);
1270 platform_driver_unregister(&msm_charger_driver);
1271}
1272
1273module_init(msm_charger_init);
1274module_exit(msm_charger_exit);
1275
1276MODULE_LICENSE("GPL v2");
1277MODULE_AUTHOR("Abhijeet Dharmapurikar <adharmap@codeaurora.org>");
1278MODULE_DESCRIPTION("Battery driver for Qualcomm MSM chipsets.");
1279MODULE_VERSION("1.0");