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
719454d2
Commit
719454d2
authored
Dec 10, 2012
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/wm2200' into asoc-next
parents
ac92f112
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 @
719454d2
...
...
@@ -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 @
719454d2
...
...
@@ -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 @
719454d2
...
...
@@ -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 @
719454d2
...
...
@@ -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 @
719454d2
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