Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
a067c035
cloud-kernel
项目概览
openanolis
/
cloud-kernel
大约 2 年 前同步成功
通知
173
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
a067c035
编写于
7月 15, 2013
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-3.12' into for-next
上级
ad81f054
97c4de8f
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
783 addition
and
4648 deletion
+783
-4648
sound/firewire/speakers.c
sound/firewire/speakers.c
+1
-3
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_analog.c
+244
-4418
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/hdspm.c
+538
-227
未找到文件。
sound/firewire/speakers.c
浏览文件 @
a067c035
...
@@ -49,7 +49,6 @@ struct fwspk {
...
@@ -49,7 +49,6 @@ struct fwspk {
struct
snd_card
*
card
;
struct
snd_card
*
card
;
struct
fw_unit
*
unit
;
struct
fw_unit
*
unit
;
const
struct
device_info
*
device_info
;
const
struct
device_info
*
device_info
;
struct
snd_pcm_substream
*
pcm
;
struct
mutex
mutex
;
struct
mutex
mutex
;
struct
cmp_connection
connection
;
struct
cmp_connection
connection
;
struct
amdtp_out_stream
stream
;
struct
amdtp_out_stream
stream
;
...
@@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk)
...
@@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk)
return
err
;
return
err
;
pcm
->
private_data
=
fwspk
;
pcm
->
private_data
=
fwspk
;
strcpy
(
pcm
->
name
,
fwspk
->
device_info
->
short_name
);
strcpy
(
pcm
->
name
,
fwspk
->
device_info
->
short_name
);
fwspk
->
pcm
=
pcm
->
streams
[
SNDRV_PCM_STREAM_PLAYBACK
].
substream
;
snd_pcm_set_ops
(
pcm
,
SNDRV_PCM_STREAM_PLAYBACK
,
&
ops
);
fwspk
->
pcm
->
ops
=
&
ops
;
return
0
;
return
0
;
}
}
...
...
sound/pci/hda/patch_analog.c
浏览文件 @
a067c035
...
@@ -32,7 +32,6 @@
...
@@ -32,7 +32,6 @@
#include "hda_jack.h"
#include "hda_jack.h"
#include "hda_generic.h"
#include "hda_generic.h"
#define ENABLE_AD_STATIC_QUIRKS
struct
ad198x_spec
{
struct
ad198x_spec
{
struct
hda_gen_spec
gen
;
struct
hda_gen_spec
gen
;
...
@@ -43,114 +42,8 @@ struct ad198x_spec {
...
@@ -43,114 +42,8 @@ struct ad198x_spec {
hda_nid_t
eapd_nid
;
hda_nid_t
eapd_nid
;
unsigned
int
beep_amp
;
/* beep amp value, set via set_beep_amp() */
unsigned
int
beep_amp
;
/* beep amp value, set via set_beep_amp() */
#ifdef ENABLE_AD_STATIC_QUIRKS
const
struct
snd_kcontrol_new
*
mixers
[
6
];
int
num_mixers
;
const
struct
hda_verb
*
init_verbs
[
6
];
/* initialization verbs
* don't forget NULL termination!
*/
unsigned
int
num_init_verbs
;
/* playback */
struct
hda_multi_out
multiout
;
/* playback set-up
* max_channels, dacs must be set
* dig_out_nid and hp_nid are optional
*/
unsigned
int
cur_eapd
;
unsigned
int
need_dac_fix
;
/* capture */
unsigned
int
num_adc_nids
;
const
hda_nid_t
*
adc_nids
;
hda_nid_t
dig_in_nid
;
/* digital-in NID; optional */
/* capture source */
const
struct
hda_input_mux
*
input_mux
;
const
hda_nid_t
*
capsrc_nids
;
unsigned
int
cur_mux
[
3
];
/* channel model */
const
struct
hda_channel_mode
*
channel_mode
;
int
num_channel_mode
;
/* PCM information */
struct
hda_pcm
pcm_rec
[
3
];
/* used in alc_build_pcms() */
unsigned
int
spdif_route
;
unsigned
int
jack_present
:
1
;
unsigned
int
inv_jack_detect
:
1
;
/* inverted jack-detection */
unsigned
int
analog_beep
:
1
;
/* analog beep input present */
unsigned
int
avoid_init_slave_vol
:
1
;
#ifdef CONFIG_PM
struct
hda_loopback_check
loopback
;
#endif
/* for virtual master */
hda_nid_t
vmaster_nid
;
const
char
*
const
*
slave_vols
;
const
char
*
const
*
slave_sws
;
#endif
/* ENABLE_AD_STATIC_QUIRKS */
};
#ifdef ENABLE_AD_STATIC_QUIRKS
/*
* input MUX handling (common part)
*/
static
int
ad198x_mux_enum_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_input_mux_info
(
spec
->
input_mux
,
uinfo
);
}
static
int
ad198x_mux_enum_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
unsigned
int
adc_idx
=
snd_ctl_get_ioffidx
(
kcontrol
,
&
ucontrol
->
id
);
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
spec
->
cur_mux
[
adc_idx
];
return
0
;
}
static
int
ad198x_mux_enum_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
unsigned
int
adc_idx
=
snd_ctl_get_ioffidx
(
kcontrol
,
&
ucontrol
->
id
);
return
snd_hda_input_mux_put
(
codec
,
spec
->
input_mux
,
ucontrol
,
spec
->
capsrc_nids
[
adc_idx
],
&
spec
->
cur_mux
[
adc_idx
]);
}
/*
* initialization (common callbacks)
*/
static
int
ad198x_init
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
int
i
;
for
(
i
=
0
;
i
<
spec
->
num_init_verbs
;
i
++
)
snd_hda_sequence_write
(
codec
,
spec
->
init_verbs
[
i
]);
return
0
;
}
static
const
char
*
const
ad_slave_pfxs
[]
=
{
"Front"
,
"Surround"
,
"Center"
,
"LFE"
,
"Side"
,
"Headphone"
,
"Mono"
,
"Speaker"
,
"IEC958"
,
NULL
};
};
static
const
char
*
const
ad1988_6stack_fp_slave_pfxs
[]
=
{
"Front"
,
"Surround"
,
"Center"
,
"LFE"
,
"Side"
,
"IEC958"
,
NULL
};
#endif
/* ENABLE_AD_STATIC_QUIRKS */
#ifdef CONFIG_SND_HDA_INPUT_BEEP
#ifdef CONFIG_SND_HDA_INPUT_BEEP
/* additional beep mixers; the actual parameters are overwritten at build */
/* additional beep mixers; the actual parameters are overwritten at build */
...
@@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = {
...
@@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = {
{
}
/* end */
{
}
/* end */
};
};
static
const
struct
snd_kcontrol_new
ad_beep2_mixer
[]
=
{
HDA_CODEC_VOLUME
(
"Digital Beep Playback Volume"
,
0
,
0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_BEEP
(
"Digital Beep Playback Switch"
,
0
,
0
,
HDA_OUTPUT
),
{
}
/* end */
};
#define set_beep_amp(spec, nid, idx, dir) \
#define set_beep_amp(spec, nid, idx, dir) \
((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
/* mono */
((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
/* mono */
#else
#else
...
@@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec)
...
@@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec)
if
(
!
spec
->
beep_amp
)
if
(
!
spec
->
beep_amp
)
return
0
;
return
0
;
knew
=
spec
->
analog_beep
?
ad_beep2_mixer
:
ad_beep_mixer
;
for
(
knew
=
ad_beep_mixer
;
knew
->
name
;
knew
++
)
{
for
(
;
knew
->
name
;
knew
++
)
{
int
err
;
int
err
;
struct
snd_kcontrol
*
kctl
;
struct
snd_kcontrol
*
kctl
;
kctl
=
snd_ctl_new1
(
knew
,
codec
);
kctl
=
snd_ctl_new1
(
knew
,
codec
);
...
@@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec)
...
@@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec)
#define create_beep_ctls(codec) 0
#define create_beep_ctls(codec) 0
#endif
#endif
#ifdef ENABLE_AD_STATIC_QUIRKS
static
int
ad198x_build_controls
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
struct
snd_kcontrol
*
kctl
;
unsigned
int
i
;
int
err
;
for
(
i
=
0
;
i
<
spec
->
num_mixers
;
i
++
)
{
err
=
snd_hda_add_new_ctls
(
codec
,
spec
->
mixers
[
i
]);
if
(
err
<
0
)
return
err
;
}
if
(
spec
->
multiout
.
dig_out_nid
)
{
err
=
snd_hda_create_spdif_out_ctls
(
codec
,
spec
->
multiout
.
dig_out_nid
,
spec
->
multiout
.
dig_out_nid
);
if
(
err
<
0
)
return
err
;
err
=
snd_hda_create_spdif_share_sw
(
codec
,
&
spec
->
multiout
);
if
(
err
<
0
)
return
err
;
spec
->
multiout
.
share_spdif
=
1
;
}
if
(
spec
->
dig_in_nid
)
{
err
=
snd_hda_create_spdif_in_ctls
(
codec
,
spec
->
dig_in_nid
);
if
(
err
<
0
)
return
err
;
}
/* create beep controls if needed */
err
=
create_beep_ctls
(
codec
);
if
(
err
<
0
)
return
err
;
/* if we have no master control, let's create it */
if
(
!
snd_hda_find_mixer_ctl
(
codec
,
"Master Playback Volume"
))
{
unsigned
int
vmaster_tlv
[
4
];
snd_hda_set_vmaster_tlv
(
codec
,
spec
->
vmaster_nid
,
HDA_OUTPUT
,
vmaster_tlv
);
err
=
__snd_hda_add_vmaster
(
codec
,
"Master Playback Volume"
,
vmaster_tlv
,
(
spec
->
slave_vols
?
spec
->
slave_vols
:
ad_slave_pfxs
),
"Playback Volume"
,
!
spec
->
avoid_init_slave_vol
,
NULL
);
if
(
err
<
0
)
return
err
;
}
if
(
!
snd_hda_find_mixer_ctl
(
codec
,
"Master Playback Switch"
))
{
err
=
snd_hda_add_vmaster
(
codec
,
"Master Playback Switch"
,
NULL
,
(
spec
->
slave_sws
?
spec
->
slave_sws
:
ad_slave_pfxs
),
"Playback Switch"
);
if
(
err
<
0
)
return
err
;
}
/* assign Capture Source enums to NID */
kctl
=
snd_hda_find_mixer_ctl
(
codec
,
"Capture Source"
);
if
(
!
kctl
)
kctl
=
snd_hda_find_mixer_ctl
(
codec
,
"Input Source"
);
for
(
i
=
0
;
kctl
&&
i
<
kctl
->
count
;
i
++
)
{
err
=
snd_hda_add_nid
(
codec
,
kctl
,
i
,
spec
->
capsrc_nids
[
i
]);
if
(
err
<
0
)
return
err
;
}
/* assign IEC958 enums to NID */
kctl
=
snd_hda_find_mixer_ctl
(
codec
,
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
);
if
(
kctl
)
{
err
=
snd_hda_add_nid
(
codec
,
kctl
,
0
,
spec
->
multiout
.
dig_out_nid
);
if
(
err
<
0
)
return
err
;
}
return
0
;
}
#ifdef CONFIG_PM
static
int
ad198x_check_power_status
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_check_amp_list_power
(
codec
,
&
spec
->
loopback
,
nid
);
}
#endif
/*
* Analog playback callbacks
*/
static
int
ad198x_playback_pcm_open
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_analog_open
(
codec
,
&
spec
->
multiout
,
substream
,
hinfo
);
}
static
int
ad198x_playback_pcm_prepare
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
unsigned
int
format
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_analog_prepare
(
codec
,
&
spec
->
multiout
,
stream_tag
,
format
,
substream
);
}
static
int
ad198x_playback_pcm_cleanup
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_analog_cleanup
(
codec
,
&
spec
->
multiout
);
}
/*
* Digital out
*/
static
int
ad198x_dig_playback_pcm_open
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_dig_open
(
codec
,
&
spec
->
multiout
);
}
static
int
ad198x_dig_playback_pcm_close
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_dig_close
(
codec
,
&
spec
->
multiout
);
}
static
int
ad198x_dig_playback_pcm_prepare
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
unsigned
int
format
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_dig_prepare
(
codec
,
&
spec
->
multiout
,
stream_tag
,
format
,
substream
);
}
static
int
ad198x_dig_playback_pcm_cleanup
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
return
snd_hda_multi_out_dig_cleanup
(
codec
,
&
spec
->
multiout
);
}
/*
* Analog capture
*/
static
int
ad198x_capture_pcm_prepare
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
unsigned
int
format
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
snd_hda_codec_setup_stream
(
codec
,
spec
->
adc_nids
[
substream
->
number
],
stream_tag
,
0
,
format
);
return
0
;
}
static
int
ad198x_capture_pcm_cleanup
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
snd_hda_codec_cleanup_stream
(
codec
,
spec
->
adc_nids
[
substream
->
number
]);
return
0
;
}
/*
*/
static
const
struct
hda_pcm_stream
ad198x_pcm_analog_playback
=
{
.
substreams
=
1
,
.
channels_min
=
2
,
.
channels_max
=
6
,
/* changed later */
.
nid
=
0
,
/* fill later */
.
ops
=
{
.
open
=
ad198x_playback_pcm_open
,
.
prepare
=
ad198x_playback_pcm_prepare
,
.
cleanup
=
ad198x_playback_pcm_cleanup
,
},
};
static
const
struct
hda_pcm_stream
ad198x_pcm_analog_capture
=
{
.
substreams
=
1
,
.
channels_min
=
2
,
.
channels_max
=
2
,
.
nid
=
0
,
/* fill later */
.
ops
=
{
.
prepare
=
ad198x_capture_pcm_prepare
,
.
cleanup
=
ad198x_capture_pcm_cleanup
},
};
static
const
struct
hda_pcm_stream
ad198x_pcm_digital_playback
=
{
.
substreams
=
1
,
.
channels_min
=
2
,
.
channels_max
=
2
,
.
nid
=
0
,
/* fill later */
.
ops
=
{
.
open
=
ad198x_dig_playback_pcm_open
,
.
close
=
ad198x_dig_playback_pcm_close
,
.
prepare
=
ad198x_dig_playback_pcm_prepare
,
.
cleanup
=
ad198x_dig_playback_pcm_cleanup
},
};
static
const
struct
hda_pcm_stream
ad198x_pcm_digital_capture
=
{
.
substreams
=
1
,
.
channels_min
=
2
,
.
channels_max
=
2
,
/* NID is set in alc_build_pcms */
};
static
int
ad198x_build_pcms
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
=
spec
->
pcm_rec
;
codec
->
num_pcms
=
1
;
codec
->
pcm_info
=
info
;
info
->
name
=
"AD198x Analog"
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
]
=
ad198x_pcm_analog_playback
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
].
channels_max
=
spec
->
multiout
.
max_channels
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
].
nid
=
spec
->
multiout
.
dac_nids
[
0
];
info
->
stream
[
SNDRV_PCM_STREAM_CAPTURE
]
=
ad198x_pcm_analog_capture
;
info
->
stream
[
SNDRV_PCM_STREAM_CAPTURE
].
substreams
=
spec
->
num_adc_nids
;
info
->
stream
[
SNDRV_PCM_STREAM_CAPTURE
].
nid
=
spec
->
adc_nids
[
0
];
if
(
spec
->
multiout
.
dig_out_nid
)
{
info
++
;
codec
->
num_pcms
++
;
codec
->
spdif_status_reset
=
1
;
info
->
name
=
"AD198x Digital"
;
info
->
pcm_type
=
HDA_PCM_TYPE_SPDIF
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
]
=
ad198x_pcm_digital_playback
;
info
->
stream
[
SNDRV_PCM_STREAM_PLAYBACK
].
nid
=
spec
->
multiout
.
dig_out_nid
;
if
(
spec
->
dig_in_nid
)
{
info
->
stream
[
SNDRV_PCM_STREAM_CAPTURE
]
=
ad198x_pcm_digital_capture
;
info
->
stream
[
SNDRV_PCM_STREAM_CAPTURE
].
nid
=
spec
->
dig_in_nid
;
}
}
return
0
;
}
#endif
/* ENABLE_AD_STATIC_QUIRKS */
static
void
ad198x_power_eapd_write
(
struct
hda_codec
*
codec
,
hda_nid_t
front
,
static
void
ad198x_power_eapd_write
(
struct
hda_codec
*
codec
,
hda_nid_t
front
,
hda_nid_t
hp
)
hda_nid_t
hp
)
...
@@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec)
...
@@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec)
ad198x_power_eapd
(
codec
);
ad198x_power_eapd
(
codec
);
}
}
static
void
ad198x_free
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
if
(
!
spec
)
return
;
snd_hda_gen_spec_free
(
&
spec
->
gen
);
kfree
(
spec
);
snd_hda_detach_beep_device
(
codec
);
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM
static
int
ad198x_suspend
(
struct
hda_codec
*
codec
)
static
int
ad198x_suspend
(
struct
hda_codec
*
codec
)
{
{
...
@@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec)
...
@@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec)
}
}
#endif
#endif
#ifdef ENABLE_AD_STATIC_QUIRKS
static
const
struct
hda_codec_ops
ad198x_patch_ops
=
{
.
build_controls
=
ad198x_build_controls
,
.
build_pcms
=
ad198x_build_pcms
,
.
init
=
ad198x_init
,
.
free
=
ad198x_free
,
#ifdef CONFIG_PM
.
check_power_status
=
ad198x_check_power_status
,
.
suspend
=
ad198x_suspend
,
#endif
.
reboot_notify
=
ad198x_shutup
,
};
/*
* EAPD control
* the private value = nid
*/
#define ad198x_eapd_info snd_ctl_boolean_mono_info
static
int
ad198x_eapd_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
if
(
codec
->
inv_eapd
)
ucontrol
->
value
.
integer
.
value
[
0
]
=
!
spec
->
cur_eapd
;
else
ucontrol
->
value
.
integer
.
value
[
0
]
=
spec
->
cur_eapd
;
return
0
;
}
static
int
ad198x_eapd_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
hda_nid_t
nid
=
kcontrol
->
private_value
&
0xff
;
unsigned
int
eapd
;
eapd
=
!!
ucontrol
->
value
.
integer
.
value
[
0
];
if
(
codec
->
inv_eapd
)
eapd
=
!
eapd
;
if
(
eapd
==
spec
->
cur_eapd
)
return
0
;
spec
->
cur_eapd
=
eapd
;
snd_hda_codec_write_cache
(
codec
,
nid
,
0
,
AC_VERB_SET_EAPD_BTLENABLE
,
eapd
?
0x02
:
0x00
);
return
1
;
}
static
int
ad198x_ch_mode_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
);
static
int
ad198x_ch_mode_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
);
static
int
ad198x_ch_mode_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
);
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
/*
* Automatic parse of I/O pins from the BIOS configuration
* Automatic parse of I/O pins from the BIOS configuration
...
@@ -646,580 +199,124 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
...
@@ -646,580 +199,124 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
* AD1986A specific
* AD1986A specific
*/
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
static
int
alloc_ad_spec
(
struct
hda_codec
*
codec
)
#define AD1986A_SPDIF_OUT 0x02
{
#define AD1986A_FRONT_DAC 0x03
struct
ad198x_spec
*
spec
;
#define AD1986A_SURR_DAC 0x04
#define AD1986A_CLFE_DAC 0x05
#define AD1986A_ADC 0x06
static
const
hda_nid_t
ad1986a_dac_nids
[
3
]
=
{
AD1986A_FRONT_DAC
,
AD1986A_SURR_DAC
,
AD1986A_CLFE_DAC
};
static
const
hda_nid_t
ad1986a_adc_nids
[
1
]
=
{
AD1986A_ADC
};
static
const
hda_nid_t
ad1986a_capsrc_nids
[
1
]
=
{
0x12
};
static
const
struct
hda_input_mux
ad1986a_capture_source
=
{
.
num_items
=
7
,
.
items
=
{
{
"Mic"
,
0x0
},
{
"CD"
,
0x1
},
{
"Aux"
,
0x3
},
{
"Line"
,
0x4
},
{
"Mix"
,
0x5
},
{
"Mono"
,
0x6
},
{
"Phone"
,
0x7
},
},
};
static
const
struct
hda_bind_ctls
ad1986a_bind_pcm_vol
=
{
.
ops
=
&
snd_hda_bind_vol
,
.
values
=
{
HDA_COMPOSE_AMP_VAL
(
AD1986A_FRONT_DAC
,
3
,
0
,
HDA_OUTPUT
),
HDA_COMPOSE_AMP_VAL
(
AD1986A_SURR_DAC
,
3
,
0
,
HDA_OUTPUT
),
HDA_COMPOSE_AMP_VAL
(
AD1986A_CLFE_DAC
,
3
,
0
,
HDA_OUTPUT
),
0
},
};
static
const
struct
hda_bind_ctls
ad1986a_bind_pcm_sw
=
{
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
.
ops
=
&
snd_hda_bind_sw
,
if
(
!
spec
)
.
values
=
{
return
-
ENOMEM
;
HDA_COMPOSE_AMP_VAL
(
AD1986A_FRONT_DAC
,
3
,
0
,
HDA_OUTPUT
),
codec
->
spec
=
spec
;
HDA_COMPOSE_AMP_VAL
(
AD1986A_SURR_DAC
,
3
,
0
,
HDA_OUTPUT
),
snd_hda_gen_spec_init
(
&
spec
->
gen
);
HDA_COMPOSE_AMP_VAL
(
AD1986A_CLFE_DAC
,
3
,
0
,
HDA_OUTPUT
),
return
0
;
0
}
},
};
/*
/*
* mixers
* AD1986A fixup codes
*/
static
const
struct
snd_kcontrol_new
ad1986a_mixers
[]
=
{
/*
* bind volumes/mutes of 3 DACs as a single PCM control for simplicity
*/
*/
HDA_BIND_VOL
(
"PCM Playback Volume"
,
&
ad1986a_bind_pcm_vol
),
HDA_BIND_SW
(
"PCM Playback Switch"
,
&
ad1986a_bind_pcm_sw
),
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Front Playback Switch"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Surround Playback Volume"
,
0x1c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Surround Playback Switch"
,
0x1c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Center Playback Volume"
,
0x1d
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"LFE Playback Volume"
,
0x1d
,
2
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Center Playback Switch"
,
0x1d
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"LFE Playback Switch"
,
0x1d
,
2
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Headphone Playback Volume"
,
0x1a
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x1a
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x17
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x17
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Aux Playback Volume"
,
0x16
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Aux Playback Switch"
,
0x16
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x0f
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mono Playback Volume"
,
0x1e
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Mono Playback Switch"
,
0x1e
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
HDA_CODEC_MUTE
(
"Stereo Downmix Switch"
,
0x09
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
/* additional mixers for 3stack mode */
/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
static
const
struct
snd_kcontrol_new
ad1986a_3st_mixers
[]
=
{
static
void
ad_fixup_inv_jack_detect
(
struct
hda_codec
*
codec
,
{
const
struct
hda_fixup
*
fix
,
int
action
)
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
{
.
name
=
"Channel Mode"
,
if
(
action
==
HDA_FIXUP_ACT_PRE_PROBE
)
.
info
=
ad198x_ch_mode_info
,
codec
->
inv_jack_detect
=
1
;
.
get
=
ad198x_ch_mode_get
,
}
.
put
=
ad198x_ch_mode_put
,
},
{
}
/* end */
};
/* laptop model - 2ch only */
static
const
hda_nid_t
ad1986a_laptop_dac_nids
[
1
]
=
{
AD1986A_FRONT_DAC
};
/* master controls both pins 0x1a and 0x1b */
enum
{
static
const
struct
hda_bind_ctls
ad1986a_laptop_master_vol
=
{
AD1986A_FIXUP_INV_JACK_DETECT
,
.
ops
=
&
snd_hda_bind_vol
,
AD1986A_FIXUP_ULTRA
,
.
values
=
{
AD1986A_FIXUP_SAMSUNG
,
HDA_COMPOSE_AMP_VAL
(
0x1a
,
3
,
0
,
HDA_OUTPUT
),
AD1986A_FIXUP_3STACK
,
HDA_COMPOSE_AMP_VAL
(
0x1b
,
3
,
0
,
HDA_OUTPUT
),
AD1986A_FIXUP_LAPTOP
,
0
,
AD1986A_FIXUP_LAPTOP_IMIC
,
},
};
};
static
const
struct
hda_bind_ctls
ad1986a_laptop_master_sw
=
{
static
const
struct
hda_fixup
ad1986a_fixups
[]
=
{
.
ops
=
&
snd_hda_bind_sw
,
[
AD1986A_FIXUP_INV_JACK_DETECT
]
=
{
.
values
=
{
.
type
=
HDA_FIXUP_FUNC
,
HDA_COMPOSE_AMP_VAL
(
0x1a
,
3
,
0
,
HDA_OUTPUT
),
.
v
.
func
=
ad_fixup_inv_jack_detect
,
HDA_COMPOSE_AMP_VAL
(
0x1b
,
3
,
0
,
HDA_OUTPUT
),
0
,
},
},
};
[
AD1986A_FIXUP_ULTRA
]
=
{
.
type
=
HDA_FIXUP_PINS
,
static
const
struct
snd_kcontrol_new
ad1986a_laptop_mixers
[]
=
{
.
v
.
pins
=
(
const
struct
hda_pintbl
[])
{
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x03
,
0x0
,
HDA_OUTPUT
),
{
0x1b
,
0x90170110
},
/* speaker */
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x03
,
0x0
,
HDA_OUTPUT
),
{
0x1d
,
0x90a7013e
},
/* int mic */
HDA_BIND_VOL
(
"Master Playback Volume"
,
&
ad1986a_laptop_master_vol
),
{}
HDA_BIND_SW
(
"Master Playback Switch"
,
&
ad1986a_laptop_master_sw
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x17
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x17
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Aux Playback Volume"
,
0x16
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Aux Playback Switch"
,
0x16
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x0f
,
0x0
,
HDA_OUTPUT
),
/*
HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
},
{
}
/* end */
};
/* laptop-eapd model - 2ch only */
static
const
struct
hda_input_mux
ad1986a_laptop_eapd_capture_source
=
{
.
num_items
=
3
,
.
items
=
{
{
"Mic"
,
0x0
},
{
"Internal Mic"
,
0x4
},
{
"Mix"
,
0x5
},
},
},
};
[
AD1986A_FIXUP_SAMSUNG
]
=
{
.
type
=
HDA_FIXUP_PINS
,
static
const
struct
hda_input_mux
ad1986a_automic_capture_source
=
{
.
v
.
pins
=
(
const
struct
hda_pintbl
[])
{
.
num_items
=
2
,
{
0x1b
,
0x90170110
},
/* speaker */
.
items
=
{
{
0x1d
,
0x90a7013e
},
/* int mic */
{
"Mic"
,
0x0
},
{
0x20
,
0x411111f0
},
/* N/A */
{
"Mix"
,
0x5
},
{
0x24
,
0x411111f0
},
/* N/A */
{}
},
},
};
static
const
struct
snd_kcontrol_new
ad1986a_laptop_master_mixers
[]
=
{
HDA_BIND_VOL
(
"Master Playback Volume"
,
&
ad1986a_laptop_master_vol
),
HDA_BIND_SW
(
"Master Playback Switch"
,
&
ad1986a_laptop_master_sw
),
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1986a_laptop_eapd_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x03
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x03
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x0f
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
},
{
[
AD1986A_FIXUP_3STACK
]
=
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
type
=
HDA_FIXUP_PINS
,
.
name
=
"External Amplifier"
,
.
v
.
pins
=
(
const
struct
hda_pintbl
[])
{
.
subdevice
=
HDA_SUBDEV_NID_FLAG
|
0x1b
,
{
0x1a
,
0x02214021
},
/* headphone */
.
info
=
ad198x_eapd_info
,
{
0x1b
,
0x01014011
},
/* front */
.
get
=
ad198x_eapd_get
,
{
0x1c
,
0x01013012
},
/* surround */
.
put
=
ad198x_eapd_put
,
{
0x1d
,
0x01019015
},
/* clfe */
.
private_value
=
0x1b
,
/* port-D */
{
0x1e
,
0x411111f0
},
/* N/A */
{
0x1f
,
0x02a190f0
},
/* mic */
{
0x20
,
0x018130f0
},
/* line-in */
{}
},
},
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1986a_laptop_intmic_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Internal Mic Playback Volume"
,
0x17
,
0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Internal Mic Playback Switch"
,
0x17
,
0
,
HDA_OUTPUT
),
{
}
/* end */
};
/* re-connect the mic boost input according to the jack sensing */
static
void
ad1986a_automic
(
struct
hda_codec
*
codec
)
{
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x1f
);
/* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
snd_hda_codec_write
(
codec
,
0x0f
,
0
,
AC_VERB_SET_CONNECT_SEL
,
present
?
0
:
2
);
}
#define AD1986A_MIC_EVENT 0x36
static
void
ad1986a_automic_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
if
((
res
>>
26
)
!=
AD1986A_MIC_EVENT
)
return
;
ad1986a_automic
(
codec
);
}
static
int
ad1986a_automic_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1986a_automic
(
codec
);
return
0
;
}
/* laptop-automute - 2ch only */
static
void
ad1986a_update_hp
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
unsigned
int
mute
;
if
(
spec
->
jack_present
)
mute
=
HDA_AMP_MUTE
;
/* mute internal speaker */
else
/* unmute internal speaker if necessary */
mute
=
snd_hda_codec_amp_read
(
codec
,
0x1a
,
0
,
HDA_OUTPUT
,
0
);
snd_hda_codec_amp_stereo
(
codec
,
0x1b
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
mute
);
}
static
void
ad1986a_hp_automute
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
spec
->
jack_present
=
snd_hda_jack_detect
(
codec
,
0x1a
);
if
(
spec
->
inv_jack_detect
)
spec
->
jack_present
=
!
spec
->
jack_present
;
ad1986a_update_hp
(
codec
);
}
#define AD1986A_HP_EVENT 0x37
static
void
ad1986a_hp_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
if
((
res
>>
26
)
!=
AD1986A_HP_EVENT
)
return
;
ad1986a_hp_automute
(
codec
);
}
static
int
ad1986a_hp_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1986a_hp_automute
(
codec
);
return
0
;
}
/* bind hp and internal speaker mute (with plug check) */
static
int
ad1986a_hp_master_sw_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
int
change
=
snd_hda_mixer_amp_switch_put
(
kcontrol
,
ucontrol
);
if
(
change
)
ad1986a_update_hp
(
codec
);
return
change
;
}
static
const
struct
snd_kcontrol_new
ad1986a_automute_master_mixers
[]
=
{
HDA_BIND_VOL
(
"Master Playback Volume"
,
&
ad1986a_laptop_master_vol
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Master Playback Switch"
,
.
subdevice
=
HDA_SUBDEV_AMP_FLAG
,
.
info
=
snd_hda_mixer_amp_switch_info
,
.
get
=
snd_hda_mixer_amp_switch_get
,
.
put
=
ad1986a_hp_master_sw_put
,
.
private_value
=
HDA_COMPOSE_AMP_VAL
(
0x1a
,
3
,
0
,
HDA_OUTPUT
),
},
},
{
}
/* end */
[
AD1986A_FIXUP_LAPTOP
]
=
{
};
.
type
=
HDA_FIXUP_PINS
,
.
v
.
pins
=
(
const
struct
hda_pintbl
[])
{
{
0x1a
,
0x02214021
},
/* headphone */
/*
{
0x1b
,
0x90170110
},
/* speaker */
* initialization verbs
{
0x1c
,
0x411111f0
},
/* N/A */
*/
{
0x1d
,
0x411111f0
},
/* N/A */
static
const
struct
hda_verb
ad1986a_init_verbs
[]
=
{
{
0x1e
,
0x411111f0
},
/* N/A */
/* Front, Surround, CLFE DAC; mute as default */
{
0x1f
,
0x02a191f0
},
/* mic */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x20
,
0x411111f0
},
/* N/A */
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x05
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* Downmix - off */
{
0x09
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* HP, Line-Out, Surround, CLFE selectors */
{
0x0a
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x0b
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x0c
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Mono selector */
{
0x0e
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Mic selector: Mic 1/2 pin */
{
0x0f
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Line-in selector: Line-in */
{
0x10
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Mic 1/2 swap */
{
0x11
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Record selector: mic */
{
0x12
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Mic, Phone, CD, Aux, Line-In amp; mute as default */
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x16
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x17
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* PC beep */
{
0x18
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
{
0x1a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* HP Pin */
{
0x1a
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0xc0
},
/* Front, Surround, CLFE Pins */
{
0x1b
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
/* Mono Pin */
{
0x1e
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
/* Mic Pin */
{
0x1f
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x24
},
/* Line, Aux, CD, Beep-In Pin */
{
0x20
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x20
},
{
0x21
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x20
},
{
0x22
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x20
},
{
0x23
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x20
},
{
0x24
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x20
},
{
}
/* end */
};
static
const
struct
hda_verb
ad1986a_ch2_init
[]
=
{
/* Surround out -> Line In */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* Line-in selectors */
{
0x10
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* CLFE -> Mic in */
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
/* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
{
0x0f
,
AC_VERB_SET_CONNECT_SEL
,
0x4
},
{
}
/* end */
};
static
const
struct
hda_verb
ad1986a_ch4_init
[]
=
{
/* Surround out -> Surround */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x10
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* CLFE -> Mic in */
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x0f
,
AC_VERB_SET_CONNECT_SEL
,
0x4
},
{
}
/* end */
};
static
const
struct
hda_verb
ad1986a_ch6_init
[]
=
{
/* Surround out -> Surround out */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x10
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* CLFE -> CLFE */
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x0f
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
}
/* end */
};
static
const
struct
hda_channel_mode
ad1986a_modes
[
3
]
=
{
{
2
,
ad1986a_ch2_init
},
{
4
,
ad1986a_ch4_init
},
{
6
,
ad1986a_ch6_init
},
};
/* eapd initialization */
static
const
struct
hda_verb
ad1986a_eapd_init_verbs
[]
=
{
{
0x1b
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x00
},
{}
};
static
const
struct
hda_verb
ad1986a_automic_verbs
[]
=
{
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x1f
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
/*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
{
0x0f
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x1f
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1986A_MIC_EVENT
},
{}
};
/* Ultra initialization */
static
const
struct
hda_verb
ad1986a_ultra_init
[]
=
{
/* eapd initialization */
{
0x1b
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x00
},
/* CLFE -> Mic in */
{
0x0f
,
AC_VERB_SET_CONNECT_SEL
,
0x2
},
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x24
},
{
0x1d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
}
/* end */
};
/* pin sensing on HP jack */
static
const
struct
hda_verb
ad1986a_hp_init_verbs
[]
=
{
{
0x1a
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1986A_HP_EVENT
},
{}
{}
};
},
},
static
void
ad1986a_samsung_p50_unsol_event
(
struct
hda_codec
*
codec
,
[
AD1986A_FIXUP_LAPTOP_IMIC
]
=
{
unsigned
int
res
)
.
type
=
HDA_FIXUP_PINS
,
{
.
v
.
pins
=
(
const
struct
hda_pintbl
[])
{
switch
(
res
>>
26
)
{
{
0x1d
,
0x90a7013e
},
/* int mic */
case
AD1986A_HP_EVENT
:
ad1986a_hp_automute
(
codec
);
break
;
case
AD1986A_MIC_EVENT
:
ad1986a_automic
(
codec
);
break
;
}
}
static
int
ad1986a_samsung_p50_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1986a_hp_automute
(
codec
);
ad1986a_automic
(
codec
);
return
0
;
}
/* models */
enum
{
AD1986A_AUTO
,
AD1986A_6STACK
,
AD1986A_3STACK
,
AD1986A_LAPTOP
,
AD1986A_LAPTOP_EAPD
,
AD1986A_LAPTOP_AUTOMUTE
,
AD1986A_ULTRA
,
AD1986A_SAMSUNG
,
AD1986A_SAMSUNG_P50
,
AD1986A_MODELS
};
static
const
char
*
const
ad1986a_models
[
AD1986A_MODELS
]
=
{
[
AD1986A_AUTO
]
=
"auto"
,
[
AD1986A_6STACK
]
=
"6stack"
,
[
AD1986A_3STACK
]
=
"3stack"
,
[
AD1986A_LAPTOP
]
=
"laptop"
,
[
AD1986A_LAPTOP_EAPD
]
=
"laptop-eapd"
,
[
AD1986A_LAPTOP_AUTOMUTE
]
=
"laptop-automute"
,
[
AD1986A_ULTRA
]
=
"ultra"
,
[
AD1986A_SAMSUNG
]
=
"samsung"
,
[
AD1986A_SAMSUNG_P50
]
=
"samsung-p50"
,
};
static
const
struct
snd_pci_quirk
ad1986a_cfg_tbl
[]
=
{
SND_PCI_QUIRK
(
0x103c
,
0x30af
,
"HP B2800"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x1153
,
"ASUS M9"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x11f7
,
"ASUS U5A"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x1213
,
"ASUS A6J"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x1263
,
"ASUS U5F"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x1297
,
"ASUS Z62F"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x12b3
,
"ASUS V1j"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x1302
,
"ASUS W3j"
,
AD1986A_LAPTOP_EAPD
),
SND_PCI_QUIRK
(
0x1043
,
0x1443
,
"ASUS VX1"
,
AD1986A_LAPTOP
),
SND_PCI_QUIRK
(
0x1043
,
0x1447
,
"ASUS A8J"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x1043
,
0x817f
,
"ASUS P5"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x1043
,
0x818f
,
"ASUS P5"
,
AD1986A_LAPTOP
),
SND_PCI_QUIRK
(
0x1043
,
0x81b3
,
"ASUS P5"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x1043
,
0x81cb
,
"ASUS M2N"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x1043
,
0x8234
,
"ASUS M2N"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x10de
,
0xcb84
,
"ASUS A8N-VM"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x1179
,
0xff40
,
"Toshiba Satellite L40-10Q"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x144d
,
0xb03c
,
"Samsung R55"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x144d
,
0xc01e
,
"FSC V2060"
,
AD1986A_LAPTOP
),
SND_PCI_QUIRK
(
0x144d
,
0xc024
,
"Samsung P50"
,
AD1986A_SAMSUNG_P50
),
SND_PCI_QUIRK
(
0x144d
,
0xc027
,
"Samsung Q1"
,
AD1986A_ULTRA
),
SND_PCI_QUIRK_MASK
(
0x144d
,
0xff00
,
0xc000
,
"Samsung"
,
AD1986A_SAMSUNG
),
SND_PCI_QUIRK
(
0x144d
,
0xc504
,
"Samsung Q35"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x17aa
,
0x1011
,
"Lenovo M55"
,
AD1986A_LAPTOP
),
SND_PCI_QUIRK
(
0x17aa
,
0x1017
,
"Lenovo A60"
,
AD1986A_3STACK
),
SND_PCI_QUIRK
(
0x17aa
,
0x2066
,
"Lenovo N100"
,
AD1986A_LAPTOP_AUTOMUTE
),
SND_PCI_QUIRK
(
0x17c0
,
0x2017
,
"Samsung M50"
,
AD1986A_LAPTOP
),
{}
{}
};
},
.
chained_before
=
1
,
#ifdef CONFIG_PM
.
chain_id
=
AD1986A_FIXUP_LAPTOP
,
static
const
struct
hda_amp_list
ad1986a_loopbacks
[]
=
{
{
0x13
,
HDA_OUTPUT
,
0
},
/* Mic */
{
0x14
,
HDA_OUTPUT
,
0
},
/* Phone */
{
0x15
,
HDA_OUTPUT
,
0
},
/* CD */
{
0x16
,
HDA_OUTPUT
,
0
},
/* Aux */
{
0x17
,
HDA_OUTPUT
,
0
},
/* Line */
{
}
/* end */
};
#endif
static
int
is_jack_available
(
struct
hda_codec
*
codec
,
hda_nid_t
nid
)
{
unsigned
int
conf
=
snd_hda_codec_get_pincfg
(
codec
,
nid
);
return
get_defcfg_connect
(
conf
)
!=
AC_JACK_PORT_NONE
;
}
#endif
/* ENABLE_AD_STATIC_QUIRKS */
static
int
alloc_ad_spec
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
spec
=
kzalloc
(
sizeof
(
*
spec
),
GFP_KERNEL
);
if
(
!
spec
)
return
-
ENOMEM
;
codec
->
spec
=
spec
;
snd_hda_gen_spec_init
(
&
spec
->
gen
);
return
0
;
}
/*
* AD1986A fixup codes
*/
/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
static
void
ad_fixup_inv_jack_detect
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
{
if
(
action
==
HDA_FIXUP_ACT_PRE_PROBE
)
codec
->
inv_jack_detect
=
1
;
}
enum
{
AD1986A_FIXUP_INV_JACK_DETECT
,
};
static
const
struct
hda_fixup
ad1986a_fixups
[]
=
{
[
AD1986A_FIXUP_INV_JACK_DETECT
]
=
{
.
type
=
HDA_FIXUP_FUNC
,
.
v
.
func
=
ad_fixup_inv_jack_detect
,
},
},
};
};
static
const
struct
snd_pci_quirk
ad1986a_fixup_tbl
[]
=
{
static
const
struct
snd_pci_quirk
ad1986a_fixup_tbl
[]
=
{
SND_PCI_QUIRK
(
0x103c
,
0x30af
,
"HP B2800"
,
AD1986A_FIXUP_LAPTOP_IMIC
),
SND_PCI_QUIRK_MASK
(
0x1043
,
0xff00
,
0x8100
,
"ASUS P5"
,
AD1986A_FIXUP_3STACK
),
SND_PCI_QUIRK_MASK
(
0x1043
,
0xff00
,
0x8200
,
"ASUS M2"
,
AD1986A_FIXUP_3STACK
),
SND_PCI_QUIRK
(
0x10de
,
0xcb84
,
"ASUS A8N-VM"
,
AD1986A_FIXUP_3STACK
),
SND_PCI_QUIRK
(
0x144d
,
0xc01e
,
"FSC V2060"
,
AD1986A_FIXUP_LAPTOP
),
SND_PCI_QUIRK_MASK
(
0x144d
,
0xff00
,
0xc000
,
"Samsung"
,
AD1986A_FIXUP_SAMSUNG
),
SND_PCI_QUIRK
(
0x144d
,
0xc027
,
"Samsung Q1"
,
AD1986A_FIXUP_ULTRA
),
SND_PCI_QUIRK
(
0x17aa
,
0x2066
,
"Lenovo N100"
,
AD1986A_FIXUP_INV_JACK_DETECT
),
SND_PCI_QUIRK
(
0x17aa
,
0x2066
,
"Lenovo N100"
,
AD1986A_FIXUP_INV_JACK_DETECT
),
SND_PCI_QUIRK
(
0x17aa
,
0x1011
,
"Lenovo M55"
,
AD1986A_FIXUP_3STACK
),
SND_PCI_QUIRK
(
0x17aa
,
0x1017
,
"Lenovo A60"
,
AD1986A_FIXUP_3STACK
),
{}
};
static
const
struct
hda_model_fixup
ad1986a_fixup_models
[]
=
{
{
.
id
=
AD1986A_FIXUP_3STACK
,
.
name
=
"3stack"
},
{
.
id
=
AD1986A_FIXUP_LAPTOP
,
.
name
=
"laptop"
},
{
.
id
=
AD1986A_FIXUP_LAPTOP_IMIC
,
.
name
=
"laptop-imic"
},
{
.
id
=
AD1986A_FIXUP_LAPTOP_IMIC
,
.
name
=
"laptop-eapd"
},
/* alias */
{}
{}
};
};
/*
/*
*/
*/
static
int
ad1986a_parse_auto_config
(
struct
hda_codec
*
codec
)
static
int
patch_ad1986a
(
struct
hda_codec
*
codec
)
{
{
int
err
;
int
err
;
struct
ad198x_spec
*
spec
;
struct
ad198x_spec
*
spec
;
...
@@ -1244,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
...
@@ -1244,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
*/
*/
spec
->
gen
.
multiout
.
no_share_stream
=
1
;
spec
->
gen
.
multiout
.
no_share_stream
=
1
;
snd_hda_pick_fixup
(
codec
,
NULL
,
ad1986a_fixup_tbl
,
ad1986a_fixups
);
snd_hda_pick_fixup
(
codec
,
ad1986a_fixup_models
,
ad1986a_fixup_tbl
,
ad1986a_fixups
);
snd_hda_apply_fixup
(
codec
,
HDA_FIXUP_ACT_PRE_PROBE
);
snd_hda_apply_fixup
(
codec
,
HDA_FIXUP_ACT_PRE_PROBE
);
err
=
ad198x_parse_auto_config
(
codec
);
err
=
ad198x_parse_auto_config
(
codec
);
...
@@ -1258,330 +356,11 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
...
@@ -1258,330 +356,11 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
return
0
;
return
0
;
}
}
#ifdef ENABLE_AD_STATIC_QUIRKS
static
int
patch_ad1986a
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
err
,
board_config
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1986A_MODELS
,
ad1986a_models
,
ad1986a_cfg_tbl
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1986A_AUTO
;
}
if
(
board_config
==
AD1986A_AUTO
)
return
ad1986a_parse_auto_config
(
codec
);
err
=
alloc_ad_spec
(
codec
);
if
(
err
<
0
)
return
err
;
spec
=
codec
->
spec
;
err
=
snd_hda_attach_beep_device
(
codec
,
0x19
);
if
(
err
<
0
)
{
ad198x_free
(
codec
);
return
err
;
}
set_beep_amp
(
spec
,
0x18
,
0
,
HDA_OUTPUT
);
spec
->
multiout
.
max_channels
=
6
;
spec
->
multiout
.
num_dacs
=
ARRAY_SIZE
(
ad1986a_dac_nids
);
spec
->
multiout
.
dac_nids
=
ad1986a_dac_nids
;
spec
->
multiout
.
dig_out_nid
=
AD1986A_SPDIF_OUT
;
spec
->
num_adc_nids
=
1
;
spec
->
adc_nids
=
ad1986a_adc_nids
;
spec
->
capsrc_nids
=
ad1986a_capsrc_nids
;
spec
->
input_mux
=
&
ad1986a_capture_source
;
spec
->
num_mixers
=
1
;
spec
->
mixers
[
0
]
=
ad1986a_mixers
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1986a_init_verbs
;
#ifdef CONFIG_PM
spec
->
loopback
.
amplist
=
ad1986a_loopbacks
;
#endif
spec
->
vmaster_nid
=
0x1b
;
codec
->
inv_eapd
=
1
;
/* AD1986A has the inverted EAPD implementation */
codec
->
patch_ops
=
ad198x_patch_ops
;
/* override some parameters */
switch
(
board_config
)
{
case
AD1986A_3STACK
:
spec
->
num_mixers
=
2
;
spec
->
mixers
[
1
]
=
ad1986a_3st_mixers
;
spec
->
num_init_verbs
=
2
;
spec
->
init_verbs
[
1
]
=
ad1986a_ch2_init
;
spec
->
channel_mode
=
ad1986a_modes
;
spec
->
num_channel_mode
=
ARRAY_SIZE
(
ad1986a_modes
);
spec
->
need_dac_fix
=
1
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
break
;
case
AD1986A_LAPTOP
:
spec
->
mixers
[
0
]
=
ad1986a_laptop_mixers
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
spec
->
multiout
.
dac_nids
=
ad1986a_laptop_dac_nids
;
break
;
case
AD1986A_LAPTOP_EAPD
:
spec
->
num_mixers
=
3
;
spec
->
mixers
[
0
]
=
ad1986a_laptop_master_mixers
;
spec
->
mixers
[
1
]
=
ad1986a_laptop_eapd_mixers
;
spec
->
mixers
[
2
]
=
ad1986a_laptop_intmic_mixers
;
spec
->
num_init_verbs
=
2
;
spec
->
init_verbs
[
1
]
=
ad1986a_eapd_init_verbs
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
spec
->
multiout
.
dac_nids
=
ad1986a_laptop_dac_nids
;
if
(
!
is_jack_available
(
codec
,
0x25
))
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1986a_laptop_eapd_capture_source
;
break
;
case
AD1986A_SAMSUNG
:
spec
->
num_mixers
=
2
;
spec
->
mixers
[
0
]
=
ad1986a_laptop_master_mixers
;
spec
->
mixers
[
1
]
=
ad1986a_laptop_eapd_mixers
;
spec
->
num_init_verbs
=
3
;
spec
->
init_verbs
[
1
]
=
ad1986a_eapd_init_verbs
;
spec
->
init_verbs
[
2
]
=
ad1986a_automic_verbs
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
spec
->
multiout
.
dac_nids
=
ad1986a_laptop_dac_nids
;
if
(
!
is_jack_available
(
codec
,
0x25
))
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1986a_automic_capture_source
;
codec
->
patch_ops
.
unsol_event
=
ad1986a_automic_unsol_event
;
codec
->
patch_ops
.
init
=
ad1986a_automic_init
;
break
;
case
AD1986A_SAMSUNG_P50
:
spec
->
num_mixers
=
2
;
spec
->
mixers
[
0
]
=
ad1986a_automute_master_mixers
;
spec
->
mixers
[
1
]
=
ad1986a_laptop_eapd_mixers
;
spec
->
num_init_verbs
=
4
;
spec
->
init_verbs
[
1
]
=
ad1986a_eapd_init_verbs
;
spec
->
init_verbs
[
2
]
=
ad1986a_automic_verbs
;
spec
->
init_verbs
[
3
]
=
ad1986a_hp_init_verbs
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
spec
->
multiout
.
dac_nids
=
ad1986a_laptop_dac_nids
;
if
(
!
is_jack_available
(
codec
,
0x25
))
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1986a_automic_capture_source
;
codec
->
patch_ops
.
unsol_event
=
ad1986a_samsung_p50_unsol_event
;
codec
->
patch_ops
.
init
=
ad1986a_samsung_p50_init
;
break
;
case
AD1986A_LAPTOP_AUTOMUTE
:
spec
->
num_mixers
=
3
;
spec
->
mixers
[
0
]
=
ad1986a_automute_master_mixers
;
spec
->
mixers
[
1
]
=
ad1986a_laptop_eapd_mixers
;
spec
->
mixers
[
2
]
=
ad1986a_laptop_intmic_mixers
;
spec
->
num_init_verbs
=
3
;
spec
->
init_verbs
[
1
]
=
ad1986a_eapd_init_verbs
;
spec
->
init_verbs
[
2
]
=
ad1986a_hp_init_verbs
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
spec
->
multiout
.
dac_nids
=
ad1986a_laptop_dac_nids
;
if
(
!
is_jack_available
(
codec
,
0x25
))
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1986a_laptop_eapd_capture_source
;
codec
->
patch_ops
.
unsol_event
=
ad1986a_hp_unsol_event
;
codec
->
patch_ops
.
init
=
ad1986a_hp_init
;
/* Lenovo N100 seems to report the reversed bit
* for HP jack-sensing
*/
spec
->
inv_jack_detect
=
1
;
break
;
case
AD1986A_ULTRA
:
spec
->
mixers
[
0
]
=
ad1986a_laptop_eapd_mixers
;
spec
->
num_init_verbs
=
2
;
spec
->
init_verbs
[
1
]
=
ad1986a_ultra_init
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
spec
->
multiout
.
dac_nids
=
ad1986a_laptop_dac_nids
;
spec
->
multiout
.
dig_out_nid
=
0
;
break
;
}
/* AD1986A has a hardware problem that it can't share a stream
* with multiple output pins. The copy of front to surrounds
* causes noisy or silent outputs at a certain timing, e.g.
* changing the volume.
* So, let's disable the shared stream.
*/
spec
->
multiout
.
no_share_stream
=
1
;
codec
->
no_trigger_sense
=
1
;
codec
->
no_sticky_stream
=
1
;
return
0
;
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1986a ad1986a_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
/*
* AD1983 specific
* AD1983 specific
*/
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
#define AD1983_SPDIF_OUT 0x02
#define AD1983_DAC 0x03
#define AD1983_ADC 0x04
static
const
hda_nid_t
ad1983_dac_nids
[
1
]
=
{
AD1983_DAC
};
static
const
hda_nid_t
ad1983_adc_nids
[
1
]
=
{
AD1983_ADC
};
static
const
hda_nid_t
ad1983_capsrc_nids
[
1
]
=
{
0x15
};
static
const
struct
hda_input_mux
ad1983_capture_source
=
{
.
num_items
=
4
,
.
items
=
{
{
"Mic"
,
0x0
},
{
"Line"
,
0x1
},
{
"Mix"
,
0x2
},
{
"Mix Mono"
,
0x3
},
},
};
/*
* SPDIF playback route
*/
static
int
ad1983_spdif_route_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
static
const
char
*
const
texts
[]
=
{
"PCM"
,
"ADC"
};
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_ENUMERATED
;
uinfo
->
count
=
1
;
uinfo
->
value
.
enumerated
.
items
=
2
;
if
(
uinfo
->
value
.
enumerated
.
item
>
1
)
uinfo
->
value
.
enumerated
.
item
=
1
;
strcpy
(
uinfo
->
value
.
enumerated
.
name
,
texts
[
uinfo
->
value
.
enumerated
.
item
]);
return
0
;
}
static
int
ad1983_spdif_route_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
spec
->
spdif_route
;
return
0
;
}
static
int
ad1983_spdif_route_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
if
(
ucontrol
->
value
.
enumerated
.
item
[
0
]
>
1
)
return
-
EINVAL
;
if
(
spec
->
spdif_route
!=
ucontrol
->
value
.
enumerated
.
item
[
0
])
{
spec
->
spdif_route
=
ucontrol
->
value
.
enumerated
.
item
[
0
];
snd_hda_codec_write_cache
(
codec
,
spec
->
multiout
.
dig_out_nid
,
0
,
AC_VERB_SET_CONNECT_SEL
,
spec
->
spdif_route
);
return
1
;
}
return
0
;
}
static
const
struct
snd_kcontrol_new
ad1983_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x05
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Front Playback Switch"
,
0x05
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Headphone Playback Volume"
,
0x06
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x06
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Mono Playback Volume"
,
0x07
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Mono Playback Switch"
,
0x07
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x15
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
,
.
info
=
ad1983_spdif_route_info
,
.
get
=
ad1983_spdif_route_get
,
.
put
=
ad1983_spdif_route_put
,
},
{
}
/* end */
};
static
const
struct
hda_verb
ad1983_init_verbs
[]
=
{
/* Front, HP, Mono; mute as default */
{
0x05
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x06
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* Beep, PCM, Mic, Line-In: mute */
{
0x10
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* Front, HP selectors; from Mix */
{
0x05
,
AC_VERB_SET_CONNECT_SEL
,
0x01
},
{
0x06
,
AC_VERB_SET_CONNECT_SEL
,
0x01
},
/* Mono selector; from Mix */
{
0x0b
,
AC_VERB_SET_CONNECT_SEL
,
0x03
},
/* Mic selector; Mic */
{
0x0c
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Line-in selector: Line-in */
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Mic boost: 0dB */
{
0x0c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb000
},
/* Record selector: mic */
{
0x15
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* SPDIF route: PCM */
{
0x02
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Front Pin */
{
0x05
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
/* HP Pin */
{
0x06
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0xc0
},
/* Mono Pin */
{
0x07
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
/* Mic Pin */
{
0x08
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x24
},
/* Line Pin */
{
0x09
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x20
},
{
}
/* end */
};
#ifdef CONFIG_PM
static
const
struct
hda_amp_list
ad1983_loopbacks
[]
=
{
{
0x12
,
HDA_OUTPUT
,
0
},
/* Mic */
{
0x13
,
HDA_OUTPUT
,
0
},
/* Line */
{
}
/* end */
};
#endif
/* models */
enum
{
AD1983_AUTO
,
AD1983_BASIC
,
AD1983_MODELS
};
static
const
char
*
const
ad1983_models
[
AD1983_MODELS
]
=
{
[
AD1983_AUTO
]
=
"auto"
,
[
AD1983_BASIC
]
=
"basic"
,
};
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
/*
* SPDIF mux control for AD1983 auto-parser
* SPDIF mux control for AD1983 auto-parser
*/
*/
...
@@ -1656,7 +435,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
...
@@ -1656,7 +435,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
return
0
;
return
0
;
}
}
static
int
ad1983_parse_auto_config
(
struct
hda_codec
*
codec
)
static
int
patch_ad1983
(
struct
hda_codec
*
codec
)
{
{
struct
ad198x_spec
*
spec
;
struct
ad198x_spec
*
spec
;
int
err
;
int
err
;
...
@@ -1681,432 +460,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
...
@@ -1681,432 +460,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
return
err
;
return
err
;
}
}
#ifdef ENABLE_AD_STATIC_QUIRKS
static
int
patch_ad1983
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
board_config
;
int
err
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1983_MODELS
,
ad1983_models
,
NULL
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1983_AUTO
;
}
if
(
board_config
==
AD1983_AUTO
)
return
ad1983_parse_auto_config
(
codec
);
err
=
alloc_ad_spec
(
codec
);
if
(
err
<
0
)
return
err
;
spec
=
codec
->
spec
;
err
=
snd_hda_attach_beep_device
(
codec
,
0x10
);
if
(
err
<
0
)
{
ad198x_free
(
codec
);
return
err
;
}
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
ARRAY_SIZE
(
ad1983_dac_nids
);
spec
->
multiout
.
dac_nids
=
ad1983_dac_nids
;
spec
->
multiout
.
dig_out_nid
=
AD1983_SPDIF_OUT
;
spec
->
num_adc_nids
=
1
;
spec
->
adc_nids
=
ad1983_adc_nids
;
spec
->
capsrc_nids
=
ad1983_capsrc_nids
;
spec
->
input_mux
=
&
ad1983_capture_source
;
spec
->
num_mixers
=
1
;
spec
->
mixers
[
0
]
=
ad1983_mixers
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1983_init_verbs
;
spec
->
spdif_route
=
0
;
#ifdef CONFIG_PM
spec
->
loopback
.
amplist
=
ad1983_loopbacks
;
#endif
spec
->
vmaster_nid
=
0x05
;
codec
->
patch_ops
=
ad198x_patch_ops
;
codec
->
no_trigger_sense
=
1
;
codec
->
no_sticky_stream
=
1
;
return
0
;
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1983 ad1983_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
/*
* AD1981 HD specific
* AD1981 HD specific
*/
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
#define AD1981_SPDIF_OUT 0x02
#define AD1981_DAC 0x03
#define AD1981_ADC 0x04
static
const
hda_nid_t
ad1981_dac_nids
[
1
]
=
{
AD1981_DAC
};
static
const
hda_nid_t
ad1981_adc_nids
[
1
]
=
{
AD1981_ADC
};
static
const
hda_nid_t
ad1981_capsrc_nids
[
1
]
=
{
0x15
};
/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
static
const
struct
hda_input_mux
ad1981_capture_source
=
{
.
num_items
=
7
,
.
items
=
{
{
"Front Mic"
,
0x0
},
{
"Line"
,
0x1
},
{
"Mix"
,
0x2
},
{
"Mix Mono"
,
0x3
},
{
"CD"
,
0x4
},
{
"Mic"
,
0x6
},
{
"Aux"
,
0x7
},
},
};
static
const
struct
snd_kcontrol_new
ad1981_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x05
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Front Playback Switch"
,
0x05
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Headphone Playback Volume"
,
0x06
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x06
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Mono Playback Volume"
,
0x07
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Mono Playback Switch"
,
0x07
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Aux Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Aux Playback Switch"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x1c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x1c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x1d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x1d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Boost Volume"
,
0x08
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x18
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x15
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
/* identical with AD1983 */
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
,
.
info
=
ad1983_spdif_route_info
,
.
get
=
ad1983_spdif_route_get
,
.
put
=
ad1983_spdif_route_put
,
},
{
}
/* end */
};
static
const
struct
hda_verb
ad1981_init_verbs
[]
=
{
/* Front, HP, Mono; mute as default */
{
0x05
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x06
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
{
0x0d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* Front, HP selectors; from Mix */
{
0x05
,
AC_VERB_SET_CONNECT_SEL
,
0x01
},
{
0x06
,
AC_VERB_SET_CONNECT_SEL
,
0x01
},
/* Mono selector; from Mix */
{
0x0b
,
AC_VERB_SET_CONNECT_SEL
,
0x03
},
/* Mic Mixer; select Front Mic */
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb000
},
{
0x1f
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* Mic boost: 0dB */
{
0x08
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x18
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
/* Record selector: Front mic */
{
0x15
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
/* SPDIF route: PCM */
{
0x02
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Front Pin */
{
0x05
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
/* HP Pin */
{
0x06
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0xc0
},
/* Mono Pin */
{
0x07
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x40
},
/* Front & Rear Mic Pins */
{
0x08
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x24
},
{
0x18
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x24
},
/* Line Pin */
{
0x09
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
0x20
},
/* Digital Beep */
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* Line-Out as Input: disabled */
{
0x1a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
}
/* end */
};
#ifdef CONFIG_PM
static
const
struct
hda_amp_list
ad1981_loopbacks
[]
=
{
{
0x12
,
HDA_OUTPUT
,
0
},
/* Front Mic */
{
0x13
,
HDA_OUTPUT
,
0
},
/* Line */
{
0x1b
,
HDA_OUTPUT
,
0
},
/* Aux */
{
0x1c
,
HDA_OUTPUT
,
0
},
/* Mic */
{
0x1d
,
HDA_OUTPUT
,
0
},
/* CD */
{
}
/* end */
};
#endif
/*
* Patch for HP nx6320
*
* nx6320 uses EAPD in the reverse way - EAPD-on means the internal
* speaker output enabled _and_ mute-LED off.
*/
#define AD1981_HP_EVENT 0x37
#define AD1981_MIC_EVENT 0x38
static
const
struct
hda_verb
ad1981_hp_init_verbs
[]
=
{
{
0x05
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x00
},
/* default off */
/* pin sensing on HP and Mic jacks */
{
0x06
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1981_HP_EVENT
},
{
0x08
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1981_MIC_EVENT
},
{}
};
/* turn on/off EAPD (+ mute HP) as a master switch */
static
int
ad1981_hp_master_sw_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
if
(
!
ad198x_eapd_put
(
kcontrol
,
ucontrol
))
return
0
;
/* change speaker pin appropriately */
snd_hda_set_pin_ctl
(
codec
,
0x05
,
spec
->
cur_eapd
?
PIN_OUT
:
0
);
/* toggle HP mute appropriately */
snd_hda_codec_amp_stereo
(
codec
,
0x06
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
spec
->
cur_eapd
?
0
:
HDA_AMP_MUTE
);
return
1
;
}
/* bind volumes of both NID 0x05 and 0x06 */
static
const
struct
hda_bind_ctls
ad1981_hp_bind_master_vol
=
{
.
ops
=
&
snd_hda_bind_vol
,
.
values
=
{
HDA_COMPOSE_AMP_VAL
(
0x05
,
3
,
0
,
HDA_OUTPUT
),
HDA_COMPOSE_AMP_VAL
(
0x06
,
3
,
0
,
HDA_OUTPUT
),
0
},
};
/* mute internal speaker if HP is plugged */
static
void
ad1981_hp_automute
(
struct
hda_codec
*
codec
)
{
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x06
);
snd_hda_codec_amp_stereo
(
codec
,
0x05
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
present
?
HDA_AMP_MUTE
:
0
);
}
/* toggle input of built-in and mic jack appropriately */
static
void
ad1981_hp_automic
(
struct
hda_codec
*
codec
)
{
static
const
struct
hda_verb
mic_jack_on
[]
=
{
{
0x1f
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb000
},
{}
};
static
const
struct
hda_verb
mic_jack_off
[]
=
{
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb080
},
{
0x1f
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb000
},
{}
};
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x08
);
if
(
present
)
snd_hda_sequence_write
(
codec
,
mic_jack_on
);
else
snd_hda_sequence_write
(
codec
,
mic_jack_off
);
}
/* unsolicited event for HP jack sensing */
static
void
ad1981_hp_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
res
>>=
26
;
switch
(
res
)
{
case
AD1981_HP_EVENT
:
ad1981_hp_automute
(
codec
);
break
;
case
AD1981_MIC_EVENT
:
ad1981_hp_automic
(
codec
);
break
;
}
}
static
const
struct
hda_input_mux
ad1981_hp_capture_source
=
{
.
num_items
=
3
,
.
items
=
{
{
"Mic"
,
0x0
},
{
"Dock Mic"
,
0x1
},
{
"Mix"
,
0x2
},
},
};
static
const
struct
snd_kcontrol_new
ad1981_hp_mixers
[]
=
{
HDA_BIND_VOL
(
"Master Playback Volume"
,
&
ad1981_hp_bind_master_vol
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
subdevice
=
HDA_SUBDEV_NID_FLAG
|
0x05
,
.
name
=
"Master Playback Switch"
,
.
info
=
ad198x_eapd_info
,
.
get
=
ad198x_eapd_get
,
.
put
=
ad1981_hp_master_sw_put
,
.
private_value
=
0x05
,
},
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
#if 0
/* FIXME: analog mic/line loopback doesn't work with my tests...
* (although recording is OK)
*/
HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
/* FIXME: does this laptop have analog CD connection? */
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
#endif
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x08
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Boost Volume"
,
0x18
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x15
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
{
}
/* end */
};
/* initialize jack-sensing, too */
static
int
ad1981_hp_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1981_hp_automute
(
codec
);
ad1981_hp_automic
(
codec
);
return
0
;
}
/* configuration for Toshiba Laptops */
static
const
struct
hda_verb
ad1981_toshiba_init_verbs
[]
=
{
{
0x05
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x01
},
/* default on */
/* pin sensing on HP and Mic jacks */
{
0x06
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1981_HP_EVENT
},
{
0x08
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1981_MIC_EVENT
},
{}
};
static
const
struct
snd_kcontrol_new
ad1981_toshiba_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Amp Volume"
,
0x1a
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Amp Switch"
,
0x1a
,
0x0
,
HDA_OUTPUT
),
{
}
};
/* configuration for Lenovo Thinkpad T60 */
static
const
struct
snd_kcontrol_new
ad1981_thinkpad_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Master Playback Volume"
,
0x05
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Master Playback Switch"
,
0x05
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x1d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x1d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x08
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x15
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
/* identical with AD1983 */
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
,
.
info
=
ad1983_spdif_route_info
,
.
get
=
ad1983_spdif_route_get
,
.
put
=
ad1983_spdif_route_put
,
},
{
}
/* end */
};
static
const
struct
hda_input_mux
ad1981_thinkpad_capture_source
=
{
.
num_items
=
3
,
.
items
=
{
{
"Mic"
,
0x0
},
{
"Mix"
,
0x2
},
{
"CD"
,
0x4
},
},
};
/* models */
enum
{
AD1981_AUTO
,
AD1981_BASIC
,
AD1981_HP
,
AD1981_THINKPAD
,
AD1981_TOSHIBA
,
AD1981_MODELS
};
static
const
char
*
const
ad1981_models
[
AD1981_MODELS
]
=
{
[
AD1981_AUTO
]
=
"auto"
,
[
AD1981_HP
]
=
"hp"
,
[
AD1981_THINKPAD
]
=
"thinkpad"
,
[
AD1981_BASIC
]
=
"basic"
,
[
AD1981_TOSHIBA
]
=
"toshiba"
};
static
const
struct
snd_pci_quirk
ad1981_cfg_tbl
[]
=
{
SND_PCI_QUIRK
(
0x1014
,
0x0597
,
"Lenovo Z60"
,
AD1981_THINKPAD
),
SND_PCI_QUIRK
(
0x1014
,
0x05b7
,
"Lenovo Z60m"
,
AD1981_THINKPAD
),
/* All HP models */
SND_PCI_QUIRK_VENDOR
(
0x103c
,
"HP nx"
,
AD1981_HP
),
SND_PCI_QUIRK
(
0x1179
,
0x0001
,
"Toshiba U205"
,
AD1981_TOSHIBA
),
/* Lenovo Thinkpad T60/X60/Z6xx */
SND_PCI_QUIRK_VENDOR
(
0x17aa
,
"Lenovo Thinkpad"
,
AD1981_THINKPAD
),
/* HP nx6320 (reversed SSID, H/W bug) */
SND_PCI_QUIRK
(
0x30b0
,
0x103c
,
"HP nx6320"
,
AD1981_HP
),
{}
};
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/* follow EAPD via vmaster hook */
/* follow EAPD via vmaster hook */
static
void
ad_vmaster_eapd_hook
(
void
*
private_data
,
int
enabled
)
static
void
ad_vmaster_eapd_hook
(
void
*
private_data
,
int
enabled
)
{
{
...
@@ -2172,7 +530,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
...
@@ -2172,7 +530,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
{}
{}
};
};
static
int
ad1981_parse_auto_config
(
struct
hda_codec
*
codec
)
static
int
patch_ad1981
(
struct
hda_codec
*
codec
)
{
{
struct
ad198x_spec
*
spec
;
struct
ad198x_spec
*
spec
;
int
err
;
int
err
;
...
@@ -2205,110 +563,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
...
@@ -2205,110 +563,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
return
err
;
return
err
;
}
}
#ifdef ENABLE_AD_STATIC_QUIRKS
static
int
patch_ad1981
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
err
,
board_config
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1981_MODELS
,
ad1981_models
,
ad1981_cfg_tbl
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1981_AUTO
;
}
if
(
board_config
==
AD1981_AUTO
)
return
ad1981_parse_auto_config
(
codec
);
err
=
alloc_ad_spec
(
codec
);
if
(
err
<
0
)
return
-
ENOMEM
;
spec
=
codec
->
spec
;
err
=
snd_hda_attach_beep_device
(
codec
,
0x10
);
if
(
err
<
0
)
{
ad198x_free
(
codec
);
return
err
;
}
set_beep_amp
(
spec
,
0x0d
,
0
,
HDA_OUTPUT
);
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
ARRAY_SIZE
(
ad1981_dac_nids
);
spec
->
multiout
.
dac_nids
=
ad1981_dac_nids
;
spec
->
multiout
.
dig_out_nid
=
AD1981_SPDIF_OUT
;
spec
->
num_adc_nids
=
1
;
spec
->
adc_nids
=
ad1981_adc_nids
;
spec
->
capsrc_nids
=
ad1981_capsrc_nids
;
spec
->
input_mux
=
&
ad1981_capture_source
;
spec
->
num_mixers
=
1
;
spec
->
mixers
[
0
]
=
ad1981_mixers
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1981_init_verbs
;
spec
->
spdif_route
=
0
;
#ifdef CONFIG_PM
spec
->
loopback
.
amplist
=
ad1981_loopbacks
;
#endif
spec
->
vmaster_nid
=
0x05
;
codec
->
patch_ops
=
ad198x_patch_ops
;
/* override some parameters */
switch
(
board_config
)
{
case
AD1981_HP
:
spec
->
mixers
[
0
]
=
ad1981_hp_mixers
;
spec
->
num_init_verbs
=
2
;
spec
->
init_verbs
[
1
]
=
ad1981_hp_init_verbs
;
if
(
!
is_jack_available
(
codec
,
0x0a
))
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1981_hp_capture_source
;
codec
->
patch_ops
.
init
=
ad1981_hp_init
;
codec
->
patch_ops
.
unsol_event
=
ad1981_hp_unsol_event
;
/* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading
*/
snd_hda_override_amp_caps
(
codec
,
0x11
,
HDA_INPUT
,
(
0x17
<<
AC_AMPCAP_OFFSET_SHIFT
)
|
(
0x17
<<
AC_AMPCAP_NUM_STEPS_SHIFT
)
|
(
0x05
<<
AC_AMPCAP_STEP_SIZE_SHIFT
)
|
(
1
<<
AC_AMPCAP_MUTE_SHIFT
));
break
;
case
AD1981_THINKPAD
:
spec
->
mixers
[
0
]
=
ad1981_thinkpad_mixers
;
spec
->
input_mux
=
&
ad1981_thinkpad_capture_source
;
/* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading
*/
snd_hda_override_amp_caps
(
codec
,
0x11
,
HDA_INPUT
,
(
0x17
<<
AC_AMPCAP_OFFSET_SHIFT
)
|
(
0x17
<<
AC_AMPCAP_NUM_STEPS_SHIFT
)
|
(
0x05
<<
AC_AMPCAP_STEP_SIZE_SHIFT
)
|
(
1
<<
AC_AMPCAP_MUTE_SHIFT
));
break
;
case
AD1981_TOSHIBA
:
spec
->
mixers
[
0
]
=
ad1981_hp_mixers
;
spec
->
mixers
[
1
]
=
ad1981_toshiba_mixers
;
spec
->
num_init_verbs
=
2
;
spec
->
init_verbs
[
1
]
=
ad1981_toshiba_init_verbs
;
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1981_hp_capture_source
;
codec
->
patch_ops
.
init
=
ad1981_hp_init
;
codec
->
patch_ops
.
unsol_event
=
ad1981_hp_unsol_event
;
break
;
}
codec
->
no_trigger_sense
=
1
;
codec
->
no_sticky_stream
=
1
;
return
0
;
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1981 ad1981_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
/*
* AD1988
* AD1988
...
@@ -2395,90 +649,7 @@ static int patch_ad1981(struct hda_codec *codec)
...
@@ -2395,90 +649,7 @@ static int patch_ad1981(struct hda_codec *codec)
* E/F quad mic array
* E/F quad mic array
*/
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
#ifdef ENABLE_AD_STATIC_QUIRKS
/* models */
enum
{
AD1988_AUTO
,
AD1988_6STACK
,
AD1988_6STACK_DIG
,
AD1988_3STACK
,
AD1988_3STACK_DIG
,
AD1988_LAPTOP
,
AD1988_LAPTOP_DIG
,
AD1988_MODEL_LAST
,
};
/* reivision id to check workarounds */
#define AD1988A_REV2 0x100200
#define is_rev2(codec) \
((codec)->vendor_id == 0x11d41988 && \
(codec)->revision_id == AD1988A_REV2)
/*
* mixers
*/
static
const
hda_nid_t
ad1988_6stack_dac_nids
[
4
]
=
{
0x04
,
0x06
,
0x05
,
0x0a
};
static
const
hda_nid_t
ad1988_3stack_dac_nids
[
3
]
=
{
0x04
,
0x05
,
0x0a
};
/* for AD1988A revision-2, DAC2-4 are swapped */
static
const
hda_nid_t
ad1988_6stack_dac_nids_rev2
[
4
]
=
{
0x04
,
0x05
,
0x0a
,
0x06
};
static
const
hda_nid_t
ad1988_alt_dac_nid
[
1
]
=
{
0x03
};
static
const
hda_nid_t
ad1988_3stack_dac_nids_rev2
[
3
]
=
{
0x04
,
0x0a
,
0x06
};
static
const
hda_nid_t
ad1988_adc_nids
[
3
]
=
{
0x08
,
0x09
,
0x0f
};
static
const
hda_nid_t
ad1988_capsrc_nids
[
3
]
=
{
0x0c
,
0x0d
,
0x0e
};
#define AD1988_SPDIF_OUT 0x02
#define AD1988_SPDIF_OUT_HDMI 0x0b
#define AD1988_SPDIF_IN 0x07
static
const
hda_nid_t
ad1989b_slave_dig_outs
[]
=
{
AD1988_SPDIF_OUT
,
AD1988_SPDIF_OUT_HDMI
,
0
};
static
const
struct
hda_input_mux
ad1988_6stack_capture_source
=
{
.
num_items
=
5
,
.
items
=
{
{
"Front Mic"
,
0x1
},
/* port-B */
{
"Line"
,
0x2
},
/* port-C */
{
"Mic"
,
0x4
},
/* port-E */
{
"CD"
,
0x5
},
{
"Mix"
,
0x9
},
},
};
static
const
struct
hda_input_mux
ad1988_laptop_capture_source
=
{
.
num_items
=
3
,
.
items
=
{
{
"Mic/Line"
,
0x1
},
/* port-B */
{
"CD"
,
0x5
},
{
"Mix"
,
0x9
},
},
};
/*
*/
static
int
ad198x_ch_mode_info
(
struct
snd_kcontrol
*
kcontrol
,
static
int
ad198x_ch_mode_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
...
@@ -2509,602 +680,39 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
...
@@ -2509,602 +680,39 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
spec
->
multiout
.
num_dacs
=
spec
->
multiout
.
max_channels
/
2
;
spec
->
multiout
.
num_dacs
=
spec
->
multiout
.
max_channels
/
2
;
return
err
;
return
err
;
}
}
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/* 6-stack mode */
static
int
ad1988_auto_smux_enum_info
(
struct
snd_kcontrol
*
kcontrol
,
static
const
struct
snd_kcontrol_new
ad1988_6stack_mixers1
[]
=
{
struct
snd_ctl_elem_info
*
uinfo
)
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
{
HDA_CODEC_VOLUME
(
"Surround Playback Volume"
,
0x06
,
0x0
,
HDA_OUTPUT
),
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
HDA_CODEC_VOLUME_MONO
(
"Center Playback Volume"
,
0x05
,
1
,
0x0
,
HDA_OUTPUT
),
static
const
char
*
const
texts
[]
=
{
HDA_CODEC_VOLUME_MONO
(
"LFE Playback Volume"
,
0x05
,
2
,
0x0
,
HDA_OUTPUT
),
"PCM"
,
"ADC1"
,
"ADC2"
,
"ADC3"
,
HDA_CODEC_VOLUME
(
"Side Playback Volume"
,
0x0a
,
0x0
,
HDA_OUTPUT
),
};
{
}
/* end */
int
num_conns
=
snd_hda_get_num_conns
(
codec
,
0x0b
)
+
1
;
};
if
(
num_conns
>
4
)
num_conns
=
4
;
static
const
struct
snd_kcontrol_new
ad1988_6stack_mixers1_rev2
[]
=
{
return
snd_hda_enum_helper_info
(
kcontrol
,
uinfo
,
num_conns
,
texts
);
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
}
HDA_CODEC_VOLUME
(
"Surround Playback Volume"
,
0x05
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Center Playback Volume"
,
0x0a
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"LFE Playback Volume"
,
0x0a
,
2
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Side Playback Volume"
,
0x06
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1988_6stack_mixers2
[]
=
{
static
int
ad1988_auto_smux_enum_get
(
struct
snd_kcontrol
*
kcontrol
,
HDA_CODEC_VOLUME
(
"Headphone Playback Volume"
,
0x03
,
0x0
,
HDA_OUTPUT
),
struct
snd_ctl_elem_value
*
ucontrol
)
HDA_BIND_MUTE
(
"Front Playback Switch"
,
0x29
,
2
,
HDA_INPUT
),
{
HDA_BIND_MUTE
(
"Surround Playback Switch"
,
0x2a
,
2
,
HDA_INPUT
),
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
HDA_BIND_MUTE_MONO
(
"Center Playback Switch"
,
0x27
,
1
,
2
,
HDA_INPUT
),
struct
ad198x_spec
*
spec
=
codec
->
spec
;
HDA_BIND_MUTE_MONO
(
"LFE Playback Switch"
,
0x27
,
2
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE
(
"Side Playback Switch"
,
0x28
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE
(
"Headphone Playback Switch"
,
0x22
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE
(
"Mono Playback Switch"
,
0x1e
,
2
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x20
,
0x6
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x20
,
0x6
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x20
,
0x0
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x20
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x20
,
0x1
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x20
,
0x1
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x4
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x4
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Analog Mix Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Analog Mix Playback Switch"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Boost Volume"
,
0x39
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x3c
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
/* 3-stack mode */
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
spec
->
cur_smux
;
static
const
struct
snd_kcontrol_new
ad1988_3stack_mixers1
[]
=
{
return
0
;
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
}
HDA_CODEC_VOLUME
(
"Surround Playback Volume"
,
0x0a
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Center Playback Volume"
,
0x05
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"LFE Playback Volume"
,
0x05
,
2
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1988_3stack_mixers1_rev2
[]
=
{
static
int
ad1988_auto_smux_enum_put
(
struct
snd_kcontrol
*
kcontrol
,
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
struct
snd_ctl_elem_value
*
ucontrol
)
HDA_CODEC_VOLUME
(
"Surround Playback Volume"
,
0x0a
,
0x0
,
HDA_OUTPUT
),
{
HDA_CODEC_VOLUME_MONO
(
"Center Playback Volume"
,
0x06
,
1
,
0x0
,
HDA_OUTPUT
),
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
HDA_CODEC_VOLUME_MONO
(
"LFE Playback Volume"
,
0x06
,
2
,
0x0
,
HDA_OUTPUT
),
struct
ad198x_spec
*
spec
=
codec
->
spec
;
{
}
/* end */
unsigned
int
val
=
ucontrol
->
value
.
enumerated
.
item
[
0
];
};
struct
nid_path
*
path
;
int
num_conns
=
snd_hda_get_num_conns
(
codec
,
0x0b
)
+
1
;
static
const
struct
snd_kcontrol_new
ad1988_3stack_mixers2
[]
=
{
HDA_CODEC_VOLUME
(
"Headphone Playback Volume"
,
0x03
,
0x0
,
HDA_OUTPUT
),
HDA_BIND_MUTE
(
"Front Playback Switch"
,
0x29
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE
(
"Surround Playback Switch"
,
0x2c
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE_MONO
(
"Center Playback Switch"
,
0x26
,
1
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE_MONO
(
"LFE Playback Switch"
,
0x26
,
2
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE
(
"Headphone Playback Switch"
,
0x22
,
2
,
HDA_INPUT
),
HDA_BIND_MUTE
(
"Mono Playback Switch"
,
0x1e
,
2
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x20
,
0x6
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x20
,
0x6
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x20
,
0x0
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x20
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x20
,
0x1
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x20
,
0x1
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x4
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x4
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Analog Mix Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Analog Mix Playback Switch"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Boost Volume"
,
0x39
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x3c
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Channel Mode"
,
.
info
=
ad198x_ch_mode_info
,
.
get
=
ad198x_ch_mode_get
,
.
put
=
ad198x_ch_mode_put
,
},
{
}
/* end */
};
/* laptop mode */
static
const
struct
snd_kcontrol_new
ad1988_laptop_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Headphone Playback Volume"
,
0x03
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x29
,
0x0
,
HDA_INPUT
),
HDA_BIND_MUTE
(
"Mono Playback Switch"
,
0x1e
,
2
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x20
,
0x6
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x20
,
0x6
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x0
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x20
,
0x1
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x20
,
0x1
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Analog Mix Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Analog Mix Playback Switch"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x39
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"External Amplifier"
,
.
subdevice
=
HDA_SUBDEV_NID_FLAG
|
0x12
,
.
info
=
ad198x_eapd_info
,
.
get
=
ad198x_eapd_get
,
.
put
=
ad198x_eapd_put
,
.
private_value
=
0x12
,
/* port-D */
},
{
}
/* end */
};
/* capture */
static
const
struct
snd_kcontrol_new
ad1988_capture_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_IDX
(
"Capture Volume"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_IDX
(
"Capture Switch"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_IDX
(
"Capture Volume"
,
2
,
0x0e
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_IDX
(
"Capture Switch"
,
2
,
0x0e
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
/* The multiple "Capture Source" controls confuse alsamixer
* So call somewhat different..
*/
/* .name = "Capture Source", */
.
name
=
"Input Source"
,
.
count
=
3
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
{
}
/* end */
};
static
int
ad1988_spdif_playback_source_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
static
const
char
*
const
texts
[]
=
{
"PCM"
,
"ADC1"
,
"ADC2"
,
"ADC3"
};
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_ENUMERATED
;
uinfo
->
count
=
1
;
uinfo
->
value
.
enumerated
.
items
=
4
;
if
(
uinfo
->
value
.
enumerated
.
item
>=
4
)
uinfo
->
value
.
enumerated
.
item
=
3
;
strcpy
(
uinfo
->
value
.
enumerated
.
name
,
texts
[
uinfo
->
value
.
enumerated
.
item
]);
return
0
;
}
static
int
ad1988_spdif_playback_source_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
unsigned
int
sel
;
sel
=
snd_hda_codec_read
(
codec
,
0x1d
,
0
,
AC_VERB_GET_AMP_GAIN_MUTE
,
AC_AMP_GET_INPUT
);
if
(
!
(
sel
&
0x80
))
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
0
;
else
{
sel
=
snd_hda_codec_read
(
codec
,
0x0b
,
0
,
AC_VERB_GET_CONNECT_SEL
,
0
);
if
(
sel
<
3
)
sel
++
;
else
sel
=
0
;
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
sel
;
}
return
0
;
}
static
int
ad1988_spdif_playback_source_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
unsigned
int
val
,
sel
;
int
change
;
val
=
ucontrol
->
value
.
enumerated
.
item
[
0
];
if
(
val
>
3
)
return
-
EINVAL
;
if
(
!
val
)
{
sel
=
snd_hda_codec_read
(
codec
,
0x1d
,
0
,
AC_VERB_GET_AMP_GAIN_MUTE
,
AC_AMP_GET_INPUT
);
change
=
sel
&
0x80
;
if
(
change
)
{
snd_hda_codec_write_cache
(
codec
,
0x1d
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
));
snd_hda_codec_write_cache
(
codec
,
0x1d
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
));
}
}
else
{
sel
=
snd_hda_codec_read
(
codec
,
0x1d
,
0
,
AC_VERB_GET_AMP_GAIN_MUTE
,
AC_AMP_GET_INPUT
|
0x01
);
change
=
sel
&
0x80
;
if
(
change
)
{
snd_hda_codec_write_cache
(
codec
,
0x1d
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
));
snd_hda_codec_write_cache
(
codec
,
0x1d
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
));
}
sel
=
snd_hda_codec_read
(
codec
,
0x0b
,
0
,
AC_VERB_GET_CONNECT_SEL
,
0
)
+
1
;
change
|=
sel
!=
val
;
if
(
change
)
snd_hda_codec_write_cache
(
codec
,
0x0b
,
0
,
AC_VERB_SET_CONNECT_SEL
,
val
-
1
);
}
return
change
;
}
static
const
struct
snd_kcontrol_new
ad1988_spdif_out_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"IEC958 Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"IEC958 Playback Source"
,
.
subdevice
=
HDA_SUBDEV_NID_FLAG
|
0x1b
,
.
info
=
ad1988_spdif_playback_source_info
,
.
get
=
ad1988_spdif_playback_source_get
,
.
put
=
ad1988_spdif_playback_source_put
,
},
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1988_spdif_in_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"IEC958 Capture Volume"
,
0x1c
,
0x0
,
HDA_INPUT
),
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1989_spdif_out_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"IEC958 Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"HDMI Playback Volume"
,
0x1d
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
/*
* initialization verbs
*/
/*
* for 6-stack (+dig)
*/
static
const
struct
hda_verb
ad1988_6stack_init_verbs
[]
=
{
/* Front, Surround, CLFE, side DAC; unmute as default */
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x06
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x05
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x0a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Port-A front headphon path */
{
0x37
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* DAC0:03h */
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
/* Port-D line-out path */
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x12
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* Port-F surround path */
{
0x2a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x2a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x16
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x16
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* Port-G CLFE path */
{
0x27
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x27
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x24
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x24
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* Port-H side path */
{
0x28
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x28
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x25
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x25
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* Mono out path */
{
0x36
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* DAC1:04h */
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x13
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb01f
},
/* unmute, 0dB */
/* Port-B front mic-in path */
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x14
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x39
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* Port-C line-in path */
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
{
0x3a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x33
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Port-E mic-in path */
{
0x17
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x3c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x34
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Analog CD Input */
{
0x18
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x1f
},
/* 0dB */
{
}
};
static
const
struct
hda_verb
ad1988_6stack_fp_init_verbs
[]
=
{
/* Headphone; unmute as default */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Port-A front headphon path */
{
0x37
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* DAC0:03h */
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
}
};
static
const
struct
hda_verb
ad1988_capture_init_verbs
[]
=
{
/* mute analog mix */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
5
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
6
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
7
)},
/* select ADCs - front-mic */
{
0x0c
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
0x0e
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
}
};
static
const
struct
hda_verb
ad1988_spdif_init_verbs
[]
=
{
/* SPDIF out sel */
{
0x02
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* PCM */
{
0x0b
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* ADC1 */
{
0x1d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x1d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
/* SPDIF out pin */
{
0x1b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x27
},
/* 0dB */
{
}
};
static
const
struct
hda_verb
ad1988_spdif_in_init_verbs
[]
=
{
/* unmute SPDIF input pin */
{
0x1c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
}
};
/* AD1989 has no ADC -> SPDIF route */
static
const
struct
hda_verb
ad1989_spdif_init_verbs
[]
=
{
/* SPDIF-1 out pin */
{
0x1b
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x1b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x27
},
/* 0dB */
/* SPDIF-2/HDMI out pin */
{
0x1d
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x1d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x27
},
/* 0dB */
{
}
};
/*
* verbs for 3stack (+dig)
*/
static
const
struct
hda_verb
ad1988_3stack_ch2_init
[]
=
{
/* set port-C to line-in */
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* set port-E to mic-in */
{
0x17
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
}
/* end */
};
static
const
struct
hda_verb
ad1988_3stack_ch6_init
[]
=
{
/* set port-C to surround out */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* set port-E to CLFE out */
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x17
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
}
/* end */
};
static
const
struct
hda_channel_mode
ad1988_3stack_modes
[
2
]
=
{
{
2
,
ad1988_3stack_ch2_init
},
{
6
,
ad1988_3stack_ch6_init
},
};
static
const
struct
hda_verb
ad1988_3stack_init_verbs
[]
=
{
/* Front, Surround, CLFE, side DAC; unmute as default */
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x06
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x05
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x0a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Port-A front headphon path */
{
0x37
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* DAC0:03h */
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
/* Port-D line-out path */
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x12
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* Mono out path */
{
0x36
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* DAC1:04h */
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x13
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb01f
},
/* unmute, 0dB */
/* Port-B front mic-in path */
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x14
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x39
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* Port-C line-in/surround path - 6ch mode as default */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x3a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x31
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* output sel: DAC 0x05 */
{
0x33
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* Port-E mic-in/CLFE path - 6ch mode as default */
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x17
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x3c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x32
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* output sel: DAC 0x0a */
{
0x34
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* mute analog mix */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
5
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
6
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
7
)},
/* select ADCs - front-mic */
{
0x0c
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
0x0e
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x1f
},
/* 0dB */
{
}
};
/*
* verbs for laptop mode (+dig)
*/
static
const
struct
hda_verb
ad1988_laptop_hp_on
[]
=
{
/* unmute port-A and mute port-D */
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
}
/* end */
};
static
const
struct
hda_verb
ad1988_laptop_hp_off
[]
=
{
/* mute port-A and unmute port-D */
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
}
/* end */
};
#define AD1988_HP_EVENT 0x01
static
const
struct
hda_verb
ad1988_laptop_init_verbs
[]
=
{
/* Front, Surround, CLFE, side DAC; unmute as default */
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x06
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x05
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x0a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Port-A front headphon path */
{
0x37
,
AC_VERB_SET_CONNECT_SEL
,
0x00
},
/* DAC0:03h */
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
/* unsolicited event for pin-sense */
{
0x11
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1988_HP_EVENT
},
/* Port-D line-out path + EAPD */
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x12
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x12
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x00
},
/* EAPD-off */
/* Mono out path */
{
0x36
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* DAC1:04h */
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x13
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0xb01f
},
/* unmute, 0dB */
/* Port-B mic-in path */
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x14
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x39
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* Port-C docking station - try to output */
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x3a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x33
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* mute analog mix */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
5
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
6
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
7
)},
/* select ADCs - mic */
{
0x0c
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
0x0e
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x1f
},
/* 0dB */
{
}
};
static
void
ad1988_laptop_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
if
((
res
>>
26
)
!=
AD1988_HP_EVENT
)
return
;
if
(
snd_hda_jack_detect
(
codec
,
0x11
))
snd_hda_sequence_write
(
codec
,
ad1988_laptop_hp_on
);
else
snd_hda_sequence_write
(
codec
,
ad1988_laptop_hp_off
);
}
#ifdef CONFIG_PM
static
const
struct
hda_amp_list
ad1988_loopbacks
[]
=
{
{
0x20
,
HDA_INPUT
,
0
},
/* Front Mic */
{
0x20
,
HDA_INPUT
,
1
},
/* Line */
{
0x20
,
HDA_INPUT
,
4
},
/* Mic */
{
0x20
,
HDA_INPUT
,
6
},
/* CD */
{
}
/* end */
};
#endif
#endif
/* ENABLE_AD_STATIC_QUIRKS */
static
int
ad1988_auto_smux_enum_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
static
const
char
*
const
texts
[]
=
{
"PCM"
,
"ADC1"
,
"ADC2"
,
"ADC3"
,
};
int
num_conns
=
snd_hda_get_num_conns
(
codec
,
0x0b
)
+
1
;
if
(
num_conns
>
4
)
num_conns
=
4
;
return
snd_hda_enum_helper_info
(
kcontrol
,
uinfo
,
num_conns
,
texts
);
}
static
int
ad1988_auto_smux_enum_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
spec
->
cur_smux
;
return
0
;
}
static
int
ad1988_auto_smux_enum_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
ad198x_spec
*
spec
=
codec
->
spec
;
unsigned
int
val
=
ucontrol
->
value
.
enumerated
.
item
[
0
];
struct
nid_path
*
path
;
int
num_conns
=
snd_hda_get_num_conns
(
codec
,
0x0b
)
+
1
;
if
(
val
>=
num_conns
)
if
(
val
>=
num_conns
)
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -3220,7 +828,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
...
@@ -3220,7 +828,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
/*
/*
*/
*/
static
int
ad1988_parse_auto_config
(
struct
hda_codec
*
codec
)
enum
{
AD1988_FIXUP_6STACK_DIG
,
};
static
const
struct
hda_fixup
ad1988_fixups
[]
=
{
[
AD1988_FIXUP_6STACK_DIG
]
=
{
.
type
=
HDA_FIXUP_PINS
,
.
v
.
pins
=
(
const
struct
hda_pintbl
[])
{
{
0x11
,
0x02214130
},
/* front-hp */
{
0x12
,
0x01014010
},
/* line-out */
{
0x14
,
0x02a19122
},
/* front-mic */
{
0x15
,
0x01813021
},
/* line-in */
{
0x16
,
0x01011012
},
/* line-out */
{
0x17
,
0x01a19020
},
/* mic */
{
0x1b
,
0x0145f1f0
},
/* SPDIF */
{
0x24
,
0x01016011
},
/* line-out */
{
0x25
,
0x01012013
},
/* line-out */
{
}
}
},
};
static
const
struct
hda_model_fixup
ad1988_fixup_models
[]
=
{
{
.
id
=
AD1988_FIXUP_6STACK_DIG
,
.
name
=
"6stack-dig"
},
{}
};
static
int
patch_ad1988
(
struct
hda_codec
*
codec
)
{
{
struct
ad198x_spec
*
spec
;
struct
ad198x_spec
*
spec
;
int
err
;
int
err
;
...
@@ -3234,12 +869,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
...
@@ -3234,12 +869,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
spec
->
gen
.
mixer_merge_nid
=
0x21
;
spec
->
gen
.
mixer_merge_nid
=
0x21
;
spec
->
gen
.
beep_nid
=
0x10
;
spec
->
gen
.
beep_nid
=
0x10
;
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
snd_hda_pick_fixup
(
codec
,
ad1988_fixup_models
,
NULL
,
ad1988_fixups
);
snd_hda_apply_fixup
(
codec
,
HDA_FIXUP_ACT_PRE_PROBE
);
err
=
ad198x_parse_auto_config
(
codec
);
err
=
ad198x_parse_auto_config
(
codec
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
error
;
goto
error
;
err
=
ad1988_add_spdif_mux_ctl
(
codec
);
err
=
ad1988_add_spdif_mux_ctl
(
codec
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
error
;
goto
error
;
snd_hda_apply_fixup
(
codec
,
HDA_FIXUP_ACT_PROBE
);
return
0
;
return
0
;
error:
error:
...
@@ -3247,169 +889,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
...
@@ -3247,169 +889,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
return
err
;
return
err
;
}
}
/*
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
static
const
char
*
const
ad1988_models
[
AD1988_MODEL_LAST
]
=
{
[
AD1988_6STACK
]
=
"6stack"
,
[
AD1988_6STACK_DIG
]
=
"6stack-dig"
,
[
AD1988_3STACK
]
=
"3stack"
,
[
AD1988_3STACK_DIG
]
=
"3stack-dig"
,
[
AD1988_LAPTOP
]
=
"laptop"
,
[
AD1988_LAPTOP_DIG
]
=
"laptop-dig"
,
[
AD1988_AUTO
]
=
"auto"
,
};
static
const
struct
snd_pci_quirk
ad1988_cfg_tbl
[]
=
{
SND_PCI_QUIRK
(
0x1043
,
0x81ec
,
"Asus P5B-DLX"
,
AD1988_6STACK_DIG
),
SND_PCI_QUIRK
(
0x1043
,
0x81f6
,
"Asus M2N-SLI"
,
AD1988_6STACK_DIG
),
SND_PCI_QUIRK
(
0x1043
,
0x8277
,
"Asus P5K-E/WIFI-AP"
,
AD1988_6STACK_DIG
),
SND_PCI_QUIRK
(
0x1043
,
0x82c0
,
"Asus M3N-HT Deluxe"
,
AD1988_6STACK_DIG
),
SND_PCI_QUIRK
(
0x1043
,
0x8311
,
"Asus P5Q-Premium/Pro"
,
AD1988_6STACK_DIG
),
{}
};
static
int
patch_ad1988
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
err
,
board_config
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1988_MODEL_LAST
,
ad1988_models
,
ad1988_cfg_tbl
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1988_AUTO
;
}
if
(
board_config
==
AD1988_AUTO
)
return
ad1988_parse_auto_config
(
codec
);
err
=
alloc_ad_spec
(
codec
);
if
(
err
<
0
)
return
err
;
spec
=
codec
->
spec
;
if
(
is_rev2
(
codec
))
snd_printk
(
KERN_INFO
"patch_analog: AD1988A rev.2 is detected, enable workarounds
\n
"
);
err
=
snd_hda_attach_beep_device
(
codec
,
0x10
);
if
(
err
<
0
)
{
ad198x_free
(
codec
);
return
err
;
}
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
if
(
!
spec
->
multiout
.
hp_nid
)
spec
->
multiout
.
hp_nid
=
ad1988_alt_dac_nid
[
0
];
switch
(
board_config
)
{
case
AD1988_6STACK
:
case
AD1988_6STACK_DIG
:
spec
->
multiout
.
max_channels
=
8
;
spec
->
multiout
.
num_dacs
=
4
;
if
(
is_rev2
(
codec
))
spec
->
multiout
.
dac_nids
=
ad1988_6stack_dac_nids_rev2
;
else
spec
->
multiout
.
dac_nids
=
ad1988_6stack_dac_nids
;
spec
->
input_mux
=
&
ad1988_6stack_capture_source
;
spec
->
num_mixers
=
2
;
if
(
is_rev2
(
codec
))
spec
->
mixers
[
0
]
=
ad1988_6stack_mixers1_rev2
;
else
spec
->
mixers
[
0
]
=
ad1988_6stack_mixers1
;
spec
->
mixers
[
1
]
=
ad1988_6stack_mixers2
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1988_6stack_init_verbs
;
if
(
board_config
==
AD1988_6STACK_DIG
)
{
spec
->
multiout
.
dig_out_nid
=
AD1988_SPDIF_OUT
;
spec
->
dig_in_nid
=
AD1988_SPDIF_IN
;
}
break
;
case
AD1988_3STACK
:
case
AD1988_3STACK_DIG
:
spec
->
multiout
.
max_channels
=
6
;
spec
->
multiout
.
num_dacs
=
3
;
if
(
is_rev2
(
codec
))
spec
->
multiout
.
dac_nids
=
ad1988_3stack_dac_nids_rev2
;
else
spec
->
multiout
.
dac_nids
=
ad1988_3stack_dac_nids
;
spec
->
input_mux
=
&
ad1988_6stack_capture_source
;
spec
->
channel_mode
=
ad1988_3stack_modes
;
spec
->
num_channel_mode
=
ARRAY_SIZE
(
ad1988_3stack_modes
);
spec
->
num_mixers
=
2
;
if
(
is_rev2
(
codec
))
spec
->
mixers
[
0
]
=
ad1988_3stack_mixers1_rev2
;
else
spec
->
mixers
[
0
]
=
ad1988_3stack_mixers1
;
spec
->
mixers
[
1
]
=
ad1988_3stack_mixers2
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1988_3stack_init_verbs
;
if
(
board_config
==
AD1988_3STACK_DIG
)
spec
->
multiout
.
dig_out_nid
=
AD1988_SPDIF_OUT
;
break
;
case
AD1988_LAPTOP
:
case
AD1988_LAPTOP_DIG
:
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
spec
->
multiout
.
dac_nids
=
ad1988_3stack_dac_nids
;
spec
->
input_mux
=
&
ad1988_laptop_capture_source
;
spec
->
num_mixers
=
1
;
spec
->
mixers
[
0
]
=
ad1988_laptop_mixers
;
codec
->
inv_eapd
=
1
;
/* inverted EAPD */
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1988_laptop_init_verbs
;
if
(
board_config
==
AD1988_LAPTOP_DIG
)
spec
->
multiout
.
dig_out_nid
=
AD1988_SPDIF_OUT
;
break
;
}
spec
->
num_adc_nids
=
ARRAY_SIZE
(
ad1988_adc_nids
);
spec
->
adc_nids
=
ad1988_adc_nids
;
spec
->
capsrc_nids
=
ad1988_capsrc_nids
;
spec
->
mixers
[
spec
->
num_mixers
++
]
=
ad1988_capture_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1988_capture_init_verbs
;
if
(
spec
->
multiout
.
dig_out_nid
)
{
if
(
codec
->
vendor_id
>=
0x11d4989a
)
{
spec
->
mixers
[
spec
->
num_mixers
++
]
=
ad1989_spdif_out_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1989_spdif_init_verbs
;
codec
->
slave_dig_outs
=
ad1989b_slave_dig_outs
;
}
else
{
spec
->
mixers
[
spec
->
num_mixers
++
]
=
ad1988_spdif_out_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1988_spdif_init_verbs
;
}
}
if
(
spec
->
dig_in_nid
&&
codec
->
vendor_id
<
0x11d4989a
)
{
spec
->
mixers
[
spec
->
num_mixers
++
]
=
ad1988_spdif_in_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1988_spdif_in_init_verbs
;
}
codec
->
patch_ops
=
ad198x_patch_ops
;
switch
(
board_config
)
{
case
AD1988_LAPTOP
:
case
AD1988_LAPTOP_DIG
:
codec
->
patch_ops
.
unsol_event
=
ad1988_laptop_unsol_event
;
break
;
}
#ifdef CONFIG_PM
spec
->
loopback
.
amplist
=
ad1988_loopbacks
;
#endif
spec
->
vmaster_nid
=
0x04
;
codec
->
no_trigger_sense
=
1
;
codec
->
no_sticky_stream
=
1
;
return
0
;
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1988 ad1988_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
/*
* AD1884 / AD1984
* AD1884 / AD1984
...
@@ -3423,190 +902,62 @@ static int patch_ad1988(struct hda_codec *codec)
...
@@ -3423,190 +902,62 @@ static int patch_ad1988(struct hda_codec *codec)
*
*
* AD1984 = AD1884 + two digital mic-ins
* AD1984 = AD1884 + two digital mic-ins
*
*
* FIXME:
* AD1883 / AD1884A / AD1984A / AD1984B
* For simplicity, we share the single DAC for both HP and line-outs
*
* right now. The inidividual playbacks could be easily implemented,
* port-B (0x14) - front mic-in
* but no build-up framework is given, so far.
* port-E (0x1c) - rear mic-in
* port-F (0x16) - CD / ext out
* port-C (0x15) - rear line-in
* port-D (0x12) - rear line-out
* port-A (0x11) - front hp-out
*
* AD1984A = AD1884A + digital-mic
* AD1883 = equivalent with AD1984A
* AD1984B = AD1984A + extra SPDIF-out
*/
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
/* set the upper-limit for mixer amp to 0dB for avoiding the possible
static
const
hda_nid_t
ad1884_dac_nids
[
1
]
=
{
* damage by overloading
0x04
,
*/
};
static
void
ad1884_fixup_amp_override
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
static
const
hda_nid_t
ad1884_adc_nids
[
2
]
=
{
{
0x08
,
0x09
,
if
(
action
==
HDA_FIXUP_ACT_PRE_PROBE
)
};
snd_hda_override_amp_caps
(
codec
,
0x20
,
HDA_INPUT
,
(
0x17
<<
AC_AMPCAP_OFFSET_SHIFT
)
|
(
0x17
<<
AC_AMPCAP_NUM_STEPS_SHIFT
)
|
(
0x05
<<
AC_AMPCAP_STEP_SIZE_SHIFT
)
|
(
1
<<
AC_AMPCAP_MUTE_SHIFT
));
}
static
const
hda_nid_t
ad1884_capsrc_nids
[
2
]
=
{
/* toggle GPIO1 according to the mute state */
0x0c
,
0x0d
,
static
void
ad1884_vmaster_hp_gpio_hook
(
void
*
private_data
,
int
enabled
)
};
{
struct
hda_codec
*
codec
=
private_data
;
struct
ad198x_spec
*
spec
=
codec
->
spec
;
#define AD1884_SPDIF_OUT 0x02
if
(
spec
->
eapd_nid
)
ad_vmaster_eapd_hook
(
private_data
,
enabled
);
static
const
struct
hda_input_mux
ad1884_capture_source
=
{
snd_hda_codec_update_cache
(
codec
,
0x01
,
0
,
.
num_items
=
4
,
AC_VERB_SET_GPIO_DATA
,
.
items
=
{
enabled
?
0x00
:
0x02
);
{
"Front Mic"
,
0x0
},
}
{
"Mic"
,
0x1
},
{
"CD"
,
0x2
},
{
"Mix"
,
0x3
},
},
};
static
const
struct
snd_kcontrol_new
ad1884_base_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Front Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Mono Playback Volume"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Mono Playback Switch"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x20
,
0x02
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x20
,
0x02
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x15
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Boost Volume"
,
0x14
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_IDX
(
"Capture Volume"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_IDX
(
"Capture Switch"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
/* The multiple "Capture Source" controls confuse alsamixer
* So call somewhat different..
*/
/* .name = "Capture Source", */
.
name
=
"Input Source"
,
.
count
=
2
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
/* SPDIF controls */
HDA_CODEC_VOLUME
(
"IEC958 Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
,
/* identical with ad1983 */
.
info
=
ad1983_spdif_route_info
,
.
get
=
ad1983_spdif_route_get
,
.
put
=
ad1983_spdif_route_put
,
},
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1984_dmic_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Digital Mic Capture Volume"
,
0x05
,
0x0
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Digital Mic Capture Switch"
,
0x05
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME_IDX
(
"Digital Mic Capture Volume"
,
1
,
0x06
,
0x0
,
HDA_INPUT
),
HDA_CODEC_MUTE_IDX
(
"Digital Mic Capture Switch"
,
1
,
0x06
,
0x0
,
HDA_INPUT
),
{
}
/* end */
};
/*
* initialization verbs
*/
static
const
struct
hda_verb
ad1884_init_verbs
[]
=
{
/* DACs; mute as default */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* Port-A (HP) mixer */
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-A pin */
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* HP selector - select DAC2 */
{
0x22
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* Port-D (Line-out) mixer */
{
0x0a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x0a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-D pin */
{
0x12
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Mono-out mixer */
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Mono-out pin */
{
0x13
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Mono selector */
{
0x0e
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* Port-B (front mic) pin */
{
0x14
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
/* Port-C (rear mic) pin */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
/* Analog mixer; mute as default */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x1f
},
/* 0dB */
/* SPDIF output selector */
{
0x02
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* PCM */
{
0x1b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x27
},
/* 0dB */
{
}
/* end */
};
#ifdef CONFIG_PM
static
const
struct
hda_amp_list
ad1884_loopbacks
[]
=
{
{
0x20
,
HDA_INPUT
,
0
},
/* Front Mic */
{
0x20
,
HDA_INPUT
,
1
},
/* Mic */
{
0x20
,
HDA_INPUT
,
2
},
/* CD */
{
0x20
,
HDA_INPUT
,
4
},
/* Docking */
{
}
/* end */
};
#endif
static
const
char
*
const
ad1884_slave_vols
[]
=
{
"PCM"
,
"Mic"
,
"Mono"
,
"Front Mic"
,
"Mic"
,
"CD"
,
"Internal Mic"
,
"Dock Mic"
,
/* "Beep", */
"IEC958"
,
NULL
};
enum
{
AD1884_AUTO
,
AD1884_BASIC
,
AD1884_MODELS
};
static
const
char
*
const
ad1884_models
[
AD1884_MODELS
]
=
{
[
AD1884_AUTO
]
=
"auto"
,
[
AD1884_BASIC
]
=
"basic"
,
};
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/* set the upper-limit for mixer amp to 0dB for avoiding the possible
* damage by overloading
*/
static
void
ad1884_fixup_amp_override
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
{
if
(
action
==
HDA_FIXUP_ACT_PRE_PROBE
)
snd_hda_override_amp_caps
(
codec
,
0x20
,
HDA_INPUT
,
(
0x17
<<
AC_AMPCAP_OFFSET_SHIFT
)
|
(
0x17
<<
AC_AMPCAP_NUM_STEPS_SHIFT
)
|
(
0x05
<<
AC_AMPCAP_STEP_SIZE_SHIFT
)
|
(
1
<<
AC_AMPCAP_MUTE_SHIFT
));
}
static
void
ad1884_fixup_hp_eapd
(
struct
hda_codec
*
codec
,
static
void
ad1884_fixup_hp_eapd
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
const
struct
hda_fixup
*
fix
,
int
action
)
{
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
struct
ad198x_spec
*
spec
=
codec
->
spec
;
static
const
struct
hda_verb
gpio_init_verbs
[]
=
{
{
0x01
,
AC_VERB_SET_GPIO_MASK
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DIRECTION
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DATA
,
0x02
},
{},
};
switch
(
action
)
{
switch
(
action
)
{
case
HDA_FIXUP_ACT_PRE_PROBE
:
case
HDA_FIXUP_ACT_PRE_PROBE
:
spec
->
gen
.
vmaster_mute
.
hook
=
ad_vmaster_eapd_hook
;
spec
->
gen
.
vmaster_mute
.
hook
=
ad1884_vmaster_hp_gpio_hook
;
snd_hda_sequence_write_cache
(
codec
,
gpio_init_verbs
);
break
;
break
;
case
HDA_FIXUP_ACT_PROBE
:
case
HDA_FIXUP_ACT_PROBE
:
if
(
spec
->
gen
.
autocfg
.
line_out_type
==
AUTO_PIN_SPEAKER_OUT
)
if
(
spec
->
gen
.
autocfg
.
line_out_type
==
AUTO_PIN_SPEAKER_OUT
)
...
@@ -3617,9 +968,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
...
@@ -3617,9 +968,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
}
}
}
}
/* set magic COEFs for dmic */
static
const
struct
hda_verb
ad1884_dmic_init_verbs
[]
=
{
{
0x01
,
AC_VERB_SET_COEF_INDEX
,
0x13f7
},
{
0x01
,
AC_VERB_SET_PROC_COEF
,
0x08
},
{}
};
enum
{
enum
{
AD1884_FIXUP_AMP_OVERRIDE
,
AD1884_FIXUP_AMP_OVERRIDE
,
AD1884_FIXUP_HP_EAPD
,
AD1884_FIXUP_HP_EAPD
,
AD1884_FIXUP_DMIC_COEF
,
AD1884_FIXUP_HP_TOUCHSMART
,
};
};
static
const
struct
hda_fixup
ad1884_fixups
[]
=
{
static
const
struct
hda_fixup
ad1884_fixups
[]
=
{
...
@@ -3633,15 +993,27 @@ static const struct hda_fixup ad1884_fixups[] = {
...
@@ -3633,15 +993,27 @@ static const struct hda_fixup ad1884_fixups[] = {
.
chained
=
true
,
.
chained
=
true
,
.
chain_id
=
AD1884_FIXUP_AMP_OVERRIDE
,
.
chain_id
=
AD1884_FIXUP_AMP_OVERRIDE
,
},
},
[
AD1884_FIXUP_DMIC_COEF
]
=
{
.
type
=
HDA_FIXUP_VERBS
,
.
v
.
verbs
=
ad1884_dmic_init_verbs
,
},
[
AD1884_FIXUP_HP_TOUCHSMART
]
=
{
.
type
=
HDA_FIXUP_VERBS
,
.
v
.
verbs
=
ad1884_dmic_init_verbs
,
.
chained
=
true
,
.
chain_id
=
AD1884_FIXUP_HP_EAPD
,
},
};
};
static
const
struct
snd_pci_quirk
ad1884_fixup_tbl
[]
=
{
static
const
struct
snd_pci_quirk
ad1884_fixup_tbl
[]
=
{
SND_PCI_QUIRK
(
0x103c
,
0x2a82
,
"HP Touchsmart"
,
AD1884_FIXUP_HP_TOUCHSMART
),
SND_PCI_QUIRK_VENDOR
(
0x103c
,
"HP"
,
AD1884_FIXUP_HP_EAPD
),
SND_PCI_QUIRK_VENDOR
(
0x103c
,
"HP"
,
AD1884_FIXUP_HP_EAPD
),
SND_PCI_QUIRK_VENDOR
(
0x17aa
,
"Lenovo Thinkpad"
,
AD1884_FIXUP_DMIC_COEF
),
{}
{}
};
};
static
int
ad1884_parse_auto_config
(
struct
hda_codec
*
codec
)
static
int
patch_ad1884
(
struct
hda_codec
*
codec
)
{
{
struct
ad198x_spec
*
spec
;
struct
ad198x_spec
*
spec
;
int
err
;
int
err
;
...
@@ -3674,8 +1046,19 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
...
@@ -3674,8 +1046,19 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
return
err
;
return
err
;
}
}
#ifdef ENABLE_AD_STATIC_QUIRKS
/*
static
int
patch_ad1884_basic
(
struct
hda_codec
*
codec
)
* AD1882 / AD1882A
*
* port-A - front hp-out
* port-B - front mic-in
* port-C - rear line-in, shared surr-out (3stack)
* port-D - rear line-out
* port-E - rear mic-in, shared clfe-out (3stack)
* port-F - rear surr-out (6stack)
* port-G - rear clfe-out (6stack)
*/
static
int
patch_ad1882
(
struct
hda_codec
*
codec
)
{
{
struct
ad198x_spec
*
spec
;
struct
ad198x_spec
*
spec
;
int
err
;
int
err
;
...
@@ -3685,1594 +1068,37 @@ static int patch_ad1884_basic(struct hda_codec *codec)
...
@@ -3685,1594 +1068,37 @@ static int patch_ad1884_basic(struct hda_codec *codec)
return
err
;
return
err
;
spec
=
codec
->
spec
;
spec
=
codec
->
spec
;
err
=
snd_hda_attach_beep_device
(
codec
,
0x10
);
spec
->
gen
.
mixer_nid
=
0x20
;
if
(
err
<
0
)
{
spec
->
gen
.
mixer_merge_nid
=
0x21
;
ad198x_free
(
codec
);
spec
->
gen
.
beep_nid
=
0x10
;
return
err
;
}
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
err
=
ad198x_parse_auto_config
(
codec
);
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
ARRAY_SIZE
(
ad1884_dac_nids
);
spec
->
multiout
.
dac_nids
=
ad1884_dac_nids
;
spec
->
multiout
.
dig_out_nid
=
AD1884_SPDIF_OUT
;
spec
->
num_adc_nids
=
ARRAY_SIZE
(
ad1884_adc_nids
);
spec
->
adc_nids
=
ad1884_adc_nids
;
spec
->
capsrc_nids
=
ad1884_capsrc_nids
;
spec
->
input_mux
=
&
ad1884_capture_source
;
spec
->
num_mixers
=
1
;
spec
->
mixers
[
0
]
=
ad1884_base_mixers
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1884_init_verbs
;
spec
->
spdif_route
=
0
;
#ifdef CONFIG_PM
spec
->
loopback
.
amplist
=
ad1884_loopbacks
;
#endif
spec
->
vmaster_nid
=
0x04
;
/* we need to cover all playback volumes */
spec
->
slave_vols
=
ad1884_slave_vols
;
/* slaves may contain input volumes, so we can't raise to 0dB blindly */
spec
->
avoid_init_slave_vol
=
1
;
codec
->
patch_ops
=
ad198x_patch_ops
;
codec
->
no_trigger_sense
=
1
;
codec
->
no_sticky_stream
=
1
;
return
0
;
}
static
int
patch_ad1884
(
struct
hda_codec
*
codec
)
{
int
board_config
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1884_MODELS
,
ad1884_models
,
NULL
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1884_AUTO
;
}
if
(
board_config
==
AD1884_AUTO
)
return
ad1884_parse_auto_config
(
codec
);
else
return
patch_ad1884_basic
(
codec
);
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1884 ad1884_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
#ifdef ENABLE_AD_STATIC_QUIRKS
/*
* Lenovo Thinkpad T61/X61
*/
static
const
struct
hda_input_mux
ad1984_thinkpad_capture_source
=
{
.
num_items
=
4
,
.
items
=
{
{
"Mic"
,
0x0
},
{
"Internal Mic"
,
0x1
},
{
"Mix"
,
0x3
},
{
"Dock Mic"
,
0x4
},
},
};
/*
* Dell Precision T3400
*/
static
const
struct
hda_input_mux
ad1984_dell_desktop_capture_source
=
{
.
num_items
=
3
,
.
items
=
{
{
"Front Mic"
,
0x0
},
{
"Line-In"
,
0x1
},
{
"Mix"
,
0x3
},
},
};
static
const
struct
snd_kcontrol_new
ad1984_thinkpad_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Speaker Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Internal Mic Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Beep Playback Volume"
,
0x20
,
0x03
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Beep Playback Switch"
,
0x20
,
0x03
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Dock Mic Playback Volume"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Dock Mic Playback Switch"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x14
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Boost Volume"
,
0x15
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Dock Mic Boost Volume"
,
0x25
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_IDX
(
"Capture Volume"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_IDX
(
"Capture Switch"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
/* The multiple "Capture Source" controls confuse alsamixer
* So call somewhat different..
*/
/* .name = "Capture Source", */
.
name
=
"Input Source"
,
.
count
=
2
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
/* SPDIF controls */
HDA_CODEC_VOLUME
(
"IEC958 Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
,
/* identical with ad1983 */
.
info
=
ad1983_spdif_route_info
,
.
get
=
ad1983_spdif_route_get
,
.
put
=
ad1983_spdif_route_put
,
},
{
}
/* end */
};
/* additional verbs */
static
const
struct
hda_verb
ad1984_thinkpad_init_verbs
[]
=
{
/* Port-E (docking station mic) pin */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x1c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* docking mic boost */
{
0x25
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* Analog PC Beeper - allow firmware/ACPI beeps */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
3
)
|
0x1a
},
/* Analog mixer - docking mic; mute as default */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
/* enable EAPD bit */
{
0x12
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x02
},
{
}
/* end */
};
/*
* Dell Precision T3400
*/
static
const
struct
snd_kcontrol_new
ad1984_dell_desktop_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Speaker Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Mono Playback Volume"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Mono Playback Switch"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line-In Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Line-In Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line-In Boost Volume"
,
0x15
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Boost Volume"
,
0x14
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_IDX
(
"Capture Volume"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_IDX
(
"Capture Switch"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
/* The multiple "Capture Source" controls confuse alsamixer
* So call somewhat different..
*/
/* .name = "Capture Source", */
.
name
=
"Input Source"
,
.
count
=
2
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
{
}
/* end */
};
/* Digial MIC ADC NID 0x05 + 0x06 */
static
int
ad1984_pcm_dmic_prepare
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
unsigned
int
stream_tag
,
unsigned
int
format
,
struct
snd_pcm_substream
*
substream
)
{
snd_hda_codec_setup_stream
(
codec
,
0x05
+
substream
->
number
,
stream_tag
,
0
,
format
);
return
0
;
}
static
int
ad1984_pcm_dmic_cleanup
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
codec
,
struct
snd_pcm_substream
*
substream
)
{
snd_hda_codec_cleanup_stream
(
codec
,
0x05
+
substream
->
number
);
return
0
;
}
static
const
struct
hda_pcm_stream
ad1984_pcm_dmic_capture
=
{
.
substreams
=
2
,
.
channels_min
=
2
,
.
channels_max
=
2
,
.
nid
=
0x05
,
.
ops
=
{
.
prepare
=
ad1984_pcm_dmic_prepare
,
.
cleanup
=
ad1984_pcm_dmic_cleanup
},
};
static
int
ad1984_build_pcms
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
=
codec
->
spec
;
struct
hda_pcm
*
info
;
int
err
;
err
=
ad198x_build_pcms
(
codec
);
if
(
err
<
0
)
if
(
err
<
0
)
return
err
;
goto
error
;
err
=
ad1988_add_spdif_mux_ctl
(
codec
);
info
=
spec
->
pcm_rec
+
codec
->
num_pcms
;
codec
->
num_pcms
++
;
info
->
name
=
"AD1984 Digital Mic"
;
info
->
stream
[
SNDRV_PCM_STREAM_CAPTURE
]
=
ad1984_pcm_dmic_capture
;
return
0
;
}
/* models */
enum
{
AD1984_AUTO
,
AD1984_BASIC
,
AD1984_THINKPAD
,
AD1984_DELL_DESKTOP
,
AD1984_MODELS
};
static
const
char
*
const
ad1984_models
[
AD1984_MODELS
]
=
{
[
AD1984_AUTO
]
=
"auto"
,
[
AD1984_BASIC
]
=
"basic"
,
[
AD1984_THINKPAD
]
=
"thinkpad"
,
[
AD1984_DELL_DESKTOP
]
=
"dell_desktop"
,
};
static
const
struct
snd_pci_quirk
ad1984_cfg_tbl
[]
=
{
/* Lenovo Thinkpad T61/X61 */
SND_PCI_QUIRK_VENDOR
(
0x17aa
,
"Lenovo Thinkpad"
,
AD1984_THINKPAD
),
SND_PCI_QUIRK
(
0x1028
,
0x0214
,
"Dell T3400"
,
AD1984_DELL_DESKTOP
),
SND_PCI_QUIRK
(
0x1028
,
0x0233
,
"Dell Latitude E6400"
,
AD1984_DELL_DESKTOP
),
{}
};
static
int
patch_ad1984
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
board_config
,
err
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1984_MODELS
,
ad1984_models
,
ad1984_cfg_tbl
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1984_AUTO
;
}
if
(
board_config
==
AD1984_AUTO
)
return
ad1884_parse_auto_config
(
codec
);
err
=
patch_ad1884_basic
(
codec
);
if
(
err
<
0
)
if
(
err
<
0
)
return
err
;
goto
error
;
spec
=
codec
->
spec
;
switch
(
board_config
)
{
case
AD1984_BASIC
:
/* additional digital mics */
spec
->
mixers
[
spec
->
num_mixers
++
]
=
ad1984_dmic_mixers
;
codec
->
patch_ops
.
build_pcms
=
ad1984_build_pcms
;
break
;
case
AD1984_THINKPAD
:
if
(
codec
->
subsystem_id
==
0x17aa20fb
)
{
/* Thinpad X300 does not have the ability to do SPDIF,
or attach to docking station to use SPDIF */
spec
->
multiout
.
dig_out_nid
=
0
;
}
else
spec
->
multiout
.
dig_out_nid
=
AD1884_SPDIF_OUT
;
spec
->
input_mux
=
&
ad1984_thinkpad_capture_source
;
spec
->
mixers
[
0
]
=
ad1984_thinkpad_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1984_thinkpad_init_verbs
;
spec
->
analog_beep
=
1
;
break
;
case
AD1984_DELL_DESKTOP
:
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1984_dell_desktop_capture_source
;
spec
->
mixers
[
0
]
=
ad1984_dell_desktop_mixers
;
break
;
}
return
0
;
return
0
;
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1984 ad1884_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
* AD1883 / AD1884A / AD1984A / AD1984B
*
* port-B (0x14) - front mic-in
* port-E (0x1c) - rear mic-in
* port-F (0x16) - CD / ext out
* port-C (0x15) - rear line-in
* port-D (0x12) - rear line-out
* port-A (0x11) - front hp-out
*
* AD1984A = AD1884A + digital-mic
* AD1883 = equivalent with AD1984A
* AD1984B = AD1984A + extra SPDIF-out
*
* FIXME:
* We share the single DAC for both HP and line-outs (see AD1884/1984).
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
static
const
hda_nid_t
ad1884a_dac_nids
[
1
]
=
{
0x03
,
};
#define ad1884a_adc_nids ad1884_adc_nids
#define ad1884a_capsrc_nids ad1884_capsrc_nids
#define AD1884A_SPDIF_OUT 0x02
static
const
struct
hda_input_mux
ad1884a_capture_source
=
{
.
num_items
=
5
,
.
items
=
{
{
"Front Mic"
,
0x0
},
{
"Mic"
,
0x4
},
{
"Line"
,
0x1
},
{
"CD"
,
0x2
},
{
"Mix"
,
0x3
},
},
};
static
const
struct
snd_kcontrol_new
ad1884a_base_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Master Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Master Playback Switch"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Front Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Mono Playback Volume"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Mono Playback Switch"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x20
,
0x02
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x20
,
0x02
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Boost Volume"
,
0x14
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line Boost Volume"
,
0x15
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x25
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_IDX
(
"Capture Volume"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_IDX
(
"Capture Switch"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
/* The multiple "Capture Source" controls confuse alsamixer
* So call somewhat different..
*/
/* .name = "Capture Source", */
.
name
=
"Input Source"
,
.
count
=
2
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
/* SPDIF controls */
HDA_CODEC_VOLUME
(
"IEC958 Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
,
/* identical with ad1983 */
.
info
=
ad1983_spdif_route_info
,
.
get
=
ad1983_spdif_route_get
,
.
put
=
ad1983_spdif_route_put
,
},
{
}
/* end */
};
/*
* initialization verbs
*/
static
const
struct
hda_verb
ad1884a_init_verbs
[]
=
{
/* DACs; unmute as default */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x27
},
/* 0dB */
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x27
},
/* 0dB */
/* Port-A (HP) mixer - route only from analog mixer */
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-A pin */
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Port-D (Line-out) mixer - route only from analog mixer */
{
0x0a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x0a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-D pin */
{
0x12
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Mono-out mixer - route only from analog mixer */
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Mono-out pin */
{
0x13
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Port-B (front mic) pin */
{
0x14
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
/* Port-C (rear line-in) pin */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
/* Port-E (rear mic) pin */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x1c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x25
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* no boost */
/* Port-F (CD) pin */
{
0x16
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
{
0x16
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Analog mixer; mute as default */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
4
)},
/* aux */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
5
)},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* capture sources */
{
0x0c
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x0c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x0d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* SPDIF output amp */
{
0x1b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x27
},
/* 0dB */
{
}
/* end */
};
#ifdef CONFIG_PM
static
const
struct
hda_amp_list
ad1884a_loopbacks
[]
=
{
{
0x20
,
HDA_INPUT
,
0
},
/* Front Mic */
{
0x20
,
HDA_INPUT
,
1
},
/* Mic */
{
0x20
,
HDA_INPUT
,
2
},
/* CD */
{
0x20
,
HDA_INPUT
,
4
},
/* Docking */
{
}
/* end */
};
#endif
/*
* Laptop model
*
* Port A: Headphone jack
* Port B: MIC jack
* Port C: Internal MIC
* Port D: Dock Line Out (if enabled)
* Port E: Dock Line In (if enabled)
* Port F: Internal speakers
*/
static
int
ad1884a_mobile_master_sw_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hda_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
int
ret
=
snd_hda_mixer_amp_switch_put
(
kcontrol
,
ucontrol
);
int
mute
=
(
!
ucontrol
->
value
.
integer
.
value
[
0
]
&&
!
ucontrol
->
value
.
integer
.
value
[
1
]);
/* toggle GPIO1 according to the mute state */
snd_hda_codec_write_cache
(
codec
,
0x01
,
0
,
AC_VERB_SET_GPIO_DATA
,
mute
?
0x02
:
0x0
);
return
ret
;
}
static
const
struct
snd_kcontrol_new
ad1884a_laptop_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Master Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Master Playback Switch"
,
.
subdevice
=
HDA_SUBDEV_AMP_FLAG
,
.
info
=
snd_hda_mixer_amp_switch_info
,
.
get
=
snd_hda_mixer_amp_switch_get
,
.
put
=
ad1884a_mobile_master_sw_put
,
.
private_value
=
HDA_COMPOSE_AMP_VAL
(
0x21
,
3
,
0
,
HDA_OUTPUT
),
},
HDA_CODEC_MUTE
(
"Dock Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Internal Mic Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Dock Mic Playback Volume"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Dock Mic Playback Switch"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x14
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Boost Volume"
,
0x15
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Dock Mic Boost Volume"
,
0x25
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1884a_mobile_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Master Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
/*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Master Playback Switch"
,
.
subdevice
=
HDA_SUBDEV_AMP_FLAG
,
.
info
=
snd_hda_mixer_amp_switch_info
,
.
get
=
snd_hda_mixer_amp_switch_get
,
.
put
=
ad1884a_mobile_master_sw_put
,
.
private_value
=
HDA_COMPOSE_AMP_VAL
(
0x21
,
3
,
0
,
HDA_OUTPUT
),
},
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Capture Volume"
,
0x14
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Capture Volume"
,
0x15
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
/* mute internal speaker if HP is plugged */
static
void
ad1884a_hp_automute
(
struct
hda_codec
*
codec
)
{
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x11
);
error:
snd_hda_codec_amp_stereo
(
codec
,
0x16
,
HDA_OUTPUT
,
0
,
snd_hda_gen_free
(
codec
);
HDA_AMP_MUTE
,
present
?
HDA_AMP_MUTE
:
0
);
return
err
;
snd_hda_codec_write
(
codec
,
0x16
,
0
,
AC_VERB_SET_EAPD_BTLENABLE
,
present
?
0x00
:
0x02
);
}
}
/* switch to external mic if plugged */
static
void
ad1884a_hp_automic
(
struct
hda_codec
*
codec
)
{
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x14
);
snd_hda_codec_write
(
codec
,
0x0c
,
0
,
AC_VERB_SET_CONNECT_SEL
,
present
?
0
:
1
);
}
#define AD1884A_HP_EVENT 0x37
#define AD1884A_MIC_EVENT 0x36
/* unsolicited event for HP jack sensing */
static
void
ad1884a_hp_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
switch
(
res
>>
26
)
{
case
AD1884A_HP_EVENT
:
ad1884a_hp_automute
(
codec
);
break
;
case
AD1884A_MIC_EVENT
:
ad1884a_hp_automic
(
codec
);
break
;
}
}
/* initialize jack-sensing, too */
static
int
ad1884a_hp_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1884a_hp_automute
(
codec
);
ad1884a_hp_automic
(
codec
);
return
0
;
}
/* mute internal speaker if HP or docking HP is plugged */
static
void
ad1884a_laptop_automute
(
struct
hda_codec
*
codec
)
{
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x11
);
if
(
!
present
)
present
=
snd_hda_jack_detect
(
codec
,
0x12
);
snd_hda_codec_amp_stereo
(
codec
,
0x16
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
present
?
HDA_AMP_MUTE
:
0
);
snd_hda_codec_write
(
codec
,
0x16
,
0
,
AC_VERB_SET_EAPD_BTLENABLE
,
present
?
0x00
:
0x02
);
}
/* switch to external mic if plugged */
static
void
ad1884a_laptop_automic
(
struct
hda_codec
*
codec
)
{
unsigned
int
idx
;
if
(
snd_hda_jack_detect
(
codec
,
0x14
))
idx
=
0
;
else
if
(
snd_hda_jack_detect
(
codec
,
0x1c
))
idx
=
4
;
else
idx
=
1
;
snd_hda_codec_write
(
codec
,
0x0c
,
0
,
AC_VERB_SET_CONNECT_SEL
,
idx
);
}
/* unsolicited event for HP jack sensing */
static
void
ad1884a_laptop_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
switch
(
res
>>
26
)
{
case
AD1884A_HP_EVENT
:
ad1884a_laptop_automute
(
codec
);
break
;
case
AD1884A_MIC_EVENT
:
ad1884a_laptop_automic
(
codec
);
break
;
}
}
/* initialize jack-sensing, too */
static
int
ad1884a_laptop_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1884a_laptop_automute
(
codec
);
ad1884a_laptop_automic
(
codec
);
return
0
;
}
/* additional verbs for laptop model */
static
const
struct
hda_verb
ad1884a_laptop_verbs
[]
=
{
/* Port-A (HP) pin - always unmuted */
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Port-F (int speaker) mixer - route only from analog mixer */
{
0x0b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x0b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-F (int speaker) pin */
{
0x16
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x16
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* required for compaq 6530s/6531s speaker output */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
/* Port-C pin - internal mic-in */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x7002
},
/* raise mic as default */
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x7002
},
/* raise mic as default */
/* Port-D (docking line-out) pin - default unmuted */
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* analog mix */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
/* unsolicited event for pin-sense */
{
0x11
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_HP_EVENT
},
{
0x12
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_HP_EVENT
},
{
0x14
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_MIC_EVENT
},
{
0x1c
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_MIC_EVENT
},
/* allow to touch GPIO1 (for mute control) */
{
0x01
,
AC_VERB_SET_GPIO_MASK
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DIRECTION
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DATA
,
0x02
},
/* first muted */
{
}
/* end */
};
static
const
struct
hda_verb
ad1884a_mobile_verbs
[]
=
{
/* DACs; unmute as default */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x27
},
/* 0dB */
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x27
},
/* 0dB */
/* Port-A (HP) mixer - route only from analog mixer */
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-A pin */
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
/* Port-A (HP) pin - always unmuted */
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Port-B (mic jack) pin */
{
0x14
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x7002
},
/* raise mic as default */
/* Port-C (int mic) pin */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x7002
},
/* raise mic as default */
/* Port-F (int speaker) mixer - route only from analog mixer */
{
0x0b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x0b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-F pin */
{
0x16
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x16
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Analog mixer; mute as default */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
5
)},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* capture sources */
/* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */
/* set via unsol */
{
0x0c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x0d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* unsolicited event for pin-sense */
{
0x11
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_HP_EVENT
},
{
0x14
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_MIC_EVENT
},
/* allow to touch GPIO1 (for mute control) */
{
0x01
,
AC_VERB_SET_GPIO_MASK
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DIRECTION
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DATA
,
0x02
},
/* first muted */
{
}
/* end */
};
/*
* Thinkpad X300
* 0x11 - HP
* 0x12 - speaker
* 0x14 - mic-in
* 0x17 - built-in mic
*/
static
const
struct
hda_verb
ad1984a_thinkpad_verbs
[]
=
{
/* HP unmute */
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* analog mix */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
/* turn on EAPD */
{
0x12
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x02
},
/* unsolicited event for pin-sense */
{
0x11
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_HP_EVENT
},
/* internal mic - dmic */
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* set magic COEFs for dmic */
{
0x01
,
AC_VERB_SET_COEF_INDEX
,
0x13f7
},
{
0x01
,
AC_VERB_SET_PROC_COEF
,
0x08
},
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1984a_thinkpad_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Master Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Master Playback Switch"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x14
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Boost Volume"
,
0x17
,
0x0
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Capture Source"
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
{
}
/* end */
};
static
const
struct
hda_input_mux
ad1984a_thinkpad_capture_source
=
{
.
num_items
=
3
,
.
items
=
{
{
"Mic"
,
0x0
},
{
"Internal Mic"
,
0x5
},
{
"Mix"
,
0x3
},
},
};
/* mute internal speaker if HP is plugged */
static
void
ad1984a_thinkpad_automute
(
struct
hda_codec
*
codec
)
{
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x11
);
snd_hda_codec_amp_stereo
(
codec
,
0x12
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
present
?
HDA_AMP_MUTE
:
0
);
}
/* unsolicited event for HP jack sensing */
static
void
ad1984a_thinkpad_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
if
((
res
>>
26
)
!=
AD1884A_HP_EVENT
)
return
;
ad1984a_thinkpad_automute
(
codec
);
}
/* initialize jack-sensing, too */
static
int
ad1984a_thinkpad_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1984a_thinkpad_automute
(
codec
);
return
0
;
}
/*
* Precision R5500
* 0x12 - HP/line-out
* 0x13 - speaker (mono)
* 0x15 - mic-in
*/
static
const
struct
hda_verb
ad1984a_precision_verbs
[]
=
{
/* Unmute main output path */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x27
},
/* 0dB */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
+
0x1f
},
/* 0dB */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
5
)
+
0x17
},
/* 0dB */
/* Analog mixer; mute as default */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
/* Select mic as input */
{
0x0c
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
{
0x0c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
+
0x27
},
/* 0dB */
/* Configure as mic */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x7002
},
/* raise mic as default */
/* HP unmute */
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* turn on EAPD */
{
0x13
,
AC_VERB_SET_EAPD_BTLENABLE
,
0x02
},
/* unsolicited event for pin-sense */
{
0x12
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_HP_EVENT
},
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1984a_precision_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Master Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Master Playback Switch"
,
0x21
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x15
,
0x0
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Speaker Playback Volume"
,
0x13
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
/* mute internal speaker if HP is plugged */
static
void
ad1984a_precision_automute
(
struct
hda_codec
*
codec
)
{
unsigned
int
present
;
present
=
snd_hda_jack_detect
(
codec
,
0x12
);
snd_hda_codec_amp_stereo
(
codec
,
0x13
,
HDA_OUTPUT
,
0
,
HDA_AMP_MUTE
,
present
?
HDA_AMP_MUTE
:
0
);
}
/* unsolicited event for HP jack sensing */
static
void
ad1984a_precision_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
if
((
res
>>
26
)
!=
AD1884A_HP_EVENT
)
return
;
ad1984a_precision_automute
(
codec
);
}
/* initialize jack-sensing, too */
static
int
ad1984a_precision_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1984a_precision_automute
(
codec
);
return
0
;
}
/*
* HP Touchsmart
* port-A (0x11) - front hp-out
* port-B (0x14) - unused
* port-C (0x15) - unused
* port-D (0x12) - rear line out
* port-E (0x1c) - front mic-in
* port-F (0x16) - Internal speakers
* digital-mic (0x17) - Internal mic
*/
static
const
struct
hda_verb
ad1984a_touchsmart_verbs
[]
=
{
/* DACs; unmute as default */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x27
},
/* 0dB */
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x27
},
/* 0dB */
/* Port-A (HP) mixer - route only from analog mixer */
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x07
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-A pin */
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
/* Port-A (HP) pin - always unmuted */
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
/* Port-E (int speaker) mixer - route only from analog mixer */
{
0x25
,
AC_VERB_SET_AMP_GAIN_MUTE
,
0x03
},
/* Port-E pin */
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
{
0x1c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
},
{
0x1c
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
/* Port-F (int speaker) mixer - route only from analog mixer */
{
0x0b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x0b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-F pin */
{
0x16
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x16
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Analog mixer; mute as default */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
5
)},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* capture sources */
/* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */
/* set via unsol */
{
0x0c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x0d
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
{
0x0d
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* unsolicited event for pin-sense */
{
0x11
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_HP_EVENT
},
{
0x1c
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1884A_MIC_EVENT
},
/* allow to touch GPIO1 (for mute control) */
{
0x01
,
AC_VERB_SET_GPIO_MASK
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DIRECTION
,
0x02
},
{
0x01
,
AC_VERB_SET_GPIO_DATA
,
0x02
},
/* first muted */
/* internal mic - dmic */
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
/* set magic COEFs for dmic */
{
0x01
,
AC_VERB_SET_COEF_INDEX
,
0x13f7
},
{
0x01
,
AC_VERB_SET_PROC_COEF
,
0x08
},
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1984a_touchsmart_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Master Playback Volume"
,
0x21
,
0x0
,
HDA_OUTPUT
),
/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
subdevice
=
HDA_SUBDEV_AMP_FLAG
,
.
name
=
"Master Playback Switch"
,
.
info
=
snd_hda_mixer_amp_switch_info
,
.
get
=
snd_hda_mixer_amp_switch_get
,
.
put
=
ad1884a_mobile_master_sw_put
,
.
private_value
=
HDA_COMPOSE_AMP_VAL
(
0x21
,
3
,
0
,
HDA_OUTPUT
),
},
HDA_CODEC_VOLUME
(
"PCM Playback Volume"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"PCM Playback Switch"
,
0x20
,
0x5
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x25
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Internal Mic Boost Volume"
,
0x17
,
0x0
,
HDA_INPUT
),
{
}
/* end */
};
/* switch to external mic if plugged */
static
void
ad1984a_touchsmart_automic
(
struct
hda_codec
*
codec
)
{
if
(
snd_hda_jack_detect
(
codec
,
0x1c
))
snd_hda_codec_write
(
codec
,
0x0c
,
0
,
AC_VERB_SET_CONNECT_SEL
,
0x4
);
else
snd_hda_codec_write
(
codec
,
0x0c
,
0
,
AC_VERB_SET_CONNECT_SEL
,
0x5
);
}
/* unsolicited event for HP jack sensing */
static
void
ad1984a_touchsmart_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
switch
(
res
>>
26
)
{
case
AD1884A_HP_EVENT
:
ad1884a_hp_automute
(
codec
);
break
;
case
AD1884A_MIC_EVENT
:
ad1984a_touchsmart_automic
(
codec
);
break
;
}
}
/* initialize jack-sensing, too */
static
int
ad1984a_touchsmart_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1884a_hp_automute
(
codec
);
ad1984a_touchsmart_automic
(
codec
);
return
0
;
}
/*
*/
enum
{
AD1884A_AUTO
,
AD1884A_DESKTOP
,
AD1884A_LAPTOP
,
AD1884A_MOBILE
,
AD1884A_THINKPAD
,
AD1984A_TOUCHSMART
,
AD1984A_PRECISION
,
AD1884A_MODELS
};
static
const
char
*
const
ad1884a_models
[
AD1884A_MODELS
]
=
{
[
AD1884A_AUTO
]
=
"auto"
,
[
AD1884A_DESKTOP
]
=
"desktop"
,
[
AD1884A_LAPTOP
]
=
"laptop"
,
[
AD1884A_MOBILE
]
=
"mobile"
,
[
AD1884A_THINKPAD
]
=
"thinkpad"
,
[
AD1984A_TOUCHSMART
]
=
"touchsmart"
,
[
AD1984A_PRECISION
]
=
"precision"
,
};
static
const
struct
snd_pci_quirk
ad1884a_cfg_tbl
[]
=
{
SND_PCI_QUIRK
(
0x1028
,
0x04ac
,
"Precision R5500"
,
AD1984A_PRECISION
),
SND_PCI_QUIRK
(
0x103c
,
0x3030
,
"HP"
,
AD1884A_MOBILE
),
SND_PCI_QUIRK
(
0x103c
,
0x3037
,
"HP 2230s"
,
AD1884A_LAPTOP
),
SND_PCI_QUIRK
(
0x103c
,
0x3056
,
"HP"
,
AD1884A_MOBILE
),
SND_PCI_QUIRK_MASK
(
0x103c
,
0xfff0
,
0x3070
,
"HP"
,
AD1884A_MOBILE
),
SND_PCI_QUIRK_MASK
(
0x103c
,
0xfff0
,
0x30d0
,
"HP laptop"
,
AD1884A_LAPTOP
),
SND_PCI_QUIRK_MASK
(
0x103c
,
0xfff0
,
0x30e0
,
"HP laptop"
,
AD1884A_LAPTOP
),
SND_PCI_QUIRK_MASK
(
0x103c
,
0xff00
,
0x3600
,
"HP laptop"
,
AD1884A_LAPTOP
),
SND_PCI_QUIRK_MASK
(
0x103c
,
0xfff0
,
0x7010
,
"HP laptop"
,
AD1884A_MOBILE
),
SND_PCI_QUIRK
(
0x17aa
,
0x20ac
,
"Thinkpad X300"
,
AD1884A_THINKPAD
),
SND_PCI_QUIRK
(
0x103c
,
0x2a82
,
"Touchsmart"
,
AD1984A_TOUCHSMART
),
{}
};
static
int
patch_ad1884a
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
err
,
board_config
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1884A_MODELS
,
ad1884a_models
,
ad1884a_cfg_tbl
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1884A_AUTO
;
}
if
(
board_config
==
AD1884A_AUTO
)
return
ad1884_parse_auto_config
(
codec
);
err
=
alloc_ad_spec
(
codec
);
if
(
err
<
0
)
return
err
;
spec
=
codec
->
spec
;
err
=
snd_hda_attach_beep_device
(
codec
,
0x10
);
if
(
err
<
0
)
{
ad198x_free
(
codec
);
return
err
;
}
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
ARRAY_SIZE
(
ad1884a_dac_nids
);
spec
->
multiout
.
dac_nids
=
ad1884a_dac_nids
;
spec
->
multiout
.
dig_out_nid
=
AD1884A_SPDIF_OUT
;
spec
->
num_adc_nids
=
ARRAY_SIZE
(
ad1884a_adc_nids
);
spec
->
adc_nids
=
ad1884a_adc_nids
;
spec
->
capsrc_nids
=
ad1884a_capsrc_nids
;
spec
->
input_mux
=
&
ad1884a_capture_source
;
spec
->
num_mixers
=
1
;
spec
->
mixers
[
0
]
=
ad1884a_base_mixers
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1884a_init_verbs
;
spec
->
spdif_route
=
0
;
#ifdef CONFIG_PM
spec
->
loopback
.
amplist
=
ad1884a_loopbacks
;
#endif
codec
->
patch_ops
=
ad198x_patch_ops
;
/* override some parameters */
switch
(
board_config
)
{
case
AD1884A_LAPTOP
:
spec
->
mixers
[
0
]
=
ad1884a_laptop_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1884a_laptop_verbs
;
spec
->
multiout
.
dig_out_nid
=
0
;
codec
->
patch_ops
.
unsol_event
=
ad1884a_laptop_unsol_event
;
codec
->
patch_ops
.
init
=
ad1884a_laptop_init
;
/* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading
*/
snd_hda_override_amp_caps
(
codec
,
0x20
,
HDA_INPUT
,
(
0x17
<<
AC_AMPCAP_OFFSET_SHIFT
)
|
(
0x17
<<
AC_AMPCAP_NUM_STEPS_SHIFT
)
|
(
0x05
<<
AC_AMPCAP_STEP_SIZE_SHIFT
)
|
(
1
<<
AC_AMPCAP_MUTE_SHIFT
));
break
;
case
AD1884A_MOBILE
:
spec
->
mixers
[
0
]
=
ad1884a_mobile_mixers
;
spec
->
init_verbs
[
0
]
=
ad1884a_mobile_verbs
;
spec
->
multiout
.
dig_out_nid
=
0
;
codec
->
patch_ops
.
unsol_event
=
ad1884a_hp_unsol_event
;
codec
->
patch_ops
.
init
=
ad1884a_hp_init
;
/* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading
*/
snd_hda_override_amp_caps
(
codec
,
0x20
,
HDA_INPUT
,
(
0x17
<<
AC_AMPCAP_OFFSET_SHIFT
)
|
(
0x17
<<
AC_AMPCAP_NUM_STEPS_SHIFT
)
|
(
0x05
<<
AC_AMPCAP_STEP_SIZE_SHIFT
)
|
(
1
<<
AC_AMPCAP_MUTE_SHIFT
));
break
;
case
AD1884A_THINKPAD
:
spec
->
mixers
[
0
]
=
ad1984a_thinkpad_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1984a_thinkpad_verbs
;
spec
->
multiout
.
dig_out_nid
=
0
;
spec
->
input_mux
=
&
ad1984a_thinkpad_capture_source
;
codec
->
patch_ops
.
unsol_event
=
ad1984a_thinkpad_unsol_event
;
codec
->
patch_ops
.
init
=
ad1984a_thinkpad_init
;
break
;
case
AD1984A_PRECISION
:
spec
->
mixers
[
0
]
=
ad1984a_precision_mixers
;
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1984a_precision_verbs
;
spec
->
multiout
.
dig_out_nid
=
0
;
codec
->
patch_ops
.
unsol_event
=
ad1984a_precision_unsol_event
;
codec
->
patch_ops
.
init
=
ad1984a_precision_init
;
break
;
case
AD1984A_TOUCHSMART
:
spec
->
mixers
[
0
]
=
ad1984a_touchsmart_mixers
;
spec
->
init_verbs
[
0
]
=
ad1984a_touchsmart_verbs
;
spec
->
multiout
.
dig_out_nid
=
0
;
codec
->
patch_ops
.
unsol_event
=
ad1984a_touchsmart_unsol_event
;
codec
->
patch_ops
.
init
=
ad1984a_touchsmart_init
;
/* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading
*/
snd_hda_override_amp_caps
(
codec
,
0x20
,
HDA_INPUT
,
(
0x17
<<
AC_AMPCAP_OFFSET_SHIFT
)
|
(
0x17
<<
AC_AMPCAP_NUM_STEPS_SHIFT
)
|
(
0x05
<<
AC_AMPCAP_STEP_SIZE_SHIFT
)
|
(
1
<<
AC_AMPCAP_MUTE_SHIFT
));
break
;
}
codec
->
no_trigger_sense
=
1
;
codec
->
no_sticky_stream
=
1
;
return
0
;
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1884a ad1884_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
* AD1882 / AD1882A
*
* port-A - front hp-out
* port-B - front mic-in
* port-C - rear line-in, shared surr-out (3stack)
* port-D - rear line-out
* port-E - rear mic-in, shared clfe-out (3stack)
* port-F - rear surr-out (6stack)
* port-G - rear clfe-out (6stack)
*/
#ifdef ENABLE_AD_STATIC_QUIRKS
static
const
hda_nid_t
ad1882_dac_nids
[
3
]
=
{
0x04
,
0x03
,
0x05
};
static
const
hda_nid_t
ad1882_adc_nids
[
2
]
=
{
0x08
,
0x09
,
};
static
const
hda_nid_t
ad1882_capsrc_nids
[
2
]
=
{
0x0c
,
0x0d
,
};
#define AD1882_SPDIF_OUT 0x02
/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
static
const
struct
hda_input_mux
ad1882_capture_source
=
{
.
num_items
=
5
,
.
items
=
{
{
"Front Mic"
,
0x1
},
{
"Mic"
,
0x4
},
{
"Line"
,
0x2
},
{
"CD"
,
0x3
},
{
"Mix"
,
0x7
},
},
};
/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
static
const
struct
hda_input_mux
ad1882a_capture_source
=
{
.
num_items
=
5
,
.
items
=
{
{
"Front Mic"
,
0x1
},
{
"Mic"
,
0x4
},
{
"Line"
,
0x2
},
{
"Digital Mic"
,
0x06
},
{
"Mix"
,
0x7
},
},
};
static
const
struct
snd_kcontrol_new
ad1882_base_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Front Playback Volume"
,
0x04
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Surround Playback Volume"
,
0x03
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Center Playback Volume"
,
0x05
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"LFE Playback Volume"
,
0x05
,
2
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Headphone Playback Switch"
,
0x11
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Front Playback Switch"
,
0x12
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_MONO
(
"Mono Playback Volume"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Mono Playback Switch"
,
0x13
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Mic Boost Volume"
,
0x3c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Front Mic Boost Volume"
,
0x39
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Line-In Boost Volume"
,
0x3a
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME
(
"Capture Volume"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE
(
"Capture Switch"
,
0x0c
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_VOLUME_IDX
(
"Capture Volume"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_IDX
(
"Capture Switch"
,
1
,
0x0d
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
/* The multiple "Capture Source" controls confuse alsamixer
* So call somewhat different..
*/
/* .name = "Capture Source", */
.
name
=
"Input Source"
,
.
count
=
2
,
.
info
=
ad198x_mux_enum_info
,
.
get
=
ad198x_mux_enum_get
,
.
put
=
ad198x_mux_enum_put
,
},
/* SPDIF controls */
HDA_CODEC_VOLUME
(
"IEC958 Playback Volume"
,
0x1b
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
SNDRV_CTL_NAME_IEC958
(
""
,
PLAYBACK
,
NONE
)
"Source"
,
/* identical with ad1983 */
.
info
=
ad1983_spdif_route_info
,
.
get
=
ad1983_spdif_route_get
,
.
put
=
ad1983_spdif_route_put
,
},
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1882_loopback_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x20
,
0x06
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x20
,
0x06
,
HDA_INPUT
),
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1882a_loopback_mixers
[]
=
{
HDA_CODEC_VOLUME
(
"Front Mic Playback Volume"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Front Mic Playback Switch"
,
0x20
,
0x00
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Mic Playback Volume"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Mic Playback Switch"
,
0x20
,
0x04
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Line Playback Volume"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"Line Playback Switch"
,
0x20
,
0x01
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"CD Playback Volume"
,
0x20
,
0x06
,
HDA_INPUT
),
HDA_CODEC_MUTE
(
"CD Playback Switch"
,
0x20
,
0x06
,
HDA_INPUT
),
HDA_CODEC_VOLUME
(
"Digital Mic Boost Volume"
,
0x1f
,
0x0
,
HDA_INPUT
),
{
}
/* end */
};
static
const
struct
snd_kcontrol_new
ad1882_3stack_mixers
[]
=
{
HDA_CODEC_MUTE
(
"Surround Playback Switch"
,
0x15
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Center Playback Switch"
,
0x17
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"LFE Playback Switch"
,
0x17
,
2
,
0x0
,
HDA_OUTPUT
),
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
"Channel Mode"
,
.
info
=
ad198x_ch_mode_info
,
.
get
=
ad198x_ch_mode_get
,
.
put
=
ad198x_ch_mode_put
,
},
{
}
/* end */
};
/* simple auto-mute control for AD1882 3-stack board */
#define AD1882_HP_EVENT 0x01
static
void
ad1882_3stack_automute
(
struct
hda_codec
*
codec
)
{
bool
mute
=
snd_hda_jack_detect
(
codec
,
0x11
);
snd_hda_codec_write
(
codec
,
0x12
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
mute
?
0
:
PIN_OUT
);
}
static
int
ad1882_3stack_automute_init
(
struct
hda_codec
*
codec
)
{
ad198x_init
(
codec
);
ad1882_3stack_automute
(
codec
);
return
0
;
}
static
void
ad1882_3stack_unsol_event
(
struct
hda_codec
*
codec
,
unsigned
int
res
)
{
switch
(
res
>>
26
)
{
case
AD1882_HP_EVENT
:
ad1882_3stack_automute
(
codec
);
break
;
}
}
static
const
struct
snd_kcontrol_new
ad1882_6stack_mixers
[]
=
{
HDA_CODEC_MUTE
(
"Surround Playback Switch"
,
0x16
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"Center Playback Switch"
,
0x24
,
1
,
0x0
,
HDA_OUTPUT
),
HDA_CODEC_MUTE_MONO
(
"LFE Playback Switch"
,
0x24
,
2
,
0x0
,
HDA_OUTPUT
),
{
}
/* end */
};
static
const
struct
hda_verb
ad1882_ch2_init
[]
=
{
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
}
/* end */
};
static
const
struct
hda_verb
ad1882_ch4_init
[]
=
{
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
}
/* end */
};
static
const
struct
hda_verb
ad1882_ch6_init
[]
=
{
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
{
}
/* end */
};
static
const
struct
hda_channel_mode
ad1882_modes
[
3
]
=
{
{
2
,
ad1882_ch2_init
},
{
4
,
ad1882_ch4_init
},
{
6
,
ad1882_ch6_init
},
};
/*
* initialization verbs
*/
static
const
struct
hda_verb
ad1882_init_verbs
[]
=
{
/* DACs; mute as default */
{
0x03
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x04
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
{
0x05
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* Port-A (HP) mixer */
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x22
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-A pin */
{
0x11
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x11
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* HP selector - select DAC2 */
{
0x37
,
AC_VERB_SET_CONNECT_SEL
,
0x1
},
/* Port-D (Line-out) mixer */
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x29
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Port-D pin */
{
0x12
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x12
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Mono-out mixer */
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
0
)},
{
0x1e
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_UNMUTE
(
1
)},
/* Mono-out pin */
{
0x13
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_HP
},
{
0x13
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Port-B (front mic) pin */
{
0x14
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x14
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x39
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* boost */
/* Port-C (line-in) pin */
{
0x15
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_IN
},
{
0x15
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x3a
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* boost */
/* Port-C mixer - mute as input */
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x2c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
/* Port-E (mic-in) pin */
{
0x17
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_VREF80
},
{
0x17
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
{
0x3c
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_ZERO
},
/* boost */
/* Port-E mixer - mute as input */
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x26
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
/* Port-F (surround) */
{
0x16
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x16
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Port-G (CLFE) */
{
0x24
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
},
{
0x24
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
},
/* Analog mixer; mute as default */
/* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
0
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
1
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
2
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
3
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
4
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
5
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
6
)},
{
0x20
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_IN_MUTE
(
7
)},
/* Analog Mix output amp */
{
0x21
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x1f
},
/* 0dB */
/* SPDIF output selector */
{
0x02
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x27
},
/* 0dB */
{
0x02
,
AC_VERB_SET_CONNECT_SEL
,
0x0
},
/* PCM */
{
0x1b
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
|
0x27
},
/* 0dB */
{
}
/* end */
};
static
const
struct
hda_verb
ad1882_3stack_automute_verbs
[]
=
{
{
0x11
,
AC_VERB_SET_UNSOLICITED_ENABLE
,
AC_USRSP_EN
|
AD1882_HP_EVENT
},
{
}
/* end */
};
#ifdef CONFIG_PM
static
const
struct
hda_amp_list
ad1882_loopbacks
[]
=
{
{
0x20
,
HDA_INPUT
,
0
},
/* Front Mic */
{
0x20
,
HDA_INPUT
,
1
},
/* Mic */
{
0x20
,
HDA_INPUT
,
4
},
/* Line */
{
0x20
,
HDA_INPUT
,
6
},
/* CD */
{
}
/* end */
};
#endif
/* models */
enum
{
AD1882_AUTO
,
AD1882_3STACK
,
AD1882_6STACK
,
AD1882_3STACK_AUTOMUTE
,
AD1882_MODELS
};
static
const
char
*
const
ad1882_models
[
AD1986A_MODELS
]
=
{
[
AD1882_AUTO
]
=
"auto"
,
[
AD1882_3STACK
]
=
"3stack"
,
[
AD1882_6STACK
]
=
"6stack"
,
[
AD1882_3STACK_AUTOMUTE
]
=
"3stack-automute"
,
};
#endif
/* ENABLE_AD_STATIC_QUIRKS */
static
int
ad1882_parse_auto_config
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
err
;
err
=
alloc_ad_spec
(
codec
);
if
(
err
<
0
)
return
err
;
spec
=
codec
->
spec
;
spec
->
gen
.
mixer_nid
=
0x20
;
spec
->
gen
.
mixer_merge_nid
=
0x21
;
spec
->
gen
.
beep_nid
=
0x10
;
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
err
=
ad198x_parse_auto_config
(
codec
);
if
(
err
<
0
)
goto
error
;
err
=
ad1988_add_spdif_mux_ctl
(
codec
);
if
(
err
<
0
)
goto
error
;
return
0
;
error:
snd_hda_gen_free
(
codec
);
return
err
;
}
#ifdef ENABLE_AD_STATIC_QUIRKS
static
int
patch_ad1882
(
struct
hda_codec
*
codec
)
{
struct
ad198x_spec
*
spec
;
int
err
,
board_config
;
board_config
=
snd_hda_check_board_config
(
codec
,
AD1882_MODELS
,
ad1882_models
,
NULL
);
if
(
board_config
<
0
)
{
printk
(
KERN_INFO
"hda_codec: %s: BIOS auto-probing.
\n
"
,
codec
->
chip_name
);
board_config
=
AD1882_AUTO
;
}
if
(
board_config
==
AD1882_AUTO
)
return
ad1882_parse_auto_config
(
codec
);
err
=
alloc_ad_spec
(
codec
);
if
(
err
<
0
)
return
err
;
spec
=
codec
->
spec
;
err
=
snd_hda_attach_beep_device
(
codec
,
0x10
);
if
(
err
<
0
)
{
ad198x_free
(
codec
);
return
err
;
}
set_beep_amp
(
spec
,
0x10
,
0
,
HDA_OUTPUT
);
spec
->
multiout
.
max_channels
=
6
;
spec
->
multiout
.
num_dacs
=
3
;
spec
->
multiout
.
dac_nids
=
ad1882_dac_nids
;
spec
->
multiout
.
dig_out_nid
=
AD1882_SPDIF_OUT
;
spec
->
num_adc_nids
=
ARRAY_SIZE
(
ad1882_adc_nids
);
spec
->
adc_nids
=
ad1882_adc_nids
;
spec
->
capsrc_nids
=
ad1882_capsrc_nids
;
if
(
codec
->
vendor_id
==
0x11d41882
)
spec
->
input_mux
=
&
ad1882_capture_source
;
else
spec
->
input_mux
=
&
ad1882a_capture_source
;
spec
->
num_mixers
=
2
;
spec
->
mixers
[
0
]
=
ad1882_base_mixers
;
if
(
codec
->
vendor_id
==
0x11d41882
)
spec
->
mixers
[
1
]
=
ad1882_loopback_mixers
;
else
spec
->
mixers
[
1
]
=
ad1882a_loopback_mixers
;
spec
->
num_init_verbs
=
1
;
spec
->
init_verbs
[
0
]
=
ad1882_init_verbs
;
spec
->
spdif_route
=
0
;
#ifdef CONFIG_PM
spec
->
loopback
.
amplist
=
ad1882_loopbacks
;
#endif
spec
->
vmaster_nid
=
0x04
;
codec
->
patch_ops
=
ad198x_patch_ops
;
/* override some parameters */
switch
(
board_config
)
{
default:
case
AD1882_3STACK
:
case
AD1882_3STACK_AUTOMUTE
:
spec
->
num_mixers
=
3
;
spec
->
mixers
[
2
]
=
ad1882_3stack_mixers
;
spec
->
channel_mode
=
ad1882_modes
;
spec
->
num_channel_mode
=
ARRAY_SIZE
(
ad1882_modes
);
spec
->
need_dac_fix
=
1
;
spec
->
multiout
.
max_channels
=
2
;
spec
->
multiout
.
num_dacs
=
1
;
if
(
board_config
!=
AD1882_3STACK
)
{
spec
->
init_verbs
[
spec
->
num_init_verbs
++
]
=
ad1882_3stack_automute_verbs
;
codec
->
patch_ops
.
unsol_event
=
ad1882_3stack_unsol_event
;
codec
->
patch_ops
.
init
=
ad1882_3stack_automute_init
;
}
break
;
case
AD1882_6STACK
:
spec
->
num_mixers
=
3
;
spec
->
mixers
[
2
]
=
ad1882_6stack_mixers
;
break
;
}
codec
->
no_trigger_sense
=
1
;
codec
->
no_sticky_stream
=
1
;
return
0
;
}
#else
/* ENABLE_AD_STATIC_QUIRKS */
#define patch_ad1882 ad1882_parse_auto_config
#endif
/* ENABLE_AD_STATIC_QUIRKS */
/*
/*
* patch entries
* patch entries
*/
*/
static
const
struct
hda_codec_preset
snd_hda_preset_analog
[]
=
{
static
const
struct
hda_codec_preset
snd_hda_preset_analog
[]
=
{
{
.
id
=
0x11d4184a
,
.
name
=
"AD1884A"
,
.
patch
=
patch_ad1884
a
},
{
.
id
=
0x11d4184a
,
.
name
=
"AD1884A"
,
.
patch
=
patch_ad1884
},
{
.
id
=
0x11d41882
,
.
name
=
"AD1882"
,
.
patch
=
patch_ad1882
},
{
.
id
=
0x11d41882
,
.
name
=
"AD1882"
,
.
patch
=
patch_ad1882
},
{
.
id
=
0x11d41883
,
.
name
=
"AD1883"
,
.
patch
=
patch_ad1884
a
},
{
.
id
=
0x11d41883
,
.
name
=
"AD1883"
,
.
patch
=
patch_ad1884
},
{
.
id
=
0x11d41884
,
.
name
=
"AD1884"
,
.
patch
=
patch_ad1884
},
{
.
id
=
0x11d41884
,
.
name
=
"AD1884"
,
.
patch
=
patch_ad1884
},
{
.
id
=
0x11d4194a
,
.
name
=
"AD1984A"
,
.
patch
=
patch_ad1884
a
},
{
.
id
=
0x11d4194a
,
.
name
=
"AD1984A"
,
.
patch
=
patch_ad1884
},
{
.
id
=
0x11d4194b
,
.
name
=
"AD1984B"
,
.
patch
=
patch_ad1884
a
},
{
.
id
=
0x11d4194b
,
.
name
=
"AD1984B"
,
.
patch
=
patch_ad1884
},
{
.
id
=
0x11d41981
,
.
name
=
"AD1981"
,
.
patch
=
patch_ad1981
},
{
.
id
=
0x11d41981
,
.
name
=
"AD1981"
,
.
patch
=
patch_ad1981
},
{
.
id
=
0x11d41983
,
.
name
=
"AD1983"
,
.
patch
=
patch_ad1983
},
{
.
id
=
0x11d41983
,
.
name
=
"AD1983"
,
.
patch
=
patch_ad1983
},
{
.
id
=
0x11d41984
,
.
name
=
"AD1984"
,
.
patch
=
patch_ad1
9
84
},
{
.
id
=
0x11d41984
,
.
name
=
"AD1984"
,
.
patch
=
patch_ad1
8
84
},
{
.
id
=
0x11d41986
,
.
name
=
"AD1986A"
,
.
patch
=
patch_ad1986a
},
{
.
id
=
0x11d41986
,
.
name
=
"AD1986A"
,
.
patch
=
patch_ad1986a
},
{
.
id
=
0x11d41988
,
.
name
=
"AD1988"
,
.
patch
=
patch_ad1988
},
{
.
id
=
0x11d41988
,
.
name
=
"AD1988"
,
.
patch
=
patch_ad1988
},
{
.
id
=
0x11d4198b
,
.
name
=
"AD1988B"
,
.
patch
=
patch_ad1988
},
{
.
id
=
0x11d4198b
,
.
name
=
"AD1988B"
,
.
patch
=
patch_ad1988
},
...
...
sound/pci/rme9652/hdspm.c
浏览文件 @
a067c035
...
@@ -38,6 +38,97 @@
...
@@ -38,6 +38,97 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*/
*/
/* ************* Register Documentation *******************************************************
*
* Work in progress! Documentation is based on the code in this file.
*
* --------- HDSPM_controlRegister ---------
* :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
* :||||.||||:||||.||||:||||.||||:||||.||||:
* :3322.2222:2222.1111:1111.1100:0000.0000: bit number
* :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
* :||||.||||:||||.||||:||||.||||:||||.||||:
* :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
* : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits
* : . : . : . : . x: HDSPM_Start / enables audio IO
* : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave
* : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency
* : . : . : . : . : 0:64, 1:128, 2:256, 3:512,
* : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192
* :x . : . : . x:xx . : HDSPM_FrequencyMask
* : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=??
* : . : . : . x: . : <MADI> HDSPM_DoubleSpeed
* :x . : . : . : . : <MADI> HDSPM_QuadSpeed
* : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask :
* : . : . x: . : . : HDSPM_SyncRef0
* : . : . x : . : . : HDSPM_SyncRef1
* : . : . : x . : . : <AES32> HDSPM_SyncRef2
* : . x : . : . : . : <AES32> HDSPM_SyncRef3
* : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn
* : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn?
* : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT
* : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax
* : . : . :x . : . : <MADI> HDSPM_InputSelect1
* : . : .x : . : . : <MADI> HDSPM_clr_tms
* : . : . : . x : . : <MADI> HDSPM_TX_64ch
* : . : . : . x : . : <AES32> HDSPM_Emphasis
* : . : . : .x : . : <MADI> HDSPM_AutoInp
* : . : . x : . : . : <MADI> HDSPM_SMUX
* : . : .x : . : . : <MADI> HDSPM_clr_tms
* : . : x. : . : . : <MADI> HDSPM_taxi_reset
* : . x: . : . : . : <MADI> HDSPM_LineOut
* : . x: . : . : . : <AES32> ??????????????????
* : . : x. : . : . : <AES32> HDSPM_WCK48
* : . : . : .x : . : <AES32> HDSPM_Dolby
* : . : x . : . : . : HDSPM_Midi0InterruptEnable
* : . :x . : . : . : HDSPM_Midi1InterruptEnable
* : . : x . : . : . : HDSPM_Midi2InterruptEnable
* : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable
* : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire
* : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire
* : x. : . : . : . : <AES32> HDSPM_QS_QuadWire
* : . : . : . x : . : <AES32> HDSPM_Professional
* : x . : . : . : . : HDSPM_wclk_sel
* : . : . : . : . :
* :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
* :||||.||||:||||.||||:||||.||||:||||.||||:
* :3322.2222:2222.1111:1111.1100:0000.0000: bit number
* :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
* :||||.||||:||||.||||:||||.||||:||||.||||:
* :8421.8421:8421.8421:8421.8421:8421.8421:hex digit
*
*
*
* AIO / RayDAT only
*
* ------------ HDSPM_WR_SETTINGS ----------
* :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
* :1098.7654:3210.9876:5432.1098:7654.3210:
* :||||.||||:||||.||||:||||.||||:||||.||||: bit number
* :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
* :||||.||||:||||.||||:||||.||||:||||.||||:
* :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
* : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave
* : . : . : . : . x : HDSPM_c0_SyncRef0
* : . : . : . : . x : HDSPM_c0_SyncRef1
* : . : . : . : .x : HDSPM_c0_SyncRef2
* : . : . : . : x. : HDSPM_c0_SyncRef3
* : . : . : . : 3.210 : HDSPM_c0_SyncRefMask:
* : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4,
* : . : . : . : . : 9:TCO, 10:SyncIn
* : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT,
* : . : . : . : . : 9:TCO, 10:SyncIn
* : . : . : . : . :
* : . : . : . : . :
* :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
* :1098.7654:3210.9876:5432.1098:7654.3210:
* :||||.||||:||||.||||:||||.||||:||||.||||: bit number
* :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
* :||||.||||:||||.||||:||||.||||:||||.||||:
* :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
*
*/
#include <linux/init.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
...
@@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
...
@@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_controlRegister 64
#define HDSPM_controlRegister 64
#define HDSPM_interruptConfirmation 96
#define HDSPM_interruptConfirmation 96
#define HDSPM_control2Reg 256
/* not in specs ???????? */
#define HDSPM_control2Reg 256
/* not in specs ???????? */
#define HDSPM_freqReg 256
/* for
AES32
*/
#define HDSPM_freqReg 256
/* for
setting arbitrary clock values (DDS feature)
*/
#define HDSPM_midiDataOut0 352
/* just believe in old code */
#define HDSPM_midiDataOut0 352
/* just believe in old code */
#define HDSPM_midiDataOut1 356
#define HDSPM_midiDataOut1 356
#define HDSPM_eeprom_wr 384
/* for AES32 */
#define HDSPM_eeprom_wr 384
/* for AES32 */
...
@@ -258,6 +349,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
...
@@ -258,6 +349,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_wclk_sel (1<<30)
#define HDSPM_wclk_sel (1<<30)
/* additional control register bits for AIO*/
#define HDSPM_c0_Wck48 0x20
/* also RayDAT */
#define HDSPM_c0_Input0 0x1000
#define HDSPM_c0_Input1 0x2000
#define HDSPM_c0_Spdif_Opt 0x4000
#define HDSPM_c0_Pro 0x8000
#define HDSPM_c0_clr_tms 0x10000
#define HDSPM_c0_AEB1 0x20000
#define HDSPM_c0_AEB2 0x40000
#define HDSPM_c0_LineOut 0x80000
#define HDSPM_c0_AD_GAIN0 0x100000
#define HDSPM_c0_AD_GAIN1 0x200000
#define HDSPM_c0_DA_GAIN0 0x400000
#define HDSPM_c0_DA_GAIN1 0x800000
#define HDSPM_c0_PH_GAIN0 0x1000000
#define HDSPM_c0_PH_GAIN1 0x2000000
#define HDSPM_c0_Sym6db 0x4000000
/* --- bit helper defines */
/* --- bit helper defines */
#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\
#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\
...
@@ -341,11 +451,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
...
@@ -341,11 +451,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_madiLock (1<<3)
/* MADI Locked =1, no=0 */
#define HDSPM_madiLock (1<<3)
/* MADI Locked =1, no=0 */
#define HDSPM_madiSync (1<<18)
/* MADI is in sync */
#define HDSPM_madiSync (1<<18)
/* MADI is in sync */
#define HDSPM_tcoLock
0x00000020
/* Optional TCO locked status FOR HDSPe MADI!
*/
#define HDSPM_tcoLock
Madi 0x00000020
/* Optional TCO locked status for HDSPe MADI
*/
#define HDSPM_tcoSync 0x10000000
/* Optional TCO sync status */
#define HDSPM_tcoSync 0x10000000
/* Optional TCO sync status
for HDSPe MADI and AES32!
*/
#define HDSPM_syncInLock 0x00010000
/* Sync In lock status
FOR
HDSPe MADI! */
#define HDSPM_syncInLock 0x00010000
/* Sync In lock status
for
HDSPe MADI! */
#define HDSPM_syncInSync 0x00020000
/* Sync In sync status
FOR
HDSPe MADI! */
#define HDSPM_syncInSync 0x00020000
/* Sync In sync status
for
HDSPe MADI! */
#define HDSPM_BufferPositionMask 0x000FFC0
/* Bit 6..15 : h/w buffer pointer */
#define HDSPM_BufferPositionMask 0x000FFC0
/* Bit 6..15 : h/w buffer pointer */
/* since 64byte accurate, last 6 bits are not used */
/* since 64byte accurate, last 6 bits are not used */
...
@@ -363,7 +473,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
...
@@ -363,7 +473,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
* Interrupt
* Interrupt
*/
*/
#define HDSPM_tco_detect 0x08000000
#define HDSPM_tco_detect 0x08000000
#define HDSPM_tco
_lock 0x20000000
#define HDSPM_tco
LockAes 0x20000000
/* Optional TCO locked status for HDSPe AES */
#define HDSPM_s2_tco_detect 0x00000040
#define HDSPM_s2_tco_detect 0x00000040
#define HDSPM_s2_AEBO_D 0x00000080
#define HDSPM_s2_AEBO_D 0x00000080
...
@@ -461,7 +571,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
...
@@ -461,7 +571,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9
#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9
#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10
#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11
/* status2 */
/* status2 */
/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
...
@@ -537,36 +649,39 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
...
@@ -537,36 +649,39 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
/* names for speed modes */
/* names for speed modes */
static
char
*
hdspm_speed_names
[]
=
{
"single"
,
"double"
,
"quad"
};
static
char
*
hdspm_speed_names
[]
=
{
"single"
,
"double"
,
"quad"
};
static
c
har
*
texts_autosync_aes_tco
[]
=
{
"Word Clock"
,
static
c
onst
char
*
const
texts_autosync_aes_tco
[]
=
{
"Word Clock"
,
"AES1"
,
"AES2"
,
"AES3"
,
"AES4"
,
"AES1"
,
"AES2"
,
"AES3"
,
"AES4"
,
"AES5"
,
"AES6"
,
"AES7"
,
"AES8"
,
"AES5"
,
"AES6"
,
"AES7"
,
"AES8"
,
"TCO"
};
"TCO"
,
"Sync In"
static
char
*
texts_autosync_aes
[]
=
{
"Word Clock"
,
};
static
const
char
*
const
texts_autosync_aes
[]
=
{
"Word Clock"
,
"AES1"
,
"AES2"
,
"AES3"
,
"AES4"
,
"AES1"
,
"AES2"
,
"AES3"
,
"AES4"
,
"AES5"
,
"AES6"
,
"AES7"
,
"AES8"
};
"AES5"
,
"AES6"
,
"AES7"
,
"AES8"
,
static
char
*
texts_autosync_madi_tco
[]
=
{
"Word Clock"
,
"Sync In"
};
static
const
char
*
const
texts_autosync_madi_tco
[]
=
{
"Word Clock"
,
"MADI"
,
"TCO"
,
"Sync In"
};
"MADI"
,
"TCO"
,
"Sync In"
};
static
c
har
*
texts_autosync_madi
[]
=
{
"Word Clock"
,
static
c
onst
char
*
const
texts_autosync_madi
[]
=
{
"Word Clock"
,
"MADI"
,
"Sync In"
};
"MADI"
,
"Sync In"
};
static
c
har
*
texts_autosync_raydat_tco
[]
=
{
static
c
onst
char
*
const
texts_autosync_raydat_tco
[]
=
{
"Word Clock"
,
"Word Clock"
,
"ADAT 1"
,
"ADAT 2"
,
"ADAT 3"
,
"ADAT 4"
,
"ADAT 1"
,
"ADAT 2"
,
"ADAT 3"
,
"ADAT 4"
,
"AES"
,
"SPDIF"
,
"TCO"
,
"Sync In"
"AES"
,
"SPDIF"
,
"TCO"
,
"Sync In"
};
};
static
c
har
*
texts_autosync_raydat
[]
=
{
static
c
onst
char
*
const
texts_autosync_raydat
[]
=
{
"Word Clock"
,
"Word Clock"
,
"ADAT 1"
,
"ADAT 2"
,
"ADAT 3"
,
"ADAT 4"
,
"ADAT 1"
,
"ADAT 2"
,
"ADAT 3"
,
"ADAT 4"
,
"AES"
,
"SPDIF"
,
"Sync In"
"AES"
,
"SPDIF"
,
"Sync In"
};
};
static
c
har
*
texts_autosync_aio_tco
[]
=
{
static
c
onst
char
*
const
texts_autosync_aio_tco
[]
=
{
"Word Clock"
,
"Word Clock"
,
"ADAT"
,
"AES"
,
"SPDIF"
,
"TCO"
,
"Sync In"
"ADAT"
,
"AES"
,
"SPDIF"
,
"TCO"
,
"Sync In"
};
};
static
c
har
*
texts_autosync_aio
[]
=
{
"Word Clock"
,
static
c
onst
char
*
const
texts_autosync_aio
[]
=
{
"Word Clock"
,
"ADAT"
,
"AES"
,
"SPDIF"
,
"Sync In"
};
"ADAT"
,
"AES"
,
"SPDIF"
,
"Sync In"
};
static
c
har
*
texts_freq
[]
=
{
static
c
onst
char
*
const
texts_freq
[]
=
{
"No Lock"
,
"No Lock"
,
"32 kHz"
,
"32 kHz"
,
"44.1 kHz"
,
"44.1 kHz"
,
...
@@ -629,7 +744,8 @@ static char *texts_ports_aio_in_ss[] = {
...
@@ -629,7 +744,8 @@ static char *texts_ports_aio_in_ss[] = {
"AES.L"
,
"AES.R"
,
"AES.L"
,
"AES.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"ADAT.5"
,
"ADAT.6"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"ADAT.5"
,
"ADAT.6"
,
"ADAT.7"
,
"ADAT.8"
"ADAT.7"
,
"ADAT.8"
,
"AEB.1"
,
"AEB.2"
,
"AEB.3"
,
"AEB.4"
};
};
static
char
*
texts_ports_aio_out_ss
[]
=
{
static
char
*
texts_ports_aio_out_ss
[]
=
{
...
@@ -638,14 +754,16 @@ static char *texts_ports_aio_out_ss[] = {
...
@@ -638,14 +754,16 @@ static char *texts_ports_aio_out_ss[] = {
"SPDIF.L"
,
"SPDIF.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"ADAT.5"
,
"ADAT.6"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"ADAT.5"
,
"ADAT.6"
,
"ADAT.7"
,
"ADAT.8"
,
"ADAT.7"
,
"ADAT.8"
,
"Phone.L"
,
"Phone.R"
"Phone.L"
,
"Phone.R"
,
"AEB.1"
,
"AEB.2"
,
"AEB.3"
,
"AEB.4"
};
};
static
char
*
texts_ports_aio_in_ds
[]
=
{
static
char
*
texts_ports_aio_in_ds
[]
=
{
"Analogue.L"
,
"Analogue.R"
,
"Analogue.L"
,
"Analogue.R"
,
"AES.L"
,
"AES.R"
,
"AES.L"
,
"AES.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"AEB.1"
,
"AEB.2"
,
"AEB.3"
,
"AEB.4"
};
};
static
char
*
texts_ports_aio_out_ds
[]
=
{
static
char
*
texts_ports_aio_out_ds
[]
=
{
...
@@ -653,14 +771,16 @@ static char *texts_ports_aio_out_ds[] = {
...
@@ -653,14 +771,16 @@ static char *texts_ports_aio_out_ds[] = {
"AES.L"
,
"AES.R"
,
"AES.L"
,
"AES.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"Phone.L"
,
"Phone.R"
"Phone.L"
,
"Phone.R"
,
"AEB.1"
,
"AEB.2"
,
"AEB.3"
,
"AEB.4"
};
};
static
char
*
texts_ports_aio_in_qs
[]
=
{
static
char
*
texts_ports_aio_in_qs
[]
=
{
"Analogue.L"
,
"Analogue.R"
,
"Analogue.L"
,
"Analogue.R"
,
"AES.L"
,
"AES.R"
,
"AES.L"
,
"AES.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"AEB.1"
,
"AEB.2"
,
"AEB.3"
,
"AEB.4"
};
};
static
char
*
texts_ports_aio_out_qs
[]
=
{
static
char
*
texts_ports_aio_out_qs
[]
=
{
...
@@ -668,7 +788,8 @@ static char *texts_ports_aio_out_qs[] = {
...
@@ -668,7 +788,8 @@ static char *texts_ports_aio_out_qs[] = {
"AES.L"
,
"AES.R"
,
"AES.L"
,
"AES.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"SPDIF.L"
,
"SPDIF.R"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"ADAT.1"
,
"ADAT.2"
,
"ADAT.3"
,
"ADAT.4"
,
"Phone.L"
,
"Phone.R"
"Phone.L"
,
"Phone.R"
,
"AEB.1"
,
"AEB.2"
,
"AEB.3"
,
"AEB.4"
};
};
static
char
*
texts_ports_aes32
[]
=
{
static
char
*
texts_ports_aes32
[]
=
{
...
@@ -745,8 +866,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = {
...
@@ -745,8 +866,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = {
8
,
9
,
/* aes in, */
8
,
9
,
/* aes in, */
10
,
11
,
/* spdif in */
10
,
11
,
/* spdif in */
12
,
13
,
14
,
15
,
16
,
17
,
18
,
19
,
/* ADAT in */
12
,
13
,
14
,
15
,
16
,
17
,
18
,
19
,
/* ADAT in */
-
1
,
-
1
,
2
,
3
,
4
,
5
,
/* AEB */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
...
@@ -760,7 +881,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = {
...
@@ -760,7 +881,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = {
10
,
11
,
/* spdif out */
10
,
11
,
/* spdif out */
12
,
13
,
14
,
15
,
16
,
17
,
18
,
19
,
/* ADAT out */
12
,
13
,
14
,
15
,
16
,
17
,
18
,
19
,
/* ADAT out */
6
,
7
,
/* phone out */
6
,
7
,
/* phone out */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
2
,
3
,
4
,
5
,
/* AEB */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
...
@@ -773,7 +895,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = {
...
@@ -773,7 +895,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = {
8
,
9
,
/* aes in */
8
,
9
,
/* aes in */
10
,
11
,
/* spdif in */
10
,
11
,
/* spdif in */
12
,
14
,
16
,
18
,
/* adat in */
12
,
14
,
16
,
18
,
/* adat in */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
2
,
3
,
4
,
5
,
/* AEB */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
...
@@ -788,7 +911,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = {
...
@@ -788,7 +911,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = {
10
,
11
,
/* spdif out */
10
,
11
,
/* spdif out */
12
,
14
,
16
,
18
,
/* adat out */
12
,
14
,
16
,
18
,
/* adat out */
6
,
7
,
/* phone out */
6
,
7
,
/* phone out */
-
1
,
-
1
,
-
1
,
-
1
,
2
,
3
,
4
,
5
,
/* AEB */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
...
@@ -802,7 +925,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = {
...
@@ -802,7 +925,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = {
8
,
9
,
/* aes in */
8
,
9
,
/* aes in */
10
,
11
,
/* spdif in */
10
,
11
,
/* spdif in */
12
,
16
,
/* adat in */
12
,
16
,
/* adat in */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
2
,
3
,
4
,
5
,
/* AEB */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
...
@@ -817,7 +941,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = {
...
@@ -817,7 +941,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = {
10
,
11
,
/* spdif out */
10
,
11
,
/* spdif out */
12
,
16
,
/* adat out */
12
,
16
,
/* adat out */
6
,
7
,
/* phone out */
6
,
7
,
/* phone out */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
2
,
3
,
4
,
5
,
/* AEB */
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
...
@@ -856,11 +981,11 @@ struct hdspm_midi {
...
@@ -856,11 +981,11 @@ struct hdspm_midi {
};
};
struct
hdspm_tco
{
struct
hdspm_tco
{
int
input
;
int
input
;
/* 0: LTC, 1:Video, 2: WC*/
int
framerate
;
int
framerate
;
/* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */
int
wordclock
;
int
wordclock
;
/* 0=1:1, 1=44.1->48, 2=48->44.1 */
int
samplerate
;
int
samplerate
;
/* 0=44.1, 1=48, 2= freq from app */
int
pull
;
int
pull
;
/* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/
int
term
;
/* 0 = off, 1 = on */
int
term
;
/* 0 = off, 1 = on */
};
};
...
@@ -879,7 +1004,7 @@ struct hdspm {
...
@@ -879,7 +1004,7 @@ struct hdspm {
u32
control_register
;
/* cached value */
u32
control_register
;
/* cached value */
u32
control2_register
;
/* cached value */
u32
control2_register
;
/* cached value */
u32
settings_register
;
u32
settings_register
;
/* cached value for AIO / RayDat (sync reference, master/slave) */
struct
hdspm_midi
midi
[
4
];
struct
hdspm_midi
midi
[
4
];
struct
tasklet_struct
midi_tasklet
;
struct
tasklet_struct
midi_tasklet
;
...
@@ -941,7 +1066,7 @@ struct hdspm {
...
@@ -941,7 +1066,7 @@ struct hdspm {
struct
hdspm_tco
*
tco
;
/* NULL if no TCO detected */
struct
hdspm_tco
*
tco
;
/* NULL if no TCO detected */
c
har
*
*
texts_autosync
;
c
onst
char
*
const
*
texts_autosync
;
int
texts_autosync_items
;
int
texts_autosync_items
;
cycles_t
last_interrupt
;
cycles_t
last_interrupt
;
...
@@ -976,12 +1101,24 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
...
@@ -976,12 +1101,24 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
static
inline
int
hdspm_get_pll_freq
(
struct
hdspm
*
hdspm
);
static
inline
int
hdspm_get_pll_freq
(
struct
hdspm
*
hdspm
);
static
int
hdspm_update_simple_mixer_controls
(
struct
hdspm
*
hdspm
);
static
int
hdspm_update_simple_mixer_controls
(
struct
hdspm
*
hdspm
);
static
int
hdspm_autosync_ref
(
struct
hdspm
*
hdspm
);
static
int
hdspm_autosync_ref
(
struct
hdspm
*
hdspm
);
static
int
hdspm_set_toggle_setting
(
struct
hdspm
*
hdspm
,
u32
regmask
,
int
out
);
static
int
snd_hdspm_set_defaults
(
struct
hdspm
*
hdspm
);
static
int
snd_hdspm_set_defaults
(
struct
hdspm
*
hdspm
);
static
int
hdspm_system_clock_mode
(
struct
hdspm
*
hdspm
);
static
int
hdspm_system_clock_mode
(
struct
hdspm
*
hdspm
);
static
void
hdspm_set_sgbuf
(
struct
hdspm
*
hdspm
,
static
void
hdspm_set_sgbuf
(
struct
hdspm
*
hdspm
,
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_substream
*
substream
,
unsigned
int
reg
,
int
channels
);
unsigned
int
reg
,
int
channels
);
static
int
hdspm_aes_sync_check
(
struct
hdspm
*
hdspm
,
int
idx
);
static
int
hdspm_wc_sync_check
(
struct
hdspm
*
hdspm
);
static
int
hdspm_tco_sync_check
(
struct
hdspm
*
hdspm
);
static
int
hdspm_sync_in_sync_check
(
struct
hdspm
*
hdspm
);
static
int
hdspm_get_aes_sample_rate
(
struct
hdspm
*
hdspm
,
int
index
);
static
int
hdspm_get_tco_sample_rate
(
struct
hdspm
*
hdspm
);
static
int
hdspm_get_wc_sample_rate
(
struct
hdspm
*
hdspm
);
static
inline
int
HDSPM_bit2freq
(
int
n
)
static
inline
int
HDSPM_bit2freq
(
int
n
)
{
{
static
const
int
bit2freq_tab
[]
=
{
static
const
int
bit2freq_tab
[]
=
{
...
@@ -992,6 +1129,12 @@ static inline int HDSPM_bit2freq(int n)
...
@@ -992,6 +1129,12 @@ static inline int HDSPM_bit2freq(int n)
return
bit2freq_tab
[
n
];
return
bit2freq_tab
[
n
];
}
}
static
bool
hdspm_is_raydat_or_aio
(
struct
hdspm
*
hdspm
)
{
return
((
AIO
==
hdspm
->
io_type
)
||
(
RayDAT
==
hdspm
->
io_type
));
}
/* Write/read to/from HDSPM with Adresses in Bytes
/* Write/read to/from HDSPM with Adresses in Bytes
not words but only 32Bit writes are allowed */
not words but only 32Bit writes are allowed */
...
@@ -1111,10 +1254,7 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
...
@@ -1111,10 +1254,7 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
return
rate
;
return
rate
;
}
}
static
int
hdspm_tco_sync_check
(
struct
hdspm
*
hdspm
);
/* check for external sample rate, returns the sample rate in Hz*/
static
int
hdspm_sync_in_sync_check
(
struct
hdspm
*
hdspm
);
/* check for external sample rate */
static
int
hdspm_external_sample_rate
(
struct
hdspm
*
hdspm
)
static
int
hdspm_external_sample_rate
(
struct
hdspm
*
hdspm
)
{
{
unsigned
int
status
,
status2
,
timecode
;
unsigned
int
status
,
status2
,
timecode
;
...
@@ -1127,17 +1267,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
...
@@ -1127,17 +1267,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
timecode
=
hdspm_read
(
hdspm
,
HDSPM_timecodeRegister
);
timecode
=
hdspm_read
(
hdspm
,
HDSPM_timecodeRegister
);
syncref
=
hdspm_autosync_ref
(
hdspm
);
syncref
=
hdspm_autosync_ref
(
hdspm
);
switch
(
syncref
)
{
case
HDSPM_AES32_AUTOSYNC_FROM_WORD
:
/* Check WC sync and get sample rate */
if
(
hdspm_wc_sync_check
(
hdspm
))
return
HDSPM_bit2freq
(
hdspm_get_wc_sample_rate
(
hdspm
));
break
;
case
HDSPM_AES32_AUTOSYNC_FROM_AES1
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES2
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES3
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES4
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES5
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES6
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES7
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES8
:
/* Check AES sync and get sample rate */
if
(
hdspm_aes_sync_check
(
hdspm
,
syncref
-
HDSPM_AES32_AUTOSYNC_FROM_AES1
))
return
HDSPM_bit2freq
(
hdspm_get_aes_sample_rate
(
hdspm
,
syncref
-
HDSPM_AES32_AUTOSYNC_FROM_AES1
));
break
;
if
(
syncref
==
HDSPM_AES32_AUTOSYNC_FROM_WORD
&&
status
&
HDSPM_AES32_wcLock
)
return
HDSPM_bit2freq
((
status
>>
HDSPM_AES32_wcFreq_bit
)
&
0xF
);
if
(
syncref
>=
HDSPM_AES32_AUTOSYNC_FROM_AES1
&&
case
HDSPM_AES32_AUTOSYNC_FROM_TCO
:
syncref
<=
HDSPM_AES32_AUTOSYNC_FROM_AES8
&&
/* Check TCO sync and get sample rate */
status2
&
(
HDSPM_LockAES
>>
if
(
hdspm_tco_sync_check
(
hdspm
))
(
syncref
-
HDSPM_AES32_AUTOSYNC_FROM_AES1
)))
return
HDSPM_bit2freq
(
hdspm_get_tco_sample_rate
(
hdspm
));
return
HDSPM_bit2freq
((
timecode
>>
(
4
*
(
syncref
-
HDSPM_AES32_AUTOSYNC_FROM_AES1
)))
&
0xF
);
break
;
default:
return
0
;
return
0
;
}
/* end switch(syncref) */
break
;
break
;
case
MADIface
:
case
MADIface
:
...
@@ -2129,6 +2288,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
...
@@ -2129,6 +2288,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
status
=
hdspm_read
(
hdspm
,
HDSPM_RD_STATUS_1
);
status
=
hdspm_read
(
hdspm
,
HDSPM_RD_STATUS_1
);
return
(
status
>>
16
)
&
0xF
;
return
(
status
>>
16
)
&
0xF
;
break
;
break
;
case
AES32
:
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
return
(
status
>>
HDSPM_AES32_wcFreq_bit
)
&
0xF
;
default:
default:
break
;
break
;
}
}
...
@@ -2152,6 +2314,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
...
@@ -2152,6 +2314,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
status
=
hdspm_read
(
hdspm
,
HDSPM_RD_STATUS_1
);
status
=
hdspm_read
(
hdspm
,
HDSPM_RD_STATUS_1
);
return
(
status
>>
20
)
&
0xF
;
return
(
status
>>
20
)
&
0xF
;
break
;
break
;
case
AES32
:
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
return
(
status
>>
1
)
&
0xF
;
default:
default:
break
;
break
;
}
}
...
@@ -2183,6 +2348,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
...
@@ -2183,6 +2348,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
return
0
;
return
0
;
}
}
/**
* Returns the AES sample rate class for the given card.
**/
static
int
hdspm_get_aes_sample_rate
(
struct
hdspm
*
hdspm
,
int
index
)
{
int
timecode
;
switch
(
hdspm
->
io_type
)
{
case
AES32
:
timecode
=
hdspm_read
(
hdspm
,
HDSPM_timecodeRegister
);
return
(
timecode
>>
(
4
*
index
))
&
0xF
;
break
;
default:
break
;
}
return
0
;
}
/**
/**
* Returns the sample rate class for input source <idx> for
* Returns the sample rate class for input source <idx> for
...
@@ -2196,16 +2378,24 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
...
@@ -2196,16 +2378,24 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
}
}
#define ENUMERATED_CTL_INFO(info, texts) \
#define ENUMERATED_CTL_INFO(info, texts) \
{ \
snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts)
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \
uinfo->count = 1; \
uinfo->value.enumerated.items = ARRAY_SIZE(texts); \
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; \
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \
}
/* Helper function to query the external sample rate and return the
* corresponding enum to be returned to userspace.
*/
static
int
hdspm_external_rate_to_enum
(
struct
hdspm
*
hdspm
)
{
int
rate
=
hdspm_external_sample_rate
(
hdspm
);
int
i
,
selected_rate
=
0
;
for
(
i
=
1
;
i
<
10
;
i
++
)
if
(
HDSPM_bit2freq
(
i
)
==
rate
)
{
selected_rate
=
i
;
break
;
}
return
selected_rate
;
}
#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
...
@@ -2270,7 +2460,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
...
@@ -2270,7 +2460,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
default:
default:
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
hdspm_get_s1_sample_rate
(
hdspm
,
hdspm_get_s1_sample_rate
(
hdspm
,
ucontrol
->
id
.
index
-
1
);
kcontrol
->
private_value
-
1
);
}
}
break
;
break
;
...
@@ -2289,28 +2479,24 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
...
@@ -2289,28 +2479,24 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
hdspm_get_sync_in_sample_rate
(
hdspm
);
hdspm_get_sync_in_sample_rate
(
hdspm
);
break
;
break
;
case
11
:
/* External Rate */
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
hdspm_external_rate_to_enum
(
hdspm
);
break
;
default:
/* AES1 to AES8 */
default:
/* AES1 to AES8 */
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
hdspm_get_s1_sample_rate
(
hdspm
,
hdspm_get_aes_sample_rate
(
hdspm
,
kcontrol
->
private_value
-
1
);
kcontrol
->
private_value
-
HDSPM_AES32_AUTOSYNC_FROM_AES1
);
break
;
break
;
}
}
break
;
break
;
case
MADI
:
case
MADI
:
case
MADIface
:
case
MADIface
:
{
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
int
rate
=
hdspm_external_sample_rate
(
hdspm
);
hdspm_external_rate_to_enum
(
hdspm
);
int
i
,
selected_rate
=
0
;
for
(
i
=
1
;
i
<
10
;
i
++
)
if
(
HDSPM_bit2freq
(
i
)
==
rate
)
{
selected_rate
=
i
;
break
;
}
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
selected_rate
;
}
break
;
break
;
default:
default:
break
;
break
;
}
}
...
@@ -2359,33 +2545,17 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm)
...
@@ -2359,33 +2545,17 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm)
**/
**/
static
void
hdspm_set_system_clock_mode
(
struct
hdspm
*
hdspm
,
int
mode
)
static
void
hdspm_set_system_clock_mode
(
struct
hdspm
*
hdspm
,
int
mode
)
{
{
switch
(
hdspm
->
io_type
)
{
hdspm_set_toggle_setting
(
hdspm
,
case
AIO
:
(
hdspm_is_raydat_or_aio
(
hdspm
))
?
case
RayDAT
:
HDSPM_c0Master
:
HDSPM_ClockModeMaster
,
if
(
0
==
mode
)
(
0
==
mode
));
hdspm
->
settings_register
|=
HDSPM_c0Master
;
else
hdspm
->
settings_register
&=
~
HDSPM_c0Master
;
hdspm_write
(
hdspm
,
HDSPM_WR_SETTINGS
,
hdspm
->
settings_register
);
break
;
default:
if
(
0
==
mode
)
hdspm
->
control_register
|=
HDSPM_ClockModeMaster
;
else
hdspm
->
control_register
&=
~
HDSPM_ClockModeMaster
;
hdspm_write
(
hdspm
,
HDSPM_controlRegister
,
hdspm
->
control_register
);
}
}
}
static
int
snd_hdspm_info_system_clock_mode
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_system_clock_mode
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"Master"
,
"AutoSync"
};
static
c
onst
char
*
const
texts
[]
=
{
"Master"
,
"AutoSync"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -2809,16 +2979,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
...
@@ -2809,16 +2979,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
{
{
struct
hdspm
*
hdspm
=
snd_kcontrol_chip
(
kcontrol
);
struct
hdspm
*
hdspm
=
snd_kcontrol_chip
(
kcontrol
);
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_ENUMERATED
;
snd_ctl_enum_info
(
uinfo
,
1
,
hdspm
->
texts_autosync_items
,
hdspm
->
texts_autosync
);
uinfo
->
count
=
1
;
uinfo
->
value
.
enumerated
.
items
=
hdspm
->
texts_autosync_items
;
if
(
uinfo
->
value
.
enumerated
.
item
>=
uinfo
->
value
.
enumerated
.
items
)
uinfo
->
value
.
enumerated
.
item
=
uinfo
->
value
.
enumerated
.
items
-
1
;
strcpy
(
uinfo
->
value
.
enumerated
.
name
,
hdspm
->
texts_autosync
[
uinfo
->
value
.
enumerated
.
item
]);
return
0
;
return
0
;
}
}
...
@@ -2873,19 +3034,20 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
...
@@ -2873,19 +3034,20 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
static
int
hdspm_autosync_ref
(
struct
hdspm
*
hdspm
)
static
int
hdspm_autosync_ref
(
struct
hdspm
*
hdspm
)
{
{
/* This looks at the autosync selected sync reference */
if
(
AES32
==
hdspm
->
io_type
)
{
if
(
AES32
==
hdspm
->
io_type
)
{
unsigned
int
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
unsigned
int
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
unsigned
int
syncref
=
unsigned
int
syncref
=
(
status
>>
HDSPM_AES32_syncref_bit
)
&
0xF
;
(
status
>>
HDSPM_AES32_syncref_bit
)
&
0xF
;
if
((
syncref
>=
HDSPM_AES32_AUTOSYNC_FROM_WORD
)
&&
if
(
syncref
==
0
)
(
syncref
<=
HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN
))
{
return
HDSPM_AES32_AUTOSYNC_FROM_WORD
;
if
(
syncref
<=
8
)
return
syncref
;
return
syncref
;
}
return
HDSPM_AES32_AUTOSYNC_FROM_NONE
;
return
HDSPM_AES32_AUTOSYNC_FROM_NONE
;
}
else
if
(
MADI
==
hdspm
->
io_type
)
{
}
else
if
(
MADI
==
hdspm
->
io_type
)
{
/* This looks at the autosync selected sync reference */
unsigned
int
status2
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister2
);
unsigned
int
status2
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister2
);
switch
(
status2
&
HDSPM_SelSyncRefMask
)
{
switch
(
status2
&
HDSPM_SelSyncRefMask
)
{
case
HDSPM_SelSyncRef_WORD
:
case
HDSPM_SelSyncRef_WORD
:
return
HDSPM_AUTOSYNC_FROM_WORD
;
return
HDSPM_AUTOSYNC_FROM_WORD
;
...
@@ -2898,7 +3060,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm)
...
@@ -2898,7 +3060,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm)
case
HDSPM_SelSyncRef_NVALID
:
case
HDSPM_SelSyncRef_NVALID
:
return
HDSPM_AUTOSYNC_FROM_NONE
;
return
HDSPM_AUTOSYNC_FROM_NONE
;
default:
default:
return
0
;
return
HDSPM_AUTOSYNC_FROM_NONE
;
}
}
}
}
...
@@ -2912,31 +3074,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
...
@@ -2912,31 +3074,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
struct
hdspm
*
hdspm
=
snd_kcontrol_chip
(
kcontrol
);
struct
hdspm
*
hdspm
=
snd_kcontrol_chip
(
kcontrol
);
if
(
AES32
==
hdspm
->
io_type
)
{
if
(
AES32
==
hdspm
->
io_type
)
{
static
c
har
*
texts
[]
=
{
"WordClock"
,
"AES1"
,
"AES2"
,
"AES3"
,
static
c
onst
char
*
const
texts
[]
=
{
"WordClock"
,
"AES1"
,
"AES2"
,
"AES3"
,
"AES4"
,
"AES5"
,
"AES6"
,
"AES7"
,
"AES8"
,
"None"
};
"AES4"
,
"AES5"
,
"AES6"
,
"AES7"
,
"AES8"
,
"
TCO"
,
"Sync In"
,
"
None"
};
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_ENUMERATED
;
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
uinfo
->
count
=
1
;
uinfo
->
value
.
enumerated
.
items
=
10
;
if
(
uinfo
->
value
.
enumerated
.
item
>=
uinfo
->
value
.
enumerated
.
items
)
uinfo
->
value
.
enumerated
.
item
=
uinfo
->
value
.
enumerated
.
items
-
1
;
strcpy
(
uinfo
->
value
.
enumerated
.
name
,
texts
[
uinfo
->
value
.
enumerated
.
item
]);
}
else
if
(
MADI
==
hdspm
->
io_type
)
{
}
else
if
(
MADI
==
hdspm
->
io_type
)
{
static
c
har
*
texts
[]
=
{
"Word Clock"
,
"MADI"
,
"TCO"
,
static
c
onst
char
*
const
texts
[]
=
{
"Word Clock"
,
"MADI"
,
"TCO"
,
"Sync In"
,
"None"
};
"Sync In"
,
"None"
};
uinfo
->
type
=
SNDRV_CTL_ELEM_TYPE_ENUMERATED
;
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
uinfo
->
count
=
1
;
uinfo
->
value
.
enumerated
.
items
=
5
;
if
(
uinfo
->
value
.
enumerated
.
item
>=
uinfo
->
value
.
enumerated
.
items
)
uinfo
->
value
.
enumerated
.
item
=
uinfo
->
value
.
enumerated
.
items
-
1
;
strcpy
(
uinfo
->
value
.
enumerated
.
name
,
texts
[
uinfo
->
value
.
enumerated
.
item
]);
}
}
return
0
;
return
0
;
}
}
...
@@ -2964,7 +3110,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
...
@@ -2964,7 +3110,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_info_tco_video_input_format
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_tco_video_input_format
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"No video"
,
"NTSC"
,
"PAL"
};
static
c
onst
char
*
const
texts
[]
=
{
"No video"
,
"NTSC"
,
"PAL"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -3010,7 +3156,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
...
@@ -3010,7 +3156,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_info_tco_ltc_frames
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_tco_ltc_frames
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"No lock"
,
"24 fps"
,
"25 fps"
,
"29.97 fps"
,
static
c
onst
char
*
const
texts
[]
=
{
"No lock"
,
"24 fps"
,
"25 fps"
,
"29.97 fps"
,
"30 fps"
};
"30 fps"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
...
@@ -3067,16 +3213,35 @@ static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
...
@@ -3067,16 +3213,35 @@ static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
static
int
hdspm_toggle_setting
(
struct
hdspm
*
hdspm
,
u32
regmask
)
static
int
hdspm_toggle_setting
(
struct
hdspm
*
hdspm
,
u32
regmask
)
{
{
return
(
hdspm
->
control_register
&
regmask
)
?
1
:
0
;
u32
reg
;
if
(
hdspm_is_raydat_or_aio
(
hdspm
))
reg
=
hdspm
->
settings_register
;
else
reg
=
hdspm
->
control_register
;
return
(
reg
&
regmask
)
?
1
:
0
;
}
}
static
int
hdspm_set_toggle_setting
(
struct
hdspm
*
hdspm
,
u32
regmask
,
int
out
)
static
int
hdspm_set_toggle_setting
(
struct
hdspm
*
hdspm
,
u32
regmask
,
int
out
)
{
{
u32
*
reg
;
u32
target_reg
;
if
(
hdspm_is_raydat_or_aio
(
hdspm
))
{
reg
=
&
(
hdspm
->
settings_register
);
target_reg
=
HDSPM_WR_SETTINGS
;
}
else
{
reg
=
&
(
hdspm
->
control_register
);
target_reg
=
HDSPM_controlRegister
;
}
if
(
out
)
if
(
out
)
hdspm
->
control_register
|=
regmask
;
*
reg
|=
regmask
;
else
else
hdspm
->
control_register
&=
~
regmask
;
*
reg
&=
~
regmask
;
hdspm_write
(
hdspm
,
HDSPM_controlRegister
,
hdspm
->
control_register
);
hdspm_write
(
hdspm
,
target_reg
,
*
reg
);
return
0
;
return
0
;
}
}
...
@@ -3141,7 +3306,7 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out)
...
@@ -3141,7 +3306,7 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out)
static
int
snd_hdspm_info_input_select
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_input_select
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"optical"
,
"coaxial"
};
static
c
onst
char
*
const
texts
[]
=
{
"optical"
,
"coaxial"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -3203,7 +3368,7 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
...
@@ -3203,7 +3368,7 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
static
int
snd_hdspm_info_ds_wire
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_ds_wire
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"Single"
,
"Double"
};
static
c
onst
char
*
const
texts
[]
=
{
"Single"
,
"Double"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -3276,7 +3441,7 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
...
@@ -3276,7 +3441,7 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
static
int
snd_hdspm_info_qs_wire
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_qs_wire
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"Single"
,
"Double"
,
"Quad"
};
static
c
onst
char
*
const
texts
[]
=
{
"Single"
,
"Double"
,
"Quad"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -3313,6 +3478,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
...
@@ -3313,6 +3478,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
return
change
;
return
change
;
}
}
#define HDSPM_CONTROL_TRISTATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.private_value = xindex, \
.info = snd_hdspm_info_tristate, \
.get = snd_hdspm_get_tristate, \
.put = snd_hdspm_put_tristate \
}
static
int
hdspm_tristate
(
struct
hdspm
*
hdspm
,
u32
regmask
)
{
u32
reg
=
hdspm
->
settings_register
&
(
regmask
*
3
);
return
reg
/
regmask
;
}
static
int
hdspm_set_tristate
(
struct
hdspm
*
hdspm
,
int
mode
,
u32
regmask
)
{
hdspm
->
settings_register
&=
~
(
regmask
*
3
);
hdspm
->
settings_register
|=
(
regmask
*
mode
);
hdspm_write
(
hdspm
,
HDSPM_WR_SETTINGS
,
hdspm
->
settings_register
);
return
0
;
}
static
int
snd_hdspm_info_tristate
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
{
u32
regmask
=
kcontrol
->
private_value
;
static
const
char
*
const
texts_spdif
[]
=
{
"Optical"
,
"Coaxial"
,
"Internal"
};
static
const
char
*
const
texts_levels
[]
=
{
"Hi Gain"
,
"+4 dBu"
,
"-10 dBV"
};
switch
(
regmask
)
{
case
HDSPM_c0_Input0
:
ENUMERATED_CTL_INFO
(
uinfo
,
texts_spdif
);
break
;
default:
ENUMERATED_CTL_INFO
(
uinfo
,
texts_levels
);
break
;
}
return
0
;
}
static
int
snd_hdspm_get_tristate
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hdspm
*
hdspm
=
snd_kcontrol_chip
(
kcontrol
);
u32
regmask
=
kcontrol
->
private_value
;
spin_lock_irq
(
&
hdspm
->
lock
);
ucontrol
->
value
.
enumerated
.
item
[
0
]
=
hdspm_tristate
(
hdspm
,
regmask
);
spin_unlock_irq
(
&
hdspm
->
lock
);
return
0
;
}
static
int
snd_hdspm_put_tristate
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
hdspm
*
hdspm
=
snd_kcontrol_chip
(
kcontrol
);
u32
regmask
=
kcontrol
->
private_value
;
int
change
;
int
val
;
if
(
!
snd_hdspm_use_is_exclusive
(
hdspm
))
return
-
EBUSY
;
val
=
ucontrol
->
value
.
integer
.
value
[
0
];
if
(
val
<
0
)
val
=
0
;
if
(
val
>
2
)
val
=
2
;
spin_lock_irq
(
&
hdspm
->
lock
);
change
=
val
!=
hdspm_tristate
(
hdspm
,
regmask
);
hdspm_set_tristate
(
hdspm
,
val
,
regmask
);
spin_unlock_irq
(
&
hdspm
->
lock
);
return
change
;
}
#define HDSPM_MADI_SPEEDMODE(xname, xindex) \
#define HDSPM_MADI_SPEEDMODE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.name = xname, \
...
@@ -3352,7 +3595,7 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode)
...
@@ -3352,7 +3595,7 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode)
static
int
snd_hdspm_info_madi_speedmode
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_madi_speedmode
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"Single"
,
"Double"
,
"Quad"
};
static
c
onst
char
*
const
texts
[]
=
{
"Single"
,
"Double"
,
"Quad"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -3587,7 +3830,7 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
...
@@ -3587,7 +3830,7 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_info_sync_check
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_sync_check
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"No Lock"
,
"Lock"
,
"Sync"
,
"N/A"
};
static
c
onst
char
*
const
texts
[]
=
{
"No Lock"
,
"Lock"
,
"Sync"
,
"N/A"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -3595,7 +3838,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
...
@@ -3595,7 +3838,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_tco_info_lock_check
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_tco_info_lock_check
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"No Lock"
,
"Lock"
};
static
c
onst
char
*
const
texts
[]
=
{
"No Lock"
,
"Lock"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -3745,9 +3988,18 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm)
...
@@ -3745,9 +3988,18 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm)
if
(
hdspm
->
tco
)
{
if
(
hdspm
->
tco
)
{
switch
(
hdspm
->
io_type
)
{
switch
(
hdspm
->
io_type
)
{
case
MADI
:
case
MADI
:
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
if
(
status
&
HDSPM_tcoLockMadi
)
{
if
(
status
&
HDSPM_tcoSync
)
return
2
;
else
return
1
;
}
return
0
;
break
;
case
AES32
:
case
AES32
:
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
if
(
status
&
HDSPM_tcoLock
)
{
if
(
status
&
HDSPM_tcoLock
Aes
)
{
if
(
status
&
HDSPM_tcoSync
)
if
(
status
&
HDSPM_tcoSync
)
return
2
;
return
2
;
else
else
...
@@ -3807,7 +4059,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
...
@@ -3807,7 +4059,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
case
5
:
/* SYNC IN */
case
5
:
/* SYNC IN */
val
=
hdspm_sync_in_sync_check
(
hdspm
);
break
;
val
=
hdspm_sync_in_sync_check
(
hdspm
);
break
;
default:
default:
val
=
hdspm_s1_sync_check
(
hdspm
,
ucontrol
->
id
.
index
-
1
);
val
=
hdspm_s1_sync_check
(
hdspm
,
kcontrol
->
private_value
-
1
);
}
}
break
;
break
;
...
@@ -3975,7 +4228,8 @@ static void hdspm_tco_write(struct hdspm *hdspm)
...
@@ -3975,7 +4228,8 @@ static void hdspm_tco_write(struct hdspm *hdspm)
static
int
snd_hdspm_info_tco_sample_rate
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_tco_sample_rate
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
char
*
texts
[]
=
{
"44.1 kHz"
,
"48 kHz"
};
/* TODO freq from app could be supported here, see tco->samplerate */
static
const
char
*
const
texts
[]
=
{
"44.1 kHz"
,
"48 kHz"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -4021,7 +4275,8 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol,
...
@@ -4021,7 +4275,8 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_info_tco_pull
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_tco_pull
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
char
*
texts
[]
=
{
"0"
,
"+ 0.1 %"
,
"- 0.1 %"
,
"+ 4 %"
,
"- 4 %"
};
static
const
char
*
const
texts
[]
=
{
"0"
,
"+ 0.1 %"
,
"- 0.1 %"
,
"+ 4 %"
,
"- 4 %"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -4066,7 +4321,7 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol,
...
@@ -4066,7 +4321,7 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_info_tco_wck_conversion
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_tco_wck_conversion
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"1:1"
,
"44.1 -> 48"
,
"48 -> 44.1"
};
static
c
onst
char
*
const
texts
[]
=
{
"1:1"
,
"44.1 -> 48"
,
"48 -> 44.1"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -4112,7 +4367,7 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol,
...
@@ -4112,7 +4367,7 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_info_tco_frame_rate
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_tco_frame_rate
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"24 fps"
,
"25 fps"
,
"29.97fps"
,
static
c
onst
char
*
const
texts
[]
=
{
"24 fps"
,
"25 fps"
,
"29.97fps"
,
"29.97 dfps"
,
"30 fps"
,
"30 dfps"
};
"29.97 dfps"
,
"30 fps"
,
"30 dfps"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
...
@@ -4159,7 +4414,7 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol,
...
@@ -4159,7 +4414,7 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol,
static
int
snd_hdspm_info_tco_sync_source
(
struct
snd_kcontrol
*
kcontrol
,
static
int
snd_hdspm_info_tco_sync_source
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
struct
snd_ctl_elem_info
*
uinfo
)
{
{
static
c
har
*
texts
[]
=
{
"LTC"
,
"Video"
,
"WCK"
};
static
c
onst
char
*
const
texts
[]
=
{
"LTC"
,
"Video"
,
"WCK"
};
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
ENUMERATED_CTL_INFO
(
uinfo
,
texts
);
return
0
;
return
0
;
}
}
...
@@ -4284,7 +4539,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
...
@@ -4284,7 +4539,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
HDSPM_INTERNAL_CLOCK
(
"Internal Clock"
,
0
),
HDSPM_INTERNAL_CLOCK
(
"Internal Clock"
,
0
),
HDSPM_SYSTEM_CLOCK_MODE
(
"System Clock Mode"
,
0
),
HDSPM_SYSTEM_CLOCK_MODE
(
"System Clock Mode"
,
0
),
HDSPM_PREF_SYNC_REF
(
"Preferred Sync Reference"
,
0
),
HDSPM_PREF_SYNC_REF
(
"Preferred Sync Reference"
,
0
),
HDSPM_AUTOSYNC_REF
(
"AutoSync Reference"
,
0
),
HDSPM_SYSTEM_SAMPLE_RATE
(
"System Sample Rate"
,
0
),
HDSPM_SYSTEM_SAMPLE_RATE
(
"System Sample Rate"
,
0
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"External Rate"
,
0
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"External Rate"
,
0
),
HDSPM_SYNC_CHECK
(
"WC SyncCheck"
,
0
),
HDSPM_SYNC_CHECK
(
"WC SyncCheck"
,
0
),
...
@@ -4298,7 +4552,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
...
@@ -4298,7 +4552,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"SPDIF Frequency"
,
2
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"SPDIF Frequency"
,
2
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"ADAT Frequency"
,
3
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"ADAT Frequency"
,
3
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"TCO Frequency"
,
4
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"TCO Frequency"
,
4
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"SYNC IN Frequency"
,
5
)
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"SYNC IN Frequency"
,
5
),
HDSPM_CONTROL_TRISTATE
(
"S/PDIF Input"
,
HDSPM_c0_Input0
),
HDSPM_TOGGLE_SETTING
(
"S/PDIF Out Optical"
,
HDSPM_c0_Spdif_Opt
),
HDSPM_TOGGLE_SETTING
(
"S/PDIF Out Professional"
,
HDSPM_c0_Pro
),
HDSPM_TOGGLE_SETTING
(
"ADAT internal (AEB/TEB)"
,
HDSPM_c0_AEB1
),
HDSPM_TOGGLE_SETTING
(
"XLR Breakout Cable"
,
HDSPM_c0_Sym6db
),
HDSPM_TOGGLE_SETTING
(
"Single Speed WordClock Out"
,
HDSPM_c0_Wck48
),
HDSPM_CONTROL_TRISTATE
(
"Input Level"
,
HDSPM_c0_AD_GAIN0
),
HDSPM_CONTROL_TRISTATE
(
"Output Level"
,
HDSPM_c0_DA_GAIN0
),
HDSPM_CONTROL_TRISTATE
(
"Phones Level"
,
HDSPM_c0_PH_GAIN0
)
/*
/*
HDSPM_INPUT_SELECT("Input Select", 0),
HDSPM_INPUT_SELECT("Input Select", 0),
...
@@ -4335,7 +4598,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = {
...
@@ -4335,7 +4598,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = {
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"ADAT3 Frequency"
,
5
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"ADAT3 Frequency"
,
5
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"ADAT4 Frequency"
,
6
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"ADAT4 Frequency"
,
6
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"TCO Frequency"
,
7
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"TCO Frequency"
,
7
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"SYNC IN Frequency"
,
8
)
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"SYNC IN Frequency"
,
8
),
HDSPM_TOGGLE_SETTING
(
"S/PDIF Out Professional"
,
HDSPM_c0_Pro
),
HDSPM_TOGGLE_SETTING
(
"Single Speed WordClock Out"
,
HDSPM_c0_Wck48
)
};
};
static
struct
snd_kcontrol_new
snd_hdspm_controls_aes32
[]
=
{
static
struct
snd_kcontrol_new
snd_hdspm_controls_aes32
[]
=
{
...
@@ -4345,7 +4610,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
...
@@ -4345,7 +4610,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
HDSPM_PREF_SYNC_REF
(
"Preferred Sync Reference"
,
0
),
HDSPM_PREF_SYNC_REF
(
"Preferred Sync Reference"
,
0
),
HDSPM_AUTOSYNC_REF
(
"AutoSync Reference"
,
0
),
HDSPM_AUTOSYNC_REF
(
"AutoSync Reference"
,
0
),
HDSPM_SYSTEM_SAMPLE_RATE
(
"System Sample Rate"
,
0
),
HDSPM_SYSTEM_SAMPLE_RATE
(
"System Sample Rate"
,
0
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"External Rate"
,
0
),
HDSPM_AUTOSYNC_SAMPLE_RATE
(
"External Rate"
,
11
),
HDSPM_SYNC_CHECK
(
"WC Sync Check"
,
0
),
HDSPM_SYNC_CHECK
(
"WC Sync Check"
,
0
),
HDSPM_SYNC_CHECK
(
"AES1 Sync Check"
,
1
),
HDSPM_SYNC_CHECK
(
"AES1 Sync Check"
,
1
),
HDSPM_SYNC_CHECK
(
"AES2 Sync Check"
,
2
),
HDSPM_SYNC_CHECK
(
"AES2 Sync Check"
,
2
),
...
@@ -4501,77 +4766,22 @@ static int snd_hdspm_create_controls(struct snd_card *card,
...
@@ -4501,77 +4766,22 @@ static int snd_hdspm_create_controls(struct snd_card *card,
------------------------------------------------------------*/
------------------------------------------------------------*/
static
void
static
void
snd_hdspm_proc_read_
madi
(
struct
snd_info_entry
*
entry
,
snd_hdspm_proc_read_
tco
(
struct
snd_info_entry
*
entry
,
struct
snd_info_buffer
*
buffer
)
struct
snd_info_buffer
*
buffer
)
{
{
struct
hdspm
*
hdspm
=
entry
->
private_data
;
struct
hdspm
*
hdspm
=
entry
->
private_data
;
unsigned
int
status
,
status2
,
control
,
freq
;
unsigned
int
status
,
control
;
char
*
pref_sync_ref
;
char
*
autosync_ref
;
char
*
system_clock_mode
;
char
*
insel
;
int
x
,
x2
;
/* TCO stuff */
int
a
,
ltc
,
frames
,
seconds
,
minutes
,
hours
;
int
a
,
ltc
,
frames
,
seconds
,
minutes
,
hours
;
unsigned
int
period
;
unsigned
int
period
;
u64
freq_const
=
0
;
u64
freq_const
=
0
;
u32
rate
;
u32
rate
;
snd_iprintf
(
buffer
,
"--- TCO ---
\n
"
);
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
status2
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister2
);
control
=
hdspm
->
control_register
;
control
=
hdspm
->
control_register
;
freq
=
hdspm_read
(
hdspm
,
HDSPM_timecodeRegister
);
snd_iprintf
(
buffer
,
"%s (Card #%d) Rev.%x Status2first3bits: %x
\n
"
,
hdspm
->
card_name
,
hdspm
->
card
->
number
+
1
,
hdspm
->
firmware_rev
,
(
status2
&
HDSPM_version0
)
|
(
status2
&
HDSPM_version1
)
|
(
status2
&
HDSPM_version2
));
snd_iprintf
(
buffer
,
"HW Serial: 0x%06x%06x
\n
"
,
(
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn1
)
>>
8
)
&
0xFFFFFF
,
hdspm
->
serial
);
snd_iprintf
(
buffer
,
"IRQ: %d Registers bus: 0x%lx VM: 0x%lx
\n
"
,
hdspm
->
irq
,
hdspm
->
port
,
(
unsigned
long
)
hdspm
->
iobase
);
snd_iprintf
(
buffer
,
"--- System ---
\n
"
);
snd_iprintf
(
buffer
,
"IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d
\n
"
,
status
&
HDSPM_audioIRQPending
,
(
status
&
HDSPM_midi0IRQPending
)
?
1
:
0
,
(
status
&
HDSPM_midi1IRQPending
)
?
1
:
0
,
hdspm
->
irq_count
);
snd_iprintf
(
buffer
,
"HW pointer: id = %d, rawptr = %d (%d->%d) "
"estimated= %ld (bytes)
\n
"
,
((
status
&
HDSPM_BufferID
)
?
1
:
0
),
(
status
&
HDSPM_BufferPositionMask
),
(
status
&
HDSPM_BufferPositionMask
)
%
(
2
*
(
int
)
hdspm
->
period_bytes
),
((
status
&
HDSPM_BufferPositionMask
)
-
64
)
%
(
2
*
(
int
)
hdspm
->
period_bytes
),
(
long
)
hdspm_hw_pointer
(
hdspm
)
*
4
);
snd_iprintf
(
buffer
,
"MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x
\n
"
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusOut0
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusOut1
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn0
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn1
)
&
0xFF
);
snd_iprintf
(
buffer
,
"MIDIoverMADI FIFO: In=0x%x, Out=0x%x
\n
"
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn2
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusOut2
)
&
0xFF
);
snd_iprintf
(
buffer
,
"Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
"status2=0x%x
\n
"
,
hdspm
->
control_register
,
hdspm
->
control2_register
,
status
,
status2
);
if
(
status
&
HDSPM_tco_detect
)
{
if
(
status
&
HDSPM_tco_detect
)
{
snd_iprintf
(
buffer
,
"TCO module detected.
\n
"
);
snd_iprintf
(
buffer
,
"TCO module detected.
\n
"
);
a
=
hdspm_read
(
hdspm
,
HDSPM_RD_TCO
+
4
);
a
=
hdspm_read
(
hdspm
,
HDSPM_RD_TCO
+
4
);
...
@@ -4665,6 +4875,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
...
@@ -4665,6 +4875,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
}
else
{
}
else
{
snd_iprintf
(
buffer
,
"No TCO module detected.
\n
"
);
snd_iprintf
(
buffer
,
"No TCO module detected.
\n
"
);
}
}
}
static
void
snd_hdspm_proc_read_madi
(
struct
snd_info_entry
*
entry
,
struct
snd_info_buffer
*
buffer
)
{
struct
hdspm
*
hdspm
=
entry
->
private_data
;
unsigned
int
status
,
status2
,
control
,
freq
;
char
*
pref_sync_ref
;
char
*
autosync_ref
;
char
*
system_clock_mode
;
char
*
insel
;
int
x
,
x2
;
status
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister
);
status2
=
hdspm_read
(
hdspm
,
HDSPM_statusRegister2
);
control
=
hdspm
->
control_register
;
freq
=
hdspm_read
(
hdspm
,
HDSPM_timecodeRegister
);
snd_iprintf
(
buffer
,
"%s (Card #%d) Rev.%x Status2first3bits: %x
\n
"
,
hdspm
->
card_name
,
hdspm
->
card
->
number
+
1
,
hdspm
->
firmware_rev
,
(
status2
&
HDSPM_version0
)
|
(
status2
&
HDSPM_version1
)
|
(
status2
&
HDSPM_version2
));
snd_iprintf
(
buffer
,
"HW Serial: 0x%06x%06x
\n
"
,
(
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn1
)
>>
8
)
&
0xFFFFFF
,
hdspm
->
serial
);
snd_iprintf
(
buffer
,
"IRQ: %d Registers bus: 0x%lx VM: 0x%lx
\n
"
,
hdspm
->
irq
,
hdspm
->
port
,
(
unsigned
long
)
hdspm
->
iobase
);
snd_iprintf
(
buffer
,
"--- System ---
\n
"
);
snd_iprintf
(
buffer
,
"IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d
\n
"
,
status
&
HDSPM_audioIRQPending
,
(
status
&
HDSPM_midi0IRQPending
)
?
1
:
0
,
(
status
&
HDSPM_midi1IRQPending
)
?
1
:
0
,
hdspm
->
irq_count
);
snd_iprintf
(
buffer
,
"HW pointer: id = %d, rawptr = %d (%d->%d) "
"estimated= %ld (bytes)
\n
"
,
((
status
&
HDSPM_BufferID
)
?
1
:
0
),
(
status
&
HDSPM_BufferPositionMask
),
(
status
&
HDSPM_BufferPositionMask
)
%
(
2
*
(
int
)
hdspm
->
period_bytes
),
((
status
&
HDSPM_BufferPositionMask
)
-
64
)
%
(
2
*
(
int
)
hdspm
->
period_bytes
),
(
long
)
hdspm_hw_pointer
(
hdspm
)
*
4
);
snd_iprintf
(
buffer
,
"MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x
\n
"
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusOut0
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusOut1
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn0
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn1
)
&
0xFF
);
snd_iprintf
(
buffer
,
"MIDIoverMADI FIFO: In=0x%x, Out=0x%x
\n
"
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusIn2
)
&
0xFF
,
hdspm_read
(
hdspm
,
HDSPM_midiStatusOut2
)
&
0xFF
);
snd_iprintf
(
buffer
,
"Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
"status2=0x%x
\n
"
,
hdspm
->
control_register
,
hdspm
->
control2_register
,
status
,
status2
);
snd_iprintf
(
buffer
,
"--- Settings ---
\n
"
);
snd_iprintf
(
buffer
,
"--- Settings ---
\n
"
);
...
@@ -4768,6 +5047,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
...
@@ -4768,6 +5047,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
(
status
&
HDSPM_RX_64ch
)
?
"64 channels"
:
(
status
&
HDSPM_RX_64ch
)
?
"64 channels"
:
"56 channels"
);
"56 channels"
);
/* call readout function for TCO specific status */
snd_hdspm_proc_read_tco
(
entry
,
buffer
);
snd_iprintf
(
buffer
,
"
\n
"
);
snd_iprintf
(
buffer
,
"
\n
"
);
}
}
...
@@ -4909,11 +5191,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
...
@@ -4909,11 +5191,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
autosync_ref
=
"AES7"
;
break
;
autosync_ref
=
"AES7"
;
break
;
case
HDSPM_AES32_AUTOSYNC_FROM_AES8
:
case
HDSPM_AES32_AUTOSYNC_FROM_AES8
:
autosync_ref
=
"AES8"
;
break
;
autosync_ref
=
"AES8"
;
break
;
case
HDSPM_AES32_AUTOSYNC_FROM_TCO
:
autosync_ref
=
"TCO"
;
break
;
case
HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN
:
autosync_ref
=
"Sync In"
;
break
;
default:
default:
autosync_ref
=
"---"
;
break
;
autosync_ref
=
"---"
;
break
;
}
}
snd_iprintf
(
buffer
,
"AutoSync ref = %s
\n
"
,
autosync_ref
);
snd_iprintf
(
buffer
,
"AutoSync ref = %s
\n
"
,
autosync_ref
);
/* call readout function for TCO specific status */
snd_hdspm_proc_read_tco
(
entry
,
buffer
);
snd_iprintf
(
buffer
,
"
\n
"
);
snd_iprintf
(
buffer
,
"
\n
"
);
}
}
...
@@ -5097,7 +5386,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
...
@@ -5097,7 +5386,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
case
AES32
:
case
AES32
:
hdspm
->
control_register
=
hdspm
->
control_register
=
HDSPM_ClockModeMaster
|
/* Master Clo
a
ck Mode on */
HDSPM_ClockModeMaster
|
/* Master Clock Mode on */
hdspm_encode_latency
(
7
)
|
/* latency max=8192samples */
hdspm_encode_latency
(
7
)
|
/* latency max=8192samples */
HDSPM_SyncRef0
|
/* AES1 is syncclock */
HDSPM_SyncRef0
|
/* AES1 is syncclock */
HDSPM_LineOut
|
/* Analog output in */
HDSPM_LineOut
|
/* Analog output in */
...
@@ -5123,9 +5412,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
...
@@ -5123,9 +5412,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
all_in_all_mixer
(
hdspm
,
0
*
UNITY_GAIN
);
all_in_all_mixer
(
hdspm
,
0
*
UNITY_GAIN
);
if
(
hdspm
->
io_type
==
AIO
||
hdspm
->
io_type
==
RayDAT
)
{
if
(
hdspm
_is_raydat_or_aio
(
hdspm
))
hdspm_write
(
hdspm
,
HDSPM_WR_SETTINGS
,
hdspm
->
settings_register
);
hdspm_write
(
hdspm
,
HDSPM_WR_SETTINGS
,
hdspm
->
settings_register
);
}
/* set a default rate so that the channel map is set up. */
/* set a default rate so that the channel map is set up. */
hdspm_set_rate
(
hdspm
,
48000
,
1
);
hdspm_set_rate
(
hdspm
,
48000
,
1
);
...
@@ -5371,6 +5659,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
...
@@ -5371,6 +5659,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
*/
*/
/* For AES cards, the float format bit is the same as the
* preferred sync reference. Since we don't want to break
* sync settings, we have to skip the remaining part of this
* function.
*/
if
(
hdspm
->
io_type
==
AES32
)
{
return
0
;
}
/* Switch to native float format if requested */
/* Switch to native float format if requested */
if
(
SNDRV_PCM_FORMAT_FLOAT_LE
==
params_format
(
params
))
{
if
(
SNDRV_PCM_FORMAT_FLOAT_LE
==
params_format
(
params
))
{
if
(
!
(
hdspm
->
control_register
&
HDSPe_FLOAT_FORMAT
))
if
(
!
(
hdspm
->
control_register
&
HDSPe_FLOAT_FORMAT
))
...
@@ -6479,10 +6777,6 @@ static int snd_hdspm_create(struct snd_card *card,
...
@@ -6479,10 +6777,6 @@ static int snd_hdspm_create(struct snd_card *card,
break
;
break
;
case
AIO
:
case
AIO
:
if
(
0
==
(
hdspm_read
(
hdspm
,
HDSPM_statusRegister2
)
&
HDSPM_s2_AEBI_D
))
{
snd_printk
(
KERN_INFO
"HDSPM: AEB input board found, but not supported
\n
"
);
}
hdspm
->
ss_in_channels
=
AIO_IN_SS_CHANNELS
;
hdspm
->
ss_in_channels
=
AIO_IN_SS_CHANNELS
;
hdspm
->
ds_in_channels
=
AIO_IN_DS_CHANNELS
;
hdspm
->
ds_in_channels
=
AIO_IN_DS_CHANNELS
;
hdspm
->
qs_in_channels
=
AIO_IN_QS_CHANNELS
;
hdspm
->
qs_in_channels
=
AIO_IN_QS_CHANNELS
;
...
@@ -6490,6 +6784,20 @@ static int snd_hdspm_create(struct snd_card *card,
...
@@ -6490,6 +6784,20 @@ static int snd_hdspm_create(struct snd_card *card,
hdspm
->
ds_out_channels
=
AIO_OUT_DS_CHANNELS
;
hdspm
->
ds_out_channels
=
AIO_OUT_DS_CHANNELS
;
hdspm
->
qs_out_channels
=
AIO_OUT_QS_CHANNELS
;
hdspm
->
qs_out_channels
=
AIO_OUT_QS_CHANNELS
;
if
(
0
==
(
hdspm_read
(
hdspm
,
HDSPM_statusRegister2
)
&
HDSPM_s2_AEBI_D
))
{
snd_printk
(
KERN_INFO
"HDSPM: AEB input board found
\n
"
);
hdspm
->
ss_in_channels
+=
4
;
hdspm
->
ds_in_channels
+=
4
;
hdspm
->
qs_in_channels
+=
4
;
}
if
(
0
==
(
hdspm_read
(
hdspm
,
HDSPM_statusRegister2
)
&
HDSPM_s2_AEBO_D
))
{
snd_printk
(
KERN_INFO
"HDSPM: AEB output board found
\n
"
);
hdspm
->
ss_out_channels
+=
4
;
hdspm
->
ds_out_channels
+=
4
;
hdspm
->
qs_out_channels
+=
4
;
}
hdspm
->
channel_map_out_ss
=
channel_map_aio_out_ss
;
hdspm
->
channel_map_out_ss
=
channel_map_aio_out_ss
;
hdspm
->
channel_map_out_ds
=
channel_map_aio_out_ds
;
hdspm
->
channel_map_out_ds
=
channel_map_aio_out_ds
;
hdspm
->
channel_map_out_qs
=
channel_map_aio_out_qs
;
hdspm
->
channel_map_out_qs
=
channel_map_aio_out_qs
;
...
@@ -6558,6 +6866,7 @@ static int snd_hdspm_create(struct snd_card *card,
...
@@ -6558,6 +6866,7 @@ static int snd_hdspm_create(struct snd_card *card,
break
;
break
;
case
MADI
:
case
MADI
:
case
AES32
:
if
(
hdspm_read
(
hdspm
,
HDSPM_statusRegister
)
&
HDSPM_tco_detect
)
{
if
(
hdspm_read
(
hdspm
,
HDSPM_statusRegister
)
&
HDSPM_tco_detect
)
{
hdspm
->
midiPorts
++
;
hdspm
->
midiPorts
++
;
hdspm
->
tco
=
kzalloc
(
sizeof
(
struct
hdspm_tco
),
hdspm
->
tco
=
kzalloc
(
sizeof
(
struct
hdspm_tco
),
...
@@ -6565,7 +6874,7 @@ static int snd_hdspm_create(struct snd_card *card,
...
@@ -6565,7 +6874,7 @@ static int snd_hdspm_create(struct snd_card *card,
if
(
NULL
!=
hdspm
->
tco
)
{
if
(
NULL
!=
hdspm
->
tco
)
{
hdspm_tco_write
(
hdspm
);
hdspm_tco_write
(
hdspm
);
}
}
snd_printk
(
KERN_INFO
"HDSPM: MADI TCO module found
\n
"
);
snd_printk
(
KERN_INFO
"HDSPM: MADI
/AES
TCO module found
\n
"
);
}
else
{
}
else
{
hdspm
->
tco
=
NULL
;
hdspm
->
tco
=
NULL
;
}
}
...
@@ -6580,10 +6889,12 @@ static int snd_hdspm_create(struct snd_card *card,
...
@@ -6580,10 +6889,12 @@ static int snd_hdspm_create(struct snd_card *card,
case
AES32
:
case
AES32
:
if
(
hdspm
->
tco
)
{
if
(
hdspm
->
tco
)
{
hdspm
->
texts_autosync
=
texts_autosync_aes_tco
;
hdspm
->
texts_autosync
=
texts_autosync_aes_tco
;
hdspm
->
texts_autosync_items
=
10
;
hdspm
->
texts_autosync_items
=
ARRAY_SIZE
(
texts_autosync_aes_tco
);
}
else
{
}
else
{
hdspm
->
texts_autosync
=
texts_autosync_aes
;
hdspm
->
texts_autosync
=
texts_autosync_aes
;
hdspm
->
texts_autosync_items
=
9
;
hdspm
->
texts_autosync_items
=
ARRAY_SIZE
(
texts_autosync_aes
);
}
}
break
;
break
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录