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
Kirill Smelkov
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