Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
6a93dd24
Commit
6a93dd24
authored
Mar 05, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/pcm512x' into asoc-next
parents
0af1327b
f29933c9
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
159 additions
and
19 deletions
+159
-19
sound/soc/codecs/pcm512x.c
sound/soc/codecs/pcm512x.c
+159
-19
No files found.
sound/soc/codecs/pcm512x.c
View file @
6a93dd24
...
...
@@ -54,6 +54,9 @@ struct pcm512x_priv {
int
pll_d
;
int
pll_p
;
unsigned
long
real_pll
;
unsigned
long
overclock_pll
;
unsigned
long
overclock_dac
;
unsigned
long
overclock_dsp
;
};
/*
...
...
@@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
}
}
static
int
pcm512x_overclock_pll_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_codec
*
codec
=
snd_soc_kcontrol_codec
(
kcontrol
);
struct
pcm512x_priv
*
pcm512x
=
snd_soc_codec_get_drvdata
(
codec
);
ucontrol
->
value
.
integer
.
value
[
0
]
=
pcm512x
->
overclock_pll
;
return
0
;
}
static
int
pcm512x_overclock_pll_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_codec
*
codec
=
snd_soc_kcontrol_codec
(
kcontrol
);
struct
pcm512x_priv
*
pcm512x
=
snd_soc_codec_get_drvdata
(
codec
);
switch
(
codec
->
dapm
.
bias_level
)
{
case
SND_SOC_BIAS_OFF
:
case
SND_SOC_BIAS_STANDBY
:
break
;
default:
return
-
EBUSY
;
}
pcm512x
->
overclock_pll
=
ucontrol
->
value
.
integer
.
value
[
0
];
return
0
;
}
static
int
pcm512x_overclock_dsp_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_codec
*
codec
=
snd_soc_kcontrol_codec
(
kcontrol
);
struct
pcm512x_priv
*
pcm512x
=
snd_soc_codec_get_drvdata
(
codec
);
ucontrol
->
value
.
integer
.
value
[
0
]
=
pcm512x
->
overclock_dsp
;
return
0
;
}
static
int
pcm512x_overclock_dsp_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_codec
*
codec
=
snd_soc_kcontrol_codec
(
kcontrol
);
struct
pcm512x_priv
*
pcm512x
=
snd_soc_codec_get_drvdata
(
codec
);
switch
(
codec
->
dapm
.
bias_level
)
{
case
SND_SOC_BIAS_OFF
:
case
SND_SOC_BIAS_STANDBY
:
break
;
default:
return
-
EBUSY
;
}
pcm512x
->
overclock_dsp
=
ucontrol
->
value
.
integer
.
value
[
0
];
return
0
;
}
static
int
pcm512x_overclock_dac_get
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_codec
*
codec
=
snd_soc_kcontrol_codec
(
kcontrol
);
struct
pcm512x_priv
*
pcm512x
=
snd_soc_codec_get_drvdata
(
codec
);
ucontrol
->
value
.
integer
.
value
[
0
]
=
pcm512x
->
overclock_dac
;
return
0
;
}
static
int
pcm512x_overclock_dac_put
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_soc_codec
*
codec
=
snd_soc_kcontrol_codec
(
kcontrol
);
struct
pcm512x_priv
*
pcm512x
=
snd_soc_codec_get_drvdata
(
codec
);
switch
(
codec
->
dapm
.
bias_level
)
{
case
SND_SOC_BIAS_OFF
:
case
SND_SOC_BIAS_STANDBY
:
break
;
default:
return
-
EBUSY
;
}
pcm512x
->
overclock_dac
=
ucontrol
->
value
.
integer
.
value
[
0
];
return
0
;
}
static
const
DECLARE_TLV_DB_SCALE
(
digital_tlv
,
-
10350
,
50
,
1
);
static
const
DECLARE_TLV_DB_SCALE
(
analog_tlv
,
-
600
,
600
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
boost_tlv
,
0
,
80
,
0
);
...
...
@@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
SOC_ENUM
(
"Volume Ramp Up Step"
,
pcm512x_vnus
),
SOC_ENUM
(
"Volume Ramp Down Emergency Rate"
,
pcm512x_vedf
),
SOC_ENUM
(
"Volume Ramp Down Emergency Step"
,
pcm512x_veds
),
SOC_SINGLE_EXT
(
"Max Overclock PLL"
,
SND_SOC_NOPM
,
0
,
20
,
0
,
pcm512x_overclock_pll_get
,
pcm512x_overclock_pll_put
),
SOC_SINGLE_EXT
(
"Max Overclock DSP"
,
SND_SOC_NOPM
,
0
,
40
,
0
,
pcm512x_overclock_dsp_get
,
pcm512x_overclock_dsp_put
),
SOC_SINGLE_EXT
(
"Max Overclock DAC"
,
SND_SOC_NOPM
,
0
,
40
,
0
,
pcm512x_overclock_dac_get
,
pcm512x_overclock_dac_put
),
};
static
const
struct
snd_soc_dapm_widget
pcm512x_dapm_widgets
[]
=
{
...
...
@@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
{
"OUTR"
,
NULL
,
"DACR"
},
};
static
unsigned
long
pcm512x_pll_max
(
struct
pcm512x_priv
*
pcm512x
)
{
return
25000000
+
25000000
*
pcm512x
->
overclock_pll
/
100
;
}
static
unsigned
long
pcm512x_dsp_max
(
struct
pcm512x_priv
*
pcm512x
)
{
return
50000000
+
50000000
*
pcm512x
->
overclock_dsp
/
100
;
}
static
unsigned
long
pcm512x_dac_max
(
struct
pcm512x_priv
*
pcm512x
,
unsigned
long
rate
)
{
return
rate
+
rate
*
pcm512x
->
overclock_dac
/
100
;
}
static
unsigned
long
pcm512x_sck_max
(
struct
pcm512x_priv
*
pcm512x
)
{
if
(
!
pcm512x
->
pll_out
)
return
25000000
;
return
pcm512x_pll_max
(
pcm512x
);
}
static
unsigned
long
pcm512x_ncp_target
(
struct
pcm512x_priv
*
pcm512x
,
unsigned
long
dac_rate
)
{
/*
* If the DAC is not actually overclocked, use the good old
* NCP target rate...
*/
if
(
dac_rate
<=
6144000
)
return
1536000
;
/*
* ...but if the DAC is in fact overclocked, bump the NCP target
* rate to get the recommended dividers even when overclocking.
*/
return
pcm512x_dac_max
(
pcm512x
,
1536000
);
}
static
const
u32
pcm512x_dai_rates
[]
=
{
8000
,
11025
,
16000
,
22050
,
32000
,
44100
,
48000
,
64000
,
88200
,
96000
,
176400
,
192000
,
384000
,
...
...
@@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = {
static
int
pcm512x_hw_rule_rate
(
struct
snd_pcm_hw_params
*
params
,
struct
snd_pcm_hw_rule
*
rule
)
{
struct
pcm512x_priv
*
pcm512x
=
rule
->
private
;
struct
snd_interval
ranges
[
2
];
int
frame_size
;
...
...
@@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
*/
memset
(
ranges
,
0
,
sizeof
(
ranges
));
ranges
[
0
].
min
=
8000
;
ranges
[
0
].
max
=
25000000
/
frame_size
/
2
;
ranges
[
0
].
max
=
pcm512x_sck_max
(
pcm512x
)
/
frame_size
/
2
;
ranges
[
1
].
min
=
DIV_ROUND_UP
(
16000000
,
frame_size
);
ranges
[
1
].
max
=
384000
;
break
;
...
...
@@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
return
snd_pcm_hw_rule_add
(
substream
->
runtime
,
0
,
SNDRV_PCM_HW_PARAM_RATE
,
pcm512x_hw_rule_rate
,
NULL
,
pcm512x
,
SNDRV_PCM_HW_PARAM_FRAME_BITS
,
SNDRV_PCM_HW_PARAM_CHANNELS
,
-
1
);
...
...
@@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
unsigned
long
bclk_rate
)
{
struct
device
*
dev
=
dai
->
dev
;
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
pcm512x_priv
*
pcm512x
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
long
sck_rate
;
int
pow2
;
...
...
@@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
* as many factors of 2 as possible, as that makes it easier
* to find a fast DAC rate
*/
pow2
=
1
<<
fls
((
25000000
-
16000000
)
/
bclk_rate
);
pow2
=
1
<<
fls
((
pcm512x_pll_max
(
pcm512x
)
-
16000000
)
/
bclk_rate
);
for
(;
pow2
;
pow2
>>=
1
)
{
sck_rate
=
rounddown
(
25000000
,
bclk_rate
*
pow2
);
sck_rate
=
rounddown
(
pcm512x_pll_max
(
pcm512x
),
bclk_rate
*
pow2
);
if
(
sck_rate
>=
16000000
)
break
;
}
...
...
@@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
return
0
;
/* futile, quit early */
/* run DAC no faster than 6144000 Hz */
for
(
dac_rate
=
rounddown
(
6144000
,
osr_rate
);
for
(
dac_rate
=
rounddown
(
pcm512x_dac_max
(
pcm512x
,
6144000
)
,
osr_rate
);
dac_rate
;
dac_rate
-=
osr_rate
)
{
...
...
@@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
osr_rate
=
16
*
sample_rate
;
/* run DSP no faster than 50 MHz */
dsp_div
=
mck_rate
>
50000000
?
2
:
1
;
dsp_div
=
mck_rate
>
pcm512x_dsp_max
(
pcm512x
)
?
2
:
1
;
dac_rate
=
pcm512x_pllin_dac_rate
(
dai
,
osr_rate
,
pllin_rate
);
if
(
dac_rate
)
{
...
...
@@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
dacsrc_rate
=
pllin_rate
;
}
else
{
/* run DAC no faster than 6144000 Hz */
unsigned
long
dac_mul
=
6144000
/
osr_rate
;
unsigned
long
dac_mul
=
pcm512x_dac_max
(
pcm512x
,
6144000
)
/
osr_rate
;
unsigned
long
sck_mul
=
sck_rate
/
osr_rate
;
for
(;
dac_mul
;
dac_mul
--
)
{
...
...
@@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
dacsrc_rate
=
sck_rate
;
}
osr_div
=
DIV_ROUND_CLOSEST
(
dac_rate
,
osr_rate
);
if
(
osr_div
>
128
)
{
dev_err
(
dev
,
"Failed to find OSR divider
\n
"
);
return
-
EINVAL
;
}
dac_div
=
DIV_ROUND_CLOSEST
(
dacsrc_rate
,
dac_rate
);
if
(
dac_div
>
128
)
{
dev_err
(
dev
,
"Failed to find DAC divider
\n
"
);
return
-
EINVAL
;
}
dac_rate
=
dacsrc_rate
/
dac_div
;
ncp_div
=
DIV_ROUND_CLOSEST
(
dacsrc_rate
/
dac_div
,
1536000
);
if
(
ncp_div
>
128
||
dacsrc_rate
/
dac_div
/
ncp_div
>
2048000
)
{
ncp_div
=
DIV_ROUND_CLOSEST
(
dac_rate
,
pcm512x_ncp_target
(
pcm512x
,
dac_rate
));
if
(
ncp_div
>
128
||
dac_rate
/
ncp_div
>
2048000
)
{
/* run NCP no faster than 2048000 Hz, but why? */
ncp_div
=
DIV_ROUND_UP
(
dac
src_rate
/
dac_div
,
2048000
);
ncp_div
=
DIV_ROUND_UP
(
dac
_rate
,
2048000
);
if
(
ncp_div
>
128
)
{
dev_err
(
dev
,
"Failed to find NCP divider
\n
"
);
return
-
EINVAL
;
}
}
osr_div
=
DIV_ROUND_CLOSEST
(
dac_rate
,
osr_rate
);
if
(
osr_div
>
128
)
{
dev_err
(
dev
,
"Failed to find OSR divider
\n
"
);
return
-
EINVAL
;
}
idac
=
mck_rate
/
(
dsp_div
*
sample_rate
);
ret
=
regmap_write
(
pcm512x
->
regmap
,
PCM512x_DSP_CLKDIV
,
dsp_div
-
1
);
...
...
@@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
return
ret
;
}
if
(
sample_rate
<=
48000
)
if
(
sample_rate
<=
pcm512x_dac_max
(
pcm512x
,
48000
)
)
fssp
=
PCM512x_FSSP_48KHZ
;
else
if
(
sample_rate
<=
96000
)
else
if
(
sample_rate
<=
pcm512x_dac_max
(
pcm512x
,
96000
)
)
fssp
=
PCM512x_FSSP_96KHZ
;
else
if
(
sample_rate
<=
192000
)
else
if
(
sample_rate
<=
pcm512x_dac_max
(
pcm512x
,
192000
)
)
fssp
=
PCM512x_FSSP_192KHZ
;
else
fssp
=
PCM512x_FSSP_384KHZ
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment