Commit 896e361e authored by Connor McAdams's avatar Connor McAdams Committed by Takashi Iwai
Browse files

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: default avatarConnor McAdams <conmanx360@gmail.com>
Link: https://lore.kernel.org/r/20200825201040.30339-3-conmanx360@gmail.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent bf2aa9cc
Loading
Loading
Loading
Loading
+119 −0
Original line number Diff line number Diff line
@@ -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);
}