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
nexedi
linux
Commits
6bf4cd28
Commit
6bf4cd28
authored
Jul 03, 2017
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
parents
2016d5ed
82885913
Changes
28
Show whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
1960 additions
and
382 deletions
+1960
-382
Documentation/devicetree/bindings/sound/audio-graph-card.txt
Documentation/devicetree/bindings/sound/audio-graph-card.txt
+124
-0
Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
...tation/devicetree/bindings/sound/audio-graph-scu-card.txt
+117
-0
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+22
-15
Documentation/devicetree/bindings/sound/simple-scu-card.txt
Documentation/devicetree/bindings/sound/simple-scu-card.txt
+25
-42
drivers/of/base.c
drivers/of/base.c
+52
-10
include/linux/of_graph.h
include/linux/of_graph.h
+21
-0
include/sound/simple_card_utils.h
include/sound/simple_card_utils.h
+16
-3
include/sound/soc.h
include/sound/soc.h
+3
-0
sound/soc/generic/Kconfig
sound/soc/generic/Kconfig
+17
-0
sound/soc/generic/Makefile
sound/soc/generic/Makefile
+4
-0
sound/soc/generic/audio-graph-card.c
sound/soc/generic/audio-graph-card.c
+301
-0
sound/soc/generic/audio-graph-scu-card.c
sound/soc/generic/audio-graph-scu-card.c
+411
-0
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card-utils.c
+88
-8
sound/soc/generic/simple-card.c
sound/soc/generic/simple-card.c
+4
-11
sound/soc/generic/simple-scu-card.c
sound/soc/generic/simple-scu-card.c
+7
-12
sound/soc/sh/Kconfig
sound/soc/sh/Kconfig
+1
-1
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/adg.c
+30
-31
sound/soc/sh/rcar/cmd.c
sound/soc/sh/rcar/cmd.c
+5
-2
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/core.c
+348
-146
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/ctu.c
+6
-0
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dma.c
+26
-6
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/dvc.c
+9
-3
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/gen.c
+2
-0
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/rsnd.h
+47
-21
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/src.c
+2
-18
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssi.c
+191
-50
sound/soc/sh/rcar/ssiu.c
sound/soc/sh/rcar/ssiu.c
+37
-0
sound/soc/soc-core.c
sound/soc/soc-core.c
+44
-3
No files found.
Documentation/devicetree/bindings/sound/audio-graph-card.txt
0 → 100644
View file @
6bf4cd28
Audio Graph Card:
Audio Graph Card specifies audio DAI connections of SoC <-> codec.
It is based on common bindings for device graphs.
see ${LINUX}/Documentation/devicetree/bindings/graph.txt
Basically, Audio Graph Card property is same as Simple Card.
see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
Below are same as Simple-Card.
- label
- dai-format
- frame-master
- bitclock-master
- bitclock-inversion
- frame-inversion
- dai-tdm-slot-num
- dai-tdm-slot-width
- clocks / system-clock-frequency
Required properties:
- compatible : "audio-graph-card";
- dais : list of CPU DAI port{s}
Example: Single DAI case
sound_card {
compatible = "audio-graph-card";
dais = <&cpu_port>;
};
dai-controller {
...
cpu_port: port {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
dai-format = "left_j";
...
};
};
};
audio-codec {
...
port {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
Example: Multi DAI case
sound-card {
compatible = "audio-graph-card";
label = "sound-card";
dais = <&cpu_port0
&cpu_port1
&cpu_port2>;
};
audio-codec@0 {
...
port {
codec0_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint0>;
};
};
};
audio-codec@1 {
...
port {
codec1_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint1>;
};
};
};
audio-codec@2 {
...
port {
codec2_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint2>;
};
};
};
dai-controller {
...
ports {
cpu_port0: port@0 {
cpu_endpoint0: endpoint {
remote-endpoint = <&codec0_endpoint>;
dai-format = "left_j";
...
};
};
cpu_port1: port@1 {
cpu_endpoint1: endpoint {
remote-endpoint = <&codec1_endpoint>;
dai-format = "i2s";
...
};
};
cpu_port2: port@2 {
cpu_endpoint2: endpoint {
remote-endpoint = <&codec2_endpoint>;
dai-format = "i2s";
...
};
};
};
};
Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
0 → 100644
View file @
6bf4cd28
Audio-Graph-SCU-Card:
Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM".
It is based on common bindings for device graphs.
see ${LINUX}/Documentation/devicetree/bindings/graph.txt
Basically, Audio-Graph-SCU-Card property is same as
Simple-Card / Simple-SCU-Card / Audio-Graph-Card.
see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
${LINUX}/Documentation/devicetree/bindings/sound/simple-scu-card.txt
${LINUX}/Documentation/devicetree/bindings/sound/audio-graph-card.txt
Below are same as Simple-Card / Audio-Graph-Card.
- label
- dai-format
- frame-master
- bitclock-master
- bitclock-inversion
- frame-inversion
- dai-tdm-slot-num
- dai-tdm-slot-width
- clocks / system-clock-frequency
Below are same as Simple-SCU-Card.
- convert-rate
- convert-channels
- prefix
- routing
Required properties:
- compatible : "audio-graph-scu-card";
- dais : list of CPU DAI port{s}
Example 1. Sampling Rate Conversion
sound_card {
compatible = "audio-graph-scu-card";
label = "sound-card";
prefix = "codec";
routing = "codec Playback", "DAI0 Playback",
"codec Playback", "DAI1 Playback";
convert-rate = <48000>;
dais = <&cpu_port>;
};
audio-codec {
...
port {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
dai-controller {
...
cpu_port: port {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
dai-format = "left_j";
...
};
};
};
Example 2. 2 CPU 1 Codec (Mixing)
sound_card {
compatible = "audio-graph-scu-card";
label = "sound-card";
prefix = "codec";
routing = "codec Playback", "DAI0 Playback",
"codec Playback", "DAI1 Playback";
convert-rate = <48000>;
dais = <&cpu_port0
&cpu_port1>;
};
audio-codec {
...
port {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint0>;
};
};
};
dai-controller {
...
ports {
cpu_port0: port {
cpu_endpoint0: endpoint {
remote-endpoint = <&codec_endpoint>;
dai-format = "left_j";
...
};
};
cpu_port1: port {
cpu_endpoint1: endpoint {
dai-format = "left_j";
...
};
};
};
};
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
View file @
6bf4cd28
...
...
@@ -83,11 +83,11 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
** Asynchronous mode
------------------
You need to use "
renesas,rsrc
-card" sound card for it.
You need to use "
simple-scu-audio
-card" sound card for it.
example)
sound {
compatible = "
renesas,rsrc
-card";
compatible = "
simple-scu-audio
-card";
...
/*
* SRC Asynchronous mode setting
...
...
@@ -97,12 +97,12 @@ example)
* Inputed 48kHz data will be converted to
* system specified Hz
*/
convert-rate = <48000>;
simple-audio-card,
convert-rate = <48000>;
...
cpu {
simple-audio-card,
cpu {
sound-dai = <&rcar_sound>;
};
codec {
simple-audio-card,
codec {
...
};
};
...
...
@@ -141,23 +141,23 @@ For more detail information, see below
${LINUX}/sound/soc/sh/rcar/ctu.c
- comment of header
You need to use "
renesas,rsrc
-card" sound card for it.
You need to use "
simple-scu-audio
-card" sound card for it.
example)
sound {
compatible = "
renesas,rsrc
-card";
compatible = "
simple-scu-audio
-card";
...
/*
* CTU setting
* All input data will be converted to 2ch
* as output data
*/
convert-channels = <2>;
simple-audio-card,
convert-channels = <2>;
...
cpu {
simple-audio-card,
cpu {
sound-dai = <&rcar_sound>;
};
codec {
simple-audio-card,
codec {
...
};
};
...
...
@@ -190,22 +190,22 @@ and these sounds will be merged by MIX.
aplay -D plughw:0,0 xxxx.wav &
aplay -D plughw:0,1 yyyy.wav
You need to use "
renesas,rsrc
-card" sound card for it.
You need to use "
simple-scu-audio
-card" sound card for it.
Ex)
[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
|
[MEM] -> [SRC2] -> [CTU03] -+
sound {
compatible = "
renesas,rsrc
-card";
compatible = "
simple-scu-audio
-card";
...
cpu@0 {
simple-audio-card,
cpu@0 {
sound-dai = <&rcar_sound 0>;
};
cpu@1 {
simple-audio-card,
cpu@1 {
sound-dai = <&rcar_sound 1>;
};
codec {
simple-audio-card,
codec {
...
};
};
...
...
@@ -368,6 +368,10 @@ Required properties:
see below for detail.
- #sound-dai-cells : it must be 0 if your system is using single DAI
it must be 1 if your system is using multi DAI
- clocks : References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks.
- clock-names : List of necessary clock names.
"ssi-all", "ssi.X", "src.X", "mix.X", "ctu.X",
"dvc.X", "clk_a", "clk_b", "clk_c", "clk_i"
Optional properties:
- #clock-cells : it must be 0 if your system has audio_clkout
...
...
@@ -375,6 +379,9 @@ Optional properties:
- clock-frequency : for all audio_clkout0/1/2/3
- clkout-lr-asynchronous : boolean property. it indicates that audio_clkoutn
is asynchronizes with lr-clock.
- resets : References to SSI resets.
- reset-names : List of valid reset names.
"ssi-all", "ssi.X"
SSI subnode properties:
- interrupts : Should contain SSI interrupt for PIO transfer
...
...
Documentation/devicetree/bindings/sound/simple-scu-card.txt
View file @
6bf4cd28
ASoC
s
imple SCU Sound Card
ASoC
S
imple SCU Sound Card
Simple-Card specifies audio DAI connections of SoC <-> codec.
Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM".
For example, you can use this driver if you want to exchange sampling rate convert,
Mixing, etc...
Required properties:
- compatible : "simple-scu-audio-card"
"renesas,rsrc-card"
Optional properties:
- simple-audio-card,name : User specified audio sound card name, one string
property.
- simple-audio-card,cpu : CPU sub-node
- simple-audio-card,codec : CODEC sub-node
- simple-audio-card,name : see simple-audio-card.txt
- simple-audio-card,cpu : see simple-audio-card.txt
- simple-audio-card,codec : see simple-audio-card.txt
Optional subnode properties:
- simple-audio-card,format : CPU/CODEC common audio format.
"i2s", "right_j", "left_j" , "dsp_a"
"dsp_b", "ac97", "pdm", "msb", "lsb"
- simple-audio-card,frame-master : Indicates dai-link frame master.
phandle to a cpu or codec subnode.
- simple-audio-card,bitclock-master : Indicates dai-link bit clock master.
phandle to a cpu or codec subnode.
- simple-audio-card,bitclock-inversion : bool property. Add this if the
dai-link uses bit clock inversion.
- simple-audio-card,frame-inversion : bool property. Add this if the
dai-link uses frame clock inversion.
- simple-audio-card,format : see simple-audio-card.txt
- simple-audio-card,frame-master : see simple-audio-card.txt
- simple-audio-card,bitclock-master : see simple-audio-card.txt
- simple-audio-card,bitclock-inversion : see simple-audio-card.txt
- simple-audio-card,frame-inversion : see simple-audio-card.txt
- simple-audio-card,convert-rate : platform specified sampling rate convert
- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch)
- simple-audio-card,prefix : see
audio-
routing
- simple-audio-card,prefix : see routing
- simple-audio-card,routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources.
...
...
@@ -38,32 +32,23 @@ Optional subnode properties:
Required CPU/CODEC subnodes properties:
- sound-dai :
phandle and port of CPU/CODEC
- sound-dai :
see simple-audio-card.txt
Optional CPU/CODEC subnodes properties:
- clocks / system-clock-frequency : specify subnode's clock if needed.
it can be specified via "clocks" if system has
clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock)
If a clock is specified, it is
enabled with clk_prepare_enable()
in dai startup() and disabled with
clk_disable_unprepare() in dai
shutdown().
- clocks / system-clock-frequency : see simple-audio-card.txt
Example 1. Sampling Rate Co
vert
Example 1. Sampling Rate Co
nversion
sound {
compatible = "simple-scu-audio-card";
simple-audio-card,name = "rsnd-ak4643";
simple-audio-card,format = "left_j";
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&sndcodec>;
simple-audio-card,frame-master = <&sndcodec>;
simple-audio-card,convert-rate = <48000>;
/* see audio_clk_a */
simple-audio-card,convert-rate = <48000>;
simple-audio-card,prefix = "ak4642";
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
...
...
@@ -79,20 +64,18 @@ sound {
};
};
Example 2. 2 CPU 1 Codec
Example 2. 2 CPU 1 Codec
(Mixing)
sound {
compatible = "renesas,rsrc-card";
card-name = "rsnd-ak4643";
format = "left_j";
bitclock-master = <&dpcmcpu>;
frame-master = <&dpcmcpu>;
compatible = "simple-scu-audio-card";
convert-rate = <48000>; /* see audio_clk_a */
simple-audio-card,name = "rsnd-ak4643";
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&dpcmcpu>;
simple-audio-card,frame-master = <&dpcmcpu>;
audio-
prefix = "ak4642";
audio-
routing = "ak4642 Playback", "DAI0 Playback",
simple-audio-card,
prefix = "ak4642";
simple-audio-card,
routing = "ak4642 Playback", "DAI0 Playback",
"ak4642 Playback", "DAI1 Playback";
dpcmcpu: cpu@0 {
...
...
drivers/of/base.c
View file @
6bf4cd28
...
...
@@ -1601,6 +1601,7 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_phandle_iterator_init
);
int
of_phandle_iterator_next
(
struct
of_phandle_iterator
*
it
)
{
...
...
@@ -1670,6 +1671,7 @@ int of_phandle_iterator_next(struct of_phandle_iterator *it)
return
-
EINVAL
;
}
EXPORT_SYMBOL_GPL
(
of_phandle_iterator_next
);
int
of_phandle_iterator_args
(
struct
of_phandle_iterator
*
it
,
uint32_t
*
args
,
...
...
@@ -2484,6 +2486,41 @@ struct device_node *of_graph_get_endpoint_by_regs(
}
EXPORT_SYMBOL
(
of_graph_get_endpoint_by_regs
);
/**
* of_graph_get_remote_endpoint() - get remote endpoint node
* @node: pointer to a local endpoint device_node
*
* Return: Remote endpoint node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_endpoint
(
const
struct
device_node
*
node
)
{
/* Get remote endpoint node. */
return
of_parse_phandle
(
node
,
"remote-endpoint"
,
0
);
}
EXPORT_SYMBOL
(
of_graph_get_remote_endpoint
);
/**
* of_graph_get_port_parent() - get port's parent node
* @node: pointer to a local endpoint device_node
*
* Return: device node associated with endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_port_parent
(
struct
device_node
*
node
)
{
unsigned
int
depth
;
/* Walk 3 levels up only if there is 'ports' node. */
for
(
depth
=
3
;
depth
&&
node
;
depth
--
)
{
node
=
of_get_next_parent
(
node
);
if
(
depth
==
2
&&
of_node_cmp
(
node
->
name
,
"ports"
))
break
;
}
return
node
;
}
EXPORT_SYMBOL
(
of_graph_get_port_parent
);
/**
* of_graph_get_remote_port_parent() - get remote port's parent node
* @node: pointer to a local endpoint device_node
...
...
@@ -2495,18 +2532,11 @@ struct device_node *of_graph_get_remote_port_parent(
const
struct
device_node
*
node
)
{
struct
device_node
*
np
;
unsigned
int
depth
;
/* Get remote endpoint node. */
np
=
of_
parse_phandle
(
node
,
"remote-endpoint"
,
0
);
np
=
of_
graph_get_remote_endpoint
(
node
);
/* Walk 3 levels up only if there is 'ports' node. */
for
(
depth
=
3
;
depth
&&
np
;
depth
--
)
{
np
=
of_get_next_parent
(
np
);
if
(
depth
==
2
&&
of_node_cmp
(
np
->
name
,
"ports"
))
break
;
}
return
np
;
return
of_graph_get_port_parent
(
np
);
}
EXPORT_SYMBOL
(
of_graph_get_remote_port_parent
);
...
...
@@ -2522,13 +2552,25 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node)
struct
device_node
*
np
;
/* Get remote endpoint node. */
np
=
of_
parse_phandle
(
node
,
"remote-endpoint"
,
0
);
np
=
of_
graph_get_remote_endpoint
(
node
);
if
(
!
np
)
return
NULL
;
return
of_get_next_parent
(
np
);
}
EXPORT_SYMBOL
(
of_graph_get_remote_port
);
int
of_graph_get_endpoint_count
(
const
struct
device_node
*
np
)
{
struct
device_node
*
endpoint
;
int
num
=
0
;
for_each_endpoint_of_node
(
np
,
endpoint
)
num
++
;
return
num
;
}
EXPORT_SYMBOL
(
of_graph_get_endpoint_count
);
/**
* of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
* @node: pointer to parent device_node containing graph port/endpoint
...
...
include/linux/of_graph.h
View file @
6bf4cd28
...
...
@@ -43,11 +43,15 @@ struct of_endpoint {
#ifdef CONFIG_OF
int
of_graph_parse_endpoint
(
const
struct
device_node
*
node
,
struct
of_endpoint
*
endpoint
);
int
of_graph_get_endpoint_count
(
const
struct
device_node
*
np
);
struct
device_node
*
of_graph_get_port_by_id
(
struct
device_node
*
node
,
u32
id
);
struct
device_node
*
of_graph_get_next_endpoint
(
const
struct
device_node
*
parent
,
struct
device_node
*
previous
);
struct
device_node
*
of_graph_get_endpoint_by_regs
(
const
struct
device_node
*
parent
,
int
port_reg
,
int
reg
);
struct
device_node
*
of_graph_get_remote_endpoint
(
const
struct
device_node
*
node
);
struct
device_node
*
of_graph_get_port_parent
(
struct
device_node
*
node
);
struct
device_node
*
of_graph_get_remote_port_parent
(
const
struct
device_node
*
node
);
struct
device_node
*
of_graph_get_remote_port
(
const
struct
device_node
*
node
);
...
...
@@ -61,6 +65,11 @@ static inline int of_graph_parse_endpoint(const struct device_node *node,
return
-
ENOSYS
;
}
static
inline
int
of_graph_get_endpoint_count
(
const
struct
device_node
*
np
)
{
return
0
;
}
static
inline
struct
device_node
*
of_graph_get_port_by_id
(
struct
device_node
*
node
,
u32
id
)
{
...
...
@@ -80,6 +89,18 @@ static inline struct device_node *of_graph_get_endpoint_by_regs(
return
NULL
;
}
static
inline
struct
device_node
*
of_graph_get_remote_endpoint
(
const
struct
device_node
*
node
)
{
return
NULL
;
}
static
inline
struct
device_node
*
of_graph_get_port_parent
(
struct
device_node
*
node
)
{
return
NULL
;
}
static
inline
struct
device_node
*
of_graph_get_remote_port_parent
(
const
struct
device_node
*
node
)
{
...
...
include/sound/simple_card_utils.h
View file @
6bf4cd28
...
...
@@ -35,13 +35,16 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
char
*
prefix
);
#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai)
asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
dai_link->cpu_dai_name)
#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai)
asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
dai_link->codec_dai_name)
int
asoc_simple_card_parse_clk
(
struct
device
*
dev
,
struct
device_node
*
node
,
struct
device_node
*
dai_of_node
,
struct
asoc_simple_dai
*
simple_dai
);
struct
asoc_simple_dai
*
simple_dai
,
const
char
*
name
);
#define asoc_simple_card_parse_cpu(node, dai_link, \
list_name, cells_name, is_single_link) \
...
...
@@ -60,6 +63,16 @@ int asoc_simple_card_parse_dai(struct device_node *node,
const
char
*
cells_name
,
int
*
is_single_links
);
#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \
asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \
&dai_link->cpu_dai_name)
#define asoc_simple_card_parse_graph_codec(ep, dai_link) \
asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \
&dai_link->codec_dai_name)
int
asoc_simple_card_parse_graph_dai
(
struct
device_node
*
ep
,
struct
device_node
**
endpoint_np
,
const
char
**
dai_name
);
int
asoc_simple_card_init_dai
(
struct
snd_soc_dai
*
dai
,
struct
asoc_simple_dai
*
simple_dai
);
...
...
include/sound/soc.h
View file @
6bf4cd28
...
...
@@ -803,6 +803,8 @@ struct snd_soc_component_driver {
int
(
*
of_xlate_dai_name
)(
struct
snd_soc_component
*
component
,
struct
of_phandle_args
*
args
,
const
char
**
dai_name
);
int
(
*
of_xlate_dai_id
)(
struct
snd_soc_component
*
comment
,
struct
device_node
*
endpoint
);
void
(
*
seq_notifier
)(
struct
snd_soc_component
*
,
enum
snd_soc_dapm_type
,
int
subseq
);
int
(
*
stream_event
)(
struct
snd_soc_component
*
,
int
event
);
...
...
@@ -1676,6 +1678,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
const
char
*
prefix
,
struct
device_node
**
bitclkmaster
,
struct
device_node
**
framemaster
);
int
snd_soc_get_dai_id
(
struct
device_node
*
ep
);
int
snd_soc_get_dai_name
(
struct
of_phandle_args
*
args
,
const
char
**
dai_name
);
int
snd_soc_of_get_dai_name
(
struct
device_node
*
of_node
,
...
...
sound/soc/generic/Kconfig
View file @
6bf4cd28
...
...
@@ -14,3 +14,20 @@ config SND_SIMPLE_SCU_CARD
help
This option enables generic simple SCU sound card support.
It supports DPCM of multi CPU single Codec system.
config SND_AUDIO_GRAPH_CARD
tristate "ASoC Audio Graph sound card support"
depends on OF
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple simple sound card support
with OF-graph DT bindings.
config SND_AUDIO_GRAPH_SCU_CARD
tristate "ASoC Audio Graph SCU sound card support"
depends on OF
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple SCU sound card support
with OF-graph DT bindings.
It supports DPCM of multi CPU single Codec ststem.
sound/soc/generic/Makefile
View file @
6bf4cd28
snd-soc-simple-card-utils-objs
:=
simple-card-utils.o
snd-soc-simple-card-objs
:=
simple-card.o
snd-soc-simple-scu-card-objs
:=
simple-scu-card.o
snd-soc-audio-graph-card-objs
:=
audio-graph-card.o
snd-soc-audio-graph-scu-card-objs
:=
audio-graph-scu-card.o
obj-$(CONFIG_SND_SIMPLE_CARD_UTILS)
+=
snd-soc-simple-card-utils.o
obj-$(CONFIG_SND_SIMPLE_CARD)
+=
snd-soc-simple-card.o
obj-$(CONFIG_SND_SIMPLE_SCU_CARD)
+=
snd-soc-simple-scu-card.o
obj-$(CONFIG_SND_AUDIO_GRAPH_CARD)
+=
snd-soc-audio-graph-card.o
obj-$(CONFIG_SND_AUDIO_GRAPH_SCU_CARD)
+=
snd-soc-audio-graph-scu-card.o
sound/soc/generic/audio-graph-card.c
0 → 100644
View file @
6bf4cd28
/*
* ASoC audio graph sound card support
*
* Copyright (C) 2016 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* based on ${LINUX}/sound/soc/generic/simple-card.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <sound/jack.h>
#include <sound/simple_card_utils.h>
struct
graph_card_data
{
struct
snd_soc_card
snd_card
;
struct
graph_dai_props
{
struct
asoc_simple_dai
cpu_dai
;
struct
asoc_simple_dai
codec_dai
;
}
*
dai_props
;
struct
snd_soc_dai_link
*
dai_link
;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
static
int
asoc_graph_card_startup
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
graph_card_data
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
graph_dai_props
*
dai_props
=
graph_priv_to_props
(
priv
,
rtd
->
num
);
int
ret
;
ret
=
clk_prepare_enable
(
dai_props
->
cpu_dai
.
clk
);
if
(
ret
)
return
ret
;
ret
=
clk_prepare_enable
(
dai_props
->
codec_dai
.
clk
);
if
(
ret
)
clk_disable_unprepare
(
dai_props
->
cpu_dai
.
clk
);
return
ret
;
}
static
void
asoc_graph_card_shutdown
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
graph_card_data
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
graph_dai_props
*
dai_props
=
graph_priv_to_props
(
priv
,
rtd
->
num
);
clk_disable_unprepare
(
dai_props
->
cpu_dai
.
clk
);
clk_disable_unprepare
(
dai_props
->
codec_dai
.
clk
);
}
static
struct
snd_soc_ops
asoc_graph_card_ops
=
{
.
startup
=
asoc_graph_card_startup
,
.
shutdown
=
asoc_graph_card_shutdown
,
};
static
int
asoc_graph_card_dai_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
graph_card_data
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
snd_soc_dai
*
codec
=
rtd
->
codec_dai
;
struct
snd_soc_dai
*
cpu
=
rtd
->
cpu_dai
;
struct
graph_dai_props
*
dai_props
=
graph_priv_to_props
(
priv
,
rtd
->
num
);
int
ret
;
ret
=
asoc_simple_card_init_dai
(
codec
,
&
dai_props
->
codec_dai
);
if
(
ret
<
0
)
return
ret
;
ret
=
asoc_simple_card_init_dai
(
cpu
,
&
dai_props
->
cpu_dai
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
int
asoc_graph_card_dai_link_of
(
struct
device_node
*
cpu_port
,
struct
graph_card_data
*
priv
,
int
idx
)
{
struct
device
*
dev
=
graph_priv_to_dev
(
priv
);
struct
snd_soc_dai_link
*
dai_link
=
graph_priv_to_link
(
priv
,
idx
);
struct
graph_dai_props
*
dai_props
=
graph_priv_to_props
(
priv
,
idx
);
struct
asoc_simple_dai
*
cpu_dai
=
&
dai_props
->
cpu_dai
;
struct
asoc_simple_dai
*
codec_dai
=
&
dai_props
->
codec_dai
;
struct
snd_soc_card
*
card
=
graph_priv_to_card
(
priv
);
struct
device_node
*
cpu_ep
=
of_get_next_child
(
cpu_port
,
NULL
);
struct
device_node
*
codec_ep
=
of_graph_get_remote_endpoint
(
cpu_ep
);
struct
device_node
*
rcpu_ep
=
of_graph_get_remote_endpoint
(
codec_ep
);
int
ret
;
if
(
rcpu_ep
!=
cpu_ep
)
{
dev_err
(
dev
,
"remote-endpoint mismatch (%s/%s/%s)
\n
"
,
cpu_ep
->
name
,
codec_ep
->
name
,
rcpu_ep
->
name
);
ret
=
-
EINVAL
;
goto
dai_link_of_err
;
}
ret
=
asoc_simple_card_parse_daifmt
(
dev
,
cpu_ep
,
codec_ep
,
NULL
,
&
dai_link
->
dai_fmt
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
/*
* we need to consider "mclk-fs" around here
* see simple-card
*/
ret
=
asoc_simple_card_parse_graph_cpu
(
cpu_ep
,
dai_link
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
ret
=
asoc_simple_card_parse_graph_codec
(
codec_ep
,
dai_link
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
ret
=
snd_soc_of_parse_tdm_slot
(
cpu_ep
,
&
cpu_dai
->
tx_slot_mask
,
&
cpu_dai
->
rx_slot_mask
,
&
cpu_dai
->
slots
,
&
cpu_dai
->
slot_width
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
ret
=
snd_soc_of_parse_tdm_slot
(
codec_ep
,
&
codec_dai
->
tx_slot_mask
,
&
codec_dai
->
rx_slot_mask
,
&
codec_dai
->
slots
,
&
codec_dai
->
slot_width
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
ret
=
asoc_simple_card_parse_clk_cpu
(
dev
,
cpu_ep
,
dai_link
,
cpu_dai
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
ret
=
asoc_simple_card_parse_clk_codec
(
dev
,
codec_ep
,
dai_link
,
codec_dai
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
ret
=
asoc_simple_card_canonicalize_dailink
(
dai_link
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
ret
=
asoc_simple_card_set_dailink_name
(
dev
,
dai_link
,
"%s-%s"
,
dai_link
->
cpu_dai_name
,
dai_link
->
codec_dai_name
);
if
(
ret
<
0
)
goto
dai_link_of_err
;
dai_link
->
ops
=
&
asoc_graph_card_ops
;
dai_link
->
init
=
asoc_graph_card_dai_init
;
asoc_simple_card_canonicalize_cpu
(
dai_link
,
card
->
num_links
==
1
);
dai_link_of_err:
of_node_put
(
cpu_ep
);
of_node_put
(
rcpu_ep
);
of_node_put
(
codec_ep
);
return
ret
;
}
static
int
asoc_graph_card_parse_of
(
struct
graph_card_data
*
priv
)
{
struct
of_phandle_iterator
it
;
struct
device
*
dev
=
graph_priv_to_dev
(
priv
);
struct
snd_soc_card
*
card
=
graph_priv_to_card
(
priv
);
struct
device_node
*
node
=
dev
->
of_node
;
int
rc
,
idx
=
0
;
int
ret
;
/*
* we need to consider "widgets", "routing", "mclk-fs" around here
* see simple-card
*/
of_for_each_phandle
(
&
it
,
rc
,
node
,
"dais"
,
NULL
,
0
)
{
ret
=
asoc_graph_card_dai_link_of
(
it
.
node
,
priv
,
idx
++
);
of_node_put
(
it
.
node
);
if
(
ret
<
0
)
return
ret
;
}
return
asoc_simple_card_parse_card_name
(
card
,
NULL
);
}
static
int
asoc_graph_get_dais_count
(
struct
device
*
dev
)
{
struct
of_phandle_iterator
it
;
struct
device_node
*
node
=
dev
->
of_node
;
int
count
=
0
;
int
rc
;
of_for_each_phandle
(
&
it
,
rc
,
node
,
"dais"
,
NULL
,
0
)
{
count
++
;
of_node_put
(
it
.
node
);
}
return
count
;
}
static
int
asoc_graph_card_probe
(
struct
platform_device
*
pdev
)
{
struct
graph_card_data
*
priv
;
struct
snd_soc_dai_link
*
dai_link
;
struct
graph_dai_props
*
dai_props
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
snd_soc_card
*
card
;
int
num
,
ret
;
/* Allocate the private data and the DAI link array */
priv
=
devm_kzalloc
(
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
num
=
asoc_graph_get_dais_count
(
dev
);
if
(
num
==
0
)
return
-
EINVAL
;
dai_props
=
devm_kzalloc
(
dev
,
sizeof
(
*
dai_props
)
*
num
,
GFP_KERNEL
);
dai_link
=
devm_kzalloc
(
dev
,
sizeof
(
*
dai_link
)
*
num
,
GFP_KERNEL
);
if
(
!
dai_props
||
!
dai_link
)
return
-
ENOMEM
;
priv
->
dai_props
=
dai_props
;
priv
->
dai_link
=
dai_link
;
/* Init snd_soc_card */
card
=
graph_priv_to_card
(
priv
);
card
->
owner
=
THIS_MODULE
;
card
->
dev
=
dev
;
card
->
dai_link
=
dai_link
;
card
->
num_links
=
num
;
ret
=
asoc_graph_card_parse_of
(
priv
);
if
(
ret
<
0
)
{
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
dev
,
"parse error %d
\n
"
,
ret
);
goto
err
;
}
snd_soc_card_set_drvdata
(
card
,
priv
);
ret
=
devm_snd_soc_register_card
(
dev
,
card
);
if
(
ret
<
0
)
goto
err
;
return
0
;
err:
asoc_simple_card_clean_reference
(
card
);
return
ret
;
}
static
int
asoc_graph_card_remove
(
struct
platform_device
*
pdev
)
{
struct
snd_soc_card
*
card
=
platform_get_drvdata
(
pdev
);
return
asoc_simple_card_clean_reference
(
card
);
}
static
const
struct
of_device_id
asoc_graph_of_match
[]
=
{
{
.
compatible
=
"audio-graph-card"
,
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
asoc_graph_of_match
);
static
struct
platform_driver
asoc_graph_card
=
{
.
driver
=
{
.
name
=
"asoc-audio-graph-card"
,
.
of_match_table
=
asoc_graph_of_match
,
},
.
probe
=
asoc_graph_card_probe
,
.
remove
=
asoc_graph_card_remove
,
};
module_platform_driver
(
asoc_graph_card
);
MODULE_ALIAS
(
"platform:asoc-audio-graph-card"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_DESCRIPTION
(
"ASoC Audio Graph Sound Card"
);
MODULE_AUTHOR
(
"Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"
);
sound/soc/generic/audio-graph-scu-card.c
0 → 100644
View file @
6bf4cd28
/*
* ASoC audio graph SCU sound card support
*
* Copyright (C) 2017 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* based on
* ${LINUX}/sound/soc/generic/simple-scu-card.c
* ${LINUX}/sound/soc/generic/audio-graph-card.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <sound/jack.h>
#include <sound/simple_card_utils.h>
struct
graph_card_data
{
struct
snd_soc_card
snd_card
;
struct
snd_soc_codec_conf
codec_conf
;
struct
asoc_simple_dai
*
dai_props
;
struct
snd_soc_dai_link
*
dai_link
;
u32
convert_rate
;
u32
convert_channels
;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
static
int
asoc_graph_card_startup
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
graph_card_data
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
asoc_simple_dai
*
dai_props
=
graph_priv_to_props
(
priv
,
rtd
->
num
);
return
clk_prepare_enable
(
dai_props
->
clk
);
}
static
void
asoc_graph_card_shutdown
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
graph_card_data
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
asoc_simple_dai
*
dai_props
=
graph_priv_to_props
(
priv
,
rtd
->
num
);
clk_disable_unprepare
(
dai_props
->
clk
);
}
static
struct
snd_soc_ops
asoc_graph_card_ops
=
{
.
startup
=
asoc_graph_card_startup
,
.
shutdown
=
asoc_graph_card_shutdown
,
};
static
int
asoc_graph_card_dai_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
graph_card_data
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
snd_soc_dai
*
dai
;
struct
snd_soc_dai_link
*
dai_link
;
struct
asoc_simple_dai
*
dai_props
;
int
num
=
rtd
->
num
;
dai_link
=
graph_priv_to_link
(
priv
,
num
);
dai_props
=
graph_priv_to_props
(
priv
,
num
);
dai
=
dai_link
->
dynamic
?
rtd
->
cpu_dai
:
rtd
->
codec_dai
;
return
asoc_simple_card_init_dai
(
dai
,
dai_props
);
}
static
int
asoc_graph_card_be_hw_params_fixup
(
struct
snd_soc_pcm_runtime
*
rtd
,
struct
snd_pcm_hw_params
*
params
)
{
struct
graph_card_data
*
priv
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
snd_interval
*
rate
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_RATE
);
struct
snd_interval
*
channels
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_CHANNELS
);
if
(
priv
->
convert_rate
)
rate
->
min
=
rate
->
max
=
priv
->
convert_rate
;
if
(
priv
->
convert_channels
)
channels
->
min
=
channels
->
max
=
priv
->
convert_channels
;
return
0
;
}
static
int
asoc_graph_card_dai_link_of
(
struct
device_node
*
ep
,
struct
graph_card_data
*
priv
,
unsigned
int
daifmt
,
int
idx
,
int
is_fe
)
{
struct
device
*
dev
=
graph_priv_to_dev
(
priv
);
struct
snd_soc_dai_link
*
dai_link
=
graph_priv_to_link
(
priv
,
idx
);
struct
asoc_simple_dai
*
dai_props
=
graph_priv_to_props
(
priv
,
idx
);
struct
snd_soc_card
*
card
=
graph_priv_to_card
(
priv
);
int
ret
;
if
(
is_fe
)
{
/* BE is dummy */
dai_link
->
codec_of_node
=
NULL
;
dai_link
->
codec_dai_name
=
"snd-soc-dummy-dai"
;
dai_link
->
codec_name
=
"snd-soc-dummy"
;
/* FE settings */
dai_link
->
dynamic
=
1
;
dai_link
->
dpcm_merged_format
=
1
;
ret
=
asoc_simple_card_parse_graph_cpu
(
ep
,
dai_link
);
if
(
ret
)
return
ret
;
ret
=
asoc_simple_card_parse_clk_cpu
(
dev
,
ep
,
dai_link
,
dai_props
);
if
(
ret
<
0
)
return
ret
;
ret
=
asoc_simple_card_set_dailink_name
(
dev
,
dai_link
,
"fe.%s"
,
dai_link
->
cpu_dai_name
);
if
(
ret
<
0
)
return
ret
;
/* card->num_links includes Codec */
asoc_simple_card_canonicalize_cpu
(
dai_link
,
(
card
->
num_links
-
1
)
==
1
);
}
else
{
/* FE is dummy */
dai_link
->
cpu_of_node
=
NULL
;
dai_link
->
cpu_dai_name
=
"snd-soc-dummy-dai"
;
dai_link
->
cpu_name
=
"snd-soc-dummy"
;
/* BE settings */
dai_link
->
no_pcm
=
1
;
dai_link
->
be_hw_params_fixup
=
asoc_graph_card_be_hw_params_fixup
;
ret
=
asoc_simple_card_parse_graph_codec
(
ep
,
dai_link
);
if
(
ret
<
0
)
return
ret
;
ret
=
asoc_simple_card_parse_clk_codec
(
dev
,
ep
,
dai_link
,
dai_props
);
if
(
ret
<
0
)
return
ret
;
ret
=
asoc_simple_card_set_dailink_name
(
dev
,
dai_link
,
"be.%s"
,
dai_link
->
codec_dai_name
);
if
(
ret
<
0
)
return
ret
;
snd_soc_of_parse_audio_prefix
(
card
,
&
priv
->
codec_conf
,
dai_link
->
codec_of_node
,
"prefix"
);
}
ret
=
snd_soc_of_parse_tdm_slot
(
ep
,
&
dai_props
->
tx_slot_mask
,
&
dai_props
->
rx_slot_mask
,
&
dai_props
->
slots
,
&
dai_props
->
slot_width
);
if
(
ret
)
return
ret
;
ret
=
asoc_simple_card_canonicalize_dailink
(
dai_link
);
if
(
ret
<
0
)
return
ret
;
dai_link
->
dai_fmt
=
daifmt
;
dai_link
->
dpcm_playback
=
1
;
dai_link
->
dpcm_capture
=
1
;
dai_link
->
ops
=
&
asoc_graph_card_ops
;
dai_link
->
init
=
asoc_graph_card_dai_init
;
return
0
;
}
static
int
asoc_graph_card_parse_of
(
struct
graph_card_data
*
priv
)
{
struct
of_phandle_iterator
it
;
struct
device
*
dev
=
graph_priv_to_dev
(
priv
);
struct
snd_soc_card
*
card
=
graph_priv_to_card
(
priv
);
struct
device_node
*
node
=
dev
->
of_node
;
struct
device_node
*
cpu_port
;
struct
device_node
*
cpu_ep
;
struct
device_node
*
codec_ep
;
struct
device_node
*
rcpu_ep
;
unsigned
int
daifmt
=
0
;
int
dai_idx
,
ret
;
int
rc
,
codec
;
if
(
!
node
)
return
-
EINVAL
;
/*
* we need to consider "widgets", "mclk-fs" around here
* see simple-card
*/
ret
=
snd_soc_of_parse_audio_routing
(
card
,
"routing"
);
if
(
ret
)
return
ret
;
/* sampling rate convert */
of_property_read_u32
(
node
,
"convert-rate"
,
&
priv
->
convert_rate
);
/* channels transfer */
of_property_read_u32
(
node
,
"convert-channels"
,
&
priv
->
convert_channels
);
/*
* it supports multi CPU, single CODEC only here
* see asoc_graph_get_dais_count
*/
/* find 1st codec */
of_for_each_phandle
(
&
it
,
rc
,
node
,
"dais"
,
NULL
,
0
)
{
cpu_port
=
it
.
node
;
cpu_ep
=
of_get_next_child
(
cpu_port
,
NULL
);
codec_ep
=
of_graph_get_remote_endpoint
(
cpu_ep
);
rcpu_ep
=
of_graph_get_remote_endpoint
(
codec_ep
);
of_node_put
(
cpu_port
);
of_node_put
(
cpu_ep
);
of_node_put
(
codec_ep
);
of_node_put
(
rcpu_ep
);
if
(
!
codec_ep
)
continue
;
if
(
rcpu_ep
!=
cpu_ep
)
{
dev_err
(
dev
,
"remote-endpoint missmatch (%s/%s/%s)
\n
"
,
cpu_ep
->
name
,
codec_ep
->
name
,
rcpu_ep
->
name
);
ret
=
-
EINVAL
;
goto
parse_of_err
;
}
ret
=
asoc_simple_card_parse_daifmt
(
dev
,
cpu_ep
,
codec_ep
,
NULL
,
&
daifmt
);
if
(
ret
<
0
)
goto
parse_of_err
;
}
dai_idx
=
0
;
for
(
codec
=
0
;
codec
<
2
;
codec
++
)
{
/*
* To listup valid sounds continuously,
* detect all CPU-dummy first, and
* detect all dummy-Codec second
*/
of_for_each_phandle
(
&
it
,
rc
,
node
,
"dais"
,
NULL
,
0
)
{
cpu_port
=
it
.
node
;
cpu_ep
=
of_get_next_child
(
cpu_port
,
NULL
);
codec_ep
=
of_graph_get_remote_endpoint
(
cpu_ep
);
of_node_put
(
cpu_port
);
of_node_put
(
cpu_ep
);
of_node_put
(
codec_ep
);
if
(
codec
)
{
if
(
!
codec_ep
)
continue
;
/* Back-End (= Codec) */
ret
=
asoc_graph_card_dai_link_of
(
codec_ep
,
priv
,
daifmt
,
dai_idx
++
,
0
);
if
(
ret
<
0
)
goto
parse_of_err
;
}
else
{
/* Front-End (= CPU) */
ret
=
asoc_graph_card_dai_link_of
(
cpu_ep
,
priv
,
daifmt
,
dai_idx
++
,
1
);
if
(
ret
<
0
)
goto
parse_of_err
;
}
}
}
ret
=
asoc_simple_card_parse_card_name
(
card
,
NULL
);
if
(
ret
)
goto
parse_of_err
;
dev_dbg
(
dev
,
"convert_rate %d
\n
"
,
priv
->
convert_rate
);
dev_dbg
(
dev
,
"convert_channels %d
\n
"
,
priv
->
convert_channels
);
ret
=
0
;
parse_of_err:
return
ret
;
}
static
int
asoc_graph_get_dais_count
(
struct
device
*
dev
)
{
struct
of_phandle_iterator
it
;
struct
device_node
*
node
=
dev
->
of_node
;
struct
device_node
*
cpu_port
;
struct
device_node
*
cpu_ep
;
struct
device_node
*
codec_ep
;
int
count
=
0
;
int
rc
;
of_for_each_phandle
(
&
it
,
rc
,
node
,
"dais"
,
NULL
,
0
)
{
cpu_port
=
it
.
node
;
cpu_ep
=
of_get_next_child
(
cpu_port
,
NULL
);
codec_ep
=
of_graph_get_remote_endpoint
(
cpu_ep
);
of_node_put
(
cpu_port
);
of_node_put
(
cpu_ep
);
of_node_put
(
codec_ep
);
if
(
cpu_ep
)
count
++
;
if
(
codec_ep
)
count
++
;
}
return
count
;
}
static
int
asoc_graph_card_probe
(
struct
platform_device
*
pdev
)
{
struct
graph_card_data
*
priv
;
struct
snd_soc_dai_link
*
dai_link
;
struct
asoc_simple_dai
*
dai_props
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
snd_soc_card
*
card
;
int
num
,
ret
;
/* Allocate the private data and the DAI link array */
priv
=
devm_kzalloc
(
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
num
=
asoc_graph_get_dais_count
(
dev
);
if
(
num
==
0
)
return
-
EINVAL
;
dai_props
=
devm_kzalloc
(
dev
,
sizeof
(
*
dai_props
)
*
num
,
GFP_KERNEL
);
dai_link
=
devm_kzalloc
(
dev
,
sizeof
(
*
dai_link
)
*
num
,
GFP_KERNEL
);
if
(
!
dai_props
||
!
dai_link
)
return
-
ENOMEM
;
priv
->
dai_props
=
dai_props
;
priv
->
dai_link
=
dai_link
;
/* Init snd_soc_card */
card
=
graph_priv_to_card
(
priv
);
card
->
owner
=
THIS_MODULE
;
card
->
dev
=
dev
;
card
->
dai_link
=
priv
->
dai_link
;
card
->
num_links
=
num
;
card
->
codec_conf
=
&
priv
->
codec_conf
;
card
->
num_configs
=
1
;
ret
=
asoc_graph_card_parse_of
(
priv
);
if
(
ret
<
0
)
{
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
dev
,
"parse error %d
\n
"
,
ret
);
goto
err
;
}
snd_soc_card_set_drvdata
(
card
,
priv
);
ret
=
devm_snd_soc_register_card
(
dev
,
card
);
if
(
ret
<
0
)
goto
err
;
return
0
;
err:
asoc_simple_card_clean_reference
(
card
);
return
ret
;
}
static
int
asoc_graph_card_remove
(
struct
platform_device
*
pdev
)
{
struct
snd_soc_card
*
card
=
platform_get_drvdata
(
pdev
);
return
asoc_simple_card_clean_reference
(
card
);
}
static
const
struct
of_device_id
asoc_graph_of_match
[]
=
{
{
.
compatible
=
"audio-graph-scu-card"
,
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
asoc_graph_of_match
);
static
struct
platform_driver
asoc_graph_card
=
{
.
driver
=
{
.
name
=
"asoc-audio-graph-scu-card"
,
.
of_match_table
=
asoc_graph_of_match
,
},
.
probe
=
asoc_graph_card_probe
,
.
remove
=
asoc_graph_card_remove
,
};
module_platform_driver
(
asoc_graph_card
);
MODULE_ALIAS
(
"platform:asoc-audio-graph-scu-card"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_DESCRIPTION
(
"ASoC Audio Graph SCU Sound Card"
);
MODULE_AUTHOR
(
"Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"
);
sound/soc/generic/simple-card-utils.c
View file @
6bf4cd28
...
...
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <sound/simple_card_utils.h>
int
asoc_simple_card_parse_daifmt
(
struct
device
*
dev
,
...
...
@@ -20,14 +21,13 @@ int asoc_simple_card_parse_daifmt(struct device *dev,
{
struct
device_node
*
bitclkmaster
=
NULL
;
struct
device_node
*
framemaster
=
NULL
;
int
prefix_len
=
prefix
?
strlen
(
prefix
)
:
0
;
unsigned
int
daifmt
;
daifmt
=
snd_soc_of_parse_daifmt
(
node
,
prefix
,
&
bitclkmaster
,
&
framemaster
);
daifmt
&=
~
SND_SOC_DAIFMT_MASTER_MASK
;
if
(
prefix_len
&&
!
bitclkmaster
&&
!
framemaster
)
{
if
(
!
bitclkmaster
&&
!
framemaster
)
{
/*
* No dai-link level and master setting was not found from
* sound node level, revert back to legacy DT parsing and
...
...
@@ -51,6 +51,8 @@ int asoc_simple_card_parse_daifmt(struct device *dev,
*
retfmt
=
daifmt
;
dev_dbg
(
dev
,
"format : %04x
\n
"
,
daifmt
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
asoc_simple_card_parse_daifmt
);
...
...
@@ -72,6 +74,8 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
dai_link
->
name
=
name
;
dai_link
->
stream_name
=
name
;
dev_dbg
(
dev
,
"name : %s
\n
"
,
name
);
}
return
ret
;
...
...
@@ -81,19 +85,27 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name);
int
asoc_simple_card_parse_card_name
(
struct
snd_soc_card
*
card
,
char
*
prefix
)
{
char
prop
[
128
];
int
ret
;
snprintf
(
prop
,
sizeof
(
prop
),
"%sname"
,
prefix
);
if
(
!
prefix
)
prefix
=
""
;
/* Parse the card name from DT */
ret
=
snd_soc_of_parse_card_name
(
card
,
"label"
);
if
(
ret
<
0
)
{
char
prop
[
128
];
snprintf
(
prop
,
sizeof
(
prop
),
"%sname"
,
prefix
);
ret
=
snd_soc_of_parse_card_name
(
card
,
prop
);
if
(
ret
<
0
)
return
ret
;
}
if
(
!
card
->
name
&&
card
->
dai_link
)
card
->
name
=
card
->
dai_link
->
name
;
dev_dbg
(
card
->
dev
,
"Card Name: %s
\n
"
,
card
->
name
?
card
->
name
:
""
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
asoc_simple_card_parse_card_name
);
...
...
@@ -101,7 +113,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
int
asoc_simple_card_parse_clk
(
struct
device
*
dev
,
struct
device_node
*
node
,
struct
device_node
*
dai_of_node
,
struct
asoc_simple_dai
*
simple_dai
)
struct
asoc_simple_dai
*
simple_dai
,
const
char
*
name
)
{
struct
clk
*
clk
;
u32
val
;
...
...
@@ -124,6 +137,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
simple_dai
->
sysclk
=
clk_get_rate
(
clk
);
}
dev_dbg
(
dev
,
"%s : sysclk = %d
\n
"
,
name
,
simple_dai
->
sysclk
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
asoc_simple_card_parse_clk
);
...
...
@@ -165,6 +180,71 @@ int asoc_simple_card_parse_dai(struct device_node *node,
}
EXPORT_SYMBOL_GPL
(
asoc_simple_card_parse_dai
);
static
int
asoc_simple_card_get_dai_id
(
struct
device_node
*
ep
)
{
struct
device_node
*
node
;
struct
device_node
*
endpoint
;
int
i
,
id
;
int
ret
;
ret
=
snd_soc_get_dai_id
(
ep
);
if
(
ret
!=
-
ENOTSUPP
)
return
ret
;
node
=
of_graph_get_port_parent
(
ep
);
/*
* Non HDMI sound case, counting port/endpoint on its DT
* is enough. Let's count it.
*/
i
=
0
;
id
=
-
1
;
for_each_endpoint_of_node
(
node
,
endpoint
)
{
if
(
endpoint
==
ep
)
id
=
i
;
i
++
;
}
if
(
id
<
0
)
return
-
ENODEV
;
return
id
;
}
int
asoc_simple_card_parse_graph_dai
(
struct
device_node
*
ep
,
struct
device_node
**
dai_of_node
,
const
char
**
dai_name
)
{
struct
device_node
*
node
;
struct
of_phandle_args
args
;
int
ret
;
if
(
!
ep
)
return
0
;
if
(
!
dai_name
)
return
0
;
/*
* of_graph_get_port_parent() will call
* of_node_put(). So, call of_node_get() here
*/
of_node_get
(
ep
);
node
=
of_graph_get_port_parent
(
ep
);
/* Get dai->name */
args
.
np
=
node
;
args
.
args
[
0
]
=
asoc_simple_card_get_dai_id
(
ep
);
args
.
args_count
=
(
of_graph_get_endpoint_count
(
node
)
>
1
);
ret
=
snd_soc_get_dai_name
(
&
args
,
dai_name
);
if
(
ret
<
0
)
return
ret
;
*
dai_of_node
=
node
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
asoc_simple_card_parse_graph_dai
);
int
asoc_simple_card_init_dai
(
struct
snd_soc_dai
*
dai
,
struct
asoc_simple_dai
*
simple_dai
)
{
...
...
sound/soc/generic/simple-card.c
View file @
6bf4cd28
...
...
@@ -301,15 +301,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
dai_link
->
ops
=
&
asoc_simple_card_ops
;
dai_link
->
init
=
asoc_simple_card_dai_init
;
dev_dbg
(
dev
,
"
\t
name : %s
\n
"
,
dai_link
->
stream_name
);
dev_dbg
(
dev
,
"
\t
format : %04x
\n
"
,
dai_link
->
dai_fmt
);
dev_dbg
(
dev
,
"
\t
cpu : %s / %d
\n
"
,
dai_link
->
cpu_dai_name
,
dai_props
->
cpu_dai
.
sysclk
);
dev_dbg
(
dev
,
"
\t
codec : %s / %d
\n
"
,
dai_link
->
codec_dai_name
,
dai_props
->
codec_dai
.
sysclk
);
asoc_simple_card_canonicalize_cpu
(
dai_link
,
single_cpu
);
dai_link_of_err:
...
...
@@ -497,8 +488,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata
(
card
,
priv
);
ret
=
devm_snd_soc_register_card
(
dev
,
card
);
if
(
ret
>=
0
)
return
ret
;
if
(
ret
<
0
)
goto
err
;
return
0
;
err:
asoc_simple_card_clean_reference
(
card
);
...
...
sound/soc/generic/simple-scu-card.c
View file @
6bf4cd28
...
...
@@ -189,21 +189,16 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link
->
ops
=
&
asoc_simple_card_ops
;
dai_link
->
init
=
asoc_simple_card_dai_init
;
dev_dbg
(
dev
,
"
\t
%s / %04x / %d
\n
"
,
dai_link
->
name
,
dai_link
->
dai_fmt
,
dai_props
->
sysclk
);
return
0
;
}
static
int
asoc_simple_card_parse_of
(
struct
device_node
*
node
,
struct
simple_card_data
*
priv
)
static
int
asoc_simple_card_parse_of
(
struct
simple_card_data
*
priv
)
{
struct
device
*
dev
=
simple_priv_to_dev
(
priv
);
struct
device_node
*
np
;
struct
snd_soc_card
*
card
=
simple_priv_to_card
(
priv
);
struct
device_node
*
node
=
dev
->
of_node
;
unsigned
int
daifmt
=
0
;
bool
is_fe
;
int
ret
,
i
;
...
...
@@ -246,8 +241,6 @@ static int asoc_simple_card_parse_of(struct device_node *node,
if
(
ret
<
0
)
return
ret
;
dev_dbg
(
dev
,
"New card: %s
\n
"
,
card
->
name
?
card
->
name
:
""
);
dev_dbg
(
dev
,
"convert_rate %d
\n
"
,
priv
->
convert_rate
);
dev_dbg
(
dev
,
"convert_channels %d
\n
"
,
priv
->
convert_channels
);
...
...
@@ -288,7 +281,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
card
->
codec_conf
=
&
priv
->
codec_conf
;
card
->
num_configs
=
1
;
ret
=
asoc_simple_card_parse_of
(
np
,
priv
);
ret
=
asoc_simple_card_parse_of
(
priv
);
if
(
ret
<
0
)
{
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
dev
,
"parse error %d
\n
"
,
ret
);
...
...
@@ -298,8 +291,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata
(
card
,
priv
);
ret
=
devm_snd_soc_register_card
(
dev
,
card
);
if
(
ret
>=
0
)
return
ret
;
if
(
ret
<
0
)
goto
err
;
return
0
;
err:
asoc_simple_card_clean_reference
(
card
);
...
...
sound/soc/sh/Kconfig
View file @
6bf4cd28
...
...
@@ -38,7 +38,7 @@ config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support"
depends on COMMON_CLK
depends on OF || COMPILE_TEST
select SND_SIMPLE_CARD
select SND_SIMPLE_CARD
_UTILS
select REGMAP_MMIO
help
This option enables R-Car SRU/SCU/SSIU/SSI sound support
...
...
sound/soc/sh/rcar/adg.c
View file @
6bf4cd28
...
...
@@ -308,23 +308,12 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
}
}
int
rsnd_adg_ssi_clk_stop
(
struct
rsnd_mod
*
ssi_mod
)
{
rsnd_adg_set_ssi_clk
(
ssi_mod
,
0
);
return
0
;
}
int
rsnd_adg_ssi_clk_try_start
(
struct
rsnd_mod
*
ssi_mod
,
unsigned
int
rate
)
int
rsnd_adg_clk_query
(
struct
rsnd_priv
*
priv
,
unsigned
int
rate
)
{
struct
rsnd_priv
*
priv
=
rsnd_mod_to_priv
(
ssi_mod
);
struct
rsnd_adg
*
adg
=
rsnd_priv_to_adg
(
priv
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
rsnd_mod
*
adg_mod
=
rsnd_mod_get
(
adg
);
struct
clk
*
clk
;
int
i
;
u32
data
;
u32
ckr
=
0
;
int
sel_table
[]
=
{
[
CLKA
]
=
0x1
,
[
CLKB
]
=
0x2
,
...
...
@@ -338,30 +327,42 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
* find suitable clock from
* AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
*/
data
=
0
;
for_each_rsnd_clk
(
clk
,
adg
,
i
)
{
if
(
rate
==
clk_get_rate
(
clk
))
{
data
=
sel_table
[
i
];
goto
found_clock
;
}
if
(
rate
==
clk_get_rate
(
clk
))
return
sel_table
[
i
];
}
/*
* find divided clock from BRGA/BRGB
*/
if
(
rate
==
adg
->
rbga_rate_for_441khz
)
{
data
=
0x10
;
goto
found_clock
;
}
if
(
rate
==
adg
->
rbga_rate_for_441khz
)
return
0x10
;
if
(
rate
==
adg
->
rbgb_rate_for_48khz
)
{
data
=
0x20
;
goto
found_clock
;
}
if
(
rate
==
adg
->
rbgb_rate_for_48khz
)
return
0x20
;
return
-
EIO
;
}
found_clock:
int
rsnd_adg_ssi_clk_stop
(
struct
rsnd_mod
*
ssi_mod
)
{
rsnd_adg_set_ssi_clk
(
ssi_mod
,
0
);
return
0
;
}
int
rsnd_adg_ssi_clk_try_start
(
struct
rsnd_mod
*
ssi_mod
,
unsigned
int
rate
)
{
struct
rsnd_priv
*
priv
=
rsnd_mod_to_priv
(
ssi_mod
);
struct
rsnd_adg
*
adg
=
rsnd_priv_to_adg
(
priv
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
rsnd_mod
*
adg_mod
=
rsnd_mod_get
(
adg
);
int
data
;
u32
ckr
=
0
;
data
=
rsnd_adg_clk_query
(
priv
,
rate
);
if
(
data
<
0
)
return
data
;
rsnd_adg_set_ssi_clk
(
ssi_mod
,
data
);
...
...
@@ -480,6 +481,9 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
if
(
req_rate
[
0
]
%
48000
==
0
)
adg
->
flags
=
AUDIO_OUT_48
;
if
(
of_get_property
(
np
,
"clkout-lr-asynchronous"
,
NULL
))
adg
->
flags
=
LRCLK_ASYNC
;
/*
* This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
* have 44.1kHz or 48kHz base clocks for now.
...
...
@@ -555,7 +559,6 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
clk
=
clk_register_fixed_rate
(
dev
,
clkout_name
[
i
],
parent_clk_name
,
0
,
req_rate
[
0
]);
adg
->
clkout
[
i
]
=
ERR_PTR
(
-
ENOENT
);
if
(
!
IS_ERR
(
clk
))
adg
->
clkout
[
i
]
=
clk
;
}
...
...
@@ -580,7 +583,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
{
struct
rsnd_adg
*
adg
;
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
device_node
*
np
=
dev
->
of_node
;
int
ret
;
adg
=
devm_kzalloc
(
dev
,
sizeof
(
*
adg
),
GFP_KERNEL
);
...
...
@@ -597,9 +599,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
rsnd_adg_get_clkin
(
priv
,
adg
);
rsnd_adg_get_clkout
(
priv
,
adg
);
if
(
of_get_property
(
np
,
"clkout-lr-asynchronous"
,
NULL
))
adg
->
flags
=
LRCLK_ASYNC
;
priv
->
adg
=
adg
;
rsnd_adg_clk_enable
(
priv
);
...
...
sound/soc/sh/rcar/cmd.c
View file @
6bf4cd28
...
...
@@ -31,7 +31,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
struct
rsnd_mod
*
mix
=
rsnd_io_to_mod_mix
(
io
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
u32
data
;
u32
path
[]
=
{
static
const
u32
path
[]
=
{
[
1
]
=
1
<<
0
,
[
5
]
=
1
<<
8
,
[
6
]
=
1
<<
12
,
...
...
@@ -71,7 +71,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
}
else
{
struct
rsnd_mod
*
src
=
rsnd_io_to_mod_src
(
io
);
u8
cmd_case
[]
=
{
static
const
u8
cmd_case
[]
=
{
[
0
]
=
0x3
,
[
1
]
=
0x3
,
[
2
]
=
0x4
,
...
...
@@ -82,6 +82,9 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
[
9
]
=
0x2
,
};
if
(
unlikely
(
!
src
))
return
-
EIO
;
data
=
path
[
rsnd_mod_id
(
src
)]
|
cmd_case
[
rsnd_mod_id
(
src
)]
<<
16
;
}
...
...
sound/soc/sh/rcar/core.c
View file @
6bf4cd28
...
...
@@ -203,27 +203,6 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
return
!!
io
->
substream
;
}
void
rsnd_set_slot
(
struct
rsnd_dai
*
rdai
,
int
slots
,
int
num
)
{
rdai
->
slots
=
slots
;
rdai
->
slots_num
=
num
;
}
int
rsnd_get_slot
(
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_dai
*
rdai
=
rsnd_io_to_rdai
(
io
);
return
rdai
->
slots
;
}
int
rsnd_get_slot_num
(
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_dai
*
rdai
=
rsnd_io_to_rdai
(
io
);
return
rdai
->
slots_num
;
}
int
rsnd_runtime_channel_original
(
struct
rsnd_dai_stream
*
io
)
{
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
...
...
@@ -248,13 +227,14 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
int
rsnd_runtime_channel_for_ssi
(
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_dai
*
rdai
=
rsnd_io_to_rdai
(
io
);
int
chan
=
rsnd_io_is_play
(
io
)
?
rsnd_runtime_channel_after_ctu
(
io
)
:
rsnd_runtime_channel_original
(
io
);
/* Use Multi SSI */
if
(
rsnd_runtime_is_ssi_multi
(
io
))
chan
/=
rsnd_
get_slot_num
(
io
);
chan
/=
rsnd_
rdai_ssi_lane_get
(
rdai
);
/* TDM Extend Mode needs 8ch */
if
(
chan
==
6
)
...
...
@@ -265,12 +245,13 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io)
int
rsnd_runtime_is_ssi_multi
(
struct
rsnd_dai_stream
*
io
)
{
int
slots
=
rsnd_get_slot_num
(
io
);
struct
rsnd_dai
*
rdai
=
rsnd_io_to_rdai
(
io
);
int
lane
=
rsnd_rdai_ssi_lane_get
(
rdai
);
int
chan
=
rsnd_io_is_play
(
io
)
?
rsnd_runtime_channel_after_ctu
(
io
)
:
rsnd_runtime_channel_original
(
io
);
return
(
chan
>
=
6
)
&&
(
slots
>
1
);
return
(
chan
>
2
)
&&
(
lane
>
1
);
}
int
rsnd_runtime_is_ssi_tdm
(
struct
rsnd_dai_stream
*
io
)
...
...
@@ -310,6 +291,24 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
u32
val
=
0x76543210
;
u32
mask
=
~
0
;
/*
* *Hardware* L/R and *Software* L/R are inverted.
* We need to care about inversion timing to control
* Playback/Capture correctly.
* The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
*
* sL/R : software L/R
* hL/R : hardware L/R
* (*) : conversion timing
*
* Playback
* sL/R (*) hL/R hL/R hL/R hL/R hL/R
* [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec
*
* Capture
* hL/R hL/R hL/R hL/R hL/R (*) sL/R
* codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM]
*/
if
(
rsnd_io_is_play
(
io
))
{
struct
rsnd_mod
*
src
=
rsnd_io_to_mod_src
(
io
);
...
...
@@ -470,8 +469,7 @@ static int rsnd_status_update(u32 *status,
#define rsnd_dai_call(fn, io, param...) \
({ \
struct rsnd_priv *priv = rsnd_io_to_priv(io); \
struct device *dev = rsnd_priv_to_dev(priv); \
struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \
struct rsnd_mod *mod; \
int is_play = rsnd_io_is_play(io); \
int ret = 0, i; \
...
...
@@ -532,6 +530,24 @@ static void rsnd_dai_disconnect(struct rsnd_mod *mod,
io
->
mod
[
type
]
=
NULL
;
}
int
rsnd_rdai_channels_ctrl
(
struct
rsnd_dai
*
rdai
,
int
max_channels
)
{
if
(
max_channels
>
0
)
rdai
->
max_channels
=
max_channels
;
return
rdai
->
max_channels
;
}
int
rsnd_rdai_ssi_lane_ctrl
(
struct
rsnd_dai
*
rdai
,
int
ssi_lane
)
{
if
(
ssi_lane
>
0
)
rdai
->
ssi_lane
=
ssi_lane
;
return
rdai
->
ssi_lane
;
}
struct
rsnd_dai
*
rsnd_rdai_get
(
struct
rsnd_priv
*
priv
,
int
id
)
{
if
((
id
<
0
)
||
(
id
>=
rsnd_rdai_nr
(
priv
)))
...
...
@@ -551,40 +567,6 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
/*
* rsnd_soc_dai functions
*/
int
rsnd_dai_pointer_offset
(
struct
rsnd_dai_stream
*
io
,
int
additional
)
{
struct
snd_pcm_substream
*
substream
=
io
->
substream
;
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
int
pos
=
io
->
byte_pos
+
additional
;
pos
%=
(
runtime
->
periods
*
io
->
byte_per_period
);
return
pos
;
}
bool
rsnd_dai_pointer_update
(
struct
rsnd_dai_stream
*
io
,
int
byte
)
{
io
->
byte_pos
+=
byte
;
if
(
io
->
byte_pos
>=
io
->
next_period_byte
)
{
struct
snd_pcm_substream
*
substream
=
io
->
substream
;
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
io
->
period_pos
++
;
io
->
next_period_byte
+=
io
->
byte_per_period
;
if
(
io
->
period_pos
>=
runtime
->
periods
)
{
io
->
byte_pos
=
0
;
io
->
period_pos
=
0
;
io
->
next_period_byte
=
io
->
byte_per_period
;
}
return
true
;
}
return
false
;
}
void
rsnd_dai_period_elapsed
(
struct
rsnd_dai_stream
*
io
)
{
struct
snd_pcm_substream
*
substream
=
io
->
substream
;
...
...
@@ -602,15 +584,7 @@ void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io)
static
void
rsnd_dai_stream_init
(
struct
rsnd_dai_stream
*
io
,
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
io
->
substream
=
substream
;
io
->
byte_pos
=
0
;
io
->
period_pos
=
0
;
io
->
byte_per_period
=
runtime
->
period_size
*
runtime
->
channels
*
samples_to_bytes
(
runtime
,
1
);
io
->
next_period_byte
=
io
->
byte_per_period
;
}
static
void
rsnd_dai_stream_quit
(
struct
rsnd_dai_stream
*
io
)
...
...
@@ -749,9 +723,13 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
switch
(
slots
)
{
case
2
:
case
6
:
case
8
:
case
16
:
/* TDM Extend Mode */
rsnd_set_slot
(
rdai
,
slots
,
1
);
rsnd_rdai_channels_set
(
rdai
,
slots
);
rsnd_rdai_ssi_lane_set
(
rdai
,
1
);
break
;
default:
dev_err
(
dev
,
"unsupported TDM slots (%d)
\n
"
,
slots
);
...
...
@@ -761,22 +739,177 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
return
0
;
}
static
unsigned
int
rsnd_soc_hw_channels_list
[]
=
{
2
,
6
,
8
,
16
,
};
static
unsigned
int
rsnd_soc_hw_rate_list
[]
=
{
8000
,
11025
,
16000
,
22050
,
32000
,
44100
,
48000
,
64000
,
88200
,
96000
,
176400
,
192000
,
};
static
int
rsnd_soc_hw_rule
(
struct
rsnd_priv
*
priv
,
unsigned
int
*
list
,
int
list_num
,
struct
snd_interval
*
baseline
,
struct
snd_interval
*
iv
)
{
struct
snd_interval
p
;
unsigned
int
rate
;
int
i
;
snd_interval_any
(
&
p
);
p
.
min
=
UINT_MAX
;
p
.
max
=
0
;
for
(
i
=
0
;
i
<
list_num
;
i
++
)
{
if
(
!
snd_interval_test
(
iv
,
list
[
i
]))
continue
;
rate
=
rsnd_ssi_clk_query
(
priv
,
baseline
->
min
,
list
[
i
],
NULL
);
if
(
rate
>
0
)
{
p
.
min
=
min
(
p
.
min
,
list
[
i
]);
p
.
max
=
max
(
p
.
max
,
list
[
i
]);
}
rate
=
rsnd_ssi_clk_query
(
priv
,
baseline
->
max
,
list
[
i
],
NULL
);
if
(
rate
>
0
)
{
p
.
min
=
min
(
p
.
min
,
list
[
i
]);
p
.
max
=
max
(
p
.
max
,
list
[
i
]);
}
}
return
snd_interval_refine
(
iv
,
&
p
);
}
static
int
rsnd_soc_hw_rule_rate
(
struct
snd_pcm_hw_params
*
params
,
struct
snd_pcm_hw_rule
*
rule
)
{
struct
snd_interval
*
ic_
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_CHANNELS
);
struct
snd_interval
*
ir
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_RATE
);
struct
snd_interval
ic
;
struct
snd_soc_dai
*
dai
=
rule
->
private
;
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
rsnd_priv
*
priv
=
rsnd_rdai_to_priv
(
rdai
);
/*
* possible sampling rate limitation is same as
* 2ch if it supports multi ssi
*/
ic
=
*
ic_
;
if
(
1
<
rsnd_rdai_ssi_lane_get
(
rdai
))
{
ic
.
min
=
2
;
ic
.
max
=
2
;
}
return
rsnd_soc_hw_rule
(
priv
,
rsnd_soc_hw_rate_list
,
ARRAY_SIZE
(
rsnd_soc_hw_rate_list
),
&
ic
,
ir
);
}
static
int
rsnd_soc_hw_rule_channels
(
struct
snd_pcm_hw_params
*
params
,
struct
snd_pcm_hw_rule
*
rule
)
{
struct
snd_interval
*
ic_
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_CHANNELS
);
struct
snd_interval
*
ir
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_RATE
);
struct
snd_interval
ic
;
struct
snd_soc_dai
*
dai
=
rule
->
private
;
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
rsnd_priv
*
priv
=
rsnd_rdai_to_priv
(
rdai
);
/*
* possible sampling rate limitation is same as
* 2ch if it supports multi ssi
*/
ic
=
*
ic_
;
if
(
1
<
rsnd_rdai_ssi_lane_get
(
rdai
))
{
ic
.
min
=
2
;
ic
.
max
=
2
;
}
return
rsnd_soc_hw_rule
(
priv
,
rsnd_soc_hw_channels_list
,
ARRAY_SIZE
(
rsnd_soc_hw_channels_list
),
ir
,
&
ic
);
}
static
void
rsnd_soc_hw_constraint
(
struct
snd_pcm_runtime
*
runtime
,
struct
snd_soc_dai
*
dai
)
{
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
snd_pcm_hw_constraint_list
*
constraint
=
&
rdai
->
constraint
;
unsigned
int
max_channels
=
rsnd_rdai_channels_get
(
rdai
);
int
i
;
/*
* Channel Limitation
* It depends on Platform design
*/
constraint
->
list
=
rsnd_soc_hw_channels_list
;
constraint
->
count
=
0
;
constraint
->
mask
=
0
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
rsnd_soc_hw_channels_list
);
i
++
)
{
if
(
rsnd_soc_hw_channels_list
[
i
]
>
max_channels
)
break
;
constraint
->
count
=
i
+
1
;
}
snd_pcm_hw_constraint_list
(
runtime
,
0
,
SNDRV_PCM_HW_PARAM_CHANNELS
,
constraint
);
/*
* Sampling Rate / Channel Limitation
* It depends on Clock Master Mode
*/
if
(
!
rsnd_rdai_is_clk_master
(
rdai
))
return
;
snd_pcm_hw_rule_add
(
runtime
,
0
,
SNDRV_PCM_HW_PARAM_RATE
,
rsnd_soc_hw_rule_rate
,
dai
,
SNDRV_PCM_HW_PARAM_CHANNELS
,
-
1
);
snd_pcm_hw_rule_add
(
runtime
,
0
,
SNDRV_PCM_HW_PARAM_CHANNELS
,
rsnd_soc_hw_rule_channels
,
dai
,
SNDRV_PCM_HW_PARAM_RATE
,
-
1
);
}
static
int
rsnd_soc_dai_startup
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
rsnd_priv
*
priv
=
rsnd_rdai_to_priv
(
rdai
);
struct
rsnd_dai_stream
*
io
=
rsnd_rdai_to_io
(
rdai
,
substream
);
int
ret
;
/* rsnd_io_to_runtime() is not yet enabled here */
rsnd_soc_hw_constraint
(
substream
->
runtime
,
dai
);
/*
* call rsnd_dai_call without spinlock
*/
return
rsnd_dai_call
(
nolock_start
,
io
,
priv
);
ret
=
rsnd_dai_call
(
nolock_start
,
io
,
priv
);
if
(
ret
<
0
)
rsnd_dai_call
(
nolock_stop
,
io
,
priv
);
return
ret
;
}
static
void
rsnd_soc_dai_shutdown
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
rsnd_priv
*
priv
=
rsnd_rdai_to_priv
(
rdai
);
struct
rsnd_dai_stream
*
io
=
rsnd_rdai_to_io
(
rdai
,
substream
);
/*
...
...
@@ -820,44 +953,56 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
of_node_put
(
node
);
}
static
int
rsnd_dai_probe
(
struct
rsnd_priv
*
priv
)
static
struct
device_node
*
rsnd_dai_of_node
(
struct
rsnd_priv
*
priv
,
int
*
is_graph
)
{
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
device_node
*
np
=
dev
->
of_node
;
struct
device_node
*
dai_node
;
struct
device_node
*
dai_np
;
struct
device_node
*
ret
;
*
is_graph
=
0
;
/*
* parse both previous dai (= rcar_sound,dai), and
* graph dai (= ports/port)
*/
dai_node
=
of_get_child_by_name
(
np
,
RSND_NODE_DAI
);
if
(
dai_node
)
{
ret
=
dai_node
;
goto
of_node_compatible
;
}
ret
=
np
;
dai_node
=
of_graph_get_next_endpoint
(
np
,
NULL
);
if
(
dai_node
)
goto
of_node_graph
;
return
NULL
;
of_node_graph:
*
is_graph
=
1
;
of_node_compatible:
of_node_put
(
dai_node
);
return
ret
;
}
static
void
__rsnd_dai_probe
(
struct
rsnd_priv
*
priv
,
struct
device_node
*
dai_np
,
int
dai_i
,
int
is_graph
)
{
struct
device_node
*
playback
,
*
capture
;
struct
rsnd_dai_stream
*
io_playback
;
struct
rsnd_dai_stream
*
io_capture
;
struct
snd_soc_dai_driver
*
rdrv
,
*
drv
;
struct
snd_soc_dai_driver
*
drv
;
struct
rsnd_dai
*
rdai
;
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
int
nr
,
dai_i
,
io_i
;
int
ret
;
dai_node
=
rsnd_dai_of_node
(
priv
);
nr
=
of_get_child_count
(
dai_node
);
if
(
!
nr
)
{
ret
=
-
EINVAL
;
goto
rsnd_dai_probe_done
;
}
rdrv
=
devm_kzalloc
(
dev
,
sizeof
(
*
rdrv
)
*
nr
,
GFP_KERNEL
);
rdai
=
devm_kzalloc
(
dev
,
sizeof
(
*
rdai
)
*
nr
,
GFP_KERNEL
);
if
(
!
rdrv
||
!
rdai
)
{
ret
=
-
ENOMEM
;
goto
rsnd_dai_probe_done
;
}
priv
->
rdai_nr
=
nr
;
priv
->
daidrv
=
rdrv
;
priv
->
rdai
=
rdai
;
int
io_i
;
/*
* parse all dai
*/
dai_i
=
0
;
for_each_child_of_node
(
dai_node
,
dai_np
)
{
rdai
=
rsnd_rdai_get
(
priv
,
dai_i
);
drv
=
r
drv
+
dai_i
;
drv
=
priv
->
dai
drv
+
dai_i
;
io_playback
=
&
rdai
->
playback
;
io_capture
=
&
rdai
->
capture
;
...
...
@@ -872,7 +1017,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
drv
->
playback
.
rates
=
RSND_RATES
;
drv
->
playback
.
formats
=
RSND_FMTS
;
drv
->
playback
.
channels_min
=
2
;
drv
->
playback
.
channels_max
=
6
;
drv
->
playback
.
channels_max
=
1
6
;
drv
->
playback
.
stream_name
=
rdai
->
playback
.
name
;
snprintf
(
rdai
->
capture
.
name
,
RSND_DAI_NAME_SIZE
,
...
...
@@ -880,12 +1025,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
drv
->
capture
.
rates
=
RSND_RATES
;
drv
->
capture
.
formats
=
RSND_FMTS
;
drv
->
capture
.
channels_min
=
2
;
drv
->
capture
.
channels_max
=
6
;
drv
->
capture
.
channels_max
=
1
6
;
drv
->
capture
.
stream_name
=
rdai
->
capture
.
name
;
rdai
->
playback
.
rdai
=
rdai
;
rdai
->
capture
.
rdai
=
rdai
;
rsnd_set_slot
(
rdai
,
2
,
1
);
/* default */
rsnd_rdai_channels_set
(
rdai
,
2
);
/* default 2ch */
rsnd_rdai_ssi_lane_set
(
rdai
,
1
);
/* default 1lane */
for
(
io_i
=
0
;;
io_i
++
)
{
playback
=
of_parse_phandle
(
dai_np
,
"playback"
,
io_i
);
...
...
@@ -904,19 +1050,56 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
of_node_put
(
capture
);
}
dai_i
++
;
dev_dbg
(
dev
,
"%s (%s/%s)
\n
"
,
rdai
->
name
,
rsnd_io_to_mod_ssi
(
io_playback
)
?
"play"
:
" -- "
,
rsnd_io_to_mod_ssi
(
io_capture
)
?
"capture"
:
" -- "
);
}
}
ret
=
0
;
static
int
rsnd_dai_probe
(
struct
rsnd_priv
*
priv
)
{
struct
device_node
*
dai_node
;
struct
device_node
*
dai_np
;
struct
snd_soc_dai_driver
*
rdrv
;
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
rsnd_dai
*
rdai
;
int
nr
;
int
is_graph
;
int
dai_i
;
rsnd_dai_probe_done:
of_node_put
(
dai_node
);
dai_node
=
rsnd_dai_of_node
(
priv
,
&
is_graph
);
if
(
is_graph
)
nr
=
of_graph_get_endpoint_count
(
dai_node
);
else
nr
=
of_get_child_count
(
dai_node
);
return
ret
;
if
(
!
nr
)
return
-
EINVAL
;
rdrv
=
devm_kzalloc
(
dev
,
sizeof
(
*
rdrv
)
*
nr
,
GFP_KERNEL
);
rdai
=
devm_kzalloc
(
dev
,
sizeof
(
*
rdai
)
*
nr
,
GFP_KERNEL
);
if
(
!
rdrv
||
!
rdai
)
return
-
ENOMEM
;
priv
->
rdai_nr
=
nr
;
priv
->
daidrv
=
rdrv
;
priv
->
rdai
=
rdai
;
/*
* parse all dai
*/
dai_i
=
0
;
if
(
is_graph
)
{
for_each_endpoint_of_node
(
dai_node
,
dai_np
)
{
__rsnd_dai_probe
(
priv
,
dai_np
,
dai_i
,
is_graph
);
rsnd_ssi_parse_hdmi_connection
(
priv
,
dai_np
,
dai_i
);
dai_i
++
;
}
}
else
{
for_each_child_of_node
(
dai_node
,
dai_np
)
__rsnd_dai_probe
(
priv
,
dai_np
,
dai_i
++
,
is_graph
);
}
return
0
;
}
/*
...
...
@@ -965,12 +1148,14 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream,
static
snd_pcm_uframes_t
rsnd_pointer
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
snd_soc_dai
*
dai
=
rsnd_substream_to_dai
(
substream
);
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
rsnd_dai_stream
*
io
=
rsnd_rdai_to_io
(
rdai
,
substream
);
snd_pcm_uframes_t
pointer
=
0
;
rsnd_dai_call
(
pointer
,
io
,
&
pointer
);
return
bytes_to_frames
(
runtime
,
io
->
byte_pos
)
;
return
pointer
;
}
static
struct
snd_pcm_ops
rsnd_pcm_ops
=
{
...
...
@@ -1033,6 +1218,9 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
struct
rsnd_kctrl_cfg
*
cfg
=
kcontrol_to_cfg
(
kctrl
);
int
i
,
change
=
0
;
if
(
!
cfg
->
accept
(
cfg
->
io
))
return
0
;
for
(
i
=
0
;
i
<
cfg
->
size
;
i
++
)
{
if
(
cfg
->
texts
)
{
change
|=
(
uc
->
value
.
enumerated
.
item
[
i
]
!=
cfg
->
val
[
i
]);
...
...
@@ -1049,6 +1237,18 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
return
change
;
}
int
rsnd_kctrl_accept_anytime
(
struct
rsnd_dai_stream
*
io
)
{
return
1
;
}
int
rsnd_kctrl_accept_runtime
(
struct
rsnd_dai_stream
*
io
)
{
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
return
!!
runtime
;
}
struct
rsnd_kctrl_cfg
*
rsnd_kctrl_init_m
(
struct
rsnd_kctrl_cfg_m
*
cfg
)
{
cfg
->
cfg
.
val
=
cfg
->
val
;
...
...
@@ -1067,6 +1267,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
struct
rsnd_dai_stream
*
io
,
struct
snd_soc_pcm_runtime
*
rtd
,
const
unsigned
char
*
name
,
int
(
*
accept
)(
struct
rsnd_dai_stream
*
io
),
void
(
*
update
)(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod
),
struct
rsnd_kctrl_cfg
*
cfg
,
...
...
@@ -1101,6 +1302,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
cfg
->
texts
=
texts
;
cfg
->
max
=
max
;
cfg
->
size
=
size
;
cfg
->
accept
=
accept
;
cfg
->
update
=
update
;
cfg
->
card
=
card
;
cfg
->
kctrl
=
kctrl
;
...
...
@@ -1332,7 +1534,7 @@ static int rsnd_resume(struct device *dev)
return
0
;
}
static
struct
dev_pm_ops
rsnd_pm_ops
=
{
static
const
struct
dev_pm_ops
rsnd_pm_ops
=
{
.
suspend
=
rsnd_suspend
,
.
resume
=
rsnd_resume
,
};
...
...
sound/soc/sh/rcar/ctu.c
View file @
6bf4cd28
...
...
@@ -279,12 +279,14 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
/* CTU Pass */
ret
=
rsnd_kctrl_new_m
(
mod
,
io
,
rtd
,
"CTU Pass"
,
rsnd_kctrl_accept_anytime
,
NULL
,
&
ctu
->
pass
,
RSND_MAX_CHANNELS
,
0xC
);
/* ROW0 */
ret
=
rsnd_kctrl_new_m
(
mod
,
io
,
rtd
,
"CTU SV0"
,
rsnd_kctrl_accept_anytime
,
NULL
,
&
ctu
->
sv0
,
RSND_MAX_CHANNELS
,
0x00FFFFFF
);
...
...
@@ -293,6 +295,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
/* ROW1 */
ret
=
rsnd_kctrl_new_m
(
mod
,
io
,
rtd
,
"CTU SV1"
,
rsnd_kctrl_accept_anytime
,
NULL
,
&
ctu
->
sv1
,
RSND_MAX_CHANNELS
,
0x00FFFFFF
);
...
...
@@ -301,6 +304,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
/* ROW2 */
ret
=
rsnd_kctrl_new_m
(
mod
,
io
,
rtd
,
"CTU SV2"
,
rsnd_kctrl_accept_anytime
,
NULL
,
&
ctu
->
sv2
,
RSND_MAX_CHANNELS
,
0x00FFFFFF
);
...
...
@@ -309,6 +313,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
/* ROW3 */
ret
=
rsnd_kctrl_new_m
(
mod
,
io
,
rtd
,
"CTU SV3"
,
rsnd_kctrl_accept_anytime
,
NULL
,
&
ctu
->
sv3
,
RSND_MAX_CHANNELS
,
0x00FFFFFF
);
...
...
@@ -317,6 +322,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
/* Reset */
ret
=
rsnd_kctrl_new_s
(
mod
,
io
,
rtd
,
"CTU Reset"
,
rsnd_kctrl_accept_anytime
,
rsnd_ctu_value_reset
,
&
ctu
->
reset
,
1
);
...
...
sound/soc/sh/rcar/dma.c
View file @
6bf4cd28
...
...
@@ -25,6 +25,7 @@
struct
rsnd_dmaen
{
struct
dma_chan
*
chan
;
dma_cookie_t
cookie
;
dma_addr_t
dma_buf
;
unsigned
int
dma_len
;
unsigned
int
dma_period
;
...
...
@@ -103,10 +104,6 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
* In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
* But, Audio-DMAC-peri-peri doesn't have interrupt,
* and this driver is assuming that here.
*
* If Audio-DMAC-peri-peri has interrpt,
* rsnd_dai_pointer_update() will be called twice,
* ant it will breaks io->byte_pos
*/
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
...
...
@@ -121,7 +118,7 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
*/
rsnd_dmaen_sync
(
dmaen
,
io
,
dmaen
->
dma_cnt
+
2
);
elapsed
=
rsnd_dai_pointer_update
(
io
,
io
->
byte_per_period
)
;
elapsed
=
true
;
dmaen
->
dma_cnt
++
;
}
...
...
@@ -292,7 +289,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
for
(
i
=
0
;
i
<
2
;
i
++
)
rsnd_dmaen_sync
(
dmaen
,
io
,
i
);
if
(
dmaengine_submit
(
desc
)
<
0
)
{
dmaen
->
cookie
=
dmaengine_submit
(
desc
);
if
(
dmaen
->
cookie
<
0
)
{
dev_err
(
dev
,
"dmaengine_submit() fail
\n
"
);
return
-
EIO
;
}
...
...
@@ -348,12 +346,34 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
return
0
;
}
static
int
rsnd_dmaen_pointer
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
snd_pcm_uframes_t
*
pointer
)
{
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
struct
rsnd_dma
*
dma
=
rsnd_mod_to_dma
(
mod
);
struct
rsnd_dmaen
*
dmaen
=
rsnd_dma_to_dmaen
(
dma
);
struct
dma_tx_state
state
;
enum
dma_status
status
;
unsigned
int
pos
=
0
;
status
=
dmaengine_tx_status
(
dmaen
->
chan
,
dmaen
->
cookie
,
&
state
);
if
(
status
==
DMA_IN_PROGRESS
||
status
==
DMA_PAUSED
)
{
if
(
state
.
residue
>
0
&&
state
.
residue
<=
dmaen
->
dma_len
)
pos
=
dmaen
->
dma_len
-
state
.
residue
;
}
*
pointer
=
bytes_to_frames
(
runtime
,
pos
);
return
0
;
}
static
struct
rsnd_mod_ops
rsnd_dmaen_ops
=
{
.
name
=
"audmac"
,
.
nolock_start
=
rsnd_dmaen_nolock_start
,
.
nolock_stop
=
rsnd_dmaen_nolock_stop
,
.
start
=
rsnd_dmaen_start
,
.
stop
=
rsnd_dmaen_stop
,
.
pointer
=
rsnd_dmaen_pointer
,
};
/*
...
...
sound/soc/sh/rcar/dvc.c
View file @
6bf4cd28
...
...
@@ -249,16 +249,18 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
rsnd_dvc
*
dvc
=
rsnd_mod_to_dvc
(
mod
);
struct
rsnd_dai
*
rdai
=
rsnd_io_to_rdai
(
io
);
int
is_play
=
rsnd_io_is_play
(
io
);
int
slots
=
rsnd_get_slot
(
io
);
int
channels
=
rsnd_rdai_channels_get
(
rdai
);
int
ret
;
/* Volume */
ret
=
rsnd_kctrl_new_m
(
mod
,
io
,
rtd
,
is_play
?
"DVC Out Playback Volume"
:
"DVC In Capture Volume"
,
rsnd_kctrl_accept_anytime
,
rsnd_dvc_volume_update
,
&
dvc
->
volume
,
slot
s
,
&
dvc
->
volume
,
channel
s
,
0x00800000
-
1
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -267,8 +269,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
ret
=
rsnd_kctrl_new_m
(
mod
,
io
,
rtd
,
is_play
?
"DVC Out Mute Switch"
:
"DVC In Mute Switch"
,
rsnd_kctrl_accept_anytime
,
rsnd_dvc_volume_update
,
&
dvc
->
mute
,
slot
s
,
&
dvc
->
mute
,
channel
s
,
1
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -277,6 +280,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
ret
=
rsnd_kctrl_new_s
(
mod
,
io
,
rtd
,
is_play
?
"DVC Out Ramp Switch"
:
"DVC In Ramp Switch"
,
rsnd_kctrl_accept_anytime
,
rsnd_dvc_volume_update
,
&
dvc
->
ren
,
1
);
if
(
ret
<
0
)
...
...
@@ -285,6 +289,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
ret
=
rsnd_kctrl_new_e
(
mod
,
io
,
rtd
,
is_play
?
"DVC Out Ramp Up Rate"
:
"DVC In Ramp Up Rate"
,
rsnd_kctrl_accept_anytime
,
rsnd_dvc_volume_update
,
&
dvc
->
rup
,
dvc_ramp_rate
);
...
...
@@ -294,6 +299,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
ret
=
rsnd_kctrl_new_e
(
mod
,
io
,
rtd
,
is_play
?
"DVC Out Ramp Down Rate"
:
"DVC In Ramp Down Rate"
,
rsnd_kctrl_accept_anytime
,
rsnd_dvc_volume_update
,
&
dvc
->
rdown
,
dvc_ramp_rate
);
...
...
sound/soc/sh/rcar/gen.c
View file @
6bf4cd28
...
...
@@ -219,6 +219,8 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_S_REG
(
SSI_SYS_STATUS5
,
0x884
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS6
,
0x888
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS7
,
0x88c
),
RSND_GEN_S_REG
(
HDMI0_SEL
,
0x9e0
),
RSND_GEN_S_REG
(
HDMI1_SEL
,
0x9e4
),
/* FIXME: it needs SSI_MODE2/3 in the future */
RSND_GEN_M_REG
(
SSI_BUSIF_MODE
,
0x0
,
0x80
),
...
...
sound/soc/sh/rcar/rsnd.h
View file @
6bf4cd28
...
...
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/of_irq.h>
#include <linux/sh_dma.h>
#include <linux/workqueue.h>
...
...
@@ -170,6 +171,8 @@ enum rsnd_reg {
RSND_REG_SSI_SYS_STATUS5
,
RSND_REG_SSI_SYS_STATUS6
,
RSND_REG_SSI_SYS_STATUS7
,
RSND_REG_HDMI0_SEL
,
RSND_REG_HDMI1_SEL
,
/* SSI */
RSND_REG_SSICR
,
...
...
@@ -268,6 +271,9 @@ struct rsnd_mod_ops {
struct
rsnd_dai_stream
*
io
,
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
hw_params
);
int
(
*
pointer
)(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
snd_pcm_uframes_t
*
pointer
);
int
(
*
fallback
)(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
);
...
...
@@ -305,6 +311,7 @@ struct rsnd_mod {
* H 0: pcm_new
* H 0: fallback
* H 0: hw_params
* H 0: pointer
*/
#define __rsnd_mod_shift_nolock_start 0
#define __rsnd_mod_shift_nolock_stop 0
...
...
@@ -318,6 +325,7 @@ struct rsnd_mod {
#define __rsnd_mod_shift_pcm_new 28
/* always called */
#define __rsnd_mod_shift_fallback 28
/* always called */
#define __rsnd_mod_shift_hw_params 28
/* always called */
#define __rsnd_mod_shift_pointer 28
/* always called */
#define __rsnd_mod_add_probe 0
#define __rsnd_mod_add_remove 0
...
...
@@ -331,6 +339,7 @@ struct rsnd_mod {
#define __rsnd_mod_add_pcm_new 0
#define __rsnd_mod_add_fallback 0
#define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_add_pointer 0
#define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 0
...
...
@@ -342,6 +351,7 @@ struct rsnd_mod {
#define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 0
#define __rsnd_mod_call_hw_params 0
#define __rsnd_mod_call_pointer 0
#define __rsnd_mod_call_nolock_start 0
#define __rsnd_mod_call_nolock_stop 1
...
...
@@ -389,11 +399,6 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
struct
device_node
*
playback
,
struct
device_node
*
capture
);
void
rsnd_set_slot
(
struct
rsnd_dai
*
rdai
,
int
slots
,
int
slots_total
);
int
rsnd_get_slot
(
struct
rsnd_dai_stream
*
io
);
int
rsnd_get_slot_num
(
struct
rsnd_dai_stream
*
io
);
int
rsnd_runtime_channel_original
(
struct
rsnd_dai_stream
*
io
);
int
rsnd_runtime_channel_after_ctu
(
struct
rsnd_dai_stream
*
io
);
int
rsnd_runtime_channel_for_ssi
(
struct
rsnd_dai_stream
*
io
);
...
...
@@ -420,13 +425,8 @@ struct rsnd_dai_stream {
char
name
[
RSND_DAI_NAME_SIZE
];
struct
snd_pcm_substream
*
substream
;
struct
rsnd_mod
*
mod
[
RSND_MOD_MAX
];
struct
rsnd_dai_path_info
*
info
;
/* rcar_snd.h */
struct
rsnd_dai
*
rdai
;
u32
parent_ssi_status
;
int
byte_pos
;
int
period_pos
;
int
byte_per_period
;
int
next_period_byte
;
};
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
...
...
@@ -449,9 +449,10 @@ struct rsnd_dai {
struct
rsnd_dai_stream
playback
;
struct
rsnd_dai_stream
capture
;
struct
rsnd_priv
*
priv
;
struct
snd_pcm_hw_constraint_list
constraint
;
int
slots
;
int
s
lots_num
;
int
max_channels
;
/* 2ch - 16ch */
int
s
si_lane
;
/* 1lane - 4lane */
unsigned
int
clk_master
:
1
;
unsigned
int
bit_clk_inv
:
1
;
...
...
@@ -471,13 +472,24 @@ struct rsnd_dai {
struct
rsnd_dai
*
rsnd_rdai_get
(
struct
rsnd_priv
*
priv
,
int
id
);
bool
rsnd_dai_pointer_update
(
struct
rsnd_dai_stream
*
io
,
int
cnt
);
#define rsnd_rdai_channels_set(rdai, max_channels) \
rsnd_rdai_channels_ctrl(rdai, max_channels)
#define rsnd_rdai_channels_get(rdai) \
rsnd_rdai_channels_ctrl(rdai, 0)
int
rsnd_rdai_channels_ctrl
(
struct
rsnd_dai
*
rdai
,
int
max_channels
);
#define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \
rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane)
#define rsnd_rdai_ssi_lane_get(rdai) \
rsnd_rdai_ssi_lane_ctrl(rdai, 0)
int
rsnd_rdai_ssi_lane_ctrl
(
struct
rsnd_dai
*
rdai
,
int
ssi_lane
);
void
rsnd_dai_period_elapsed
(
struct
rsnd_dai_stream
*
io
);
int
rsnd_dai_pointer_offset
(
struct
rsnd_dai_stream
*
io
,
int
additional
);
int
rsnd_dai_connect
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
enum
rsnd_mod_type
type
);
#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
/*
* R-Car Gen1/Gen2
...
...
@@ -491,6 +503,7 @@ phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
/*
* R-Car ADG
*/
int
rsnd_adg_clk_query
(
struct
rsnd_priv
*
priv
,
unsigned
int
rate
);
int
rsnd_adg_ssi_clk_stop
(
struct
rsnd_mod
*
mod
);
int
rsnd_adg_ssi_clk_try_start
(
struct
rsnd_mod
*
mod
,
unsigned
int
rate
);
int
rsnd_adg_probe
(
struct
rsnd_priv
*
priv
);
...
...
@@ -596,6 +609,7 @@ struct rsnd_kctrl_cfg {
unsigned
int
size
;
u32
*
val
;
const
char
*
const
*
texts
;
int
(
*
accept
)(
struct
rsnd_dai_stream
*
io
);
void
(
*
update
)(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod
);
struct
rsnd_dai_stream
*
io
;
struct
snd_card
*
card
;
...
...
@@ -613,12 +627,15 @@ struct rsnd_kctrl_cfg_s {
u32
val
;
};
int
rsnd_kctrl_accept_anytime
(
struct
rsnd_dai_stream
*
io
);
int
rsnd_kctrl_accept_runtime
(
struct
rsnd_dai_stream
*
io
);
struct
rsnd_kctrl_cfg
*
rsnd_kctrl_init_m
(
struct
rsnd_kctrl_cfg_m
*
cfg
);
struct
rsnd_kctrl_cfg
*
rsnd_kctrl_init_s
(
struct
rsnd_kctrl_cfg_s
*
cfg
);
int
rsnd_kctrl_new
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
snd_soc_pcm_runtime
*
rtd
,
const
unsigned
char
*
name
,
int
(
*
accept
)(
struct
rsnd_dai_stream
*
io
),
void
(
*
update
)(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod
),
struct
rsnd_kctrl_cfg
*
cfg
,
...
...
@@ -626,16 +643,16 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
int
size
,
u32
max
);
#define rsnd_kctrl_new_m(mod, io, rtd, name, update, cfg, size, max) \
rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_m(cfg), \
#define rsnd_kctrl_new_m(mod, io, rtd, name,
accept,
update, cfg, size, max) \
rsnd_kctrl_new(mod, io, rtd, name,
accept,
update, rsnd_kctrl_init_m(cfg), \
NULL, size, max)
#define rsnd_kctrl_new_s(mod, io, rtd, name, update, cfg, max) \
rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \
#define rsnd_kctrl_new_s(mod, io, rtd, name,
accept,
update, cfg, max) \
rsnd_kctrl_new(mod, io, rtd, name,
accept,
update, rsnd_kctrl_init_s(cfg), \
NULL, 1, max)
#define rsnd_kctrl_new_e(mod, io, rtd, name, update, cfg, texts) \
rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \
#define rsnd_kctrl_new_e(mod, io, rtd, name,
accept,
update, cfg, texts) \
rsnd_kctrl_new(mod, io, rtd, name,
accept,
update, rsnd_kctrl_init_s(cfg), \
texts, 1, ARRAY_SIZE(texts))
/*
...
...
@@ -648,6 +665,13 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int
rsnd_ssi_use_busif
(
struct
rsnd_dai_stream
*
io
);
u32
rsnd_ssi_multi_slaves_runtime
(
struct
rsnd_dai_stream
*
io
);
#define RSND_SSI_HDMI_PORT0 0xf0
#define RSND_SSI_HDMI_PORT1 0xf1
int
rsnd_ssi_hdmi_port
(
struct
rsnd_dai_stream
*
io
);
void
rsnd_ssi_parse_hdmi_connection
(
struct
rsnd_priv
*
priv
,
struct
device_node
*
endpoint
,
int
dai_i
);
#define rsnd_ssi_is_pin_sharing(io) \
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
int
__rsnd_ssi_is_pin_sharing
(
struct
rsnd_mod
*
mod
);
...
...
@@ -656,6 +680,8 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
void
rsnd_parse_connect_ssi
(
struct
rsnd_dai
*
rdai
,
struct
device_node
*
playback
,
struct
device_node
*
capture
);
unsigned
int
rsnd_ssi_clk_query
(
struct
rsnd_priv
*
priv
,
int
param1
,
int
param2
,
int
*
idx
);
/*
* R-Car SSIU
...
...
sound/soc/sh/rcar/src.c
View file @
6bf4cd28
...
...
@@ -12,10 +12,6 @@
#define SRC_NAME "src"
/* SRCx_STATUS */
#define OUF_SRCO ((1 << 12) | (1 << 13))
#define OUF_SRCI ((1 << 9) | (1 << 8))
/* SCU_SYSTEM_STATUS0/1 */
#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id))
...
...
@@ -55,20 +51,6 @@ struct rsnd_src {
*
*/
/*
* src.c is caring...
*
* Gen1
*
* [mem] -> [SRU] -> [SSI]
* |--------|
*
* Gen2
*
* [mem] -> [SRC] -> [SSIU] -> [SSI]
* |-----------------|
*/
static
void
rsnd_src_activation
(
struct
rsnd_mod
*
mod
)
{
rsnd_mod_write
(
mod
,
SRC_SWRSR
,
0
);
...
...
@@ -515,6 +497,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
rsnd_io_is_play
(
io
)
?
"SRC Out Rate Switch"
:
"SRC In Rate Switch"
,
rsnd_kctrl_accept_anytime
,
rsnd_src_set_convert_rate
,
&
src
->
sen
,
1
);
if
(
ret
<
0
)
...
...
@@ -524,6 +507,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
rsnd_io_is_play
(
io
)
?
"SRC Out Rate"
:
"SRC In Rate"
,
rsnd_kctrl_accept_runtime
,
rsnd_src_set_convert_rate
,
&
src
->
sync
,
192000
);
...
...
sound/soc/sh/rcar/ssi.c
View file @
6bf4cd28
...
...
@@ -11,6 +11,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <sound/simple_card_utils.h>
#include <linux/delay.h>
#include "rsnd.h"
#define RSND_SSI_NAME_SIZE 16
...
...
@@ -76,11 +77,18 @@ struct rsnd_ssi {
int
rate
;
int
irq
;
unsigned
int
usrcnt
;
int
byte_pos
;
int
period_pos
;
int
byte_per_period
;
int
next_period_byte
;
};
/* flags */
#define RSND_SSI_CLK_PIN_SHARE (1 << 0)
#define RSND_SSI_NO_BUSIF (1 << 1)
/* SSI+DMA without BUSIF */
#define RSND_SSI_HDMI0 (1 << 2)
/* for HDMI0 */
#define RSND_SSI_HDMI1 (1 << 3)
/* for HDMI1 */
#define for_each_rsnd_ssi(pos, priv, i) \
for (i = 0; \
...
...
@@ -99,6 +107,20 @@ struct rsnd_ssi {
#define rsnd_ssi_is_run_mods(mod, io) \
(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
int
rsnd_ssi_hdmi_port
(
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_mod
*
mod
=
rsnd_io_to_mod_ssi
(
io
);
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
if
(
rsnd_ssi_mode_flags
(
ssi
)
&
RSND_SSI_HDMI0
)
return
RSND_SSI_HDMI_PORT0
;
if
(
rsnd_ssi_mode_flags
(
ssi
)
&
RSND_SSI_HDMI1
)
return
RSND_SSI_HDMI_PORT1
;
return
0
;
}
int
rsnd_ssi_use_busif
(
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_mod
*
mod
=
rsnd_io_to_mod_ssi
(
io
);
...
...
@@ -186,6 +208,46 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
return
0
;
}
unsigned
int
rsnd_ssi_clk_query
(
struct
rsnd_priv
*
priv
,
int
param1
,
int
param2
,
int
*
idx
)
{
int
ssi_clk_mul_table
[]
=
{
1
,
2
,
4
,
8
,
16
,
6
,
12
,
};
int
j
,
ret
;
unsigned
int
main_rate
;
for
(
j
=
0
;
j
<
ARRAY_SIZE
(
ssi_clk_mul_table
);
j
++
)
{
/*
* It will set SSIWSR.CONT here, but SSICR.CKDV = 000
* with it is not allowed. (SSIWSR.WS_MODE with
* SSICR.CKDV = 000 is not allowed either).
* Skip it. See SSICR.CKDV
*/
if
(
j
==
0
)
continue
;
/*
* this driver is assuming that
* system word is 32bit x chan
* see rsnd_ssi_init()
*/
main_rate
=
32
*
param1
*
param2
*
ssi_clk_mul_table
[
j
];
ret
=
rsnd_adg_clk_query
(
priv
,
main_rate
);
if
(
ret
<
0
)
continue
;
if
(
idx
)
*
idx
=
j
;
return
main_rate
;
}
return
0
;
}
static
int
rsnd_ssi_master_clk_start
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
)
{
...
...
@@ -195,10 +257,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
struct
rsnd_mod
*
ssi_parent_mod
=
rsnd_io_to_mod_ssip
(
io
);
int
chan
=
rsnd_runtime_channel_for_ssi
(
io
);
int
j
,
ret
;
int
ssi_clk_mul_table
[]
=
{
1
,
2
,
4
,
8
,
16
,
6
,
12
,
};
int
idx
,
ret
;
unsigned
int
main_rate
;
unsigned
int
rate
=
rsnd_io_is_play
(
io
)
?
rsnd_src_get_out_rate
(
priv
,
io
)
:
...
...
@@ -222,33 +281,18 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return
0
;
}
/*
* Find best clock, and try to start ADG
*/
for
(
j
=
0
;
j
<
ARRAY_SIZE
(
ssi_clk_mul_table
);
j
++
)
{
/*
* It will set SSIWSR.CONT here, but SSICR.CKDV = 000
* with it is not allowed. (SSIWSR.WS_MODE with
* SSICR.CKDV = 000 is not allowed either).
* Skip it. See SSICR.CKDV
*/
if
(
j
==
0
)
continue
;
/*
* this driver is assuming that
* system word is 32bit x chan
* see rsnd_ssi_init()
*/
main_rate
=
rate
*
32
*
chan
*
ssi_clk_mul_table
[
j
];
main_rate
=
rsnd_ssi_clk_query
(
priv
,
rate
,
chan
,
&
idx
);
if
(
!
main_rate
)
{
dev_err
(
dev
,
"unsupported clock rate
\n
"
);
return
-
EIO
;
}
ret
=
rsnd_adg_ssi_clk_try_start
(
mod
,
main_rate
);
if
(
0
==
ret
)
{
ssi
->
cr_clk
=
FORCE
|
SWL_32
|
SCKD
|
SWSD
|
CKDV
(
j
);
ssi
->
wsr
=
CONT
;
if
(
ret
<
0
)
return
ret
;
ssi
->
cr_clk
=
FORCE
|
SWL_32
|
SCKD
|
SWSD
|
CKDV
(
idx
);
ssi
->
wsr
=
CONT
;
ssi
->
rate
=
rate
;
dev_dbg
(
dev
,
"%s[%d] outputs %u Hz
\n
"
,
...
...
@@ -256,11 +300,6 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
rsnd_mod_id
(
mod
),
rate
);
return
0
;
}
}
dev_err
(
dev
,
"unsupported clock rate
\n
"
);
return
-
EIO
;
}
static
void
rsnd_ssi_master_clk_stop
(
struct
rsnd_mod
*
mod
,
...
...
@@ -357,6 +396,59 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
ssi
->
cr_mode
);
/* without EN */
}
static
void
rsnd_ssi_pointer_init
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
ssi
->
byte_pos
=
0
;
ssi
->
period_pos
=
0
;
ssi
->
byte_per_period
=
runtime
->
period_size
*
runtime
->
channels
*
samples_to_bytes
(
runtime
,
1
);
ssi
->
next_period_byte
=
ssi
->
byte_per_period
;
}
static
int
rsnd_ssi_pointer_offset
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
int
additional
)
{
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
int
pos
=
ssi
->
byte_pos
+
additional
;
pos
%=
(
runtime
->
periods
*
ssi
->
byte_per_period
);
return
pos
;
}
static
bool
rsnd_ssi_pointer_update
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
int
byte
)
{
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
ssi
->
byte_pos
+=
byte
;
if
(
ssi
->
byte_pos
>=
ssi
->
next_period_byte
)
{
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
ssi
->
period_pos
++
;
ssi
->
next_period_byte
+=
ssi
->
byte_per_period
;
if
(
ssi
->
period_pos
>=
runtime
->
periods
)
{
ssi
->
byte_pos
=
0
;
ssi
->
period_pos
=
0
;
ssi
->
next_period_byte
=
ssi
->
byte_per_period
;
}
return
true
;
}
return
false
;
}
/*
* SSI mod common functions
*/
...
...
@@ -370,6 +462,8 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
if
(
!
rsnd_ssi_is_run_mods
(
mod
,
io
))
return
0
;
rsnd_ssi_pointer_init
(
mod
,
io
);
ssi
->
usrcnt
++
;
rsnd_mod_power_on
(
mod
);
...
...
@@ -549,7 +643,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
if
(
!
is_dma
&&
(
status
&
DIRQ
))
{
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
u32
*
buf
=
(
u32
*
)(
runtime
->
dma_area
+
rsnd_
dai_pointer_offset
(
io
,
0
));
rsnd_
ssi_pointer_offset
(
mod
,
io
,
0
));
int
shift
=
0
;
switch
(
runtime
->
sample_bits
)
{
...
...
@@ -568,7 +662,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
else
*
buf
=
(
rsnd_mod_read
(
mod
,
SSIRDR
)
>>
shift
);
elapsed
=
rsnd_
dai_pointer_update
(
io
,
sizeof
(
*
buf
));
elapsed
=
rsnd_
ssi_pointer_update
(
mod
,
io
,
sizeof
(
*
buf
));
}
/* DMA only */
...
...
@@ -675,6 +769,18 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
return
ret
;
}
static
int
rsnd_ssi_pointer
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
snd_pcm_uframes_t
*
pointer
)
{
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
*
pointer
=
bytes_to_frames
(
runtime
,
ssi
->
byte_pos
);
return
0
;
}
static
struct
rsnd_mod_ops
rsnd_ssi_pio_ops
=
{
.
name
=
SSI_NAME
,
.
probe
=
rsnd_ssi_common_probe
,
...
...
@@ -683,6 +789,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.
start
=
rsnd_ssi_start
,
.
stop
=
rsnd_ssi_stop
,
.
irq
=
rsnd_ssi_irq
,
.
pointer
=
rsnd_ssi_pointer
,
.
pcm_new
=
rsnd_ssi_pcm_new
,
.
hw_params
=
rsnd_ssi_hw_params
,
};
...
...
@@ -786,13 +893,6 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
}
/*
* Non SSI
*/
static
struct
rsnd_mod_ops
rsnd_ssi_non_ops
=
{
.
name
=
SSI_NAME
,
};
/*
* ssi mod function
*/
...
...
@@ -814,7 +914,8 @@ static void rsnd_ssi_connect(struct rsnd_mod *mod,
type
=
types
[
i
];
if
(
!
rsnd_io_to_mod
(
io
,
type
))
{
rsnd_dai_connect
(
mod
,
io
,
type
);
rsnd_set_slot
(
rdai
,
2
*
(
i
+
1
),
(
i
+
1
));
rsnd_rdai_channels_set
(
rdai
,
(
i
+
1
)
*
2
);
rsnd_rdai_ssi_lane_set
(
rdai
,
(
i
+
1
));
return
;
}
}
...
...
@@ -847,6 +948,47 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
of_node_put
(
node
);
}
static
void
__rsnd_ssi_parse_hdmi_connection
(
struct
rsnd_priv
*
priv
,
struct
rsnd_dai_stream
*
io
,
struct
device_node
*
remote_ep
)
{
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
rsnd_mod
*
mod
=
rsnd_io_to_mod_ssi
(
io
);
struct
rsnd_ssi
*
ssi
;
if
(
!
mod
)
return
;
ssi
=
rsnd_mod_to_ssi
(
mod
);
if
(
strstr
(
remote_ep
->
full_name
,
"hdmi0"
))
{
ssi
->
flags
|=
RSND_SSI_HDMI0
;
dev_dbg
(
dev
,
"%s[%d] connected to HDMI0
\n
"
,
rsnd_mod_name
(
mod
),
rsnd_mod_id
(
mod
));
}
if
(
strstr
(
remote_ep
->
full_name
,
"hdmi1"
))
{
ssi
->
flags
|=
RSND_SSI_HDMI1
;
dev_dbg
(
dev
,
"%s[%d] connected to HDMI1
\n
"
,
rsnd_mod_name
(
mod
),
rsnd_mod_id
(
mod
));
}
}
void
rsnd_ssi_parse_hdmi_connection
(
struct
rsnd_priv
*
priv
,
struct
device_node
*
endpoint
,
int
dai_i
)
{
struct
rsnd_dai
*
rdai
=
rsnd_rdai_get
(
priv
,
dai_i
);
struct
device_node
*
remote_ep
;
remote_ep
=
of_graph_get_remote_endpoint
(
endpoint
);
if
(
!
remote_ep
)
return
;
__rsnd_ssi_parse_hdmi_connection
(
priv
,
&
rdai
->
playback
,
remote_ep
);
__rsnd_ssi_parse_hdmi_connection
(
priv
,
&
rdai
->
capture
,
remote_ep
);
}
struct
rsnd_mod
*
rsnd_ssi_mod_get
(
struct
rsnd_priv
*
priv
,
int
id
)
{
if
(
WARN_ON
(
id
<
0
||
id
>=
rsnd_ssi_nr
(
priv
)))
...
...
@@ -952,7 +1094,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
goto
rsnd_ssi_probe_done
;
}
ops
=
&
rsnd_ssi_non_ops
;
if
(
of_property_read_bool
(
np
,
"pio-transfer"
))
ops
=
&
rsnd_ssi_pio_ops
;
else
...
...
sound/soc/sh/rcar/ssiu.c
View file @
6bf4cd28
...
...
@@ -123,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
)
{
int
hdmi
=
rsnd_ssi_hdmi_port
(
io
);
int
ret
;
ret
=
rsnd_ssiu_init
(
mod
,
io
,
priv
);
...
...
@@ -150,6 +151,42 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
rsnd_get_dalign
(
mod
,
io
));
}
if
(
hdmi
)
{
enum
rsnd_mod_type
rsnd_ssi_array
[]
=
{
RSND_MOD_SSIM1
,
RSND_MOD_SSIM2
,
RSND_MOD_SSIM3
,
};
struct
rsnd_mod
*
ssi_mod
=
rsnd_io_to_mod_ssi
(
io
);
struct
rsnd_mod
*
pos
;
u32
val
;
int
i
,
shift
;
i
=
rsnd_mod_id
(
ssi_mod
);
/* output all same SSI as default */
val
=
i
<<
16
|
i
<<
20
|
i
<<
24
|
i
<<
28
|
i
;
for_each_rsnd_mod_array
(
i
,
pos
,
io
,
rsnd_ssi_array
)
{
shift
=
(
i
*
4
)
+
16
;
val
=
(
val
&
~
(
0xF
<<
shift
))
|
rsnd_mod_id
(
pos
)
<<
shift
;
}
switch
(
hdmi
)
{
case
RSND_SSI_HDMI_PORT0
:
rsnd_mod_write
(
mod
,
HDMI0_SEL
,
val
);
break
;
case
RSND_SSI_HDMI_PORT1
:
rsnd_mod_write
(
mod
,
HDMI1_SEL
,
val
);
break
;
}
}
return
0
;
}
...
...
sound/soc/soc-core.c
View file @
6bf4cd28
...
...
@@ -34,6 +34,7 @@
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/dmi.h>
#include <sound/core.h>
#include <sound/jack.h>
...
...
@@ -3992,11 +3993,15 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
prefix
=
""
;
/*
* check "[prefix]format = xxx"
* check "dai-format = xxx"
* or "[prefix]format = xxx"
* SND_SOC_DAIFMT_FORMAT_MASK area
*/
ret
=
of_property_read_string
(
np
,
"dai-format"
,
&
str
);
if
(
ret
<
0
)
{
snprintf
(
prop
,
sizeof
(
prop
),
"%sformat"
,
prefix
);
ret
=
of_property_read_string
(
np
,
prop
,
&
str
);
}
if
(
ret
==
0
)
{
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
of_fmt_table
);
i
++
)
{
if
(
strcmp
(
str
,
of_fmt_table
[
i
].
name
)
==
0
)
{
...
...
@@ -4076,6 +4081,42 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
}
EXPORT_SYMBOL_GPL
(
snd_soc_of_parse_daifmt
);
int
snd_soc_get_dai_id
(
struct
device_node
*
ep
)
{
struct
snd_soc_component
*
pos
;
struct
device_node
*
node
;
int
ret
;
node
=
of_graph_get_port_parent
(
ep
);
/*
* For example HDMI case, HDMI has video/sound port,
* but ALSA SoC needs sound port number only.
* Thus counting HDMI DT port/endpoint doesn't work.
* Then, it should have .of_xlate_dai_id
*/
ret
=
-
ENOTSUPP
;
mutex_lock
(
&
client_mutex
);
list_for_each_entry
(
pos
,
&
component_list
,
list
)
{
struct
device_node
*
component_of_node
=
pos
->
dev
->
of_node
;
if
(
!
component_of_node
&&
pos
->
dev
->
parent
)
component_of_node
=
pos
->
dev
->
parent
->
of_node
;
if
(
component_of_node
!=
node
)
continue
;
if
(
pos
->
driver
->
of_xlate_dai_id
)
ret
=
pos
->
driver
->
of_xlate_dai_id
(
pos
,
ep
);
break
;
}
mutex_unlock
(
&
client_mutex
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
snd_soc_get_dai_id
);
int
snd_soc_get_dai_name
(
struct
of_phandle_args
*
args
,
const
char
**
dai_name
)
{
...
...
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