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.
Anthony Wong asked me to try to SRU this patch in order to be able to certify
a machine for 12.04.
The CS4213 shares some code with the CS4210 chip, but the CS4210 chip - which
would be the possible regression risk here, was AFAIK never used in production.
Therefore I believe this should be safe to SRU.
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index ee2c1ed..297f5e2 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -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 */
@@ -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;
@@ -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;
- /* 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];
@@ -976,7 +980,12 @@ 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) {
if (spec->cur_input != spec->automic_idx) {
spec->last_input = spec->cur_input;
@@ -986,11 +995,6 @@ static void cs_automic(struct hda_codec *codec)
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);
}
}
@@ -1072,15 +1076,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);
@@ -1094,6 +1091,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);
+ }
}
}
spec->board_config =
snd_hda_check_board_config(codec, CS421X_MODELS,
@@ -1956,14 +1964,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;
The CS4213 chip is similar to the CS4210, but it does not have autoswitch) . However, we don't know anything about
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/
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 <email address hidden>
Signed-off-by: David Henningsson <email address hidden>
Signed-off-by: Takashi Iwai <email address hidden>
(cherry picked from commit 5660ffd06935e56 4404412997a7032 79e325fa64) pci/hda/ patch_cirrus. c | 105 +++++++ +++++++ +++++++ +++++++ ------- -------
Signed-off-by: David Henningsson <email address hidden>
---
sound/
1 file changed, 70 insertions(+), 35 deletions(-)
Anthony Wong asked me to try to SRU this patch in order to be able to certify
a machine for 12.04.
The CS4213 shares some code with the CS4210 chip, but the CS4210 chip - which
would be the possible regression risk here, was AFAIK never used in production.
Therefore I believe this should be safe to SRU.
diff --git a/sound/ pci/hda/ patch_cirrus. c b/sound/ pci/hda/ patch_cirrus. c pci/hda/ patch_cirrus. c pci/hda/ patch_cirrus. c SPDIF_PIN_ NID 0x0A /* Port H */
index ee2c1ed..297f5e2 100644
--- a/sound/
+++ b/sound/
@@ -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_
@@ -149,6 +149,10 @@ enum {
#define SPDIF_EVENT 0x04
+/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */ coef_get( struct hda_codec *codec, unsigned int idx)
+#define CS4213_VENDOR_NID 0x09
+
+
static inline int cs_vendor_
{
struct cs_spec *spec = codec->spec;
@@ -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] ;
AC_VERB_ SET_GPIO_ DATA, gpio);
@@ -938,8 +942,8 @@ static void cs_automute(struct hda_codec *codec)
}
- /* specific to CS421x */ jack_detect( codec, nid);
- 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];
@@ -976,7 +980,12 @@ static void cs_automic(struct hda_codec *codec)
present = snd_hda_
/* specific to CS421x, single ADC */ cur_input( codec, spec->automic_idx, 0); cur_input( codec, !spec->automic_idx, 0); >last_input = spec->cur_input; input_select( codec); cur_input( codec, spec->automic_idx, 0); cur_input( codec, !spec->automic_idx, 0);
- if (spec->vendor_nid == CS421X_VENDOR_NID) {
+ if (spec->vendor_nid == CS420X_VENDOR_NID) {
+ if (present)
+ change_
+ else
+ change_
+ } else {
if (present) {
if (spec->cur_input != spec->automic_idx) {
spec-
@@ -986,11 +995,6 @@ static void cs_automic(struct hda_codec *codec)
spec->cur_input = spec->last_input;
}
cs_update_
- } else {
- if (present)
- change_
- else
- change_
}
}
@@ -1072,15 +1076,8 @@ static void init_input(struct hda_codec *codec) hda_jack_ detect_ enable( codec, pin, MIC_EVENT); nid[spec- >cur_input] ; input_select( codec); cur_input( codec, spec->cur_input, 1); automic( codec); coef_set( codec, IDX_ADC_CFG, coef); nid[spec- >cur_input] ; input_select( codec);
if (spec->mic_detect && spec->automic_idx == i)
snd_
}
- /* specific to CS421x */
- if (spec->vendor_nid == CS421X_VENDOR_NID) {
- if (spec->mic_detect)
- cs_automic(codec);
- else {
- spec->cur_adc = spec->adc_
- cs_update_
- }
- } else {
+ /* CS420x has multiple ADC, CS421x has single ADC */
+ if (spec->vendor_nid == CS420X_VENDOR_NID) {
change_
if (spec->mic_detect)
cs_
@@ -1094,6 +1091,13 @@ static void init_input(struct hda_codec *codec)
* selected in IDX_SPDIF_CTL.
*/
cs_vendor_
+ } else {
+ if (spec->mic_detect)
+ cs_automic(codec);
+ else {
+ spec->cur_adc = spec->adc_
+ cs_update_
+ }
}
}
@@ -1567,7 +1571,7 @@ static const struct snd_kcontrol_new cs421x_ speaker_ bost_ctl = { speaker_ boost_db_ scale },
.tlv = { .p = cs421x_
};
-static void cs421x_ pinmux_ init(struct hda_codec *codec) pinmux_ init(struct hda_codec *codec)
+static void cs4210_
{
struct cs_spec *spec = codec->spec;
unsigned int def_conf, coef;
@@ -1622,10 +1626,11 @@ static int cs421x_init(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
- snd_hda_ sequence_ write(codec, cs421x_ coef_init_ verbs); sequence_ write(codec, cs421x_ coef_init_ verbs_A1_ silicon_ fixes); pinmux_ init(codec) ; sequence_ write(codec, cs421x_ coef_init_ verbs); sequence_ write(codec, cs421x_ coef_init_ verbs_A1_ silicon_ fixes); pinmux_ init(codec) ;
- snd_hda_
-
- cs421x_
+ if (spec->vendor_nid == CS4210_VENDOR_NID) {
+ snd_hda_
+ snd_hda_
+ cs4210_
+ }
if (spec->gpio_mask) { hda_codec_ write(codec, 0x01, 0, AC_VERB_ SET_GPIO_ MASK, output( struct hda_codec *codec)
snd_
@@ -1793,7 +1798,7 @@ static int build_cs421x_
if (err < 0)
return err;
- if (cfg->speaker_outs) { ctl_add( codec, 0, ctl_new1( &cs421x_ speaker_ bost_ctl, codec)); parse_auto_ config( struct hda_codec *codec) suspend( struct hda_codec *codec, pm_message_t state)
+ if (cfg->speaker_outs && (spec->vendor_nid == CS4210_VENDOR_NID)) {
err = snd_hda_
snd_
if (err < 0)
@@ -1890,6 +1895,7 @@ static int cs421x_
*/
static int cs421x_
{
+ struct cs_spec *spec = codec->spec;
unsigned int coef;
snd_hda_ shutup_ pins(codec) ; suspend( struct hda_codec *codec, pm_message_t state) codec_write( codec, CS4210_ADC_NID, 0,
AC_VERB_ SET_POWER_ STATE, AC_PWRST_D3);
@@ -1899,15 +1905,17 @@ static int cs421x_
snd_hda_
- coef = cs_vendor_ coef_get( codec, CS421X_ IDX_DEV_ CFG); coef_set( codec, CS421X_IDX_DEV_CFG, coef); coef_get( codec, CS421X_ IDX_DEV_ CFG); coef_set( codec, CS421X_IDX_DEV_CFG, coef);
- coef |= 0x0004; /* PDREF */
- cs_vendor_
+ if (spec->vendor_nid == CS4210_VENDOR_NID) {
+ coef = cs_vendor_
+ coef |= 0x0004; /* PDREF */
+ cs_vendor_
+ }
return 0;
}
#endif
-static struct hda_codec_ops cs4210_patch_ops = { build_controls,
+static struct hda_codec_ops cs421x_patch_ops = {
.build_controls = cs421x_
.build_pcms = cs_build_pcms,
.init = cs421x_init,
@@ -1918,7 +1926,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;
@@ -1928,7 +1936,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 = hda_check_ board_config( codec, CS421X_MODELS, pinmux_ init(codec) ; pinmux_ init(codec) ;
snd_
@@ -1956,14 +1964,39 @@ static int patch_cs421x(struct hda_codec *codec)
is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
is disabled.
*/
- cs421x_
+ cs4210_
err = cs421x_ parse_auto_ config( codec);
if (err < 0)
goto error;
- codec->patch_ops = cs4210_patch_ops; sizeof( *spec), GFP_KERNEL); parse_auto_ config( codec);
+ 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(
+ if (!spec)
+ return -ENOMEM;
+ codec->spec = spec;
+
+ spec->vendor_nid = CS4213_VENDOR_NID;
+
+ err = cs421x_
+ if (err < 0)
+ goto error;
+ codec->patch_ops = cs421x_patch_ops;
return 0;
error: preset_ cirrus[ ] = {
@@ -1979,13 +2012,15 @@ static int patch_cs421x(struct hda_codec *codec)
static const struct hda_codec_preset snd_hda_
{ .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" ); ALIAS(" snd-hda- codec-id: 10134207" ); ALIAS(" snd-hda- codec-id: 10134210" ); ALIAS(" snd-hda- codec-id: 10134213" );
MODULE_
MODULE_
+MODULE_
MODULE_ LICENSE( "GPL"); DESCRIPTION( "Cirrus Logic HD-audio codec");
MODULE_
--
1.7.9.5