Received: by 2002:a25:1506:0:0:0:0:0 with SMTP id 6csp5325034ybv; Tue, 11 Feb 2020 13:32:36 -0800 (PST) X-Google-Smtp-Source: APXvYqwFDm0HX62qg17MZS2JprGt3bxMzVnAc4nuU4qFiH6giAIKOezDcE50C2fHDDRuXyyRgXYk X-Received: by 2002:a05:6830:16d8:: with SMTP id l24mr6880320otr.268.1581456756249; Tue, 11 Feb 2020 13:32:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1581456756; cv=none; d=google.com; s=arc-20160816; b=ksLNedlbLtCwfsbAiIo59OkyjbFBQf9ieKCL07bfrm0hEc3xUBtZ+I32g8P8/UwcVD uY0xopiyVr4ix8zzhH4Vy2LqM5OgMWJppD8y7Wu9+Q5ky/bdA2SJphHoO9f6jsBGPRHA QzXz/+9MxBYHwgSjW/pzHjlhe5/MwEFUijVJyl1cHVH6qkiquxQYoWF8EFWznaF1MIEH cjeGcd/iUQPdwEFNngdUF8cwLBLpWK+6YLl8gRtTdFjJ+mv697ZzAjMnuslDbaq+MrCZ DM96PfWcvHgt0ko3rRVJzoXTWPLwlwbWNxnZybP//MCYm9MiFKX72cwpZYT+Lzj6UjyT aOLw== 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 :message-id:date:subject:cc:to:from; bh=NV32eOtxUd7goQhUkHMExoQdC/Zxb//9Ui15MIp8ONs=; b=rRKKOV3BKjLV0IKlrpyJFfNWWQi15fpp/6mBXyGIc0mXhVyRBVdXI4KkRfavt4dpKN j+K1nZ38lUiz6Ma5pTZOd6QIe9I2bFMLWAVoyJ2kbrsfAMq1eA09soXjGKrE2DhptBzv fqCBQ1POlfdQpnrDMOMH9pBcBxGV0rJ5QVastIk24FiKK2VYFPwtkoQya5T6gG3hUK71 9D8D5nBNK3q4VOs9xQfN+bZboQluSvJ/8hF4tF1KYOjVgaSHmXoClLHpWSDGRFRJd3Gm 9rWwzf5CwXco4aC7GaczTAfBbP5ASk1y07rNdEwurWz12r6fGsiBnbpIb2g04aYyn2I6 8N5A== ARC-Authentication-Results: i=1; mx.google.com; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c14si2590353otn.118.2020.02.11.13.32.24; Tue, 11 Feb 2020 13:32:36 -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; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731005AbgBKSKL (ORCPT + 99 others); Tue, 11 Feb 2020 13:10:11 -0500 Received: from muru.com ([72.249.23.125]:54794 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727764AbgBKSKL (ORCPT ); Tue, 11 Feb 2020 13:10:11 -0500 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id BCA5080D4; Tue, 11 Feb 2020 18:10:53 +0000 (UTC) From: Tony Lindgren To: Mark Brown Cc: Liam Girdwood , Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, "Arthur D ." , Merlijn Wajer , Pavel Machek , Sebastian Reichel Subject: [PATCH] ASoC: cpcap: Implement set_tdm_slot for voice call support Date: Tue, 11 Feb 2020 10:10:05 -0800 Message-Id: <20200211181005.54008-1-tony@atomide.com> X-Mailer: git-send-email 2.25.0 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 For using cpcap for voice calls, we need to route audio directly from the modem to cpcap for TDM (Time Division Multiplexing). The voice call is direct data between the modem and cpcap with no CPU involvment. In this mode, the cpcap related audio mixer controls work for the speaker selection and volume though. To do this, we need to implement standard snd_soc_dai_set_tdm_slot() for cpcap. Then the modem codec driver can use snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt(), and snd_soc_dai_set_tdm_slot() to configure a voice call. Let's add cpcap_voice_set_tdm_slot() for this, and cpcap_voice_call() helper to configure the additional registers needed for voice call. Let's also clear CPCAP_REG_VAUDIOC on init in case we have the bit for CPCAP_BIT_VAUDIO_MODE0 set on init. Cc: Arthur D. Cc: Merlijn Wajer Cc: Pavel Machek Cc: Sebastian Reichel Signed-off-by: Tony Lindgren --- sound/soc/codecs/cpcap.c | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -16,6 +16,14 @@ #include #include +/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */ +#define CPCAP_BIT_AUDIO_LOW_PWR 6 +#define CPCAP_BIT_AUD_LOWPWR_SPEED 5 +#define CPCAP_BIT_VAUDIOPRISTBY 4 +#define CPCAP_BIT_VAUDIO_MODE1 2 +#define CPCAP_BIT_VAUDIO_MODE0 1 +#define CPCAP_BIT_V_AUDIO_EN 0 + /* Register 513 CPCAP_REG_CC --- CODEC */ #define CPCAP_BIT_CDC_CLK2 15 #define CPCAP_BIT_CDC_CLK1 14 @@ -221,6 +229,7 @@ struct cpcap_reg_info { }; static const struct cpcap_reg_info cpcap_default_regs[] = { + { CPCAP_REG_VAUDIOC, 0x003F, 0x0000 }, { CPCAP_REG_CC, 0xFFFF, 0x0000 }, { CPCAP_REG_CC, 0xFFFF, 0x0000 }, { CPCAP_REG_CDI, 0xBFFF, 0x0000 }, @@ -1370,6 +1379,119 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +/* + * Configure codec for voice call if requested. + * + * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt() + * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the + * cpcap related hardware as CPU is not involved in the voice call. + */ +static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai, + bool voice_call) +{ + int mask, err; + + /* Modem to codec VAUDIO_MODE1 */ + mask = BIT(CPCAP_BIT_VAUDIO_MODE1); + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC, + mask, voice_call ? mask : 0); + if (err) + return err; + + /* Clear MIC1_MUX for call */ + mask = BIT(CPCAP_BIT_MIC1_MUX); + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, + mask, voice_call ? 0 : mask); + if (err) + return err; + + /* Set MIC2_MUX for call */ + mask = BIT(CPCAP_BIT_MB_ON1L) | BIT(CPCAP_BIT_MB_ON1R) | + BIT(CPCAP_BIT_MIC2_MUX) | BIT(CPCAP_BIT_MIC2_PGA_EN); + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, + mask, voice_call ? mask : 0); + if (err) + return err; + + /* Enable LDSP for call */ + mask = BIT(CPCAP_BIT_A2_LDSP_L_EN) | BIT(CPCAP_BIT_A2_LDSP_R_EN); + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA, + mask, voice_call ? mask : 0); + if (err) + return err; + + /* Enable CPCAP_BIT_PGA_CDC_EN for call */ + mask = BIT(CPCAP_BIT_PGA_CDC_EN); + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA, + mask, voice_call ? mask : 0); + if (err) + return err; + + /* Unmute voice for call */ + if (dai) { + err = snd_soc_dai_digital_mute(dai, !voice_call, + SNDRV_PCM_STREAM_PLAYBACK); + if (err) + return err; + } + + /* Set modem to codec mic CDC and HPF for call */ + mask = BIT(CPCAP_BIT_MIC2_CDC_EN) | BIT(CPCAP_BIT_CDC_EN_RX) | + BIT(CPCAP_BIT_AUDOHPF_1) | BIT(CPCAP_BIT_AUDOHPF_0) | + BIT(CPCAP_BIT_AUDIHPF_1) | BIT(CPCAP_BIT_AUDIHPF_0); + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, + mask, voice_call ? mask : 0); + if (err) + return err; + + /* Enable modem to codec CDC for call*/ + mask = BIT(CPCAP_BIT_CDC_CLK_EN); + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, + mask, voice_call ? mask : 0); + + return err; +} + +static int cpcap_voice_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); + int err, ts_mask, mask; + bool voice_call; + + /* + * Primitive test for voice call, probably needs more checks + * later on for 16-bit calls detected, Bluetooth headset etc. + */ + if (tx_mask == 0 && rx_mask == 1 && slot_width == 8) + voice_call = true; + else + voice_call = false; + + ts_mask = 0x7 << CPCAP_BIT_MIC2_TIMESLOT0; + ts_mask |= 0x7 << CPCAP_BIT_MIC1_RX_TIMESLOT0; + + mask = (tx_mask & 0x7) << CPCAP_BIT_MIC2_TIMESLOT0; + mask |= (rx_mask & 0x7) << CPCAP_BIT_MIC1_RX_TIMESLOT0; + + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, + ts_mask, mask); + if (err) + return err; + + err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, slot_width * 1000); + if (err) + return err; + + err = cpcap_voice_call(cpcap, dai, voice_call); + if (err) + return err; + + return 0; +} + static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_component *component = dai->component; @@ -1391,6 +1513,7 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = { .hw_params = cpcap_voice_hw_params, .set_sysclk = cpcap_voice_set_dai_sysclk, .set_fmt = cpcap_voice_set_dai_fmt, + .set_tdm_slot = cpcap_voice_set_tdm_slot, .digital_mute = cpcap_voice_set_mute, }; -- 2.25.0