Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
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
Hide 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
;
dev_dbg
(
&
hdac
->
hdac
.
dev
,
"num_mux_nids %d for pin: %d
\n
"
,
pin
->
num_mux_nids
,
pin
->
nid
);
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:port %d:%d
\n
"
,
port
->
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
(
pin
)
{
ret
=
hdac_hdmi_query_pin_connlist
(
edev
,
pin
);
if
(
ret
<
0
)
return
NULL
;
for
(
i
=
0
;
i
<
pin
->
num_mux_nids
;
i
++
)
{
if
(
pin
->
mux_nids
[
i
]
==
cvt
->
nid
)
return
pin
;
if
(
list_empty
(
&
pcm
->
port_list
))
continue
;
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
)
continue
;
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
);
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
);
pcm
=
hdac_hdmi_get_pcm_from_cvt
(
hdmi
,
dai_map
->
cvt
);
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
)
return
pcm
;
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,26 +867,35 @@ 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
;
/*
* 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
);
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
);
}
}
}
snd_jack_report
(
pcm
->
jack
,
SND_JACK_AVOUT
);
/*
* Jack status is not reported during device probe as the
* PCMs are not registered by then. So report it here.
*/
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
;
}
}
mutex_unlock
(
&
hdmi
->
pin_mutex
);
...
...
@@ -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,14 +1032,14 @@ 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
)),
GFP_KERNEL
);
widgets
=
devm_kzalloc
(
dapm
->
dev
,
(
sizeof
(
*
widgets
)
*
((
2
*
hdmi
->
num_ports
)
+
hdmi
->
num_cvt
)),
GFP_KERNEL
);
if
(
!
widgets
)
return
-
ENOMEM
;
...
...
@@ -949,37 +1048,50 @@ 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
);
ret
=
hdac_hdmi_fill_widget_info
(
dapm
->
dev
,
&
widgets
[
i
],
snd_soc_dapm_output
,
&
pin
->
nid
,
widget_name
,
NULL
,
NULL
,
0
);
if
(
ret
<
0
)
return
ret
;
i
++
;
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
->
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
],
widget_name
);
if
(
ret
<
0
)
return
ret
;
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
;
i
++
;
/* For cvt to pin_mux mapping */
num_routes
+=
hdmi
->
num_cvt
;
/* For cvt to pin_mux mapping */
num_routes
+=
hdmi
->
num_cvt
;
/* For pin_mux to pin mapping */
num_routes
++
;
/* For pin_mux to pin mapping */
num_routes
++
;
}
}
route
=
devm_kzalloc
(
dapm
->
dev
,
(
sizeof
(
*
route
)
*
num_routes
),
...
...
@@ -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
)
{
int
sink_index
=
i
+
hdmi
->
num_cvt
;
int
src_index
=
sink_index
+
hdmi
->
num_pin
;
for
(
j
=
0
;
j
<
pin
->
num_ports
;
j
++
)
{
int
sink_index
=
i
+
hdmi
->
num_cvt
;
int
src_index
=
sink_index
+
pin
->
num_ports
*
hdmi
->
num_pin
;
hdac_hdmi_fill_route
(
&
route
[
i
],
hdac_hdmi_fill_route
(
&
route
[
i
],
widgets
[
sink_index
].
name
,
NULL
,
widgets
[
src_index
].
name
,
NULL
);
i
++
;
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
;
}
pcm
=
hdac_hdmi_get_pcm
(
edev
,
pin
);
if
(
size
>
0
)
{
port
->
eld
.
eld_valid
=
true
;
port
->
eld
.
eld_size
=
size
;
}
else
{
port
->
eld
.
eld_valid
=
false
;
port
->
eld
.
eld_size
=
0
;
}
if
(
!
pin
->
eld
.
monitor_present
||
!
pin
->
eld
.
eld_valid
)
{
pcm
=
hdac_hdmi_get_pcm
(
edev
,
port
);
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: disconnect for pin %d
\n
"
,
__func__
,
pin
->
nid
);
if
(
!
port
->
eld
.
monitor_present
||
!
port
->
eld
.
eld_valid
)
{
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
;
return
;
}
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
(
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
);
snd_jack_report
(
pcm
->
jack
,
SND_JACK_AVOUT
);
}
hdac_hdmi_parse_eld
(
edev
,
pin
);
print_hex_dump_debug
(
"ELD: "
,
DUMP_PREFIX_OFFSET
,
16
,
1
,
port
->
eld
.
eld_buffer
,
port
->
eld
.
eld_size
,
false
);
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
(
pcm
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
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
,
p
in
->
chmap
,
ARRAY_SIZE
(
pin
->
chmap
));
memcpy
(
chmap
,
p
cm
->
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
;
mutex_lock
(
&
pin
->
lock
);
pin
->
chmap_set
=
true
;
memcpy
(
pin
->
chmap
,
chmap
,
ARRAY_SIZE
(
pin
->
chmap
));
if
(
prepared
)
hdac_hdmi_setup_audio_infoframe
(
edev
,
pcm
->
cvt
->
nid
,
pin
->
nid
);
mutex_unlock
(
&
pin
->
lock
);
struct
hdac_hdmi_port
*
port
;
if
(
list_empty
(
&
pcm
->
port_list
))
return
;
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
,
port
);
mutex_unlock
(
&
pcm
->
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,19 +100,30 @@ 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 when codec is
* runtime suspended. Codec needs clock for jack detection and button
* press. MCLK is turned off with clock framework or ACPI.
*/
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
RT5645_SCLK_S_RCCLK
,
48000
*
512
,
SND_SOC_CLOCK_IN
);
if
(
ret
<
0
)
{
dev_err
(
card
->
dev
,
"can't set codec sysclk: %d
\n
"
,
ret
);
return
ret
;
}
/* 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
* runtime suspended. Codec needs clock for jack detection and button
* press.
*/
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
RT5645_SCLK_S_RCCLK
,
0
,
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,28 +243,65 @@ 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
);
/* Select clk_i2s1_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_I2S1_ASRC
);
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
|
RT5645_DA_MONO_L_FILTER
|
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
;
/* set SSP2 to 24-bit */
params_set_format
(
params
,
SNDRV_PCM_FORMAT_S24_LE
);
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
);
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