Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1264356imu; Fri, 21 Dec 2018 16:10:26 -0800 (PST) X-Google-Smtp-Source: AFSGD/UkFVk+5hGFUVN3YHT9CP2/sGLX6xSvMxn5LCra/v/Firs4WjjuESNvZQGwP/d3C20Ocsc6 X-Received: by 2002:a62:7042:: with SMTP id l63mr4775798pfc.89.1545437426632; Fri, 21 Dec 2018 16:10:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1545437426; cv=none; d=google.com; s=arc-20160816; b=D/WtVf0fadjqGZTXyzHwFeDKdH8DSaaxjc8TbQ8wSUpRGmoROJ3JTqO3AHbnLL07cv qEGlJEQjN8szuAYNIflzk3834tQaxpyoomLo3SfaNPYu/nZ4S9vXZaXWUGrldAzQJKZk RTWOeQ2St+nsYe4USz0+By30Wu5qV4l0iYsG8W5pQMrCGEn0aGW2FCJYwKSUTpiSObmZ lLtFp3dpaRTRaUp3DsThcXH3oAJTviQmUrPMoCtdciW3i00ioruY6xQjQuYgFaWBTjVz gnA8hEzYx10cqbSPIykGD/AK7HCTaPxxlAmD+34OG8SPQLzUWgzKDJxe6XdHpO87LUtu T2uQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=WttkbvrJMbeZSlFiVpQSvZj2pxx/qQWUGD6I3DfhS0U=; b=ynYdnvxVFtRWqog5QL70FWEoFobbvaxB+LpKM3diJRPUClY8pkvQnXn6WVZm5Hcst4 9E+p2hhHcNK88NUaleVkCT80GuHIhKvtcBjsZL8NaHsy9x+7iCHdCaJR9X1NZ8zfD0lC zWouxvlqwCI90TnYHFmETcUVQ0qzgA0Tb3gUIU/4wQY8rawe0Ht0CC13NsWsS/+2qA/m cphIIzOMyATpERqAv/szBDMX6jIZVViCo9CLCGTI4HQD3CIZ6sGYYmw7d8f0sTcc6QaF EDzIGTMKElKri1hGT+Dw/eAZG2KT4J2Yyc/Olc+b4LluFeUttTEp8VU4QHLfdQDsZ1X6 cy+w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="ktqJ1kt/"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e2si14201438pgj.316.2018.12.21.16.10.10; Fri, 21 Dec 2018 16:10:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="ktqJ1kt/"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404079AbeLUPVa (ORCPT + 99 others); Fri, 21 Dec 2018 10:21:30 -0500 Received: from mail-lj1-f194.google.com ([209.85.208.194]:44977 "EHLO mail-lj1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390999AbeLUPV0 (ORCPT ); Fri, 21 Dec 2018 10:21:26 -0500 Received: by mail-lj1-f194.google.com with SMTP id k19-v6so5039471lji.11 for ; Fri, 21 Dec 2018 07:21:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WttkbvrJMbeZSlFiVpQSvZj2pxx/qQWUGD6I3DfhS0U=; b=ktqJ1kt/lk3JTICDqMUMFZnM2hvnF0zNJ9f6saRYbOT1cE39WkOTvcMSCKRmCo5piX CGP/+24RvDovdWvNf0HgXyJqzb8JHy5505WjBekXy/W8z7pjRWfTrKROy/ouRa2DIO/5 akULMl1zJyNbmQkHL95C2XYX+cXp6iqznK2W4Y0QGV3o04sEVQf5R8pQpTd01xz9dgSO 79c/QTYzU+5IsulRWwGHlSCpsTFPkqymht4qE4bslgc+YMMFyy5+4YCsy4TuSSNMCJ8E dTdM3wsdbmuUgMvAlQ0P+VucQRLdwvGeiGWPKxkpMyWmIaiTas7ZOO7eIOBEGvJuujWk 97vA== 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:mime-version:content-transfer-encoding; bh=WttkbvrJMbeZSlFiVpQSvZj2pxx/qQWUGD6I3DfhS0U=; b=SDgH1z/rpu9YjzaF2S9r6UnMicT5V+ES7w7+DycFnkJZpXQpn/rg8fzFtBJoD2+aHS HvDFWvDc0Cv4wcTYZ1Yo44sc9xuCFXL80kaeswh92G9X+8m6efUkP3C+H3j6CvNQ6Oxj WjeEhzrualxsrXAP6jqVZE+qilzZUmLzC3dDY71txM4WGotp3OdijUt9JSpYObMtoR7w W2fqBCQEGRuS+Sf1nA3ODVuSmtdm7j4FtZ0jnxIUg7+g+StM6A721OWgZTUAaZYL5CnW uqaYclc3zxXaBiAOil29z+vyz9T+JlTkiR7RftO9bZ+R7GtRRgqPS+ntIrTWRf7oHEks +C6w== X-Gm-Message-State: AJcUukfjFv4OZhWdQTAa3q+euMnBrOW8CBvpi3fGxD3i8+Vr8kShx6bz xXW6x0pSzURZvg8X1Igu4Fg= X-Received: by 2002:a2e:2416:: with SMTP id k22-v6mr2090824ljk.80.1545405684248; Fri, 21 Dec 2018 07:21:24 -0800 (PST) Received: from localhost.localdomain (c90-142-43-138.bredband.comhem.se. [90.142.43.138]) by smtp.gmail.com with ESMTPSA id q30sm5005601lfi.94.2018.12.21.07.21.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 21 Dec 2018 07:21:23 -0800 (PST) From: codekipper@gmail.com To: maxime.ripard@free-electrons.com, wens@csie.org, linux-sunxi@googlegroups.com Cc: linux-arm-kernel@lists.infradead.org, lgirdwood@gmail.com, broonie@kernel.org, linux-kernel@vger.kernel.org, alsa-devel@alsa-project.org, be17068@iperbole.bo.it, Marcus Cooper Subject: [PATCH v3 9/9] ASoC: sun4i-i2s: Add multichannel functionality Date: Fri, 21 Dec 2018 16:21:10 +0100 Message-Id: <20181221152110.17982-10-codekipper@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181221152110.17982-1-codekipper@gmail.com> References: <20181221152110.17982-1-codekipper@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Marcus Cooper The i2s block can be used to pass PCM data over multiple channels and is sometimes used for the audio side of an HDMI connection. Signed-off-by: Marcus Cooper --- sound/soc/sunxi/sun4i-i2s.c | 121 +++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index cfcf427270fd..2be3a3e7a3c0 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -199,6 +199,7 @@ struct sun4i_i2s { unsigned int tdm_slots; unsigned int slot_width; + unsigned int offset; }; struct sun4i_i2s_clk_div { @@ -406,56 +407,71 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, int lines; channels = params_channels(params); - if ((channels > dai->driver->playback.channels_max) || - (channels < dai->driver->playback.channels_min)) { - dev_err(dai->dev, "Unsupported number of channels: %d\n", - channels); - return -EINVAL; - } - - lines = (channels + 1) / 2; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if ((channels > dai->driver->playback.channels_max) || + (channels < dai->driver->playback.channels_min)) { + dev_err(dai->dev, "Unsupported number of channels: %d\n", + channels); + return -EINVAL; + } - /* Enable the required output lines */ - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_SDO_EN_MASK, - SUN4I_I2S_CTRL_SDO_EN(lines)); - - if (i2s->variant->has_chcfg) { - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); - } + lines = (channels + 1) / 2; - /* Map the channels for playback and capture */ - regmap_field_write(i2s->field_rxchanmap, 0x00003210); - regmap_field_write(i2s->field_txchanmap, 0x10); - if (i2s->variant->has_chsel_tx_chen) { - if (channels > 2) - regmap_write(i2s->regmap, - SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32); - if (channels > 4) - regmap_write(i2s->regmap, - SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54); - if (channels > 6) - regmap_write(i2s->regmap, - SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76); + /* Enable the required output lines */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_SDO_EN_MASK, + SUN4I_I2S_CTRL_SDO_EN(lines)); + + if (i2s->variant->has_chcfg) + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); + + regmap_field_write(i2s->field_txchanmap, 0x10); + /* Configure the channels */ + regmap_field_write(i2s->field_txchansel, SUN4I_I2S_CHAN_SEL(2)); + + if (i2s->variant->has_chsel_tx_chen) { + u32 chan_sel = SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset) | 0x1; + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + chan_sel | 0x30); + + if (channels > 2) { + regmap_write(i2s->regmap, + SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32); + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG+4, + chan_sel | 0x30); + } + if (channels > 4) { + regmap_write(i2s->regmap, + SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54); + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG+8, + chan_sel | 0x30); + } + if (channels > 6) { + regmap_write(i2s->regmap, + SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76); + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG+12, + chan_sel | 0x30); + } + } + } else { + /* Map the channels for capture */ + regmap_field_write(i2s->field_rxchanmap, 0x00003210); + regmap_field_write(i2s->field_rxchansel, + SUN4I_I2S_CHAN_SEL(params_channels(params))); + + if (i2s->variant->has_chcfg) + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); + + if (i2s->variant->has_chsel_tx_chen) + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset)); } - /* Configure the channels */ - regmap_field_write(i2s->field_txchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); - - regmap_field_write(i2s->field_rxchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); - - if (i2s->variant->has_chsel_tx_chen) - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_EN_MASK, - SUN8I_I2S_TX_CHAN_EN(channels)); - switch (params_physical_width(params)) { case 16: width = DMA_SLAVE_BUSWIDTH_2_BYTES; @@ -509,7 +525,6 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); u32 val; - u32 offset = 0; u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; @@ -517,7 +532,7 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: val = SUN4I_I2S_FMT0_FMT_I2S; - offset = 1; + i2s->offset = 1; break; case SND_SOC_DAIFMT_LEFT_J: val = SUN4I_I2S_FMT0_FMT_LEFT_J; @@ -538,16 +553,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) * i2s shares the same setting with the LJ format. Increment * val so that the bit to value to write is correct. */ - if (offset > 0) + if (i2s->offset > 0) val++; - /* blck offset determines whether i2s or LJ */ - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); - - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); } regmap_field_write(i2s->field_fmt_mode, val); -- 2.20.1