Received: by 10.192.165.148 with SMTP id m20csp4564039imm; Tue, 8 May 2018 10:23:05 -0700 (PDT) X-Google-Smtp-Source: AB8JxZra31jb+ZybqVVg9CPzRb0fkCuV9bEU/yBZG+OHgvVADVBbWF+Q7iCu4ar7txArs/yipJWq X-Received: by 10.98.155.141 with SMTP id e13mr41222181pfk.157.1525800185045; Tue, 08 May 2018 10:23:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525800185; cv=none; d=google.com; s=arc-20160816; b=z1VAM793G9+q/wWguCb9t1VKD3Xn7/4ueoR2y5Ry+Nn3zf2FzME5YgKZdXvOwMrw7E 1LQT5HiluJrbrzZ0/dsmTrUtaGYTdHnZIqssIn9fWOfBRemWFw8R1BEFZckNh8RASDaJ ziyH9cXd7F/OR/gETVdOUkQSUUit2BgE06+baDT6TwqKyrmN6FvXiYvBAh2jyMZgtzhp +wlA6T0GtWWD6l3+hz2o6bkualtr9/ZXwDjF1XypY8KFerGW5snU5827u1Xo5s9GoAai /eZqqGgrFgG6DPrJspYm6rQ/kIFqm08nihPX99nGMjvZQ2USWEFbXFa0TLnQDSHP303s jYvQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:to:references:in-reply-to:message-id:date :subject:cc:from:dkim-signature:arc-authentication-results; bh=pRujDIlzn80DygcIS/DBfH0P/oP/V4hgtxbPTDqdWPA=; b=WYM0gy7jLScc4mkB7Rn84tjC9GL++VJRygBcEGxIEyqof0/T99Rg2CA+rZMcSgWZru 6/qmkNmAZPIEI4YMjWyMjIYw8fdf+zG3AaQswtYeUL/ZXSzTp4j3zlUw25iK89skPdW6 h5SsYuQKnPbqCz/jiRl7iCHPW9Oo17l4/Ni5qeKIHJSaZJZBkcEk1ehC007cIOZSZhXi 043VfmT2YuxdARV5WHIk5WwewQ6v1XWDDif01Y+tAA7uE1E3oWbB86rd1UzqF/Bue7uK +ZmWSv5iun90ptxblylFIYBx2qsgi8Grumzy2fbQXg0tv4k2VOJTU+Ncov72jDngAL1m kXdA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=EPqgsr0D; 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=fail (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 u6-v6si25058195plz.461.2018.05.08.10.22.50; Tue, 08 May 2018 10:23:05 -0700 (PDT) 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=fail header.i=@gmail.com header.s=20161025 header.b=EPqgsr0D; 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=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932732AbeEHRVW (ORCPT + 99 others); Tue, 8 May 2018 13:21:22 -0400 Received: from mail-io0-f195.google.com ([209.85.223.195]:41411 "EHLO mail-io0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932204AbeEHRVK (ORCPT ); Tue, 8 May 2018 13:21:10 -0400 Received: by mail-io0-f195.google.com with SMTP id e12-v6so39354029iob.8 for ; Tue, 08 May 2018 10:21:09 -0700 (PDT) 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; bh=pRujDIlzn80DygcIS/DBfH0P/oP/V4hgtxbPTDqdWPA=; b=EPqgsr0DCNFglMYnxXhpDCPbQ9h0b2INcd2Lo9W+jDxrg2r6eKJHHbJJdCyRVUQ3oH wmIs3xlcaNw/0M/T798sJ6PujG/VM6X/NfIKCqc+NwtUCT9Qh4jBzdUz3cheV3ZAY2VP PtrPTsuFSZVJTFsEfOoQweQ6H+5Bhdt2brnC5xVGqZBSW93nPCz5c2VblFolTPU2sT9+ 1ZS7xMSEa+8FMZR8cfRd+y6uvPeEAD42T1BJuPPDNlTcC+VQ2gBf2tT7doc8MtklSxXl ktDUSTSVQ+3VPsfmPlhPFRq3w/wwdOq+RzkBBhAqTZXgs8+tr9rf14GLSy7hbOvQ/i/W C5cA== 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=pRujDIlzn80DygcIS/DBfH0P/oP/V4hgtxbPTDqdWPA=; b=A8Ez8IZIgKrLAgZQkGqg2Zn0oyOOJZHN/mNEqwZWdBrgs4xRZU2MtDc7EYFuIlI7fI E2uTXIcCtcBK34qj7tGWJfF4kpFzC1b6VoKDI0eT+uH0FXANCjmJcsSE3pFGAe2wiDa8 onvxayMBuk+pogDXH12zXNYNuIPByfiFHnGXxEtTkR9MZi17katrdU+yAENnThgqlp+Y JN/dR5avE99Pdu2mkH6V5U1roLk65sCoCCQT0aIOE0777Jbq3ZK2WjkDTXScprxfxjKH /hh5R5b+hXjhNmvS6c5Tc7LyUr46s01nlONf/zYIrOdqXgLkqzZmywiYhBK7dwOTFARJ /GaA== X-Gm-Message-State: ALKqPwdQSo3ihqstEHUSPymlDhl4bJLYL2CR2K2V2b332S+1+ohE9HiV W+3/KvDJOed1Ib9UHNHao8E= X-Received: by 2002:a6b:1f4c:: with SMTP id f73-v6mr1510375iof.236.1525800069242; Tue, 08 May 2018 10:21:09 -0700 (PDT) Received: from localhost.localdomain ([2605:a000:1316:4462:80cc:335d:e307:b5cb]) by smtp.googlemail.com with ESMTPSA id k62-v6sm13160209ioo.23.2018.05.08.10.21.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 08 May 2018 10:21:08 -0700 (PDT) From: Connor McAdams Cc: o-takashi@sakamocchi.jp, Connor McAdams , Jaroslav Kysela , Takashi Iwai , =?UTF-8?q?J=C3=A9r=C3=A9my=20Lefaure?= , alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 11/13] ALSA: hda/ca0132: Add DSP Volume set and New mixers for SBZ + R3Di Date: Tue, 8 May 2018 13:20:11 -0400 Message-Id: <1525800015-2920-12-git-send-email-conmanx360@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1525800015-2920-1-git-send-email-conmanx360@gmail.com> References: <1525800015-2920-1-git-send-email-conmanx360@gmail.com> To: unlisted-recipients:; (no To-header on input) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Adds lookup table for floating point decibel volume, and new functions to allow for setting the decibel level on the DSP. Signed-off-by: Connor McAdams --- sound/pci/hda/patch_ca0132.c | 203 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 2a42faf..311df61 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -537,6 +537,31 @@ static const struct ca0132_alt_out_set alt_out_presets[] = { } }; +/* + * DSP volume setting structs. Req 1 is left volume, req 2 is right volume, + * and I don't know what the third req is, but it's always zero. I assume it's + * some sort of update or set command to tell the DSP there's new volume info. + */ +#define DSP_VOL_OUT 0 +#define DSP_VOL_IN 1 + +struct ct_dsp_volume_ctl { + hda_nid_t vnid; + int mid; /* module ID*/ + unsigned int reqs[3]; /* scp req ID */ +}; + +static struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = { + { .vnid = VNID_SPK, + .mid = 0x32, + .reqs = {3, 4, 2} + }, + { .vnid = VNID_MIC, + .mid = 0x37, + .reqs = {2, 3, 1} + } +}; + enum hda_cmd_vendor_io { /* for DspIO node */ VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, @@ -3248,6 +3273,24 @@ static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info, .tlv = { .c = ca0132_volume_tlv }, \ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } +/* + * Creates a mixer control that uses defaults of HDA_CODEC_VOL except for the + * volume put, which is used for setting the DSP volume. This was done because + * the ca0132 functions were taking too much time and causing lag. + */ +#define CA0132_ALT_CODEC_VOL_MONO(xname, nid, channel, dir) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_AMP_FLAG, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ + .info = snd_hda_mixer_amp_volume_info, \ + .get = snd_hda_mixer_amp_volume_get, \ + .put = ca0132_alt_volume_put, \ + .tlv = { .c = snd_hda_mixer_amp_tlv }, \ + .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } + #define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -3260,9 +3303,40 @@ static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info, /* stereo */ #define CA0132_CODEC_VOL(xname, nid, dir) \ CA0132_CODEC_VOL_MONO(xname, nid, 3, dir) +#define CA0132_ALT_CODEC_VOL(xname, nid, dir) \ + CA0132_ALT_CODEC_VOL_MONO(xname, nid, 3, dir) #define CA0132_CODEC_MUTE(xname, nid, dir) \ CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir) +/* lookup tables */ +/* + * Lookup table with decibel values for the DSP. When volume is changed in + * Windows, the DSP is also sent the dB value in floating point. In Windows, + * these values have decimal points, probably because the Windows driver + * actually uses floating point. We can't here, so I made a lookup table of + * values -90 to 9. -90 is the lowest decibel value for both the ADC's and the + * DAC's, and 9 is the maximum. + */ +static const unsigned int float_vol_db_lookup[] = { +0xC2B40000, 0xC2B20000, 0xC2B00000, 0xC2AE0000, 0xC2AC0000, 0xC2AA0000, +0xC2A80000, 0xC2A60000, 0xC2A40000, 0xC2A20000, 0xC2A00000, 0xC29E0000, +0xC29C0000, 0xC29A0000, 0xC2980000, 0xC2960000, 0xC2940000, 0xC2920000, +0xC2900000, 0xC28E0000, 0xC28C0000, 0xC28A0000, 0xC2880000, 0xC2860000, +0xC2840000, 0xC2820000, 0xC2800000, 0xC27C0000, 0xC2780000, 0xC2740000, +0xC2700000, 0xC26C0000, 0xC2680000, 0xC2640000, 0xC2600000, 0xC25C0000, +0xC2580000, 0xC2540000, 0xC2500000, 0xC24C0000, 0xC2480000, 0xC2440000, +0xC2400000, 0xC23C0000, 0xC2380000, 0xC2340000, 0xC2300000, 0xC22C0000, +0xC2280000, 0xC2240000, 0xC2200000, 0xC21C0000, 0xC2180000, 0xC2140000, +0xC2100000, 0xC20C0000, 0xC2080000, 0xC2040000, 0xC2000000, 0xC1F80000, +0xC1F00000, 0xC1E80000, 0xC1E00000, 0xC1D80000, 0xC1D00000, 0xC1C80000, +0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000, +0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000, +0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000, +0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000, +0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000, +0x40C00000, 0x40E00000, 0x41000000, 0x41100000 +}; + /* The following are for tuning of products */ #ifdef ENABLE_TUNING_CONTROLS @@ -4629,6 +4703,41 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, /* * Volume related */ +/* + * Sets the internal DSP decibel level to match the DAC for output, and the + * ADC for input. Currently only the SBZ sets dsp capture volume level, and + * all alternative codecs set DSP playback volume. + */ +static void ca0132_alt_dsp_volume_put(struct hda_codec *codec, hda_nid_t nid) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int dsp_dir; + unsigned int lookup_val; + + if (nid == VNID_SPK) + dsp_dir = DSP_VOL_OUT; + else + dsp_dir = DSP_VOL_IN; + + lookup_val = spec->vnode_lvol[nid - VNODE_START_NID]; + + dspio_set_uint_param(codec, + ca0132_alt_vol_ctls[dsp_dir].mid, + ca0132_alt_vol_ctls[dsp_dir].reqs[0], + float_vol_db_lookup[lookup_val]); + + lookup_val = spec->vnode_rvol[nid - VNODE_START_NID]; + + dspio_set_uint_param(codec, + ca0132_alt_vol_ctls[dsp_dir].mid, + ca0132_alt_vol_ctls[dsp_dir].reqs[1], + float_vol_db_lookup[lookup_val]); + + dspio_set_uint_param(codec, + ca0132_alt_vol_ctls[dsp_dir].mid, + ca0132_alt_vol_ctls[dsp_dir].reqs[2], FLOAT_ZERO); +} + static int ca0132_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -4730,6 +4839,51 @@ static int ca0132_volume_put(struct snd_kcontrol *kcontrol, return changed; } +/* + * This function is the same as the one above, because using an if statement + * inside of the above volume control for the DSP volume would cause too much + * lag. This is a lot more smooth. + */ +static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int ch = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + hda_nid_t vnid = 0; + int changed = 1; + + switch (nid) { + case 0x02: + vnid = VNID_SPK; + break; + case 0x07: + vnid = VNID_MIC; + break; + } + + /* store the left and right volume */ + if (ch & 1) { + spec->vnode_lvol[vnid - VNODE_START_NID] = *valp; + valp++; + } + if (ch & 2) { + spec->vnode_rvol[vnid - VNODE_START_NID] = *valp; + valp++; + } + + snd_hda_power_up(codec); + ca0132_alt_dsp_volume_put(codec, vnid); + mutex_lock(&codec->control_mutex); + changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + mutex_unlock(&codec->control_mutex); + snd_hda_power_down(codec); + + return changed; +} + static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) { @@ -4849,6 +5003,39 @@ static struct snd_kcontrol_new ca0132_mixer[] = { { } /* end */ }; +/* + * SBZ specific control mixer. Removes auto-detect for mic, and adds surround + * controls. Also sets both the Front Playback and Capture Volume controls to + * alt so they set the DSP's decibel level. + */ +static struct snd_kcontrol_new sbz_mixer[] = { + CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT), + CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT), + CA0132_ALT_CODEC_VOL("Capture Volume", 0x07, HDA_INPUT), + CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT), + HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT), + HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT), + CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch", + VNID_HP_ASEL, 1, HDA_OUTPUT), + { } /* end */ +}; + +/* + * Same as the Sound Blaster Z, except doesn't use the alt volume for capture + * because it doesn't set decibel levels for the DSP for capture. + */ +static struct snd_kcontrol_new r3di_mixer[] = { + CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT), + CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT), + CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT), + CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT), + HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT), + HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT), + CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch", + VNID_HP_ASEL, 1, HDA_OUTPUT), + { } /* end */ +}; + static int ca0132_build_controls(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -6562,7 +6749,21 @@ static int patch_ca0132(struct hda_codec *codec) spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; - spec->mixers[0] = ca0132_mixer; + + /* Set which mixers each quirk uses. */ + switch (spec->quirk) { + case QUIRK_SBZ: + spec->mixers[0] = sbz_mixer; + snd_hda_codec_set_name(codec, "Sound Blaster Z"); + break; + case QUIRK_R3DI: + spec->mixers[0] = r3di_mixer; + snd_hda_codec_set_name(codec, "Recon3Di"); + break; + default: + spec->mixers[0] = ca0132_mixer; + break; + } /* Setup whether or not to use alt functions */ switch (spec->quirk) { -- 2.7.4