blob: d49c23e864c3e22b791372ce61c4e148b25bcf72 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/htc_battery.c
2 *
3 * Copyright (C) 2008 HTC Corporation.
4 * Copyright (C) 2008 Google, Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/init.h>
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/err.h>
21#include <linux/power_supply.h>
22#include <linux/platform_device.h>
23#include <linux/debugfs.h>
24#include <linux/wakelock.h>
25#include <asm/gpio.h>
26#include <mach/msm_rpcrouter.h>
27#include <mach/board.h>
28
29static struct wake_lock vbus_wake_lock;
30
31#define TRACE_BATT 0
32
33#if TRACE_BATT
34#define BATT(x...) printk(KERN_INFO "[BATT] " x)
35#else
36#define BATT(x...) do {} while (0)
37#endif
38
39/* rpc related */
40#define APP_BATT_PDEV_NAME "rs30100001"
41#define APP_BATT_PROG 0x30100001
42#define APP_BATT_VER 0
43#define HTC_PROCEDURE_BATTERY_NULL 0
44#define HTC_PROCEDURE_GET_BATT_LEVEL 1
45#define HTC_PROCEDURE_GET_BATT_INFO 2
46#define HTC_PROCEDURE_GET_CABLE_STATUS 3
47#define HTC_PROCEDURE_SET_BATT_DELTA 4
48
49/* module debugger */
50#define HTC_BATTERY_DEBUG 1
51#define BATTERY_PREVENTION 1
52
53/* Enable this will shut down if no battery */
54#define ENABLE_BATTERY_DETECTION 0
55
56#define GPIO_BATTERY_DETECTION 21
57#define GPIO_BATTERY_CHARGER_EN 128
58
59/* Charge current selection */
60#define GPIO_BATTERY_CHARGER_CURRENT 129
61
62typedef enum {
63 DISABLE = 0,
64 ENABLE_SLOW_CHG,
65 ENABLE_FAST_CHG
66} batt_ctl_t;
67
68/* This order is the same as htc_power_supplies[]
69 * And it's also the same as htc_cable_status_update()
70 */
71typedef enum {
72 CHARGER_BATTERY = 0,
73 CHARGER_USB,
74 CHARGER_AC
75} charger_type_t;
76
77struct battery_info_reply {
78 u32 batt_id; /* Battery ID from ADC */
79 u32 batt_vol; /* Battery voltage from ADC */
80 u32 batt_temp; /* Battery Temperature (C) from formula and ADC */
81 u32 batt_current; /* Battery current from ADC */
82 u32 level; /* formula */
83 u32 charging_source; /* 0: no cable, 1:usb, 2:AC */
84 u32 charging_enabled; /* 0: Disable, 1: Enable */
85 u32 full_bat; /* Full capacity of battery (mAh) */
86};
87
88struct htc_battery_info {
89 int present;
90 unsigned long update_time;
91
92 /* lock to protect the battery info */
93 struct mutex lock;
94
95 /* lock held while calling the arm9 to query the battery info */
96 struct mutex rpc_lock;
97 struct battery_info_reply rep;
98};
99
100static struct msm_rpc_endpoint *endpoint;
101
102static struct htc_battery_info htc_batt_info;
103
104static unsigned int cache_time = 1000;
105
106static int htc_battery_initial = 0;
107
108static enum power_supply_property htc_battery_properties[] = {
109 POWER_SUPPLY_PROP_STATUS,
110 POWER_SUPPLY_PROP_HEALTH,
111 POWER_SUPPLY_PROP_PRESENT,
112 POWER_SUPPLY_PROP_TECHNOLOGY,
113 POWER_SUPPLY_PROP_CAPACITY,
114};
115
116static enum power_supply_property htc_power_properties[] = {
117 POWER_SUPPLY_PROP_ONLINE,
118};
119
120static char *supply_list[] = {
121 "battery",
122};
123
124/* HTC dedicated attributes */
125static ssize_t htc_battery_show_property(struct device *dev,
126 struct device_attribute *attr,
127 char *buf);
128
129static int htc_power_get_property(struct power_supply *psy,
130 enum power_supply_property psp,
131 union power_supply_propval *val);
132
133static int htc_battery_get_property(struct power_supply *psy,
134 enum power_supply_property psp,
135 union power_supply_propval *val);
136
137static struct power_supply htc_power_supplies[] = {
138 {
139 .name = "battery",
140 .type = POWER_SUPPLY_TYPE_BATTERY,
141 .properties = htc_battery_properties,
142 .num_properties = ARRAY_SIZE(htc_battery_properties),
143 .get_property = htc_battery_get_property,
144 },
145 {
146 .name = "usb",
147 .type = POWER_SUPPLY_TYPE_USB,
148 .supplied_to = supply_list,
149 .num_supplicants = ARRAY_SIZE(supply_list),
150 .properties = htc_power_properties,
151 .num_properties = ARRAY_SIZE(htc_power_properties),
152 .get_property = htc_power_get_property,
153 },
154 {
155 .name = "ac",
156 .type = POWER_SUPPLY_TYPE_MAINS,
157 .supplied_to = supply_list,
158 .num_supplicants = ARRAY_SIZE(supply_list),
159 .properties = htc_power_properties,
160 .num_properties = ARRAY_SIZE(htc_power_properties),
161 .get_property = htc_power_get_property,
162 },
163};
164
165
166/* -------------------------------------------------------------------------- */
167
168#if defined(CONFIG_DEBUG_FS)
169int htc_battery_set_charging(batt_ctl_t ctl);
170static int batt_debug_set(void *data, u64 val)
171{
172 return htc_battery_set_charging((batt_ctl_t) val);
173}
174
175static int batt_debug_get(void *data, u64 *val)
176{
177 return -ENOSYS;
178}
179
180DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n");
181static int __init batt_debug_init(void)
182{
183 struct dentry *dent;
184
185 dent = debugfs_create_dir("htc_battery", 0);
186 if (IS_ERR(dent))
187 return PTR_ERR(dent);
188
189 debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops);
190
191 return 0;
192}
193
194device_initcall(batt_debug_init);
195#endif
196
197static int init_batt_gpio(void)
198{
199 if (gpio_request(GPIO_BATTERY_DETECTION, "batt_detect") < 0)
200 goto gpio_failed;
201 if (gpio_request(GPIO_BATTERY_CHARGER_EN, "charger_en") < 0)
202 goto gpio_failed;
203 if (gpio_request(GPIO_BATTERY_CHARGER_CURRENT, "charge_current") < 0)
204 goto gpio_failed;
205
206 return 0;
207
208gpio_failed:
209 return -EINVAL;
210
211}
212
213/*
214 * battery_charging_ctrl - battery charing control.
215 * @ctl: battery control command
216 *
217 */
218static int battery_charging_ctrl(batt_ctl_t ctl)
219{
220 int result = 0;
221
222 switch (ctl) {
223 case DISABLE:
224 BATT("charger OFF\n");
225 /* 0 for enable; 1 disable */
226 result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 1);
227 break;
228 case ENABLE_SLOW_CHG:
229 BATT("charger ON (SLOW)\n");
230 result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 0);
231 result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
232 break;
233 case ENABLE_FAST_CHG:
234 BATT("charger ON (FAST)\n");
235 result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 1);
236 result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
237 break;
238 default:
239 printk(KERN_ERR "Not supported battery ctr called.!\n");
240 result = -EINVAL;
241 break;
242 }
243
244 return result;
245}
246
247int htc_battery_set_charging(batt_ctl_t ctl)
248{
249 int rc;
250
251 if ((rc = battery_charging_ctrl(ctl)) < 0)
252 goto result;
253
254 if (!htc_battery_initial) {
255 htc_batt_info.rep.charging_enabled = ctl & 0x3;
256 } else {
257 mutex_lock(&htc_batt_info.lock);
258 htc_batt_info.rep.charging_enabled = ctl & 0x3;
259 mutex_unlock(&htc_batt_info.lock);
260 }
261result:
262 return rc;
263}
264
265int htc_battery_status_update(u32 curr_level)
266{
267 int notify;
268 if (!htc_battery_initial)
269 return 0;
270
271 mutex_lock(&htc_batt_info.lock);
272 notify = (htc_batt_info.rep.level != curr_level);
273 htc_batt_info.rep.level = curr_level;
274 mutex_unlock(&htc_batt_info.lock);
275
276 if (notify)
277 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
278 return 0;
279}
280
281int htc_cable_status_update(int status)
282{
283 int rc = 0;
284 unsigned source;
285
286 if (!htc_battery_initial)
287 return 0;
288
289 mutex_lock(&htc_batt_info.lock);
290 switch(status) {
291 case CHARGER_BATTERY:
292 BATT("cable NOT PRESENT\n");
293 htc_batt_info.rep.charging_source = CHARGER_BATTERY;
294 break;
295 case CHARGER_USB:
296 BATT("cable USB\n");
297 htc_batt_info.rep.charging_source = CHARGER_USB;
298 break;
299 case CHARGER_AC:
300 BATT("cable AC\n");
301 htc_batt_info.rep.charging_source = CHARGER_AC;
302 break;
303 default:
304 printk(KERN_ERR "%s: Not supported cable status received!\n",
305 __FUNCTION__);
306 rc = -EINVAL;
307 }
308 source = htc_batt_info.rep.charging_source;
309 mutex_unlock(&htc_batt_info.lock);
310
311 msm_hsusb_set_vbus_state(source == CHARGER_USB);
312 if (source == CHARGER_USB) {
313 wake_lock(&vbus_wake_lock);
314 } else {
315 /* give userspace some time to see the uevent and update
316 * LED state or whatnot...
317 */
318 wake_lock_timeout(&vbus_wake_lock, HZ / 2);
319 }
320
321 /* if the power source changes, all power supplies may change state */
322 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
323 power_supply_changed(&htc_power_supplies[CHARGER_USB]);
324 power_supply_changed(&htc_power_supplies[CHARGER_AC]);
325
326 return rc;
327}
328
329static int htc_get_batt_info(struct battery_info_reply *buffer)
330{
331 struct rpc_request_hdr req;
332
333 struct htc_get_batt_info_rep {
334 struct rpc_reply_hdr hdr;
335 struct battery_info_reply info;
336 } rep;
337
338 int rc;
339
340 if (buffer == NULL)
341 return -EINVAL;
342
343 rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
344 &req, sizeof(req),
345 &rep, sizeof(rep),
346 5 * HZ);
347 if ( rc < 0 )
348 return rc;
349
350 mutex_lock(&htc_batt_info.lock);
351 buffer->batt_id = be32_to_cpu(rep.info.batt_id);
352 buffer->batt_vol = be32_to_cpu(rep.info.batt_vol);
353 buffer->batt_temp = be32_to_cpu(rep.info.batt_temp);
354 buffer->batt_current = be32_to_cpu(rep.info.batt_current);
355 buffer->level = be32_to_cpu(rep.info.level);
356 buffer->charging_source = be32_to_cpu(rep.info.charging_source);
357 buffer->charging_enabled = be32_to_cpu(rep.info.charging_enabled);
358 buffer->full_bat = be32_to_cpu(rep.info.full_bat);
359 mutex_unlock(&htc_batt_info.lock);
360
361 return 0;
362}
363
364#if 0
365static int htc_get_cable_status(void)
366{
367
368 struct rpc_request_hdr req;
369
370 struct htc_get_cable_status_rep {
371 struct rpc_reply_hdr hdr;
372 int status;
373 } rep;
374
375 int rc;
376
377 rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_CABLE_STATUS,
378 &req, sizeof(req),
379 &rep, sizeof(rep),
380 5 * HZ);
381 if (rc < 0)
382 return rc;
383
384 return be32_to_cpu(rep.status);
385}
386#endif
387
388/* -------------------------------------------------------------------------- */
389static int htc_power_get_property(struct power_supply *psy,
390 enum power_supply_property psp,
391 union power_supply_propval *val)
392{
393 charger_type_t charger;
394
395 mutex_lock(&htc_batt_info.lock);
396 charger = htc_batt_info.rep.charging_source;
397 mutex_unlock(&htc_batt_info.lock);
398
399 switch (psp) {
400 case POWER_SUPPLY_PROP_ONLINE:
401 if (psy->type == POWER_SUPPLY_TYPE_MAINS)
402 val->intval = (charger == CHARGER_AC ? 1 : 0);
403 else if (psy->type == POWER_SUPPLY_TYPE_USB)
404 val->intval = (charger == CHARGER_USB ? 1 : 0);
405 else
406 val->intval = 0;
407 break;
408 default:
409 return -EINVAL;
410 }
411
412 return 0;
413}
414
415static int htc_battery_get_charging_status(void)
416{
417 u32 level;
418 charger_type_t charger;
419 int ret;
420
421 mutex_lock(&htc_batt_info.lock);
422 charger = htc_batt_info.rep.charging_source;
423
424 switch (charger) {
425 case CHARGER_BATTERY:
426 ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
427 break;
428 case CHARGER_USB:
429 case CHARGER_AC:
430 level = htc_batt_info.rep.level;
431 if (level == 100)
432 ret = POWER_SUPPLY_STATUS_FULL;
433 else
434 ret = POWER_SUPPLY_STATUS_CHARGING;
435 break;
436 default:
437 ret = POWER_SUPPLY_STATUS_UNKNOWN;
438 }
439 mutex_unlock(&htc_batt_info.lock);
440 return ret;
441}
442
443static int htc_battery_get_property(struct power_supply *psy,
444 enum power_supply_property psp,
445 union power_supply_propval *val)
446{
447 switch (psp) {
448 case POWER_SUPPLY_PROP_STATUS:
449 val->intval = htc_battery_get_charging_status();
450 break;
451 case POWER_SUPPLY_PROP_HEALTH:
452 val->intval = POWER_SUPPLY_HEALTH_GOOD;
453 break;
454 case POWER_SUPPLY_PROP_PRESENT:
455 val->intval = htc_batt_info.present;
456 break;
457 case POWER_SUPPLY_PROP_TECHNOLOGY:
458 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
459 break;
460 case POWER_SUPPLY_PROP_CAPACITY:
461 mutex_lock(&htc_batt_info.lock);
462 val->intval = htc_batt_info.rep.level;
463 mutex_unlock(&htc_batt_info.lock);
464 break;
465 default:
466 return -EINVAL;
467 }
468
469 return 0;
470}
471
472#define HTC_BATTERY_ATTR(_name) \
473{ \
474 .attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE }, \
475 .show = htc_battery_show_property, \
476 .store = NULL, \
477}
478
479static struct device_attribute htc_battery_attrs[] = {
480 HTC_BATTERY_ATTR(batt_id),
481 HTC_BATTERY_ATTR(batt_vol),
482 HTC_BATTERY_ATTR(batt_temp),
483 HTC_BATTERY_ATTR(batt_current),
484 HTC_BATTERY_ATTR(charging_source),
485 HTC_BATTERY_ATTR(charging_enabled),
486 HTC_BATTERY_ATTR(full_bat),
487};
488
489enum {
490 BATT_ID = 0,
491 BATT_VOL,
492 BATT_TEMP,
493 BATT_CURRENT,
494 CHARGING_SOURCE,
495 CHARGING_ENABLED,
496 FULL_BAT,
497};
498
499static int htc_rpc_set_delta(unsigned delta)
500{
501 struct set_batt_delta_req {
502 struct rpc_request_hdr hdr;
503 uint32_t data;
504 } req;
505
506 req.data = cpu_to_be32(delta);
507 return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA,
508 &req, sizeof(req), 5 * HZ);
509}
510
511
512static ssize_t htc_battery_set_delta(struct device *dev,
513 struct device_attribute *attr,
514 const char *buf, size_t count)
515{
516 int rc;
517 unsigned long delta = 0;
518
519 delta = simple_strtoul(buf, NULL, 10);
520
521 if (delta > 100)
522 return -EINVAL;
523
524 mutex_lock(&htc_batt_info.rpc_lock);
525 rc = htc_rpc_set_delta(delta);
526 mutex_unlock(&htc_batt_info.rpc_lock);
527 if (rc < 0)
528 return rc;
529 return count;
530}
531
532static struct device_attribute htc_set_delta_attrs[] = {
533 __ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta),
534};
535
536static int htc_battery_create_attrs(struct device * dev)
537{
538 int i, j, rc;
539
540 for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) {
541 rc = device_create_file(dev, &htc_battery_attrs[i]);
542 if (rc)
543 goto htc_attrs_failed;
544 }
545
546 for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) {
547 rc = device_create_file(dev, &htc_set_delta_attrs[j]);
548 if (rc)
549 goto htc_delta_attrs_failed;
550 }
551
552 goto succeed;
553
554htc_attrs_failed:
555 while (i--)
556 device_remove_file(dev, &htc_battery_attrs[i]);
557htc_delta_attrs_failed:
558 while (j--)
559 device_remove_file(dev, &htc_set_delta_attrs[i]);
560succeed:
561 return rc;
562}
563
564static ssize_t htc_battery_show_property(struct device *dev,
565 struct device_attribute *attr,
566 char *buf)
567{
568 int i = 0;
569 const ptrdiff_t off = attr - htc_battery_attrs;
570
571 /* rpc lock is used to prevent two threads from calling
572 * into the get info rpc at the same time
573 */
574
575 mutex_lock(&htc_batt_info.rpc_lock);
576 /* check cache time to decide if we need to update */
577 if (htc_batt_info.update_time &&
578 time_before(jiffies, htc_batt_info.update_time +
579 msecs_to_jiffies(cache_time)))
580 goto dont_need_update;
581
582 if (htc_get_batt_info(&htc_batt_info.rep) < 0)
583 printk(KERN_ERR "%s: rpc failed!!!\n", __FUNCTION__);
584 else
585 htc_batt_info.update_time = jiffies;
586dont_need_update:
587 mutex_unlock(&htc_batt_info.rpc_lock);
588
589 mutex_lock(&htc_batt_info.lock);
590 switch (off) {
591 case BATT_ID:
592 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
593 htc_batt_info.rep.batt_id);
594 break;
595 case BATT_VOL:
596 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
597 htc_batt_info.rep.batt_vol);
598 break;
599 case BATT_TEMP:
600 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
601 htc_batt_info.rep.batt_temp);
602 break;
603 case BATT_CURRENT:
604 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
605 htc_batt_info.rep.batt_current);
606 break;
607 case CHARGING_SOURCE:
608 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
609 htc_batt_info.rep.charging_source);
610 break;
611 case CHARGING_ENABLED:
612 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
613 htc_batt_info.rep.charging_enabled);
614 break;
615 case FULL_BAT:
616 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
617 htc_batt_info.rep.full_bat);
618 break;
619 default:
620 i = -EINVAL;
621 }
622 mutex_unlock(&htc_batt_info.lock);
623
624 return i;
625}
626
627static int htc_battery_probe(struct platform_device *pdev)
628{
629 int i, rc;
630
631 if (pdev->id != (APP_BATT_VER & RPC_VERSION_MAJOR_MASK))
632 return -EINVAL;
633
634 /* init battery gpio */
635 if ((rc = init_batt_gpio()) < 0) {
636 printk(KERN_ERR "%s: init battery gpio failed!\n", __FUNCTION__);
637 return rc;
638 }
639
640 /* init structure data member */
641 htc_batt_info.update_time = jiffies;
642 htc_batt_info.present = gpio_get_value(GPIO_BATTERY_DETECTION);
643
644 /* init rpc */
645 endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
646 if (IS_ERR(endpoint)) {
647 printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
648 __FUNCTION__, PTR_ERR(endpoint));
649 return rc;
650 }
651
652 /* init power supplier framework */
653 for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) {
654 rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]);
655 if (rc)
656 printk(KERN_ERR "Failed to register power supply (%d)\n", rc);
657 }
658
659 /* create htc detail attributes */
660 htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev);
661
662 /* After battery driver gets initialized, send rpc request to inquiry
663 * the battery status in case of we lost some info
664 */
665 htc_battery_initial = 1;
666
667 mutex_lock(&htc_batt_info.rpc_lock);
668 if (htc_get_batt_info(&htc_batt_info.rep) < 0)
669 printk(KERN_ERR "%s: get info failed\n", __FUNCTION__);
670
671 htc_cable_status_update(htc_batt_info.rep.charging_source);
672 battery_charging_ctrl(htc_batt_info.rep.charging_enabled ?
673 ENABLE_SLOW_CHG : DISABLE);
674
675 if (htc_rpc_set_delta(1) < 0)
676 printk(KERN_ERR "%s: set delta failed\n", __FUNCTION__);
677 htc_batt_info.update_time = jiffies;
678 mutex_unlock(&htc_batt_info.rpc_lock);
679
680 if (htc_batt_info.rep.charging_enabled == 0)
681 battery_charging_ctrl(DISABLE);
682
683 return 0;
684}
685
686static struct platform_driver htc_battery_driver = {
687 .probe = htc_battery_probe,
688 .driver = {
689 .name = APP_BATT_PDEV_NAME,
690 .owner = THIS_MODULE,
691 },
692};
693
694/* batt_mtoa server definitions */
695#define BATT_MTOA_PROG 0x30100000
696#define BATT_MTOA_VERS 0
697#define RPC_BATT_MTOA_NULL 0
698#define RPC_BATT_MTOA_SET_CHARGING_PROC 1
699#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC 2
700#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC 3
701
702struct rpc_batt_mtoa_set_charging_args {
703 int enable;
704};
705
706struct rpc_batt_mtoa_cable_status_update_args {
707 int status;
708};
709
710struct rpc_dem_battery_update_args {
711 uint32_t level;
712};
713
714static int handle_battery_call(struct msm_rpc_server *server,
715 struct rpc_request_hdr *req, unsigned len)
716{
717 switch (req->procedure) {
718 case RPC_BATT_MTOA_NULL:
719 return 0;
720
721 case RPC_BATT_MTOA_SET_CHARGING_PROC: {
722 struct rpc_batt_mtoa_set_charging_args *args;
723 args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1);
724 args->enable = be32_to_cpu(args->enable);
725 BATT("set_charging: enable=%d\n",args->enable);
726 htc_battery_set_charging(args->enable);
727 return 0;
728 }
729 case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: {
730 struct rpc_batt_mtoa_cable_status_update_args *args;
731 args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
732 args->status = be32_to_cpu(args->status);
733 BATT("cable_status_update: status=%d\n",args->status);
734 htc_cable_status_update(args->status);
735 return 0;
736 }
737 case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: {
738 struct rpc_dem_battery_update_args *args;
739 args = (struct rpc_dem_battery_update_args *)(req + 1);
740 args->level = be32_to_cpu(args->level);
741 BATT("dem_battery_update: level=%d\n",args->level);
742 htc_battery_status_update(args->level);
743 return 0;
744 }
745 default:
746 printk(KERN_ERR "%s: program 0x%08x:%d: unknown procedure %d\n",
747 __FUNCTION__, req->prog, req->vers, req->procedure);
748 return -ENODEV;
749 }
750}
751
752static struct msm_rpc_server battery_server = {
753 .prog = BATT_MTOA_PROG,
754 .vers = BATT_MTOA_VERS,
755 .rpc_call = handle_battery_call,
756};
757
758static int __init htc_battery_init(void)
759{
760 wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
761 mutex_init(&htc_batt_info.lock);
762 mutex_init(&htc_batt_info.rpc_lock);
763 msm_rpc_create_server(&battery_server);
764 platform_driver_register(&htc_battery_driver);
765 return 0;
766}
767
768module_init(htc_battery_init);
769MODULE_DESCRIPTION("HTC Battery Driver");
770MODULE_LICENSE("GPL");
771