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
54fc5a1a
Commit
54fc5a1a
authored
Dec 02, 2012
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/wm2200' into asoc-next
parents
9f07f658
f55ec27f
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
200 additions
and
471 deletions
+200
-471
drivers/base/regmap/internal.h
drivers/base/regmap/internal.h
+2
-0
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap-debugfs.c
+45
-5
drivers/base/regmap/regmap.c
drivers/base/regmap/regmap.c
+107
-47
include/linux/regmap.h
include/linux/regmap.h
+5
-1
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm2200.c
+41
-418
No files found.
drivers/base/regmap/internal.h
View file @
54fc5a1a
...
...
@@ -120,6 +120,8 @@ int _regmap_write(struct regmap *map, unsigned int reg,
struct
regmap_range_node
{
struct
rb_node
node
;
const
char
*
name
;
struct
regmap
*
map
;
unsigned
int
range_min
;
unsigned
int
range_max
;
...
...
drivers/base/regmap/regmap-debugfs.c
View file @
54fc5a1a
...
...
@@ -56,15 +56,15 @@ static const struct file_operations regmap_name_fops = {
.
llseek
=
default_llseek
,
};
static
ssize_t
regmap_map_read_file
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
static
ssize_t
regmap_read_debugfs
(
struct
regmap
*
map
,
unsigned
int
from
,
unsigned
int
to
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
int
reg_len
,
val_len
,
tot_len
;
size_t
buf_pos
=
0
;
loff_t
p
=
0
;
ssize_t
ret
;
int
i
;
struct
regmap
*
map
=
file
->
private_data
;
char
*
buf
;
unsigned
int
val
;
...
...
@@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
val_len
=
2
*
map
->
format
.
val_bytes
;
tot_len
=
reg_len
+
val_len
+
3
;
/* : \n */
for
(
i
=
0
;
i
<=
map
->
max_register
;
i
+=
map
->
reg_stride
)
{
for
(
i
=
from
;
i
<=
to
;
i
+=
map
->
reg_stride
)
{
if
(
!
regmap_readable
(
map
,
i
))
continue
;
...
...
@@ -95,7 +95,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
/* Format the register */
snprintf
(
buf
+
buf_pos
,
count
-
buf_pos
,
"%.*x: "
,
reg_len
,
i
);
reg_len
,
i
-
from
);
buf_pos
+=
reg_len
+
2
;
/* Format the value, write all X if we can't read */
...
...
@@ -126,6 +126,15 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
return
ret
;
}
static
ssize_t
regmap_map_read_file
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
regmap
*
map
=
file
->
private_data
;
return
regmap_read_debugfs
(
map
,
0
,
map
->
max_register
,
user_buf
,
count
,
ppos
);
}
#undef REGMAP_ALLOW_WRITE_DEBUGFS
#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
/*
...
...
@@ -174,6 +183,22 @@ static const struct file_operations regmap_map_fops = {
.
llseek
=
default_llseek
,
};
static
ssize_t
regmap_range_read_file
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
regmap_range_node
*
range
=
file
->
private_data
;
struct
regmap
*
map
=
range
->
map
;
return
regmap_read_debugfs
(
map
,
range
->
range_min
,
range
->
range_max
,
user_buf
,
count
,
ppos
);
}
static
const
struct
file_operations
regmap_range_fops
=
{
.
open
=
simple_open
,
.
read
=
regmap_range_read_file
,
.
llseek
=
default_llseek
,
};
static
ssize_t
regmap_access_read_file
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
...
...
@@ -244,6 +269,9 @@ static const struct file_operations regmap_access_fops = {
void
regmap_debugfs_init
(
struct
regmap
*
map
,
const
char
*
name
)
{
struct
rb_node
*
next
;
struct
regmap_range_node
*
range_node
;
if
(
name
)
{
map
->
debugfs_name
=
kasprintf
(
GFP_KERNEL
,
"%s-%s"
,
dev_name
(
map
->
dev
),
name
);
...
...
@@ -276,6 +304,18 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
debugfs_create_bool
(
"cache_bypass"
,
0400
,
map
->
debugfs
,
&
map
->
cache_bypass
);
}
next
=
rb_first
(
&
map
->
range_tree
);
while
(
next
)
{
range_node
=
rb_entry
(
next
,
struct
regmap_range_node
,
node
);
if
(
range_node
->
name
)
debugfs_create_file
(
range_node
->
name
,
0400
,
map
->
debugfs
,
range_node
,
&
regmap_range_fops
);
next
=
rb_next
(
&
range_node
->
node
);
}
}
void
regmap_debugfs_exit
(
struct
regmap
*
map
)
...
...
drivers/base/regmap/regmap.c
View file @
54fc5a1a
...
...
@@ -519,20 +519,38 @@ struct regmap *regmap_init(struct device *dev,
}
map
->
range_tree
=
RB_ROOT
;
for
(
i
=
0
;
i
<
config
->
n_ranges
;
i
++
)
{
for
(
i
=
0
;
i
<
config
->
n
um
_ranges
;
i
++
)
{
const
struct
regmap_range_cfg
*
range_cfg
=
&
config
->
ranges
[
i
];
struct
regmap_range_node
*
new
;
/* Sanity check */
if
(
range_cfg
->
range_max
<
range_cfg
->
range_min
||
range_cfg
->
range_max
>
map
->
max_register
||
range_cfg
->
selector_reg
>
map
->
max_register
||
range_cfg
->
window_len
==
0
)
if
(
range_cfg
->
range_max
<
range_cfg
->
range_min
)
{
dev_err
(
map
->
dev
,
"Invalid range %d: %d < %d
\n
"
,
i
,
range_cfg
->
range_max
,
range_cfg
->
range_min
);
goto
err_range
;
}
if
(
range_cfg
->
range_max
>
map
->
max_register
)
{
dev_err
(
map
->
dev
,
"Invalid range %d: %d > %d
\n
"
,
i
,
range_cfg
->
range_max
,
map
->
max_register
);
goto
err_range
;
}
if
(
range_cfg
->
selector_reg
>
map
->
max_register
)
{
dev_err
(
map
->
dev
,
"Invalid range %d: selector out of map
\n
"
,
i
);
goto
err_range
;
}
if
(
range_cfg
->
window_len
==
0
)
{
dev_err
(
map
->
dev
,
"Invalid range %d: window_len 0
\n
"
,
i
);
goto
err_range
;
}
/* Make sure, that this register range has no selector
or data window within its boundary */
for
(
j
=
0
;
j
<
config
->
n_ranges
;
j
++
)
{
for
(
j
=
0
;
j
<
config
->
n
um
_ranges
;
j
++
)
{
unsigned
sel_reg
=
config
->
ranges
[
j
].
selector_reg
;
unsigned
win_min
=
config
->
ranges
[
j
].
window_start
;
unsigned
win_max
=
win_min
+
...
...
@@ -540,11 +558,17 @@ struct regmap *regmap_init(struct device *dev,
if
(
range_cfg
->
range_min
<=
sel_reg
&&
sel_reg
<=
range_cfg
->
range_max
)
{
dev_err
(
map
->
dev
,
"Range %d: selector for %d in window
\n
"
,
i
,
j
);
goto
err_range
;
}
if
(
!
(
win_max
<
range_cfg
->
range_min
||
win_min
>
range_cfg
->
range_max
))
{
dev_err
(
map
->
dev
,
"Range %d: window for %d in window
\n
"
,
i
,
j
);
goto
err_range
;
}
}
...
...
@@ -555,6 +579,8 @@ struct regmap *regmap_init(struct device *dev,
goto
err_range
;
}
new
->
map
=
map
;
new
->
name
=
range_cfg
->
name
;
new
->
range_min
=
range_cfg
->
range_min
;
new
->
range_max
=
range_cfg
->
range_max
;
new
->
selector_reg
=
range_cfg
->
selector_reg
;
...
...
@@ -564,6 +590,7 @@ struct regmap *regmap_init(struct device *dev,
new
->
window_len
=
range_cfg
->
window_len
;
if
(
_regmap_range_add
(
map
,
new
)
==
false
)
{
dev_err
(
map
->
dev
,
"Failed to add range %d
\n
"
,
i
);
kfree
(
new
);
goto
err_range
;
}
...
...
@@ -579,7 +606,7 @@ struct regmap *regmap_init(struct device *dev,
}
ret
=
regcache_init
(
map
,
config
);
if
(
ret
<
0
)
if
(
ret
!=
0
)
goto
err_range
;
regmap_debugfs_init
(
map
,
config
->
name
);
...
...
@@ -738,59 +765,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name)
EXPORT_SYMBOL_GPL
(
dev_get_regmap
);
static
int
_regmap_select_page
(
struct
regmap
*
map
,
unsigned
int
*
reg
,
struct
regmap_range_node
*
range
,
unsigned
int
val_num
)
{
struct
regmap_range_node
*
range
;
void
*
orig_work_buf
;
unsigned
int
win_offset
;
unsigned
int
win_page
;
bool
page_chg
;
int
ret
;
range
=
_regmap_range_lookup
(
map
,
*
reg
);
if
(
range
)
{
win_offset
=
(
*
reg
-
range
->
range_min
)
%
range
->
window_len
;
win_page
=
(
*
reg
-
range
->
range_min
)
/
range
->
window_len
;
if
(
val_num
>
1
)
{
/* Bulk write shouldn't cross range boundary */
if
(
*
reg
+
val_num
-
1
>
range
->
range_max
)
return
-
EINVAL
;
win_offset
=
(
*
reg
-
range
->
range_min
)
%
range
->
window_len
;
win_page
=
(
*
reg
-
range
->
range_min
)
/
range
->
window_len
;
/* ... or single page boundary */
if
(
val_num
>
range
->
window_len
-
win_offset
)
return
-
EINVAL
;
}
if
(
val_num
>
1
)
{
/* Bulk write shouldn't cross range boundary */
if
(
*
reg
+
val_num
-
1
>
range
->
range_max
)
return
-
EINVAL
;
/* It is possible to have selector register inside data window.
In that case, selector register is located on every page and
it needs no page switching, when accessed alone. */
if
(
val_num
>
1
||
range
->
window_start
+
win_offset
!=
range
->
selector_reg
)
{
/* Use separate work_buf during page switching */
orig_work_buf
=
map
->
work_buf
;
map
->
work_buf
=
map
->
selector_work_buf
;
/* ... or single page boundary */
if
(
val_num
>
range
->
window_len
-
win_offset
)
return
-
EINVAL
;
}
ret
=
_regmap_update_bits
(
map
,
range
->
selector_reg
,
range
->
selector_mask
,
win_page
<<
range
->
selector_shift
,
&
page_chg
);
/* It is possible to have selector register inside data window.
In that case, selector register is located on every page and
it needs no page switching, when accessed alone. */
if
(
val_num
>
1
||
range
->
window_start
+
win_offset
!=
range
->
selector_reg
)
{
/* Use separate work_buf during page switching */
orig_work_buf
=
map
->
work_buf
;
map
->
work_buf
=
map
->
selector_work_buf
;
map
->
work_buf
=
orig_work_buf
;
ret
=
_regmap_update_bits
(
map
,
range
->
selector_reg
,
range
->
selector_mask
,
win_page
<<
range
->
selector_shift
,
&
page_chg
);
if
(
ret
<
0
)
return
ret
;
}
map
->
work_buf
=
orig_work_buf
;
*
reg
=
range
->
window_start
+
win_offset
;
if
(
ret
!=
0
)
return
ret
;
}
*
reg
=
range
->
window_start
+
win_offset
;
return
0
;
}
static
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
)
{
struct
regmap_range_node
*
range
;
u8
*
u8
=
map
->
work_buf
;
void
*
buf
;
int
ret
=
-
ENOTSUPP
;
...
...
@@ -825,9 +850,35 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
}
}
ret
=
_regmap_select_page
(
map
,
&
reg
,
val_len
/
map
->
format
.
val_bytes
);
if
(
ret
<
0
)
return
ret
;
range
=
_regmap_range_lookup
(
map
,
reg
);
if
(
range
)
{
int
val_num
=
val_len
/
map
->
format
.
val_bytes
;
int
win_offset
=
(
reg
-
range
->
range_min
)
%
range
->
window_len
;
int
win_residue
=
range
->
window_len
-
win_offset
;
/* If the write goes beyond the end of the window split it */
while
(
val_num
>
win_residue
)
{
dev_dbg
(
map
->
dev
,
"Writing window %d/%d
\n
"
,
win_residue
,
val_len
/
map
->
format
.
val_bytes
);
ret
=
_regmap_raw_write
(
map
,
reg
,
val
,
win_residue
*
map
->
format
.
val_bytes
);
if
(
ret
!=
0
)
return
ret
;
reg
+=
win_residue
;
val_num
-=
win_residue
;
val
+=
win_residue
*
map
->
format
.
val_bytes
;
val_len
-=
win_residue
*
map
->
format
.
val_bytes
;
win_offset
=
(
reg
-
range
->
range_min
)
%
range
->
window_len
;
win_residue
=
range
->
window_len
-
win_offset
;
}
ret
=
_regmap_select_page
(
map
,
&
reg
,
range
,
val_num
);
if
(
ret
!=
0
)
return
ret
;
}
map
->
format
.
format_reg
(
map
->
work_buf
,
reg
,
map
->
reg_shift
);
...
...
@@ -876,6 +927,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
int
_regmap_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
unsigned
int
val
)
{
struct
regmap_range_node
*
range
;
int
ret
;
BUG_ON
(
!
map
->
format
.
format_write
&&
!
map
->
format
.
format_val
);
...
...
@@ -897,9 +949,12 @@ int _regmap_write(struct regmap *map, unsigned int reg,
trace_regmap_reg_write
(
map
->
dev
,
reg
,
val
);
if
(
map
->
format
.
format_write
)
{
ret
=
_regmap_select_page
(
map
,
&
reg
,
1
);
if
(
ret
<
0
)
return
ret
;
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
);
...
...
@@ -1055,12 +1110,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
static
int
_regmap_raw_read
(
struct
regmap
*
map
,
unsigned
int
reg
,
void
*
val
,
unsigned
int
val_len
)
{
struct
regmap_range_node
*
range
;
u8
*
u8
=
map
->
work_buf
;
int
ret
;
ret
=
_regmap_select_page
(
map
,
&
reg
,
val_len
/
map
->
format
.
val_bytes
);
if
(
ret
<
0
)
return
ret
;
range
=
_regmap_range_lookup
(
map
,
reg
);
if
(
range
)
{
ret
=
_regmap_select_page
(
map
,
&
reg
,
range
,
val_len
/
map
->
format
.
val_bytes
);
if
(
ret
!=
0
)
return
ret
;
}
map
->
format
.
format_reg
(
map
->
work_buf
,
reg
,
map
->
reg_shift
);
...
...
include/linux/regmap.h
View file @
54fc5a1a
...
...
@@ -133,7 +133,7 @@ struct regmap_config {
enum
regmap_endian
val_format_endian
;
const
struct
regmap_range_cfg
*
ranges
;
unsigned
int
n_ranges
;
unsigned
int
n
um
_ranges
;
};
/**
...
...
@@ -142,6 +142,8 @@ struct regmap_config {
* 1. page selector register update;
* 2. access through data window registers.
*
* @name: Descriptive name for diagnostics
*
* @range_min: Address of the lowest register address in virtual range.
* @range_max: Address of the highest register in virtual range.
*
...
...
@@ -153,6 +155,8 @@ struct regmap_config {
* @window_len: Number of registers in data window.
*/
struct
regmap_range_cfg
{
const
char
*
name
;
/* Registers of virtual address range */
unsigned
int
range_min
;
unsigned
int
range_max
;
...
...
sound/soc/codecs/wm2200.c
View file @
54fc5a1a
This diff is collapsed.
Click to expand it.
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