Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
06f1c663
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
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看板
提交
06f1c663
编写于
12月 10, 2012
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'asoc/topic/wm8994' into asoc-next
上级
6f5716a2
98869f68
变更
7
显示空白变更内容
内联
并排
Showing
7 changed file
with
273 addition
and
208 deletion
+273
-208
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-core.c
+19
-16
include/linux/mfd/wm8994/core.h
include/linux/mfd/wm8994/core.h
+4
-0
include/linux/mfd/wm8994/pdata.h
include/linux/mfd/wm8994/pdata.h
+5
-0
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8958-dsp2.c
+34
-45
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.c
+202
-141
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8994.h
+8
-5
sound/soc/samsung/littlemill.c
sound/soc/samsung/littlemill.c
+1
-1
未找到文件。
drivers/mfd/wm8994-core.c
浏览文件 @
06f1c663
...
...
@@ -401,13 +401,19 @@ static const __devinitconst struct reg_default wm1811_reva_patch[] = {
*/
static
__devinit
int
wm8994_device_init
(
struct
wm8994
*
wm8994
,
int
irq
)
{
struct
wm8994_pdata
*
pdata
=
wm8994
->
dev
->
platform_data
;
struct
wm8994_pdata
*
pdata
;
struct
regmap_config
*
regmap_config
;
const
struct
reg_default
*
regmap_patch
=
NULL
;
const
char
*
devname
;
int
ret
,
i
,
patch_regs
;
int
pulls
=
0
;
if
(
dev_get_platdata
(
wm8994
->
dev
))
{
pdata
=
dev_get_platdata
(
wm8994
->
dev
);
wm8994
->
pdata
=
*
pdata
;
}
pdata
=
&
wm8994
->
pdata
;
dev_set_drvdata
(
wm8994
->
dev
,
wm8994
);
/* Add the on-chip regulators first for bootstrapping */
...
...
@@ -604,7 +610,6 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
}
}
if
(
pdata
)
{
wm8994
->
irq_base
=
pdata
->
irq_base
;
wm8994
->
gpio_base
=
pdata
->
gpio_base
;
...
...
@@ -612,8 +617,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pdata
->
gpio_defaults
);
i
++
)
{
if
(
pdata
->
gpio_defaults
[
i
])
{
wm8994_set_bits
(
wm8994
,
WM8994_GPIO_1
+
i
,
0xffff
,
pdata
->
gpio_defaults
[
i
]);
0xffff
,
pdata
->
gpio_defaults
[
i
]);
}
}
...
...
@@ -621,7 +625,6 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
if
(
pdata
->
spkmode_pu
)
pulls
|=
WM8994_SPKMODE_PU
;
}
/* Disable unneeded pulls */
wm8994_set_bits
(
wm8994
,
WM8994_PULL_CONTROL_2
,
...
...
include/linux/mfd/wm8994/core.h
浏览文件 @
06f1c663
...
...
@@ -19,6 +19,8 @@
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/mfd/wm8994/pdata.h>
enum
wm8994_type
{
WM8994
=
0
,
WM8958
=
1
,
...
...
@@ -55,6 +57,8 @@ struct regulator_bulk_data;
struct
wm8994
{
struct
mutex
irq_lock
;
struct
wm8994_pdata
pdata
;
enum
wm8994_type
type
;
int
revision
;
int
cust_id
;
...
...
include/linux/mfd/wm8994/pdata.h
浏览文件 @
06f1c663
...
...
@@ -176,6 +176,11 @@ struct wm8994_pdata {
unsigned
int
lineout1fb
:
1
;
unsigned
int
lineout2fb
:
1
;
/* Delay between detecting a jack and starting microphone
* detect (specified in ms)
*/
int
micdet_delay
;
/* IRQ for microphone detection if brought out directly as a
* signal.
*/
...
...
sound/soc/codecs/wm8958-dsp2.c
浏览文件 @
06f1c663
...
...
@@ -195,7 +195,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
static
void
wm8958_dsp_start_mbc
(
struct
snd_soc_codec
*
codec
,
int
path
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
i
;
/* If the DSP is already running then noop */
...
...
@@ -210,9 +210,9 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
WM8958_DSP2_ENA
,
WM8958_DSP2_ENA
);
/* If we've got user supplied MBC settings use them */
if
(
pdata
&&
pdata
->
num_mbc_cfgs
)
{
if
(
control
->
pdata
.
num_mbc_cfgs
)
{
struct
wm8958_mbc_cfg
*
cfg
=
&
pdata
->
mbc_cfgs
[
wm8994
->
mbc_cfg
];
=
&
control
->
pdata
.
mbc_cfgs
[
wm8994
->
mbc_cfg
];
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cfg
->
coeff_regs
);
i
++
)
snd_soc_write
(
codec
,
i
+
WM8958_MBC_BAND_1_K_1
,
...
...
@@ -239,7 +239,7 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
static
void
wm8958_dsp_start_vss
(
struct
snd_soc_codec
*
codec
,
int
path
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
i
,
ena
;
if
(
wm8994
->
mbc_vss
)
...
...
@@ -249,26 +249,26 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
WM8958_DSP2_ENA
,
WM8958_DSP2_ENA
);
/* If we've got user supplied settings use them */
if
(
pdata
&&
pdata
->
num_mbc_cfgs
)
{
if
(
control
->
pdata
.
num_mbc_cfgs
)
{
struct
wm8958_mbc_cfg
*
cfg
=
&
pdata
->
mbc_cfgs
[
wm8994
->
mbc_cfg
];
=
&
control
->
pdata
.
mbc_cfgs
[
wm8994
->
mbc_cfg
];
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cfg
->
combined_regs
);
i
++
)
snd_soc_write
(
codec
,
i
+
0x2800
,
cfg
->
combined_regs
[
i
]);
}
if
(
pdata
&&
pdata
->
num_vss_cfgs
)
{
if
(
control
->
pdata
.
num_vss_cfgs
)
{
struct
wm8958_vss_cfg
*
cfg
=
&
pdata
->
vss_cfgs
[
wm8994
->
vss_cfg
];
=
&
control
->
pdata
.
vss_cfgs
[
wm8994
->
vss_cfg
];
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cfg
->
regs
);
i
++
)
snd_soc_write
(
codec
,
i
+
0x2600
,
cfg
->
regs
[
i
]);
}
if
(
pdata
&&
pdata
->
num_vss_hpf_cfgs
)
{
if
(
control
->
pdata
.
num_vss_hpf_cfgs
)
{
struct
wm8958_vss_hpf_cfg
*
cfg
=
&
pdata
->
vss_hpf_cfgs
[
wm8994
->
vss_hpf_cfg
];
=
&
control
->
pdata
.
vss_hpf_cfgs
[
wm8994
->
vss_hpf_cfg
];
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cfg
->
regs
);
i
++
)
snd_soc_write
(
codec
,
i
+
0x2400
,
cfg
->
regs
[
i
]);
...
...
@@ -300,7 +300,7 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
static
void
wm8958_dsp_start_enh_eq
(
struct
snd_soc_codec
*
codec
,
int
path
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
i
;
wm8958_dsp2_fw
(
codec
,
"ENH_EQ"
,
wm8994
->
enh_eq
,
false
);
...
...
@@ -309,9 +309,9 @@ static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
WM8958_DSP2_ENA
,
WM8958_DSP2_ENA
);
/* If we've got user supplied settings use them */
if
(
pdata
&&
pdata
->
num_enh_eq_cfgs
)
{
if
(
control
->
pdata
.
num_enh_eq_cfgs
)
{
struct
wm8958_enh_eq_cfg
*
cfg
=
&
pdata
->
enh_eq_cfgs
[
wm8994
->
enh_eq_cfg
];
=
&
control
->
pdata
.
enh_eq_cfgs
[
wm8994
->
enh_eq_cfg
];
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cfg
->
regs
);
i
++
)
snd_soc_write
(
codec
,
i
+
0x2200
,
...
...
@@ -458,7 +458,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
{
struct
snd_soc_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
value
=
ucontrol
->
value
.
integer
.
value
[
0
];
int
reg
;
...
...
@@ -467,7 +467,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
if
(
reg
<
0
||
reg
&
WM8958_DSP2CLK_ENA
)
return
-
EBUSY
;
if
(
value
>=
pdata
->
num_mbc_cfgs
)
if
(
value
>=
control
->
pdata
.
num_mbc_cfgs
)
return
-
EINVAL
;
wm8994
->
mbc_cfg
=
value
;
...
...
@@ -548,7 +548,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
{
struct
snd_soc_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
value
=
ucontrol
->
value
.
integer
.
value
[
0
];
int
reg
;
...
...
@@ -557,7 +557,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
if
(
reg
<
0
||
reg
&
WM8958_DSP2CLK_ENA
)
return
-
EBUSY
;
if
(
value
>=
pdata
->
num_vss_cfgs
)
if
(
value
>=
control
->
pdata
.
num_vss_cfgs
)
return
-
EINVAL
;
wm8994
->
vss_cfg
=
value
;
...
...
@@ -581,7 +581,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
{
struct
snd_soc_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
value
=
ucontrol
->
value
.
integer
.
value
[
0
];
int
reg
;
...
...
@@ -590,7 +590,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
if
(
reg
<
0
||
reg
&
WM8958_DSP2CLK_ENA
)
return
-
EBUSY
;
if
(
value
>=
pdata
->
num_vss_hpf_cfgs
)
if
(
value
>=
control
->
pdata
.
num_vss_hpf_cfgs
)
return
-
EINVAL
;
wm8994
->
vss_hpf_cfg
=
value
;
...
...
@@ -748,7 +748,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
{
struct
snd_soc_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
value
=
ucontrol
->
value
.
integer
.
value
[
0
];
int
reg
;
...
...
@@ -757,7 +757,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
if
(
reg
<
0
||
reg
&
WM8958_DSP2CLK_ENA
)
return
-
EBUSY
;
if
(
value
>=
pdata
->
num_enh_eq_cfgs
)
if
(
value
>=
control
->
pdata
.
num_enh_eq_cfgs
)
return
-
EINVAL
;
wm8994
->
enh_eq_cfg
=
value
;
...
...
@@ -883,13 +883,6 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
wm8994
->
mbc_vss
=
fw
;
mutex_unlock
(
&
codec
->
mutex
);
}
/* We can't have more than one request outstanding at once so
* we daisy chain.
*/
request_firmware_nowait
(
THIS_MODULE
,
FW_ACTION_HOTPLUG
,
"wm8958_enh_eq.wfw"
,
codec
->
dev
,
GFP_KERNEL
,
codec
,
wm8958_enh_eq_loaded
);
}
static
void
wm8958_mbc_loaded
(
const
struct
firmware
*
fw
,
void
*
context
)
...
...
@@ -897,25 +890,18 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
struct
snd_soc_codec
*
codec
=
context
;
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
if
(
wm8958_dsp2_fw
(
codec
,
"MBC"
,
fw
,
true
)
!=
0
)
return
;
if
(
fw
&&
(
wm8958_dsp2_fw
(
codec
,
"MBC"
,
fw
,
true
)
==
0
))
{
mutex_lock
(
&
codec
->
mutex
);
wm8994
->
mbc
=
fw
;
mutex_unlock
(
&
codec
->
mutex
);
/* We can't have more than one request outstanding at once so
* we daisy chain.
*/
request_firmware_nowait
(
THIS_MODULE
,
FW_ACTION_HOTPLUG
,
"wm8958_mbc_vss.wfw"
,
codec
->
dev
,
GFP_KERNEL
,
codec
,
wm8958_mbc_vss_loaded
);
}
}
void
wm8958_dsp2_init
(
struct
snd_soc_codec
*
codec
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
wm8994_pdata
*
pdata
=
&
control
->
pdata
;
int
ret
,
i
;
wm8994
->
dsp_active
=
-
1
;
...
...
@@ -932,9 +918,12 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
request_firmware_nowait
(
THIS_MODULE
,
FW_ACTION_HOTPLUG
,
"wm8958_mbc.wfw"
,
codec
->
dev
,
GFP_KERNEL
,
codec
,
wm8958_mbc_loaded
);
if
(
!
pdata
)
return
;
request_firmware_nowait
(
THIS_MODULE
,
FW_ACTION_HOTPLUG
,
"wm8958_mbc_vss.wfw"
,
codec
->
dev
,
GFP_KERNEL
,
codec
,
wm8958_mbc_vss_loaded
);
request_firmware_nowait
(
THIS_MODULE
,
FW_ACTION_HOTPLUG
,
"wm8958_enh_eq.wfw"
,
codec
->
dev
,
GFP_KERNEL
,
codec
,
wm8958_enh_eq_loaded
);
if
(
pdata
->
num_mbc_cfgs
)
{
struct
snd_kcontrol_new
control
[]
=
{
...
...
sound/soc/codecs/wm8994.c
浏览文件 @
06f1c663
...
...
@@ -91,8 +91,6 @@ static int wm8994_retune_mobile_base[] = {
WM8994_AIF2_EQ_GAINS_1
,
};
static
void
wm8958_default_micdet
(
u16
status
,
void
*
data
);
static
const
struct
wm8958_micd_rate
micdet_rates
[]
=
{
{
32768
,
true
,
1
,
4
},
{
32768
,
false
,
1
,
1
},
...
...
@@ -110,15 +108,12 @@ static const struct wm8958_micd_rate jackdet_rates[] = {
static
void
wm8958_micd_set_rate
(
struct
snd_soc_codec
*
codec
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
best
,
i
,
sysclk
,
val
;
bool
idle
;
const
struct
wm8958_micd_rate
*
rates
;
int
num_rates
;
if
(
!
(
wm8994
->
pdata
&&
wm8994
->
pdata
->
micd_rates
)
&&
wm8994
->
jack_cb
!=
wm8958_default_micdet
)
return
;
idle
=
!
wm8994
->
jack_mic
;
sysclk
=
snd_soc_read
(
codec
,
WM8994_CLOCKING_1
);
...
...
@@ -127,9 +122,9 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
else
sysclk
=
wm8994
->
aifclk
[
0
];
if
(
wm8994
->
pdata
&&
wm8994
->
pdata
->
micd_rates
)
{
rates
=
wm8994
->
pdata
->
micd_rates
;
num_rates
=
wm8994
->
pdata
->
num_micd_rates
;
if
(
control
->
pdata
.
micd_rates
)
{
rates
=
control
->
pdata
.
micd_rates
;
num_rates
=
control
->
pdata
.
num_micd_rates
;
}
else
if
(
wm8994
->
jackdet
)
{
rates
=
jackdet_rates
;
num_rates
=
ARRAY_SIZE
(
jackdet_rates
);
...
...
@@ -326,7 +321,8 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
static
void
wm8994_set_drc
(
struct
snd_soc_codec
*
codec
,
int
drc
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
wm8994_pdata
*
pdata
=
&
control
->
pdata
;
int
base
=
wm8994_drc_base
[
drc
];
int
cfg
=
wm8994
->
drc_cfg
[
drc
];
int
save
,
i
;
...
...
@@ -362,7 +358,8 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
{
struct
snd_soc_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
wm8994_pdata
*
pdata
=
&
control
->
pdata
;
int
drc
=
wm8994_get_drc
(
kcontrol
->
id
.
name
);
int
value
=
ucontrol
->
value
.
integer
.
value
[
0
];
...
...
@@ -394,7 +391,8 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
static
void
wm8994_set_retune_mobile
(
struct
snd_soc_codec
*
codec
,
int
block
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
wm8994_pdata
*
pdata
=
&
control
->
pdata
;
int
base
=
wm8994_retune_mobile_base
[
block
];
int
iface
,
best
,
best_val
,
save
,
i
,
cfg
;
...
...
@@ -465,7 +463,8 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
{
struct
snd_soc_codec
*
codec
=
snd_kcontrol_chip
(
kcontrol
);
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
wm8994_pdata
*
pdata
=
&
control
->
pdata
;
int
block
=
wm8994_get_retune_mobile_block
(
kcontrol
->
id
.
name
);
int
value
=
ucontrol
->
value
.
integer
.
value
[
0
];
...
...
@@ -736,7 +735,7 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
if
(
!
wm8994
->
jackdet
||
!
wm8994
->
jack_cb
)
if
(
!
wm8994
->
jackdet
||
!
wm8994
->
micdet
[
0
].
jack
)
return
;
if
(
wm8994
->
active_refcount
)
...
...
@@ -862,7 +861,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
WM8994_BIAS_SRC
|
WM8994_STARTUP_BIAS_ENA
|
WM8994_VMID_BUF_ENA
|
(
0x
3
<<
WM8994_VMID_RAMP_SHIFT
));
(
0x
2
<<
WM8994_VMID_RAMP_SHIFT
));
/* Main bias enable, VMID=2x40k */
snd_soc_update_bits
(
codec
,
WM8994_POWER_MANAGEMENT_1
,
...
...
@@ -870,7 +869,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
WM8994_VMID_SEL_MASK
,
WM8994_BIAS_ENA
|
0x2
);
msleep
(
5
0
);
msleep
(
30
0
);
snd_soc_update_bits
(
codec
,
WM8994_ANTIPOP_2
,
WM8994_VMID_RAMP_MASK
|
...
...
@@ -939,16 +938,10 @@ static void vmid_dereference(struct snd_soc_codec *codec)
WM8994_BIAS_SRC
|
WM8994_VMID_DISCH
);
switch
(
wm8994
->
vmid_mode
)
{
case
WM8994_VMID_FORCE
:
msleep
(
350
);
break
;
default:
break
;
}
snd_soc_update_bits
(
codec
,
WM8994_POWER_MANAGEMENT_1
,
WM8994_VMID_SEL_MASK
,
0
);
snd_soc_update_bits
(
codec
,
WM8994_ADDITIONAL_CONTROL
,
WM8994_VROI
,
WM8994_VROI
);
msleep
(
400
);
/* Active discharge */
snd_soc_update_bits
(
codec
,
WM8994_ANTIPOP_1
,
...
...
@@ -957,17 +950,12 @@ static void vmid_dereference(struct snd_soc_codec *codec)
WM8994_LINEOUT1_DISCH
|
WM8994_LINEOUT2_DISCH
);
msleep
(
150
);
snd_soc_update_bits
(
codec
,
WM8994_POWER_MANAGEMENT_3
,
WM8994_LINEOUT1N_ENA
|
WM8994_LINEOUT1P_ENA
|
WM8994_LINEOUT2N_ENA
|
WM8994_LINEOUT2P_ENA
,
0
);
snd_soc_update_bits
(
codec
,
WM8994_ADDITIONAL_CONTROL
,
WM8994_VROI
,
0
);
/* Switch off startup biases */
snd_soc_update_bits
(
codec
,
WM8994_ANTIPOP_2
,
WM8994_BIAS_SRC
|
...
...
@@ -976,10 +964,7 @@ static void vmid_dereference(struct snd_soc_codec *codec)
WM8994_VMID_RAMP_MASK
,
0
);
snd_soc_update_bits
(
codec
,
WM8994_POWER_MANAGEMENT_1
,
WM8994_BIAS_ENA
|
WM8994_VMID_SEL_MASK
,
0
);
snd_soc_update_bits
(
codec
,
WM8994_ANTIPOP_2
,
WM8994_VMID_RAMP_MASK
,
0
);
WM8994_VMID_SEL_MASK
,
0
);
}
pm_runtime_put
(
codec
->
dev
);
...
...
@@ -2277,6 +2262,18 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
configure_clock
(
codec
);
/*
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
* for detection.
*/
if
(
max
(
wm8994
->
aifclk
[
0
],
wm8994
->
aifclk
[
1
])
<
50000
)
{
dev_dbg
(
codec
->
dev
,
"Configuring AIFs for 128fs
\n
"
);
snd_soc_update_bits
(
codec
,
WM8994_AIF1_RATE
,
WM8994_AIF1CLK_RATE_MASK
,
0x1
);
snd_soc_update_bits
(
codec
,
WM8994_AIF2_RATE
,
WM8994_AIF2CLK_RATE_MASK
,
0x1
);
}
return
0
;
}
...
...
@@ -2365,6 +2362,18 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
configure_clock
(
codec
);
/*
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
* for detection.
*/
if
(
max
(
wm8994
->
aifclk
[
0
],
wm8994
->
aifclk
[
1
])
<
50000
)
{
dev_dbg
(
codec
->
dev
,
"Configuring AIFs for 128fs
\n
"
);
snd_soc_update_bits
(
codec
,
WM8994_AIF1_RATE
,
WM8994_AIF1CLK_RATE_MASK
,
0x1
);
snd_soc_update_bits
(
codec
,
WM8994_AIF2_RATE
,
WM8994_AIF2CLK_RATE_MASK
,
0x1
);
}
return
0
;
}
...
...
@@ -3082,7 +3091,8 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
static
void
wm8994_handle_retune_mobile_pdata
(
struct
wm8994_priv
*
wm8994
)
{
struct
snd_soc_codec
*
codec
=
wm8994
->
hubs
.
codec
;
struct
wm8994_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
wm8994_pdata
*
pdata
=
&
control
->
pdata
;
struct
snd_kcontrol_new
controls
[]
=
{
SOC_ENUM_EXT
(
"AIF1.1 EQ Mode"
,
wm8994
->
retune_mobile_enum
,
...
...
@@ -3149,7 +3159,8 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
static
void
wm8994_handle_pdata
(
struct
wm8994_priv
*
wm8994
)
{
struct
snd_soc_codec
*
codec
=
wm8994
->
hubs
.
codec
;
struct
wm8994_pdata
*
pdata
=
wm8994
->
pdata
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
wm8994_pdata
*
pdata
=
&
control
->
pdata
;
int
ret
,
i
;
if
(
!
pdata
)
...
...
@@ -3389,38 +3400,80 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
return
IRQ_HANDLED
;
}
/* Default microphone detection handler for WM8958 - the user can
* override this if they wish.
*/
static
void
wm8958_default_micdet
(
u16
status
,
void
*
data
)
static
void
wm1811_micd_stop
(
struct
snd_soc_codec
*
codec
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
if
(
!
wm8994
->
jackdet
)
return
;
mutex_lock
(
&
wm8994
->
accdet_lock
);
snd_soc_update_bits
(
codec
,
WM8958_MIC_DETECT_1
,
WM8958_MICD_ENA
,
0
);
wm1811_jackdet_set_mode
(
codec
,
WM1811_JACKDET_MODE_JACK
);
mutex_unlock
(
&
wm8994
->
accdet_lock
);
if
(
wm8994
->
wm8994
->
pdata
.
jd_ext_cap
)
snd_soc_dapm_disable_pin
(
&
codec
->
dapm
,
"MICBIAS2"
);
}
static
void
wm8958_button_det
(
struct
snd_soc_codec
*
codec
,
u16
status
)
{
struct
snd_soc_codec
*
codec
=
data
;
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
int
report
;
dev_dbg
(
codec
->
dev
,
"MICDET %x
\n
"
,
status
);
report
=
0
;
if
(
status
&
0x4
)
report
|=
SND_JACK_BTN_0
;
if
(
status
&
0x8
)
report
|=
SND_JACK_BTN_1
;
if
(
status
&
0x10
)
report
|=
SND_JACK_BTN_2
;
if
(
status
&
0x20
)
report
|=
SND_JACK_BTN_3
;
if
(
status
&
0x40
)
report
|=
SND_JACK_BTN_4
;
if
(
status
&
0x80
)
report
|=
SND_JACK_BTN_5
;
snd_soc_jack_report
(
wm8994
->
micdet
[
0
].
jack
,
report
,
wm8994
->
btn_mask
);
}
static
void
wm8958_mic_id
(
void
*
data
,
u16
status
)
{
struct
snd_soc_codec
*
codec
=
data
;
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
/* Either nothing present or just starting detection */
if
(
!
(
status
&
WM8958_MICD_STS
))
{
if
(
!
wm8994
->
jackdet
)
{
/* If nothing present then clear our statuses */
dev_dbg
(
codec
->
dev
,
"Detected open circuit
\n
"
);
wm8994
->
jack_mic
=
false
;
wm8994
->
mic_detecting
=
true
;
wm1811_micd_stop
(
codec
);
wm8958_micd_set_rate
(
codec
);
snd_soc_jack_report
(
wm8994
->
micdet
[
0
].
jack
,
0
,
wm8994
->
btn_mask
|
SND_JACK_HEADSET
);
}
return
;
}
/* If the measurement is showing a high impedence we've got a
* microphone.
*/
if
(
wm8994
->
mic_detecting
&&
(
status
&
0x600
)
)
{
if
(
status
&
0x600
)
{
dev_dbg
(
codec
->
dev
,
"Detected microphone
\n
"
);
wm8994
->
mic_detecting
=
false
;
...
...
@@ -3433,64 +3486,67 @@ static void wm8958_default_micdet(u16 status, void *data)
}
if
(
wm8994
->
mic_detecting
&&
status
&
0xfc
)
{
if
(
status
&
0xfc
)
{
dev_dbg
(
codec
->
dev
,
"Detected headphone
\n
"
);
wm8994
->
mic_detecting
=
false
;
wm8958_micd_set_rate
(
codec
);
/* If we have jackdet that will detect removal */
if
(
wm8994
->
jackdet
)
{
mutex_lock
(
&
wm8994
->
accdet_lock
);
snd_soc_update_bits
(
codec
,
WM8958_MIC_DETECT_1
,
WM8958_MICD_ENA
,
0
);
wm1811_jackdet_set_mode
(
codec
,
WM1811_JACKDET_MODE_JACK
);
mutex_unlock
(
&
wm8994
->
accdet_lock
);
if
(
wm8994
->
pdata
->
jd_ext_cap
)
snd_soc_dapm_disable_pin
(
&
codec
->
dapm
,
"MICBIAS2"
);
}
wm1811_micd_stop
(
codec
);
snd_soc_jack_report
(
wm8994
->
micdet
[
0
].
jack
,
SND_JACK_HEADPHONE
,
SND_JACK_HEADSET
);
}
}
/* Report short circuit as a button */
if
(
wm8994
->
jack_mic
)
{
report
=
0
;
if
(
status
&
0x4
)
report
|=
SND_JACK_BTN_0
;
/* Deferred mic detection to allow for extra settling time */
static
void
wm1811_mic_work
(
struct
work_struct
*
work
)
{
struct
wm8994_priv
*
wm8994
=
container_of
(
work
,
struct
wm8994_priv
,
mic_work
.
work
);
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
snd_soc_codec
*
codec
=
wm8994
->
hubs
.
codec
;
if
(
status
&
0x8
)
report
|=
SND_JACK_BTN_1
;
pm_runtime_get_sync
(
codec
->
dev
);
if
(
status
&
0x10
)
report
|=
SND_JACK_BTN_2
;
/* If required for an external cap force MICBIAS on */
if
(
control
->
pdata
.
jd_ext_cap
)
{
snd_soc_dapm_force_enable_pin
(
&
codec
->
dapm
,
"MICBIAS2"
);
snd_soc_dapm_sync
(
&
codec
->
dapm
);
}
if
(
status
&
0x20
)
report
|=
SND_JACK_BTN_3
;
mutex_lock
(
&
wm8994
->
accdet_lock
);
if
(
status
&
0x40
)
report
|=
SND_JACK_BTN_4
;
dev_dbg
(
codec
->
dev
,
"Starting mic detection
\n
"
);
if
(
status
&
0x80
)
report
|=
SND_JACK_BTN_5
;
/* Use a user-supplied callback if we have one */
if
(
wm8994
->
micd_cb
)
{
wm8994
->
micd_cb
(
wm8994
->
micd_cb_data
);
}
else
{
/*
* Start off measument of microphone impedence to find out
* what's actually there.
*/
wm8994
->
mic_detecting
=
true
;
wm1811_jackdet_set_mode
(
codec
,
WM1811_JACKDET_MODE_MIC
);
snd_soc_
jack_report
(
wm8994
->
micdet
[
0
].
jack
,
report
,
wm8994
->
btn_mask
);
snd_soc_
update_bits
(
codec
,
WM8958_MIC_DETECT_1
,
WM8958_MICD_ENA
,
WM8958_MICD_ENA
);
}
mutex_unlock
(
&
wm8994
->
accdet_lock
);
pm_runtime_put
(
codec
->
dev
);
}
static
irqreturn_t
wm1811_jackdet_irq
(
int
irq
,
void
*
data
)
{
struct
wm8994_priv
*
wm8994
=
data
;
struct
wm8994
*
control
=
wm8994
->
wm8994
;
struct
snd_soc_codec
*
codec
=
wm8994
->
hubs
.
codec
;
int
reg
;
int
reg
,
delay
;
bool
present
;
pm_runtime_get_sync
(
codec
->
dev
);
...
...
@@ -3521,18 +3577,14 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
snd_soc_update_bits
(
codec
,
WM1811_JACKDET_CTRL
,
WM1811_JACKDET_DB
,
0
);
/*
* Start off measument of microphone impedence to find
* out what's actually there.
*/
wm8994
->
mic_detecting
=
true
;
wm1811_jackdet_set_mode
(
codec
,
WM1811_JACKDET_MODE_MIC
);
snd_soc_update_bits
(
codec
,
WM8958_MIC_DETECT_1
,
WM8958_MICD_ENA
,
WM8958_MICD_ENA
);
delay
=
control
->
pdata
.
micdet_delay
;
schedule_delayed_work
(
&
wm8994
->
mic_work
,
msecs_to_jiffies
(
delay
));
}
else
{
dev_dbg
(
codec
->
dev
,
"Jack not detected
\n
"
);
cancel_delayed_work_sync
(
&
wm8994
->
mic_work
);
snd_soc_update_bits
(
codec
,
WM8958_MICBIAS2
,
WM8958_MICB2_DISCH
,
WM8958_MICB2_DISCH
);
...
...
@@ -3549,14 +3601,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
mutex_unlock
(
&
wm8994
->
accdet_lock
);
/* If required for an external cap force MICBIAS on */
if
(
wm8994
->
pdata
->
jd_ext_cap
)
{
if
(
present
)
snd_soc_dapm_force_enable_pin
(
&
codec
->
dapm
,
"MICBIAS2"
);
else
/* Turn off MICBIAS if it was on for an external cap */
if
(
control
->
pdata
.
jd_ext_cap
&&
!
present
)
snd_soc_dapm_disable_pin
(
&
codec
->
dapm
,
"MICBIAS2"
);
}
if
(
present
)
snd_soc_jack_report
(
wm8994
->
micdet
[
0
].
jack
,
...
...
@@ -3599,7 +3646,8 @@ static void wm1811_jackdet_bootstrap(struct work_struct *work)
* detection algorithm.
*/
int
wm8958_mic_detect
(
struct
snd_soc_codec
*
codec
,
struct
snd_soc_jack
*
jack
,
wm8958_micdet_cb
cb
,
void
*
cb_data
)
wm1811_micdet_cb
det_cb
,
void
*
det_cb_data
,
wm1811_mic_id_cb
id_cb
,
void
*
id_cb_data
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
*
control
=
wm8994
->
wm8994
;
...
...
@@ -3614,27 +3662,32 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
}
if
(
jack
)
{
if
(
!
cb
)
{
dev_dbg
(
codec
->
dev
,
"Using default micdet callback
\n
"
);
cb
=
wm8958_default_micdet
;
cb_data
=
codec
;
}
snd_soc_dapm_force_enable_pin
(
&
codec
->
dapm
,
"CLK_SYS"
);
snd_soc_dapm_sync
(
&
codec
->
dapm
);
wm8994
->
micdet
[
0
].
jack
=
jack
;
wm8994
->
jack_cb
=
cb
;
wm8994
->
jack_cb_data
=
cb_data
;
if
(
det_cb
)
{
wm8994
->
micd_cb
=
det_cb
;
wm8994
->
micd_cb_data
=
det_cb_data
;
}
else
{
wm8994
->
mic_detecting
=
true
;
wm8994
->
jack_mic
=
false
;
}
if
(
id_cb
)
{
wm8994
->
mic_id_cb
=
id_cb
;
wm8994
->
mic_id_cb_data
=
id_cb_data
;
}
else
{
wm8994
->
mic_id_cb
=
wm8958_mic_id
;
wm8994
->
mic_id_cb_data
=
codec
;
}
wm8958_micd_set_rate
(
codec
);
/* Detect microphones and short circuits by default */
if
(
wm8994
->
pdata
->
micd_lvl_sel
)
micd_lvl_sel
=
wm8994
->
pdata
->
micd_lvl_sel
;
if
(
control
->
pdata
.
micd_lvl_sel
)
micd_lvl_sel
=
control
->
pdata
.
micd_lvl_sel
;
else
micd_lvl_sel
=
0x41
;
...
...
@@ -3728,10 +3781,22 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
trace_snd_soc_jack_irq
(
dev_name
(
codec
->
dev
));
#endif
if
(
wm8994
->
jack_cb
)
wm8994
->
jack_cb
(
reg
,
wm8994
->
jack_cb_data
);
/* Avoid a transient report when the accessory is being removed */
if
(
wm8994
->
jackdet
)
{
reg
=
snd_soc_read
(
codec
,
WM1811_JACKDET_CTRL
);
if
(
reg
<
0
)
{
dev_err
(
codec
->
dev
,
"Failed to read jack status: %d
\n
"
,
reg
);
}
else
if
(
!
(
reg
&
WM1811_JACKDET_LVL
))
{
dev_dbg
(
codec
->
dev
,
"Ignoring removed jack
\n
"
);
return
IRQ_HANDLED
;
}
}
if
(
wm8994
->
mic_detecting
)
wm8994
->
mic_id_cb
(
wm8994
->
mic_id_cb_data
,
reg
);
else
dev_warn
(
codec
->
dev
,
"Accessory detection with no callback
\n
"
);
wm8958_button_det
(
codec
,
reg
);
out:
pm_runtime_put
(
codec
->
dev
);
...
...
@@ -3779,15 +3844,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_cache_io
(
codec
,
16
,
16
,
SND_SOC_REGMAP
);
mutex_init
(
&
wm8994
->
accdet_lock
);
INIT_DELAYED_WORK
(
&
wm8994
->
mic_work
,
wm8994_mic_work
);
INIT_DELAYED_WORK
(
&
wm8994
->
jackdet_bootstrap
,
wm1811_jackdet_bootstrap
);
switch
(
control
->
type
)
{
case
WM8994
:
INIT_DELAYED_WORK
(
&
wm8994
->
mic_work
,
wm8994_mic_work
);
break
;
case
WM1811
:
INIT_DELAYED_WORK
(
&
wm8994
->
mic_work
,
wm1811_mic_work
);
break
;
default:
break
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8994
->
fll_locked
);
i
++
)
init_completion
(
&
wm8994
->
fll_locked
[
i
]);
if
(
wm8994
->
pdata
&&
wm8994
->
pdata
->
micdet_irq
)
wm8994
->
micdet_irq
=
wm8994
->
pdata
->
micdet_irq
;
wm8994
->
micdet_irq
=
control
->
pdata
.
micdet_irq
;
pm_runtime_enable
(
codec
->
dev
);
pm_runtime_idle
(
codec
->
dev
);
...
...
@@ -3800,8 +3874,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
switch
(
control
->
type
)
{
case
WM8994
:
/* Single ended line outputs should have VMID on. */
if
(
!
wm8994
->
pdata
->
lineout1_diff
||
!
wm8994
->
pdata
->
lineout2_diff
)
if
(
!
control
->
pdata
.
lineout1_diff
||
!
control
->
pdata
.
lineout2_diff
)
codec
->
dapm
.
idle_bias_off
=
0
;
switch
(
wm8994
->
revision
)
{
...
...
@@ -3839,20 +3913,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994
->
hubs
.
no_cache_dac_hp_direct
=
true
;
wm8994
->
fll_byp
=
true
;
switch
(
control
->
cust_id
)
{
case
0
:
case
2
:
wm8994
->
hubs
.
dcs_codes_l
=
-
9
;
wm8994
->
hubs
.
dcs_codes_r
=
-
7
;
break
;
case
1
:
case
3
:
wm8994
->
hubs
.
dcs_codes_l
=
-
8
;
wm8994
->
hubs
.
dcs_codes_r
=
-
7
;
break
;
default:
break
;
}
snd_soc_update_bits
(
codec
,
WM8994_ANALOGUE_HP_1
,
WM1811_HPOUT1_ATTN
,
WM1811_HPOUT1_ATTN
);
...
...
@@ -4236,7 +4298,6 @@ static int __devinit wm8994_probe(struct platform_device *pdev)
platform_set_drvdata
(
pdev
,
wm8994
);
wm8994
->
wm8994
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
wm8994
->
pdata
=
dev_get_platdata
(
pdev
->
dev
.
parent
);
return
snd_soc_register_codec
(
&
pdev
->
dev
,
&
soc_codec_dev_wm8994
,
wm8994_dai
,
ARRAY_SIZE
(
wm8994_dai
));
...
...
@@ -4266,7 +4327,7 @@ static int wm8994_resume(struct device *dev)
{
struct
wm8994_priv
*
wm8994
=
dev_get_drvdata
(
dev
);
if
(
wm8994
->
jackdet
&&
wm8994
->
jack
_cb
)
if
(
wm8994
->
jackdet
&&
wm8994
->
jack
det_mode
)
regmap_update_bits
(
wm8994
->
wm8994
->
regmap
,
WM8994_ANTIPOP_2
,
WM1811_JACKDET_MODE_MASK
,
WM1811_JACKDET_MODE_AUDIO
);
...
...
sound/soc/codecs/wm8994.h
浏览文件 @
06f1c663
...
...
@@ -39,12 +39,14 @@ enum wm8994_vmid_mode {
WM8994_VMID_FORCE
,
};
typedef
void
(
*
wm8958_micdet_cb
)(
u16
status
,
void
*
data
);
typedef
void
(
*
wm1811_micdet_cb
)(
void
*
data
);
typedef
void
(
*
wm1811_mic_id_cb
)(
void
*
data
,
u16
status
);
int
wm8994_mic_detect
(
struct
snd_soc_codec
*
codec
,
struct
snd_soc_jack
*
jack
,
int
micbias
);
int
wm8958_mic_detect
(
struct
snd_soc_codec
*
codec
,
struct
snd_soc_jack
*
jack
,
wm8958_micdet_cb
cb
,
void
*
cb_data
);
wm1811_micdet_cb
cb
,
void
*
det_cb_data
,
wm1811_mic_id_cb
id_cb
,
void
*
id_cb_data
);
int
wm8994_vmid_mode
(
struct
snd_soc_codec
*
codec
,
enum
wm8994_vmid_mode
mode
);
...
...
@@ -138,12 +140,13 @@ struct wm8994_priv {
int
jackdet_mode
;
struct
delayed_work
jackdet_bootstrap
;
wm8958_micdet_cb
jack_cb
;
void
*
jack_cb_data
;
int
micdet_irq
;
wm1811_micdet_cb
micd_cb
;
void
*
micd_cb_data
;
wm1811_mic_id_cb
mic_id_cb
;
void
*
mic_id_cb_data
;
int
revision
;
struct
wm8994_pdata
*
pdata
;
unsigned
int
aif1clk_enable
:
1
;
unsigned
int
aif2clk_enable
:
1
;
...
...
sound/soc/samsung/littlemill.c
浏览文件 @
06f1c663
...
...
@@ -270,7 +270,7 @@ static int littlemill_late_probe(struct snd_soc_card *card)
return
ret
;
/* This will check device compatibility itself */
wm8958_mic_detect
(
codec
,
&
littlemill_headset
,
NULL
,
NULL
);
wm8958_mic_detect
(
codec
,
&
littlemill_headset
,
NULL
,
NULL
,
NULL
,
NULL
);
/* As will this */
wm8994_mic_detect
(
codec
,
&
littlemill_headset
,
1
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录