Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
5eff79fe
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
5eff79fe
编写于
10月 28, 2013
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'regmap/topic/async' into regmap-next
上级
70c1c86d
04c50ccf
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
225 addition
and
50 deletion
+225
-50
drivers/base/regmap/internal.h
drivers/base/regmap/internal.h
+3
-2
drivers/base/regmap/regcache.c
drivers/base/regmap/regcache.c
+15
-4
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap-spi.c
+2
-1
drivers/base/regmap/regmap.c
drivers/base/regmap/regmap.c
+174
-43
include/linux/regmap.h
include/linux/regmap.h
+31
-0
未找到文件。
drivers/base/regmap/internal.h
浏览文件 @
5eff79fe
...
...
@@ -44,7 +44,6 @@ struct regmap_format {
struct
regmap_async
{
struct
list_head
list
;
struct
work_struct
cleanup
;
struct
regmap
*
map
;
void
*
work_buf
;
};
...
...
@@ -64,9 +63,11 @@ struct regmap {
void
*
bus_context
;
const
char
*
name
;
bool
async
;
spinlock_t
async_lock
;
wait_queue_head_t
async_waitq
;
struct
list_head
async_list
;
struct
list_head
async_free
;
int
async_ret
;
#ifdef CONFIG_DEBUG_FS
...
...
@@ -218,7 +219,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
int
regcache_lookup_reg
(
struct
regmap
*
map
,
unsigned
int
reg
);
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
,
bool
async
);
const
void
*
val
,
size_t
val_len
);
void
regmap_async_complete_cb
(
struct
regmap_async
*
async
,
int
ret
);
...
...
drivers/base/regmap/regcache.c
浏览文件 @
5eff79fe
...
...
@@ -307,6 +307,8 @@ int regcache_sync(struct regmap *map)
if
(
!
map
->
cache_dirty
)
goto
out
;
map
->
async
=
true
;
/* Apply any patch first */
map
->
cache_bypass
=
1
;
for
(
i
=
0
;
i
<
map
->
patch_regs
;
i
++
)
{
...
...
@@ -332,11 +334,15 @@ int regcache_sync(struct regmap *map)
map
->
cache_dirty
=
false
;
out:
trace_regcache_sync
(
map
->
dev
,
name
,
"stop"
);
/* Restore the bypass state */
map
->
async
=
false
;
map
->
cache_bypass
=
bypass
;
map
->
unlock
(
map
->
lock_arg
);
regmap_async_complete
(
map
);
trace_regcache_sync
(
map
->
dev
,
name
,
"stop"
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regcache_sync
);
...
...
@@ -375,17 +381,23 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
if
(
!
map
->
cache_dirty
)
goto
out
;
map
->
async
=
true
;
if
(
map
->
cache_ops
->
sync
)
ret
=
map
->
cache_ops
->
sync
(
map
,
min
,
max
);
else
ret
=
regcache_default_sync
(
map
,
min
,
max
);
out:
trace_regcache_sync
(
map
->
dev
,
name
,
"stop region"
);
/* Restore the bypass state */
map
->
cache_bypass
=
bypass
;
map
->
async
=
false
;
map
->
unlock
(
map
->
lock_arg
);
regmap_async_complete
(
map
);
trace_regcache_sync
(
map
->
dev
,
name
,
"stop region"
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regcache_sync_region
);
...
...
@@ -631,8 +643,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
map
->
cache_bypass
=
1
;
ret
=
_regmap_raw_write
(
map
,
base
,
*
data
,
count
*
val_bytes
,
false
);
ret
=
_regmap_raw_write
(
map
,
base
,
*
data
,
count
*
val_bytes
);
map
->
cache_bypass
=
0
;
...
...
drivers/base/regmap/regmap-spi.c
浏览文件 @
5eff79fe
...
...
@@ -73,7 +73,8 @@ static int regmap_spi_async_write(void *context,
spi_message_init
(
&
async
->
m
);
spi_message_add_tail
(
&
async
->
t
[
0
],
&
async
->
m
);
spi_message_add_tail
(
&
async
->
t
[
1
],
&
async
->
m
);
if
(
val
)
spi_message_add_tail
(
&
async
->
t
[
1
],
&
async
->
m
);
async
->
m
.
complete
=
regmap_spi_complete
;
async
->
m
.
context
=
async
;
...
...
drivers/base/regmap/regmap.c
浏览文件 @
5eff79fe
...
...
@@ -42,15 +42,6 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
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
,
const
struct
regmap_range
*
ranges
,
unsigned
int
nranges
)
...
...
@@ -465,6 +456,7 @@ struct regmap *regmap_init(struct device *dev,
spin_lock_init
(
&
map
->
async_lock
);
INIT_LIST_HEAD
(
&
map
->
async_list
);
INIT_LIST_HEAD
(
&
map
->
async_free
);
init_waitqueue_head
(
&
map
->
async_waitq
);
if
(
config
->
read_flag_mask
||
config
->
write_flag_mask
)
{
...
...
@@ -942,12 +934,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache);
*/
void
regmap_exit
(
struct
regmap
*
map
)
{
struct
regmap_async
*
async
;
regcache_exit
(
map
);
regmap_debugfs_exit
(
map
);
regmap_range_exit
(
map
);
if
(
map
->
bus
&&
map
->
bus
->
free_context
)
map
->
bus
->
free_context
(
map
->
bus_context
);
kfree
(
map
->
work_buf
);
while
(
!
list_empty
(
&
map
->
async_free
))
{
async
=
list_first_entry_or_null
(
&
map
->
async_free
,
struct
regmap_async
,
list
);
list_del
(
&
async
->
list
);
kfree
(
async
->
work_buf
);
kfree
(
async
);
}
kfree
(
map
);
}
EXPORT_SYMBOL_GPL
(
regmap_exit
);
...
...
@@ -1039,7 +1041,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
}
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
,
bool
async
)
const
void
*
val
,
size_t
val_len
)
{
struct
regmap_range_node
*
range
;
unsigned
long
flags
;
...
...
@@ -1091,7 +1093,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
dev_dbg
(
map
->
dev
,
"Writing window %d/%zu
\n
"
,
win_residue
,
val_len
/
map
->
format
.
val_bytes
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
win_residue
*
map
->
format
.
val_bytes
,
async
);
map
->
format
.
val_bytes
);
if
(
ret
!=
0
)
return
ret
;
...
...
@@ -1114,49 +1116,72 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
u8
[
0
]
|=
map
->
write_flag_mask
;
if
(
async
&&
map
->
bus
->
async_write
)
{
struct
regmap_async
*
async
=
map
->
bus
->
async_alloc
();
if
(
!
async
)
return
-
ENOMEM
;
/*
* Essentially all I/O mechanisms will be faster with a single
* buffer to write. Since register syncs often generate raw
* writes of single registers optimise that case.
*/
if
(
val
!=
work_val
&&
val_len
==
map
->
format
.
val_bytes
)
{
memcpy
(
work_val
,
val
,
map
->
format
.
val_bytes
);
val
=
work_val
;
}
if
(
map
->
async
&&
map
->
bus
->
async_write
)
{
struct
regmap_async
*
async
;
trace_regmap_async_write_start
(
map
->
dev
,
reg
,
val_len
);
async
->
work_buf
=
kzalloc
(
map
->
format
.
buf_size
,
GFP_KERNEL
|
GFP_DMA
);
if
(
!
async
->
work_buf
)
{
kfree
(
async
);
return
-
ENOMEM
;
spin_lock_irqsave
(
&
map
->
async_lock
,
flags
);
async
=
list_first_entry_or_null
(
&
map
->
async_free
,
struct
regmap_async
,
list
);
if
(
async
)
list_del
(
&
async
->
list
);
spin_unlock_irqrestore
(
&
map
->
async_lock
,
flags
);
if
(
!
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
(
val
!=
work_val
)
ret
=
map
->
bus
->
async_write
(
map
->
bus_context
,
async
->
work_buf
,
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
val
,
val_len
,
async
);
else
ret
=
map
->
bus
->
async_write
(
map
->
bus_context
,
async
->
work_buf
,
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
+
val_len
,
NULL
,
0
,
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
);
list_
move
(
&
async
->
list
,
&
map
->
async_free
);
spin_unlock_irqrestore
(
&
map
->
async_lock
,
flags
);
kfree
(
async
->
work_buf
);
kfree
(
async
);
}
return
ret
;
...
...
@@ -1253,7 +1278,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
map
->
work_buf
+
map
->
format
.
reg_bytes
+
map
->
format
.
pad_bytes
,
map
->
format
.
val_bytes
,
false
);
map
->
format
.
val_bytes
);
}
static
inline
void
*
_regmap_map_get_context
(
struct
regmap
*
map
)
...
...
@@ -1317,6 +1342,37 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
}
EXPORT_SYMBOL_GPL
(
regmap_write
);
/**
* regmap_write_async(): Write a value to a single register asynchronously
*
* @map: Register map to write to
* @reg: Register to write to
* @val: Value to be written
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int
regmap_write_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
val
)
{
int
ret
;
if
(
reg
%
map
->
reg_stride
)
return
-
EINVAL
;
map
->
lock
(
map
->
lock_arg
);
map
->
async
=
true
;
ret
=
_regmap_write
(
map
,
reg
,
val
);
map
->
async
=
false
;
map
->
unlock
(
map
->
lock_arg
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_write_async
);
/**
* regmap_raw_write(): Write raw values to one or more registers
*
...
...
@@ -1345,7 +1401,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
map
->
lock
(
map
->
lock_arg
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
val_len
,
false
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
val_len
);
map
->
unlock
(
map
->
lock_arg
);
...
...
@@ -1421,14 +1477,12 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
ret
=
_regmap_raw_write
(
map
,
reg
+
(
i
*
map
->
reg_stride
),
val
+
(
i
*
val_bytes
),
val_bytes
,
false
);
val_bytes
);
if
(
ret
!=
0
)
return
ret
;
}
}
else
{
ret
=
_regmap_raw_write
(
map
,
reg
,
wval
,
val_bytes
*
val_count
,
false
);
ret
=
_regmap_raw_write
(
map
,
reg
,
wval
,
val_bytes
*
val_count
);
}
if
(
val_bytes
!=
1
)
...
...
@@ -1474,7 +1528,11 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
map
->
lock
(
map
->
lock_arg
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
val_len
,
true
);
map
->
async
=
true
;
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
val_len
);
map
->
async
=
false
;
map
->
unlock
(
map
->
lock_arg
);
...
...
@@ -1788,6 +1846,41 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL
(
regmap_update_bits
);
/**
* regmap_update_bits_async: Perform a read/modify/write cycle on the register
* map asynchronously
*
* @map: Register map to update
* @reg: Register to update
* @mask: Bitmask to change
* @val: New value for bitmask
*
* With most buses the read must be done synchronously so this is most
* useful for devices with a cache which do not need to interact with
* the hardware to determine the current register value.
*
* Returns zero for success, a negative number on error.
*/
int
regmap_update_bits_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
)
{
bool
change
;
int
ret
;
map
->
lock
(
map
->
lock_arg
);
map
->
async
=
true
;
ret
=
_regmap_update_bits
(
map
,
reg
,
mask
,
val
,
&
change
);
map
->
async
=
false
;
map
->
unlock
(
map
->
lock_arg
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_update_bits_async
);
/**
* regmap_update_bits_check: Perform a read/modify/write cycle on the
* register map and report if updated
...
...
@@ -1813,6 +1906,43 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL
(
regmap_update_bits_check
);
/**
* regmap_update_bits_check_async: Perform a read/modify/write cycle on the
* register map asynchronously and report if
* updated
*
* @map: Register map to update
* @reg: Register to update
* @mask: Bitmask to change
* @val: New value for bitmask
* @change: Boolean indicating if a write was done
*
* With most buses the read must be done synchronously so this is most
* useful for devices with a cache which do not need to interact with
* the hardware to determine the current register value.
*
* Returns zero for success, a negative number on error.
*/
int
regmap_update_bits_check_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
,
bool
*
change
)
{
int
ret
;
map
->
lock
(
map
->
lock_arg
);
map
->
async
=
true
;
ret
=
_regmap_update_bits
(
map
,
reg
,
mask
,
val
,
change
);
map
->
async
=
false
;
map
->
unlock
(
map
->
lock_arg
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_update_bits_check_async
);
void
regmap_async_complete_cb
(
struct
regmap_async
*
async
,
int
ret
)
{
struct
regmap
*
map
=
async
->
map
;
...
...
@@ -1821,8 +1951,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
trace_regmap_async_io_complete
(
map
->
dev
);
spin_lock
(
&
map
->
async_lock
);
list_del
(
&
async
->
list
);
list_move
(
&
async
->
list
,
&
map
->
async_free
);
wake
=
list_empty
(
&
map
->
async_list
);
if
(
ret
!=
0
)
...
...
@@ -1830,8 +1959,6 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
spin_unlock
(
&
map
->
async_lock
);
schedule_work
(
&
async
->
cleanup
);
if
(
wake
)
wake_up
(
&
map
->
async_waitq
);
}
...
...
@@ -1907,6 +2034,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
bypass
=
map
->
cache_bypass
;
map
->
cache_bypass
=
true
;
map
->
async
=
true
;
/* Write out first; it's useful to apply even if we fail later. */
for
(
i
=
0
;
i
<
num_regs
;
i
++
)
{
...
...
@@ -1930,10 +2058,13 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
}
out:
map
->
async
=
false
;
map
->
cache_bypass
=
bypass
;
map
->
unlock
(
map
->
lock_arg
);
regmap_async_complete
(
map
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_register_patch
);
...
...
include/linux/regmap.h
浏览文件 @
5eff79fe
...
...
@@ -374,6 +374,7 @@ int regmap_reinit_cache(struct regmap *map,
const
struct
regmap_config
*
config
);
struct
regmap
*
dev_get_regmap
(
struct
device
*
dev
,
const
char
*
name
);
int
regmap_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
val
);
int
regmap_write_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
val
);
int
regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
);
int
regmap_bulk_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
...
...
@@ -387,9 +388,14 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t
val_count
);
int
regmap_update_bits
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
);
int
regmap_update_bits_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
);
int
regmap_update_bits_check
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
,
bool
*
change
);
int
regmap_update_bits_check_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
,
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
);
...
...
@@ -527,6 +533,13 @@ static inline int regmap_write(struct regmap *map, unsigned int reg,
return
-
EINVAL
;
}
static
inline
int
regmap_write_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
val
)
{
WARN_ONCE
(
1
,
"regmap API is disabled"
);
return
-
EINVAL
;
}
static
inline
int
regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
)
{
...
...
@@ -576,6 +589,14 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
return
-
EINVAL
;
}
static
inline
int
regmap_update_bits_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
)
{
WARN_ONCE
(
1
,
"regmap API is disabled"
);
return
-
EINVAL
;
}
static
inline
int
regmap_update_bits_check
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
,
...
...
@@ -585,6 +606,16 @@ static inline int regmap_update_bits_check(struct regmap *map,
return
-
EINVAL
;
}
static
inline
int
regmap_update_bits_check_async
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
val
,
bool
*
change
)
{
WARN_ONCE
(
1
,
"regmap API is disabled"
);
return
-
EINVAL
;
}
static
inline
int
regmap_get_val_bytes
(
struct
regmap
*
map
)
{
WARN_ONCE
(
1
,
"regmap API is disabled"
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录