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
Show 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,7 +56,8 @@ 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
,
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
;
...
...
@@ -64,7 +65,6 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
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,17 +765,15 @@ 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
;
...
...
@@ -778,12 +803,11 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
map
->
work_buf
=
orig_work_buf
;
if
(
ret
<
0
)
if
(
ret
!=
0
)
return
ret
;
}
*
reg
=
range
->
window_start
+
win_offset
;
}
return
0
;
}
...
...
@@ -791,6 +815,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
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
)
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
)
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
)
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
...
...
@@ -34,6 +34,7 @@
#include "wm2200.h"
#include "wmfw.h"
#include "wm_adsp.h"
#define WM2200_DSP_CONTROL_1 0x00
#define WM2200_DSP_CONTROL_2 0x02
...
...
@@ -83,6 +84,7 @@ struct wm2200_fll {
/* codec private data */
struct
wm2200_priv
{
struct
wm_adsp
dsp
[
2
];
struct
regmap
*
regmap
;
struct
device
*
dev
;
struct
snd_soc_codec
*
codec
;
...
...
@@ -109,48 +111,42 @@ struct wm2200_priv {
#define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING))
static
const
struct
regmap_range_cfg
wm2200_ranges
[]
=
{
/* DSP1 DM */
{
.
range_min
=
WM2200_DSP1_DM_BASE
,
{
.
name
=
"DSP1DM"
,
.
range_min
=
WM2200_DSP1_DM_BASE
,
.
range_max
=
WM2200_DSP1_DM_BASE
+
12287
,
.
selector_reg
=
WM2200_DSP1_CONTROL_3
,
.
selector_mask
=
WM2200_DSP1_PAGE_BASE_DM_0_MASK
,
.
selector_shift
=
WM2200_DSP1_PAGE_BASE_DM_0_SHIFT
,
.
window_start
=
WM2200_DSP1_DM_0
,
.
window_len
=
2048
,
},
/* DSP1 PM */
{
.
range_min
=
WM2200_DSP1_PM_BASE
,
{
.
name
=
"DSP1PM"
,
.
range_min
=
WM2200_DSP1_PM_BASE
,
.
range_max
=
WM2200_DSP1_PM_BASE
+
12287
,
.
selector_reg
=
WM2200_DSP1_CONTROL_2
,
.
selector_mask
=
WM2200_DSP1_PAGE_BASE_PM_0_MASK
,
.
selector_shift
=
WM2200_DSP1_PAGE_BASE_PM_0_SHIFT
,
.
window_start
=
WM2200_DSP1_PM_0
,
.
window_len
=
768
,
},
/* DSP1 ZM */
{
.
range_min
=
WM2200_DSP1_ZM_BASE
,
{
.
name
=
"DSP1ZM"
,
.
range_min
=
WM2200_DSP1_ZM_BASE
,
.
range_max
=
WM2200_DSP1_ZM_BASE
+
2047
,
.
selector_reg
=
WM2200_DSP1_CONTROL_4
,
.
selector_mask
=
WM2200_DSP1_PAGE_BASE_ZM_0_MASK
,
.
selector_shift
=
WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT
,
.
window_start
=
WM2200_DSP1_ZM_0
,
.
window_len
=
1024
,
},
/* DSP2 DM */
{
.
range_min
=
WM2200_DSP2_DM_BASE
,
{
.
name
=
"DSP2DM"
,
.
range_min
=
WM2200_DSP2_DM_BASE
,
.
range_max
=
WM2200_DSP2_DM_BASE
+
4095
,
.
selector_reg
=
WM2200_DSP2_CONTROL_3
,
.
selector_mask
=
WM2200_DSP2_PAGE_BASE_DM_0_MASK
,
.
selector_shift
=
WM2200_DSP2_PAGE_BASE_DM_0_SHIFT
,
.
window_start
=
WM2200_DSP2_DM_0
,
.
window_len
=
2048
,
},
/* DSP2 PM */
{
.
range_min
=
WM2200_DSP2_PM_BASE
,
{
.
name
=
"DSP2PM"
,
.
range_min
=
WM2200_DSP2_PM_BASE
,
.
range_max
=
WM2200_DSP2_PM_BASE
+
11287
,
.
selector_reg
=
WM2200_DSP2_CONTROL_2
,
.
selector_mask
=
WM2200_DSP2_PAGE_BASE_PM_0_MASK
,
.
selector_shift
=
WM2200_DSP2_PAGE_BASE_PM_0_SHIFT
,
.
window_start
=
WM2200_DSP2_PM_0
,
.
window_len
=
768
,
},
/* DSP2 ZM */
{
.
range_min
=
WM2200_DSP2_ZM_BASE
,
{
.
name
=
"DSP2ZM"
,
.
range_min
=
WM2200_DSP2_ZM_BASE
,
.
range_max
=
WM2200_DSP2_ZM_BASE
+
2047
,
.
selector_reg
=
WM2200_DSP2_CONTROL_4
,
.
selector_mask
=
WM2200_DSP2_PAGE_BASE_ZM_0_MASK
,
...
...
@@ -158,6 +154,18 @@ static const struct regmap_range_cfg wm2200_ranges[] = {
.
window_start
=
WM2200_DSP2_ZM_0
,
.
window_len
=
1024
,
},
};
static
const
struct
wm_adsp_region
wm2200_dsp1_regions
[]
=
{
{
.
type
=
WMFW_ADSP1_PM
,
.
base
=
WM2200_DSP1_PM_BASE
},
{
.
type
=
WMFW_ADSP1_DM
,
.
base
=
WM2200_DSP1_DM_BASE
},
{
.
type
=
WMFW_ADSP1_ZM
,
.
base
=
WM2200_DSP1_ZM_BASE
},
};
static
const
struct
wm_adsp_region
wm2200_dsp2_regions
[]
=
{
{
.
type
=
WMFW_ADSP1_PM
,
.
base
=
WM2200_DSP2_PM_BASE
},
{
.
type
=
WMFW_ADSP1_DM
,
.
base
=
WM2200_DSP2_DM_BASE
},
{
.
type
=
WMFW_ADSP1_ZM
,
.
base
=
WM2200_DSP2_ZM_BASE
},
};
static
struct
reg_default
wm2200_reg_defaults
[]
=
{
{
0x000B
,
0x0000
},
/* R11 - Tone Generator 1 */
{
0x0102
,
0x0000
},
/* R258 - Clocking 3 */
...
...
@@ -987,400 +995,6 @@ static int wm2200_reset(struct wm2200_priv *wm2200)
}
}
static
int
wm2200_dsp_load
(
struct
snd_soc_codec
*
codec
,
int
base
)
{
const
struct
firmware
*
firmware
;
struct
regmap
*
regmap
=
codec
->
control_data
;
unsigned
int
pos
=
0
;
const
struct
wmfw_header
*
header
;
const
struct
wmfw_adsp1_sizes
*
adsp1_sizes
;
const
struct
wmfw_footer
*
footer
;
const
struct
wmfw_region
*
region
;
const
char
*
file
,
*
region_name
;
char
*
text
;
unsigned
int
dm
,
pm
,
zm
,
reg
;
int
regions
=
0
;
int
ret
,
offset
,
type
;
switch
(
base
)
{
case
WM2200_DSP1_CONTROL_1
:
file
=
"wm2200-dsp1.wmfw"
;
dm
=
WM2200_DSP1_DM_BASE
;
pm
=
WM2200_DSP1_PM_BASE
;
zm
=
WM2200_DSP1_ZM_BASE
;
break
;
case
WM2200_DSP2_CONTROL_1
:
file
=
"wm2200-dsp2.wmfw"
;
dm
=
WM2200_DSP2_DM_BASE
;
pm
=
WM2200_DSP2_PM_BASE
;
zm
=
WM2200_DSP2_ZM_BASE
;
break
;
default:
dev_err
(
codec
->
dev
,
"BASE %x
\n
"
,
base
);
BUG_ON
(
1
);
return
-
EINVAL
;
}
ret
=
request_firmware
(
&
firmware
,
file
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request '%s'
\n
"
,
file
);
return
ret
;
}
pos
=
sizeof
(
*
header
)
+
sizeof
(
*
adsp1_sizes
)
+
sizeof
(
*
footer
);
if
(
pos
>=
firmware
->
size
)
{
dev_err
(
codec
->
dev
,
"%s: file too short, %d bytes
\n
"
,
file
,
firmware
->
size
);
return
-
EINVAL
;
}
header
=
(
void
*
)
&
firmware
->
data
[
0
];
if
(
memcmp
(
&
header
->
magic
[
0
],
"WMFW"
,
4
)
!=
0
)
{
dev_err
(
codec
->
dev
,
"%s: invalid magic
\n
"
,
file
);
return
-
EINVAL
;
}
if
(
header
->
ver
!=
0
)
{
dev_err
(
codec
->
dev
,
"%s: unknown file format %d
\n
"
,
file
,
header
->
ver
);
return
-
EINVAL
;
}
if
(
le32_to_cpu
(
header
->
len
)
!=
sizeof
(
*
header
)
+
sizeof
(
*
adsp1_sizes
)
+
sizeof
(
*
footer
))
{
dev_err
(
codec
->
dev
,
"%s: unexpected header length %d
\n
"
,
file
,
le32_to_cpu
(
header
->
len
));
return
-
EINVAL
;
}
if
(
header
->
core
!=
WMFW_ADSP1
)
{
dev_err
(
codec
->
dev
,
"%s: invalid core %d
\n
"
,
file
,
header
->
core
);
return
-
EINVAL
;
}
adsp1_sizes
=
(
void
*
)
&
(
header
[
1
]);
footer
=
(
void
*
)
&
(
adsp1_sizes
[
1
]);
dev_dbg
(
codec
->
dev
,
"%s: %d DM, %d PM, %d ZM
\n
"
,
file
,
le32_to_cpu
(
adsp1_sizes
->
dm
),
le32_to_cpu
(
adsp1_sizes
->
pm
),
le32_to_cpu
(
adsp1_sizes
->
zm
));
dev_dbg
(
codec
->
dev
,
"%s: timestamp %llu
\n
"
,
file
,
le64_to_cpu
(
footer
->
timestamp
));
while
(
pos
<
firmware
->
size
&&
pos
-
firmware
->
size
>
sizeof
(
*
region
))
{
region
=
(
void
*
)
&
(
firmware
->
data
[
pos
]);
region_name
=
"Unknown"
;
reg
=
0
;
text
=
NULL
;
offset
=
le32_to_cpu
(
region
->
offset
)
&
0xffffff
;
type
=
be32_to_cpu
(
region
->
type
)
&
0xff
;
switch
(
type
)
{
case
WMFW_NAME_TEXT
:
region_name
=
"Firmware name"
;
text
=
kzalloc
(
le32_to_cpu
(
region
->
len
)
+
1
,
GFP_KERNEL
);
break
;
case
WMFW_INFO_TEXT
:
region_name
=
"Information"
;
text
=
kzalloc
(
le32_to_cpu
(
region
->
len
)
+
1
,
GFP_KERNEL
);
break
;
case
WMFW_ABSOLUTE
:
region_name
=
"Absolute"
;
reg
=
offset
;
break
;
case
WMFW_ADSP1_PM
:
region_name
=
"PM"
;
reg
=
pm
+
(
offset
*
3
);
break
;
case
WMFW_ADSP1_DM
:
region_name
=
"DM"
;
reg
=
dm
+
(
offset
*
2
);
break
;
case
WMFW_ADSP1_ZM
:
region_name
=
"ZM"
;
reg
=
zm
+
(
offset
*
2
);
break
;
default:
dev_warn
(
codec
->
dev
,
"%s.%d: Unknown region type %x at %d(%x)
\n
"
,
file
,
regions
,
type
,
pos
,
pos
);
break
;
}
dev_dbg
(
codec
->
dev
,
"%s.%d: %d bytes at %d in %s
\n
"
,
file
,
regions
,
le32_to_cpu
(
region
->
len
),
offset
,
region_name
);
if
(
text
)
{
memcpy
(
text
,
region
->
data
,
le32_to_cpu
(
region
->
len
));
dev_info
(
codec
->
dev
,
"%s: %s
\n
"
,
file
,
text
);
kfree
(
text
);
}
if
(
reg
)
{
ret
=
regmap_raw_write
(
regmap
,
reg
,
region
->
data
,
le32_to_cpu
(
region
->
len
));
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"%s.%d: Failed to write %d bytes at %d in %s: %d
\n
"
,
file
,
regions
,
le32_to_cpu
(
region
->
len
),
offset
,
region_name
,
ret
);
goto
out
;
}
}
pos
+=
le32_to_cpu
(
region
->
len
)
+
sizeof
(
*
region
);
regions
++
;
}
if
(
pos
>
firmware
->
size
)
dev_warn
(
codec
->
dev
,
"%s.%d: %d bytes at end of file
\n
"
,
file
,
regions
,
pos
-
firmware
->
size
);
out:
release_firmware
(
firmware
);
return
ret
;
}
static
int
wm2200_setup_algs
(
struct
snd_soc_codec
*
codec
,
int
base
)
{
struct
regmap
*
regmap
=
codec
->
control_data
;
struct
wmfw_adsp1_id_hdr
id
;
struct
wmfw_adsp1_alg_hdr
*
alg
;
size_t
algs
;
int
zm
,
dm
,
pm
,
ret
,
i
;
__be32
val
;
switch
(
base
)
{
case
WM2200_DSP1_CONTROL_1
:
dm
=
WM2200_DSP1_DM_BASE
;
pm
=
WM2200_DSP1_PM_BASE
;
zm
=
WM2200_DSP1_ZM_BASE
;
break
;
case
WM2200_DSP2_CONTROL_1
:
dm
=
WM2200_DSP2_DM_BASE
;
pm
=
WM2200_DSP2_PM_BASE
;
zm
=
WM2200_DSP2_ZM_BASE
;
break
;
default:
dev_err
(
codec
->
dev
,
"BASE %x
\n
"
,
base
);
BUG_ON
(
1
);
return
-
EINVAL
;
}
ret
=
regmap_raw_read
(
regmap
,
dm
,
&
id
,
sizeof
(
id
));
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to read algorithm info: %d
\n
"
,
ret
);
return
ret
;
}
algs
=
be32_to_cpu
(
id
.
algs
);
dev_info
(
codec
->
dev
,
"Firmware: %x v%d.%d.%d, %d algorithms
\n
"
,
be32_to_cpu
(
id
.
fw
.
id
),
(
be32_to_cpu
(
id
.
fw
.
ver
)
&
0xff000
)
>>
16
,
(
be32_to_cpu
(
id
.
fw
.
ver
)
&
0xff00
)
>>
8
,
be32_to_cpu
(
id
.
fw
.
ver
)
&
0xff
,
algs
);
/* Read the terminator first to validate the length */
ret
=
regmap_raw_read
(
regmap
,
dm
+
(
sizeof
(
id
)
+
(
algs
*
sizeof
(
*
alg
)))
/
2
,
&
val
,
sizeof
(
val
));
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to read algorithm list end: %d
\n
"
,
ret
);
return
ret
;
}
if
(
be32_to_cpu
(
val
)
!=
0xbedead
)
dev_warn
(
codec
->
dev
,
"Algorithm list end %x 0x%x != 0xbeadead
\n
"
,
(
sizeof
(
id
)
+
(
algs
*
sizeof
(
*
alg
)))
/
2
,
be32_to_cpu
(
val
));
alg
=
kzalloc
(
sizeof
(
*
alg
)
*
algs
,
GFP_KERNEL
);
if
(
!
alg
)
return
-
ENOMEM
;
ret
=
regmap_raw_read
(
regmap
,
dm
+
(
sizeof
(
id
)
/
2
),
alg
,
algs
*
sizeof
(
*
alg
));
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to read algorithm list: %d
\n
"
,
ret
);
goto
out
;
}
for
(
i
=
0
;
i
<
algs
;
i
++
)
{
dev_info
(
codec
->
dev
,
"%d: ID %x v%d.%d.%d
\n
"
,
i
,
be32_to_cpu
(
alg
[
i
].
alg
.
id
),
(
be32_to_cpu
(
alg
[
i
].
alg
.
ver
)
&
0xff000
)
>>
16
,
(
be32_to_cpu
(
alg
[
i
].
alg
.
ver
)
&
0xff00
)
>>
8
,
be32_to_cpu
(
alg
[
i
].
alg
.
ver
)
&
0xff
);
}
out:
kfree
(
alg
);
return
ret
;
}
static
int
wm2200_load_coeff
(
struct
snd_soc_codec
*
codec
,
int
base
)
{
struct
regmap
*
regmap
=
codec
->
control_data
;
struct
wmfw_coeff_hdr
*
hdr
;
struct
wmfw_coeff_item
*
blk
;
const
struct
firmware
*
firmware
;
const
char
*
file
,
*
region_name
;
int
ret
,
dm
,
pm
,
zm
,
pos
,
blocks
,
type
,
offset
,
reg
;
switch
(
base
)
{
case
WM2200_DSP1_CONTROL_1
:
file
=
"wm2200-dsp1.bin"
;
dm
=
WM2200_DSP1_DM_BASE
;
pm
=
WM2200_DSP1_PM_BASE
;
zm
=
WM2200_DSP1_ZM_BASE
;
break
;
case
WM2200_DSP2_CONTROL_1
:
file
=
"wm2200-dsp2.bin"
;
dm
=
WM2200_DSP2_DM_BASE
;
pm
=
WM2200_DSP2_PM_BASE
;
zm
=
WM2200_DSP2_ZM_BASE
;
break
;
default:
dev_err
(
codec
->
dev
,
"BASE %x
\n
"
,
base
);
BUG_ON
(
1
);
return
-
EINVAL
;
}
ret
=
request_firmware
(
&
firmware
,
file
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request '%s'
\n
"
,
file
);
return
ret
;
}
if
(
sizeof
(
*
hdr
)
>=
firmware
->
size
)
{
dev_err
(
codec
->
dev
,
"%s: file too short, %d bytes
\n
"
,
file
,
firmware
->
size
);
return
-
EINVAL
;
}
hdr
=
(
void
*
)
&
firmware
->
data
[
0
];
if
(
memcmp
(
hdr
->
magic
,
"WMDR"
,
4
)
!=
0
)
{
dev_err
(
codec
->
dev
,
"%s: invalid magic
\n
"
,
file
);
return
-
EINVAL
;
}
dev_dbg
(
codec
->
dev
,
"%s: v%d.%d.%d
\n
"
,
file
,
(
le32_to_cpu
(
hdr
->
ver
)
>>
16
)
&
0xff
,
(
le32_to_cpu
(
hdr
->
ver
)
>>
8
)
&
0xff
,
le32_to_cpu
(
hdr
->
ver
)
&
0xff
);
pos
=
le32_to_cpu
(
hdr
->
len
);
blocks
=
0
;
while
(
pos
<
firmware
->
size
&&
pos
-
firmware
->
size
>
sizeof
(
*
blk
))
{
blk
=
(
void
*
)(
&
firmware
->
data
[
pos
]);
type
=
be32_to_cpu
(
blk
->
type
)
&
0xff
;
offset
=
le32_to_cpu
(
blk
->
offset
)
&
0xffffff
;
dev_dbg
(
codec
->
dev
,
"%s.%d: %x v%d.%d.%d
\n
"
,
file
,
blocks
,
le32_to_cpu
(
blk
->
id
),
(
le32_to_cpu
(
blk
->
ver
)
>>
16
)
&
0xff
,
(
le32_to_cpu
(
blk
->
ver
)
>>
8
)
&
0xff
,
le32_to_cpu
(
blk
->
ver
)
&
0xff
);
dev_dbg
(
codec
->
dev
,
"%s.%d: %d bytes at 0x%x in %x
\n
"
,
file
,
blocks
,
le32_to_cpu
(
blk
->
len
),
offset
,
type
);
reg
=
0
;
region_name
=
"Unknown"
;
switch
(
type
)
{
case
WMFW_NAME_TEXT
:
case
WMFW_INFO_TEXT
:
break
;
case
WMFW_ABSOLUTE
:
region_name
=
"register"
;
reg
=
offset
;
break
;
default:
dev_err
(
codec
->
dev
,
"Unknown region type %x
\n
"
,
type
);
break
;
}
if
(
reg
)
{
ret
=
regmap_raw_write
(
regmap
,
reg
,
blk
->
data
,
le32_to_cpu
(
blk
->
len
));
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"%s.%d: Failed to write to %x in %s
\n
"
,
file
,
blocks
,
reg
,
region_name
);
}
}
pos
+=
le32_to_cpu
(
blk
->
len
)
+
sizeof
(
*
blk
);
blocks
++
;
}
if
(
pos
>
firmware
->
size
)
dev_warn
(
codec
->
dev
,
"%s.%d: %d bytes at end of file
\n
"
,
file
,
blocks
,
pos
-
firmware
->
size
);
return
0
;
}
static
int
wm2200_dsp_ev
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kcontrol
,
int
event
)
{
struct
snd_soc_codec
*
codec
=
w
->
codec
;
int
base
=
w
->
reg
-
WM2200_DSP_CONTROL_30
;
int
ret
;
switch
(
event
)
{
case
SND_SOC_DAPM_POST_PMU
:
ret
=
wm2200_dsp_load
(
codec
,
base
);
if
(
ret
!=
0
)
return
ret
;
ret
=
wm2200_setup_algs
(
codec
,
base
);
if
(
ret
!=
0
)
return
ret
;
ret
=
wm2200_load_coeff
(
codec
,
base
);
if
(
ret
!=
0
)
return
ret
;
/* Start the core running */
snd_soc_update_bits
(
codec
,
w
->
reg
,
WM2200_DSP1_CORE_ENA
|
WM2200_DSP1_START
,
WM2200_DSP1_CORE_ENA
|
WM2200_DSP1_START
);
break
;
case
SND_SOC_DAPM_PRE_PMD
:
/* Halt the core */
snd_soc_update_bits
(
codec
,
w
->
reg
,
WM2200_DSP1_CORE_ENA
|
WM2200_DSP1_START
,
0
);
snd_soc_update_bits
(
codec
,
base
+
WM2200_DSP_CONTROL_19
,
WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK
,
0
);
break
;
default:
break
;
}
return
0
;
}
static
DECLARE_TLV_DB_SCALE
(
in_tlv
,
-
6300
,
100
,
0
);
static
DECLARE_TLV_DB_SCALE
(
digital_tlv
,
-
6400
,
50
,
0
);
static
DECLARE_TLV_DB_SCALE
(
out_tlv
,
-
6400
,
100
,
0
);
...
...
@@ -1728,12 +1342,8 @@ SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA
(
"LHPF2"
,
WM2200_HPLPF2_1
,
WM2200_LHPF2_ENA_SHIFT
,
0
,
NULL
,
0
),
SND_SOC_DAPM_PGA_E
(
"DSP1"
,
WM2200_DSP1_CONTROL_30
,
WM2200_DSP1_SYS_ENA_SHIFT
,
0
,
NULL
,
0
,
wm2200_dsp_ev
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_PRE_PMD
),
SND_SOC_DAPM_PGA_E
(
"DSP2"
,
WM2200_DSP2_CONTROL_30
,
WM2200_DSP2_SYS_ENA_SHIFT
,
0
,
NULL
,
0
,
wm2200_dsp_ev
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_PRE_PMD
),
WM_ADSP1
(
"DSP1"
,
0
),
WM_ADSP1
(
"DSP2"
,
1
),
SND_SOC_DAPM_AIF_OUT
(
"AIF1TX1"
,
"Capture"
,
0
,
WM2200_AUDIO_IF_1_22
,
WM2200_AIF1TX1_ENA_SHIFT
,
0
),
...
...
@@ -2595,9 +2205,25 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
ret
=
PTR_ERR
(
wm2200
->
regmap
);
dev_err
(
&
i2c
->
dev
,
"Failed to allocate register map: %d
\n
"
,
ret
);
goto
err
;
return
ret
;
}
for
(
i
=
0
;
i
<
2
;
i
++
)
{
wm2200
->
dsp
[
i
].
type
=
WMFW_ADSP1
;
wm2200
->
dsp
[
i
].
part
=
"wm2200"
;
wm2200
->
dsp
[
i
].
num
=
i
+
1
;
wm2200
->
dsp
[
i
].
dev
=
&
i2c
->
dev
;
wm2200
->
dsp
[
i
].
regmap
=
wm2200
->
regmap
;
}
wm2200
->
dsp
[
0
].
base
=
WM2200_DSP1_CONTROL_1
;
wm2200
->
dsp
[
0
].
mem
=
wm2200_dsp1_regions
;
wm2200
->
dsp
[
0
].
num_mems
=
ARRAY_SIZE
(
wm2200_dsp1_regions
);
wm2200
->
dsp
[
1
].
base
=
WM2200_DSP2_CONTROL_1
;
wm2200
->
dsp
[
1
].
mem
=
wm2200_dsp2_regions
;
wm2200
->
dsp
[
1
].
num_mems
=
ARRAY_SIZE
(
wm2200_dsp2_regions
);
if
(
pdata
)
wm2200
->
pdata
=
*
pdata
;
...
...
@@ -2612,7 +2238,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
if
(
ret
!=
0
)
{
dev_err
(
&
i2c
->
dev
,
"Failed to request core supplies: %d
\n
"
,
ret
);
goto
err_regmap
;
return
ret
;
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
wm2200
->
core_supplies
),
...
...
@@ -2620,7 +2246,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
if
(
ret
!=
0
)
{
dev_err
(
&
i2c
->
dev
,
"Failed to enable core supplies: %d
\n
"
,
ret
);
goto
err_core
;
return
ret
;
}
if
(
wm2200
->
pdata
.
ldo_ena
)
{
...
...
@@ -2756,9 +2382,6 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
err_enable:
regulator_bulk_disable
(
ARRAY_SIZE
(
wm2200
->
core_supplies
),
wm2200
->
core_supplies
);
err_core:
err_regmap:
err:
return
ret
;
}
...
...
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