mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-29 13:00:35 +00:00
Merge branch 'topic/of-graph' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-rcar
This commit is contained in:
commit
5ea929467d
124
Documentation/devicetree/bindings/sound/audio-graph-card.txt
Normal file
124
Documentation/devicetree/bindings/sound/audio-graph-card.txt
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
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";
|
||||||
|
...
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -1,35 +1,29 @@
|
|||||||
ASoC simple SCU Sound Card
|
ASoC Simple 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:
|
Required properties:
|
||||||
|
|
||||||
- compatible : "simple-scu-audio-card"
|
- compatible : "simple-scu-audio-card"
|
||||||
"renesas,rsrc-card"
|
"renesas,rsrc-card"
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|
||||||
- simple-audio-card,name : User specified audio sound card name, one string
|
- simple-audio-card,name : see simple-audio-card.txt
|
||||||
property.
|
- simple-audio-card,cpu : see simple-audio-card.txt
|
||||||
- simple-audio-card,cpu : CPU sub-node
|
- simple-audio-card,codec : see simple-audio-card.txt
|
||||||
- simple-audio-card,codec : CODEC sub-node
|
|
||||||
|
|
||||||
Optional subnode properties:
|
Optional subnode properties:
|
||||||
|
|
||||||
- simple-audio-card,format : CPU/CODEC common audio format.
|
- simple-audio-card,format : see simple-audio-card.txt
|
||||||
"i2s", "right_j", "left_j" , "dsp_a"
|
- simple-audio-card,frame-master : see simple-audio-card.txt
|
||||||
"dsp_b", "ac97", "pdm", "msb", "lsb"
|
- simple-audio-card,bitclock-master : see simple-audio-card.txt
|
||||||
- simple-audio-card,frame-master : Indicates dai-link frame master.
|
- simple-audio-card,bitclock-inversion : see simple-audio-card.txt
|
||||||
phandle to a cpu or codec subnode.
|
- simple-audio-card,frame-inversion : see simple-audio-card.txt
|
||||||
- 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,convert-rate : platform specified sampling rate convert
|
- 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,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.
|
- 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,
|
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.
|
the second being the connection's source. Valid names for sources.
|
||||||
@ -38,19 +32,11 @@ Optional subnode properties:
|
|||||||
|
|
||||||
Required CPU/CODEC subnodes 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:
|
Optional CPU/CODEC subnodes properties:
|
||||||
|
|
||||||
- clocks / system-clock-frequency : specify subnode's clock if needed.
|
- clocks / system-clock-frequency : see simple-audio-card.txt
|
||||||
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().
|
|
||||||
|
|
||||||
Example 1. Sampling Rate Covert
|
Example 1. Sampling Rate Covert
|
||||||
|
|
||||||
@ -59,11 +45,10 @@ sound {
|
|||||||
|
|
||||||
simple-audio-card,name = "rsnd-ak4643";
|
simple-audio-card,name = "rsnd-ak4643";
|
||||||
simple-audio-card,format = "left_j";
|
simple-audio-card,format = "left_j";
|
||||||
simple-audio-card,format = "left_j";
|
|
||||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||||
simple-audio-card,frame-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,prefix = "ak4642";
|
||||||
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
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 {
|
sound {
|
||||||
compatible = "renesas,rsrc-card";
|
compatible = "simple-scu-audio-card";
|
||||||
|
|
||||||
card-name = "rsnd-ak4643";
|
simple-audio-card,name = "rsnd-ak4643";
|
||||||
format = "left_j";
|
simple-audio-card,format = "left_j";
|
||||||
bitclock-master = <&dpcmcpu>;
|
simple-audio-card,bitclock-master = <&dpcmcpu>;
|
||||||
frame-master = <&dpcmcpu>;
|
simple-audio-card,frame-master = <&dpcmcpu>;
|
||||||
|
|
||||||
convert-rate = <48000>; /* see audio_clk_a */
|
simple-audio-card,prefix = "ak4642";
|
||||||
|
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
||||||
audio-prefix = "ak4642";
|
|
||||||
audio-routing = "ak4642 Playback", "DAI0 Playback",
|
|
||||||
"ak4642 Playback", "DAI1 Playback";
|
"ak4642 Playback", "DAI1 Playback";
|
||||||
|
|
||||||
dpcmcpu: cpu@0 {
|
dpcmcpu: cpu@0 {
|
||||||
|
@ -1601,6 +1601,7 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(of_phandle_iterator_init);
|
||||||
|
|
||||||
int of_phandle_iterator_next(struct of_phandle_iterator *it)
|
int of_phandle_iterator_next(struct of_phandle_iterator *it)
|
||||||
{
|
{
|
||||||
@ -1670,6 +1671,7 @@ err:
|
|||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(of_phandle_iterator_next);
|
||||||
|
|
||||||
int of_phandle_iterator_args(struct of_phandle_iterator *it,
|
int of_phandle_iterator_args(struct of_phandle_iterator *it,
|
||||||
uint32_t *args,
|
uint32_t *args,
|
||||||
@ -2484,6 +2486,41 @@ struct device_node *of_graph_get_endpoint_by_regs(
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(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
|
* of_graph_get_remote_port_parent() - get remote port's parent node
|
||||||
* @node: pointer to a local endpoint device_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)
|
const struct device_node *node)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
unsigned int depth;
|
|
||||||
|
|
||||||
/* Get remote endpoint node. */
|
/* 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. */
|
return of_graph_get_port_parent(np);
|
||||||
for (depth = 3; depth && np; depth--) {
|
|
||||||
np = of_get_next_parent(np);
|
|
||||||
if (depth == 2 && of_node_cmp(np->name, "ports"))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return np;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(of_graph_get_remote_port_parent);
|
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;
|
struct device_node *np;
|
||||||
|
|
||||||
/* Get remote endpoint node. */
|
/* Get remote endpoint node. */
|
||||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
np = of_graph_get_remote_endpoint(node);
|
||||||
if (!np)
|
if (!np)
|
||||||
return NULL;
|
return NULL;
|
||||||
return of_get_next_parent(np);
|
return of_get_next_parent(np);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(of_graph_get_remote_port);
|
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
|
* of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
|
||||||
* @node: pointer to parent device_node containing graph port/endpoint
|
* @node: pointer to parent device_node containing graph port/endpoint
|
||||||
|
@ -43,11 +43,15 @@ struct of_endpoint {
|
|||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
int of_graph_parse_endpoint(const struct device_node *node,
|
int of_graph_parse_endpoint(const struct device_node *node,
|
||||||
struct of_endpoint *endpoint);
|
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_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 *of_graph_get_next_endpoint(const struct device_node *parent,
|
||||||
struct device_node *previous);
|
struct device_node *previous);
|
||||||
struct device_node *of_graph_get_endpoint_by_regs(
|
struct device_node *of_graph_get_endpoint_by_regs(
|
||||||
const struct device_node *parent, int port_reg, int reg);
|
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(
|
struct device_node *of_graph_get_remote_port_parent(
|
||||||
const struct device_node *node);
|
const struct device_node *node);
|
||||||
struct device_node *of_graph_get_remote_port(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;
|
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(
|
static inline struct device_node *of_graph_get_port_by_id(
|
||||||
struct device_node *node, u32 id)
|
struct device_node *node, u32 id)
|
||||||
{
|
{
|
||||||
@ -80,6 +89,18 @@ static inline struct device_node *of_graph_get_endpoint_by_regs(
|
|||||||
return NULL;
|
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(
|
static inline struct device_node *of_graph_get_remote_port_parent(
|
||||||
const struct device_node *node)
|
const struct device_node *node)
|
||||||
{
|
{
|
||||||
|
@ -60,6 +60,16 @@ int asoc_simple_card_parse_dai(struct device_node *node,
|
|||||||
const char *cells_name,
|
const char *cells_name,
|
||||||
int *is_single_links);
|
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,
|
int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
|
||||||
struct asoc_simple_dai *simple_dai);
|
struct asoc_simple_dai *simple_dai);
|
||||||
|
|
||||||
|
@ -803,6 +803,8 @@ struct snd_soc_component_driver {
|
|||||||
int (*of_xlate_dai_name)(struct snd_soc_component *component,
|
int (*of_xlate_dai_name)(struct snd_soc_component *component,
|
||||||
struct of_phandle_args *args,
|
struct of_phandle_args *args,
|
||||||
const char **dai_name);
|
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,
|
void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type,
|
||||||
int subseq);
|
int subseq);
|
||||||
int (*stream_event)(struct snd_soc_component *, int event);
|
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,
|
const char *prefix,
|
||||||
struct device_node **bitclkmaster,
|
struct device_node **bitclkmaster,
|
||||||
struct device_node **framemaster);
|
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,
|
int snd_soc_get_dai_name(struct of_phandle_args *args,
|
||||||
const char **dai_name);
|
const char **dai_name);
|
||||||
int snd_soc_of_get_dai_name(struct device_node *of_node,
|
int snd_soc_of_get_dai_name(struct device_node *of_node,
|
||||||
|
@ -14,3 +14,11 @@ config SND_SIMPLE_SCU_CARD
|
|||||||
help
|
help
|
||||||
This option enables generic simple SCU sound card support.
|
This option enables generic simple SCU sound card support.
|
||||||
It supports DPCM of multi CPU single Codec system.
|
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.
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
snd-soc-simple-card-utils-objs := simple-card-utils.o
|
snd-soc-simple-card-utils-objs := simple-card-utils.o
|
||||||
snd-soc-simple-card-objs := simple-card.o
|
snd-soc-simple-card-objs := simple-card.o
|
||||||
snd-soc-simple-scu-card-objs := simple-scu-card.o
|
snd-soc-simple-scu-card-objs := simple-scu-card.o
|
||||||
|
snd-soc-audio-graph-card-objs := audio-graph-card.o
|
||||||
|
|
||||||
obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.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_CARD) += snd-soc-simple-card.o
|
||||||
obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-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
|
||||||
|
310
sound/soc/generic/audio-graph-card.c
Normal file
310
sound/soc/generic/audio-graph-card.c
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
|
||||||
|
dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
|
||||||
|
dev_dbg(dev, "\tcpu : %s / %d\n",
|
||||||
|
dai_link->cpu_dai_name,
|
||||||
|
cpu_dai->sysclk);
|
||||||
|
dev_dbg(dev, "\tcodec : %s / %d\n",
|
||||||
|
dai_link->codec_dai_name,
|
||||||
|
codec_dai->sysclk);
|
||||||
|
|
||||||
|
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>");
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_graph.h>
|
||||||
#include <sound/simple_card_utils.h>
|
#include <sound/simple_card_utils.h>
|
||||||
|
|
||||||
int asoc_simple_card_parse_daifmt(struct device *dev,
|
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 *bitclkmaster = NULL;
|
||||||
struct device_node *framemaster = NULL;
|
struct device_node *framemaster = NULL;
|
||||||
int prefix_len = prefix ? strlen(prefix) : 0;
|
|
||||||
unsigned int daifmt;
|
unsigned int daifmt;
|
||||||
|
|
||||||
daifmt = snd_soc_of_parse_daifmt(node, prefix,
|
daifmt = snd_soc_of_parse_daifmt(node, prefix,
|
||||||
&bitclkmaster, &framemaster);
|
&bitclkmaster, &framemaster);
|
||||||
daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
|
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
|
* No dai-link level and master setting was not found from
|
||||||
* sound node level, revert back to legacy DT parsing and
|
* sound node level, revert back to legacy DT parsing and
|
||||||
@ -81,15 +81,21 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name);
|
|||||||
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
||||||
char *prefix)
|
char *prefix)
|
||||||
{
|
{
|
||||||
char prop[128];
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
snprintf(prop, sizeof(prop), "%sname", prefix);
|
if (!prefix)
|
||||||
|
prefix = "";
|
||||||
|
|
||||||
/* Parse the card name from DT */
|
/* Parse the card name from DT */
|
||||||
ret = snd_soc_of_parse_card_name(card, prop);
|
ret = snd_soc_of_parse_card_name(card, "label");
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
return ret;
|
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)
|
if (!card->name && card->dai_link)
|
||||||
card->name = card->dai_link->name;
|
card->name = card->dai_link->name;
|
||||||
@ -165,6 +171,71 @@ int asoc_simple_card_parse_dai(struct device_node *node,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai);
|
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,
|
int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
|
||||||
struct asoc_simple_dai *simple_dai)
|
struct asoc_simple_dai *simple_dai)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_graph.h>
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/jack.h>
|
#include <sound/jack.h>
|
||||||
@ -3960,11 +3961,15 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
|
|||||||
prefix = "";
|
prefix = "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check "[prefix]format = xxx"
|
* check "dai-format = xxx"
|
||||||
|
* or "[prefix]format = xxx"
|
||||||
* SND_SOC_DAIFMT_FORMAT_MASK area
|
* SND_SOC_DAIFMT_FORMAT_MASK area
|
||||||
*/
|
*/
|
||||||
snprintf(prop, sizeof(prop), "%sformat", prefix);
|
ret = of_property_read_string(np, "dai-format", &str);
|
||||||
ret = of_property_read_string(np, prop, &str);
|
if (ret < 0) {
|
||||||
|
snprintf(prop, sizeof(prop), "%sformat", prefix);
|
||||||
|
ret = of_property_read_string(np, prop, &str);
|
||||||
|
}
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) {
|
for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) {
|
||||||
if (strcmp(str, of_fmt_table[i].name) == 0) {
|
if (strcmp(str, of_fmt_table[i].name) == 0) {
|
||||||
@ -4044,6 +4049,42 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
|
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,
|
int snd_soc_get_dai_name(struct of_phandle_args *args,
|
||||||
const char **dai_name)
|
const char **dai_name)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user