From mboxrd@z Thu Jan 1 00:00:00 1970 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.7 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,URIBL_BLOCKED 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 087CAC07E95 for ; Tue, 20 Jul 2021 01:43:13 +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 67B71610CC for ; Tue, 20 Jul 2021 01:43:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 67B71610CC 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-devel-bounces@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 00D513E; Tue, 20 Jul 2021 03:42:21 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 00D513E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1626745391; bh=L69MH+FiJq7DJKIlzextV0AcPx6ycnJjx3IV9YB19UY=; h=Date:From:Subject:To:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=aE4iO5v75515D9UjnqQXTj3eue7o8x769fV+Z/CyQsd3yVsTTgCDaJyVFsuXviP1u iBsrTWiB5MSRB9nMyAd23f8FMuQmM68W6PNfxwHantZxdEcTndRmcSF/jFqb5XknxI u0osjPWqrrGSNbhDtJAGdIR55UAi+/e13vvbHBX4= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id B1976F8050F; Tue, 20 Jul 2021 03:40:30 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9370EF80518; Tue, 20 Jul 2021 03:40:29 +0200 (CEST) Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by alsa1.perex.cz (Postfix) with ESMTP id 77FE9F8050F for ; Tue, 20 Jul 2021 03:40:25 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 77FE9F8050F Date: 20 Jul 2021 10:40:25 +0900 X-IronPort-AV: E=Sophos;i="5.84,253,1620658800"; d="scan'208";a="88181521" Received: from unknown (HELO relmlir6.idc.renesas.com) ([10.200.68.152]) by relmlie5.idc.renesas.com with ESMTP; 20 Jul 2021 10:40:25 +0900 Received: from mercury.renesas.com (unknown [10.166.252.133]) by relmlir6.idc.renesas.com (Postfix) with ESMTP id 0D8CA4153B50; Tue, 20 Jul 2021 10:40:25 +0900 (JST) Message-ID: <87y2a1vk3a.wl-kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto Subject: [PATCH v2 08/14] ASoC: audio-graph-card2: add Codec2Codec support User-Agent: Wanderlust/2.15.9 Emacs/26.3 Mule/6.0 To: Mark Brown In-Reply-To: <87a6mhwyqn.wl-kuninori.morimoto.gx@renesas.com> References: <87a6mhwyqn.wl-kuninori.morimoto.gx@renesas.com> MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset=US-ASCII 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 audio-graph-card2. It can use Codec2Codec but very limited/simple case only for now. It doesn't have "SWITCH" control yet, thus it start automatically when probed, but 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. It is assuming 2channel, S32_LE format for now. It needs to be updated, too. Codec2Codec support needs to have extra node (= X) to indicate it. Codec2Codec needs "routing" (= A) and "rate" (= C). "links" (= B) needs to indicate Codec2Codec's CPU part node (= D). +--+ | |<-- Codec0 | |--> Codec1 +--+ sound { compatible = "audio-graph-card2"; (A) routing = "OUT" ,"DAI1 Playback", "DAI0 Capture", "IN"; (B) links = <&codec2codec>; }; (X) CODEC2CODEC { compatible = "audio-graph-card2-codec2codec"; (C) rate = <48000>; ports { (D) codec2codec: port@0 { fe_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; port@1 { be_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; }; }; Codec { ports { port@0 { bitclock-master; frame-master; codec0_ep: endpoint { remote-endpoint = <&fe_ep>; }; }; port@1 { codec1_ep: endpoint { remote-endpoint = <&be_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/audio-graph-card2.c | 164 ++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h index d0ccb7afda78..e870ae133a15 100644 --- a/include/sound/graph_card.h +++ b/include/sound/graph_card.h @@ -19,6 +19,7 @@ struct graph_custom_hooks { GRAPH_CUSTOM custom_normal; GRAPH_CUSTOM custom_dpcm; GRAPH_CUSTOM custom_multi; + GRAPH_CUSTOM custom_c2c; }; int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev); @@ -31,5 +32,7 @@ int audio_graph2_link_dpcm(struct asoc_simple_priv *priv, struct device_node *lnk, struct link_info *li); int audio_graph2_link_multi(struct asoc_simple_priv *priv, struct device_node *lnk, struct link_info *li); +int audio_graph2_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/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index f77cf02c0eef..06f8556913e0 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -184,16 +184,58 @@ CPU2 <--> * * <--> Codec2 port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; }; }; + + + ************************************ + Codec to Codec + ************************************ + + +--+ + | |<-- Codec0 + | |--> Codec1 + +--+ + + sound { + compatible = "audio-graph-card2"; + + routing = "OUT" ,"DAI1 Playback", + "DAI0 Capture", "IN"; + + links = <&codec2codec>; + }; + + CODEC2CODEC { + compatible = "audio-graph-card2-codec2codec"; + + rate = <48000>; + ports { + codec2codec: port@0 { fe_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; + port@1 { be_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; + }; + }; + + Codec { + ports { + port@0 { + bitclock-master; + frame-master; + codec0_ep: endpoint { remote-endpoint = <&fe_ep>; }; }; + port@1 { codec1_ep: endpoint { remote-endpoint = <&be_ep>; }; }; + }; + }; + */ enum graph_type { GRAPH_NORMAL, GRAPH_DPCM, GRAPH_MULTI, + GRAPH_C2C, }; #define GRAPH_COMPATIBLE_DPCM "audio-graph-card2-dsp" #define GRAPH_COMPATIBLE_MULTI "audio-graph-card2-multi" +#define GRAPH_COMPATIBLE_C2C "audio-graph-card2-codec2codec" #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint") @@ -220,6 +262,8 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv, type = GRAPH_DPCM; else if (strcmp(string, GRAPH_COMPATIBLE_MULTI) == 0) type = GRAPH_MULTI; + else if (strcmp(string, GRAPH_COMPATIBLE_C2C) == 0) + type = GRAPH_C2C; end: #ifdef DEBUG { @@ -236,6 +280,9 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv, case GRAPH_MULTI: str = "MULTI"; break; + case GRAPH_C2C: + str = "Codec2Codec"; + break; default: break; } @@ -777,6 +824,93 @@ int audio_graph2_link_multi(struct asoc_simple_priv *priv, } EXPORT_SYMBOL_GPL(audio_graph2_link_multi); +int audio_graph2_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 *port = lnk; + struct device_node *ports = of_get_parent(port); + struct device_node *top = of_get_parent(ports); + struct device_node *ep; + struct device_node *rep; + struct device_node *first_rep = NULL; + char dai_name[64]; + u32 val; + int is_cpu; + int ret = -EINVAL; + + /* + * top: CODEC2CODEC { + * compatible = "audio-graph-card2-codec2codec"; + * + * rate = <48000>; + * ports { + * => lnk: port@0 { ep: endpoint { remote-endpoint = <&rep>; }; }; + * port@1 { ... }; + * }; + * }; + */ + if (!of_get_property(top, "rate", &val)) { + struct device *dev = simple_priv_to_dev(priv); + + dev_err(dev, "unknown codec2codec rate\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; + + of_node_get(lnk); + for (is_cpu = 1; is_cpu >= 0; is_cpu--) { + int is_single_links = 0; + + ep = port_to_endpoint(port); + rep = of_graph_get_remote_endpoint(ep); + + if (!first_rep) + first_rep = rep; + + ret = graph_parse_node(priv, rep, li, 0, + is_cpu ? &is_single_links : NULL); + if (ret < 0) + goto err; + + of_node_put(ep); + of_node_put(rep); + + /* + * 1st turn was for CPU part of Codec (is_cpu = 1) + * 2nd turn is for Codec part of Codec (is_cpu = 0) + */ + if (is_cpu) { + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + + asoc_simple_canonicalize_cpu(cpus, is_single_links); + + /* next port = Codec part port */ + port = of_get_next_child(ports, port); + } + } + + snprintf(dai_name, sizeof(dai_name), "codec2codec-%pOFP", top); + + ret = graph_link_init(priv, first_rep, li, 0, dai_name); /* Codec base */ +err: + of_node_put(ports); + of_node_put(port); + of_node_put(top); + + return ret; +} +EXPORT_SYMBOL_GPL(audio_graph2_link_c2c); + static int graph_link(struct asoc_simple_priv *priv, struct graph_custom_hooks *hooks, enum graph_type gtype, @@ -806,6 +940,12 @@ static int graph_link(struct asoc_simple_priv *priv, else func = audio_graph2_link_multi; break; + case GRAPH_C2C: + if (hooks && hooks->custom_c2c) + func = hooks->custom_c2c; + else + func = audio_graph2_link_c2c; + break; } if (!func) { @@ -903,6 +1043,27 @@ static int graph_count_multi(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) +{ + /* + * CODEC2CODEC { + * compatible = "audio-graph-card2-codec2codec"; + * + * ports { + * => lnk: port@0 { endpoint { ... }; }; + * port@1 { endpoint { ... }; }; + * }; + * }; + */ + li->num[li->link].cpus = 1; + li->num[li->link].codecs = 1; + li->num[li->link].c2c = 1; + + return 0; +} + static int graph_count(struct asoc_simple_priv *priv, struct graph_custom_hooks *hooks, enum graph_type gtype, @@ -928,6 +1089,9 @@ static int graph_count(struct asoc_simple_priv *priv, case GRAPH_MULTI: func = graph_count_multi; break; + case GRAPH_C2C: + func = graph_count_c2c; + break; } if (!func) { -- 2.25.1