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
848272e9
Commit
848272e9
authored
Mar 28, 2018
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/samsung' into asoc-next
parents
36e82da9
4718840e
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
431 additions
and
150 deletions
+431
-150
Documentation/devicetree/bindings/sound/samsung,odroid.txt
Documentation/devicetree/bindings/sound/samsung,odroid.txt
+5
-3
Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt
...mentation/devicetree/bindings/sound/samsung,tm2-audio.txt
+9
-5
Documentation/devicetree/bindings/sound/samsung-i2s.txt
Documentation/devicetree/bindings/sound/samsung-i2s.txt
+12
-10
Documentation/devicetree/bindings/sound/snow.txt
Documentation/devicetree/bindings/sound/snow.txt
+11
-2
include/sound/soc.h
include/sound/soc.h
+1
-0
sound/soc/samsung/Makefile
sound/soc/samsung/Makefile
+0
-3
sound/soc/samsung/i2s-regs.h
sound/soc/samsung/i2s-regs.h
+6
-5
sound/soc/samsung/i2s.c
sound/soc/samsung/i2s.c
+38
-14
sound/soc/samsung/i2s.h
sound/soc/samsung/i2s.h
+8
-3
sound/soc/samsung/odroid.c
sound/soc/samsung/odroid.c
+12
-21
sound/soc/samsung/snow.c
sound/soc/samsung/snow.c
+177
-52
sound/soc/samsung/tm2_wm5110.c
sound/soc/samsung/tm2_wm5110.c
+129
-23
sound/soc/soc-core.c
sound/soc/soc-core.c
+23
-9
No files found.
Documentation/devicetree/bindings/sound/samsung,odroid.txt
View file @
848272e9
...
...
@@ -2,8 +2,10 @@ Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec
Required properties:
- compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board,
"samsung,odroidxu4-audio" - for Odroid XU4 board
- compatible - "hardkernel,odroid-xu3-audio" - for Odroid XU3 board,
"hardkernel,odroid-xu4-audio" - for Odroid XU4 board (deprecated),
"samsung,odroid-xu3-audio" - for Odroid XU3 board (deprecated),
"samsung,odroid-xu4-audio" - for Odroid XU4 board (deprecated)
- model - the user-visible name of this sound complex
- clocks - should contain entries matching clock names in the clock-names
property
...
...
@@ -35,7 +37,7 @@ Required sub-nodes:
Example:
sound {
compatible = "
samsung,odroid
xu3-audio";
compatible = "
hardkernel,odroid-
xu3-audio";
model = "Odroid-XU3";
samsung,audio-routing =
"Headphone Jack", "HPL",
...
...
Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt
View file @
848272e9
...
...
@@ -4,9 +4,13 @@ Required properties:
- compatible : "samsung,tm2-audio"
- model : the user-visible name of this sound complex
- audio-codec : the phandle of the wm5110 audio codec node,
as described in ../mfd/arizona.txt
- i2s-controller : the phandle of the I2S controller
- audio-codec : the first entry should be phandle of the wm5110 audio
codec node, as described in ../mfd/arizona.txt;
the second entry should be phandle of the HDMI
transmitter node
- i2s-controller : the list of phandle and argument tuples pointing to
I2S controllers, the first entry should be I2S0 and
the second one I2S1
- audio-amplifier : the phandle of the MAX98504 amplifier
- samsung,audio-routing : a list of the connections between audio components;
each entry is a pair of strings, the first being the
...
...
@@ -22,8 +26,8 @@ Example:
sound {
compatible = "samsung,tm2-audio";
audio-codec = <&wm5110>;
i2s-controller = <&i2s0>;
audio-codec = <&wm5110>
, <&hdmi>
;
i2s-controller = <&i2s0
0>, <&i2s1 0
>;
audio-amplifier = <&max98504>;
mic-bias-gpios = <&gpr3 2 0>;
model = "wm5110";
...
...
Documentation/devicetree/bindings/sound/samsung-i2s.txt
View file @
848272e9
...
...
@@ -7,7 +7,7 @@ Required SoC Specific Properties:
- samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
secondary fifo, s/w reset control and internal mux for root clk src.
- samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
playback, ster
i
o channel capture, secondary fifo using internal
playback, ster
e
o channel capture, secondary fifo using internal
or external dma, s/w reset control, internal mux for root clk src
and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
is to allow transfer of multiple channel audio data on single data line.
...
...
@@ -25,7 +25,7 @@ Required SoC Specific Properties:
These strings correspond 1:1 with the ordered pairs in dmas.
- clocks: Handle to iis clock and RCLK source clk.
- clock-names:
i2s0 uses some base clks from CMU and some are from audio subsystem internal
i2s0 uses some base cl
oc
ks from CMU and some are from audio subsystem internal
clock controller. The clock names for i2s0 should be "iis", "i2s_opclk0" and
"i2s_opclk1" as shown in the example below.
i2s1 and i2s2 uses clocks from CMU. The clock names for i2s1 and i2s2 should
...
...
@@ -36,9 +36,9 @@ Required SoC Specific Properties:
- #clock-cells: should be 1, this property must be present if the I2S device
is a clock provider in terms of the common clock bindings, described in
../clock/clock-bindings.txt.
- clock-output-names
: from the common clock bindings, names of the CDCLK
I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
"i2s_cdclk3" for the I2S0, I2S1, I2S2 devices re
c
pectively.
- clock-output-names
(deprecated): from the common clock bindings, names of
the CDCLK
I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
"i2s_cdclk3" for the I2S0, I2S1, I2S2 devices re
s
pectively.
There are following clocks available at the I2S device nodes:
CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock,
...
...
@@ -49,9 +49,10 @@ There are following clocks available at the I2S device nodes:
Refer to the SoC datasheet for availability of the above clocks.
The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
in the IIS Multi Audio Interface (I2S0).
Note: Old DTs may not have the #clock-cells, clock-output-names properties
and then not use the I2S node as a clock supplier.
in the IIS Multi Audio Interface.
Note: Old DTs may not have the #clock-cells property and then not use the I2S
node as a clock supplier.
Optional SoC Specific Properties:
...
...
@@ -59,6 +60,7 @@ Optional SoC Specific Properties:
sub system(used in secondary sound source).
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
- #sound-dai-cells: should be 1.
Example:
...
...
@@ -74,9 +76,9 @@ i2s0: i2s@3830000 {
<&clock_audss EXYNOS_I2S_BUS>,
<&clock_audss EXYNOS_SCLK_I2S>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
#clock-cells;
clock-output-names = "i2s_cdclk0";
#clock-cells = <1>;
samsung,idma-addr = <0x03000000>;
pinctrl-names = "default";
pinctrl-0 = <&i2s0_bus>;
#sound-dai-cells = <1>;
};
Documentation/devicetree/bindings/sound/snow.txt
View file @
848272e9
...
...
@@ -5,8 +5,17 @@ Required properties:
"google,snow-audio-max98090" or
"google,snow-audio-max98091" or
"google,snow-audio-max98095"
- samsung,i2s-controller: The phandle of the Samsung I2S controller
- samsung,audio-codec: The phandle of the audio codec
- samsung,i2s-controller (deprecated): The phandle of the Samsung I2S controller
- samsung,audio-codec (deprecated): The phandle of the audio codec
Required sub-nodes:
- 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
controller
- 'codec' subnode with a 'sound-dai' property containing list of phandles
to the CODEC nodes, first entry must be the phandle of the MAX98090,
MAX98091 or MAX98095 CODEC (exact device type is indicated by the compatible
string) and the second entry must be the phandle of the HDMI IP block node
Optional:
- samsung,model: The name of the sound-card
...
...
include/sound/soc.h
View file @
848272e9
...
...
@@ -1807,6 +1807,7 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
int
snd_soc_of_get_dai_link_codecs
(
struct
device
*
dev
,
struct
device_node
*
of_node
,
struct
snd_soc_dai_link
*
dai_link
);
void
snd_soc_of_put_dai_link_codecs
(
struct
snd_soc_dai_link
*
dai_link
);
int
snd_soc_add_dai_link
(
struct
snd_soc_card
*
card
,
struct
snd_soc_dai_link
*
dai_link
);
...
...
sound/soc/samsung/Makefile
View file @
848272e9
...
...
@@ -21,8 +21,6 @@ obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs
:=
jive_wm8750.o
snd-soc-neo1973-wm8753-objs
:=
neo1973_wm8753.o
snd-soc-smdk2443-wm9710-objs
:=
smdk2443_wm9710.o
snd-soc-ln2440sbc-alc650-objs
:=
ln2440sbc_alc650.o
snd-soc-s3c24xx-uda134x-objs
:=
s3c24xx_uda134x.o
snd-soc-s3c24xx-simtec-objs
:=
s3c24xx_simtec.o
snd-soc-s3c24xx-simtec-hermes-objs
:=
s3c24xx_simtec_hermes.o
...
...
@@ -32,7 +30,6 @@ snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
snd-soc-smdk-wm8580-objs
:=
smdk_wm8580.o
snd-soc-smdk-wm8994-objs
:=
smdk_wm8994.o
snd-soc-snow-objs
:=
snow.o
snd-soc-smdk-wm9713-objs
:=
smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs
:=
smartq_wm8987.o
snd-soc-smdk-spdif-objs
:=
smdk_spdif.o
snd-soc-smdk-wm8994pcm-objs
:=
smdk_wm8994pcm.o
...
...
sound/soc/samsung/i2s-regs.h
View file @
848272e9
...
...
@@ -65,11 +65,12 @@
#define CON_RXDMA_ACTIVE (1 << 1)
#define CON_ACTIVE (1 << 0)
#define MOD_OPCLK_CDCLK_OUT (0 << 30)
#define MOD_OPCLK_CDCLK_IN (1 << 30)
#define MOD_OPCLK_BCLK_OUT (2 << 30)
#define MOD_OPCLK_PCLK (3 << 30)
#define MOD_OPCLK_MASK (3 << 30)
#define MOD_OPCLK_SHIFT 30
#define MOD_OPCLK_CDCLK_OUT (0 << MOD_OPCLK_SHIFT)
#define MOD_OPCLK_CDCLK_IN (1 << MOD_OPCLK_SHIFT)
#define MOD_OPCLK_BCLK_OUT (2 << MOD_OPCLK_SHIFT)
#define MOD_OPCLK_PCLK (3 << MOD_OPCLK_SHIFT)
#define MOD_OPCLK_MASK (3 << MOD_OPCLK_SHIFT)
#define MOD_TXS_IDMA (1 << 28)
/* Sec_TXFIFO use I-DMA */
#define MOD_BLCS_SHIFT 26
...
...
sound/soc/samsung/i2s.c
View file @
848272e9
...
...
@@ -489,7 +489,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
switch
(
clk_id
)
{
case
SAMSUNG_I2S_OPCLK
:
mask
=
MOD_OPCLK_MASK
;
val
=
dir
;
val
=
(
dir
<<
MOD_OPCLK_SHIFT
)
&
MOD_OPCLK_MASK
;
break
;
case
SAMSUNG_I2S_CDCLK
:
mask
=
1
<<
i2s_regs
->
cdclkcon_off
;
...
...
@@ -656,8 +656,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
tmp
|=
mod_slave
;
break
;
case
SND_SOC_DAIFMT_CBS_CFS
:
/* Set default source clock in Master mode */
if
(
i2s
->
rclk_srcrate
==
0
)
/*
* Set default source clock in Master mode, only when the
* CLK_I2S_RCLK_SRC clock is not exposed so we ensure any
* clock configuration assigned in DT is not overwritten.
*/
if
(
i2s
->
rclk_srcrate
==
0
&&
i2s
->
clk_data
.
clks
==
NULL
)
i2s_set_sysclk
(
dai
,
SAMSUNG_I2S_RCLKSRC_0
,
0
,
SND_SOC_CLOCK_IN
);
break
;
...
...
@@ -881,6 +885,11 @@ static int config_setup(struct i2s_dai *i2s)
return
0
;
if
(
!
(
i2s
->
quirks
&
QUIRK_NO_MUXPSR
))
{
struct
clk
*
rclksrc
=
i2s
->
clk_table
[
CLK_I2S_RCLK_SRC
];
if
(
rclksrc
&&
!
IS_ERR
(
rclksrc
))
i2s
->
rclk_srcrate
=
clk_get_rate
(
rclksrc
);
psr
=
i2s
->
rclk_srcrate
/
i2s
->
frmclk
/
rfs
;
writel
(((
psr
-
1
)
<<
8
)
|
PSR_PSREN
,
i2s
->
addr
+
I2SPSR
);
dev_dbg
(
&
i2s
->
pdev
->
dev
,
...
...
@@ -1184,11 +1193,13 @@ static void i2s_unregister_clock_provider(struct platform_device *pdev)
static
int
i2s_register_clock_provider
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
i2s_dai
*
i2s
=
dev_get_drvdata
(
dev
);
const
char
*
const
i2s_clk_desc
[]
=
{
"cdclk"
,
"rclk_src"
,
"prescaler"
};
const
char
*
clk_name
[
2
]
=
{
"i2s_opclk0"
,
"i2s_opclk1"
};
const
char
*
p_names
[
2
]
=
{
NULL
};
struct
device
*
dev
=
&
pdev
->
dev
;
struct
i2s_dai
*
i2s
=
dev_get_drvdata
(
dev
);
const
struct
samsung_i2s_variant_regs
*
reg_info
=
i2s
->
variant_regs
;
const
char
*
i2s_clk_name
[
ARRAY_SIZE
(
i2s_clk_desc
)];
struct
clk
*
rclksrc
;
int
ret
,
i
;
...
...
@@ -1205,30 +1216,38 @@ static int i2s_register_clock_provider(struct platform_device *pdev)
clk_put
(
rclksrc
);
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
i2s_clk_desc
);
i
++
)
{
i2s_clk_name
[
i
]
=
devm_kasprintf
(
dev
,
GFP_KERNEL
,
"%s_%s"
,
dev_name
(
dev
),
i2s_clk_desc
[
i
]);
if
(
!
i2s_clk_name
[
i
])
return
-
ENOMEM
;
}
if
(
!
(
i2s
->
quirks
&
QUIRK_NO_MUXPSR
))
{
/* Activate the prescaler */
u32
val
=
readl
(
i2s
->
addr
+
I2SPSR
);
writel
(
val
|
PSR_PSREN
,
i2s
->
addr
+
I2SPSR
);
i2s
->
clk_table
[
CLK_I2S_RCLK_SRC
]
=
clk_register_mux
(
dev
,
"i2s_rclksrc"
,
p_names
,
ARRAY_SIZE
(
p_names
),
i2s_clk_name
[
CLK_I2S_RCLK_SRC
],
p_names
,
ARRAY_SIZE
(
p_names
),
CLK_SET_RATE_NO_REPARENT
|
CLK_SET_RATE_PARENT
,
i2s
->
addr
+
I2SMOD
,
reg_info
->
rclksrc_off
,
1
,
0
,
i2s
->
lock
);
i2s
->
clk_table
[
CLK_I2S_RCLK_PSR
]
=
clk_register_divider
(
dev
,
"i2s_presc"
,
"i2s_rclksrc"
,
i2s_clk_name
[
CLK_I2S_RCLK_PSR
],
i2s_clk_name
[
CLK_I2S_RCLK_SRC
],
CLK_SET_RATE_PARENT
,
i2s
->
addr
+
I2SPSR
,
8
,
6
,
0
,
i2s
->
lock
);
p_names
[
0
]
=
"i2s_presc"
;
p_names
[
0
]
=
i2s_clk_name
[
CLK_I2S_RCLK_PSR
]
;
i2s
->
clk_data
.
clk_num
=
2
;
}
of_property_read_string_index
(
dev
->
of_node
,
"clock-output-names"
,
0
,
&
clk_name
[
0
]);
i2s
->
clk_table
[
CLK_I2S_CDCLK
]
=
clk_register_gate
(
dev
,
clk_name
[
0
],
p_names
[
0
],
CLK_SET_RATE_PARENT
,
i2s
->
clk_table
[
CLK_I2S_CDCLK
]
=
clk_register_gate
(
dev
,
i2s_clk_name
[
CLK_I2S_CDCLK
],
p_names
[
0
],
CLK_SET_RATE_PARENT
,
i2s
->
addr
+
I2SMOD
,
reg_info
->
cdclkcon_off
,
CLK_GATE_SET_TO_DISABLE
,
i2s
->
lock
);
...
...
@@ -1385,9 +1404,14 @@ static int samsung_i2s_probe(struct platform_device *pdev)
pm_runtime_enable
(
&
pdev
->
dev
);
ret
=
i2s_register_clock_provider
(
pdev
);
if
(
!
ret
)
return
0
;
if
(
ret
<
0
)
goto
err_disable_pm
;
pri_dai
->
op_clk
=
clk_get_parent
(
pri_dai
->
clk_table
[
CLK_I2S_RCLK_SRC
]);
return
0
;
err_disable_pm:
pm_runtime_disable
(
&
pdev
->
dev
);
err_disable_clk:
clk_disable_unprepare
(
pri_dai
->
clk
);
...
...
sound/soc/samsung/i2s.h
View file @
848272e9
...
...
@@ -16,11 +16,16 @@
#define SAMSUNG_I2S_DAI "samsung-i2s"
#define SAMSUNG_I2S_DAI_SEC "samsung-i2s-sec"
#define SAMSUNG_I2S_DIV_BCLK 1
#define SAMSUNG_I2S_DIV_BCLK
1
#define SAMSUNG_I2S_RCLKSRC_0 0
#define SAMSUNG_I2S_RCLKSRC_1 1
#define SAMSUNG_I2S_RCLKSRC_0
0
#define SAMSUNG_I2S_RCLKSRC_1
1
#define SAMSUNG_I2S_CDCLK 2
/* Operation clock for IIS logic */
#define SAMSUNG_I2S_OPCLK 3
#define SAMSUNG_I2S_OPCLK_CDCLK_OUT 0
/* CODEC clock out */
#define SAMSUNG_I2S_OPCLK_CDCLK_IN 1
/* CODEC clock in */
#define SAMSUNG_I2S_OPCLK_BCLK_OUT 2
/* Bit clock out */
#define SAMSUNG_I2S_OPCLK_PCLK 3
/* Audio bus clock */
#endif
/* __SND_SOC_SAMSUNG_I2S_H */
sound/soc/samsung/odroid.c
View file @
848272e9
...
...
@@ -36,23 +36,24 @@ static int odroid_card_hw_params(struct snd_pcm_substream *substream,
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
odroid_priv
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
unsigned
int
pll_freq
,
rclk_freq
;
unsigned
int
pll_freq
,
rclk_freq
,
rfs
;
int
ret
;
switch
(
params_rate
(
params
))
{
case
32000
:
case
64000
:
pll_freq
=
131072006U
;
pll_freq
=
196608001U
;
rfs
=
384
;
break
;
case
44100
:
case
88200
:
case
176400
:
pll_freq
=
180633609U
;
rfs
=
512
;
break
;
case
32000
:
case
48000
:
case
96000
:
case
192000
:
pll_freq
=
196608001U
;
rfs
=
512
;
break
;
default:
return
-
EINVAL
;
...
...
@@ -67,7 +68,7 @@ static int odroid_card_hw_params(struct snd_pcm_substream *substream,
* frequency values due to the EPLL output frequency not being exact
* multiple of the audio sampling rate.
*/
rclk_freq
=
params_rate
(
params
)
*
256
+
1
;
rclk_freq
=
params_rate
(
params
)
*
rfs
+
1
;
ret
=
clk_set_rate
(
priv
->
sclk_i2s
,
rclk_freq
);
if
(
ret
<
0
)
...
...
@@ -90,18 +91,6 @@ static const struct snd_soc_ops odroid_card_ops = {
.
hw_params
=
odroid_card_hw_params
,
};
static
void
odroid_put_codec_of_nodes
(
struct
snd_soc_dai_link
*
link
)
{
struct
snd_soc_dai_link_component
*
component
=
link
->
codecs
;
int
i
;
for
(
i
=
0
;
i
<
link
->
num_codecs
;
i
++
,
component
++
)
{
if
(
!
component
->
of_node
)
break
;
of_node_put
(
component
->
of_node
);
}
}
static
int
odroid_audio_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
...
...
@@ -196,7 +185,7 @@ static int odroid_audio_probe(struct platform_device *pdev)
err_put_i2s_n:
of_node_put
(
link
->
cpu_of_node
);
err_put_codec_n:
odroid_put_codec_of_node
s
(
link
);
snd_soc_of_put_dai_link_codec
s
(
link
);
return
ret
;
}
...
...
@@ -205,7 +194,7 @@ static int odroid_audio_remove(struct platform_device *pdev)
struct
odroid_priv
*
priv
=
platform_get_drvdata
(
pdev
);
of_node_put
(
priv
->
dai_link
.
cpu_of_node
);
odroid_put_codec_of_node
s
(
&
priv
->
dai_link
);
snd_soc_of_put_dai_link_codec
s
(
&
priv
->
dai_link
);
clk_put
(
priv
->
sclk_i2s
);
clk_put
(
priv
->
clk_i2s_bus
);
...
...
@@ -213,8 +202,10 @@ static int odroid_audio_remove(struct platform_device *pdev)
}
static
const
struct
of_device_id
odroid_audio_of_match
[]
=
{
{
.
compatible
=
"hardkernel,odroid-xu3-audio"
},
{
.
compatible
=
"hardkernel,odroid-xu4-audio"
},
{
.
compatible
=
"samsung,odroid-xu3-audio"
},
{
.
compatible
=
"samsung,odroid-xu4-audio"
},
{
.
compatible
=
"samsung,odroid-xu4-audio"
},
{
},
};
MODULE_DEVICE_TABLE
(
of
,
odroid_audio_of_match
);
...
...
sound/soc/samsung/snow.c
View file @
848272e9
...
...
@@ -11,97 +11,207 @@
* General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "i2s.h"
#define FIN_PLL_RATE 24000000
static
struct
snd_soc_dai_link
snow_dai
[]
=
{
{
.
name
=
"Primary"
,
.
stream_name
=
"Primary"
,
.
codec_dai_name
=
"HiFi"
,
.
dai_fmt
=
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBS_CFS
,
},
struct
snow_priv
{
struct
snd_soc_dai_link
dai_link
;
struct
clk
*
clk_i2s_bus
;
};
static
int
snow_card_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
static
const
unsigned
int
pll_rate
[]
=
{
73728000U
,
67737602U
,
49152000U
,
45158401U
,
32768001U
};
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
snow_priv
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
int
bfs
,
psr
,
rfs
,
bitwidth
;
unsigned
long
int
rclk
;
long
int
freq
=
-
EINVAL
;
int
ret
,
i
;
bitwidth
=
snd_pcm_format_width
(
params_format
(
params
));
if
(
bitwidth
<
0
)
{
dev_err
(
rtd
->
card
->
dev
,
"Invalid bit-width: %d
\n
"
,
bitwidth
);
return
bitwidth
;
}
if
(
bitwidth
!=
16
&&
bitwidth
!=
24
)
{
dev_err
(
rtd
->
card
->
dev
,
"Unsupported bit-width: %d
\n
"
,
bitwidth
);
return
-
EINVAL
;
}
bfs
=
2
*
bitwidth
;
switch
(
params_rate
(
params
))
{
case
16000
:
case
22050
:
case
24000
:
case
32000
:
case
44100
:
case
48000
:
case
88200
:
case
96000
:
rfs
=
8
*
bfs
;
break
;
case
64000
:
rfs
=
384
;
break
;
case
8000
:
case
11025
:
case
12000
:
rfs
=
16
*
bfs
;
break
;
default:
return
-
EINVAL
;
}
rclk
=
params_rate
(
params
)
*
rfs
;
for
(
psr
=
8
;
psr
>
0
;
psr
/=
2
)
{
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pll_rate
);
i
++
)
{
if
((
pll_rate
[
i
]
-
rclk
*
psr
)
<=
2
)
{
freq
=
pll_rate
[
i
];
break
;
}
}
}
if
(
freq
<
0
)
{
dev_err
(
rtd
->
card
->
dev
,
"Unsupported RCLK rate: %lu
\n
"
,
rclk
);
return
-
EINVAL
;
}
ret
=
clk_set_rate
(
priv
->
clk_i2s_bus
,
freq
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
card
->
dev
,
"I2S bus clock rate set failed
\n
"
);
return
ret
;
}
return
0
;
}
static
const
struct
snd_soc_ops
snow_card_ops
=
{
.
hw_params
=
snow_card_hw_params
,
};
static
int
snow_late_probe
(
struct
snd_soc_card
*
card
)
{
struct
snd_soc_pcm_runtime
*
rtd
;
struct
snd_soc_dai
*
codec_dai
;
struct
snd_soc_dai
*
cpu_dai
;
int
ret
;
rtd
=
snd_soc_get_pcm_runtime
(
card
,
card
->
dai_link
[
0
].
name
);
codec_dai
=
rtd
->
codec_dai
;
cpu_dai
=
rtd
->
cpu_dai
;
/*
Set the MCLK rate for the codec
*/
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
0
,
FIN_PLL_RATE
,
SND_SOC_CLOCK_IN
)
;
if
(
ret
<
0
)
return
ret
;
/*
In the multi-codec case codec_dais 0 is MAX98095 and 1 is HDMI.
*/
if
(
rtd
->
num_codecs
>
1
)
codec_dai
=
rtd
->
codec_dais
[
0
]
;
else
codec_dai
=
rtd
->
codec_dai
;
/* Select I2S Bus clock to set RCLK and BCLK */
ret
=
snd_soc_dai_set_sysclk
(
cpu_dai
,
SAMSUNG_I2S_RCLKSRC_0
,
0
,
SND_SOC_CLOCK_IN
);
if
(
ret
<
0
)
return
ret
;
return
0
;
/* Set the MCLK rate for the codec */
return
snd_soc_dai_set_sysclk
(
codec_dai
,
0
,
FIN_PLL_RATE
,
SND_SOC_CLOCK_IN
);
}
static
struct
snd_soc_card
snow_snd
=
{
.
name
=
"Snow-I2S"
,
.
owner
=
THIS_MODULE
,
.
dai_link
=
snow_dai
,
.
num_links
=
ARRAY_SIZE
(
snow_dai
),
.
late_probe
=
snow_late_probe
,
};
static
int
snow_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
snd_soc_card
*
card
=
&
snow_snd
;
struct
device_node
*
i2s_node
,
*
codec_node
;
int
i
,
ret
;
i2s_node
=
of_parse_phandle
(
pdev
->
dev
.
of_node
,
"samsung,i2s-controller"
,
0
);
if
(
!
i2s_node
)
{
dev_err
(
&
pdev
->
dev
,
"Property 'i2s-controller' missing or invalid
\n
"
);
return
-
EINVAL
;
}
struct
device_node
*
cpu
,
*
codec
;
struct
snd_soc_dai_link
*
link
;
struct
snow_priv
*
priv
;
int
ret
;
codec_node
=
of_parse_phandle
(
pdev
->
dev
.
of_node
,
"samsung,audio-codec"
,
0
);
if
(
!
codec_node
)
{
dev_err
(
&
pdev
->
dev
,
"Property 'audio-codec' missing or invalid
\n
"
);
return
-
EINVAL
;
}
priv
=
devm_kzalloc
(
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
link
=
&
priv
->
dai_link
;
link
->
dai_fmt
=
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBS_CFS
;
link
->
name
=
"Primary"
;
link
->
stream_name
=
link
->
name
;
card
->
dai_link
=
link
;
card
->
num_links
=
1
;
card
->
dev
=
dev
;
/* Try new DT bindings with HDMI support first. */
cpu
=
of_get_child_by_name
(
dev
->
of_node
,
"cpu"
);
if
(
cpu
)
{
link
->
ops
=
&
snow_card_ops
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
snow_dai
);
i
++
)
{
snow_dai
[
i
].
codec_of_node
=
codec_node
;
snow_dai
[
i
].
cpu_of_node
=
i2s_node
;
snow_dai
[
i
].
platform_of_node
=
i2s_node
;
link
->
cpu_of_node
=
of_parse_phandle
(
cpu
,
"sound-dai"
,
0
);
of_node_put
(
cpu
);
if
(
!
link
->
cpu_of_node
)
{
dev_err
(
dev
,
"Failed parsing cpu/sound-dai property
\n
"
);
return
-
EINVAL
;
}
codec
=
of_get_child_by_name
(
dev
->
of_node
,
"codec"
);
ret
=
snd_soc_of_get_dai_link_codecs
(
dev
,
codec
,
link
);
of_node_put
(
codec
);
if
(
ret
<
0
)
{
of_node_put
(
link
->
cpu_of_node
);
dev_err
(
dev
,
"Failed parsing codec node
\n
"
);
return
ret
;
}
priv
->
clk_i2s_bus
=
of_clk_get_by_name
(
link
->
cpu_of_node
,
"i2s_opclk0"
);
if
(
IS_ERR
(
priv
->
clk_i2s_bus
))
{
snd_soc_of_put_dai_link_codecs
(
link
);
of_node_put
(
link
->
cpu_of_node
);
return
PTR_ERR
(
priv
->
clk_i2s_bus
);
}
}
else
{
link
->
codec_dai_name
=
"HiFi"
,
link
->
cpu_of_node
=
of_parse_phandle
(
dev
->
of_node
,
"samsung,i2s-controller"
,
0
);
if
(
!
link
->
cpu_of_node
)
{
dev_err
(
dev
,
"i2s-controller property parse error
\n
"
);
return
-
EINVAL
;
}
link
->
codec_of_node
=
of_parse_phandle
(
dev
->
of_node
,
"samsung,audio-codec"
,
0
);
if
(
!
link
->
codec_of_node
)
{
of_node_put
(
link
->
cpu_of_node
);
dev_err
(
dev
,
"audio-codec property parse error
\n
"
);
return
-
EINVAL
;
}
}
card
->
dev
=
&
pdev
->
dev
;
link
->
platform_of_node
=
link
->
cpu_of_node
;
/* Update card-name if provided through DT, else use default name */
snd_soc_of_parse_card_name
(
card
,
"samsung,model"
);
ret
=
devm_snd_soc_register_card
(
&
pdev
->
dev
,
card
);
snd_soc_card_set_drvdata
(
card
,
priv
);
ret
=
devm_snd_soc_register_card
(
dev
,
card
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"snd_soc_register_card failed (%d)
\n
"
,
ret
);
return
ret
;
...
...
@@ -110,6 +220,20 @@ static int snow_probe(struct platform_device *pdev)
return
ret
;
}
static
int
snow_remove
(
struct
platform_device
*
pdev
)
{
struct
snow_priv
*
priv
=
platform_get_drvdata
(
pdev
);
struct
snd_soc_dai_link
*
link
=
&
priv
->
dai_link
;
of_node_put
(
link
->
cpu_of_node
);
of_node_put
(
link
->
codec_of_node
);
snd_soc_of_put_dai_link_codecs
(
link
);
clk_put
(
priv
->
clk_i2s_bus
);
return
0
;
}
static
const
struct
of_device_id
snow_of_match
[]
=
{
{
.
compatible
=
"google,snow-audio-max98090"
,
},
{
.
compatible
=
"google,snow-audio-max98091"
,
},
...
...
@@ -125,6 +249,7 @@ static struct platform_driver snow_driver = {
.
of_match_table
=
snow_of_match
,
},
.
probe
=
snow_probe
,
.
remove
=
snow_remove
,
};
module_platform_driver
(
snow_driver
);
...
...
sound/soc/samsung/tm2_wm5110.c
View file @
848272e9
...
...
@@ -210,6 +210,59 @@ static struct snd_soc_ops tm2_aif2_ops = {
.
hw_free
=
tm2_aif2_hw_free
,
};
static
int
tm2_hdmi_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
snd_soc_dai
*
cpu_dai
=
rtd
->
cpu_dai
;
unsigned
int
bfs
;
int
bitwidth
,
ret
;
bitwidth
=
snd_pcm_format_width
(
params_format
(
params
));
if
(
bitwidth
<
0
)
{
dev_err
(
rtd
->
card
->
dev
,
"Invalid bit-width: %d
\n
"
,
bitwidth
);
return
bitwidth
;
}
switch
(
bitwidth
)
{
case
48
:
bfs
=
64
;
break
;
case
16
:
bfs
=
32
;
break
;
default:
dev_err
(
rtd
->
card
->
dev
,
"Unsupported bit-width: %d
\n
"
,
bitwidth
);
return
-
EINVAL
;
}
switch
(
params_rate
(
params
))
{
case
48000
:
case
96000
:
case
192000
:
break
;
default:
dev_err
(
rtd
->
card
->
dev
,
"Unsupported sample rate: %d
\n
"
,
params_rate
(
params
));
return
-
EINVAL
;
}
ret
=
snd_soc_dai_set_sysclk
(
cpu_dai
,
SAMSUNG_I2S_OPCLK
,
0
,
SAMSUNG_I2S_OPCLK_PCLK
);
if
(
ret
<
0
)
return
ret
;
ret
=
snd_soc_dai_set_clkdiv
(
cpu_dai
,
SAMSUNG_I2S_DIV_BCLK
,
bfs
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
struct
snd_soc_ops
tm2_hdmi_ops
=
{
.
hw_params
=
tm2_hdmi_hw_params
,
};
static
int
tm2_mic_bias
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kcontrol
,
int
event
)
{
...
...
@@ -405,6 +458,12 @@ static struct snd_soc_dai_link tm2_dai_links[] = {
.
dai_fmt
=
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBM_CFM
,
.
ignore_suspend
=
1
,
},
{
.
name
=
"HDMI"
,
.
stream_name
=
"i2s1"
,
.
ops
=
&
tm2_hdmi_ops
,
.
dai_fmt
=
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBS_CFS
,
}
};
...
...
@@ -412,7 +471,6 @@ static struct snd_soc_card tm2_card = {
.
owner
=
THIS_MODULE
,
.
dai_link
=
tm2_dai_links
,
.
num_links
=
ARRAY_SIZE
(
tm2_dai_links
),
.
controls
=
tm2_controls
,
.
num_controls
=
ARRAY_SIZE
(
tm2_controls
),
.
dapm_widgets
=
tm2_dapm_widgets
,
...
...
@@ -426,11 +484,14 @@ static struct snd_soc_card tm2_card = {
static
int
tm2_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
cpu_dai_node
[
2
]
=
{};
struct
device_node
*
codec_dai_node
[
2
]
=
{};
const
char
*
cells_name
=
NULL
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
snd_soc_card
*
card
=
&
tm2_card
;
struct
tm2_machine_priv
*
priv
;
struct
device_node
*
cpu_dai_node
,
*
codec_dai_node
;
int
ret
,
i
;
struct
of_phandle_args
args
;
int
num_codecs
,
ret
,
i
;
priv
=
devm_kzalloc
(
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
...
...
@@ -464,47 +525,92 @@ static int tm2_probe(struct platform_device *pdev)
return
-
EINVAL
;
}
cpu_dai_node
=
of_parse_phandle
(
dev
->
of_node
,
"i2s-controller"
,
0
);
if
(
!
cpu_dai_node
)
{
dev_err
(
dev
,
"i2s-controllers property invalid or missing
\n
"
);
ret
=
-
EINVAL
;
goto
amp_node_put
;
num_codecs
=
of_count_phandle_with_args
(
dev
->
of_node
,
"audio-codec"
,
NULL
);
/* Skip the HDMI link if not specified in DT */
if
(
num_codecs
>
1
)
{
card
->
num_links
=
ARRAY_SIZE
(
tm2_dai_links
);
cells_name
=
"#sound-dai-cells"
;
}
else
{
card
->
num_links
=
ARRAY_SIZE
(
tm2_dai_links
)
-
1
;
}
codec_dai_node
=
of_parse_phandle
(
dev
->
of_node
,
"audio-codec"
,
0
);
if
(
!
codec_dai_node
)
{
dev_err
(
dev
,
"audio-codec property invalid or missing
\n
"
);
ret
=
-
EINVAL
;
goto
cpu_dai_node_put
;
for
(
i
=
0
;
i
<
num_codecs
;
i
++
)
{
struct
of_phandle_args
args
;
ret
=
of_parse_phandle_with_args
(
dev
->
of_node
,
"i2s-controller"
,
cells_name
,
i
,
&
args
);
if
(
!
args
.
np
)
{
dev_err
(
dev
,
"i2s-controller property parse error: %d
\n
"
,
i
);
ret
=
-
EINVAL
;
goto
dai_node_put
;
}
cpu_dai_node
[
i
]
=
args
.
np
;
codec_dai_node
[
i
]
=
of_parse_phandle
(
dev
->
of_node
,
"audio-codec"
,
i
);
if
(
!
codec_dai_node
[
i
])
{
dev_err
(
dev
,
"audio-codec property parse error
\n
"
);
ret
=
-
EINVAL
;
goto
dai_node_put
;
}
}
/* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */
for
(
i
=
0
;
i
<
card
->
num_links
;
i
++
)
{
unsigned
int
dai_index
=
0
;
/* WM5110 */
card
->
dai_link
[
i
].
cpu_name
=
NULL
;
card
->
dai_link
[
i
].
platform_name
=
NULL
;
card
->
dai_link
[
i
].
codec_of_node
=
codec_dai_node
;
card
->
dai_link
[
i
].
cpu_of_node
=
cpu_dai_node
;
card
->
dai_link
[
i
].
platform_of_node
=
cpu_dai_node
;
if
(
num_codecs
>
1
&&
i
==
card
->
num_links
-
1
)
dai_index
=
1
;
/* HDMI */
card
->
dai_link
[
i
].
codec_of_node
=
codec_dai_node
[
dai_index
];
card
->
dai_link
[
i
].
cpu_of_node
=
cpu_dai_node
[
dai_index
];
card
->
dai_link
[
i
].
platform_of_node
=
cpu_dai_node
[
dai_index
];
}
if
(
num_codecs
>
1
)
{
/* HDMI DAI link (I2S1) */
i
=
card
->
num_links
-
1
;
ret
=
of_parse_phandle_with_fixed_args
(
dev
->
of_node
,
"audio-codec"
,
0
,
1
,
&
args
);
if
(
ret
)
{
dev_err
(
dev
,
"audio-codec property parse error
\n
"
);
goto
dai_node_put
;
}
ret
=
snd_soc_get_dai_name
(
&
args
,
&
card
->
dai_link
[
i
].
codec_dai_name
);
if
(
ret
)
{
dev_err
(
dev
,
"Unable to get codec_dai_name
\n
"
);
goto
dai_node_put
;
}
}
ret
=
devm_snd_soc_register_component
(
dev
,
&
tm2_component
,
tm2_ext_dai
,
ARRAY_SIZE
(
tm2_ext_dai
));
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Failed to register component: %d
\n
"
,
ret
);
goto
codec_
dai_node_put
;
goto
dai_node_put
;
}
ret
=
devm_snd_soc_register_card
(
dev
,
card
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Failed to register card: %d
\n
"
,
ret
);
goto
codec_dai_node_put
;
goto
dai_node_put
;
}
dai_node_put:
for
(
i
=
0
;
i
<
num_codecs
;
i
++
)
{
of_node_put
(
codec_dai_node
[
i
]);
of_node_put
(
cpu_dai_node
[
i
]);
}
codec_dai_node_put:
of_node_put
(
codec_dai_node
);
cpu_dai_node_put:
of_node_put
(
cpu_dai_node
);
amp_node_put:
of_node_put
(
card
->
aux_dev
[
0
].
codec_of_node
);
return
ret
;
}
...
...
sound/soc/soc-core.c
View file @
848272e9
...
...
@@ -4356,6 +4356,26 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
}
EXPORT_SYMBOL_GPL
(
snd_soc_of_get_dai_name
);
/*
* snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
* @dai_link: DAI link
*
* Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs().
*/
void
snd_soc_of_put_dai_link_codecs
(
struct
snd_soc_dai_link
*
dai_link
)
{
struct
snd_soc_dai_link_component
*
component
=
dai_link
->
codecs
;
int
index
;
for
(
index
=
0
;
index
<
dai_link
->
num_codecs
;
index
++
,
component
++
)
{
if
(
!
component
->
of_node
)
break
;
of_node_put
(
component
->
of_node
);
component
->
of_node
=
NULL
;
}
}
EXPORT_SYMBOL_GPL
(
snd_soc_of_put_dai_link_codecs
);
/*
* snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree
* @dev: Card device
...
...
@@ -4365,7 +4385,8 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
* Builds an array of CODEC DAI components from the DAI link property
* 'sound-dai'.
* The array is set in the DAI link and the number of DAIs is set accordingly.
* The device nodes in the array (of_node) must be dereferenced by the caller.
* The device nodes in the array (of_node) must be dereferenced by calling
* snd_soc_of_put_dai_link_codecs() on @dai_link.
*
* Returns 0 for success
*/
...
...
@@ -4413,14 +4434,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
}
return
0
;
err:
for
(
index
=
0
,
component
=
dai_link
->
codecs
;
index
<
dai_link
->
num_codecs
;
index
++
,
component
++
)
{
if
(
!
component
->
of_node
)
break
;
of_node_put
(
component
->
of_node
);
component
->
of_node
=
NULL
;
}
snd_soc_of_put_dai_link_codecs
(
dai_link
);
dai_link
->
codecs
=
NULL
;
dai_link
->
num_codecs
=
0
;
return
ret
;
...
...
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