From patchwork Mon Oct 19 23:49:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Zhang X-Patchwork-Id: 7440621 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 ABCD5BEEA4 for ; Mon, 19 Oct 2015 23:50:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8E76D207D0 for ; Mon, 19 Oct 2015 23:50:29 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id BE830206D9 for ; Mon, 19 Oct 2015 23:50:25 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 2AFD6265FCB; Tue, 20 Oct 2015 01:50:24 +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=-2.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_LOW, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 125F4265E3A; Tue, 20 Oct 2015 01:50:02 +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 6F65C26609B; Tue, 20 Oct 2015 01:50:00 +0200 (CEST) Received: from mail-pa0-f44.google.com (mail-pa0-f44.google.com [209.85.220.44]) by alsa0.perex.cz (Postfix) with ESMTP id 2EC96265E32 for ; Tue, 20 Oct 2015 01:49:32 +0200 (CEST) Received: by pasz6 with SMTP id z6so1138466pas.2 for ; Mon, 19 Oct 2015 16:49:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Pmeuv0lM+0OwG8V0tKMalZX4L8CeuvyJCag/sTfIOfk=; b=i6zfSKbSiTVWHAzrUGtsofYwU2EAN4v7fXbaf6rS4mJqTtObBcVNb34gPGZkPxBkeK mq7DkCfRjq2rlVxSiXJrjT6PW1arEg1Lu/KHM4M//n8H3zVCNeHxXINSuGRbciJlSZ0i celzuvJTmzIDFsZ47Tq5b+yHz7no1GGINCGPg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Pmeuv0lM+0OwG8V0tKMalZX4L8CeuvyJCag/sTfIOfk=; b=Beu3vIDGMkYV+i5GeEX55iYc863mwa4cFN15d5vkxNNTKFT3ug9o8Sgvf2r+pIEtcD FRddB0N5V4BVm+B77A9joexObLvwXMYyOxKLcQWerkdA4B6hDP8SYNs3xAID/xVZEAq2 WL+3aMDTIgRD20gs/QBLP9Dal8+HOV9FTC57n4qqM6exyk58hQHqLQoMz+QAG1gqeNfD HfriiAfIFO8sj2VgmRIl8akay1J9aQazUNTzXz/g9jh7JgYnBvqovzn6tF5sJN25GfqV GFc0MiYayDbGtTeZIb4pjnaaqrrr1bvUHcItnfnlo1giz8fBF2Kt+m9AoZYxI5anWkRX vfMw== X-Gm-Message-State: ALoCoQnR39nMlTzjAFpWq/21M3SEmztOr6AQt3JtSUIqRt7biPktZ9JcFjdQZt7fX02mjS58xEB7 X-Received: by 10.66.131.76 with SMTP id ok12mr234770pab.30.1445298571094; Mon, 19 Oct 2015 16:49:31 -0700 (PDT) Received: from benzh.mtv.corp.google.com ([172.22.65.67]) by smtp.gmail.com with ESMTPSA id ha3sm147877pbb.28.2015.10.19.16.49.29 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 19 Oct 2015 16:49:30 -0700 (PDT) From: Ben Zhang To: Mark Brown Date: Mon, 19 Oct 2015 16:49:05 -0700 Message-Id: <1445298546-23975-2-git-send-email-benzh@chromium.org> X-Mailer: git-send-email 2.6.0.rc2.230.g3dd15c0 In-Reply-To: <1445298546-23975-1-git-send-email-benzh@chromium.org> References: <1445298546-23975-1-git-send-email-benzh@chromium.org> Cc: alsa-devel@alsa-project.org, John Hsu , Liam Girdwood , Ben Zhang , Anatol Pomozov , Chih-Chiang Chang Subject: [alsa-devel] [PATCH v4 1/2] ASoC: nau8825: Add FLL configuration 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: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP snd_soc_codec_driver.set_pll is implemented to configure the FLL. The codec internal SYSCLK can be from either the MCLK pin directly, or the FLL. This is configured by snd_soc_codec_driver.set_pll. Signed-off-by: Ben Zhang --- sound/soc/codecs/nau8825.c | 163 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/nau8825.h | 28 ++++++-- 2 files changed, 186 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 5c1badf..bd58b96 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,58 @@ #include "nau8825.h" +#define NAU_FREF_MAX 13500000 +#define NAU_FVCO_MAX 100000000 +#define NAU_FVCO_MIN 90000000 + +struct nau8825_fll { + int mclk_src; + int ratio; + int fll_frac; + int fll_int; + int clk_ref_div; +}; + +struct nau8825_fll_attr { + unsigned int param; + unsigned int val; +}; + +/* scaling for mclk from sysclk_src output */ +static const struct nau8825_fll_attr mclk_src_scaling[] = { + { 1, 0x0 }, + { 2, 0x2 }, + { 4, 0x3 }, + { 8, 0x4 }, + { 16, 0x5 }, + { 32, 0x6 }, + { 3, 0x7 }, + { 6, 0xa }, + { 12, 0xb }, + { 24, 0xc }, + { 48, 0xd }, + { 96, 0xe }, + { 5, 0xf }, +}; + +/* ratio for input clk freq */ +static const struct nau8825_fll_attr fll_ratio[] = { + { 512000, 0x01 }, + { 256000, 0x02 }, + { 128000, 0x04 }, + { 64000, 0x08 }, + { 32000, 0x10 }, + { 8000, 0x20 }, + { 4000, 0x40 }, +}; + +static const struct nau8825_fll_attr fll_pre_scalar[] = { + { 1, 0x0 }, + { 2, 0x1 }, + { 4, 0x2 }, + { 8, 0x3 }, +}; + static const struct reg_default nau8825_reg_defaults[] = { { NAU8825_REG_ENA_CTRL, 0x00ff }, { NAU8825_REG_CLK_DIVIDER, 0x0050 }, @@ -808,6 +861,115 @@ static int nau8825_codec_probe(struct snd_soc_codec *codec) return 0; } +/** + * nau8825_calc_fll_param - Calculate FLL parameters. + * @fll_in: external clock provided to codec. + * @fs: sampling rate. + * @fll_param: Pointer to structure of FLL parameters. + * + * Calculate FLL parameters to configure codec. + * + * Returns 0 for success or negative error code. + */ +static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs, + struct nau8825_fll *fll_param) +{ + u64 fvco; + unsigned int fref, i; + + /* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing + * freq_in by 1, 2, 4, or 8 using FLL pre-scalar. + * FREF = freq_in / NAU8825_FLL_REF_DIV_MASK + */ + for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) { + fref = fll_in / fll_pre_scalar[i].param; + if (fref <= NAU_FREF_MAX) + break; + } + if (i == ARRAY_SIZE(fll_pre_scalar)) + return -EINVAL; + fll_param->clk_ref_div = fll_pre_scalar[i].val; + + /* Choose the FLL ratio based on FREF */ + for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) { + if (fref >= fll_ratio[i].param) + break; + } + if (i == ARRAY_SIZE(fll_ratio)) + return -EINVAL; + fll_param->ratio = fll_ratio[i].val; + + /* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs. + * FDCO must be within the 90MHz - 100MHz or the FFL cannot be + * guaranteed across the full range of operation. + * FDCO = freq_out * 2 * mclk_src_scaling + */ + for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { + fvco = 256 * fs * 2 * mclk_src_scaling[i].param; + if (NAU_FVCO_MIN < fvco && fvco < NAU_FVCO_MAX) + break; + } + if (i == ARRAY_SIZE(mclk_src_scaling)) + return -EINVAL; + fll_param->mclk_src = mclk_src_scaling[i].val; + + /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional + * input based on FDCO, FREF and FLL ratio. + */ + fvco = div_u64(fvco << 16, fref * fll_param->ratio); + fll_param->fll_int = (fvco >> 16) & 0x3FF; + fll_param->fll_frac = fvco & 0xFFFF; + return 0; +} + +static void nau8825_fll_apply(struct nau8825 *nau8825, + struct nau8825_fll *fll_param) +{ + regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_MCLK_SRC_MASK, fll_param->mclk_src); + regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1, + NAU8825_FLL_RATIO_MASK, fll_param->ratio); + /* FLL 16-bit fractional input */ + regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac); + /* FLL 10-bit integer input */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL3, + NAU8825_FLL_INTEGER_MASK, fll_param->fll_int); + /* FLL pre-scaler */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL4, + NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div); + /* select divided VCO input */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, + NAU8825_FLL_FILTER_SW_MASK, 0x0000); + /* FLL sigma delta modulator enable */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, + NAU8825_SDM_EN_MASK, NAU8825_SDM_EN); +} + +/* freq_out must be 256*Fs in order to achieve the best performance */ +static int nau8825_set_pll(struct snd_soc_codec *codec, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); + struct nau8825_fll fll_param; + int ret, fs; + + fs = freq_out / 256; + ret = nau8825_calc_fll_param(freq_in, fs, &fll_param); + if (ret < 0) { + dev_err(codec->dev, "Unsupported input clock %d\n", freq_in); + return ret; + } + dev_dbg(codec->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n", + fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac, + fll_param.fll_int, fll_param.clk_ref_div); + + nau8825_fll_apply(nau8825, &fll_param); + mdelay(2); + regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO); + return 0; +} + static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, unsigned int freq) { @@ -920,6 +1082,7 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec, static struct snd_soc_codec_driver nau8825_codec_driver = { .probe = nau8825_codec_probe, .set_sysclk = nau8825_set_sysclk, + .set_pll = nau8825_set_pll, .set_bias_level = nau8825_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 8774923..dff8edb 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -101,13 +101,31 @@ #define NAU8825_ENABLE_SAR_SFT 1 /* CLK_DIVIDER (0x3) */ -#define NAU8825_CLK_SRC_SFT 15 -#define NAU8825_CLK_SRC_MASK (1 << NAU8825_CLK_SRC_SFT) -#define NAU8825_CLK_SRC_VCO (1 << NAU8825_CLK_SRC_SFT) -#define NAU8825_CLK_SRC_MCLK (0 << NAU8825_CLK_SRC_SFT) +#define NAU8825_CLK_SRC_SFT 15 +#define NAU8825_CLK_SRC_MASK (1 << NAU8825_CLK_SRC_SFT) +#define NAU8825_CLK_SRC_VCO (1 << NAU8825_CLK_SRC_SFT) +#define NAU8825_CLK_SRC_MCLK (0 << NAU8825_CLK_SRC_SFT) +#define NAU8825_CLK_MCLK_SRC_MASK (0xf << 0) + +/* FLL1 (0x04) */ +#define NAU8825_FLL_RATIO_MASK (0x7f << 0) + +/* FLL3 (0x06) */ +#define NAU8825_FLL_INTEGER_MASK (0x3ff << 0) + +/* FLL4 (0x07) */ +#define NAU8825_FLL_REF_DIV_MASK (0x3 << 10) + +/* FLL5 (0x08) */ +#define NAU8825_FLL_FILTER_SW_MASK (0x1 << 14) /* FLL6 (0x9) */ -#define NAU8825_DCO_EN (1 << 15) +#define NAU8825_DCO_EN_MASK (0x1 << 15) +#define NAU8825_DCO_EN (0x1 << 15) +#define NAU8825_DCO_DIS (0x0 << 15) +#define NAU8825_SDM_EN_MASK (0x1 << 14) +#define NAU8825_SDM_EN (0x1 << 14) +#define NAU8825_SDM_DIS (0x0 << 14) /* HSD_CTRL (0xc) */ #define NAU8825_HSD_AUTO_MODE (1 << 6)