ALSA: hda/ca0132 - Add speaker tuning initialization commands.

Add speaker tuning initialization DSP commands, and also define
previously unknown DSP command values.

Signed-off-by: Connor McAdams <conmanx360@gmail.com>
Link: https://lore.kernel.org/r/20200825201040.30339-3-conmanx360@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Connor McAdams 2020-08-25 16:10:21 -04:00 committed by Takashi Iwai
parent bf2aa9ccc8
commit 896e361e82

View File

@ -589,6 +589,60 @@ static const struct ct_eq_preset ca0132_alt_eq_presets[] = {
}
};
/*
* Definitions for the DSP req's to handle speaker tuning. These all belong to
* module ID 0x96, the output effects module.
*/
enum speaker_tuning_reqs {
/*
* Currently, this value is always set to 0.0f. However, on Windows,
* when selecting certain headphone profiles on the new Sound Blaster
* connect software, the QUERY_SPEAKER_EQ_ADDRESS req on mid 0x80 is
* sent. This gets the speaker EQ address area, which is then used to
* send over (presumably) an equalizer profile for the specific
* headphone setup. It is sent using the same method the DSP
* firmware is uploaded with, which I believe is why the 'ctspeq.bin'
* file exists in linux firmware tree but goes unused. It would also
* explain why the QUERY_SPEAKER_EQ_ADDRESS req is defined but unused.
* Once this profile is sent over, SPEAKER_TUNING_USE_SPEAKER_EQ is
* set to 1.0f.
*/
SPEAKER_TUNING_USE_SPEAKER_EQ = 0x1f,
SPEAKER_TUNING_ENABLE_CENTER_EQ = 0x20,
SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL = 0x21,
SPEAKER_TUNING_FRONT_RIGHT_VOL_LEVEL = 0x22,
SPEAKER_TUNING_CENTER_VOL_LEVEL = 0x23,
SPEAKER_TUNING_LFE_VOL_LEVEL = 0x24,
SPEAKER_TUNING_REAR_LEFT_VOL_LEVEL = 0x25,
SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL = 0x26,
SPEAKER_TUNING_SURROUND_LEFT_VOL_LEVEL = 0x27,
SPEAKER_TUNING_SURROUND_RIGHT_VOL_LEVEL = 0x28,
/*
* Inversion is used when setting headphone virtualization to line
* out. Not sure why this is, but it's the only place it's ever used.
*/
SPEAKER_TUNING_FRONT_LEFT_INVERT = 0x29,
SPEAKER_TUNING_FRONT_RIGHT_INVERT = 0x2a,
SPEAKER_TUNING_CENTER_INVERT = 0x2b,
SPEAKER_TUNING_LFE_INVERT = 0x2c,
SPEAKER_TUNING_REAR_LEFT_INVERT = 0x2d,
SPEAKER_TUNING_REAR_RIGHT_INVERT = 0x2e,
SPEAKER_TUNING_SURROUND_LEFT_INVERT = 0x2f,
SPEAKER_TUNING_SURROUND_RIGHT_INVERT = 0x30,
/* Delay is used when setting surround speaker distance in Windows. */
SPEAKER_TUNING_FRONT_LEFT_DELAY = 0x31,
SPEAKER_TUNING_FRONT_RIGHT_DELAY = 0x32,
SPEAKER_TUNING_CENTER_DELAY = 0x33,
SPEAKER_TUNING_LFE_DELAY = 0x34,
SPEAKER_TUNING_REAR_LEFT_DELAY = 0x35,
SPEAKER_TUNING_REAR_RIGHT_DELAY = 0x36,
SPEAKER_TUNING_SURROUND_LEFT_DELAY = 0x37,
SPEAKER_TUNING_SURROUND_RIGHT_DELAY = 0x38,
/* Of these two, only mute seems to ever be used. */
SPEAKER_TUNING_MAIN_VOLUME = 0x39,
SPEAKER_TUNING_MUTE = 0x3a,
};
/* DSP command sequences for ca0132_alt_select_out */
#define ALT_OUT_SET_MAX_COMMANDS 9 /* Max number of commands in sequence */
struct ca0132_alt_out_set {
@ -6874,6 +6928,67 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
}
}
/*
* Default speaker tuning values setup for alternative codecs.
*/
static const unsigned int sbz_default_delay_values[] = {
/* Non-zero values are floating point 0.000198. */
0x394f9e38, 0x394f9e38, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
static const unsigned int zxr_default_delay_values[] = {
/* Non-zero values are floating point 0.000220. */
0x00000000, 0x00000000, 0x3966afcd, 0x3966afcd, 0x3966afcd, 0x3966afcd
};
static const unsigned int ae5_default_delay_values[] = {
/* Non-zero values are floating point 0.000100. */
0x00000000, 0x00000000, 0x38d1b717, 0x38d1b717, 0x38d1b717, 0x38d1b717
};
/*
* If we never change these, probably only need them on initialization.
*/
static void ca0132_alt_init_speaker_tuning(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
unsigned int i, tmp, start_req, end_req;
const unsigned int *values;
switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
values = sbz_default_delay_values;
break;
case QUIRK_ZXR:
values = zxr_default_delay_values;
break;
case QUIRK_AE5:
values = ae5_default_delay_values;
break;
default:
values = sbz_default_delay_values;
break;
}
tmp = FLOAT_ZERO;
dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_ENABLE_CENTER_EQ, tmp);
start_req = SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL;
end_req = SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL;
for (i = start_req; i < end_req + 1; i++)
dspio_set_uint_param(codec, 0x96, i, tmp);
start_req = SPEAKER_TUNING_FRONT_LEFT_INVERT;
end_req = SPEAKER_TUNING_REAR_RIGHT_INVERT;
for (i = start_req; i < end_req + 1; i++)
dspio_set_uint_param(codec, 0x96, i, tmp);
for (i = 0; i < 6; i++)
dspio_set_uint_param(codec, 0x96,
SPEAKER_TUNING_FRONT_LEFT_DELAY + i, values[i]);
}
/*
* Creates a dummy stream to bind the output to. This seems to have to be done
* after changing the main outputs source and destination streams.
@ -7373,6 +7488,8 @@ static void sbz_setup_defaults(struct hda_codec *codec)
}
}
ca0132_alt_init_speaker_tuning(codec);
ca0132_alt_create_dummy_stream(codec);
}
@ -7440,6 +7557,8 @@ static void ae5_setup_defaults(struct hda_codec *codec)
}
}
ca0132_alt_init_speaker_tuning(codec);
ca0132_alt_create_dummy_stream(codec);
}