regulator: ltc3589: Staticize ltc3589_reg_defaults
[firefly-linux-kernel-4.4.55.git] / sound / pci / hda / patch_conexant.c
index bcf91bea33179ce50b9485fd1db59caf1349b64c..1dc7e974f3b1cd554988eb2d2be26ca889aafab8 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
@@ -35,7 +34,7 @@
 #include "hda_jack.h"
 #include "hda_generic.h"
 
-#define ENABLE_CXT_STATIC_QUIRKS
+#undef ENABLE_CXT_STATIC_QUIRKS
 
 #define CXT_PIN_DIR_IN              0x00
 #define CXT_PIN_DIR_OUT             0x01
@@ -68,6 +67,12 @@ struct conexant_spec {
 
        unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
 
+       /* OPLC XO specific */
+       bool recording;
+       bool dc_enable;
+       unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
+       struct nid_path *dc_mode_path;
+
 #ifdef ENABLE_CXT_STATIC_QUIRKS
        const struct snd_kcontrol_new *mixers[5];
        int num_mixers;
@@ -123,19 +128,6 @@ struct conexant_spec {
        unsigned int hp_laptop:1;
        unsigned int asus:1;
 
-       unsigned int ext_mic_present;
-       unsigned int recording;
-       void (*capture_prepare)(struct hda_codec *codec);
-       void (*capture_cleanup)(struct hda_codec *codec);
-
-       /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
-        * through the microphone jack.
-        * When the user enables this through a mixer switch, both internal and
-        * external microphones are disabled. Gain is fixed at 0dB. In this mode,
-        * we also allow the bias to be configured through a separate mixer
-        * control. */
-       unsigned int dc_enable;
-       unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
        unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
 #endif /* ENABLE_CXT_STATIC_QUIRKS */
 };
@@ -253,8 +245,6 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct snd_pcm_substream *substream)
 {
        struct conexant_spec *spec = codec->spec;
-       if (spec->capture_prepare)
-               spec->capture_prepare(codec);
        snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
                                   stream_tag, 0, format);
        return 0;
@@ -266,8 +256,6 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 {
        struct conexant_spec *spec = codec->spec;
        snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
-       if (spec->capture_cleanup)
-               spec->capture_cleanup(codec);
        return 0;
 }
 
@@ -457,9 +445,7 @@ static int conexant_init(struct hda_codec *codec)
 
 static void conexant_free(struct hda_codec *codec)
 {
-       struct conexant_spec *spec = codec->spec;
-       snd_hda_detach_beep_device(codec);
-       kfree(spec);
+       kfree(codec->spec);
 }
 
 static const struct snd_kcontrol_new cxt_capture_mixers[] = {
@@ -673,14 +659,6 @@ static const struct hda_input_mux cxt5045_capture_source_benq = {
        }
 };
 
-static const struct hda_input_mux cxt5045_capture_source_hp530 = {
-       .num_items = 2,
-       .items = {
-               { "Mic",          0x1 },
-               { "Internal Mic", 0x2 },
-       }
-};
-
 /* turn on/off EAPD (+ mute HP) as a master switch */
 static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
@@ -796,28 +774,6 @@ static const struct snd_kcontrol_new cxt5045_benq_mixers[] = {
        {}
 };
 
-static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
-       HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = cxt_eapd_info,
-               .get = cxt_eapd_get,
-               .put = cxt5045_hp_master_sw_put,
-               .private_value = 0x10,
-       },
-
-       {}
-};
-
 static const struct hda_verb cxt5045_init_verbs[] = {
        /* Line in, Mic */
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
@@ -1000,7 +956,6 @@ enum {
        CXT5045_LAPTOP_MICSENSE,
        CXT5045_LAPTOP_HPMICSENSE,
        CXT5045_BENQ,
-       CXT5045_LAPTOP_HP530,
 #ifdef CONFIG_SND_DEBUG
        CXT5045_TEST,
 #endif
@@ -1013,7 +968,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
        [CXT5045_LAPTOP_MICSENSE]       = "laptop-micsense",
        [CXT5045_LAPTOP_HPMICSENSE]     = "laptop-hpmicsense",
        [CXT5045_BENQ]                  = "benq",
-       [CXT5045_LAPTOP_HP530]          = "laptop-hp530",
 #ifdef CONFIG_SND_DEBUG
        [CXT5045_TEST]          = "test",
 #endif
@@ -1021,8 +975,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
 };
 
 static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
-       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
        SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
@@ -1113,14 +1065,6 @@ static int patch_cxt5045(struct hda_codec *codec)
                spec->num_mixers = 2;
                codec->patch_ops.init = cxt5045_init;
                break;
-       case CXT5045_LAPTOP_HP530:
-               codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
-               spec->input_mux = &cxt5045_capture_source_hp530;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
-               spec->mixers[0] = cxt5045_mixers_hp530;
-               codec->patch_ops.init = cxt5045_init;
-               break;
 #ifdef CONFIG_SND_DEBUG
        case CXT5045_TEST:
                spec->input_mux = &cxt5045_test_capture_source;
@@ -1940,11 +1884,6 @@ static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
 static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
 static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
 
-/* OLPC's microphone port is DC coupled for use with external sensors,
- * therefore we use a 50% mic bias in order to center the input signal with
- * the DC input range of the codec. */
-#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50
-
 static const struct hda_channel_mode cxt5066_modes[1] = {
        { 2, NULL },
 };
@@ -1959,7 +1898,8 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
        struct conexant_spec *spec = codec->spec;
        unsigned int pinctl;
 
-       snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
+       codec_dbg(codec,
+                 "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
                    spec->hp_present, spec->cur_eapd);
 
        /* Port A (HP) */
@@ -1997,88 +1937,6 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-static const struct hda_input_mux cxt5066_olpc_dc_bias = {
-       .num_items = 3,
-       .items = {
-               { "Off", PIN_IN },
-               { "50%", PIN_VREF50 },
-               { "80%", PIN_VREF80 },
-       },
-};
-
-static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       /* Even though port F is the DC input, the bias is controlled on port B.
-        * we also leave that port as an active input (but unselected) in DC mode
-        * just in case that is necessary to make the bias setting take effect. */
-       return snd_hda_set_pin_ctl_cache(codec, 0x1a,
-               cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
-}
-
-/* OLPC defers mic widget control until when capture is started because the
- * microphone LED comes on as soon as these settings are put in place. if we
- * did this before recording, it would give the false indication that recording
- * is happening when it is not. */
-static void cxt5066_olpc_select_mic(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       if (!spec->recording)
-               return;
-
-       if (spec->dc_enable) {
-               /* in DC mode we ignore presence detection and just use the jack
-                * through our special DC port */
-               const struct hda_verb enable_dc_mode[] = {
-                       /* disble internal mic, port C */
-                       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-                       /* enable DC capture, port F */
-                       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-                       {},
-               };
-
-               snd_hda_sequence_write(codec, enable_dc_mode);
-               /* port B input disabled (and bias set) through the following call */
-               cxt5066_set_olpc_dc_bias(codec);
-               return;
-       }
-
-       /* disable DC (port F) */
-       snd_hda_set_pin_ctl(codec, 0x1e, 0);
-
-       /* external mic, port B */
-       snd_hda_set_pin_ctl(codec, 0x1a,
-               spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
-
-       /* internal mic, port C */
-       snd_hda_set_pin_ctl(codec, 0x1b,
-               spec->ext_mic_present ? 0 : PIN_VREF80);
-}
-
-/* toggle input of built-in and mic jack appropriately */
-static void cxt5066_olpc_automic(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       unsigned int present;
-
-       if (spec->dc_enable) /* don't do presence detection in DC mode */
-               return;
-
-       present = snd_hda_codec_read(codec, 0x1a, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       if (present)
-               snd_printdd("CXT5066: external microphone detected\n");
-       else
-               snd_printdd("CXT5066: external microphone absent\n");
-
-       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
-               present ? 0 : 1);
-       spec->ext_mic_present = !!present;
-
-       cxt5066_olpc_select_mic(codec);
-}
-
 /* toggle input of built-in digital mic and mic jack appropriately */
 static void cxt5066_vostro_automic(struct hda_codec *codec)
 {
@@ -2110,10 +1968,10 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
 
        present = snd_hda_jack_detect(codec, 0x1a);
        if (present) {
-               snd_printdd("CXT5066: external microphone detected\n");
+               codec_dbg(codec, "CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
        } else {
-               snd_printdd("CXT5066: external microphone absent\n");
+               codec_dbg(codec, "CXT5066: external microphone absent\n");
                snd_hda_sequence_write(codec, ext_mic_absent);
        }
 }
@@ -2138,10 +1996,10 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
 
        present = snd_hda_jack_detect(codec, 0x1b);
        if (present) {
-               snd_printdd("CXT5066: external microphone detected\n");
+               codec_dbg(codec, "CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
        } else {
-               snd_printdd("CXT5066: external microphone absent\n");
+               codec_dbg(codec, "CXT5066: external microphone absent\n");
                snd_hda_sequence_write(codec, ext_mic_absent);
        }
 }
@@ -2153,7 +2011,7 @@ static void cxt5066_asus_automic(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_jack_detect(codec, 0x1b);
-       snd_printdd("CXT5066: external microphone present=%d\n", present);
+       codec_dbg(codec, "CXT5066: external microphone present=%d\n", present);
        snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
                            present ? 1 : 0);
 }
@@ -2165,7 +2023,7 @@ static void cxt5066_hp_laptop_automic(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_jack_detect(codec, 0x1b);
-       snd_printdd("CXT5066: external microphone present=%d\n", present);
+       codec_dbg(codec, "CXT5066: external microphone present=%d\n", present);
        snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
                            present ? 1 : 3);
 }
@@ -2204,13 +2062,13 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
        ext_present = snd_hda_jack_detect(codec, 0x1b);
        dock_present = snd_hda_jack_detect(codec, 0x1a);
        if (ext_present) {
-               snd_printdd("CXT5066: external microphone detected\n");
+               codec_dbg(codec, "CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
        } else if (dock_present) {
-               snd_printdd("CXT5066: dock microphone detected\n");
+               codec_dbg(codec, "CXT5066: dock microphone detected\n");
                snd_hda_sequence_write(codec, dock_mic_present);
        } else {
-               snd_printdd("CXT5066: external microphone absent\n");
+               codec_dbg(codec, "CXT5066: external microphone absent\n");
                snd_hda_sequence_write(codec, ext_mic_absent);
        }
 }
@@ -2229,7 +2087,7 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
 
        spec->hp_present = portA ? HP_PRESENT_PORT_A : 0;
        spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0;
-       snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
+       codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n",
                portA, portD, spec->hp_present);
        cxt5066_update_speaker(codec);
 }
@@ -2251,27 +2109,10 @@ static void cxt5066_automic(struct hda_codec *codec)
                cxt5066_asus_automic(codec);
 }
 
-/* unsolicited event for jack sensing */
-static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       struct conexant_spec *spec = codec->spec;
-       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
-       switch (res >> 26) {
-       case CONEXANT_HP_EVENT:
-               cxt5066_hp_automute(codec);
-               break;
-       case CONEXANT_MIC_EVENT:
-               /* ignore mic events in DC mode; we're always using the jack */
-               if (!spec->dc_enable)
-                       cxt5066_olpc_automic(codec);
-               break;
-       }
-}
-
 /* unsolicited event for jack sensing */
 static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
+       codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26);
        switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cxt5066_hp_automute(codec);
@@ -2338,124 +2179,10 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
                idx = imux->num_items - 1;
 
        spec->mic_boost = idx;
-       if (!spec->dc_enable)
-               cxt5066_set_mic_boost(codec);
-       return 1;
-}
-
-static void cxt5066_enable_dc(struct hda_codec *codec)
-{
-       const struct hda_verb enable_dc_mode[] = {
-               /* disable gain */
-               {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-               /* switch to DC input */
-               {0x17, AC_VERB_SET_CONNECT_SEL, 3},
-               {}
-       };
-
-       /* configure as input source */
-       snd_hda_sequence_write(codec, enable_dc_mode);
-       cxt5066_olpc_select_mic(codec); /* also sets configured bias */
-}
-
-static void cxt5066_disable_dc(struct hda_codec *codec)
-{
-       /* reconfigure input source */
        cxt5066_set_mic_boost(codec);
-       /* automic also selects the right mic if we're recording */
-       cxt5066_olpc_automic(codec);
-}
-
-static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       ucontrol->value.integer.value[0] = spec->dc_enable;
-       return 0;
-}
-
-static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       int dc_enable = !!ucontrol->value.integer.value[0];
-
-       if (dc_enable == spec->dc_enable)
-               return 0;
-
-       spec->dc_enable = dc_enable;
-       if (dc_enable)
-               cxt5066_enable_dc(codec);
-       else
-               cxt5066_disable_dc(codec);
-
-       return 1;
-}
-
-static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
-                                          struct snd_ctl_elem_info *uinfo)
-{
-       return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo);
-}
-
-static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
-       return 0;
-}
-
-static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
-       unsigned int idx;
-
-       idx = ucontrol->value.enumerated.item[0];
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-
-       spec->dc_input_bias = idx;
-       if (spec->dc_enable)
-               cxt5066_set_olpc_dc_bias(codec);
        return 1;
 }
 
-static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       /* mark as recording and configure the microphone widget so that the
-        * recording LED comes on. */
-       spec->recording = 1;
-       cxt5066_olpc_select_mic(codec);
-}
-
-static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       const struct hda_verb disable_mics[] = {
-               /* disable external mic, port B */
-               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-               /* disble internal mic, port C */
-               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-               /* disable DC capture, port F */
-               {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-               {},
-       };
-
-       snd_hda_sequence_write(codec, disable_mics);
-       spec->recording = 0;
-}
-
 static void conexant_check_dig_outs(struct hda_codec *codec,
                                    const hda_nid_t *dig_pins,
                                    int num_pins)
@@ -2506,43 +2233,6 @@ static const struct snd_kcontrol_new cxt5066_mixer_master[] = {
        {}
 };
 
-static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Volume",
-               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                                 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
-                                 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_volume_info,
-               .get = snd_hda_mixer_amp_volume_get,
-               .put = snd_hda_mixer_amp_volume_put,
-               .tlv = { .c = snd_hda_mixer_amp_tlv },
-               /* offset by 28 volume steps to limit minimum gain to -46dB */
-               .private_value =
-                       HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28),
-       },
-       {}
-};
-
-static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "DC Mode Enable Switch",
-               .info = snd_ctl_boolean_mono_info,
-               .get = cxt5066_olpc_dc_get,
-               .put = cxt5066_olpc_dc_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "DC Input Bias Enum",
-               .info = cxt5066_olpc_dc_bias_enum_info,
-               .get = cxt5066_olpc_dc_bias_enum_get,
-               .put = cxt5066_olpc_dc_bias_enum_put,
-       },
-       {}
-};
-
 static const struct snd_kcontrol_new cxt5066_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2633,67 +2323,6 @@ static const struct hda_verb cxt5066_init_verbs[] = {
        { } /* end */
 };
 
-static const struct hda_verb cxt5066_init_verbs_olpc[] = {
-       /* Port A: headphones */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
-
-       /* Port B: external microphone */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port C: internal microphone */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port D: unused */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port E: unused, but has primary EAPD */
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
-
-       /* Port F: external DC input through microphone port */
-       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port G: internal speakers */
-       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
-
-       /* DAC1 */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* DAC2: unused */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-
-       /* Disable digital microphone port */
-       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Audio input selectors */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-
-       /* Disable SPDIF */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* enable unsolicited events for Port A and B */
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
-       { } /* end */
-};
-
 static const struct hda_verb cxt5066_init_verbs_vostro[] = {
        /* Port A: headphones */
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2879,7 +2508,7 @@ static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
 /* initialize jack-sensing, too */
 static int cxt5066_init(struct hda_codec *codec)
 {
-       snd_printdd("CXT5066: init\n");
+       codec_dbg(codec, "CXT5066: init\n");
        conexant_init(codec);
        if (codec->patch_ops.unsol_event) {
                cxt5066_hp_automute(codec);
@@ -2889,25 +2518,9 @@ static int cxt5066_init(struct hda_codec *codec)
        return 0;
 }
 
-static int cxt5066_olpc_init(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       snd_printdd("CXT5066: init\n");
-       conexant_init(codec);
-       cxt5066_hp_automute(codec);
-       if (!spec->dc_enable) {
-               cxt5066_set_mic_boost(codec);
-               cxt5066_olpc_automic(codec);
-       } else {
-               cxt5066_enable_dc(codec);
-       }
-       return 0;
-}
-
 enum {
        CXT5066_LAPTOP,         /* Laptops w/ EAPD support */
        CXT5066_DELL_LAPTOP,    /* Dell Laptop */
-       CXT5066_OLPC_XO_1_5,    /* OLPC XO 1.5 */
        CXT5066_DELL_VOSTRO,    /* Dell Vostro 1015i */
        CXT5066_IDEAPAD,        /* Lenovo IdeaPad U150 */
        CXT5066_THINKPAD,       /* Lenovo ThinkPad T410s, others? */
@@ -2920,7 +2533,6 @@ enum {
 static const char * const cxt5066_models[CXT5066_MODELS] = {
        [CXT5066_LAPTOP]        = "laptop",
        [CXT5066_DELL_LAPTOP]   = "dell-laptop",
-       [CXT5066_OLPC_XO_1_5]   = "olpc-xo-1_5",
        [CXT5066_DELL_VOSTRO]   = "dell-vostro",
        [CXT5066_IDEAPAD]       = "ideapad",
        [CXT5066_THINKPAD]      = "thinkpad",
@@ -2941,10 +2553,8 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
        SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
        SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
-       SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
                      CXT5066_LAPTOP),
-       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
@@ -3030,32 +2640,11 @@ static int patch_cxt5066(struct hda_codec *codec)
                spec->mic_boost = 3; /* default 30dB gain */
                break;
 
-       case CXT5066_OLPC_XO_1_5:
-               codec->patch_ops.init = cxt5066_olpc_init;
-               codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
-               spec->init_verbs[0] = cxt5066_init_verbs_olpc;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixers;
-               spec->port_d_mode = 0;
-               spec->mic_boost = 3; /* default 30dB gain */
-
-               /* no S/PDIF out */
-               spec->multiout.dig_out_nid = 0;
-
-               /* input source automatically selected */
-               spec->input_mux = NULL;
-
-               /* our capture hooks which allow us to turn on the microphone LED
-                * at the right time */
-               spec->capture_prepare = cxt5066_olpc_capture_prepare;
-               spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
-               break;
        case CXT5066_DELL_VOSTRO:
                codec->patch_ops.init = cxt5066_init;
                codec->patch_ops.unsol_event = cxt5066_unsol_event;
                spec->init_verbs[0] = cxt5066_init_verbs_vostro;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
                spec->mixers[spec->num_mixers++] = cxt5066_mixers;
                spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers;
                spec->port_d_mode = 0;
@@ -3207,11 +2796,7 @@ static int cx_auto_init(struct hda_codec *codec)
        return 0;
 }
 
-static void cx_auto_free(struct hda_codec *codec)
-{
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
-       snd_hda_gen_free(codec);
-}
+#define cx_auto_free   snd_hda_gen_free
 
 static const struct hda_codec_ops cx_auto_patch_ops = {
        .build_controls = cx_auto_build_controls,
@@ -3238,6 +2823,11 @@ enum {
        CXT_FIXUP_HEADPHONE_MIC,
        CXT_FIXUP_GPIO1,
        CXT_FIXUP_THINKPAD_ACPI,
+       CXT_FIXUP_OLPC_XO,
+       CXT_FIXUP_CAP_MIX_AMP,
+       CXT_FIXUP_TOSHIBA_P105,
+       CXT_FIXUP_HP_530,
+       CXT_FIXUP_CAP_MIX_AMP_5047,
 };
 
 /* for hda_fixup_thinkpad_acpi() */
@@ -3316,6 +2906,288 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec,
        }
 }
 
+/* OPLC XO 1.5 fixup */
+
+/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
+ * through the microphone jack.
+ * When the user enables this through a mixer switch, both internal and
+ * external microphones are disabled. Gain is fixed at 0dB. In this mode,
+ * we also allow the bias to be configured through a separate mixer
+ * control. */
+
+#define update_mic_pin(codec, nid, val)                                        \
+       snd_hda_codec_update_cache(codec, nid, 0,                       \
+                                  AC_VERB_SET_PIN_WIDGET_CONTROL, val)
+
+static const struct hda_input_mux olpc_xo_dc_bias = {
+       .num_items = 3,
+       .items = {
+               { "Off", PIN_IN },
+               { "50%", PIN_VREF50 },
+               { "80%", PIN_VREF80 },
+       },
+};
+
+static void olpc_xo_update_mic_boost(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int ch, val;
+
+       for (ch = 0; ch < 2; ch++) {
+               val = AC_AMP_SET_OUTPUT |
+                       (ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT);
+               if (!spec->dc_enable)
+                       val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0);
+               snd_hda_codec_write(codec, 0x17, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, val);
+       }
+}
+
+static void olpc_xo_update_mic_pins(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int cur_input, val;
+       struct nid_path *path;
+
+       cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]];
+
+       /* Set up mic pins for port-B, C and F dynamically as the recording
+        * LED is turned on/off by these pin controls
+        */
+       if (!spec->dc_enable) {
+               /* disable DC bias path and pin for port F */
+               update_mic_pin(codec, 0x1e, 0);
+               snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
+
+               /* update port B (ext mic) and C (int mic) */
+               /* OLPC defers mic widget control until when capture is
+                * started because the microphone LED comes on as soon as
+                * these settings are put in place. if we did this before
+                * recording, it would give the false indication that
+                * recording is happening when it is not.
+                */
+               update_mic_pin(codec, 0x1a, spec->recording ?
+                              snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
+               update_mic_pin(codec, 0x1b, spec->recording ?
+                              snd_hda_codec_get_pin_target(codec, 0x1b) : 0);
+               /* enable normal mic path */
+               path = snd_hda_get_path_from_idx(codec, cur_input);
+               if (path)
+                       snd_hda_activate_path(codec, path, true, false);
+       } else {
+               /* disable normal mic path */
+               path = snd_hda_get_path_from_idx(codec, cur_input);
+               if (path)
+                       snd_hda_activate_path(codec, path, false, false);
+
+               /* Even though port F is the DC input, the bias is controlled
+                * on port B.  We also leave that port as an active input (but
+                * unselected) in DC mode just in case that is necessary to
+                * make the bias setting take effect.
+                */
+               if (spec->recording)
+                       val = olpc_xo_dc_bias.items[spec->dc_input_bias].index;
+               else
+                       val = 0;
+               update_mic_pin(codec, 0x1a, val);
+               update_mic_pin(codec, 0x1b, 0);
+               /* enable DC bias path and pin */
+               update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
+               snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
+       }
+}
+
+/* mic_autoswitch hook */
+static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack)
+{
+       struct conexant_spec *spec = codec->spec;
+       int saved_cached_write = codec->cached_write;
+
+       codec->cached_write = 1;
+       /* in DC mode, we don't handle automic */
+       if (!spec->dc_enable)
+               snd_hda_gen_mic_autoswitch(codec, jack);
+       olpc_xo_update_mic_pins(codec);
+       snd_hda_codec_flush_cache(codec);
+       codec->cached_write = saved_cached_write;
+       if (spec->dc_enable)
+               olpc_xo_update_mic_boost(codec);
+}
+
+/* pcm_capture hook */
+static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo,
+                                struct hda_codec *codec,
+                                struct snd_pcm_substream *substream,
+                                int action)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       /* toggle spec->recording flag and update mic pins accordingly
+        * for turning on/off LED
+        */
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               spec->recording = 1;
+               olpc_xo_update_mic_pins(codec);
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               spec->recording = 0;
+               olpc_xo_update_mic_pins(codec);
+               break;
+       }
+}
+
+static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.integer.value[0] = spec->dc_enable;
+       return 0;
+}
+
+static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       int dc_enable = !!ucontrol->value.integer.value[0];
+
+       if (dc_enable == spec->dc_enable)
+               return 0;
+
+       spec->dc_enable = dc_enable;
+       olpc_xo_update_mic_pins(codec);
+       olpc_xo_update_mic_boost(codec);
+       return 1;
+}
+
+static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
+       return 0;
+}
+
+static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo);
+}
+
+static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       const struct hda_input_mux *imux = &olpc_xo_dc_bias;
+       unsigned int idx;
+
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (spec->dc_input_bias == idx)
+               return 0;
+
+       spec->dc_input_bias = idx;
+       if (spec->dc_enable)
+               olpc_xo_update_mic_pins(codec);
+       return 1;
+}
+
+static const struct snd_kcontrol_new olpc_xo_mixers[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Mode Enable Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = olpc_xo_dc_mode_get,
+               .put = olpc_xo_dc_mode_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Input Bias Enum",
+               .info = olpc_xo_dc_bias_enum_info,
+               .get = olpc_xo_dc_bias_enum_get,
+               .put = olpc_xo_dc_bias_enum_put,
+       },
+       {}
+};
+
+/* overriding mic boost put callback; update mic boost volume only when
+ * DC mode is disabled
+ */
+static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+       if (ret > 0 && spec->dc_enable)
+               olpc_xo_update_mic_boost(codec);
+       return ret;
+}
+
+static void cxt_fixup_olpc_xo(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+       int i;
+
+       if (action != HDA_FIXUP_ACT_PROBE)
+               return;
+
+       spec->gen.mic_autoswitch_hook = olpc_xo_automic;
+       spec->gen.pcm_capture_hook = olpc_xo_capture_hook;
+       spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0);
+
+       snd_hda_add_new_ctls(codec, olpc_xo_mixers);
+
+       /* OLPC's microphone port is DC coupled for use with external sensors,
+        * therefore we use a 50% mic bias in order to center the input signal
+        * with the DC input range of the codec.
+        */
+       snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
+
+       /* override mic boost control */
+       for (i = 0; i < spec->gen.kctls.used; i++) {
+               struct snd_kcontrol_new *kctl =
+                       snd_array_elem(&spec->gen.kctls, i);
+               if (!strcmp(kctl->name, "Mic Boost Volume")) {
+                       kctl->put = olpc_xo_mic_boost_put;
+                       break;
+               }
+       }
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x2b steps with 0dB offset 0x14)
+ */
+static void cxt_fixup_cap_mix_amp(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+                                 (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x1e steps with 0 dB offset 0x17)
+ */
+static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
+                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+}
 
 /* ThinkPad X200 & co with cxt5051 */
 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
@@ -3401,6 +3273,68 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = hda_fixup_thinkpad_acpi,
        },
+       [CXT_FIXUP_OLPC_XO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_olpc_xo,
+       },
+       [CXT_FIXUP_CAP_MIX_AMP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_cap_mix_amp,
+       },
+       [CXT_FIXUP_TOSHIBA_P105] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x10, 0x961701f0 }, /* speaker/hp */
+                       { 0x12, 0x02a1901e }, /* ext mic */
+                       { 0x14, 0x95a70110 }, /* int mic */
+                       {}
+               },
+       },
+       [CXT_FIXUP_HP_530] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x90a60160 }, /* int mic */
+                       {}
+               },
+               .chained = true,
+               .chain_id = CXT_FIXUP_CAP_MIX_AMP,
+       },
+       [CXT_FIXUP_CAP_MIX_AMP_5047] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_cap_mix_amp_5047,
+       },
+};
+
+static const struct snd_pci_quirk cxt5045_fixups[] = {
+       SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
+       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
+       /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
+        * really bad sound over 0dB on NID 0x17.
+        */
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP),
+       {}
+};
+
+static const struct hda_model_fixup cxt5045_fixup_models[] = {
+       { .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" },
+       { .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" },
+       { .id = CXT_FIXUP_HP_530, .name = "hp-530" },
+       {}
+};
+
+static const struct snd_pci_quirk cxt5047_fixups[] = {
+       /* HP laptops have really bad sound over 0 dB on NID 0x10.
+        */
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
+       {}
+};
+
+static const struct hda_model_fixup cxt5047_fixup_models[] = {
+       { .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" },
+       {}
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3408,10 +3342,16 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
        {}
 };
 
+static const struct hda_model_fixup cxt5051_fixup_models[] = {
+       { .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" },
+       {}
+};
+
 static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
+       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
@@ -3428,6 +3368,17 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        {}
 };
 
+static const struct hda_model_fixup cxt5066_fixup_models[] = {
+       { .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" },
+       { .id = CXT_FIXUP_GPIO1, .name = "gpio1" },
+       { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
+       { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
+       { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
+       { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
+       { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
+       {}
+};
+
 /* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
  * can be created (bko#42825)
  */
@@ -3449,8 +3400,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
        struct conexant_spec *spec;
        int err;
 
-       printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-              codec->chip_name);
+       codec_info(codec, "%s: BIOS auto-probing.\n", codec->chip_name);
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
@@ -3467,19 +3417,28 @@ static int patch_conexant_auto(struct hda_codec *codec)
        switch (codec->vendor_id) {
        case 0x14f15045:
                codec->single_adc_amp = 1;
+               spec->gen.mixer_nid = 0x17;
+               spec->gen.add_stereo_mix_input = 1;
+               snd_hda_pick_fixup(codec, cxt5045_fixup_models,
+                                  cxt5045_fixups, cxt_fixups);
                break;
        case 0x14f15047:
                codec->pin_amp_workaround = 1;
                spec->gen.mixer_nid = 0x19;
+               spec->gen.add_stereo_mix_input = 1;
+               snd_hda_pick_fixup(codec, cxt5047_fixup_models,
+                                  cxt5047_fixups, cxt_fixups);
                break;
        case 0x14f15051:
                add_cx5051_fake_mutes(codec);
                codec->pin_amp_workaround = 1;
-               snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups);
+               snd_hda_pick_fixup(codec, cxt5051_fixup_models,
+                                  cxt5051_fixups, cxt_fixups);
                break;
        default:
                codec->pin_amp_workaround = 1;
-               snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups);
+               snd_hda_pick_fixup(codec, cxt5066_fixup_models,
+                                  cxt5066_fixups, cxt_fixups);
                break;
        }
 
@@ -3513,7 +3472,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
         * Better to make reset, then.
         */
        if (!codec->bus->sync_write) {
-               snd_printd("hda_codec: "
+               codec_info(codec,
                           "Enable sync_write for stable communication\n");
                codec->bus->sync_write = 1;
                codec->bus->allow_bus_reset = 1;