Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
54643897
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
54643897
编写于
6月 17, 2013
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'asoc/topic/wm8994' into asoc-next
上级
f57019aa
2da1c4bf
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
161 addition
and
43 deletion
+161
-43
include/linux/mfd/wm8994/pdata.h
include/linux/mfd/wm8994/pdata.h
+5
-0
include/linux/mfd/wm8994/registers.h
include/linux/mfd/wm8994/registers.h
+8
-0
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.c
+145
-43
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8994.h
+3
-0
未找到文件。
include/linux/mfd/wm8994/pdata.h
浏览文件 @
54643897
...
...
@@ -182,6 +182,11 @@ struct wm8994_pdata {
*/
int
micdet_delay
;
/* Delay between microphone detect completing and reporting on
* insert (specified in ms)
*/
int
mic_id_delay
;
/* IRQ for microphone detection if brought out directly as a
* signal.
*/
...
...
include/linux/mfd/wm8994/registers.h
浏览文件 @
54643897
...
...
@@ -2668,6 +2668,10 @@
/*
* R772 (0x304) - AIF1ADC LRCLK
*/
#define WM8958_AIF1_LRCLK_INV 0x1000
/* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_MASK 0x1000
/* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_SHIFT 12
/* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_WIDTH 1
/* AIF1_LRCLK_INV */
#define WM8994_AIF1ADC_LRCLK_DIR 0x0800
/* AIF1ADC_LRCLK_DIR */
#define WM8994_AIF1ADC_LRCLK_DIR_MASK 0x0800
/* AIF1ADC_LRCLK_DIR */
#define WM8994_AIF1ADC_LRCLK_DIR_SHIFT 11
/* AIF1ADC_LRCLK_DIR */
...
...
@@ -2679,6 +2683,10 @@
/*
* R773 (0x305) - AIF1DAC LRCLK
*/
#define WM8958_AIF1_LRCLK_INV 0x1000
/* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_MASK 0x1000
/* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_SHIFT 12
/* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_WIDTH 1
/* AIF1_LRCLK_INV */
#define WM8994_AIF1DAC_LRCLK_DIR 0x0800
/* AIF1DAC_LRCLK_DIR */
#define WM8994_AIF1DAC_LRCLK_DIR_MASK 0x0800
/* AIF1DAC_LRCLK_DIR */
#define WM8994_AIF1DAC_LRCLK_DIR_SHIFT 11
/* AIF1DAC_LRCLK_DIR */
...
...
sound/soc/codecs/wm8994.c
浏览文件 @
54643897
...
...
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/gcd.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
...
...
@@ -1498,6 +1499,24 @@ static const char *aif1dac_text[] = {
"AIF1DACDAT"
,
"AIF3DACDAT"
,
};
static
const
char
*
loopback_text
[]
=
{
"None"
,
"ADCDAT"
,
};
static
const
struct
soc_enum
aif1_loopback_enum
=
SOC_ENUM_SINGLE
(
WM8994_AIF1_CONTROL_2
,
WM8994_AIF1_LOOPBACK_SHIFT
,
2
,
loopback_text
);
static
const
struct
snd_kcontrol_new
aif1_loopback
=
SOC_DAPM_ENUM
(
"AIF1 Loopback"
,
aif1_loopback_enum
);
static
const
struct
soc_enum
aif2_loopback_enum
=
SOC_ENUM_SINGLE
(
WM8994_AIF2_CONTROL_2
,
WM8994_AIF2_LOOPBACK_SHIFT
,
2
,
loopback_text
);
static
const
struct
snd_kcontrol_new
aif2_loopback
=
SOC_DAPM_ENUM
(
"AIF2 Loopback"
,
aif2_loopback_enum
);
static
const
struct
soc_enum
aif1dac_enum
=
SOC_ENUM_SINGLE
(
WM8994_POWER_MANAGEMENT_6
,
0
,
2
,
aif1dac_text
);
...
...
@@ -1744,6 +1763,9 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
SND_SOC_DAPM_ADC
(
"ADCL"
,
NULL
,
SND_SOC_NOPM
,
1
,
0
),
SND_SOC_DAPM_ADC
(
"ADCR"
,
NULL
,
SND_SOC_NOPM
,
0
,
0
),
SND_SOC_DAPM_MUX
(
"AIF1 Loopback"
,
SND_SOC_NOPM
,
0
,
0
,
&
aif1_loopback
),
SND_SOC_DAPM_MUX
(
"AIF2 Loopback"
,
SND_SOC_NOPM
,
0
,
0
,
&
aif2_loopback
),
SND_SOC_DAPM_POST
(
"Debug log"
,
post_ev
),
};
...
...
@@ -1875,9 +1897,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{
"AIF1DAC2L"
,
NULL
,
"AIF1DAC Mux"
},
{
"AIF1DAC2R"
,
NULL
,
"AIF1DAC Mux"
},
{
"AIF1DAC Mux"
,
"AIF1DACDAT"
,
"AIF1
DACDAT
"
},
{
"AIF1DAC Mux"
,
"AIF1DACDAT"
,
"AIF1
Loopback
"
},
{
"AIF1DAC Mux"
,
"AIF3DACDAT"
,
"AIF3DACDAT"
},
{
"AIF2DAC Mux"
,
"AIF2DACDAT"
,
"AIF2
DACDAT
"
},
{
"AIF2DAC Mux"
,
"AIF2DACDAT"
,
"AIF2
Loopback
"
},
{
"AIF2DAC Mux"
,
"AIF3DACDAT"
,
"AIF3DACDAT"
},
{
"AIF2ADC Mux"
,
"AIF2ADCDAT"
,
"AIF2ADCL"
},
{
"AIF2ADC Mux"
,
"AIF2ADCDAT"
,
"AIF2ADCR"
},
...
...
@@ -1928,6 +1950,12 @@ static const struct snd_soc_dapm_route intercon[] = {
{
"AIF3ADCDAT"
,
"AIF2DACDAT"
,
"AIF2DACL"
},
{
"AIF3ADCDAT"
,
"AIF2DACDAT"
,
"AIF2DACR"
},
/* Loopback */
{
"AIF1 Loopback"
,
"ADCDAT"
,
"AIF1ADCDAT"
},
{
"AIF1 Loopback"
,
"None"
,
"AIF1DACDAT"
},
{
"AIF2 Loopback"
,
"ADCDAT"
,
"AIF2ADCDAT"
},
{
"AIF2 Loopback"
,
"None"
,
"AIF2DACDAT"
},
/* Sidetone */
{
"Left Sidetone"
,
"ADC/DMIC1"
,
"ADCL Mux"
},
{
"Left Sidetone"
,
"DMIC2"
,
"DMIC2L"
},
...
...
@@ -2010,15 +2038,16 @@ struct fll_div {
u16
outdiv
;
u16
n
;
u16
k
;
u16
lambda
;
u16
clk_ref_div
;
u16
fll_fratio
;
};
static
int
wm8994_get_fll_config
(
struct
fll_div
*
fll
,
static
int
wm8994_get_fll_config
(
struct
wm8994
*
control
,
struct
fll_div
*
fll
,
int
freq_in
,
int
freq_out
)
{
u64
Kpart
;
unsigned
int
K
,
Ndiv
,
Nmod
;
unsigned
int
K
,
Ndiv
,
Nmod
,
gcd_fll
;
pr_debug
(
"FLL input=%dHz, output=%dHz
\n
"
,
freq_in
,
freq_out
);
...
...
@@ -2067,20 +2096,32 @@ static int wm8994_get_fll_config(struct fll_div *fll,
Nmod
=
freq_out
%
freq_in
;
pr_debug
(
"Nmod=%d
\n
"
,
Nmod
);
/* Calculate fractional part - scale up so we can round. */
Kpart
=
FIXED_FLL_SIZE
*
(
long
long
)
Nmod
;
switch
(
control
->
type
)
{
case
WM8994
:
/* Calculate fractional part - scale up so we can round. */
Kpart
=
FIXED_FLL_SIZE
*
(
long
long
)
Nmod
;
do_div
(
Kpart
,
freq_in
);
K
=
Kpart
&
0xFFFFFFFF
;
do_div
(
Kpart
,
freq_in
);
if
((
K
%
10
)
>=
5
)
K
+=
5
;
K
=
Kpart
&
0xFFFFFFFF
;
/* Move down to proper range now rounding is done */
fll
->
k
=
K
/
10
;
fll
->
lambda
=
0
;
if
((
K
%
10
)
>=
5
)
K
+=
5
;
pr_debug
(
"N=%x K=%x
\n
"
,
fll
->
n
,
fll
->
k
);
break
;
/* Move down to proper range now rounding is done */
fll
->
k
=
K
/
10
;
default:
gcd_fll
=
gcd
(
freq_out
,
freq_in
)
;
pr_debug
(
"N=%x K=%x
\n
"
,
fll
->
n
,
fll
->
k
);
fll
->
k
=
(
freq_out
-
(
freq_in
*
fll
->
n
))
/
gcd_fll
;
fll
->
lambda
=
freq_in
/
gcd_fll
;
}
return
0
;
}
...
...
@@ -2144,9 +2185,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
* analysis bugs spewing warnings.
*/
if
(
freq_out
)
ret
=
wm8994_get_fll_config
(
&
fll
,
freq_in
,
freq_out
);
ret
=
wm8994_get_fll_config
(
control
,
&
fll
,
freq_in
,
freq_out
);
else
ret
=
wm8994_get_fll_config
(
&
fll
,
wm8994
->
fll
[
id
].
in
,
ret
=
wm8994_get_fll_config
(
control
,
&
fll
,
wm8994
->
fll
[
id
].
in
,
wm8994
->
fll
[
id
].
out
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -2191,6 +2232,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
WM8994_FLL1_N_MASK
,
fll
.
n
<<
WM8994_FLL1_N_SHIFT
);
if
(
fll
.
lambda
)
{
snd_soc_update_bits
(
codec
,
WM8958_FLL1_EFS_1
+
reg_offset
,
WM8958_FLL1_LAMBDA_MASK
,
fll
.
lambda
);
snd_soc_update_bits
(
codec
,
WM8958_FLL1_EFS_2
+
reg_offset
,
WM8958_FLL1_EFS_ENA
,
WM8958_FLL1_EFS_ENA
);
}
else
{
snd_soc_update_bits
(
codec
,
WM8958_FLL1_EFS_2
+
reg_offset
,
WM8958_FLL1_EFS_ENA
,
0
);
}
snd_soc_update_bits
(
codec
,
WM8994_FLL1_CONTROL_5
+
reg_offset
,
WM8994_FLL1_FRC_NCO
|
WM8958_FLL1_BYP
|
WM8994_FLL1_REFCLK_DIV_MASK
|
...
...
@@ -2555,17 +2607,24 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
ms_reg
;
int
aif1_reg
;
int
dac_reg
;
int
adc_reg
;
int
ms
=
0
;
int
aif1
=
0
;
int
lrclk
=
0
;
switch
(
dai
->
id
)
{
case
1
:
ms_reg
=
WM8994_AIF1_MASTER_SLAVE
;
aif1_reg
=
WM8994_AIF1_CONTROL_1
;
dac_reg
=
WM8994_AIF1DAC_LRCLK
;
adc_reg
=
WM8994_AIF1ADC_LRCLK
;
break
;
case
2
:
ms_reg
=
WM8994_AIF2_MASTER_SLAVE
;
aif1_reg
=
WM8994_AIF2_CONTROL_1
;
dac_reg
=
WM8994_AIF1DAC_LRCLK
;
adc_reg
=
WM8994_AIF1ADC_LRCLK
;
break
;
default:
return
-
EINVAL
;
...
...
@@ -2584,6 +2643,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch
(
fmt
&
SND_SOC_DAIFMT_FORMAT_MASK
)
{
case
SND_SOC_DAIFMT_DSP_B
:
aif1
|=
WM8994_AIF1_LRCLK_INV
;
lrclk
|=
WM8958_AIF1_LRCLK_INV
;
case
SND_SOC_DAIFMT_DSP_A
:
aif1
|=
0x18
;
break
;
...
...
@@ -2622,12 +2682,14 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break
;
case
SND_SOC_DAIFMT_IB_IF
:
aif1
|=
WM8994_AIF1_BCLK_INV
|
WM8994_AIF1_LRCLK_INV
;
lrclk
|=
WM8958_AIF1_LRCLK_INV
;
break
;
case
SND_SOC_DAIFMT_IB_NF
:
aif1
|=
WM8994_AIF1_BCLK_INV
;
break
;
case
SND_SOC_DAIFMT_NB_IF
:
aif1
|=
WM8994_AIF1_LRCLK_INV
;
lrclk
|=
WM8958_AIF1_LRCLK_INV
;
break
;
default:
return
-
EINVAL
;
...
...
@@ -2658,6 +2720,10 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
aif1
);
snd_soc_update_bits
(
codec
,
ms_reg
,
WM8994_AIF1_MSTR
,
ms
);
snd_soc_update_bits
(
codec
,
dac_reg
,
WM8958_AIF1_LRCLK_INV
,
lrclk
);
snd_soc_update_bits
(
codec
,
adc_reg
,
WM8958_AIF1_LRCLK_INV
,
lrclk
);
return
0
;
}
...
...
@@ -3096,24 +3162,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec)
static
int
wm8994_codec_resume
(
struct
snd_soc_codec
*
codec
)
{
struct
wm8994_priv
*
wm8994
=
snd_soc_codec_get_drvdata
(
codec
);
struct
wm8994
*
control
=
wm8994
->
wm8994
;
int
i
,
ret
;
unsigned
int
val
,
mask
;
if
(
control
->
revision
<
4
)
{
/* force a HW read */
ret
=
regmap_read
(
control
->
regmap
,
WM8994_POWER_MANAGEMENT_5
,
&
val
);
/* modify the cache only */
codec
->
cache_only
=
1
;
mask
=
WM8994_DAC1R_ENA
|
WM8994_DAC1L_ENA
|
WM8994_DAC2R_ENA
|
WM8994_DAC2L_ENA
;
val
&=
mask
;
snd_soc_update_bits
(
codec
,
WM8994_POWER_MANAGEMENT_5
,
mask
,
val
);
codec
->
cache_only
=
0
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8994
->
fll
);
i
++
)
{
if
(
!
wm8994
->
fll_suspend
[
i
].
out
)
...
...
@@ -3495,6 +3544,31 @@ static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
wm8994
->
btn_mask
);
}
static
void
wm8958_open_circuit_work
(
struct
work_struct
*
work
)
{
struct
wm8994_priv
*
wm8994
=
container_of
(
work
,
struct
wm8994_priv
,
open_circuit_work
.
work
);
struct
device
*
dev
=
wm8994
->
wm8994
->
dev
;
wm1811_micd_stop
(
wm8994
->
hubs
.
codec
);
mutex_lock
(
&
wm8994
->
accdet_lock
);
dev_dbg
(
dev
,
"Reporting open circuit
\n
"
);
wm8994
->
jack_mic
=
false
;
wm8994
->
mic_detecting
=
true
;
wm8958_micd_set_rate
(
wm8994
->
hubs
.
codec
);
snd_soc_jack_report
(
wm8994
->
micdet
[
0
].
jack
,
0
,
wm8994
->
btn_mask
|
SND_JACK_HEADSET
);
mutex_unlock
(
&
wm8994
->
accdet_lock
);
}
static
void
wm8958_mic_id
(
void
*
data
,
u16
status
)
{
struct
snd_soc_codec
*
codec
=
data
;
...
...
@@ -3504,16 +3578,9 @@ static void wm8958_mic_id(void *data, u16 status)
if
(
!
(
status
&
WM8958_MICD_STS
))
{
/* 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
);
schedule_delayed_work
(
&
wm8994
->
open_circuit_work
,
msecs_to_jiffies
(
2500
));
return
;
}
...
...
@@ -3598,6 +3665,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
pm_runtime_get_sync
(
codec
->
dev
);
cancel_delayed_work_sync
(
&
wm8994
->
mic_complete_work
);
mutex_lock
(
&
wm8994
->
accdet_lock
);
reg
=
snd_soc_read
(
codec
,
WM1811_JACKDET_CTRL
);
...
...
@@ -3780,11 +3849,33 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
}
EXPORT_SYMBOL_GPL
(
wm8958_mic_detect
);
static
void
wm8958_mic_work
(
struct
work_struct
*
work
)
{
struct
wm8994_priv
*
wm8994
=
container_of
(
work
,
struct
wm8994_priv
,
mic_complete_work
.
work
);
struct
snd_soc_codec
*
codec
=
wm8994
->
hubs
.
codec
;
dev_crit
(
codec
->
dev
,
"MIC WORK %x
\n
"
,
wm8994
->
mic_status
);
pm_runtime_get_sync
(
codec
->
dev
);
mutex_lock
(
&
wm8994
->
accdet_lock
);
wm8994
->
mic_id_cb
(
wm8994
->
mic_id_cb_data
,
wm8994
->
mic_status
);
mutex_unlock
(
&
wm8994
->
accdet_lock
);
pm_runtime_put
(
codec
->
dev
);
dev_crit
(
codec
->
dev
,
"MIC WORK %x DONE
\n
"
,
wm8994
->
mic_status
);
}
static
irqreturn_t
wm8958_mic_irq
(
int
irq
,
void
*
data
)
{
struct
wm8994_priv
*
wm8994
=
data
;
struct
snd_soc_codec
*
codec
=
wm8994
->
hubs
.
codec
;
int
reg
,
count
,
ret
;
int
reg
,
count
,
ret
,
id_delay
;
/*
* Jack detection may have detected a removal simulataneously
...
...
@@ -3794,6 +3885,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
if
(
!
(
snd_soc_read
(
codec
,
WM8958_MIC_DETECT_1
)
&
WM8958_MICD_ENA
))
return
IRQ_HANDLED
;
cancel_delayed_work_sync
(
&
wm8994
->
mic_complete_work
);
cancel_delayed_work_sync
(
&
wm8994
->
open_circuit_work
);
pm_runtime_get_sync
(
codec
->
dev
);
/* We may occasionally read a detection without an impedence
...
...
@@ -3846,8 +3940,12 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
goto
out
;
}
wm8994
->
mic_status
=
reg
;
id_delay
=
wm8994
->
wm8994
->
pdata
.
mic_id_delay
;
if
(
wm8994
->
mic_detecting
)
wm8994
->
mic_id_cb
(
wm8994
->
mic_id_cb_data
,
reg
);
schedule_delayed_work
(
&
wm8994
->
mic_complete_work
,
msecs_to_jiffies
(
id_delay
));
else
wm8958_button_det
(
codec
,
reg
);
...
...
@@ -3899,6 +3997,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
mutex_init
(
&
wm8994
->
accdet_lock
);
INIT_DELAYED_WORK
(
&
wm8994
->
jackdet_bootstrap
,
wm1811_jackdet_bootstrap
);
INIT_DELAYED_WORK
(
&
wm8994
->
open_circuit_work
,
wm8958_open_circuit_work
);
switch
(
control
->
type
)
{
case
WM8994
:
...
...
@@ -3911,6 +4011,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
break
;
}
INIT_DELAYED_WORK
(
&
wm8994
->
mic_complete_work
,
wm8958_mic_work
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8994
->
fll_locked
);
i
++
)
init_completion
(
&
wm8994
->
fll_locked
[
i
]);
...
...
sound/soc/codecs/wm8994.h
浏览文件 @
54643897
...
...
@@ -134,6 +134,9 @@ struct wm8994_priv {
struct
mutex
accdet_lock
;
struct
wm8994_micdet
micdet
[
2
];
struct
delayed_work
mic_work
;
struct
delayed_work
open_circuit_work
;
struct
delayed_work
mic_complete_work
;
u16
mic_status
;
bool
mic_detecting
;
bool
jack_mic
;
int
btn_mask
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录