From patchwork Fri Mar 9 17:48:58 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: 10271451 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 BFE0B6016D for ; Fri, 9 Mar 2018 17:50:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AC056262F2 for ; Fri, 9 Mar 2018 17:50:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A02D429D59; Fri, 9 Mar 2018 17:50:56 +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 E1B4229973 for ; Fri, 9 Mar 2018 17:50:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932261AbeCIRuw (ORCPT ); Fri, 9 Mar 2018 12:50:52 -0500 Received: from mailout2.samsung.com ([203.254.224.25]:37238 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932664AbeCIRuX (ORCPT ); Fri, 9 Mar 2018 12:50:23 -0500 Received: from epcas2p2.samsung.com (unknown [182.195.41.54]) by mailout2.samsung.com (KnoxPortal) with ESMTP id 20180309175021epoutp02215a73665b3201091c046e029b6000ac~aUdojx4Ua1345513455epoutp027; Fri, 9 Mar 2018 17:50:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.samsung.com 20180309175021epoutp02215a73665b3201091c046e029b6000ac~aUdojx4Ua1345513455epoutp027 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1520617821; bh=sf/UjqUH2cdbWWMmsMretcAgsB/o2bOnkn+6N/rbPwU=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=uSJlNv+7T6UXtNxrYwQwXkFxKXAR3D0tLJoZKbgTvzsLP90/zO882JvR++oc1KipZ VOINQvBruKxMSYrkWb1EjClN/uddxIzlvlzrlZLyzCjleTlek1aGFY72nCubzy0P9Z mO4qDS/A7kZoP6ibIuQeR2Bb5nqdS1Q+okK03z00= Received: from epsmges2p2.samsung.com (unknown [182.195.42.70]) by epcas2p2.samsung.com (KnoxPortal) with ESMTP id 20180309175020epcas2p234867771fac63f4d0c957d13b1d6daa3~aUdnN0rVP2477524775epcas2p21; Fri, 9 Mar 2018 17:50:20 +0000 (GMT) Received: from epcas2p1.samsung.com ( [182.195.41.53]) by epsmges2p2.samsung.com (Symantec Messaging Gateway) with SMTP id 37.92.04137.B59C2AA5; Sat, 10 Mar 2018 02:50:20 +0900 (KST) Received: from epsmgms2p2new.samsung.com (unknown [182.195.42.143]) by epcas2p3.samsung.com (KnoxPortal) with ESMTP id 20180309175019epcas2p34a7fd706117cb18d31109dbc9c8cf60b~aUdmrHjKm1317613176epcas2p3f; Fri, 9 Mar 2018 17:50:19 +0000 (GMT) X-AuditID: b6c32a46-3a9ff70000001029-f4-5aa2c95bec84 Received: from epmmp2 ( [203.254.227.17]) by epsmgms2p2new.samsung.com (Symantec Messaging Gateway) with SMTP id 59.DD.03890.B59C2AA5; Sat, 10 Mar 2018 02:50:19 +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 <0P5C0033645R9230@mmp2.samsung.com>; Sat, 10 Mar 2018 02:50:19 +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, javierm@redhat.com, linux-samsung-soc@vger.kernel.org, b.zolnierkie@samsung.com, m.szyprowski@samsung.com, Sylwester Nawrocki Subject: [PATCH v2 7/7] ASoC: samsung: Add HDMI audio support for Chromebook Snow Date: Fri, 09 Mar 2018 18:48:58 +0100 Message-id: <20180309174858.24017-7-s.nawrocki@samsung.com> X-Mailer: git-send-email 2.14.2 In-reply-to: <20180309174858.24017-1-s.nawrocki@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrAIsWRmVeSWpSXmKPExsWy7bCmqW7MyUVRBrueMFpcuXiIyWLjjPWs FlMfPmGzmH/kHKvFwmnLGS3On9/AbvHtSgeTxYzz+5gs1h65y27RuvcIu8XhN+2sFhdXfGFy 4PHY8LmJzWPnrLvsHptWdbJ5vN93lc2jb8sqRo/Pm+QC2KK4bFJSczLLUov07RK4Mi6evcxU 0G9f8fuuagPjDaMuRk4OCQETic9zD7OC2EICOxglms8rdDFyAdnfGSXaZ3WwwBQ9mTWfGSKx gVHi48ezjBDOL0aJhVMXMoFUsQkYSvQe7WMEsUUExCRuz+kE62AWWMUkser+WjaQhLBAsMS6 GwfAbBYBVYnnZ94C2RwcvALWEp9uykJsk5d4v+A+2BxOARuJ3paHYMskBLawSVw7t4wdoshF 4vvzx1DnCUu8Or4FKi4t8WzVRkYIu1qis62LHaK5hVHiz7RLbBAJa4nDxy+CPc0swCfRcfgv O8gREgK8Eh1tQhCmh8S5R8EQ1Y4S0yZ1MkE83M8osfb8f/YJjFILGBlWMYqlFhTnpqcWGxUY 6RUn5haX5qXrJefnbmIEx7OW2w7GJed8DjEKcDAq8fAKzFgUJcSaWFZcmXuIUYKDWUmE930N UIg3JbGyKrUoP76oNCe1+BCjNAeLkjhva4BLlJBAemJJanZqakFqEUyWiYNTqoHxysbkG9sf uXbINsR5z5VcY1u50Pa66UkxL7lJuaZ3q7M2cmjPZHCNFtr+oDZsXky4ySR/tWM+vz4ZVDsx tPm7LIhONS9ebZ/3IMr70mKD+NJjt/tL65aXvYzV/6V37vxC5ZZ+6xOzXOY6vY2dsG7PgTiD qYq7Gc7sv5XLqll1J8j4X33Cy0glluKMREMt5qLiRACeRW2c4wIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrBLMWRmVeSWpSXmKPExsVy+t9jQd3ok4uiDDp6pSyuXDzEZLFxxnpW i6kPn7BZzD9yjtVi4bTljBbnz29gt/h2pYPJYsb5fUwWa4/cZbdo3XuE3eLwm3ZWi4srvjA5 8Hhs+NzE5rFz1l12j02rOtk83u+7yubRt2UVo8fnTXIBbFFcNimpOZllqUX6dglcGRfPXmYq 6Lev+H1XtYHxhlEXIyeHhICJxJNZ85m7GLk4hATWMUr8+bKFHcL5xSixasYLRpAqNgFDid6j fWC2iICYxO05nWAdzAKrmCQaJj5hBUkICwRLrLtxgA3EZhFQlXh+5i2QzcHBK2At8emmLMQ2 eYn3C+6DzeEUsJHobXnICFIiBFSy7Vz0BEaeBYwMqxglUwuKc9Nzi40KjPJSy/WKE3OLS/PS 9ZLzczcxAsNv22Gt/h2Mj5fEH2IU4GBU4uEVmLEoSog1say4MvcQowQHs5II7/saoBBvSmJl VWpRfnxRaU5q8SFGaQ4WJXFe/vxjkUIC6YklqdmpqQWpRTBZJg5OqQZGq5LOxxwXJ0zhe9vq unHfv7JnQcJS7DPeVHoL7xEI9Qy9qTB1q30hf0H45Jv3a3Say6fvWzNX1n6i585MU0ZvhetX Mpke7uMO0Zy1clJIuajJ8c082+J8MncJbRX6Iu/04o2L77eAiIK4m5/PvAiuctHaYXBveyJT y0sLQXalN8cYtfK6WHKUWIozEg21mIuKEwHaRxX+OwIAAA== X-CMS-MailID: 20180309175019epcas2p34a7fd706117cb18d31109dbc9c8cf60b X-Msg-Generator: CA CMS-TYPE: 102P X-CMS-RootMailID: 20180309175019epcas2p34a7fd706117cb18d31109dbc9c8cf60b X-RootMTR: 20180309175019epcas2p34a7fd706117cb18d31109dbc9c8cf60b References: <20180309174858.24017-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, the new DT bindings with cpu, codec subnodes can be used, in order to support sound on the HDMI interface. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski --- Changes since v1: - adjustments to changed order of codecs in codec/cpu-dai property, - fixed errors in snow_remove(). --- sound/soc/samsung/snow.c | 226 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 178 insertions(+), 48 deletions(-) -- 2.14.2 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index fc62110f500f..f00ca1ca0171 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 +#define FIN_PLL_RATE 24000000UL -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);