htcleo: add Cotulla's fixes for non-android touchscreen!
[htc-linux.git] / arch / arm / mach-msm / htc_battery.c
blob19f4effba9265ca055126788f70635bb765d2b4d
1 /* arch/arm/mach-msm/htc_battery.c
3 * Copyright (C) 2008 HTC Corporation.
4 * Copyright (C) 2008 Google, Inc.
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.
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.
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 #include <asm/mach-types.h>
29 #include <mach/board_htc.h>
30 #include <mach/msm_fb.h> /* Jay, to register display notifier */
31 #include <mach/htc_battery.h>
32 #include <linux/rtc.h>
33 #include <linux/workqueue.h>
34 #include <linux/tps65200.h>
35 #ifdef CONFIG_HTC_BATTCHG_SMEM
36 #include "smd_private.h"
37 #endif
38 #include <linux/io.h>
39 #include <mach/msm_iomap.h>
41 #if defined(CONFIG_TROUT_BATTCHG_DOCK)
42 #include <mach/htc_one_wire.h>
43 #endif
44 #ifdef CONFIG_BATTERY_DS2784
45 #include <linux/ds2784_battery.h>
46 #elif defined(CONFIG_BATTERY_DS2746)
47 #include <linux/ds2746_battery.h>
48 #endif
50 static struct wake_lock vbus_wake_lock;
52 enum {
53 HTC_BATT_DEBUG_M2A_RPC = 1U << 0,
54 HTC_BATT_DEBUG_A2M_RPC = 1U << 1,
55 HTC_BATT_DEBUG_UEVT = 1U << 2,
56 HTC_BATT_DEBUG_USER_QUERY = 1U << 3,
57 HTC_BATT_DEBUG_USB_NOTIFY = 1U << 4,
58 HTC_BATT_DEBUG_SMEM = 1U << 5,
60 static int htc_batt_debug_mask = HTC_BATT_DEBUG_M2A_RPC | HTC_BATT_DEBUG_A2M_RPC
61 | HTC_BATT_DEBUG_UEVT | HTC_BATT_DEBUG_USB_NOTIFY | HTC_BATT_DEBUG_SMEM;
62 module_param_named(debug_mask, htc_batt_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
64 #define BATT_LOG(x...) do { \
65 struct timespec ts; \
66 struct rtc_time tm; \
67 getnstimeofday(&ts); \
68 rtc_time_to_tm(ts.tv_sec, &tm); \
69 printk(KERN_INFO "batt: " x); \
70 printk(" at %lld (%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", \
71 ktime_to_ns(ktime_get()), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
72 tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
73 } while (0)
75 #define BATT_ERR(x...) do { \
76 struct timespec ts; \
77 struct rtc_time tm; \
78 getnstimeofday(&ts); \
79 rtc_time_to_tm(ts.tv_sec, &tm); \
80 printk(KERN_ERR "batt: err:" x); \
81 printk(" at %lld (%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", \
82 ktime_to_ns(ktime_get()), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
83 tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
84 } while (0)
86 /* rpc related */
87 #define APP_BATT_PDEV_NAME "rs30100001:00000000"
88 #define APP_BATT_PROG 0x30100001
89 #define APP_BATT_VER MSM_RPC_VERS(0,0)
90 #define HTC_PROCEDURE_BATTERY_NULL 0
91 #define HTC_PROCEDURE_GET_BATT_LEVEL 1
92 #define HTC_PROCEDURE_GET_BATT_INFO 2
93 #define HTC_PROCEDURE_GET_CABLE_STATUS 3
94 #define HTC_PROCEDURE_SET_BATT_DELTA 4
95 #define HTC_PROCEDURE_CHARGER_SWITCH 6
96 #define HTC_PROCEDURE_SET_FULL_LEVEL 7
97 #define HTC_PROCEDURE_GET_USB_ACCESSORY_ADC_LEVEL 10
99 const char *charger_tags[] = {"none", "USB", "AC"};
101 struct htc_battery_info {
102 int device_id;
103 int present;
104 unsigned long update_time;
106 /* lock to protect the battery info */
107 struct mutex lock;
109 /* lock held while calling the arm9 to query the battery info */
110 struct mutex rpc_lock;
111 struct battery_info_reply rep;
112 int (*func_show_batt_attr)(struct device_attribute *attr, char *buf);
113 int gpio_mbat_in;
114 int gpio_usb_id;
115 int gpio_mchg_en_n;
116 int gpio_iset;
117 int gpio_power;
118 int guage_driver;
119 int m2a_cable_detect;
120 int force_no_rpc;
121 int charger;
124 static struct msm_rpc_endpoint *endpoint;
126 static struct htc_battery_info htc_batt_info;
128 /* Remove cache mechanism to prevent cable status not sync. */
129 static unsigned int cache_time;
131 static int htc_battery_initial = 0;
132 static int htc_full_level_flag = 0;
134 static enum power_supply_property htc_battery_properties[] = {
135 POWER_SUPPLY_PROP_STATUS,
136 POWER_SUPPLY_PROP_HEALTH,
137 POWER_SUPPLY_PROP_PRESENT,
138 POWER_SUPPLY_PROP_TECHNOLOGY,
139 POWER_SUPPLY_PROP_CAPACITY,
142 static enum power_supply_property htc_power_properties[] = {
143 POWER_SUPPLY_PROP_ONLINE,
146 static char *supply_list[] = {
147 "battery",
150 /* HTC dedicated attributes */
151 static ssize_t htc_battery_show_property(struct device *dev,
152 struct device_attribute *attr,
153 char *buf);
155 static int htc_power_get_property(struct power_supply *psy,
156 enum power_supply_property psp,
157 union power_supply_propval *val);
159 static int htc_battery_get_property(struct power_supply *psy,
160 enum power_supply_property psp,
161 union power_supply_propval *val);
163 static struct power_supply htc_power_supplies[] = {
165 .name = "battery",
166 .type = POWER_SUPPLY_TYPE_BATTERY,
167 .properties = htc_battery_properties,
168 .num_properties = ARRAY_SIZE(htc_battery_properties),
169 .get_property = htc_battery_get_property,
172 .name = "usb",
173 .type = POWER_SUPPLY_TYPE_USB,
174 .supplied_to = supply_list,
175 .num_supplicants = ARRAY_SIZE(supply_list),
176 .properties = htc_power_properties,
177 .num_properties = ARRAY_SIZE(htc_power_properties),
178 .get_property = htc_power_get_property,
181 .name = "ac",
182 .type = POWER_SUPPLY_TYPE_MAINS,
183 .supplied_to = supply_list,
184 .num_supplicants = ARRAY_SIZE(supply_list),
185 .properties = htc_power_properties,
186 .num_properties = ARRAY_SIZE(htc_power_properties),
187 .get_property = htc_power_get_property,
191 static int update_batt_info(void);
192 static void usb_status_notifier_func(int online);
193 //static int g_usb_online;
194 static struct t_usb_status_notifier usb_status_notifier = {
195 .name = "htc_battery",
196 .func = usb_status_notifier_func,
199 /* Move cable detection/notification to standard PMIC RPC. */
200 static BLOCKING_NOTIFIER_HEAD(cable_status_notifier_list);
201 int register_notifier_cable_status(struct notifier_block *nb)
203 return blocking_notifier_chain_register(&cable_status_notifier_list, nb);
206 int unregister_notifier_cable_status(struct notifier_block *nb)
208 return blocking_notifier_chain_unregister(&cable_status_notifier_list, nb);
211 /* -------------------------------------------------------------------------- */
212 /* HTCLeo Dex Functions. */
213 #if defined(CONFIG_MACH_HTCLEO)
215 static int get_vbus_state(void)
217 if (readl(MSM_SHARED_RAM_BASE + 0xEF20C))
218 return 1;
219 else
220 return 0;
223 void notify_cable_status(int status)
225 pr_info("notify_cable_status(%d)\n", status);
226 msm_hsusb_set_vbus_state(status);
229 // called from DEX intrrupt
230 void notify_vbus_change_intr(void)
232 int vbus;
233 if (!htc_battery_initial) return;
234 vbus = get_vbus_state();
235 notify_cable_status(vbus);
238 #endif
239 /* -------------------------------------------------------------------------- */
240 /* For sleep charging screen. */
241 static int zcharge_enabled;
242 static int htc_is_zcharge_enabled(void)
244 return zcharge_enabled;
246 static int __init enable_zcharge_setup(char *str)
248 int cal = simple_strtol(str, NULL, 0);
250 zcharge_enabled = cal;
251 return 1;
253 __setup("enable_zcharge=", enable_zcharge_setup);
255 static int htc_is_cable_in(void)
257 if (!htc_batt_info.update_time) {
258 BATT_ERR("%s: battery driver hasn't been initialized yet.", __func__);
259 return -EINVAL;
261 return (htc_batt_info.rep.charging_source != CHARGER_BATTERY) ? 1 : 0;
265 * htc_power_policy - check if it obeys our policy
266 * return 0 for no errors, to indicate it follows policy.
267 * non zero otherwise.
269 static int __htc_power_policy(void)
271 if (!zcharge_enabled)
272 return 0;
274 if (htc_is_cable_in())
275 return 1;
277 return 0;
281 * Jay, 7/1/09'
283 static int htc_power_policy(struct notifier_block *nfb,
284 unsigned long action, void *ignored)
286 int rc;
287 switch (action) {
288 case NOTIFY_POWER:
289 pr_info("%s: enter.\n", __func__);
290 rc = __htc_power_policy();
291 if (rc)
292 return NOTIFY_STOP;
293 else
294 return NOTIFY_OK;
296 return NOTIFY_DONE; /* we did not care other action here */
299 unsigned int batt_get_status(enum power_supply_property psp)
301 union power_supply_propval val;
303 if (update_batt_info())
304 return -EINVAL;
306 switch (psp) {
307 case POWER_SUPPLY_PROP_CAPACITY:
308 mutex_lock(&htc_batt_info.lock);
309 val.intval = htc_batt_info.rep.level;
310 mutex_unlock(&htc_batt_info.lock);
311 /* prevent shutdown before battery driver ready. */
312 if (htc_batt_info.device_id == 0)
313 val.intval = 55; /* 55 == ?? */
314 break;
315 case POWER_SUPPLY_PROP_TEMP:
316 mutex_lock(&htc_batt_info.lock);
317 val.intval = htc_batt_info.rep.batt_temp;
318 mutex_unlock(&htc_batt_info.lock);
319 break;
320 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
321 mutex_lock(&htc_batt_info.lock);
322 val.intval = htc_batt_info.rep.batt_vol;
323 mutex_unlock(&htc_batt_info.lock);
324 break;
325 default:
326 return -EINVAL;
329 return val.intval;
332 #if defined(CONFIG_DEBUG_FS)
333 static int htc_battery_set_charging(enum batt_ctl_t ctl);
334 static int batt_debug_set(void *data, u64 val)
336 return htc_battery_set_charging((enum batt_ctl_t) val);
339 static int batt_debug_get(void *data, u64 *val)
341 return -ENOSYS;
344 DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n");
345 static int __init batt_debug_init(void)
347 struct dentry *dent;
349 dent = debugfs_create_dir("htc_battery", 0);
350 if (IS_ERR(dent))
351 return PTR_ERR(dent);
353 debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops);
355 return 0;
358 device_initcall(batt_debug_init);
359 #endif
361 static int init_batt_gpio(void)
363 if (htc_batt_info.gpio_mbat_in > 0 &&
364 gpio_request(htc_batt_info.gpio_mbat_in, "batt_detect") < 0)
365 goto gpio_failed;
366 if (htc_batt_info.gpio_mchg_en_n > 0 &&
367 gpio_request(htc_batt_info.gpio_mchg_en_n, "charger_en") < 0)
368 goto gpio_failed;
369 else
370 gpio_direction_output(htc_batt_info.gpio_mchg_en_n, 1);
371 if (htc_batt_info.gpio_iset > 0 &&
372 gpio_request(htc_batt_info.gpio_iset, "charge_current") < 0)
373 goto gpio_failed;
374 else
375 gpio_direction_output(htc_batt_info.gpio_iset, 1);
377 if (htc_batt_info.gpio_power > 0 &&
378 gpio_request(htc_batt_info.gpio_power, "usb_power") < 0)
379 goto gpio_failed;
380 else
381 gpio_direction_output(htc_batt_info.gpio_power, 0);
383 return 0;
385 gpio_failed:
386 return -EINVAL;
391 * battery_charging_ctrl - battery charing control.
392 * @ctl: battery control command
395 int battery_charging_ctrl(enum batt_ctl_t ctl)
397 int result = 0;
398 if (!htc_battery_initial) return 0;
400 switch (ctl) {
401 case DISABLE:
402 BATT_LOG("charger OFF");
403 /* 0 for enable; 1 disable */
404 result = gpio_direction_output(htc_batt_info.gpio_mchg_en_n, 1);
405 break;
406 case ENABLE_SLOW_CHG:
407 BATT_LOG("charger ON (SLOW)");
408 result = gpio_direction_output(htc_batt_info.gpio_iset, 0);
409 result = gpio_direction_output(htc_batt_info.gpio_mchg_en_n, 0);
410 break;
411 case ENABLE_FAST_CHG:
412 BATT_LOG("charger ON (FAST)");
413 result = gpio_direction_output(htc_batt_info.gpio_iset, 1);
414 result = gpio_direction_output(htc_batt_info.gpio_mchg_en_n, 0);
415 break;
416 default:
417 BATT_ERR("%s: Not supported battery ctr called.!", __func__);
418 result = -EINVAL;
419 break;
422 return result;
425 static int htc_battery_set_charging(enum batt_ctl_t ctl)
427 int rc;
429 if ((rc = battery_charging_ctrl(ctl)) < 0)
430 goto result;
432 if (!htc_battery_initial) {
433 htc_batt_info.rep.charging_enabled = ctl & 0x3;
434 } else {
435 mutex_lock(&htc_batt_info.lock);
436 htc_batt_info.rep.charging_enabled = ctl & 0x3;
437 mutex_unlock(&htc_batt_info.lock);
439 result:
440 return rc;
443 static int htc_battery_status_update(u32 curr_level)
445 int notify;
446 if (!htc_battery_initial)
447 return 0;
449 mutex_lock(&htc_batt_info.lock);
450 notify = (htc_batt_info.rep.level != curr_level);
451 htc_batt_info.rep.level = curr_level;
452 mutex_unlock(&htc_batt_info.lock);
453 #if 0
454 if (notify) {
455 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
456 if (htc_batt_debug_mask & HTC_BATT_DEBUG_UEVT)
457 BATT_LOG("power_supply_changed: battery");
459 #else
460 /* we don't check level here for charging over temp RPC call */
461 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
462 if (htc_batt_debug_mask & HTC_BATT_DEBUG_UEVT)
463 BATT_LOG("batt:power_supply_changed: battery");
464 #endif
465 return 0;
468 static void update_wake_lock(int status)
470 if (status == CHARGER_USB) {
471 wake_lock(&vbus_wake_lock);
472 } else if (__htc_power_policy()) {
473 /* Lock suspend for DOPOD charging animation */
474 wake_lock(&vbus_wake_lock);
475 } else {
476 /* give userspace some time to see the uevent and update
477 * LED state or whatnot...
479 wake_lock_timeout(&vbus_wake_lock, HZ * 5);
483 #ifdef CONFIG_HTC_BATTCHG_SMEM
484 static int htc_set_smem_cable_type(u32 cable_type);
485 #else
486 static int htc_set_smem_cable_type(u32 cable_type) { return -1; }
487 #endif
488 #if 1 //JH //this is for packet filter (notify port list while USB in/out)
489 int update_port_list_charging_state(int enable);
490 #endif
491 static int htc_cable_status_update(int status)
493 int rc = 0;
494 // unsigned last_source;
496 if (!htc_battery_initial)
497 return 0;
499 if (status < CHARGER_BATTERY || status > CHARGER_AC) {
500 BATT_ERR("%s: Not supported cable status received!", __func__);
501 return -EINVAL;
504 mutex_lock(&htc_batt_info.lock);
505 #if 1
506 pr_info("batt: %s: %d -> %d\n", __func__, htc_batt_info.rep.charging_source, status);
507 if (status == htc_batt_info.rep.charging_source) {
508 /* When cable overvoltage(5V => 7V) A9 will report the same source, so only sent the uevent */
509 if (status == CHARGER_USB) {
510 power_supply_changed(&htc_power_supplies[CHARGER_USB]);
511 if (htc_batt_debug_mask & HTC_BATT_DEBUG_UEVT)
512 BATT_LOG("batt:(htc_cable_status_update)power_supply_changed: OverVoltage");
514 mutex_unlock(&htc_batt_info.lock);
515 return 0;
518 /* TODO: replace charging_source to vbus_present */
519 htc_batt_info.rep.charging_source = status;
520 /* ARM9 should know the status it notifies,
521 * keep this code for old projects. */
522 /* htc_set_smem_cable_type(status); */
524 update_wake_lock(status);
525 /*ARM9 report CHARGER_AC while plug in htc_adaptor which is identify by usbid*/
526 /*don't need to notify usb driver*/
527 if ((htc_batt_info.guage_driver == GUAGE_MODEM) && (status == CHARGER_AC)) {
528 htc_set_smem_cable_type(CHARGER_AC);
529 power_supply_changed(&htc_power_supplies[CHARGER_AC]);
530 } else
531 msm_hsusb_set_vbus_state(!!htc_batt_info.rep.charging_source);
533 /* TODO: use power_supply_change to notify battery drivers. */
534 if (htc_batt_info.guage_driver == GUAGE_DS2784 ||
535 htc_batt_info.guage_driver == GUAGE_DS2746)
536 blocking_notifier_call_chain(&cable_status_notifier_list,
537 status, NULL);
539 if (status == CHARGER_BATTERY) {
540 htc_set_smem_cable_type(CHARGER_BATTERY);
541 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
542 if (htc_batt_debug_mask & HTC_BATT_DEBUG_UEVT)
543 BATT_LOG("batt:(htc_cable_status_update)power_supply_changed: battery");
546 #else
547 /* A9 reports USB charging when helf AC cable in and China AC charger. */
548 /* notify userspace USB charging first,
549 and then usb driver will notify AC while D+/D- Line short. */
550 /* China AC detection:
551 * Write SMEM as USB first, and update SMEM to AC
552 * if receives AC notification */
553 last_source = htc_batt_info.rep.charging_source;
554 if (status == CHARGER_USB && g_usb_online == 0) {
555 htc_set_smem_cable_type(CHARGER_USB);
556 htc_batt_info.rep.charging_source = CHARGER_USB;
557 } else {
558 htc_set_smem_cable_type(status);
559 htc_batt_info.rep.charging_source = status;
560 /* usb driver will not notify usb offline. */
561 if (status == CHARGER_BATTERY && g_usb_online != 0)
562 g_usb_online = 0;
565 msm_hsusb_set_vbus_state(status == CHARGER_USB);
566 if (htc_batt_info.guage_driver == GUAGE_DS2784 ||
567 htc_batt_info.guage_driver == GUAGE_DS2746)
568 blocking_notifier_call_chain(&cable_status_notifier_list,
569 htc_batt_info.rep.charging_source, NULL);
571 if (htc_batt_info.rep.charging_source != last_source) {
572 #if 1 //JH //this is for packet filter (notify port list while USB in/out)
573 update_port_list_charging_state(!(htc_batt_info.rep.charging_source == CHARGER_BATTERY));
574 #endif
575 /* Lock suspend only when USB in for ADB or other USB functions. */
576 if (htc_batt_info.rep.charging_source == CHARGER_USB) {
577 wake_lock(&vbus_wake_lock);
578 } else if (__htc_power_policy()) {
579 /* Lock suspend for DOPOD charging animation */
580 wake_lock(&vbus_wake_lock);
581 } else {
582 if (htc_batt_info.rep.charging_source == CHARGER_AC
583 && last_source == CHARGER_USB)
584 BATT_ERR("%s: USB->AC\n", __func__);
585 /* give userspace some time to see the uevent and update
586 * LED state or whatnot...
588 wake_lock_timeout(&vbus_wake_lock, HZ * 5);
590 if (htc_batt_info.rep.charging_source == CHARGER_BATTERY || last_source == CHARGER_BATTERY)
591 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
592 if (htc_batt_info.rep.charging_source == CHARGER_USB || last_source == CHARGER_USB)
593 power_supply_changed(&htc_power_supplies[CHARGER_USB]);
594 if (htc_batt_info.rep.charging_source == CHARGER_AC || last_source == CHARGER_AC)
595 power_supply_changed(&htc_power_supplies[CHARGER_AC]);
596 if (htc_batt_debug_mask & HTC_BATT_DEBUG_UEVT)
597 BATT_LOG("power_supply_changed: %s -> %s",
598 charger_tags[last_source], charger_tags[htc_batt_info.rep.charging_source]);
600 #endif
601 mutex_unlock(&htc_batt_info.lock);
603 return rc;
606 #ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC
607 int htc_get_usb_accessory_adc_level(uint32_t *buffer)
609 struct rpc_request_hdr req;
611 struct htc_get_usb_adc_value_rep {
612 struct rpc_reply_hdr hdr;
613 uint32_t adc_value;
614 } rep;
616 int rc;
617 printk(KERN_INFO "%s\n", __func__);
619 if (buffer == NULL) {
620 printk(KERN_INFO "%s: buffer null\n", __func__);
621 return -EINVAL;
624 rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_USB_ACCESSORY_ADC_LEVEL,
625 &req, sizeof(req),
626 &rep, sizeof(rep),
627 5 * HZ);
628 if (rc < 0) {
629 printk(KERN_INFO "%s: msm_rpc_call_reply fail\n", __func__);
630 return rc;
632 *buffer = be32_to_cpu(rep.adc_value);
634 printk(KERN_INFO "%s: adc = %d\n", __func__, *buffer);
635 return 0;
637 EXPORT_SYMBOL(htc_get_usb_accessory_adc_level);
638 #endif
640 /* A9 reports USB charging when helf AC cable in and China AC charger. */
641 /* notify userspace USB charging first,
642 and then usb driver will notify AC while D+/D- Line short. */
643 static void usb_status_notifier_func(int online)
645 #if 1
646 pr_info("batt:online=%d",online);
647 /* TODO: replace charging_source to usb_status */
648 htc_batt_info.rep.charging_source = online;
649 htc_set_smem_cable_type(htc_batt_info.rep.charging_source);
651 /* TODO: use power_supply_change to notify battery drivers. */
652 if (htc_batt_info.guage_driver == GUAGE_DS2784 || htc_batt_info.guage_driver == GUAGE_DS2746)
653 blocking_notifier_call_chain(&cable_status_notifier_list,
654 htc_batt_info.rep.charging_source, NULL);
656 if (htc_battery_initial) {
657 power_supply_changed(&htc_power_supplies[CHARGER_AC]);
658 power_supply_changed(&htc_power_supplies[CHARGER_USB]);
659 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
660 } else {
661 pr_err("\n\n ### htc_battery_code is not inited yet! ###\n\n");
663 update_wake_lock(htc_batt_info.rep.charging_source);
664 #else
665 mutex_lock(&htc_batt_info.lock);
666 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USB_NOTIFY)
667 BATT_LOG("%s: online=%d, g_usb_online=%d", __func__, online, g_usb_online);
668 if (g_usb_online != online) {
669 g_usb_online = online;
670 if (online == CHARGER_AC && htc_batt_info.rep.charging_source == CHARGER_USB) {
671 mutex_unlock(&htc_batt_info.lock);
672 htc_cable_status_update(CHARGER_AC);
673 mutex_lock(&htc_batt_info.lock);
676 mutex_unlock(&htc_batt_info.lock);
677 #endif
680 static int htc_get_batt_info(struct battery_info_reply *buffer)
682 struct rpc_request_hdr req;
684 struct htc_get_batt_info_rep {
685 struct rpc_reply_hdr hdr;
686 struct battery_info_reply info;
687 } rep;
689 int rc;
691 if (buffer == NULL)
692 return -EINVAL;
694 rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
695 &req, sizeof(req),
696 &rep, sizeof(rep),
697 5 * HZ);
698 if ( rc < 0 )
699 return rc;
701 mutex_lock(&htc_batt_info.lock);
702 buffer->batt_id = be32_to_cpu(rep.info.batt_id);
703 buffer->batt_vol = be32_to_cpu(rep.info.batt_vol);
704 buffer->batt_temp = be32_to_cpu(rep.info.batt_temp);
705 buffer->batt_current = be32_to_cpu(rep.info.batt_current);
706 buffer->level = be32_to_cpu(rep.info.level);
707 /* Move the rules of charging_source to cable_status_update. */
708 /* buffer->charging_source = be32_to_cpu(rep.info.charging_source); */
709 buffer->charging_enabled = be32_to_cpu(rep.info.charging_enabled);
710 buffer->full_bat = be32_to_cpu(rep.info.full_bat);
711 /* Over_vchg only update in SMEM from A9 */
712 /* buffer->over_vchg = be32_to_cpu(rep.info.over_vchg); */
713 mutex_unlock(&htc_batt_info.lock);
715 if (htc_batt_debug_mask & HTC_BATT_DEBUG_A2M_RPC)
716 BATT_LOG("A2M_RPC: get_batt_info: batt_id=%d, batt_vol=%d, batt_temp=%d, "
717 "batt_current=%d, level=%d, charging_source=%d, "
718 "charging_enabled=%d, full_bat=%d, over_vchg=%d",
719 buffer->batt_id, buffer->batt_vol, buffer->batt_temp,
720 buffer->batt_current, buffer->level, buffer->charging_source,
721 buffer->charging_enabled, buffer->full_bat, buffer->over_vchg);
723 return 0;
726 #ifdef CONFIG_HTC_BATTCHG_SMEM
727 struct htc_batt_info_full {
728 u32 batt_id;
729 u32 batt_vol;
730 u32 batt_vol_last;
731 u32 batt_temp;
732 s32 batt_current;
733 s32 batt_current_last;
734 u32 batt_discharge_current;
736 u32 VREF_2;
737 u32 VREF;
738 u32 ADC4096_VREF;
740 u32 Rtemp;
741 s32 Temp;
742 s32 Temp_last;
744 u32 pd_M;
745 u32 MBAT_pd;
746 s32 I_MBAT;
748 u32 pd_temp;
749 u32 percent_last;
750 u32 percent_update;
751 u32 dis_percent;
753 u32 vbus;
754 u32 usbid;
755 u32 charging_source;
757 u32 MBAT_IN;
758 u32 full_bat;
760 u32 eval_current;
761 u32 eval_current_last;
762 u32 charging_enabled;
764 u32 timeout;
765 u32 fullcharge;
766 u32 level;
767 u32 delta;
769 u32 chg_time;
770 s32 level_change;
771 u32 sleep_timer_count;
772 u32 OT_led_on;
773 u32 overloading_charge;
775 u32 a2m_cable_type;
776 u32 vchg; // VCHG => 0: Not, 1: In
777 u32 over_vchg; /*over voltage charger detection, 0:VCHG normal(below 6V) 1:VCHG over(upper 6V)*/
778 u32 reserve4;
779 u32 reserve5;
782 /* SMEM_BATT_INFO is allocated by A9 after first A2M RPC is sent. */
783 static struct htc_batt_info_full *smem_batt_info;
785 static int htc_get_batt_info_smem(struct battery_info_reply *buffer)
787 if (!smem_batt_info) {
788 smem_batt_info = smem_alloc(SMEM_BATT_INFO,
789 sizeof(struct htc_batt_info_full));
790 if (!smem_batt_info) {
791 BATT_ERR("battery SMEM allocate fail, "
792 "use RPC instead of");
793 return htc_get_batt_info(buffer);
797 if (!buffer)
798 return -EINVAL;
800 mutex_lock(&htc_batt_info.lock);
801 buffer->batt_id = smem_batt_info->batt_id;
802 buffer->batt_vol = smem_batt_info->batt_vol;
803 buffer->batt_temp = smem_batt_info->Temp;
804 buffer->batt_current = smem_batt_info->batt_current;
805 buffer->eval_current = smem_batt_info->eval_current;
806 /* Fix issue that recharging percent drop to 99%. */
807 /* The level in SMEM is for A9 internal use,
808 * always use value reported by M2A level update RPC. */
809 #if 0
810 buffer->level = smem_batt_info->percent_update;
811 #endif
812 /* Move the rules of charging_source to cable_status_update. */
813 /* buffer->charging_source = be32_to_cpu(smem_batt_info->charging_source); */
814 buffer->charging_enabled = smem_batt_info->charging_enabled;
815 buffer->full_bat = smem_batt_info->full_bat;
816 buffer->over_vchg = smem_batt_info->over_vchg;
817 mutex_unlock(&htc_batt_info.lock);
819 if (htc_batt_debug_mask & HTC_BATT_DEBUG_SMEM)
820 BATT_LOG("SMEM_BATT: get_batt_info: batt_id=%d, batt_vol=%d, batt_temp=%d, "
821 "batt_current=%d, eval_current=%d, level=%d, charging_source=%d, "
822 "charging_enabled=%d, full_bat=%d, over_vchg=%d",
823 buffer->batt_id, buffer->batt_vol, buffer->batt_temp,
824 buffer->batt_current, buffer->eval_current, buffer->level, buffer->charging_source,
825 buffer->charging_enabled, buffer->full_bat, buffer->over_vchg);
827 return 0;
830 static ssize_t htc_battery_show_smem(struct device *dev,
831 struct device_attribute *attr,
832 char *buf)
834 int len = 0;
836 if (!smem_batt_info) {
837 smem_batt_info = smem_alloc(SMEM_BATT_INFO,
838 sizeof(struct htc_batt_info_full));
839 if (!smem_batt_info) {
840 BATT_ERR("Show SMEM: allocate fail");
841 return 0;
845 if (!strcmp(attr->attr.name, "smem_raw")) {
846 len = sizeof(struct htc_batt_info_full);
847 memcpy(buf, smem_batt_info, len);
848 } else if (!strcmp(attr->attr.name, "smem_text")) {
849 len += scnprintf(buf + len, PAGE_SIZE - len,
850 "batt_id: %d\n"
851 "batt_vol: %d\n"
852 "batt_vol_last: %d\n"
853 "batt_temp: %d\n"
854 "batt_current: %d\n"
855 "batt_current_last: %d\n"
856 "batt_discharge_current: %d\n"
857 "VREF_2: %d\n"
858 "VREF: %d\n"
859 "ADC4096_VREF: %d\n"
860 "Rtemp: %d\n"
861 "Temp: %d\n"
862 "Temp_last: %d\n"
863 "pd_M: %d\n"
864 "MBAT_pd: %d\n"
865 "I_MBAT: %d\n"
866 "pd_temp: %d\n"
867 "percent_last: %d\n"
868 "percent_update: %d\n"
869 "dis_percent: %d\n"
870 "vbus: %d\n"
871 "usbid: %d\n"
872 "charging_source: %d\n"
873 "MBAT_IN: %d\n"
874 "full_bat: %d\n"
875 "eval_current: %d\n"
876 "eval_current_last: %d\n"
877 "charging_enabled: %d\n"
878 "timeout: %d\n"
879 "fullcharge: %d\n"
880 "level: %d\n"
881 "delta: %d\n"
882 "chg_time: %d\n"
883 "level_change: %d\n"
884 "sleep_timer_count: %d\n"
885 "OT_led_on: %d\n"
886 "overloading_charge: %d\n"
887 "a2m_cable_type: %d\n"
888 "vchg: %d\n"
889 "over_vchg: %d\n",
890 smem_batt_info->batt_id,
891 smem_batt_info->batt_vol,
892 smem_batt_info->batt_vol_last,
893 smem_batt_info->batt_temp,
894 smem_batt_info->batt_current,
895 smem_batt_info->batt_current_last,
896 smem_batt_info->batt_discharge_current,
897 smem_batt_info->VREF_2,
898 smem_batt_info->VREF,
899 smem_batt_info->ADC4096_VREF,
900 smem_batt_info->Rtemp,
901 smem_batt_info->Temp,
902 smem_batt_info->Temp_last,
903 smem_batt_info->pd_M,
904 smem_batt_info->MBAT_pd,
905 smem_batt_info->I_MBAT,
906 smem_batt_info->pd_temp,
907 smem_batt_info->percent_last,
908 smem_batt_info->percent_update,
909 smem_batt_info->dis_percent,
910 smem_batt_info->vbus,
911 smem_batt_info->usbid,
912 smem_batt_info->charging_source,
913 smem_batt_info->MBAT_IN,
914 smem_batt_info->full_bat,
915 smem_batt_info->eval_current,
916 smem_batt_info->eval_current_last,
917 smem_batt_info->charging_enabled,
918 smem_batt_info->timeout,
919 smem_batt_info->fullcharge,
920 smem_batt_info->level,
921 smem_batt_info->delta,
922 smem_batt_info->chg_time,
923 smem_batt_info->level_change,
924 smem_batt_info->sleep_timer_count,
925 smem_batt_info->OT_led_on,
926 smem_batt_info->overloading_charge,
927 smem_batt_info->a2m_cable_type,
928 smem_batt_info->vchg,
929 smem_batt_info->over_vchg);
932 return len;
935 static int htc_set_smem_cable_type(u32 cable_type)
937 if (!smem_batt_info) {
938 smem_batt_info = smem_alloc(SMEM_BATT_INFO,
939 sizeof(struct htc_batt_info_full));
940 if (!smem_batt_info) {
941 BATT_ERR("Update SMEM: allocate fail");
942 return -EINVAL;
946 smem_batt_info->a2m_cable_type = cable_type;
947 BATT_LOG("Update SMEM: cable type %d", cable_type);
949 return 0;
951 #endif
952 static ssize_t htc_battery_show_batt_attr(struct device *dev,
953 struct device_attribute *attr,
954 char *buf)
956 switch (htc_batt_info.guage_driver) {
957 case GUAGE_MODEM:
958 #ifdef CONFIG_HTC_BATTCHG_SMEM
959 return htc_battery_show_smem(dev, attr, buf);
960 #endif
961 break;
962 case GUAGE_DS2784:
963 case GUAGE_DS2746:
964 return htc_batt_info.func_show_batt_attr(attr, buf);
965 break;
967 return 0;
970 /* -------------------------------------------------------------------------- */
971 static int htc_power_get_property(struct power_supply *psy,
972 enum power_supply_property psp,
973 union power_supply_propval *val)
975 enum charger_type_t charger;
977 mutex_lock(&htc_batt_info.lock);
979 charger = htc_batt_info.rep.charging_source;
980 /* ARM9 decides charging_enabled value by battery id */
981 if (htc_batt_info.rep.batt_id == 255)
982 charger = CHARGER_BATTERY;
984 mutex_unlock(&htc_batt_info.lock);
986 switch (psp) {
987 case POWER_SUPPLY_PROP_ONLINE:
988 if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
989 val->intval = (charger == CHARGER_AC ? 1 : 0);
990 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
991 BATT_LOG("%s: %s: online=%d", __func__, psy->name, val->intval);
992 } else if (psy->type == POWER_SUPPLY_TYPE_USB) {
993 val->intval = (charger == CHARGER_USB ? 1 : 0);
994 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
995 BATT_LOG("%s: %s: online=%d", __func__, psy->name, val->intval);
996 } else
997 val->intval = 0;
998 break;
999 default:
1000 return -EINVAL;
1003 return 0;
1006 /* Once charge full, set this flag */
1007 static int htc_charge_full = 0;
1009 static int htc_battery_get_charging_status(void)
1011 u32 level;
1012 enum charger_type_t charger;
1013 int ret;
1015 mutex_lock(&htc_batt_info.lock);
1017 charger = htc_batt_info.rep.charging_source;
1019 /* ARM9 decides charging_enabled value by battery id */
1020 if (htc_batt_info.rep.batt_id == 255)
1021 charger = CHARGER_UNKNOWN;
1023 switch (charger) {
1024 case CHARGER_BATTERY:
1025 htc_charge_full = 0;
1026 ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
1027 break;
1028 case CHARGER_USB:
1029 case CHARGER_AC:
1030 #if !defined(CONFIG_BATTERY_DS2746)
1031 if ((htc_charge_full) && (htc_batt_info.rep.full_level == 100)) {
1032 htc_batt_info.rep.level = 100;
1034 #endif
1035 level = htc_batt_info.rep.level;
1036 if (level == 100){
1037 htc_charge_full = 1;}
1038 else
1039 htc_charge_full = 0;
1041 if (htc_charge_full)
1042 ret = POWER_SUPPLY_STATUS_FULL;
1043 else if (htc_batt_info.rep.charging_enabled != 0)
1044 ret = POWER_SUPPLY_STATUS_CHARGING;
1045 else
1046 ret = POWER_SUPPLY_STATUS_DISCHARGING;
1047 break;
1048 default:
1049 ret = POWER_SUPPLY_STATUS_UNKNOWN;
1051 mutex_unlock(&htc_batt_info.lock);
1052 return ret;
1055 static int htc_battery_get_property(struct power_supply *psy,
1056 enum power_supply_property psp,
1057 union power_supply_propval *val)
1059 switch (psp) {
1060 case POWER_SUPPLY_PROP_STATUS:
1061 val->intval = htc_battery_get_charging_status();
1062 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
1063 BATT_LOG("%s: %s: status=%d", __func__, psy->name, val->intval);
1064 break;
1065 case POWER_SUPPLY_PROP_HEALTH:
1066 val->intval = POWER_SUPPLY_HEALTH_GOOD;
1067 if (machine_is_paradise()) {
1068 if (htc_batt_info.rep.batt_temp >= 500 ||
1069 htc_batt_info.rep.batt_temp <= 0)
1070 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
1071 } else if (machine_is_spade()) {
1072 if (htc_batt_info.rep.batt_temp >= 450 ||
1073 htc_batt_info.rep.batt_temp <= 0)
1074 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
1075 } else {
1076 if (htc_batt_info.rep.batt_temp >= 480 ||
1077 htc_batt_info.rep.batt_temp <= 0)
1078 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
1081 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
1082 BATT_LOG("%s: %s: health=%d", __func__, psy->name, val->intval);
1083 break;
1084 case POWER_SUPPLY_PROP_PRESENT:
1085 val->intval = htc_batt_info.present;
1086 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
1087 BATT_LOG("%s: %s: present=%d", __func__, psy->name, val->intval);
1088 break;
1089 case POWER_SUPPLY_PROP_TECHNOLOGY:
1090 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1091 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
1092 BATT_LOG("%s: %s: technology=%d", __func__, psy->name, val->intval);
1093 break;
1094 case POWER_SUPPLY_PROP_CAPACITY:
1095 mutex_lock(&htc_batt_info.lock);
1096 val->intval = htc_batt_info.rep.level;
1097 /* prevent shutdown before battery driver ready. */
1098 if (htc_batt_info.device_id == 0)
1099 val->intval = 55; /* 55 == ?? */
1100 mutex_unlock(&htc_batt_info.lock);
1101 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
1102 BATT_LOG("%s: %s: capacity=%d", __func__, psy->name, val->intval);
1103 break;
1104 default:
1105 return -EINVAL;
1108 return 0;
1111 #define HTC_BATTERY_ATTR(_name) \
1113 .attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE }, \
1114 .show = htc_battery_show_property, \
1115 .store = NULL, \
1118 static struct device_attribute htc_battery_attrs[] = {
1119 HTC_BATTERY_ATTR(batt_id),
1120 HTC_BATTERY_ATTR(batt_vol),
1121 HTC_BATTERY_ATTR(batt_temp),
1122 HTC_BATTERY_ATTR(batt_current),
1123 HTC_BATTERY_ATTR(charging_source),
1124 HTC_BATTERY_ATTR(charging_enabled),
1125 HTC_BATTERY_ATTR(full_bat),
1126 HTC_BATTERY_ATTR(over_vchg),
1127 /*[FIXME]__ATTR(batt_attr_raw, S_IRUGO, htc_battery_show_batt_attr, NULL),*/
1128 #ifdef CONFIG_HTC_BATTCHG_SMEM
1129 __ATTR(smem_raw, S_IRUGO, htc_battery_show_smem, NULL),
1130 __ATTR(smem_text, S_IRUGO, htc_battery_show_smem, NULL),
1131 #endif
1132 __ATTR(batt_attr_text, S_IRUGO, htc_battery_show_batt_attr, NULL),
1135 enum {
1136 BATT_ID = 0,
1137 BATT_VOL,
1138 BATT_TEMP,
1139 BATT_CURRENT,
1140 CHARGING_SOURCE,
1141 CHARGING_ENABLED,
1142 FULL_BAT,
1143 OVER_VCHG,
1146 static int htc_rpc_set_delta(unsigned delta)
1148 struct set_batt_delta_req {
1149 struct rpc_request_hdr hdr;
1150 uint32_t data;
1151 } req;
1153 req.data = cpu_to_be32(delta);
1154 return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA,
1155 &req, sizeof(req), 5 * HZ);
1158 static int htc_rpc_charger_switch(unsigned enable)
1160 struct charger_switch_req {
1161 struct rpc_request_hdr hdr;
1162 uint32_t data;
1163 } req;
1165 req.data = cpu_to_be32(enable);
1166 return msm_rpc_call(endpoint, HTC_PROCEDURE_CHARGER_SWITCH,
1167 &req, sizeof(req), 5 * HZ);
1170 static int htc_rpc_set_full_level(unsigned level)
1172 struct set_batt_full_level_req {
1173 struct rpc_request_hdr hdr;
1174 uint32_t data;
1175 } req;
1177 req.data = cpu_to_be32(level);
1178 return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_FULL_LEVEL,
1179 &req, sizeof(req), 5 * HZ);
1182 static ssize_t htc_battery_set_delta(struct device *dev,
1183 struct device_attribute *attr,
1184 const char *buf, size_t count)
1186 int rc;
1187 unsigned long delta = 0;
1189 delta = simple_strtoul(buf, NULL, 10);
1191 if (delta > 100)
1192 return -EINVAL;
1194 mutex_lock(&htc_batt_info.rpc_lock);
1195 rc = htc_rpc_set_delta(delta);
1196 mutex_unlock(&htc_batt_info.rpc_lock);
1197 if (rc < 0)
1198 return rc;
1199 return count;
1203 * For PA and QA test
1204 * 0x10-> fake temp to 250
1205 * 0x11->TBD if needed
1206 * 0x12->TBD if needed
1207 * ....
1209 static ssize_t htc_battery_debug_flag(struct device *dev,
1210 struct device_attribute *attr,
1211 const char *buf, size_t count)
1213 unsigned long debug_flag;
1214 debug_flag = simple_strtoul(buf, NULL, 10);
1216 if (debug_flag > 100 || debug_flag == 0)
1217 return -EINVAL;
1219 mutex_lock(&htc_batt_info.lock);
1220 blocking_notifier_call_chain(&cable_status_notifier_list,
1221 debug_flag, 0);
1222 mutex_unlock(&htc_batt_info.lock);
1223 return 0;
1227 static ssize_t htc_battery_charger_switch(struct device *dev,
1228 struct device_attribute *attr,
1229 const char *buf, size_t count)
1231 int rc;
1232 unsigned long enable = 0;
1234 enable = simple_strtoul(buf, NULL, 10);
1236 if (enable > 1 || enable < 0)
1237 return -EINVAL;
1239 mutex_lock(&htc_batt_info.rpc_lock);
1240 rc = htc_rpc_charger_switch(enable);
1241 mutex_unlock(&htc_batt_info.rpc_lock);
1242 if (rc < 0)
1243 return rc;
1244 return count;
1248 static ssize_t htc_battery_set_full_level(struct device *dev,
1249 struct device_attribute *attr,
1250 const char *buf, size_t count)
1252 int rc = 0;
1253 unsigned long percent = 100;
1255 percent = simple_strtoul(buf, NULL, 10);
1257 if (percent > 100 || percent == 0)
1258 return -EINVAL;
1260 switch (htc_batt_info.guage_driver) {
1261 case GUAGE_MODEM:
1262 mutex_lock(&htc_batt_info.rpc_lock);
1263 htc_batt_info.rep.full_level = percent;
1264 rc = htc_rpc_set_full_level(percent);
1265 mutex_unlock(&htc_batt_info.rpc_lock);
1266 break;
1267 case GUAGE_DS2784:
1268 case GUAGE_DS2746:
1269 if (htc_full_level_flag == 0) {
1270 mutex_lock(&htc_batt_info.lock);
1271 htc_full_level_flag = 1;
1272 htc_batt_info.rep.full_level = percent;
1273 blocking_notifier_call_chain(&cable_status_notifier_list,
1274 0xff, (void *) &htc_batt_info.rep.full_level);
1275 mutex_unlock(&htc_batt_info.lock);
1277 rc = 0;
1278 break;
1280 if (rc < 0)
1281 return rc;
1282 return rc;
1285 static struct device_attribute htc_set_delta_attrs[] = {
1286 __ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta),
1287 __ATTR(full_level, S_IWUSR | S_IWGRP, NULL, htc_battery_set_full_level),
1288 __ATTR(batt_debug_flag,S_IWUSR | S_IWGRP, NULL, htc_battery_debug_flag),
1289 __ATTR(charger_control, S_IWUSR | S_IWGRP, NULL, htc_battery_charger_switch),
1292 static int htc_battery_create_attrs(struct device * dev)
1294 int i = 0, j = 0, rc = 0;
1296 for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) {
1297 rc = device_create_file(dev, &htc_battery_attrs[i]);
1298 if (rc)
1299 goto htc_attrs_failed;
1302 for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) {
1303 rc = device_create_file(dev, &htc_set_delta_attrs[j]);
1304 if (rc)
1305 goto htc_delta_attrs_failed;
1308 goto succeed;
1310 htc_attrs_failed:
1311 while (i--)
1312 device_remove_file(dev, &htc_battery_attrs[i]);
1313 htc_delta_attrs_failed:
1314 while (j--)
1315 device_remove_file(dev, &htc_set_delta_attrs[i]);
1316 succeed:
1317 return rc;
1320 static int update_batt_info(void)
1322 int ret = 0;
1324 /* FIXME */
1325 switch (htc_batt_info.guage_driver) {
1326 case GUAGE_MODEM:
1327 #ifdef CONFIG_HTC_BATTCHG_SMEM
1328 if (htc_get_batt_info_smem(&htc_batt_info.rep) < 0) {
1329 BATT_ERR("%s: smem read failed!!!", __func__);
1330 ret = -1;
1332 #else
1333 if (htc_get_batt_info(&htc_batt_info.rep) < 0) {
1334 BATT_ERR("%s: rpc failed!!!", __func__);
1335 ret = -1;
1337 #endif
1338 break;
1339 #ifdef CONFIG_BATTERY_DS2784
1340 case GUAGE_DS2784:
1341 if (ds2784_get_battery_info(&htc_batt_info.rep)) {
1342 BATT_ERR("%s: ds2784 read failed!!!", __func__);
1343 ret = -1;
1345 break;
1346 #elif defined(CONFIG_BATTERY_DS2746)
1347 case GUAGE_DS2746:
1348 if (ds2746_get_battery_info(&htc_batt_info.rep)) {
1349 BATT_ERR("%s: ds2746 read failed!!!", __func__);
1350 ret = -1;
1352 break;
1353 #endif
1355 default:
1356 return -EINVAL;
1359 return ret;
1362 static ssize_t htc_battery_show_property(struct device *dev,
1363 struct device_attribute *attr,
1364 char *buf)
1366 int i = 0;
1367 const ptrdiff_t off = attr - htc_battery_attrs;
1369 /* rpc lock is used to prevent two threads from calling
1370 * into the get info rpc at the same time
1373 mutex_lock(&htc_batt_info.rpc_lock);
1374 /* check cache time to decide if we need to update */
1375 if (htc_batt_info.update_time &&
1376 time_before(jiffies, htc_batt_info.update_time +
1377 msecs_to_jiffies(cache_time))) {
1378 BATT_LOG("%s: use cached values", __func__);
1379 goto dont_need_update;
1382 if (!update_batt_info())
1383 htc_batt_info.update_time = jiffies;
1385 dont_need_update:
1386 mutex_unlock(&htc_batt_info.rpc_lock);
1388 mutex_lock(&htc_batt_info.lock);
1389 switch (off) {
1390 case BATT_ID:
1391 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1392 htc_batt_info.rep.batt_id);
1393 break;
1394 case BATT_VOL:
1395 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1396 htc_batt_info.rep.batt_vol);
1397 break;
1398 case BATT_TEMP:
1399 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1400 htc_batt_info.rep.batt_temp);
1401 break;
1402 case BATT_CURRENT:
1403 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1404 htc_batt_info.rep.batt_current);
1405 break;
1406 case CHARGING_SOURCE:
1407 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1408 htc_batt_info.rep.charging_source);
1409 break;
1410 case CHARGING_ENABLED:
1411 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1412 htc_batt_info.rep.charging_enabled);
1413 break;
1414 case FULL_BAT:
1415 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1416 htc_batt_info.rep.full_bat);
1417 break;
1418 case OVER_VCHG:
1419 i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
1420 htc_batt_info.rep.over_vchg);
1421 break;
1422 default:
1423 i = -EINVAL;
1425 mutex_unlock(&htc_batt_info.lock);
1427 if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY) {
1428 if (i < 0)
1429 BATT_LOG("%s: battery: attribute is not supported: %d", __func__, off);
1430 else
1431 BATT_LOG("%s: battery: %s=%s", __func__, attr->attr.name, buf);
1433 return i;
1436 static irqreturn_t tps65200_int_detection(int irq, void *data)
1438 struct htc_battery_tps65200_int *ip = data;
1440 BATT_LOG("%s: over voltage is detected.", __func__);
1442 disable_irq_nosync(ip->chg_int);
1444 ip->tps65200_reg = 0;
1446 schedule_delayed_work(&ip->int_work, msecs_to_jiffies(200));
1448 return IRQ_HANDLED;
1451 static void htc_battery_tps65200_int_func(struct work_struct *work)
1453 struct htc_battery_tps65200_int *ip;
1454 int fault_bit;
1455 ip = container_of(work, struct htc_battery_tps65200_int,
1456 int_work.work);
1458 switch (ip->tps65200_reg) {
1459 case CHECK_INT1:
1460 /* read twice. First read to trigger TPS65200 clear fault bit
1461 on INT1. Second read to make sure that fault bit is cleared
1462 and call off ovp function.*/
1463 fault_bit = tps_set_charger_ctrl(CHECK_INT1);
1464 BATT_LOG("INT1 value: %d", fault_bit);
1465 fault_bit = tps_set_charger_ctrl(CHECK_INT1);
1467 if (fault_bit) {
1468 #ifdef CONFIG_HTC_BATTCHG_SMEM
1469 smem_batt_info->over_vchg = 1;
1470 #else
1471 htc_batt_info.rep.over_vchg = 1;
1472 #endif
1473 power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
1474 schedule_delayed_work(&ip->int_work,
1475 msecs_to_jiffies(5000));
1476 BATT_LOG("OVER_VOLTAGE: "
1477 "over voltage fault bit on TPS65200 is raised:"
1478 " %d", fault_bit);
1479 } else {
1480 #ifdef CONFIG_HTC_BATTCHG_SMEM
1481 smem_batt_info->over_vchg = 0;
1482 #else
1483 htc_batt_info.rep.over_vchg = 0;
1484 #endif
1485 cancel_delayed_work(&ip->int_work);
1486 enable_irq(ip->chg_int);
1488 break;
1489 default:
1490 fault_bit = tps_set_charger_ctrl(CHECK_INT2);
1491 BATT_LOG("Read TPS65200 INT2 register value: %x", fault_bit);
1492 if (fault_bit) {
1493 fault_bit = tps_set_charger_ctrl(CHECK_INT2);
1494 BATT_LOG("Read TPS65200 INT2 register value: %x"
1495 , fault_bit);
1496 fault_bit = tps_set_charger_ctrl(CHECK_INT2);
1497 BATT_LOG("Read TPS65200 INT2 register value: %x"
1498 , fault_bit);
1499 fault_bit = tps_set_charger_ctrl(CHECK_CONTROL);
1500 #ifdef CONFIG_HTC_BATTCHG_SMEM
1501 smem_batt_info->reserve4 = 1;
1502 #endif
1503 cancel_delayed_work(&ip->int_work);
1504 enable_irq(ip->chg_int);
1505 } else {
1506 fault_bit = tps_set_charger_ctrl(CHECK_INT1);
1507 BATT_LOG("Read TPS65200 INT1 register value: %x"
1508 , fault_bit);
1509 if (fault_bit) {
1510 ip->tps65200_reg = CHECK_INT1;
1511 schedule_delayed_work(&ip->int_work,
1512 msecs_to_jiffies(200));
1515 break;
1519 static int htc_battery_core_probe(struct platform_device *pdev)
1521 int i, rc;
1522 pr_info("%s\n", __func__);
1523 /* init battery gpio */
1524 if (htc_batt_info.charger == LINEAR_CHARGER) {
1525 if ((rc = init_batt_gpio()) < 0) {
1526 BATT_ERR("%s: init battery gpio failed!", __func__);
1527 return rc;
1531 /* init structure data member */
1532 htc_batt_info.update_time = jiffies;
1533 /* A9 will shutdown the phone if battery is pluged out, so this value is always 1.
1534 htc_batt_info.present = gpio_get_value(GPIO_TROUT_MBAT_IN);
1536 htc_batt_info.present = 1;
1538 if(!htc_batt_info.force_no_rpc) {
1539 /* init rpc */
1540 endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
1541 if (IS_ERR(endpoint)) {
1542 BATT_ERR("%s: init rpc failed! rc = %ld",
1543 __func__, PTR_ERR(endpoint));
1544 return -EINVAL;
1548 /* init power supplier framework */
1549 for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) {
1550 rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]);
1551 if (rc)
1552 BATT_ERR("%s: Failed to register power supply (%d)", __func__, rc);
1555 /* create htc detail attributes */
1556 htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev);
1558 /* After battery driver gets initialized, send rpc request to inquiry
1559 * the battery status in case of we lost some info
1561 htc_battery_initial = 1;
1563 if(htc_batt_info.force_no_rpc) {
1564 update_batt_info();
1566 else {
1567 mutex_lock(&htc_batt_info.rpc_lock);
1568 htc_batt_info.rep.charging_source = CHARGER_BATTERY;
1569 if (htc_get_batt_info(&htc_batt_info.rep) < 0)
1570 BATT_ERR("%s: get info failed", __func__);
1572 if (htc_rpc_set_delta(1) < 0)
1573 BATT_ERR("%s: set delta failed", __func__);
1574 htc_batt_info.update_time = jiffies;
1575 mutex_unlock(&htc_batt_info.rpc_lock);
1578 return 0;
1581 static struct platform_driver htc_battery_core_driver = {
1582 .probe = htc_battery_core_probe,
1583 .driver = {
1584 .name = APP_BATT_PDEV_NAME,
1585 .owner = THIS_MODULE,
1589 /* batt_mtoa server definitions */
1590 #define BATT_MTOA_PROG 0x30100000
1591 #define BATT_MTOA_VERS 0
1592 #define RPC_BATT_MTOA_NULL 0
1593 #define RPC_BATT_MTOA_SET_CHARGING_PROC 1
1594 #define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC 2
1595 #define RPC_BATT_MTOA_LEVEL_UPDATE_PROC 3
1597 struct rpc_batt_mtoa_set_charging_args {
1598 int enable;
1601 struct rpc_batt_mtoa_cable_status_update_args {
1602 int status;
1605 struct rpc_dem_battery_update_args {
1606 uint32_t level;
1609 static int handle_battery_call(struct msm_rpc_server *server,
1610 struct rpc_request_hdr *req, unsigned len)
1612 switch (req->procedure) {
1613 case RPC_BATT_MTOA_NULL:
1614 return 0;
1616 case RPC_BATT_MTOA_SET_CHARGING_PROC: {
1617 struct rpc_batt_mtoa_set_charging_args *args;
1618 args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1);
1619 args->enable = be32_to_cpu(args->enable);
1620 if (htc_batt_debug_mask & HTC_BATT_DEBUG_M2A_RPC)
1621 BATT_LOG("M2A_RPC: set_charging: %d", args->enable);
1622 if (htc_batt_info.charger == SWITCH_CHARGER)
1623 blocking_notifier_call_chain(&cable_status_notifier_list,
1624 args->enable, NULL);
1625 else {
1626 htc_battery_set_charging(args->enable);
1628 return 0;
1630 case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: {
1631 struct rpc_batt_mtoa_cable_status_update_args *args;
1632 args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
1633 args->status = be32_to_cpu(args->status);
1634 if (htc_batt_debug_mask & HTC_BATT_DEBUG_M2A_RPC)
1635 BATT_LOG("M2A_RPC: cable_update: %s", charger_tags[args->status]);
1636 #if 0
1637 /* FIXME: work arround for usb function, remove it after battery driver ready */
1638 if (machine_is_incrediblec() && args->status == CHARGER_AC)
1639 args->status = CHARGER_USB;
1640 #endif
1641 htc_cable_status_update(args->status);
1642 #if defined(CONFIG_TROUT_BATTCHG_DOCK)
1643 dock_detect_start(args->status);
1644 #endif
1645 return 0;
1647 case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: {
1648 struct rpc_dem_battery_update_args *args;
1649 args = (struct rpc_dem_battery_update_args *)(req + 1);
1650 args->level = be32_to_cpu(args->level);
1651 if (htc_batt_debug_mask & HTC_BATT_DEBUG_M2A_RPC)
1652 BATT_LOG("M2A_RPC: level_update: %d", args->level);
1653 htc_battery_status_update(args->level);
1654 return 0;
1656 default:
1657 BATT_ERR("%s: program 0x%08x:%d: unknown procedure %d",
1658 __func__, req->prog, req->vers, req->procedure);
1659 return -ENODEV;
1663 static struct msm_rpc_server battery_server = {
1664 .prog = BATT_MTOA_PROG,
1665 .vers = BATT_MTOA_VERS,
1666 .rpc_call = handle_battery_call,
1669 #if defined(CONFIG_BATTERY_DS2784) || defined(CONFIG_BATTERY_DS2746)
1670 static int ds2784_notifier_func(struct notifier_block *nfb,
1671 unsigned long action, void *param)
1673 u8 arg = 0;
1674 if (param)
1675 arg = *(u8 *)param;
1677 BATT_LOG("ds2784_notify: %ld %d", action, arg);
1678 switch (action) {
1679 case DS2784_CHARGING_CONTROL:
1680 if (htc_batt_info.charger == LINEAR_CHARGER)
1681 battery_charging_ctrl(arg);
1682 // else if(htc_batt_info.charger == SWITCH_CHARGER)
1683 // set_charger_ctrl(arg);
1684 break;
1685 case DS2784_LEVEL_UPDATE:
1686 htc_battery_status_update(arg);
1687 break;
1688 case DS2784_BATTERY_FAULT:
1689 case DS2784_OVER_TEMP:
1690 htc_battery_status_update(htc_batt_info.rep.level);
1691 break;
1692 default:
1693 return NOTIFY_BAD;
1696 return NOTIFY_OK; /* we did not care other action here */
1699 static struct notifier_block ds2784_notifier = {
1700 .notifier_call = ds2784_notifier_func,
1703 #endif
1705 static int htc_battery_probe(struct platform_device *pdev)
1707 int rc = 0;
1708 struct htc_battery_platform_data *pdata = pdev->dev.platform_data;
1709 pr_info("HTC Battery Probe\n");
1710 htc_batt_info.device_id = pdev->id;
1711 htc_batt_info.gpio_usb_id = pdata->gpio_usb_id;
1712 htc_batt_info.gpio_power = pdata->gpio_power;
1713 htc_batt_info.guage_driver = pdata->guage_driver;
1714 htc_batt_info.m2a_cable_detect = pdata->m2a_cable_detect;
1715 htc_batt_info.force_no_rpc = pdata->force_no_rpc;
1716 htc_batt_info.func_show_batt_attr = pdata->func_show_batt_attr;
1717 htc_batt_info.charger = pdata->charger;
1718 htc_batt_info.rep.full_level = 100;
1720 if (htc_batt_info.charger == LINEAR_CHARGER) {
1721 htc_batt_info.gpio_mbat_in = pdata->gpio_mbat_in;
1722 htc_batt_info.gpio_mchg_en_n = pdata->gpio_mchg_en_n;
1723 htc_batt_info.gpio_iset = pdata->gpio_iset;
1726 if (pdata->guage_driver == GUAGE_MODEM ||
1727 pdata->m2a_cable_detect)
1728 msm_rpc_create_server(&battery_server);
1729 #ifdef CONFIG_BATTERY_DS2784
1730 if (pdata->guage_driver == GUAGE_DS2784)
1731 ds2784_register_notifier(&ds2784_notifier);
1732 #elif defined(CONFIG_BATTERY_DS2746)
1733 if (pdata->guage_driver == GUAGE_DS2746)
1734 ds2746_register_notifier(&ds2784_notifier);
1735 #endif
1737 if (system_rev >= 1 || machine_is_htcleo()) {
1738 if (pdata->int_data.chg_int) {
1739 BATT_LOG("init over voltage interrupt detection.");
1740 INIT_DELAYED_WORK(&pdata->int_data.int_work,
1741 htc_battery_tps65200_int_func);
1743 rc = request_irq(pdata->int_data.chg_int,
1744 tps65200_int_detection,
1745 IRQF_TRIGGER_LOW,
1746 "over_voltage_interrupt",
1747 &pdata->int_data);
1749 if (rc) {
1750 BATT_LOG("request irq failed");
1751 return rc;
1755 #if defined(CONFIG_MACH_HTCLEO)
1756 if(pdata->force_no_rpc) {
1757 htc_battery_core_probe(pdev);
1758 msm_hsusb_set_vbus_state(get_vbus_state());
1760 #endif
1761 return 0;
1764 int get_cable_status(void)
1766 // if(htc_batt_info.rep.charging_source == CHARGER_AC || htc_batt_info.rep.charging_source == CHARGER_USB)
1767 // htc_cable_status_update(htc_batt_info.rep.charging_source);
1768 return htc_batt_info.rep.charging_source;
1771 static struct platform_driver htc_battery_driver = {
1772 .probe = htc_battery_probe,
1773 .driver = {
1774 .name = "htc_battery",
1775 .owner = THIS_MODULE,
1779 static struct notifier_block batt_notify = {
1780 .notifier_call = htc_power_policy,
1783 static BLOCKING_NOTIFIER_HEAD(battery_notifier_list);
1784 int batt_register_client(struct notifier_block *nb)
1786 return blocking_notifier_chain_register(&battery_notifier_list, nb);
1789 int batt_unregister_client(struct notifier_block *nb)
1791 return blocking_notifier_chain_unregister(&battery_notifier_list, nb);
1794 int batt_notifier_call_chain(unsigned long val, void *v)
1796 return blocking_notifier_call_chain(&battery_notifier_list, val, v);
1799 static int __init htc_battery_init(void)
1801 wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
1802 mutex_init(&htc_batt_info.lock);
1803 mutex_init(&htc_batt_info.rpc_lock);
1804 usb_register_notifier(&usb_status_notifier);
1805 platform_driver_register(&htc_battery_driver);
1806 platform_driver_register(&htc_battery_core_driver);
1807 batt_register_client(&batt_notify);
1808 /* Jay, The msm_fb need to consult htc_battery for power policy */
1809 display_notifier(htc_power_policy, NOTIFY_POWER);
1810 return 0;
1813 module_init(htc_battery_init);
1814 MODULE_DESCRIPTION("HTC Battery Driver");
1815 MODULE_LICENSE("GPL");
1816 EXPORT_SYMBOL(htc_is_cable_in);
1817 EXPORT_SYMBOL(htc_is_zcharge_enabled);