aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r--sound/pci/hda/patch_conexant.c114
1 files changed, 111 insertions, 3 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index b20e1cede00b..75de40aaab0a 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -25,6 +25,8 @@
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/pci.h> 26#include <linux/pci.h>
27#include <sound/core.h> 27#include <sound/core.h>
28#include <sound/jack.h>
29
28#include "hda_codec.h" 30#include "hda_codec.h"
29#include "hda_local.h" 31#include "hda_local.h"
30 32
@@ -37,8 +39,21 @@
37#define CONEXANT_HP_EVENT 0x37 39#define CONEXANT_HP_EVENT 0x37
38#define CONEXANT_MIC_EVENT 0x38 40#define CONEXANT_MIC_EVENT 0x38
39 41
42/* Conexant 5051 specific */
43
44#define CXT5051_SPDIF_OUT 0x1C
45#define CXT5051_PORTB_EVENT 0x38
46#define CXT5051_PORTC_EVENT 0x39
40 47
41 48
49struct conexant_jack {
50
51 hda_nid_t nid;
52 int type;
53 struct snd_jack *jack;
54
55};
56
42struct conexant_spec { 57struct conexant_spec {
43 58
44 struct snd_kcontrol_new *mixers[5]; 59 struct snd_kcontrol_new *mixers[5];
@@ -83,6 +98,9 @@ struct conexant_spec {
83 98
84 unsigned int spdif_route; 99 unsigned int spdif_route;
85 100
101 /* jack detection */
102 struct snd_array jacks;
103
86 /* dynamic controls, init_verbs and input_mux */ 104 /* dynamic controls, init_verbs and input_mux */
87 struct auto_pin_cfg autocfg; 105 struct auto_pin_cfg autocfg;
88 struct hda_input_mux private_imux; 106 struct hda_input_mux private_imux;
@@ -329,6 +347,86 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
329 &spec->cur_mux[adc_idx]); 347 &spec->cur_mux[adc_idx]);
330} 348}
331 349
350static int conexant_add_jack(struct hda_codec *codec,
351 hda_nid_t nid, int type)
352{
353 struct conexant_spec *spec;
354 struct conexant_jack *jack;
355 const char *name;
356
357 spec = codec->spec;
358 snd_array_init(&spec->jacks, sizeof(*jack), 32);
359 jack = snd_array_new(&spec->jacks);
360 name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
361
362 if (!jack)
363 return -ENOMEM;
364
365 jack->nid = nid;
366 jack->type = type;
367
368 return snd_jack_new(codec->bus->card, name, type, &jack->jack);
369}
370
371static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
372{
373 struct conexant_spec *spec = codec->spec;
374 struct conexant_jack *jacks = spec->jacks.list;
375
376 if (jacks) {
377 int i;
378 for (i = 0; i < spec->jacks.used; i++) {
379 if (jacks->nid == nid) {
380 unsigned int present;
381 present = snd_hda_codec_read(codec, nid, 0,
382 AC_VERB_GET_PIN_SENSE, 0) &
383 AC_PINSENSE_PRESENCE;
384
385 present = (present) ? jacks->type : 0 ;
386
387 snd_jack_report(jacks->jack,
388 present);
389 }
390 jacks++;
391 }
392 }
393}
394
395static int conexant_init_jacks(struct hda_codec *codec)
396{
397#ifdef CONFIG_SND_JACK
398 struct conexant_spec *spec = codec->spec;
399 int i;
400
401 for (i = 0; i < spec->num_init_verbs; i++) {
402 const struct hda_verb *hv;
403
404 hv = spec->init_verbs[i];
405 while (hv->nid) {
406 int err = 0;
407 switch (hv->param ^ AC_USRSP_EN) {
408 case CONEXANT_HP_EVENT:
409 err = conexant_add_jack(codec, hv->nid,
410 SND_JACK_HEADPHONE);
411 conexant_report_jack(codec, hv->nid);
412 break;
413 case CXT5051_PORTC_EVENT:
414 case CONEXANT_MIC_EVENT:
415 err = conexant_add_jack(codec, hv->nid,
416 SND_JACK_MICROPHONE);
417 conexant_report_jack(codec, hv->nid);
418 break;
419 }
420 if (err < 0)
421 return err;
422 ++hv;
423 }
424 }
425#endif
426 return 0;
427
428}
429
332static int conexant_init(struct hda_codec *codec) 430static int conexant_init(struct hda_codec *codec)
333{ 431{
334 struct conexant_spec *spec = codec->spec; 432 struct conexant_spec *spec = codec->spec;
@@ -341,6 +439,16 @@ static int conexant_init(struct hda_codec *codec)
341 439
342static void conexant_free(struct hda_codec *codec) 440static void conexant_free(struct hda_codec *codec)
343{ 441{
442#ifdef CONFIG_SND_JACK
443 struct conexant_spec *spec = codec->spec;
444 if (spec->jacks.list) {
445 struct conexant_jack *jacks = spec->jacks.list;
446 int i;
447 for (i = 0; i < spec->jacks.used; i++)
448 snd_device_free(codec->bus->card, &jacks[i].jack);
449 snd_array_free(&spec->jacks);
450 }
451#endif
344 kfree(codec->spec); 452 kfree(codec->spec);
345} 453}
346 454
@@ -1526,9 +1634,6 @@ static int patch_cxt5047(struct hda_codec *codec)
1526/* Conexant 5051 specific */ 1634/* Conexant 5051 specific */
1527static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; 1635static hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
1528static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; 1636static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
1529#define CXT5051_SPDIF_OUT 0x1C
1530#define CXT5051_PORTB_EVENT 0x38
1531#define CXT5051_PORTC_EVENT 0x39
1532 1637
1533static struct hda_channel_mode cxt5051_modes[1] = { 1638static struct hda_channel_mode cxt5051_modes[1] = {
1534 { 2, NULL }, 1639 { 2, NULL },
@@ -1608,6 +1713,7 @@ static void cxt5051_hp_automute(struct hda_codec *codec)
1608static void cxt5051_hp_unsol_event(struct hda_codec *codec, 1713static void cxt5051_hp_unsol_event(struct hda_codec *codec,
1609 unsigned int res) 1714 unsigned int res)
1610{ 1715{
1716 int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
1611 switch (res >> 26) { 1717 switch (res >> 26) {
1612 case CONEXANT_HP_EVENT: 1718 case CONEXANT_HP_EVENT:
1613 cxt5051_hp_automute(codec); 1719 cxt5051_hp_automute(codec);
@@ -1619,6 +1725,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
1619 cxt5051_portc_automic(codec); 1725 cxt5051_portc_automic(codec);
1620 break; 1726 break;
1621 } 1727 }
1728 conexant_report_jack(codec, nid);
1622} 1729}
1623 1730
1624static struct snd_kcontrol_new cxt5051_mixers[] = { 1731static struct snd_kcontrol_new cxt5051_mixers[] = {
@@ -1693,6 +1800,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
1693static int cxt5051_init(struct hda_codec *codec) 1800static int cxt5051_init(struct hda_codec *codec)
1694{ 1801{
1695 conexant_init(codec); 1802 conexant_init(codec);
1803 conexant_init_jacks(codec);
1696 if (codec->patch_ops.unsol_event) { 1804 if (codec->patch_ops.unsol_event) {
1697 cxt5051_hp_automute(codec); 1805 cxt5051_hp_automute(codec);
1698 cxt5051_portb_automic(codec); 1806 cxt5051_portb_automic(codec);