From patchwork Mon Apr 3 08:15:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 9658931 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 11A4C60353 for ; Mon, 3 Apr 2017 08:16:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F16E128438 for ; Mon, 3 Apr 2017 08:16:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E3D0928450; Mon, 3 Apr 2017 08:16:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A5F2128438 for ; Mon, 3 Apr 2017 08:16:29 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 67237266D74; Mon, 3 Apr 2017 10:16:19 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 749DB266D71; Mon, 3 Apr 2017 10:16:18 +0200 (CEST) Received: from relmlie2.idc.renesas.com (relmlor3.renesas.com [210.160.252.173]) by alsa0.perex.cz (Postfix) with ESMTP id B9606266C9A for ; Mon, 3 Apr 2017 10:15:29 +0200 (CEST) Received: from unknown (HELO relmlir3.idc.renesas.com) ([10.200.68.153]) by relmlie2.idc.renesas.com with ESMTP; 03 Apr 2017 17:15:28 +0900 Received: from relmlac2.idc.renesas.com (relmlac2.idc.renesas.com [10.200.69.22]) by relmlir3.idc.renesas.com (Postfix) with ESMTP id 3A84C6C119; Mon, 3 Apr 2017 17:15:28 +0900 (JST) Received: by relmlac2.idc.renesas.com (Postfix, from userid 0) id 36FEF28076; Mon, 3 Apr 2017 17:15:28 +0900 (JST) Received: from relmlac2.idc.renesas.com (localhost [127.0.0.1]) by relmlac2.idc.renesas.com (Postfix) with ESMTP id 2EAC828070; Mon, 3 Apr 2017 17:15:28 +0900 (JST) Received: from relmlii1.idc.renesas.com [10.200.68.65] by relmlac2.idc.renesas.com with ESMTP id TAA32214; Mon, 3 Apr 2017 17:15:28 +0900 X-IronPort-AV: E=Sophos;i="5.36,269,1486393200"; d="scan'208";a="238552862" Received: from mail-sg2apc01lp0247.outbound.protection.outlook.com (HELO APC01-SG2-obe.outbound.protection.outlook.com) ([65.55.88.247]) by relmlii1.idc.renesas.com with ESMTP/TLS/AES256-SHA256; 03 Apr 2017 17:15:26 +0900 Authentication-Results: kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=none action=none header.from=renesas.com; Received: from morimoto-PC.renesas.com (211.11.155.144) by SIXPR06MB0826.apcprd06.prod.outlook.com (10.162.174.148) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1005.10; Mon, 3 Apr 2017 08:15:24 +0000 Message-ID: <87h925nc5s.wl%kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto To: Mark Brown , Rob Herring In-Reply-To: <87vaqlnceg.wl%kuninori.morimoto.gx@renesas.com> References: <87vaqlnceg.wl%kuninori.morimoto.gx@renesas.com> User-Agent: Wanderlust/2.15.9 Emacs/24.3 Mule/6.0 MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Date: Mon, 3 Apr 2017 08:15:24 +0000 X-Originating-IP: [211.11.155.144] X-ClientProxiedBy: OS1PR01CA0049.jpnprd01.prod.outlook.com (10.164.162.31) To SIXPR06MB0826.apcprd06.prod.outlook.com (10.162.174.148) X-MS-Office365-Filtering-Correlation-Id: 782d4a3e-bcdb-4990-9666-08d47a6994a2 X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(48565401081)(201703131423075)(201703031133081); SRVR:SIXPR06MB0826; X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0826; 3:pcTPv5p7nZGJuuYNisKQzE+i3VuL47qXVXn+BQJ3sf7lbO3X3b+xx19PK85x/6nwC8WunGIc7j0tQM8qcd8ec6/KUXBihlkzwrcfvBjxqqyY1DPa6nKwlv5O/dRDWYxqTJAO+MynrwaGUvj6R5Ed6fd/YOSqeTQX4eOKc587lGRsAzwzhuYflb/OA/WJX/toTZGEJ7gAh3mZNps34/S4UW0Gl8p6ZMWqDFcmQnll4A8WCb4OIKOw8pxhouFms7vmb84XdilqCj/xYoOnsUpQvqvWdUc2aQ+kRICOm14yHAEwwcXWZ4UupL/lYNmUnVu5Q07xe2pDC2/elCjURX7sHH+720E1Bj8NL7ygCInQGgE=; 25:Xw05okpfVnWKzHj6JfUkXcdPZXc+aI5zYNPKoQrZmg2U2BcoG2J6tFEmu7+GSvjshbyD4Z4p/xi8YNqy0RLjV5DZmXawOKN7OsL7brxSkB2fkVCw3KlP5aROQBOBNLp6uDZxjECnO2UJs6yVHfskp3ruYI2kddeLDmmQS401Q0tAGGjjHdVfJMeK1rfOHu3fIo929emo3/qy3dcDg7R2RBPl+uzl94mSJEQ7ioTe99g/X5UxuINlNxxffex3RqzWrTdlzhNfotpBQKa83ZmgslyWeFjNNVPOS/w5bQPP1wDkKUxhsr8mqA/Uu5DX8Im1Uz1600OwsPl3OYPRnjS7omc/tpCm8P4+6YJhVt4iRfj98tWErrTb2uc0UbBs/vwGdNemL7Ea1+rrg8WlI7EzAbo60H29qQNdgTQ1eu/CwpFxQB48Pn16Jfd5g6iVroK9jmBSdFLzrhA/hIZiE9Orhg== X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0826; 31:B+QrQmfXpssgMSlwTwWIe53fSDtKf5oF7msq1EUHGJgrqNJN66VR1cZaSjcXTgPWzz8TwSeZlSZ9wvUGnQXqM2ueav7s1ErCvUzQ2U7QbGqA4xzUjB2oHDUOvWlxa3KDHEJxFLcmnlCAWFlpoikuWd/1yr0xXQrncR97LsJ+ZdrJczlJQpr9WsA3j2RMaLxi5C18grPfW40NVJ2GK3WClvVw6EhcTjTw8PIHC9XFyK349rIJDKVVUzxhl90g+M2ZeXg6paVJWb+hoEYtYqZzaqP46T8Y75d709pVzJ5M/4o=; 20:vNQRZuP3isbp/bA3CtROOdHdWBNxRct3A4qFdmiDxi2KCi9O54HXNki5w2+Y9d/Z1cQBsaKbk1FruiVG2vQfhMt/RuEeuZHU6843XU/Hmo8ST8XeB0iBXWcgfsEq+OD0muL+Hz+wUOBoHCSBIlNN1ugmT/vmS5mwiaFndff/Dm8oan0zzjf7wx0MUxuPKpdS1jpn7l1DS8dKLkx/aF+mwzAIQE6oEyLZwcGXHJ73p2mRyTrQnAkwYvqUz6unqFRsezW53D23Di3sUa0CyC87NzXZHH9+1ah4jyKNzuN4PDkOhiyr4od0W2f85amwD/X+5ONkyqUkvJuqWYQKdivaUpAx5936/awjcC0Hzbwr8Jicm1FpNaiEBXlttisOb70a86Wg3+KuGZV7SwxuWDvNsq7JCl1lLuk1vL7YuwV33zxHscA4JVekOunzZRXAbF4sFEIyFIgzoFJyUzXb2DilOEzMgvoszyfpgVvAXoed+6iomKDC1XJWNpBokHtQHtEI X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040450)(601004)(2401047)(5005006)(8121501046)(3002001)(93006095)(93001095)(10201501046)(6055026)(6041248)(20161123555025)(20161123560025)(20161123562025)(201703131423075)(201702281528075)(201703061421075)(20161123564025)(6072148); SRVR:SIXPR06MB0826; BCL:0; PCL:0; RULEID:; SRVR:SIXPR06MB0826; X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0826; 4:L8OWJH5D8rOYM2wAtsDWU762c0JG0AWLoMaXMiw2QE9IkScQo3Qmme/G9iFU7SG51c/RTpW+5s8lKTeBHR1bRyDRV6/8yY75UtUSyDUEvbxAWrLSmp8mmHEbUI4WxljkGtfgE7r0r4uDvFr2PN6mhGEuwDgDiyEu/sWdSf+6TJdz/OO6t2Is+ZgtuXl3x8gm8J+pha83GXuK9GahG24n0yFV9EjC/cdp3OyA4fx9YzbrJjikVM3hpZdSqscz02TNdgzLs7Qj0r4qrtpliZT8sOkxHA9ddzks1yMlXamZynzz7WIowXKH2tsuRPWMEb592GHexDNQWM6TirMCZs8rcfJ5AaMyxrY7CV8YUYi8S9Pw3Ngagrp9ve4m365ByWeiDeX1INanbIw9QDZBYYryuADGOo4pDMxI8BktjGdLdZwNIwcLhVLPqz2W48eDd1dKRRSa3LSIozM/Oq3N9eSVOcdYRhXUFxtGsUuq7HC6jTAHEHGu08Xy/89H85LNBXdjMMLCdS1O3V/y6hy6aDG0wX3OA/R6qoESkjtpJPDLJPSIrtKOUCq49jU9YJgaRvAeNiaVQSZUlZw6WIQKaqpnUKVlbNHktYdtk33ps6OrK/ZIj5xU2OukwNPAsGtKRax23MogOvFVoD/4SNkchkyZooxFkAIdm/fJxIZNvQQLvN6WAQyzTZ97gWSskKOeu4Y0uxMsspRrkWtjcaOt2Lq1/1aTOnEyNwqw8HqDxVQ5b4M= X-Forefront-PRVS: 0266491E90 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(39400400002)(39840400002)(39410400002)(39850400002)(39860400002)(39450400003)(2950100002)(5660300001)(54906002)(25786009)(83506001)(4001350100001)(23726003)(36756003)(189998001)(305945005)(6486002)(53936002)(6116002)(3846002)(46406003)(66066001)(76176999)(54356999)(4326008)(50986999)(2906002)(8676002)(230783001)(81166006)(53416004)(42186005)(33646002)(38730400002)(86362001)(7736002)(2004002)(16060500001); DIR:OUT; SFP:1102; SCL:1; SRVR:SIXPR06MB0826; H:morimoto-PC.renesas.com; FPR:; SPF:None; MLV:sfv; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; SIXPR06MB0826; 23:HcmpTQR7AqKWGPd0T0Cl5DXXF5EoBfWEAxEMmMrZs?= =?us-ascii?Q?sjoxBVPI04M7bOqQVreH2d4Xm6/DHrrLrIsZUVBirN51UEbDPsLAgId9u1Ct?= =?us-ascii?Q?gR1Ta3VlIfjbVTe9YMZ1/R6cKLel9lC/doSkUxxrZkNp6jGPWnz+HqMcaIBy?= =?us-ascii?Q?h4effcf89d1mOt5vCghg16zeG94s+IcHT5/pffrWvbGVSAhXFieetOY1qOyl?= =?us-ascii?Q?uC4m5s53MgWkltMqWzqoEN/IIGjb/K8utcYFDvy/VNnwVgdxjmEaNr2oL98D?= =?us-ascii?Q?Ef2FRGrvMW+yBJhX+3ZOYtyJe43tUXemul3ENGrUGTgOBrIxjj4pPC8WAZCZ?= =?us-ascii?Q?47J5rbPCpFqKr1aviBuf6KHBAORAimlbDrYTmI63tvjgOJrL+edNfjfAH4Vt?= =?us-ascii?Q?7xF1Um7n5YCgrePMLuYOeeleKjvPFTlLly2VcQAkQrgftz3Ebnnpi7lr2+fB?= =?us-ascii?Q?3+XpZ/vP6LrtgVbF60LLIK1V+oNBSHBLUb//EU1/fnFM00P0he0i5eqpxOL/?= =?us-ascii?Q?3W4JGhOaTEPDK+Ri/es7jvwW+xGuhfIdkj7GSce8TWp1VnCZQYNanPBRUXDi?= =?us-ascii?Q?Gq8bzohG8Hb36CAUYwC0kpJNzwqV4Kk7AYUAR5np7UdyzMTfDPExhg921U2z?= =?us-ascii?Q?Laf6qgv3uq+uZEom0Ug4yPXEk5Jree525qPDW0pbkxpDWdbbVu7hMNx4WKN7?= =?us-ascii?Q?dPc9SoaiYbK1JY3GhFaxslDAKCmLxEN910HBIS8qC2Zv7wghuowZNZx2iAGR?= =?us-ascii?Q?5EV7zzT7ICQX/qJuFDFyH/PBQOfwQe17P7cTV3BpN3n/dl/fzu3GhIU+ROpA?= =?us-ascii?Q?XGsk06H34XZdJ+FhcxZfZq3RMws0tiy/a65e4UV94qMoBnPy+zMnEUCqT+Ga?= =?us-ascii?Q?NaGl41ay1Ej0mcnBKRyHJ02ZKF/R69CtZbJDQbvFOCTjTLSuyOIFyJ5I46TC?= =?us-ascii?Q?JvjIuoXY/2vkRhyv8m+xl1GkYX6u2tSU7hMRTD6h48dtQJzWB4kopmmgRvS0?= =?us-ascii?Q?eHlP/RCWk30xWRLQ3j74/kOqBbEmFNXf4xLUBLulgNtow=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0826; 6:lxaba7Ks7Y1C6MdMzVRWyCZCwVBclKOE5ZeZLWQZ+ds7LQDe1yVAmMCGlPr3Dk2laQZ5/PXmMTGirjeCMvAikUhuhOgRAtAns8rGWugP4qkH+GV8og0409wPyibwKwgmTbJ/JRmiYqdWoaXXJWqidaQQAJDQX0zwA4g/2Gs4uZ99cqg1rTr/EhaepwSw4GbFyXRm9A2Qy5pWVQ03kQq2J1iIB4VAehkzVFA0UfiI2Ze3B1QU+PPuWZCwS8v8tB0aJorV7XFPBY854w9c0cfofrMjLrMbi0tNos4yP+HeGSv+87kcEagHUVIrjAh6YhtCn/lPlRgJjqqRXDrnN14gmnhV96/focudi5ND2OBBQR86o3EDbVHxKENgSqgUYDbcFTDVS0PTVv67/DSeAw875ZPwalmgzFp6j0pNf8ZROag=; 5:zHnt3+3e8hclizVqKA77xc6ypMASAWDNnZDNTnCY6rrf7mcwVmok7baCTgB28RA57Ua5lJp7pKlnehMV1Ld4U0idHhTRAB2p26mvc0s5dxsis2vcWAZT4mLJ3K0jnesXoxonQy3yvdnlHP5klSf8Sw==; 24:3Voh+75cZA407+NRMLcwSxwwA4hNrEAzl2kP9sDgxvEXOAXpbiechI4kB2RWot8DOWYP528/oY82c+eNKnEjdjCxeXb5QOQaJlI8dK6Tue0= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0826; 7:qEk6XRRDCTvhGbE2WSUfJ3Mfw6x7aqM2bC+8OrzfaAZWBWsGvamNTuSROO46omDFT1GVnhdDmsUbL5CkHZJL+UgE1Cl/7SxHHzm9UseFlGKl1YEt9p0To6ls06VkXouYbBkNynZMllwtwJg2NtCIpNeS84KAMJSf2gwWIbZGiOsvYOXcNCbVDciTblaQyRn85PHhsDLPP+9uA6BQTYfJKHtgMLrNHIIk5WXmJiL/uHnYmWpUCzwwHzGi6Qbbi/uND5c2YdQ9GYnGHqaCdDihVdLFA6REq45LTqBH2FpRqU/UeDPTbN/5Cmw9cgkb/DBE0MMTOWhjm6LOtL8bHp4ieQ==; 20:kQKvs1VfmO2aVmIGm08wGNe3f96cIf3zscZgbIwMRpPmu/jesNo3A4k2DkqTtdQLEvYxDd+hJOsGIWlu5Tkb3PUHLnR0MnYcQP+3ebA2S9mRR5YWQAAZ385Ak0svb6Ak5K3tI+0U6MEcM9CqBmqkqVqEZqDStkp+iKDtXt3XX5Q= X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Apr 2017 08:15:24.3514 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: SIXPR06MB0826 Cc: Linux-DT , Linux-ALSA , Simon Subject: [alsa-devel] [resend][PATCH v5 10/10] ASoC: add audio-graph-card support X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 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-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kuninori Morimoto OF-graph base DT binding are used on V4L2, and ALSA SoC is using different style of DT today. Now ALSA SoC supports simple-card driver for generic/simple sound card. In the future, V4L2 / ALSA will support HDMI, and then, DT bindings between V4L2 / ALSA should be merged. This patch adds new Audio Graph Card which is OF-graph base of simple-card Signed-off-by: Kuninori Morimoto --- v4 -> v5 - added graph_priv_to_card() - use of_for_each_phandle() sound/soc/generic/Kconfig | 8 + sound/soc/generic/Makefile | 2 + sound/soc/generic/audio-graph-card.c | 308 +++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 sound/soc/generic/audio-graph-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index d023959..121a48e 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -14,3 +14,11 @@ 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. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index ee750f3..670068f 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,7 +1,9 @@ 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 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 diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c new file mode 100644 index 0000000..07e010d --- /dev/null +++ b/sound/soc/generic/audio-graph-card.c @@ -0,0 +1,308 @@ +/* + * ASoC audio graph sound card support + * + * Copyright (C) 2016 Renesas Solutions Corp. + * Kuninori Morimoto + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 missmatch (%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) + return ret; +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 ");