Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
b5db7cde
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
b5db7cde
编写于
2月 28, 2011
作者:
A
Anton Vorontsov
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'bq27x00-for-upstream' of
git://git.metafoo.de/linux-2.6
上级
d6ccc442
9e912f45
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
593 addition
and
171 deletion
+593
-171
drivers/power/Kconfig
drivers/power/Kconfig
+14
-0
drivers/power/bq27x00_battery.c
drivers/power/bq27x00_battery.c
+557
-168
drivers/power/power_supply_core.c
drivers/power/power_supply_core.c
+2
-2
drivers/power/power_supply_sysfs.c
drivers/power/power_supply_sysfs.c
+1
-1
include/linux/power/bq27x00_battery.h
include/linux/power/bq27x00_battery.h
+19
-0
未找到文件。
drivers/power/Kconfig
浏览文件 @
b5db7cde
...
...
@@ -117,10 +117,24 @@ config BATTERY_BQ20Z75
config BATTERY_BQ27x00
tristate "BQ27x00 battery driver"
help
Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips.
config BATTERY_BQ27X00_I2C
bool "BQ27200/BQ27500 support"
depends on BATTERY_BQ27x00
depends on I2C
default y
help
Say Y here to enable support for batteries with BQ27x00 (I2C) chips.
config BATTERY_BQ27X00_PLATFORM
bool "BQ27000 support"
depends on BATTERY_BQ27x00
default y
help
Say Y here to enable support for batteries with BQ27000 (HDQ) chips.
config BATTERY_DA9030
tristate "DA9030 battery driver"
depends on PMIC_DA903X
...
...
drivers/power/bq27x00_battery.c
浏览文件 @
b5db7cde
...
...
@@ -3,6 +3,7 @@
*
* Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
* Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
* Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
*
* Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
*
...
...
@@ -15,6 +16,13 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
/*
* Datasheets:
* http://focus.ti.com/docs/prod/folders/print/bq27000.html
* http://focus.ti.com/docs/prod/folders/print/bq27500.html
*/
#include <linux/module.h>
#include <linux/param.h>
#include <linux/jiffies.h>
...
...
@@ -27,7 +35,9 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
#define DRIVER_VERSION "1.1.0"
#include <linux/power/bq27x00_battery.h>
#define DRIVER_VERSION "1.2.0"
#define BQ27x00_REG_TEMP 0x06
#define BQ27x00_REG_VOLT 0x08
...
...
@@ -36,36 +46,59 @@
#define BQ27x00_REG_TTE 0x16
#define BQ27x00_REG_TTF 0x18
#define BQ27x00_REG_TTECP 0x26
#define BQ27x00_REG_NAC 0x0C
/* Nominal available capaciy */
#define BQ27x00_REG_LMD 0x12
/* Last measured discharge */
#define BQ27x00_REG_CYCT 0x2A
/* Cycle count total */
#define BQ27x00_REG_AE 0x22
/* Available enery */
#define BQ27000_REG_RSOC 0x0B
/* Relative State-of-Charge */
#define BQ27000_REG_ILMD 0x76
/* Initial last measured discharge */
#define BQ27000_FLAG_CHGS BIT(7)
#define BQ27000_FLAG_FC BIT(5)
#define BQ27500_REG_SOC 0x2c
#define BQ27500_REG_SOC 0x2C
#define BQ27500_REG_DCAP 0x3C
/* Design capacity */
#define BQ27500_FLAG_DSC BIT(0)
#define BQ27500_FLAG_FC BIT(9)
/* If the system has several batteries we need a different name for each
* of them...
*/
static
DEFINE_IDR
(
battery_id
);
static
DEFINE_MUTEX
(
battery_mutex
);
#define BQ27000_RS 20
/* Resistor sense */
struct
bq27x00_device_info
;
struct
bq27x00_access_methods
{
int
(
*
read
)(
u8
reg
,
int
*
rt_value
,
int
b_single
,
struct
bq27x00_device_info
*
di
);
int
(
*
read
)(
struct
bq27x00_device_info
*
di
,
u8
reg
,
bool
single
);
};
enum
bq27x00_chip
{
BQ27000
,
BQ27500
};
struct
bq27x00_reg_cache
{
int
temperature
;
int
time_to_empty
;
int
time_to_empty_avg
;
int
time_to_full
;
int
charge_full
;
int
charge_counter
;
int
capacity
;
int
flags
;
int
current_now
;
};
struct
bq27x00_device_info
{
struct
device
*
dev
;
int
id
;
struct
bq27x00_access_methods
*
bus
;
struct
power_supply
bat
;
enum
bq27x00_chip
chip
;
struct
i2c_client
*
client
;
struct
bq27x00_reg_cache
cache
;
int
charge_design_full
;
unsigned
long
last_update
;
struct
delayed_work
work
;
struct
power_supply
bat
;
struct
bq27x00_access_methods
bus
;
struct
mutex
lock
;
};
static
enum
power_supply_property
bq27x00_battery_props
[]
=
{
...
...
@@ -78,164 +111,328 @@ static enum power_supply_property bq27x00_battery_props[] = {
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW
,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG
,
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW
,
POWER_SUPPLY_PROP_TECHNOLOGY
,
POWER_SUPPLY_PROP_CHARGE_FULL
,
POWER_SUPPLY_PROP_CHARGE_NOW
,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
POWER_SUPPLY_PROP_CHARGE_COUNTER
,
POWER_SUPPLY_PROP_ENERGY_NOW
,
};
static
unsigned
int
poll_interval
=
360
;
module_param
(
poll_interval
,
uint
,
0644
);
MODULE_PARM_DESC
(
poll_interval
,
"battery poll interval in seconds - "
\
"0 disables polling"
);
/*
* Common code for BQ27x00 devices
*/
static
in
t
bq27x00_read
(
u8
reg
,
int
*
rt_value
,
int
b_single
,
struct
bq27x00_device_info
*
di
)
static
in
line
int
bq27x00_read
(
struct
bq27x00_device_info
*
di
,
u8
reg
,
bool
single
)
{
return
di
->
bus
->
read
(
reg
,
rt_value
,
b_single
,
di
);
return
di
->
bus
.
read
(
di
,
reg
,
single
);
}
/*
* Return the battery
temperature in tenths of degree Celsius
* Return the battery
Relative State-of-Charge
* Or < 0 if something fails.
*/
static
int
bq27x00_battery_
temperature
(
struct
bq27x00_device_info
*
di
)
static
int
bq27x00_battery_
read_rsoc
(
struct
bq27x00_device_info
*
di
)
{
int
ret
;
int
temp
=
0
;
int
rsoc
;
ret
=
bq27x00_read
(
BQ27x00_REG_TEMP
,
&
temp
,
0
,
di
);
if
(
ret
)
{
dev_err
(
di
->
dev
,
"error reading temperature
\n
"
);
return
ret
;
if
(
di
->
chip
==
BQ27500
)
rsoc
=
bq27x00_read
(
di
,
BQ27500_REG_SOC
,
false
);
else
rsoc
=
bq27x00_read
(
di
,
BQ27000_REG_RSOC
,
true
);
if
(
rsoc
<
0
)
dev_err
(
di
->
dev
,
"error reading relative State-of-Charge
\n
"
);
return
rsoc
;
}
/*
* Return a battery charge value in µAh
* Or < 0 if something fails.
*/
static
int
bq27x00_battery_read_charge
(
struct
bq27x00_device_info
*
di
,
u8
reg
)
{
int
charge
;
charge
=
bq27x00_read
(
di
,
reg
,
false
);
if
(
charge
<
0
)
{
dev_err
(
di
->
dev
,
"error reading nominal available capacity
\n
"
);
return
charge
;
}
if
(
di
->
chip
==
BQ27500
)
return
temp
-
2731
;
charge
*=
1000
;
else
return
((
temp
>>
2
)
-
273
)
*
10
;
charge
=
charge
*
3570
/
BQ27000_RS
;
return
charge
;
}
/*
* Return the battery
Voltage in milivolts
* Return the battery
Nominal available capaciy in µAh
* Or < 0 if something fails.
*/
static
in
t
bq27x00_battery_voltage
(
struct
bq27x00_device_info
*
di
)
static
in
line
int
bq27x00_battery_read_nac
(
struct
bq27x00_device_info
*
di
)
{
int
ret
;
int
volt
=
0
;
return
bq27x00_battery_read_charge
(
di
,
BQ27x00_REG_NAC
)
;
}
ret
=
bq27x00_read
(
BQ27x00_REG_VOLT
,
&
volt
,
0
,
di
);
if
(
ret
)
{
dev_err
(
di
->
dev
,
"error reading voltage
\n
"
);
return
ret
;
/*
* Return the battery Last measured discharge in µAh
* Or < 0 if something fails.
*/
static
inline
int
bq27x00_battery_read_lmd
(
struct
bq27x00_device_info
*
di
)
{
return
bq27x00_battery_read_charge
(
di
,
BQ27x00_REG_LMD
);
}
/*
* Return the battery Initial last measured discharge in µAh
* Or < 0 if something fails.
*/
static
int
bq27x00_battery_read_ilmd
(
struct
bq27x00_device_info
*
di
)
{
int
ilmd
;
if
(
di
->
chip
==
BQ27500
)
ilmd
=
bq27x00_read
(
di
,
BQ27500_REG_DCAP
,
false
);
else
ilmd
=
bq27x00_read
(
di
,
BQ27000_REG_ILMD
,
true
);
if
(
ilmd
<
0
)
{
dev_err
(
di
->
dev
,
"error reading initial last measured discharge
\n
"
);
return
ilmd
;
}
return
volt
*
1000
;
if
(
di
->
chip
==
BQ27500
)
ilmd
*=
1000
;
else
ilmd
=
ilmd
*
256
*
3570
/
BQ27000_RS
;
return
ilmd
;
}
/*
* Return the battery average current
* Note that current can be negative signed as well
* Or 0 if something fails.
* Return the battery Cycle count total
* Or < 0 if something fails.
*/
static
int
bq27x00_battery_
curren
t
(
struct
bq27x00_device_info
*
di
)
static
int
bq27x00_battery_
read_cyc
t
(
struct
bq27x00_device_info
*
di
)
{
int
ret
;
int
curr
=
0
;
int
flags
=
0
;
int
cyct
;
ret
=
bq27x00_read
(
BQ27x00_REG_AI
,
&
curr
,
0
,
di
);
if
(
ret
)
{
dev_err
(
di
->
dev
,
"error reading current
\n
"
);
return
0
;
cyct
=
bq27x00_read
(
di
,
BQ27x00_REG_CYCT
,
false
);
if
(
cyct
<
0
)
dev_err
(
di
->
dev
,
"error reading cycle count total
\n
"
);
return
cyct
;
}
/*
* Read a time register.
* Return < 0 if something fails.
*/
static
int
bq27x00_battery_read_time
(
struct
bq27x00_device_info
*
di
,
u8
reg
)
{
int
tval
;
tval
=
bq27x00_read
(
di
,
reg
,
false
);
if
(
tval
<
0
)
{
dev_err
(
di
->
dev
,
"error reading register %02x: %d
\n
"
,
reg
,
tval
);
return
tval
;
}
if
(
di
->
chip
==
BQ27500
)
{
/* bq27500 returns signed value */
curr
=
(
int
)(
s16
)
curr
;
}
else
{
ret
=
bq27x00_read
(
BQ27x00_REG_FLAGS
,
&
flags
,
0
,
di
);
if
(
ret
<
0
)
{
dev_err
(
di
->
dev
,
"error reading flags
\n
"
);
return
0
;
}
if
(
flags
&
BQ27000_FLAG_CHGS
)
{
dev_dbg
(
di
->
dev
,
"negative current!
\n
"
);
curr
=
-
curr
;
}
if
(
tval
==
65535
)
return
-
ENODATA
;
return
tval
*
60
;
}
static
void
bq27x00_update
(
struct
bq27x00_device_info
*
di
)
{
struct
bq27x00_reg_cache
cache
=
{
0
,
};
bool
is_bq27500
=
di
->
chip
==
BQ27500
;
cache
.
flags
=
bq27x00_read
(
di
,
BQ27x00_REG_FLAGS
,
is_bq27500
);
if
(
cache
.
flags
>=
0
)
{
cache
.
capacity
=
bq27x00_battery_read_rsoc
(
di
);
cache
.
temperature
=
bq27x00_read
(
di
,
BQ27x00_REG_TEMP
,
false
);
cache
.
time_to_empty
=
bq27x00_battery_read_time
(
di
,
BQ27x00_REG_TTE
);
cache
.
time_to_empty_avg
=
bq27x00_battery_read_time
(
di
,
BQ27x00_REG_TTECP
);
cache
.
time_to_full
=
bq27x00_battery_read_time
(
di
,
BQ27x00_REG_TTF
);
cache
.
charge_full
=
bq27x00_battery_read_lmd
(
di
);
cache
.
charge_counter
=
bq27x00_battery_read_cyct
(
di
);
if
(
!
is_bq27500
)
cache
.
current_now
=
bq27x00_read
(
di
,
BQ27x00_REG_AI
,
false
);
/* We only have to read charge design full once */
if
(
di
->
charge_design_full
<=
0
)
di
->
charge_design_full
=
bq27x00_battery_read_ilmd
(
di
);
}
/* Ignore current_now which is a snapshot of the current battery state
* and is likely to be different even between two consecutive reads */
if
(
memcmp
(
&
di
->
cache
,
&
cache
,
sizeof
(
cache
)
-
sizeof
(
int
))
!=
0
)
{
di
->
cache
=
cache
;
power_supply_changed
(
&
di
->
bat
);
}
return
curr
*
1000
;
di
->
last_update
=
jiffies
;
}
static
void
bq27x00_battery_poll
(
struct
work_struct
*
work
)
{
struct
bq27x00_device_info
*
di
=
container_of
(
work
,
struct
bq27x00_device_info
,
work
.
work
);
bq27x00_update
(
di
);
if
(
poll_interval
>
0
)
{
/* The timer does not have to be accurate. */
set_timer_slack
(
&
di
->
work
.
timer
,
poll_interval
*
HZ
/
4
);
schedule_delayed_work
(
&
di
->
work
,
poll_interval
*
HZ
);
}
}
/*
* Return the battery
Relative State-of-Charge
* Return the battery
temperature in tenths of degree Celsius
* Or < 0 if something fails.
*/
static
int
bq27x00_battery_rsoc
(
struct
bq27x00_device_info
*
di
)
static
int
bq27x00_battery_temperature
(
struct
bq27x00_device_info
*
di
,
union
power_supply_propval
*
val
)
{
i
nt
ret
;
int
rsoc
=
0
;
i
f
(
di
->
cache
.
temperature
<
0
)
return
di
->
cache
.
temperature
;
if
(
di
->
chip
==
BQ27500
)
ret
=
bq27x00_read
(
BQ27500_REG_SOC
,
&
rsoc
,
0
,
di
)
;
val
->
intval
=
di
->
cache
.
temperature
-
2731
;
else
ret
=
bq27x00_read
(
BQ27000_REG_RSOC
,
&
rsoc
,
1
,
di
);
if
(
ret
)
{
dev_err
(
di
->
dev
,
"error reading relative State-of-Charge
\n
"
);
return
ret
;
val
->
intval
=
((
di
->
cache
.
temperature
*
5
)
-
5463
)
/
2
;
return
0
;
}
/*
* Return the battery average current in µA
* Note that current can be negative signed as well
* Or 0 if something fails.
*/
static
int
bq27x00_battery_current
(
struct
bq27x00_device_info
*
di
,
union
power_supply_propval
*
val
)
{
int
curr
;
if
(
di
->
chip
==
BQ27500
)
curr
=
bq27x00_read
(
di
,
BQ27x00_REG_AI
,
false
);
else
curr
=
di
->
cache
.
current_now
;
if
(
curr
<
0
)
return
curr
;
if
(
di
->
chip
==
BQ27500
)
{
/* bq27500 returns signed value */
val
->
intval
=
(
int
)((
s16
)
curr
)
*
1000
;
}
else
{
if
(
di
->
cache
.
flags
&
BQ27000_FLAG_CHGS
)
{
dev_dbg
(
di
->
dev
,
"negative current!
\n
"
);
curr
=
-
curr
;
}
val
->
intval
=
curr
*
3570
/
BQ27000_RS
;
}
return
rsoc
;
return
0
;
}
static
int
bq27x00_battery_status
(
struct
bq27x00_device_info
*
di
,
union
power_supply_propval
*
val
)
union
power_supply_propval
*
val
)
{
int
flags
=
0
;
int
status
;
int
ret
;
ret
=
bq27x00_read
(
BQ27x00_REG_FLAGS
,
&
flags
,
0
,
di
);
if
(
ret
<
0
)
{
dev_err
(
di
->
dev
,
"error reading flags
\n
"
);
return
ret
;
}
if
(
di
->
chip
==
BQ27500
)
{
if
(
flags
&
BQ27500_FLAG_FC
)
if
(
di
->
cache
.
flags
&
BQ27500_FLAG_FC
)
status
=
POWER_SUPPLY_STATUS_FULL
;
else
if
(
flags
&
BQ27500_FLAG_DSC
)
else
if
(
di
->
cache
.
flags
&
BQ27500_FLAG_DSC
)
status
=
POWER_SUPPLY_STATUS_DISCHARGING
;
else
status
=
POWER_SUPPLY_STATUS_CHARGING
;
}
else
{
if
(
flags
&
BQ27000_FLAG_CHGS
)
if
(
di
->
cache
.
flags
&
BQ27000_FLAG_FC
)
status
=
POWER_SUPPLY_STATUS_FULL
;
else
if
(
di
->
cache
.
flags
&
BQ27000_FLAG_CHGS
)
status
=
POWER_SUPPLY_STATUS_CHARGING
;
else
if
(
power_supply_am_i_supplied
(
&
di
->
bat
))
status
=
POWER_SUPPLY_STATUS_NOT_CHARGING
;
else
status
=
POWER_SUPPLY_STATUS_DISCHARGING
;
}
val
->
intval
=
status
;
return
0
;
}
/*
* Re
ad a time register.
*
Return
< 0 if something fails.
* Re
turn the battery Voltage in milivolts
*
Or
< 0 if something fails.
*/
static
int
bq27x00_battery_
time
(
struct
bq27x00_device_info
*
di
,
int
reg
,
union
power_supply_propval
*
val
)
static
int
bq27x00_battery_
voltage
(
struct
bq27x00_device_info
*
di
,
union
power_supply_propval
*
val
)
{
int
tval
=
0
;
int
ret
;
int
volt
;
ret
=
bq27x00_read
(
reg
,
&
tval
,
0
,
di
);
if
(
ret
)
{
dev_err
(
di
->
dev
,
"error reading register %02x
\n
"
,
reg
);
return
ret
;
volt
=
bq27x00_read
(
di
,
BQ27x00_REG_VOLT
,
false
);
if
(
volt
<
0
)
return
volt
;
val
->
intval
=
volt
*
1000
;
return
0
;
}
/*
* Return the battery Available energy in µWh
* Or < 0 if something fails.
*/
static
int
bq27x00_battery_energy
(
struct
bq27x00_device_info
*
di
,
union
power_supply_propval
*
val
)
{
int
ae
;
ae
=
bq27x00_read
(
di
,
BQ27x00_REG_AE
,
false
);
if
(
ae
<
0
)
{
dev_err
(
di
->
dev
,
"error reading available energy
\n
"
);
return
ae
;
}
if
(
tval
==
65535
)
return
-
ENODATA
;
if
(
di
->
chip
==
BQ27500
)
ae
*=
1000
;
else
ae
=
ae
*
29200
/
BQ27000_RS
;
val
->
intval
=
ae
;
return
0
;
}
static
int
bq27x00_simple_value
(
int
value
,
union
power_supply_propval
*
val
)
{
if
(
value
<
0
)
return
value
;
val
->
intval
=
value
;
val
->
intval
=
tval
*
60
;
return
0
;
}
...
...
@@ -249,33 +446,61 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
int
ret
=
0
;
struct
bq27x00_device_info
*
di
=
to_bq27x00_device_info
(
psy
);
mutex_lock
(
&
di
->
lock
);
if
(
time_is_before_jiffies
(
di
->
last_update
+
5
*
HZ
))
{
cancel_delayed_work_sync
(
&
di
->
work
);
bq27x00_battery_poll
(
&
di
->
work
.
work
);
}
mutex_unlock
(
&
di
->
lock
);
if
(
psp
!=
POWER_SUPPLY_PROP_PRESENT
&&
di
->
cache
.
flags
<
0
)
return
-
ENODEV
;
switch
(
psp
)
{
case
POWER_SUPPLY_PROP_STATUS
:
ret
=
bq27x00_battery_status
(
di
,
val
);
break
;
case
POWER_SUPPLY_PROP_VOLTAGE_NOW
:
ret
=
bq27x00_battery_voltage
(
di
,
val
);
break
;
case
POWER_SUPPLY_PROP_PRESENT
:
val
->
intval
=
bq27x00_battery_voltage
(
di
);
if
(
psp
==
POWER_SUPPLY_PROP_PRESENT
)
val
->
intval
=
val
->
intval
<=
0
?
0
:
1
;
val
->
intval
=
di
->
cache
.
flags
<
0
?
0
:
1
;
break
;
case
POWER_SUPPLY_PROP_CURRENT_NOW
:
val
->
intval
=
bq27x00_battery_current
(
di
);
ret
=
bq27x00_battery_current
(
di
,
val
);
break
;
case
POWER_SUPPLY_PROP_CAPACITY
:
val
->
intval
=
bq27x00_battery_rsoc
(
di
);
ret
=
bq27x00_simple_value
(
di
->
cache
.
capacity
,
val
);
break
;
case
POWER_SUPPLY_PROP_TEMP
:
val
->
intval
=
bq27x00_battery_temperature
(
di
);
ret
=
bq27x00_battery_temperature
(
di
,
val
);
break
;
case
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW
:
ret
=
bq27x00_
battery_time
(
di
,
BQ27x00_REG_TTE
,
val
);
ret
=
bq27x00_
simple_value
(
di
->
cache
.
time_to_empty
,
val
);
break
;
case
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG
:
ret
=
bq27x00_
battery_time
(
di
,
BQ27x00_REG_TTECP
,
val
);
ret
=
bq27x00_
simple_value
(
di
->
cache
.
time_to_empty_avg
,
val
);
break
;
case
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW
:
ret
=
bq27x00_battery_time
(
di
,
BQ27x00_REG_TTF
,
val
);
ret
=
bq27x00_simple_value
(
di
->
cache
.
time_to_full
,
val
);
break
;
case
POWER_SUPPLY_PROP_TECHNOLOGY
:
val
->
intval
=
POWER_SUPPLY_TECHNOLOGY_LION
;
break
;
case
POWER_SUPPLY_PROP_CHARGE_NOW
:
ret
=
bq27x00_simple_value
(
bq27x00_battery_read_nac
(
di
),
val
);
break
;
case
POWER_SUPPLY_PROP_CHARGE_FULL
:
ret
=
bq27x00_simple_value
(
di
->
cache
.
charge_full
,
val
);
break
;
case
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
ret
=
bq27x00_simple_value
(
di
->
charge_design_full
,
val
);
break
;
case
POWER_SUPPLY_PROP_CHARGE_COUNTER
:
ret
=
bq27x00_simple_value
(
di
->
cache
.
charge_counter
,
val
);
break
;
case
POWER_SUPPLY_PROP_ENERGY_NOW
:
ret
=
bq27x00_battery_energy
(
di
,
val
);
break
;
default:
return
-
EINVAL
;
...
...
@@ -284,56 +509,91 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
return
ret
;
}
static
void
bq27x00_
powersupply_init
(
struct
bq27x00_device_info
*
di
)
static
void
bq27x00_
external_power_changed
(
struct
power_supply
*
psy
)
{
struct
bq27x00_device_info
*
di
=
to_bq27x00_device_info
(
psy
);
cancel_delayed_work_sync
(
&
di
->
work
);
schedule_delayed_work
(
&
di
->
work
,
0
);
}
static
int
bq27x00_powersupply_init
(
struct
bq27x00_device_info
*
di
)
{
int
ret
;
di
->
bat
.
type
=
POWER_SUPPLY_TYPE_BATTERY
;
di
->
bat
.
properties
=
bq27x00_battery_props
;
di
->
bat
.
num_properties
=
ARRAY_SIZE
(
bq27x00_battery_props
);
di
->
bat
.
get_property
=
bq27x00_battery_get_property
;
di
->
bat
.
external_power_changed
=
NULL
;
di
->
bat
.
external_power_changed
=
bq27x00_external_power_changed
;
INIT_DELAYED_WORK
(
&
di
->
work
,
bq27x00_battery_poll
);
mutex_init
(
&
di
->
lock
);
ret
=
power_supply_register
(
di
->
dev
,
&
di
->
bat
);
if
(
ret
)
{
dev_err
(
di
->
dev
,
"failed to register battery: %d
\n
"
,
ret
);
return
ret
;
}
dev_info
(
di
->
dev
,
"support ver. %s enabled
\n
"
,
DRIVER_VERSION
);
bq27x00_update
(
di
);
return
0
;
}
/*
* i2c specific code
static
void
bq27x00_powersupply_unregister
(
struct
bq27x00_device_info
*
di
)
{
cancel_delayed_work_sync
(
&
di
->
work
);
power_supply_unregister
(
&
di
->
bat
);
mutex_destroy
(
&
di
->
lock
);
}
/* i2c specific code */
#ifdef CONFIG_BATTERY_BQ27X00_I2C
/* If the system has several batteries we need a different name for each
* of them...
*/
static
DEFINE_IDR
(
battery_id
);
static
DEFINE_MUTEX
(
battery_mutex
);
static
int
bq27x00_read_i2c
(
u8
reg
,
int
*
rt_value
,
int
b_single
,
struct
bq27x00_device_info
*
di
)
static
int
bq27x00_read_i2c
(
struct
bq27x00_device_info
*
di
,
u8
reg
,
bool
single
)
{
struct
i2c_client
*
client
=
di
->
client
;
struct
i2c_msg
msg
[
1
];
struct
i2c_client
*
client
=
to_i2c_client
(
di
->
dev
)
;
struct
i2c_msg
msg
[
2
];
unsigned
char
data
[
2
];
int
err
;
int
ret
;
if
(
!
client
->
adapter
)
return
-
ENODEV
;
msg
->
addr
=
client
->
addr
;
msg
->
flags
=
0
;
msg
->
len
=
1
;
msg
->
buf
=
data
;
data
[
0
]
=
reg
;
err
=
i2c_transfer
(
client
->
adapter
,
msg
,
1
);
msg
[
0
].
addr
=
client
->
addr
;
msg
[
0
].
flags
=
0
;
msg
[
0
].
buf
=
&
reg
;
msg
[
0
].
len
=
sizeof
(
reg
);
msg
[
1
].
addr
=
client
->
addr
;
msg
[
1
].
flags
=
I2C_M_RD
;
msg
[
1
].
buf
=
data
;
if
(
single
)
msg
[
1
].
len
=
1
;
else
msg
[
1
].
len
=
2
;
if
(
err
>=
0
)
{
if
(
!
b_single
)
msg
->
len
=
2
;
else
msg
->
len
=
1
;
ret
=
i2c_transfer
(
client
->
adapter
,
msg
,
ARRAY_SIZE
(
msg
));
if
(
ret
<
0
)
return
ret
;
msg
->
flags
=
I2C_M_RD
;
err
=
i2c_transfer
(
client
->
adapter
,
msg
,
1
);
if
(
err
>=
0
)
{
if
(
!
b_single
)
*
rt_value
=
get_unaligned_le16
(
data
);
else
*
rt_value
=
data
[
0
];
if
(
!
single
)
ret
=
get_unaligned_le16
(
data
);
else
ret
=
data
[
0
];
return
0
;
}
}
return
err
;
return
ret
;
}
static
int
bq27x00_battery_probe
(
struct
i2c_client
*
client
,
...
...
@@ -341,7 +601,6 @@ static int bq27x00_battery_probe(struct i2c_client *client,
{
char
*
name
;
struct
bq27x00_device_info
*
di
;
struct
bq27x00_access_methods
*
bus
;
int
num
;
int
retval
=
0
;
...
...
@@ -368,38 +627,20 @@ static int bq27x00_battery_probe(struct i2c_client *client,
retval
=
-
ENOMEM
;
goto
batt_failed_2
;
}
di
->
id
=
num
;
di
->
dev
=
&
client
->
dev
;
di
->
chip
=
id
->
driver_data
;
di
->
bat
.
name
=
name
;
di
->
bus
.
read
=
&
bq27x00_read_i2c
;
bus
=
kzalloc
(
sizeof
(
*
bus
),
GFP_KERNEL
);
if
(
!
bus
)
{
dev_err
(
&
client
->
dev
,
"failed to allocate access method "
"data
\n
"
);
retval
=
-
ENOMEM
;
if
(
bq27x00_powersupply_init
(
di
))
goto
batt_failed_3
;
}
i2c_set_clientdata
(
client
,
di
);
di
->
dev
=
&
client
->
dev
;
di
->
bat
.
name
=
name
;
bus
->
read
=
&
bq27x00_read_i2c
;
di
->
bus
=
bus
;
di
->
client
=
client
;
bq27x00_powersupply_init
(
di
);
retval
=
power_supply_register
(
&
client
->
dev
,
&
di
->
bat
);
if
(
retval
)
{
dev_err
(
&
client
->
dev
,
"failed to register battery
\n
"
);
goto
batt_failed_4
;
}
dev_info
(
&
client
->
dev
,
"support ver. %s enabled
\n
"
,
DRIVER_VERSION
);
return
0
;
batt_failed_4:
kfree
(
bus
);
batt_failed_3:
kfree
(
di
);
batt_failed_2:
...
...
@@ -416,9 +657,8 @@ static int bq27x00_battery_remove(struct i2c_client *client)
{
struct
bq27x00_device_info
*
di
=
i2c_get_clientdata
(
client
);
power_supply_unregister
(
&
di
->
bat
);
bq27x00_powersupply_unregister
(
di
);
kfree
(
di
->
bus
);
kfree
(
di
->
bat
.
name
);
mutex_lock
(
&
battery_mutex
);
...
...
@@ -430,15 +670,12 @@ static int bq27x00_battery_remove(struct i2c_client *client)
return
0
;
}
/*
* Module stuff
*/
static
const
struct
i2c_device_id
bq27x00_id
[]
=
{
{
"bq27200"
,
BQ27000
},
/* bq27200 is same as bq27000, but with i2c */
{
"bq27500"
,
BQ27500
},
{},
};
MODULE_DEVICE_TABLE
(
i2c
,
bq27x00_id
);
static
struct
i2c_driver
bq27x00_battery_driver
=
{
.
driver
=
{
...
...
@@ -449,13 +686,164 @@ static struct i2c_driver bq27x00_battery_driver = {
.
id_table
=
bq27x00_id
,
};
static
inline
int
bq27x00_battery_i2c_init
(
void
)
{
int
ret
=
i2c_add_driver
(
&
bq27x00_battery_driver
);
if
(
ret
)
printk
(
KERN_ERR
"Unable to register BQ27x00 i2c driver
\n
"
);
return
ret
;
}
static
inline
void
bq27x00_battery_i2c_exit
(
void
)
{
i2c_del_driver
(
&
bq27x00_battery_driver
);
}
#else
static
inline
int
bq27x00_battery_i2c_init
(
void
)
{
return
0
;
}
static
inline
void
bq27x00_battery_i2c_exit
(
void
)
{};
#endif
/* platform specific code */
#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM
static
int
bq27000_read_platform
(
struct
bq27x00_device_info
*
di
,
u8
reg
,
bool
single
)
{
struct
device
*
dev
=
di
->
dev
;
struct
bq27000_platform_data
*
pdata
=
dev
->
platform_data
;
unsigned
int
timeout
=
3
;
int
upper
,
lower
;
int
temp
;
if
(
!
single
)
{
/* Make sure the value has not changed in between reading the
* lower and the upper part */
upper
=
pdata
->
read
(
dev
,
reg
+
1
);
do
{
temp
=
upper
;
if
(
upper
<
0
)
return
upper
;
lower
=
pdata
->
read
(
dev
,
reg
);
if
(
lower
<
0
)
return
lower
;
upper
=
pdata
->
read
(
dev
,
reg
+
1
);
}
while
(
temp
!=
upper
&&
--
timeout
);
if
(
timeout
==
0
)
return
-
EIO
;
return
(
upper
<<
8
)
|
lower
;
}
return
pdata
->
read
(
dev
,
reg
);
}
static
int
__devinit
bq27000_battery_probe
(
struct
platform_device
*
pdev
)
{
struct
bq27x00_device_info
*
di
;
struct
bq27000_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
int
ret
;
if
(
!
pdata
)
{
dev_err
(
&
pdev
->
dev
,
"no platform_data supplied
\n
"
);
return
-
EINVAL
;
}
if
(
!
pdata
->
read
)
{
dev_err
(
&
pdev
->
dev
,
"no hdq read callback supplied
\n
"
);
return
-
EINVAL
;
}
di
=
kzalloc
(
sizeof
(
*
di
),
GFP_KERNEL
);
if
(
!
di
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate device info data
\n
"
);
return
-
ENOMEM
;
}
platform_set_drvdata
(
pdev
,
di
);
di
->
dev
=
&
pdev
->
dev
;
di
->
chip
=
BQ27000
;
di
->
bat
.
name
=
pdata
->
name
?:
dev_name
(
&
pdev
->
dev
);
di
->
bus
.
read
=
&
bq27000_read_platform
;
ret
=
bq27x00_powersupply_init
(
di
);
if
(
ret
)
goto
err_free
;
return
0
;
err_free:
platform_set_drvdata
(
pdev
,
NULL
);
kfree
(
di
);
return
ret
;
}
static
int
__devexit
bq27000_battery_remove
(
struct
platform_device
*
pdev
)
{
struct
bq27x00_device_info
*
di
=
platform_get_drvdata
(
pdev
);
bq27x00_powersupply_unregister
(
di
);
platform_set_drvdata
(
pdev
,
NULL
);
kfree
(
di
);
return
0
;
}
static
struct
platform_driver
bq27000_battery_driver
=
{
.
probe
=
bq27000_battery_probe
,
.
remove
=
__devexit_p
(
bq27000_battery_remove
),
.
driver
=
{
.
name
=
"bq27000-battery"
,
.
owner
=
THIS_MODULE
,
},
};
static
inline
int
bq27x00_battery_platform_init
(
void
)
{
int
ret
=
platform_driver_register
(
&
bq27000_battery_driver
);
if
(
ret
)
printk
(
KERN_ERR
"Unable to register BQ27000 platform driver
\n
"
);
return
ret
;
}
static
inline
void
bq27x00_battery_platform_exit
(
void
)
{
platform_driver_unregister
(
&
bq27000_battery_driver
);
}
#else
static
inline
int
bq27x00_battery_platform_init
(
void
)
{
return
0
;
}
static
inline
void
bq27x00_battery_platform_exit
(
void
)
{};
#endif
/*
* Module stuff
*/
static
int
__init
bq27x00_battery_init
(
void
)
{
int
ret
;
ret
=
i2c_add_driver
(
&
bq27x00_battery_driver
);
ret
=
bq27x00_battery_i2c_init
(
);
if
(
ret
)
printk
(
KERN_ERR
"Unable to register BQ27x00 driver
\n
"
);
return
ret
;
ret
=
bq27x00_battery_platform_init
();
if
(
ret
)
bq27x00_battery_i2c_exit
();
return
ret
;
}
...
...
@@ -463,7 +851,8 @@ module_init(bq27x00_battery_init);
static
void
__exit
bq27x00_battery_exit
(
void
)
{
i2c_del_driver
(
&
bq27x00_battery_driver
);
bq27x00_battery_platform_exit
();
bq27x00_battery_i2c_exit
();
}
module_exit
(
bq27x00_battery_exit
);
...
...
drivers/power/power_supply_core.c
浏览文件 @
b5db7cde
...
...
@@ -171,6 +171,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
dev_set_drvdata
(
dev
,
psy
);
psy
->
dev
=
dev
;
INIT_WORK
(
&
psy
->
changed_work
,
power_supply_changed_work
);
rc
=
kobject_set_name
(
&
dev
->
kobj
,
"%s"
,
psy
->
name
);
if
(
rc
)
goto
kobject_set_name_failed
;
...
...
@@ -179,8 +181,6 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
if
(
rc
)
goto
device_add_failed
;
INIT_WORK
(
&
psy
->
changed_work
,
power_supply_changed_work
);
rc
=
power_supply_create_triggers
(
psy
);
if
(
rc
)
goto
create_triggers_failed
;
...
...
drivers/power/power_supply_sysfs.c
浏览文件 @
b5db7cde
...
...
@@ -270,7 +270,7 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
attr
=
&
power_supply_attrs
[
psy
->
properties
[
j
]];
ret
=
power_supply_show_property
(
dev
,
attr
,
prop_buf
);
if
(
ret
==
-
ENODEV
)
{
if
(
ret
==
-
ENODEV
||
ret
==
-
ENODATA
)
{
/* When a battery is absent, we expect -ENODEV. Don't abort;
send the uevent with at least the the PRESENT=0 property */
ret
=
0
;
...
...
include/linux/power/bq27x00_battery.h
0 → 100644
浏览文件 @
b5db7cde
#ifndef __LINUX_BQ27X00_BATTERY_H__
#define __LINUX_BQ27X00_BATTERY_H__
/**
* struct bq27000_plaform_data - Platform data for bq27000 devices
* @name: Name of the battery. If NULL the driver will fallback to "bq27000".
* @read: HDQ read callback.
* This function should provide access to the HDQ bus the battery is
* connected to.
* The first parameter is a pointer to the battery device, the second the
* register to be read. The return value should either be the content of
* the passed register or an error value.
*/
struct
bq27000_platform_data
{
const
char
*
name
;
int
(
*
read
)(
struct
device
*
dev
,
unsigned
int
);
};
#endif
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录