522db7962b398392d5dac35d7f1da1d2cf84e74c
[linux-3.10.git] / drivers / power / battery-charger-gauge-comm.c
1 /*
2  * battery-charger-gauge-comm.c -- Communication between battery charger and
3  *      battery gauge driver.
4  *
5  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
6  *
7  * Author: Laxman Dewangan <ldewangan@nvidia.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation version 2.
12  *
13  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
14  * whether express or implied; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307, USA
22  */
23
24 #include <linux/alarmtimer.h>
25 #include <linux/module.h>
26 #include <linux/err.h>
27 #include <linux/export.h>
28 #include <linux/workqueue.h>
29 #include <linux/delay.h>
30 #include <linux/sched.h>
31 #include <linux/slab.h>
32 #include <linux/mutex.h>
33 #include <linux/thermal.h>
34 #include <linux/list.h>
35 #include <linux/rtc.h>
36 #include <linux/time.h>
37 #include <linux/timer.h>
38 #include <linux/power/battery-charger-gauge-comm.h>
39 #include <linux/power/reset/system-pmic.h>
40 #include <linux/wakelock.h>
41
42 #define JETI_TEMP_COLD          0
43 #define JETI_TEMP_COOL          10
44 #define JETI_TEMP_WARM          45
45 #define JETI_TEMP_HOT           60
46
47 static DEFINE_MUTEX(charger_gauge_list_mutex);
48 static LIST_HEAD(charger_list);
49 static LIST_HEAD(gauge_list);
50
51 struct battery_charger_dev {
52         int                             cell_id;
53         char                            tz_name[THERMAL_NAME_LENGTH];
54         struct device                   *parent_dev;
55         struct battery_charging_ops     *ops;
56         struct list_head                list;
57         void                            *drv_data;
58         struct delayed_work             restart_charging_wq;
59         struct delayed_work             poll_temp_monitor_wq;
60         int                             polling_time_sec;
61         struct thermal_zone_device      *battery_tz;
62         bool                            start_monitoring;
63         struct wake_lock                charger_wake_lock;
64         bool                            locked;
65         struct rtc_device               *rtc;
66 };
67
68 struct battery_gauge_dev {
69         int                             cell_id;
70         char                            tz_name[THERMAL_NAME_LENGTH];
71         struct device                   *parent_dev;
72         struct battery_gauge_ops        *ops;
73         struct list_head                list;
74         void                            *drv_data;
75         struct thermal_zone_device      *battery_tz;
76 };
77
78 static void battery_charger_restart_charging_wq(struct work_struct *work)
79 {
80         struct battery_charger_dev *bc_dev;
81
82         bc_dev = container_of(work, struct battery_charger_dev,
83                                         restart_charging_wq.work);
84         if (!bc_dev->ops->restart_charging) {
85                 dev_err(bc_dev->parent_dev,
86                                 "No callback for restart charging\n");
87                 return;
88         }
89         bc_dev->ops->restart_charging(bc_dev);
90 }
91
92 static void battery_charger_thermal_monitor_wq(struct work_struct *work)
93 {
94         struct battery_charger_dev *bc_dev;
95         struct device *dev;
96         long temperature;
97         bool charger_enable_state;
98         bool charger_current_half;
99         int battery_thersold_voltage;
100         int ret;
101
102         bc_dev = container_of(work, struct battery_charger_dev,
103                                         poll_temp_monitor_wq.work);
104         dev = bc_dev->parent_dev;
105
106         if (!bc_dev->battery_tz)
107                 bc_dev->battery_tz =
108                         thermal_zone_device_find_by_name(bc_dev->tz_name);
109
110         if (!bc_dev->battery_tz) {
111                 dev_info(dev, "Battery thermal zone %s is not registered yet\n",
112                                         bc_dev->tz_name);
113                 schedule_delayed_work(&bc_dev->poll_temp_monitor_wq,
114                         msecs_to_jiffies(bc_dev->polling_time_sec * HZ));
115                 return;
116         }
117
118         ret = thermal_zone_get_temp(bc_dev->battery_tz, &temperature);
119         if (ret < 0) {
120                 dev_err(dev, "Temperature read failed: %d\n ", ret);
121                 goto exit;
122         }
123
124         temperature = temperature / 1000;
125         charger_enable_state = true;
126         charger_current_half = false;
127         battery_thersold_voltage = 4250;
128
129         if (temperature <= JETI_TEMP_COLD || temperature >= JETI_TEMP_HOT) {
130                 charger_enable_state = false;
131         } else if (temperature <= JETI_TEMP_COOL ||
132                                 temperature >= JETI_TEMP_WARM) {
133                 charger_current_half = true;
134                 battery_thersold_voltage = 4100;
135         }
136
137         if (bc_dev->ops->thermal_configure)
138                 bc_dev->ops->thermal_configure(bc_dev, temperature,
139                         charger_enable_state, charger_current_half,
140                         battery_thersold_voltage);
141
142 exit:
143         if (bc_dev->start_monitoring)
144                 schedule_delayed_work(&bc_dev->poll_temp_monitor_wq,
145                         msecs_to_jiffies(bc_dev->polling_time_sec * HZ));
146         return;
147 }
148
149 int battery_charger_set_current_broadcast(struct battery_charger_dev *bc_dev)
150 {
151         struct battery_gauge_dev *bg_dev;
152         int ret = 0;
153
154         if (!bc_dev) {
155                 dev_err(bc_dev->parent_dev, "Invalid parameters\n");
156                 return -EINVAL;
157         }
158
159         mutex_lock(&charger_gauge_list_mutex);
160
161         list_for_each_entry(bg_dev, &gauge_list, list) {
162                 if (bg_dev->cell_id != bc_dev->cell_id)
163                         continue;
164                 if (bg_dev->ops && bg_dev->ops->set_current_broadcast)
165                         ret = bg_dev->ops->set_current_broadcast(bg_dev);
166         }
167
168         mutex_unlock(&charger_gauge_list_mutex);
169         return ret;
170 }
171 EXPORT_SYMBOL_GPL(battery_charger_set_current_broadcast);
172
173 int battery_charger_thermal_start_monitoring(
174         struct battery_charger_dev *bc_dev)
175 {
176         if (!bc_dev || !bc_dev->polling_time_sec)
177                 return -EINVAL;
178
179         bc_dev->start_monitoring = true;
180         schedule_delayed_work(&bc_dev->poll_temp_monitor_wq,
181                         msecs_to_jiffies(bc_dev->polling_time_sec * HZ));
182         return 0;
183 }
184 EXPORT_SYMBOL_GPL(battery_charger_thermal_start_monitoring);
185
186 int battery_charger_thermal_stop_monitoring(
187         struct battery_charger_dev *bc_dev)
188 {
189         if (!bc_dev || !bc_dev->polling_time_sec)
190                 return -EINVAL;
191
192         bc_dev->start_monitoring = false;
193         cancel_delayed_work(&bc_dev->poll_temp_monitor_wq);
194         return 0;
195 }
196 EXPORT_SYMBOL_GPL(battery_charger_thermal_stop_monitoring);
197
198 int battery_charger_acquire_wake_lock(struct battery_charger_dev *bc_dev)
199 {
200         if (!bc_dev->locked) {
201                 wake_lock(&bc_dev->charger_wake_lock);
202                 bc_dev->locked = true;
203         }
204         return 0;
205 }
206 EXPORT_SYMBOL_GPL(battery_charger_acquire_wake_lock);
207
208 int battery_charger_release_wake_lock(struct battery_charger_dev *bc_dev)
209 {
210         if (bc_dev->locked) {
211                 wake_unlock(&bc_dev->charger_wake_lock);
212                 bc_dev->locked = false;
213         }
214         return 0;
215 }
216 EXPORT_SYMBOL_GPL(battery_charger_release_wake_lock);
217
218 int battery_charging_restart(struct battery_charger_dev *bc_dev, int after_sec)
219 {
220         if (!bc_dev->ops->restart_charging) {
221                 dev_err(bc_dev->parent_dev,
222                         "No callback for restart charging\n");
223                 return -EINVAL;
224         }
225         schedule_delayed_work(&bc_dev->restart_charging_wq,
226                         msecs_to_jiffies(after_sec * HZ));
227         return 0;
228 }
229 EXPORT_SYMBOL_GPL(battery_charging_restart);
230
231 void battery_charging_restart_cancel(struct battery_charger_dev *bc_dev)
232 {
233         if (!bc_dev->ops->restart_charging) {
234                 dev_err(bc_dev->parent_dev,
235                         "No callback for restart charging\n");
236                 return;
237         }
238         cancel_delayed_work(&bc_dev->restart_charging_wq);
239 }
240 EXPORT_SYMBOL_GPL(battery_charging_restart_cancel);
241
242 int battery_charging_wakeup(struct battery_charger_dev *bc_dev, int after_sec)
243 {
244         int ret;
245         unsigned long now;
246         struct rtc_wkalrm alm;
247         int alarm_time = after_sec;
248
249         if (!alarm_time)
250                 return 0;
251
252         bc_dev->rtc = alarmtimer_get_rtcdev();
253         if (!bc_dev->rtc) {
254                 dev_err(bc_dev->parent_dev, "No RTC device found\n");
255                 return -ENODEV;
256         }
257
258         alm.enabled = true;
259         ret = rtc_read_time(bc_dev->rtc, &alm.time);
260         if (ret < 0) {
261                 dev_err(bc_dev->parent_dev, "RTC read time failed %d\n", ret);
262                 return ret;
263         }
264         rtc_tm_to_time(&alm.time, &now);
265
266         rtc_time_to_tm(now + alarm_time, &alm.time);
267         ret = rtc_set_alarm(bc_dev->rtc, &alm);
268         if (ret < 0) {
269                 dev_err(bc_dev->parent_dev, "RTC set alarm failed %d\n", ret);
270                 alm.enabled = false;
271                 return ret;
272         }
273         alm.enabled = false;
274         return 0;
275 }
276 EXPORT_SYMBOL_GPL(battery_charging_wakeup);
277
278 int battery_charging_system_reset_after(struct battery_charger_dev *bc_dev,
279         int after_sec)
280 {
281         struct system_pmic_rtc_data rtc_data;
282         int ret;
283
284         dev_info(bc_dev->parent_dev, "Setting system on after %d sec\n",
285                 after_sec);
286         battery_charging_wakeup(bc_dev, after_sec);
287         rtc_data.power_on_after_sec = after_sec;
288
289         ret = system_pmic_set_power_on_event(SYSTEM_PMIC_RTC_ALARM, &rtc_data);
290         if (ret < 0)
291                 dev_err(bc_dev->parent_dev,
292                         "Setting power on event failed: %d\n", ret);
293         return ret;
294 }
295 EXPORT_SYMBOL_GPL(battery_charging_system_reset_after);
296
297 int battery_charging_system_power_on_usb_event(
298         struct battery_charger_dev *bc_dev)
299 {
300         int ret;
301
302         dev_info(bc_dev->parent_dev,
303                 "Setting system on with USB connect/disconnect\n");
304
305         ret = system_pmic_set_power_on_event(SYSTEM_PMIC_USB_VBUS_INSERTION,
306                 NULL);
307         if (ret < 0)
308                 dev_err(bc_dev->parent_dev,
309                         "Setting power on event failed: %d\n", ret);
310         return ret;
311 }
312 EXPORT_SYMBOL_GPL(battery_charging_system_power_on_usb_event);
313
314 struct battery_charger_dev *battery_charger_register(struct device *dev,
315         struct battery_charger_info *bci, void *drv_data)
316 {
317         struct battery_charger_dev *bc_dev;
318
319         dev_info(dev, "Registering battery charger driver\n");
320
321         if (!dev || !bci) {
322                 dev_err(dev, "Invalid parameters\n");
323                 return ERR_PTR(-EINVAL);
324         }
325
326         bc_dev = kzalloc(sizeof(*bc_dev), GFP_KERNEL);
327         if (!bc_dev) {
328                 dev_err(dev, "Memory alloc for bc_dev failed\n");
329                 return ERR_PTR(-ENOMEM);
330         }
331
332         mutex_lock(&charger_gauge_list_mutex);
333
334         INIT_LIST_HEAD(&bc_dev->list);
335         bc_dev->cell_id = bci->cell_id;
336         bc_dev->ops = bci->bc_ops;
337         bc_dev->parent_dev = dev;
338         bc_dev->drv_data = drv_data;
339
340         /* Thermal monitoring */
341         if (!bc_dev->tz_name) {
342                 bc_dev->polling_time_sec = bci->polling_time_sec;
343                 strcpy(bc_dev->tz_name, bci->tz_name ? : "");
344                 bc_dev->battery_tz = thermal_zone_device_find_by_name(
345                                                 bc_dev->tz_name);
346                 if (!bc_dev->battery_tz)
347                         dev_info(dev,
348                             "Battery thermal zone %s is not registered yet\n",
349                                 bc_dev->tz_name);
350                 INIT_DELAYED_WORK(&bc_dev->poll_temp_monitor_wq,
351                                 battery_charger_thermal_monitor_wq);
352         }
353
354         INIT_DELAYED_WORK(&bc_dev->restart_charging_wq,
355                         battery_charger_restart_charging_wq);
356
357         wake_lock_init(&bc_dev->charger_wake_lock, WAKE_LOCK_SUSPEND,
358                                                 "charger-suspend-lock");
359         list_add(&bc_dev->list, &charger_list);
360         mutex_unlock(&charger_gauge_list_mutex);
361         return bc_dev;
362 }
363 EXPORT_SYMBOL_GPL(battery_charger_register);
364
365 void battery_charger_unregister(struct battery_charger_dev *bc_dev)
366 {
367         mutex_lock(&charger_gauge_list_mutex);
368         list_del(&bc_dev->list);
369         if (bc_dev->polling_time_sec)
370                 cancel_delayed_work(&bc_dev->poll_temp_monitor_wq);
371         cancel_delayed_work(&bc_dev->restart_charging_wq);
372         wake_lock_destroy(&bc_dev->charger_wake_lock);
373         mutex_unlock(&charger_gauge_list_mutex);
374         kfree(bc_dev);
375 }
376 EXPORT_SYMBOL_GPL(battery_charger_unregister);
377
378 int battery_gauge_get_battery_temperature(struct battery_gauge_dev *bg_dev,
379         int *temp)
380 {
381         int ret;
382         long temperature;
383
384         if (!bg_dev)
385                 return -EINVAL;
386
387         if (!bg_dev->battery_tz)
388                 bg_dev->battery_tz =
389                         thermal_zone_device_find_by_name(bg_dev->tz_name);
390
391         if (!bg_dev->battery_tz) {
392                 dev_info(bg_dev->parent_dev,
393                         "Battery thermal zone %s is not registered yet\n",
394                         bg_dev->tz_name);
395                 return -ENODEV;
396         }
397
398         ret = thermal_zone_get_temp(bg_dev->battery_tz, &temperature);
399         if (ret < 0)
400                 return ret;
401
402         *temp = temperature / 1000;
403         return 0;
404 }
405 EXPORT_SYMBOL_GPL(battery_gauge_get_battery_temperature);
406
407 struct battery_gauge_dev *battery_gauge_register(struct device *dev,
408         struct battery_gauge_info *bgi, void *drv_data)
409 {
410         struct battery_gauge_dev *bg_dev;
411
412         dev_info(dev, "Registering battery gauge driver\n");
413
414         if (!dev || !bgi) {
415                 dev_err(dev, "Invalid parameters\n");
416                 return ERR_PTR(-EINVAL);
417         }
418
419         bg_dev = kzalloc(sizeof(*bg_dev), GFP_KERNEL);
420         if (!bg_dev) {
421                 dev_err(dev, "Memory alloc for bg_dev failed\n");
422                 return ERR_PTR(-ENOMEM);
423         }
424
425         mutex_lock(&charger_gauge_list_mutex);
426
427         INIT_LIST_HEAD(&bg_dev->list);
428         bg_dev->cell_id = bgi->cell_id;
429         bg_dev->ops = bgi->bg_ops;
430         bg_dev->parent_dev = dev;
431         bg_dev->drv_data = drv_data;
432         strcpy(bg_dev->tz_name, bgi->tz_name ? : "");
433         bg_dev->battery_tz = thermal_zone_device_find_by_name(bg_dev->tz_name);
434         if (!bg_dev->battery_tz)
435                 dev_info(dev, "Battery thermal zone %s is not registered yet\n",
436                         bg_dev->tz_name);
437         list_add(&bg_dev->list, &gauge_list);
438         mutex_unlock(&charger_gauge_list_mutex);
439         return bg_dev;
440 }
441 EXPORT_SYMBOL_GPL(battery_gauge_register);
442
443 void battery_gauge_unregister(struct battery_gauge_dev *bg_dev)
444 {
445         mutex_lock(&charger_gauge_list_mutex);
446         list_del(&bg_dev->list);
447         mutex_unlock(&charger_gauge_list_mutex);
448         kfree(bg_dev);
449 }
450 EXPORT_SYMBOL_GPL(battery_gauge_unregister);
451
452 int battery_charging_status_update(struct battery_charger_dev *bc_dev,
453         enum battery_charger_status status)
454 {
455         struct battery_gauge_dev *node;
456         int ret = -EINVAL;
457
458         if (!bc_dev) {
459                 dev_err(bc_dev->parent_dev, "Invalid parameters\n");
460                 return -EINVAL;
461         }
462
463         mutex_lock(&charger_gauge_list_mutex);
464
465         list_for_each_entry(node, &gauge_list, list) {
466                 if (node->cell_id != bc_dev->cell_id)
467                         continue;
468                 if (node->ops && node->ops->update_battery_status)
469                         ret = node->ops->update_battery_status(node, status);
470         }
471
472         mutex_unlock(&charger_gauge_list_mutex);
473         return ret;
474 }
475 EXPORT_SYMBOL_GPL(battery_charging_status_update);
476
477 void *battery_charger_get_drvdata(struct battery_charger_dev *bc_dev)
478 {
479         if (bc_dev)
480                 return bc_dev->drv_data;
481         return NULL;
482 }
483 EXPORT_SYMBOL_GPL(battery_charger_get_drvdata);
484
485 void battery_charger_set_drvdata(struct battery_charger_dev *bc_dev, void *data)
486 {
487         if (bc_dev)
488                 bc_dev->drv_data = data;
489 }
490 EXPORT_SYMBOL_GPL(battery_charger_set_drvdata);
491
492 void *battery_gauge_get_drvdata(struct battery_gauge_dev *bg_dev)
493 {
494         if (bg_dev)
495                 return bg_dev->drv_data;
496         return NULL;
497 }
498 EXPORT_SYMBOL_GPL(battery_gauge_get_drvdata);
499
500 void battery_gauge_set_drvdata(struct battery_gauge_dev *bg_dev, void *data)
501 {
502         if (bg_dev)
503                 bg_dev->drv_data = data;
504 }
505 EXPORT_SYMBOL_GPL(battery_gauge_set_drvdata);