|
@@ -25,6 +25,8 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/pci.h>
|
|
|
#include <sound/core.h>
|
|
|
+#include <sound/jack.h>
|
|
|
+
|
|
|
#include "hda_codec.h"
|
|
|
#include "hda_local.h"
|
|
|
|
|
@@ -37,8 +39,21 @@
|
|
|
#define CONEXANT_HP_EVENT 0x37
|
|
|
#define CONEXANT_MIC_EVENT 0x38
|
|
|
|
|
|
+/* Conexant 5051 specific */
|
|
|
+
|
|
|
+#define CXT5051_SPDIF_OUT 0x1C
|
|
|
+#define CXT5051_PORTB_EVENT 0x38
|
|
|
+#define CXT5051_PORTC_EVENT 0x39
|
|
|
|
|
|
|
|
|
+struct conexant_jack {
|
|
|
+
|
|
|
+ hda_nid_t nid;
|
|
|
+ int type;
|
|
|
+ struct snd_jack *jack;
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
struct conexant_spec {
|
|
|
|
|
|
struct snd_kcontrol_new *mixers[5];
|
|
@@ -83,6 +98,9 @@ struct conexant_spec {
|
|
|
|
|
|
unsigned int spdif_route;
|
|
|
|
|
|
+ /* jack detection */
|
|
|
+ struct snd_array jacks;
|
|
|
+
|
|
|
/* dynamic controls, init_verbs and input_mux */
|
|
|
struct auto_pin_cfg autocfg;
|
|
|
struct hda_input_mux private_imux;
|
|
@@ -329,6 +347,86 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
|
|
|
&spec->cur_mux[adc_idx]);
|
|
|
}
|
|
|
|
|
|
+static int conexant_add_jack(struct hda_codec *codec,
|
|
|
+ hda_nid_t nid, int type)
|
|
|
+{
|
|
|
+ struct conexant_spec *spec;
|
|
|
+ struct conexant_jack *jack;
|
|
|
+ const char *name;
|
|
|
+
|
|
|
+ spec = codec->spec;
|
|
|
+ snd_array_init(&spec->jacks, sizeof(*jack), 32);
|
|
|
+ jack = snd_array_new(&spec->jacks);
|
|
|
+ name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
|
|
|
+
|
|
|
+ if (!jack)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ jack->nid = nid;
|
|
|
+ jack->type = type;
|
|
|
+
|
|
|
+ return snd_jack_new(codec->bus->card, name, type, &jack->jack);
|
|
|
+}
|
|
|
+
|
|
|
+static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ struct conexant_spec *spec = codec->spec;
|
|
|
+ struct conexant_jack *jacks = spec->jacks.list;
|
|
|
+
|
|
|
+ if (jacks) {
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < spec->jacks.used; i++) {
|
|
|
+ if (jacks->nid == nid) {
|
|
|
+ unsigned int present;
|
|
|
+ present = snd_hda_codec_read(codec, nid, 0,
|
|
|
+ AC_VERB_GET_PIN_SENSE, 0) &
|
|
|
+ AC_PINSENSE_PRESENCE;
|
|
|
+
|
|
|
+ present = (present) ? jacks->type : 0 ;
|
|
|
+
|
|
|
+ snd_jack_report(jacks->jack,
|
|
|
+ present);
|
|
|
+ }
|
|
|
+ jacks++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int conexant_init_jacks(struct hda_codec *codec)
|
|
|
+{
|
|
|
+#ifdef CONFIG_SND_JACK
|
|
|
+ struct conexant_spec *spec = codec->spec;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < spec->num_init_verbs; i++) {
|
|
|
+ const struct hda_verb *hv;
|
|
|
+
|
|
|
+ hv = spec->init_verbs[i];
|
|
|
+ while (hv->nid) {
|
|
|
+ int err = 0;
|
|
|
+ switch (hv->param ^ AC_USRSP_EN) {
|
|
|
+ case CONEXANT_HP_EVENT:
|
|
|
+ err = conexant_add_jack(codec, hv->nid,
|
|
|
+ SND_JACK_HEADPHONE);
|
|
|
+ conexant_report_jack(codec, hv->nid);
|
|
|
+ break;
|
|
|
+ case CXT5051_PORTC_EVENT:
|
|
|
+ case CONEXANT_MIC_EVENT:
|
|
|
+ err = conexant_add_jack(codec, hv->nid,
|
|
|
+ SND_JACK_MICROPHONE);
|
|
|
+ conexant_report_jack(codec, hv->nid);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ ++hv;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return 0;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
static int conexant_init(struct hda_codec *codec)
|
|
|
{
|
|
|
struct conexant_spec *spec = codec->spec;
|
|
@@ -341,6 +439,16 @@ static int conexant_init(struct hda_codec *codec)
|
|
|
|
|
|
static void conexant_free(struct hda_codec *codec)
|
|
|
{
|
|
|
+#ifdef CONFIG_SND_JACK
|
|
|
+ struct conexant_spec *spec = codec->spec;
|
|
|
+ if (spec->jacks.list) {
|
|
|
+ struct conexant_jack *jacks = spec->jacks.list;
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < spec->jacks.used; i++)
|
|
|
+ snd_device_free(codec->bus->card, &jacks[i].jack);
|
|
|
+ snd_array_free(&spec->jacks);
|
|
|
+ }
|
|
|
+#endif
|
|
|
kfree(codec->spec);
|
|
|
}
|
|
|
|
|
@@ -1526,9 +1634,6 @@ static int patch_cxt5047(struct hda_codec *codec)
|
|
|
/* Conexant 5051 specific */
|
|
|
static hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
|
|
|
static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
|
|
|
-#define CXT5051_SPDIF_OUT 0x1C
|
|
|
-#define CXT5051_PORTB_EVENT 0x38
|
|
|
-#define CXT5051_PORTC_EVENT 0x39
|
|
|
|
|
|
static struct hda_channel_mode cxt5051_modes[1] = {
|
|
|
{ 2, NULL },
|