Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
5b3b4484
Commit
5b3b4484
authored
Apr 16, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regmap/topic/cache' into regmap-next
parents
b508c80c
5a08d156
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
316 additions
and
110 deletions
+316
-110
drivers/base/regmap/internal.h
drivers/base/regmap/internal.h
+33
-6
drivers/base/regmap/regcache-lzo.c
drivers/base/regmap/regcache-lzo.c
+2
-4
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache-rbtree.c
+46
-54
drivers/base/regmap/regcache.c
drivers/base/regmap/regcache.c
+178
-18
drivers/base/regmap/regmap.c
drivers/base/regmap/regmap.c
+56
-28
include/linux/regmap.h
include/linux/regmap.h
+1
-0
No files found.
drivers/base/regmap/internal.h
View file @
5b3b4484
...
...
@@ -38,7 +38,8 @@ struct regmap_format {
unsigned
int
reg
,
unsigned
int
val
);
void
(
*
format_reg
)(
void
*
buf
,
unsigned
int
reg
,
unsigned
int
shift
);
void
(
*
format_val
)(
void
*
buf
,
unsigned
int
val
,
unsigned
int
shift
);
unsigned
int
(
*
parse_val
)(
void
*
buf
);
unsigned
int
(
*
parse_val
)(
const
void
*
buf
);
void
(
*
parse_inplace
)(
void
*
buf
);
};
struct
regmap_async
{
...
...
@@ -125,6 +126,9 @@ struct regmap {
void
*
cache
;
u32
cache_dirty
;
unsigned
long
*
cache_present
;
unsigned
int
cache_present_nbits
;
struct
reg_default
*
patch
;
int
patch_regs
;
...
...
@@ -187,12 +191,35 @@ int regcache_read(struct regmap *map,
int
regcache_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
value
);
int
regcache_sync
(
struct
regmap
*
map
);
unsigned
int
regcache_get_val
(
const
void
*
base
,
unsigned
int
idx
,
unsigned
int
word_size
);
bool
regcache_set_val
(
void
*
base
,
unsigned
int
idx
,
unsigned
int
val
,
unsigned
int
word_size
);
int
regcache_sync_block
(
struct
regmap
*
map
,
void
*
block
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
);
static
inline
const
void
*
regcache_get_val_addr
(
struct
regmap
*
map
,
const
void
*
base
,
unsigned
int
idx
)
{
return
base
+
(
map
->
cache_word_size
*
idx
);
}
unsigned
int
regcache_get_val
(
struct
regmap
*
map
,
const
void
*
base
,
unsigned
int
idx
);
bool
regcache_set_val
(
struct
regmap
*
map
,
void
*
base
,
unsigned
int
idx
,
unsigned
int
val
);
int
regcache_lookup_reg
(
struct
regmap
*
map
,
unsigned
int
reg
);
int
regcache_set_reg_present
(
struct
regmap
*
map
,
unsigned
int
reg
);
static
inline
bool
regcache_reg_present
(
struct
regmap
*
map
,
unsigned
int
reg
)
{
if
(
!
map
->
cache_present
)
return
true
;
if
(
reg
>
map
->
cache_present_nbits
)
return
false
;
return
map
->
cache_present
[
BIT_WORD
(
reg
)]
&
BIT_MASK
(
reg
);
}
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
,
bool
async
);
void
regmap_async_complete_cb
(
struct
regmap_async
*
async
,
int
ret
);
...
...
drivers/base/regmap/regcache-lzo.c
View file @
5b3b4484
...
...
@@ -260,8 +260,7 @@ static int regcache_lzo_read(struct regmap *map,
ret
=
regcache_lzo_decompress_cache_block
(
map
,
lzo_block
);
if
(
ret
>=
0
)
/* fetch the value from the cache */
*
value
=
regcache_get_val
(
lzo_block
->
dst
,
blkpos
,
map
->
cache_word_size
);
*
value
=
regcache_get_val
(
map
,
lzo_block
->
dst
,
blkpos
);
kfree
(
lzo_block
->
dst
);
/* restore the pointer and length of the compressed block */
...
...
@@ -304,8 +303,7 @@ static int regcache_lzo_write(struct regmap *map,
}
/* write the new value to the cache */
if
(
regcache_set_val
(
lzo_block
->
dst
,
blkpos
,
value
,
map
->
cache_word_size
))
{
if
(
regcache_set_val
(
map
,
lzo_block
->
dst
,
blkpos
,
value
))
{
kfree
(
lzo_block
->
dst
);
goto
out
;
}
...
...
drivers/base/regmap/regcache-rbtree.c
View file @
5b3b4484
...
...
@@ -47,22 +47,21 @@ static inline void regcache_rbtree_get_base_top_reg(
*
top
=
rbnode
->
base_reg
+
((
rbnode
->
blklen
-
1
)
*
map
->
reg_stride
);
}
static
unsigned
int
regcache_rbtree_get_register
(
struct
regcache_rbtree_node
*
rbnode
,
unsigned
int
idx
,
unsigned
int
word_size
)
static
unsigned
int
regcache_rbtree_get_register
(
struct
regmap
*
map
,
struct
regcache_rbtree_node
*
rbnode
,
unsigned
int
idx
)
{
return
regcache_get_val
(
rbnode
->
block
,
idx
,
word_size
);
return
regcache_get_val
(
map
,
rbnode
->
block
,
idx
);
}
static
void
regcache_rbtree_set_register
(
struct
reg
cache_rbtree_node
*
rbnode
,
unsigned
int
idx
,
unsigned
int
val
,
unsigned
int
word_size
)
static
void
regcache_rbtree_set_register
(
struct
reg
map
*
map
,
struct
regcache_rbtree_node
*
rbnode
,
unsigned
int
idx
,
unsigned
int
val
)
{
regcache_set_val
(
rbnode
->
block
,
idx
,
val
,
word_size
);
regcache_set_val
(
map
,
rbnode
->
block
,
idx
,
val
);
}
static
struct
regcache_rbtree_node
*
regcache_rbtree_lookup
(
struct
regmap
*
map
,
unsigned
int
reg
)
unsigned
int
reg
)
{
struct
regcache_rbtree_ctx
*
rbtree_ctx
=
map
->
cache
;
struct
rb_node
*
node
;
...
...
@@ -139,15 +138,21 @@ static int rbtree_show(struct seq_file *s, void *ignored)
struct
regcache_rbtree_node
*
n
;
struct
rb_node
*
node
;
unsigned
int
base
,
top
;
size_t
mem_size
;
int
nodes
=
0
;
int
registers
=
0
;
int
this_registers
,
average
;
map
->
lock
(
map
);
mem_size
=
sizeof
(
*
rbtree_ctx
);
mem_size
+=
BITS_TO_LONGS
(
map
->
cache_present_nbits
)
*
sizeof
(
long
);
for
(
node
=
rb_first
(
&
rbtree_ctx
->
root
);
node
!=
NULL
;
node
=
rb_next
(
node
))
{
n
=
container_of
(
node
,
struct
regcache_rbtree_node
,
node
);
mem_size
+=
sizeof
(
*
n
);
mem_size
+=
(
n
->
blklen
*
map
->
cache_word_size
);
regcache_rbtree_get_base_top_reg
(
map
,
n
,
&
base
,
&
top
);
this_registers
=
((
top
-
base
)
/
map
->
reg_stride
)
+
1
;
...
...
@@ -162,8 +167,8 @@ static int rbtree_show(struct seq_file *s, void *ignored)
else
average
=
0
;
seq_printf
(
s
,
"%d nodes, %d registers, average %d registers
\n
"
,
nodes
,
registers
,
average
);
seq_printf
(
s
,
"%d nodes, %d registers, average %d registers
, used %zu bytes
\n
"
,
nodes
,
registers
,
average
,
mem_size
);
map
->
unlock
(
map
);
...
...
@@ -260,8 +265,9 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode
=
regcache_rbtree_lookup
(
map
,
reg
);
if
(
rbnode
)
{
reg_tmp
=
(
reg
-
rbnode
->
base_reg
)
/
map
->
reg_stride
;
*
value
=
regcache_rbtree_get_register
(
rbnode
,
reg_tmp
,
map
->
cache_word_size
);
if
(
!
regcache_reg_present
(
map
,
reg
))
return
-
ENOENT
;
*
value
=
regcache_rbtree_get_register
(
map
,
rbnode
,
reg_tmp
);
}
else
{
return
-
ENOENT
;
}
...
...
@@ -270,21 +276,23 @@ static int regcache_rbtree_read(struct regmap *map,
}
static
int
regcache_rbtree_insert_to_block
(
struct
regcache_rbtree_node
*
rbnode
,
static
int
regcache_rbtree_insert_to_block
(
struct
regmap
*
map
,
struct
regcache_rbtree_node
*
rbnode
,
unsigned
int
pos
,
unsigned
int
reg
,
unsigned
int
value
,
unsigned
int
word_size
)
unsigned
int
value
)
{
u8
*
blk
;
blk
=
krealloc
(
rbnode
->
block
,
(
rbnode
->
blklen
+
1
)
*
word_size
,
GFP_KERNEL
);
(
rbnode
->
blklen
+
1
)
*
map
->
cache_word_size
,
GFP_KERNEL
);
if
(
!
blk
)
return
-
ENOMEM
;
/* insert the register value in the correct place in the rbnode block */
memmove
(
blk
+
(
pos
+
1
)
*
word_size
,
blk
+
pos
*
word_size
,
(
rbnode
->
blklen
-
pos
)
*
word_size
);
memmove
(
blk
+
(
pos
+
1
)
*
map
->
cache_
word_size
,
blk
+
pos
*
map
->
cache_
word_size
,
(
rbnode
->
blklen
-
pos
)
*
map
->
cache_
word_size
);
/* update the rbnode block, its size and the base register */
rbnode
->
block
=
blk
;
...
...
@@ -292,7 +300,7 @@ static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
if
(
!
pos
)
rbnode
->
base_reg
=
reg
;
regcache_rbtree_set_register
(
rbnode
,
pos
,
value
,
word_siz
e
);
regcache_rbtree_set_register
(
map
,
rbnode
,
pos
,
valu
e
);
return
0
;
}
...
...
@@ -302,25 +310,24 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
struct
regcache_rbtree_ctx
*
rbtree_ctx
;
struct
regcache_rbtree_node
*
rbnode
,
*
rbnode_tmp
;
struct
rb_node
*
node
;
unsigned
int
val
;
unsigned
int
reg_tmp
;
unsigned
int
pos
;
int
i
;
int
ret
;
rbtree_ctx
=
map
->
cache
;
/* update the reg_present bitmap, make space if necessary */
ret
=
regcache_set_reg_present
(
map
,
reg
);
if
(
ret
<
0
)
return
ret
;
/* if we can't locate it in the cached rbnode we'll have
* to traverse the rbtree looking for it.
*/
rbnode
=
regcache_rbtree_lookup
(
map
,
reg
);
if
(
rbnode
)
{
reg_tmp
=
(
reg
-
rbnode
->
base_reg
)
/
map
->
reg_stride
;
val
=
regcache_rbtree_get_register
(
rbnode
,
reg_tmp
,
map
->
cache_word_size
);
if
(
val
==
value
)
return
0
;
regcache_rbtree_set_register
(
rbnode
,
reg_tmp
,
value
,
map
->
cache_word_size
);
regcache_rbtree_set_register
(
map
,
rbnode
,
reg_tmp
,
value
);
}
else
{
/* look for an adjacent register to the one we are about to add */
for
(
node
=
rb_first
(
&
rbtree_ctx
->
root
);
node
;
...
...
@@ -337,9 +344,10 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
pos
=
i
+
1
;
else
pos
=
i
;
ret
=
regcache_rbtree_insert_to_block
(
rbnode_tmp
,
pos
,
reg
,
value
,
map
->
cache_word_size
);
ret
=
regcache_rbtree_insert_to_block
(
map
,
rbnode_tmp
,
pos
,
reg
,
value
);
if
(
ret
)
return
ret
;
rbtree_ctx
->
cached_rbnode
=
rbnode_tmp
;
...
...
@@ -354,7 +362,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
rbnode
=
kzalloc
(
sizeof
*
rbnode
,
GFP_KERNEL
);
if
(
!
rbnode
)
return
-
ENOMEM
;
rbnode
->
blklen
=
1
;
rbnode
->
blklen
=
sizeof
(
*
rbnode
)
;
rbnode
->
base_reg
=
reg
;
rbnode
->
block
=
kmalloc
(
rbnode
->
blklen
*
map
->
cache_word_size
,
GFP_KERNEL
);
...
...
@@ -362,7 +370,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
kfree
(
rbnode
);
return
-
ENOMEM
;
}
regcache_rbtree_set_register
(
rbnode
,
0
,
value
,
map
->
cache_word_siz
e
);
regcache_rbtree_set_register
(
map
,
rbnode
,
0
,
valu
e
);
regcache_rbtree_insert
(
map
,
&
rbtree_ctx
->
root
,
rbnode
);
rbtree_ctx
->
cached_rbnode
=
rbnode
;
}
...
...
@@ -376,10 +384,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
struct
regcache_rbtree_ctx
*
rbtree_ctx
;
struct
rb_node
*
node
;
struct
regcache_rbtree_node
*
rbnode
;
unsigned
int
regtmp
;
unsigned
int
val
;
int
ret
;
int
i
,
base
,
end
;
int
base
,
end
;
rbtree_ctx
=
map
->
cache
;
for
(
node
=
rb_first
(
&
rbtree_ctx
->
root
);
node
;
node
=
rb_next
(
node
))
{
...
...
@@ -402,27 +408,13 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
else
end
=
rbnode
->
blklen
;
for
(
i
=
base
;
i
<
end
;
i
++
)
{
regtmp
=
rbnode
->
base_reg
+
(
i
*
map
->
reg_stride
);
val
=
regcache_rbtree_get_register
(
rbnode
,
i
,
map
->
cache_word_size
);
/* Is this the hardware default? If so skip. */
ret
=
regcache_lookup_reg
(
map
,
regtmp
);
if
(
ret
>=
0
&&
val
==
map
->
reg_defaults
[
ret
].
def
)
continue
;
map
->
cache_bypass
=
1
;
ret
=
_regmap_write
(
map
,
regtmp
,
val
);
map
->
cache_bypass
=
0
;
if
(
ret
)
return
ret
;
dev_dbg
(
map
->
dev
,
"Synced register %#x, value %#x
\n
"
,
regtmp
,
val
);
}
ret
=
regcache_sync_block
(
map
,
rbnode
->
block
,
rbnode
->
base_reg
,
base
,
end
);
if
(
ret
!=
0
)
return
ret
;
}
return
0
;
return
regmap_async_complete
(
map
)
;
}
struct
regcache_ops
regcache_rbtree_ops
=
{
...
...
drivers/base/regmap/regcache.c
View file @
5b3b4484
...
...
@@ -45,8 +45,8 @@ static int regcache_hw_init(struct regmap *map)
tmp_buf
=
kmalloc
(
map
->
cache_size_raw
,
GFP_KERNEL
);
if
(
!
tmp_buf
)
return
-
EINVAL
;
ret
=
regmap_
bulk
_read
(
map
,
0
,
tmp_buf
,
map
->
num_reg_defaults_raw
);
ret
=
regmap_
raw
_read
(
map
,
0
,
tmp_buf
,
map
->
num_reg_defaults_raw
);
map
->
cache_bypass
=
cache_bypass
;
if
(
ret
<
0
)
{
kfree
(
tmp_buf
);
...
...
@@ -58,8 +58,7 @@ static int regcache_hw_init(struct regmap *map)
/* calculate the size of reg_defaults */
for
(
count
=
0
,
i
=
0
;
i
<
map
->
num_reg_defaults_raw
;
i
++
)
{
val
=
regcache_get_val
(
map
->
reg_defaults_raw
,
i
,
map
->
cache_word_size
);
val
=
regcache_get_val
(
map
,
map
->
reg_defaults_raw
,
i
);
if
(
regmap_volatile
(
map
,
i
*
map
->
reg_stride
))
continue
;
count
++
;
...
...
@@ -75,8 +74,7 @@ static int regcache_hw_init(struct regmap *map)
/* fill the reg_defaults */
map
->
num_reg_defaults
=
count
;
for
(
i
=
0
,
j
=
0
;
i
<
map
->
num_reg_defaults_raw
;
i
++
)
{
val
=
regcache_get_val
(
map
->
reg_defaults_raw
,
i
,
map
->
cache_word_size
);
val
=
regcache_get_val
(
map
,
map
->
reg_defaults_raw
,
i
);
if
(
regmap_volatile
(
map
,
i
*
map
->
reg_stride
))
continue
;
map
->
reg_defaults
[
j
].
reg
=
i
*
map
->
reg_stride
;
...
...
@@ -123,6 +121,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
map
->
reg_defaults_raw
=
config
->
reg_defaults_raw
;
map
->
cache_word_size
=
DIV_ROUND_UP
(
config
->
val_bits
,
8
);
map
->
cache_size_raw
=
map
->
cache_word_size
*
config
->
num_reg_defaults_raw
;
map
->
cache_present
=
NULL
;
map
->
cache_present_nbits
=
0
;
map
->
cache
=
NULL
;
map
->
cache_ops
=
cache_types
[
i
];
...
...
@@ -181,6 +181,7 @@ void regcache_exit(struct regmap *map)
BUG_ON
(
!
map
->
cache_ops
);
kfree
(
map
->
cache_present
);
kfree
(
map
->
reg_defaults
);
if
(
map
->
cache_free
)
kfree
(
map
->
reg_defaults_raw
);
...
...
@@ -417,28 +418,68 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
}
EXPORT_SYMBOL_GPL
(
regcache_cache_bypass
);
bool
regcache_set_val
(
void
*
base
,
unsigned
int
idx
,
unsigned
int
val
,
unsigned
int
word_size
)
int
regcache_set_reg_present
(
struct
regmap
*
map
,
unsigned
int
reg
)
{
switch
(
word_size
)
{
unsigned
long
*
cache_present
;
unsigned
int
cache_present_size
;
unsigned
int
nregs
;
int
i
;
nregs
=
reg
+
1
;
cache_present_size
=
BITS_TO_LONGS
(
nregs
);
cache_present_size
*=
sizeof
(
long
);
if
(
!
map
->
cache_present
)
{
cache_present
=
kmalloc
(
cache_present_size
,
GFP_KERNEL
);
if
(
!
cache_present
)
return
-
ENOMEM
;
bitmap_zero
(
cache_present
,
nregs
);
map
->
cache_present
=
cache_present
;
map
->
cache_present_nbits
=
nregs
;
}
if
(
nregs
>
map
->
cache_present_nbits
)
{
cache_present
=
krealloc
(
map
->
cache_present
,
cache_present_size
,
GFP_KERNEL
);
if
(
!
cache_present
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
nregs
;
i
++
)
if
(
i
>=
map
->
cache_present_nbits
)
clear_bit
(
i
,
cache_present
);
map
->
cache_present
=
cache_present
;
map
->
cache_present_nbits
=
nregs
;
}
set_bit
(
reg
,
map
->
cache_present
);
return
0
;
}
bool
regcache_set_val
(
struct
regmap
*
map
,
void
*
base
,
unsigned
int
idx
,
unsigned
int
val
)
{
if
(
regcache_get_val
(
map
,
base
,
idx
)
==
val
)
return
true
;
/* Use device native format if possible */
if
(
map
->
format
.
format_val
)
{
map
->
format
.
format_val
(
base
+
(
map
->
cache_word_size
*
idx
),
val
,
0
);
return
false
;
}
switch
(
map
->
cache_word_size
)
{
case
1
:
{
u8
*
cache
=
base
;
if
(
cache
[
idx
]
==
val
)
return
true
;
cache
[
idx
]
=
val
;
break
;
}
case
2
:
{
u16
*
cache
=
base
;
if
(
cache
[
idx
]
==
val
)
return
true
;
cache
[
idx
]
=
val
;
break
;
}
case
4
:
{
u32
*
cache
=
base
;
if
(
cache
[
idx
]
==
val
)
return
true
;
cache
[
idx
]
=
val
;
break
;
}
...
...
@@ -448,13 +489,18 @@ bool regcache_set_val(void *base, unsigned int idx,
return
false
;
}
unsigned
int
regcache_get_val
(
const
void
*
base
,
unsigned
int
idx
,
unsigned
int
word_size
)
unsigned
int
regcache_get_val
(
struct
regmap
*
map
,
const
void
*
base
,
unsigned
int
idx
)
{
if
(
!
base
)
return
-
EINVAL
;
switch
(
word_size
)
{
/* Use device native format if possible */
if
(
map
->
format
.
parse_val
)
return
map
->
format
.
parse_val
(
regcache_get_val_addr
(
map
,
base
,
idx
));
switch
(
map
->
cache_word_size
)
{
case
1
:
{
const
u8
*
cache
=
base
;
return
cache
[
idx
];
...
...
@@ -498,3 +544,117 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
else
return
-
ENOENT
;
}
static
int
regcache_sync_block_single
(
struct
regmap
*
map
,
void
*
block
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
)
{
unsigned
int
i
,
regtmp
,
val
;
int
ret
;
for
(
i
=
start
;
i
<
end
;
i
++
)
{
regtmp
=
block_base
+
(
i
*
map
->
reg_stride
);
if
(
!
regcache_reg_present
(
map
,
regtmp
))
continue
;
val
=
regcache_get_val
(
map
,
block
,
i
);
/* Is this the hardware default? If so skip. */
ret
=
regcache_lookup_reg
(
map
,
regtmp
);
if
(
ret
>=
0
&&
val
==
map
->
reg_defaults
[
ret
].
def
)
continue
;
map
->
cache_bypass
=
1
;
ret
=
_regmap_write
(
map
,
regtmp
,
val
);
map
->
cache_bypass
=
0
;
if
(
ret
!=
0
)
return
ret
;
dev_dbg
(
map
->
dev
,
"Synced register %#x, value %#x
\n
"
,
regtmp
,
val
);
}
return
0
;
}
static
int
regcache_sync_block_raw_flush
(
struct
regmap
*
map
,
const
void
**
data
,
unsigned
int
base
,
unsigned
int
cur
)
{
size_t
val_bytes
=
map
->
format
.
val_bytes
;
int
ret
,
count
;
if
(
*
data
==
NULL
)
return
0
;
count
=
cur
-
base
;
dev_dbg
(
map
->
dev
,
"Writing %zu bytes for %d registers from 0x%x-0x%x
\n
"
,
count
*
val_bytes
,
count
,
base
,
cur
-
1
);
map
->
cache_bypass
=
1
;
ret
=
_regmap_raw_write
(
map
,
base
,
*
data
,
count
*
val_bytes
,
false
);
map
->
cache_bypass
=
0
;
*
data
=
NULL
;
return
ret
;
}
static
int
regcache_sync_block_raw
(
struct
regmap
*
map
,
void
*
block
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
)
{
unsigned
int
i
,
val
;
unsigned
int
regtmp
=
0
;
unsigned
int
base
=
0
;
const
void
*
data
=
NULL
;
int
ret
;
for
(
i
=
start
;
i
<
end
;
i
++
)
{
regtmp
=
block_base
+
(
i
*
map
->
reg_stride
);
if
(
!
regcache_reg_present
(
map
,
regtmp
))
{
ret
=
regcache_sync_block_raw_flush
(
map
,
&
data
,
base
,
regtmp
);
if
(
ret
!=
0
)
return
ret
;
continue
;
}
val
=
regcache_get_val
(
map
,
block
,
i
);
/* Is this the hardware default? If so skip. */
ret
=
regcache_lookup_reg
(
map
,
regtmp
);
if
(
ret
>=
0
&&
val
==
map
->
reg_defaults
[
ret
].
def
)
{
ret
=
regcache_sync_block_raw_flush
(
map
,
&
data
,
base
,
regtmp
);
if
(
ret
!=
0
)
return
ret
;
continue
;
}
if
(
!
data
)
{
data
=
regcache_get_val_addr
(
map
,
block
,
i
);
base
=
regtmp
;
}
}
return
regcache_sync_block_raw_flush
(
map
,
&
data
,
base
,
regtmp
);
}
int
regcache_sync_block
(
struct
regmap
*
map
,
void
*
block
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
)
{
if
(
regmap_can_raw_write
(
map
))
return
regcache_sync_block_raw
(
map
,
block
,
block_base
,
start
,
end
);
else
return
regcache_sync_block_single
(
map
,
block
,
block_base
,
start
,
end
);
}
drivers/base/regmap/regmap.c
View file @
5b3b4484
...
...
@@ -228,30 +228,39 @@ static void regmap_format_32_native(void *buf, unsigned int val,
*
(
u32
*
)
buf
=
val
<<
shift
;
}
static
unsigned
int
regmap_parse_8
(
void
*
buf
)
static
void
regmap_parse_inplace_noop
(
void
*
buf
)
{
u8
*
b
=
buf
;
}
static
unsigned
int
regmap_parse_8
(
const
void
*
buf
)
{
const
u8
*
b
=
buf
;
return
b
[
0
];
}
static
unsigned
int
regmap_parse_16_be
(
void
*
buf
)
static
unsigned
int
regmap_parse_16_be
(
const
void
*
buf
)
{
const
__be16
*
b
=
buf
;
return
be16_to_cpu
(
b
[
0
]);
}
static
void
regmap_parse_16_be_inplace
(
void
*
buf
)
{
__be16
*
b
=
buf
;
b
[
0
]
=
be16_to_cpu
(
b
[
0
]);
return
b
[
0
];
}
static
unsigned
int
regmap_parse_16_native
(
void
*
buf
)
static
unsigned
int
regmap_parse_16_native
(
const
void
*
buf
)
{
return
*
(
u16
*
)
buf
;
}
static
unsigned
int
regmap_parse_24
(
void
*
buf
)
static
unsigned
int
regmap_parse_24
(
const
void
*
buf
)
{
u8
*
b
=
buf
;
const
u8
*
b
=
buf
;
unsigned
int
ret
=
b
[
2
];
ret
|=
((
unsigned
int
)
b
[
1
])
<<
8
;
ret
|=
((
unsigned
int
)
b
[
0
])
<<
16
;
...
...
@@ -259,16 +268,21 @@ static unsigned int regmap_parse_24(void *buf)
return
ret
;
}
static
unsigned
int
regmap_parse_32_be
(
void
*
buf
)
static
unsigned
int
regmap_parse_32_be
(
const
void
*
buf
)
{
const
__be32
*
b
=
buf
;
return
be32_to_cpu
(
b
[
0
]);
}
static
void
regmap_parse_32_be_inplace
(
void
*
buf
)
{
__be32
*
b
=
buf
;
b
[
0
]
=
be32_to_cpu
(
b
[
0
]);
return
b
[
0
];
}
static
unsigned
int
regmap_parse_32_native
(
void
*
buf
)
static
unsigned
int
regmap_parse_32_native
(
const
void
*
buf
)
{
return
*
(
u32
*
)
buf
;
}
...
...
@@ -555,16 +569,21 @@ struct regmap *regmap_init(struct device *dev,
goto
err_map
;
}
if
(
val_endian
==
REGMAP_ENDIAN_NATIVE
)
map
->
format
.
parse_inplace
=
regmap_parse_inplace_noop
;
switch
(
config
->
val_bits
)
{
case
8
:
map
->
format
.
format_val
=
regmap_format_8
;
map
->
format
.
parse_val
=
regmap_parse_8
;
map
->
format
.
parse_inplace
=
regmap_parse_inplace_noop
;
break
;
case
16
:
switch
(
val_endian
)
{
case
REGMAP_ENDIAN_BIG
:
map
->
format
.
format_val
=
regmap_format_16_be
;
map
->
format
.
parse_val
=
regmap_parse_16_be
;
map
->
format
.
parse_inplace
=
regmap_parse_16_be_inplace
;
break
;
case
REGMAP_ENDIAN_NATIVE
:
map
->
format
.
format_val
=
regmap_format_16_native
;
...
...
@@ -585,6 +604,7 @@ struct regmap *regmap_init(struct device *dev,
case
REGMAP_ENDIAN_BIG
:
map
->
format
.
format_val
=
regmap_format_32_be
;
map
->
format
.
parse_val
=
regmap_parse_32_be
;
map
->
format
.
parse_inplace
=
regmap_parse_32_be_inplace
;
break
;
case
REGMAP_ENDIAN_NATIVE
:
map
->
format
.
format_val
=
regmap_format_32_native
;
...
...
@@ -917,8 +937,8 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
return
0
;
}
static
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
,
bool
async
)
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
,
bool
async
)
{
struct
regmap_range_node
*
range
;
unsigned
long
flags
;
...
...
@@ -930,7 +950,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
size_t
len
;
int
i
;
BUG
_ON
(
!
map
->
bus
);
WARN
_ON
(
!
map
->
bus
);
/* Check for unwritable registers before we start */
if
(
map
->
writeable_reg
)
...
...
@@ -943,8 +963,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
unsigned
int
ival
;
int
val_bytes
=
map
->
format
.
val_bytes
;
for
(
i
=
0
;
i
<
val_len
/
val_bytes
;
i
++
)
{
memcpy
(
map
->
work_buf
,
val
+
(
i
*
val_bytes
),
val_bytes
);
ival
=
map
->
format
.
parse_val
(
map
->
work_buf
);
ival
=
map
->
format
.
parse_val
(
val
+
(
i
*
val_bytes
));
ret
=
regcache_write
(
map
,
reg
+
(
i
*
map
->
reg_stride
),
ival
);
if
(
ret
)
{
...
...
@@ -1081,6 +1100,17 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
return
ret
;
}
/**
* regmap_can_raw_write - Test if regmap_raw_write() is supported
*
* @map: Map to check.
*/
bool
regmap_can_raw_write
(
struct
regmap
*
map
)
{
return
map
->
bus
&&
map
->
format
.
format_val
&&
map
->
format
.
format_reg
;
}
EXPORT_SYMBOL_GPL
(
regmap_can_raw_write
);
static
int
_regmap_bus_formatted_write
(
void
*
context
,
unsigned
int
reg
,
unsigned
int
val
)
{
...
...
@@ -1088,7 +1118,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
struct
regmap_range_node
*
range
;
struct
regmap
*
map
=
context
;
BUG
_ON
(
!
map
->
bus
||
!
map
->
format
.
format_write
);
WARN
_ON
(
!
map
->
bus
||
!
map
->
format
.
format_write
);
range
=
_regmap_range_lookup
(
map
,
reg
);
if
(
range
)
{
...
...
@@ -1114,7 +1144,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
{
struct
regmap
*
map
=
context
;
BUG
_ON
(
!
map
->
bus
||
!
map
->
format
.
format_val
);
WARN
_ON
(
!
map
->
bus
||
!
map
->
format
.
format_val
);
map
->
format
.
format_val
(
map
->
work_buf
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
val
,
0
);
...
...
@@ -1204,12 +1234,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{
int
ret
;
if
(
!
map
->
bus
)
if
(
!
regmap_can_raw_write
(
map
)
)
return
-
EINVAL
;
if
(
val_len
%
map
->
format
.
val_bytes
)
return
-
EINVAL
;
if
(
reg
%
map
->
reg_stride
)
return
-
EINVAL
;
map
->
lock
(
map
->
lock_arg
);
...
...
@@ -1244,7 +1272,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if
(
!
map
->
bus
)
return
-
EINVAL
;
if
(
!
map
->
format
.
parse_
val
)
if
(
!
map
->
format
.
parse_
inplace
)
return
-
EINVAL
;
if
(
reg
%
map
->
reg_stride
)
return
-
EINVAL
;
...
...
@@ -1262,7 +1290,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
goto
out
;
}
for
(
i
=
0
;
i
<
val_count
*
val_bytes
;
i
+=
val_bytes
)
map
->
format
.
parse_
val
(
wval
+
i
);
map
->
format
.
parse_
inplace
(
wval
+
i
);
}
/*
* Some devices does not support bulk write, for
...
...
@@ -1340,7 +1368,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
u8
*
u8
=
map
->
work_buf
;
int
ret
;
BUG
_ON
(
!
map
->
bus
);
WARN
_ON
(
!
map
->
bus
);
range
=
_regmap_range_lookup
(
map
,
reg
);
if
(
range
)
{
...
...
@@ -1395,7 +1423,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
int
ret
;
void
*
context
=
_regmap_map_get_context
(
map
);
BUG
_ON
(
!
map
->
reg_read
);
WARN
_ON
(
!
map
->
reg_read
);
if
(
!
map
->
cache_bypass
)
{
ret
=
regcache_read
(
map
,
reg
,
val
);
...
...
@@ -1523,7 +1551,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
if
(
!
map
->
bus
)
return
-
EINVAL
;
if
(
!
map
->
format
.
parse_
val
)
if
(
!
map
->
format
.
parse_
inplace
)
return
-
EINVAL
;
if
(
reg
%
map
->
reg_stride
)
return
-
EINVAL
;
...
...
@@ -1550,7 +1578,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
}
for
(
i
=
0
;
i
<
val_count
*
val_bytes
;
i
+=
val_bytes
)
map
->
format
.
parse_
val
(
val
+
i
);
map
->
format
.
parse_
inplace
(
val
+
i
);
}
else
{
for
(
i
=
0
;
i
<
val_count
;
i
++
)
{
unsigned
int
ival
;
...
...
include/linux/regmap.h
View file @
5b3b4484
...
...
@@ -389,6 +389,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
bool
*
change
);
int
regmap_get_val_bytes
(
struct
regmap
*
map
);
int
regmap_async_complete
(
struct
regmap
*
map
);
bool
regmap_can_raw_write
(
struct
regmap
*
map
);
int
regcache_sync
(
struct
regmap
*
map
);
int
regcache_sync_region
(
struct
regmap
*
map
,
unsigned
int
min
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment