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
e39f6bc7
Commit
e39f6bc7
authored
Jun 22, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/tas2552' into asoc-next
parents
6afff9e0
8604bc28
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
158 additions
and
91 deletions
+158
-91
Documentation/devicetree/bindings/sound/tas2552.txt
Documentation/devicetree/bindings/sound/tas2552.txt
+6
-0
sound/soc/codecs/tas2552.c
sound/soc/codecs/tas2552.c
+118
-64
sound/soc/codecs/tas2552.h
sound/soc/codecs/tas2552.h
+34
-27
No files found.
Documentation/devicetree/bindings/sound/tas2552.txt
View file @
e39f6bc7
...
...
@@ -14,6 +14,12 @@ Required properties:
Optional properties:
- enable-gpio - gpio pin to enable/disable the device
tas2552 can receive it's reference clock via MCLK, BCLK, IVCLKIN pin or use the
internal 1.8MHz. This CLKIN is used by the PLL. In addition to PLL, the PDM
reference clock is also selectable: PLL, IVCLKIN, BCLK or MCLK.
For system integration the dt-bindings/sound/tas2552.h header file provides
defined values to selct and configure the PLL and PDM reference clocks.
Example:
tas2552: tas2552@41 {
...
...
sound/soc/codecs/tas2552.c
View file @
e39f6bc7
...
...
@@ -45,7 +45,7 @@ static struct reg_default tas2552_reg_defs[] = {
{
TAS2552_OUTPUT_DATA
,
0xc0
},
{
TAS2552_PDM_CFG
,
0x01
},
{
TAS2552_PGA_GAIN
,
0x00
},
{
TAS2552_BOOST_PT_CTRL
,
0x0f
},
{
TAS2552_BOOST_
A
PT_CTRL
,
0x0f
},
{
TAS2552_RESERVED_0D
,
0xbe
},
{
TAS2552_LIMIT_RATE_HYS
,
0x08
},
{
TAS2552_CFG_2
,
0xef
},
...
...
@@ -77,7 +77,9 @@ struct tas2552_data {
struct
gpio_desc
*
enable_gpio
;
unsigned
char
regs
[
TAS2552_VBAT_DATA
];
unsigned
int
pll_clkin
;
int
pll_clk_id
;
unsigned
int
pdm_clk
;
int
pdm_clk_id
;
unsigned
int
dai_fmt
;
unsigned
int
tdm_delay
;
...
...
@@ -143,31 +145,105 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = {
};
#ifdef CONFIG_PM
static
void
tas2552_sw_shutdown
(
struct
tas2552_data
*
tas
_data
,
int
sw_shutdown
)
static
void
tas2552_sw_shutdown
(
struct
tas2552_data
*
tas
2552
,
int
sw_shutdown
)
{
u8
cfg1_reg
=
0
;
if
(
!
tas
_data
->
codec
)
if
(
!
tas
2552
->
codec
)
return
;
if
(
sw_shutdown
)
cfg1_reg
=
TAS2552_SWS
;
snd_soc_update_bits
(
tas
_data
->
codec
,
TAS2552_CFG_1
,
TAS2552_SWS
,
snd_soc_update_bits
(
tas
2552
->
codec
,
TAS2552_CFG_1
,
TAS2552_SWS
,
cfg1_reg
);
}
#endif
static
int
tas2552_setup_pll
(
struct
snd_soc_codec
*
codec
,
struct
snd_pcm_hw_params
*
params
)
{
struct
tas2552_data
*
tas2552
=
dev_get_drvdata
(
codec
->
dev
);
bool
bypass_pll
=
false
;
unsigned
int
pll_clk
=
params_rate
(
params
)
*
512
;
unsigned
int
pll_clkin
=
tas2552
->
pll_clkin
;
u8
pll_enable
;
if
(
!
pll_clkin
)
{
if
(
tas2552
->
pll_clk_id
!=
TAS2552_PLL_CLKIN_BCLK
)
return
-
EINVAL
;
pll_clkin
=
snd_soc_params_to_bclk
(
params
);
pll_clkin
+=
tas2552
->
tdm_delay
;
}
pll_enable
=
snd_soc_read
(
codec
,
TAS2552_CFG_2
)
&
TAS2552_PLL_ENABLE
;
snd_soc_update_bits
(
codec
,
TAS2552_CFG_2
,
TAS2552_PLL_ENABLE
,
0
);
if
(
pll_clkin
==
pll_clk
)
bypass_pll
=
true
;
if
(
bypass_pll
)
{
/* By pass the PLL configuration */
snd_soc_update_bits
(
codec
,
TAS2552_PLL_CTRL_2
,
TAS2552_PLL_BYPASS
,
TAS2552_PLL_BYPASS
);
}
else
{
/* Fill in the PLL control registers for J & D
* pll_clk = (.5 * pll_clkin * J.D) / 2^p
* Need to fill in J and D here based on incoming freq
*/
unsigned
int
d
;
u8
j
;
u8
pll_sel
=
(
tas2552
->
pll_clk_id
<<
3
)
&
TAS2552_PLL_SRC_MASK
;
u8
p
=
snd_soc_read
(
codec
,
TAS2552_PLL_CTRL_1
);
p
=
(
p
>>
7
);
recalc:
j
=
(
pll_clk
*
2
*
(
1
<<
p
))
/
pll_clkin
;
d
=
(
pll_clk
*
2
*
(
1
<<
p
))
%
pll_clkin
;
d
/=
(
pll_clkin
/
10000
);
if
(
d
&&
(
pll_clkin
<
512000
||
pll_clkin
>
9200000
))
{
if
(
tas2552
->
pll_clk_id
==
TAS2552_PLL_CLKIN_BCLK
)
{
pll_clkin
=
1800000
;
pll_sel
=
(
TAS2552_PLL_CLKIN_1_8_FIXED
<<
3
)
&
TAS2552_PLL_SRC_MASK
;
}
else
{
pll_clkin
=
snd_soc_params_to_bclk
(
params
);
pll_clkin
+=
tas2552
->
tdm_delay
;
pll_sel
=
(
TAS2552_PLL_CLKIN_BCLK
<<
3
)
&
TAS2552_PLL_SRC_MASK
;
}
goto
recalc
;
}
snd_soc_update_bits
(
codec
,
TAS2552_CFG_1
,
TAS2552_PLL_SRC_MASK
,
pll_sel
);
snd_soc_update_bits
(
codec
,
TAS2552_PLL_CTRL_1
,
TAS2552_PLL_J_MASK
,
j
);
/* Will clear the PLL_BYPASS bit */
snd_soc_write
(
codec
,
TAS2552_PLL_CTRL_2
,
TAS2552_PLL_D_UPPER
(
d
));
snd_soc_write
(
codec
,
TAS2552_PLL_CTRL_3
,
TAS2552_PLL_D_LOWER
(
d
));
}
/* Restore PLL status */
snd_soc_update_bits
(
codec
,
TAS2552_CFG_2
,
TAS2552_PLL_ENABLE
,
pll_enable
);
return
0
;
}
static
int
tas2552_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
,
struct
snd_soc_dai
*
dai
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
tas2552_data
*
tas2552
=
dev_get_drvdata
(
codec
->
dev
);
int
sample_rate
,
pll_clk
;
int
d
;
int
cpf
;
u8
p
,
j
;
u8
ser_ctrl1_reg
,
wclk_rate
;
switch
(
params_width
(
params
))
{
...
...
@@ -245,49 +321,7 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits
(
codec
,
TAS2552_CFG_3
,
TAS2552_WCLK_FREQ_MASK
,
wclk_rate
);
if
(
!
tas2552
->
pll_clkin
)
return
-
EINVAL
;
snd_soc_update_bits
(
codec
,
TAS2552_CFG_2
,
TAS2552_PLL_ENABLE
,
0
);
if
(
tas2552
->
pll_clkin
==
TAS2552_245MHZ_CLK
||
tas2552
->
pll_clkin
==
TAS2552_225MHZ_CLK
)
{
/* By pass the PLL configuration */
snd_soc_update_bits
(
codec
,
TAS2552_PLL_CTRL_2
,
TAS2552_PLL_BYPASS_MASK
,
TAS2552_PLL_BYPASS
);
}
else
{
/* Fill in the PLL control registers for J & D
* PLL_CLK = (.5 * freq * J.D) / 2^p
* Need to fill in J and D here based on incoming freq
*/
p
=
snd_soc_read
(
codec
,
TAS2552_PLL_CTRL_1
);
p
=
(
p
>>
7
);
sample_rate
=
params_rate
(
params
);
if
(
sample_rate
==
48000
)
pll_clk
=
TAS2552_245MHZ_CLK
;
else
if
(
sample_rate
==
44100
)
pll_clk
=
TAS2552_225MHZ_CLK
;
else
{
dev_vdbg
(
codec
->
dev
,
"Substream sample rate is not found %i
\n
"
,
params_rate
(
params
));
return
-
EINVAL
;
}
j
=
(
pll_clk
*
2
*
(
1
<<
p
))
/
tas2552
->
pll_clkin
;
d
=
(
pll_clk
*
2
*
(
1
<<
p
))
%
tas2552
->
pll_clkin
;
snd_soc_update_bits
(
codec
,
TAS2552_PLL_CTRL_1
,
TAS2552_PLL_J_MASK
,
j
);
snd_soc_write
(
codec
,
TAS2552_PLL_CTRL_2
,
(
d
>>
7
)
&
TAS2552_PLL_D_UPPER_MASK
);
snd_soc_write
(
codec
,
TAS2552_PLL_CTRL_3
,
d
&
TAS2552_PLL_D_LOWER_MASK
);
}
return
0
;
return
tas2552_setup_pll
(
codec
,
params
);
}
#define TAS2552_DAI_FMT_MASK (TAS2552_BCLKDIR | \
...
...
@@ -370,12 +404,21 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
switch
(
clk_id
)
{
case
TAS2552_PLL_CLKIN_MCLK
:
case
TAS2552_PLL_CLKIN_BCLK
:
case
TAS2552_PLL_CLKIN_IVCLKIN
:
if
(
freq
<
512000
||
freq
>
24576000
)
{
/* out of range PLL_CLKIN, fall back to use BCLK */
dev_warn
(
codec
->
dev
,
"Out of range PLL_CLKIN: %u
\n
"
,
freq
);
clk_id
=
TAS2552_PLL_CLKIN_BCLK
;
freq
=
0
;
}
/* fall through */
case
TAS2552_PLL_CLKIN_BCLK
:
case
TAS2552_PLL_CLKIN_1_8_FIXED
:
mask
=
TAS2552_PLL_SRC_MASK
;
val
=
(
clk_id
<<
3
)
&
mask
;
/* bit 4:5 in the register */
reg
=
TAS2552_CFG_1
;
tas2552
->
pll_clk_id
=
clk_id
;
tas2552
->
pll_clkin
=
freq
;
break
;
case
TAS2552_PDM_CLK_PLL
:
...
...
@@ -385,6 +428,7 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
mask
=
TAS2552_PDM_CLK_SEL_MASK
;
val
=
(
clk_id
>>
1
)
&
mask
;
/* bit 0:1 in the register */
reg
=
TAS2552_PDM_CFG
;
tas2552
->
pdm_clk_id
=
clk_id
;
tas2552
->
pdm_clk
=
freq
;
break
;
default:
...
...
@@ -509,9 +553,20 @@ static struct snd_soc_dai_driver tas2552_dai[] = {
*/
static
DECLARE_TLV_DB_SCALE
(
dac_tlv
,
-
7
,
100
,
0
);
static
const
char
*
const
tas2552_din_source_select
[]
=
{
"Muted"
,
"Left"
,
"Right"
,
"Left + Right average"
,
};
static
SOC_ENUM_SINGLE_DECL
(
tas2552_din_source_enum
,
TAS2552_CFG_3
,
3
,
tas2552_din_source_select
);
static
const
struct
snd_kcontrol_new
tas2552_snd_controls
[]
=
{
SOC_SINGLE_TLV
(
"Speaker Driver Playback Volume"
,
TAS2552_PGA_GAIN
,
0
,
0x1f
,
0
,
dac_tlv
),
SOC_ENUM
(
"DIN source"
,
tas2552_din_source_enum
),
};
static
int
tas2552_codec_probe
(
struct
snd_soc_codec
*
codec
)
...
...
@@ -543,13 +598,14 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
snd_soc_update_bits
(
codec
,
TAS2552_CFG_1
,
TAS2552_MUTE
,
TAS2552_MUTE
);
snd_soc_write
(
codec
,
TAS2552_CFG_3
,
TAS2552_I2S_OUT_SEL
|
TAS2552_DIN_SRC_SEL_AVG_L_R
);
snd_soc_write
(
codec
,
TAS2552_DOUT
,
TAS2552_PDM_DATA_I
);
snd_soc_write
(
codec
,
TAS2552_OUTPUT_DATA
,
TAS2552_PDM_DATA_V_I
|
0x8
);
snd_soc_write
(
codec
,
TAS2552_BOOST_PT_CTRL
,
TAS2552_APT_DELAY_200
|
TAS2552_APT_THRESH_2_1_7
);
snd_soc_write
(
codec
,
TAS2552_OUTPUT_DATA
,
TAS2552_PDM_DATA_SEL_V_I
|
TAS2552_R_DATA_OUT
(
TAS2552_DATA_OUT_V_DATA
));
snd_soc_write
(
codec
,
TAS2552_BOOST_APT_CTRL
,
TAS2552_APT_DELAY_200
|
TAS2552_APT_THRESH_20_17
);
snd_soc_write
(
codec
,
TAS2552_CFG_2
,
TAS2552_BOOST_EN
|
TAS2552_APT_EN
|
TAS2552_LIM_EN
);
snd_soc_write
(
codec
,
TAS2552_CFG_2
,
TAS2552_BOOST_EN
|
TAS2552_APT_EN
|
TAS2552_LIM_EN
);
return
0
;
...
...
@@ -647,13 +703,10 @@ static int tas2552_probe(struct i2c_client *client,
if
(
data
==
NULL
)
return
-
ENOMEM
;
data
->
enable_gpio
=
devm_gpiod_get
(
dev
,
"enable"
,
GPIOD_OUT_LOW
);
if
(
IS_ERR
(
data
->
enable_gpio
))
{
if
(
PTR_ERR
(
data
->
enable_gpio
)
==
-
EPROBE_DEFER
)
return
-
EPROBE_DEFER
;
data
->
enable_gpio
=
NULL
;;
}
data
->
enable_gpio
=
devm_gpiod_get_optional
(
dev
,
"enable"
,
GPIOD_OUT_LOW
);
if
(
IS_ERR
(
data
->
enable_gpio
))
return
PTR_ERR
(
data
->
enable_gpio
);
data
->
tas2552_client
=
client
;
data
->
regmap
=
devm_regmap_init_i2c
(
client
,
&
tas2552_regmap_config
);
...
...
@@ -695,6 +748,7 @@ static int tas2552_probe(struct i2c_client *client,
static
int
tas2552_i2c_remove
(
struct
i2c_client
*
client
)
{
snd_soc_unregister_codec
(
&
client
->
dev
);
pm_runtime_disable
(
&
client
->
dev
);
return
0
;
}
...
...
sound/soc/codecs/tas2552.h
View file @
e39f6bc7
...
...
@@ -39,7 +39,7 @@
#define TAS2552_PDM_CFG 0x11
#define TAS2552_PGA_GAIN 0x12
#define TAS2552_EDGE_RATE_CTRL 0x13
#define TAS2552_BOOST_
PT_CTRL
0x14
#define TAS2552_BOOST_
APT_CTRL
0x14
#define TAS2552_VER_NUM 0x16
#define TAS2552_VBAT_DATA 0x19
#define TAS2552_MAX_REG 0x20
...
...
@@ -103,10 +103,21 @@
#define TAS2552_WCLKDIR (1 << 7)
/* OUTPUT_DATA register */
#define TAS2552_PDM_DATA_I 0x00
#define TAS2552_PDM_DATA_V (1 << 6)
#define TAS2552_PDM_DATA_I_V (1 << 7)
#define TAS2552_PDM_DATA_V_I (0x11 << 6)
#define TAS2552_DATA_OUT_I_DATA (0x0)
#define TAS2552_DATA_OUT_V_DATA (0x1)
#define TAS2552_DATA_OUT_VBAT_DATA (0x2)
#define TAS2552_DATA_OUT_VBOOST_DATA (0x3)
#define TAS2552_DATA_OUT_PGA_GAIN (0x4)
#define TAS2552_DATA_OUT_IV_DATA (0x5)
#define TAS2552_DATA_OUT_VBAT_VBOOST_GAIN (0x6)
#define TAS2552_DATA_OUT_DISABLED (0x7)
#define TAS2552_L_DATA_OUT(x) ((x) << 0)
#define TAS2552_R_DATA_OUT(x) ((x) << 3)
#define TAS2552_PDM_DATA_SEL_I (0x0 << 6)
#define TAS2552_PDM_DATA_SEL_V (0x1 << 6)
#define TAS2552_PDM_DATA_SEL_I_V (0x2 << 6)
#define TAS2552_PDM_DATA_SEL_V_I (0x3 << 6)
#define TAS2552_PDM_DATA_SEL_MASK TAS2552_PDM_DATA_SEL_V_I
/* PDM CFG Register */
#define TAS2552_PDM_CLK_SEL_PLL (0x0 << 0)
...
...
@@ -116,24 +127,20 @@
#define TAS2552_PDM_CLK_SEL_MASK TAS2552_PDM_CLK_SEL_MCLK
#define TAS2552_PDM_DATA_ES (1 << 2)
/* Boost pass-through register */
#define TAS2552_APT_DELAY_50 0x00
#define TAS2552_APT_DELAY_75 (1 << 1)
#define TAS2552_APT_DELAY_125 (1 << 2)
#define TAS2552_APT_DELAY_200 (1 << 3)
#define TAS2552_APT_THRESH_2_5 0x00
#define TAS2552_APT_THRESH_1_7 (1 << 3)
#define TAS2552_APT_THRESH_1_4_1_1 (1 << 4)
#define TAS2552_APT_THRESH_2_1_7 (0x11 << 2)
/* Boost Auto-pass through register */
#define TAS2552_APT_DELAY_50 (0x0 << 0)
#define TAS2552_APT_DELAY_75 (0x1 << 0)
#define TAS2552_APT_DELAY_125 (0x2 << 0)
#define TAS2552_APT_DELAY_200 (0x3 << 0)
#define TAS2552_APT_THRESH_05_02 (0x0 << 2)
#define TAS2552_APT_THRESH_10_07 (0x1 << 2)
#define TAS2552_APT_THRESH_14_11 (0x2 << 2)
#define TAS2552_APT_THRESH_20_17 (0x3 << 2)
/* PLL Control Register */
#define TAS2552_245MHZ_CLK 24576000
#define TAS2552_225MHZ_CLK 22579200
#define TAS2552_PLL_J_MASK 0x7f
#define TAS2552_PLL_D_UPPER_MASK 0x3f
#define TAS2552_PLL_D_LOWER_MASK 0xff
#define TAS2552_PLL_BYPASS_MASK 0x80
#define TAS2552_PLL_BYPASS 0x80
#define TAS2552_PLL_D_UPPER(x) (((x) >> 8) & 0x3f)
#define TAS2552_PLL_D_LOWER(x) ((x) & 0xff)
#define TAS2552_PLL_BYPASS (1 << 7)
#endif
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