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

Signed-off-by: Connor McAdams <conmanx...@gmail.com>
---
 sound/pci/hda/patch_ca0132.c | 119 +++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 7491e2044638..2e664aeee1c4 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -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);
 }
 
-- 
2.20.1

Reply via email to