htcleo: add new battery driver
This driver is comming from desire hd and is modificated for htcleo
This commit is contained in:
parent
dbd408efab
commit
55ca1d277a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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");
|
@ -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);
|
||||
|
@ -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 *) ¶m);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
1248
drivers/power/ds2746_battery.c
Normal file
1248
drivers/power/ds2746_battery.c
Normal file
File diff suppressed because it is too large
Load Diff
852
drivers/power/ds2746_param.c
Normal file
852
drivers/power/ds2746_param.c
Normal 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(®_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(®_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(®[0], 0x01))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[2], 0x08))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[3], 0x09))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[4], 0x0a))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[5], 0x0b))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[6], 0x0c))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[7], 0x0d))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[8], 0x0e))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[9], 0x0f))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[10], 0x10))
|
||||
return FALSE;
|
||||
if (!ds2746_i2c_read_u8(®[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 *) ®)) {
|
||||
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);*/
|
||||
}
|
||||
|
147
include/linux/ds2746_battery.h
Normal file
147
include/linux/ds2746_battery.h
Normal 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
|
44
include/linux/ds2746_battery_config.h
Normal file
44
include/linux/ds2746_battery_config.h
Normal 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;
|
||||
}
|
||||
|
70
include/linux/ds2746_param.h
Normal file
70
include/linux/ds2746_param.h
Normal 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__*/
|
274
include/linux/ds2746_param_config.h
Normal file
274
include/linux/ds2746_param_config.h
Normal 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
23
include/linux/tps65200.h
Normal 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
|
92
include/linux/wrapper_types.h
Normal file
92
include/linux/wrapper_types.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user