From patchwork Mon Mar 12 18:49:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Sylwester Nawrocki/Kernel \\(PLT\\) /SRPOL/Staff Engineer/Samsung Electronics" X-Patchwork-Id: 10277035 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 3E93A602C2 for ; Mon, 12 Mar 2018 18:50:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 30AB4286FD for ; Mon, 12 Mar 2018 18:50:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 250B228B0A; Mon, 12 Mar 2018 18:50:07 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5F886286FD for ; Mon, 12 Mar 2018 18:50:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751473AbeCLSuF (ORCPT ); Mon, 12 Mar 2018 14:50:05 -0400 Received: from mailout3.samsung.com ([203.254.224.33]:62527 "EHLO mailout3.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751232AbeCLSuD (ORCPT ); Mon, 12 Mar 2018 14:50:03 -0400 Received: from epcas1p2.samsung.com (unknown [182.195.41.46]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20180312185001epoutp039cd88c6aa62b9855d092b2c203983cbf~bQNlD6Q4p2282022820epoutp03N; Mon, 12 Mar 2018 18:50:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20180312185001epoutp039cd88c6aa62b9855d092b2c203983cbf~bQNlD6Q4p2282022820epoutp03N DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1520880601; bh=LhDGfnecGDtV7v1D483F/5DlbHU3JosNU5s1KSDMRYU=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=brsDiaF5K/ocJjK77DxVimFJYYLIQFRC250hgKzgE4pzeV04Y+b0OH8hNBt6Pp2x7 c1jdxkARbTNH5H6kAvhWVWsA0Ru8MwAk4dNcAWzcuJcyj8SeA84GaK6qpFGJAm6PWt cOxglkMdqq7vzo9YeaYEGbj3XgmV/VXik1kTL4oE= Received: from epsmges1p3.samsung.com (unknown [182.195.42.55]) by epcas1p3.samsung.com (KnoxPortal) with ESMTP id 20180312185000epcas1p3b4d818bdd853fe15e853f8353f1d7021~bQNkuAa3a3234132341epcas1p38; Mon, 12 Mar 2018 18:50:00 +0000 (GMT) Received: from epcas1p1.samsung.com ( [182.195.41.45]) by epsmges1p3.samsung.com (Symantec Messaging Gateway) with SMTP id 1E.66.04137.8DBC6AA5; Tue, 13 Mar 2018 03:50:00 +0900 (KST) Received: from epsmgms2p1new.samsung.com (unknown [182.195.42.142]) by epcas1p2.samsung.com (KnoxPortal) with ESMTP id 20180312185000epcas1p2ae13436139bee76311206ac3fd74267c~bQNkVeXcW0973709737epcas1p2y; Mon, 12 Mar 2018 18:50:00 +0000 (GMT) X-AuditID: b6c32a37-433ff70000001029-f1-5aa6cbd85666 Received: from epmmp2 ( [203.254.227.17]) by epsmgms2p1new.samsung.com (Symantec Messaging Gateway) with SMTP id 71.3F.03826.8DBC6AA5; Tue, 13 Mar 2018 03:50:00 +0900 (KST) Received: from AMDC3061.digital.local ([106.116.147.40]) by mmp2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0P5H00ABHQYT4Z50@mmp2.samsung.com>; Tue, 13 Mar 2018 03:49:59 +0900 (KST) From: Sylwester Nawrocki To: broonie@kernel.org Cc: lgirdwood@gmail.com, krzk@kernel.org, sbkim73@samsung.com, alsa-devel@alsa-project.org, robh+dt@kernel.org, devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, b.zolnierkie@samsung.com, m.szyprowski@samsung.com, Sylwester Nawrocki Subject: [PATCH v3 2/2] ASoC: samsung: Add HDMI audio support for Snow Date: Mon, 12 Mar 2018 19:49:39 +0100 Message-id: <20180312184939.11327-2-s.nawrocki@samsung.com> X-Mailer: git-send-email 2.14.2 In-reply-to: <20180312184939.11327-1-s.nawrocki@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrPIsWRmVeSWpSXmKPExsWy7bCmru6N08uiDD7+VLe4cvEQk8XGGetZ LaY+fMJmMf/IOVaL8+c3sFt8u9LBZLHp8TVWixnn9zFZrD1yl92ide8RdovDb9pZLS6u+MLk wOOx4XMTm8fOWXfZPTat6mTz2Lyk3qNvyypGj8+b5ALYorhsUlJzMstSi/TtErgyGpZMZyuY 7lCxtOM4UwPjBuMuRk4OCQETiWOzT7J3MXJxCAnsYJT4fPoOC4TznVFi3sJ5bDBVO05PYIVI bGCUmPJxLlTLL0aJpX82sINUsQkYSvQe7WMEsUUExCRuz+lkBiliFtjDJLH37j9mkISwgJvE uT0rgIo4OFgEVCXOv5MFMXkFrCVerjWFWCYv8X7BfbAxnAI2Ek8uXQUbIyGwhU1i4VeQWzmA HBeJDQ35EPXCEq+Ob4EKS0tcOmoLEa6W6GzrYodobWGU+DPtEtQz1hKHj19kBbGZBfgk3n3t YYXo5ZXoaBOCKPGQeDL9KjOE7ShxafsNJoh3+xkldj09zzSBUWoBI8MqRrHUguLc9NRiwwJj veLE3OLSvHS95PzcTYzgaNYy38G44ZzPIUYBDkYlHl6D5mVRQqyJZcWVuYcYJTiYlUR4F+4E CvGmJFZWpRblxxeV5qQWH2KU5mBREucNCHCJEhJITyxJzU5NLUgtgskycXBKNTCGHLWaPenq q6kbm5zOFeTsytzBUsux3PEQq5nSs7VhjyYpJFTe1/SM2308Mf0Kw/ocLtliN7OmcIt76ZWT 3rId+ci9xfmSd0ZA5sVDvFeZj727GPJuwdnf4tFhIsGxrTMrfycHf9IytHlX5b7nuuDjqP7J LedXMmwutQ0/OPWPzoIpDD98zsQrsRRnJBpqMRcVJwIAuGvy3eICAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrGLMWRmVeSWpSXmKPExsVy+t9jQd0bp5dFGUxp5rG4cvEQk8XGGetZ LaY+fMJmMf/IOVaL8+c3sFt8u9LBZLHp8TVWixnn9zFZrD1yl92ide8RdovDb9pZLS6u+MLk wOOx4XMTm8fOWXfZPTat6mTz2Lyk3qNvyypGj8+b5ALYorhsUlJzMstSi/TtErgyGpZMZyuY 7lCxtOM4UwPjBuMuRk4OCQETiR2nJ7B2MXJxCAmsY5Q48/4LI4Tzi1GifdY9dpAqNgFDid6j fYwgtoiAmMTtOZ3MIDazwB4miSP3fEFsYQE3iXN7VgDVcHCwCKhKnH8nC2LyClhLvFxrCrFL XuL9gvtgUzgFbCSeXLrKDFIiBFTyYk7EBEaeBYwMqxglUwuKc9Nzi40KDPNSy/WKE3OLS/PS 9ZLzczcxAkNv22Gtvh2M95fEH2IU4GBU4uHtaF0WJcSaWFZcmXuIUYKDWUmEd+FOoBBvSmJl VWpRfnxRaU5q8SFGaQ4WJXHe23nHIoUE0hNLUrNTUwtSi2CyTBycUg2MwgIy0kqi0cbsoc8v /HGWOcQoybfZxSTrle5tya6Lvjf182as0uHqDFJn7v3oNyd3Xriu9AuF1ylHShJ11q7i0OcK 6/xh+Oi2csrZ3UKGE3/cO5xz4Qc/v+Ob6XdWVdudNXM7/Gveg7P1Xtbb9mtsOPjBUn37K4fb kgcqutvVHk6d3Ge9wPmHEktxRqKhFnNRcSIAEI8bWjkCAAA= X-CMS-MailID: 20180312185000epcas1p2ae13436139bee76311206ac3fd74267c X-Msg-Generator: CA CMS-TYPE: 101P X-CMS-RootMailID: 20180312185000epcas1p2ae13436139bee76311206ac3fd74267c X-RootMTR: 20180312185000epcas1p2ae13436139bee76311206ac3fd74267c References: <20180312184939.11327-1-s.nawrocki@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch updates the driver so, in addition to current DT bindings, it also can also use the new DT bindings with cpu, codec subnodes which allow to support sound on the HDMI interface. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski --- Changes since v2: - dropped addition of UL postfix in the FIN_PLL_RATE constant definition from this patch, - edited summary line. Changes since v1: - adjustments to changed order of codecs in codec/cpu-dai property, - fixed errors in snow_remove(). --- sound/soc/samsung/snow.c | 224 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 177 insertions(+), 47 deletions(-) diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index fc62110f500f..5d8efc2d5c38 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -11,92 +11,207 @@ * General Public License for more details. */ +#include #include #include #include #include - +#include #include #include "i2s.h" #define FIN_PLL_RATE 24000000 -static struct snd_soc_dai_link snow_dai[] = { - { - .name = "Primary", - .stream_name = "Primary", - .codec_dai_name = "HiFi", - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - }, +struct snow_priv { + struct snd_soc_dai_link dai_link; + struct clk *clk_i2s_bus; +}; + +static int snow_card_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + static const unsigned int pll_rate[] = { + 73728000U, 67737602U, 49152000U, 45158401U, 32768001U + }; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snow_priv *priv = snd_soc_card_get_drvdata(rtd->card); + int bfs, psr, rfs, bitwidth; + unsigned long int rclk; + long int freq = -EINVAL; + int ret, i; + + bitwidth = snd_pcm_format_width(params_format(params)); + if (bitwidth < 0) { + dev_err(rtd->card->dev, "Invalid bit-width: %d\n", bitwidth); + return bitwidth; + } + + if (bitwidth != 16 && bitwidth != 24) { + dev_err(rtd->card->dev, "Unsupported bit-width: %d\n", bitwidth); + return -EINVAL; + } + + bfs = 2 * bitwidth; + + switch (params_rate(params)) { + case 16000: + case 22050: + case 24000: + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + rfs = 8 * bfs; + break; + case 64000: + rfs = 384; + break; + case 8000: + case 11025: + case 12000: + rfs = 16 * bfs; + break; + default: + return -EINVAL; + } + + rclk = params_rate(params) * rfs; + + for (psr = 8; psr > 0; psr /= 2) { + for (i = 0; i < ARRAY_SIZE(pll_rate); i++) { + if ((pll_rate[i] - rclk * psr) <= 2) { + freq = pll_rate[i]; + break; + } + } + } + if (freq < 0) { + dev_err(rtd->card->dev, "Unsupported RCLK rate: %lu\n", rclk); + return -EINVAL; + } + + ret = clk_set_rate(priv->clk_i2s_bus, freq); + if (ret < 0) { + dev_err(rtd->card->dev, "I2S bus clock rate set failed\n"); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops snow_card_ops = { + .hw_params = snow_card_hw_params, }; static int snow_late_probe(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *codec_dai; - struct snd_soc_dai *cpu_dai; - int ret; rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); - codec_dai = rtd->codec_dai; - cpu_dai = rtd->cpu_dai; - - /* Set the MCLK rate for the codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, - FIN_PLL_RATE, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; + /* In the multi-codec case codec_dais 0 is MAX98095 and 1 is HDMI. */ + if (rtd->num_codecs > 1) + codec_dai = rtd->codec_dais[0]; + else + codec_dai = rtd->codec_dai; - return 0; + /* Set the MCLK rate for the codec */ + return snd_soc_dai_set_sysclk(codec_dai, 0, + FIN_PLL_RATE, SND_SOC_CLOCK_IN); } static struct snd_soc_card snow_snd = { .name = "Snow-I2S", .owner = THIS_MODULE, - .dai_link = snow_dai, - .num_links = ARRAY_SIZE(snow_dai), - .late_probe = snow_late_probe, }; static int snow_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct snd_soc_card *card = &snow_snd; - struct device_node *i2s_node, *codec_node; - int i, ret; - - i2s_node = of_parse_phandle(pdev->dev.of_node, - "samsung,i2s-controller", 0); - if (!i2s_node) { - dev_err(&pdev->dev, - "Property 'i2s-controller' missing or invalid\n"); - return -EINVAL; - } + struct device_node *cpu, *codec; + struct snd_soc_dai_link *link; + struct snow_priv *priv; + int ret; - codec_node = of_parse_phandle(pdev->dev.of_node, - "samsung,audio-codec", 0); - if (!codec_node) { - dev_err(&pdev->dev, - "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; - } + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + link = &priv->dai_link; + + link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + + link->name = "Primary"; + link->stream_name = link->name; + + card->dai_link = link; + card->num_links = 1; + card->dev = dev; + + /* Try new DT bindings with HDMI support first. */ + cpu = of_get_child_by_name(dev->of_node, "cpu"); + + if (cpu) { + link->ops = &snow_card_ops; - for (i = 0; i < ARRAY_SIZE(snow_dai); i++) { - snow_dai[i].codec_of_node = codec_node; - snow_dai[i].cpu_of_node = i2s_node; - snow_dai[i].platform_of_node = i2s_node; + link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); + of_node_put(cpu); + + if (!link->cpu_of_node) { + dev_err(dev, "Failed parsing cpu/sound-dai property\n"); + return -EINVAL; + } + + codec = of_get_child_by_name(dev->of_node, "codec"); + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + of_node_put(codec); + + if (ret < 0) { + of_node_put(link->cpu_of_node); + dev_err(dev, "Failed parsing codec node\n"); + return ret; + } + + priv->clk_i2s_bus = of_clk_get_by_name(link->cpu_of_node, + "i2s_opclk0"); + if (IS_ERR(priv->clk_i2s_bus)) { + snd_soc_of_put_dai_link_codecs(link); + of_node_put(link->cpu_of_node); + return PTR_ERR(priv->clk_i2s_bus); + } + } else { + link->codec_dai_name = "HiFi", + + link->cpu_of_node = of_parse_phandle(dev->of_node, + "samsung,i2s-controller", 0); + if (!link->cpu_of_node) { + dev_err(dev, "i2s-controller property parse error\n"); + return -EINVAL; + } + + link->codec_of_node = of_parse_phandle(dev->of_node, + "samsung,audio-codec", 0); + if (!link->codec_of_node) { + of_node_put(link->cpu_of_node); + dev_err(dev, "audio-codec property parse error\n"); + return -EINVAL; + } } - card->dev = &pdev->dev; + link->platform_of_node = link->cpu_of_node; /* Update card-name if provided through DT, else use default name */ snd_soc_of_parse_card_name(card, "samsung,model"); - ret = devm_snd_soc_register_card(&pdev->dev, card); + snd_soc_card_set_drvdata(card, priv); + + ret = devm_snd_soc_register_card(dev, card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); return ret; @@ -105,6 +220,20 @@ static int snow_probe(struct platform_device *pdev) return ret; } +static int snow_remove(struct platform_device *pdev) +{ + struct snow_priv *priv = platform_get_drvdata(pdev); + struct snd_soc_dai_link *link = &priv->dai_link; + + of_node_put(link->cpu_of_node); + of_node_put(link->codec_of_node); + snd_soc_of_put_dai_link_codecs(link); + + clk_put(priv->clk_i2s_bus); + + return 0; +} + static const struct of_device_id snow_of_match[] = { { .compatible = "google,snow-audio-max98090", }, { .compatible = "google,snow-audio-max98091", }, @@ -120,6 +249,7 @@ static struct platform_driver snow_driver = { .of_match_table = snow_of_match, }, .probe = snow_probe, + .remove = snow_remove, }; module_platform_driver(snow_driver);