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>
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"
39 #include <mach/msm_iomap.h>
41 #if defined(CONFIG_TROUT_BATTCHG_DOCK)
42 #include <mach/htc_one_wire.h>
44 #ifdef CONFIG_BATTERY_DS2784
45 #include <linux/ds2784_battery.h>
46 #elif defined(CONFIG_BATTERY_DS2746)
47 #include <linux/ds2746_battery.h>
50 static struct wake_lock vbus_wake_lock
;
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 { \
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); \
75 #define BATT_ERR(x...) do { \
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); \
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
{
104 unsigned long update_time
;
106 /* lock to protect the battery info */
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
);
119 int m2a_cable_detect
;
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
[] = {
150 /* HTC dedicated attributes */
151 static ssize_t
htc_battery_show_property(struct device
*dev
,
152 struct device_attribute
*attr
,
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
[] = {
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
,
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
,
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))
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)
233 if (!htc_battery_initial
) return;
234 vbus
= get_vbus_state();
235 notify_cable_status(vbus
);
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
;
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__
);
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
)
274 if (htc_is_cable_in())
283 static int htc_power_policy(struct notifier_block
*nfb
,
284 unsigned long action
, void *ignored
)
289 pr_info("%s: enter.\n", __func__
);
290 rc
= __htc_power_policy();
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())
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 == ?? */
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
);
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
);
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
)
344 DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops
, batt_debug_get
, batt_debug_set
, "%llu\n");
345 static int __init
batt_debug_init(void)
349 dent
= debugfs_create_dir("htc_battery", 0);
351 return PTR_ERR(dent
);
353 debugfs_create_file("charger_state", 0644, dent
, NULL
, &batt_debug_fops
);
358 device_initcall(batt_debug_init
);
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)
366 if (htc_batt_info
.gpio_mchg_en_n
> 0 &&
367 gpio_request(htc_batt_info
.gpio_mchg_en_n
, "charger_en") < 0)
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)
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)
381 gpio_direction_output(htc_batt_info
.gpio_power
, 0);
391 * battery_charging_ctrl - battery charing control.
392 * @ctl: battery control command
395 int battery_charging_ctrl(enum batt_ctl_t ctl
)
398 if (!htc_battery_initial
) return 0;
402 BATT_LOG("charger OFF");
403 /* 0 for enable; 1 disable */
404 result
= gpio_direction_output(htc_batt_info
.gpio_mchg_en_n
, 1);
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);
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);
417 BATT_ERR("%s: Not supported battery ctr called.!", __func__
);
425 static int htc_battery_set_charging(enum batt_ctl_t ctl
)
429 if ((rc
= battery_charging_ctrl(ctl
)) < 0)
432 if (!htc_battery_initial
) {
433 htc_batt_info
.rep
.charging_enabled
= ctl
& 0x3;
435 mutex_lock(&htc_batt_info
.lock
);
436 htc_batt_info
.rep
.charging_enabled
= ctl
& 0x3;
437 mutex_unlock(&htc_batt_info
.lock
);
443 static int htc_battery_status_update(u32 curr_level
)
446 if (!htc_battery_initial
)
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
);
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");
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");
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
);
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
);
486 static int htc_set_smem_cable_type(u32 cable_type
) { return -1; }
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
);
491 static int htc_cable_status_update(int status
)
494 // unsigned last_source;
496 if (!htc_battery_initial
)
499 if (status
< CHARGER_BATTERY
|| status
> CHARGER_AC
) {
500 BATT_ERR("%s: Not supported cable status received!", __func__
);
504 mutex_lock(&htc_batt_info
.lock
);
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
);
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
]);
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
,
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");
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
;
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)
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
));
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
);
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
]);
601 mutex_unlock(&htc_batt_info
.lock
);
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
;
617 printk(KERN_INFO
"%s\n", __func__
);
619 if (buffer
== NULL
) {
620 printk(KERN_INFO
"%s: buffer null\n", __func__
);
624 rc
= msm_rpc_call_reply(endpoint
, HTC_PROCEDURE_GET_USB_ACCESSORY_ADC_LEVEL
,
629 printk(KERN_INFO
"%s: msm_rpc_call_reply fail\n", __func__
);
632 *buffer
= be32_to_cpu(rep
.adc_value
);
634 printk(KERN_INFO
"%s: adc = %d\n", __func__
, *buffer
);
637 EXPORT_SYMBOL(htc_get_usb_accessory_adc_level
);
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
)
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
]);
661 pr_err("\n\n ### htc_battery_code is not inited yet! ###\n\n");
663 update_wake_lock(htc_batt_info
.rep
.charging_source
);
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
);
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
;
694 rc
= msm_rpc_call_reply(endpoint
, HTC_PROCEDURE_GET_BATT_INFO
,
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
);
726 #ifdef CONFIG_HTC_BATTCHG_SMEM
727 struct htc_batt_info_full
{
733 s32 batt_current_last
;
734 u32 batt_discharge_current
;
761 u32 eval_current_last
;
762 u32 charging_enabled
;
771 u32 sleep_timer_count
;
773 u32 overloading_charge
;
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)*/
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
);
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. */
810 buffer
->level
= smem_batt_info
->percent_update
;
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
);
830 static ssize_t
htc_battery_show_smem(struct device
*dev
,
831 struct device_attribute
*attr
,
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");
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
,
852 "batt_vol_last: %d\n"
855 "batt_current_last: %d\n"
856 "batt_discharge_current: %d\n"
868 "percent_update: %d\n"
872 "charging_source: %d\n"
876 "eval_current_last: %d\n"
877 "charging_enabled: %d\n"
884 "sleep_timer_count: %d\n"
886 "overloading_charge: %d\n"
887 "a2m_cable_type: %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
);
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");
946 smem_batt_info
->a2m_cable_type
= cable_type
;
947 BATT_LOG("Update SMEM: cable type %d", cable_type
);
952 static ssize_t
htc_battery_show_batt_attr(struct device
*dev
,
953 struct device_attribute
*attr
,
956 switch (htc_batt_info
.guage_driver
) {
958 #ifdef CONFIG_HTC_BATTCHG_SMEM
959 return htc_battery_show_smem(dev
, attr
, buf
);
964 return htc_batt_info
.func_show_batt_attr(attr
, buf
);
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
);
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
);
1006 /* Once charge full, set this flag */
1007 static int htc_charge_full
= 0;
1009 static int htc_battery_get_charging_status(void)
1012 enum charger_type_t charger
;
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
;
1024 case CHARGER_BATTERY
:
1025 htc_charge_full
= 0;
1026 ret
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
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;
1035 level
= htc_batt_info
.rep
.level
;
1037 htc_charge_full
= 1;}
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
;
1046 ret
= POWER_SUPPLY_STATUS_DISCHARGING
;
1049 ret
= POWER_SUPPLY_STATUS_UNKNOWN
;
1051 mutex_unlock(&htc_batt_info
.lock
);
1055 static int htc_battery_get_property(struct power_supply
*psy
,
1056 enum power_supply_property psp
,
1057 union power_supply_propval
*val
)
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
);
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
;
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
);
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
);
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
);
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
);
1111 #define HTC_BATTERY_ATTR(_name) \
1113 .attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE }, \
1114 .show = htc_battery_show_property, \
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
),
1132 __ATTR(batt_attr_text
, S_IRUGO
, htc_battery_show_batt_attr
, NULL
),
1146 static int htc_rpc_set_delta(unsigned delta
)
1148 struct set_batt_delta_req
{
1149 struct rpc_request_hdr hdr
;
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
;
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
;
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
)
1187 unsigned long delta
= 0;
1189 delta
= simple_strtoul(buf
, NULL
, 10);
1194 mutex_lock(&htc_batt_info
.rpc_lock
);
1195 rc
= htc_rpc_set_delta(delta
);
1196 mutex_unlock(&htc_batt_info
.rpc_lock
);
1203 * For PA and QA test
1204 * 0x10-> fake temp to 250
1205 * 0x11->TBD if needed
1206 * 0x12->TBD if needed
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)
1219 mutex_lock(&htc_batt_info
.lock
);
1220 blocking_notifier_call_chain(&cable_status_notifier_list
,
1222 mutex_unlock(&htc_batt_info
.lock
);
1227 static ssize_t
htc_battery_charger_switch(struct device
*dev
,
1228 struct device_attribute
*attr
,
1229 const char *buf
, size_t count
)
1232 unsigned long enable
= 0;
1234 enable
= simple_strtoul(buf
, NULL
, 10);
1236 if (enable
> 1 || enable
< 0)
1239 mutex_lock(&htc_batt_info
.rpc_lock
);
1240 rc
= htc_rpc_charger_switch(enable
);
1241 mutex_unlock(&htc_batt_info
.rpc_lock
);
1248 static ssize_t
htc_battery_set_full_level(struct device
*dev
,
1249 struct device_attribute
*attr
,
1250 const char *buf
, size_t count
)
1253 unsigned long percent
= 100;
1255 percent
= simple_strtoul(buf
, NULL
, 10);
1257 if (percent
> 100 || percent
== 0)
1260 switch (htc_batt_info
.guage_driver
) {
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
);
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
);
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
]);
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
]);
1305 goto htc_delta_attrs_failed
;
1312 device_remove_file(dev
, &htc_battery_attrs
[i
]);
1313 htc_delta_attrs_failed
:
1315 device_remove_file(dev
, &htc_set_delta_attrs
[i
]);
1320 static int update_batt_info(void)
1325 switch (htc_batt_info
.guage_driver
) {
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__
);
1333 if (htc_get_batt_info(&htc_batt_info
.rep
) < 0) {
1334 BATT_ERR("%s: rpc failed!!!", __func__
);
1339 #ifdef CONFIG_BATTERY_DS2784
1341 if (ds2784_get_battery_info(&htc_batt_info
.rep
)) {
1342 BATT_ERR("%s: ds2784 read failed!!!", __func__
);
1346 #elif defined(CONFIG_BATTERY_DS2746)
1348 if (ds2746_get_battery_info(&htc_batt_info
.rep
)) {
1349 BATT_ERR("%s: ds2746 read failed!!!", __func__
);
1362 static ssize_t
htc_battery_show_property(struct device
*dev
,
1363 struct device_attribute
*attr
,
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
;
1386 mutex_unlock(&htc_batt_info
.rpc_lock
);
1388 mutex_lock(&htc_batt_info
.lock
);
1391 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1392 htc_batt_info
.rep
.batt_id
);
1395 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1396 htc_batt_info
.rep
.batt_vol
);
1399 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1400 htc_batt_info
.rep
.batt_temp
);
1403 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1404 htc_batt_info
.rep
.batt_current
);
1406 case CHARGING_SOURCE
:
1407 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1408 htc_batt_info
.rep
.charging_source
);
1410 case CHARGING_ENABLED
:
1411 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1412 htc_batt_info
.rep
.charging_enabled
);
1415 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1416 htc_batt_info
.rep
.full_bat
);
1419 i
+= scnprintf(buf
+ i
, PAGE_SIZE
- i
, "%d\n",
1420 htc_batt_info
.rep
.over_vchg
);
1425 mutex_unlock(&htc_batt_info
.lock
);
1427 if (htc_batt_debug_mask
& HTC_BATT_DEBUG_USER_QUERY
) {
1429 BATT_LOG("%s: battery: attribute is not supported: %d", __func__
, off
);
1431 BATT_LOG("%s: battery: %s=%s", __func__
, attr
->attr
.name
, buf
);
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));
1451 static void htc_battery_tps65200_int_func(struct work_struct
*work
)
1453 struct htc_battery_tps65200_int
*ip
;
1455 ip
= container_of(work
, struct htc_battery_tps65200_int
,
1458 switch (ip
->tps65200_reg
) {
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
);
1468 #ifdef CONFIG_HTC_BATTCHG_SMEM
1469 smem_batt_info
->over_vchg
= 1;
1471 htc_batt_info
.rep
.over_vchg
= 1;
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:"
1480 #ifdef CONFIG_HTC_BATTCHG_SMEM
1481 smem_batt_info
->over_vchg
= 0;
1483 htc_batt_info
.rep
.over_vchg
= 0;
1485 cancel_delayed_work(&ip
->int_work
);
1486 enable_irq(ip
->chg_int
);
1490 fault_bit
= tps_set_charger_ctrl(CHECK_INT2
);
1491 BATT_LOG("Read TPS65200 INT2 register value: %x", fault_bit
);
1493 fault_bit
= tps_set_charger_ctrl(CHECK_INT2
);
1494 BATT_LOG("Read TPS65200 INT2 register value: %x"
1496 fault_bit
= tps_set_charger_ctrl(CHECK_INT2
);
1497 BATT_LOG("Read TPS65200 INT2 register value: %x"
1499 fault_bit
= tps_set_charger_ctrl(CHECK_CONTROL
);
1500 #ifdef CONFIG_HTC_BATTCHG_SMEM
1501 smem_batt_info
->reserve4
= 1;
1503 cancel_delayed_work(&ip
->int_work
);
1504 enable_irq(ip
->chg_int
);
1506 fault_bit
= tps_set_charger_ctrl(CHECK_INT1
);
1507 BATT_LOG("Read TPS65200 INT1 register value: %x"
1510 ip
->tps65200_reg
= CHECK_INT1
;
1511 schedule_delayed_work(&ip
->int_work
,
1512 msecs_to_jiffies(200));
1519 static int htc_battery_core_probe(struct platform_device
*pdev
)
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__
);
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
) {
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
));
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
]);
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
) {
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
);
1581 static struct platform_driver htc_battery_core_driver
= {
1582 .probe
= htc_battery_core_probe
,
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
{
1601 struct rpc_batt_mtoa_cable_status_update_args
{
1605 struct rpc_dem_battery_update_args
{
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
:
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
);
1626 htc_battery_set_charging(args
->enable
);
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
]);
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
;
1641 htc_cable_status_update(args
->status
);
1642 #if defined(CONFIG_TROUT_BATTCHG_DOCK)
1643 dock_detect_start(args
->status
);
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
);
1657 BATT_ERR("%s: program 0x%08x:%d: unknown procedure %d",
1658 __func__
, req
->prog
, req
->vers
, req
->procedure
);
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
)
1677 BATT_LOG("ds2784_notify: %ld %d", action
, arg
);
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);
1685 case DS2784_LEVEL_UPDATE
:
1686 htc_battery_status_update(arg
);
1688 case DS2784_BATTERY_FAULT
:
1689 case DS2784_OVER_TEMP
:
1690 htc_battery_status_update(htc_batt_info
.rep
.level
);
1696 return NOTIFY_OK
; /* we did not care other action here */
1699 static struct notifier_block ds2784_notifier
= {
1700 .notifier_call
= ds2784_notifier_func
,
1705 static int htc_battery_probe(struct platform_device
*pdev
)
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
);
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
,
1746 "over_voltage_interrupt",
1750 BATT_LOG("request irq failed");
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());
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
,
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
);
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
);