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
3689cf7f
Commit
3689cf7f
authored
Feb 14, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regmap/topic/async' into regmap-next
parents
3bef9059
95601d65
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
354 additions
and
47 deletions
+354
-47
drivers/base/regmap/internal.h
drivers/base/regmap/internal.h
+18
-0
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap-spi.c
+54
-0
drivers/base/regmap/regmap.c
drivers/base/regmap/regmap.c
+254
-47
include/linux/regmap.h
include/linux/regmap.h
+28
-0
No files found.
drivers/base/regmap/internal.h
View file @
3689cf7f
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
#include <linux/regmap.h>
#include <linux/regmap.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/list.h>
#include <linux/wait.h>
struct
regmap
;
struct
regmap
;
struct
regcache_ops
;
struct
regcache_ops
;
...
@@ -39,6 +40,13 @@ struct regmap_format {
...
@@ -39,6 +40,13 @@ struct regmap_format {
unsigned
int
(
*
parse_val
)(
void
*
buf
);
unsigned
int
(
*
parse_val
)(
void
*
buf
);
};
};
struct
regmap_async
{
struct
list_head
list
;
struct
work_struct
cleanup
;
struct
regmap
*
map
;
void
*
work_buf
;
};
struct
regmap
{
struct
regmap
{
struct
mutex
mutex
;
struct
mutex
mutex
;
spinlock_t
spinlock
;
spinlock_t
spinlock
;
...
@@ -53,6 +61,11 @@ struct regmap {
...
@@ -53,6 +61,11 @@ struct regmap {
void
*
bus_context
;
void
*
bus_context
;
const
char
*
name
;
const
char
*
name
;
spinlock_t
async_lock
;
wait_queue_head_t
async_waitq
;
struct
list_head
async_list
;
int
async_ret
;
#ifdef CONFIG_DEBUG_FS
#ifdef CONFIG_DEBUG_FS
struct
dentry
*
debugfs
;
struct
dentry
*
debugfs
;
const
char
*
debugfs_name
;
const
char
*
debugfs_name
;
...
@@ -74,6 +87,9 @@ struct regmap {
...
@@ -74,6 +87,9 @@ struct regmap {
const
struct
regmap_access_table
*
volatile_table
;
const
struct
regmap_access_table
*
volatile_table
;
const
struct
regmap_access_table
*
precious_table
;
const
struct
regmap_access_table
*
precious_table
;
int
(
*
reg_read
)(
void
*
context
,
unsigned
int
reg
,
unsigned
int
*
val
);
int
(
*
reg_write
)(
void
*
context
,
unsigned
int
reg
,
unsigned
int
val
);
u8
read_flag_mask
;
u8
read_flag_mask
;
u8
write_flag_mask
;
u8
write_flag_mask
;
...
@@ -175,6 +191,8 @@ bool regcache_set_val(void *base, unsigned int idx,
...
@@ -175,6 +191,8 @@ bool regcache_set_val(void *base, unsigned int idx,
unsigned
int
val
,
unsigned
int
word_size
);
unsigned
int
val
,
unsigned
int
word_size
);
int
regcache_lookup_reg
(
struct
regmap
*
map
,
unsigned
int
reg
);
int
regcache_lookup_reg
(
struct
regmap
*
map
,
unsigned
int
reg
);
void
regmap_async_complete_cb
(
struct
regmap_async
*
async
,
int
ret
);
extern
struct
regcache_ops
regcache_rbtree_ops
;
extern
struct
regcache_ops
regcache_rbtree_ops
;
extern
struct
regcache_ops
regcache_lzo_ops
;
extern
struct
regcache_ops
regcache_lzo_ops
;
...
...
drivers/base/regmap/regmap-spi.c
View file @
3689cf7f
...
@@ -15,6 +15,21 @@
...
@@ -15,6 +15,21 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include "internal.h"
struct
regmap_async_spi
{
struct
regmap_async
core
;
struct
spi_message
m
;
struct
spi_transfer
t
[
2
];
};
static
void
regmap_spi_complete
(
void
*
data
)
{
struct
regmap_async_spi
*
async
=
data
;
regmap_async_complete_cb
(
&
async
->
core
,
async
->
m
.
status
);
}
static
int
regmap_spi_write
(
void
*
context
,
const
void
*
data
,
size_t
count
)
static
int
regmap_spi_write
(
void
*
context
,
const
void
*
data
,
size_t
count
)
{
{
struct
device
*
dev
=
context
;
struct
device
*
dev
=
context
;
...
@@ -40,6 +55,43 @@ static int regmap_spi_gather_write(void *context,
...
@@ -40,6 +55,43 @@ static int regmap_spi_gather_write(void *context,
return
spi_sync
(
spi
,
&
m
);
return
spi_sync
(
spi
,
&
m
);
}
}
static
int
regmap_spi_async_write
(
void
*
context
,
const
void
*
reg
,
size_t
reg_len
,
const
void
*
val
,
size_t
val_len
,
struct
regmap_async
*
a
)
{
struct
regmap_async_spi
*
async
=
container_of
(
a
,
struct
regmap_async_spi
,
core
);
struct
device
*
dev
=
context
;
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
async
->
t
[
0
].
tx_buf
=
reg
;
async
->
t
[
0
].
len
=
reg_len
;
async
->
t
[
1
].
tx_buf
=
val
;
async
->
t
[
1
].
len
=
val_len
;
spi_message_init
(
&
async
->
m
);
spi_message_add_tail
(
&
async
->
t
[
0
],
&
async
->
m
);
spi_message_add_tail
(
&
async
->
t
[
1
],
&
async
->
m
);
async
->
m
.
complete
=
regmap_spi_complete
;
async
->
m
.
context
=
async
;
return
spi_async
(
spi
,
&
async
->
m
);
}
static
struct
regmap_async
*
regmap_spi_async_alloc
(
void
)
{
struct
regmap_async_spi
*
async_spi
;
async_spi
=
kzalloc
(
sizeof
(
*
async_spi
),
GFP_KERNEL
);
if
(
!
async_spi
)
return
NULL
;
return
&
async_spi
->
core
;
}
static
int
regmap_spi_read
(
void
*
context
,
static
int
regmap_spi_read
(
void
*
context
,
const
void
*
reg
,
size_t
reg_size
,
const
void
*
reg
,
size_t
reg_size
,
void
*
val
,
size_t
val_size
)
void
*
val
,
size_t
val_size
)
...
@@ -53,6 +105,8 @@ static int regmap_spi_read(void *context,
...
@@ -53,6 +105,8 @@ static int regmap_spi_read(void *context,
static
struct
regmap_bus
regmap_spi
=
{
static
struct
regmap_bus
regmap_spi
=
{
.
write
=
regmap_spi_write
,
.
write
=
regmap_spi_write
,
.
gather_write
=
regmap_spi_gather_write
,
.
gather_write
=
regmap_spi_gather_write
,
.
async_write
=
regmap_spi_async_write
,
.
async_alloc
=
regmap_spi_async_alloc
,
.
read
=
regmap_spi_read
,
.
read
=
regmap_spi_read
,
.
read_flag_mask
=
0x80
,
.
read_flag_mask
=
0x80
,
};
};
...
...
drivers/base/regmap/regmap.c
View file @
3689cf7f
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/rbtree.h>
#include <linux/rbtree.h>
#include <linux/sched.h>
#define CREATE_TRACE_POINTS
#define CREATE_TRACE_POINTS
#include <trace/events/regmap.h>
#include <trace/events/regmap.h>
...
@@ -34,6 +35,22 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
...
@@ -34,6 +35,22 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned
int
mask
,
unsigned
int
val
,
unsigned
int
mask
,
unsigned
int
val
,
bool
*
change
);
bool
*
change
);
static
int
_regmap_bus_read
(
void
*
context
,
unsigned
int
reg
,
unsigned
int
*
val
);
static
int
_regmap_bus_formatted_write
(
void
*
context
,
unsigned
int
reg
,
unsigned
int
val
);
static
int
_regmap_bus_raw_write
(
void
*
context
,
unsigned
int
reg
,
unsigned
int
val
);
static
void
async_cleanup
(
struct
work_struct
*
work
)
{
struct
regmap_async
*
async
=
container_of
(
work
,
struct
regmap_async
,
cleanup
);
kfree
(
async
->
work_buf
);
kfree
(
async
);
}
bool
regmap_reg_in_ranges
(
unsigned
int
reg
,
bool
regmap_reg_in_ranges
(
unsigned
int
reg
,
const
struct
regmap_range
*
ranges
,
const
struct
regmap_range
*
ranges
,
unsigned
int
nranges
)
unsigned
int
nranges
)
...
@@ -423,6 +440,10 @@ struct regmap *regmap_init(struct device *dev,
...
@@ -423,6 +440,10 @@ struct regmap *regmap_init(struct device *dev,
map
->
cache_type
=
config
->
cache_type
;
map
->
cache_type
=
config
->
cache_type
;
map
->
name
=
config
->
name
;
map
->
name
=
config
->
name
;
spin_lock_init
(
&
map
->
async_lock
);
INIT_LIST_HEAD
(
&
map
->
async_list
);
init_waitqueue_head
(
&
map
->
async_waitq
);
if
(
config
->
read_flag_mask
||
config
->
write_flag_mask
)
{
if
(
config
->
read_flag_mask
||
config
->
write_flag_mask
)
{
map
->
read_flag_mask
=
config
->
read_flag_mask
;
map
->
read_flag_mask
=
config
->
read_flag_mask
;
map
->
write_flag_mask
=
config
->
write_flag_mask
;
map
->
write_flag_mask
=
config
->
write_flag_mask
;
...
@@ -430,6 +451,8 @@ struct regmap *regmap_init(struct device *dev,
...
@@ -430,6 +451,8 @@ struct regmap *regmap_init(struct device *dev,
map
->
read_flag_mask
=
bus
->
read_flag_mask
;
map
->
read_flag_mask
=
bus
->
read_flag_mask
;
}
}
map
->
reg_read
=
_regmap_bus_read
;
reg_endian
=
config
->
reg_format_endian
;
reg_endian
=
config
->
reg_format_endian
;
if
(
reg_endian
==
REGMAP_ENDIAN_DEFAULT
)
if
(
reg_endian
==
REGMAP_ENDIAN_DEFAULT
)
reg_endian
=
bus
->
reg_format_endian_default
;
reg_endian
=
bus
->
reg_format_endian_default
;
...
@@ -581,6 +604,11 @@ struct regmap *regmap_init(struct device *dev,
...
@@ -581,6 +604,11 @@ struct regmap *regmap_init(struct device *dev,
goto
err_map
;
goto
err_map
;
}
}
if
(
map
->
format
.
format_write
)
map
->
reg_write
=
_regmap_bus_formatted_write
;
else
if
(
map
->
format
.
format_val
)
map
->
reg_write
=
_regmap_bus_raw_write
;
map
->
range_tree
=
RB_ROOT
;
map
->
range_tree
=
RB_ROOT
;
for
(
i
=
0
;
i
<
config
->
num_ranges
;
i
++
)
{
for
(
i
=
0
;
i
<
config
->
num_ranges
;
i
++
)
{
const
struct
regmap_range_cfg
*
range_cfg
=
&
config
->
ranges
[
i
];
const
struct
regmap_range_cfg
*
range_cfg
=
&
config
->
ranges
[
i
];
...
@@ -876,10 +904,13 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
...
@@ -876,10 +904,13 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
}
}
static
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
static
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
)
const
void
*
val
,
size_t
val_len
,
bool
async
)
{
{
struct
regmap_range_node
*
range
;
struct
regmap_range_node
*
range
;
unsigned
long
flags
;
u8
*
u8
=
map
->
work_buf
;
u8
*
u8
=
map
->
work_buf
;
void
*
work_val
=
map
->
work_buf
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
;
void
*
buf
;
void
*
buf
;
int
ret
=
-
ENOTSUPP
;
int
ret
=
-
ENOTSUPP
;
size_t
len
;
size_t
len
;
...
@@ -924,7 +955,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
...
@@ -924,7 +955,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
dev_dbg
(
map
->
dev
,
"Writing window %d/%zu
\n
"
,
dev_dbg
(
map
->
dev
,
"Writing window %d/%zu
\n
"
,
win_residue
,
val_len
/
map
->
format
.
val_bytes
);
win_residue
,
val_len
/
map
->
format
.
val_bytes
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
win_residue
*
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
win_residue
*
map
->
format
.
val_bytes
);
map
->
format
.
val_bytes
,
async
);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
return
ret
;
return
ret
;
...
@@ -947,6 +978,50 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
...
@@ -947,6 +978,50 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
u8
[
0
]
|=
map
->
write_flag_mask
;
u8
[
0
]
|=
map
->
write_flag_mask
;
if
(
async
&&
map
->
bus
->
async_write
)
{
struct
regmap_async
*
async
=
map
->
bus
->
async_alloc
();
if
(
!
async
)
return
-
ENOMEM
;
async
->
work_buf
=
kzalloc
(
map
->
format
.
buf_size
,
GFP_KERNEL
|
GFP_DMA
);
if
(
!
async
->
work_buf
)
{
kfree
(
async
);
return
-
ENOMEM
;
}
INIT_WORK
(
&
async
->
cleanup
,
async_cleanup
);
async
->
map
=
map
;
/* If the caller supplied the value we can use it safely. */
memcpy
(
async
->
work_buf
,
map
->
work_buf
,
map
->
format
.
pad_bytes
+
map
->
format
.
reg_bytes
+
map
->
format
.
val_bytes
);
if
(
val
==
work_val
)
val
=
async
->
work_buf
+
map
->
format
.
pad_bytes
+
map
->
format
.
reg_bytes
;
spin_lock_irqsave
(
&
map
->
async_lock
,
flags
);
list_add_tail
(
&
async
->
list
,
&
map
->
async_list
);
spin_unlock_irqrestore
(
&
map
->
async_lock
,
flags
);
ret
=
map
->
bus
->
async_write
(
map
->
bus_context
,
async
->
work_buf
,
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
val
,
val_len
,
async
);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
"Failed to schedule write: %d
\n
"
,
ret
);
spin_lock_irqsave
(
&
map
->
async_lock
,
flags
);
list_del
(
&
async
->
list
);
spin_unlock_irqrestore
(
&
map
->
async_lock
,
flags
);
kfree
(
async
->
work_buf
);
kfree
(
async
);
}
}
trace_regmap_hw_write_start
(
map
->
dev
,
reg
,
trace_regmap_hw_write_start
(
map
->
dev
,
reg
,
val_len
/
map
->
format
.
val_bytes
);
val_len
/
map
->
format
.
val_bytes
);
...
@@ -954,8 +1029,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
...
@@ -954,8 +1029,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
* send the work_buf directly, otherwise try to do a gather
* send the work_buf directly, otherwise try to do a gather
* write.
* write.
*/
*/
if
(
val
==
(
map
->
work_buf
+
map
->
format
.
pad_bytes
+
if
(
val
==
work_val
)
map
->
format
.
reg_bytes
))
ret
=
map
->
bus
->
write
(
map
->
bus_context
,
map
->
work_buf
,
ret
=
map
->
bus
->
write
(
map
->
bus_context
,
map
->
work_buf
,
map
->
format
.
reg_bytes
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
+
map
->
format
.
pad_bytes
+
...
@@ -987,12 +1061,54 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
...
@@ -987,12 +1061,54 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
return
ret
;
return
ret
;
}
}
static
int
_regmap_bus_formatted_write
(
void
*
context
,
unsigned
int
reg
,
unsigned
int
val
)
{
int
ret
;
struct
regmap_range_node
*
range
;
struct
regmap
*
map
=
context
;
BUG_ON
(
!
map
->
format
.
format_write
);
range
=
_regmap_range_lookup
(
map
,
reg
);
if
(
range
)
{
ret
=
_regmap_select_page
(
map
,
&
reg
,
range
,
1
);
if
(
ret
!=
0
)
return
ret
;
}
map
->
format
.
format_write
(
map
,
reg
,
val
);
trace_regmap_hw_write_start
(
map
->
dev
,
reg
,
1
);
ret
=
map
->
bus
->
write
(
map
->
bus_context
,
map
->
work_buf
,
map
->
format
.
buf_size
);
trace_regmap_hw_write_done
(
map
->
dev
,
reg
,
1
);
return
ret
;
}
static
int
_regmap_bus_raw_write
(
void
*
context
,
unsigned
int
reg
,
unsigned
int
val
)
{
struct
regmap
*
map
=
context
;
BUG_ON
(
!
map
->
format
.
format_val
);
map
->
format
.
format_val
(
map
->
work_buf
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
val
,
0
);
return
_regmap_raw_write
(
map
,
reg
,
map
->
work_buf
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
map
->
format
.
val_bytes
,
false
);
}
int
_regmap_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
int
_regmap_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
val
)
unsigned
int
val
)
{
{
struct
regmap_range_node
*
range
;
int
ret
;
int
ret
;
BUG_ON
(
!
map
->
format
.
format_write
&&
!
map
->
format
.
format_val
);
if
(
!
map
->
cache_bypass
&&
map
->
format
.
format_write
)
{
if
(
!
map
->
cache_bypass
&&
map
->
format
.
format_write
)
{
ret
=
regcache_write
(
map
,
reg
,
val
);
ret
=
regcache_write
(
map
,
reg
,
val
);
...
@@ -1011,33 +1127,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
...
@@ -1011,33 +1127,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
trace_regmap_reg_write
(
map
->
dev
,
reg
,
val
);
trace_regmap_reg_write
(
map
->
dev
,
reg
,
val
);
if
(
map
->
format
.
format_write
)
{
return
map
->
reg_write
(
map
,
reg
,
val
);
range
=
_regmap_range_lookup
(
map
,
reg
);
if
(
range
)
{
ret
=
_regmap_select_page
(
map
,
&
reg
,
range
,
1
);
if
(
ret
!=
0
)
return
ret
;
}
map
->
format
.
format_write
(
map
,
reg
,
val
);
trace_regmap_hw_write_start
(
map
->
dev
,
reg
,
1
);
ret
=
map
->
bus
->
write
(
map
->
bus_context
,
map
->
work_buf
,
map
->
format
.
buf_size
);
trace_regmap_hw_write_done
(
map
->
dev
,
reg
,
1
);
return
ret
;
}
else
{
map
->
format
.
format_val
(
map
->
work_buf
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
val
,
0
);
return
_regmap_raw_write
(
map
,
reg
,
map
->
work_buf
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
map
->
format
.
val_bytes
);
}
}
}
/**
/**
...
@@ -1095,7 +1185,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
...
@@ -1095,7 +1185,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
map
->
lock
(
map
->
lock_arg
);
map
->
lock
(
map
->
lock_arg
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
val_len
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
val_len
,
false
);
map
->
unlock
(
map
->
lock_arg
);
map
->
unlock
(
map
->
lock_arg
);
...
@@ -1151,14 +1241,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
...
@@ -1151,14 +1241,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if
(
map
->
use_single_rw
)
{
if
(
map
->
use_single_rw
)
{
for
(
i
=
0
;
i
<
val_count
;
i
++
)
{
for
(
i
=
0
;
i
<
val_count
;
i
++
)
{
ret
=
regmap_raw_write
(
map
,
ret
=
regmap_raw_write
(
map
,
reg
+
(
i
*
map
->
reg_stride
),
reg
+
(
i
*
map
->
reg_stride
),
val
+
(
i
*
val_bytes
),
val
+
(
i
*
val_bytes
),
val_bytes
);
val_bytes
);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
return
ret
;
return
ret
;
}
}
}
else
{
}
else
{
ret
=
_regmap_raw_write
(
map
,
reg
,
wval
,
val_bytes
*
val_count
);
ret
=
_regmap_raw_write
(
map
,
reg
,
wval
,
val_bytes
*
val_count
,
false
);
}
}
if
(
val_bytes
!=
1
)
if
(
val_bytes
!=
1
)
...
@@ -1170,6 +1261,48 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
...
@@ -1170,6 +1261,48 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
}
}
EXPORT_SYMBOL_GPL
(
regmap_bulk_write
);
EXPORT_SYMBOL_GPL
(
regmap_bulk_write
);
/**
* regmap_raw_write_async(): Write raw values to one or more registers
* asynchronously
*
* @map: Register map to write to
* @reg: Initial register to write to
* @val: Block of data to be written, laid out for direct transmission to the
* device. Must be valid until regmap_async_complete() is called.
* @val_len: Length of data pointed to by val.
*
* This function is intended to be used for things like firmware
* download where a large block of data needs to be transferred to the
* device. No formatting will be done on the data provided.
*
* If supported by the underlying bus the write will be scheduled
* asynchronously, helping maximise I/O speed on higher speed buses
* like SPI. regmap_async_complete() can be called to ensure that all
* asynchrnous writes have been completed.
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int
regmap_raw_write_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
)
{
int
ret
;
if
(
val_len
%
map
->
format
.
val_bytes
)
return
-
EINVAL
;
if
(
reg
%
map
->
reg_stride
)
return
-
EINVAL
;
map
->
lock
(
map
->
lock_arg
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
val_len
,
true
);
map
->
unlock
(
map
->
lock_arg
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_raw_write_async
);
static
int
_regmap_raw_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
void
*
val
,
static
int
_regmap_raw_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
void
*
val
,
unsigned
int
val_len
)
unsigned
int
val_len
)
{
{
...
@@ -1208,10 +1341,27 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
...
@@ -1208,10 +1341,27 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
return
ret
;
return
ret
;
}
}
static
int
_regmap_bus_read
(
void
*
context
,
unsigned
int
reg
,
unsigned
int
*
val
)
{
int
ret
;
struct
regmap
*
map
=
context
;
if
(
!
map
->
format
.
parse_val
)
return
-
EINVAL
;
ret
=
_regmap_raw_read
(
map
,
reg
,
map
->
work_buf
,
map
->
format
.
val_bytes
);
if
(
ret
==
0
)
*
val
=
map
->
format
.
parse_val
(
map
->
work_buf
);
return
ret
;
}
static
int
_regmap_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
static
int
_regmap_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
*
val
)
unsigned
int
*
val
)
{
{
int
ret
;
int
ret
;
BUG_ON
(
!
map
->
reg_read
);
if
(
!
map
->
cache_bypass
)
{
if
(
!
map
->
cache_bypass
)
{
ret
=
regcache_read
(
map
,
reg
,
val
);
ret
=
regcache_read
(
map
,
reg
,
val
);
...
@@ -1219,26 +1369,21 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
...
@@ -1219,26 +1369,21 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
return
0
;
return
0
;
}
}
if
(
!
map
->
format
.
parse_val
)
return
-
EINVAL
;
if
(
map
->
cache_only
)
if
(
map
->
cache_only
)
return
-
EBUSY
;
return
-
EBUSY
;
ret
=
_regmap_raw_read
(
map
,
reg
,
map
->
work_buf
,
map
->
format
.
val_bytes
);
ret
=
map
->
reg_read
(
map
,
reg
,
val
);
if
(
ret
==
0
)
{
if
(
ret
==
0
)
{
*
val
=
map
->
format
.
parse_val
(
map
->
work_buf
);
#ifdef LOG_DEVICE
#ifdef LOG_DEVICE
if
(
strcmp
(
dev_name
(
map
->
dev
),
LOG_DEVICE
)
==
0
)
if
(
strcmp
(
dev_name
(
map
->
dev
),
LOG_DEVICE
)
==
0
)
dev_info
(
map
->
dev
,
"%x => %x
\n
"
,
reg
,
*
val
);
dev_info
(
map
->
dev
,
"%x => %x
\n
"
,
reg
,
*
val
);
#endif
#endif
trace_regmap_reg_read
(
map
->
dev
,
reg
,
*
val
);
trace_regmap_reg_read
(
map
->
dev
,
reg
,
*
val
);
}
if
(
ret
==
0
&&
!
map
->
cache_bypass
)
if
(
!
map
->
cache_bypass
)
regcache_write
(
map
,
reg
,
*
val
);
regcache_write
(
map
,
reg
,
*
val
);
}
return
ret
;
return
ret
;
}
}
...
@@ -1456,6 +1601,68 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
...
@@ -1456,6 +1601,68 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
}
}
EXPORT_SYMBOL_GPL
(
regmap_update_bits_check
);
EXPORT_SYMBOL_GPL
(
regmap_update_bits_check
);
void
regmap_async_complete_cb
(
struct
regmap_async
*
async
,
int
ret
)
{
struct
regmap
*
map
=
async
->
map
;
bool
wake
;
spin_lock
(
&
map
->
async_lock
);
list_del
(
&
async
->
list
);
wake
=
list_empty
(
&
map
->
async_list
);
if
(
ret
!=
0
)
map
->
async_ret
=
ret
;
spin_unlock
(
&
map
->
async_lock
);
schedule_work
(
&
async
->
cleanup
);
if
(
wake
)
wake_up
(
&
map
->
async_waitq
);
}
EXPORT_SYMBOL_GPL
(
regmap_async_complete_cb
);
static
int
regmap_async_is_done
(
struct
regmap
*
map
)
{
unsigned
long
flags
;
int
ret
;
spin_lock_irqsave
(
&
map
->
async_lock
,
flags
);
ret
=
list_empty
(
&
map
->
async_list
);
spin_unlock_irqrestore
(
&
map
->
async_lock
,
flags
);
return
ret
;
}
/**
* regmap_async_complete: Ensure all asynchronous I/O has completed.
*
* @map: Map to operate on.
*
* Blocks until any pending asynchronous I/O has completed. Returns
* an error code for any failed I/O operations.
*/
int
regmap_async_complete
(
struct
regmap
*
map
)
{
unsigned
long
flags
;
int
ret
;
/* Nothing to do with no async support */
if
(
!
map
->
bus
->
async_write
)
return
0
;
wait_event
(
map
->
async_waitq
,
regmap_async_is_done
(
map
));
spin_lock_irqsave
(
&
map
->
async_lock
,
flags
);
ret
=
map
->
async_ret
;
map
->
async_ret
=
0
;
spin_unlock_irqrestore
(
&
map
->
async_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_async_complete
);
/**
/**
* regmap_register_patch: Register and apply register updates to be applied
* regmap_register_patch: Register and apply register updates to be applied
* on device initialistion
* on device initialistion
...
...
include/linux/regmap.h
View file @
3689cf7f
...
@@ -235,14 +235,21 @@ struct regmap_range_cfg {
...
@@ -235,14 +235,21 @@ struct regmap_range_cfg {
unsigned
int
window_len
;
unsigned
int
window_len
;
};
};
struct
regmap_async
;
typedef
int
(
*
regmap_hw_write
)(
void
*
context
,
const
void
*
data
,
typedef
int
(
*
regmap_hw_write
)(
void
*
context
,
const
void
*
data
,
size_t
count
);
size_t
count
);
typedef
int
(
*
regmap_hw_gather_write
)(
void
*
context
,
typedef
int
(
*
regmap_hw_gather_write
)(
void
*
context
,
const
void
*
reg
,
size_t
reg_len
,
const
void
*
reg
,
size_t
reg_len
,
const
void
*
val
,
size_t
val_len
);
const
void
*
val
,
size_t
val_len
);
typedef
int
(
*
regmap_hw_async_write
)(
void
*
context
,
const
void
*
reg
,
size_t
reg_len
,
const
void
*
val
,
size_t
val_len
,
struct
regmap_async
*
async
);
typedef
int
(
*
regmap_hw_read
)(
void
*
context
,
typedef
int
(
*
regmap_hw_read
)(
void
*
context
,
const
void
*
reg_buf
,
size_t
reg_size
,
const
void
*
reg_buf
,
size_t
reg_size
,
void
*
val_buf
,
size_t
val_size
);
void
*
val_buf
,
size_t
val_size
);
typedef
struct
regmap_async
*
(
*
regmap_hw_async_alloc
)(
void
);
typedef
void
(
*
regmap_hw_free_context
)(
void
*
context
);
typedef
void
(
*
regmap_hw_free_context
)(
void
*
context
);
/**
/**
...
@@ -255,8 +262,11 @@ typedef void (*regmap_hw_free_context)(void *context);
...
@@ -255,8 +262,11 @@ typedef void (*regmap_hw_free_context)(void *context);
* @write: Write operation.
* @write: Write operation.
* @gather_write: Write operation with split register/value, return -ENOTSUPP
* @gather_write: Write operation with split register/value, return -ENOTSUPP
* if not implemented on a given device.
* if not implemented on a given device.
* @async_write: Write operation which completes asynchronously, optional and
* must serialise with respect to non-async I/O.
* @read: Read operation. Data is returned in the buffer used to transmit
* @read: Read operation. Data is returned in the buffer used to transmit
* data.
* data.
* @async_alloc: Allocate a regmap_async() structure.
* @read_flag_mask: Mask to be set in the top byte of the register when doing
* @read_flag_mask: Mask to be set in the top byte of the register when doing
* a read.
* a read.
* @reg_format_endian_default: Default endianness for formatted register
* @reg_format_endian_default: Default endianness for formatted register
...
@@ -265,13 +275,16 @@ typedef void (*regmap_hw_free_context)(void *context);
...
@@ -265,13 +275,16 @@ typedef void (*regmap_hw_free_context)(void *context);
* @val_format_endian_default: Default endianness for formatted register
* @val_format_endian_default: Default endianness for formatted register
* values. Used when the regmap_config specifies DEFAULT. If this is
* values. Used when the regmap_config specifies DEFAULT. If this is
* DEFAULT, BIG is assumed.
* DEFAULT, BIG is assumed.
* @async_size: Size of struct used for async work.
*/
*/
struct
regmap_bus
{
struct
regmap_bus
{
bool
fast_io
;
bool
fast_io
;
regmap_hw_write
write
;
regmap_hw_write
write
;
regmap_hw_gather_write
gather_write
;
regmap_hw_gather_write
gather_write
;
regmap_hw_async_write
async_write
;
regmap_hw_read
read
;
regmap_hw_read
read
;
regmap_hw_free_context
free_context
;
regmap_hw_free_context
free_context
;
regmap_hw_async_alloc
async_alloc
;
u8
read_flag_mask
;
u8
read_flag_mask
;
enum
regmap_endian
reg_format_endian_default
;
enum
regmap_endian
reg_format_endian_default
;
enum
regmap_endian
val_format_endian_default
;
enum
regmap_endian
val_format_endian_default
;
...
@@ -310,6 +323,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
...
@@ -310,6 +323,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
const
void
*
val
,
size_t
val_len
);
const
void
*
val
,
size_t
val_len
);
int
regmap_bulk_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
int
regmap_bulk_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_count
);
size_t
val_count
);
int
regmap_raw_write_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
);
int
regmap_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
*
val
);
int
regmap_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
*
val
);
int
regmap_raw_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
int
regmap_raw_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
void
*
val
,
size_t
val_len
);
void
*
val
,
size_t
val_len
);
...
@@ -321,6 +336,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
...
@@ -321,6 +336,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
unsigned
int
mask
,
unsigned
int
val
,
unsigned
int
mask
,
unsigned
int
val
,
bool
*
change
);
bool
*
change
);
int
regmap_get_val_bytes
(
struct
regmap
*
map
);
int
regmap_get_val_bytes
(
struct
regmap
*
map
);
int
regmap_async_complete
(
struct
regmap
*
map
);
int
regcache_sync
(
struct
regmap
*
map
);
int
regcache_sync
(
struct
regmap
*
map
);
int
regcache_sync_region
(
struct
regmap
*
map
,
unsigned
int
min
,
int
regcache_sync_region
(
struct
regmap
*
map
,
unsigned
int
min
,
...
@@ -422,6 +438,13 @@ static inline int regmap_raw_write(struct regmap *map, unsigned int reg,
...
@@ -422,6 +438,13 @@ static inline int regmap_raw_write(struct regmap *map, unsigned int reg,
return
-
EINVAL
;
return
-
EINVAL
;
}
}
static
inline
int
regmap_raw_write_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
)
{
WARN_ONCE
(
1
,
"regmap API is disabled"
);
return
-
EINVAL
;
}
static
inline
int
regmap_bulk_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
static
inline
int
regmap_bulk_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_count
)
const
void
*
val
,
size_t
val_count
)
{
{
...
@@ -500,6 +523,11 @@ static inline void regcache_mark_dirty(struct regmap *map)
...
@@ -500,6 +523,11 @@ static inline void regcache_mark_dirty(struct regmap *map)
WARN_ONCE
(
1
,
"regmap API is disabled"
);
WARN_ONCE
(
1
,
"regmap API is disabled"
);
}
}
static
inline
void
regmap_async_complete
(
struct
regmap
*
map
)
{
WARN_ONCE
(
1
,
"regmap API is disabled"
);
}
static
inline
int
regmap_register_patch
(
struct
regmap
*
map
,
static
inline
int
regmap_register_patch
(
struct
regmap
*
map
,
const
struct
reg_default
*
regs
,
const
struct
reg_default
*
regs
,
int
num_regs
)
int
num_regs
)
...
...
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