htcleo: add new battery driver

This driver is comming from desire hd and is modificated for htcleo
This commit is contained in:
Markinus 2010-10-26 17:41:48 +02:00
parent dbd408efab
commit 55ca1d277a
15 changed files with 3008 additions and 997 deletions

View File

@ -236,7 +236,7 @@ CONFIG_MACH_HTCLEO=y
# CONFIG_MACH_INCREDIBLE is not set
# CONFIG_MACH_INCREDIBLEC is not set
# CONFIG_MACH_SUPERSONIC is not set
# CONFIG_HTC_BATTCHG is not set
CONFIG_HTC_BATTCHG=y
# CONFIG_HTC_PWRSINK is not set
CONFIG_HTC_SLEEP_MODE_GPIO_DUMP=y
# CONFIG_HTC_POWER_COLLAPSE_MAGIC is not set
@ -1161,7 +1161,7 @@ CONFIG_POWER_SUPPLY=y
# CONFIG_BATTERY_DS2760 is not set
# CONFIG_BATTERY_DS2782 is not set
# CONFIG_BATTERY_DS2784 is not set
# CONFIG_BATTERY_DS2746 is not set
CONFIG_BATTERY_DS2746=y
# CONFIG_BATTERY_BQ27x00 is not set
# CONFIG_BATTERY_MAX17040 is not set
# CONFIG_HWMON is not set

View File

@ -115,9 +115,9 @@ obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-wifi.o htc_awb_cal.o
obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-microp.o clock.o
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o board-htcleo-panel.o board-htcleo-keypad.o
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-ts.o board-htcleo-mmc.o ieee754-df.o board-htcleo-power.o
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-ts.o board-htcleo-mmc.o ieee754-df.o
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-battery.o board-htcleo-log.o board-htcleo-audio.o board-htcleo-acoustic.o
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-audio.o board-htcleo-acoustic.o
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-rfkill.o board-htcleo-wifi.o board-htcleo-microp.o
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-proximity.o board-htcleo-leds.o board-htcleo-ls.o
obj-$(CONFIG_MACH_HTCLEO) += clock-wince.o

View File

@ -1,728 +0,0 @@
/* arch/arm/mach-msm/board-htcleo-battery.h
*
* Copyright (C) 2010 Markinus
* Copyright (C) 2009 HTC Corporation
* Copyright (C) 2009 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*
actually this file called "board-htcleo-battery.c", so it's HTC LEO specific only
most values are hard coded here really.
this driver designed for android.
proper ds2745 driver located at "driver/i2c/chips/ds2745.c"
I don't want and have not resources to support any "proper" linux drivers coding.
("proper" for them, not for me ofcourse)
my primary target was to make high quality battery support in Android for HTC LEO. kefir with us!
*/
//#define DEBUG
#include <linux/module.h>
#include <linux/param.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/wakelock.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <mach/board-htcleo-battery.h>
#include "gpio_chip.h"
#include "board-htcleo.h"
static enum power_supply_property battery_properties[] =
{
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
};
static int battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val);
static void htcleo_program_alarm(struct htcleo_device_info *di, int seconds);
static void battery_ext_power_changed(struct power_supply *psy);
#define BATTERY_LOG_MAX 1024
#define BATTERY_LOG_MASK (BATTERY_LOG_MAX - 1)
static DEFINE_MUTEX(battery_log_lock);
static struct battery_status battery_log[BATTERY_LOG_MAX];
static unsigned battery_log_head;
static unsigned battery_log_tail;
void battery_log_status(struct battery_status *s)
{
unsigned n;
mutex_lock(&battery_log_lock);
n = battery_log_head;
memcpy(battery_log + n, s, sizeof(struct battery_status));
n = (n + 1) & BATTERY_LOG_MASK;
if (n == battery_log_tail)
battery_log_tail = (battery_log_tail + 1) & BATTERY_LOG_MASK;
battery_log_head = n;
mutex_unlock(&battery_log_lock);
}
static const char *battery_source[3] = { "none", " usb", " ac" };
static const char *battery_mode[4] = { " off", "slow", "fast", "full" };
static int battery_log_print(struct seq_file *sf, void *private)
{
unsigned n;
mutex_lock(&battery_log_lock);
seq_printf(sf, "timestamp mV mA avg mA uAh dC %% src mode reg full\n");
for (n = battery_log_tail; n != battery_log_head; n = (n + 1) & BATTERY_LOG_MASK)
{
struct battery_status *s = battery_log + n;
seq_printf(sf, "%9d %5d %6d %6d %8d %4d %3d %s %s 0x%02x %d\n",
s->timestamp, s->voltage_uV / 1000,
s->current_uA / 1000, s->current_avg_uA / 1000,
s->charge_uAh, s->temp_C,
s->percentage,
battery_source[s->charge_source],
battery_mode[s->charge_mode],
s->status_reg, s->battery_full);
}
mutex_unlock(&battery_log_lock);
return 0;
}
static int I2C_Read_Status(struct htcleo_device_info *di)
{
uint8_t i2c_msg[1];
uint8_t i2c_data[2];
i2c_msg[0] = 0x01; //status reg
i2c_master_send(di->client, i2c_msg, 1);
i2c_master_recv(di->client, i2c_data, 2);
dev_dbg(&di->client->dev, "I2C_Read_Status() = %08X!\n", i2c_data[0]);
di->raw_status = i2c_data[0];
return 0;
}
static int I2C_Read_Data(struct htcleo_device_info *di)
{
uint8_t i2c_msg[1];
uint8_t i2c_data[10];
i2c_msg[0] = 0x08; // AUX0 AUX1 VOLTAGE CURRENT ACR
i2c_master_send(di->client, i2c_msg, 1);
i2c_master_recv(di->client, i2c_data, 10);
dev_dbg(&di->client->dev, "I2C_Read_Data() %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X!\n",
i2c_data[0], i2c_data[1], i2c_data[2], i2c_data[3], i2c_data[4],
i2c_data[5], i2c_data[6], i2c_data[7], i2c_data[8], i2c_data[9]);
memcpy(di->raw, i2c_data, 10);
return 0;
}
static int I2C_Write_ACR(struct htcleo_device_info *di, uint16_t val)
{
uint8_t i2c_msg[3];
i2c_msg[0] = 0x10;
i2c_msg[1] = (val >> 8) & 0xFF;
i2c_msg[2] = (val >> 0) & 0xFF;
// dev_dbg(&di->client->dev, "I2C_Write_ACR() = %04X!\n", val);
i2c_master_send(di->client, i2c_msg, 3);
return 0;
}
//////////////////////////////////////////////////////////////////////////
static int htcleo_charge(int on, int fast)
{
gpio_direction_output(HTCLEO_GPIO_BATTERY_CHARGER_CURRENT, !!fast);
gpio_direction_output(HTCLEO_GPIO_BATTERY_CHARGER_ENABLE, !on);
return 0;
}
static void htcleo_parse_data(uint32_t raw_status, u8 *raw, struct battery_status *s)
{
short n;
uint32_t n32;
uint32_t FL, ACR, ACR_EMPTY;
/* Get status reg */
s->status_reg = raw_status;
/* Get Level */
// TODO: FL too wrong (?)
ACR = ((raw[8] << 8) | raw[9]);
FL = (LEO_BATTERY_CAPACITY * 1570) / 625;
ACR_EMPTY = (LEO_BATTERY_EMPTY * 1570) / 625;
s->percentage = (100 * (ACR - ACR_EMPTY)) / FL;
s->charge_uAh = 1000 * (((ACR - ACR_EMPTY) * 625) / 1570);
if (s->percentage < 0 ) s->percentage = 0;
if (s->percentage > 100 ) s->percentage = 100;
/* Get Voltage */
n32 = (((raw[4] << 8) | raw[5]) / 16);
//s->voltage_uV = (n32 * 244) / 100;
s->voltage_uV = 1000 * ((n32 * 312) >> 7); // div to 128
/* Get Current */
n = ((raw[6]) << 8) | raw[7];
s->current_uA = 1000 * (((n/4) * 625) / 1570);
printk("ACR=%d CURR=%d VOL=%d RAAC=%d\n", ACR, s->current_uA, s->voltage_uV, s->percentage);
// average current not supported by DS2746
s->current_avg_uA = s->current_uA;
/* Get Temperature */
n = ((raw[0] << 8) | (raw[1]));
n /= 16;
// printk("temp = %x\n", n);
if (n > 2047 || n == 0)
{
s->temp_C = 250;
}
else
{
double v = 0.021277 * (300.0 / (2047.0 / n - 1.0));
s->temp_C = 10 * (1.0 / ((log(v) * 0.000290698) + 0.003354016) - 273.15);
}
if (s->temp_C < -250)
{
s->temp_C = -250;
}
}
static int htcleo_battery_read_status(struct htcleo_device_info *di)
{
// read status
I2C_Read_Status(di);
I2C_Read_Data(di);
// printk("status = %04X\n", di->raw_status);
htcleo_parse_data(di->raw_status, di->raw, &di->status);
dev_dbg(&di->client->dev, "batt: %3d%%, %d mV, %d mA (%d avg), %d.%d C, %d mAh\n",
di->status.percentage,
di->status.voltage_uV / 1000, di->status.current_uA / 1000,
di->status.current_avg_uA / 1000,
di->status.temp_C / 10, di->status.temp_C % 10,
di->status.charge_uAh / 1000);
return 0;
}
//////////////////////////////////////////////////////////////////////////
static int htcleo_set_cc(struct htcleo_device_info *di, bool enable)
{
// not supported for DS2745, there no CE bit
return 0;
}
static int battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{
struct htcleo_device_info *di = psy_to_dev_info(psy);
switch (psp)
{
case POWER_SUPPLY_PROP_STATUS:
switch (di->status.charge_source)
{
case CHARGE_OFF:
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
case CHARGE_FAST:
case CHARGE_SLOW:
if (di->status.battery_full)
val->intval = POWER_SUPPLY_STATUS_FULL;
else if (di->status.charge_mode == CHARGE_OFF)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_CHARGING;
break;
default:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
}
break;
case POWER_SUPPLY_PROP_HEALTH:
if (di->status.temp_C >= TEMP_HOT)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
else
val->intval = POWER_SUPPLY_HEALTH_GOOD;
break;
case POWER_SUPPLY_PROP_PRESENT:
/* XXX todo */
val->intval = 1;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
if (di->dummy)
val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
else
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_CAPACITY:
if (di->dummy)
val->intval = 75;
else
val->intval = di->status.percentage;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = di->status.voltage_uV;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = di->status.temp_C;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = di->status.current_uA;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
val->intval = di->status.current_avg_uA;
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
val->intval = di->status.charge_uAh;
break;
default:
return -EINVAL;
}
return 0;
}
static void htcleo_battery_update_status(struct htcleo_device_info *di)
{
u8 last_level;
last_level = di->status.percentage;
htcleo_battery_read_status(di);
// CotullaTODO: add ACR = FL at top point here
if ((last_level != di->status.percentage) || (di->status.temp_C > 450))
{
power_supply_changed(&di->bat);
}
}
static DEFINE_MUTEX(charge_state_lock);
static bool check_timeout(ktime_t now, ktime_t last, int seconds)
{
ktime_t timeout = ktime_add(last, ktime_set(seconds, 0));
return ktime_sub(timeout, now).tv64 < 0;
}
static int battery_adjust_charge_state(struct htcleo_device_info *di)
{
unsigned source;
int rc = 0;
int temp, volt, curr, perc;
int ovp;
u8 charge_mode;
bool charge_timeout = false;
static int lastval=0xffff;
const int min_curr=5000;
mutex_lock(&charge_state_lock);
curr = di->status.current_uA;
perc = di->status.percentage;
temp = di->status.temp_C;
volt = di->status.voltage_uV / 1000;
source = di->status.charge_source;
/* initially our charge mode matches our source:
* NONE:OFF, USB:SLOW, AC:FAST
*/
charge_mode = source;
// Check whether the bat is full and change the ACR to right 100% value
if(curr >=0 && curr < min_curr && lastval < min_curr && perc > 95 && source) {
uint32_t FL = (LEO_BATTERY_CAPACITY * 1570) / 625;
uint32_t ACR_EMPTY = (LEO_BATTERY_EMPTY * 1570) / 625;
I2C_Write_ACR(di, FL+ACR_EMPTY);
di->status.battery_full = 1;
di->status.percentage = 100;
charge_mode = CHARGE_OFF;
}
else {
di->status.battery_full = 0;
}
if(curr >=0) lastval=curr;
else lastval=0xffff;
ovp = gpio_get_value(HTCLEO_GPIO_BATTERY_OVER_CHG);
if (ovp)
{
printk("Battery overpowered!\n");
}
if (temp >= TEMP_HOT || ovp)
{
if (temp >= TEMP_CRITICAL)
{
charge_mode = CHARGE_OFF;
}
/* once we charge to max voltage when hot, disable
* charging until the temp drops or the voltage drops
*/
if (volt >= TEMP_HOT_MAX_MV)
{
di->status.cooldown = 1;
}
}
/* when the battery is warm, only charge in slow charge mode */
if ((temp >= TEMP_WARM) && (charge_mode == CHARGE_FAST))
charge_mode = CHARGE_SLOW;
if (di->status.cooldown)
{
if ((temp < TEMP_WARM) || (volt <= TEMP_HOT_MIN_MV))
di->status.cooldown = 0;
else
charge_mode = CHARGE_OFF;
}
if (di->status.current_uA > 1024)
{
di->last_charge_seen = di->last_poll;
}
else if (di->last_charge_mode != CHARGE_OFF && check_timeout(di->last_poll, di->last_charge_seen, 60 * 60))
{
/* The charger has probably stopped charging. Turn it
* off until the next sample period.
*/
charge_timeout = true;
charge_mode = CHARGE_OFF;
}
if (source == CHARGE_OFF)
charge_mode = CHARGE_OFF;
if (di->last_charge_mode == charge_mode)
goto done;
di->last_charge_mode = charge_mode;
di->status.charge_mode = charge_mode;
switch (charge_mode)
{
case CHARGE_OFF:
htcleo_charge(0, 0);
htcleo_set_cc(di, true);
if (temp >= TEMP_CRITICAL)
pr_info("batt: charging OFF [OVERTEMP]\n");
else if (di->status.cooldown)
pr_info("batt: charging OFF [COOLDOWN]\n");
else if (di->status.battery_full)
pr_info("batt: charging OFF [FULL]\n");
else if (charge_timeout)
pr_info("batt: charging OFF [TIMEOUT]\n");
else
pr_info("batt: charging OFF\n");
break;
case CHARGE_SLOW:
di->last_charge_seen = di->last_poll;
htcleo_set_cc(di, true);
htcleo_charge(1, 0);
pr_info("batt: charging SLOW\n");
break;
case CHARGE_FAST:
di->last_charge_seen = di->last_poll;
htcleo_set_cc(di, true);
htcleo_charge(1, 1);
pr_info("batt: charging FAST\n");
break;
}
rc = 1;
done:
mutex_unlock(&charge_state_lock);
return rc;
}
static void htcleo_battery_work(struct work_struct *work)
{
struct htcleo_device_info *di = container_of(work, struct htcleo_device_info, monitor_work);
struct timespec ts;
unsigned long flags;
htcleo_battery_update_status(di);
di->last_poll = alarm_get_elapsed_realtime();
if (battery_adjust_charge_state(di))
{
power_supply_changed(&di->bat);
}
ts = ktime_to_timespec(di->last_poll);
di->status.timestamp = ts.tv_sec;
battery_log_status(&di->status);
/* prevent suspend before starting the alarm */
local_irq_save(flags);
wake_unlock(&di->work_wake_lock);
htcleo_program_alarm(di, FAST_POLL);
local_irq_restore(flags);
}
//////////////////////////////////////////////////////////////////////////
static void htcleo_program_alarm(struct htcleo_device_info *di, int seconds)
{
ktime_t low_interval = ktime_set(seconds - 10, 0);
ktime_t slack = ktime_set(20, 0);
ktime_t next;
next = ktime_add(di->last_poll, low_interval);
alarm_start_range(&di->alarm, next, ktime_add(next, slack));
}
static void htcleo_battery_alarm(struct alarm *alarm)
{
struct htcleo_device_info *di = container_of(alarm, struct htcleo_device_info, alarm);
wake_lock(&di->work_wake_lock);
queue_work(di->monitor_wqueue, &di->monitor_work);
}
static void battery_ext_power_changed(struct power_supply *psy)
{
struct htcleo_device_info *di;
int got_power;
di = psy_to_dev_info(psy);
got_power = power_supply_am_i_supplied(psy);
if (got_power)
{
if (is_ac_power_supplied())
di->status.charge_source = SOURCE_AC;
else
di->status.charge_source = SOURCE_USB;
wake_lock(&vbus_wake_lock);
}
else
{
di->status.charge_source = SOURCE_NONE;
/* give userspace some time to see the uevent and update
* LED state or whatnot...
*/
wake_lock_timeout(&vbus_wake_lock, HZ / 2);
}
battery_adjust_charge_state(di);
power_supply_changed(psy);
}
static int htcleo_battery_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int rc;
struct htcleo_device_info *di;
printk("%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE))
{
return -EIO;
}
di = kzalloc(sizeof(*di), GFP_KERNEL);
if (!di)
{
return -ENOMEM;
}
mydi=di;
di->client = client;
i2c_set_clientdata(client, di);
gpio_request(HTCLEO_GPIO_BATTERY_CHARGER_CURRENT, "charger_current");
gpio_request(HTCLEO_GPIO_BATTERY_CHARGER_ENABLE, "charger_enable");
gpio_request(HTCLEO_GPIO_BATTERY_OVER_CHG, "charger_over_chg");
gpio_direction_output(HTCLEO_GPIO_BATTERY_CHARGER_CURRENT, 1);
gpio_direction_output(HTCLEO_GPIO_BATTERY_CHARGER_ENABLE, 1);
gpio_direction_input(HTCLEO_GPIO_BATTERY_OVER_CHG);
di->bat.name = "battery";
di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
di->bat.properties = battery_properties;
di->bat.num_properties = ARRAY_SIZE(battery_properties);
di->bat.external_power_changed = battery_ext_power_changed;
di->bat.get_property = battery_get_property;
di->last_charge_mode = 0xff;
rc = power_supply_register(&client->dev, &di->bat);
if (rc)
{
goto fail_register;
}
INIT_WORK(&di->monitor_work, htcleo_battery_work);
di->monitor_wqueue = create_freezeable_workqueue(dev_name(&client->dev));
/* init to something sane */
di->last_poll = alarm_get_elapsed_realtime();
if (!di->monitor_wqueue)
{
rc = -ESRCH;
goto fail_workqueue;
}
wake_lock_init(&di->work_wake_lock, WAKE_LOCK_SUSPEND, "htcleo-battery");
printk("alarm init\n");
alarm_init(&di->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, htcleo_battery_alarm);
wake_lock(&di->work_wake_lock);
queue_work(di->monitor_wqueue, &di->monitor_work);
printk("%s: done!\n", __func__);
return 0;
fail_workqueue:
power_supply_unregister(&di->bat);
fail_register:
gpio_free(HTCLEO_GPIO_BATTERY_CHARGER_CURRENT);
gpio_free(HTCLEO_GPIO_BATTERY_CHARGER_ENABLE);
gpio_free(HTCLEO_GPIO_BATTERY_OVER_CHG);
kfree(di);
return rc;
}
static int htcleo_suspend(struct device *dev)
{
struct htcleo_device_info *di = dev_get_drvdata(dev);
/* If we are on battery, reduce our update rate until
* we next resume.
*/
if (di->status.charge_source == SOURCE_NONE)
{
htcleo_program_alarm(di, SLOW_POLL);
di->slow_poll = 1;
}
return 0;
}
static int htcleo_resume(struct device *dev)
{
struct htcleo_device_info *di = dev_get_drvdata(dev);
/* We might be on a slow sample cycle. If we're
* resuming we should resample the battery state
* if it's been over a minute since we last did
* so, and move back to sampling every minute until
* we suspend again.
*/
if (di->slow_poll)
{
htcleo_program_alarm(di, FAST_POLL);
di->slow_poll = 0;
}
return 0;
}
static struct dev_pm_ops htcleo_pm_ops =
{
.suspend = htcleo_suspend,
.resume = htcleo_resume,
};
static const struct i2c_device_id htcleo_battery_id[] =
{
{ "htcleo-battery", 0 },
{ }
};
static struct i2c_driver htcleo_battery_driver =
{
.driver =
{
.name = "htcleo-battery",
.owner = THIS_MODULE,
.pm = &htcleo_pm_ops,
},
.id_table = htcleo_battery_id,
.probe = htcleo_battery_probe,
#ifndef CONFIG_HAS_EARLYSUSPEND
/* .suspend = htcleo_suspend,
.resume = htcleo_resume,*/
#endif
};
static int battery_log_open(struct inode *inode, struct file *file)
{
return single_open(file, battery_log_print, NULL);
}
static struct file_operations battery_log_fops =
{
.open = battery_log_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init htcleo_battery_init(void)
{
debugfs_create_file("battery_log", 0444, NULL, NULL, &battery_log_fops);
wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
return i2c_add_driver(&htcleo_battery_driver);
}
//module_init(htcleo_battery_init);
late_initcall(htcleo_battery_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cotulla");
MODULE_DESCRIPTION("htcleo battery driver");
// END OF FILE

View File

@ -1,214 +0,0 @@
/* arch/arm/mach-msm/board-htcleo-power.c
*
* Copyright (C) 2010 Cotulla
* Copyright (C) 2008 HTC Corporation.
* Copyright (C) 2008 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
//
// calls seq:
//
// notify_vbus_change_intr -> vbus_work_func -> msm_hsusb_set_vbus_state -> USB -> notify_usb_connected
//
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/power_supply.h>
#include <linux/platform_device.h>
#include <mach/msm_fast_timer.h>
#include <mach/msm_rpcrouter.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/switch.h>
#include <mach/board-htcleo-battery.h>
#include "board-htcleo.h"
static char *supply_list[] =
{
"battery",
};
static int inited;
static int vbus_present;
static int usb_status;
static struct work_struct vbus_work;
#ifdef CONFIG_USB_ANDROID
void notify_usb_connected(int status);
static struct t_usb_status_notifier usb_status_notifier = {
.name = "htc_battery",
.func = notify_usb_connected,
};
#endif
static int power_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
if (psp != POWER_SUPPLY_PROP_ONLINE)
return -EINVAL;
if (psy->type == POWER_SUPPLY_TYPE_MAINS)
{
val->intval = (usb_status == 2);
}
else
{
val->intval = vbus_present;
}
return 0;
}
static enum power_supply_property power_properties[] =
{
POWER_SUPPLY_PROP_ONLINE,
};
static struct power_supply ac_supply =
{
.name = "ac",
.type = POWER_SUPPLY_TYPE_MAINS,
.supplied_to = supply_list,
.num_supplicants = ARRAY_SIZE(supply_list),
.properties = power_properties,
.num_properties = ARRAY_SIZE(power_properties),
.get_property = power_get_property,
};
static struct power_supply usb_supply =
{
.name = "usb",
.type = POWER_SUPPLY_TYPE_USB,
.supplied_to = supply_list,
.num_supplicants = ARRAY_SIZE(supply_list),
.properties = power_properties,
.num_properties = ARRAY_SIZE(power_properties),
.get_property = power_get_property,
};
static int get_vbus_state(void)
{
if (readl(MSM_SHARED_RAM_BASE + 0xEF20C))
return 1;
else
return 0;
}
void notify_cable_status(int status)
{
pr_info("### notify_cable_status(%d) ###\n", status);
vbus_present = status;
msm_hsusb_set_vbus_state(vbus_present);
power_supply_changed(&ac_supply);
power_supply_changed(&usb_supply);
if(mydi)
power_supply_changed(&mydi->bat);
}
// called from USB driver
void notify_usb_connected(int status)
{
if (!inited) return;
pr_info("### notify_usb_connected(%d) ###\n", status);
usb_status = status;
power_supply_changed(&ac_supply);
power_supply_changed(&usb_supply);
if(mydi)
power_supply_changed(&mydi->bat);
}
// called from DEX intrrupt
void notify_vbus_change_intr(void)
{
if (!inited) return;
schedule_work(&vbus_work);
}
// used by battery driver
int is_ac_power_supplied(void)
{
return (usb_status == 2);
}
static void vbus_work_func(struct work_struct *work)
{
int vbus = get_vbus_state();
printk(" new vbus = %d\n", vbus);
#ifdef CONFIG_USB_EHCI_HCD
if (vbus)
return 0;
else
return 0;
#else
if (vbus)
gpio_set_value(HTCLEO_GPIO_POWER_USB, 0);
else
gpio_set_value(HTCLEO_GPIO_POWER_USB, 1);
#endif
notify_cable_status(vbus);
}
static int htcleo_power_probe(struct platform_device *pdev)
{
printk("$$$ htcleo_power_probe $$$\n");
INIT_WORK(&vbus_work, vbus_work_func);
gpio_request(HTCLEO_GPIO_POWER_USB, "power_usb");
gpio_direction_output(HTCLEO_GPIO_POWER_USB, 0);
power_supply_register(&pdev->dev, &ac_supply);
power_supply_register(&pdev->dev, &usb_supply);
inited = 1;
// init VBUS state
notify_vbus_change_intr();
return 0;
}
//#define APP_BATT_PDEV_NAME "rs30100001:00000000"
#define APP_BATT_PDEV_NAME "htcleo_power"
static struct platform_driver htcleo_power_driver =
{
.probe = htcleo_power_probe,
.driver =
{
.name = APP_BATT_PDEV_NAME,
.owner = THIS_MODULE,
},
};
static int __init htcleo_power_init(void)
{
printk("htcleo_power_init\n");
platform_driver_register(&htcleo_power_driver);
#ifdef CONFIG_USB_ANDROID
usb_register_notifier(&usb_status_notifier);
#endif
return 0;
}
//module_init(htcleo_power_init);
late_initcall(htcleo_power_init);
MODULE_DESCRIPTION("HTCLEO Power Driver");
MODULE_LICENSE("GPL");

View File

@ -34,6 +34,7 @@
#endif
#include <linux/akm8973.h>
#include <../../../drivers/staging/android/timed_gpio.h>
#include <linux/ds2746_battery.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@ -231,9 +232,6 @@ static struct microp_i2c_platform_data microp_data = {
static struct i2c_board_info base_i2c_devices[] =
{
{
I2C_BOARD_INFO("htcleo-battery", 0x26),
},
{
I2C_BOARD_INFO(LEO_TOUCH_DRV_NAME, 0),
},
@ -716,11 +714,45 @@ static struct platform_device ram_console_device = {
// Power/Battery
///////////////////////////////////////////////////////////////////////
static struct platform_device htcleo_power =
{
.name = "htcleo_power",
.id = -1,
static struct htc_battery_platform_data htc_battery_pdev_data = {
.func_show_batt_attr = htc_battery_show_attr,
.gpio_mbat_in = -1,
.gpio_mchg_en_n = HTCLEO_GPIO_BATTERY_CHARGER_ENABLE,
.gpio_iset = HTCLEO_GPIO_BATTERY_CHARGER_CURRENT,
.guage_driver = GUAGE_DS2746,
.charger = LINEAR_CHARGER,
.m2a_cable_detect = 0,
.force_no_rpc = 1,
.int_data = {
.chg_int = HTCLEO_GPIO_BATTERY_OVER_CHG,
},
};
static struct platform_device htc_battery_pdev = {
.name = "htc_battery",
.id = -1,
.dev = {
.platform_data = &htc_battery_pdev_data,
},
};
static int get_thermal_id(void)
{
return THERMAL_300;
}
static struct ds2746_platform_data ds2746_pdev_data = {
.func_get_thermal_id = get_thermal_id,
};
static struct platform_device ds2746_battery_pdev = {
.name = "ds2746-battery",
.id = -1,
.dev = {
.platform_data = &ds2746_pdev_data,
},
};
///////////////////////////////////////////////////////////////////////
// Real Time Clock
///////////////////////////////////////////////////////////////////////
@ -751,10 +783,11 @@ static struct platform_device *devices[] __initdata =
&android_pmem_adsp_device,
&android_pmem_venc_device,
&msm_device_i2c,
&ds2746_battery_pdev,
&htc_battery_pdev,
&msm_kgsl_device,
&msm_camera_sensor_s5k3e2fx,
&htcleo_flashlight_device,
&htcleo_power,
&qsd_device_spi,
&htc_headset_mgr,
&htc_headset_gpio,
@ -905,10 +938,6 @@ static void __init htcleo_init(void)
platform_device_register(&htcleo_timed_gpios);
#ifdef CONFIG_USB_ANDROID
msm_hsusb_set_vbus_state(htcleo_get_vbus_state());
#endif
/* Blink the camera LED shortly to show that we're alive! */
#ifdef CONFIG_HTCLEO_BLINK_AT_BOOT
bank6_in = (unsigned int*)(MSM_GPIO1_BASE + 0x0864);

View File

@ -30,21 +30,23 @@
#include <mach/msm_fb.h> /* Jay, to register display notifier */
#include <mach/htc_battery.h>
#include <linux/rtc.h>
#include <linux/workqueue.h>
#include <linux/tps65200.h>
#ifdef CONFIG_HTC_BATTCHG_SMEM
#include "smd_private.h"
#endif
#include <linux/io.h>
#include <mach/msm_iomap.h>
#if defined(CONFIG_TROUT_BATTCHG_DOCK)
#include <mach/htc_one_wire.h>
#endif
#ifdef CONFIG_BATTERY_DS2784
#include <linux/ds2784_battery.h>
#elif CONFIG_BATTERY_DS2746
#elif defined(CONFIG_BATTERY_DS2746)
#include <linux/ds2746_battery.h>
#endif
#include <linux/smb329.h>
static struct wake_lock vbus_wake_lock;
enum {
@ -114,6 +116,7 @@ struct htc_battery_info {
int gpio_iset;
int guage_driver;
int m2a_cable_detect;
int force_no_rpc;
int charger;
};
@ -204,6 +207,37 @@ int unregister_notifier_cable_status(struct notifier_block *nb)
return blocking_notifier_chain_unregister(&cable_status_notifier_list, nb);
}
/* -------------------------------------------------------------------------- */
/* HTCLeo Dex Functions. */
#if defined(CONFIG_MACH_HTCLEO)
static int get_vbus_state(void)
{
if (readl(MSM_SHARED_RAM_BASE + 0xEF20C))
return 1;
else
return 0;
}
void notify_cable_status(int status)
{
pr_info("notify_cable_status(%d)\n", status);
msm_hsusb_set_vbus_state(status);
power_supply_changed(&htc_power_supplies[CHARGER_USB]);
power_supply_changed(&htc_power_supplies[CHARGER_AC]);
power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
}
// called from DEX intrrupt
void notify_vbus_change_intr(void)
{
int vbus;
if (!htc_battery_initial) return;
vbus = get_vbus_state();
notify_cable_status(vbus);
}
#endif
/* -------------------------------------------------------------------------- */
/* For sleep charging screen. */
static int zcharge_enabled;
@ -328,7 +362,6 @@ device_initcall(batt_debug_init);
static int init_batt_gpio(void)
{
if (htc_batt_info.gpio_mbat_in > 0 &&
gpio_request(htc_batt_info.gpio_mbat_in, "batt_detect") < 0)
goto gpio_failed;
@ -355,6 +388,7 @@ int battery_charging_ctrl(enum batt_ctl_t ctl)
{
int result = 0;
if (!htc_battery_initial) return 0;
switch (ctl) {
case DISABLE:
BATT_LOG("charger OFF");
@ -611,9 +645,13 @@ static void usb_status_notifier_func(int online)
blocking_notifier_call_chain(&cable_status_notifier_list,
htc_batt_info.rep.charging_source, NULL);
power_supply_changed(&htc_power_supplies[CHARGER_AC]);
power_supply_changed(&htc_power_supplies[CHARGER_USB]);
power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
if (htc_battery_initial) {
power_supply_changed(&htc_power_supplies[CHARGER_AC]);
power_supply_changed(&htc_power_supplies[CHARGER_USB]);
power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
} else {
pr_err("\n\n ### htc_battery_code is not inited yet! ###\n\n");
}
update_wake_lock(htc_batt_info.rep.charging_source);
#else
mutex_lock(&htc_batt_info.lock);
@ -981,13 +1019,17 @@ static int htc_battery_get_charging_status(void)
break;
case CHARGER_USB:
case CHARGER_AC:
#if !defined(CONFIG_BATTERY_DS2746)
if ((htc_charge_full) && (htc_batt_info.rep.full_level == 100)) {
htc_batt_info.rep.level = 100;
}
#endif
level = htc_batt_info.rep.level;
if (level == 100){
htc_charge_full = 1;}
else
htc_charge_full = 0;
if (htc_charge_full)
ret = POWER_SUPPLY_STATUS_FULL;
else if (htc_batt_info.rep.charging_enabled != 0)
@ -1014,12 +1056,20 @@ static int htc_battery_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = POWER_SUPPLY_HEALTH_GOOD;
if (machine_is_paradise() && (htc_batt_info.rep.batt_temp >= 500 ||
htc_batt_info.rep.batt_temp <= 0))
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
else if (!machine_is_paradise() && (htc_batt_info.rep.batt_temp >= 480 ||
htc_batt_info.rep.batt_temp <= 0))
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
if (machine_is_paradise()) {
if (htc_batt_info.rep.batt_temp >= 500 ||
htc_batt_info.rep.batt_temp <= 0)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
} else if (machine_is_spade()) {
if (htc_batt_info.rep.batt_temp >= 450 ||
htc_batt_info.rep.batt_temp <= 0)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
} else {
if (htc_batt_info.rep.batt_temp >= 480 ||
htc_batt_info.rep.batt_temp <= 0)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
}
if (htc_batt_debug_mask & HTC_BATT_DEBUG_USER_QUERY)
BATT_LOG("%s: %s: health=%d", __func__, psy->name, val->intval);
break;
@ -1070,9 +1120,8 @@ static struct device_attribute htc_battery_attrs[] = {
#ifdef CONFIG_HTC_BATTCHG_SMEM
__ATTR(smem_raw, S_IRUGO, htc_battery_show_smem, NULL),
__ATTR(smem_text, S_IRUGO, htc_battery_show_smem, NULL),
#else
__ATTR(batt_attr_text, S_IRUGO, htc_battery_show_batt_attr, NULL),
#endif
__ATTR(batt_attr_text, S_IRUGO, htc_battery_show_batt_attr, NULL),
};
enum {
@ -1194,7 +1243,6 @@ static ssize_t htc_battery_set_full_level(struct device *dev,
{
int rc = 0;
unsigned long percent = 100;
unsigned long param = 0;
percent = simple_strtoul(buf, NULL, 10);
@ -1214,9 +1262,8 @@ static ssize_t htc_battery_set_full_level(struct device *dev,
mutex_lock(&htc_batt_info.lock);
htc_full_level_flag = 1;
htc_batt_info.rep.full_level = percent;
param = percent;
blocking_notifier_call_chain(&cable_status_notifier_list,
0xff, (void *) &param);
0xff, (void *) &htc_batt_info.rep.full_level);
mutex_unlock(&htc_batt_info.lock);
}
rc = 0;
@ -1288,7 +1335,7 @@ static int update_batt_info(void)
ret = -1;
}
break;
#elif CONFIG_BATTERY_DS2746
#elif defined(CONFIG_BATTERY_DS2746)
case GUAGE_DS2746:
if (ds2746_get_battery_info(&htc_batt_info.rep)) {
BATT_ERR("%s: ds2746 read failed!!!", __func__);
@ -1378,10 +1425,93 @@ dont_need_update:
return i;
}
static irqreturn_t tps65200_int_detection(int irq, void *data)
{
struct htc_battery_tps65200_int *ip = data;
BATT_LOG("%s: over voltage is detected.", __func__);
disable_irq_nosync(ip->chg_int);
ip->tps65200_reg = 0;
schedule_delayed_work(&ip->int_work, msecs_to_jiffies(200));
return IRQ_HANDLED;
}
static void htc_battery_tps65200_int_func(struct work_struct *work)
{
struct htc_battery_tps65200_int *ip;
int fault_bit;
ip = container_of(work, struct htc_battery_tps65200_int,
int_work.work);
switch (ip->tps65200_reg) {
case CHECK_INT1:
/* read twice. First read to trigger TPS65200 clear fault bit
on INT1. Second read to make sure that fault bit is cleared
and call off ovp function.*/
fault_bit = tps_set_charger_ctrl(CHECK_INT1);
BATT_LOG("INT1 value: %d", fault_bit);
fault_bit = tps_set_charger_ctrl(CHECK_INT1);
if (fault_bit) {
#ifdef CONFIG_HTC_BATTCHG_SMEM
smem_batt_info->over_vchg = 1;
#else
htc_batt_info.rep.over_vchg = 1;
#endif
power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
schedule_delayed_work(&ip->int_work,
msecs_to_jiffies(5000));
BATT_LOG("OVER_VOLTAGE: "
"over voltage fault bit on TPS65200 is raised:"
" %d", fault_bit);
} else {
#ifdef CONFIG_HTC_BATTCHG_SMEM
smem_batt_info->over_vchg = 0;
#else
htc_batt_info.rep.over_vchg = 0;
#endif
cancel_delayed_work(&ip->int_work);
enable_irq(ip->chg_int);
}
break;
default:
fault_bit = tps_set_charger_ctrl(CHECK_INT2);
BATT_LOG("Read TPS65200 INT2 register value: %x", fault_bit);
if (fault_bit) {
fault_bit = tps_set_charger_ctrl(CHECK_INT2);
BATT_LOG("Read TPS65200 INT2 register value: %x"
, fault_bit);
fault_bit = tps_set_charger_ctrl(CHECK_INT2);
BATT_LOG("Read TPS65200 INT2 register value: %x"
, fault_bit);
fault_bit = tps_set_charger_ctrl(CHECK_CONTROL);
#ifdef CONFIG_HTC_BATTCHG_SMEM
smem_batt_info->reserve4 = 1;
#endif
cancel_delayed_work(&ip->int_work);
enable_irq(ip->chg_int);
} else {
fault_bit = tps_set_charger_ctrl(CHECK_INT1);
BATT_LOG("Read TPS65200 INT1 register value: %x"
, fault_bit);
if (fault_bit) {
ip->tps65200_reg = CHECK_INT1;
schedule_delayed_work(&ip->int_work,
msecs_to_jiffies(200));
}
}
break;
}
}
static int htc_battery_core_probe(struct platform_device *pdev)
{
int i, rc;
pr_info("%s\n", __func__);
/* init battery gpio */
if (htc_batt_info.charger == LINEAR_CHARGER) {
if ((rc = init_batt_gpio()) < 0) {
@ -1397,12 +1527,14 @@ static int htc_battery_core_probe(struct platform_device *pdev)
*/
htc_batt_info.present = 1;
/* init rpc */
endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
if (IS_ERR(endpoint)) {
BATT_ERR("%s: init rpc failed! rc = %ld",
__func__, PTR_ERR(endpoint));
return -EINVAL;
if(!htc_batt_info.force_no_rpc) {
/* init rpc */
endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
if (IS_ERR(endpoint)) {
BATT_ERR("%s: init rpc failed! rc = %ld",
__func__, PTR_ERR(endpoint));
return -EINVAL;
}
}
/* init power supplier framework */
@ -1419,16 +1551,21 @@ static int htc_battery_core_probe(struct platform_device *pdev)
* the battery status in case of we lost some info
*/
htc_battery_initial = 1;
if(htc_batt_info.force_no_rpc) {
update_batt_info();
}
else {
mutex_lock(&htc_batt_info.rpc_lock);
htc_batt_info.rep.charging_source = CHARGER_BATTERY;
if (htc_get_batt_info(&htc_batt_info.rep) < 0)
BATT_ERR("%s: get info failed", __func__);
mutex_lock(&htc_batt_info.rpc_lock);
htc_batt_info.rep.charging_source = CHARGER_BATTERY;
if (htc_get_batt_info(&htc_batt_info.rep) < 0)
BATT_ERR("%s: get info failed", __func__);
if (htc_rpc_set_delta(1) < 0)
BATT_ERR("%s: set delta failed", __func__);
htc_batt_info.update_time = jiffies;
mutex_unlock(&htc_batt_info.rpc_lock);
if (htc_rpc_set_delta(1) < 0)
BATT_ERR("%s: set delta failed", __func__);
htc_batt_info.update_time = jiffies;
mutex_unlock(&htc_batt_info.rpc_lock);
}
return 0;
}
@ -1526,7 +1663,6 @@ static int ds2784_notifier_func(struct notifier_block *nfb,
unsigned long action, void *param)
{
u8 arg = 0;
if (param)
arg = *(u8 *)param;
@ -1560,12 +1696,14 @@ static struct notifier_block ds2784_notifier = {
static int htc_battery_probe(struct platform_device *pdev)
{
int rc = 0;
struct htc_battery_platform_data *pdata = pdev->dev.platform_data;
htc_batt_info.device_id = pdev->id;
htc_batt_info.gpio_usb_id = pdata->gpio_usb_id;
htc_batt_info.guage_driver = pdata->guage_driver;
htc_batt_info.m2a_cable_detect = pdata->m2a_cable_detect;
htc_batt_info.force_no_rpc = pdata->force_no_rpc;
htc_batt_info.func_show_batt_attr = pdata->func_show_batt_attr;
htc_batt_info.charger = pdata->charger;
htc_batt_info.rep.full_level = 100;
@ -1582,11 +1720,35 @@ static int htc_battery_probe(struct platform_device *pdev)
#ifdef CONFIG_BATTERY_DS2784
if (pdata->guage_driver == GUAGE_DS2784)
ds2784_register_notifier(&ds2784_notifier);
#elif CONFIG_BATTERY_DS2746
#elif defined(CONFIG_BATTERY_DS2746)
if (pdata->guage_driver == GUAGE_DS2746)
ds2746_register_notifier(&ds2784_notifier);
#endif
if (system_rev >= 1 || machine_is_htcleo()) {
if (pdata->int_data.chg_int) {
BATT_LOG("init over voltage interrupt detection.");
INIT_DELAYED_WORK(&pdata->int_data.int_work,
htc_battery_tps65200_int_func);
rc = request_irq(pdata->int_data.chg_int,
tps65200_int_detection,
IRQF_TRIGGER_LOW,
"over_voltage_interrupt",
&pdata->int_data);
if (rc) {
BATT_LOG("request irq failed");
return rc;
}
}
}
#if defined(CONFIG_MACH_HTCLEO)
if(pdata->force_no_rpc) {
htc_battery_core_probe(pdev);
htc_cable_status_update(get_vbus_state());
}
#endif
return 0;
}

View File

@ -22,7 +22,10 @@
#define SET_ICL500 0X65
#define SET_ICL100 0X66
#define CHECK_INT2 0X67
#define OVERTEMP_VREG_4060 0XC8
#define NORMALTEMP_VREG_4200 0XC9
#define CHECK_INT1 0XCA
#define CHECK_CONTROL 0xCB
/* information about the system we're running on */
extern unsigned int system_rev;
@ -67,6 +70,13 @@ struct battery_info_reply {
u32 over_vchg; /* 0:normal, 1:over voltage charger */
s32 eval_current; /* System loading current from ADC */
};
struct htc_battery_tps65200_int {
int chg_int;
int tps65200_reg;
struct delayed_work int_work;
};
struct htc_battery_platform_data {
int (*func_show_batt_attr)(struct device_attribute *attr,
char *buf);
@ -77,6 +87,8 @@ struct htc_battery_platform_data {
int guage_driver;
int m2a_cable_detect;
int charger;
struct htc_battery_tps65200_int int_data;
int force_no_rpc;
};
#if CONFIG_HTC_BATTCHG

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,852 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 2010 High Tech Computer Corporation
Module Name:
ds2784_param.c
Abstract:
This module implements the battery formula based on power spec, including below concepts:
1. adc converter
2. voltage mapping to capacity
3. over temperature algorithm
4. id range algorithm
5. ACR maintainance
Add from TPE PMA:
1. temperature index
2. pd_m_coef_boot
3. preserved_capacity_by_temp
Remove from TAO PMA:
1. pd_temp
To adapt different PMA/projects, we need to modify below tables:
1. ID_RANGE: which battery is used in the project?
2. FL_25: the full capacity in temp 25C.
3. pd_m_bias_mA: the discharge current threshold to calculating pd_m
4. M_PARAMTER_TABLE: the voltage-capacity mapping table
5. TEMP_RANGE: how many temp condition we need to consider
6. PD_M_COEF_TABLE(BOOT)/PD_M_RESL_TABLE(BOOT): voltage compensation based on current
7. PD_T_COEF: voltage compensation based on temp
8. CAPACITY_DEDUCTION_01p: the capacity deduction due to low temperature
Original Auther:
Andy.ys Wang June-01-2010
---------------------------------------------------------------------------------*/
#include <linux/kernel.h>
#include <linux/ds2746_battery.h>
#include <linux/ds2746_param.h>
#include <linux/ds2746_param_config.h>
#include <linux/wrapper_types.h>
#include <linux/time.h>
#include <asm/setup.h>
/*========================================================================================
build flags
========================================================================================*/
#define HTC_ENABLE_POWER_DEBUG 0
#define HTC_ENABLE_DUMMY_BATTERY 0
/*========================================================================================
battery common parameter defines (independent on battery id yet...)
========================================================================================*/
#define BATTERY_VOLTAGE_MIN 2000
#define BATTERY_VOLTAGE_MAX 20000
/*========================================================================================
battery parameter helper functions
========================================================================================*/
static INT32 get_id_index(struct battery_type *battery)
{
int i;
for (i = 0; i < BATTERY_ID_NUM - 1; i++) {
/* minus 1, unknown battery is not in ID_RANGE
[min, max)*/
UINT32 resister_min = ID_RANGE[i*2];
UINT32 resister_max = ID_RANGE[i*2 + 1];
if (resister_min <= battery->id_ohm && resister_max > battery->id_ohm) {
return i + 1;
}
}
return BATTERY_ID_UNKNOWN;
}
static INT32 get_temp_index(struct battery_type *battery)
{
int i;
for (i = 0; i < 255; i++) {
/* the table size shall not be greater then 255, to ensure no infinite looping
[min, max)*/
INT32 temp = TEMP_RANGE[i];
if (battery->temp_01c >= temp)
return i;
}
printk(DRIVER_ZONE " invalid batt_temp (%d) or temp range mapping.\n", battery->temp_01c);
return -1;
}
/*========================================================================================
temperature formula definitions
========================================================================================*/
static INT32 get_temp_01c(struct battery_type *battery)
{
int current_index = battery->temp_check_index;
int search_direction = 0;
if (battery->last_temp_adc > battery->temp_adc) {
search_direction = -1;
} else {
search_direction = 1;
}
while (current_index >= 0 && current_index < TEMP_NUM-1) {
UINT32 temp_min = TEMP_MAP[current_index];
UINT32 temp_max = TEMP_MAP[current_index + 1];
if (temp_max > battery->temp_adc && temp_min <= battery->temp_adc) {
battery->temp_check_index = current_index;
battery->last_temp_adc = battery->temp_adc;
return (TEMP_MAX-current_index)*10;
}
current_index += search_direction;
}
return (TEMP_MIN-1)*10;
}
/*========================================================================================
over temperature protection
========================================================================================*/
static BOOL is_over_temp(struct battery_type *battery)
{
/* stop charging*/
if (battery->temp_01c < over_low_temp_lock_01c || battery->temp_01c >= over_high_temp_lock_01c) {
return TRUE;
}
return FALSE;
}
static BOOL is_not_over_temp(struct battery_type *battery)
{
/* start charging*/
if (battery->temp_01c >= over_low_temp_release_01c &&
battery->temp_01c < over_high_temp_release_01c) {
return TRUE;
}
return FALSE;
}
static void __protect_flags_update(struct battery_type *battery,
struct protect_flags_type *flags)
{
/* Flags:
is_charging_enable_available - Over temperature, need to stop charging
is_charging_high_current_avaialble - Temperature is too high so that we have to slow charge*/
if (is_over_temp(battery)) {
/* Ex: T<0 or T>45 */
flags->is_charging_enable_available = FALSE;
flags->is_charging_high_current_avaialble = FALSE;
#if 0
flags->is_battery_overtemp = TRUE;
#endif
} else if (is_not_over_temp(battery)) {
/* Ex: T<42 or T>3*/
flags->is_charging_enable_available = TRUE;
flags->is_charging_high_current_avaialble = TRUE;
#if 0
flags->is_battery_overtemp = FALSE;
#endif
}
/* Flags:
is_battery_dead - If battery is dead, show special indicator for it*/
if (battery->voltage_mV < BATTERY_DEAD_VOLTAGE_LEVEL) {
flags->is_battery_dead = TRUE;
}
else if (battery->voltage_mV > BATTERY_DEAD_VOLTAGE_RELEASE) {
flags->is_battery_dead = FALSE;
}
}
/*========================================================================================
Voltage-Percentage mapping
========================================================================================*/
/*------------------------------------------------------------------------
Example:
p0 = (4200, 10000); 4.2V for 100%
p1 = (3900, 8000); 3.9V for 80%
p2 = (3700, 2000); 3.7V for 20%
p3 = (3300, 0); 3.3V for 0%
if V = 4000, (3900<4000<4200)
P = (4000-3900) * (10000-8000)/(4200-3900) + 8000 = 8666*/
#define NUM_SAMPLED_POINTS_MAX 12
struct sampled_point_type {
DWORD voltage;
DWORD capacity;
};
struct voltage_curve_translator {
DWORD voltage_min;
DWORD voltage_max;
DWORD capacity_min;
DWORD capacity_max;
int sampled_point_count;
struct sampled_point_type sampled_points[NUM_SAMPLED_POINTS_MAX];
};
static void voltage_curve_translator_init(struct voltage_curve_translator *t)
{
memset(t, 0, sizeof(*t));
}
static void voltage_curve_translator_add(struct voltage_curve_translator *t, DWORD voltage, DWORD capacity)
{
struct sampled_point_type *pt;
if (t->sampled_point_count >= NUM_SAMPLED_POINTS_MAX) {
return;
}
t->sampled_points[t->sampled_point_count].voltage = voltage;
t->sampled_points[t->sampled_point_count].capacity = capacity;
pt = &t->sampled_points[t->sampled_point_count];
t->sampled_point_count++;
if (pt->voltage > t->voltage_max)
t->voltage_max = pt->voltage;
if (pt->voltage < t->voltage_min)
t->voltage_min = pt->voltage;
if (pt->capacity > t->capacity_max)
t->capacity_max = pt->capacity;
if (pt->capacity < t->capacity_min)
t->capacity_min = pt->capacity;
#if HTC_ENABLE_POWER_DEBUG
printk(DRIVER_ZONE " kadc t: capacity=%d voltage=%d\n", capacity, voltage);
#endif /* HTC_ENABLE_POWER_DEBUG*/
}
static INT32 voltage_curve_translator_get(struct voltage_curve_translator *t, DWORD voltage)
{
struct sampled_point_type *p0, *p1;
INT32 capacity;
int i;
if (voltage > t->voltage_max)
voltage = t->voltage_max;
if (voltage < t->voltage_min)
voltage = t->voltage_min;
p0 = &t->sampled_points[0];
p1 = p0 + 1;
for (i = 0; i < t->sampled_point_count - 1 && voltage < p1->voltage; i++) {
p0++;
p1++;
}
/* DIV ZERO check*/
if (p0->voltage - p1->voltage == 0) {
return 0;
}
/* INT32 overflow check: mv(4200) * capacity(10000), shall be no problem at all...*/
capacity = (voltage - p1->voltage) * (p0->capacity - p1->capacity) / (p0->voltage - p1->voltage) + p1->capacity;
if (capacity > t->capacity_max) {
capacity = t->capacity_max;
}
if (capacity < t->capacity_min) {
capacity = t->capacity_min;
}
return capacity;
}
/*========================================================================================
KADC mapping functions
========================================================================================*/
static struct voltage_curve_translator __get_kadc_t;
static INT32 get_kadc_001p(struct battery_type *battery)
{
INT32 pd_m = 0;
INT32 pd_temp = 0;
INT32 temp_01c = battery->temp_01c;
INT32 current_mA = battery->current_mA;
UINT32 *m_paramtable;
INT32 pd_m_coef;
INT32 pd_m_resl;
INT32 capacity_deduction_01p = CAPACITY_DEDUCTION_01p[battery->temp_index];
INT32 capacity_predict_001p;
/* 1. INT32 overflow check: assert abs(iChgCurrent_ma) <= 3000, iBattTemp_01c>-250, pd_t_coef <= 1000
when calculating pd_temp: 0x7FFFFFFF / (500 * 3000 * 1000) =:= 1.4*/
if (battery->current_mA > 3000)
current_mA = 3000;
else if (battery->current_mA < -3000)
current_mA = -3000;
if (battery->temp_01c <= -250)
temp_01c = -250;
/* 2. calculate pd_m and pd_temp*/
if (battery->is_power_on_reset) {
pd_m_coef = PD_M_COEF_TABLE_BOOT[battery->temp_index][battery->id_index];
pd_m_resl = PD_M_RESL_TABLE_BOOT[battery->temp_index][battery->id_index];
}
else{
pd_m_coef = PD_M_COEF_TABLE[battery->temp_index][battery->id_index];
pd_m_resl = PD_M_RESL_TABLE[battery->temp_index][battery->id_index];
}
if (battery->current_mA < -pd_m_bias_mA) {
/* ex: -150mA < -130mA*/
pd_m = (abs(battery->current_mA) - pd_m_bias_mA) * pd_m_coef /pd_m_resl;
}
if (battery->temp_01c < 250) {
pd_temp = ((250 - battery->temp_01c) * (abs(battery->current_mA) * PD_T_COEF[battery->id_index])) / (10 * 10000);
}
battery->pd_m = pd_m;
/* 3. calculate KADC using M_PARAMTER_TABLE*/
m_paramtable = M_PARAMTER_TABLE[battery->id_index];
if (m_paramtable) {
int i = 0; /* assume that m_paramtable has at least 2 items...the last capacity item must be 0 to end the loop...*/
voltage_curve_translator_init(&__get_kadc_t);
while (1) {
INT32 capacity = m_paramtable[i];
INT32 voltage = m_paramtable[i + 1];
if (capacity == 10000) {
/* full capacity, no need to fix voltage level*/
voltage_curve_translator_add(&__get_kadc_t, voltage, capacity);
}
else {
voltage_curve_translator_add(&__get_kadc_t, voltage - pd_temp, capacity);
}
if (capacity == 0)
break;
i += 2;
}
#if HTC_ENABLE_POWER_DEBUG
printk(DRIVER_ZONE " pd_m=%d, pd_temp=%d\n", pd_m, pd_temp);
#endif /* HTC_ENABLE_POWER_DEBUG*/
capacity_predict_001p = voltage_curve_translator_get(&__get_kadc_t, battery->voltage_mV + pd_m);
}
else{
capacity_predict_001p = (battery->voltage_mV - 3400) * 10000 / (4200 - 3400);
}
return (capacity_predict_001p - capacity_deduction_01p * 10) * 10000 / (10000 - capacity_deduction_01p * 10);
}
/*========================================================================================
coulomb counter+curve tracer
========================================================================================*/
static INT32 get_software_acr_revise(struct battery_type *battery, UINT32 ms)
{
INT32 kadc_01p = battery->KADC_01p;
INT32 ccbi_01p = battery->RARC_01p;
INT32 delta_01p = kadc_01p - ccbi_01p;
DWORD C = 5; /* KADC = 15%~100%*/
if (kadc_01p <= 150) {
C = 5;
} /* KADC = 0%~15%*/
if (delta_01p < 0) {
/* if KADC is less than RARC, p shall be lower*/
return -(INT32) (C * ms * delta_01p * delta_01p) / 1000;
}
else{
/* if KADC is larger than RARC, p shall be higher*/
return (INT32) (C * ms * delta_01p * delta_01p) / 1000;
}
}
/*========================================================================================
ds2746 gauge ic functions, to access ds2746 registers and convert ADC to battery param
========================================================================================*/
static void __ds2746_clear_porf(void)
{
UINT8 reg_data;
if (!ds2746_i2c_read_u8(&reg_data, 0x01)) {
printk(DRIVER_ZONE " clear porf error in read.\n");
return;
}
if (!ds2746_i2c_write_u8((reg_data & (~DS2746_STATUS_PORF)), 0x01)) {
printk(DRIVER_ZONE " clear porf error in write.\n");
return;
}
}
static void __ds2746_acr_update(struct battery_type *battery, int capacity_01p)
{
printk(DRIVER_ZONE " acr update: P=%d, C=%d.\n",
capacity_01p,
battery->charge_counter_adc);
ds2746_i2c_write_u8((battery->charge_counter_adc & 0xFF00) >> 8, 0x10);
ds2746_i2c_write_u8((battery->charge_counter_adc & 0x00FF), 0x11);
if (battery->is_power_on_reset) {
__ds2746_clear_porf();
}
}
static void __ds2746_init_config(struct battery_type *battery)
{
UINT8 reg_data;
if (!ds2746_i2c_read_u8(&reg_data, 0x01)) {
printk(DRIVER_ZONE " init config error in read.\n");
return;
}
/* Erase SMOD and NBEN value in DS2746 status/config register*/
reg_data &= ~(DS2746_STATUS_SMOD | DS2746_STATUS_NBEN);
if (!ds2746_i2c_write_u8(reg_data, 0x01)) {
printk(DRIVER_ZONE " init config error in write.\n");
return;
}
}
static BOOL __ds2746_get_reg_data(UINT8 *reg)
{
memset(reg, 0, 12);
if (!ds2746_i2c_read_u8(&reg[0], 0x01))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[2], 0x08))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[3], 0x09))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[4], 0x0a))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[5], 0x0b))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[6], 0x0c))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[7], 0x0d))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[8], 0x0e))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[9], 0x0f))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[10], 0x10))
return FALSE;
if (!ds2746_i2c_read_u8(&reg[11], 0x11))
return FALSE;
return TRUE;
}
static BOOL __ds2746_battery_adc_udpate(struct battery_type *battery)
{
UINT8 reg[12];
if (!__ds2746_get_reg_data((UINT8 *) &reg)) {
printk(DRIVER_ZONE " get ds2746 data failed...\n");
return FALSE;
}
printk(DRIVER_ZONE " [x0]%x [x8]%x %x %x %x %x %x %x %x %x %x\n",
reg[0],
reg[2],
reg[3],
reg[4],
reg[5],
reg[6],
reg[7],
reg[8],
reg[9],
reg[10],
reg[11]);
if (!(reg[0] & DS2746_STATUS_AIN0) || !(reg[0] & DS2746_STATUS_AIN1)) {
printk(DRIVER_ZONE " AIN not ready...\n");
return FALSE;
}
if (reg[0] & DS2746_STATUS_PORF) {
battery->is_power_on_reset = TRUE;
}
else{
battery->is_power_on_reset = FALSE;
}
/* adc register value*/
battery->voltage_adc = MAKEWORD(reg[7], reg[6]) >> 4;
battery->current_adc = MAKEWORD(reg[9], reg[8]);
if (battery->current_adc & 0x8000) {
battery->current_adc = -(0x10000 - battery->current_adc);
}
battery->current_adc /= 4;
battery->charge_counter_adc = MAKEWORD(reg[11], reg[10]);
if (battery->charge_counter_adc & 0x8000) {
battery->charge_counter_adc = -(0x10000 - battery->charge_counter_adc);
}
battery->id_adc = MAKEWORD(reg[5], reg[4]) >> 4;
battery->temp_adc = MAKEWORD(reg[3], reg[2]) >> 4;
if (support_ds2746_gauge_ic) {
/* we preserve 500mAh for capacity lower than 0%, however the 500mAh is still drained out...we need to do predict for correct ACR*/
if ((battery->charge_counter_adc & 0xFFFF) >= 0xF000){
printk(DRIVER_ZONE " ACR out of range (x%x)...\n",
battery->charge_counter_adc);
battery->is_power_on_reset = TRUE;
}
}
return TRUE;
}
/*========================================================================================
softwar acr functions, to accumulate ACR by software and revise by battery parameter
========================================================================================*/
static void __software_charge_counter_update(struct battery_type *battery, UINT32 ms)
{
/* if the charge counter is maintained by sw, batt_alg shall use this routine to update charge counter and related parameters*/
INT32 capacity_deduction_01p = CAPACITY_DEDUCTION_01p[battery->temp_index];
/* AEL(mAh): A low temp unusable battery capacity, calculated in runtime*/
INT32 ael_mAh = capacity_deduction_01p *battery->charge_full_real_mAh / 1000;
#if HTC_ENABLE_POWER_DEBUG
printk(DRIVER_ZONE "chgctr update: I=%d ms=%d.\n", battery->current_mA, ms);
#endif /* HTC_ENABLE_POWER_DEBUG*/
/* ACRt(mAh): The total capacity battery owns, stored in battery->charge_counter_mAh*/
battery->software_charge_counter_mAms += (INT32) (battery->current_mA * ms);
battery->charge_counter_mAh += (battery->software_charge_counter_mAms / 3600000);
battery->software_charge_counter_mAms -= (battery->software_charge_counter_mAms / 3600000) * 3600000;
/* CCBI(0.1%): A software RARC*/
battery->RARC_01p = (battery->charge_counter_mAh - ael_mAh) * 1000 / (battery->charge_full_real_mAh - ael_mAh);
/* store back the battery->charge_counter_mAh to battery->charge_counter_adc*/
battery->charge_counter_adc = (battery->charge_counter_mAh + charge_counter_zero_base_mAh) * acr_adc_to_mv_coef / acr_adc_to_mv_resl;
}
static void __software_charge_counter_revise(struct battery_type *battery, UINT32 ms)
{
if (battery->current_mA < 0) {
#if HTC_ENABLE_POWER_DEBUG
printk(DRIVER_ZONE "chgctr revise: delta=%d.\n", get_software_acr_revise(battery, ms));
#endif /* HTC_ENABLE_POWER_DEBUG*/
/* revise software charge counter by coulomb counter+curve tracer*/
battery->software_charge_counter_mAms += get_software_acr_revise(battery, ms);
battery->charge_counter_mAh += (battery->software_charge_counter_mAms / 3600000);
battery->software_charge_counter_mAms -= (battery->software_charge_counter_mAms / 3600000) * 3600000;
/* store back the battery->charge_counter_mAh to battery->charge_counter_adc*/
battery->charge_counter_adc = (battery->charge_counter_mAh + charge_counter_zero_base_mAh) * acr_adc_to_mv_coef / acr_adc_to_mv_resl;
}
}
static void __software_acr_update(struct battery_type *battery)
{
static BOOL s_bFirstEntry = TRUE;
static DWORD last_time_ms;
DWORD now_time_ms = BAHW_MyGetMSecs();
if (s_bFirstEntry) {
s_bFirstEntry = FALSE;
last_time_ms = now_time_ms;
}
#if HTC_ENABLE_POWER_DEBUG
printk(DRIVER_ZONE "+acr update: adc=%d C=%d mams=%d.\n",
battery->charge_counter_adc,
battery->charge_counter_mAh,
battery->software_charge_counter_mAms);
#endif /* HTC_ENABLE_POWER_DEBUG*/
__software_charge_counter_update(battery, now_time_ms - last_time_ms);
__software_charge_counter_revise(battery, now_time_ms - last_time_ms);
#if HTC_ENABLE_POWER_DEBUG
printk(DRIVER_ZONE "-acr update: adc=%d C=%d mams=%d.\n",
battery->charge_counter_adc,
battery->charge_counter_mAh,
battery->software_charge_counter_mAms);
#endif /* HTC_ENABLE_POWER_DEBUG*/
last_time_ms = now_time_ms;
}
/*========================================================================================
battery param update, the coef are referenced from power spec
========================================================================================*/
static BOOL __battery_param_udpate(struct battery_type *battery)
{
static int batt_id_stable_counter = 0;
INT32 batt_id_index;
INT32 temp_01c;
if (support_ds2746_gauge_ic) {
/* adc register value are read from __ds2746_battery_adc_udpate()*/
if (!__ds2746_battery_adc_udpate(battery))
return FALSE;
}
else{
/* adc register value are read from BAHW_get_batt_info_all()
if ( !BAHW_get_batt_info_all(battery) ) return FALSE;*/
}
/*real physical value*/
battery->voltage_mV = (battery->voltage_adc * voltage_adc_to_mv_coef / voltage_adc_to_mv_resl);
battery->current_mA = (battery->current_adc * current_adc_to_mv_coef / current_adc_to_mv_resl);
battery->discharge_mA = (battery->discharge_adc * discharge_adc_to_mv_coef / discharge_adc_to_mv_resl);
battery->charge_counter_mAh = (battery->charge_counter_adc * acr_adc_to_mv_coef / acr_adc_to_mv_resl) - charge_counter_zero_base_mAh;
battery->current_mA = battery->current_mA - battery->discharge_mA;
/* prevent from adc out of range*/
if (battery->id_adc >= id_adc_resl) {
battery->id_adc = id_adc_resl - 1;
}
if (battery->id_adc <= 0) {
battery->id_adc = 1;
}
if (battery->temp_adc >= temp_adc_resl) {
battery->temp_adc = temp_adc_resl - 1;
}
if (battery->temp_adc <= 0) {
battery->temp_adc = 1;
}
/* battery ID shall be ready first for temp/kadc calculation*/
// if ( id_conversion ) battery->id_ohm = ((float)id_R_kohm / ((float)id_adc_resl/battery->id_adc - 1)) * 1000; // kohm -> ohm
// else battery->id_ohm = battery->id_adc;
battery->id_ohm = battery->id_adc;
calibrate_id_ohm(battery);
batt_id_index = get_id_index(battery);
if (is_allow_batt_id_change) {
/*! TODO: batt_id changes immediately; may need to modify in future*/
if (batt_id_stable_counter >= 3 && batt_id_index != battery->id_index){
/* if batt_id is stable but is different from previous one*/
batt_id_stable_counter = 0; /* reset stable counter and set batt_id to new one*/
}
}
if (batt_id_stable_counter < 3) {
if (batt_id_stable_counter == 0) {
/* first time to get the batt id*/
battery->id_index = batt_id_index;
battery->charge_full_design_mAh = FL_25[battery->id_index];
battery->charge_full_real_mAh = battery->charge_full_design_mAh;
batt_id_stable_counter = 1;
}
else{
/* 2nd and further time to get the batt id*/
if (batt_id_index == battery->id_index)
batt_id_stable_counter++;
else
batt_id_stable_counter = 0;
}
}
/* calculate temperature*/
// battery->temp_01c = get_temp_c((float)temp_R_kohm / ((float)temp_adc_resl/battery->temp_adc - 1))*10;
temp_01c = get_temp_01c(battery);
if (temp_01c >= TEMP_MIN*10)
battery->temp_01c = temp_01c;
else
printk(DRIVER_ZONE " get temp_01c(%d) failed...\n", temp_01c);
battery->temp_index = get_temp_index(battery);
/* calculate KADC and RARC*/
battery->KADC_01p = CEILING(get_kadc_001p(battery), 10);
battery->RARC_01p = CEILING(10000 * battery->charge_counter_mAh / battery->charge_full_real_mAh, 10);
if (!support_ds2746_gauge_ic) {
__software_acr_update(battery);
}
if (battery->voltage_mV <BATTERY_VOLTAGE_MIN ||
battery->voltage_mV> BATTERY_VOLTAGE_MAX) {
printk(DRIVER_ZONE " invalid V(%d).\n", battery->voltage_mV);
return FALSE;
}
/*! star_lee 20100426 - minimum RARC is 0%*/
if (battery->RARC_01p <= 0) {
battery->RARC_01p = 0;
}
printk(DRIVER_ZONE " V=%d(%x) I=%d(%x) C=%d.%d/%d(%x) id=%d(%x) T=%d(%x) KADC=%d\n",
battery->voltage_mV,
battery->voltage_adc,
battery->current_mA,
battery->current_adc,
battery->charge_counter_mAh,
battery->software_charge_counter_mAms,
battery->charge_full_real_mAh,
battery->charge_counter_adc,
battery->id_index,
battery->id_adc,
battery->temp_01c,
battery->temp_adc,
battery->KADC_01p);
return TRUE;
}
/*========================================================================================
time functions
========================================================================================*/
DWORD BAHW_MyGetMSecs(void)
{
struct timespec now;
getnstimeofday(&now);
/*struct timespec t;
t.tv_sec = t.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC, &t);*/
return now.tv_sec * 1000 + now.tv_nsec / 1000000;
}
/*========================================================================================
battery param public function
========================================================================================*/
void battery_capacity_update(struct battery_type *battery, int capacity_01p)
{
/* ACR 500~500+FULL mapping to capacity 0~FULL*/
battery->charge_counter_mAh = capacity_01p * battery->charge_full_real_mAh / 1000;
battery->charge_counter_adc = (battery->charge_counter_mAh + charge_counter_zero_base_mAh) * acr_adc_to_mv_resl / acr_adc_to_mv_coef;
battery->RARC_01p = capacity_01p;
if (support_ds2746_gauge_ic) {
__ds2746_acr_update(battery, capacity_01p);
}
printk(DRIVER_ZONE "new RARC=%d C=%dmAh adc=%d.\n",
battery->RARC_01p,
battery->charge_counter_mAh,
battery->charge_counter_adc);
battery->is_power_on_reset = FALSE;
}
BOOL battery_param_update(struct battery_type *battery, struct protect_flags_type *flags)
{
if (!__battery_param_udpate(battery)) {
return FALSE;
}
if (flags->is_fake_room_temp) {
battery->temp_01c = 250;
printk(DRIVER_ZONE "fake temp=%d(%x)\n",
battery->temp_01c,
battery->temp_adc);
}
__protect_flags_update(battery, flags);
#if ! HTC_ENABLE_DUMMY_BATTERY
if (battery->id_index == BATTERY_ID_UNKNOWN) {
flags->is_charging_enable_available = FALSE;
}
#else /* HTC_ENABLE_DUMMY_BATTERY*/
/* do not disable charging for debug stage*/
flags->is_charging_enable_available = TRUE;
#endif /* HTC_ENABLE_DUMMY_BATTERY*/
return TRUE;
}
void battery_param_init(struct battery_type *battery)
{
/* set battery id to unknown to get battery id and related characters*/
battery->id_index = BATTERY_ID_UNKNOWN;
/* default to 25C unless we can get valid battery temp from adc*/
battery->temp_01c = 250;
battery->last_temp_01c = battery->temp_01c;
battery->temp_check_index = 0;
battery->last_temp_adc = 0;
battery->voltage_mV = 3800;
/* this is used when accumulate current by software; initial it as 0mAs*/
battery->software_charge_counter_mAms = 0;
/* set POR at first by software; gauge ic will has correct value*/
battery->is_power_on_reset = TRUE;
if (support_ds2746_gauge_ic) {
__ds2746_init_config(battery);
}
if (battery->thermal_id == THERMAL_1000) {
TEMP_MAP = TEMP_MAP_1000K;
printk(DRIVER_ZONE "Use 1000 Kohm thermal resistance");
} else {
printk(DRIVER_ZONE "Use default(300 Kohm) thermal resistance");
}
/*printk(DRIVER_ZONE "battery param inited with board name <%s>\n", HTC_BATT_BOARD_NAME);*/
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2007 HTC Incorporated
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _DS2746_BATTERY_H_
#define _DS2746_BATTERY_H_
#include <linux/notifier.h>
#include <mach/htc_battery.h>
#include <linux/wrapper_types.h>
#include <linux/ds2746_param.h>
enum ds2784_notify_evt_t {
DS2784_CHARGING_CONTROL = 0,
DS2784_LEVEL_UPDATE,
DS2784_BATTERY_FAULT,
DS2784_OVER_TEMP,
DS2784_NUM_EVENTS,
};
/* battery charging state*/
enum {
CHARGE_STATE_UNKNOWN, /* before anything is ready, we are in this state. shall default low current charge and show charging LED*/
CHARGE_STATE_PREDICTION, /* in normal case, we need to enter prediction for 10 seconds for 1st KADC*/
CHARGE_STATE_DISCHARGE, /* cable out state*/
CHARGE_STATE_CHARGING, /* charging state*/
CHARGE_STATE_PENDING, /* charging state but no good*/
CHARGE_STATE_FULL_WAIT_STABLE, /* charging state but going full*/
CHARGE_STATE_FULL_CHARGING, /* charging full, keep charging*/
CHARGE_STATE_FULL_PENDING, /* charging full, stop charging*/
};
enum {
THERMAL_300,
THERMAL_1000,
};
/* power algorithm data structure and config data structure*/
struct poweralg_type
{
int charge_state;
int capacity_01p;
int last_capacity_01p;
int fst_discharge_capacity_01p;
int fst_discharge_acr_mAh;
int charging_source;
int charging_enable;
BOOL is_need_calibrate_at_49p;
BOOL is_need_calibrate_at_14p;
BOOL is_charge_over_load;
struct battery_type battery;
struct protect_flags_type protect_flags;
BOOL is_china_ac_in;
BOOL is_cable_in;
BOOL is_voltage_stable;
BOOL is_software_charger_timeout;
UINT32 state_start_time_ms;
};
struct poweralg_config_type
{
INT32 full_charging_mv;
INT32 full_charging_ma;
INT32 full_pending_ma; /* 0 to disable*/
INT32 full_charging_timeout_sec; /* 0 to disable*/
INT32 voltage_recharge_mv; /* 0 to disable*/
INT32 capacity_recharge_p; /* 0 to disable*/
INT32 voltage_exit_full_mv; /* 0 to disable*/
INT32 wait_votlage_statble_sec;
INT32 predict_timeout_sec;
INT32 polling_time_in_charging_sec;
INT32 polling_time_in_discharging_sec;
BOOL enable_full_calibration;
BOOL enable_weight_percentage;
INT32 software_charger_timeout_sec; /* 0 to disable*/
BOOL debug_disable_shutdown;
BOOL debug_fake_room_temp;
BOOL debug_disable_hw_timer;
BOOL debug_always_predict;
INT32 full_level; /* 0 to disable*/
};
struct ds2746_platform_data {
int (*func_get_thermal_id)(void);
};
/* battery behavior constant*/
#define BATTERY_PERCENTAGE_UNKNOWN 0xFF
#define BATTERY_LOW_PERCENTAGE 10 /* in 1%*/
#define BATTERY_CRITICAL_PERCENTAGE 5 /* in 1%*/
#define BATTERY_EMPTY_PERCENTAGE 0 /* in 1%*/
/* battery algorithm public functions*/
int get_state_check_interval_min_sec( void);
BOOL do_power_alg( BOOL is_event_triggered);
void power_alg_init( struct poweralg_config_type *debug_config);
void power_alg_preinit( void);
int ds2746_blocking_notify( unsigned long val, void *v);
void ds2746_charger_control( int type);
int ds2746_i2c_write_u8( u8 value, u8 reg);
int ds2746_i2c_read_u8( u8* value, u8 reg);
void calibrate_id_ohm( struct battery_type *battery);
/* external function implemented by upper layer*/
/*extern void powerlog_to_file(struct poweralg_type* poweralg);*/
/*extern void update_os_batt_status(struct poweralg_type* poweralg);*/
#ifdef CONFIG_BATTERY_DS2746
extern int ds2746_register_notifier( struct notifier_block *nb);
extern int ds2746_unregister_notifier( struct notifier_block *nb);
extern int ds2746_get_battery_info( struct battery_info_reply *batt_info);
extern ssize_t htc_battery_show_attr( struct device_attribute *attr, char *buf);
#else
static int ds2746_register_notifier( struct notifier_block *nb) {
return 0;
}
static int ds2746_unregister_notifier( struct notifier_block *nb) {
return 0;
}
static int ds2746_get_battery_info( struct battery_info_reply *batt_info) {
batt_info->level = 10;
return 0;
}
extern ssize_t htc_battery_show_attr( struct device_attribute *attr, char *buf) {
return 0;
}
#endif
#endif

View File

@ -0,0 +1,44 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 2010 High Tech Computer Corporation
Module Name:
batt_alg_config.c
Abstract:
This module tells batt_alg.c module how to config power alg.
Original Auther:
Star Lee (star_lee) Apr-12-2010
---------------------------------------------------------------------------------*/
#define HTC_BATT_BOARD_NAME "ACE"
static void poweralg_config_init(struct poweralg_config_type *config)
{
config->full_charging_mv = 4110;
config->full_charging_ma = 50;
config->full_pending_ma = 0; /* disabled*/
config->full_charging_timeout_sec = 60 * 60;
config->voltage_recharge_mv = 4150;
config->capacity_recharge_p = 0; /* disabled*/
config->voltage_exit_full_mv = 4100;
config->wait_votlage_statble_sec = 1 * 60;
config->predict_timeout_sec = 10;
config->polling_time_in_charging_sec = 30;
config->polling_time_in_discharging_sec = 30;
config->enable_full_calibration = TRUE;
config->enable_weight_percentage = TRUE;
config->software_charger_timeout_sec = 0; /* disabled*/
config->debug_disable_shutdown = FALSE;
config->debug_fake_room_temp = FALSE;
config->debug_disable_hw_timer = FALSE;
config->debug_always_predict = FALSE;
config->full_level = 0;
}

View File

@ -0,0 +1,70 @@
#ifndef __BATT_PARAM_H__
#define __BATT_PARAM_H__
/* battery status and charging information*/
struct battery_type{
BOOL is_power_on_reset;
INT32 voltage_mV;
INT32 current_mA;
INT32 discharge_mA;
INT32 charge_counter_mAh;
INT32 temp_01c;
INT32 last_temp_01c;
INT32 id_ohm;
INT32 vref_mv;
INT32 voltage_adc;
INT32 current_adc;
INT32 discharge_adc;
INT32 charge_counter_adc;
INT32 temp_adc;
INT32 last_temp_adc;
INT32 id_adc;
INT32 vref_adc;
INT32 id_index;
INT32 charge_full_design_mAh;
INT32 charge_full_real_mAh;
INT32 temp_index;
INT32 temp_check_index;
INT32 KADC_01p;
INT32 RARC_01p;
INT32 pd_m;
INT32 software_charge_counter_mAms;
INT32 thermal_id;
};
struct protect_flags_type{
BOOL is_charging_enable_available;
BOOL is_charging_high_current_avaialble;
BOOL is_charging_indicator_available;
BOOL is_battery_dead;
#if 0
BOOL is_battery_overtemp;
#endif
BOOL is_fake_room_temp;
};
/* ds2746 register definition*/
#define DS2746_STATUS_PORF (1 << 6) /* write to 0 as power-up sequence ready*/
#define DS2746_STATUS_SMOD (1 << 5) /* write to 0 to disable DS2746 sleep mode*/
#define DS2746_STATUS_NBEN (1 << 4) /* write to 0 to disable blanking of negative currents*/
#define DS2746_STATUS_AIN0 (1 << 0)
#define DS2746_STATUS_AIN1 (1 << 1)
/* function prototypes*/
void battery_capacity_update(struct battery_type *battery, int capacity_01p);
BOOL battery_param_update(struct battery_type *battery, struct protect_flags_type *flags);
DWORD BAHW_MyGetMSecs(void);
void battery_param_init(struct battery_type *battery);
#endif /* __BATT_PARAM_H__*/

View File

@ -0,0 +1,274 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 2010 High Tech Computer Corporation
Module Name:
ds2746_param_config.c
Abstract:
This module tells batt_param.c module what the battery characteristic is.
And also which charger/gauge component hardware uses, to decide if software/hardware function is available.
Original Auther:
Andy.ys Wang June-01-2010
---------------------------------------------------------------------------------*/
#ifndef __BATT_PARAM_CONFIG_H__
#define __BATT_PARAM_CONFIG_H__
#define HTC_BATT_BOARD_NAME "ACE"
/*========================================================================================
battery parameter defines (depend on board design)
========================================================================================*/
static BOOL support_ds2746_gauge_ic = TRUE;
enum BATTERY_ID_ENUM {
BATTERY_ID_UNKNOWN = 0,
BATTERY_ID_SONY_1300MAH_FORMOSA,
BATTERY_ID_SONY_1300MAH_HTE,
BATTERY_ID_SANYO_1300MAH_HTE,
BATTERY_ID_SANYO_1300MAH_TWS,
BATTERY_ID_NUM /* include unknown battery*/
};
UINT32 ID_RANGE[] =
{
/* id resister range = [min, max)*/
7150, 15500, /* Sony 1300mAh (Formosa) */ /* 7.1k~15k */
27500, 49500, /* Sony 1300mAh (HTE) */ /* 28k~49.5k */
15500, 27500, /* Sanyo 1300mAh (HTE) */ /* 16k~27k */
0, 7150, /* Samsung 1230mAh */ /* 0k~7k */
};
/*This table is calculated according to temp formula for temp mapping.
If temp_adc is located on 0-95, then the temp_01c is 700.
96-99, then the temp_01c is 690.
100-102, then the temp_01c is 680.
...
1117777777-1145, then the temp_01c is 0.
1146-1175, then the temp_01c is -1.
...
1433-2046, then the temp_01c is -11.
*/
UINT32 TEMP_MAP_300K[] =
{
0, 96, 100, 103, 107, 111, 115, 119, 123, 127,
133, 137, 143, 148, 154, 159, 165, 172, 178, 185,
192, 199, 207, 215, 223, 232, 241, 250, 260, 270,
280, 291, 301, 314, 326, 339, 352, 366, 380, 394,
410, 425, 442, 458, 476, 494, 512, 531, 551, 571,
592, 614, 636, 659, 682, 706, 730, 755, 780, 806,
833, 860, 887, 942, 943, 971, 1000, 1028, 1058, 1087,
1117, 1146, 1176, 1205, 1234, 1264, 1293, 1321, 1350, 1378,
1406, 1433, 2047,
};
UINT32 TEMP_MAP_1000K[] =
{
0, 30, 31, 32, 34, 35, 36, 38, 39, 40,
42, 44, 45, 47, 49, 51, 53, 55, 57, 60,
62, 64, 67, 70, 73, 76, 79, 82, 86, 89,
93, 97, 101, 106, 111, 115, 120, 126, 131, 137,
143, 150, 156, 163, 171, 178, 187, 195, 204, 213,
223, 233, 244, 255, 267, 279, 292, 306, 320, 334,
350, 365, 382, 399, 418, 436, 456, 476, 497, 519,
542, 566, 590, 615, 641, 668, 695, 723, 752, 782,
812, 843, 2047,
};
UINT32 *TEMP_MAP = TEMP_MAP_300K;
UINT32 FL_25[] =
{
1280, /* Unknown battery */
1280, /* Sony 1300mAh (Formosa) */
1280, /* Sony 1300mAh (HTE) */
1250, /* Sanyo 1300mAh (HTE) */
1230, /* Samsung 1230mAh */
};
UINT32 PD_M_COEF[] =
{
/* for TAO PMA, this is defined as PD_M; for TPE PMA, this is defined as FT or t*/
24, /* Unknown battery */
24, /* Sony 1300mAh (Formosa) */
24, /* Sony 1300mAh (HTE) */
27, /* Sanyo 1300mAh (HTE) */
30, /* Samsung 1230mAh */
};
UINT32 PD_M_RESL[] =
{
/* for TAO PMA, this is defined as PD_M; for TPE PMA, this is defined as FT or t*/
100, /* Unknown battery */
100, /* Sony 1300mAh (Formosa) */
100, /* Sony 1300mAh (HTE) */
100, /* Sanyo 1300mAh (HTE) */
100, /* Samsung 1230mAh */
};
UINT32 PD_T_COEF[] =
{
/* Ex: 140 -> 0.014, 156 -> 0.0156*/
140, /* Unknown battery */
140, /* Sony 1300mAh (Formosa) */
140, /* Sony 1300mAh (HTE) */
156, /* Sanyo 1300mAh (HTE) */
250, /* Samsung 1230mAh */
};
/*! star_lee 20100426 - update KADC discharge parameter */
UINT32 M_PARAMETER_SONY_1300MAH_FORMOSA[] =
{
/* capacity (in 0.01%) -> voltage (in mV)*/
10000, 4100, 5500, 3839, 2400, 3759, 400, 3667, 0, 3397,
};
UINT32 M_PARAMETER_Samsung_1230MAH_FORMOSA[] =
{
/* capacity (in 0.01%) -> voltage (in mV)*/
10000, 4135, 7500, 3960, 4700, 3800, 1700, 3727, 900, 3674, 300, 3640, 0, 3420,
};
UINT32 *M_PARAMTER_TABLE[] =
{
/* Unknown battery */
(UINT32 *) (M_PARAMETER_SONY_1300MAH_FORMOSA),
/* same as Sony 1300mAh (Formosa) currently... */
/* Sony 1300mAh (Formosa) */
(UINT32 *) (M_PARAMETER_SONY_1300MAH_FORMOSA),
/* Sony 1300mAh (HTE) */
(UINT32 *) (M_PARAMETER_SONY_1300MAH_FORMOSA),
/* same as Sony 1300mAh (Formosa) currently... */
/* Sanyo 1300mAh (HTE) */
(UINT32 *) (M_PARAMETER_SONY_1300MAH_FORMOSA),
/* same as Sony 1300mAh (Formosa) currently... */
/* Samsung 1230mAh */
(UINT32 *) (M_PARAMETER_Samsung_1230MAH_FORMOSA),
/* same as Sony 1300mAh (Formosa) currently... */
};
INT32 TEMP_RANGE[] =
{
/* mapping temp to temp_index*/
200, /* ~20C */
100, /* 20~10C */
50, /* 10~5C */
0, /* 5~0C */ -5, /* 0~-5C */ -10, /* -5~-10C */ -3000,
/* -10C~ */
};
UINT32 *PD_M_COEF_TABLE_BOOT[] =
{
/* mapping current to pd_m_coef table when booting*/
(UINT32 *) (PD_M_COEF), /* ~20C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 20~10C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 10~5C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 5~0C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 0~-5C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* -5~-10C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* -10C~, using PD_M_COEF */
};
UINT32 *PD_M_COEF_TABLE[] =
{
/* mapping current to pd_m_coef table*/
(UINT32 *) (PD_M_COEF), /* ~20C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 20~10C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 10~5C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 5~0C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* 0~-5C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* -5~-10C, using PD_M_COEF */
(UINT32 *) (PD_M_COEF), /* -10C~, using PD_M_COEF */
};
UINT32 *PD_M_RESL_TABLE_BOOT[] =
{
/* mapping current to pd_m_coef table when booting*/
(UINT32 *) (PD_M_RESL), /* ~20C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 20~10C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 10~5C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 5~0C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 0~-5C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* -5~-10C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* -10C~, using PD_M_RESL */
};
UINT32 *PD_M_RESL_TABLE[] =
{
/* mapping current to pd_m_coef table*/
(UINT32 *) (PD_M_RESL), /* ~20C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 20~10C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 10~5C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 5~0C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* 0~-5C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* -5~-10C, using PD_M_RESL */
(UINT32 *) (PD_M_RESL), /* -10C~, using PD_M_RESL */
};
UINT32 CAPACITY_DEDUCTION_01p[] =
{
0, /* ~20C, upper capacity 100 is usable */
0, /* 20~10C, upper capacity 95 is usable */
0, /* 10~5C, upper capacity 92 is usable */
0, /* 5~0C, upper capacity 90 is usable */
0, /* 0~-5C, upper capacity 87 is usable */
0, /* -5~-10C, upper capacity 85 is usable */
0, /* -10C~, upper capacity 85 is usable */
};
/*========================================================================================
battery formula coef definition, can be re-programable
========================================================================================*/
/* adc converter*/
static INT32 voltage_adc_to_mv_coef = 244;
static INT32 voltage_adc_to_mv_resl = 100;
static INT32 current_adc_to_mv_coef = 625;
static INT32 current_adc_to_mv_resl = 1580;
static INT32 discharge_adc_to_mv_coef = 625;
static INT32 discharge_adc_to_mv_resl = 1580;
static INT32 acr_adc_to_mv_coef = 625;
static INT32 acr_adc_to_mv_resl = 1580;
static INT32 charge_counter_zero_base_mAh = 500;
static INT32 id_adc_resl = 2047;
static INT32 temp_adc_resl = 2047;
/* kadc parameter*/
static INT32 pd_m_bias_mA; /* the bias current when calculating pd_m*/
/* over temperature algorithm*/
static INT32 over_high_temp_lock_01c = 450;
static INT32 over_high_temp_release_01c = 420;
static INT32 over_low_temp_lock_01c; /*over_low_temp_lock_01c = 0*/
static INT32 over_low_temp_release_01c = 30;
/* function config*/
static BOOL is_allow_batt_id_change = FALSE;
/*boot up voltage*/
/*dead battery is voltage < M_0*/
#define BATTERY_DEAD_VOLTAGE_LEVEL 3420
#define BATTERY_DEAD_VOLTAGE_RELEASE 3450
#define TEMP_MAX 70
#define TEMP_MIN -11
#define TEMP_NUM 83
#endif

23
include/linux/tps65200.h Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007 HTC Incorporated
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _TPS65200_H_
#define _TPS65200_H_
#include <linux/notifier.h>
#include <mach/htc_battery.h>
#ifdef CONFIG_TPS65200
extern int tps_set_charger_ctrl(u32 ctl);
#else
static int tps_set_charger_ctrl(u32 ctl) {return 0 ; }
#endif
#endif

View File

@ -0,0 +1,92 @@
#ifndef __WRAPPER_TYPES_H_
#define __WRAPPER_TYPES_H_
#define DRIVER_ZONE "[D:BATT]"
#define DRIVER_BATTERY (1<<9)
/* The left side of these typedefs are machine and compiler dependent */
typedef signed char INT8;
typedef unsigned char UINT8;
typedef signed short INT16;
typedef unsigned short UINT16;
typedef signed int INT32;
typedef unsigned int UINT32;
typedef struct _INT64{
UINT32 u0, u1, u2; INT32 u3;
} INT64;
typedef struct _UINT64{
UINT32 u0, u1, u2, u3;
} UINT64;
typedef struct _INT128{
UINT32 u0, u1, u2; INT32 u3;
} INT128;
typedef struct _UINT128{
UINT32 u0, u1, u2, u3;
} UINT128;
typedef INT8 * PINT8;
typedef UINT8 *PUINT8;
typedef INT16 * PINT16;
typedef UINT16 * PUINT16;
typedef INT32 *PINT32;
typedef UINT32 *PUINT32;
typedef INT64 * PINT64;
typedef UINT64 * PUINT64;
typedef INT128 * PINT128;
typedef UINT128 * PUINT128;
typedef const void *PCVOID;
typedef void **PPVOID;
/*typedef unsigned char uchar;*/
typedef void (*PFNVOID)( void);
typedef char CHAR;
typedef UINT8 BYTE;
typedef UINT8 UCHAR;
typedef UINT32 ULONG;
typedef INT32 LONG;
typedef UINT32 DWORD;
typedef UINT32 UINT;
typedef UINT32 BOOL;
typedef UINT16 WORD;
typedef UINT16 USHORT;
typedef INT32 INT;
typedef void *LPVOID;
typedef void *PVOID;
typedef void VOID;
typedef void *HLOCAL;
typedef CHAR * LPCHAR;
typedef CHAR * PBYTE;
typedef INT16 * LPCWSTR;
typedef UINT8 *LPTSTR;
typedef UINT8 *LPCSTR;
typedef UINT8 *LPCTSTR;
typedef BYTE * LPBYTE;
typedef DWORD *LPDWORD;
typedef DWORD *PDWORD;
typedef CHAR TCHAR;
typedef UINT32 HINSTANCE;
typedef UINT32 HKEY;
typedef UINT32 HMODULE;
typedef UINT32 FARPROC;
typedef UINT32 HRESULT;
typedef UINT32 HREGNOTIFY;
typedef UINT32 LPSTARTUPINFO;
typedef UINT32 LPPROCESS_INFORMATION;
typedef UINT32 REGISTRYNOTIFYCALLBACK;
typedef UINT32 NOTIFICATIONCONDITION;
typedef UINT32 REGSAM;
typedef UINT32 PHKEY;
#define FALSE 0
#define TRUE 1
#define INFINITE 0x7fffffffffffffffL
#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
#define CEILING(n, precision) ((n+precision-1)/precision) /* ex: CEILING(989, 10)=99, means 98.9 mapping to 99*/
#endif