Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
85ee1f42
Commit
85ee1f42
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
51fa6a8f
82885913
Changes
28
Hide 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 @
85ee1f42
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 @
85ee1f42
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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
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 @
85ee1f42
/*
* 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 @
85ee1f42
/*
* 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 @
85ee1f42
...
...
@@ -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
,
prop
);
if
(
ret
<
0
)
return
ret
;
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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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,32 +953,132 @@ 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
;
int
io_i
;
rdai
=
rsnd_rdai_get
(
priv
,
dai_i
);
drv
=
priv
->
daidrv
+
dai_i
;
io_playback
=
&
rdai
->
playback
;
io_capture
=
&
rdai
->
capture
;
snprintf
(
rdai
->
name
,
RSND_DAI_NAME_SIZE
,
"rsnd-dai.%d"
,
dai_i
);
rdai
->
priv
=
priv
;
drv
->
name
=
rdai
->
name
;
drv
->
ops
=
&
rsnd_soc_dai_ops
;
snprintf
(
rdai
->
playback
.
name
,
RSND_DAI_NAME_SIZE
,
"DAI%d Playback"
,
dai_i
);
drv
->
playback
.
rates
=
RSND_RATES
;
drv
->
playback
.
formats
=
RSND_FMTS
;
drv
->
playback
.
channels_min
=
2
;
drv
->
playback
.
channels_max
=
16
;
drv
->
playback
.
stream_name
=
rdai
->
playback
.
name
;
snprintf
(
rdai
->
capture
.
name
,
RSND_DAI_NAME_SIZE
,
"DAI%d Capture"
,
dai_i
);
drv
->
capture
.
rates
=
RSND_RATES
;
drv
->
capture
.
formats
=
RSND_FMTS
;
drv
->
capture
.
channels_min
=
2
;
drv
->
capture
.
channels_max
=
16
;
drv
->
capture
.
stream_name
=
rdai
->
capture
.
name
;
rdai
->
playback
.
rdai
=
rdai
;
rdai
->
capture
.
rdai
=
rdai
;
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
);
capture
=
of_parse_phandle
(
dai_np
,
"capture"
,
io_i
);
if
(
!
playback
&&
!
capture
)
break
;
dai_node
=
rsnd_dai_of_node
(
priv
);
nr
=
of_get_child_count
(
dai_node
);
if
(
!
nr
)
{
ret
=
-
EINVAL
;
goto
rsnd_dai_probe_done
;
rsnd_parse_connect_ssi
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_src
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_ctu
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_mix
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_dvc
(
rdai
,
playback
,
capture
);
of_node_put
(
playback
);
of_node_put
(
capture
);
}
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"
:
" -- "
);
}
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
;
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
);
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
)
{
ret
=
-
ENOMEM
;
goto
rsnd_dai_probe_done
;
}
if
(
!
rdrv
||
!
rdai
)
return
-
ENOMEM
;
priv
->
rdai_nr
=
nr
;
priv
->
daidrv
=
rdrv
;
...
...
@@ -855,68 +1088,18 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
* parse all dai
*/
dai_i
=
0
;
for_each_child_of_node
(
dai_node
,
dai_np
)
{
rdai
=
rsnd_rdai_get
(
priv
,
dai_i
);
drv
=
rdrv
+
dai_i
;
io_playback
=
&
rdai
->
playback
;
io_capture
=
&
rdai
->
capture
;
snprintf
(
rdai
->
name
,
RSND_DAI_NAME_SIZE
,
"rsnd-dai.%d"
,
dai_i
);
rdai
->
priv
=
priv
;
drv
->
name
=
rdai
->
name
;
drv
->
ops
=
&
rsnd_soc_dai_ops
;
snprintf
(
rdai
->
playback
.
name
,
RSND_DAI_NAME_SIZE
,
"DAI%d Playback"
,
dai_i
);
drv
->
playback
.
rates
=
RSND_RATES
;
drv
->
playback
.
formats
=
RSND_FMTS
;
drv
->
playback
.
channels_min
=
2
;
drv
->
playback
.
channels_max
=
6
;
drv
->
playback
.
stream_name
=
rdai
->
playback
.
name
;
snprintf
(
rdai
->
capture
.
name
,
RSND_DAI_NAME_SIZE
,
"DAI%d Capture"
,
dai_i
);
drv
->
capture
.
rates
=
RSND_RATES
;
drv
->
capture
.
formats
=
RSND_FMTS
;
drv
->
capture
.
channels_min
=
2
;
drv
->
capture
.
channels_max
=
6
;
drv
->
capture
.
stream_name
=
rdai
->
capture
.
name
;
rdai
->
playback
.
rdai
=
rdai
;
rdai
->
capture
.
rdai
=
rdai
;
rsnd_set_slot
(
rdai
,
2
,
1
);
/* default */
for
(
io_i
=
0
;;
io_i
++
)
{
playback
=
of_parse_phandle
(
dai_np
,
"playback"
,
io_i
);
capture
=
of_parse_phandle
(
dai_np
,
"capture"
,
io_i
);
if
(
!
playback
&&
!
capture
)
break
;
rsnd_parse_connect_ssi
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_src
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_ctu
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_mix
(
rdai
,
playback
,
capture
);
rsnd_parse_connect_dvc
(
rdai
,
playback
,
capture
);
of_node_put
(
playback
);
of_node_put
(
capture
);
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
++
;
}
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"
:
" -- "
);
}
else
{
for_each_child_of_node
(
dai_node
,
dai_np
)
__rsnd_dai_probe
(
priv
,
dai_np
,
dai_i
++
,
is_graph
);
}
ret
=
0
;
rsnd_dai_probe_done:
of_node_put
(
dai_node
);
return
ret
;
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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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,45 +281,25 @@ 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
];
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
;
main_rate
=
rsnd_ssi_clk_query
(
priv
,
rate
,
chan
,
&
idx
);
if
(
!
main_rate
)
{
dev_err
(
dev
,
"unsupported clock rate
\n
"
);
return
-
EIO
;
}
ssi
->
rate
=
rate
;
ret
=
rsnd_adg_ssi_clk_try_start
(
mod
,
main_rate
);
if
(
ret
<
0
)
return
ret
;
dev_dbg
(
dev
,
"%s[%d] outputs %u Hz
\n
"
,
rsnd_mod_name
(
mod
),
rsnd_mod_id
(
mod
),
rate
)
;
ssi
->
cr_clk
=
FORCE
|
SWL_32
|
SCKD
|
SWSD
|
CKDV
(
idx
);
ssi
->
wsr
=
CONT
;
ssi
->
rate
=
rate
;
return
0
;
}
}
dev_dbg
(
dev
,
"%s[%d] outputs %u Hz
\n
"
,
rsnd_mod_name
(
mod
),
rsnd_mod_id
(
mod
),
rate
);
dev_err
(
dev
,
"unsupported clock rate
\n
"
);
return
-
EIO
;
return
0
;
}
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 @
85ee1f42
...
...
@@ -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 @
85ee1f42
...
...
@@ -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
*/
snprintf
(
prop
,
sizeof
(
prop
),
"%sformat"
,
prefix
);
ret
=
of_property_read_string
(
np
,
prop
,
&
str
);
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