From patchwork Wed Mar 16 07:02:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zidan Wang X-Patchwork-Id: 8594991 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B1BB49F6E1 for ; Wed, 16 Mar 2016 06:59:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2BACB203B6 for ; Wed, 16 Mar 2016 06:59:03 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 10CD2202E6 for ; Wed, 16 Mar 2016 06:59:01 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 41AAD2657FC; Wed, 16 Mar 2016 07:58:59 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Status: No, score=-1.8 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, DKIM_SIGNED,NO_DNS_FOR_FROM,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 027F8261293; Wed, 16 Mar 2016 07:58:51 +0100 (CET) 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 D99282614FD; Wed, 16 Mar 2016 07:58:48 +0100 (CET) Received: from na01-by2-obe.outbound.protection.outlook.com (mail-by2on0113.outbound.protection.outlook.com [207.46.100.113]) by alsa0.perex.cz (Postfix) with ESMTP id 9720B261171 for ; Wed, 16 Mar 2016 07:58:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freescale.onmicrosoft.com; s=selector1-freescale-com; h=From:To:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=ANinPvvBS98RII2N3M4+QXwasffJ1TVbZud6V5tCY+g=; b=ngPNHMY2QI3DvCMr0FBQo1pBoiSyTL4Y9hF2sTWeydpLmCfotxEW7lfG5Wa269OTfGCqQIMNV2BHDDdJJDlRwWaX4aW4HSvuINvmmtIJTZrsrDhFtpgQXmDdWz/ijqjOk4NRLVBBPoGSwCFwhe0VQlb3S3uRqw4vNbRdWS/Mxi0= Received: from BY2PR03CA079.namprd03.prod.outlook.com (10.141.249.52) by BY1PR0301MB1255.namprd03.prod.outlook.com (10.161.203.27) with Microsoft SMTP Server (TLS) id 15.1.434.16; Wed, 16 Mar 2016 06:58:40 +0000 Received: from BN1BFFO11FD025.protection.gbl (2a01:111:f400:7c10::1:165) by BY2PR03CA079.outlook.office365.com (2a01:111:e400:2c5d::52) with Microsoft SMTP Server (TLS) id 15.1.434.16 via Frontend Transport; Wed, 16 Mar 2016 06:58:40 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=freescale.com; freescale.mail.onmicrosoft.com; dkim=none (message not signed) header.d=none; freescale.mail.onmicrosoft.com; dmarc=none action=none header.from=freescale.com; Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BN1BFFO11FD025.mail.protection.outlook.com (10.58.144.88) with Microsoft SMTP Server (TLS) id 15.1.434.11 via Frontend Transport; Wed, 16 Mar 2016 06:58:40 +0000 Received: from b50113.ap.freescale.net (b50113.ap.freescale.net [10.192.241.147]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id u2G6wZLP023939; Tue, 15 Mar 2016 23:58:36 -0700 From: Zidan Wang To: Date: Wed, 16 Mar 2016 15:02:14 +0800 Message-ID: <2b3ab1bf0f38a0618dab05280b6339e6d264dc5c.1458111513.git.zidan.wang@freescale.com> X-Mailer: git-send-email 1.9.1 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(2980300002)(1109001)(1110001)(339900001)(3190300001)(199003)(189002)(85426001)(92566002)(47776003)(2351001)(105606002)(81166005)(104016004)(5890100001)(106466001)(6806005)(15975445007)(19580395003)(77096005)(5008740100001)(4001430100002)(229853001)(118296001)(1096002)(189998001)(107886002)(1220700001)(586003)(110136002)(11100500001)(50226001)(48376002)(2906002)(50466002)(36756003)(19580405001)(33646002)(5003940100001)(50986999)(86362001)(4326007); DIR:OUT; SFP:1102; SCL:1; SRVR:BY1PR0301MB1255; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; MLV:sfv; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1BFFO11FD025; 1:YeZHlKWCRYx84BiHgoJUKNiJB+2Bq7P3cqnp9c5Al7yhr5u71MLsimveo0f5l1h/l4k0NfE4u5N4P+eEZzusED+eCC2TWQif6ayfTOtIgxjwLVxqp3dJgdqaT7m5Bh40/pcDKzyMfTt+Cl6sm+WAxEIxNarolbdSujmpvqiT2w1Qb1x3Ia7qn9QxMqMk/sXHeW41x73nzqMuvf6qb59YcygXfA/C5NK087qaJtQ/8hvOw+J1V9os3pQj5FsqyhO8kWxXWg11RxAopE+n9KavPVcgIFDEY1OGGqH4A/bb/NOzxIkqrIycnZzBgKTbjlgl5/HfD9Wrb0Nmz7DJ1w31ojv/KKxs/tZ6f1tSOqg9VkJnFwOM5RGANqmqnfexR36+7BhKyDnrxp1Datv4lj/PV1pB1WU3dSaPwM0WG0FVW+wftkUqyWE5sBQx9BNftxYxpshoM1lSYoQq9LQ3nQYloNJHXPmmAH4mwPUfoQcNgfjfnB5W3eGg6Q1TJAcsprFJgyOPFPEPpC95RTlkL8uHPw== MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 2c4c287f-c78f-488c-337f-08d34d6867d5 X-Microsoft-Exchange-Diagnostics: 1; BY1PR0301MB1255; 2:1pU/koNzrermp0WVY9V5Sx9UR+Vb66o+Cq8cMMolzEyVLYPBRr11Q3dasXdZmrfCoW4LxT6euzEck2qvzwqdG94rmAgGiVaILtyzihPONAPWikL6Soj3LwxN9XFH9/wq6GjWz5ssUztn6jU0SlBPaQL8EBMaS5ilW6y1NiNSSMkca8l61G3m0mRQvwpFWADX; 3:gX1iJtdQ6bEbXPigrqjXBkTS4iHrXk73WgNLgP6F71e2G3YZSJGJraZuX9VeecsAo4JOQOELYAR7G6dZwAOH3UNvXo7R0hbCNfaqNsbFvsP4omtbzbEqVB60+uiYoL2MUgiYOEv1MGjfaEePuoWrT2NpgndWV7J2sXdGZVa/0NRzkTxirj/bm3r58i5GjzRkQlXDl9DX6CyINb9ZtcGpiGs6EL26ssOtq1lw9c8MgCQ=; 25:DsR/cQm6kByZoCLQ8E3q+x8vyUNIoMukBqZMKs/K08eyZYsndUzdQpBAvIeOzFVCcrJVW7yrT7JHixbH2USxqHV1bRID0IQw9+7UrXHSy8keW+db0+N24qjQ+K7WKvsbiWOiso5WzplNLxoXb3m/fy3hci3x3Lp8kTCZSq+HGkHhYBD17ZYV//c+BmDguhPoACNHiX0afwl1IIm8ygjjFvJSHo2rzdMqwrb9FZ2JJPQ3bWc+azVBPIo2rbSlEBelH8MWCRkSyDJlxPkPv25FIxz3gue4HEKpsQTkB57ObJ8pREZ40K2FHXZqzIUiwj5rS6gRJc/7Bn4de6pep8ck5A== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY1PR0301MB1255; X-Microsoft-Exchange-Diagnostics: 1; BY1PR0301MB1255; 20:x0Ul8B5rkgZ5VAANJVFK4ZLoCJXHSiLWHyBakhmnZOoExUMLJ9cYR+m2+R1wbG10xgpFhDzupRRkKZ3Jw/Ju2wxIUh0q+3Q0nven9aKnT43kuM7IuuCzL6nON2OmRROSz/dTtppxtWNuljSn4CGbvPJ5d3moWbq4MyNcfmlcl/9np24eKQ1wB1K2YNPpAPiIndbNQsJcXwvpTjsnbhgYe51bTl6a8ze7TCPv2oezlYbdSZWCTKyb6dKj2YIm18SoscSWf+n7HFbxIMxI9cOBRokW8B07XHlJWxZs7yyOCt5Jimk5t/5EFf4uPTg53LgPstKqEJZfLyo4g1OqEwYMUKd7+wKIObYacY5bFeR13EsEtXKUvB/2Ked2mkp7X+MTZO7cAkKmWnnAiozDMS7eS9usfs5Y6cnszBcZ6xos0B0n9Xkg1lCT5Mapr81mfpzm; 4:2n6xQ3grh/0mhrtBpQTriV7Sc14gu2aoa2srUjviugMWIx0kJHbIHpvXF1cGEQTuQijh8h7eWsFxOYTYDqQZSUBpN9Zha2SNHP0PdPjKJGVuoF6TAqDVn7vYpihQFGIaZyMSyeB1QhpxInqPzopHtleBPmO9MS5ScbhhgiCVIw7rOVdFXsmc1dSSI1SJBNQsCaM48d+4aALEzo7k4Ef9AQS/qiAh1XgexqKJ2tnOLOJk1x84vpiWQs2sBB+d1PFqriXivZ9KUpOPoAHUyP9T6nJnqYEcr1/1ncODO70gKAJ/9UMMA1lcwZVJKnOynT41IMNvYUfk5PxbtdjwBn8vvJKYuwQuUoe9R38IxqYupEisf9QFUgr9Px5u8Zb2CFXURUAP9T7Sehft+/tkj+EpjBEKtkODgn5FZayTg3PpQwMGkb+D73X8rr4MWdHO3sthWFOz7GQDdT5/8FiMqpcrKQ== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13024025)(13015025)(13018025)(13017025)(13023025)(5005006)(8121501046)(10201501046)(3002001); SRVR:BY1PR0301MB1255; BCL:0; PCL:0; RULEID:; SRVR:BY1PR0301MB1255; X-Forefront-PRVS: 08831F51DC X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY1PR0301MB1255; 23:YK6afrEKqWZ3BA9MP4BQ12smiWNuyu91+ltYDC8?= =?us-ascii?Q?XFxTAvZx4crg9J3Irj68yhKhWcyO8UDrj4EHnCk2zVI24uwC5y37o4yJOHOo?= =?us-ascii?Q?jhCeTBG37PCSOnfmfWZKwpf6JYeO7OBHGTKpOYSe0Q88F7z3LHA916nWGXC5?= =?us-ascii?Q?eQY1y6DdfI8v0lWY1YmXLIcSJp7uzj7rY17AQtaparB8nxcuRBraPLFxKFpG?= =?us-ascii?Q?zGOBvUsZqci6ue4Ugy3aFK8nQ0LC4ToSSUorVGZ7aStfrEOUaFbaefqh8pd+?= =?us-ascii?Q?hST9FWXxl+OvWa9Luyf6uWA7RPDVfa0q1PpI1d8ua+3wArjB8aH9DjTRjBrQ?= =?us-ascii?Q?LWnpwUVwtLX6qniEaoOVaX+Ypscg45b6uc9GQru1aLLoA9lqke7oEdWXjyFb?= =?us-ascii?Q?+TdNikp3MFh4n0rXfo4Y087pQYlQhVgvxEWjP3U8acco5FyzSKeDAZ5VHL1w?= =?us-ascii?Q?vmcwdkfMggQYZvyp9JEQkt+RrtEnlE7UKx2AFWaMx+2534n4UOBXSxyd+vtH?= =?us-ascii?Q?Q4a1gbVwtILutmClIyCWYKeH2gmBHwG4+zTohkhvi2HpmFHRGhY7daFhQUWH?= =?us-ascii?Q?R9yZAuY+2xJnsIJdz2heOFbDLepLtMcF8YEW3zizQOcqUqd8fik2uBErsvdA?= =?us-ascii?Q?MH8fHNo/LzJ75/mwnLFGBQqpEM+VXme/YCJ4QWGIpnYP1JeAfl7chxTIfKKB?= =?us-ascii?Q?dstx06QtWR6r1pURHFGIU6A04/YikI4GLI9gpPibvW0+sI4Nn/2SUSSleOPr?= =?us-ascii?Q?uHXLnzM0chY8KlvDYd9V7aJ1Xbz8v/tdPVgDyAgLjZc0Xx2xLBwYjWomDJ7I?= =?us-ascii?Q?W+5CY/DeCcbhGgc2kl1lKuF/W0Pg9hBEAYrFM7gxZ80Z7HJwS42H5F1lrerv?= =?us-ascii?Q?IxkesBY7JRPyGjDk0zTgczVAQnJgf+4C1lCI6hi4i8grOJWSyJuPJBIbfUWd?= =?us-ascii?Q?ioxNNNRUgeLU0uE4gZDzckzNxk+mky7+kMakhe08UfCYS1+iFV+SnvRnyX2p?= =?us-ascii?Q?psuEnzXk6rGlyJg1bf67jATbiJR/QUQeewvsFCqrlviqrDSOvRO9oMMyHNEJ?= =?us-ascii?Q?HdQDj6qD8ZzZYrY1CKagpZavKHy6phqY9PGr3N+la6sysNSjQk9FtYKb2FuD?= =?us-ascii?Q?27oar4PqV1tY4TJ5uDU0lZXeGJ3cpF8SZ?= X-Microsoft-Exchange-Diagnostics: 1; BY1PR0301MB1255; 5:dHYppknvsukfOt71uH6R15wegVniKeIN++imIhRfJUxK92gqcpsjdT3t2+SFAMfQywqC9Ulxnsbs+6lSjCx81oBp7vu5iVICp7cCgVqKGeIYAirIW++EkPxFgJfh+ITF018SWkhaE6guPWggLsHx7Q==; 24:wXq6Y20N08LXpzZbvNZzL4kfGIIlMaJuM2QddLvFt4ZvIxF08B0uk5ZX9xVmDCaJ0FEAThQyKMn+hxk6czpROseVmBAZjRLCGM6rVErsK1I= X-OriginatorOrg: freescale.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Mar 2016 06:58:40.1619 (UTC) X-MS-Exchange-CrossTenant-Id: 710a03f5-10f6-4d38-9ff4-a80b81da590d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=710a03f5-10f6-4d38-9ff4-a80b81da590d; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY1PR0301MB1255 Cc: nicoleotsuka@gmail.com, alsa-devel@alsa-project.org, Zidan Wang , Xiubo.Lee@gmail.com Subject: [alsa-devel] [PATCH v6] ASoC: imx-wm8958: add imx-wm8958 machine driver 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 This is an initial imx-wm8958 device-tree-only machine driver. The sound card driver support three dai link, AIF1-DAI, AIF2-DAI and AIF3-DAI. We can configure the cpu dai from device tree, if present it will create corresponding sound card subdevice. At least one cpu dai phandle should be set from device tree. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen --- v5->v6: some header files should be moved to the next patch. So remove it. .../devicetree/bindings/sound/imx-audio-wm8958.txt | 69 +++++ sound/soc/fsl/Kconfig | 14 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/imx-wm8958.c | 325 +++++++++++++++++++++ 4 files changed, 410 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/imx-audio-wm8958.txt create mode 100644 sound/soc/fsl/imx-wm8958.c diff --git a/Documentation/devicetree/bindings/sound/imx-audio-wm8958.txt b/Documentation/devicetree/bindings/sound/imx-audio-wm8958.txt new file mode 100644 index 0000000..7978c62 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/imx-audio-wm8958.txt @@ -0,0 +1,69 @@ +Freescale i.MX audio complex with WM8958 codec + +Required properties: + + - compatible : "fsl,imx-audio-wm8958" + + - model : The user-visible name of this sound complex + + - audio-codec : The phandle of the WM8958 audio codec + + - audio-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 could be power + supplies, WM8958 pins, and the jacks on the board: + + Power supplies: + * MICBIAS1 + * MICBIAS2 + + Board connectors: + * Headphone Jack + * Ext Spk + +Optional properties: + + - cpu-dai1 : The phandle of CPU DAI1 controller, which is for + aif1 of wm8958. At least one cpu dai is required. + + - cpu-dai2 : The phandle of CPU DAI2 controller, which is for + aif2 of wm8958. At least one cpu dai is required. + + - cpu-dai3 : The phandle of CPU DAI3 controller, which is for + aif3 of wm8958. At least one cpu dai is required. + + - dai-link1-name : If present, set the dai link1 name and stream name + to the specific strings. Otherwise, set the dai + link1 name and stream name to "AIF1-DAI". + + - dai-link2-name : If present, set the dai link2 name and stream name + to the specific strings. Otherwise, set the dai + link2 name and stream name to "AIF2-DAI". + + - dai-link3-name : If present, set the dai link3 name and stream name + to the specific strings. Otherwise, set the dai + link3 name and stream name to "AIF3-DAI". + + - fsl,cpu-dai1-master : If present, cpu dai1 works as master, and will + provide bit clock and frame clock. Otherwise, + cpu dai1 works as slave. + +Example: + +sound { + compatible = "fsl,imx6ul-ddr3-arm2-wm8958", + "fsl,imx-audio-wm8958"; + model = "wm8958-audio"; + cpu-dai1 = <&sai1>; + dai-link1-name = "Hifi"; + audio-codec = <&codec>; + audio-routing = + "Headphone Jack", "HPOUT1L", + "Headphone Jack", "HPOUT1R", + "Ext Spk", "SPKOUTLP", + "Ext Spk", "SPKOUTLN", + "Ext Spk", "SPKOUTRP", + "Ext Spk", "SPKOUTRN", + "IN1LN", "MICBIAS2"; +}; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 35aabf9..f6e5d96 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -229,6 +229,20 @@ config SND_SOC_EUKREA_TLV320 Enable I2S based access to the TLV320AIC23B codec attached to the SSI interface +config SND_SOC_IMX_WM8958 + tristate "SoC Audio support for i.MX boards with wm8958" + depends on OF && I2C + select MFD_WM8994 + select SND_SOC_WM8994 + select SND_SOC_IMX_PCM_DMA + select SND_SOC_FSL_SAI + select SND_SOC_FSL_UTILS + select SND_KCTL_JACK + help + SoC Audio support for i.MX boards with WM8958 + Say Y if you want to add support for SoC audio on an i.MX board with + a wm8958 codec. + config SND_SOC_IMX_WM8962 tristate "SoC Audio support for i.MX boards with wm8962" depends on OF && I2C && INPUT diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index d28dc25..2a781c0 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -54,6 +54,7 @@ snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o snd-soc-wm1133-ev1-objs := wm1133-ev1.o snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o +snd-soc-imx-wm8958-objs := imx-wm8958.o snd-soc-imx-wm8962-objs := imx-wm8962.o snd-soc-imx-spdif-objs := imx-spdif.o snd-soc-imx-mc13783-objs := imx-mc13783.o @@ -64,6 +65,7 @@ obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o +obj-$(CONFIG_SND_SOC_IMX_WM8958) += snd-soc-imx-wm8958.o obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o diff --git a/sound/soc/fsl/imx-wm8958.c b/sound/soc/fsl/imx-wm8958.c new file mode 100644 index 0000000..5ac200e --- /dev/null +++ b/sound/soc/fsl/imx-wm8958.c @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../codecs/wm8994.h" + +#define DAI_NAME_SIZE 32 + +#define DAI_LINK_NUM (3) +#define AIF1_DAI (0) +#define AIF2_DAI (1) +#define AIF3_DAI (2) + +#define WM8958_MCLK_MAX (2) + +#define WM8994_FLL(id) (id == AIF1_DAI ? WM8994_FLL1 : WM8994_FLL2) +#define WM8994_SYSCLK_FLL(id) (id == AIF1_DAI ? WM8994_SYSCLK_FLL1 : WM8994_SYSCLK_FLL2) +#define WM8994_FLL_SRC_MCLK(id) (id == AIF1_DAI ? WM8994_FLL_SRC_MCLK1 : WM8994_FLL_SRC_MCLK2) + +struct imx_wm8958_data { + struct snd_soc_dai_link dai_link[DAI_LINK_NUM]; + struct snd_soc_card card; + unsigned long mclk_freq[WM8958_MCLK_MAX]; + bool is_cpu_dai1_master; + bool is_stream_in_use[DAI_LINK_NUM][2]; +}; + +static const struct snd_soc_dapm_widget imx_wm8958_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static int imx_wm8958_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_card *card = rtd->card; + struct device *dev = card->dev; + struct imx_wm8958_data *data = snd_soc_card_get_drvdata(card); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + bool hifi_dai_sysclk_dir = SND_SOC_CLOCK_OUT; + u32 mclk_id, id = codec_dai->id - 1; + u32 pll_out; + int ret; + + data->is_stream_in_use[id][tx] = true; + + if (data->mclk_freq[id]) + mclk_id = WM8994_FLL_SRC_MCLK(id); + else if (id == AIF1_DAI) + mclk_id = WM8994_FLL_SRC_MCLK2; + else + mclk_id = WM8994_FLL_SRC_MCLK1; + + if (id == AIF1_DAI) { + if (data->is_cpu_dai1_master) + hifi_dai_sysclk_dir = SND_SOC_CLOCK_IN; + + ret = snd_soc_dai_set_sysclk(cpu_dai, + 0, 0, !hifi_dai_sysclk_dir); + + if (ret) { + dev_err(dev, "failed to set cpu sysclk: %d\n", ret); + return ret; + } + + if (data->is_cpu_dai1_master) { + ret = snd_soc_dai_set_sysclk(codec_dai, mclk_id, + data->mclk_freq[mclk_id - 1], + hifi_dai_sysclk_dir); + if (ret) { + dev_err(dev, + "failed to set codec sysclk: %d\n", + ret); + return ret; + } + + return 0; + } + } + + if (params_width(params) == 24) + pll_out = params_rate(params) * 384; + else + pll_out = params_rate(params) * 256; + + ret = snd_soc_dai_set_pll(codec_dai, + WM8994_FLL(id), + mclk_id, + data->mclk_freq[mclk_id - 1], + pll_out); + if (ret) { + dev_err(dev, "failed to set codec pll: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + WM8994_SYSCLK_FLL(id), + pll_out, + SND_SOC_CLOCK_OUT); + if (ret) { + dev_err(dev, "failed to set codec sysclk: %d\n", ret); + return ret; + } + + return 0; +} + +static int imx_wm8958_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_card *card = rtd->card; + struct imx_wm8958_data *data = snd_soc_card_get_drvdata(card); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int id = codec_dai->id - 1; + + data->is_stream_in_use[id][tx] = false; + + if (id == AIF1_DAI && data->is_cpu_dai1_master) + return 0; + + if (!data->is_stream_in_use[id][!tx]) { + /* + * We should connect AIFxCLK source to FLL after enable FLL, + * and disconnect AIF1CLK source to FLL before disable FLL, + * otherwise FLL worked abnormal. + */ + snd_soc_dai_set_sysclk(codec_dai, WM8994_FLL_SRC_MCLK(id), + data->mclk_freq[id], SND_SOC_CLOCK_OUT); + + /* Disable FLL1 after all stream finished. */ + snd_soc_dai_set_pll(codec_dai, WM8994_FLL(id), 0, 0, 0); + } + + return 0; +} + +static struct snd_soc_ops imx_wm8958_ops = { + .hw_params = imx_wm8958_hw_params, + .hw_free = imx_wm8958_hw_free, +}; + +static struct snd_soc_dai_link imx_wm8958_dai_link[] = { + [AIF1_DAI] = { + .name = "AIF1-DAI", + .stream_name = "AIF1-DAI", + .codec_name = "wm8994-codec", + .codec_dai_name = "wm8994-aif1", + .ops = &imx_wm8958_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF, + }, + [AIF2_DAI] = { + .name = "AIF2-DAI", + .stream_name = "AIF2-DAI", + .codec_name = "wm8994-codec", + .codec_dai_name = "wm8994-aif2", + .ops = &imx_wm8958_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + }, + [AIF3_DAI] = { + .name = "AIF3-DAI", + .stream_name = "AIF3-DAI", + .codec_name = "wm8994-codec", + .codec_dai_name = "wm8994-aif3", + }, +}; + +static int imx_wm8958_probe(struct platform_device *pdev) +{ + struct device_node *cpu_np[DAI_LINK_NUM], *codec_np; + struct device_node *np = pdev->dev.of_node; + struct platform_device *cpu_pdev[DAI_LINK_NUM]; + struct i2c_client *codec_dev; + struct imx_wm8958_data *data; + struct clk *mclk; + char tmp[8], *name; + int num_links = 0; + int ret, i; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + for (i = 0; i < DAI_LINK_NUM; i++) { + sprintf(tmp, "cpu-dai%d", i + 1); + cpu_np[i] = of_parse_phandle(np, tmp, 0); + if (!cpu_np[i]) + continue; + + cpu_pdev[i] = of_find_device_by_node(cpu_np[i]); + if (!cpu_pdev[i]) { + dev_err(&pdev->dev, + "failed to get cpu dai%d platform device\n", i); + ret = -EINVAL; + goto fail; + } + data->dai_link[num_links] = imx_wm8958_dai_link[i]; + data->dai_link[num_links].cpu_dai_name = dev_name(&cpu_pdev[i]->dev); + data->dai_link[num_links].platform_of_node = cpu_np[i]; + + sprintf(tmp, "dai-link%d-name", i + 1); + if(!of_property_read_string(np, tmp, (const char **)&name)) { + data->dai_link[num_links].name = name; + data->dai_link[num_links].stream_name = name; + } + num_links++; + } + + if (!num_links) { + dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + codec_dev = of_find_i2c_device_by_node(codec_np); + if (!codec_dev || !codec_dev->dev.driver) { + dev_err(&pdev->dev, "failed to find codec platform device\n"); + ret = -EINVAL; + goto fail; + } + + /* cpu dai1 link support cpu dai master and slave mode */ + if (of_property_read_bool(np, "fsl,cpu-dai1-master")) { + data->is_cpu_dai1_master = true; + data->dai_link[AIF1_DAI].dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } else { + data->is_cpu_dai1_master = false; + data->dai_link[AIF1_DAI].dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } + + for (i = 0; i < WM8958_MCLK_MAX; i++) { + sprintf(tmp, "MCLK%d", i + 1); + mclk = devm_clk_get(&codec_dev->dev, tmp); + if (!IS_ERR(mclk)) + data->mclk_freq[i] = clk_get_rate(mclk); + } + + if (!data->mclk_freq[0] && !data->mclk_freq[1]) { + dev_err(&pdev->dev, "failed to get mclk clock\n"); + ret = -EINVAL; + goto fail; + } + + data->card.dev = &pdev->dev; + ret = snd_soc_of_parse_card_name(&data->card, "model"); + if (ret) + goto fail; + + data->card.num_links = num_links; + data->card.dai_link = data->dai_link; + data->card.dapm_widgets = imx_wm8958_dapm_widgets; + data->card.num_dapm_widgets = ARRAY_SIZE(imx_wm8958_dapm_widgets); + data->card.owner = THIS_MODULE; + + ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); + if (ret) + goto fail; + + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + goto fail; + } + +fail: + of_node_put(cpu_np[AIF1_DAI]); + of_node_put(cpu_np[AIF2_DAI]); + of_node_put(cpu_np[AIF3_DAI]); + of_node_put(codec_np); + + return ret; +} + +static const struct of_device_id imx_wm8958_dt_ids[] = { + { .compatible = "fsl,imx-audio-wm8958", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_wm8958_dt_ids); + +static struct platform_driver imx_wm8958_driver = { + .driver = { + .name = "imx-wm8958", + .pm = &snd_soc_pm_ops, + .of_match_table = imx_wm8958_dt_ids, + }, + .probe = imx_wm8958_probe, +}; +module_platform_driver(imx_wm8958_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("Freescale i.MX WM8958 ASoC machine driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx-wm8958");