ALSA: hda/ca0132 - Add quirk output selection structures.
authorConnor McAdams <conmanx360@gmail.com>
Tue, 25 Aug 2020 20:10:27 +0000 (16:10 -0400)
committerTakashi Iwai <tiwai@suse.de>
Wed, 26 Aug 2020 08:25:26 +0000 (10:25 +0200)
Add structures containing the changes that need to happen on output
selection for each quirk. This should streamline the addition of new
quirks.

Signed-off-by: Connor McAdams <conmanx360@gmail.com>
Link: https://lore.kernel.org/r/20200825201040.30339-9-conmanx360@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_ca0132.c

index 39e3338..ab84ea3 100644 (file)
@@ -1256,6 +1256,164 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
        {}
 };
 
+/* Output selection quirk info structures. */
+#define MAX_QUIRK_MMIO_GPIO_SET_VALS 3
+#define MAX_QUIRK_SCP_SET_VALS 2
+struct ca0132_alt_out_set_info {
+       unsigned int dac2port; /* ParamID 0x0d value. */
+
+       bool has_hda_gpio;
+       char hda_gpio_pin;
+       char hda_gpio_set;
+
+       unsigned int mmio_gpio_count;
+       char mmio_gpio_pin[MAX_QUIRK_MMIO_GPIO_SET_VALS];
+       char mmio_gpio_set[MAX_QUIRK_MMIO_GPIO_SET_VALS];
+
+       unsigned int scp_cmds_count;
+       unsigned int scp_cmd_mid[MAX_QUIRK_SCP_SET_VALS];
+       unsigned int scp_cmd_req[MAX_QUIRK_SCP_SET_VALS];
+       unsigned int scp_cmd_val[MAX_QUIRK_SCP_SET_VALS];
+
+       bool has_chipio_write;
+       unsigned int chipio_write_addr;
+       unsigned int chipio_write_data;
+};
+
+struct ca0132_alt_out_set_quirk_data {
+       int quirk_id;
+
+       bool has_headphone_gain;
+       bool is_ae_series;
+
+       struct ca0132_alt_out_set_info out_set_info[NUM_OF_OUTPUTS];
+};
+
+static const struct ca0132_alt_out_set_quirk_data quirk_out_set_data[] = {
+       { .quirk_id = QUIRK_R3DI,
+         .has_headphone_gain = false,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x24,
+                 .has_hda_gpio     = true,
+                 .hda_gpio_pin     = 2,
+                 .hda_gpio_set     = 1,
+                 .mmio_gpio_count  = 0,
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               },
+               /* Headphones. */
+               { .dac2port         = 0x21,
+                 .has_hda_gpio     = true,
+                 .hda_gpio_pin     = 2,
+                 .hda_gpio_set     = 0,
+                 .mmio_gpio_count  = 0,
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_R3D,
+         .has_headphone_gain = false,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x24,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 1,
+                 .mmio_gpio_pin    = { 1 },
+                 .mmio_gpio_set    = { 1 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               },
+               /* Headphones. */
+               { .dac2port         = 0x21,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 1,
+                 .mmio_gpio_pin    = { 1 },
+                 .mmio_gpio_set    = { 0 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_SBZ,
+         .has_headphone_gain = false,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x18,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 7, 4, 1 },
+                 .mmio_gpio_set    = { 0, 1, 1 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false, },
+               /* Headphones. */
+               { .dac2port         = 0x12,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 7, 4, 1 },
+                 .mmio_gpio_set    = { 1, 1, 0 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_ZXR,
+         .has_headphone_gain = true,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x24,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 2, 3, 5 },
+                 .mmio_gpio_set    = { 1, 1, 0 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               },
+               /* Headphones. */
+               { .dac2port         = 0x21,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 2, 3, 5 },
+                 .mmio_gpio_set    = { 0, 1, 1 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_AE5,
+         .has_headphone_gain = true,
+         .is_ae_series       = true,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port          = 0xa4,
+                 .has_hda_gpio      = false,
+                 .mmio_gpio_count   = 0,
+                 .scp_cmds_count    = 2,
+                 .scp_cmd_mid       = { 0x96, 0x96 },
+                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
+                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
+                 .scp_cmd_val       = { FLOAT_ZERO, FLOAT_ZERO },
+                 .has_chipio_write  = true,
+                 .chipio_write_addr = 0x0018b03c,
+                 .chipio_write_data = 0x00000012
+               },
+               /* Headphones. */
+               { .dac2port          = 0xa1,
+                 .has_hda_gpio      = false,
+                 .mmio_gpio_count   = 0,
+                 .scp_cmds_count    = 2,
+                 .scp_cmd_mid       = { 0x96, 0x96 },
+                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
+                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
+                 .scp_cmd_val       = { FLOAT_ONE, FLOAT_ONE },
+                 .has_chipio_write  = true,
+                 .chipio_write_addr = 0x0018b03c,
+                 .chipio_write_data = 0x00000012
+               } },
+       }
+};
+
 /*
  * CA0132 codec access
  */
@@ -3513,26 +3671,6 @@ static void r3di_gpio_mic_set(struct hda_codec *codec,
                            AC_VERB_SET_GPIO_DATA, cur_gpio);
 }
 
-static void r3di_gpio_out_set(struct hda_codec *codec,
-               enum r3di_out_select cur_out)
-{
-       unsigned int cur_gpio;
-
-       /* Get the current GPIO Data setup */
-       cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0);
-
-       switch (cur_out) {
-       case R3DI_HEADPHONE_OUT:
-               cur_gpio &= ~(1 << R3DI_OUT_SELECT_BIT);
-               break;
-       case R3DI_LINE_OUT:
-               cur_gpio |= (1 << R3DI_OUT_SELECT_BIT);
-               break;
-       }
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_GPIO_DATA, cur_gpio);
-}
-
 static void r3di_gpio_dsp_status_set(struct hda_codec *codec,
                enum r3di_dsp_status dsp_status)
 {
@@ -4314,86 +4452,93 @@ static int ca0132_alt_surround_set_bass_redirection(struct hda_codec *codec,
  * These are the commands needed to setup output on each of the different card
  * types.
  */
-static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
+static void ca0132_alt_select_out_get_quirk_data(struct hda_codec *codec,
+               const struct ca0132_alt_out_set_quirk_data **quirk_data)
 {
        struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
+       int quirk = ca0132_quirk(spec);
+       unsigned int i;
 
-       switch (spec->cur_out_type) {
-       case SPEAKER_OUT:
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-                       ca0113_mmio_gpio_set(codec, 7, false);
-                       ca0113_mmio_gpio_set(codec, 4, true);
-                       ca0113_mmio_gpio_set(codec, 1, true);
-                       chipio_set_control_param(codec, 0x0d, 0x18);
-                       break;
-               case QUIRK_ZXR:
-                       ca0113_mmio_gpio_set(codec, 2, true);
-                       ca0113_mmio_gpio_set(codec, 3, true);
-                       ca0113_mmio_gpio_set(codec, 5, false);
-                       zxr_headphone_gain_set(codec, 0);
-                       chipio_set_control_param(codec, 0x0d, 0x24);
-                       break;
-               case QUIRK_R3DI:
-                       chipio_set_control_param(codec, 0x0d, 0x24);
-                       r3di_gpio_out_set(codec, R3DI_LINE_OUT);
-                       break;
-               case QUIRK_R3D:
-                       chipio_set_control_param(codec, 0x0d, 0x24);
-                       ca0113_mmio_gpio_set(codec, 1, true);
-                       break;
-               case QUIRK_AE5:
-                       ae5_mmio_select_out(codec);
-                       ae5_headphone_gain_set(codec, 2);
-                       tmp = FLOAT_ZERO;
-                       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
-                       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
-                       chipio_set_control_param(codec, 0x0d, 0xa4);
-                       chipio_write(codec, 0x18b03c, 0x00000012);
-                       break;
-               default:
-                       break;
+       *quirk_data = NULL;
+       for (i = 0; i < ARRAY_SIZE(quirk_out_set_data); i++) {
+               if (quirk_out_set_data[i].quirk_id == quirk) {
+                       *quirk_data = &quirk_out_set_data[i];
+                       return;
                }
-               break;
-       case HEADPHONE_OUT:
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-                       ca0113_mmio_gpio_set(codec, 7, true);
-                       ca0113_mmio_gpio_set(codec, 4, true);
-                       ca0113_mmio_gpio_set(codec, 1, false);
-                       chipio_set_control_param(codec, 0x0d, 0x12);
-                       break;
-               case QUIRK_ZXR:
-                       ca0113_mmio_gpio_set(codec, 2, false);
-                       ca0113_mmio_gpio_set(codec, 3, false);
-                       ca0113_mmio_gpio_set(codec, 5, true);
-                       zxr_headphone_gain_set(codec, spec->zxr_gain_set);
-                       chipio_set_control_param(codec, 0x0d, 0x21);
-                       break;
-               case QUIRK_R3DI:
-                       chipio_set_control_param(codec, 0x0d, 0x21);
-                       r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
-                       break;
-               case QUIRK_R3D:
-                       chipio_set_control_param(codec, 0x0d, 0x21);
-                       ca0113_mmio_gpio_set(codec, 0x1, false);
-                       break;
-               case QUIRK_AE5:
-                       ae5_mmio_select_out(codec);
-                       ae5_headphone_gain_set(codec,
-                                       spec->ae5_headphone_gain_val);
-                       tmp = FLOAT_ONE;
-                       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
-                       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
-                       chipio_set_control_param(codec, 0x0d, 0xa1);
-                       chipio_write(codec, 0x18b03c, 0x00000012);
-                       break;
-               default:
-                       break;
+       }
+}
+
+static int ca0132_alt_select_out_quirk_set(struct hda_codec *codec)
+{
+       const struct ca0132_alt_out_set_quirk_data *quirk_data;
+       const struct ca0132_alt_out_set_info *out_info;
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int i, gpio_data;
+       int err;
+
+       ca0132_alt_select_out_get_quirk_data(codec, &quirk_data);
+       if (!quirk_data)
+               return 0;
+
+       out_info = &quirk_data->out_set_info[spec->cur_out_type];
+       if (quirk_data->is_ae_series)
+               ae5_mmio_select_out(codec);
+
+       if (out_info->has_hda_gpio) {
+               gpio_data = snd_hda_codec_read(codec, codec->core.afg, 0,
+                               AC_VERB_GET_GPIO_DATA, 0);
+
+               if (out_info->hda_gpio_set)
+                       gpio_data |= (1 << out_info->hda_gpio_pin);
+               else
+                       gpio_data &= ~(1 << out_info->hda_gpio_pin);
+
+               snd_hda_codec_write(codec, codec->core.afg, 0,
+                                   AC_VERB_SET_GPIO_DATA, gpio_data);
+       }
+
+       if (out_info->mmio_gpio_count) {
+               for (i = 0; i < out_info->mmio_gpio_count; i++) {
+                       ca0113_mmio_gpio_set(codec, out_info->mmio_gpio_pin[i],
+                                       out_info->mmio_gpio_set[i]);
                }
-               break;
        }
+
+       if (out_info->scp_cmds_count) {
+               for (i = 0; i < out_info->scp_cmds_count; i++) {
+                       err = dspio_set_uint_param(codec,
+                                       out_info->scp_cmd_mid[i],
+                                       out_info->scp_cmd_req[i],
+                                       out_info->scp_cmd_val[i]);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       chipio_set_control_param(codec, 0x0d, out_info->dac2port);
+
+       if (out_info->has_chipio_write) {
+               chipio_write(codec, out_info->chipio_write_addr,
+                               out_info->chipio_write_data);
+       }
+
+       if (quirk_data->has_headphone_gain) {
+               if (spec->cur_out_type != HEADPHONE_OUT) {
+                       if (quirk_data->is_ae_series)
+                               ae5_headphone_gain_set(codec, 2);
+                       else
+                               zxr_headphone_gain_set(codec, 0);
+               } else {
+                       if (quirk_data->is_ae_series)
+                               ae5_headphone_gain_set(codec,
+                                               spec->ae5_headphone_gain_val);
+                       else
+                               zxr_headphone_gain_set(codec,
+                                               spec->zxr_gain_set);
+               }
+       }
+
+       return 0;
 }
 
 static void ca0132_set_out_node_pincfg(struct hda_codec *codec, hda_nid_t nid,
@@ -4456,7 +4601,8 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
        if (err < 0)
                goto exit;
 
-       ca0132_alt_select_out_quirk_handler(codec);
+       if (ca0132_alt_select_out_quirk_set(codec) < 0)
+               goto exit;
 
        switch (spec->cur_out_type) {
        case SPEAKER_OUT: