htcleo: add power and battery driver
All credits here and in much other things to Cotulla
This commit is contained in:
parent
4b3aa128b9
commit
772ab54360
@ -100,8 +100,8 @@ 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-spi.o board-htcleo-panel.o board-htcleo-keypad.o
|
||||
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-ts.o board-htcleo-mmc.o ieee754-df.o
|
||||
obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-log.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-battery.o board-htcleo-log.o
|
||||
obj-$(CONFIG_MACH_HTCLEO) += clock-wince.o
|
||||
|
||||
# MSM7x30 boards
|
||||
|
914
arch/arm/mach-msm/board-htcleo-battery.c
Normal file
914
arch/arm/mach-msm/board-htcleo-battery.c
Normal file
@ -0,0 +1,914 @@
|
||||
/* arch/arm/mach-msm/board-htcleo-battery.c
|
||||
*
|
||||
* Copyright (C) 2010 Cotulla
|
||||
* 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/android_alarm.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 "gpio_chip.h"
|
||||
#include "board-htcleo.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#define LEO_BATTERY_CAPACITY 1230
|
||||
#define LEO_BATTERY_EMPTY 500
|
||||
|
||||
|
||||
/* Known commands to the DS2784 chip */
|
||||
#define W1_DS2784_SWAP 0xAA
|
||||
#define W1_DS2784_READ_DATA 0x69
|
||||
#define W1_DS2784_WRITE_DATA 0x6C
|
||||
#define W1_DS2784_COPY_DATA 0x48
|
||||
#define W1_DS2784_RECALL_DATA 0xB8
|
||||
#define W1_DS2784_LOCK 0x6A
|
||||
|
||||
/* Number of valid register addresses */
|
||||
#define DS2784_DATA_SIZE 0x80
|
||||
|
||||
#define DS2784_EEPROM_BLOCK0 0x20
|
||||
#define DS2784_ACTIVE_FULL 0x20
|
||||
#define DS2784_EEPROM_BLOCK1 0x30
|
||||
#define DS2784_RATED_CAPACITY 0x32
|
||||
#define DS2784_CURRENT_OFFSET_BIAS 0x33
|
||||
#define DS2784_ACTIVE_EMPTY 0x3b
|
||||
|
||||
/**
|
||||
* The DS2482 registers - there are 3 registers that are addressed by a read
|
||||
* pointer. The read pointer is set by the last command executed.
|
||||
*
|
||||
* To read the data, issue a register read for any address
|
||||
*/
|
||||
#define DS2482_CMD_RESET 0xF0 /* No param */
|
||||
#define DS2482_CMD_SET_READ_PTR 0xE1 /* Param: DS2482_PTR_CODE_xxx */
|
||||
#define DS2482_CMD_CHANNEL_SELECT 0xC3
|
||||
#define DS2482_CMD_WRITE_CONFIG 0xD2 /* Param: Config byte */
|
||||
#define DS2482_CMD_1WIRE_RESET 0xB4 /* Param: None */
|
||||
#define DS2482_CMD_1WIRE_SINGLE_BIT 0x87 /* Param: Bit byte (bit7) */
|
||||
#define DS2482_CMD_1WIRE_WRITE_BYTE 0xA5 /* Param: Data byte */
|
||||
#define DS2482_CMD_1WIRE_READ_BYTE 0x96 /* Param: None */
|
||||
/* Note to read the byte, Set the ReadPtr to Data then read (any addr) */
|
||||
#define DS2482_CMD_1WIRE_TRIPLET 0x78 /* Param: Dir byte (bit7) */
|
||||
|
||||
/* Values for DS2482_CMD_SET_READ_PTR */
|
||||
#define DS2482_PTR_CODE_STATUS 0xF0
|
||||
#define DS2482_PTR_CODE_DATA 0xE1
|
||||
#define DS2482_PTR_CODE_CHANNEL 0xD2 /* DS2482-800 only */
|
||||
#define DS2482_PTR_CODE_CONFIG 0xC3
|
||||
|
||||
|
||||
#define RAW_DATA_SIZE 10
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// from board-htcleo-power.c
|
||||
extern int is_ac_power_supplied(void);
|
||||
|
||||
// from board-htcleo-log.c
|
||||
extern double log(double x);
|
||||
|
||||
|
||||
struct battery_status
|
||||
{
|
||||
int timestamp;
|
||||
|
||||
int voltage_uV; /* units of uV */
|
||||
int current_uA; /* units of uA */
|
||||
int current_avg_uA;
|
||||
int charge_uAh;
|
||||
|
||||
s16 temp_C; /* units of 0.1 C */
|
||||
|
||||
u8 percentage; /* battery percentage */
|
||||
u8 charge_source;
|
||||
u8 status_reg;
|
||||
u8 battery_full; /* battery full (don't charge) */
|
||||
|
||||
u8 cooldown; /* was overtemp */
|
||||
u8 charge_mode;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
#define SOURCE_NONE 0
|
||||
#define SOURCE_USB 1
|
||||
#define SOURCE_AC 2
|
||||
|
||||
#define CHARGE_OFF 0
|
||||
#define CHARGE_SLOW 1
|
||||
#define CHARGE_FAST 2
|
||||
#define CHARGE_BATT_DISABLE 3 /* disable charging at battery */
|
||||
|
||||
#define TEMP_CRITICAL 600 /* no charging at all */
|
||||
#define TEMP_HOT 500 /* no fast charge, no charge > 4.1v */
|
||||
#define TEMP_WARM 450 /* no fast charge above this */
|
||||
|
||||
#define TEMP_HOT_MAX_MV 4100 /* stop charging here when hot */
|
||||
#define TEMP_HOT_MIN_MV 3800 /* resume charging here when hot */
|
||||
#define CE_DISABLE_MIN_MV 4100
|
||||
|
||||
#define BATTERY_LOG_MAX 1024
|
||||
#define BATTERY_LOG_MASK (BATTERY_LOG_MAX - 1)
|
||||
|
||||
/* When we're awake or running on wall power, sample the battery
|
||||
* gauge every FAST_POLL seconds. If we're asleep and on battery
|
||||
* power, sample every SLOW_POLL seconds
|
||||
*/
|
||||
#define FAST_POLL (1 * 60)
|
||||
#define SLOW_POLL (10 * 60)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
struct htcleo_device_info
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
/* DS2784 data, valid after calling htcleo_battery_read_status() */
|
||||
char raw[RAW_DATA_SIZE]; /* raw HTCLEO data */
|
||||
uint32_t raw_status;
|
||||
|
||||
struct battery_status status;
|
||||
|
||||
struct power_supply bat;
|
||||
struct workqueue_struct *monitor_wqueue;
|
||||
struct work_struct monitor_work;
|
||||
struct alarm alarm;
|
||||
struct wake_lock work_wake_lock;
|
||||
|
||||
// int (*charge)(int on, int fast);
|
||||
// struct w1_slave *w1_slave;
|
||||
struct i2c_client *client;
|
||||
|
||||
u8 dummy; /* dummy battery flag */
|
||||
u8 last_charge_mode; /* previous charger state */
|
||||
u8 slow_poll;
|
||||
|
||||
ktime_t last_poll;
|
||||
ktime_t last_charge_seen;
|
||||
};
|
||||
|
||||
#define psy_to_dev_info(x) container_of((x), struct htcleo_device_info, bat)
|
||||
|
||||
static struct wake_lock vbus_wake_lock;
|
||||
|
||||
#define BATT_RSNSP (67) /*Passion battery source 1*/
|
||||
|
||||
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 to_htcleo_device_info(x) container_of((x), struct htcleo_device_info, bat);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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);
|
||||
printk("ACR=%d FL=%d RAAC=%d\n", ACR, ACR_EMPTY, s->percentage);
|
||||
|
||||
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);
|
||||
|
||||
// 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 ||
|
||||
di->status.charge_mode == CHARGE_BATT_DISABLE)
|
||||
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;
|
||||
int ovp;
|
||||
u8 charge_mode;
|
||||
bool charge_timeout = false;
|
||||
|
||||
mutex_lock(&charge_state_lock);
|
||||
|
||||
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;
|
||||
|
||||
/* shut off charger when full:
|
||||
* - CHGTF flag is set
|
||||
*/
|
||||
#if 1
|
||||
/*if (di->status.status_reg & 0x80)
|
||||
{
|
||||
di->status.battery_full = 1;
|
||||
charge_mode = CHARGE_BATT_DISABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
di->status.battery_full = 0;
|
||||
}*/
|
||||
if(di->status.percentage >= 99)
|
||||
{
|
||||
di->status.battery_full = 1;
|
||||
charge_mode = CHARGE_BATT_DISABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
di->status.battery_full = 0;
|
||||
}
|
||||
#else
|
||||
// CotullaTODO: add DS274X check code here
|
||||
di->status.battery_full = 0;
|
||||
#endif
|
||||
|
||||
ovp = gpio_get_value(HTCLEO_GPIO_BATTERY_OVER_CHG);
|
||||
if (ovp)
|
||||
{
|
||||
// printk("OVERPOWER!!!! FACK!\n");
|
||||
}
|
||||
|
||||
if (temp >= TEMP_HOT || ovp)
|
||||
{
|
||||
if (temp >= TEMP_CRITICAL)
|
||||
{
|
||||
charge_mode = CHARGE_BATT_DISABLE;
|
||||
}
|
||||
|
||||
/* 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_BATT_DISABLE;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
if (di->last_charge_mode == CHARGE_BATT_DISABLE)
|
||||
{
|
||||
/* The charger is only powering the phone. Toggle the
|
||||
* enable line periodically to prevent auto shutdown.
|
||||
*/
|
||||
di->last_charge_seen = di->last_poll;
|
||||
pr_info("batt: charging POKE CHARGER\n");
|
||||
htcleo_charge(0, 0);
|
||||
udelay(10);
|
||||
htcleo_charge(1, source == CHARGE_FAST);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* Don't use CHARGE_BATT_DISABLE unless the voltage is high since the
|
||||
* voltage drop over the discharge-path diode can cause a shutdown.
|
||||
*/
|
||||
if (charge_mode == CHARGE_BATT_DISABLE && volt < CE_DISABLE_MIN_MV)
|
||||
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_BATT_DISABLE:
|
||||
di->last_charge_seen = di->last_poll;
|
||||
htcleo_set_cc(di, false);
|
||||
htcleo_charge(1, source == CHARGE_FAST);
|
||||
if (temp >= TEMP_CRITICAL)
|
||||
pr_info("batt: charging BATTOFF [OVERTEMP]\n");
|
||||
else if (di->status.cooldown)
|
||||
pr_info("batt: charging BATTOFF [COOLDOWN]\n");
|
||||
else if (di->status.battery_full)
|
||||
pr_info("batt: charging BATTOFF [FULL]\n");
|
||||
else
|
||||
pr_info("batt: charging BATTOFF [UNKNOWN]\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("$$$ htcleo_battery_probe $$$\n");
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE))
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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("probe exit!\n");
|
||||
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
|
209
arch/arm/mach-msm/board-htcleo-power.c
Normal file
209
arch/arm/mach-msm/board-htcleo-power.c
Normal file
@ -0,0 +1,209 @@
|
||||
/* 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 "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
|
||||
extern 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
//later_init(htcleo_power_init);
|
||||
MODULE_DESCRIPTION("HTCLEO Power Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -139,6 +139,9 @@ static struct platform_device htcleo_timed_gpios = {
|
||||
|
||||
static struct i2c_board_info base_i2c_devices[] =
|
||||
{
|
||||
{
|
||||
I2C_BOARD_INFO("htcleo-battery", 0x26),
|
||||
},
|
||||
{
|
||||
I2C_BOARD_INFO(LEO_TOUCH_DRV_NAME, 0),
|
||||
},
|
||||
@ -334,6 +337,13 @@ static struct platform_device ram_console_device = {
|
||||
.resource = ram_console_resources,
|
||||
};
|
||||
|
||||
/* Battery */
|
||||
static struct platform_device htcleo_power =
|
||||
{
|
||||
.name = "htcleo_power",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static struct platform_device *devices[] __initdata =
|
||||
{
|
||||
&ram_console_device,
|
||||
@ -355,7 +365,7 @@ static struct platform_device *devices[] __initdata =
|
||||
// &capella_cm3602,
|
||||
// &msm_camera_sensor_s5k3e2fx,
|
||||
// &htcleo_flashlight_device,
|
||||
// &htcleo_power,
|
||||
&htcleo_power,
|
||||
&qsd_device_spi,
|
||||
|
||||
};
|
||||
|
@ -31,8 +31,7 @@
|
||||
|
||||
|
||||
// from board-htcleo-power.c
|
||||
//void notify_vbus_change_intr(void);
|
||||
void notify_vbus_change_intr(void){};
|
||||
void notify_vbus_change_intr(void);
|
||||
|
||||
#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user