From patchwork Fri Sep 10 01:22:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 12484215 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2FD2AC433F5 for ; Fri, 10 Sep 2021 01:25:06 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A7C42610C8 for ; Fri, 10 Sep 2021 01:25:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org A7C42610C8 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=renesas.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 3557B16C1; Fri, 10 Sep 2021 03:24:14 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 3557B16C1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1631237104; bh=3cM1+POFIBxw9h3EocrG6LD6mlI39IV19/t++gey9V8=; h=Date:From:Subject:To:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=OUAefjkEoovDqK9O5gV+eXkZK9zv3wsXPOrQXSthLNlEKlaqnTR4LXJNvN94tuVkP 79irQ22EPORgr3q+maRb/FdE/i8iHK0U2ktRXB62aX/q8SFg6Au6CXmfMOTgkI1GhY ymU0EpwPikK5BtGB5xpHFpujRFwTe2I5HrQUSWM8= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id A4A5AF80515; Fri, 10 Sep 2021 03:22:43 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9AD99F80515; Fri, 10 Sep 2021 03:22:41 +0200 (CEST) Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by alsa1.perex.cz (Postfix) with ESMTP id D5282F804E3 for ; Fri, 10 Sep 2021 03:22:35 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz D5282F804E3 Date: 10 Sep 2021 10:22:34 +0900 X-IronPort-AV: E=Sophos;i="5.85,282,1624287600"; d="scan'208";a="93549121" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 10 Sep 2021 10:22:34 +0900 Received: from mercury.renesas.com (unknown [10.166.252.133]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 361944017D79; Fri, 10 Sep 2021 10:22:34 +0900 (JST) Message-ID: <87ilz9usv9.wl-kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto Subject: [PATCH v3 08/16] ASoC: rich-graph-card: add Codec2Codec support User-Agent: Wanderlust/2.15.9 Emacs/26.3 Mule/6.0 To: Mark Brown In-Reply-To: <87tuitusy4.wl-kuninori.morimoto.gx@renesas.com> References: <87tuitusy4.wl-kuninori.morimoto.gx@renesas.com> MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Cc: Linux-ALSA X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" From: Kuninori Morimoto This patch adds Codec2Codec support to rich-graph-card. It can use Codec2Codec but very simple case only for now. It doesn't have "SWITCH" control yet, thus it start automatically when it was probed, and can't stop, so far. Thus it needs to be updated around widgets/routing handling, and you need to understand that it is under experimental. Codec has SND_SOC_DAPM_INPUT() (= IN) / SND_SOC_DAPM_OUTPUT(= OUT) widgets in below case. It is assuming 2channel, S32_LE format for now. It needs to be updated, too. It needs "codec2codec" node (= C), needs to have routing (= A), need to indicate both CPU side at links (= B). ports@0 is for CPU side (= X), port@1 is Codec side (= Y). It needs to have "rate" (= D) +--+ | |<-- Codec0 <-- IN | |--> Codec1 --> OUT +--+ sound { compatible = "rich-graph-card"; (A) routing = "OUT" ,"DAI1 Playback", "DAI0 Capture", "IN"; (B) links = <&c2c>; (C) codec2codec { ports { (D) rate = <48000>; (X) c2c: port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; (Y) port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; }; }; Codec { ports { port@0 { bitclock-master; frame-master; codec0_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; }; port@1 { codec1_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; }; }; }; Link: https://lore.kernel.org/r/87k0xszlep.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto --- include/sound/graph_card.h | 3 + sound/soc/generic/rich-graph-card.c | 178 ++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h index c7b632d3e5ff..8bc8a78c0d03 100644 --- a/include/sound/graph_card.h +++ b/include/sound/graph_card.h @@ -18,6 +18,7 @@ struct graph_custom_hooks { int (*hook_post)(struct asoc_simple_priv *priv); GRAPH_CUSTOM custom_normal; GRAPH_CUSTOM custom_dpcm; + GRAPH_CUSTOM custom_c2c; }; int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev); @@ -28,5 +29,7 @@ int rich_graph_link_normal(struct asoc_simple_priv *priv, struct device_node *lnk, struct link_info *li); int rich_graph_link_dpcm(struct asoc_simple_priv *priv, struct device_node *lnk, struct link_info *li); +int rich_graph_link_c2c(struct asoc_simple_priv *priv, + struct device_node *lnk, struct link_info *li); #endif /* __GRAPH_CARD_H */ diff --git a/sound/soc/generic/rich-graph-card.c b/sound/soc/generic/rich-graph-card.c index e69fb5e73d62..5a972eda037f 100644 --- a/sound/soc/generic/rich-graph-card.c +++ b/sound/soc/generic/rich-graph-card.c @@ -176,17 +176,54 @@ links indicates connection part of CPU side (= A). }; }; + ************************************ + Codec to Codec + ************************************ + + +--+ + | |<-- Codec0 <- IN + | |--> Codec1 -> OUT + +--+ + + sound { + compatible = "rich-graph-card"; + + routing = "OUT" ,"DAI1 Playback", + "DAI0 Capture", "IN"; + + links = <&c2c>; + + codec2codec { + ports { + rate = <48000>; + c2c: port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; + port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; + }; + }; + + Codec { + ports { + port@0 { + bitclock-master; + frame-master; + codec0_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; }; + port@1 { codec1_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; }; + }; + }; + */ enum graph_type { GRAPH_NORMAL, GRAPH_DPCM, + GRAPH_C2C, GRAPH_MULTI, /* don't use ! Use this only in __graph_get_type() */ }; #define GRAPH_NODENAME_MULTI "multi" #define GRAPH_NODENAME_DPCM "dpcm" +#define GRAPH_NODENAME_C2C "codec2codec" #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint") @@ -212,6 +249,9 @@ static enum graph_type __graph_get_type(struct device_node *lnk) if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) return GRAPH_DPCM; + if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) + return GRAPH_C2C; + return GRAPH_NORMAL; } @@ -236,6 +276,9 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv, else str = "DPCM Back-End"; break; + case GRAPH_C2C: + str = "Codec2Codec"; + break; default: break; } @@ -494,6 +537,13 @@ static int __graph_parse_node(struct asoc_simple_priv *priv, asoc_simple_set_dailink_name(dev, dai_link, "be.%pOFP.%s%s", codecs->of_node, codecs->dai_name, codec_multi); break; + case GRAPH_C2C: + /* run is_cpu only. see rich_graph_link_c2c() */ + if (is_cpu) + asoc_simple_set_dailink_name(dev, dai_link, "c2c.%s%s-%s%s", + cpus->dai_name, cpu_multi, + codecs->dai_name, codec_multi); + break; default: break; } @@ -792,6 +842,88 @@ int rich_graph_link_dpcm(struct asoc_simple_priv *priv, } EXPORT_SYMBOL_GPL(rich_graph_link_dpcm); +int rich_graph_link_c2c(struct asoc_simple_priv *priv, + struct device_node *lnk, + struct link_info *li) +{ + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct snd_soc_pcm_stream *c2c_conf = dai_props->c2c_conf; + struct device_node *port0, *port1, *ports; + struct device_node *codec0_port, *codec1_port; + struct device_node *ep0, *ep1; + u32 val; + int ret = -EINVAL; + + /* + * codec2codec { + * ports { + * rate = <48000>; + * => lnk: port@0 { c2c0_ep: { ... = codec0_ep; }; }; + * port@1 { c2c1_ep: { ... = codec1_ep; }; }; + * }; + * }; + * + * Codec { + * ports { + * port@0 { codec0_ep: ... }; }; + * port@1 { codec1_ep: ... }; }; + * }; + * }; + */ + of_node_get(lnk); + port0 = lnk; + ports = of_get_parent(port0); + port1 = of_get_next_child(ports, lnk); + + if (!of_get_property(ports, "rate", &val)) { + struct device *dev = simple_priv_to_dev(priv); + + dev_err(dev, "Codec2Codec needs rate settings\n"); + goto err; + } + + c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */ + c2c_conf->rate_min = + c2c_conf->rate_max = val; + c2c_conf->channels_min = + c2c_conf->channels_max = 2; /* update ME */ + dai_link->params = c2c_conf; + + ep0 = port_to_endpoint(port0); + ep1 = port_to_endpoint(port1); + + codec0_port = of_graph_get_remote_port(ep0); + codec1_port = of_graph_get_remote_port(ep1); + + /* + * call Codec first. + * see + * __graph_parse_node() :: DAI Naming + */ + ret = graph_parse_node(priv, GRAPH_C2C, codec1_port, li, 0); + if (ret < 0) + goto err; + + /* + * call CPU, and set DAI Name + */ + ret = graph_parse_node(priv, GRAPH_C2C, codec0_port, li, 1); + if (ret < 0) + goto err; + + graph_link_init(priv, codec0_port, li, 1); +err: + of_node_put(ports); + of_node_put(port0); + of_node_put(port1); + of_node_put(ep0); + of_node_put(ep1); + + return ret; +} +EXPORT_SYMBOL_GPL(rich_graph_link_c2c); + static int graph_link(struct asoc_simple_priv *priv, struct graph_custom_hooks *hooks, enum graph_type gtype, @@ -815,6 +947,12 @@ static int graph_link(struct asoc_simple_priv *priv, else func = rich_graph_link_dpcm; break; + case GRAPH_C2C: + if (hooks && hooks->custom_c2c) + func = hooks->custom_c2c; + else + func = rich_graph_link_c2c; + break; default: break; } @@ -916,6 +1054,43 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, return 0; } +static int graph_count_c2c(struct asoc_simple_priv *priv, + struct device_node *lnk, + struct link_info *li) +{ + struct device_node *ports = of_get_parent(lnk); + struct device_node *port0 = lnk; + struct device_node *port1 = of_get_next_child(ports, lnk); + struct device_node *ep0 = port_to_endpoint(port0); + struct device_node *ep1 = port_to_endpoint(port1); + struct device_node *codec0 = of_graph_get_remote_port(ep0); + struct device_node *codec1 = of_graph_get_remote_port(ep1); + + of_node_get(lnk); + + /* + * codec2codec { + * ports { + * => lnk: port@0 { endpoint { ... }; }; + * port@1 { endpoint { ... }; }; + * }; + * }; + */ + li->num[li->link].cpus = + li->num[li->link].platforms = graph_counter(codec0); + li->num[li->link].codecs = graph_counter(codec1); + li->num[li->link].c2c = 1; + + of_node_put(ports); + of_node_put(port1); + of_node_put(ep0); + of_node_put(ep1); + of_node_put(codec0); + of_node_put(codec1); + + return 0; +} + static int graph_count(struct asoc_simple_priv *priv, struct graph_custom_hooks *hooks, enum graph_type gtype, @@ -938,6 +1113,9 @@ static int graph_count(struct asoc_simple_priv *priv, case GRAPH_DPCM: func = graph_count_dpcm; break; + case GRAPH_C2C: + func = graph_count_c2c; + break; default: }