From patchwork Mon Aug 14 22:06:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lori Hikichi X-Patchwork-Id: 9900319 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 C32B3602BA for ; Mon, 14 Aug 2017 22:08:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B482123F88 for ; Mon, 14 Aug 2017 22:08:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A8DBE2874C; Mon, 14 Aug 2017 22:08:04 +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=-2.6 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id BB0BB23F88 for ; Mon, 14 Aug 2017 22:08:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=SQSMVNaL9F18+ou8P3fD/m8Wv0B5nqVJ8mMNmd53Jho=; b=nQsUN1ycO3HjUvq8y+Ogg9F+ou bz3CtDiCUXIgqBCqnlI+T/hKfqXNUiaSOFkGPl2Lwojq8AuEbj+FkC1LzC4pBj8e2CK9diURNmuLm GppnFczjgG3dj1aUO9/7YTcjCWGF+MxxS1VgK1JSOurr3+uGQPgVv3KtTRKlvRMZ5tQvUxSuPMFvf tskPhWd5TjWhKn1e3JGR+ll0OSz3uS+a28fNU1QWWrhX6PeH2DpeHKSOCaiaNDn7EiLe9V7yu03Z+ 1EISIx/rz+pzGRzKW68zkJ+iL8LrGitIhHNMkErf0ieipjwt3ykU9wPaqyC3117/6R8bseODP3GAA WNk99m4Q==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dhNWh-0007FY-2t; Mon, 14 Aug 2017 22:07:59 +0000 Received: from mail-qk0-x230.google.com ([2607:f8b0:400d:c09::230]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dhNVU-00062p-Oe for linux-arm-kernel@lists.infradead.org; Mon, 14 Aug 2017 22:06:55 +0000 Received: by mail-qk0-x230.google.com with SMTP id d136so58137638qkg.3 for ; Mon, 14 Aug 2017 15:06:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=/WFTba2hxrsecJ+arHYSFBaPPTHYWpzL/ZX1GwqofsE=; b=g8dr0b7psXi0qVqCoW+VQUOcQyKMOvKp5zvinYG2vVvV+8bUo8j5A4XGT/W/JeD08s HUOnH3b1WXchpglLW5nFDa7VCCYor8B5JLIzRQ+mVmfRhz16Oq8BHcEbt4mHBK20Il2q /NLL94ptiTmGBRHGQshziQpQMCL+XTg8/JF4E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=/WFTba2hxrsecJ+arHYSFBaPPTHYWpzL/ZX1GwqofsE=; b=RAJTZSX7filV05lIbYF9WII18Ale3gNIdGqEXqYWKl+U5apjaqi2Mo+/ITXNLvjokY 6bb7RnTICHQ41ICPxy8hNWJQ2kUDvah/8hwJGEldcbKHcilOt+QGIMlG6N3ojGDdTkaX y3XKYR/8ksTNhuBOiNz37nH0j9uN2kgQXlwcQEj/PBHPo9gnB4QEwSqtFAkLMMiFs8cn R7MTz4ADXMH/h/WjXht2uHgWmf/ieyBRpbdvfvCyR00SKGC9Hwfng873Vmx72LeHRkDM 0hYmuePYCxf2qiqxdJP+XW37V0J3TobsCF1E3LQlrkAYJrm6b9NLzu9lO5TSoI4uU4Kj C6Hg== X-Gm-Message-State: AHYfb5gF/K7VxdnFBqjr5aLSkHaZAxQfR8W6XuoiQl3p6OuWUKmY5EC3 jzycAkWin/LuKmFs X-Received: by 10.55.68.70 with SMTP id r67mr34317553qka.63.1502748383024; Mon, 14 Aug 2017 15:06:23 -0700 (PDT) Received: from lbrmn-ubu57.dhcp.broadcom.net ([192.19.224.250]) by smtp.gmail.com with ESMTPSA id v50sm5735105qtb.10.2017.08.14.15.06.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Aug 2017 15:06:22 -0700 (PDT) From: Lori Hikichi To: Liam Girdwood , Mark Brown , Rob Herring , Mark Rutland , Ray Jui , Scott Branden , Jon Mason , bcm-kernel-feedback-list@broadcom.com, Jaroslav Kysela , Takashi Iwai Subject: [PATCH 3/9] ASoC: cygnus: Allow each port to select its clock source Date: Mon, 14 Aug 2017 15:06:51 -0700 Message-Id: <1502748417-26417-4-git-send-email-lori.hikichi@broadcom.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1502748417-26417-1-git-send-email-lori.hikichi@broadcom.com> References: <1502748417-26417-1-git-send-email-lori.hikichi@broadcom.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170814_150645_278900_8A220AE5 X-CRM114-Status: GOOD ( 22.93 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org, Lori Hikichi , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Add the ability to assign which of the 3 audio PLL outputs are to be used by each port. Remove the suspend and resume handlers because the only thing they were doing was unnecessarily maintaining the clock state. Signed-off-by: Lori Hikichi --- sound/soc/bcm/cygnus-ssp.c | 332 ++++++++++++++------------------------------- sound/soc/bcm/cygnus-ssp.h | 15 +- 2 files changed, 103 insertions(+), 244 deletions(-) diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 1a57a4e..00fd4dc 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -25,8 +25,6 @@ #include "cygnus-ssp.h" -#define DEFAULT_VCO 1354750204 - #define CAPTURE_FCI_ID_BASE 0x180 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff #define CYGNUS_PLLCLKSEL_MASK 0xf @@ -95,22 +93,10 @@ #define SPDIF_FORMAT_CFG_OFFSET 0xad8 #define SPDIF_MCLK_CFG_OFFSET 0xadc -/* AUD_FMM_IOP_PLL_0_xxx regs */ -#define IOP_PLL_0_MACRO_OFFSET 0xb00 -#define IOP_PLL_0_MDIV_Ch0_OFFSET 0xb14 -#define IOP_PLL_0_MDIV_Ch1_OFFSET 0xb18 -#define IOP_PLL_0_MDIV_Ch2_OFFSET 0xb1c - -#define IOP_PLL_0_ACTIVE_MDIV_Ch0_OFFSET 0xb30 -#define IOP_PLL_0_ACTIVE_MDIV_Ch1_OFFSET 0xb34 -#define IOP_PLL_0_ACTIVE_MDIV_Ch2_OFFSET 0xb38 - -/* AUD_FMM_IOP_xxx regs */ -#define IOP_PLL_0_CONTROL_OFFSET 0xb04 -#define IOP_PLL_0_USER_NDIV_OFFSET 0xb08 -#define IOP_PLL_0_ACTIVE_NDIV_OFFSET 0xb20 -#define IOP_PLL_0_RESET_OFFSET 0xb5c +/*-------------------------------------------- + * Register offsets for i2s_in io space + */ /* AUD_FMM_IOP_IN_I2S_xxx regs */ #define IN_I2S_0_STREAM_CFG_OFFSET 0x00 #define IN_I2S_0_CFG_OFFSET 0x04 @@ -173,12 +159,6 @@ #define SPDIF_0_OUT_DITHER_ENA 3 #define SPDIF_0_OUT_STREAM_ENA 31 -/* AUD_FMM_IOP_PLL_0_USER */ -#define IOP_PLL_0_USER_NDIV_FRAC 10 - -/* AUD_FMM_IOP_PLL_0_ACTIVE */ -#define IOP_PLL_0_ACTIVE_NDIV_FRAC 10 - #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \ .i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \ @@ -193,41 +173,6 @@ .bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \ } -struct pll_macro_entry { - u32 mclk; - u32 pll_ch_num; -}; - -/* - * PLL has 3 output channels (1x, 2x, and 4x). Below are - * the common MCLK frequencies used by audio driver - */ -static const struct pll_macro_entry pll_predef_mclk[] = { - { 4096000, 0}, - { 8192000, 1}, - {16384000, 2}, - - { 5644800, 0}, - {11289600, 1}, - {22579200, 2}, - - { 6144000, 0}, - {12288000, 1}, - {24576000, 2}, - - {12288000, 0}, - {24576000, 1}, - {49152000, 2}, - - {22579200, 0}, - {45158400, 1}, - {90316800, 2}, - - {24576000, 0}, - {49152000, 1}, - {98304000, 2}, -}; - #define CYGNUS_RATE_MIN 8000 #define CYGNUS_RATE_MAX 384000 @@ -488,59 +433,6 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio) return status; } -static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk, - struct cygnus_aio_port *aio) -{ - int i = 0, error; - bool found = false; - const struct pll_macro_entry *p_entry; - struct clk *ch_clk; - - for (i = 0; i < ARRAY_SIZE(pll_predef_mclk); i++) { - p_entry = &pll_predef_mclk[i]; - if (p_entry->mclk == mclk) { - found = true; - break; - } - } - if (!found) { - dev_err(cygaud->dev, - "%s No valid mclk freq (%u) found!\n", __func__, mclk); - return -EINVAL; - } - - ch_clk = cygaud->audio_clk[p_entry->pll_ch_num]; - - if ((aio->clk_trace.cap_en) && (!aio->clk_trace.cap_clk_en)) { - error = clk_prepare_enable(ch_clk); - if (error) { - dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n", - __func__, error); - return error; - } - aio->clk_trace.cap_clk_en = true; - } - - if ((aio->clk_trace.play_en) && (!aio->clk_trace.play_clk_en)) { - error = clk_prepare_enable(ch_clk); - if (error) { - dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n", - __func__, error); - return error; - } - aio->clk_trace.play_clk_en = true; - } - - error = clk_set_rate(ch_clk, mclk); - if (error) { - dev_err(cygaud->dev, "%s Set MCLK rate failed: %d\n", - __func__, error); - return error; - } - - return p_entry->pll_ch_num; -} - static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio) { u32 value; @@ -723,26 +615,68 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream, } /* + * Check that the actual mclk is within about 1% of the requested rate. + * The check is rather loose and is intended to catch any big mistakes. + * It is expected that the actual mclk rate may be a little different + * than the requested rate because the clock from which the mclk is + * derived (PLL) may not be an exact multiple of the mclk. + */ +static bool mclk_in_range(unsigned int target, unsigned int actual) +{ + unsigned int delta; + + /* Mclk is at least several MHz, so simple div by 100 will suffice */ + delta = target / 100; + return (actual > (target - delta)) && (actual < (target + delta)); +} + +/* * This function sets the mclk frequency for pll clock */ static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { int sel; + int ret; u32 value; + long rate; struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); - struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai); dev_dbg(aio->cygaud->dev, "%s Enter port = %d\n", __func__, aio->portnum); - sel = pll_configure_mclk(cygaud, freq, aio); - if (sel < 0) { + + /* + * This should not happen, but the machine file may inadvertently + * call set_sysclk without configuring a clock via the devicetree. + */ + if (!aio->clk_info.audio_clk) { dev_err(aio->cygaud->dev, - "%s Setting mclk failed.\n", __func__); + "%s Error. No clock assigned.\n", __func__); + return -ENODEV; + } + + rate = clk_round_rate(aio->clk_info.audio_clk, freq); + if (rate < 0) { + dev_err(aio->cygaud->dev, "%s Error with with clock %ld.\n", + __func__, rate); + return rate; + } + + if (!mclk_in_range(freq, rate)) { + dev_err(aio->cygaud->dev, "%s Can not set rate to %u actual %ld.\n", + __func__, freq, rate); return -EINVAL; } + ret = clk_set_rate(aio->clk_info.audio_clk, freq); + if (ret) { + dev_err(aio->cygaud->dev, + "%s Set MCLK rate fail %d\n", __func__, ret); + return ret; + } + aio->mclk = freq; + sel = aio->clk_info.clk_mux; dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel); value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg); @@ -759,17 +693,14 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream, struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); snd_soc_dai_set_dma_data(dai, substream, aio); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - aio->clk_trace.play_en = true; - else - aio->clk_trace.cap_en = true; substream->runtime->hw.rate_min = CYGNUS_RATE_MIN; substream->runtime->hw.rate_max = CYGNUS_RATE_MAX; snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint); - return 0; + + return clk_prepare_enable(aio->clk_info.audio_clk); } static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream, @@ -777,36 +708,7 @@ static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream, { struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - aio->clk_trace.play_en = false; - else - aio->clk_trace.cap_en = false; - - if (!aio->is_slave) { - u32 val; - - val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg); - val &= CYGNUS_PLLCLKSEL_MASK; - if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) { - dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n", - val); - return; - } - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (aio->clk_trace.play_clk_en) { - clk_disable_unprepare(aio->cygaud-> - audio_clk[val]); - aio->clk_trace.play_clk_en = false; - } - } else { - if (aio->clk_trace.cap_clk_en) { - clk_disable_unprepare(aio->cygaud-> - audio_clk[val]); - aio->clk_trace.cap_clk_en = false; - } - } - } + clk_disable_unprepare(aio->clk_info.audio_clk); } /* @@ -945,7 +847,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); - struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai); dev_dbg(aio->cygaud->dev, "%s cmd %d at port = %d\n", __func__, cmd, aio->portnum); @@ -958,7 +859,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd, audio_ssp_out_enable(aio); else audio_ssp_in_enable(aio); - cygaud->active_ports++; break; @@ -969,7 +869,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd, audio_ssp_out_disable(aio); else audio_ssp_in_disable(aio); - cygaud->active_ports--; break; default: @@ -1063,68 +962,34 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, return 0; } -#ifdef CONFIG_PM_SLEEP -static int cygnus_ssp_suspend(struct snd_soc_dai *cpu_dai) +static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out) { struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai); + struct clk *clk_pll; + int ret = 0; - if (!aio->is_slave) { - u32 val; - - val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg); - val &= CYGNUS_PLLCLKSEL_MASK; - if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) { - dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n", - val); - return -EINVAL; - } - - if (aio->clk_trace.cap_clk_en) - clk_disable_unprepare(aio->cygaud->audio_clk[val]); - if (aio->clk_trace.play_clk_en) - clk_disable_unprepare(aio->cygaud->audio_clk[val]); + if (!aio->clk_info.audio_clk) { + dev_err(aio->cygaud->dev, + "%s: port %d does not have an assigned clock.\n", + __func__, aio->portnum); + return -ENODEV; + } - aio->pll_clk_num = val; + clk_pll = clk_get_parent(aio->clk_info.audio_clk); + if (IS_ERR(clk_pll)) { + dev_err(aio->cygaud->dev, + "%s: could not get audiopll clock.\n", __func__); + return -ENODEV; } - return 0; + ret = clk_set_rate(clk_pll, freq_out); + + return ret; } -static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai) -{ - struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai); - int error; - - if (!aio->is_slave) { - if (aio->clk_trace.cap_clk_en) { - error = clk_prepare_enable(aio->cygaud-> - audio_clk[aio->pll_clk_num]); - if (error) { - dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n", - __func__); - return -EINVAL; - } - } - if (aio->clk_trace.play_clk_en) { - error = clk_prepare_enable(aio->cygaud-> - audio_clk[aio->pll_clk_num]); - if (error) { - if (aio->clk_trace.cap_clk_en) - clk_disable_unprepare(aio->cygaud-> - audio_clk[aio->pll_clk_num]); - dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n", - __func__); - return -EINVAL; - } - } - } - return 0; -} -#else -#define cygnus_ssp_suspend NULL -#define cygnus_ssp_resume NULL -#endif static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = { .startup = cygnus_ssp_startup, @@ -1134,6 +999,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai) .set_fmt = cygnus_ssp_set_fmt, .set_sysclk = cygnus_ssp_set_sysclk, .set_tdm_slot = cygnus_set_dai_tdm_slot, + .set_pll = cygnus_ssp_set_pll, }; @@ -1155,8 +1021,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai) SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &cygnus_ssp_dai_ops, \ - .suspend = cygnus_ssp_suspend, \ - .resume = cygnus_ssp_resume, \ } static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = { @@ -1175,8 +1039,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai) SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &cygnus_ssp_dai_ops, - .suspend = cygnus_ssp_suspend, - .resume = cygnus_ssp_resume, }; static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS]; @@ -1200,6 +1062,8 @@ static int parse_ssp_child_node(struct platform_device *pdev, u32 rawval; int portnum = -1; enum cygnus_audio_port_type port_type; + u32 muxval; + struct clk *clk; if (of_property_read_u32(dn, "reg", &rawval)) { dev_err(&pdev->dev, "Missing reg property\n"); @@ -1259,28 +1123,37 @@ static int parse_ssp_child_node(struct platform_device *pdev, dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum); aio->streams_on = 0; aio->cygaud->dev = &pdev->dev; - aio->clk_trace.play_en = false; - aio->clk_trace.cap_en = false; - audio_ssp_init_portregs(aio); - return 0; -} -static int audio_clk_init(struct platform_device *pdev, - struct cygnus_audio *cygaud) -{ - int i; - char clk_name[PROP_LEN_MAX]; + aio->clk_info.audio_clk = NULL; - for (i = 0; i < ARRAY_SIZE(cygaud->audio_clk); i++) { - snprintf(clk_name, PROP_LEN_MAX, "ch%d_audio", i); + /* + * The default in the DT is to assign a clock. It is possible + * the user may not want a clock if the port is only used in slave + * mode. In this case, they could override the default using this + * mechanism: /delete-property/ clocks; + */ + if (of_property_read_bool(dn, "clocks")) { + clk = devm_get_clk_from_child(&pdev->dev, dn, "ssp_clk"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, + "Port %d: devm_clk_get ssp-clk err %ld\n", + portnum, PTR_ERR(clk)); + return PTR_ERR(clk); + } - cygaud->audio_clk[i] = devm_clk_get(&pdev->dev, clk_name); - if (IS_ERR(cygaud->audio_clk[i])) - return PTR_ERR(cygaud->audio_clk[i]); + aio->clk_info.audio_clk = clk; + + if (of_property_read_u32(dn, "brcm,ssp-clk-mux", &muxval)) { + dev_err(&pdev->dev, "Missing property clock-mux\n"); + return -EINVAL; + } + aio->clk_info.clk_mux = muxval; + } else { + dev_dbg(&pdev->dev, "No clock provided for port %d\n", portnum); } - return 0; + return audio_ssp_init_portregs(aio); } static int cygnus_ssp_probe(struct platform_device *pdev) @@ -1337,7 +1210,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev) } cygaud->dev = dev; - cygaud->active_ports = 0; dev_dbg(dev, "Registering %d DAIs\n", active_port_count); err = snd_soc_register_component(dev, &cygnus_ssp_component, @@ -1354,12 +1226,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev) goto err_irq; } - err = audio_clk_init(pdev, cygaud); - if (err) { - dev_err(dev, "audio clock initialization failed\n"); - goto err_irq; - } - err = cygnus_soc_platform_register(dev, cygaud); if (err) { dev_err(dev, "platform reg error %d\n", err); diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h index 33dd343..ad15a00 100644 --- a/sound/soc/bcm/cygnus-ssp.h +++ b/sound/soc/bcm/cygnus-ssp.h @@ -19,7 +19,6 @@ #define CYGNUS_MAX_CAPTURE_PORTS 3 #define CYGNUS_MAX_I2S_PORTS 3 #define CYGNUS_MAX_PORTS CYGNUS_MAX_PLAYBACK_PORTS -#define CYGNUS_AUIDO_MAX_NUM_CLKS 3 #define CYGNUS_SSP_FRAMEBITS_DIV 1 @@ -81,11 +80,9 @@ struct cygnus_ssp_regs { u32 bf_sourcech_grp; }; -struct cygnus_track_clk { - bool cap_en; - bool play_en; - bool cap_clk_en; - bool play_clk_en; +struct cygnus_audio_clkinfo { + struct clk *audio_clk; + int clk_mux; }; struct cygnus_aio_port { @@ -110,7 +107,7 @@ struct cygnus_aio_port { struct snd_pcm_substream *play_stream; struct snd_pcm_substream *capture_stream; - struct cygnus_track_clk clk_trace; + struct cygnus_audio_clkinfo clk_info; }; @@ -121,10 +118,6 @@ struct cygnus_audio { void __iomem *audio; struct device *dev; void __iomem *i2s_in; - - struct clk *audio_clk[CYGNUS_AUIDO_MAX_NUM_CLKS]; - int active_ports; - unsigned long vco_rate; }; extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);