mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-08-26 01:02:46 +00:00
ALSA: hda/ca0132 - Add quirk output selection structures.
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>
This commit is contained in:
parent
8e00dc7ced
commit
def3f0a5c7
@ -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,88 +4452,95 @@ 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;
|
||||
}
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
bool out_enable, bool hp_enable)
|
||||
{
|
||||
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user