blob: 29dc726812beab52a03338d04a2350cc016678fb [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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{
Abhijeet Dharmapurikar35bb9402011-08-30 20:03:14 -0700196 int capacity;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
Abhijeet Dharmapurikar35bb9402011-08-30 20:03:14 -0700198 if (msm_batt_gauge && msm_batt_gauge->get_batt_remaining_capacity)
199 capacity = msm_batt_gauge->get_batt_remaining_capacity();
200 else
201 capacity = msm_chg.get_batt_capacity_percent();
202
203 if (capacity <= 10)
204 pr_err("battery capacity very low = %d\n", capacity);
205
206 return capacity;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207}
208
209static int get_prop_batt_health(void)
210{
211 int status = 0;
212
213 if (msm_chg.batt_status == BATT_STATUS_TEMPERATURE_OUT_OF_RANGE)
214 status = POWER_SUPPLY_HEALTH_OVERHEAT;
215 else
216 status = POWER_SUPPLY_HEALTH_GOOD;
217
218 return status;
219}
220
221static int get_prop_charge_type(void)
222{
223 int status = 0;
224
225 if (msm_chg.batt_status == BATT_STATUS_TRKL_CHARGING)
226 status = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
227 else if (msm_chg.batt_status == BATT_STATUS_FAST_CHARGING)
228 status = POWER_SUPPLY_CHARGE_TYPE_FAST;
229 else
230 status = POWER_SUPPLY_CHARGE_TYPE_NONE;
231
232 return status;
233}
234
235static int get_prop_batt_status(void)
236{
237 int status = 0;
238
239 if (msm_batt_gauge && msm_batt_gauge->get_battery_status) {
240 status = msm_batt_gauge->get_battery_status();
241 if (status == POWER_SUPPLY_STATUS_CHARGING ||
242 status == POWER_SUPPLY_STATUS_FULL ||
243 status == POWER_SUPPLY_STATUS_DISCHARGING)
244 return status;
245 }
246
247 if (is_batt_status_charging())
248 status = POWER_SUPPLY_STATUS_CHARGING;
249 else if (msm_chg.batt_status ==
250 BATT_STATUS_JUST_FINISHED_CHARGING
251 && msm_chg.current_chg_priv != NULL)
252 status = POWER_SUPPLY_STATUS_FULL;
253 else
254 status = POWER_SUPPLY_STATUS_DISCHARGING;
255
256 return status;
257}
258
259 /* This function should only be called within handle_event or resume */
260static void update_batt_status(void)
261{
262 if (is_battery_present()) {
263 if (is_battery_id_valid()) {
264 if (msm_chg.batt_status == BATT_STATUS_ABSENT
265 || msm_chg.batt_status
266 == BATT_STATUS_ID_INVALID) {
267 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
268 }
269 } else
270 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
271 } else
272 msm_chg.batt_status = BATT_STATUS_ABSENT;
273}
274
275static enum power_supply_property msm_power_props[] = {
276 POWER_SUPPLY_PROP_PRESENT,
277 POWER_SUPPLY_PROP_ONLINE,
278};
279
280static char *msm_power_supplied_to[] = {
281 "battery",
282};
283
284static int msm_power_get_property(struct power_supply *psy,
285 enum power_supply_property psp,
286 union power_supply_propval *val)
287{
288 struct msm_hardware_charger_priv *priv;
289
290 priv = container_of(psy, struct msm_hardware_charger_priv, psy);
291 switch (psp) {
292 case POWER_SUPPLY_PROP_PRESENT:
293 val->intval = !(priv->hw_chg_state == CHG_ABSENT_STATE);
294 break;
295 case POWER_SUPPLY_PROP_ONLINE:
296 val->intval = (priv->hw_chg_state == CHG_READY_STATE)
297 || (priv->hw_chg_state == CHG_CHARGING_STATE);
298 break;
299 default:
300 return -EINVAL;
301 }
302 return 0;
303}
304
305static enum power_supply_property msm_batt_power_props[] = {
306 POWER_SUPPLY_PROP_STATUS,
307 POWER_SUPPLY_PROP_CHARGE_TYPE,
308 POWER_SUPPLY_PROP_HEALTH,
309 POWER_SUPPLY_PROP_PRESENT,
310 POWER_SUPPLY_PROP_TECHNOLOGY,
311 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
312 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
313 POWER_SUPPLY_PROP_VOLTAGE_NOW,
314 POWER_SUPPLY_PROP_CAPACITY,
315};
316
317static int msm_batt_power_get_property(struct power_supply *psy,
318 enum power_supply_property psp,
319 union power_supply_propval *val)
320{
321 switch (psp) {
322 case POWER_SUPPLY_PROP_STATUS:
323 val->intval = get_prop_batt_status();
324 break;
325 case POWER_SUPPLY_PROP_CHARGE_TYPE:
326 val->intval = get_prop_charge_type();
327 break;
328 case POWER_SUPPLY_PROP_HEALTH:
329 val->intval = get_prop_batt_health();
330 break;
331 case POWER_SUPPLY_PROP_PRESENT:
332 val->intval = !(msm_chg.batt_status == BATT_STATUS_ABSENT);
333 break;
334 case POWER_SUPPLY_PROP_TECHNOLOGY:
335 val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
336 break;
337 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
338 val->intval = msm_chg.max_voltage * 1000;
339 break;
340 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
341 val->intval = msm_chg.min_voltage * 1000;
342 break;
343 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
344 val->intval = get_prop_battery_mvolts();
345 break;
346 case POWER_SUPPLY_PROP_CAPACITY:
347 val->intval = get_prop_batt_capacity();
348 break;
349 default:
350 return -EINVAL;
351 }
352 return 0;
353}
354
355static struct power_supply msm_psy_batt = {
356 .name = "battery",
357 .type = POWER_SUPPLY_TYPE_BATTERY,
358 .properties = msm_batt_power_props,
359 .num_properties = ARRAY_SIZE(msm_batt_power_props),
360 .get_property = msm_batt_power_get_property,
361};
362
363static int usb_chg_current;
364static struct msm_hardware_charger_priv *usb_hw_chg_priv;
365static void (*notify_vbus_state_func_ptr)(int);
366static int usb_notified_of_insertion;
367
368/* this is passed to the hsusb via platform_data msm_otg_pdata */
369int msm_charger_register_vbus_sn(void (*callback)(int))
370{
371 pr_debug(KERN_INFO "%s\n", __func__);
372 notify_vbus_state_func_ptr = callback;
373 return 0;
374}
375
376/* this is passed to the hsusb via platform_data msm_otg_pdata */
377void msm_charger_unregister_vbus_sn(void (*callback)(int))
378{
379 pr_debug(KERN_INFO "%s\n", __func__);
380 notify_vbus_state_func_ptr = NULL;
381}
382
383static void notify_usb_of_the_plugin_event(struct msm_hardware_charger_priv
384 *hw_chg, int plugin)
385{
386 plugin = !!plugin;
387 if (plugin == 1 && usb_notified_of_insertion == 0) {
388 usb_notified_of_insertion = 1;
389 if (notify_vbus_state_func_ptr) {
390 dev_dbg(msm_chg.dev, "%s notifying plugin\n", __func__);
391 (*notify_vbus_state_func_ptr) (plugin);
392 } else
393 dev_dbg(msm_chg.dev, "%s unable to notify plugin\n",
394 __func__);
395 usb_hw_chg_priv = hw_chg;
396 }
397 if (plugin == 0 && usb_notified_of_insertion == 1) {
398 if (notify_vbus_state_func_ptr) {
399 dev_dbg(msm_chg.dev, "%s notifying unplugin\n",
400 __func__);
401 (*notify_vbus_state_func_ptr) (plugin);
402 } else
403 dev_dbg(msm_chg.dev, "%s unable to notify unplugin\n",
404 __func__);
405 usb_notified_of_insertion = 0;
406 usb_hw_chg_priv = NULL;
407 }
408}
409
410static unsigned int msm_chg_get_batt_capacity_percent(void)
411{
412 unsigned int current_voltage = get_prop_battery_mvolts();
413 unsigned int low_voltage = msm_chg.min_voltage;
414 unsigned int high_voltage = msm_chg.max_voltage;
415
416 if (current_voltage <= low_voltage)
417 return 0;
418 else if (current_voltage >= high_voltage)
419 return 100;
420 else
421 return (current_voltage - low_voltage) * 100
422 / (high_voltage - low_voltage);
423}
424
425#ifdef DEBUG
426static inline void debug_print(const char *func,
427 struct msm_hardware_charger_priv *hw_chg_priv)
428{
429 dev_dbg(msm_chg.dev,
430 "%s current=(%s)(s=%d)(r=%d) new=(%s)(s=%d)(r=%d) batt=%d En\n",
431 func,
432 msm_chg.current_chg_priv ? msm_chg.current_chg_priv->
433 hw_chg->name : "none",
434 msm_chg.current_chg_priv ? msm_chg.
435 current_chg_priv->hw_chg_state : -1,
436 msm_chg.current_chg_priv ? msm_chg.current_chg_priv->
437 hw_chg->rating : -1,
438 hw_chg_priv ? hw_chg_priv->hw_chg->name : "none",
439 hw_chg_priv ? hw_chg_priv->hw_chg_state : -1,
440 hw_chg_priv ? hw_chg_priv->hw_chg->rating : -1,
441 msm_chg.batt_status);
442}
443#else
444static inline void debug_print(const char *func,
445 struct msm_hardware_charger_priv *hw_chg_priv)
446{
447}
448#endif
449
450static struct msm_hardware_charger_priv *find_best_charger(void)
451{
452 struct msm_hardware_charger_priv *hw_chg_priv;
453 struct msm_hardware_charger_priv *better;
454 int rating;
455
456 better = NULL;
457 rating = 0;
458
459 list_for_each_entry(hw_chg_priv, &msm_chg.msm_hardware_chargers, list) {
460 if (is_chg_capable_of_charging(hw_chg_priv)) {
461 if (hw_chg_priv->hw_chg->rating > rating) {
462 rating = hw_chg_priv->hw_chg->rating;
463 better = hw_chg_priv;
464 }
465 }
466 }
467
468 return better;
469}
470
471static int msm_charging_switched(struct msm_hardware_charger_priv *priv)
472{
473 int ret = 0;
474
475 if (priv->hw_chg->charging_switched)
476 ret = priv->hw_chg->charging_switched(priv->hw_chg);
477 return ret;
478}
479
480static int msm_stop_charging(struct msm_hardware_charger_priv *priv)
481{
482 int ret;
483
484 ret = priv->hw_chg->stop_charging(priv->hw_chg);
485 if (!ret)
486 wake_unlock(&msm_chg.wl);
487 return ret;
488}
489
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700490static void msm_enable_system_current(struct msm_hardware_charger_priv *priv)
491{
492 if (priv->hw_chg->start_system_current)
493 priv->hw_chg->start_system_current(priv->hw_chg,
494 priv->max_source_current);
495}
496
497static void msm_disable_system_current(struct msm_hardware_charger_priv *priv)
498{
499 if (priv->hw_chg->stop_system_current)
500 priv->hw_chg->stop_system_current(priv->hw_chg);
501}
502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503/* the best charger has been selected -start charging from current_chg_priv */
504static int msm_start_charging(void)
505{
506 int ret;
507 struct msm_hardware_charger_priv *priv;
508
509 priv = msm_chg.current_chg_priv;
510 wake_lock(&msm_chg.wl);
511 ret = priv->hw_chg->start_charging(priv->hw_chg, msm_chg.max_voltage,
512 priv->max_source_current);
513 if (ret) {
514 wake_unlock(&msm_chg.wl);
515 dev_err(msm_chg.dev, "%s couldnt start chg error = %d\n",
516 priv->hw_chg->name, ret);
517 } else
518 priv->hw_chg_state = CHG_CHARGING_STATE;
519
520 return ret;
521}
522
523static void handle_charging_done(struct msm_hardware_charger_priv *priv)
524{
525 if (msm_chg.current_chg_priv == priv) {
526 if (msm_chg.current_chg_priv->hw_chg_state ==
527 CHG_CHARGING_STATE)
528 if (msm_stop_charging(msm_chg.current_chg_priv)) {
529 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
530 msm_chg.current_chg_priv->hw_chg->name);
531 }
532 msm_chg.current_chg_priv->hw_chg_state = CHG_READY_STATE;
533
534 msm_chg.batt_status = BATT_STATUS_JUST_FINISHED_CHARGING;
535 dev_info(msm_chg.dev, "%s: stopping safety timer work\n",
536 __func__);
537 cancel_delayed_work(&msm_chg.teoc_work);
538
539 if (msm_batt_gauge && msm_batt_gauge->monitor_for_recharging)
540 msm_batt_gauge->monitor_for_recharging();
541 else
542 dev_err(msm_chg.dev,
543 "%s: no batt gauge recharge monitor\n", __func__);
544 }
545}
546
547static void teoc(struct work_struct *work)
548{
549 /* we have been charging too long - stop charging */
550 dev_info(msm_chg.dev, "%s: safety timer work expired\n", __func__);
551
552 mutex_lock(&msm_chg.status_lock);
553 if (msm_chg.current_chg_priv != NULL
554 && msm_chg.current_chg_priv->hw_chg_state == CHG_CHARGING_STATE) {
555 handle_charging_done(msm_chg.current_chg_priv);
556 }
557 mutex_unlock(&msm_chg.status_lock);
558}
559
560static void handle_battery_inserted(void)
561{
562 /* if a charger is already present start charging */
563 if (msm_chg.current_chg_priv != NULL &&
564 is_batt_status_capable_of_charging() &&
565 !is_batt_status_charging()) {
566 if (msm_start_charging()) {
567 dev_err(msm_chg.dev, "%s couldnt start chg\n",
568 msm_chg.current_chg_priv->hw_chg->name);
569 return;
570 }
571 msm_chg.batt_status = BATT_STATUS_TRKL_CHARGING;
572
573 dev_info(msm_chg.dev, "%s: starting safety timer work\n",
574 __func__);
575 queue_delayed_work(msm_chg.event_wq_thread,
576 &msm_chg.teoc_work,
577 round_jiffies_relative(msecs_to_jiffies
578 (msm_chg.
579 safety_time)));
580 }
581}
582
583static void handle_battery_removed(void)
584{
585 /* if a charger is charging the battery stop it */
586 if (msm_chg.current_chg_priv != NULL
587 && msm_chg.current_chg_priv->hw_chg_state == CHG_CHARGING_STATE) {
588 if (msm_stop_charging(msm_chg.current_chg_priv)) {
589 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
590 msm_chg.current_chg_priv->hw_chg->name);
591 }
592 msm_chg.current_chg_priv->hw_chg_state = CHG_READY_STATE;
593
594 dev_info(msm_chg.dev, "%s: stopping safety timer work\n",
595 __func__);
596 cancel_delayed_work(&msm_chg.teoc_work);
597 }
598}
599
600static void update_heartbeat(struct work_struct *work)
601{
602 int temperature;
603
604 if (msm_chg.batt_status == BATT_STATUS_ABSENT
605 || msm_chg.batt_status == BATT_STATUS_ID_INVALID) {
606 if (is_battery_present())
607 if (is_battery_id_valid()) {
608 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
609 handle_battery_inserted();
610 }
611 } else {
612 if (!is_battery_present()) {
613 msm_chg.batt_status = BATT_STATUS_ABSENT;
614 handle_battery_removed();
615 }
616 /*
617 * check battery id because a good battery could be removed
618 * and replaced with a invalid battery.
619 */
620 if (!is_battery_id_valid()) {
621 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
622 handle_battery_removed();
623 }
624 }
625 pr_debug("msm-charger %s batt_status= %d\n",
626 __func__, msm_chg.batt_status);
627
628 if (msm_chg.current_chg_priv
629 && msm_chg.current_chg_priv->hw_chg_state
630 == CHG_CHARGING_STATE) {
631 temperature = get_battery_temperature();
632 /* TODO implement JEITA SPEC*/
633 }
634
635 /* notify that the voltage has changed
636 * the read of the capacity will trigger a
637 * voltage read*/
638 power_supply_changed(&msm_psy_batt);
639
640 if (msm_chg.stop_update) {
641 msm_chg.stop_update = 0;
642 return;
643 }
644 queue_delayed_work(msm_chg.event_wq_thread,
645 &msm_chg.update_heartbeat_work,
646 round_jiffies_relative(msecs_to_jiffies
647 (msm_chg.update_time)));
648}
649
650/* set the charger state to READY before calling this */
651static void handle_charger_ready(struct msm_hardware_charger_priv *hw_chg_priv)
652{
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700653 struct msm_hardware_charger_priv *old_chg_priv = NULL;
654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 debug_print(__func__, hw_chg_priv);
656
657 if (msm_chg.current_chg_priv != NULL
658 && hw_chg_priv->hw_chg->rating >
659 msm_chg.current_chg_priv->hw_chg->rating) {
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700660 /*
661 * a better charger was found, ask the current charger
662 * to stop charging if it was charging
663 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 if (msm_chg.current_chg_priv->hw_chg_state ==
665 CHG_CHARGING_STATE) {
666 if (msm_stop_charging(msm_chg.current_chg_priv)) {
667 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
668 msm_chg.current_chg_priv->hw_chg->name);
669 return;
670 }
671 if (msm_charging_switched(msm_chg.current_chg_priv)) {
672 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
673 msm_chg.current_chg_priv->hw_chg->name);
674 return;
675 }
676 }
677 msm_chg.current_chg_priv->hw_chg_state = CHG_READY_STATE;
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700678 old_chg_priv = msm_chg.current_chg_priv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 msm_chg.current_chg_priv = NULL;
680 }
681
682 if (msm_chg.current_chg_priv == NULL) {
683 msm_chg.current_chg_priv = hw_chg_priv;
684 dev_info(msm_chg.dev,
685 "%s: best charger = %s\n", __func__,
686 msm_chg.current_chg_priv->hw_chg->name);
687
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700688 msm_enable_system_current(msm_chg.current_chg_priv);
689 /*
690 * since a better charger was chosen, ask the old
691 * charger to stop providing system current
692 */
693 if (old_chg_priv != NULL)
694 msm_disable_system_current(old_chg_priv);
695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696 if (!is_batt_status_capable_of_charging())
697 return;
698
699 /* start charging from the new charger */
700 if (!msm_start_charging()) {
701 /* if we simply switched chg continue with teoc timer
702 * else we update the batt state and set the teoc
703 * timer */
704 if (!is_batt_status_charging()) {
705 dev_info(msm_chg.dev,
706 "%s: starting safety timer\n", __func__);
707 queue_delayed_work(msm_chg.event_wq_thread,
708 &msm_chg.teoc_work,
709 round_jiffies_relative
710 (msecs_to_jiffies
711 (msm_chg.safety_time)));
712 msm_chg.batt_status = BATT_STATUS_TRKL_CHARGING;
713 }
714 } else {
715 /* we couldnt start charging from the new readied
716 * charger */
717 if (is_batt_status_charging())
718 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
719 }
720 }
721}
722
723static void handle_charger_removed(struct msm_hardware_charger_priv
724 *hw_chg_removed, int new_state)
725{
726 struct msm_hardware_charger_priv *hw_chg_priv;
727
728 debug_print(__func__, hw_chg_removed);
729
730 if (msm_chg.current_chg_priv == hw_chg_removed) {
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700731 msm_disable_system_current(hw_chg_removed);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732 if (msm_chg.current_chg_priv->hw_chg_state
733 == CHG_CHARGING_STATE) {
734 if (msm_stop_charging(hw_chg_removed)) {
735 dev_err(msm_chg.dev, "%s couldnt stop chg\n",
736 msm_chg.current_chg_priv->hw_chg->name);
737 }
738 }
739 msm_chg.current_chg_priv = NULL;
740 }
741
742 hw_chg_removed->hw_chg_state = new_state;
743
744 if (msm_chg.current_chg_priv == NULL) {
745 hw_chg_priv = find_best_charger();
746 if (hw_chg_priv == NULL) {
747 dev_info(msm_chg.dev, "%s: no chargers\n", __func__);
748 /* if the battery was Just finished charging
749 * we keep that state as is so that we dont rush
750 * in to charging the battery when a charger is
751 * plugged in shortly. */
752 if (is_batt_status_charging())
753 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
754 } else {
755 msm_chg.current_chg_priv = hw_chg_priv;
Abhijeet Dharmapurikar57390b02011-07-14 18:05:11 -0700756 msm_enable_system_current(hw_chg_priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757 dev_info(msm_chg.dev,
758 "%s: best charger = %s\n", __func__,
759 msm_chg.current_chg_priv->hw_chg->name);
760
761 if (!is_batt_status_capable_of_charging())
762 return;
763
764 if (msm_start_charging()) {
765 /* we couldnt start charging for some reason */
766 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
767 }
768 }
769 }
770
771 /* if we arent charging stop the safety timer */
772 if (!is_batt_status_charging()) {
773 dev_info(msm_chg.dev, "%s: stopping safety timer work\n",
774 __func__);
775 cancel_delayed_work(&msm_chg.teoc_work);
776 }
777}
778
779static void handle_event(struct msm_hardware_charger *hw_chg, int event)
780{
781 struct msm_hardware_charger_priv *priv = NULL;
782
783 /*
784 * if hw_chg is NULL then this event comes from non-charger
785 * parties like battery gauge
786 */
787 if (hw_chg)
788 priv = hw_chg->charger_private;
789
790 mutex_lock(&msm_chg.status_lock);
791
792 switch (event) {
793 case CHG_INSERTED_EVENT:
794 if (priv->hw_chg_state != CHG_ABSENT_STATE) {
795 dev_info(msm_chg.dev,
796 "%s insertion detected when cbl present",
797 hw_chg->name);
798 break;
799 }
800 update_batt_status();
801 if (hw_chg->type == CHG_TYPE_USB) {
802 priv->hw_chg_state = CHG_PRESENT_STATE;
803 notify_usb_of_the_plugin_event(priv, 1);
804 if (usb_chg_current) {
805 priv->max_source_current = usb_chg_current;
806 usb_chg_current = 0;
807 /* usb has already indicated us to charge */
808 priv->hw_chg_state = CHG_READY_STATE;
809 handle_charger_ready(priv);
810 }
811 } else {
812 priv->hw_chg_state = CHG_READY_STATE;
813 handle_charger_ready(priv);
814 }
815 break;
816 case CHG_ENUMERATED_EVENT: /* only in USB types */
817 if (priv->hw_chg_state == CHG_ABSENT_STATE) {
818 dev_info(msm_chg.dev, "%s enum withuot presence\n",
819 hw_chg->name);
820 break;
821 }
822 update_batt_status();
823 dev_dbg(msm_chg.dev, "%s enum with %dmA to draw\n",
824 hw_chg->name, priv->max_source_current);
825 if (priv->max_source_current == 0) {
826 /* usb subsystem doesnt want us to draw
827 * charging current */
828 /* act as if the charge is removed */
829 if (priv->hw_chg_state != CHG_PRESENT_STATE)
830 handle_charger_removed(priv, CHG_PRESENT_STATE);
831 } else {
832 if (priv->hw_chg_state != CHG_READY_STATE) {
833 priv->hw_chg_state = CHG_READY_STATE;
834 handle_charger_ready(priv);
835 }
836 }
837 break;
838 case CHG_REMOVED_EVENT:
839 if (priv->hw_chg_state == CHG_ABSENT_STATE) {
840 dev_info(msm_chg.dev, "%s cable already removed\n",
841 hw_chg->name);
842 break;
843 }
844 update_batt_status();
845 if (hw_chg->type == CHG_TYPE_USB) {
846 usb_chg_current = 0;
847 notify_usb_of_the_plugin_event(priv, 0);
848 }
849 handle_charger_removed(priv, CHG_ABSENT_STATE);
850 break;
851 case CHG_DONE_EVENT:
852 if (priv->hw_chg_state == CHG_CHARGING_STATE)
853 handle_charging_done(priv);
854 break;
855 case CHG_BATT_BEGIN_FAST_CHARGING:
856 /* only update if we are TRKL charging */
857 if (msm_chg.batt_status == BATT_STATUS_TRKL_CHARGING)
858 msm_chg.batt_status = BATT_STATUS_FAST_CHARGING;
859 break;
860 case CHG_BATT_NEEDS_RECHARGING:
861 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
862 handle_battery_inserted();
863 priv = msm_chg.current_chg_priv;
864 break;
865 case CHG_BATT_TEMP_OUTOFRANGE:
866 /* the batt_temp out of range can trigger
867 * when the battery is absent */
868 if (!is_battery_present()
869 && msm_chg.batt_status != BATT_STATUS_ABSENT) {
870 msm_chg.batt_status = BATT_STATUS_ABSENT;
871 handle_battery_removed();
872 break;
873 }
874 if (msm_chg.batt_status == BATT_STATUS_TEMPERATURE_OUT_OF_RANGE)
875 break;
876 msm_chg.batt_status = BATT_STATUS_TEMPERATURE_OUT_OF_RANGE;
877 handle_battery_removed();
878 break;
879 case CHG_BATT_TEMP_INRANGE:
880 if (msm_chg.batt_status != BATT_STATUS_TEMPERATURE_OUT_OF_RANGE)
881 break;
882 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
883 /* check id */
884 if (!is_battery_id_valid())
885 break;
886 /* assume that we are discharging from the battery
887 * and act as if the battery was inserted
888 * if a charger is present charging will be resumed */
889 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
890 handle_battery_inserted();
891 break;
892 case CHG_BATT_INSERTED:
893 if (msm_chg.batt_status != BATT_STATUS_ABSENT)
894 break;
895 /* debounce */
896 if (!is_battery_present())
897 break;
898 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
899 if (!is_battery_id_valid())
900 break;
901 /* assume that we are discharging from the battery */
902 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
903 /* check if a charger is present */
904 handle_battery_inserted();
905 break;
906 case CHG_BATT_REMOVED:
907 if (msm_chg.batt_status == BATT_STATUS_ABSENT)
908 break;
909 /* debounce */
910 if (is_battery_present())
911 break;
912 msm_chg.batt_status = BATT_STATUS_ABSENT;
913 handle_battery_removed();
914 break;
915 case CHG_BATT_STATUS_CHANGE:
916 /* TODO battery SOC like battery-alarm/charging-full features
917 can be added here for future improvement */
918 break;
919 }
920 dev_dbg(msm_chg.dev, "%s %d done batt_status=%d\n", __func__,
921 event, msm_chg.batt_status);
922
923 /* update userspace */
924 if (msm_batt_gauge)
925 power_supply_changed(&msm_psy_batt);
926 if (priv)
927 power_supply_changed(&priv->psy);
928
929 mutex_unlock(&msm_chg.status_lock);
930}
931
932static int msm_chg_dequeue_event(struct msm_charger_event **event)
933{
934 unsigned long flags;
935
936 spin_lock_irqsave(&msm_chg.queue_lock, flags);
937 if (msm_chg.queue_count == 0) {
938 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
939 return -EINVAL;
940 }
941 *event = &msm_chg.queue[msm_chg.head];
942 msm_chg.head = (msm_chg.head + 1) % MSM_CHG_MAX_EVENTS;
943 pr_debug("%s dequeueing %d\n", __func__, (*event)->event);
944 msm_chg.queue_count--;
945 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
946 return 0;
947}
948
949static int msm_chg_enqueue_event(struct msm_hardware_charger *hw_chg,
950 enum msm_hardware_charger_event event)
951{
952 unsigned long flags;
953
954 spin_lock_irqsave(&msm_chg.queue_lock, flags);
955 if (msm_chg.queue_count == MSM_CHG_MAX_EVENTS) {
956 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
957 pr_err("%s: queue full cannot enqueue %d\n",
958 __func__, event);
959 return -EAGAIN;
960 }
961 pr_debug("%s queueing %d\n", __func__, event);
962 msm_chg.queue[msm_chg.tail].event = event;
963 msm_chg.queue[msm_chg.tail].hw_chg = hw_chg;
964 msm_chg.tail = (msm_chg.tail + 1)%MSM_CHG_MAX_EVENTS;
965 msm_chg.queue_count++;
966 spin_unlock_irqrestore(&msm_chg.queue_lock, flags);
967 return 0;
968}
969
970static void process_events(struct work_struct *work)
971{
972 struct msm_charger_event *event;
973 int rc;
974
975 do {
976 rc = msm_chg_dequeue_event(&event);
977 if (!rc)
978 handle_event(event->hw_chg, event->event);
979 } while (!rc);
980}
981
982/* USB calls these to tell us how much charging current we should draw */
983void msm_charger_vbus_draw(unsigned int mA)
984{
985 if (usb_hw_chg_priv) {
986 usb_hw_chg_priv->max_source_current = mA;
987 msm_charger_notify_event(usb_hw_chg_priv->hw_chg,
988 CHG_ENUMERATED_EVENT);
989 } else
990 /* remember the current, to be used when charger is ready */
991 usb_chg_current = mA;
992}
993
Stephen Boyd4c894512012-04-25 11:52:42 -0700994static int determine_initial_batt_status(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 if (is_battery_present())
997 if (is_battery_id_valid())
998 if (is_battery_temp_within_range())
999 msm_chg.batt_status = BATT_STATUS_DISCHARGING;
1000 else
1001 msm_chg.batt_status
1002 = BATT_STATUS_TEMPERATURE_OUT_OF_RANGE;
1003 else
1004 msm_chg.batt_status = BATT_STATUS_ID_INVALID;
1005 else
1006 msm_chg.batt_status = BATT_STATUS_ABSENT;
1007
1008 if (is_batt_status_capable_of_charging())
1009 handle_battery_inserted();
1010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011 /* start updaing the battery powersupply every msm_chg.update_time
1012 * milliseconds */
1013 queue_delayed_work(msm_chg.event_wq_thread,
1014 &msm_chg.update_heartbeat_work,
1015 round_jiffies_relative(msecs_to_jiffies
1016 (msm_chg.update_time)));
1017
1018 pr_debug("%s:OK batt_status=%d\n", __func__, msm_chg.batt_status);
1019 return 0;
1020}
1021
1022static int __devinit msm_charger_probe(struct platform_device *pdev)
1023{
1024 msm_chg.dev = &pdev->dev;
1025 if (pdev->dev.platform_data) {
1026 unsigned int milli_secs;
1027
1028 struct msm_charger_platform_data *pdata
1029 =
1030 (struct msm_charger_platform_data *)pdev->dev.platform_data;
1031
1032 milli_secs = pdata->safety_time * 60 * MSEC_PER_SEC;
1033 if (milli_secs > jiffies_to_msecs(MAX_JIFFY_OFFSET)) {
1034 dev_warn(&pdev->dev, "%s: safety time too large"
1035 "%dms\n", __func__, milli_secs);
1036 milli_secs = jiffies_to_msecs(MAX_JIFFY_OFFSET);
1037 }
1038 msm_chg.safety_time = milli_secs;
1039
1040 milli_secs = pdata->update_time * 60 * MSEC_PER_SEC;
1041 if (milli_secs > jiffies_to_msecs(MAX_JIFFY_OFFSET)) {
1042 dev_warn(&pdev->dev, "%s: safety time too large"
1043 "%dms\n", __func__, milli_secs);
1044 milli_secs = jiffies_to_msecs(MAX_JIFFY_OFFSET);
1045 }
1046 msm_chg.update_time = milli_secs;
1047
1048 msm_chg.max_voltage = pdata->max_voltage;
1049 msm_chg.min_voltage = pdata->min_voltage;
1050 msm_chg.get_batt_capacity_percent =
1051 pdata->get_batt_capacity_percent;
1052 }
1053 if (msm_chg.safety_time == 0)
1054 msm_chg.safety_time = CHARGING_TEOC_MS;
1055 if (msm_chg.update_time == 0)
1056 msm_chg.update_time = UPDATE_TIME_MS;
1057 if (msm_chg.max_voltage == 0)
1058 msm_chg.max_voltage = DEFAULT_BATT_MAX_V;
1059 if (msm_chg.min_voltage == 0)
1060 msm_chg.min_voltage = DEFAULT_BATT_MIN_V;
1061 if (msm_chg.get_batt_capacity_percent == NULL)
1062 msm_chg.get_batt_capacity_percent =
1063 msm_chg_get_batt_capacity_percent;
1064
1065 mutex_init(&msm_chg.status_lock);
1066 INIT_DELAYED_WORK(&msm_chg.teoc_work, teoc);
1067 INIT_DELAYED_WORK(&msm_chg.update_heartbeat_work, update_heartbeat);
1068
1069 wake_lock_init(&msm_chg.wl, WAKE_LOCK_SUSPEND, "msm_charger");
1070 return 0;
1071}
1072
1073static int __devexit msm_charger_remove(struct platform_device *pdev)
1074{
Abhijeet Dharmapurikar0f828242011-07-11 12:12:25 -07001075 wake_lock_destroy(&msm_chg.wl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 mutex_destroy(&msm_chg.status_lock);
1077 power_supply_unregister(&msm_psy_batt);
1078 return 0;
1079}
1080
1081int msm_charger_notify_event(struct msm_hardware_charger *hw_chg,
1082 enum msm_hardware_charger_event event)
1083{
1084 msm_chg_enqueue_event(hw_chg, event);
1085 queue_work(msm_chg.event_wq_thread, &msm_chg.queue_work);
1086 return 0;
1087}
1088EXPORT_SYMBOL(msm_charger_notify_event);
1089
1090int msm_charger_register(struct msm_hardware_charger *hw_chg)
1091{
1092 struct msm_hardware_charger_priv *priv;
1093 int rc = 0;
1094
1095 if (!msm_chg.inited) {
1096 pr_err("%s: msm_chg is NULL,Too early to register\n", __func__);
1097 return -EAGAIN;
1098 }
1099
1100 if (hw_chg->start_charging == NULL
1101 || hw_chg->stop_charging == NULL
1102 || hw_chg->name == NULL
1103 || hw_chg->rating == 0) {
1104 pr_err("%s: invalid hw_chg\n", __func__);
1105 return -EINVAL;
1106 }
1107
1108 priv = kzalloc(sizeof *priv, GFP_KERNEL);
1109 if (priv == NULL) {
1110 dev_err(msm_chg.dev, "%s kzalloc failed\n", __func__);
1111 return -ENOMEM;
1112 }
1113
1114 priv->psy.name = hw_chg->name;
1115 if (hw_chg->type == CHG_TYPE_USB)
1116 priv->psy.type = POWER_SUPPLY_TYPE_USB;
1117 else
1118 priv->psy.type = POWER_SUPPLY_TYPE_MAINS;
1119
1120 priv->psy.supplied_to = msm_power_supplied_to;
1121 priv->psy.num_supplicants = ARRAY_SIZE(msm_power_supplied_to);
1122 priv->psy.properties = msm_power_props;
1123 priv->psy.num_properties = ARRAY_SIZE(msm_power_props);
1124 priv->psy.get_property = msm_power_get_property;
1125
1126 rc = power_supply_register(NULL, &priv->psy);
1127 if (rc) {
1128 dev_err(msm_chg.dev, "%s power_supply_register failed\n",
1129 __func__);
1130 goto out;
1131 }
1132
1133 priv->hw_chg = hw_chg;
1134 priv->hw_chg_state = CHG_ABSENT_STATE;
1135 INIT_LIST_HEAD(&priv->list);
1136 mutex_lock(&msm_chg.msm_hardware_chargers_lock);
1137 list_add_tail(&priv->list, &msm_chg.msm_hardware_chargers);
1138 mutex_unlock(&msm_chg.msm_hardware_chargers_lock);
1139 hw_chg->charger_private = (void *)priv;
1140 return 0;
1141
1142out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 kfree(priv);
1144 return rc;
1145}
1146EXPORT_SYMBOL(msm_charger_register);
1147
1148void msm_battery_gauge_register(struct msm_battery_gauge *batt_gauge)
1149{
Michael Bohan2f090af2011-10-05 11:38:25 -07001150 int rc;
1151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 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 {
Michael Bohan2f090af2011-10-05 11:38:25 -07001157 rc = power_supply_register(msm_chg.dev, &msm_psy_batt);
1158 if (rc < 0) {
1159 dev_err(msm_chg.dev, "%s: power_supply_register failed"
1160 " rc=%d\n", __func__, rc);
1161 return;
1162 }
1163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 msm_batt_gauge = batt_gauge;
1165 determine_initial_batt_status();
1166 }
1167}
1168EXPORT_SYMBOL(msm_battery_gauge_register);
1169
1170void msm_battery_gauge_unregister(struct msm_battery_gauge *batt_gauge)
1171{
1172 msm_batt_gauge = NULL;
1173}
1174EXPORT_SYMBOL(msm_battery_gauge_unregister);
1175
1176int msm_charger_unregister(struct msm_hardware_charger *hw_chg)
1177{
1178 struct msm_hardware_charger_priv *priv;
1179
1180 priv = (struct msm_hardware_charger_priv *)(hw_chg->charger_private);
1181 mutex_lock(&msm_chg.msm_hardware_chargers_lock);
1182 list_del(&priv->list);
1183 mutex_unlock(&msm_chg.msm_hardware_chargers_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 power_supply_unregister(&priv->psy);
1185 kfree(priv);
1186 return 0;
1187}
1188EXPORT_SYMBOL(msm_charger_unregister);
1189
1190static int msm_charger_suspend(struct device *dev)
1191{
1192 dev_dbg(msm_chg.dev, "%s suspended\n", __func__);
1193 msm_chg.stop_update = 1;
1194 cancel_delayed_work(&msm_chg.update_heartbeat_work);
1195 mutex_lock(&msm_chg.status_lock);
1196 handle_battery_removed();
1197 mutex_unlock(&msm_chg.status_lock);
1198 return 0;
1199}
1200
1201static int msm_charger_resume(struct device *dev)
1202{
1203 dev_dbg(msm_chg.dev, "%s resumed\n", __func__);
1204 msm_chg.stop_update = 0;
1205 /* start updaing the battery powersupply every msm_chg.update_time
1206 * milliseconds */
1207 queue_delayed_work(msm_chg.event_wq_thread,
1208 &msm_chg.update_heartbeat_work,
1209 round_jiffies_relative(msecs_to_jiffies
1210 (msm_chg.update_time)));
1211 mutex_lock(&msm_chg.status_lock);
1212 handle_battery_inserted();
1213 mutex_unlock(&msm_chg.status_lock);
1214 return 0;
1215}
1216
1217static SIMPLE_DEV_PM_OPS(msm_charger_pm_ops,
1218 msm_charger_suspend, msm_charger_resume);
1219
1220static struct platform_driver msm_charger_driver = {
1221 .probe = msm_charger_probe,
1222 .remove = __devexit_p(msm_charger_remove),
1223 .driver = {
1224 .name = "msm-charger",
1225 .owner = THIS_MODULE,
1226 .pm = &msm_charger_pm_ops,
1227 },
1228};
1229
1230static int __init msm_charger_init(void)
1231{
1232 int rc;
1233
1234 INIT_LIST_HEAD(&msm_chg.msm_hardware_chargers);
1235 msm_chg.count_chargers = 0;
1236 mutex_init(&msm_chg.msm_hardware_chargers_lock);
1237
1238 msm_chg.queue = kzalloc(sizeof(struct msm_charger_event)
1239 * MSM_CHG_MAX_EVENTS,
1240 GFP_KERNEL);
1241 if (!msm_chg.queue) {
1242 rc = -ENOMEM;
1243 goto out;
1244 }
1245 msm_chg.tail = 0;
1246 msm_chg.head = 0;
1247 spin_lock_init(&msm_chg.queue_lock);
1248 msm_chg.queue_count = 0;
1249 INIT_WORK(&msm_chg.queue_work, process_events);
1250 msm_chg.event_wq_thread = create_workqueue("msm_charger_eventd");
1251 if (!msm_chg.event_wq_thread) {
1252 rc = -ENOMEM;
1253 goto free_queue;
1254 }
1255 rc = platform_driver_register(&msm_charger_driver);
1256 if (rc < 0) {
1257 pr_err("%s: FAIL: platform_driver_register. rc = %d\n",
1258 __func__, rc);
1259 goto destroy_wq_thread;
1260 }
1261 msm_chg.inited = 1;
1262 return 0;
1263
1264destroy_wq_thread:
1265 destroy_workqueue(msm_chg.event_wq_thread);
1266free_queue:
1267 kfree(msm_chg.queue);
1268out:
1269 return rc;
1270}
1271
1272static void __exit msm_charger_exit(void)
1273{
1274 flush_workqueue(msm_chg.event_wq_thread);
1275 destroy_workqueue(msm_chg.event_wq_thread);
1276 kfree(msm_chg.queue);
1277 platform_driver_unregister(&msm_charger_driver);
1278}
1279
1280module_init(msm_charger_init);
1281module_exit(msm_charger_exit);
1282
1283MODULE_LICENSE("GPL v2");
1284MODULE_AUTHOR("Abhijeet Dharmapurikar <adharmap@codeaurora.org>");
1285MODULE_DESCRIPTION("Battery driver for Qualcomm MSM chipsets.");
1286MODULE_VERSION("1.0");