Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
L
linux
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Model registry
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Toby Churchill
linux
Commits
00306aad
Commit
00306aad
authored
6 years ago
by
Sjoerd Simons
Browse files
Options
Downloads
Patches
Plain Diff
WIP
parent
7b6649da
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
drivers/power/supply/bq27xxx_battery.c
+130
-51
130 additions, 51 deletions
drivers/power/supply/bq27xxx_battery.c
with
130 additions
and
51 deletions
drivers/power/supply/bq27xxx_battery.c
+
130
−
51
View file @
00306aad
...
...
@@ -884,6 +884,14 @@ struct bq27xxx_dm_buf {
bool
has_data
,
dirty
;
};
/**
* Struct holding ding a cache of read dm_bufs
*/
#define DM_BUF_CACHE_SIZE 4;
struct
bq27xxx_dm_buf_cache
{
struct
bq27xxx_dm_buf
blocks
[
DM_BUF_CACHE_SIZE
];
}
#define BQ27XXX_DM_BUF(di, i) { \
.class = (di)->dm_regs[i].subclass_id, \
.block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \
...
...
@@ -1121,33 +1129,35 @@ static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
return
ret
;
}
static
void
bq27xxx_battery_update_dm_block
(
struct
bq27xxx_device_info
*
di
,
struct
bq27xxx_dm_buf
*
buf
,
static
int
bq27xxx_battery_update_dm_block
(
struct
bq27xxx_device_info
*
di
,
struct
bq27xxx_dm_buf
_cache
*
cache
,
enum
bq27xxx_dm_reg_id
reg_id
,
unsigned
int
val
)
{
struct
bq27xxx_dm_reg
*
reg
=
&
di
->
dm_regs
[
reg_id
];
const
char
*
str
=
bq27xxx_dm_reg_name
[
reg_id
];
struct
bq27xxx_dm_buf
*
buf
=
bq27xxx_battery_cache_get_dm_buf
(
di
,
cache
,
reg_id
);
u16
*
prev
=
bq27xxx_dm_reg_ptr
(
buf
,
reg
);
if
(
prev
==
NULL
)
{
dev_warn
(
di
->
dev
,
"buffer does not match %s dm spec
\n
"
,
str
);
return
;
return
-
1
;
}
if
(
reg
->
bytes
!=
2
)
{
dev_warn
(
di
->
dev
,
"%s dm spec has unsupported byte size
\n
"
,
str
);
return
;
return
-
1
;
}
if
(
!
buf
->
has_data
)
{
dev_warn
(
di
->
dev
,
"%s buffer has no data
\n
"
,
str
);
return
;
return
-
1
;
}
if
(
be16_to_cpup
(
prev
)
==
val
)
{
dev_info
(
di
->
dev
,
"%s has %u
\n
"
,
str
,
val
);
return
;
return
0
;
}
dev_info
(
di
->
dev
,
"%s had %u
\n
"
,
str
,
be16_to_cpup
(
prev
));
...
...
@@ -1164,15 +1174,77 @@ static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di,
"for flash/NVM data memory"
#endif
"
\n
"
,
str
,
be16_to_cpup
(
prev
),
val
);
return
;
return
0
;
}
dev_info
(
di
->
dev
,
"update %s to %u
\n
"
,
str
,
val
);
*
prev
=
cpu_to_be16
(
val
);
buf
->
dirty
=
true
;
return
1
;
}
static
struct
bq27xxx_dm_buf
*
bq27xxx_battery_cache_get_dm_buf
(
struct
bq27xxx_device_info
*
di
,
struct
bq27xxx_dm_buf_cache
*
cache
,
int
regindex
)
{
u8
class
=
di
->
dm_regs
[
regindex
].
subclass_id
;
u8
block
=
di
->
dm_regs
[
regindex
].
offset
/
BQ27XXX_DM_SZ
,;
int
i
;
struct
bq27xxx_dm_buf
*
buf
;
for
(
i
=
0
;
i
<
DM_BUF_CACHE_SIZE
;
i
++
)
{
buf
=
cache
->
blocks
+
i
;
if
(
buf
->
class
==
class
&&
buf
->
block
==
block
)
{
return
buf
;
}
if
(
buf
->
class
==
0
)
{
/* unallocated */
buf
->
class
=
class
;
buf
->
block
=
block
;
bq27xxx_battery_read_dm_block
(
di
,
buf
);
return
buf
;
}
}
BUG_ON
(
"ran out of cache space"
);
return
NULL
;
}
/*
* Flush cached blocked back to storage if needed; return negative on error,
* number of blocks written back on success
*/
static
int
bq27xxx_dm_buf
*
bq27xxx_battery_cache_flush
(
struct
bq27xxx_device_info
*
di
,
struct
bq27xxx_dm_buf_cache
*
cache
)
{
int
i
;
int
ret
=
0
;
for
(
i
=
0
;
i
<
DM_BUF_CACHE_SIZE
;
i
++
)
{
struct
bq27xxx_dm_buf
*
buf
=
cache
->
blocks
+
i
;
if
(
buf
->
class
==
0
)
break
;
if
(
buf
->
dirty
)
{
int
r
;
r
=
bq27xxx_battery_write_dm_block
(
di
,
buf
);
if
(
r
<
0
)
{
return
r
;
}
ret
++
;
}
}
return
ret
;
}
static
int
bq27xxx_battery_cfgupdate_priv
(
struct
bq27xxx_device_info
*
di
,
bool
active
)
{
const
int
limit
=
100
;
...
...
@@ -1284,13 +1356,13 @@ static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
}
static
int
bq27xxx_battery_repair_bd_block
(
struct
bq27xxx_device_info
*
di
,
struct
bq27xxx_dm_buf
*
bd
)
struct
bq27xxx_dm_buf
_cache
*
cache
)
{
const
char
*
model
=
"bq27532"
;
int
i
;
int
ret
;
int
valid
=
true
;
struct
bq27xxx_dm_buf
cc
=
BQ27XXX_DM_BUF
(
di
,
BQ27XXX_DM_CYCLE_COUNT
)
;
struct
bq27xxx_dm_buf
*
bd
,
*
cc
;
u8
defaults
[]
=
{
0x3
,
0x84
,
/* CC threshold */
0x3
,
0xe8
,
/* Design capacity*/
0x1
,
/* Des Energy Scale */
...
...
@@ -1299,11 +1371,12 @@ static int bq27xxx_battery_repair_bd_block (struct bq27xxx_device_info *di,
'b'
,
'q'
,
'2'
,
'7'
,
'5'
,
'3'
,
'2'
,
'\0'
,
0x0
};
ret
=
bq27xxx_battery_read_dm_block
(
di
,
bd
);
if
(
ret
<
0
)
{
dev_warn
(
di
->
dev
,
"failed to read bd block
\n
"
);
return
ret
;
bd
=
bq27xxx_battery_cache_get_dm_buf
(
di
,
cache
,
BQ27XXX_DM_DESIGN_CAPACITY
)
if
(
bd
==
NULL
)
{
dev_warn
(
di
->
dev
,
"failed to get bd block
\n
"
);
return
-
EINVAL
;
}
for
(
i
=
0
;
model
[
i
]
!=
'\0'
;
i
++
)
{
...
...
@@ -1329,17 +1402,14 @@ static int bq27xxx_battery_repair_bd_block (struct bq27xxx_device_info *di,
}
memcpy
(
bd
->
data
,
defaults
,
ARRAY_SIZE
(
defaults
));
bd
->
dirty
=
true
;
bq27xxx_battery_write_dm_block
(
di
,
bd
);
dev_info
(
di
->
dev
,
"Set cycle count to 0"
);
bq27xxx_battery_read_dm_block
(
di
,
&
cc
);
bq27xxx_battery_update_dm_block
(
di
,
&
cc
,
dev_info
(
di
->
dev
,
"Set cycle count to 0 after bd repair"
);
cc
=
bq27xxx_battery_cache_get_dm_buf
(
di
,
cache
,
BQ27XXX_DM_CYCLE_COUNT
);
bq27xxx_battery_update_dm_block
(
di
,
cc
,
BQ27XXX_DM_CYCLE_COUNT
,
0
);
bq27xxx_battery_write_dm_block
(
di
,
&
cc
);
return
1
;
}
...
...
@@ -1347,53 +1417,62 @@ static int bq27xxx_battery_repair_bd_block (struct bq27xxx_device_info *di,
static
void
bq27xxx_battery_set_config
(
struct
bq27xxx_device_info
*
di
,
struct
power_supply_battery_info
*
info
)
{
struct
bq27xxx_dm_buf
bd
=
BQ27XXX_DM_BUF
(
di
,
BQ27XXX_DM_DESIGN_CAPACITY
);
struct
bq27xxx_dm_buf
bt
=
BQ27XXX_DM_BUF
(
di
,
BQ27XXX_DM_TERMINATE_VOLTAGE
);
struct
bq27xxx_dm_buf_cache
cache
;
bool
updated
;
int
repaired
;
if
(
bq27xxx_battery_unseal
(
di
)
<
0
)
return
;
repaired
=
bq27xxx_battery_repair_bd_block
(
di
,
&
bd
);
repaired
=
bq27xxx_battery_repair_bd_block
(
di
,
&
cache
);
if
(
info
->
charge_full_design_uah
!=
-
EINVAL
&&
info
->
energy_full_design_uwh
!=
-
EINVAL
)
{
struct
bq27xxx_dm_buf
qmax
=
BQ27XXX_DM_BUF
(
di
,
BQ27XXX_DM_QMAX0
)
;
if
(
info
->
charge_full_design_uah
!=
-
EINVAL
)
{
struct
bq27xxx_dm_buf
*
bd
;
int
updated
;
bq27xxx_battery_
read
_dm_b
lock
(
di
,
&
bd
);
bq27xxx_battery_read_dm_block
(
di
,
&
qmax
);
bd
=
bq27xxx_battery_
cache_get
_dm_b
uf
(
di
,
&
cache
,
BQ27XXX_DM_DESIGN_CAPACITY
)
/* assume design energy & capacity are in same block */
bq27xxx_battery_update_dm_block
(
di
,
&
bd
,
updated
=
bq27xxx_battery_update_dm_block
(
di
,
bd
,
BQ27XXX_DM_DESIGN_CAPACITY
,
info
->
charge_full_design_uah
/
1000
);
/* Also reset Qmax 0 */
if
(
updated
)
{
struct
bq27xxx_dm_buf
*
qmax
;
qmax
=
bq27xxx_battery_cache_get_dm_buf
(
di
,
&
cache
,
BQ27XXX_DM_DESIGN_CAPACITY
)
bq27xxx_battery_update_dm_block
(
di
,
&
qmax
,
BQ27XXX_DM_QMAX0
,
info
->
charge_full_design_uah
/
1000
);
bq27xxx_battery_write_dm_block
(
di
,
&
qmax
);
if
(
di
->
dm_regs
[
BQ27XXX_DM_DESIGN_ENERGY
].
subclass_id
!=
INVALID_SUBCLASS_ID
)
}
/* TODO update cycle threshold! to 90 of full design ?*/
/* Reset cycle count ? */
}
if
(
info
->
energy_full_design_uwh
!=
-
EINVAL
&&
di
->
dm_regs
[
BQ27XXX_DM_DESIGN_ENERGY
].
subclass_id
!=
INVALID_SUBCLASS_ID
)
{
struct
bq27xxx_dm_buf
*
be
;
be
=
bq27xxx_battery_cache_get_dm_buf
(
di
,
&
cache
,
BQ27XXX_DM_DESIGN_ENERGY
);
bq27xxx_battery_update_dm_block
(
di
,
&
bd
,
BQ27XXX_DM_DESIGN_ENERGY
,
info
->
energy_full_design_uwh
/
1000
);
}
if
(
info
->
voltage_min_design_uv
!=
-
EINVAL
)
{
bool
same
=
bd
.
class
==
bt
.
class
&&
bd
.
block
==
bt
.
block
;
if
(
!
same
)
bq27xxx_battery_read_dm_block
(
di
,
&
bt
);
bq27xxx_battery_update_dm_block
(
di
,
same
?
&
bd
:
&
bt
,
struct
bq27xxx_dm_buf
*
bt
;
bt
=
bq27xxx_battery_cache_get_dm_buf
(
di
,
&
cache
,
BQ27XXX_DM_TERMINATE_VOLTAGE
);
bq27xxx_battery_update_dm_block
(
di
,
&
bt
,
BQ27XXX_DM_TERMINATE_VOLTAGE
,
info
->
voltage_min_design_uv
/
1000
);
}
updated
=
repaired
||
bd
.
dirty
||
bt
.
dirty
;
bq27xxx_battery_write_dm_block
(
di
,
&
bd
);
bq27xxx_battery_write_dm_block
(
di
,
&
bt
);
updated
=
bq27xxx_battery_cache_flush
(
di
,
&
cache
)
if
(
updated
&&
!
(
di
->
opts
&
BQ27XXX_O_CFGUP
))
{
if
(
updated
>
0
&&
!
(
di
->
opts
&
BQ27XXX_O_CFGUP
))
{
dev_info
(
di
->
dev
,
"Resetting due to update options"
);
bq27xxx_write
(
di
,
BQ27XXX_REG_CTRL
,
BQ27XXX_RESET
,
false
);
BQ27XXX_MSLEEP
(
300
);
/* reset time is not documented */
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment