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
941725f5
Commit
941725f5
authored
Dec 08, 2014
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/core' into asoc-next
parents
3ee3f454
c362effe
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1388 additions
and
1446 deletions
+1388
-1446
include/sound/soc-dai.h
include/sound/soc-dai.h
+0
-3
include/sound/soc-dapm.h
include/sound/soc-dapm.h
+6
-3
include/sound/soc.h
include/sound/soc.h
+11
-18
sound/soc/Makefile
sound/soc/Makefile
+1
-1
sound/soc/soc-core.c
sound/soc/soc-core.c
+17
-1062
sound/soc/soc-dapm.c
sound/soc/soc-dapm.c
+397
-358
sound/soc/soc-ops.c
sound/soc/soc-ops.c
+952
-0
sound/soc/soc-pcm.c
sound/soc/soc-pcm.c
+3
-0
sound/soc/txx9/txx9aclc.c
sound/soc/txx9/txx9aclc.c
+1
-1
No files found.
include/sound/soc-dai.h
View file @
941725f5
...
@@ -268,7 +268,6 @@ struct snd_soc_dai {
...
@@ -268,7 +268,6 @@ struct snd_soc_dai {
unsigned
int
sample_bits
;
unsigned
int
sample_bits
;
/* parent platform/codec */
/* parent platform/codec */
struct
snd_soc_platform
*
platform
;
struct
snd_soc_codec
*
codec
;
struct
snd_soc_codec
*
codec
;
struct
snd_soc_component
*
component
;
struct
snd_soc_component
*
component
;
...
@@ -276,8 +275,6 @@ struct snd_soc_dai {
...
@@ -276,8 +275,6 @@ struct snd_soc_dai {
unsigned
int
tx_mask
;
unsigned
int
tx_mask
;
unsigned
int
rx_mask
;
unsigned
int
rx_mask
;
struct
snd_soc_card
*
card
;
struct
list_head
list
;
struct
list_head
list
;
};
};
...
...
include/sound/soc-dapm.h
View file @
941725f5
...
@@ -435,7 +435,7 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
...
@@ -435,7 +435,7 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
unsigned
int
dapm_kcontrol_get_value
(
const
struct
snd_kcontrol
*
kcontrol
);
unsigned
int
dapm_kcontrol_get_value
(
const
struct
snd_kcontrol
*
kcontrol
);
/* Mostly internal - should not normally be used */
/* Mostly internal - should not normally be used */
void
dapm_mark_
io_dirty
(
struct
snd_soc_dapm_context
*
dapm
);
void
dapm_mark_
endpoints_dirty
(
struct
snd_soc_card
*
card
);
/* dapm path query */
/* dapm path query */
int
snd_soc_dapm_dai_get_connected_widgets
(
struct
snd_soc_dai
*
dai
,
int
stream
,
int
snd_soc_dapm_dai_get_connected_widgets
(
struct
snd_soc_dai
*
dai
,
int
stream
,
...
@@ -508,9 +508,9 @@ struct snd_soc_dapm_path {
...
@@ -508,9 +508,9 @@ struct snd_soc_dapm_path {
/* status */
/* status */
u32
connect
:
1
;
/* source and sink widgets are connected */
u32
connect
:
1
;
/* source and sink widgets are connected */
u32
walked
:
1
;
/* path has been walked */
u32
walking
:
1
;
/* path is in the process of being walked */
u32
walking
:
1
;
/* path is in the process of being walked */
u32
weak
:
1
;
/* path ignored for power management */
u32
weak
:
1
;
/* path ignored for power management */
u32
is_supply
:
1
;
/* At least one of the connected widgets is a supply */
int
(
*
connected
)(
struct
snd_soc_dapm_widget
*
source
,
int
(
*
connected
)(
struct
snd_soc_dapm_widget
*
source
,
struct
snd_soc_dapm_widget
*
sink
);
struct
snd_soc_dapm_widget
*
sink
);
...
@@ -544,11 +544,13 @@ struct snd_soc_dapm_widget {
...
@@ -544,11 +544,13 @@ struct snd_soc_dapm_widget {
unsigned
char
active
:
1
;
/* active stream on DAC, ADC's */
unsigned
char
active
:
1
;
/* active stream on DAC, ADC's */
unsigned
char
connected
:
1
;
/* connected codec pin */
unsigned
char
connected
:
1
;
/* connected codec pin */
unsigned
char
new
:
1
;
/* cnew complete */
unsigned
char
new
:
1
;
/* cnew complete */
unsigned
char
ext
:
1
;
/* has external widgets */
unsigned
char
force
:
1
;
/* force state */
unsigned
char
force
:
1
;
/* force state */
unsigned
char
ignore_suspend
:
1
;
/* kept enabled over suspend */
unsigned
char
ignore_suspend
:
1
;
/* kept enabled over suspend */
unsigned
char
new_power
:
1
;
/* power from this run */
unsigned
char
new_power
:
1
;
/* power from this run */
unsigned
char
power_checked
:
1
;
/* power checked this run */
unsigned
char
power_checked
:
1
;
/* power checked this run */
unsigned
char
is_supply
:
1
;
/* Widget is a supply type widget */
unsigned
char
is_sink
:
1
;
/* Widget is a sink type widget */
unsigned
char
is_source
:
1
;
/* Widget is a source type widget */
int
subseq
;
/* sort within widget type */
int
subseq
;
/* sort within widget type */
int
(
*
power_check
)(
struct
snd_soc_dapm_widget
*
w
);
int
(
*
power_check
)(
struct
snd_soc_dapm_widget
*
w
);
...
@@ -567,6 +569,7 @@ struct snd_soc_dapm_widget {
...
@@ -567,6 +569,7 @@ struct snd_soc_dapm_widget {
struct
list_head
sinks
;
struct
list_head
sinks
;
/* used during DAPM updates */
/* used during DAPM updates */
struct
list_head
work_list
;
struct
list_head
power_list
;
struct
list_head
power_list
;
struct
list_head
dirty
;
struct
list_head
dirty
;
int
inputs
;
int
inputs
;
...
...
include/sound/soc.h
View file @
941725f5
...
@@ -36,6 +36,11 @@
...
@@ -36,6 +36,11 @@
{.reg = xreg, .rreg = xreg, .shift = shift_left, \
{.reg = xreg, .rreg = xreg, .shift = shift_left, \
.rshift = shift_right, .max = xmax, .platform_max = xmax, \
.rshift = shift_right, .max = xmax, .platform_max = xmax, \
.invert = xinvert, .autodisable = xautodisable})
.invert = xinvert, .autodisable = xautodisable})
#define SOC_DOUBLE_S_VALUE(xreg, shift_left, shift_right, xmin, xmax, xsign_bit, xinvert, xautodisable) \
((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .rreg = xreg, .shift = shift_left, \
.rshift = shift_right, .min = xmin, .max = xmax, .platform_max = xmax, \
.sign_bit = xsign_bit, .invert = xinvert, .autodisable = xautodisable})
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
...
@@ -171,11 +176,9 @@
...
@@ -171,11 +176,9 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw_s8, \
.put = snd_soc_put_volsw, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
.private_value = SOC_DOUBLE_S_VALUE(xreg, 0, 8, xmin, xmax, 7, 0, 0) }
{.reg = xreg, .min = xmin, .max = xmax, \
.platform_max = xmax} }
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
.items = xitems, .texts = xtexts, \
.items = xitems, .texts = xtexts, \
...
@@ -541,12 +544,6 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
...
@@ -541,12 +544,6 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
struct
snd_ctl_elem_value
*
ucontrol
);
struct
snd_ctl_elem_value
*
ucontrol
);
int
snd_soc_put_volsw_sx
(
struct
snd_kcontrol
*
kcontrol
,
int
snd_soc_put_volsw_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
);
struct
snd_ctl_elem_value
*
ucontrol
);
int
snd_soc_info_volsw_s8
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
);
int
snd_soc_get_volsw_s8
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
);
int
snd_soc_put_volsw_s8
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
);
int
snd_soc_info_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
int
snd_soc_info_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
);
struct
snd_ctl_elem_info
*
uinfo
);
int
snd_soc_put_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
int
snd_soc_put_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
...
@@ -854,8 +851,6 @@ struct snd_soc_platform_driver {
...
@@ -854,8 +851,6 @@ struct snd_soc_platform_driver {
int
(
*
probe
)(
struct
snd_soc_platform
*
);
int
(
*
probe
)(
struct
snd_soc_platform
*
);
int
(
*
remove
)(
struct
snd_soc_platform
*
);
int
(
*
remove
)(
struct
snd_soc_platform
*
);
int
(
*
suspend
)(
struct
snd_soc_dai
*
dai
);
int
(
*
resume
)(
struct
snd_soc_dai
*
dai
);
struct
snd_soc_component_driver
component_driver
;
struct
snd_soc_component_driver
component_driver
;
/* pcm creation and destruction */
/* pcm creation and destruction */
...
@@ -880,7 +875,7 @@ struct snd_soc_platform_driver {
...
@@ -880,7 +875,7 @@ struct snd_soc_platform_driver {
struct
snd_soc_dai_link_component
{
struct
snd_soc_dai_link_component
{
const
char
*
name
;
const
char
*
name
;
const
struct
device_node
*
of_node
;
struct
device_node
*
of_node
;
const
char
*
dai_name
;
const
char
*
dai_name
;
};
};
...
@@ -888,8 +883,6 @@ struct snd_soc_platform {
...
@@ -888,8 +883,6 @@ struct snd_soc_platform {
struct
device
*
dev
;
struct
device
*
dev
;
const
struct
snd_soc_platform_driver
*
driver
;
const
struct
snd_soc_platform_driver
*
driver
;
unsigned
int
suspended
:
1
;
/* platform is suspended */
struct
list_head
list
;
struct
list_head
list
;
struct
snd_soc_component
component
;
struct
snd_soc_component
component
;
...
@@ -984,7 +977,7 @@ struct snd_soc_codec_conf {
...
@@ -984,7 +977,7 @@ struct snd_soc_codec_conf {
* DT/OF node, but not both.
* DT/OF node, but not both.
*/
*/
const
char
*
dev_name
;
const
char
*
dev_name
;
const
struct
device_node
*
of_node
;
struct
device_node
*
of_node
;
/*
/*
* optional map of kcontrol, widget and path name prefixes that are
* optional map of kcontrol, widget and path name prefixes that are
...
@@ -1001,7 +994,7 @@ struct snd_soc_aux_dev {
...
@@ -1001,7 +994,7 @@ struct snd_soc_aux_dev {
* DT/OF node, but not both.
* DT/OF node, but not both.
*/
*/
const
char
*
codec_name
;
const
char
*
codec_name
;
const
struct
device_node
*
codec_of_node
;
struct
device_node
*
codec_of_node
;
/* codec/machine specific init - e.g. add machine controls */
/* codec/machine specific init - e.g. add machine controls */
int
(
*
init
)(
struct
snd_soc_component
*
component
);
int
(
*
init
)(
struct
snd_soc_component
*
component
);
...
...
sound/soc/Makefile
View file @
941725f5
snd-soc-core-objs
:=
soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
snd-soc-core-objs
:=
soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
snd-soc-core-objs
+=
soc-pcm.o soc-compress.o soc-io.o soc-devres.o
snd-soc-core-objs
+=
soc-pcm.o soc-compress.o soc-io.o soc-devres.o
soc-ops.o
ifneq
($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
ifneq
($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs
+=
soc-generic-dmaengine-pcm.o
snd-soc-core-objs
+=
soc-generic-dmaengine-pcm.o
...
...
sound/soc/soc-core.c
View file @
941725f5
...
@@ -589,17 +589,12 @@ int snd_soc_suspend(struct device *dev)
...
@@ -589,17 +589,12 @@ int snd_soc_suspend(struct device *dev)
for
(
i
=
0
;
i
<
card
->
num_rtd
;
i
++
)
{
for
(
i
=
0
;
i
<
card
->
num_rtd
;
i
++
)
{
struct
snd_soc_dai
*
cpu_dai
=
card
->
rtd
[
i
].
cpu_dai
;
struct
snd_soc_dai
*
cpu_dai
=
card
->
rtd
[
i
].
cpu_dai
;
struct
snd_soc_platform
*
platform
=
card
->
rtd
[
i
].
platform
;
if
(
card
->
rtd
[
i
].
dai_link
->
ignore_suspend
)
if
(
card
->
rtd
[
i
].
dai_link
->
ignore_suspend
)
continue
;
continue
;
if
(
cpu_dai
->
driver
->
suspend
&&
!
cpu_dai
->
driver
->
ac97_control
)
if
(
cpu_dai
->
driver
->
suspend
&&
!
cpu_dai
->
driver
->
ac97_control
)
cpu_dai
->
driver
->
suspend
(
cpu_dai
);
cpu_dai
->
driver
->
suspend
(
cpu_dai
);
if
(
platform
->
driver
->
suspend
&&
!
platform
->
suspended
)
{
platform
->
driver
->
suspend
(
cpu_dai
);
platform
->
suspended
=
1
;
}
}
}
/* close any waiting streams and save state */
/* close any waiting streams and save state */
...
@@ -626,8 +621,8 @@ int snd_soc_suspend(struct device *dev)
...
@@ -626,8 +621,8 @@ int snd_soc_suspend(struct device *dev)
SND_SOC_DAPM_STREAM_SUSPEND
);
SND_SOC_DAPM_STREAM_SUSPEND
);
}
}
/* Recheck all
analogue paths too
*/
/* Recheck all
endpoints too, their state is affected by suspend
*/
dapm_mark_
io_dirty
(
&
card
->
dapm
);
dapm_mark_
endpoints_dirty
(
card
);
snd_soc_dapm_sync
(
&
card
->
dapm
);
snd_soc_dapm_sync
(
&
card
->
dapm
);
/* suspend all CODECs */
/* suspend all CODECs */
...
@@ -771,17 +766,12 @@ static void soc_resume_deferred(struct work_struct *work)
...
@@ -771,17 +766,12 @@ static void soc_resume_deferred(struct work_struct *work)
for
(
i
=
0
;
i
<
card
->
num_rtd
;
i
++
)
{
for
(
i
=
0
;
i
<
card
->
num_rtd
;
i
++
)
{
struct
snd_soc_dai
*
cpu_dai
=
card
->
rtd
[
i
].
cpu_dai
;
struct
snd_soc_dai
*
cpu_dai
=
card
->
rtd
[
i
].
cpu_dai
;
struct
snd_soc_platform
*
platform
=
card
->
rtd
[
i
].
platform
;
if
(
card
->
rtd
[
i
].
dai_link
->
ignore_suspend
)
if
(
card
->
rtd
[
i
].
dai_link
->
ignore_suspend
)
continue
;
continue
;
if
(
cpu_dai
->
driver
->
resume
&&
!
cpu_dai
->
driver
->
ac97_control
)
if
(
cpu_dai
->
driver
->
resume
&&
!
cpu_dai
->
driver
->
ac97_control
)
cpu_dai
->
driver
->
resume
(
cpu_dai
);
cpu_dai
->
driver
->
resume
(
cpu_dai
);
if
(
platform
->
driver
->
resume
&&
platform
->
suspended
)
{
platform
->
driver
->
resume
(
cpu_dai
);
platform
->
suspended
=
0
;
}
}
}
if
(
card
->
resume_post
)
if
(
card
->
resume_post
)
...
@@ -792,8 +782,8 @@ static void soc_resume_deferred(struct work_struct *work)
...
@@ -792,8 +782,8 @@ static void soc_resume_deferred(struct work_struct *work)
/* userspace can access us now we are back as we were before */
/* userspace can access us now we are back as we were before */
snd_power_change_state
(
card
->
snd_card
,
SNDRV_CTL_POWER_D0
);
snd_power_change_state
(
card
->
snd_card
,
SNDRV_CTL_POWER_D0
);
/* Recheck all
analogue paths too
*/
/* Recheck all
endpoints too, their state is affected by suspend
*/
dapm_mark_
io_dirty
(
&
card
->
dapm
);
dapm_mark_
endpoints_dirty
(
card
);
snd_soc_dapm_sync
(
&
card
->
dapm
);
snd_soc_dapm_sync
(
&
card
->
dapm
);
}
}
...
@@ -1247,25 +1237,22 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
...
@@ -1247,25 +1237,22 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
return
0
;
return
0
;
}
}
static
int
soc_probe_codec_dai
(
struct
snd_soc_card
*
card
,
static
int
soc_probe_dai
(
struct
snd_soc_dai
*
dai
,
int
order
)
struct
snd_soc_dai
*
codec_dai
,
int
order
)
{
{
int
ret
;
int
ret
;
if
(
!
codec_dai
->
probed
&&
codec_
dai
->
driver
->
probe_order
==
order
)
{
if
(
!
dai
->
probed
&&
dai
->
driver
->
probe_order
==
order
)
{
if
(
codec_
dai
->
driver
->
probe
)
{
if
(
dai
->
driver
->
probe
)
{
ret
=
codec_dai
->
driver
->
probe
(
codec_
dai
);
ret
=
dai
->
driver
->
probe
(
dai
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
dev_err
(
codec_
dai
->
dev
,
dev_err
(
dai
->
dev
,
"ASoC: failed to probe
CODEC
DAI %s: %d
\n
"
,
"ASoC: failed to probe DAI %s: %d
\n
"
,
codec_
dai
->
name
,
ret
);
dai
->
name
,
ret
);
return
ret
;
return
ret
;
}
}
}
}
/* mark codec_dai as probed and add to card dai list */
dai
->
probed
=
1
;
codec_dai
->
probed
=
1
;
}
}
return
0
;
return
0
;
...
@@ -1315,40 +1302,22 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
...
@@ -1315,40 +1302,22 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
{
{
struct
snd_soc_dai_link
*
dai_link
=
&
card
->
dai_link
[
num
];
struct
snd_soc_dai_link
*
dai_link
=
&
card
->
dai_link
[
num
];
struct
snd_soc_pcm_runtime
*
rtd
=
&
card
->
rtd
[
num
];
struct
snd_soc_pcm_runtime
*
rtd
=
&
card
->
rtd
[
num
];
struct
snd_soc_platform
*
platform
=
rtd
->
platform
;
struct
snd_soc_dai
*
cpu_dai
=
rtd
->
cpu_dai
;
struct
snd_soc_dai
*
cpu_dai
=
rtd
->
cpu_dai
;
int
i
,
ret
;
int
i
,
ret
;
dev_dbg
(
card
->
dev
,
"ASoC: probe %s dai link %d late %d
\n
"
,
dev_dbg
(
card
->
dev
,
"ASoC: probe %s dai link %d late %d
\n
"
,
card
->
name
,
num
,
order
);
card
->
name
,
num
,
order
);
/* config components */
cpu_dai
->
platform
=
platform
;
cpu_dai
->
card
=
card
;
for
(
i
=
0
;
i
<
rtd
->
num_codecs
;
i
++
)
rtd
->
codec_dais
[
i
]
->
card
=
card
;
/* set default power off timeout */
/* set default power off timeout */
rtd
->
pmdown_time
=
pmdown_time
;
rtd
->
pmdown_time
=
pmdown_time
;
/* probe the cpu_dai */
ret
=
soc_probe_dai
(
cpu_dai
,
order
);
if
(
!
cpu_dai
->
probed
&&
if
(
ret
)
cpu_dai
->
driver
->
probe_order
==
order
)
{
if
(
cpu_dai
->
driver
->
probe
)
{
ret
=
cpu_dai
->
driver
->
probe
(
cpu_dai
);
if
(
ret
<
0
)
{
dev_err
(
cpu_dai
->
dev
,
"ASoC: failed to probe CPU DAI %s: %d
\n
"
,
cpu_dai
->
name
,
ret
);
return
ret
;
return
ret
;
}
}
cpu_dai
->
probed
=
1
;
}
/* probe the CODEC DAI */
/* probe the CODEC DAI */
for
(
i
=
0
;
i
<
rtd
->
num_codecs
;
i
++
)
{
for
(
i
=
0
;
i
<
rtd
->
num_codecs
;
i
++
)
{
ret
=
soc_probe_
codec_dai
(
card
,
rtd
->
codec_dais
[
i
],
order
);
ret
=
soc_probe_
dai
(
rtd
->
codec_dais
[
i
],
order
);
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
}
}
...
@@ -2322,1027 +2291,13 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
...
@@ -2322,1027 +2291,13 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
int
snd_soc_add_dai_controls
(
struct
snd_soc_dai
*
dai
,
int
snd_soc_add_dai_controls
(
struct
snd_soc_dai
*
dai
,
const
struct
snd_kcontrol_new
*
controls
,
int
num_controls
)
const
struct
snd_kcontrol_new
*
controls
,
int
num_controls
)
{
{
struct
snd_card
*
card
=
dai
->
card
->
snd_card
;
struct
snd_card
*
card
=
dai
->
c
omponent
->
c
ard
->
snd_card
;
return
snd_soc_add_controls
(
card
,
dai
->
dev
,
controls
,
num_controls
,
return
snd_soc_add_controls
(
card
,
dai
->
dev
,
controls
,
num_controls
,
NULL
,
dai
);
NULL
,
dai
);
}
}
EXPORT_SYMBOL_GPL
(
snd_soc_add_dai_controls
);
EXPORT_SYMBOL_GPL
(
snd_soc_add_dai_controls
);
/**
* snd_soc_info_enum_double - enumerated double mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a double enumerated
* mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_info_enum_double
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_ENUMERATED
;
uinfo
->
count
=
e
->
shift_l
==
e
->
shift_r
?
1
:
2
;
uinfo
->
value
.
enumerated
.
items
=
e
->
items
;
if
(
uinfo
->
value
.
enumerated
.
item
>=
e
->
items
)
uinfo
->
value
.
enumerated
.
item
=
e
->
items
-
1
;
strlcpy
(
uinfo
->
value
.
enumerated
.
name
,
e
->
texts
[
uinfo
->
value
.
enumerated
.
item
],
sizeof
(
uinfo
->
value
.
enumerated
.
name
));
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_enum_double
);
/**
* snd_soc_get_enum_double - enumerated double mixer get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value of a double enumerated mixer.
*
* Returns 0 for success.
*/
int
snd_soc_get_enum_double
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
unsigned
int
val
,
item
;
unsigned
int
reg_val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
e
->
reg
,
&
reg_val
);
if
(
ret
)
return
ret
;
val
=
(
reg_val
>>
e
->
shift_l
)
&
e
->
mask
;
item
=
snd_soc_enum_val_to_item
(
e
,
val
);
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
item
;
if
(
e
->
shift_l
!=
e
->
shift_r
)
{
val
=
(
reg_val
>>
e
->
shift_l
)
&
e
->
mask
;
item
=
snd_soc_enum_val_to_item
(
e
,
val
);
ucontrol
->
value
.
enumerated
.
item
[
1
]
=
item
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_enum_double
);
/**
* snd_soc_put_enum_double - enumerated double mixer put callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value of a double enumerated mixer.
*
* Returns 0 for success.
*/
int
snd_soc_put_enum_double
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
unsigned
int
*
item
=
ucontrol
->
value
.
enumerated
.
item
;
unsigned
int
val
;
unsigned
int
mask
;
if
(
item
[
0
]
>=
e
->
items
)
return
-
EINVAL
;
val
=
snd_soc_enum_item_to_val
(
e
,
item
[
0
])
<<
e
->
shift_l
;
mask
=
e
->
mask
<<
e
->
shift_l
;
if
(
e
->
shift_l
!=
e
->
shift_r
)
{
if
(
item
[
1
]
>=
e
->
items
)
return
-
EINVAL
;
val
|=
snd_soc_enum_item_to_val
(
e
,
item
[
1
])
<<
e
->
shift_r
;
mask
|=
e
->
mask
<<
e
->
shift_r
;
}
return
snd_soc_component_update_bits
(
component
,
e
->
reg
,
mask
,
val
);
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_enum_double
);
/**
* snd_soc_read_signed - Read a codec register and interprete as signed value
* @component: component
* @reg: Register to read
* @mask: Mask to use after shifting the register value
* @shift: Right shift of register value
* @sign_bit: Bit that describes if a number is negative or not.
* @signed_val: Pointer to where the read value should be stored
*
* This functions reads a codec register. The register value is shifted right
* by 'shift' bits and masked with the given 'mask'. Afterwards it translates
* the given registervalue into a signed integer if sign_bit is non-zero.
*
* Returns 0 on sucess, otherwise an error value
*/
static
int
snd_soc_read_signed
(
struct
snd_soc_component
*
component
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
shift
,
unsigned
int
sign_bit
,
int
*
signed_val
)
{
int
ret
;
unsigned
int
val
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
<
0
)
return
ret
;
val
=
(
val
>>
shift
)
&
mask
;
if
(
!
sign_bit
)
{
*
signed_val
=
val
;
return
0
;
}
/* non-negative number */
if
(
!
(
val
&
BIT
(
sign_bit
)))
{
*
signed_val
=
val
;
return
0
;
}
ret
=
val
;
/*
* The register most probably does not contain a full-sized int.
* Instead we have an arbitrary number of bits in a signed
* representation which has to be translated into a full-sized int.
* This is done by filling up all bits above the sign-bit.
*/
ret
|=
~
((
int
)(
BIT
(
sign_bit
)
-
1
));
*
signed_val
=
ret
;
return
0
;
}
/**
* snd_soc_info_volsw - single mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a single mixer control, or a double
* mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_info_volsw
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
int
platform_max
;
if
(
!
mc
->
platform_max
)
mc
->
platform_max
=
mc
->
max
;
platform_max
=
mc
->
platform_max
;
if
(
platform_max
==
1
&&
!
strstr
(
kcontrol
->
id
.
name
,
" Volume"
))
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
else
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_INTEGER
;
uinfo
->
count
=
snd_soc_volsw_is_stereo
(
mc
)
?
2
:
1
;
uinfo
->
value
.
integer
.
min
=
0
;
uinfo
->
value
.
integer
.
max
=
platform_max
-
mc
->
min
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_volsw
);
/**
* snd_soc_get_volsw - single mixer get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value of a single mixer control, or a double mixer
* control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_get_volsw
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
int
sign_bit
=
mc
->
sign_bit
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
int
val
;
int
ret
;
if
(
sign_bit
)
mask
=
BIT
(
sign_bit
+
1
)
-
1
;
ret
=
snd_soc_read_signed
(
component
,
reg
,
mask
,
shift
,
sign_bit
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
val
-
min
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
0
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
0
];
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
if
(
reg
==
reg2
)
ret
=
snd_soc_read_signed
(
component
,
reg
,
mask
,
rshift
,
sign_bit
,
&
val
);
else
ret
=
snd_soc_read_signed
(
component
,
reg2
,
mask
,
shift
,
sign_bit
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
1
]
=
val
-
min
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
1
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
1
];
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_volsw
);
/**
* snd_soc_put_volsw - single mixer put callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value of a single mixer control, or a double mixer
* control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_put_volsw
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
unsigned
int
sign_bit
=
mc
->
sign_bit
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
int
err
;
bool
type_2r
=
false
;
unsigned
int
val2
=
0
;
unsigned
int
val
,
val_mask
;
if
(
sign_bit
)
mask
=
BIT
(
sign_bit
+
1
)
-
1
;
val
=
((
ucontrol
->
value
.
integer
.
value
[
0
]
+
min
)
&
mask
);
if
(
invert
)
val
=
max
-
val
;
val_mask
=
mask
<<
shift
;
val
=
val
<<
shift
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
val2
=
((
ucontrol
->
value
.
integer
.
value
[
1
]
+
min
)
&
mask
);
if
(
invert
)
val2
=
max
-
val2
;
if
(
reg
==
reg2
)
{
val_mask
|=
mask
<<
rshift
;
val
|=
val2
<<
rshift
;
}
else
{
val2
=
val2
<<
shift
;
type_2r
=
true
;
}
}
err
=
snd_soc_component_update_bits
(
component
,
reg
,
val_mask
,
val
);
if
(
err
<
0
)
return
err
;
if
(
type_2r
)
err
=
snd_soc_component_update_bits
(
component
,
reg2
,
val_mask
,
val2
);
return
err
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_volsw
);
/**
* snd_soc_get_volsw_sx - single mixer get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value of a single mixer control, or a double mixer
* control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_get_volsw_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
int
mask
=
(
1
<<
(
fls
(
min
+
max
)
-
1
))
-
1
;
unsigned
int
val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
<
0
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
((
val
>>
shift
)
-
min
)
&
mask
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
ret
=
snd_soc_component_read
(
component
,
reg2
,
&
val
);
if
(
ret
<
0
)
return
ret
;
val
=
((
val
>>
rshift
)
-
min
)
&
mask
;
ucontrol
->
value
.
integer
.
value
[
1
]
=
val
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_volsw_sx
);
/**
* snd_soc_put_volsw_sx - double mixer set callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to set the value of a double mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_put_volsw_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
int
mask
=
(
1
<<
(
fls
(
min
+
max
)
-
1
))
-
1
;
int
err
=
0
;
unsigned
int
val
,
val_mask
,
val2
=
0
;
val_mask
=
mask
<<
shift
;
val
=
(
ucontrol
->
value
.
integer
.
value
[
0
]
+
min
)
&
mask
;
val
=
val
<<
shift
;
err
=
snd_soc_component_update_bits
(
component
,
reg
,
val_mask
,
val
);
if
(
err
<
0
)
return
err
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
val_mask
=
mask
<<
rshift
;
val2
=
(
ucontrol
->
value
.
integer
.
value
[
1
]
+
min
)
&
mask
;
val2
=
val2
<<
rshift
;
err
=
snd_soc_component_update_bits
(
component
,
reg2
,
val_mask
,
val2
);
}
return
err
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_volsw_sx
);
/**
* snd_soc_info_volsw_s8 - signed mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a signed mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_info_volsw_s8
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
int
platform_max
;
int
min
=
mc
->
min
;
if
(
!
mc
->
platform_max
)
mc
->
platform_max
=
mc
->
max
;
platform_max
=
mc
->
platform_max
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_INTEGER
;
uinfo
->
count
=
2
;
uinfo
->
value
.
integer
.
min
=
0
;
uinfo
->
value
.
integer
.
max
=
platform_max
-
min
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_volsw_s8
);
/**
* snd_soc_get_volsw_s8 - signed mixer get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value of a signed mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_get_volsw_s8
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
val
;
int
min
=
mc
->
min
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
((
signed
char
)(
val
&
0xff
))
-
min
;
ucontrol
->
value
.
integer
.
value
[
1
]
=
((
signed
char
)((
val
>>
8
)
&
0xff
))
-
min
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_volsw_s8
);
/**
* snd_soc_put_volsw_sgn - signed mixer put callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value of a signed mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_put_volsw_s8
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
unsigned
int
reg
=
mc
->
reg
;
int
min
=
mc
->
min
;
unsigned
int
val
;
val
=
(
ucontrol
->
value
.
integer
.
value
[
0
]
+
min
)
&
0xff
;
val
|=
((
ucontrol
->
value
.
integer
.
value
[
1
]
+
min
)
&
0xff
)
<<
8
;
return
snd_soc_component_update_bits
(
component
,
reg
,
0xffff
,
val
);
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_volsw_s8
);
/**
* snd_soc_info_volsw_range - single mixer info callback with range.
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information, within a range, about a single
* mixer control.
*
* returns 0 for success.
*/
int
snd_soc_info_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
int
platform_max
;
int
min
=
mc
->
min
;
if
(
!
mc
->
platform_max
)
mc
->
platform_max
=
mc
->
max
;
platform_max
=
mc
->
platform_max
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_INTEGER
;
uinfo
->
count
=
snd_soc_volsw_is_stereo
(
mc
)
?
2
:
1
;
uinfo
->
value
.
integer
.
min
=
0
;
uinfo
->
value
.
integer
.
max
=
platform_max
-
min
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_volsw_range
);
/**
* snd_soc_put_volsw_range - single mixer put value callback with range.
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value, within a range, for a single mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_put_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
rreg
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
int
min
=
mc
->
min
;
int
max
=
mc
->
max
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
int
val
,
val_mask
;
int
ret
;
if
(
invert
)
val
=
(
max
-
ucontrol
->
value
.
integer
.
value
[
0
])
&
mask
;
else
val
=
((
ucontrol
->
value
.
integer
.
value
[
0
]
+
min
)
&
mask
);
val_mask
=
mask
<<
shift
;
val
=
val
<<
shift
;
ret
=
snd_soc_component_update_bits
(
component
,
reg
,
val_mask
,
val
);
if
(
ret
<
0
)
return
ret
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
if
(
invert
)
val
=
(
max
-
ucontrol
->
value
.
integer
.
value
[
1
])
&
mask
;
else
val
=
((
ucontrol
->
value
.
integer
.
value
[
1
]
+
min
)
&
mask
);
val_mask
=
mask
<<
shift
;
val
=
val
<<
shift
;
ret
=
snd_soc_component_update_bits
(
component
,
rreg
,
val_mask
,
val
);
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_volsw_range
);
/**
* snd_soc_get_volsw_range - single mixer get callback with range
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value, within a range, of a single mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_get_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
rreg
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
int
min
=
mc
->
min
;
int
max
=
mc
->
max
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
int
val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
(
val
>>
shift
)
&
mask
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
0
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
0
];
else
ucontrol
->
value
.
integer
.
value
[
0
]
=
ucontrol
->
value
.
integer
.
value
[
0
]
-
min
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
ret
=
snd_soc_component_read
(
component
,
rreg
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
1
]
=
(
val
>>
shift
)
&
mask
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
1
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
1
];
else
ucontrol
->
value
.
integer
.
value
[
1
]
=
ucontrol
->
value
.
integer
.
value
[
1
]
-
min
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_volsw_range
);
/**
* snd_soc_limit_volume - Set new limit to an existing volume control.
*
* @codec: where to look for the control
* @name: Name of the control
* @max: new maximum limit
*
* Return 0 for success, else error.
*/
int
snd_soc_limit_volume
(
struct
snd_soc_codec
*
codec
,
const
char
*
name
,
int
max
)
{
struct
snd_card
*
card
=
codec
->
component
.
card
->
snd_card
;
struct
snd_kcontrol
*
kctl
;
struct
soc_mixer_control
*
mc
;
int
found
=
0
;
int
ret
=
-
EINVAL
;
/* Sanity check for name and max */
if
(
unlikely
(
!
name
||
max
<=
0
))
return
-
EINVAL
;
list_for_each_entry
(
kctl
,
&
card
->
controls
,
list
)
{
if
(
!
strncmp
(
kctl
->
id
.
name
,
name
,
sizeof
(
kctl
->
id
.
name
)))
{
found
=
1
;
break
;
}
}
if
(
found
)
{
mc
=
(
struct
soc_mixer_control
*
)
kctl
->
private_value
;
if
(
max
<=
mc
->
max
)
{
mc
->
platform_max
=
max
;
ret
=
0
;
}
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_limit_volume
);
int
snd_soc_bytes_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_bytes
*
params
=
(
void
*
)
kcontrol
->
private_value
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_BYTES
;
uinfo
->
count
=
params
->
num_regs
*
component
->
val_bytes
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_info
);
int
snd_soc_bytes_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_bytes
*
params
=
(
void
*
)
kcontrol
->
private_value
;
int
ret
;
if
(
component
->
regmap
)
ret
=
regmap_raw_read
(
component
->
regmap
,
params
->
base
,
ucontrol
->
value
.
bytes
.
data
,
params
->
num_regs
*
component
->
val_bytes
);
else
ret
=
-
EINVAL
;
/* Hide any masked bytes to ensure consistent data reporting */
if
(
ret
==
0
&&
params
->
mask
)
{
switch
(
component
->
val_bytes
)
{
case
1
:
ucontrol
->
value
.
bytes
.
data
[
0
]
&=
~
params
->
mask
;
break
;
case
2
:
((
u16
*
)(
&
ucontrol
->
value
.
bytes
.
data
))[
0
]
&=
cpu_to_be16
(
~
params
->
mask
);
break
;
case
4
:
((
u32
*
)(
&
ucontrol
->
value
.
bytes
.
data
))[
0
]
&=
cpu_to_be32
(
~
params
->
mask
);
break
;
default:
return
-
EINVAL
;
}
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_get
);
int
snd_soc_bytes_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_bytes
*
params
=
(
void
*
)
kcontrol
->
private_value
;
int
ret
,
len
;
unsigned
int
val
,
mask
;
void
*
data
;
if
(
!
component
->
regmap
||
!
params
->
num_regs
)
return
-
EINVAL
;
len
=
params
->
num_regs
*
component
->
val_bytes
;
data
=
kmemdup
(
ucontrol
->
value
.
bytes
.
data
,
len
,
GFP_KERNEL
|
GFP_DMA
);
if
(
!
data
)
return
-
ENOMEM
;
/*
* If we've got a mask then we need to preserve the register
* bits. We shouldn't modify the incoming data so take a
* copy.
*/
if
(
params
->
mask
)
{
ret
=
regmap_read
(
component
->
regmap
,
params
->
base
,
&
val
);
if
(
ret
!=
0
)
goto
out
;
val
&=
params
->
mask
;
switch
(
component
->
val_bytes
)
{
case
1
:
((
u8
*
)
data
)[
0
]
&=
~
params
->
mask
;
((
u8
*
)
data
)[
0
]
|=
val
;
break
;
case
2
:
mask
=
~
params
->
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
mask
,
&
mask
);
if
(
ret
!=
0
)
goto
out
;
((
u16
*
)
data
)[
0
]
&=
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
val
,
&
val
);
if
(
ret
!=
0
)
goto
out
;
((
u16
*
)
data
)[
0
]
|=
val
;
break
;
case
4
:
mask
=
~
params
->
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
mask
,
&
mask
);
if
(
ret
!=
0
)
goto
out
;
((
u32
*
)
data
)[
0
]
&=
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
val
,
&
val
);
if
(
ret
!=
0
)
goto
out
;
((
u32
*
)
data
)[
0
]
|=
val
;
break
;
default:
ret
=
-
EINVAL
;
goto
out
;
}
}
ret
=
regmap_raw_write
(
component
->
regmap
,
params
->
base
,
data
,
len
);
out:
kfree
(
data
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_put
);
int
snd_soc_bytes_info_ext
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
ucontrol
)
{
struct
soc_bytes_ext
*
params
=
(
void
*
)
kcontrol
->
private_value
;
ucontrol
->
type
=
SNDRV_CTL_ELEM_TYPE_BYTES
;
ucontrol
->
count
=
params
->
max
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_info_ext
);
int
snd_soc_bytes_tlv_callback
(
struct
snd_kcontrol
*
kcontrol
,
int
op_flag
,
unsigned
int
size
,
unsigned
int
__user
*
tlv
)
{
struct
soc_bytes_ext
*
params
=
(
void
*
)
kcontrol
->
private_value
;
unsigned
int
count
=
size
<
params
->
max
?
size
:
params
->
max
;
int
ret
=
-
ENXIO
;
switch
(
op_flag
)
{
case
SNDRV_CTL_TLV_OP_READ
:
if
(
params
->
get
)
ret
=
params
->
get
(
tlv
,
count
);
break
;
case
SNDRV_CTL_TLV_OP_WRITE
:
if
(
params
->
put
)
ret
=
params
->
put
(
tlv
,
count
);
break
;
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_tlv_callback
);
/**
* snd_soc_info_xr_sx - signed multi register info callback
* @kcontrol: mreg control
* @uinfo: control element information
*
* Callback to provide information of a control that can
* span multiple codec registers which together
* forms a single signed value in a MSB/LSB manner.
*
* Returns 0 for success.
*/
int
snd_soc_info_xr_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_mreg_control
*
mc
=
(
struct
soc_mreg_control
*
)
kcontrol
->
private_value
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_INTEGER
;
uinfo
->
count
=
1
;
uinfo
->
value
.
integer
.
min
=
mc
->
min
;
uinfo
->
value
.
integer
.
max
=
mc
->
max
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_xr_sx
);
/**
* snd_soc_get_xr_sx - signed multi register get callback
* @kcontrol: mreg control
* @ucontrol: control element information
*
* Callback to get the value of a control that can span
* multiple codec registers which together forms a single
* signed value in a MSB/LSB manner. The control supports
* specifying total no of bits used to allow for bitfields
* across the multiple codec registers.
*
* Returns 0 for success.
*/
int
snd_soc_get_xr_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mreg_control
*
mc
=
(
struct
soc_mreg_control
*
)
kcontrol
->
private_value
;
unsigned
int
regbase
=
mc
->
regbase
;
unsigned
int
regcount
=
mc
->
regcount
;
unsigned
int
regwshift
=
component
->
val_bytes
*
BITS_PER_BYTE
;
unsigned
int
regwmask
=
(
1
<<
regwshift
)
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
long
mask
=
(
1UL
<<
mc
->
nbits
)
-
1
;
long
min
=
mc
->
min
;
long
max
=
mc
->
max
;
long
val
=
0
;
unsigned
int
regval
;
unsigned
int
i
;
int
ret
;
for
(
i
=
0
;
i
<
regcount
;
i
++
)
{
ret
=
snd_soc_component_read
(
component
,
regbase
+
i
,
&
regval
);
if
(
ret
)
return
ret
;
val
|=
(
regval
&
regwmask
)
<<
(
regwshift
*
(
regcount
-
i
-
1
));
}
val
&=
mask
;
if
(
min
<
0
&&
val
>
max
)
val
|=
~
mask
;
if
(
invert
)
val
=
max
-
val
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
val
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_xr_sx
);
/**
* snd_soc_put_xr_sx - signed multi register get callback
* @kcontrol: mreg control
* @ucontrol: control element information
*
* Callback to set the value of a control that can span
* multiple codec registers which together forms a single
* signed value in a MSB/LSB manner. The control supports
* specifying total no of bits used to allow for bitfields
* across the multiple codec registers.
*
* Returns 0 for success.
*/
int
snd_soc_put_xr_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mreg_control
*
mc
=
(
struct
soc_mreg_control
*
)
kcontrol
->
private_value
;
unsigned
int
regbase
=
mc
->
regbase
;
unsigned
int
regcount
=
mc
->
regcount
;
unsigned
int
regwshift
=
component
->
val_bytes
*
BITS_PER_BYTE
;
unsigned
int
regwmask
=
(
1
<<
regwshift
)
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
long
mask
=
(
1UL
<<
mc
->
nbits
)
-
1
;
long
max
=
mc
->
max
;
long
val
=
ucontrol
->
value
.
integer
.
value
[
0
];
unsigned
int
i
,
regval
,
regmask
;
int
err
;
if
(
invert
)
val
=
max
-
val
;
val
&=
mask
;
for
(
i
=
0
;
i
<
regcount
;
i
++
)
{
regval
=
(
val
>>
(
regwshift
*
(
regcount
-
i
-
1
)))
&
regwmask
;
regmask
=
(
mask
>>
(
regwshift
*
(
regcount
-
i
-
1
)))
&
regwmask
;
err
=
snd_soc_component_update_bits
(
component
,
regbase
+
i
,
regmask
,
regval
);
if
(
err
<
0
)
return
err
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_xr_sx
);
/**
* snd_soc_get_strobe - strobe get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback get the value of a strobe mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_get_strobe
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
mask
=
1
<<
shift
;
unsigned
int
invert
=
mc
->
invert
!=
0
;
unsigned
int
val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
val
&=
mask
;
if
(
shift
!=
0
&&
val
!=
0
)
val
=
val
>>
shift
;
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
val
^
invert
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_strobe
);
/**
* snd_soc_put_strobe - strobe put callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback strobe a register bit to high then low (or the inverse)
* in one pass of a single mixer enum control.
*
* Returns 1 for success.
*/
int
snd_soc_put_strobe
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
mask
=
1
<<
shift
;
unsigned
int
invert
=
mc
->
invert
!=
0
;
unsigned
int
strobe
=
ucontrol
->
value
.
enumerated
.
item
[
0
]
!=
0
;
unsigned
int
val1
=
(
strobe
^
invert
)
?
mask
:
0
;
unsigned
int
val2
=
(
strobe
^
invert
)
?
0
:
mask
;
int
err
;
err
=
snd_soc_component_update_bits
(
component
,
reg
,
mask
,
val1
);
if
(
err
<
0
)
return
err
;
return
snd_soc_component_update_bits
(
component
,
reg
,
mask
,
val2
);
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_strobe
);
/**
/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
* @dai: DAI
...
...
sound/soc/soc-dapm.c
View file @
941725f5
...
@@ -159,27 +159,135 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
...
@@ -159,27 +159,135 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
}
}
}
}
void
dapm_mark_io_dirty
(
struct
snd_soc_dapm_context
*
dapm
)
/*
* dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
* paths
* @w: The widget for which to invalidate the cached number of input paths
*
* The function resets the cached number of inputs for the specified widget and
* all widgets that can be reached via outgoing paths from the widget.
*
* This function must be called if the number of input paths for a widget might
* have changed. E.g. if the source state of a widget changes or a path is added
* or activated with the widget as the sink.
*/
static
void
dapm_widget_invalidate_input_paths
(
struct
snd_soc_dapm_widget
*
w
)
{
struct
snd_soc_dapm_widget
*
sink
;
struct
snd_soc_dapm_path
*
p
;
LIST_HEAD
(
list
);
dapm_assert_locked
(
w
->
dapm
);
if
(
w
->
inputs
==
-
1
)
return
;
w
->
inputs
=
-
1
;
list_add_tail
(
&
w
->
work_list
,
&
list
);
list_for_each_entry
(
w
,
&
list
,
work_list
)
{
list_for_each_entry
(
p
,
&
w
->
sinks
,
list_source
)
{
if
(
p
->
is_supply
||
p
->
weak
||
!
p
->
connect
)
continue
;
sink
=
p
->
sink
;
if
(
sink
->
inputs
!=
-
1
)
{
sink
->
inputs
=
-
1
;
list_add_tail
(
&
sink
->
work_list
,
&
list
);
}
}
}
}
/*
* dapm_widget_invalidate_output_paths() - Invalidate the cached number of
* output paths
* @w: The widget for which to invalidate the cached number of output paths
*
* Resets the cached number of outputs for the specified widget and all widgets
* that can be reached via incoming paths from the widget.
*
* This function must be called if the number of output paths for a widget might
* have changed. E.g. if the sink state of a widget changes or a path is added
* or activated with the widget as the source.
*/
static
void
dapm_widget_invalidate_output_paths
(
struct
snd_soc_dapm_widget
*
w
)
{
struct
snd_soc_dapm_widget
*
source
;
struct
snd_soc_dapm_path
*
p
;
LIST_HEAD
(
list
);
dapm_assert_locked
(
w
->
dapm
);
if
(
w
->
outputs
==
-
1
)
return
;
w
->
outputs
=
-
1
;
list_add_tail
(
&
w
->
work_list
,
&
list
);
list_for_each_entry
(
w
,
&
list
,
work_list
)
{
list_for_each_entry
(
p
,
&
w
->
sources
,
list_sink
)
{
if
(
p
->
is_supply
||
p
->
weak
||
!
p
->
connect
)
continue
;
source
=
p
->
source
;
if
(
source
->
outputs
!=
-
1
)
{
source
->
outputs
=
-
1
;
list_add_tail
(
&
source
->
work_list
,
&
list
);
}
}
}
}
/*
* dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
* for the widgets connected to a path
* @p: The path to invalidate
*
* Resets the cached number of inputs for the sink of the path and the cached
* number of outputs for the source of the path.
*
* This function must be called when a path is added, removed or the connected
* state changes.
*/
static
void
dapm_path_invalidate
(
struct
snd_soc_dapm_path
*
p
)
{
/*
* Weak paths or supply paths do not influence the number of input or
* output paths of their neighbors.
*/
if
(
p
->
weak
||
p
->
is_supply
)
return
;
/*
* The number of connected endpoints is the sum of the number of
* connected endpoints of all neighbors. If a node with 0 connected
* endpoints is either connected or disconnected that sum won't change,
* so there is no need to re-check the path.
*/
if
(
p
->
source
->
inputs
!=
0
)
dapm_widget_invalidate_input_paths
(
p
->
sink
);
if
(
p
->
sink
->
outputs
!=
0
)
dapm_widget_invalidate_output_paths
(
p
->
source
);
}
void
dapm_mark_endpoints_dirty
(
struct
snd_soc_card
*
card
)
{
{
struct
snd_soc_card
*
card
=
dapm
->
card
;
struct
snd_soc_dapm_widget
*
w
;
struct
snd_soc_dapm_widget
*
w
;
mutex_lock
(
&
card
->
dapm_mutex
);
mutex_lock
(
&
card
->
dapm_mutex
);
list_for_each_entry
(
w
,
&
card
->
widgets
,
list
)
{
list_for_each_entry
(
w
,
&
card
->
widgets
,
list
)
{
switch
(
w
->
id
)
{
if
(
w
->
is_sink
||
w
->
is_source
)
{
case
snd_soc_dapm_input
:
dapm_mark_dirty
(
w
,
"Rechecking endpoints"
);
case
snd_soc_dapm_output
:
if
(
w
->
is_sink
)
dapm_mark_dirty
(
w
,
"Rechecking inputs and outputs"
);
dapm_widget_invalidate_output_paths
(
w
);
break
;
if
(
w
->
is_source
)
default:
dapm_widget_invalidate_input_paths
(
w
);
break
;
}
}
}
}
mutex_unlock
(
&
card
->
dapm_mutex
);
mutex_unlock
(
&
card
->
dapm_mutex
);
}
}
EXPORT_SYMBOL_GPL
(
dapm_mark_
io
_dirty
);
EXPORT_SYMBOL_GPL
(
dapm_mark_
endpoints
_dirty
);
/* create a new dapm widget */
/* create a new dapm widget */
static
inline
struct
snd_soc_dapm_widget
*
dapm_cnew_widget
(
static
inline
struct
snd_soc_dapm_widget
*
dapm_cnew_widget
(
...
@@ -386,8 +494,6 @@ static void dapm_reset(struct snd_soc_card *card)
...
@@ -386,8 +494,6 @@ static void dapm_reset(struct snd_soc_card *card)
list_for_each_entry
(
w
,
&
card
->
widgets
,
list
)
{
list_for_each_entry
(
w
,
&
card
->
widgets
,
list
)
{
w
->
new_power
=
w
->
power
;
w
->
new_power
=
w
->
power
;
w
->
power_checked
=
false
;
w
->
power_checked
=
false
;
w
->
inputs
=
-
1
;
w
->
outputs
=
-
1
;
}
}
}
}
...
@@ -469,10 +575,9 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
...
@@ -469,10 +575,9 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
/* connect mux widget to its interconnecting audio paths */
/* connect mux widget to its interconnecting audio paths */
static
int
dapm_connect_mux
(
struct
snd_soc_dapm_context
*
dapm
,
static
int
dapm_connect_mux
(
struct
snd_soc_dapm_context
*
dapm
,
struct
snd_soc_dapm_widget
*
src
,
struct
snd_soc_dapm_widget
*
dest
,
struct
snd_soc_dapm_path
*
path
,
const
char
*
control_name
)
struct
snd_soc_dapm_path
*
path
,
const
char
*
control_name
,
const
struct
snd_kcontrol_new
*
kcontrol
)
{
{
const
struct
snd_kcontrol_new
*
kcontrol
=
&
path
->
sink
->
kcontrol_news
[
0
];
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
unsigned
int
val
,
item
;
unsigned
int
val
,
item
;
int
i
;
int
i
;
...
@@ -493,10 +598,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
...
@@ -493,10 +598,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
for
(
i
=
0
;
i
<
e
->
items
;
i
++
)
{
for
(
i
=
0
;
i
<
e
->
items
;
i
++
)
{
if
(
!
(
strcmp
(
control_name
,
e
->
texts
[
i
])))
{
if
(
!
(
strcmp
(
control_name
,
e
->
texts
[
i
])))
{
list_add
(
&
path
->
list
,
&
dapm
->
card
->
paths
);
path
->
name
=
e
->
texts
[
i
];
list_add
(
&
path
->
list_sink
,
&
dest
->
sources
);
list_add
(
&
path
->
list_source
,
&
src
->
sinks
);
path
->
name
=
(
char
*
)
e
->
texts
[
i
];
if
(
i
==
item
)
if
(
i
==
item
)
path
->
connect
=
1
;
path
->
connect
=
1
;
else
else
...
@@ -509,11 +611,10 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
...
@@ -509,11 +611,10 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
}
}
/* set up initial codec paths */
/* set up initial codec paths */
static
void
dapm_set_mixer_path_status
(
struct
snd_soc_dapm_widget
*
w
,
static
void
dapm_set_mixer_path_status
(
struct
snd_soc_dapm_path
*
p
,
int
i
)
struct
snd_soc_dapm_path
*
p
,
int
i
)
{
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
w
->
kcontrol_news
[
i
].
private_value
;
p
->
sink
->
kcontrol_news
[
i
].
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
max
=
mc
->
max
;
unsigned
int
max
=
mc
->
max
;
...
@@ -522,7 +623,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
...
@@ -522,7 +623,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
unsigned
int
val
;
unsigned
int
val
;
if
(
reg
!=
SND_SOC_NOPM
)
{
if
(
reg
!=
SND_SOC_NOPM
)
{
soc_dapm_read
(
w
->
dapm
,
reg
,
&
val
);
soc_dapm_read
(
p
->
sink
->
dapm
,
reg
,
&
val
);
val
=
(
val
>>
shift
)
&
mask
;
val
=
(
val
>>
shift
)
&
mask
;
if
(
invert
)
if
(
invert
)
val
=
max
-
val
;
val
=
max
-
val
;
...
@@ -534,19 +635,15 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
...
@@ -534,19 +635,15 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
/* connect mixer widget to its interconnecting audio paths */
/* connect mixer widget to its interconnecting audio paths */
static
int
dapm_connect_mixer
(
struct
snd_soc_dapm_context
*
dapm
,
static
int
dapm_connect_mixer
(
struct
snd_soc_dapm_context
*
dapm
,
struct
snd_soc_dapm_widget
*
src
,
struct
snd_soc_dapm_widget
*
dest
,
struct
snd_soc_dapm_path
*
path
,
const
char
*
control_name
)
struct
snd_soc_dapm_path
*
path
,
const
char
*
control_name
)
{
{
int
i
;
int
i
;
/* search for mixer kcontrol */
/* search for mixer kcontrol */
for
(
i
=
0
;
i
<
dest
->
num_kcontrols
;
i
++
)
{
for
(
i
=
0
;
i
<
path
->
sink
->
num_kcontrols
;
i
++
)
{
if
(
!
strcmp
(
control_name
,
dest
->
kcontrol_news
[
i
].
name
))
{
if
(
!
strcmp
(
control_name
,
path
->
sink
->
kcontrol_news
[
i
].
name
))
{
list_add
(
&
path
->
list
,
&
dapm
->
card
->
paths
);
path
->
name
=
path
->
sink
->
kcontrol_news
[
i
].
name
;
list_add
(
&
path
->
list_sink
,
&
dest
->
sources
);
dapm_set_mixer_path_status
(
path
,
i
);
list_add
(
&
path
->
list_source
,
&
src
->
sinks
);
path
->
name
=
dest
->
kcontrol_news
[
i
].
name
;
dapm_set_mixer_path_status
(
dest
,
path
,
i
);
return
0
;
return
0
;
}
}
}
}
...
@@ -738,8 +835,10 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
...
@@ -738,8 +835,10 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
if
(
ret
<
0
)
if
(
ret
<
0
)
return
ret
;
return
ret
;
list_for_each_entry
(
path
,
&
w
->
sources
,
list_sink
)
list_for_each_entry
(
path
,
&
w
->
sources
,
list_sink
)
{
if
(
path
->
name
)
dapm_kcontrol_add_path
(
w
->
kcontrols
[
0
],
path
);
dapm_kcontrol_add_path
(
w
->
kcontrols
[
0
],
path
);
}
return
0
;
return
0
;
}
}
...
@@ -754,34 +853,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
...
@@ -754,34 +853,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
return
0
;
return
0
;
}
}
/* reset 'walked' bit for each dapm path */
static
void
dapm_clear_walk_output
(
struct
snd_soc_dapm_context
*
dapm
,
struct
list_head
*
sink
)
{
struct
snd_soc_dapm_path
*
p
;
list_for_each_entry
(
p
,
sink
,
list_source
)
{
if
(
p
->
walked
)
{
p
->
walked
=
0
;
dapm_clear_walk_output
(
dapm
,
&
p
->
sink
->
sinks
);
}
}
}
static
void
dapm_clear_walk_input
(
struct
snd_soc_dapm_context
*
dapm
,
struct
list_head
*
source
)
{
struct
snd_soc_dapm_path
*
p
;
list_for_each_entry
(
p
,
source
,
list_sink
)
{
if
(
p
->
walked
)
{
p
->
walked
=
0
;
dapm_clear_walk_input
(
dapm
,
&
p
->
source
->
sources
);
}
}
}
/* We implement power down on suspend by checking the power state of
/* We implement power down on suspend by checking the power state of
* the ALSA card - when we are suspending the ALSA state for the card
* the ALSA card - when we are suspending the ALSA state for the card
* is set to D3.
* is set to D3.
...
@@ -856,61 +927,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
...
@@ -856,61 +927,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT
(
widget
,
path_checks
);
DAPM_UPDATE_STAT
(
widget
,
path_checks
);
switch
(
widget
->
id
)
{
if
(
widget
->
is_sink
&&
widget
->
connected
)
{
case
snd_soc_dapm_supply
:
case
snd_soc_dapm_regulator_supply
:
case
snd_soc_dapm_clock_supply
:
case
snd_soc_dapm_kcontrol
:
return
0
;
default:
break
;
}
switch
(
widget
->
id
)
{
case
snd_soc_dapm_adc
:
case
snd_soc_dapm_aif_out
:
case
snd_soc_dapm_dai_out
:
if
(
widget
->
active
)
{
widget
->
outputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
outputs
;
}
default:
break
;
}
if
(
widget
->
connected
)
{
/* connected pin ? */
if
(
widget
->
id
==
snd_soc_dapm_output
&&
!
widget
->
ext
)
{
widget
->
outputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
outputs
;
}
/* connected jack or spk ? */
if
(
widget
->
id
==
snd_soc_dapm_hp
||
widget
->
id
==
snd_soc_dapm_spk
||
(
widget
->
id
==
snd_soc_dapm_line
&&
!
list_empty
(
&
widget
->
sources
)))
{
widget
->
outputs
=
snd_soc_dapm_suspend_check
(
widget
);
widget
->
outputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
outputs
;
return
widget
->
outputs
;
}
}
}
list_for_each_entry
(
path
,
&
widget
->
sinks
,
list_source
)
{
list_for_each_entry
(
path
,
&
widget
->
sinks
,
list_source
)
{
DAPM_UPDATE_STAT
(
widget
,
neighbour_checks
);
DAPM_UPDATE_STAT
(
widget
,
neighbour_checks
);
if
(
path
->
weak
)
if
(
path
->
weak
||
path
->
is_supply
)
continue
;
continue
;
if
(
path
->
walking
)
if
(
path
->
walking
)
return
1
;
return
1
;
if
(
path
->
walked
)
continue
;
trace_snd_soc_dapm_output_path
(
widget
,
path
);
trace_snd_soc_dapm_output_path
(
widget
,
path
);
if
(
path
->
sink
&&
path
->
connect
)
{
if
(
path
->
connect
)
{
path
->
walked
=
1
;
path
->
walking
=
1
;
path
->
walking
=
1
;
/* do we need to add this widget to the list ? */
/* do we need to add this widget to the list ? */
...
@@ -952,73 +985,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
...
@@ -952,73 +985,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT
(
widget
,
path_checks
);
DAPM_UPDATE_STAT
(
widget
,
path_checks
);
switch
(
widget
->
id
)
{
if
(
widget
->
is_source
&&
widget
->
connected
)
{
case
snd_soc_dapm_supply
:
case
snd_soc_dapm_regulator_supply
:
case
snd_soc_dapm_clock_supply
:
case
snd_soc_dapm_kcontrol
:
return
0
;
default:
break
;
}
/* active stream ? */
switch
(
widget
->
id
)
{
case
snd_soc_dapm_dac
:
case
snd_soc_dapm_aif_in
:
case
snd_soc_dapm_dai_in
:
if
(
widget
->
active
)
{
widget
->
inputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
inputs
;
}
default:
break
;
}
if
(
widget
->
connected
)
{
/* connected pin ? */
if
(
widget
->
id
==
snd_soc_dapm_input
&&
!
widget
->
ext
)
{
widget
->
inputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
inputs
;
}
/* connected VMID/Bias for lower pops */
if
(
widget
->
id
==
snd_soc_dapm_vmid
)
{
widget
->
inputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
inputs
;
}
/* connected jack ? */
if
(
widget
->
id
==
snd_soc_dapm_mic
||
(
widget
->
id
==
snd_soc_dapm_line
&&
!
list_empty
(
&
widget
->
sinks
)))
{
widget
->
inputs
=
snd_soc_dapm_suspend_check
(
widget
);
widget
->
inputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
inputs
;
return
widget
->
inputs
;
}
}
/* signal generator */
if
(
widget
->
id
==
snd_soc_dapm_siggen
)
{
widget
->
inputs
=
snd_soc_dapm_suspend_check
(
widget
);
return
widget
->
inputs
;
}
}
list_for_each_entry
(
path
,
&
widget
->
sources
,
list_sink
)
{
list_for_each_entry
(
path
,
&
widget
->
sources
,
list_sink
)
{
DAPM_UPDATE_STAT
(
widget
,
neighbour_checks
);
DAPM_UPDATE_STAT
(
widget
,
neighbour_checks
);
if
(
path
->
weak
)
if
(
path
->
weak
||
path
->
is_supply
)
continue
;
continue
;
if
(
path
->
walking
)
if
(
path
->
walking
)
return
1
;
return
1
;
if
(
path
->
walked
)
continue
;
trace_snd_soc_dapm_input_path
(
widget
,
path
);
trace_snd_soc_dapm_input_path
(
widget
,
path
);
if
(
path
->
source
&&
path
->
connect
)
{
if
(
path
->
connect
)
{
path
->
walked
=
1
;
path
->
walking
=
1
;
path
->
walking
=
1
;
/* do we need to add this widget to the list ? */
/* do we need to add this widget to the list ? */
...
@@ -1060,21 +1043,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
...
@@ -1060,21 +1043,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
int
snd_soc_dapm_dai_get_connected_widgets
(
struct
snd_soc_dai
*
dai
,
int
stream
,
int
snd_soc_dapm_dai_get_connected_widgets
(
struct
snd_soc_dai
*
dai
,
int
stream
,
struct
snd_soc_dapm_widget_list
**
list
)
struct
snd_soc_dapm_widget_list
**
list
)
{
{
struct
snd_soc_card
*
card
=
dai
->
card
;
struct
snd_soc_card
*
card
=
dai
->
component
->
card
;
struct
snd_soc_dapm_widget
*
w
;
int
paths
;
int
paths
;
mutex_lock_nested
(
&
card
->
dapm_mutex
,
SND_SOC_DAPM_CLASS_RUNTIME
);
mutex_lock_nested
(
&
card
->
dapm_mutex
,
SND_SOC_DAPM_CLASS_RUNTIME
);
dapm_reset
(
card
);
if
(
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
/*
* For is_connected_{output,input}_ep fully discover the graph we need
* to reset the cached number of inputs and outputs.
*/
list_for_each_entry
(
w
,
&
card
->
widgets
,
list
)
{
w
->
inputs
=
-
1
;
w
->
outputs
=
-
1
;
}
if
(
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
paths
=
is_connected_output_ep
(
dai
->
playback_widget
,
list
);
paths
=
is_connected_output_ep
(
dai
->
playback_widget
,
list
);
dapm_clear_walk_output
(
&
card
->
dapm
,
else
&
dai
->
playback_widget
->
sinks
);
}
else
{
paths
=
is_connected_input_ep
(
dai
->
capture_widget
,
list
);
paths
=
is_connected_input_ep
(
dai
->
capture_widget
,
list
);
dapm_clear_walk_input
(
&
card
->
dapm
,
&
dai
->
capture_widget
->
sources
);
}
trace_snd_soc_dapm_connected
(
paths
,
stream
);
trace_snd_soc_dapm_connected
(
paths
,
stream
);
mutex_unlock
(
&
card
->
dapm_mutex
);
mutex_unlock
(
&
card
->
dapm_mutex
);
...
@@ -1163,44 +1150,10 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
...
@@ -1163,44 +1150,10 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT
(
w
,
power_checks
);
DAPM_UPDATE_STAT
(
w
,
power_checks
);
in
=
is_connected_input_ep
(
w
,
NULL
);
in
=
is_connected_input_ep
(
w
,
NULL
);
dapm_clear_walk_input
(
w
->
dapm
,
&
w
->
sources
);
out
=
is_connected_output_ep
(
w
,
NULL
);
out
=
is_connected_output_ep
(
w
,
NULL
);
dapm_clear_walk_output
(
w
->
dapm
,
&
w
->
sinks
);
return
out
!=
0
&&
in
!=
0
;
return
out
!=
0
&&
in
!=
0
;
}
}
/* Check to see if an ADC has power */
static
int
dapm_adc_check_power
(
struct
snd_soc_dapm_widget
*
w
)
{
int
in
;
DAPM_UPDATE_STAT
(
w
,
power_checks
);
if
(
w
->
active
)
{
in
=
is_connected_input_ep
(
w
,
NULL
);
dapm_clear_walk_input
(
w
->
dapm
,
&
w
->
sources
);
return
in
!=
0
;
}
else
{
return
dapm_generic_check_power
(
w
);
}
}
/* Check to see if a DAC has power */
static
int
dapm_dac_check_power
(
struct
snd_soc_dapm_widget
*
w
)
{
int
out
;
DAPM_UPDATE_STAT
(
w
,
power_checks
);
if
(
w
->
active
)
{
out
=
is_connected_output_ep
(
w
,
NULL
);
dapm_clear_walk_output
(
w
->
dapm
,
&
w
->
sinks
);
return
out
!=
0
;
}
else
{
return
dapm_generic_check_power
(
w
);
}
}
/* Check to see if a power supply is needed */
/* Check to see if a power supply is needed */
static
int
dapm_supply_check_power
(
struct
snd_soc_dapm_widget
*
w
)
static
int
dapm_supply_check_power
(
struct
snd_soc_dapm_widget
*
w
)
{
{
...
@@ -1219,9 +1172,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
...
@@ -1219,9 +1172,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
!
path
->
connected
(
path
->
source
,
path
->
sink
))
!
path
->
connected
(
path
->
source
,
path
->
sink
))
continue
;
continue
;
if
(
!
path
->
sink
)
continue
;
if
(
dapm_widget_power_check
(
path
->
sink
))
if
(
dapm_widget_power_check
(
path
->
sink
))
return
1
;
return
1
;
}
}
...
@@ -1636,28 +1586,15 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
...
@@ -1636,28 +1586,15 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
/* If we changed our power state perhaps our neigbours changed
/* If we changed our power state perhaps our neigbours changed
* also.
* also.
*/
*/
list_for_each_entry
(
path
,
&
w
->
sources
,
list_sink
)
{
list_for_each_entry
(
path
,
&
w
->
sources
,
list_sink
)
if
(
path
->
source
)
{
dapm_widget_set_peer_power
(
path
->
source
,
power
,
path
->
connect
);
dapm_widget_set_peer_power
(
path
->
source
,
power
,
path
->
connect
);
}
}
switch
(
w
->
id
)
{
case
snd_soc_dapm_supply
:
case
snd_soc_dapm_regulator_supply
:
case
snd_soc_dapm_clock_supply
:
case
snd_soc_dapm_kcontrol
:
/* Supplies can't affect their outputs, only their inputs */
/* Supplies can't affect their outputs, only their inputs */
break
;
if
(
!
w
->
is_supply
)
{
default:
list_for_each_entry
(
path
,
&
w
->
sinks
,
list_source
)
list_for_each_entry
(
path
,
&
w
->
sinks
,
list_source
)
{
if
(
path
->
sink
)
{
dapm_widget_set_peer_power
(
path
->
sink
,
power
,
dapm_widget_set_peer_power
(
path
->
sink
,
power
,
path
->
connect
);
path
->
connect
);
}
}
}
break
;
}
if
(
power
)
if
(
power
)
dapm_seq_insert
(
w
,
up_list
,
true
);
dapm_seq_insert
(
w
,
up_list
,
true
);
...
@@ -1863,10 +1800,14 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
...
@@ -1863,10 +1800,14 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if
(
!
buf
)
if
(
!
buf
)
return
-
ENOMEM
;
return
-
ENOMEM
;
/* Supply widgets are not handled by is_connected_{input,output}_ep() */
if
(
w
->
is_supply
)
{
in
=
0
;
out
=
0
;
}
else
{
in
=
is_connected_input_ep
(
w
,
NULL
);
in
=
is_connected_input_ep
(
w
,
NULL
);
dapm_clear_walk_input
(
w
->
dapm
,
&
w
->
sources
);
out
=
is_connected_output_ep
(
w
,
NULL
);
out
=
is_connected_output_ep
(
w
,
NULL
);
dapm_clear_walk_output
(
w
->
dapm
,
&
w
->
sinks
);
}
ret
=
snprintf
(
buf
,
PAGE_SIZE
,
"%s: %s%s in %d out %d"
,
ret
=
snprintf
(
buf
,
PAGE_SIZE
,
"%s: %s%s in %d out %d"
,
w
->
name
,
w
->
power
?
"On"
:
"Off"
,
w
->
name
,
w
->
power
?
"On"
:
"Off"
,
...
@@ -2011,32 +1952,45 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
...
@@ -2011,32 +1952,45 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
#endif
#endif
/*
* soc_dapm_connect_path() - Connects or disconnects a path
* @path: The path to update
* @connect: The new connect state of the path. True if the path is connected,
* false if it is disconneted.
* @reason: The reason why the path changed (for debugging only)
*/
static
void
soc_dapm_connect_path
(
struct
snd_soc_dapm_path
*
path
,
bool
connect
,
const
char
*
reason
)
{
if
(
path
->
connect
==
connect
)
return
;
path
->
connect
=
connect
;
dapm_mark_dirty
(
path
->
source
,
reason
);
dapm_mark_dirty
(
path
->
sink
,
reason
);
dapm_path_invalidate
(
path
);
}
/* test and update the power status of a mux widget */
/* test and update the power status of a mux widget */
static
int
soc_dapm_mux_update_power
(
struct
snd_soc_card
*
card
,
static
int
soc_dapm_mux_update_power
(
struct
snd_soc_card
*
card
,
struct
snd_kcontrol
*
kcontrol
,
int
mux
,
struct
soc_enum
*
e
)
struct
snd_kcontrol
*
kcontrol
,
int
mux
,
struct
soc_enum
*
e
)
{
{
struct
snd_soc_dapm_path
*
path
;
struct
snd_soc_dapm_path
*
path
;
int
found
=
0
;
int
found
=
0
;
bool
connect
;
lockdep_assert_held
(
&
card
->
dapm_mutex
);
lockdep_assert_held
(
&
card
->
dapm_mutex
);
/* find dapm widget path assoc with kcontrol */
/* find dapm widget path assoc with kcontrol */
dapm_kcontrol_for_each_path
(
path
,
kcontrol
)
{
dapm_kcontrol_for_each_path
(
path
,
kcontrol
)
{
if
(
!
path
->
name
||
!
e
->
texts
[
mux
])
continue
;
found
=
1
;
found
=
1
;
/* we now need to match the string in the enum to the path */
/* we now need to match the string in the enum to the path */
if
(
!
(
strcmp
(
path
->
name
,
e
->
texts
[
mux
])))
{
if
(
!
(
strcmp
(
path
->
name
,
e
->
texts
[
mux
])))
path
->
connect
=
1
;
/* new connection */
connect
=
true
;
dapm_mark_dirty
(
path
->
source
,
"mux connection"
);
else
}
else
{
connect
=
false
;
if
(
path
->
connect
)
dapm_mark_dirty
(
path
->
source
,
soc_dapm_connect_path
(
path
,
connect
,
"mux update"
);
"mux disconnection"
);
path
->
connect
=
0
;
/* old connection must be powered down */
}
dapm_mark_dirty
(
path
->
sink
,
"mux change"
);
}
}
if
(
found
)
if
(
found
)
...
@@ -2075,9 +2029,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
...
@@ -2075,9 +2029,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
/* find dapm widget path assoc with kcontrol */
/* find dapm widget path assoc with kcontrol */
dapm_kcontrol_for_each_path
(
path
,
kcontrol
)
{
dapm_kcontrol_for_each_path
(
path
,
kcontrol
)
{
found
=
1
;
found
=
1
;
path
->
connect
=
connect
;
soc_dapm_connect_path
(
path
,
connect
,
"mixer update"
);
dapm_mark_dirty
(
path
->
source
,
"mixer connection"
);
dapm_mark_dirty
(
path
->
sink
,
"mixer update"
);
}
}
if
(
found
)
if
(
found
)
...
@@ -2255,8 +2207,11 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
...
@@ -2255,8 +2207,11 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
return
-
EINVAL
;
return
-
EINVAL
;
}
}
if
(
w
->
connected
!=
status
)
if
(
w
->
connected
!=
status
)
{
dapm_mark_dirty
(
w
,
"pin configuration"
);
dapm_mark_dirty
(
w
,
"pin configuration"
);
dapm_widget_invalidate_input_paths
(
w
);
dapm_widget_invalidate_output_paths
(
w
);
}
w
->
connected
=
status
;
w
->
connected
=
status
;
if
(
status
==
0
)
if
(
status
==
0
)
...
@@ -2309,6 +2264,53 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
...
@@ -2309,6 +2264,53 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
}
}
EXPORT_SYMBOL_GPL
(
snd_soc_dapm_sync
);
EXPORT_SYMBOL_GPL
(
snd_soc_dapm_sync
);
/*
* dapm_update_widget_flags() - Re-compute widget sink and source flags
* @w: The widget for which to update the flags
*
* Some widgets have a dynamic category which depends on which neighbors they
* are connected to. This function update the category for these widgets.
*
* This function must be called whenever a path is added or removed to a widget.
*/
static
void
dapm_update_widget_flags
(
struct
snd_soc_dapm_widget
*
w
)
{
struct
snd_soc_dapm_path
*
p
;
switch
(
w
->
id
)
{
case
snd_soc_dapm_input
:
w
->
is_source
=
1
;
list_for_each_entry
(
p
,
&
w
->
sources
,
list_sink
)
{
if
(
p
->
source
->
id
==
snd_soc_dapm_micbias
||
p
->
source
->
id
==
snd_soc_dapm_mic
||
p
->
source
->
id
==
snd_soc_dapm_line
||
p
->
source
->
id
==
snd_soc_dapm_output
)
{
w
->
is_source
=
0
;
break
;
}
}
break
;
case
snd_soc_dapm_output
:
w
->
is_sink
=
1
;
list_for_each_entry
(
p
,
&
w
->
sinks
,
list_source
)
{
if
(
p
->
sink
->
id
==
snd_soc_dapm_spk
||
p
->
sink
->
id
==
snd_soc_dapm_hp
||
p
->
sink
->
id
==
snd_soc_dapm_line
||
p
->
sink
->
id
==
snd_soc_dapm_input
)
{
w
->
is_sink
=
0
;
break
;
}
}
break
;
case
snd_soc_dapm_line
:
w
->
is_sink
=
!
list_empty
(
&
w
->
sources
);
w
->
is_source
=
!
list_empty
(
&
w
->
sinks
);
break
;
default:
break
;
}
}
static
int
snd_soc_dapm_add_path
(
struct
snd_soc_dapm_context
*
dapm
,
static
int
snd_soc_dapm_add_path
(
struct
snd_soc_dapm_context
*
dapm
,
struct
snd_soc_dapm_widget
*
wsource
,
struct
snd_soc_dapm_widget
*
wsink
,
struct
snd_soc_dapm_widget
*
wsource
,
struct
snd_soc_dapm_widget
*
wsink
,
const
char
*
control
,
const
char
*
control
,
...
@@ -2318,6 +2320,27 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
...
@@ -2318,6 +2320,27 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
struct
snd_soc_dapm_path
*
path
;
struct
snd_soc_dapm_path
*
path
;
int
ret
;
int
ret
;
if
(
wsink
->
is_supply
&&
!
wsource
->
is_supply
)
{
dev_err
(
dapm
->
dev
,
"Connecting non-supply widget to supply widget is not supported (%s -> %s)
\n
"
,
wsource
->
name
,
wsink
->
name
);
return
-
EINVAL
;
}
if
(
connected
&&
!
wsource
->
is_supply
)
{
dev_err
(
dapm
->
dev
,
"connected() callback only supported for supply widgets (%s -> %s)
\n
"
,
wsource
->
name
,
wsink
->
name
);
return
-
EINVAL
;
}
if
(
wsource
->
is_supply
&&
control
)
{
dev_err
(
dapm
->
dev
,
"Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)
\n
"
,
wsource
->
name
,
control
,
wsink
->
name
);
return
-
EINVAL
;
}
path
=
kzalloc
(
sizeof
(
struct
snd_soc_dapm_path
),
GFP_KERNEL
);
path
=
kzalloc
(
sizeof
(
struct
snd_soc_dapm_path
),
GFP_KERNEL
);
if
(
!
path
)
if
(
!
path
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -2330,84 +2353,48 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
...
@@ -2330,84 +2353,48 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
INIT_LIST_HEAD
(
&
path
->
list_source
);
INIT_LIST_HEAD
(
&
path
->
list_source
);
INIT_LIST_HEAD
(
&
path
->
list_sink
);
INIT_LIST_HEAD
(
&
path
->
list_sink
);
/* check for external widgets */
if
(
wsource
->
is_supply
||
wsink
->
is_supply
)
if
(
wsink
->
id
==
snd_soc_dapm_input
)
{
path
->
is_supply
=
1
;
if
(
wsource
->
id
==
snd_soc_dapm_micbias
||
wsource
->
id
==
snd_soc_dapm_mic
||
wsource
->
id
==
snd_soc_dapm_line
||
wsource
->
id
==
snd_soc_dapm_output
)
wsink
->
ext
=
1
;
}
if
(
wsource
->
id
==
snd_soc_dapm_output
)
{
if
(
wsink
->
id
==
snd_soc_dapm_spk
||
wsink
->
id
==
snd_soc_dapm_hp
||
wsink
->
id
==
snd_soc_dapm_line
||
wsink
->
id
==
snd_soc_dapm_input
)
wsource
->
ext
=
1
;
}
dapm_mark_dirty
(
wsource
,
"Route added"
);
dapm_mark_dirty
(
wsink
,
"Route added"
);
/* connect static paths */
/* connect static paths */
if
(
control
==
NULL
)
{
if
(
control
==
NULL
)
{
list_add
(
&
path
->
list
,
&
dapm
->
card
->
paths
);
list_add
(
&
path
->
list_sink
,
&
wsink
->
sources
);
list_add
(
&
path
->
list_source
,
&
wsource
->
sinks
);
path
->
connect
=
1
;
path
->
connect
=
1
;
return
0
;
}
else
{
}
/* connect dynamic paths */
/* connect dynamic paths */
switch
(
wsink
->
id
)
{
switch
(
wsink
->
id
)
{
case
snd_soc_dapm_adc
:
case
snd_soc_dapm_dac
:
case
snd_soc_dapm_pga
:
case
snd_soc_dapm_out_drv
:
case
snd_soc_dapm_input
:
case
snd_soc_dapm_output
:
case
snd_soc_dapm_siggen
:
case
snd_soc_dapm_micbias
:
case
snd_soc_dapm_vmid
:
case
snd_soc_dapm_pre
:
case
snd_soc_dapm_post
:
case
snd_soc_dapm_supply
:
case
snd_soc_dapm_regulator_supply
:
case
snd_soc_dapm_clock_supply
:
case
snd_soc_dapm_aif_in
:
case
snd_soc_dapm_aif_out
:
case
snd_soc_dapm_dai_in
:
case
snd_soc_dapm_dai_out
:
case
snd_soc_dapm_dai_link
:
case
snd_soc_dapm_kcontrol
:
list_add
(
&
path
->
list
,
&
dapm
->
card
->
paths
);
list_add
(
&
path
->
list_sink
,
&
wsink
->
sources
);
list_add
(
&
path
->
list_source
,
&
wsource
->
sinks
);
path
->
connect
=
1
;
return
0
;
case
snd_soc_dapm_mux
:
case
snd_soc_dapm_mux
:
ret
=
dapm_connect_mux
(
dapm
,
wsource
,
wsink
,
path
,
control
,
ret
=
dapm_connect_mux
(
dapm
,
path
,
control
);
&
wsink
->
kcontrol_news
[
0
]);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
goto
err
;
goto
err
;
break
;
break
;
case
snd_soc_dapm_switch
:
case
snd_soc_dapm_switch
:
case
snd_soc_dapm_mixer
:
case
snd_soc_dapm_mixer
:
case
snd_soc_dapm_mixer_named_ctl
:
case
snd_soc_dapm_mixer_named_ctl
:
ret
=
dapm_connect_mixer
(
dapm
,
wsource
,
wsink
,
path
,
control
);
ret
=
dapm_connect_mixer
(
dapm
,
path
,
control
);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
goto
err
;
goto
err
;
break
;
break
;
case
snd_soc_dapm_hp
:
default:
case
snd_soc_dapm_mic
:
dev_err
(
dapm
->
dev
,
case
snd_soc_dapm_line
:
"Control not supported for path %s -> [%s] -> %s
\n
"
,
case
snd_soc_dapm_spk
:
wsource
->
name
,
control
,
wsink
->
name
);
ret
=
-
EINVAL
;
goto
err
;
}
}
list_add
(
&
path
->
list
,
&
dapm
->
card
->
paths
);
list_add
(
&
path
->
list
,
&
dapm
->
card
->
paths
);
list_add
(
&
path
->
list_sink
,
&
wsink
->
sources
);
list_add
(
&
path
->
list_sink
,
&
wsink
->
sources
);
list_add
(
&
path
->
list_source
,
&
wsource
->
sinks
);
list_add
(
&
path
->
list_source
,
&
wsource
->
sinks
);
path
->
connect
=
0
;
return
0
;
dapm_update_widget_flags
(
wsource
);
}
dapm_update_widget_flags
(
wsink
);
dapm_mark_dirty
(
wsource
,
"Route added"
);
dapm_mark_dirty
(
wsink
,
"Route added"
);
if
(
dapm
->
card
->
instantiated
&&
path
->
connect
)
dapm_path_invalidate
(
path
);
return
0
;
return
0
;
err:
err:
...
@@ -2489,6 +2476,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
...
@@ -2489,6 +2476,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
static
int
snd_soc_dapm_del_route
(
struct
snd_soc_dapm_context
*
dapm
,
static
int
snd_soc_dapm_del_route
(
struct
snd_soc_dapm_context
*
dapm
,
const
struct
snd_soc_dapm_route
*
route
)
const
struct
snd_soc_dapm_route
*
route
)
{
{
struct
snd_soc_dapm_widget
*
wsource
,
*
wsink
;
struct
snd_soc_dapm_path
*
path
,
*
p
;
struct
snd_soc_dapm_path
*
path
,
*
p
;
const
char
*
sink
;
const
char
*
sink
;
const
char
*
source
;
const
char
*
source
;
...
@@ -2526,10 +2514,19 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
...
@@ -2526,10 +2514,19 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
}
}
if
(
path
)
{
if
(
path
)
{
dapm_mark_dirty
(
path
->
source
,
"Route removed"
);
wsource
=
path
->
source
;
dapm_mark_dirty
(
path
->
sink
,
"Route removed"
);
wsink
=
path
->
sink
;
dapm_mark_dirty
(
wsource
,
"Route removed"
);
dapm_mark_dirty
(
wsink
,
"Route removed"
);
if
(
path
->
connect
)
dapm_path_invalidate
(
path
);
dapm_free_path
(
path
);
dapm_free_path
(
path
);
/* Update any path related flags */
dapm_update_widget_flags
(
wsource
);
dapm_update_widget_flags
(
wsink
);
}
else
{
}
else
{
dev_warn
(
dapm
->
dev
,
"ASoC: Route %s->%s does not exist
\n
"
,
dev_warn
(
dapm
->
dev
,
"ASoC: Route %s->%s does not exist
\n
"
,
source
,
sink
);
source
,
sink
);
...
@@ -3087,40 +3084,44 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
...
@@ -3087,40 +3084,44 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
}
}
switch
(
w
->
id
)
{
switch
(
w
->
id
)
{
case
snd_soc_dapm_
switch
:
case
snd_soc_dapm_
mic
:
case
snd_soc_dapm_
mixer
:
case
snd_soc_dapm_
input
:
case
snd_soc_dapm_mixer_named_ctl
:
w
->
is_source
=
1
;
w
->
power_check
=
dapm_generic_check_power
;
w
->
power_check
=
dapm_generic_check_power
;
break
;
break
;
case
snd_soc_dapm_mux
:
case
snd_soc_dapm_spk
:
case
snd_soc_dapm_hp
:
case
snd_soc_dapm_output
:
w
->
is_sink
=
1
;
w
->
power_check
=
dapm_generic_check_power
;
w
->
power_check
=
dapm_generic_check_power
;
break
;
break
;
case
snd_soc_dapm_dai_out
:
case
snd_soc_dapm_vmid
:
w
->
power_check
=
dapm_adc_check_power
;
case
snd_soc_dapm_siggen
:
break
;
w
->
is_source
=
1
;
case
snd_soc_dapm_dai_in
:
w
->
power_check
=
dapm_always_on_check_power
;
w
->
power_check
=
dapm_dac_check_power
;
break
;
break
;
case
snd_soc_dapm_mux
:
case
snd_soc_dapm_switch
:
case
snd_soc_dapm_mixer
:
case
snd_soc_dapm_mixer_named_ctl
:
case
snd_soc_dapm_adc
:
case
snd_soc_dapm_adc
:
case
snd_soc_dapm_aif_out
:
case
snd_soc_dapm_aif_out
:
case
snd_soc_dapm_dac
:
case
snd_soc_dapm_dac
:
case
snd_soc_dapm_aif_in
:
case
snd_soc_dapm_aif_in
:
case
snd_soc_dapm_pga
:
case
snd_soc_dapm_pga
:
case
snd_soc_dapm_out_drv
:
case
snd_soc_dapm_out_drv
:
case
snd_soc_dapm_input
:
case
snd_soc_dapm_output
:
case
snd_soc_dapm_micbias
:
case
snd_soc_dapm_micbias
:
case
snd_soc_dapm_spk
:
case
snd_soc_dapm_hp
:
case
snd_soc_dapm_mic
:
case
snd_soc_dapm_line
:
case
snd_soc_dapm_line
:
case
snd_soc_dapm_dai_link
:
case
snd_soc_dapm_dai_link
:
case
snd_soc_dapm_dai_out
:
case
snd_soc_dapm_dai_in
:
w
->
power_check
=
dapm_generic_check_power
;
w
->
power_check
=
dapm_generic_check_power
;
break
;
break
;
case
snd_soc_dapm_supply
:
case
snd_soc_dapm_supply
:
case
snd_soc_dapm_regulator_supply
:
case
snd_soc_dapm_regulator_supply
:
case
snd_soc_dapm_clock_supply
:
case
snd_soc_dapm_clock_supply
:
case
snd_soc_dapm_kcontrol
:
case
snd_soc_dapm_kcontrol
:
w
->
is_supply
=
1
;
w
->
power_check
=
dapm_supply_check_power
;
w
->
power_check
=
dapm_supply_check_power
;
break
;
break
;
default:
default:
...
@@ -3137,6 +3138,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
...
@@ -3137,6 +3138,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
INIT_LIST_HEAD
(
&
w
->
dirty
);
INIT_LIST_HEAD
(
&
w
->
dirty
);
list_add
(
&
w
->
list
,
&
dapm
->
card
->
widgets
);
list_add
(
&
w
->
list
,
&
dapm
->
card
->
widgets
);
w
->
inputs
=
-
1
;
w
->
outputs
=
-
1
;
/* machine layer set ups unconnected pins and insertions */
/* machine layer set ups unconnected pins and insertions */
w
->
connected
=
1
;
w
->
connected
=
1
;
return
w
;
return
w
;
...
@@ -3484,6 +3488,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
...
@@ -3484,6 +3488,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
case
SND_SOC_DAPM_STREAM_PAUSE_RELEASE
:
case
SND_SOC_DAPM_STREAM_PAUSE_RELEASE
:
break
;
break
;
}
}
if
(
w
->
id
==
snd_soc_dapm_dai_in
)
{
w
->
is_source
=
w
->
active
;
dapm_widget_invalidate_input_paths
(
w
);
}
else
{
w
->
is_sink
=
w
->
active
;
dapm_widget_invalidate_output_paths
(
w
);
}
}
}
}
}
...
@@ -3610,7 +3622,15 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
...
@@ -3610,7 +3622,15 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
}
}
dev_dbg
(
w
->
dapm
->
dev
,
"ASoC: force enable pin %s
\n
"
,
pin
);
dev_dbg
(
w
->
dapm
->
dev
,
"ASoC: force enable pin %s
\n
"
,
pin
);
if
(
!
w
->
connected
)
{
/*
* w->force does not affect the number of input or output paths,
* so we only have to recheck if w->connected is changed
*/
dapm_widget_invalidate_input_paths
(
w
);
dapm_widget_invalidate_output_paths
(
w
);
w
->
connected
=
1
;
w
->
connected
=
1
;
}
w
->
force
=
1
;
w
->
force
=
1
;
dapm_mark_dirty
(
w
,
"force enable"
);
dapm_mark_dirty
(
w
,
"force enable"
);
...
@@ -3788,27 +3808,30 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
...
@@ -3788,27 +3808,30 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
}
}
EXPORT_SYMBOL_GPL
(
snd_soc_dapm_ignore_suspend
);
EXPORT_SYMBOL_GPL
(
snd_soc_dapm_ignore_suspend
);
static
bool
snd_soc_dapm_widget_in_card_paths
(
struct
snd_soc_card
*
card
,
/**
struct
snd_soc_dapm_widget
*
w
)
* dapm_is_external_path() - Checks if a path is a external path
* @card: The card the path belongs to
* @path: The path to check
*
* Returns true if the path is either between two different DAPM contexts or
* between two external pins of the same DAPM context. Otherwise returns
* false.
*/
static
bool
dapm_is_external_path
(
struct
snd_soc_card
*
card
,
struct
snd_soc_dapm_path
*
path
)
{
{
struct
snd_soc_dapm_path
*
p
;
list_for_each_entry
(
p
,
&
card
->
paths
,
list
)
{
if
((
p
->
source
==
w
)
||
(
p
->
sink
==
w
))
{
dev_dbg
(
card
->
dev
,
dev_dbg
(
card
->
dev
,
"... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)
\n
"
,
"... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)
\n
"
,
p
->
source
->
name
,
p
->
source
->
id
,
p
->
source
->
dapm
,
path
->
source
->
name
,
path
->
source
->
id
,
path
->
source
->
dapm
,
p
->
sink
->
name
,
p
->
sink
->
id
,
p
->
sink
->
dapm
);
path
->
sink
->
name
,
path
->
sink
->
id
,
path
->
sink
->
dapm
);
/* Connected to something other than the codec
*/
/* Connection between two different DAPM contexts
*/
if
(
p
->
source
->
dapm
!=
p
->
sink
->
dapm
)
if
(
path
->
source
->
dapm
!=
path
->
sink
->
dapm
)
return
true
;
return
true
;
/*
* Loopback connection from codec external pin to
/* Loopback connection from external pin to external pin */
* codec external pin
if
(
path
->
sink
->
id
==
snd_soc_dapm_input
)
{
*/
switch
(
path
->
source
->
id
)
{
if
(
p
->
sink
->
id
==
snd_soc_dapm_input
)
{
switch
(
p
->
source
->
id
)
{
case
snd_soc_dapm_output
:
case
snd_soc_dapm_output
:
case
snd_soc_dapm_micbias
:
case
snd_soc_dapm_micbias
:
return
true
;
return
true
;
...
@@ -3816,7 +3839,23 @@ static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
...
@@ -3816,7 +3839,23 @@ static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
break
;
break
;
}
}
}
}
return
false
;
}
static
bool
snd_soc_dapm_widget_in_card_paths
(
struct
snd_soc_card
*
card
,
struct
snd_soc_dapm_widget
*
w
)
{
struct
snd_soc_dapm_path
*
p
;
list_for_each_entry
(
p
,
&
w
->
sources
,
list_sink
)
{
if
(
dapm_is_external_path
(
card
,
p
))
return
true
;
}
}
list_for_each_entry
(
p
,
&
w
->
sinks
,
list_source
)
{
if
(
dapm_is_external_path
(
card
,
p
))
return
true
;
}
}
return
false
;
return
false
;
...
...
sound/soc/soc-ops.c
0 → 100644
View file @
941725f5
/*
* soc-ops.c -- Generic ASoC operations
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
* Copyright (C) 2010 Slimlogic Ltd.
* Copyright (C) 2010 Texas Instruments Inc.
*
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* with code, comments and ideas from :-
* Richard Purdie <richard@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/bitops.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dpcm.h>
#include <sound/initval.h>
/**
* snd_soc_info_enum_double - enumerated double mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a double enumerated
* mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_info_enum_double
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
return
snd_ctl_enum_info
(
uinfo
,
e
->
shift_l
==
e
->
shift_r
?
1
:
2
,
e
->
items
,
e
->
texts
);
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_enum_double
);
/**
* snd_soc_get_enum_double - enumerated double mixer get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value of a double enumerated mixer.
*
* Returns 0 for success.
*/
int
snd_soc_get_enum_double
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
unsigned
int
val
,
item
;
unsigned
int
reg_val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
e
->
reg
,
&
reg_val
);
if
(
ret
)
return
ret
;
val
=
(
reg_val
>>
e
->
shift_l
)
&
e
->
mask
;
item
=
snd_soc_enum_val_to_item
(
e
,
val
);
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
item
;
if
(
e
->
shift_l
!=
e
->
shift_r
)
{
val
=
(
reg_val
>>
e
->
shift_l
)
&
e
->
mask
;
item
=
snd_soc_enum_val_to_item
(
e
,
val
);
ucontrol
->
value
.
enumerated
.
item
[
1
]
=
item
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_enum_double
);
/**
* snd_soc_put_enum_double - enumerated double mixer put callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value of a double enumerated mixer.
*
* Returns 0 for success.
*/
int
snd_soc_put_enum_double
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
unsigned
int
*
item
=
ucontrol
->
value
.
enumerated
.
item
;
unsigned
int
val
;
unsigned
int
mask
;
if
(
item
[
0
]
>=
e
->
items
)
return
-
EINVAL
;
val
=
snd_soc_enum_item_to_val
(
e
,
item
[
0
])
<<
e
->
shift_l
;
mask
=
e
->
mask
<<
e
->
shift_l
;
if
(
e
->
shift_l
!=
e
->
shift_r
)
{
if
(
item
[
1
]
>=
e
->
items
)
return
-
EINVAL
;
val
|=
snd_soc_enum_item_to_val
(
e
,
item
[
1
])
<<
e
->
shift_r
;
mask
|=
e
->
mask
<<
e
->
shift_r
;
}
return
snd_soc_component_update_bits
(
component
,
e
->
reg
,
mask
,
val
);
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_enum_double
);
/**
* snd_soc_read_signed - Read a codec register and interprete as signed value
* @component: component
* @reg: Register to read
* @mask: Mask to use after shifting the register value
* @shift: Right shift of register value
* @sign_bit: Bit that describes if a number is negative or not.
* @signed_val: Pointer to where the read value should be stored
*
* This functions reads a codec register. The register value is shifted right
* by 'shift' bits and masked with the given 'mask'. Afterwards it translates
* the given registervalue into a signed integer if sign_bit is non-zero.
*
* Returns 0 on sucess, otherwise an error value
*/
static
int
snd_soc_read_signed
(
struct
snd_soc_component
*
component
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
shift
,
unsigned
int
sign_bit
,
int
*
signed_val
)
{
int
ret
;
unsigned
int
val
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
<
0
)
return
ret
;
val
=
(
val
>>
shift
)
&
mask
;
if
(
!
sign_bit
)
{
*
signed_val
=
val
;
return
0
;
}
/* non-negative number */
if
(
!
(
val
&
BIT
(
sign_bit
)))
{
*
signed_val
=
val
;
return
0
;
}
ret
=
val
;
/*
* The register most probably does not contain a full-sized int.
* Instead we have an arbitrary number of bits in a signed
* representation which has to be translated into a full-sized int.
* This is done by filling up all bits above the sign-bit.
*/
ret
|=
~
((
int
)(
BIT
(
sign_bit
)
-
1
));
*
signed_val
=
ret
;
return
0
;
}
/**
* snd_soc_info_volsw - single mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a single mixer control, or a double
* mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_info_volsw
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
int
platform_max
;
if
(
!
mc
->
platform_max
)
mc
->
platform_max
=
mc
->
max
;
platform_max
=
mc
->
platform_max
;
if
(
platform_max
==
1
&&
!
strstr
(
kcontrol
->
id
.
name
,
" Volume"
))
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
else
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_INTEGER
;
uinfo
->
count
=
snd_soc_volsw_is_stereo
(
mc
)
?
2
:
1
;
uinfo
->
value
.
integer
.
min
=
0
;
uinfo
->
value
.
integer
.
max
=
platform_max
-
mc
->
min
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_volsw
);
/**
* snd_soc_get_volsw - single mixer get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value of a single mixer control, or a double mixer
* control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_get_volsw
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
int
sign_bit
=
mc
->
sign_bit
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
int
val
;
int
ret
;
if
(
sign_bit
)
mask
=
BIT
(
sign_bit
+
1
)
-
1
;
ret
=
snd_soc_read_signed
(
component
,
reg
,
mask
,
shift
,
sign_bit
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
val
-
min
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
0
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
0
];
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
if
(
reg
==
reg2
)
ret
=
snd_soc_read_signed
(
component
,
reg
,
mask
,
rshift
,
sign_bit
,
&
val
);
else
ret
=
snd_soc_read_signed
(
component
,
reg2
,
mask
,
shift
,
sign_bit
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
1
]
=
val
-
min
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
1
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
1
];
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_volsw
);
/**
* snd_soc_put_volsw - single mixer put callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value of a single mixer control, or a double mixer
* control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_put_volsw
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
unsigned
int
sign_bit
=
mc
->
sign_bit
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
int
err
;
bool
type_2r
=
false
;
unsigned
int
val2
=
0
;
unsigned
int
val
,
val_mask
;
if
(
sign_bit
)
mask
=
BIT
(
sign_bit
+
1
)
-
1
;
val
=
((
ucontrol
->
value
.
integer
.
value
[
0
]
+
min
)
&
mask
);
if
(
invert
)
val
=
max
-
val
;
val_mask
=
mask
<<
shift
;
val
=
val
<<
shift
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
val2
=
((
ucontrol
->
value
.
integer
.
value
[
1
]
+
min
)
&
mask
);
if
(
invert
)
val2
=
max
-
val2
;
if
(
reg
==
reg2
)
{
val_mask
|=
mask
<<
rshift
;
val
|=
val2
<<
rshift
;
}
else
{
val2
=
val2
<<
shift
;
type_2r
=
true
;
}
}
err
=
snd_soc_component_update_bits
(
component
,
reg
,
val_mask
,
val
);
if
(
err
<
0
)
return
err
;
if
(
type_2r
)
err
=
snd_soc_component_update_bits
(
component
,
reg2
,
val_mask
,
val2
);
return
err
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_volsw
);
/**
* snd_soc_get_volsw_sx - single mixer get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value of a single mixer control, or a double mixer
* control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_get_volsw_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
int
mask
=
(
1
<<
(
fls
(
min
+
max
)
-
1
))
-
1
;
unsigned
int
val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
<
0
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
((
val
>>
shift
)
-
min
)
&
mask
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
ret
=
snd_soc_component_read
(
component
,
reg2
,
&
val
);
if
(
ret
<
0
)
return
ret
;
val
=
((
val
>>
rshift
)
-
min
)
&
mask
;
ucontrol
->
value
.
integer
.
value
[
1
]
=
val
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_volsw_sx
);
/**
* snd_soc_put_volsw_sx - double mixer set callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to set the value of a double mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int
snd_soc_put_volsw_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
reg2
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
rshift
=
mc
->
rshift
;
int
max
=
mc
->
max
;
int
min
=
mc
->
min
;
int
mask
=
(
1
<<
(
fls
(
min
+
max
)
-
1
))
-
1
;
int
err
=
0
;
unsigned
int
val
,
val_mask
,
val2
=
0
;
val_mask
=
mask
<<
shift
;
val
=
(
ucontrol
->
value
.
integer
.
value
[
0
]
+
min
)
&
mask
;
val
=
val
<<
shift
;
err
=
snd_soc_component_update_bits
(
component
,
reg
,
val_mask
,
val
);
if
(
err
<
0
)
return
err
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
val_mask
=
mask
<<
rshift
;
val2
=
(
ucontrol
->
value
.
integer
.
value
[
1
]
+
min
)
&
mask
;
val2
=
val2
<<
rshift
;
err
=
snd_soc_component_update_bits
(
component
,
reg2
,
val_mask
,
val2
);
}
return
err
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_volsw_sx
);
/**
* snd_soc_info_volsw_range - single mixer info callback with range.
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information, within a range, about a single
* mixer control.
*
* returns 0 for success.
*/
int
snd_soc_info_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
int
platform_max
;
int
min
=
mc
->
min
;
if
(
!
mc
->
platform_max
)
mc
->
platform_max
=
mc
->
max
;
platform_max
=
mc
->
platform_max
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_INTEGER
;
uinfo
->
count
=
snd_soc_volsw_is_stereo
(
mc
)
?
2
:
1
;
uinfo
->
value
.
integer
.
min
=
0
;
uinfo
->
value
.
integer
.
max
=
platform_max
-
min
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_volsw_range
);
/**
* snd_soc_put_volsw_range - single mixer put value callback with range.
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value, within a range, for a single mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_put_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
rreg
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
int
min
=
mc
->
min
;
int
max
=
mc
->
max
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
int
val
,
val_mask
;
int
ret
;
if
(
invert
)
val
=
(
max
-
ucontrol
->
value
.
integer
.
value
[
0
])
&
mask
;
else
val
=
((
ucontrol
->
value
.
integer
.
value
[
0
]
+
min
)
&
mask
);
val_mask
=
mask
<<
shift
;
val
=
val
<<
shift
;
ret
=
snd_soc_component_update_bits
(
component
,
reg
,
val_mask
,
val
);
if
(
ret
<
0
)
return
ret
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
if
(
invert
)
val
=
(
max
-
ucontrol
->
value
.
integer
.
value
[
1
])
&
mask
;
else
val
=
((
ucontrol
->
value
.
integer
.
value
[
1
]
+
min
)
&
mask
);
val_mask
=
mask
<<
shift
;
val
=
val
<<
shift
;
ret
=
snd_soc_component_update_bits
(
component
,
rreg
,
val_mask
,
val
);
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_volsw_range
);
/**
* snd_soc_get_volsw_range - single mixer get callback with range
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value, within a range, of a single mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_get_volsw_range
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
rreg
=
mc
->
rreg
;
unsigned
int
shift
=
mc
->
shift
;
int
min
=
mc
->
min
;
int
max
=
mc
->
max
;
unsigned
int
mask
=
(
1
<<
fls
(
max
))
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
int
val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
(
val
>>
shift
)
&
mask
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
0
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
0
];
else
ucontrol
->
value
.
integer
.
value
[
0
]
=
ucontrol
->
value
.
integer
.
value
[
0
]
-
min
;
if
(
snd_soc_volsw_is_stereo
(
mc
))
{
ret
=
snd_soc_component_read
(
component
,
rreg
,
&
val
);
if
(
ret
)
return
ret
;
ucontrol
->
value
.
integer
.
value
[
1
]
=
(
val
>>
shift
)
&
mask
;
if
(
invert
)
ucontrol
->
value
.
integer
.
value
[
1
]
=
max
-
ucontrol
->
value
.
integer
.
value
[
1
];
else
ucontrol
->
value
.
integer
.
value
[
1
]
=
ucontrol
->
value
.
integer
.
value
[
1
]
-
min
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_volsw_range
);
/**
* snd_soc_limit_volume - Set new limit to an existing volume control.
*
* @codec: where to look for the control
* @name: Name of the control
* @max: new maximum limit
*
* Return 0 for success, else error.
*/
int
snd_soc_limit_volume
(
struct
snd_soc_codec
*
codec
,
const
char
*
name
,
int
max
)
{
struct
snd_card
*
card
=
codec
->
component
.
card
->
snd_card
;
struct
snd_kcontrol
*
kctl
;
struct
soc_mixer_control
*
mc
;
int
found
=
0
;
int
ret
=
-
EINVAL
;
/* Sanity check for name and max */
if
(
unlikely
(
!
name
||
max
<=
0
))
return
-
EINVAL
;
list_for_each_entry
(
kctl
,
&
card
->
controls
,
list
)
{
if
(
!
strncmp
(
kctl
->
id
.
name
,
name
,
sizeof
(
kctl
->
id
.
name
)))
{
found
=
1
;
break
;
}
}
if
(
found
)
{
mc
=
(
struct
soc_mixer_control
*
)
kctl
->
private_value
;
if
(
max
<=
mc
->
max
)
{
mc
->
platform_max
=
max
;
ret
=
0
;
}
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_limit_volume
);
int
snd_soc_bytes_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_bytes
*
params
=
(
void
*
)
kcontrol
->
private_value
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_BYTES
;
uinfo
->
count
=
params
->
num_regs
*
component
->
val_bytes
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_info
);
int
snd_soc_bytes_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_bytes
*
params
=
(
void
*
)
kcontrol
->
private_value
;
int
ret
;
if
(
component
->
regmap
)
ret
=
regmap_raw_read
(
component
->
regmap
,
params
->
base
,
ucontrol
->
value
.
bytes
.
data
,
params
->
num_regs
*
component
->
val_bytes
);
else
ret
=
-
EINVAL
;
/* Hide any masked bytes to ensure consistent data reporting */
if
(
ret
==
0
&&
params
->
mask
)
{
switch
(
component
->
val_bytes
)
{
case
1
:
ucontrol
->
value
.
bytes
.
data
[
0
]
&=
~
params
->
mask
;
break
;
case
2
:
((
u16
*
)(
&
ucontrol
->
value
.
bytes
.
data
))[
0
]
&=
cpu_to_be16
(
~
params
->
mask
);
break
;
case
4
:
((
u32
*
)(
&
ucontrol
->
value
.
bytes
.
data
))[
0
]
&=
cpu_to_be32
(
~
params
->
mask
);
break
;
default:
return
-
EINVAL
;
}
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_get
);
int
snd_soc_bytes_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_bytes
*
params
=
(
void
*
)
kcontrol
->
private_value
;
int
ret
,
len
;
unsigned
int
val
,
mask
;
void
*
data
;
if
(
!
component
->
regmap
||
!
params
->
num_regs
)
return
-
EINVAL
;
len
=
params
->
num_regs
*
component
->
val_bytes
;
data
=
kmemdup
(
ucontrol
->
value
.
bytes
.
data
,
len
,
GFP_KERNEL
|
GFP_DMA
);
if
(
!
data
)
return
-
ENOMEM
;
/*
* If we've got a mask then we need to preserve the register
* bits. We shouldn't modify the incoming data so take a
* copy.
*/
if
(
params
->
mask
)
{
ret
=
regmap_read
(
component
->
regmap
,
params
->
base
,
&
val
);
if
(
ret
!=
0
)
goto
out
;
val
&=
params
->
mask
;
switch
(
component
->
val_bytes
)
{
case
1
:
((
u8
*
)
data
)[
0
]
&=
~
params
->
mask
;
((
u8
*
)
data
)[
0
]
|=
val
;
break
;
case
2
:
mask
=
~
params
->
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
mask
,
&
mask
);
if
(
ret
!=
0
)
goto
out
;
((
u16
*
)
data
)[
0
]
&=
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
val
,
&
val
);
if
(
ret
!=
0
)
goto
out
;
((
u16
*
)
data
)[
0
]
|=
val
;
break
;
case
4
:
mask
=
~
params
->
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
mask
,
&
mask
);
if
(
ret
!=
0
)
goto
out
;
((
u32
*
)
data
)[
0
]
&=
mask
;
ret
=
regmap_parse_val
(
component
->
regmap
,
&
val
,
&
val
);
if
(
ret
!=
0
)
goto
out
;
((
u32
*
)
data
)[
0
]
|=
val
;
break
;
default:
ret
=
-
EINVAL
;
goto
out
;
}
}
ret
=
regmap_raw_write
(
component
->
regmap
,
params
->
base
,
data
,
len
);
out:
kfree
(
data
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_put
);
int
snd_soc_bytes_info_ext
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
ucontrol
)
{
struct
soc_bytes_ext
*
params
=
(
void
*
)
kcontrol
->
private_value
;
ucontrol
->
type
=
SNDRV_CTL_ELEM_TYPE_BYTES
;
ucontrol
->
count
=
params
->
max
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_info_ext
);
int
snd_soc_bytes_tlv_callback
(
struct
snd_kcontrol
*
kcontrol
,
int
op_flag
,
unsigned
int
size
,
unsigned
int
__user
*
tlv
)
{
struct
soc_bytes_ext
*
params
=
(
void
*
)
kcontrol
->
private_value
;
unsigned
int
count
=
size
<
params
->
max
?
size
:
params
->
max
;
int
ret
=
-
ENXIO
;
switch
(
op_flag
)
{
case
SNDRV_CTL_TLV_OP_READ
:
if
(
params
->
get
)
ret
=
params
->
get
(
tlv
,
count
);
break
;
case
SNDRV_CTL_TLV_OP_WRITE
:
if
(
params
->
put
)
ret
=
params
->
put
(
tlv
,
count
);
break
;
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_bytes_tlv_callback
);
/**
* snd_soc_info_xr_sx - signed multi register info callback
* @kcontrol: mreg control
* @uinfo: control element information
*
* Callback to provide information of a control that can
* span multiple codec registers which together
* forms a single signed value in a MSB/LSB manner.
*
* Returns 0 for success.
*/
int
snd_soc_info_xr_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
soc_mreg_control
*
mc
=
(
struct
soc_mreg_control
*
)
kcontrol
->
private_value
;
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_INTEGER
;
uinfo
->
count
=
1
;
uinfo
->
value
.
integer
.
min
=
mc
->
min
;
uinfo
->
value
.
integer
.
max
=
mc
->
max
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_info_xr_sx
);
/**
* snd_soc_get_xr_sx - signed multi register get callback
* @kcontrol: mreg control
* @ucontrol: control element information
*
* Callback to get the value of a control that can span
* multiple codec registers which together forms a single
* signed value in a MSB/LSB manner. The control supports
* specifying total no of bits used to allow for bitfields
* across the multiple codec registers.
*
* Returns 0 for success.
*/
int
snd_soc_get_xr_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mreg_control
*
mc
=
(
struct
soc_mreg_control
*
)
kcontrol
->
private_value
;
unsigned
int
regbase
=
mc
->
regbase
;
unsigned
int
regcount
=
mc
->
regcount
;
unsigned
int
regwshift
=
component
->
val_bytes
*
BITS_PER_BYTE
;
unsigned
int
regwmask
=
(
1
<<
regwshift
)
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
long
mask
=
(
1UL
<<
mc
->
nbits
)
-
1
;
long
min
=
mc
->
min
;
long
max
=
mc
->
max
;
long
val
=
0
;
unsigned
int
regval
;
unsigned
int
i
;
int
ret
;
for
(
i
=
0
;
i
<
regcount
;
i
++
)
{
ret
=
snd_soc_component_read
(
component
,
regbase
+
i
,
&
regval
);
if
(
ret
)
return
ret
;
val
|=
(
regval
&
regwmask
)
<<
(
regwshift
*
(
regcount
-
i
-
1
));
}
val
&=
mask
;
if
(
min
<
0
&&
val
>
max
)
val
|=
~
mask
;
if
(
invert
)
val
=
max
-
val
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
val
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_xr_sx
);
/**
* snd_soc_put_xr_sx - signed multi register get callback
* @kcontrol: mreg control
* @ucontrol: control element information
*
* Callback to set the value of a control that can span
* multiple codec registers which together forms a single
* signed value in a MSB/LSB manner. The control supports
* specifying total no of bits used to allow for bitfields
* across the multiple codec registers.
*
* Returns 0 for success.
*/
int
snd_soc_put_xr_sx
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mreg_control
*
mc
=
(
struct
soc_mreg_control
*
)
kcontrol
->
private_value
;
unsigned
int
regbase
=
mc
->
regbase
;
unsigned
int
regcount
=
mc
->
regcount
;
unsigned
int
regwshift
=
component
->
val_bytes
*
BITS_PER_BYTE
;
unsigned
int
regwmask
=
(
1
<<
regwshift
)
-
1
;
unsigned
int
invert
=
mc
->
invert
;
unsigned
long
mask
=
(
1UL
<<
mc
->
nbits
)
-
1
;
long
max
=
mc
->
max
;
long
val
=
ucontrol
->
value
.
integer
.
value
[
0
];
unsigned
int
i
,
regval
,
regmask
;
int
err
;
if
(
invert
)
val
=
max
-
val
;
val
&=
mask
;
for
(
i
=
0
;
i
<
regcount
;
i
++
)
{
regval
=
(
val
>>
(
regwshift
*
(
regcount
-
i
-
1
)))
&
regwmask
;
regmask
=
(
mask
>>
(
regwshift
*
(
regcount
-
i
-
1
)))
&
regwmask
;
err
=
snd_soc_component_update_bits
(
component
,
regbase
+
i
,
regmask
,
regval
);
if
(
err
<
0
)
return
err
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_xr_sx
);
/**
* snd_soc_get_strobe - strobe get callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback get the value of a strobe mixer control.
*
* Returns 0 for success.
*/
int
snd_soc_get_strobe
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
mask
=
1
<<
shift
;
unsigned
int
invert
=
mc
->
invert
!=
0
;
unsigned
int
val
;
int
ret
;
ret
=
snd_soc_component_read
(
component
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
val
&=
mask
;
if
(
shift
!=
0
&&
val
!=
0
)
val
=
val
>>
shift
;
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
val
^
invert
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_strobe
);
/**
* snd_soc_put_strobe - strobe put callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback strobe a register bit to high then low (or the inverse)
* in one pass of a single mixer enum control.
*
* Returns 1 for success.
*/
int
snd_soc_put_strobe
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_component
*
component
=
snd_kcontrol_chip
(
kcontrol
);
struct
soc_mixer_control
*
mc
=
(
struct
soc_mixer_control
*
)
kcontrol
->
private_value
;
unsigned
int
reg
=
mc
->
reg
;
unsigned
int
shift
=
mc
->
shift
;
unsigned
int
mask
=
1
<<
shift
;
unsigned
int
invert
=
mc
->
invert
!=
0
;
unsigned
int
strobe
=
ucontrol
->
value
.
enumerated
.
item
[
0
]
!=
0
;
unsigned
int
val1
=
(
strobe
^
invert
)
?
mask
:
0
;
unsigned
int
val2
=
(
strobe
^
invert
)
?
0
:
mask
;
int
err
;
err
=
snd_soc_component_update_bits
(
component
,
reg
,
mask
,
val1
);
if
(
err
<
0
)
return
err
;
return
snd_soc_component_update_bits
(
component
,
reg
,
mask
,
val2
);
}
EXPORT_SYMBOL_GPL
(
snd_soc_put_strobe
);
sound/soc/soc-pcm.c
View file @
941725f5
...
@@ -654,6 +654,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
...
@@ -654,6 +654,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
codec_dai
->
rate
=
0
;
codec_dai
->
rate
=
0
;
}
}
snd_soc_dai_digital_mute
(
cpu_dai
,
1
,
substream
->
stream
);
if
(
cpu_dai
->
driver
->
ops
->
shutdown
)
if
(
cpu_dai
->
driver
->
ops
->
shutdown
)
cpu_dai
->
driver
->
ops
->
shutdown
(
substream
,
cpu_dai
);
cpu_dai
->
driver
->
ops
->
shutdown
(
substream
,
cpu_dai
);
...
@@ -772,6 +774,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
...
@@ -772,6 +774,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
for
(
i
=
0
;
i
<
rtd
->
num_codecs
;
i
++
)
for
(
i
=
0
;
i
<
rtd
->
num_codecs
;
i
++
)
snd_soc_dai_digital_mute
(
rtd
->
codec_dais
[
i
],
0
,
snd_soc_dai_digital_mute
(
rtd
->
codec_dais
[
i
],
0
,
substream
->
stream
);
substream
->
stream
);
snd_soc_dai_digital_mute
(
cpu_dai
,
0
,
substream
->
stream
);
out:
out:
mutex_unlock
(
&
rtd
->
pcm_mutex
);
mutex_unlock
(
&
rtd
->
pcm_mutex
);
...
...
sound/soc/txx9/txx9aclc.c
View file @
941725f5
...
@@ -292,7 +292,7 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
...
@@ -292,7 +292,7 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
struct
snd_card
*
card
=
rtd
->
card
->
snd_card
;
struct
snd_card
*
card
=
rtd
->
card
->
snd_card
;
struct
snd_soc_dai
*
dai
=
rtd
->
cpu_dai
;
struct
snd_soc_dai
*
dai
=
rtd
->
cpu_dai
;
struct
snd_pcm
*
pcm
=
rtd
->
pcm
;
struct
snd_pcm
*
pcm
=
rtd
->
pcm
;
struct
platform_device
*
pdev
=
to_platform_device
(
dai
->
platform
->
dev
);
struct
platform_device
*
pdev
=
to_platform_device
(
rtd
->
platform
->
dev
);
struct
txx9aclc_soc_device
*
dev
;
struct
txx9aclc_soc_device
*
dev
;
struct
resource
*
r
;
struct
resource
*
r
;
int
i
;
int
i
;
...
...
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