From patchwork Fri Jun 26 11:09:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zidan Wang X-Patchwork-Id: 6680341 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 8D9F8C05AC for ; Fri, 26 Jun 2015 11:08:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 65BCE206C0 for ; Fri, 26 Jun 2015 11:08:08 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id AA3A020630 for ; Fri, 26 Jun 2015 11:08:06 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9EDD6265057; Fri, 26 Jun 2015 13:08:03 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,NO_DNS_FOR_FROM, UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 0AB682614DD; Fri, 26 Jun 2015 13:07:55 +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 13FAC2614F1; Fri, 26 Jun 2015 13:07:54 +0200 (CEST) Received: from na01-bl2-obe.outbound.protection.outlook.com (mail-bl2on0142.outbound.protection.outlook.com [65.55.169.142]) by alsa0.perex.cz (Postfix) with ESMTP id 8941E2614DA for ; Fri, 26 Jun 2015 13:07:46 +0200 (CEST) Received: from BLUPR0301CA0027.namprd03.prod.outlook.com (10.162.113.165) by BN3PR0301MB1249.namprd03.prod.outlook.com (10.161.207.25) with Microsoft SMTP Server (TLS) id 15.1.195.15; Fri, 26 Jun 2015 11:07:46 +0000 Received: from BY2FFO11FD030.protection.gbl (2a01:111:f400:7c0c::109) by BLUPR0301CA0027.outlook.office365.com (2a01:111:e400:5259::37) with Microsoft SMTP Server (TLS) id 15.1.201.16 via Frontend Transport; Fri, 26 Jun 2015 11:07:45 +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; 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 BY2FFO11FD030.mail.protection.outlook.com (10.1.14.211) with Microsoft SMTP Server (TLS) id 15.1.201.10 via Frontend Transport; Fri, 26 Jun 2015 11:07:45 +0000 Received: from b50113.ap.freescale.net (b50113.ap.freescale.net [10.192.241.89]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id t5QB7dDF032056; Fri, 26 Jun 2015 04:07:40 -0700 From: Zidan Wang To: Date: Fri, 26 Jun 2015 19:09:22 +0800 Message-ID: <5630bd343217e8fa895c5d133497f50739417453.1435316484.git.zidan.wang@freescale.com> X-Mailer: git-send-email 1.9.1 X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11FD030; 1:mX11biqgt4O1iYN63Kvy9SvauNV1l2/2L+aiETAkgtFny5nfRnrx0osu7vn89CP2qckJYk3VVEQmFlLx+fE2Zq/4oAveqnVJaAoKm+hHdBxPKg4ZAxRadDPM7JKffDJ6NixC7pIMLgJmJ7lzwIBw5CwWkNjKNwI1ENPq0u5/fiva36s53T9IOJyynA2HNFUAds4aPfqsA4amHax/3iAUoqkg0UugtpMfAFDr9pxJ0kSCMOupXqL8OME0zxnGV7JSq4IY9H3BE9dT6HP3gK5+vgm7OpTIl6eB2Z5nEe2wJZov2Leb84i+nfsv0DhD3/pQuqWD2ixba7HuSBTuXZpgMLmbyDSNomcU7L6PwN17uYdAltSWytnPS9UNveXFWc8S X-Forefront-Antispam-Report: CIP:192.88.168.50; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(2980300002)(1060300003)(339900001)(199003)(189002)(118296001)(46102003)(50226001)(87936001)(5001960100002)(107886002)(110136002)(86362001)(19580405001)(19580395003)(77156002)(47776003)(106466001)(62966003)(36756003)(77096005)(50986999)(229853001)(110436001)(50466002)(2351001)(4290100001)(85426001)(6806004)(48376002)(104016003)(92566002)(33646002)(4001430100001); DIR:OUT; SFP:1102; SCL:1; SRVR:BN3PR0301MB1249; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; MLV:sfv; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1249; 2:iDdfNZQE85IIelTc32lKMlQCrg7cG2zGACQZ4Yu+eAuw3myimIP9i/pt415NX+w3; 3:uv9dy9VsQHbaFreLdpF/C8S9FsR2ITxWb4g352eCuwcahSC+nDiYt+JVcjGyBq82u8bkG4TpM6ymMpqK3myWROCauBzWCTlioICO9XCEcVVWGGvCtf4TGERHSbTiCBsAmVy4EaKOBq+YTLHV85xhvyV8991QMX84/IJGPW82k/o2KyAa4R1u+5+PGdef3mfEbEuRF/YNTXgDoXpKOdG41pZX6Id6ADdFiC4pDaAP/tI=; 20:jcg+LidzJibUdXmSWn/NOPdfc81u0Tc5jqGv9+lDo1tIYoBviZ+e8FMXh/b6fhZHNmV26Q/RHvbbNrj/FDm6nCzckj39isbEC8fZru2SiL9YGp4uyGBFqzCFU3PuIRjWV3P+dJ2NrSmohkE+rIMeS30kThfnsHyZLmWtbI3vyXNspFE3EzDJcOR/Ul2Aw19AAIhykrDDdeamknH2ST4qi4KC0dZNZwQTRmiEjmJcmMtLugiodCK6fwrVLkDuqn34VG+5eL774P8fMO5HoZEUddxEBoBEF7a2M18aoN0SFuJgx63BXMmmi5SxTd+gOhE1v7RVc1UCHUjM+QdYpVUuJaq8t9tFIQZ6XQShS6NzU84= X-Microsoft-Antispam: UriScan:;BCL:1;PCL:0;RULEID:;SRVR:BN3PR0301MB1249; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:1; PCL:0; RULEID:(601004)(1201001)(5005006)(3002001); SRVR:BN3PR0301MB1249; BCL:1; PCL:0; RULEID:; SRVR:BN3PR0301MB1249; X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1249; 4:7BBPQSzUkhr3ytaO048d+4BS/ayFxend9hvAW7NgYl4UvCYEgeMLmuBS+19dCkB65mAvsi0Ji7qdKI1QFrNyhUNKI7xzzMRQ8Cpu9AlidLGJ51/T6u/cWo6qgd5L72XlkHgcGHFeGyiXly7yLeKQPKNffpgy6Du8iAYfCeGZ99CUQlSHvkqFyZt6mmsZ1PAN9iRvxMUgY3lvdUy3IO0IlKyQOnmVVH1RrBgKXc8Y0PefgICGuFoaTvWgCNtGuUqOFlyIrc3acgaklRr4ztARNYwikV6nSQWwOoMiziuk/tNQ3qMTzxFSZrWHhdpgKwge X-Forefront-PRVS: 0619D53754 X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1249; 23:JwznIiPF/S18HrvNxeSgL4pep1E3KtzorEVAVmPNz8qF/FSPX8fVvlg7jsRpcMU4YHsyMx/gI0lwZ7kaL0mspZb1vGFule+zlbN26RPLvZO/LIiKW0CeyveDr9kTxBgMGOBaGYXuVSAt0fSCOTK1Z6Pm8zI2Z+3ZH51ajMuOY+BgfXfOHcdZviqt5tsqi1xKfYetmniN7xSh6o14mxkOOvCs6CjbAfnzX/6VmHJUNVx/UGQMWGp+WPSOzk5zYvcUqhauDG63lj4di8dF5QGMg2qU7N4TJMAGKGBbZHtc1uPj21D4Drwq0R0c9vGMqwL4eNM2Hs8R+sw5a6RnHTE1zv7r9hbFCNCnWXBN2m65P1DW+MjW/F6sZM5GAa/zFU8Yxsv2l9tYLEm3VVHuHql2+K9V9orJhpGX/gIoDcdJdK2vbUSQp/q0SYAij2Lm4iLDqWHQjJNwEUcdu15mGzjduFPsRdur7k9/T85u7n6TWynci1PxqzCCpD6P0Yc6YGlOkBC4R9HHpJXGlxMgJga/LVNAPwid5MDGFWDU4o9wvzqFnSq5kSQfW2dbR+XmT1QGR7v3yoGEsQbj+AW7Hvs6lz1xFhZWhvlNTxPluytLV1hdAGtOohVaOTxLV9Qaz+EqZKKxx9echMzG8w0QP6YGeNyMyfXZFbrD2k1zvYKJO0hVJkmZLwns33nOM0AjoAmQxEMM51w9ffyk9C+mY8lBTAr2q70w+E9IMuHBy2Kx17XH1J6Gn4MVnj+AdK71BzEmkZIa+yxQKmmp0YncTPOtMtg+Z19rHW0KqPwH2p0poaeEK+BAcmr/ZOniSwIGQdCUoCWoDc3XtwxyQYxR8GeOh0JMOsvU57u5y1OuGH4dqCrZQURrj26MO8lxoVdJGcGrD+ioG1tTDW6irGpResEl0XFRGBKY/lNf/BqoYzH3/bs= X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1249; 5:K2VMJTOcryIH515zpeqOkRsFPqIoE+7nS6nWZcLd2IKHxXs6NnvLU4n/9kUAp/jmPQOoqeqeVXE+M8qhFbGXqhQiJcHcarr3JUtgCOahxocisca8XS2na4MT7kbq7fLyuDZpRWM7CaDwRuTTblmFjQ==; 24:ofx9a8zIH9q2vdsHFHXAhE6TQJBjEI9vewCH3wMzZO4H8KiDNn+lyMbWGiWd9acgpI1YADV4lKZqSl6r9Bj46twZtXR3A3aCCfh1cuvTHhU=; 20:KWaK63KvVn4me5GTcGTNGyZyHAQqYbYsqbY0Q4iyyu53G5IuQTwgcaCvJK3hBnLTJIZpq5m2ToAxjfSv6tqzwg== X-OriginatorOrg: freescale.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jun 2015 11:07:45.0692 (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: BN3PR0301MB1249 Cc: alsa-devel@alsa-project.org, lars@metafoo.de, Zidan Wang , tiwai@suse.de, patches@opensource.wolfsonmicro.com, linux-kernel@vger.kernel.org, ckeepax@opensource.wolfsonmicro.com Subject: [alsa-devel] [PATCH] ASoC: wm8960: update pll and clock setting function 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 When using snd_soc_dai_set_pll to set pll in machine driver, we should set pll in and pll out freq and ensure 5 < PLLN < 13, otherwise set pll will be failed. In order to support more formats and sample rates for a certain MCLK, if snd_soc_dai_set_pll failed, it will calculate a available pll out freq and set the pll again. Signed-off-by: Zidan Wang --- sound/soc/codecs/wm8960.c | 160 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 126 insertions(+), 34 deletions(-) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 94c5c46..9b17ca7 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -48,6 +48,9 @@ #define WM8960_DISOP 0x40 #define WM8960_DRES_MASK 0x30 +static bool is_pll_freq_available(unsigned int source, unsigned int target); +static int wm8960_set_pll(struct snd_soc_dai *codec_dai, + unsigned int freq_in, unsigned int freq_out); /* * wm8960 register cache * We can't read the WM8960 register space when we are @@ -127,8 +130,9 @@ struct wm8960_priv { struct snd_soc_dapm_widget *out3; bool deemph; int playback_fs; - int bclk; + int freq_in; int sysclk; + int clk_id; struct wm8960_data pdata; }; @@ -565,6 +569,9 @@ static struct { { 8000, 5 }, }; +/* -1 for reserved value */ +static const int sysclk_divs[] = { 1, -1, 2, -1 }; + /* Multiply 256 for internal 256 div */ static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; @@ -574,61 +581,119 @@ static const int bclk_divs[] = { 120, 160, 220, 240, 320, 320, 320 }; -static void wm8960_configure_clocking(struct snd_soc_codec *codec, - bool tx, int lrclk) +static int wm8960_configure_clocking(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { + struct snd_soc_codec *codec = dai->codec; struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + unsigned int sample_rate = params_rate(params); + unsigned int channels = params_channels(params); + unsigned int sysclk, bclk, pll_out, freq_in; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); - u32 sysclk; - int i, j; + int i, j, k; if (!(iface1 & (1<<6))) { dev_dbg(codec->dev, "Codec is slave mode, no need to configure clock\n"); - return; + return 0; } if (!wm8960->sysclk) { dev_dbg(codec->dev, "No SYSCLK configured\n"); - return; + return -EINVAL; } - if (!wm8960->bclk || !lrclk) { - dev_dbg(codec->dev, "No audio clocks configured\n"); - return; + bclk = snd_soc_params_to_bclk(params); + if (channels == 1) + bclk *= 2; + + sysclk = wm8960->sysclk; + + if (wm8960->clk_id == WM8960_SYSCLK_PLL) { + if (!wm8960->freq_in) { + dev_dbg(codec->dev, "No PLL input clock configured\n"); + return -EINVAL; + } + + pll_out = sysclk; + /* + * If the PLL input and output frequency are not available for + * wm8960 PLL, try to calculte a available pll out frequency and + * set pll again. + */ + if (!is_pll_freq_available(wm8960->freq_in, pll_out)) + goto get_pll_freq; } - for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { - if (wm8960->sysclk == lrclk * dac_divs[i]) { - for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { - sysclk = wm8960->bclk * bclk_divs[j] / 10; - if (wm8960->sysclk == sysclk) + /* check if the sysclk frequency is available. */ + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + if (sysclk_divs[i] == -1) + continue; + sysclk /= sysclk_divs[i]; + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) + if (sysclk == dac_divs[j] * sample_rate) + break; + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) + if (sysclk == bclk * bclk_divs[k] / 10) + break; + if (j != ARRAY_SIZE(dac_divs) && k != ARRAY_SIZE(bclk_divs)) + break; + } + if (i != ARRAY_SIZE(sysclk_divs)) + goto configure_clock; + +get_pll_freq: + freq_in = wm8960->freq_in; + /* + * If the pll out frequcncy set from machine driver is not available, + * try to find a pll out frequcncy and set pll. + */ + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + if (sysclk_divs[i] == -1) + continue; + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { + sysclk = sample_rate * dac_divs[j]; + pll_out = sysclk * sysclk_divs[i]; + + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { + if (sysclk == bclk * bclk_divs[k] / 10 && + is_pll_freq_available(freq_in, pll_out)) { + wm8960_set_pll(dai, freq_in, pll_out); break; + } else + continue; } - if(j != ARRAY_SIZE(bclk_divs)) + if (k != ARRAY_SIZE(bclk_divs)) break; } + if (j != ARRAY_SIZE(dac_divs)) + break; } - if (i == ARRAY_SIZE(dac_divs)) { - dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); - return; + if (i == ARRAY_SIZE(sysclk_divs)) { + dev_err(codec->dev, "failed to configure clock\n"); + return -EINVAL; } +configure_clock: + snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1); /* * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC * pin is used as a frame clock for ADCs and DACs. */ if (iface2 & (1<<6)) - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3); else if (tx) - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3); else if (!tx) - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6); + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6); /* configure bit clock */ - snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); + snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k); + return 0; } static int wm8960_hw_params(struct snd_pcm_substream *substream, @@ -638,13 +703,8 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; - bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int i; - wm8960->bclk = snd_soc_params_to_bclk(params); - if (params_channels(params) == 1) - wm8960->bclk *= 2; - /* bit size */ switch (params_width(params)) { case 16: @@ -682,9 +742,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, /* set iface */ snd_soc_write(codec, WM8960_IFACE1, iface); - wm8960_configure_clocking(codec, tx, params_rate(params)); - - return 0; + return wm8960_configure_clocking(substream, params, dai); } static int wm8960_mute(struct snd_soc_dai *dai, int mute) @@ -892,6 +950,28 @@ struct _pll_div { u32 k:24; }; +static bool is_pll_freq_available(unsigned int source, unsigned int target) +{ + unsigned int Ndiv; + + if (source == 0 || target == 0) + return false; + + /* Scale up target to PLL operating frequency */ + target *= 4; + Ndiv = target / source; + + if (Ndiv < 6) { + source >>= 1; + Ndiv = target / source; + } + + if ((Ndiv < 6) || (Ndiv > 12)) + return false; + + return true; +} + /* The size in bits of the pll divide multiplied by 10 * to allow rounding later */ #define FIXED_PLL_SIZE ((1 << 24) * 10) @@ -916,7 +996,7 @@ static int pll_factors(unsigned int source, unsigned int target, pll_div->pre_div = 0; if ((Ndiv < 6) || (Ndiv > 12)) { - pr_err("WM8960 PLL: Unsupported N=%d\n", Ndiv); + pr_debug("WM8960 PLL: Unsupported N=%d\n", Ndiv); return -EINVAL; } @@ -943,8 +1023,8 @@ static int pll_factors(unsigned int source, unsigned int target, return 0; } -static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - int source, unsigned int freq_in, unsigned int freq_out) +static int wm8960_set_pll(struct snd_soc_dai *codec_dai, + unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; @@ -986,6 +1066,17 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, return 0; } +static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + + wm8960->freq_in = freq_in; + + return wm8960_set_pll(codec_dai, freq_in, freq_out); +} + static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) { @@ -1048,6 +1139,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, } wm8960->sysclk = freq; + wm8960->clk_id = clk_id; return 0; }