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
0e09b67e
Commit
0e09b67e
authored
Jun 11, 2009
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dapm' into for-2.6.32
parents
fa44c077
291f3bbc
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
227 additions
and
77 deletions
+227
-77
include/sound/soc.h
include/sound/soc.h
+0
-2
sound/soc/soc-dapm.c
sound/soc/soc-dapm.c
+227
-75
No files found.
include/sound/soc.h
View file @
0e09b67e
...
...
@@ -369,8 +369,6 @@ struct snd_soc_codec {
enum
snd_soc_bias_level
bias_level
;
enum
snd_soc_bias_level
suspend_bias_level
;
struct
delayed_work
delayed_work
;
struct
list_head
up_list
;
struct
list_head
down_list
;
/* codec DAI's */
struct
snd_soc_dai
*
dai
;
...
...
sound/soc/soc-dapm.c
View file @
0e09b67e
...
...
@@ -52,19 +52,37 @@
/* dapm power sequences - make this per codec in the future */
static
int
dapm_up_seq
[]
=
{
snd_soc_dapm_pre
,
snd_soc_dapm_supply
,
snd_soc_dapm_micbias
,
snd_soc_dapm_mic
,
snd_soc_dapm_mux
,
snd_soc_dapm_value_mux
,
snd_soc_dapm_dac
,
snd_soc_dapm_mixer
,
snd_soc_dapm_mixer_named_ctl
,
snd_soc_dapm_pga
,
snd_soc_dapm_adc
,
snd_soc_dapm_hp
,
snd_soc_dapm_spk
,
snd_soc_dapm_post
[
snd_soc_dapm_pre
]
=
0
,
[
snd_soc_dapm_supply
]
=
1
,
[
snd_soc_dapm_micbias
]
=
2
,
[
snd_soc_dapm_mic
]
=
3
,
[
snd_soc_dapm_mux
]
=
4
,
[
snd_soc_dapm_value_mux
]
=
4
,
[
snd_soc_dapm_dac
]
=
5
,
[
snd_soc_dapm_mixer
]
=
6
,
[
snd_soc_dapm_mixer_named_ctl
]
=
6
,
[
snd_soc_dapm_pga
]
=
7
,
[
snd_soc_dapm_adc
]
=
8
,
[
snd_soc_dapm_hp
]
=
9
,
[
snd_soc_dapm_spk
]
=
10
,
[
snd_soc_dapm_post
]
=
11
,
};
static
int
dapm_down_seq
[]
=
{
snd_soc_dapm_pre
,
snd_soc_dapm_adc
,
snd_soc_dapm_hp
,
snd_soc_dapm_spk
,
snd_soc_dapm_pga
,
snd_soc_dapm_mixer_named_ctl
,
snd_soc_dapm_mixer
,
snd_soc_dapm_dac
,
snd_soc_dapm_mic
,
snd_soc_dapm_micbias
,
snd_soc_dapm_mux
,
snd_soc_dapm_value_mux
,
snd_soc_dapm_supply
,
snd_soc_dapm_post
[
snd_soc_dapm_pre
]
=
0
,
[
snd_soc_dapm_adc
]
=
1
,
[
snd_soc_dapm_hp
]
=
2
,
[
snd_soc_dapm_spk
]
=
3
,
[
snd_soc_dapm_pga
]
=
4
,
[
snd_soc_dapm_mixer_named_ctl
]
=
5
,
[
snd_soc_dapm_mixer
]
=
5
,
[
snd_soc_dapm_dac
]
=
6
,
[
snd_soc_dapm_mic
]
=
7
,
[
snd_soc_dapm_micbias
]
=
8
,
[
snd_soc_dapm_mux
]
=
9
,
[
snd_soc_dapm_value_mux
]
=
9
,
[
snd_soc_dapm_supply
]
=
10
,
[
snd_soc_dapm_post
]
=
11
,
};
static
void
pop_wait
(
u32
pop_time
)
...
...
@@ -689,53 +707,211 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
return
power
;
}
/*
* Scan a single DAPM widget for a complete audio path and update the
* power status appropriately.
static
int
dapm_seq_compare
(
struct
snd_soc_dapm_widget
*
a
,
struct
snd_soc_dapm_widget
*
b
,
int
sort
[])
{
if
(
sort
[
a
->
id
]
!=
sort
[
b
->
id
])
return
sort
[
a
->
id
]
-
sort
[
b
->
id
];
if
(
a
->
reg
!=
b
->
reg
)
return
a
->
reg
-
b
->
reg
;
return
0
;
}
/* Insert a widget in order into a DAPM power sequence. */
static
void
dapm_seq_insert
(
struct
snd_soc_dapm_widget
*
new_widget
,
struct
list_head
*
list
,
int
sort
[])
{
struct
snd_soc_dapm_widget
*
w
;
list_for_each_entry
(
w
,
list
,
power_list
)
if
(
dapm_seq_compare
(
new_widget
,
w
,
sort
)
<
0
)
{
list_add_tail
(
&
new_widget
->
power_list
,
&
w
->
power_list
);
return
;
}
list_add_tail
(
&
new_widget
->
power_list
,
list
);
}
/* Apply the coalesced changes from a DAPM sequence */
static
void
dapm_seq_run_coalesced
(
struct
snd_soc_codec
*
codec
,
struct
list_head
*
pending
)
{
struct
snd_soc_dapm_widget
*
w
;
int
reg
,
power
,
ret
;
unsigned
int
value
=
0
;
unsigned
int
mask
=
0
;
unsigned
int
cur_mask
;
reg
=
list_first_entry
(
pending
,
struct
snd_soc_dapm_widget
,
power_list
)
->
reg
;
list_for_each_entry
(
w
,
pending
,
power_list
)
{
cur_mask
=
1
<<
w
->
shift
;
BUG_ON
(
reg
!=
w
->
reg
);
if
(
w
->
invert
)
power
=
!
w
->
power
;
else
power
=
w
->
power
;
mask
|=
cur_mask
;
if
(
power
)
value
|=
cur_mask
;
pop_dbg
(
codec
->
pop_time
,
"pop test : Queue %s: reg=0x%x, 0x%x/0x%x
\n
"
,
w
->
name
,
reg
,
value
,
mask
);
/* power up pre event */
if
(
w
->
power
&&
w
->
event
&&
(
w
->
event_flags
&
SND_SOC_DAPM_PRE_PMU
))
{
pop_dbg
(
codec
->
pop_time
,
"pop test : %s PRE_PMU
\n
"
,
w
->
name
);
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_PRE_PMU
);
if
(
ret
<
0
)
pr_err
(
"%s: pre event failed: %d
\n
"
,
w
->
name
,
ret
);
}
/* power down pre event */
if
(
!
w
->
power
&&
w
->
event
&&
(
w
->
event_flags
&
SND_SOC_DAPM_PRE_PMD
))
{
pop_dbg
(
codec
->
pop_time
,
"pop test : %s PRE_PMD
\n
"
,
w
->
name
);
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_PRE_PMD
);
if
(
ret
<
0
)
pr_err
(
"%s: pre event failed: %d
\n
"
,
w
->
name
,
ret
);
}
/* Lower PGA volume to reduce pops */
if
(
w
->
id
==
snd_soc_dapm_pga
&&
!
w
->
power
)
dapm_set_pga
(
w
,
w
->
power
);
}
if
(
reg
>=
0
)
{
pop_dbg
(
codec
->
pop_time
,
"pop test : Applying 0x%x/0x%x to %x in %dms
\n
"
,
value
,
mask
,
reg
,
codec
->
pop_time
);
pop_wait
(
codec
->
pop_time
);
snd_soc_update_bits
(
codec
,
reg
,
mask
,
value
);
}
list_for_each_entry
(
w
,
pending
,
power_list
)
{
/* Raise PGA volume to reduce pops */
if
(
w
->
id
==
snd_soc_dapm_pga
&&
w
->
power
)
dapm_set_pga
(
w
,
w
->
power
);
/* power up post event */
if
(
w
->
power
&&
w
->
event
&&
(
w
->
event_flags
&
SND_SOC_DAPM_POST_PMU
))
{
pop_dbg
(
codec
->
pop_time
,
"pop test : %s POST_PMU
\n
"
,
w
->
name
);
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_POST_PMU
);
if
(
ret
<
0
)
pr_err
(
"%s: post event failed: %d
\n
"
,
w
->
name
,
ret
);
}
/* power down post event */
if
(
!
w
->
power
&&
w
->
event
&&
(
w
->
event_flags
&
SND_SOC_DAPM_POST_PMD
))
{
pop_dbg
(
codec
->
pop_time
,
"pop test : %s POST_PMD
\n
"
,
w
->
name
);
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_POST_PMD
);
if
(
ret
<
0
)
pr_err
(
"%s: post event failed: %d
\n
"
,
w
->
name
,
ret
);
}
}
}
/* Apply a DAPM power sequence.
*
* We walk over a pre-sorted list of widgets to apply power to. In
* order to minimise the number of writes to the device required
* multiple widgets will be updated in a single write where possible.
* Currently anything that requires more than a single write is not
* handled.
*/
static
int
dapm_power_widget
(
struct
snd_soc_codec
*
codec
,
int
even
t
,
struct
snd_soc_dapm_widget
*
w
)
static
void
dapm_seq_run
(
struct
snd_soc_codec
*
codec
,
struct
list_head
*
lis
t
,
int
event
,
int
sort
[]
)
{
struct
snd_soc_dapm_widget
*
w
,
*
n
;
LIST_HEAD
(
pending
);
int
cur_sort
=
-
1
;
int
cur_reg
=
SND_SOC_NOPM
;
int
ret
;
list_for_each_entry_safe
(
w
,
n
,
list
,
power_list
)
{
ret
=
0
;
/* Do we need to apply any queued changes? */
if
(
sort
[
w
->
id
]
!=
cur_sort
||
w
->
reg
!=
cur_reg
)
{
if
(
!
list_empty
(
&
pending
))
dapm_seq_run_coalesced
(
codec
,
&
pending
);
INIT_LIST_HEAD
(
&
pending
);
cur_sort
=
-
1
;
cur_reg
=
SND_SOC_NOPM
;
}
switch
(
w
->
id
)
{
case
snd_soc_dapm_pre
:
if
(
!
w
->
event
)
return
0
;
list_for_each_entry_safe_continue
(
w
,
n
,
list
,
power_list
);
if
(
event
==
SND_SOC_DAPM_STREAM_START
)
{
if
(
event
==
SND_SOC_DAPM_STREAM_START
)
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_PRE_PMU
);
if
(
ret
<
0
)
return
ret
;
}
else
if
(
event
==
SND_SOC_DAPM_STREAM_STOP
)
{
else
if
(
event
==
SND_SOC_DAPM_STREAM_STOP
)
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_PRE_PMD
);
if
(
ret
<
0
)
return
ret
;
}
return
0
;
break
;
case
snd_soc_dapm_post
:
if
(
!
w
->
event
)
return
0
;
list_for_each_entry_safe_continue
(
w
,
n
,
list
,
power_list
);
if
(
event
==
SND_SOC_DAPM_STREAM_START
)
{
if
(
event
==
SND_SOC_DAPM_STREAM_START
)
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_POST_PMU
);
if
(
ret
<
0
)
return
ret
;
}
else
if
(
event
==
SND_SOC_DAPM_STREAM_STOP
)
{
else
if
(
event
==
SND_SOC_DAPM_STREAM_STOP
)
ret
=
w
->
event
(
w
,
NULL
,
SND_SOC_DAPM_POST_PMD
);
if
(
ret
<
0
)
return
ret
;
}
return
0
;
break
;
case
snd_soc_dapm_input
:
case
snd_soc_dapm_output
:
case
snd_soc_dapm_hp
:
case
snd_soc_dapm_mic
:
case
snd_soc_dapm_line
:
case
snd_soc_dapm_spk
:
/* No register support currently */
ret
=
dapm_generic_apply_power
(
w
);
break
;
default:
return
dapm_generic_apply_power
(
w
);
/* Queue it up for application */
cur_sort
=
sort
[
w
->
id
];
cur_reg
=
w
->
reg
;
list_move
(
&
w
->
power_list
,
&
pending
);
break
;
}
if
(
ret
<
0
)
pr_err
(
"Failed to apply widget power: %d
\n
"
,
ret
);
}
if
(
!
list_empty
(
&
pending
))
dapm_seq_run_coalesced
(
codec
,
&
pending
);
}
/*
...
...
@@ -751,23 +927,22 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
{
struct
snd_soc_device
*
socdev
=
codec
->
socdev
;
struct
snd_soc_dapm_widget
*
w
;
LIST_HEAD
(
up_list
);
LIST_HEAD
(
down_list
);
int
ret
=
0
;
int
i
,
power
;
int
power
;
int
sys_power
=
0
;
INIT_LIST_HEAD
(
&
codec
->
up_list
);
INIT_LIST_HEAD
(
&
codec
->
down_list
);
/* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down.
*/
list_for_each_entry
(
w
,
&
codec
->
dapm_widgets
,
list
)
{
switch
(
w
->
id
)
{
case
snd_soc_dapm_pre
:
list_add_tail
(
&
codec
->
down_list
,
&
w
->
power_list
);
dapm_seq_insert
(
w
,
&
down_list
,
dapm_down_seq
);
break
;
case
snd_soc_dapm_post
:
list_add_tail
(
&
codec
->
up_list
,
&
w
->
power_list
);
dapm_seq_insert
(
w
,
&
up_list
,
dapm_up_seq
);
break
;
default:
...
...
@@ -782,10 +957,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
continue
;
if
(
power
)
list_add_tail
(
&
w
->
power_list
,
&
codec
->
up_list
);
dapm_seq_insert
(
w
,
&
up_list
,
dapm_up_seq
);
else
list_add_tail
(
&
w
->
power_list
,
&
codec
->
down_list
);
dapm_seq_insert
(
w
,
&
down_list
,
dapm_down_seq
);
w
->
power
=
power
;
break
;
...
...
@@ -802,32 +976,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
}
/* Power down widgets first; try to avoid amplifying pops. */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
dapm_down_seq
);
i
++
)
{
list_for_each_entry
(
w
,
&
codec
->
down_list
,
power_list
)
{
/* is widget in stream order */
if
(
w
->
id
!=
dapm_down_seq
[
i
])
continue
;
ret
=
dapm_power_widget
(
codec
,
event
,
w
);
if
(
ret
!=
0
)
pr_err
(
"Failed to power down %s: %d
\n
"
,
w
->
name
,
ret
);
}
}
dapm_seq_run
(
codec
,
&
down_list
,
event
,
dapm_down_seq
);
/* Now power up. */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
dapm_up_seq
);
i
++
)
{
list_for_each_entry
(
w
,
&
codec
->
up_list
,
power_list
)
{
/* is widget in stream order */
if
(
w
->
id
!=
dapm_up_seq
[
i
])
continue
;
ret
=
dapm_power_widget
(
codec
,
event
,
w
);
if
(
ret
!=
0
)
pr_err
(
"Failed to power up %s: %d
\n
"
,
w
->
name
,
ret
);
}
}
dapm_seq_run
(
codec
,
&
up_list
,
event
,
dapm_up_seq
);
/* If we just powered the last thing off drop to standby bias */
if
(
codec
->
bias_level
==
SND_SOC_BIAS_PREPARE
&&
!
sys_power
)
{
...
...
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