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
16b57114
Commit
16b57114
authored
Feb 19, 2017
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
parents
c7bb6d80
7ba8ba3f
Changes
37
Show whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
1945 additions
and
845 deletions
+1945
-845
include/sound/soc.h
include/sound/soc.h
+4
-0
sound/hda/ext/hdac_ext_stream.c
sound/hda/ext/hdac_ext_stream.c
+9
-6
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/hdac_hdmi.c
+818
-509
sound/soc/codecs/hdac_hdmi.h
sound/soc/codecs/hdac_hdmi.h
+4
-1
sound/soc/codecs/rt298.c
sound/soc/codecs/rt298.c
+7
-0
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.c
+1
-0
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.c
+2
-0
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5670.c
+1
-0
sound/soc/intel/Kconfig
sound/soc/intel/Kconfig
+20
-31
sound/soc/intel/Makefile
sound/soc/intel/Makefile
+1
-1
sound/soc/intel/atom/Makefile
sound/soc/intel/atom/Makefile
+4
-3
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-atom-controls.c
+2
-2
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst-mfld-platform-pcm.c
+3
-2
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/atom/sst/sst_acpi.c
+50
-2
sound/soc/intel/atom/sst/sst_ipc.c
sound/soc/intel/atom/sst/sst_ipc.c
+0
-2
sound/soc/intel/atom/sst/sst_stream.c
sound/soc/intel/atom/sst/sst_stream.c
+0
-2
sound/soc/intel/boards/broadwell.c
sound/soc/intel/boards/broadwell.c
+2
-0
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bxt_da7219_max98357a.c
+71
-5
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/bxt_rt298.c
+73
-5
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5640.c
+10
-0
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5645.c
+349
-48
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c
+26
-8
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+26
-7
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/boards/skl_rt286.c
+23
-7
sound/soc/intel/common/sst-dsp.c
sound/soc/intel/common/sst-dsp.c
+26
-26
sound/soc/intel/skylake/bxt-sst.c
sound/soc/intel/skylake/bxt-sst.c
+22
-42
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-messages.c
+7
-0
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-nhlt.c
+49
-9
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-pcm.c
+91
-83
sound/soc/intel/skylake/skl-sst-dsp.h
sound/soc/intel/skylake/skl-sst-dsp.h
+1
-3
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst-ipc.h
+3
-2
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.c
+71
-26
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-topology.h
+19
-0
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl-tplg-interface.h
+0
-12
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.c
+12
-0
sound/soc/intel/skylake/skl.h
sound/soc/intel/skylake/skl.h
+4
-1
sound/soc/soc-core.c
sound/soc/soc-core.c
+134
-0
No files found.
include/sound/soc.h
View file @
16b57114
...
...
@@ -497,6 +497,8 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
int
snd_soc_runtime_set_dai_fmt
(
struct
snd_soc_pcm_runtime
*
rtd
,
unsigned
int
dai_fmt
);
int
snd_soc_set_dmi_name
(
struct
snd_soc_card
*
card
,
const
char
*
flavour
);
/* Utility functions to get clock rates from various things */
int
snd_soc_calc_frame_size
(
int
sample_size
,
int
channels
,
int
tdm_slots
);
int
snd_soc_params_to_frame_size
(
struct
snd_pcm_hw_params
*
params
);
...
...
@@ -1093,6 +1095,8 @@ struct snd_soc_card {
const
char
*
name
;
const
char
*
long_name
;
const
char
*
driver_name
;
char
dmi_longname
[
80
];
struct
device
*
dev
;
struct
snd_card
*
snd_card
;
struct
module
*
owner
;
...
...
sound/hda/ext/hdac_ext_stream.c
View file @
16b57114
...
...
@@ -128,14 +128,17 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
{
struct
hdac_stream
*
hstream
=
&
stream
->
hstream
;
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
u32
val
;
int
mask
=
AZX_PPCTL_PROCEN
(
hstream
->
index
);
spin_lock_irq
(
&
bus
->
reg_lock
);
if
(
decouple
)
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
0
,
AZX_PPCTL_PROCEN
(
hstream
->
index
));
else
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
AZX_PPCTL_PROCEN
(
hstream
->
index
),
0
);
val
=
readw
(
bus
->
ppcap
+
AZX_REG_PP_PPCTL
)
&
mask
;
if
(
decouple
&&
!
val
)
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
mask
,
mask
);
else
if
(
!
decouple
&&
val
)
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
mask
,
0
);
stream
->
decoupled
=
decouple
;
spin_unlock_irq
(
&
bus
->
reg_lock
);
}
...
...
sound/soc/codecs/hdac_hdmi.c
View file @
16b57114
...
...
@@ -42,10 +42,15 @@
#define HDA_MAX_CONNECTIONS 32
#define HDA_MAX_CVTS 3
#define HDA_MAX_PORTS 3
#define ELD_MAX_SIZE 256
#define ELD_FIXED_BYTES 20
#define ELD_VER_CEA_861D 2
#define ELD_VER_PARTIAL 31
#define ELD_MAX_MNL 16
struct
hdac_hdmi_cvt_params
{
unsigned
int
channels_min
;
unsigned
int
channels_max
;
...
...
@@ -77,43 +82,180 @@ struct hdac_hdmi_eld {
struct
hdac_hdmi_pin
{
struct
list_head
head
;
hda_nid_t
nid
;
bool
mst_capable
;
struct
hdac_hdmi_port
*
ports
;
int
num_ports
;
struct
hdac_ext_device
*
edev
;
};
struct
hdac_hdmi_port
{
struct
list_head
head
;
int
id
;
struct
hdac_hdmi_pin
*
pin
;
int
num_mux_nids
;
hda_nid_t
mux_nids
[
HDA_MAX_CONNECTIONS
];
struct
hdac_hdmi_eld
eld
;
struct
hdac_ext_device
*
edev
;
int
repoll_count
;
struct
delayed_work
work
;
struct
mutex
lock
;
bool
chmap_set
;
unsigned
char
chmap
[
8
];
/* ALSA API channel-map */
int
channels
;
/* current number of channels */
const
char
*
jack_pin
;
struct
snd_soc_dapm_context
*
dapm
;
const
char
*
output_pin
;
};
struct
hdac_hdmi_pcm
{
struct
list_head
head
;
int
pcm_id
;
struct
hdac_hdmi_pin
*
pin
;
struct
list_head
port_list
;
struct
hdac_hdmi_cvt
*
cvt
;
struct
snd_jack
*
jack
;
struct
snd_soc_jack
*
jack
;
int
stream_tag
;
int
channels
;
int
format
;
bool
chmap_set
;
unsigned
char
chmap
[
8
];
/* ALSA API channel-map */
struct
mutex
lock
;
int
jack_event
;
};
struct
hdac_hdmi_dai_p
in
_map
{
struct
hdac_hdmi_dai_p
ort
_map
{
int
dai_id
;
struct
hdac_hdmi_p
in
*
pin
;
struct
hdac_hdmi_p
ort
*
port
;
struct
hdac_hdmi_cvt
*
cvt
;
};
struct
hdac_hdmi_priv
{
struct
hdac_hdmi_dai_p
in
_map
dai_map
[
HDA_MAX_CVTS
];
struct
hdac_hdmi_dai_p
ort
_map
dai_map
[
HDA_MAX_CVTS
];
struct
list_head
pin_list
;
struct
list_head
cvt_list
;
struct
list_head
pcm_list
;
int
num_pin
;
int
num_cvt
;
int
num_ports
;
struct
mutex
pin_mutex
;
struct
hdac_chmap
chmap
;
};
static
struct
hdac_hdmi_pcm
*
hdac_hdmi_get_pcm_from_cvt
(
struct
hdac_hdmi_priv
*
hdmi
,
struct
hdac_hdmi_cvt
*
cvt
)
{
struct
hdac_hdmi_pcm
*
pcm
=
NULL
;
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
pcm
->
cvt
==
cvt
)
break
;
}
return
pcm
;
}
static
void
hdac_hdmi_jack_report
(
struct
hdac_hdmi_pcm
*
pcm
,
struct
hdac_hdmi_port
*
port
,
bool
is_connect
)
{
struct
hdac_ext_device
*
edev
=
port
->
pin
->
edev
;
if
(
is_connect
)
snd_soc_dapm_enable_pin
(
port
->
dapm
,
port
->
jack_pin
);
else
snd_soc_dapm_disable_pin
(
port
->
dapm
,
port
->
jack_pin
);
if
(
is_connect
)
{
/*
* Report Jack connect event when a device is connected
* for the first time where same PCM is attached to multiple
* ports.
*/
if
(
pcm
->
jack_event
==
0
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_soc_jack_report
(
pcm
->
jack
,
SND_JACK_AVOUT
,
SND_JACK_AVOUT
);
}
pcm
->
jack_event
++
;
}
else
{
/*
* Report Jack disconnect event when a device is disconnected
* is the only last connected device when same PCM is attached
* to multiple ports.
*/
if
(
pcm
->
jack_event
==
1
)
snd_soc_jack_report
(
pcm
->
jack
,
0
,
SND_JACK_AVOUT
);
if
(
pcm
->
jack_event
>
0
)
pcm
->
jack_event
--
;
}
snd_soc_dapm_sync
(
port
->
dapm
);
}
/* MST supported verbs */
/*
* Get the no devices that can be connected to a port on the Pin widget.
*/
static
int
hdac_hdmi_get_port_len
(
struct
hdac_ext_device
*
hdac
,
hda_nid_t
nid
)
{
unsigned
int
caps
;
unsigned
int
type
,
param
;
caps
=
get_wcaps
(
&
hdac
->
hdac
,
nid
);
type
=
get_wcaps_type
(
caps
);
if
(
!
(
caps
&
AC_WCAP_DIGITAL
)
||
(
type
!=
AC_WID_PIN
))
return
0
;
param
=
snd_hdac_read_parm_uncached
(
&
hdac
->
hdac
,
nid
,
AC_PAR_DEVLIST_LEN
);
if
(
param
==
-
1
)
return
param
;
return
param
&
AC_DEV_LIST_LEN_MASK
;
}
/*
* Get the port entry select on the pin. Return the port entry
* id selected on the pin. Return 0 means the first port entry
* is selected or MST is not supported.
*/
static
int
hdac_hdmi_port_select_get
(
struct
hdac_ext_device
*
hdac
,
struct
hdac_hdmi_port
*
port
)
{
return
snd_hdac_codec_read
(
&
hdac
->
hdac
,
port
->
pin
->
nid
,
0
,
AC_VERB_GET_DEVICE_SEL
,
0
);
}
/*
* Sets the selected port entry for the configuring Pin widget verb.
* returns error if port set is not equal to port get otherwise success
*/
static
int
hdac_hdmi_port_select_set
(
struct
hdac_ext_device
*
hdac
,
struct
hdac_hdmi_port
*
port
)
{
int
num_ports
;
if
(
!
port
->
pin
->
mst_capable
)
return
0
;
/* AC_PAR_DEVLIST_LEN is 0 based. */
num_ports
=
hdac_hdmi_get_port_len
(
hdac
,
port
->
pin
->
nid
);
if
(
num_ports
<
0
)
return
-
EIO
;
/*
* Device List Length is a 0 based integer value indicating the
* number of sink device that a MST Pin Widget can support.
*/
if
(
num_ports
+
1
<
port
->
id
)
return
0
;
snd_hdac_codec_write
(
&
hdac
->
hdac
,
port
->
pin
->
nid
,
0
,
AC_VERB_SET_DEVICE_SEL
,
port
->
id
);
if
(
port
->
id
!=
hdac_hdmi_port_select_get
(
hdac
,
port
))
return
-
EIO
;
dev_dbg
(
&
hdac
->
hdac
.
dev
,
"Selected the port=%d
\n
"
,
port
->
id
);
return
0
;
}
static
struct
hdac_hdmi_pcm
*
get_hdmi_pcm_from_id
(
struct
hdac_hdmi_priv
*
hdmi
,
int
pcm_idx
)
{
...
...
@@ -173,99 +315,6 @@ static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
}
/* HDMI ELD routines */
static
unsigned
int
hdac_hdmi_get_eld_data
(
struct
hdac_device
*
codec
,
hda_nid_t
nid
,
int
byte_index
)
{
unsigned
int
val
;
val
=
snd_hdac_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_HDMI_ELDD
,
byte_index
);
dev_dbg
(
&
codec
->
dev
,
"HDMI: ELD data byte %d: 0x%x
\n
"
,
byte_index
,
val
);
return
val
;
}
static
int
hdac_hdmi_get_eld_size
(
struct
hdac_device
*
codec
,
hda_nid_t
nid
)
{
return
snd_hdac_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_HDMI_DIP_SIZE
,
AC_DIPSIZE_ELD_BUF
);
}
/*
* This function queries the ELD size and ELD data and fills in the buffer
* passed by user
*/
static
int
hdac_hdmi_get_eld
(
struct
hdac_device
*
codec
,
hda_nid_t
nid
,
unsigned
char
*
buf
,
int
*
eld_size
)
{
int
i
,
size
,
ret
=
0
;
/*
* ELD size is initialized to zero in caller function. If no errors and
* ELD is valid, actual eld_size is assigned.
*/
size
=
hdac_hdmi_get_eld_size
(
codec
,
nid
);
if
(
size
<
ELD_FIXED_BYTES
||
size
>
ELD_MAX_SIZE
)
{
dev_err
(
&
codec
->
dev
,
"HDMI: invalid ELD buf size %d
\n
"
,
size
);
return
-
ERANGE
;
}
/* set ELD buffer */
for
(
i
=
0
;
i
<
size
;
i
++
)
{
unsigned
int
val
=
hdac_hdmi_get_eld_data
(
codec
,
nid
,
i
);
/*
* Graphics driver might be writing to ELD buffer right now.
* Just abort. The caller will repoll after a while.
*/
if
(
!
(
val
&
AC_ELDD_ELD_VALID
))
{
dev_err
(
&
codec
->
dev
,
"HDMI: invalid ELD data byte %d
\n
"
,
i
);
ret
=
-
EINVAL
;
goto
error
;
}
val
&=
AC_ELDD_ELD_DATA
;
/*
* The first byte cannot be zero. This can happen on some DVI
* connections. Some Intel chips may also need some 250ms delay
* to return non-zero ELD data, even when the graphics driver
* correctly writes ELD content before setting ELD_valid bit.
*/
if
(
!
val
&&
!
i
)
{
dev_err
(
&
codec
->
dev
,
"HDMI: 0 ELD data
\n
"
);
ret
=
-
EINVAL
;
goto
error
;
}
buf
[
i
]
=
val
;
}
*
eld_size
=
size
;
error:
return
ret
;
}
static
int
hdac_hdmi_setup_stream
(
struct
hdac_ext_device
*
hdac
,
hda_nid_t
cvt_nid
,
hda_nid_t
pin_nid
,
u32
stream_tag
,
int
format
)
{
unsigned
int
val
;
dev_dbg
(
&
hdac
->
hdac
.
dev
,
"cvt nid %d pnid %d stream %d format 0x%x
\n
"
,
cvt_nid
,
pin_nid
,
stream_tag
,
format
);
val
=
(
stream_tag
<<
4
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
cvt_nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
val
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
cvt_nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
format
);
return
0
;
}
static
void
hdac_hdmi_set_dip_index
(
struct
hdac_ext_device
*
hdac
,
hda_nid_t
pin_nid
,
int
packet_index
,
int
byte_index
)
...
...
@@ -291,13 +340,14 @@ struct dp_audio_infoframe {
};
static
int
hdac_hdmi_setup_audio_infoframe
(
struct
hdac_ext_device
*
hdac
,
hda_nid_t
cvt_nid
,
hda_nid_t
pin_nid
)
struct
hdac_hdmi_pcm
*
pcm
,
struct
hdac_hdmi_port
*
port
)
{
uint8_t
buffer
[
HDMI_INFOFRAME_HEADER_SIZE
+
HDMI_AUDIO_INFOFRAME_SIZE
];
struct
hdmi_audio_infoframe
frame
;
struct
hdac_hdmi_pin
*
pin
=
port
->
pin
;
struct
dp_audio_infoframe
dp_ai
;
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_
pin
*
pin
;
struct
hdac_hdmi_
cvt
*
cvt
=
pcm
->
cvt
;
u8
*
dip
;
int
ret
;
int
i
;
...
...
@@ -305,21 +355,16 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
u8
conn_type
;
int
channels
,
ca
;
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
if
(
pin
->
nid
==
pin_nid
)
break
;
}
ca
=
snd_hdac_channel_allocation
(
&
hdac
->
hdac
,
pin
->
eld
.
info
.
spk_alloc
,
pin
->
channels
,
pin
->
chmap_set
,
true
,
pin
->
chmap
);
ca
=
snd_hdac_channel_allocation
(
&
hdac
->
hdac
,
port
->
eld
.
info
.
spk_alloc
,
pcm
->
channels
,
pcm
->
chmap_set
,
true
,
pcm
->
chmap
);
channels
=
snd_hdac_get_active_channels
(
ca
);
hdmi
->
chmap
.
ops
.
set_channel_count
(
&
hdac
->
hdac
,
cvt
_
nid
,
channels
);
hdmi
->
chmap
.
ops
.
set_channel_count
(
&
hdac
->
hdac
,
cvt
->
nid
,
channels
);
snd_hdac_setup_channel_mapping
(
&
hdmi
->
chmap
,
pin
->
nid
,
false
,
ca
,
p
in
->
channels
,
pin
->
chmap
,
pin
->
chmap_set
);
p
cm
->
channels
,
pcm
->
chmap
,
pcm
->
chmap_set
);
eld_buf
=
p
in
->
eld
.
eld_buffer
;
eld_buf
=
p
ort
->
eld
.
eld_buffer
;
conn_type
=
drm_eld_get_conn_type
(
eld_buf
);
switch
(
conn_type
)
{
...
...
@@ -353,75 +398,50 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
}
/* stop infoframe transmission */
hdac_hdmi_set_dip_index
(
hdac
,
pin
_
nid
,
0x0
,
0x0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
_
nid
,
0
,
hdac_hdmi_set_dip_index
(
hdac
,
pin
->
nid
,
0x0
,
0x0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_HDMI_DIP_XMIT
,
AC_DIPXMIT_DISABLE
);
/* Fill infoframe. Index auto-incremented */
hdac_hdmi_set_dip_index
(
hdac
,
pin
_
nid
,
0x0
,
0x0
);
hdac_hdmi_set_dip_index
(
hdac
,
pin
->
nid
,
0x0
,
0x0
);
if
(
conn_type
==
DRM_ELD_CONN_TYPE_HDMI
)
{
for
(
i
=
0
;
i
<
sizeof
(
buffer
);
i
++
)
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
_
nid
,
0
,
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_HDMI_DIP_DATA
,
buffer
[
i
]);
}
else
{
for
(
i
=
0
;
i
<
sizeof
(
dp_ai
);
i
++
)
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
_
nid
,
0
,
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_HDMI_DIP_DATA
,
dip
[
i
]);
}
/* Start infoframe */
hdac_hdmi_set_dip_index
(
hdac
,
pin
_
nid
,
0x0
,
0x0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
_
nid
,
0
,
hdac_hdmi_set_dip_index
(
hdac
,
pin
->
nid
,
0x0
,
0x0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_HDMI_DIP_XMIT
,
AC_DIPXMIT_BEST
);
return
0
;
}
static
void
hdac_hdmi_set_power_state
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_dai_pin_map
*
dai_map
,
unsigned
int
pwr_state
)
static
int
hdac_hdmi_set_tdm_slot
(
struct
snd_soc_dai
*
dai
,
unsigned
int
tx_mask
,
unsigned
int
rx_mask
,
int
slots
,
int
slot_width
)
{
/* Power up pin widget */
if
(
!
snd_hdac_check_power_state
(
&
edev
->
hdac
,
dai_map
->
pin
->
nid
,
pwr_state
))
snd_hdac_codec_write
(
&
edev
->
hdac
,
dai_map
->
pin
->
nid
,
0
,
AC_VERB_SET_POWER_STATE
,
pwr_state
);
/* Power up converter */
if
(
!
snd_hdac_check_power_state
(
&
edev
->
hdac
,
dai_map
->
cvt
->
nid
,
pwr_state
))
snd_hdac_codec_write
(
&
edev
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_POWER_STATE
,
pwr_state
);
}
struct
hdac_ext_device
*
edev
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_dai_port_map
*
dai_map
;
struct
hdac_hdmi_pcm
*
pcm
;
static
int
hdac_hdmi_playback_prepare
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_ext_dma_params
*
dd
;
int
ret
;
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: strm_tag: %d
\n
"
,
__func__
,
tx_mask
);
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
pin
=
dai_map
->
pin
;
dd
=
(
struct
hdac_ext_dma_params
*
)
snd_soc_dai_get_dma_data
(
dai
,
substream
);
dev_dbg
(
&
hdac
->
hdac
.
dev
,
"stream tag from cpu dai %d format in cvt 0x%x
\n
"
,
dd
->
stream_tag
,
dd
->
format
);
mutex_lock
(
&
pin
->
lock
);
pin
->
channels
=
substream
->
runtime
->
channels
;
pcm
=
hdac_hdmi_get_pcm_from_cvt
(
hdmi
,
dai_map
->
cvt
);
ret
=
hdac_hdmi_setup_audio_infoframe
(
hdac
,
dai_map
->
cvt
->
nid
,
dai_map
->
pin
->
nid
);
mutex_unlock
(
&
pin
->
lock
);
if
(
ret
<
0
)
return
ret
;
if
(
pcm
)
pcm
->
stream_tag
=
(
tx_mask
<<
4
);
return
hdac_hdmi_setup_stream
(
hdac
,
dai_map
->
cvt
->
nid
,
dai_map
->
pin
->
nid
,
dd
->
stream_tag
,
dd
->
format
);
return
0
;
}
static
int
hdac_hdmi_set_hw_params
(
struct
snd_pcm_substream
*
substream
,
...
...
@@ -429,101 +449,41 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
{
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_ext_dma_params
*
dd
;
struct
hdac_hdmi_dai_port_map
*
dai_map
;
struct
hdac_hdmi_port
*
port
;
struct
hdac_hdmi_pcm
*
pcm
;
int
format
;
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
p
in
=
dai_map
->
pin
;
p
ort
=
dai_map
->
port
;
if
(
!
p
in
)
if
(
!
p
ort
)
return
-
ENODEV
;
if
((
!
pin
->
eld
.
monitor_present
)
||
(
!
pin
->
eld
.
eld_valid
))
{
dev_err
(
&
hdac
->
hdac
.
dev
,
"device is not configured for this pin: %d
\n
"
,
pin
->
nid
);
if
((
!
port
->
eld
.
monitor_present
)
||
(
!
port
->
eld
.
eld_valid
))
{
dev_err
(
&
hdac
->
hdac
.
dev
,
"device is not configured for this pin:port%d:%d
\n
"
,
port
->
pin
->
nid
,
port
->
id
);
return
-
ENODEV
;
}
dd
=
snd_soc_dai_get_dma_data
(
dai
,
substream
);
if
(
!
dd
)
{
dd
=
kzalloc
(
sizeof
(
*
dd
),
GFP_KERNEL
);
if
(
!
dd
)
return
-
ENOMEM
;
}
dd
->
format
=
snd_hdac_calc_stream_format
(
params_rate
(
hparams
),
format
=
snd_hdac_calc_stream_format
(
params_rate
(
hparams
),
params_channels
(
hparams
),
params_format
(
hparams
),
24
,
0
);
snd_soc_dai_set_dma_data
(
dai
,
substream
,
(
void
*
)
dd
);
return
0
;
}
static
int
hdac_hdmi_playback_cleanup
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
hdac_ext_device
*
edev
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_ext_dma_params
*
dd
;
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
dd
=
(
struct
hdac_ext_dma_params
*
)
snd_soc_dai_get_dma_data
(
dai
,
substream
);
if
(
dd
)
{
snd_soc_dai_set_dma_data
(
dai
,
substream
,
NULL
);
kfree
(
dd
);
}
return
0
;
}
static
void
hdac_hdmi_enable_cvt
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_dai_pin_map
*
dai_map
)
{
/* Enable transmission */
snd_hdac_codec_write
(
&
edev
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
1
);
/* Category Code (CC) to zero */
snd_hdac_codec_write
(
&
edev
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_DIGI_CONVERT_2
,
0
);
}
static
int
hdac_hdmi_enable_pin
(
struct
hdac_ext_device
*
hdac
,
struct
hdac_hdmi_dai_pin_map
*
dai_map
)
{
int
mux_idx
;
struct
hdac_hdmi_pin
*
pin
=
dai_map
->
pin
;
for
(
mux_idx
=
0
;
mux_idx
<
pin
->
num_mux_nids
;
mux_idx
++
)
{
if
(
pin
->
mux_nids
[
mux_idx
]
==
dai_map
->
cvt
->
nid
)
{
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_CONNECT_SEL
,
mux_idx
);
break
;
}
}
if
(
mux_idx
==
pin
->
num_mux_nids
)
pcm
=
hdac_hdmi_get_pcm_from_cvt
(
hdmi
,
dai_map
->
cvt
);
if
(
!
pcm
)
return
-
EIO
;
/* Enable out path for this pin widget */
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
hdac_hdmi_set_power_state
(
hdac
,
dai_map
,
AC_PWRST_D0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
);
pcm
->
format
=
format
;
pcm
->
channels
=
params_channels
(
hparams
);
return
0
;
}
static
int
hdac_hdmi_query_pin_connlist
(
struct
hdac_ext_device
*
hdac
,
struct
hdac_hdmi_pin
*
pin
)
static
int
hdac_hdmi_query_port_connlist
(
struct
hdac_ext_device
*
hdac
,
struct
hdac_hdmi_pin
*
pin
,
struct
hdac_hdmi_port
*
port
)
{
if
(
!
(
get_wcaps
(
&
hdac
->
hdac
,
pin
->
nid
)
&
AC_WCAP_CONN_LIST
))
{
dev_warn
(
&
hdac
->
hdac
.
dev
,
...
...
@@ -532,51 +492,60 @@ static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
return
-
EINVAL
;
}
pin
->
num_mux_nids
=
snd_hdac_get_connections
(
&
hdac
->
hdac
,
pin
->
nid
,
pin
->
mux_nids
,
HDA_MAX_CONNECTIONS
);
if
(
pin
->
num_mux_nids
==
0
)
dev_warn
(
&
hdac
->
hdac
.
dev
,
"No connections found for pin: %d
\n
"
,
pin
->
nid
);
if
(
hdac_hdmi_port_select_set
(
hdac
,
port
)
<
0
)
return
-
EIO
;
port
->
num_mux_nids
=
snd_hdac_get_connections
(
&
hdac
->
hdac
,
pin
->
nid
,
port
->
mux_nids
,
HDA_MAX_CONNECTIONS
);
if
(
port
->
num_mux_nids
==
0
)
dev_warn
(
&
hdac
->
hdac
.
dev
,
"No connections found for pin:port %d:%d
\n
"
,
pin
->
nid
,
port
->
id
);
dev_dbg
(
&
hdac
->
hdac
.
dev
,
"num_mux_nids %d for pin:
%d
\n
"
,
p
in
->
num_mux_nids
,
pin
->
n
id
);
dev_dbg
(
&
hdac
->
hdac
.
dev
,
"num_mux_nids %d for pin:
port %d:
%d
\n
"
,
p
ort
->
num_mux_nids
,
pin
->
nid
,
port
->
id
);
return
p
in
->
num_mux_nids
;
return
p
ort
->
num_mux_nids
;
}
/*
* Query pcm list and return p
in widge
t to which stream is routed.
* Query pcm list and return p
or
t to which stream is routed.
*
* Also query connection list of the pin, to validate the cvt to p
in
map.
* Also query connection list of the pin, to validate the cvt to p
ort
map.
*
* Same stream rendering to multiple p
in
s simultaneously can be done
* possibly, but not supported for now in driver. So return the first p
in
* Same stream rendering to multiple p
ort
s simultaneously can be done
* possibly, but not supported for now in driver. So return the first p
ort
* connected.
*/
static
struct
hdac_hdmi_p
in
*
hdac_hdmi_get_pin
_from_cvt
(
static
struct
hdac_hdmi_p
ort
*
hdac_hdmi_get_port
_from_cvt
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_priv
*
hdmi
,
struct
hdac_hdmi_cvt
*
cvt
)
{
struct
hdac_hdmi_pcm
*
pcm
;
struct
hdac_hdmi_p
in
*
pin
=
NULL
;
struct
hdac_hdmi_p
ort
*
port
=
NULL
;
int
ret
,
i
;
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
pcm
->
cvt
==
cvt
)
{
pin
=
pcm
->
pin
;
break
;
}
}
if
(
list_empty
(
&
pcm
->
port_list
))
continue
;
if
(
pin
)
{
ret
=
hdac_hdmi_query_pin_connlist
(
edev
,
pin
);
list_for_each_entry
(
port
,
&
pcm
->
port_list
,
head
)
{
mutex_lock
(
&
pcm
->
lock
);
ret
=
hdac_hdmi_query_port_connlist
(
edev
,
port
->
pin
,
port
);
mutex_unlock
(
&
pcm
->
lock
);
if
(
ret
<
0
)
return
NULL
;
continue
;
for
(
i
=
0
;
i
<
pin
->
num_mux_nids
;
i
++
)
{
if
(
pin
->
mux_nids
[
i
]
==
cvt
->
nid
)
return
pin
;
for
(
i
=
0
;
i
<
port
->
num_mux_nids
;
i
++
)
{
if
(
port
->
mux_nids
[
i
]
==
cvt
->
nid
&&
port
->
eld
.
monitor_present
&&
port
->
eld
.
eld_valid
)
return
port
;
}
}
}
}
...
...
@@ -593,67 +562,42 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
{
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_dai_p
in
_map
*
dai_map
;
struct
hdac_hdmi_dai_p
ort
_map
*
dai_map
;
struct
hdac_hdmi_cvt
*
cvt
;
struct
hdac_hdmi_p
in
*
pin
;
struct
hdac_hdmi_p
ort
*
port
;
int
ret
;
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
cvt
=
dai_map
->
cvt
;
p
in
=
hdac_hdmi_get_pin
_from_cvt
(
hdac
,
hdmi
,
cvt
);
p
ort
=
hdac_hdmi_get_port
_from_cvt
(
hdac
,
hdmi
,
cvt
);
/*
* To make PA and other userland happy.
* userland scans devices so returning error does not help.
*/
if
(
!
p
in
)
if
(
!
p
ort
)
return
0
;
if
((
!
pin
->
eld
.
monitor_present
)
||
(
!
pin
->
eld
.
eld_valid
))
{
if
((
!
port
->
eld
.
monitor_present
)
||
(
!
port
->
eld
.
eld_valid
))
{
dev_warn
(
&
hdac
->
hdac
.
dev
,
"Failed: monitor present? %d ELD valid?: %d for pin: %d
\n
"
,
pin
->
eld
.
monitor_present
,
pin
->
eld
.
eld_valid
,
pin
->
nid
);
"Failed: present?:%d ELD valid?:%d pin:port: %d:%d
\n
"
,
port
->
eld
.
monitor_present
,
port
->
eld
.
eld_valid
,
port
->
pin
->
nid
,
port
->
id
);
return
0
;
}
dai_map
->
pin
=
pin
;
hdac_hdmi_enable_cvt
(
hdac
,
dai_map
);
ret
=
hdac_hdmi_enable_pin
(
hdac
,
dai_map
);
if
(
ret
<
0
)
return
ret
;
dai_map
->
port
=
port
;
ret
=
hdac_hdmi_eld_limit_formats
(
substream
->
runtime
,
p
in
->
eld
.
eld_buffer
);
p
ort
->
eld
.
eld_buffer
);
if
(
ret
<
0
)
return
ret
;
return
snd_pcm_hw_constraint_eld
(
substream
->
runtime
,
pin
->
eld
.
eld_buffer
);
}
static
int
hdac_hdmi_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
,
struct
snd_soc_dai
*
dai
)
{
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
int
ret
;
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
if
(
cmd
==
SNDRV_PCM_TRIGGER_RESUME
)
{
ret
=
hdac_hdmi_enable_pin
(
hdac
,
dai_map
);
if
(
ret
<
0
)
return
ret
;
return
hdac_hdmi_playback_prepare
(
substream
,
dai
);
}
return
0
;
port
->
eld
.
eld_buffer
);
}
static
void
hdac_hdmi_pcm_close
(
struct
snd_pcm_substream
*
substream
,
...
...
@@ -661,29 +605,23 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
{
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
struct
hdac_hdmi_dai_port_map
*
dai_map
;
struct
hdac_hdmi_pcm
*
pcm
;
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
if
(
dai_map
->
pin
)
{
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
0
);
hdac_hdmi_set_power_state
(
hdac
,
dai_map
,
AC_PWRST_D3
);
pcm
=
hdac_hdmi_get_pcm_from_cvt
(
hdmi
,
dai_map
->
cvt
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
pin
->
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
);
mutex_lock
(
&
dai_map
->
pin
->
lock
);
dai_map
->
pin
->
chmap_set
=
false
;
memset
(
dai_map
->
pin
->
chmap
,
0
,
sizeof
(
dai_map
->
pin
->
chmap
));
dai_map
->
pin
->
channels
=
0
;
mutex_unlock
(
&
dai_map
->
pin
->
lock
);
dai_map
->
pin
=
NULL
;
if
(
pcm
)
{
mutex_lock
(
&
pcm
->
lock
);
pcm
->
chmap_set
=
false
;
memset
(
pcm
->
chmap
,
0
,
sizeof
(
pcm
->
chmap
));
pcm
->
channels
=
0
;
mutex_unlock
(
&
pcm
->
lock
);
}
if
(
dai_map
->
port
)
dai_map
->
port
=
NULL
;
}
static
int
...
...
@@ -716,10 +654,11 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
}
static
int
hdac_hdmi_fill_widget_info
(
struct
device
*
dev
,
struct
snd_soc_dapm_widget
*
w
,
enum
snd_soc_dapm_type
id
,
void
*
priv
,
const
char
*
wname
,
const
char
*
stream
,
struct
snd_kcontrol_new
*
wc
,
int
numkc
)
struct
snd_soc_dapm_widget
*
w
,
enum
snd_soc_dapm_type
id
,
void
*
priv
,
const
char
*
wname
,
const
char
*
stream
,
struct
snd_kcontrol_new
*
wc
,
int
numkc
,
int
(
*
event
)(
struct
snd_soc_dapm_widget
*
,
struct
snd_kcontrol
*
,
int
),
unsigned
short
event_flags
)
{
w
->
id
=
id
;
w
->
name
=
devm_kstrdup
(
dev
,
wname
,
GFP_KERNEL
);
...
...
@@ -732,6 +671,8 @@ static int hdac_hdmi_fill_widget_info(struct device *dev,
w
->
kcontrol_news
=
wc
;
w
->
num_kcontrols
=
numkc
;
w
->
priv
=
priv
;
w
->
event
=
event
;
w
->
event_flags
=
event_flags
;
return
0
;
}
...
...
@@ -748,30 +689,175 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
}
static
struct
hdac_hdmi_pcm
*
hdac_hdmi_get_pcm
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_p
in
*
pin
)
struct
hdac_hdmi_p
ort
*
port
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
NULL
;
struct
hdac_hdmi_port
*
p
;
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
pcm
->
pin
==
pin
)
if
(
list_empty
(
&
pcm
->
port_list
))
continue
;
list_for_each_entry
(
p
,
&
pcm
->
port_list
,
head
)
{
if
(
p
->
id
==
port
->
id
&&
port
->
pin
==
p
->
pin
)
return
pcm
;
}
}
return
NULL
;
}
static
void
hdac_hdmi_set_power_state
(
struct
hdac_ext_device
*
edev
,
hda_nid_t
nid
,
unsigned
int
pwr_state
)
{
if
(
get_wcaps
(
&
edev
->
hdac
,
nid
)
&
AC_WCAP_POWER
)
{
if
(
!
snd_hdac_check_power_state
(
&
edev
->
hdac
,
nid
,
pwr_state
))
snd_hdac_codec_write
(
&
edev
->
hdac
,
nid
,
0
,
AC_VERB_SET_POWER_STATE
,
pwr_state
);
}
}
static
void
hdac_hdmi_set_amp
(
struct
hdac_ext_device
*
edev
,
hda_nid_t
nid
,
int
val
)
{
if
(
get_wcaps
(
&
edev
->
hdac
,
nid
)
&
AC_WCAP_OUT_AMP
)
snd_hdac_codec_write
(
&
edev
->
hdac
,
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
val
);
}
static
int
hdac_hdmi_pin_output_widget_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kc
,
int
event
)
{
struct
hdac_hdmi_port
*
port
=
w
->
priv
;
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
w
->
dapm
->
dev
);
struct
hdac_hdmi_pcm
*
pcm
;
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: widget: %s event: %x
\n
"
,
__func__
,
w
->
name
,
event
);
pcm
=
hdac_hdmi_get_pcm
(
edev
,
port
);
if
(
!
pcm
)
return
-
EIO
;
/* set the device if pin is mst_capable */
if
(
hdac_hdmi_port_select_set
(
edev
,
port
)
<
0
)
return
-
EIO
;
switch
(
event
)
{
case
SND_SOC_DAPM_PRE_PMU
:
hdac_hdmi_set_power_state
(
edev
,
port
->
pin
->
nid
,
AC_PWRST_D0
);
/* Enable out path for this pin widget */
snd_hdac_codec_write
(
&
edev
->
hdac
,
port
->
pin
->
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
hdac_hdmi_set_amp
(
edev
,
port
->
pin
->
nid
,
AMP_OUT_UNMUTE
);
return
hdac_hdmi_setup_audio_infoframe
(
edev
,
pcm
,
port
);
case
SND_SOC_DAPM_POST_PMD
:
hdac_hdmi_set_amp
(
edev
,
port
->
pin
->
nid
,
AMP_OUT_MUTE
);
/* Disable out path for this pin widget */
snd_hdac_codec_write
(
&
edev
->
hdac
,
port
->
pin
->
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0
);
hdac_hdmi_set_power_state
(
edev
,
port
->
pin
->
nid
,
AC_PWRST_D3
);
break
;
}
return
0
;
}
static
int
hdac_hdmi_cvt_output_widget_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kc
,
int
event
)
{
struct
hdac_hdmi_cvt
*
cvt
=
w
->
priv
;
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
w
->
dapm
->
dev
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
;
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: widget: %s event: %x
\n
"
,
__func__
,
w
->
name
,
event
);
pcm
=
hdac_hdmi_get_pcm_from_cvt
(
hdmi
,
cvt
);
if
(
!
pcm
)
return
-
EIO
;
switch
(
event
)
{
case
SND_SOC_DAPM_PRE_PMU
:
hdac_hdmi_set_power_state
(
edev
,
cvt
->
nid
,
AC_PWRST_D0
);
/* Enable transmission */
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
1
);
/* Category Code (CC) to zero */
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_DIGI_CONVERT_2
,
0
);
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
pcm
->
stream_tag
);
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
pcm
->
format
);
break
;
case
SND_SOC_DAPM_POST_PMD
:
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
0
);
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
0
);
hdac_hdmi_set_power_state
(
edev
,
cvt
->
nid
,
AC_PWRST_D3
);
break
;
}
return
0
;
}
static
int
hdac_hdmi_pin_mux_widget_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kc
,
int
event
)
{
struct
hdac_hdmi_port
*
port
=
w
->
priv
;
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
w
->
dapm
->
dev
);
int
mux_idx
;
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: widget: %s event: %x
\n
"
,
__func__
,
w
->
name
,
event
);
if
(
!
kc
)
kc
=
w
->
kcontrols
[
0
];
mux_idx
=
dapm_kcontrol_get_value
(
kc
);
/* set the device if pin is mst_capable */
if
(
hdac_hdmi_port_select_set
(
edev
,
port
)
<
0
)
return
-
EIO
;
if
(
mux_idx
>
0
)
{
snd_hdac_codec_write
(
&
edev
->
hdac
,
port
->
pin
->
nid
,
0
,
AC_VERB_SET_CONNECT_SEL
,
(
mux_idx
-
1
));
}
return
0
;
}
/*
* Based on user selection, map the PINs with the PCMs.
*/
static
int
hdac_hdmi_set_pin_mux
(
struct
snd_kcontrol
*
kcontrol
,
static
int
hdac_hdmi_set_pin_
port_
mux
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
int
ret
;
struct
hdac_hdmi_port
*
p
,
*
p_next
;
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
struct
snd_soc_dapm_widget
*
w
=
snd_soc_dapm_kcontrol_widget
(
kcontrol
);
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
hdac_hdmi_p
in
*
pin
=
w
->
priv
;
struct
hdac_hdmi_p
ort
*
port
=
w
->
priv
;
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
dapm
->
dev
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
NULL
;
...
...
@@ -781,28 +867,37 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol,
if
(
ret
<
0
)
return
ret
;
if
(
port
==
NULL
)
return
-
EINVAL
;
mutex_lock
(
&
hdmi
->
pin_mutex
);
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
pcm
->
pin
==
pin
)
pcm
->
pin
=
NULL
;
if
(
list_empty
(
&
pcm
->
port_list
))
continue
;
list_for_each_entry_safe
(
p
,
p_next
,
&
pcm
->
port_list
,
head
)
{
if
(
p
==
port
&&
p
->
id
==
port
->
id
&&
p
->
pin
==
port
->
pin
)
{
hdac_hdmi_jack_report
(
pcm
,
port
,
false
);
list_del
(
&
p
->
head
);
}
}
}
/*
* Jack status is not reported during device probe as the
* PCMs are not registered by then. So report it here.
*/
if
(
!
strcmp
(
cvt_name
,
pcm
->
cvt
->
name
)
&&
!
pcm
->
pin
)
{
pcm
->
pin
=
pin
;
if
(
pin
->
eld
.
monitor_present
&&
pin
->
eld
.
eld_valid
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_jack_report
(
pcm
->
jack
,
SND_JACK_AVOUT
);
}
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
!
strcmp
(
cvt_name
,
pcm
->
cvt
->
name
))
{
list_add_tail
(
&
port
->
head
,
&
pcm
->
port_list
);
if
(
port
->
eld
.
monitor_present
&&
port
->
eld
.
eld_valid
)
{
hdac_hdmi_jack_report
(
pcm
,
port
,
true
);
mutex_unlock
(
&
hdmi
->
pin_mutex
);
return
ret
;
}
}
}
mutex_unlock
(
&
hdmi
->
pin_mutex
);
return
ret
;
...
...
@@ -817,12 +912,13 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol,
* care of selecting the right one and leaving all other inputs selected to
* "NONE"
*/
static
int
hdac_hdmi_create_pin_muxs
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_p
in
*
pin
,
static
int
hdac_hdmi_create_pin_
port_
muxs
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_p
ort
*
port
,
struct
snd_soc_dapm_widget
*
widget
,
const
char
*
widget_name
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
=
port
->
pin
;
struct
snd_kcontrol_new
*
kc
;
struct
hdac_hdmi_cvt
*
cvt
;
struct
soc_enum
*
se
;
...
...
@@ -841,7 +937,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
if
(
!
se
)
return
-
ENOMEM
;
sprintf
(
kc_name
,
"Pin %d
Input"
,
pin
->
n
id
);
sprintf
(
kc_name
,
"Pin %d
port %d Input"
,
pin
->
nid
,
port
->
id
);
kc
->
name
=
devm_kstrdup
(
&
edev
->
hdac
.
dev
,
kc_name
,
GFP_KERNEL
);
if
(
!
kc
->
name
)
return
-
ENOMEM
;
...
...
@@ -850,7 +946,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
kc
->
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
;
kc
->
access
=
0
;
kc
->
info
=
snd_soc_info_enum_double
;
kc
->
put
=
hdac_hdmi_set_pin_mux
;
kc
->
put
=
hdac_hdmi_set_pin_
port_
mux
;
kc
->
get
=
snd_soc_dapm_get_enum_double
;
se
->
reg
=
SND_SOC_NOPM
;
...
...
@@ -878,7 +974,9 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
return
-
ENOMEM
;
return
hdac_hdmi_fill_widget_info
(
&
edev
->
hdac
.
dev
,
widget
,
snd_soc_dapm_mux
,
pin
,
widget_name
,
NULL
,
kc
,
1
);
snd_soc_dapm_mux
,
port
,
widget_name
,
NULL
,
kc
,
1
,
hdac_hdmi_pin_mux_widget_event
,
SND_SOC_DAPM_PRE_PMU
|
SND_SOC_DAPM_POST_REG
);
}
/* Add cvt <- input <- mux route map */
...
...
@@ -889,10 +987,10 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
const
struct
snd_kcontrol_new
*
kc
;
struct
soc_enum
*
se
;
int
mux_index
=
hdmi
->
num_cvt
+
hdmi
->
num_p
in
;
int
mux_index
=
hdmi
->
num_cvt
+
hdmi
->
num_p
orts
;
int
i
,
j
;
for
(
i
=
0
;
i
<
hdmi
->
num_p
in
;
i
++
)
{
for
(
i
=
0
;
i
<
hdmi
->
num_p
orts
;
i
++
)
{
kc
=
widgets
[
mux_index
].
kcontrol_news
;
se
=
(
struct
soc_enum
*
)
kc
->
private_value
;
for
(
j
=
0
;
j
<
hdmi
->
num_cvt
;
j
++
)
{
...
...
@@ -911,17 +1009,18 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
/*
* Widgets are added in the below sequence
* Converter widgets for num converters enumerated
* Pin
widgets for num p
ins enumerated
* Pin mux widgets to represent connenction list of pin widget
* Pin
-port widgets for num ports for P
ins enumerated
* Pin
-port
mux widgets to represent connenction list of pin widget
*
* Total widgets elements = num_cvt + num_pin + num_pin;
* For each port, one Mux and One output widget is added
* Total widgets elements = num_cvt + (num_ports * 2);
*
* Routes are added as below:
* pin
mux -> pin (based on num_pin
s)
* cvt -> "Input sel control" -> pin_mux
* pin
-port mux -> pin (based on num_port
s)
* cvt -> "Input sel control" -> pin
-port
_mux
*
* Total route elements:
* num_p
in
s + (pin_muxes * num_cvt)
* num_p
ort
s + (pin_muxes * num_cvt)
*/
static
int
create_fill_widget_route_map
(
struct
snd_soc_dapm_context
*
dapm
)
{
...
...
@@ -933,13 +1032,13 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
char
widget_name
[
NAME_SIZE
];
struct
hdac_hdmi_cvt
*
cvt
;
struct
hdac_hdmi_pin
*
pin
;
int
ret
,
i
=
0
,
num_routes
=
0
;
int
ret
,
i
=
0
,
num_routes
=
0
,
j
;
if
(
list_empty
(
&
hdmi
->
cvt_list
)
||
list_empty
(
&
hdmi
->
pin_list
))
return
-
EINVAL
;
widgets
=
devm_kzalloc
(
dapm
->
dev
,
(
sizeof
(
*
widgets
)
*
((
2
*
hdmi
->
num_pin
)
+
hdmi
->
num_cvt
)),
widgets
=
devm_kzalloc
(
dapm
->
dev
,
(
sizeof
(
*
widgets
)
*
((
2
*
hdmi
->
num_ports
)
+
hdmi
->
num_cvt
)),
GFP_KERNEL
);
if
(
!
widgets
)
...
...
@@ -949,27 +1048,39 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
list_for_each_entry
(
cvt
,
&
hdmi
->
cvt_list
,
head
)
{
sprintf
(
widget_name
,
"Converter %d"
,
cvt
->
nid
);
ret
=
hdac_hdmi_fill_widget_info
(
dapm
->
dev
,
&
widgets
[
i
],
snd_soc_dapm_aif_in
,
&
cvt
->
nid
,
widget_name
,
dai_drv
[
i
].
playback
.
stream_name
,
NULL
,
0
);
snd_soc_dapm_aif_in
,
cvt
,
widget_name
,
dai_drv
[
i
].
playback
.
stream_name
,
NULL
,
0
,
hdac_hdmi_cvt_output_widget_event
,
SND_SOC_DAPM_PRE_PMU
|
SND_SOC_DAPM_POST_PMD
);
if
(
ret
<
0
)
return
ret
;
i
++
;
}
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
sprintf
(
widget_name
,
"hif%d Output"
,
pin
->
nid
);
for
(
j
=
0
;
j
<
pin
->
num_ports
;
j
++
)
{
sprintf
(
widget_name
,
"hif%d-%d Output"
,
pin
->
nid
,
pin
->
ports
[
j
].
id
);
ret
=
hdac_hdmi_fill_widget_info
(
dapm
->
dev
,
&
widgets
[
i
],
snd_soc_dapm_output
,
&
pin
->
nid
,
widget_name
,
NULL
,
NULL
,
0
);
snd_soc_dapm_output
,
&
pin
->
ports
[
j
],
widget_name
,
NULL
,
NULL
,
0
,
hdac_hdmi_pin_output_widget_event
,
SND_SOC_DAPM_PRE_PMU
|
SND_SOC_DAPM_POST_PMD
);
if
(
ret
<
0
)
return
ret
;
pin
->
ports
[
j
].
output_pin
=
widgets
[
i
].
name
;
i
++
;
}
}
/* DAPM widgets to represent the connection list to pin widget */
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
sprintf
(
widget_name
,
"Pin %d Mux"
,
pin
->
nid
);
ret
=
hdac_hdmi_create_pin_muxs
(
edev
,
pin
,
&
widgets
[
i
],
for
(
j
=
0
;
j
<
pin
->
num_ports
;
j
++
)
{
sprintf
(
widget_name
,
"Pin%d-Port%d Mux"
,
pin
->
nid
,
pin
->
ports
[
j
].
id
);
ret
=
hdac_hdmi_create_pin_port_muxs
(
edev
,
&
pin
->
ports
[
j
],
&
widgets
[
i
],
widget_name
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -981,6 +1092,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
/* For pin_mux to pin mapping */
num_routes
++
;
}
}
route
=
devm_kzalloc
(
dapm
->
dev
,
(
sizeof
(
*
route
)
*
num_routes
),
GFP_KERNEL
);
...
...
@@ -990,20 +1102,22 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
i
=
0
;
/* Add pin <- NULL <- mux route map */
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
for
(
j
=
0
;
j
<
pin
->
num_ports
;
j
++
)
{
int
sink_index
=
i
+
hdmi
->
num_cvt
;
int
src_index
=
sink_index
+
hdmi
->
num_pin
;
int
src_index
=
sink_index
+
pin
->
num_ports
*
hdmi
->
num_pin
;
hdac_hdmi_fill_route
(
&
route
[
i
],
widgets
[
sink_index
].
name
,
NULL
,
widgets
[
src_index
].
name
,
NULL
);
i
++
;
}
}
hdac_hdmi_add_pinmux_cvt_route
(
edev
,
widgets
,
route
,
i
);
snd_soc_dapm_new_controls
(
dapm
,
widgets
,
((
2
*
hdmi
->
num_p
in
)
+
hdmi
->
num_cvt
));
((
2
*
hdmi
->
num_p
orts
)
+
hdmi
->
num_cvt
));
snd_soc_dapm_add_routes
(
dapm
,
route
,
num_routes
);
snd_soc_dapm_new_widgets
(
dapm
->
card
);
...
...
@@ -1015,7 +1129,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
static
int
hdac_hdmi_init_dai_map
(
struct
hdac_ext_device
*
edev
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_dai_p
in
_map
*
dai_map
;
struct
hdac_hdmi_dai_p
ort
_map
*
dai_map
;
struct
hdac_hdmi_cvt
*
cvt
;
int
dai_id
=
0
;
...
...
@@ -1059,132 +1173,149 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
return
hdac_hdmi_query_cvt_params
(
&
edev
->
hdac
,
cvt
);
}
static
void
hdac_hdmi_parse_eld
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_p
in
*
pin
)
static
int
hdac_hdmi_parse_eld
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_p
ort
*
port
)
{
pin
->
eld
.
info
.
spk_alloc
=
pin
->
eld
.
eld_buffer
[
DRM_ELD_SPEAKER
];
unsigned
int
ver
,
mnl
;
ver
=
(
port
->
eld
.
eld_buffer
[
DRM_ELD_VER
]
&
DRM_ELD_VER_MASK
)
>>
DRM_ELD_VER_SHIFT
;
if
(
ver
!=
ELD_VER_CEA_861D
&&
ver
!=
ELD_VER_PARTIAL
)
{
dev_err
(
&
edev
->
hdac
.
dev
,
"HDMI: Unknown ELD version %d
\n
"
,
ver
);
return
-
EINVAL
;
}
mnl
=
(
port
->
eld
.
eld_buffer
[
DRM_ELD_CEA_EDID_VER_MNL
]
&
DRM_ELD_MNL_MASK
)
>>
DRM_ELD_MNL_SHIFT
;
if
(
mnl
>
ELD_MAX_MNL
)
{
dev_err
(
&
edev
->
hdac
.
dev
,
"HDMI: MNL Invalid %d
\n
"
,
mnl
);
return
-
EINVAL
;
}
port
->
eld
.
info
.
spk_alloc
=
port
->
eld
.
eld_buffer
[
DRM_ELD_SPEAKER
];
return
0
;
}
static
void
hdac_hdmi_present_sense
(
struct
hdac_hdmi_pin
*
pin
,
int
repoll
)
static
void
hdac_hdmi_present_sense
(
struct
hdac_hdmi_pin
*
pin
,
struct
hdac_hdmi_port
*
port
)
{
struct
hdac_ext_device
*
edev
=
pin
->
edev
;
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
;
int
val
;
int
size
=
0
;
int
port_id
=
-
1
;
pin
->
repoll_count
=
repoll
;
if
(
!
hdmi
)
return
;
pm_runtime_get_sync
(
&
edev
->
hdac
.
dev
);
val
=
snd_hdac_codec_read
(
&
edev
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_GET_PIN_SENSE
,
0
);
/*
* In case of non MST pin, get_eld info API expectes port
* to be -1.
*/
mutex_lock
(
&
hdmi
->
pin_mutex
);
port
->
eld
.
monitor_present
=
false
;
dev_dbg
(
&
edev
->
hdac
.
dev
,
"Pin sense val %x for pin: %d
\n
"
,
val
,
pin
->
nid
)
;
if
(
pin
->
mst_capable
)
port_id
=
port
->
id
;
size
=
snd_hdac_acomp_get_eld
(
&
edev
->
hdac
,
pin
->
nid
,
port_id
,
&
port
->
eld
.
monitor_present
,
port
->
eld
.
eld_buffer
,
ELD_MAX_SIZE
);
mutex_lock
(
&
hdmi
->
pin_mutex
);
pin
->
eld
.
monitor_present
=
!!
(
val
&
AC_PINSENSE_PRESENCE
);
pin
->
eld
.
eld_valid
=
!!
(
val
&
AC_PINSENSE_ELDV
);
if
(
size
>
0
)
{
size
=
min
(
size
,
ELD_MAX_SIZE
);
if
(
hdac_hdmi_parse_eld
(
edev
,
port
)
<
0
)
size
=
-
EINVAL
;
}
if
(
size
>
0
)
{
port
->
eld
.
eld_valid
=
true
;
port
->
eld
.
eld_size
=
size
;
}
else
{
port
->
eld
.
eld_valid
=
false
;
port
->
eld
.
eld_size
=
0
;
}
pcm
=
hdac_hdmi_get_pcm
(
edev
,
p
in
);
pcm
=
hdac_hdmi_get_pcm
(
edev
,
p
ort
);
if
(
!
p
in
->
eld
.
monitor_present
||
!
pin
->
eld
.
eld_valid
)
{
if
(
!
p
ort
->
eld
.
monitor_present
||
!
port
->
eld
.
eld_valid
)
{
dev_
dbg
(
&
edev
->
hdac
.
dev
,
"%s: disconnect for pin
%d
\n
"
,
__func__
,
pin
->
nid
);
dev_
err
(
&
edev
->
hdac
.
dev
,
"%s: disconnect for pin:port %d:
%d
\n
"
,
__func__
,
pin
->
nid
,
port
->
id
);
/*
* PCMs are not registered during device probe, so don't
* report jack here. It will be done in usermode mux
* control select.
*/
if
(
pcm
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_jack_report
(
pcm
->
jack
,
0
);
}
if
(
pcm
)
hdac_hdmi_jack_report
(
pcm
,
port
,
false
);
mutex_unlock
(
&
hdmi
->
pin_mutex
);
goto
put_hdac_device
;
}
if
(
pin
->
eld
.
monitor_present
&&
pin
->
eld
.
eld_valid
)
{
/* TODO: use i915 component for reading ELD later */
if
(
hdac_hdmi_get_eld
(
&
edev
->
hdac
,
pin
->
nid
,
pin
->
eld
.
eld_buffer
,
&
pin
->
eld
.
eld_size
)
==
0
)
{
if
(
pcm
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_jack_report
(
pcm
->
jack
,
SND_JACK_AVOUT
);
return
;
}
hdac_hdmi_parse_eld
(
edev
,
pin
);
print_hex_dump_debug
(
"ELD: "
,
DUMP_PREFIX_OFFSET
,
16
,
1
,
pin
->
eld
.
eld_buffer
,
pin
->
eld
.
eld_size
,
true
);
}
else
{
pin
->
eld
.
monitor_present
=
false
;
pin
->
eld
.
eld_valid
=
false
;
if
(
port
->
eld
.
monitor_present
&&
port
->
eld
.
eld_valid
)
{
if
(
pcm
)
hdac_hdmi_jack_report
(
pcm
,
port
,
true
);
if
(
pcm
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
print_hex_dump_debug
(
"ELD: "
,
DUMP_PREFIX_OFFSET
,
16
,
1
,
port
->
eld
.
eld_buffer
,
port
->
eld
.
eld_size
,
false
);
snd_jack_report
(
pcm
->
jack
,
0
);
}
}
}
mutex_unlock
(
&
hdmi
->
pin_mutex
);
/*
* Sometimes the pin_sense may present invalid monitor
* present and eld_valid. If ELD data is not valid, loop few
* more times to get correct pin sense and valid ELD.
*/
if
((
!
pin
->
eld
.
monitor_present
||
!
pin
->
eld
.
eld_valid
)
&&
repoll
)
schedule_delayed_work
(
&
pin
->
work
,
msecs_to_jiffies
(
300
));
put_hdac_device:
pm_runtime_put_sync
(
&
edev
->
hdac
.
dev
);
}
static
void
hdac_hdmi_repoll_eld
(
struct
work_struct
*
work
)
static
int
hdac_hdmi_add_ports
(
struct
hdac_hdmi_priv
*
hdmi
,
struct
hdac_hdmi_pin
*
pin
)
{
struct
hdac_hdmi_pin
*
pin
=
container_of
(
to_delayed_work
(
work
),
struct
hdac_hdmi_pin
,
work
);
struct
hdac_hdmi_port
*
ports
;
int
max_ports
=
HDA_MAX_PORTS
;
int
i
;
/*
* FIXME: max_port may vary for each platform, so pass this as
* as driver data or query from i915 interface when this API is
* implemented.
*/
/* picked from legacy HDA driver */
if
(
pin
->
repoll_count
++
>
6
)
pin
->
repoll_count
=
0
;
ports
=
kcalloc
(
max_ports
,
sizeof
(
*
ports
),
GFP_KERNEL
);
if
(
!
ports
)
return
-
ENOMEM
;
hdac_hdmi_present_sense
(
pin
,
pin
->
repoll_count
);
for
(
i
=
0
;
i
<
max_ports
;
i
++
)
{
ports
[
i
].
id
=
i
;
ports
[
i
].
pin
=
pin
;
}
pin
->
ports
=
ports
;
pin
->
num_ports
=
max_ports
;
return
0
;
}
static
int
hdac_hdmi_add_pin
(
struct
hdac_ext_device
*
edev
,
hda_nid_t
nid
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
;
int
ret
;
pin
=
kzalloc
(
sizeof
(
*
pin
),
GFP_KERNEL
);
if
(
!
pin
)
return
-
ENOMEM
;
pin
->
nid
=
nid
;
pin
->
mst_capable
=
false
;
pin
->
edev
=
edev
;
ret
=
hdac_hdmi_add_ports
(
hdmi
,
pin
);
if
(
ret
<
0
)
return
ret
;
list_add_tail
(
&
pin
->
head
,
&
hdmi
->
pin_list
);
hdmi
->
num_pin
++
;
pin
->
edev
=
edev
;
mutex_init
(
&
pin
->
lock
);
INIT_DELAYED_WORK
(
&
pin
->
work
,
hdac_hdmi_repoll_eld
);
hdmi
->
num_ports
+=
pin
->
num_ports
;
return
0
;
}
...
...
@@ -1233,9 +1364,7 @@ static struct snd_soc_dai_ops hdmi_dai_ops = {
.
startup
=
hdac_hdmi_pcm_open
,
.
shutdown
=
hdac_hdmi_pcm_close
,
.
hw_params
=
hdac_hdmi_set_hw_params
,
.
prepare
=
hdac_hdmi_playback_prepare
,
.
trigger
=
hdac_hdmi_trigger
,
.
hw_free
=
hdac_hdmi_playback_cleanup
,
.
set_tdm_slot
=
hdac_hdmi_set_tdm_slot
,
};
/*
...
...
@@ -1372,13 +1501,16 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
{
struct
hdac_ext_device
*
edev
=
aptr
;
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_hdmi_pin
*
pin
=
NULL
;
struct
hdac_hdmi_port
*
hport
=
NULL
;
struct
snd_soc_codec
*
codec
=
edev
->
scodec
;
int
i
;
/* Don't know how this mapping is derived */
hda_nid_t
pin_nid
=
port
+
0x04
;
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: for pin: %d
\n
"
,
__func__
,
pin_nid
);
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: for pin:%d port=%d
\n
"
,
__func__
,
pin_nid
,
pipe
);
/*
* skip notification during system suspend (but not in runtime PM);
...
...
@@ -1394,9 +1526,29 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
return
;
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
if
(
pin
->
nid
==
pin_nid
)
hdac_hdmi_present_sense
(
pin
,
1
);
if
(
pin
->
nid
!=
pin_nid
)
continue
;
/* In case of non MST pin, pipe is -1 */
if
(
pipe
==
-
1
)
{
pin
->
mst_capable
=
false
;
/* if not MST, default is port[0] */
hport
=
&
pin
->
ports
[
0
];
goto
out
;
}
else
{
for
(
i
=
0
;
i
<
pin
->
num_ports
;
i
++
)
{
pin
->
mst_capable
=
true
;
if
(
pin
->
ports
[
i
].
id
==
pipe
)
{
hport
=
&
pin
->
ports
[
i
];
goto
out
;
}
}
}
}
out:
if
(
pin
&&
hport
)
hdac_hdmi_present_sense
(
pin
,
hport
);
}
static
struct
i915_audio_component_audio_ops
aops
=
{
...
...
@@ -1416,13 +1568,130 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
return
NULL
;
}
int
hdac_hdmi_jack_init
(
struct
snd_soc_dai
*
dai
,
int
device
)
/* create jack pin kcontrols */
static
int
create_fill_jack_kcontrols
(
struct
snd_soc_card
*
card
,
struct
hdac_ext_device
*
edev
)
{
struct
hdac_hdmi_pin
*
pin
;
struct
snd_kcontrol_new
*
kc
;
char
kc_name
[
NAME_SIZE
],
xname
[
NAME_SIZE
];
char
*
name
;
int
i
=
0
,
j
;
struct
snd_soc_codec
*
codec
=
edev
->
scodec
;
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
kc
=
devm_kcalloc
(
codec
->
dev
,
hdmi
->
num_ports
,
sizeof
(
*
kc
),
GFP_KERNEL
);
if
(
!
kc
)
return
-
ENOMEM
;
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
for
(
j
=
0
;
j
<
pin
->
num_ports
;
j
++
)
{
snprintf
(
xname
,
sizeof
(
xname
),
"hif%d-%d Jack"
,
pin
->
nid
,
pin
->
ports
[
j
].
id
);
name
=
devm_kstrdup
(
codec
->
dev
,
xname
,
GFP_KERNEL
);
if
(
!
name
)
return
-
ENOMEM
;
snprintf
(
kc_name
,
sizeof
(
kc_name
),
"%s Switch"
,
xname
);
kc
[
i
].
name
=
devm_kstrdup
(
codec
->
dev
,
kc_name
,
GFP_KERNEL
);
if
(
!
kc
[
i
].
name
)
return
-
ENOMEM
;
kc
[
i
].
private_value
=
(
unsigned
long
)
name
;
kc
[
i
].
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
;
kc
[
i
].
access
=
0
;
kc
[
i
].
info
=
snd_soc_dapm_info_pin_switch
;
kc
[
i
].
put
=
snd_soc_dapm_put_pin_switch
;
kc
[
i
].
get
=
snd_soc_dapm_get_pin_switch
;
i
++
;
}
}
return
snd_soc_add_card_controls
(
card
,
kc
,
i
);
}
int
hdac_hdmi_jack_port_init
(
struct
snd_soc_codec
*
codec
,
struct
snd_soc_dapm_context
*
dapm
)
{
struct
hdac_ext_device
*
edev
=
snd_soc_codec_get_drvdata
(
codec
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
;
struct
snd_soc_dapm_widget
*
widgets
;
struct
snd_soc_dapm_route
*
route
;
char
w_name
[
NAME_SIZE
];
int
i
=
0
,
j
,
ret
;
widgets
=
devm_kcalloc
(
dapm
->
dev
,
hdmi
->
num_ports
,
sizeof
(
*
widgets
),
GFP_KERNEL
);
if
(
!
widgets
)
return
-
ENOMEM
;
route
=
devm_kcalloc
(
dapm
->
dev
,
hdmi
->
num_ports
,
sizeof
(
*
route
),
GFP_KERNEL
);
if
(
!
route
)
return
-
ENOMEM
;
/* create Jack DAPM widget */
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
for
(
j
=
0
;
j
<
pin
->
num_ports
;
j
++
)
{
snprintf
(
w_name
,
sizeof
(
w_name
),
"hif%d-%d Jack"
,
pin
->
nid
,
pin
->
ports
[
j
].
id
);
ret
=
hdac_hdmi_fill_widget_info
(
dapm
->
dev
,
&
widgets
[
i
],
snd_soc_dapm_spk
,
NULL
,
w_name
,
NULL
,
NULL
,
0
,
NULL
,
0
);
if
(
ret
<
0
)
return
ret
;
pin
->
ports
[
j
].
jack_pin
=
widgets
[
i
].
name
;
pin
->
ports
[
j
].
dapm
=
dapm
;
/* add to route from Jack widget to output */
hdac_hdmi_fill_route
(
&
route
[
i
],
pin
->
ports
[
j
].
jack_pin
,
NULL
,
pin
->
ports
[
j
].
output_pin
,
NULL
);
i
++
;
}
}
/* Add Route from Jack widget to the output widget */
ret
=
snd_soc_dapm_new_controls
(
dapm
,
widgets
,
hdmi
->
num_ports
);
if
(
ret
<
0
)
return
ret
;
ret
=
snd_soc_dapm_add_routes
(
dapm
,
route
,
hdmi
->
num_ports
);
if
(
ret
<
0
)
return
ret
;
ret
=
snd_soc_dapm_new_widgets
(
dapm
->
card
);
if
(
ret
<
0
)
return
ret
;
/* Add Jack Pin switch Kcontrol */
ret
=
create_fill_jack_kcontrols
(
dapm
->
card
,
edev
);
if
(
ret
<
0
)
return
ret
;
/* default set the Jack Pin switch to OFF */
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
for
(
j
=
0
;
j
<
pin
->
num_ports
;
j
++
)
snd_soc_dapm_disable_pin
(
pin
->
ports
[
j
].
dapm
,
pin
->
ports
[
j
].
jack_pin
);
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
hdac_hdmi_jack_port_init
);
int
hdac_hdmi_jack_init
(
struct
snd_soc_dai
*
dai
,
int
device
,
struct
snd_soc_jack
*
jack
)
{
char
jack_name
[
NAME_SIZE
];
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
hdac_ext_device
*
edev
=
snd_soc_codec_get_drvdata
(
codec
);
struct
snd_soc_dapm_context
*
dapm
=
snd_soc_component_get_dapm
(
&
codec
->
component
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
;
struct
snd_pcm
*
snd_pcm
;
...
...
@@ -1437,7 +1706,10 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
return
-
ENOMEM
;
pcm
->
pcm_id
=
device
;
pcm
->
cvt
=
hdmi
->
dai_map
[
dai
->
id
].
cvt
;
pcm
->
jack_event
=
0
;
pcm
->
jack
=
jack
;
mutex_init
(
&
pcm
->
lock
);
INIT_LIST_HEAD
(
&
pcm
->
port_list
);
snd_pcm
=
hdac_hdmi_get_pcm_from_id
(
dai
->
component
->
card
,
device
);
if
(
snd_pcm
)
{
err
=
snd_hdac_add_chmap_ctls
(
snd_pcm
,
device
,
&
hdmi
->
chmap
);
...
...
@@ -1452,20 +1724,40 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
list_add_tail
(
&
pcm
->
head
,
&
hdmi
->
pcm_list
);
sprintf
(
jack_name
,
"HDMI/DP, pcm=%d Jack"
,
device
);
return
snd_jack_new
(
dapm
->
card
->
snd_card
,
jack_name
,
SND_JACK_AVOUT
,
&
pcm
->
jack
,
true
,
false
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
hdac_hdmi_jack_init
);
static
void
hdac_hdmi_present_sense_all_pins
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_priv
*
hdmi
,
bool
detect_pin_caps
)
{
int
i
;
struct
hdac_hdmi_pin
*
pin
;
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
if
(
detect_pin_caps
)
{
if
(
hdac_hdmi_get_port_len
(
edev
,
pin
->
nid
)
==
0
)
pin
->
mst_capable
=
false
;
else
pin
->
mst_capable
=
true
;
}
for
(
i
=
0
;
i
<
pin
->
num_ports
;
i
++
)
{
if
(
!
pin
->
mst_capable
&&
i
>
0
)
continue
;
hdac_hdmi_present_sense
(
pin
,
&
pin
->
ports
[
i
]);
}
}
}
static
int
hdmi_codec_probe
(
struct
snd_soc_codec
*
codec
)
{
struct
hdac_ext_device
*
edev
=
snd_soc_codec_get_drvdata
(
codec
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
snd_soc_dapm_context
*
dapm
=
snd_soc_component_get_dapm
(
&
codec
->
component
);
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_ext_link
*
hlink
=
NULL
;
int
ret
;
...
...
@@ -1495,9 +1787,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
return
ret
;
}
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
hdac_hdmi_present_sense
(
pin
,
1
);
hdac_hdmi_present_sense_all_pins
(
edev
,
hdmi
,
true
);
/* Imp: Store the card pointer in hda_codec */
edev
->
card
=
dapm
->
card
->
snd_card
;
...
...
@@ -1545,7 +1835,6 @@ static void hdmi_codec_complete(struct device *dev)
{
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
dev
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_device
*
hdac
=
&
edev
->
hdac
;
/* Power up afg */
...
...
@@ -1558,10 +1847,10 @@ static void hdmi_codec_complete(struct device *dev)
/*
* As the ELD notify callback request is not entertained while the
* device is in suspend state. Need to manually check detection of
* all pins here.
* all pins here. pin capablity change is not support, so use the
* already set pin caps.
*/
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
hdac_hdmi_present_sense
(
pin
,
1
);
hdac_hdmi_present_sense_all_pins
(
edev
,
hdmi
,
false
);
pm_runtime_put_sync
(
&
edev
->
hdac
.
dev
);
}
...
...
@@ -1582,13 +1871,8 @@ static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
struct
hdac_ext_device
*
edev
=
to_ehdac_device
(
hdac
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
get_hdmi_pcm_from_id
(
hdmi
,
pcm_idx
);
struct
hdac_hdmi_pin
*
pin
=
pcm
->
pin
;
/* chmap is already set to 0 in caller */
if
(
!
pin
)
return
;
memcpy
(
chmap
,
pin
->
chmap
,
ARRAY_SIZE
(
pin
->
chmap
));
memcpy
(
chmap
,
pcm
->
chmap
,
ARRAY_SIZE
(
pcm
->
chmap
));
}
static
void
hdac_hdmi_set_chmap
(
struct
hdac_device
*
hdac
,
int
pcm_idx
,
...
...
@@ -1597,14 +1881,18 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
struct
hdac_ext_device
*
edev
=
to_ehdac_device
(
hdac
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
get_hdmi_pcm_from_id
(
hdmi
,
pcm_idx
);
struct
hdac_hdmi_pin
*
pin
=
pcm
->
pin
;
struct
hdac_hdmi_port
*
port
;
if
(
list_empty
(
&
pcm
->
port_list
))
return
;
mutex_lock
(
&
pin
->
lock
);
pin
->
chmap_set
=
true
;
memcpy
(
pin
->
chmap
,
chmap
,
ARRAY_SIZE
(
pin
->
chmap
));
mutex_lock
(
&
pcm
->
lock
);
pcm
->
chmap_set
=
true
;
memcpy
(
pcm
->
chmap
,
chmap
,
ARRAY_SIZE
(
pcm
->
chmap
));
list_for_each_entry
(
port
,
&
pcm
->
port_list
,
head
)
if
(
prepared
)
hdac_hdmi_setup_audio_infoframe
(
edev
,
pcm
->
cvt
->
nid
,
pin
->
nid
);
mutex_unlock
(
&
p
in
->
lock
);
hdac_hdmi_setup_audio_infoframe
(
edev
,
pcm
,
port
);
mutex_unlock
(
&
p
cm
->
lock
);
}
static
bool
is_hdac_hdmi_pcm_attached
(
struct
hdac_device
*
hdac
,
int
pcm_idx
)
...
...
@@ -1612,9 +1900,11 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
struct
hdac_ext_device
*
edev
=
to_ehdac_device
(
hdac
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
get_hdmi_pcm_from_id
(
hdmi
,
pcm_idx
);
struct
hdac_hdmi_pin
*
pin
=
pcm
->
pin
;
return
pin
?
true
:
false
;
if
(
list_empty
(
&
pcm
->
port_list
))
return
false
;
return
true
;
}
static
int
hdac_hdmi_get_spk_alloc
(
struct
hdac_device
*
hdac
,
int
pcm_idx
)
...
...
@@ -1622,12 +1912,20 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
struct
hdac_ext_device
*
edev
=
to_ehdac_device
(
hdac
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
get_hdmi_pcm_from_id
(
hdmi
,
pcm_idx
);
struct
hdac_hdmi_p
in
*
pin
=
pcm
->
pin
;
struct
hdac_hdmi_p
ort
*
port
;
if
(
!
pin
||
!
pin
->
eld
.
eld_valid
)
if
(
list_empty
(
&
pcm
->
port_list
)
)
return
0
;
return
pin
->
eld
.
info
.
spk_alloc
;
port
=
list_first_entry
(
&
pcm
->
port_list
,
struct
hdac_hdmi_port
,
head
);
if
(
!
port
)
return
0
;
if
(
!
port
||
!
port
->
eld
.
eld_valid
)
return
0
;
return
port
->
eld
.
info
.
spk_alloc
;
}
static
int
hdac_hdmi_dev_probe
(
struct
hdac_ext_device
*
edev
)
...
...
@@ -1700,12 +1998,19 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
struct
hdac_hdmi_pin
*
pin
,
*
pin_next
;
struct
hdac_hdmi_cvt
*
cvt
,
*
cvt_next
;
struct
hdac_hdmi_pcm
*
pcm
,
*
pcm_next
;
struct
hdac_hdmi_port
*
port
;
int
i
;
snd_soc_unregister_codec
(
&
edev
->
hdac
.
dev
);
list_for_each_entry_safe
(
pcm
,
pcm_next
,
&
hdmi
->
pcm_list
,
head
)
{
pcm
->
cvt
=
NULL
;
pcm
->
pin
=
NULL
;
if
(
list_empty
(
&
pcm
->
port_list
))
continue
;
list_for_each_entry
(
port
,
&
pcm
->
port_list
,
head
)
port
=
NULL
;
list_del
(
&
pcm
->
head
);
kfree
(
pcm
);
}
...
...
@@ -1717,6 +2022,9 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
}
list_for_each_entry_safe
(
pin
,
pin_next
,
&
hdmi
->
pin_list
,
head
)
{
for
(
i
=
0
;
i
<
pin
->
num_ports
;
i
++
)
pin
->
ports
[
i
].
pin
=
NULL
;
kfree
(
pin
->
ports
);
list_del
(
&
pin
->
head
);
kfree
(
pin
);
}
...
...
@@ -1819,6 +2127,7 @@ static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY
(
0x80862809
,
0x100000
,
"Skylake HDMI"
,
0
),
HDA_CODEC_EXT_ENTRY
(
0x8086280a
,
0x100000
,
"Broxton HDMI"
,
0
),
HDA_CODEC_EXT_ENTRY
(
0x8086280b
,
0x100000
,
"Kabylake HDMI"
,
0
),
HDA_CODEC_EXT_ENTRY
(
0x8086280d
,
0x100000
,
"Geminilake HDMI"
,
0
),
{}
};
...
...
sound/soc/codecs/hdac_hdmi.h
View file @
16b57114
#ifndef __HDAC_HDMI_H__
#define __HDAC_HDMI_H__
int
hdac_hdmi_jack_init
(
struct
snd_soc_dai
*
dai
,
int
pcm
);
int
hdac_hdmi_jack_init
(
struct
snd_soc_dai
*
dai
,
int
pcm
,
struct
snd_soc_jack
*
jack
);
int
hdac_hdmi_jack_port_init
(
struct
snd_soc_codec
*
codec
,
struct
snd_soc_dapm_context
*
dapm
);
#endif
/* __HDAC_HDMI_H__ */
sound/soc/codecs/rt298.c
View file @
16b57114
...
...
@@ -1163,6 +1163,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Broxton P"
)
}
},
{
.
ident
=
"Intel Gemini Lake"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Intel Corp"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Geminilake"
)
}
},
{
}
};
...
...
sound/soc/codecs/rt5640.c
View file @
16b57114
...
...
@@ -2313,6 +2313,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match);
#ifdef CONFIG_ACPI
static
const
struct
acpi_device_id
rt5640_acpi_match
[]
=
{
{
"INT33CA"
,
0
},
{
"10EC3276"
,
0
},
{
"10EC5640"
,
0
},
{
"10EC5642"
,
0
},
{
"INTCCFFD"
,
0
},
...
...
sound/soc/codecs/rt5645.c
View file @
16b57114
...
...
@@ -3545,8 +3545,10 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
#ifdef CONFIG_ACPI
static
const
struct
acpi_device_id
rt5645_acpi_match
[]
=
{
{
"10EC5645"
,
0
},
{
"10EC5648"
,
0
},
{
"10EC5650"
,
0
},
{
"10EC5640"
,
0
},
{
"10EC3270"
,
0
},
{},
};
MODULE_DEVICE_TABLE
(
acpi
,
rt5645_acpi_match
);
...
...
sound/soc/codecs/rt5670.c
View file @
16b57114
...
...
@@ -2814,6 +2814,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
static
const
struct
acpi_device_id
rt5670_acpi_match
[]
=
{
{
"10EC5670"
,
0
},
{
"10EC5672"
,
0
},
{
"10EC5640"
,
0
},
/* quirk */
{
},
};
MODULE_DEVICE_TABLE
(
acpi
,
rt5670_acpi_match
);
...
...
sound/soc/intel/Kconfig
View file @
16b57114
...
...
@@ -2,7 +2,7 @@ config SND_MFLD_MACHINE
tristate "SOC Machine Audio driver for Intel Medfield MID platform"
depends on INTEL_SCU_IPC
select SND_SOC_SN95031
select SND_SST_
MFLD
_PLATFORM
select SND_SST_
ATOM_HIFI2
_PLATFORM
select SND_SST_IPC_PCI
help
This adds support for ASoC machine driver for Intel(R) MID Medfield platform
...
...
@@ -10,7 +10,7 @@ config SND_MFLD_MACHINE
Say Y if you have such a device.
If unsure select "N".
config SND_SST_
MFLD
_PLATFORM
config SND_SST_
ATOM_HIFI2
_PLATFORM
tristate
select SND_SOC_COMPRESS
...
...
@@ -31,13 +31,10 @@ config SND_SOC_INTEL_SST
tristate
select SND_SOC_INTEL_SST_ACPI if ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI
depends on (X86 || COMPILE_TEST)
# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from
# the reverse selection, each machine driver needs to select
# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE
config SND_SOC_INTEL_SST_FIRMWARE
tristate
select DW_DMAC_CORE
config SND_SOC_INTEL_SST_ACPI
tristate
...
...
@@ -47,16 +44,18 @@ config SND_SOC_INTEL_SST_MATCH
config SND_SOC_INTEL_HASWELL
tristate
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_BAYTRAIL
tristate
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST
depends on DMADEVICES
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
help
...
...
@@ -68,7 +67,6 @@ config SND_SOC_INTEL_HASWELL_MACH
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_DA7219
select SND_SOC_MAX98357A
...
...
@@ -84,7 +82,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
config SND_SOC_INTEL_BXT_RT298_MACH
tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT298
select SND_SOC_DMIC
...
...
@@ -99,9 +96,8 @@ config SND_SOC_INTEL_BXT_RT298_MACH
config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
depends on DMADEVICES
depends on SND_SST_IPC_ACPI = n
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
help
...
...
@@ -112,9 +108,8 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
depends on DMADEVICES
depends on SND_SST_IPC_ACPI = n
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090
help
...
...
@@ -123,9 +118,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
config SND_SOC_INTEL_BDW_RT5677_MACH
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC
depends on DW_DMAC_CORE=y
select SND_SOC_INTEL_SST
depends on X86_INTEL_LPSS && GPIOLIB && I2C
depends on DMADEVICES
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5677
help
...
...
@@ -134,10 +128,8 @@ config SND_SOC_INTEL_BDW_RT5677_MACH
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on DMADEVICES
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286
help
...
...
@@ -150,7 +142,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
depends on X86 && I2C && ACPI
select SND_SOC_RT5640
select SND_SST_
MFLD
_PLATFORM
select SND_SST_
ATOM_HIFI2
_PLATFORM
select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI
help
...
...
@@ -163,7 +155,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
depends on X86 && I2C && ACPI
select SND_SOC_RT5651
select SND_SST_
MFLD
_PLATFORM
select SND_SST_
ATOM_HIFI2
_PLATFORM
select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI
help
...
...
@@ -176,7 +168,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5670
select SND_SST_
MFLD
_PLATFORM
select SND_SST_
ATOM_HIFI2
_PLATFORM
select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI
help
...
...
@@ -189,7 +181,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5645
select SND_SST_
MFLD
_PLATFORM
select SND_SST_
ATOM_HIFI2
_PLATFORM
select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI
help
...
...
@@ -202,7 +194,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_MAX98090
select SND_SOC_TS3A227E
select SND_SST_
MFLD
_PLATFORM
select SND_SST_
ATOM_HIFI2
_PLATFORM
select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI
help
...
...
@@ -220,7 +212,6 @@ config SND_SOC_INTEL_SKYLAKE
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "ASoC Audio driver for SKL with RT286 I2S mode"
depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286
select SND_SOC_DMIC
...
...
@@ -234,7 +225,6 @@ config SND_SOC_INTEL_SKL_RT286_MACH
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
depends on X86_INTEL_LPSS && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_NAU8825
select SND_SOC_SSM4567
...
...
@@ -249,7 +239,6 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
depends on X86_INTEL_LPSS && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_NAU8825
select SND_SOC_MAX98357A
...
...
sound/soc/intel/Makefile
View file @
16b57114
...
...
@@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
# Platform Support
obj-$(CONFIG_SND_SOC_INTEL_HASWELL)
+=
haswell/
obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL)
+=
baytrail/
obj-$(CONFIG_SND_SST_
MFLD
_PLATFORM)
+=
atom/
obj-$(CONFIG_SND_SST_
ATOM_HIFI2
_PLATFORM)
+=
atom/
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE)
+=
skylake/
# Machine support
...
...
sound/soc/intel/atom/Makefile
View file @
16b57114
snd-soc-sst-mfld-platform-objs
:=
sst-mfld-platform-pcm.o
\
sst-mfld-platform-compress.o sst-atom-controls.o
snd-soc-sst-atom-hifi2-platform-objs
:=
sst-mfld-platform-pcm.o
\
sst-mfld-platform-compress.o
\
sst-atom-controls.o
obj-$(CONFIG_SND_SST_
MFLD_PLATFORM)
+=
snd-soc-sst-mfld
-platform.o
obj-$(CONFIG_SND_SST_
ATOM_HIFI2_PLATFORM)
+=
snd-soc-sst-atom-hifi2
-platform.o
# DSP driver
obj-$(CONFIG_SND_SST_IPC)
+=
sst/
sound/soc/intel/atom/sst-atom-controls.c
View file @
16b57114
...
...
@@ -1085,8 +1085,8 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
SST_PATH_INPUT
(
"sprot_loop_in"
,
SST_TASK_SBA
,
SST_SWM_IN_SPROT_LOOP
,
NULL
),
SST_PATH_INPUT
(
"media_loop1_in"
,
SST_TASK_SBA
,
SST_SWM_IN_MEDIA_LOOP1
,
NULL
),
SST_PATH_INPUT
(
"media_loop2_in"
,
SST_TASK_SBA
,
SST_SWM_IN_MEDIA_LOOP2
,
NULL
),
SST_PATH_MEDIA_LOOP_OUTPUT
(
"sprot_loop_out"
,
SST_TASK_SBA
,
SST_SWM_OUT_SPROT_LOOP
,
SST_FMT_
MON
O
,
sst_set_media_loop
),
SST_PATH_MEDIA_LOOP_OUTPUT
(
"media_loop1_out"
,
SST_TASK_SBA
,
SST_SWM_OUT_MEDIA_LOOP1
,
SST_FMT_
MON
O
,
sst_set_media_loop
),
SST_PATH_MEDIA_LOOP_OUTPUT
(
"sprot_loop_out"
,
SST_TASK_SBA
,
SST_SWM_OUT_SPROT_LOOP
,
SST_FMT_
STERE
O
,
sst_set_media_loop
),
SST_PATH_MEDIA_LOOP_OUTPUT
(
"media_loop1_out"
,
SST_TASK_SBA
,
SST_SWM_OUT_MEDIA_LOOP1
,
SST_FMT_
STERE
O
,
sst_set_media_loop
),
SST_PATH_MEDIA_LOOP_OUTPUT
(
"media_loop2_out"
,
SST_TASK_SBA
,
SST_SWM_OUT_MEDIA_LOOP2
,
SST_FMT_STEREO
,
sst_set_media_loop
),
/* Media Mixers */
...
...
sound/soc/intel/atom/sst-mfld-platform-pcm.c
View file @
16b57114
...
...
@@ -357,14 +357,14 @@ static void sst_media_close(struct snd_pcm_substream *substream,
struct
snd_soc_dai
*
dai
)
{
struct
sst_runtime_stream
*
stream
;
int
ret_val
=
0
,
str_id
;
int
str_id
;
stream
=
substream
->
runtime
->
private_data
;
power_down_sst
(
stream
);
str_id
=
stream
->
stream_info
.
str_id
;
if
(
str_id
)
ret_val
=
stream
->
ops
->
close
(
sst
->
dev
,
str_id
);
stream
->
ops
->
close
(
sst
->
dev
,
str_id
);
module_put
(
sst
->
dev
->
driver
->
owner
);
kfree
(
stream
);
}
...
...
@@ -839,4 +839,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
MODULE_AUTHOR
(
"Vinod Koul <vinod.koul@intel.com>"
);
MODULE_AUTHOR
(
"Harsha Priya <priya.harsha@intel.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_ALIAS
(
"platform:sst-atom-hifi2-platform"
);
MODULE_ALIAS
(
"platform:sst-mfld-platform"
);
sound/soc/intel/atom/sst/sst_acpi.c
View file @
16b57114
...
...
@@ -400,6 +400,7 @@ static int sst_acpi_remove(struct platform_device *pdev)
static
unsigned
long
cht_machine_id
;
#define CHT_SURFACE_MACH 1
#define BYT_THINKPAD_10 2
static
int
cht_surface_quirk_cb
(
const
struct
dmi_system_id
*
id
)
{
...
...
@@ -407,6 +408,23 @@ static int cht_surface_quirk_cb(const struct dmi_system_id *id)
return
1
;
}
static
int
byt_thinkpad10_quirk_cb
(
const
struct
dmi_system_id
*
id
)
{
cht_machine_id
=
BYT_THINKPAD_10
;
return
1
;
}
static
const
struct
dmi_system_id
byt_table
[]
=
{
{
.
callback
=
byt_thinkpad10_quirk_cb
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"LENOVO"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"20C3001VHH"
),
},
},
{
}
};
static
const
struct
dmi_system_id
cht_table
[]
=
{
{
...
...
@@ -424,6 +442,10 @@ static struct sst_acpi_mach cht_surface_mach = {
"10EC5640"
,
"cht-bsw-rt5645"
,
"intel/fw_sst_22a8.bin"
,
"cht-bsw"
,
NULL
,
&
chv_platform_data
};
static
struct
sst_acpi_mach
byt_thinkpad_10
=
{
"10EC5640"
,
"cht-bsw-rt5672"
,
"intel/fw_sst_0f28.bin"
,
"cht-bsw"
,
NULL
,
&
byt_rvp_platform_data
};
static
struct
sst_acpi_mach
*
cht_quirk
(
void
*
arg
)
{
struct
sst_acpi_mach
*
mach
=
arg
;
...
...
@@ -436,8 +458,21 @@ static struct sst_acpi_mach *cht_quirk(void *arg)
return
mach
;
}
static
struct
sst_acpi_mach
*
byt_quirk
(
void
*
arg
)
{
struct
sst_acpi_mach
*
mach
=
arg
;
dmi_check_system
(
byt_table
);
if
(
cht_machine_id
==
BYT_THINKPAD_10
)
return
&
byt_thinkpad_10
;
else
return
mach
;
}
static
struct
sst_acpi_mach
sst_acpi_bytcr
[]
=
{
{
"10EC5640"
,
"bytcr_rt5640"
,
"intel/fw_sst_0f28.bin"
,
"bytcr_rt5640"
,
NULL
,
{
"10EC5640"
,
"bytcr_rt5640"
,
"intel/fw_sst_0f28.bin"
,
"bytcr_rt5640"
,
byt_quirk
,
&
byt_rvp_platform_data
},
{
"10EC5642"
,
"bytcr_rt5640"
,
"intel/fw_sst_0f28.bin"
,
"bytcr_rt5640"
,
NULL
,
&
byt_rvp_platform_data
},
...
...
@@ -445,6 +480,12 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {
&
byt_rvp_platform_data
},
{
"10EC5651"
,
"bytcr_rt5651"
,
"intel/fw_sst_0f28.bin"
,
"bytcr_rt5651"
,
NULL
,
&
byt_rvp_platform_data
},
/* some Baytrail platforms rely on RT5645, use CHT machine driver */
{
"10EC5645"
,
"cht-bsw-rt5645"
,
"intel/fw_sst_0f28.bin"
,
"cht-bsw"
,
NULL
,
&
byt_rvp_platform_data
},
{
"10EC5648"
,
"cht-bsw-rt5645"
,
"intel/fw_sst_0f28.bin"
,
"cht-bsw"
,
NULL
,
&
byt_rvp_platform_data
},
{},
};
...
...
@@ -458,12 +499,19 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
&
chv_platform_data
},
{
"10EC5650"
,
"cht-bsw-rt5645"
,
"intel/fw_sst_22a8.bin"
,
"cht-bsw"
,
NULL
,
&
chv_platform_data
},
{
"10EC3270"
,
"cht-bsw-rt5645"
,
"intel/fw_sst_22a8.bin"
,
"cht-bsw"
,
NULL
,
&
chv_platform_data
},
{
"193C9890"
,
"cht-bsw-max98090"
,
"intel/fw_sst_22a8.bin"
,
"cht-bsw"
,
NULL
,
&
chv_platform_data
},
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
{
"10EC5640"
,
"bytcr_rt5640"
,
"intel/fw_sst_22a8.bin"
,
"bytcr_rt5640"
,
cht_quirk
,
&
chv_platform_data
},
{
"10EC3276"
,
"bytcr_rt5640"
,
"intel/fw_sst_22a8.bin"
,
"bytcr_rt5640"
,
NULL
,
&
chv_platform_data
},
/* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
{
"10EC5651"
,
"bytcr_rt5651"
,
"intel/fw_sst_22a8.bin"
,
"bytcr_rt5651"
,
NULL
,
&
chv_platform_data
},
{},
};
...
...
sound/soc/intel/atom/sst/sst_ipc.c
View file @
16b57114
...
...
@@ -260,10 +260,8 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
u32
data_size
,
i
;
void
*
data_offset
;
struct
stream_info
*
stream
;
union
ipc_header_high
msg_high
;
u32
msg_low
,
pipe_id
;
msg_high
=
msg
->
mrfld_header
.
p
.
header_high
;
msg_low
=
msg
->
mrfld_header
.
p
.
header_low_payload
;
msg_id
=
((
struct
ipc_dsp_hdr
*
)
msg
->
mailbox_data
)
->
cmd_id
;
data_offset
=
(
msg
->
mailbox_data
+
sizeof
(
struct
ipc_dsp_hdr
));
...
...
sound/soc/intel/atom/sst/sst_stream.c
View file @
16b57114
...
...
@@ -394,7 +394,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
{
int
retval
=
0
;
struct
stream_info
*
str_info
;
struct
intel_sst_ops
*
ops
;
dev_dbg
(
sst_drv_ctx
->
dev
,
"SST DBG:sst_free_stream for %d
\n
"
,
str_id
);
...
...
@@ -407,7 +406,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
str_info
=
get_stream_info
(
sst_drv_ctx
,
str_id
);
if
(
!
str_info
)
return
-
EINVAL
;
ops
=
sst_drv_ctx
->
ops
;
mutex_lock
(
&
str_info
->
lock
);
if
(
str_info
->
status
!=
STREAM_UN_INIT
)
{
...
...
sound/soc/intel/boards/broadwell.c
View file @
16b57114
...
...
@@ -270,6 +270,8 @@ static int broadwell_audio_probe(struct platform_device *pdev)
{
broadwell_rt286
.
dev
=
&
pdev
->
dev
;
snd_soc_set_dmi_name
(
&
broadwell_rt286
,
NULL
);
return
devm_snd_soc_register_card
(
&
pdev
->
dev
,
&
broadwell_rt286
);
}
...
...
sound/soc/intel/boards/bxt_da7219_max98357a.c
View file @
16b57114
...
...
@@ -33,6 +33,17 @@
#define QUAD_CHANNEL 4
static
struct
snd_soc_jack
broxton_headset
;
static
struct
snd_soc_jack
broxton_hdmi
[
3
];
struct
bxt_hdmi_pcm
{
struct
list_head
head
;
struct
snd_soc_dai
*
codec_dai
;
int
device
;
};
struct
bxt_card_private
{
struct
list_head
hdmi_pcm_list
;
};
enum
{
BXT_DPCM_AUDIO_PB
=
0
,
...
...
@@ -84,9 +95,9 @@ static const struct snd_soc_dapm_route broxton_map[] = {
{
"codec0_in"
,
NULL
,
"ssp1 Rx"
},
{
"ssp1 Rx"
,
NULL
,
"Capture"
},
{
"HDMI1"
,
NULL
,
"hif5 Output"
},
{
"HDMI2"
,
NULL
,
"hif6 Output"
},
{
"HDMI
3"
,
NULL
,
"hif7
Output"
},
{
"HDMI1"
,
NULL
,
"hif5
-0
Output"
},
{
"HDMI2"
,
NULL
,
"hif6
-0
Output"
},
{
"HDMI
2"
,
NULL
,
"hif7-0
Output"
},
{
"hifi3"
,
NULL
,
"iDisp3 Tx"
},
{
"iDisp3 Tx"
,
NULL
,
"iDisp3_out"
},
...
...
@@ -147,9 +158,20 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
static
int
broxton_hdmi_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
bxt_card_private
*
ctx
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
struct
bxt_hdmi_pcm
*
pcm
;
pcm
=
devm_kzalloc
(
rtd
->
card
->
dev
,
sizeof
(
*
pcm
),
GFP_KERNEL
);
if
(
!
pcm
)
return
-
ENOMEM
;
return
hdac_hdmi_jack_init
(
dai
,
BXT_DPCM_AUDIO_HDMI1_PB
+
dai
->
id
);
pcm
->
device
=
BXT_DPCM_AUDIO_HDMI1_PB
+
dai
->
id
;
pcm
->
codec_dai
=
dai
;
list_add_tail
(
&
pcm
->
head
,
&
ctx
->
hdmi_pcm_list
);
return
0
;
}
static
int
broxton_da7219_fe_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
...
...
@@ -357,7 +379,6 @@ static struct snd_soc_dai_link broxton_dais[] = {
.
platform_name
=
"0000:00:0e.0"
,
.
init
=
NULL
,
.
dpcm_capture
=
1
,
.
ignore_suspend
=
1
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
.
ops
=
&
broxton_refcap_ops
,
...
...
@@ -497,6 +518,40 @@ static struct snd_soc_dai_link broxton_dais[] = {
},
};
#define NAME_SIZE 32
static
int
bxt_card_late_probe
(
struct
snd_soc_card
*
card
)
{
struct
bxt_card_private
*
ctx
=
snd_soc_card_get_drvdata
(
card
);
struct
bxt_hdmi_pcm
*
pcm
;
struct
snd_soc_codec
*
codec
=
NULL
;
int
err
,
i
=
0
;
char
jack_name
[
NAME_SIZE
];
list_for_each_entry
(
pcm
,
&
ctx
->
hdmi_pcm_list
,
head
)
{
codec
=
pcm
->
codec_dai
->
codec
;
snprintf
(
jack_name
,
sizeof
(
jack_name
),
"HDMI/DP, pcm=%d Jack"
,
pcm
->
device
);
err
=
snd_soc_card_jack_new
(
card
,
jack_name
,
SND_JACK_AVOUT
,
&
broxton_hdmi
[
i
],
NULL
,
0
);
if
(
err
)
return
err
;
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
,
&
broxton_hdmi
[
i
]);
if
(
err
<
0
)
return
err
;
i
++
;
}
if
(
!
codec
)
return
-
EINVAL
;
return
hdac_hdmi_jack_port_init
(
codec
,
&
card
->
dapm
);
}
/* broxton audio machine driver for SPT + da7219 */
static
struct
snd_soc_card
broxton_audio_card
=
{
.
name
=
"bxtda7219max"
,
...
...
@@ -510,11 +565,22 @@ static struct snd_soc_card broxton_audio_card = {
.
dapm_routes
=
broxton_map
,
.
num_dapm_routes
=
ARRAY_SIZE
(
broxton_map
),
.
fully_routed
=
true
,
.
late_probe
=
bxt_card_late_probe
,
};
static
int
broxton_audio_probe
(
struct
platform_device
*
pdev
)
{
struct
bxt_card_private
*
ctx
;
ctx
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
ctx
),
GFP_ATOMIC
);
if
(
!
ctx
)
return
-
ENOMEM
;
INIT_LIST_HEAD
(
&
ctx
->
hdmi_pcm_list
);
broxton_audio_card
.
dev
=
&
pdev
->
dev
;
snd_soc_card_set_drvdata
(
&
broxton_audio_card
,
ctx
);
return
devm_snd_soc_register_card
(
&
pdev
->
dev
,
&
broxton_audio_card
);
}
...
...
sound/soc/intel/boards/bxt_rt298.c
View file @
16b57114
...
...
@@ -26,8 +26,19 @@
#include "../../codecs/hdac_hdmi.h"
#include "../../codecs/rt298.h"
static
struct
snd_soc_jack
broxton_headset
;
/* Headset jack detection DAPM pins */
static
struct
snd_soc_jack
broxton_headset
;
static
struct
snd_soc_jack
broxton_hdmi
[
3
];
struct
bxt_hdmi_pcm
{
struct
list_head
head
;
struct
snd_soc_dai
*
codec_dai
;
int
device
;
};
struct
bxt_rt286_private
{
struct
list_head
hdmi_pcm_list
;
};
enum
{
BXT_DPCM_AUDIO_PB
=
0
,
...
...
@@ -82,9 +93,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
{
"DMIC1 Pin"
,
NULL
,
"DMIC2"
},
{
"DMic"
,
NULL
,
"SoC DMIC"
},
{
"HDMI1"
,
NULL
,
"hif5 Output"
},
{
"HDMI2"
,
NULL
,
"hif6 Output"
},
{
"HDMI
3"
,
NULL
,
"hif7
Output"
},
{
"HDMI1"
,
NULL
,
"hif5
-0
Output"
},
{
"HDMI2"
,
NULL
,
"hif6
-0
Output"
},
{
"HDMI
2"
,
NULL
,
"hif7-0
Output"
},
/* CODEC BE connections */
{
"AIF1 Playback"
,
NULL
,
"ssp5 Tx"
},
...
...
@@ -139,9 +150,20 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
static
int
broxton_hdmi_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
bxt_rt286_private
*
ctx
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
struct
bxt_hdmi_pcm
*
pcm
;
return
hdac_hdmi_jack_init
(
dai
,
BXT_DPCM_AUDIO_HDMI1_PB
+
dai
->
id
);
pcm
=
devm_kzalloc
(
rtd
->
card
->
dev
,
sizeof
(
*
pcm
),
GFP_KERNEL
);
if
(
!
pcm
)
return
-
ENOMEM
;
pcm
->
device
=
BXT_DPCM_AUDIO_HDMI1_PB
+
dai
->
id
;
pcm
->
codec_dai
=
dai
;
list_add_tail
(
&
pcm
->
head
,
&
ctx
->
hdmi_pcm_list
);
return
0
;
}
static
int
broxton_ssp5_fixup
(
struct
snd_soc_pcm_runtime
*
rtd
,
...
...
@@ -432,6 +454,41 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
},
};
#define NAME_SIZE 32
static
int
bxt_card_late_probe
(
struct
snd_soc_card
*
card
)
{
struct
bxt_rt286_private
*
ctx
=
snd_soc_card_get_drvdata
(
card
);
struct
bxt_hdmi_pcm
*
pcm
;
struct
snd_soc_codec
*
codec
=
NULL
;
int
err
,
i
=
0
;
char
jack_name
[
NAME_SIZE
];
list_for_each_entry
(
pcm
,
&
ctx
->
hdmi_pcm_list
,
head
)
{
codec
=
pcm
->
codec_dai
->
codec
;
snprintf
(
jack_name
,
sizeof
(
jack_name
),
"HDMI/DP, pcm=%d Jack"
,
pcm
->
device
);
err
=
snd_soc_card_jack_new
(
card
,
jack_name
,
SND_JACK_AVOUT
,
&
broxton_hdmi
[
i
],
NULL
,
0
);
if
(
err
)
return
err
;
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
,
&
broxton_hdmi
[
i
]);
if
(
err
<
0
)
return
err
;
i
++
;
}
if
(
!
codec
)
return
-
EINVAL
;
return
hdac_hdmi_jack_port_init
(
codec
,
&
card
->
dapm
);
}
/* broxton audio machine driver for SPT + RT298S */
static
struct
snd_soc_card
broxton_rt298
=
{
.
name
=
"broxton-rt298"
,
...
...
@@ -445,11 +502,22 @@ static struct snd_soc_card broxton_rt298 = {
.
dapm_routes
=
broxton_rt298_map
,
.
num_dapm_routes
=
ARRAY_SIZE
(
broxton_rt298_map
),
.
fully_routed
=
true
,
.
late_probe
=
bxt_card_late_probe
,
};
static
int
broxton_audio_probe
(
struct
platform_device
*
pdev
)
{
struct
bxt_rt286_private
*
ctx
;
ctx
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
ctx
),
GFP_ATOMIC
);
if
(
!
ctx
)
return
-
ENOMEM
;
INIT_LIST_HEAD
(
&
ctx
->
hdmi_pcm_list
);
broxton_rt298
.
dev
=
&
pdev
->
dev
;
snd_soc_card_set_drvdata
(
&
broxton_rt298
,
ctx
);
return
devm_snd_soc_register_card
(
&
pdev
->
dev
,
&
broxton_rt298
);
}
...
...
sound/soc/intel/boards/bytcr_rt5640.c
View file @
16b57114
...
...
@@ -386,6 +386,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_MCLK_EN
|
BYT_RT5640_SSP0_AIF1
),
},
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Insyde"
),
},
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_IN3_MAP
|
BYT_RT5640_MCLK_EN
|
BYT_RT5640_SSP0_AIF1
),
},
{}
};
...
...
sound/soc/intel/boards/cht_bsw_rt5645.c
View file @
16b57114
...
...
@@ -23,7 +23,11 @@
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
#include <linux/clk.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
...
...
@@ -33,7 +37,8 @@
#include "../common/sst-acpi.h"
#define CHT_PLAT_CLK_3_HZ 19200000
#define CHT_CODEC_DAI "rt5645-aif1"
#define CHT_CODEC_DAI1 "rt5645-aif1"
#define CHT_CODEC_DAI2 "rt5645-aif2"
struct
cht_acpi_card
{
char
*
codec_id
;
...
...
@@ -45,15 +50,36 @@ struct cht_mc_private {
struct
snd_soc_jack
jack
;
struct
cht_acpi_card
*
acpi_card
;
char
codec_name
[
16
];
struct
clk
*
mclk
;
};
#define CHT_RT5645_MAP(quirk) ((quirk) & 0xff)
#define CHT_RT5645_SSP2_AIF2 BIT(16)
/* default is using AIF1 */
#define CHT_RT5645_SSP0_AIF1 BIT(17)
#define CHT_RT5645_SSP0_AIF2 BIT(18)
static
unsigned
long
cht_rt5645_quirk
=
0
;
static
void
log_quirks
(
struct
device
*
dev
)
{
if
(
cht_rt5645_quirk
&
CHT_RT5645_SSP2_AIF2
)
dev_info
(
dev
,
"quirk SSP2_AIF2 enabled"
);
if
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF1
)
dev_info
(
dev
,
"quirk SSP0_AIF1 enabled"
);
if
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF2
)
dev_info
(
dev
,
"quirk SSP0_AIF2 enabled"
);
}
static
inline
struct
snd_soc_dai
*
cht_get_codec_dai
(
struct
snd_soc_card
*
card
)
{
struct
snd_soc_pcm_runtime
*
rtd
;
list_for_each_entry
(
rtd
,
&
card
->
rtd_list
,
list
)
{
if
(
!
strncmp
(
rtd
->
codec_dai
->
name
,
CHT_CODEC_DAI
,
strlen
(
CHT_CODEC_DAI
)))
if
(
!
strncmp
(
rtd
->
codec_dai
->
name
,
CHT_CODEC_DAI1
,
strlen
(
CHT_CODEC_DAI1
)))
return
rtd
->
codec_dai
;
if
(
!
strncmp
(
rtd
->
codec_dai
->
name
,
CHT_CODEC_DAI2
,
strlen
(
CHT_CODEC_DAI2
)))
return
rtd
->
codec_dai
;
}
return
NULL
;
...
...
@@ -65,6 +91,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
snd_soc_card
*
card
=
dapm
->
card
;
struct
snd_soc_dai
*
codec_dai
;
struct
cht_mc_private
*
ctx
=
snd_soc_card_get_drvdata
(
card
);
int
ret
;
codec_dai
=
cht_get_codec_dai
(
card
);
...
...
@@ -73,21 +100,32 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
return
-
EIO
;
}
if
(
!
SND_SOC_DAPM_EVENT_OFF
(
event
))
return
0
;
if
(
SND_SOC_DAPM_EVENT_ON
(
event
))
{
if
(
ctx
->
mclk
)
{
ret
=
clk_prepare_enable
(
ctx
->
mclk
);
if
(
ret
<
0
)
{
dev_err
(
card
->
dev
,
"could not configure MCLK state"
);
return
ret
;
}
}
}
else
{
/* Set codec sysclk source to its internal clock because codec PLL will
* be off when idle and MCLK will also be off by ACPI
when codec is
* be off when idle and MCLK will also be off
when codec is
* runtime suspended. Codec needs clock for jack detection and button
* press
.
* press. MCLK is turned off with clock framework or ACPI
.
*/
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
RT5645_SCLK_S_RCCLK
,
0
,
SND_SOC_CLOCK_IN
);
48000
*
512
,
SND_SOC_CLOCK_IN
);
if
(
ret
<
0
)
{
dev_err
(
card
->
dev
,
"can't set codec sysclk: %d
\n
"
,
ret
);
return
ret
;
}
if
(
ctx
->
mclk
)
clk_disable_unprepare
(
ctx
->
mclk
);
}
return
0
;
}
...
...
@@ -97,7 +135,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
SND_SOC_DAPM_MIC
(
"Int Mic"
,
NULL
),
SND_SOC_DAPM_SPK
(
"Ext Spk"
,
NULL
),
SND_SOC_DAPM_SUPPLY
(
"Platform Clock"
,
SND_SOC_NOPM
,
0
,
0
,
platform_clock_control
,
SND_SOC_DAPM_POST_PMD
),
platform_clock_control
,
SND_SOC_DAPM_P
RE_PMU
|
SND_SOC_DAPM_P
OST_PMD
),
};
static
const
struct
snd_soc_dapm_route
cht_rt5645_audio_map
[]
=
{
...
...
@@ -109,12 +147,6 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
{
"Headphone"
,
NULL
,
"HPOR"
},
{
"Ext Spk"
,
NULL
,
"SPOL"
},
{
"Ext Spk"
,
NULL
,
"SPOR"
},
{
"AIF1 Playback"
,
NULL
,
"ssp2 Tx"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out0"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out1"
},
{
"codec_in0"
,
NULL
,
"ssp2 Rx"
},
{
"codec_in1"
,
NULL
,
"ssp2 Rx"
},
{
"ssp2 Rx"
,
NULL
,
"AIF1 Capture"
},
{
"Headphone"
,
NULL
,
"Platform Clock"
},
{
"Headset Mic"
,
NULL
,
"Platform Clock"
},
{
"Int Mic"
,
NULL
,
"Platform Clock"
},
...
...
@@ -130,16 +162,42 @@ static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = {
{
"Headphone"
,
NULL
,
"HPOR"
},
{
"Ext Spk"
,
NULL
,
"SPOL"
},
{
"Ext Spk"
,
NULL
,
"SPOR"
},
{
"Headphone"
,
NULL
,
"Platform Clock"
},
{
"Headset Mic"
,
NULL
,
"Platform Clock"
},
{
"Int Mic"
,
NULL
,
"Platform Clock"
},
{
"Ext Spk"
,
NULL
,
"Platform Clock"
},
};
static
const
struct
snd_soc_dapm_route
cht_rt5645_ssp2_aif1_map
[]
=
{
{
"AIF1 Playback"
,
NULL
,
"ssp2 Tx"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out0"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out1"
},
{
"codec_in0"
,
NULL
,
"ssp2 Rx"
},
{
"codec_in1"
,
NULL
,
"ssp2 Rx"
},
{
"ssp2 Rx"
,
NULL
,
"AIF1 Capture"
},
{
"Headphone"
,
NULL
,
"Platform Clock"
},
{
"Headset Mic"
,
NULL
,
"Platform Clock"
},
{
"Int Mic"
,
NULL
,
"Platform Clock"
},
{
"Ext Spk"
,
NULL
,
"Platform Clock"
},
};
static
const
struct
snd_soc_dapm_route
cht_rt5645_ssp2_aif2_map
[]
=
{
{
"AIF2 Playback"
,
NULL
,
"ssp2 Tx"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out0"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out1"
},
{
"codec_in0"
,
NULL
,
"ssp2 Rx"
},
{
"codec_in1"
,
NULL
,
"ssp2 Rx"
},
{
"ssp2 Rx"
,
NULL
,
"AIF2 Capture"
},
};
static
const
struct
snd_soc_dapm_route
cht_rt5645_ssp0_aif1_map
[]
=
{
{
"AIF1 Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Tx"
,
NULL
,
"modem_out"
},
{
"modem_in"
,
NULL
,
"ssp0 Rx"
},
{
"ssp0 Rx"
,
NULL
,
"AIF1 Capture"
},
};
static
const
struct
snd_soc_dapm_route
cht_rt5645_ssp0_aif2_map
[]
=
{
{
"AIF2 Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Tx"
,
NULL
,
"modem_out"
},
{
"modem_in"
,
NULL
,
"ssp0 Rx"
},
{
"ssp0 Rx"
,
NULL
,
"AIF2 Capture"
},
};
static
const
struct
snd_kcontrol_new
cht_mc_controls
[]
=
{
...
...
@@ -185,14 +243,37 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
return
0
;
}
/* uncomment when we have a real quirk
static int cht_rt5645_quirk_cb(const struct dmi_system_id *id)
{
cht_rt5645_quirk = (unsigned long)id->driver_data;
return 1;
}
*/
static
const
struct
dmi_system_id
cht_rt5645_quirk_table
[]
=
{
{
},
};
static
int
cht_codec_init
(
struct
snd_soc_pcm_runtime
*
runtime
)
{
int
ret
;
int
jack_type
;
struct
snd_soc_codec
*
codec
=
runtime
->
codec
;
struct
snd_soc_
dai
*
codec_dai
=
runtime
->
codec_dai
;
struct
snd_soc_
card
*
card
=
runtime
->
card
;
struct
cht_mc_private
*
ctx
=
snd_soc_card_get_drvdata
(
runtime
->
card
);
if
((
cht_rt5645_quirk
&
CHT_RT5645_SSP2_AIF2
)
||
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF2
))
{
/* Select clk_i2s2_asrc as ASRC clock source */
rt5645_sel_asrc_clk_src
(
codec
,
RT5645_DA_STEREO_FILTER
|
RT5645_DA_MONO_L_FILTER
|
RT5645_DA_MONO_R_FILTER
|
RT5645_AD_STEREO_FILTER
,
RT5645_CLK_SEL_I2S2_ASRC
);
}
else
{
/* Select clk_i2s1_asrc as ASRC clock source */
rt5645_sel_asrc_clk_src
(
codec
,
RT5645_DA_STEREO_FILTER
|
...
...
@@ -200,13 +281,27 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
RT5645_DA_MONO_R_FILTER
|
RT5645_AD_STEREO_FILTER
,
RT5645_CLK_SEL_I2S1_ASRC
);
}
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
ret
=
snd_soc_dai_set_tdm_slot
(
codec_dai
,
0xF
,
0xF
,
4
,
24
);
if
(
ret
<
0
)
{
dev_err
(
runtime
->
dev
,
"can't set codec TDM slot %d
\n
"
,
ret
);
return
ret
;
if
(
cht_rt5645_quirk
&
CHT_RT5645_SSP2_AIF2
)
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
cht_rt5645_ssp2_aif2_map
,
ARRAY_SIZE
(
cht_rt5645_ssp2_aif2_map
));
}
else
if
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF1
)
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
cht_rt5645_ssp0_aif1_map
,
ARRAY_SIZE
(
cht_rt5645_ssp0_aif1_map
));
}
else
if
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF2
)
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
cht_rt5645_ssp0_aif2_map
,
ARRAY_SIZE
(
cht_rt5645_ssp0_aif2_map
));
}
else
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
cht_rt5645_ssp2_aif1_map
,
ARRAY_SIZE
(
cht_rt5645_ssp2_aif1_map
));
}
if
(
ret
)
return
ret
;
if
(
ctx
->
acpi_card
->
codec_type
==
CODEC_TYPE_RT5650
)
jack_type
=
SND_JACK_HEADPHONE
|
SND_JACK_MICROPHONE
|
...
...
@@ -225,12 +320,33 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
rt5645_set_jack_detect
(
codec
,
&
ctx
->
jack
,
&
ctx
->
jack
,
&
ctx
->
jack
);
if
(
ctx
->
mclk
)
{
/*
* The firmware might enable the clock at
* boot (this information may or may not
* be reflected in the enable clock register).
* To change the rate we must disable the clock
* first to cover these cases. Due to common
* clock framework restrictions that do not allow
* to disable a clock that has not been enabled,
* we need to enable the clock first.
*/
ret
=
clk_prepare_enable
(
ctx
->
mclk
);
if
(
!
ret
)
clk_disable_unprepare
(
ctx
->
mclk
);
ret
=
clk_set_rate
(
ctx
->
mclk
,
CHT_PLAT_CLK_3_HZ
);
if
(
ret
)
dev_err
(
runtime
->
dev
,
"unable to set MCLK rate
\n
"
);
}
return
ret
;
}
static
int
cht_codec_fixup
(
struct
snd_soc_pcm_runtime
*
rtd
,
struct
snd_pcm_hw_params
*
params
)
{
int
ret
;
struct
snd_interval
*
rate
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_RATE
);
struct
snd_interval
*
channels
=
hw_param_interval
(
params
,
...
...
@@ -240,8 +356,67 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
rate
->
min
=
rate
->
max
=
48000
;
channels
->
min
=
channels
->
max
=
2
;
if
((
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF1
)
||
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF2
))
{
/* set SSP0 to 16-bit */
params_set_format
(
params
,
SNDRV_PCM_FORMAT_S16_LE
);
/*
* Default mode for SSP configuration is TDM 4 slot, override config
* with explicit setting to I2S 2ch 16-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
ret
=
snd_soc_dai_set_fmt
(
rtd
->
cpu_dai
,
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBS_CFS
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set format to I2S, err %d
\n
"
,
ret
);
return
ret
;
}
ret
=
snd_soc_dai_set_fmt
(
rtd
->
codec_dai
,
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBS_CFS
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set format to I2S, err %d
\n
"
,
ret
);
return
ret
;
}
ret
=
snd_soc_dai_set_tdm_slot
(
rtd
->
cpu_dai
,
0x3
,
0x3
,
2
,
16
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set I2S config, err %d
\n
"
,
ret
);
return
ret
;
}
}
else
{
/* set SSP2 to 24-bit */
params_set_format
(
params
,
SNDRV_PCM_FORMAT_S24_LE
);
/*
* Default mode for SSP configuration is TDM 4 slot
*/
ret
=
snd_soc_dai_set_fmt
(
rtd
->
codec_dai
,
SND_SOC_DAIFMT_DSP_B
|
SND_SOC_DAIFMT_IB_NF
|
SND_SOC_DAIFMT_CBS_CFS
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set format to TDM %d
\n
"
,
ret
);
return
ret
;
}
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
ret
=
snd_soc_dai_set_tdm_slot
(
rtd
->
codec_dai
,
0xF
,
0xF
,
4
,
24
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set codec TDM slot %d
\n
"
,
ret
);
return
ret
;
}
}
return
0
;
}
...
...
@@ -303,8 +478,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.
no_pcm
=
1
,
.
codec_dai_name
=
"rt5645-aif1"
,
.
codec_name
=
"i2c-10EC5645:00"
,
.
dai_fmt
=
SND_SOC_DAIFMT_DSP_B
|
SND_SOC_DAIFMT_IB_NF
|
SND_SOC_DAIFMT_CBS_CFS
,
.
init
=
cht_codec_init
,
.
be_hw_params_fixup
=
cht_codec_fixup
,
.
nonatomic
=
true
,
...
...
@@ -344,10 +517,31 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
static
struct
cht_acpi_card
snd_soc_cards
[]
=
{
{
"10EC5640"
,
CODEC_TYPE_RT5645
,
&
snd_soc_card_chtrt5645
},
{
"10EC5645"
,
CODEC_TYPE_RT5645
,
&
snd_soc_card_chtrt5645
},
{
"10EC5648"
,
CODEC_TYPE_RT5645
,
&
snd_soc_card_chtrt5645
},
{
"10EC3270"
,
CODEC_TYPE_RT5645
,
&
snd_soc_card_chtrt5645
},
{
"10EC5650"
,
CODEC_TYPE_RT5650
,
&
snd_soc_card_chtrt5650
},
};
static
char
cht_rt5640_codec_name
[
16
];
/* i2c-<HID>:00 with HID being 8 chars */
static
char
cht_rt5645_codec_name
[
16
];
/* i2c-<HID>:00 with HID being 8 chars */
static
char
cht_rt5645_codec_aif_name
[
12
];
/* = "rt5645-aif[1|2]" */
static
char
cht_rt5645_cpu_dai_name
[
10
];
/* = "ssp[0|2]-port" */
static
bool
is_valleyview
(
void
)
{
static
const
struct
x86_cpu_id
cpu_ids
[]
=
{
{
X86_VENDOR_INTEL
,
6
,
55
},
/* Valleyview, Bay Trail */
{}
};
if
(
!
x86_match_cpu
(
cpu_ids
))
return
false
;
return
true
;
}
struct
acpi_chan_package
{
/* ACPICA seems to require 64 bit integers */
u64
aif_value
;
/* 1: AIF1, 2: AIF2 */
u64
mclock_value
;
/* usually 25MHz (0x17d7940), ignored */
};
static
int
snd_cht_mc_probe
(
struct
platform_device
*
pdev
)
{
...
...
@@ -358,22 +552,33 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
struct
sst_acpi_mach
*
mach
;
const
char
*
i2c_name
=
NULL
;
int
dai_index
=
0
;
bool
found
=
false
;
bool
is_bytcr
=
false
;
drv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
drv
),
GFP_ATOMIC
);
if
(
!
drv
)
return
-
ENOMEM
;
mach
=
(
&
pdev
->
dev
)
->
platform_data
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
snd_soc_cards
);
i
++
)
{
if
(
acpi_dev_found
(
snd_soc_cards
[
i
].
codec_id
))
{
if
(
acpi_dev_found
(
snd_soc_cards
[
i
].
codec_id
)
&&
(
!
strncmp
(
snd_soc_cards
[
i
].
codec_id
,
mach
->
id
,
8
)))
{
dev_dbg
(
&
pdev
->
dev
,
"found codec %s
\n
"
,
snd_soc_cards
[
i
].
codec_id
);
card
=
snd_soc_cards
[
i
].
soc_card
;
drv
->
acpi_card
=
&
snd_soc_cards
[
i
];
found
=
true
;
break
;
}
}
if
(
!
found
)
{
dev_err
(
&
pdev
->
dev
,
"No matching HID found in supported list
\n
"
);
return
-
ENODEV
;
}
card
->
dev
=
&
pdev
->
dev
;
mach
=
card
->
dev
->
platform_data
;
sprintf
(
drv
->
codec_name
,
"i2c-%s:00"
,
drv
->
acpi_card
->
codec_id
);
/* set correct codec name */
...
...
@@ -386,9 +591,105 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* fixup codec name based on HID */
i2c_name
=
sst_acpi_find_name_from_hid
(
mach
->
id
);
if
(
i2c_name
!=
NULL
)
{
snprintf
(
cht_rt564
0_codec_name
,
sizeof
(
cht_rt5640
_codec_name
),
snprintf
(
cht_rt564
5_codec_name
,
sizeof
(
cht_rt5645
_codec_name
),
"%s%s"
,
"i2c-"
,
i2c_name
);
cht_dailink
[
dai_index
].
codec_name
=
cht_rt5640_codec_name
;
cht_dailink
[
dai_index
].
codec_name
=
cht_rt5645_codec_name
;
}
/*
* swap SSP0 if bytcr is detected
* (will be overridden if DMI quirk is detected)
*/
if
(
is_valleyview
())
{
struct
sst_platform_info
*
p_info
=
mach
->
pdata
;
const
struct
sst_res_info
*
res_info
=
p_info
->
res_info
;
if
(
res_info
->
acpi_ipc_irq_index
==
0
)
is_bytcr
=
true
;
}
if
(
is_bytcr
)
{
/*
* Baytrail CR platforms may have CHAN package in BIOS, try
* to find relevant routing quirk based as done on Windows
* platforms. We have to read the information directly from the
* BIOS, at this stage the card is not created and the links
* with the codec driver/pdata are non-existent
*/
struct
acpi_chan_package
chan_package
;
/* format specified: 2 64-bit integers */
struct
acpi_buffer
format
=
{
sizeof
(
"NN"
),
"NN"
};
struct
acpi_buffer
state
=
{
0
,
NULL
};
struct
sst_acpi_package_context
pkg_ctx
;
bool
pkg_found
=
false
;
state
.
length
=
sizeof
(
chan_package
);
state
.
pointer
=
&
chan_package
;
pkg_ctx
.
name
=
"CHAN"
;
pkg_ctx
.
length
=
2
;
pkg_ctx
.
format
=
&
format
;
pkg_ctx
.
state
=
&
state
;
pkg_ctx
.
data_valid
=
false
;
pkg_found
=
sst_acpi_find_package_from_hid
(
mach
->
id
,
&
pkg_ctx
);
if
(
pkg_found
)
{
if
(
chan_package
.
aif_value
==
1
)
{
dev_info
(
&
pdev
->
dev
,
"BIOS Routing: AIF1 connected
\n
"
);
cht_rt5645_quirk
|=
CHT_RT5645_SSP0_AIF1
;
}
else
if
(
chan_package
.
aif_value
==
2
)
{
dev_info
(
&
pdev
->
dev
,
"BIOS Routing: AIF2 connected
\n
"
);
cht_rt5645_quirk
|=
CHT_RT5645_SSP0_AIF2
;
}
else
{
dev_info
(
&
pdev
->
dev
,
"BIOS Routing isn't valid, ignored
\n
"
);
pkg_found
=
false
;
}
}
if
(
!
pkg_found
)
{
/* no BIOS indications, assume SSP0-AIF2 connection */
cht_rt5645_quirk
|=
CHT_RT5645_SSP0_AIF2
;
}
}
/* check quirks before creating card */
dmi_check_system
(
cht_rt5645_quirk_table
);
log_quirks
(
&
pdev
->
dev
);
if
((
cht_rt5645_quirk
&
CHT_RT5645_SSP2_AIF2
)
||
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF2
))
{
/* fixup codec aif name */
snprintf
(
cht_rt5645_codec_aif_name
,
sizeof
(
cht_rt5645_codec_aif_name
),
"%s"
,
"rt5645-aif2"
);
cht_dailink
[
dai_index
].
codec_dai_name
=
cht_rt5645_codec_aif_name
;
}
if
((
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF1
)
||
(
cht_rt5645_quirk
&
CHT_RT5645_SSP0_AIF2
))
{
/* fixup cpu dai name name */
snprintf
(
cht_rt5645_cpu_dai_name
,
sizeof
(
cht_rt5645_cpu_dai_name
),
"%s"
,
"ssp0-port"
);
cht_dailink
[
dai_index
].
cpu_dai_name
=
cht_rt5645_cpu_dai_name
;
}
if
(
is_valleyview
())
{
drv
->
mclk
=
devm_clk_get
(
&
pdev
->
dev
,
"pmc_plt_clk_3"
);
if
(
IS_ERR
(
drv
->
mclk
))
{
dev_err
(
&
pdev
->
dev
,
"Failed to get MCLK from pmc_plt_clk_3: %ld
\n
"
,
PTR_ERR
(
drv
->
mclk
));
return
PTR_ERR
(
drv
->
mclk
);
}
}
snd_soc_card_set_drvdata
(
card
,
drv
);
...
...
sound/soc/intel/boards/skl_nau88l25_max98357a.c
View file @
16b57114
...
...
@@ -32,6 +32,7 @@
static
struct
snd_soc_jack
skylake_headset
;
static
struct
snd_soc_card
skylake_audio_card
;
static
const
struct
snd_pcm_hw_constraint_list
*
dmic_constraints
;
static
struct
snd_soc_jack
skylake_hdmi
[
3
];
struct
skl_hdmi_pcm
{
struct
list_head
head
;
...
...
@@ -111,8 +112,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC
(
"Headset Mic"
,
NULL
),
SND_SOC_DAPM_SPK
(
"Spk"
,
NULL
),
SND_SOC_DAPM_MIC
(
"SoC DMIC"
,
NULL
),
SND_SOC_DAPM_SPK
(
"DP"
,
NULL
),
SND_SOC_DAPM_SPK
(
"
HDMI
"
,
NULL
),
SND_SOC_DAPM_SPK
(
"DP
1
"
,
NULL
),
SND_SOC_DAPM_SPK
(
"
DP2
"
,
NULL
),
SND_SOC_DAPM_SUPPLY
(
"Platform Clock"
,
SND_SOC_NOPM
,
0
,
0
,
platform_clock_control
,
SND_SOC_DAPM_PRE_PMU
|
SND_SOC_DAPM_POST_PMD
),
...
...
@@ -130,9 +131,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{
"MIC"
,
NULL
,
"Headset Mic"
},
{
"DMic"
,
NULL
,
"SoC DMIC"
},
{
"HDMI"
,
NULL
,
"hif5 Output"
},
{
"DP"
,
NULL
,
"hif6 Output"
},
/* CODEC BE connections */
{
"HiFi Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Tx"
,
NULL
,
"codec0_out"
},
...
...
@@ -603,19 +601,39 @@ static struct snd_soc_dai_link skylake_dais[] = {
},
};
#define NAME_SIZE 32
static
int
skylake_card_late_probe
(
struct
snd_soc_card
*
card
)
{
struct
skl_nau8825_private
*
ctx
=
snd_soc_card_get_drvdata
(
card
);
struct
skl_hdmi_pcm
*
pcm
;
int
err
;
struct
snd_soc_codec
*
codec
=
NULL
;
int
err
,
i
=
0
;
char
jack_name
[
NAME_SIZE
];
list_for_each_entry
(
pcm
,
&
ctx
->
hdmi_pcm_list
,
head
)
{
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
);
codec
=
pcm
->
codec_dai
->
codec
;
snprintf
(
jack_name
,
sizeof
(
jack_name
),
"HDMI/DP, pcm=%d Jack"
,
pcm
->
device
);
err
=
snd_soc_card_jack_new
(
card
,
jack_name
,
SND_JACK_AVOUT
,
&
skylake_hdmi
[
i
],
NULL
,
0
);
if
(
err
)
return
err
;
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
,
&
skylake_hdmi
[
i
]);
if
(
err
<
0
)
return
err
;
i
++
;
}
return
0
;
if
(
!
codec
)
return
-
EINVAL
;
return
hdac_hdmi_jack_port_init
(
codec
,
&
card
->
dapm
);
}
/* skylake audio machine driver for SPT + NAU88L25 */
...
...
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
View file @
16b57114
...
...
@@ -36,6 +36,7 @@
static
struct
snd_soc_jack
skylake_headset
;
static
struct
snd_soc_card
skylake_audio_card
;
static
const
struct
snd_pcm_hw_constraint_list
*
dmic_constraints
;
static
struct
snd_soc_jack
skylake_hdmi
[
3
];
struct
skl_hdmi_pcm
{
struct
list_head
head
;
...
...
@@ -115,8 +116,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_SPK
(
"Left Speaker"
,
NULL
),
SND_SOC_DAPM_SPK
(
"Right Speaker"
,
NULL
),
SND_SOC_DAPM_MIC
(
"SoC DMIC"
,
NULL
),
SND_SOC_DAPM_SPK
(
"DP"
,
NULL
),
SND_SOC_DAPM_SPK
(
"
HDMI
"
,
NULL
),
SND_SOC_DAPM_SPK
(
"DP
1
"
,
NULL
),
SND_SOC_DAPM_SPK
(
"
DP2
"
,
NULL
),
SND_SOC_DAPM_SUPPLY
(
"Platform Clock"
,
SND_SOC_NOPM
,
0
,
0
,
platform_clock_control
,
SND_SOC_DAPM_PRE_PMU
|
SND_SOC_DAPM_POST_PMD
),
...
...
@@ -135,8 +136,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{
"MIC"
,
NULL
,
"Headset Mic"
},
{
"DMic"
,
NULL
,
"SoC DMIC"
},
{
"HDMI"
,
NULL
,
"hif5 Output"
},
{
"DP"
,
NULL
,
"hif6 Output"
},
/* CODEC BE connections */
{
"Left Playback"
,
NULL
,
"ssp0 Tx"
},
{
"Right Playback"
,
NULL
,
"ssp0 Tx"
},
...
...
@@ -653,19 +652,39 @@ static struct snd_soc_dai_link skylake_dais[] = {
},
};
#define NAME_SIZE 32
static
int
skylake_card_late_probe
(
struct
snd_soc_card
*
card
)
{
struct
skl_nau88125_private
*
ctx
=
snd_soc_card_get_drvdata
(
card
);
struct
skl_hdmi_pcm
*
pcm
;
int
err
;
struct
snd_soc_codec
*
codec
=
NULL
;
int
err
,
i
=
0
;
char
jack_name
[
NAME_SIZE
];
list_for_each_entry
(
pcm
,
&
ctx
->
hdmi_pcm_list
,
head
)
{
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
);
codec
=
pcm
->
codec_dai
->
codec
;
snprintf
(
jack_name
,
sizeof
(
jack_name
),
"HDMI/DP, pcm=%d Jack"
,
pcm
->
device
);
err
=
snd_soc_card_jack_new
(
card
,
jack_name
,
SND_JACK_AVOUT
,
&
skylake_hdmi
[
i
],
NULL
,
0
);
if
(
err
)
return
err
;
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
,
&
skylake_hdmi
[
i
]);
if
(
err
<
0
)
return
err
;
i
++
;
}
return
0
;
if
(
!
codec
)
return
-
EINVAL
;
return
hdac_hdmi_jack_port_init
(
codec
,
&
card
->
dapm
);
}
/* skylake audio machine driver for SPT + NAU88L25 */
...
...
sound/soc/intel/boards/skl_rt286.c
View file @
16b57114
...
...
@@ -29,6 +29,7 @@
#include "../../codecs/hdac_hdmi.h"
static
struct
snd_soc_jack
skylake_headset
;
static
struct
snd_soc_jack
skylake_hdmi
[
3
];
struct
skl_hdmi_pcm
{
struct
list_head
head
;
...
...
@@ -94,10 +95,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{
"DMIC1 Pin"
,
NULL
,
"DMIC2"
},
{
"DMic"
,
NULL
,
"SoC DMIC"
},
{
"HDMI1"
,
NULL
,
"hif5 Output"
},
{
"HDMI2"
,
NULL
,
"hif6 Output"
},
{
"HDMI3"
,
NULL
,
"hif7 Output"
},
/* CODEC BE connections */
{
"AIF1 Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Tx"
,
NULL
,
"codec0_out"
},
...
...
@@ -458,19 +455,38 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
},
};
#define NAME_SIZE 32
static
int
skylake_card_late_probe
(
struct
snd_soc_card
*
card
)
{
struct
skl_rt286_private
*
ctx
=
snd_soc_card_get_drvdata
(
card
);
struct
skl_hdmi_pcm
*
pcm
;
int
err
;
struct
snd_soc_codec
*
codec
=
NULL
;
int
err
,
i
=
0
;
char
jack_name
[
NAME_SIZE
];
list_for_each_entry
(
pcm
,
&
ctx
->
hdmi_pcm_list
,
head
)
{
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
);
codec
=
pcm
->
codec_dai
->
codec
;
snprintf
(
jack_name
,
sizeof
(
jack_name
),
"HDMI/DP, pcm=%d Jack"
,
pcm
->
device
);
err
=
snd_soc_card_jack_new
(
card
,
jack_name
,
SND_JACK_AVOUT
,
&
skylake_hdmi
[
i
],
NULL
,
0
);
if
(
err
)
return
err
;
err
=
hdac_hdmi_jack_init
(
pcm
->
codec_dai
,
pcm
->
device
,
&
skylake_hdmi
[
i
]);
if
(
err
<
0
)
return
err
;
i
++
;
}
return
0
;
if
(
!
codec
)
return
-
EINVAL
;
return
hdac_hdmi_jack_port_init
(
codec
,
&
card
->
dapm
);
}
/* skylake audio machine driver for SPT + RT286S */
...
...
sound/soc/intel/common/sst-dsp.c
View file @
16b57114
...
...
@@ -252,44 +252,44 @@ void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
EXPORT_SYMBOL_GPL
(
sst_dsp_shim_update_bits_forced
);
int
sst_dsp_register_poll
(
struct
sst_dsp
*
ctx
,
u32
offset
,
u32
mask
,
u32
target
,
u32
time
out
,
char
*
operation
)
u32
target
,
u32
time
,
char
*
operation
)
{
int
time
,
ret
;
u32
reg
;
bool
done
=
false
;
unsigned
long
timeout
;
int
k
=
0
,
s
=
500
;
/*
* we will poll for couple of ms using mdelay, if not successful
* then go to longer sleep using usleep_range
* split the loop into sleeps of varying resolution. more accurately,
* the range of wakeups are:
* Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
* Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms
* (usleep_range (500, 1000) and usleep_range(5000, 10000) are
* both possible in this phase depending on whether k > 10 or not).
* Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms.
*/
/* check if set state successful */
for
(
time
=
0
;
time
<
5
;
time
++
)
{
if
((
sst_dsp_shim_read_unlocked
(
ctx
,
offset
)
&
mask
)
==
target
)
{
done
=
true
;
break
;
}
mdelay
(
1
);
timeout
=
jiffies
+
msecs_to_jiffies
(
time
);
while
(((
sst_dsp_shim_read_unlocked
(
ctx
,
offset
)
&
mask
)
!=
target
)
&&
time_before
(
jiffies
,
timeout
))
{
k
++
;
if
(
k
>
10
)
s
=
5000
;
usleep_range
(
s
,
2
*
s
);
}
if
(
done
==
false
)
{
/* sleeping in 10ms steps so adjust timeout value */
timeout
/=
10
;
reg
=
sst_dsp_shim_read_unlocked
(
ctx
,
offset
);
for
(
time
=
0
;
time
<
timeout
;
time
++
)
{
if
((
sst_dsp_shim_read_unlocked
(
ctx
,
offset
)
&
mask
)
==
target
)
break
;
if
((
reg
&
mask
)
==
target
)
{
dev_dbg
(
ctx
->
dev
,
"FW Poll Status: reg=%#x %s successful
\n
"
,
reg
,
operation
)
;
usleep_range
(
5000
,
10000
);
}
return
0
;
}
reg
=
sst_dsp_shim_read_unlocked
(
ctx
,
offset
);
dev_dbg
(
ctx
->
dev
,
"FW Poll Status: reg=%#x %s %s
\n
"
,
reg
,
operation
,
(
time
<
timeout
)
?
"successful"
:
"timedout"
);
ret
=
time
<
timeout
?
0
:
-
ETIME
;
return
ret
;
dev_dbg
(
ctx
->
dev
,
"FW Poll Status: reg=%#x %s timedout
\n
"
,
reg
,
operation
);
return
-
ETIME
;
}
EXPORT_SYMBOL_GPL
(
sst_dsp_register_poll
);
...
...
sound/soc/intel/skylake/bxt-sst.c
View file @
16b57114
...
...
@@ -23,7 +23,6 @@
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "skl-sst-ipc.h"
#include "skl-tplg-interface.h"
#define BXT_BASEFW_TIMEOUT 3000
#define BXT_INIT_TIMEOUT 500
...
...
@@ -52,7 +51,7 @@ static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
}
static
int
bxt_load_library
(
struct
sst_dsp
*
ctx
,
struct
skl_
dfw_manifest
*
minfo
)
bxt_load_library
(
struct
sst_dsp
*
ctx
,
struct
skl_
lib_info
*
linfo
,
int
lib_count
)
{
struct
snd_dma_buffer
dmab
;
struct
skl_sst
*
skl
=
ctx
->
thread_context
;
...
...
@@ -61,11 +60,11 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
int
ret
=
0
,
i
,
dma_id
,
stream_tag
;
/* library indices start from 1 to N. 0 represents base FW */
for
(
i
=
1
;
i
<
minfo
->
lib_count
;
i
++
)
{
ret
=
request_firmware
(
&
fw
,
minfo
->
lib
[
i
].
name
,
ctx
->
dev
);
for
(
i
=
1
;
i
<
lib_count
;
i
++
)
{
ret
=
request_firmware
(
&
fw
,
linfo
[
i
].
name
,
ctx
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Request lib %s failed:%d
\n
"
,
minfo
->
lib
[
i
].
name
,
ret
);
linfo
[
i
].
name
,
ret
);
return
ret
;
}
...
...
@@ -96,7 +95,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
ret
=
skl_sst_ipc_load_library
(
&
skl
->
ipc
,
dma_id
,
i
);
if
(
ret
<
0
)
dev_err
(
ctx
->
dev
,
"IPC Load Lib for %s fail: %d
\n
"
,
minfo
->
lib
[
i
].
name
,
ret
);
linfo
[
i
].
name
,
ret
);
ctx
->
dsp_ops
.
trigger
(
ctx
->
dev
,
false
,
stream_tag
);
ctx
->
dsp_ops
.
cleanup
(
ctx
->
dev
,
&
dmab
,
stream_tag
);
...
...
@@ -119,8 +118,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
static
int
sst_bxt_prepare_fw
(
struct
sst_dsp
*
ctx
,
const
void
*
fwdata
,
u32
fwsize
)
{
int
stream_tag
,
ret
,
i
;
u32
reg
;
int
stream_tag
,
ret
;
stream_tag
=
ctx
->
dsp_ops
.
prepare
(
ctx
->
dev
,
0x40
,
fwsize
,
&
ctx
->
dmab
);
if
(
stream_tag
<=
0
)
{
...
...
@@ -153,23 +151,13 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
}
/* Step 4: Wait for DONE Bit */
for
(
i
=
BXT_INIT_TIMEOUT
;
i
>
0
;
--
i
)
{
reg
=
sst_dsp_shim_read
(
ctx
,
SKL_ADSP_REG_HIPCIE
);
if
(
reg
&
SKL_ADSP_REG_HIPCIE_DONE
)
{
sst_dsp_shim_update_bits_forced
(
ctx
,
SKL_ADSP_REG_HIPCIE
,
ret
=
sst_dsp_register_poll
(
ctx
,
SKL_ADSP_REG_HIPCIE
,
SKL_ADSP_REG_HIPCIE_DONE
,
SKL_ADSP_REG_HIPCIE_DONE
);
break
;
}
mdelay
(
1
);
}
if
(
!
i
)
{
dev_info
(
ctx
->
dev
,
"Waiting for HIPCIE done, reg: 0x%x
\n
"
,
reg
);
sst_dsp_shim_update_bits
(
ctx
,
SKL_ADSP_REG_HIPCIE
,
SKL_ADSP_REG_HIPCIE_DONE
,
SKL_ADSP_REG_HIPCIE_DONE
);
BXT_INIT_TIMEOUT
,
"HIPCIE Done"
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Timout for Purge Request%d
\n
"
,
ret
);
goto
base_fw_load_failed
;
}
/* Step 5: power down core1 */
...
...
@@ -184,19 +172,10 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
skl_ipc_op_int_enable
(
ctx
);
/* Step 7: Wait for ROM init */
for
(
i
=
BXT_INIT_TIMEOUT
;
i
>
0
;
--
i
)
{
if
(
SKL_FW_INIT
==
(
sst_dsp_shim_read
(
ctx
,
BXT_ADSP_FW_STATUS
)
&
SKL_FW_STS_MASK
))
{
dev_info
(
ctx
->
dev
,
"ROM loaded, continue FW loading
\n
"
);
break
;
}
mdelay
(
1
);
}
if
(
!
i
)
{
dev_err
(
ctx
->
dev
,
"Timeout for ROM init, HIPCIE: 0x%x
\n
"
,
reg
);
ret
=
-
EIO
;
ret
=
sst_dsp_register_poll
(
ctx
,
BXT_ADSP_FW_STATUS
,
SKL_FW_STS_MASK
,
SKL_FW_INIT
,
BXT_INIT_TIMEOUT
,
"ROM Load"
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Timeout for ROM init, ret:%d
\n
"
,
ret
);
goto
base_fw_load_failed
;
}
...
...
@@ -432,7 +411,6 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
int
ret
;
struct
skl_ipc_dxstate_info
dx
;
unsigned
int
core_mask
=
SKL_DSP_CORE_MASK
(
core_id
);
struct
skl_dfw_manifest
*
minfo
=
&
skl
->
manifest
;
if
(
skl
->
fw_loaded
==
false
)
{
skl
->
boot_complete
=
false
;
...
...
@@ -442,8 +420,9 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
return
ret
;
}
if
(
minfo
->
lib_count
>
1
)
{
ret
=
bxt_load_library
(
ctx
,
minfo
);
if
(
skl
->
lib_count
>
1
)
{
ret
=
bxt_load_library
(
ctx
,
skl
->
lib_info
,
skl
->
lib_count
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"reload libs failed: %d
\n
"
,
ret
);
return
ret
;
...
...
@@ -640,8 +619,9 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx)
skl_dsp_init_core_state
(
sst
);
if
(
ctx
->
manifest
.
lib_count
>
1
)
{
ret
=
sst
->
fw_ops
.
load_library
(
sst
,
&
ctx
->
manifest
);
if
(
ctx
->
lib_count
>
1
)
{
ret
=
sst
->
fw_ops
.
load_library
(
sst
,
ctx
->
lib_info
,
ctx
->
lib_count
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Load Library failed : %x
\n
"
,
ret
);
return
ret
;
...
...
sound/soc/intel/skylake/skl-messages.c
View file @
16b57114
...
...
@@ -220,6 +220,13 @@ static const struct skl_dsp_ops dsp_ops[] = {
.
init_fw
=
bxt_sst_init_fw
,
.
cleanup
=
bxt_sst_dsp_cleanup
},
{
.
id
=
0x3198
,
.
loader_ops
=
bxt_get_loader_ops
,
.
init
=
bxt_sst_dsp_init
,
.
init_fw
=
bxt_sst_init_fw
,
.
cleanup
=
bxt_sst_dsp_cleanup
},
};
const
struct
skl_dsp_ops
*
skl_get_dsp_ops
(
int
pci_id
)
...
...
sound/soc/intel/skylake/skl-nhlt.c
View file @
16b57114
...
...
@@ -102,14 +102,16 @@ static void dump_config(struct device *dev, u32 instance_id, u8 linktype,
}
static
bool
skl_check_ep_match
(
struct
device
*
dev
,
struct
nhlt_endpoint
*
epnt
,
u32
instance_id
,
u8
link_type
,
u8
dirn
)
u32
instance_id
,
u8
link_type
,
u8
dirn
,
u8
dev_type
)
{
dev_dbg
(
dev
,
"vbus_id=%d link_type=%d dir=%d
\n
"
,
epnt
->
virtual_bus_id
,
epnt
->
linktype
,
epnt
->
direction
);
dev_dbg
(
dev
,
"vbus_id=%d link_type=%d dir=%d dev_type = %d
\n
"
,
epnt
->
virtual_bus_id
,
epnt
->
linktype
,
epnt
->
direction
,
epnt
->
device_type
);
if
((
epnt
->
virtual_bus_id
==
instance_id
)
&&
(
epnt
->
linktype
==
link_type
)
&&
(
epnt
->
direction
==
dirn
))
(
epnt
->
direction
==
dirn
)
&&
(
epnt
->
device_type
==
dev_type
))
return
true
;
else
return
false
;
...
...
@@ -117,7 +119,8 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
struct
nhlt_specific_cfg
*
skl_get_ep_blob
(
struct
skl
*
skl
,
u32
instance
,
u8
link_type
,
u8
s_fmt
,
u8
num_ch
,
u32
s_rate
,
u8
dirn
)
u8
s_fmt
,
u8
num_ch
,
u32
s_rate
,
u8
dirn
,
u8
dev_type
)
{
struct
nhlt_fmt
*
fmt
;
struct
nhlt_endpoint
*
epnt
;
...
...
@@ -135,7 +138,8 @@ struct nhlt_specific_cfg
dev_dbg
(
dev
,
"endpoint count =%d
\n
"
,
nhlt
->
endpoint_count
);
for
(
j
=
0
;
j
<
nhlt
->
endpoint_count
;
j
++
)
{
if
(
skl_check_ep_match
(
dev
,
epnt
,
instance
,
link_type
,
dirn
))
{
if
(
skl_check_ep_match
(
dev
,
epnt
,
instance
,
link_type
,
dirn
,
dev_type
))
{
fmt
=
(
struct
nhlt_fmt
*
)(
epnt
->
config
.
caps
+
epnt
->
config
.
size
);
sp_config
=
skl_get_specific_cfg
(
dev
,
fmt
,
num_ch
,
...
...
@@ -189,9 +193,9 @@ int skl_get_dmic_geo(struct skl *skl)
return
dmic_geo
;
}
static
void
skl_nhlt_trim_space
(
struct
skl
*
skl
)
static
void
skl_nhlt_trim_space
(
char
*
trim
)
{
char
*
s
=
skl
->
tplg_name
;
char
*
s
=
trim
;
int
cnt
;
int
i
;
...
...
@@ -218,7 +222,43 @@ int skl_nhlt_update_topology_bin(struct skl *skl)
skl
->
pci_id
,
nhlt
->
header
.
oem_id
,
nhlt
->
header
.
oem_table_id
,
nhlt
->
header
.
oem_revision
,
"-tplg.bin"
);
skl_nhlt_trim_space
(
skl
);
skl_nhlt_trim_space
(
skl
->
tplg_name
);
return
0
;
}
static
ssize_t
skl_nhlt_platform_id_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
pci_dev
*
pci
=
to_pci_dev
(
dev
);
struct
hdac_ext_bus
*
ebus
=
pci_get_drvdata
(
pci
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
struct
nhlt_acpi_table
*
nhlt
=
(
struct
nhlt_acpi_table
*
)
skl
->
nhlt
;
char
platform_id
[
32
];
sprintf
(
platform_id
,
"%x-%.6s-%.8s-%d"
,
skl
->
pci_id
,
nhlt
->
header
.
oem_id
,
nhlt
->
header
.
oem_table_id
,
nhlt
->
header
.
oem_revision
);
skl_nhlt_trim_space
(
platform_id
);
return
sprintf
(
buf
,
"%s
\n
"
,
platform_id
);
}
static
DEVICE_ATTR
(
platform_id
,
0444
,
skl_nhlt_platform_id_show
,
NULL
);
int
skl_nhlt_create_sysfs
(
struct
skl
*
skl
)
{
struct
device
*
dev
=
&
skl
->
pci
->
dev
;
if
(
sysfs_create_file
(
&
dev
->
kobj
,
&
dev_attr_platform_id
.
attr
))
dev_warn
(
dev
,
"Error creating sysfs entry
\n
"
);
return
0
;
}
void
skl_nhlt_remove_sysfs
(
struct
skl
*
skl
)
{
struct
device
*
dev
=
&
skl
->
pci
->
dev
;
sysfs_remove_file
(
&
dev
->
kobj
,
&
dev_attr_platform_id
.
attr
);
}
sound/soc/intel/skylake/skl-pcm.c
View file @
16b57114
...
...
@@ -137,6 +137,80 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream,
skl
->
supend_active
--
;
}
int
skl_pcm_host_dma_prepare
(
struct
device
*
dev
,
struct
skl_pipe_params
*
params
)
{
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dev
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
unsigned
int
format_val
;
struct
hdac_stream
*
hstream
;
struct
hdac_ext_stream
*
stream
;
int
err
;
hstream
=
snd_hdac_get_stream
(
bus
,
params
->
stream
,
params
->
host_dma_id
+
1
);
if
(
!
hstream
)
return
-
EINVAL
;
stream
=
stream_to_hdac_ext_stream
(
hstream
);
snd_hdac_ext_stream_decouple
(
ebus
,
stream
,
true
);
format_val
=
snd_hdac_calc_stream_format
(
params
->
s_freq
,
params
->
ch
,
params
->
format
,
32
,
0
);
dev_dbg
(
dev
,
"format_val=%d, rate=%d, ch=%d, format=%d
\n
"
,
format_val
,
params
->
s_freq
,
params
->
ch
,
params
->
format
);
snd_hdac_stream_reset
(
hdac_stream
(
stream
));
err
=
snd_hdac_stream_set_params
(
hdac_stream
(
stream
),
format_val
);
if
(
err
<
0
)
return
err
;
err
=
snd_hdac_stream_setup
(
hdac_stream
(
stream
));
if
(
err
<
0
)
return
err
;
hdac_stream
(
stream
)
->
prepared
=
1
;
return
0
;
}
int
skl_pcm_link_dma_prepare
(
struct
device
*
dev
,
struct
skl_pipe_params
*
params
)
{
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dev
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
unsigned
int
format_val
;
struct
hdac_stream
*
hstream
;
struct
hdac_ext_stream
*
stream
;
struct
hdac_ext_link
*
link
;
hstream
=
snd_hdac_get_stream
(
bus
,
params
->
stream
,
params
->
link_dma_id
+
1
);
if
(
!
hstream
)
return
-
EINVAL
;
stream
=
stream_to_hdac_ext_stream
(
hstream
);
snd_hdac_ext_stream_decouple
(
ebus
,
stream
,
true
);
format_val
=
snd_hdac_calc_stream_format
(
params
->
s_freq
,
params
->
ch
,
params
->
format
,
24
,
0
);
dev_dbg
(
dev
,
"format_val=%d, rate=%d, ch=%d, format=%d
\n
"
,
format_val
,
params
->
s_freq
,
params
->
ch
,
params
->
format
);
snd_hdac_ext_link_stream_reset
(
stream
);
snd_hdac_ext_link_stream_setup
(
stream
,
format_val
);
list_for_each_entry
(
link
,
&
ebus
->
hlink_list
,
list
)
{
if
(
link
->
index
==
params
->
link_index
)
snd_hdac_ext_link_set_stream_id
(
link
,
hstream
->
stream_tag
);
}
stream
->
link_prepared
=
1
;
return
0
;
}
static
int
skl_pcm_open
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
...
...
@@ -188,32 +262,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
return
0
;
}
static
int
skl_get_format
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
snd_pcm_substream_chip
(
substream
);
struct
skl_dma_params
*
dma_params
;
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dai
->
dev
);
int
format_val
=
0
;
if
((
ebus_to_hbus
(
ebus
))
->
ppcap
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
format_val
=
snd_hdac_calc_stream_format
(
runtime
->
rate
,
runtime
->
channels
,
runtime
->
format
,
32
,
0
);
}
else
{
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
dma_params
=
snd_soc_dai_get_dma_data
(
codec_dai
,
substream
);
if
(
dma_params
)
format_val
=
dma_params
->
format
;
}
return
format_val
;
}
static
int
skl_be_prepare
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
...
...
@@ -234,37 +282,19 @@ static int skl_be_prepare(struct snd_pcm_substream *substream,
static
int
skl_pcm_prepare
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
hdac_ext_stream
*
stream
=
get_hdac_ext_stream
(
substream
);
struct
skl
*
skl
=
get_skl_ctx
(
dai
->
dev
);
unsigned
int
format_val
;
int
err
;
struct
skl_module_cfg
*
mconfig
;
dev_dbg
(
dai
->
dev
,
"%s: %s
\n
"
,
__func__
,
dai
->
name
);
mconfig
=
skl_tplg_fe_get_cpr_module
(
dai
,
substream
->
stream
);
format_val
=
skl_get_format
(
substream
,
dai
);
dev_dbg
(
dai
->
dev
,
"stream_tag=%d formatvalue=%d
\n
"
,
hdac_stream
(
stream
)
->
stream_tag
,
format_val
);
snd_hdac_stream_reset
(
hdac_stream
(
stream
));
/* In case of XRUN recovery, reset the FW pipe to clean state */
if
(
mconfig
&&
(
substream
->
runtime
->
status
->
state
==
SNDRV_PCM_STATE_XRUN
))
skl_reset_pipe
(
skl
->
skl_sst
,
mconfig
->
pipe
);
err
=
snd_hdac_stream_set_params
(
hdac_stream
(
stream
),
format_val
);
if
(
err
<
0
)
return
err
;
err
=
snd_hdac_stream_setup
(
hdac_stream
(
stream
));
if
(
err
<
0
)
return
err
;
hdac_stream
(
stream
)
->
prepared
=
1
;
return
err
;
return
0
;
}
static
int
skl_pcm_hw_params
(
struct
snd_pcm_substream
*
substream
,
...
...
@@ -295,6 +325,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
p_params
.
s_freq
=
params_rate
(
params
);
p_params
.
host_dma_id
=
dma_id
;
p_params
.
stream
=
substream
->
stream
;
p_params
.
format
=
params_format
(
params
);
m_cfg
=
skl_tplg_fe_get_cpr_module
(
dai
,
p_params
.
stream
);
if
(
m_cfg
)
...
...
@@ -438,7 +469,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_RESUME
:
if
(
!
w
->
ignore_suspend
)
{
skl_pcm_prepare
(
substream
,
dai
);
/*
* enable DMA Resume enable bit for the stream, set the
* dpib & lpib position to resume before starting the
...
...
@@ -447,7 +477,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
snd_hdac_ext_stream_drsm_enable
(
ebus
,
true
,
hdac_stream
(
stream
)
->
index
);
snd_hdac_ext_stream_set_dpibr
(
ebus
,
stream
,
stream
->
d
pib
);
stream
->
l
pib
);
snd_hdac_ext_stream_set_lpib
(
stream
,
stream
->
lpib
);
}
...
...
@@ -459,7 +489,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
* pipeline is started but there is a delay in starting the
* DMA channel on the host.
*/
snd_hdac_ext_stream_decouple
(
ebus
,
stream
,
true
);
ret
=
skl_decoupled_trigger
(
substream
,
cmd
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -506,9 +535,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dai
->
dev
);
struct
hdac_ext_stream
*
link_dev
;
struct
snd_soc_pcm_runtime
*
rtd
=
snd_pcm_substream_chip
(
substream
);
struct
hdac_ext_dma_params
*
dma_params
;
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
struct
skl_pipe_params
p_params
=
{
0
};
struct
hdac_ext_link
*
link
;
int
stream_tag
;
link_dev
=
snd_hdac_ext_stream_assign
(
ebus
,
substream
,
HDAC_EXT_STREAM_TYPE_LINK
);
...
...
@@ -517,16 +547,22 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data
(
dai
,
substream
,
(
void
*
)
link_dev
);
link
=
snd_hdac_ext_bus_get_link
(
ebus
,
rtd
->
codec
->
component
.
name
);
if
(
!
link
)
return
-
EINVAL
;
stream_tag
=
hdac_stream
(
link_dev
)
->
stream_tag
;
/* set the stream tag in the codec dai dma params */
dma_params
=
snd_soc_dai_get_dma_data
(
codec_dai
,
substream
);
if
(
dma_params
)
dma_params
->
stream_tag
=
hdac_stream
(
link_dev
)
->
stream_tag
;
snd_soc_dai_set_tdm_slot
(
codec_dai
,
stream_tag
,
0
,
0
,
0
);
p_params
.
s_fmt
=
snd_pcm_format_width
(
params_format
(
params
));
p_params
.
ch
=
params_channels
(
params
);
p_params
.
s_freq
=
params_rate
(
params
);
p_params
.
stream
=
substream
->
stream
;
p_params
.
link_dma_id
=
hdac_stream
(
link_dev
)
->
stream_tag
-
1
;
p_params
.
link_dma_id
=
stream_tag
-
1
;
p_params
.
link_index
=
link
->
index
;
p_params
.
format
=
params_format
(
params
);
return
skl_tplg_be_update_params
(
dai
,
&
p_params
);
}
...
...
@@ -534,41 +570,15 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
static
int
skl_link_pcm_prepare
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
snd_pcm_substream_chip
(
substream
);
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dai
->
dev
);
struct
hdac_ext_stream
*
link_dev
=
snd_soc_dai_get_dma_data
(
dai
,
substream
);
unsigned
int
format_val
=
0
;
struct
skl_dma_params
*
dma_params
;
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
struct
hdac_ext_link
*
link
;
struct
skl
*
skl
=
get_skl_ctx
(
dai
->
dev
);
struct
skl_module_cfg
*
mconfig
=
NULL
;
dma_params
=
(
struct
skl_dma_params
*
)
snd_soc_dai_get_dma_data
(
codec_dai
,
substream
);
if
(
dma_params
)
format_val
=
dma_params
->
format
;
dev_dbg
(
dai
->
dev
,
"stream_tag=%d formatvalue=%d codec_dai_name=%s
\n
"
,
hdac_stream
(
link_dev
)
->
stream_tag
,
format_val
,
codec_dai
->
name
);
link
=
snd_hdac_ext_bus_get_link
(
ebus
,
rtd
->
codec
->
component
.
name
);
if
(
!
link
)
return
-
EINVAL
;
snd_hdac_ext_link_stream_reset
(
link_dev
);
/* In case of XRUN recovery, reset the FW pipe to clean state */
mconfig
=
skl_tplg_be_get_cpr_module
(
dai
,
substream
->
stream
);
if
(
mconfig
&&
(
substream
->
runtime
->
status
->
state
==
SNDRV_PCM_STATE_XRUN
))
if
(
mconfig
&&
!
mconfig
->
pipe
->
passthru
&&
(
substream
->
runtime
->
status
->
state
==
SNDRV_PCM_STATE_XRUN
))
skl_reset_pipe
(
skl
->
skl_sst
,
mconfig
->
pipe
);
snd_hdac_ext_link_stream_setup
(
link_dev
,
format_val
);
snd_hdac_ext_link_set_stream_id
(
link
,
hdac_stream
(
link_dev
)
->
stream_tag
);
link_dev
->
link_prepared
=
1
;
return
0
;
}
...
...
@@ -583,10 +593,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
dev_dbg
(
dai
->
dev
,
"In %s cmd=%d
\n
"
,
__func__
,
cmd
);
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_RESUME
:
skl_link_pcm_prepare
(
substream
,
dai
);
case
SNDRV_PCM_TRIGGER_START
:
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
snd_hdac_ext_stream_decouple
(
ebus
,
stream
,
true
);
snd_hdac_ext_link_stream_start
(
link_dev
);
break
;
...
...
sound/soc/intel/skylake/skl-sst-dsp.h
View file @
16b57114
...
...
@@ -19,7 +19,6 @@
#include <linux/interrupt.h>
#include <sound/memalloc.h>
#include "skl-sst-cldma.h"
#include "skl-tplg-interface.h"
#include "skl-topology.h"
struct
sst_dsp
;
...
...
@@ -145,7 +144,7 @@ struct skl_dsp_fw_ops {
int
(
*
load_fw
)(
struct
sst_dsp
*
ctx
);
/* FW module parser/loader */
int
(
*
load_library
)(
struct
sst_dsp
*
ctx
,
struct
skl_
dfw_manifest
*
minfo
);
struct
skl_
lib_info
*
linfo
,
int
count
);
int
(
*
parse_fw
)(
struct
sst_dsp
*
ctx
);
int
(
*
set_state_D0
)(
struct
sst_dsp
*
ctx
,
unsigned
int
core_id
);
int
(
*
set_state_D3
)(
struct
sst_dsp
*
ctx
,
unsigned
int
core_id
);
...
...
@@ -236,5 +235,4 @@ int skl_get_pvt_instance_id_map(struct skl_sst *ctx,
void
skl_freeup_uuid_list
(
struct
skl_sst
*
ctx
);
int
skl_dsp_strip_extended_manifest
(
struct
firmware
*
fw
);
#endif
/*__SKL_SST_DSP_H__*/
sound/soc/intel/skylake/skl-sst-ipc.h
View file @
16b57114
...
...
@@ -97,8 +97,9 @@ struct skl_sst {
/* multi-core */
struct
skl_dsp_cores
cores
;
/* tplg manifest */
struct
skl_dfw_manifest
manifest
;
/* library info */
struct
skl_lib_info
lib_info
[
SKL_MAX_LIB
];
int
lib_count
;
/* Callback to update D0i3C register */
void
(
*
update_d0i3c
)(
struct
device
*
dev
,
bool
enable
);
...
...
sound/soc/intel/skylake/skl-topology.c
View file @
16b57114
...
...
@@ -330,6 +330,31 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
multiplier
;
}
static
u8
skl_tplg_be_dev_type
(
int
dev_type
)
{
int
ret
;
switch
(
dev_type
)
{
case
SKL_DEVICE_BT
:
ret
=
NHLT_DEVICE_BT
;
break
;
case
SKL_DEVICE_DMIC
:
ret
=
NHLT_DEVICE_DMIC
;
break
;
case
SKL_DEVICE_I2S
:
ret
=
NHLT_DEVICE_I2S
;
break
;
default:
ret
=
NHLT_DEVICE_INVALID
;
break
;
}
return
ret
;
}
static
int
skl_tplg_update_be_blob
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl_sst
*
ctx
)
{
...
...
@@ -338,6 +363,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
u32
ch
,
s_freq
,
s_fmt
;
struct
nhlt_specific_cfg
*
cfg
;
struct
skl
*
skl
=
get_skl_ctx
(
ctx
->
dev
);
u8
dev_type
=
skl_tplg_be_dev_type
(
m_cfg
->
dev_type
);
/* check if we already have blob */
if
(
m_cfg
->
formats_config
.
caps_size
>
0
)
...
...
@@ -374,7 +400,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
/* update the blob based on virtual bus_id and default params */
cfg
=
skl_get_ep_blob
(
skl
,
m_cfg
->
vbus_id
,
link_type
,
s_fmt
,
ch
,
s_freq
,
dir
);
s_fmt
,
ch
,
s_freq
,
dir
,
dev_type
);
if
(
cfg
)
{
m_cfg
->
formats_config
.
caps_size
=
cfg
->
size
;
m_cfg
->
formats_config
.
caps
=
(
u32
*
)
&
cfg
->
caps
;
...
...
@@ -496,6 +522,20 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
return
0
;
}
static
int
skl_tplg_module_prepare
(
struct
skl_sst
*
ctx
,
struct
skl_pipe
*
pipe
,
struct
snd_soc_dapm_widget
*
w
,
struct
skl_module_cfg
*
mcfg
)
{
switch
(
mcfg
->
dev_type
)
{
case
SKL_DEVICE_HDAHOST
:
return
skl_pcm_host_dma_prepare
(
ctx
->
dev
,
pipe
->
p_params
);
case
SKL_DEVICE_HDALINK
:
return
skl_pcm_link_dma_prepare
(
ctx
->
dev
,
pipe
->
p_params
);
}
return
0
;
}
/*
* Inside a pipe instance, we can have various modules. These modules need
* to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
...
...
@@ -535,6 +575,11 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
mconfig
->
m_state
=
SKL_MODULE_LOADED
;
}
/* prepare the DMA if the module is gateway cpr */
ret
=
skl_tplg_module_prepare
(
ctx
,
pipe
,
w
,
mconfig
);
if
(
ret
<
0
)
return
ret
;
/* update blob if blob is null for be with default value */
skl_tplg_update_be_blob
(
w
,
ctx
);
...
...
@@ -974,7 +1019,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
struct
skl_module_cfg
*
src_module
=
NULL
,
*
dst_module
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
struct
skl_pipe
*
s_pipe
=
mconfig
->
pipe
;
int
ret
=
0
;
if
(
s_pipe
->
state
==
SKL_PIPE_INVALID
)
return
-
EINVAL
;
...
...
@@ -996,7 +1040,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
src_module
=
dst_module
;
}
ret
=
skl_delete_pipe
(
ctx
,
mconfig
->
pipe
);
skl_delete_pipe
(
ctx
,
mconfig
->
pipe
);
return
skl_tplg_unload_pipe_modules
(
ctx
,
s_pipe
);
}
...
...
@@ -1207,6 +1251,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
switch
(
mcfg
->
dev_type
)
{
case
SKL_DEVICE_HDALINK
:
pipe
->
p_params
->
link_dma_id
=
params
->
link_dma_id
;
pipe
->
p_params
->
link_index
=
params
->
link_index
;
break
;
case
SKL_DEVICE_HDAHOST
:
...
...
@@ -1220,6 +1265,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
pipe
->
p_params
->
ch
=
params
->
ch
;
pipe
->
p_params
->
s_freq
=
params
->
s_freq
;
pipe
->
p_params
->
stream
=
params
->
stream
;
pipe
->
p_params
->
format
=
params
->
format
;
}
else
{
memcpy
(
pipe
->
p_params
,
params
,
sizeof
(
*
params
));
...
...
@@ -1428,6 +1474,7 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
struct
nhlt_specific_cfg
*
cfg
;
struct
skl
*
skl
=
get_skl_ctx
(
dai
->
dev
);
int
link_type
=
skl_tplg_be_link_type
(
mconfig
->
dev_type
);
u8
dev_type
=
skl_tplg_be_dev_type
(
mconfig
->
dev_type
);
skl_tplg_fill_dma_id
(
mconfig
,
params
);
...
...
@@ -1437,7 +1484,8 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
/* update the blob based on virtual bus_id*/
cfg
=
skl_get_ep_blob
(
skl
,
mconfig
->
vbus_id
,
link_type
,
params
->
s_fmt
,
params
->
ch
,
params
->
s_freq
,
params
->
stream
);
params
->
s_freq
,
params
->
stream
,
dev_type
);
if
(
cfg
)
{
mconfig
->
formats_config
.
caps_size
=
cfg
->
size
;
mconfig
->
formats_config
.
caps
=
(
u32
*
)
&
cfg
->
caps
;
...
...
@@ -2280,20 +2328,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
static
int
skl_tplg_fill_str_mfest_tkn
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_string_elem
*
str_elem
,
struct
skl
_dfw_manifest
*
minfo
)
struct
skl
*
skl
)
{
int
tkn_count
=
0
;
static
int
ref_count
;
switch
(
str_elem
->
token
)
{
case
SKL_TKN_STR_LIB_NAME
:
if
(
ref_count
>
minfo
->
lib_count
-
1
)
{
if
(
ref_count
>
skl
->
skl_sst
->
lib_count
-
1
)
{
ref_count
=
0
;
return
-
EINVAL
;
}
strncpy
(
minfo
->
lib
[
ref_count
].
name
,
str_elem
->
string
,
ARRAY_SIZE
(
minfo
->
lib
[
ref_count
].
name
));
strncpy
(
skl
->
skl_sst
->
lib_info
[
ref_count
].
name
,
str_elem
->
string
,
ARRAY_SIZE
(
skl
->
skl_sst
->
lib_info
[
ref_count
].
name
));
ref_count
++
;
tkn_count
++
;
break
;
...
...
@@ -2308,14 +2357,14 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
static
int
skl_tplg_get_str_tkn
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_array
*
array
,
struct
skl
_dfw_manifest
*
minfo
)
struct
skl
*
skl
)
{
int
tkn_count
=
0
,
ret
;
struct
snd_soc_tplg_vendor_string_elem
*
str_elem
;
str_elem
=
(
struct
snd_soc_tplg_vendor_string_elem
*
)
array
->
value
;
while
(
tkn_count
<
array
->
num_elems
)
{
ret
=
skl_tplg_fill_str_mfest_tkn
(
dev
,
str_elem
,
minfo
);
ret
=
skl_tplg_fill_str_mfest_tkn
(
dev
,
str_elem
,
skl
);
str_elem
++
;
if
(
ret
<
0
)
...
...
@@ -2329,13 +2378,13 @@ static int skl_tplg_get_str_tkn(struct device *dev,
static
int
skl_tplg_get_int_tkn
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
,
struct
skl
_dfw_manifest
*
minfo
)
struct
skl
*
skl
)
{
int
tkn_count
=
0
;
switch
(
tkn_elem
->
token
)
{
case
SKL_TKN_U32_LIB_COUNT
:
minfo
->
lib_count
=
tkn_elem
->
value
;
skl
->
skl_sst
->
lib_count
=
tkn_elem
->
value
;
tkn_count
++
;
break
;
...
...
@@ -2352,7 +2401,7 @@ static int skl_tplg_get_int_tkn(struct device *dev,
* type.
*/
static
int
skl_tplg_get_manifest_tkn
(
struct
device
*
dev
,
char
*
pvt_data
,
struct
skl
_dfw_manifest
*
minfo
,
char
*
pvt_data
,
struct
skl
*
skl
,
int
block_size
)
{
int
tkn_count
=
0
,
ret
;
...
...
@@ -2368,7 +2417,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
off
+=
array
->
size
;
switch
(
array
->
type
)
{
case
SND_SOC_TPLG_TUPLE_TYPE_STRING
:
ret
=
skl_tplg_get_str_tkn
(
dev
,
array
,
minfo
);
ret
=
skl_tplg_get_str_tkn
(
dev
,
array
,
skl
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -2390,7 +2439,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
while
(
tkn_count
<=
array
->
num_elems
-
1
)
{
ret
=
skl_tplg_get_int_tkn
(
dev
,
tkn_elem
,
minfo
);
tkn_elem
,
skl
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -2411,7 +2460,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
* preceded by descriptors for type and size of data block.
*/
static
int
skl_tplg_get_manifest_data
(
struct
snd_soc_tplg_manifest
*
manifest
,
struct
device
*
dev
,
struct
skl
_dfw_manifest
*
minfo
)
struct
device
*
dev
,
struct
skl
*
skl
)
{
struct
snd_soc_tplg_vendor_array
*
array
;
int
num_blocks
,
block_size
=
0
,
block_type
,
off
=
0
;
...
...
@@ -2454,7 +2503,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
data
=
(
manifest
->
priv
.
data
+
off
);
if
(
block_type
==
SKL_TYPE_TUPLE
)
{
ret
=
skl_tplg_get_manifest_tkn
(
dev
,
data
,
minfo
,
ret
=
skl_tplg_get_manifest_tkn
(
dev
,
data
,
skl
,
block_size
);
if
(
ret
<
0
)
...
...
@@ -2472,27 +2521,23 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
static
int
skl_manifest_load
(
struct
snd_soc_component
*
cmpnt
,
struct
snd_soc_tplg_manifest
*
manifest
)
{
struct
skl_dfw_manifest
*
minfo
;
struct
hdac_ext_bus
*
ebus
=
snd_soc_component_get_drvdata
(
cmpnt
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
int
ret
=
0
;
/* proceed only if we have private data defined */
if
(
manifest
->
priv
.
size
==
0
)
return
0
;
minfo
=
&
skl
->
skl_sst
->
manifest
;
skl_tplg_get_manifest_data
(
manifest
,
bus
->
dev
,
minfo
);
skl_tplg_get_manifest_data
(
manifest
,
bus
->
dev
,
skl
);
if
(
minfo
->
lib_count
>
HDA
_MAX_LIB
)
{
if
(
skl
->
skl_sst
->
lib_count
>
SKL
_MAX_LIB
)
{
dev_err
(
bus
->
dev
,
"Exceeding max Library count. Got:%d
\n
"
,
minfo
->
lib_count
);
ret
=
-
EINVAL
;
skl
->
skl_sst
->
lib_count
);
ret
urn
-
EINVAL
;
}
return
ret
;
return
0
;
}
static
struct
snd_soc_tplg_ops
skl_tplg_ops
=
{
...
...
sound/soc/intel/skylake/skl-topology.h
View file @
16b57114
...
...
@@ -254,6 +254,8 @@ struct skl_pipe_params {
u32
s_freq
;
u32
s_fmt
;
u8
linktype
;
snd_pcm_format_t
format
;
int
link_index
;
int
stream
;
};
...
...
@@ -332,6 +334,19 @@ struct skl_pipeline {
struct
list_head
node
;
};
#define SKL_LIB_NAME_LENGTH 128
#define SKL_MAX_LIB 16
struct
skl_lib_info
{
char
name
[
SKL_LIB_NAME_LENGTH
];
const
struct
firmware
*
fw
;
};
struct
skl_manifest
{
u32
lib_count
;
struct
skl_lib_info
lib
[
SKL_MAX_LIB
];
};
static
inline
struct
skl
*
get_skl_ctx
(
struct
device
*
dev
)
{
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dev
);
...
...
@@ -383,4 +398,8 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
struct
skl_module_cfg
*
skl_tplg_be_get_cpr_module
(
struct
snd_soc_dai
*
dai
,
int
stream
);
enum
skl_bitdepth
skl_get_bit_depth
(
int
params
);
int
skl_pcm_host_dma_prepare
(
struct
device
*
dev
,
struct
skl_pipe_params
*
params
);
int
skl_pcm_link_dma_prepare
(
struct
device
*
dev
,
struct
skl_pipe_params
*
params
);
#endif
sound/soc/intel/skylake/skl-tplg-interface.h
View file @
16b57114
...
...
@@ -157,18 +157,6 @@ struct skl_dfw_algo_data {
char
params
[
0
];
}
__packed
;
#define LIB_NAME_LENGTH 128
#define HDA_MAX_LIB 16
struct
lib_info
{
char
name
[
LIB_NAME_LENGTH
];
}
__packed
;
struct
skl_dfw_manifest
{
u32
lib_count
;
struct
lib_info
lib
[
HDA_MAX_LIB
];
}
__packed
;
enum
skl_tkn_dir
{
SKL_DIR_IN
,
SKL_DIR_OUT
...
...
sound/soc/intel/skylake/skl.c
View file @
16b57114
...
...
@@ -732,6 +732,10 @@ static int skl_probe(struct pci_dev *pci,
goto
out_display_power_off
;
}
err
=
skl_nhlt_create_sysfs
(
skl
);
if
(
err
<
0
)
goto
out_nhlt_free
;
skl_nhlt_update_topology_bin
(
skl
);
pci_set_drvdata
(
skl
->
pci
,
ebus
);
...
...
@@ -852,6 +856,7 @@ static void skl_remove(struct pci_dev *pci)
skl_free_dsp
(
skl
);
skl_machine_device_unregister
(
skl
);
skl_dmic_device_unregister
(
skl
);
skl_nhlt_remove_sysfs
(
skl
);
skl_nhlt_free
(
skl
->
nhlt
);
skl_free
(
ebus
);
dev_set_drvdata
(
&
pci
->
dev
,
NULL
);
...
...
@@ -878,6 +883,10 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
{}
};
static
struct
sst_acpi_mach
sst_glk_devdata
[]
=
{
{
"INT343A"
,
"glk_alc298s_i2s"
,
"intel/dsp_fw_glk.bin"
,
NULL
,
NULL
,
NULL
},
};
/* PCI IDs */
static
const
struct
pci_device_id
skl_ids
[]
=
{
/* Sunrise Point-LP */
...
...
@@ -889,6 +898,9 @@ static const struct pci_device_id skl_ids[] = {
/* KBL */
{
PCI_DEVICE
(
0x8086
,
0x9D71
),
.
driver_data
=
(
unsigned
long
)
&
sst_kbl_devdata
},
/* GLK */
{
PCI_DEVICE
(
0x8086
,
0x3198
),
.
driver_data
=
(
unsigned
long
)
&
sst_glk_devdata
},
{
0
,
}
};
MODULE_DEVICE_TABLE
(
pci
,
skl_ids
);
...
...
sound/soc/intel/skylake/skl.h
View file @
16b57114
...
...
@@ -118,7 +118,8 @@ int skl_platform_register(struct device *dev);
struct
nhlt_acpi_table
*
skl_nhlt_init
(
struct
device
*
dev
);
void
skl_nhlt_free
(
struct
nhlt_acpi_table
*
addr
);
struct
nhlt_specific_cfg
*
skl_get_ep_blob
(
struct
skl
*
skl
,
u32
instance
,
u8
link_type
,
u8
s_fmt
,
u8
no_ch
,
u32
s_rate
,
u8
dirn
);
u8
link_type
,
u8
s_fmt
,
u8
no_ch
,
u32
s_rate
,
u8
dirn
,
u8
dev_type
);
int
skl_get_dmic_geo
(
struct
skl
*
skl
);
int
skl_nhlt_update_topology_bin
(
struct
skl
*
skl
);
...
...
@@ -130,5 +131,7 @@ int skl_resume_dsp(struct skl *skl);
void
skl_cleanup_resources
(
struct
skl
*
skl
);
const
struct
skl_dsp_ops
*
skl_get_dsp_ops
(
int
pci_id
);
void
skl_update_d0i3c
(
struct
device
*
dev
,
bool
enable
);
int
skl_nhlt_create_sysfs
(
struct
skl
*
skl
);
void
skl_nhlt_remove_sysfs
(
struct
skl
*
skl
);
#endif
/* __SOUND_SOC_SKL_H */
sound/soc/soc-core.c
View file @
16b57114
...
...
@@ -34,6 +34,7 @@
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/dmi.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
...
...
@@ -1888,6 +1889,139 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
}
EXPORT_SYMBOL_GPL
(
snd_soc_runtime_set_dai_fmt
);
/* Trim special characters, and replace '-' with '_' since '-' is used to
* separate different DMI fields in the card long name. Only number and
* alphabet characters and a few separator characters are kept.
*/
static
void
cleanup_dmi_name
(
char
*
name
)
{
int
i
,
j
=
0
;
for
(
i
=
0
;
name
[
i
];
i
++
)
{
if
(
isalnum
(
name
[
i
])
||
(
name
[
i
]
==
'.'
)
||
(
name
[
i
]
==
'_'
))
name
[
j
++
]
=
name
[
i
];
else
if
(
name
[
i
]
==
'-'
)
name
[
j
++
]
=
'_'
;
}
name
[
j
]
=
'\0'
;
}
/**
* snd_soc_set_dmi_name() - Register DMI names to card
* @card: The card to register DMI names
* @flavour: The flavour "differentiator" for the card amongst its peers.
*
* An Intel machine driver may be used by many different devices but are
* difficult for userspace to differentiate, since machine drivers ususally
* use their own name as the card short name and leave the card long name
* blank. To differentiate such devices and fix bugs due to lack of
* device-specific configurations, this function allows DMI info to be used
* as the sound card long name, in the format of
* "vendor-product-version-board"
* (Character '-' is used to separate different DMI fields here).
* This will help the user space to load the device-specific Use Case Manager
* (UCM) configurations for the card.
*
* Possible card long names may be:
* DellInc.-XPS139343-01-0310JH
* ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
* Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
*
* This function also supports flavoring the card longname to provide
* the extra differentiation, like "vendor-product-version-board-flavor".
*
* We only keep number and alphabet characters and a few separator characters
* in the card long name since UCM in the user space uses the card long names
* as card configuration directory names and AudoConf cannot support special
* charactors like SPACE.
*
* Returns 0 on success, otherwise a negative error code.
*/
int
snd_soc_set_dmi_name
(
struct
snd_soc_card
*
card
,
const
char
*
flavour
)
{
const
char
*
vendor
,
*
product
,
*
product_version
,
*
board
;
size_t
longname_buf_size
=
sizeof
(
card
->
snd_card
->
longname
);
size_t
len
;
if
(
card
->
long_name
)
return
0
;
/* long name already set by driver or from DMI */
/* make up dmi long name as: vendor.product.version.board */
vendor
=
dmi_get_system_info
(
DMI_BOARD_VENDOR
);
if
(
!
vendor
)
{
dev_warn
(
card
->
dev
,
"ASoC: no DMI vendor name!
\n
"
);
return
0
;
}
snprintf
(
card
->
dmi_longname
,
sizeof
(
card
->
snd_card
->
longname
),
"%s"
,
vendor
);
cleanup_dmi_name
(
card
->
dmi_longname
);
product
=
dmi_get_system_info
(
DMI_PRODUCT_NAME
);
if
(
product
)
{
len
=
strlen
(
card
->
dmi_longname
);
snprintf
(
card
->
dmi_longname
+
len
,
longname_buf_size
-
len
,
"-%s"
,
product
);
len
++
;
/* skip the separator "-" */
if
(
len
<
longname_buf_size
)
cleanup_dmi_name
(
card
->
dmi_longname
+
len
);
/* some vendors like Lenovo may only put a self-explanatory
* name in the product version field
*/
product_version
=
dmi_get_system_info
(
DMI_PRODUCT_VERSION
);
if
(
product_version
)
{
len
=
strlen
(
card
->
dmi_longname
);
snprintf
(
card
->
dmi_longname
+
len
,
longname_buf_size
-
len
,
"-%s"
,
product_version
);
len
++
;
if
(
len
<
longname_buf_size
)
cleanup_dmi_name
(
card
->
dmi_longname
+
len
);
}
}
board
=
dmi_get_system_info
(
DMI_BOARD_NAME
);
if
(
board
)
{
len
=
strlen
(
card
->
dmi_longname
);
snprintf
(
card
->
dmi_longname
+
len
,
longname_buf_size
-
len
,
"-%s"
,
board
);
len
++
;
if
(
len
<
longname_buf_size
)
cleanup_dmi_name
(
card
->
dmi_longname
+
len
);
}
else
if
(
!
product
)
{
/* fall back to using legacy name */
dev_warn
(
card
->
dev
,
"ASoC: no DMI board/product name!
\n
"
);
return
0
;
}
/* Add flavour to dmi long name */
if
(
flavour
)
{
len
=
strlen
(
card
->
dmi_longname
);
snprintf
(
card
->
dmi_longname
+
len
,
longname_buf_size
-
len
,
"-%s"
,
flavour
);
len
++
;
if
(
len
<
longname_buf_size
)
cleanup_dmi_name
(
card
->
dmi_longname
+
len
);
}
/* set the card long name */
card
->
long_name
=
card
->
dmi_longname
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_set_dmi_name
);
static
int
snd_soc_instantiate_card
(
struct
snd_soc_card
*
card
)
{
struct
snd_soc_codec
*
codec
;
...
...
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