Skip to content

Commit

Permalink
ALSA: HDA: Add support for Cirrus Logic 4213
Browse files Browse the repository at this point in the history
The CS4213 chip is similar to the CS4210, but it does not have
SPDIF capabilities. Also, it has fewer pins, and the vendor specific
nid is different. With this patch, we have working inputs and outputs
(and automute/autoswitch). However, we don't know anything about
the vendor specific processing coefficients, so we don't read or write
to that node in this patch.

BugLink: https://bugs.launchpad.net/bugs/910792
Tested-by: Hsin-Yi Chen <hychen@canonical.com>
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
David Henningsson authored and Takashi Iwai committed Jan 8, 2012
1 parent 78e2a92 commit 5660ffd
Showing 1 changed file with 70 additions and 35 deletions.
105 changes: 70 additions & 35 deletions sound/pci/hda/patch_cirrus.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ enum {
*/
#define CS4210_DAC_NID 0x02
#define CS4210_ADC_NID 0x03
#define CS421X_VENDOR_NID 0x0B
#define CS4210_VENDOR_NID 0x0B
#define CS421X_DMIC_PIN_NID 0x09 /* Port E */
#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */

Expand All @@ -149,6 +149,10 @@ enum {

#define SPDIF_EVENT 0x04

/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
#define CS4213_VENDOR_NID 0x09


static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
{
struct cs_spec *spec = codec->spec;
Expand Down Expand Up @@ -923,8 +927,8 @@ static void cs_automute(struct hda_codec *codec)
/* mute speakers if spdif or hp jack is plugged in */
for (i = 0; i < cfg->speaker_outs; i++) {
int pin_ctl = hp_present ? 0 : PIN_OUT;
/* detect on spdif is specific to CS421x */
if (spdif_present && (spec->vendor_nid == CS421X_VENDOR_NID))
/* detect on spdif is specific to CS4210 */
if (spdif_present && (spec->vendor_nid == CS4210_VENDOR_NID))
pin_ctl = 0;

nid = cfg->speaker_pins[i];
Expand All @@ -938,8 +942,8 @@ static void cs_automute(struct hda_codec *codec)
AC_VERB_SET_GPIO_DATA, gpio);
}

/* specific to CS421x */
if (spec->vendor_nid == CS421X_VENDOR_NID) {
/* specific to CS4210 */
if (spec->vendor_nid == CS4210_VENDOR_NID) {
/* mute HPs if spdif jack (SENSE_B) is present */
for (i = 0; i < cfg->hp_outs; i++) {
nid = cfg->hp_pins[i];
Expand Down Expand Up @@ -976,19 +980,19 @@ static void cs_automic(struct hda_codec *codec)
present = snd_hda_jack_detect(codec, nid);

/* specific to CS421x, single ADC */
if (spec->vendor_nid == CS421X_VENDOR_NID) {
if (spec->vendor_nid == CS420X_VENDOR_NID) {
if (present)
change_cur_input(codec, spec->automic_idx, 0);
else
change_cur_input(codec, !spec->automic_idx, 0);
} else {
if (present) {
spec->last_input = spec->cur_input;
spec->cur_input = spec->automic_idx;
} else {
spec->cur_input = spec->last_input;
}
cs_update_input_select(codec);
} else {
if (present)
change_cur_input(codec, spec->automic_idx, 0);
else
change_cur_input(codec, !spec->automic_idx, 0);
}
}

Expand Down Expand Up @@ -1070,15 +1074,8 @@ static void init_input(struct hda_codec *codec)
if (spec->mic_detect && spec->automic_idx == i)
snd_hda_jack_detect_enable(codec, pin, MIC_EVENT);
}
/* specific to CS421x */
if (spec->vendor_nid == CS421X_VENDOR_NID) {
if (spec->mic_detect)
cs_automic(codec);
else {
spec->cur_adc = spec->adc_nid[spec->cur_input];
cs_update_input_select(codec);
}
} else {
/* CS420x has multiple ADC, CS421x has single ADC */
if (spec->vendor_nid == CS420X_VENDOR_NID) {
change_cur_input(codec, spec->cur_input, 1);
if (spec->mic_detect)
cs_automic(codec);
Expand All @@ -1092,6 +1089,13 @@ static void init_input(struct hda_codec *codec)
* selected in IDX_SPDIF_CTL.
*/
cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
} else {
if (spec->mic_detect)
cs_automic(codec);
else {
spec->cur_adc = spec->adc_nid[spec->cur_input];
cs_update_input_select(codec);
}
}
}

Expand Down Expand Up @@ -1565,7 +1569,7 @@ static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = {
.tlv = { .p = cs421x_speaker_boost_db_scale },
};

static void cs421x_pinmux_init(struct hda_codec *codec)
static void cs4210_pinmux_init(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
unsigned int def_conf, coef;
Expand Down Expand Up @@ -1620,10 +1624,11 @@ static int cs421x_init(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;

snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);

cs421x_pinmux_init(codec);
if (spec->vendor_nid == CS4210_VENDOR_NID) {
snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
cs4210_pinmux_init(codec);
}

if (spec->gpio_mask) {
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
Expand Down Expand Up @@ -1791,7 +1796,7 @@ static int build_cs421x_output(struct hda_codec *codec)
if (err < 0)
return err;

if (cfg->speaker_outs) {
if (cfg->speaker_outs && (spec->vendor_nid == CS4210_VENDOR_NID)) {
err = snd_hda_ctl_add(codec, 0,
snd_ctl_new1(&cs421x_speaker_bost_ctl, codec));
if (err < 0)
Expand Down Expand Up @@ -1888,6 +1893,7 @@ static int cs421x_parse_auto_config(struct hda_codec *codec)
*/
static int cs421x_suspend(struct hda_codec *codec, pm_message_t state)
{
struct cs_spec *spec = codec->spec;
unsigned int coef;

snd_hda_shutup_pins(codec);
Expand All @@ -1897,15 +1903,17 @@ static int cs421x_suspend(struct hda_codec *codec, pm_message_t state)
snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);

coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
coef |= 0x0004; /* PDREF */
cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
if (spec->vendor_nid == CS4210_VENDOR_NID) {
coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
coef |= 0x0004; /* PDREF */
cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
}

return 0;
}
#endif

static struct hda_codec_ops cs4210_patch_ops = {
static struct hda_codec_ops cs421x_patch_ops = {
.build_controls = cs421x_build_controls,
.build_pcms = cs_build_pcms,
.init = cs421x_init,
Expand All @@ -1916,7 +1924,7 @@ static struct hda_codec_ops cs4210_patch_ops = {
#endif
};

static int patch_cs421x(struct hda_codec *codec)
static int patch_cs4210(struct hda_codec *codec)
{
struct cs_spec *spec;
int err;
Expand All @@ -1926,7 +1934,7 @@ static int patch_cs421x(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;

spec->vendor_nid = CS421X_VENDOR_NID;
spec->vendor_nid = CS4210_VENDOR_NID;

spec->board_config =
snd_hda_check_board_config(codec, CS421X_MODELS,
Expand Down Expand Up @@ -1954,14 +1962,39 @@ static int patch_cs421x(struct hda_codec *codec)
is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
is disabled.
*/
cs421x_pinmux_init(codec);
cs4210_pinmux_init(codec);

err = cs421x_parse_auto_config(codec);
if (err < 0)
goto error;

codec->patch_ops = cs4210_patch_ops;
codec->patch_ops = cs421x_patch_ops;

return 0;

error:
kfree(codec->spec);
codec->spec = NULL;
return err;
}

static int patch_cs4213(struct hda_codec *codec)
{
struct cs_spec *spec;
int err;

spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
codec->spec = spec;

spec->vendor_nid = CS4213_VENDOR_NID;

err = cs421x_parse_auto_config(codec);
if (err < 0)
goto error;

codec->patch_ops = cs421x_patch_ops;
return 0;

error:
Expand All @@ -1977,13 +2010,15 @@ static int patch_cs421x(struct hda_codec *codec)
static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
{ .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
{ .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x },
{ .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 },
{ .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 },
{} /* terminator */
};

MODULE_ALIAS("snd-hda-codec-id:10134206");
MODULE_ALIAS("snd-hda-codec-id:10134207");
MODULE_ALIAS("snd-hda-codec-id:10134210");
MODULE_ALIAS("snd-hda-codec-id:10134213");

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
Expand Down

0 comments on commit 5660ffd

Please sign in to comment.