ALSA: hda - Fix pin configuration of HP Pavilion dv7
[pandora-kernel.git] / sound / pci / hda / hda_codec.c
index d010de1..8353c77 100644 (file)
@@ -738,7 +738,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device)
  *
  * Returns 0 if successful, or a negative error code.
  */
-int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
+int snd_hda_bus_new(struct snd_card *card,
                              const struct hda_bus_template *temp,
                              struct hda_bus **busp)
 {
@@ -908,7 +908,7 @@ static int get_codec_name(struct hda_codec *codec)
 /*
  * look for an AFG and MFG nodes
  */
-static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
+static void setup_fg_nodes(struct hda_codec *codec)
 {
        int i, total_nodes, function_id;
        hda_nid_t nid;
@@ -993,19 +993,6 @@ static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec,
        return NULL;
 }
 
-/* write a config value for the given NID */
-static void set_pincfg(struct hda_codec *codec, hda_nid_t nid,
-                      unsigned int cfg)
-{
-       int i;
-       for (i = 0; i < 4; i++) {
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
-                                   cfg & 0xff);
-               cfg >>= 8;
-       }
-}
-
 /* set the current pin config value for the given NID.
  * the value is cached, and read via snd_hda_codec_get_pincfg()
  */
@@ -1013,12 +1000,10 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
                       hda_nid_t nid, unsigned int cfg)
 {
        struct hda_pincfg *pin;
-       unsigned int oldcfg;
 
        if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
                return -EINVAL;
 
-       oldcfg = snd_hda_codec_get_pincfg(codec, nid);
        pin = look_up_pincfg(codec, list, nid);
        if (!pin) {
                pin = snd_array_new(list);
@@ -1027,13 +1012,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
                pin->nid = nid;
        }
        pin->cfg = cfg;
-
-       /* change only when needed; e.g. if the pincfg is already present
-        * in user_pins[], don't write it
-        */
-       cfg = snd_hda_codec_get_pincfg(codec, nid);
-       if (oldcfg != cfg)
-               set_pincfg(codec, nid, cfg);
        return 0;
 }
 
@@ -1082,17 +1060,6 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg);
 
-/* restore all current pin configs */
-static void restore_pincfgs(struct hda_codec *codec)
-{
-       int i;
-       for (i = 0; i < codec->init_pins.used; i++) {
-               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
-               set_pincfg(codec, pin->nid,
-                          snd_hda_codec_get_pincfg(codec, pin->nid));
-       }
-}
-
 /**
  * snd_hda_shutup_pins - Shut up all pins
  * @codec: the HDA codec
@@ -1137,21 +1104,30 @@ static void restore_shutup_pins(struct hda_codec *codec)
 }
 #endif
 
+static void hda_jackpoll_work(struct work_struct *work)
+{
+       struct hda_codec *codec =
+               container_of(work, struct hda_codec, jackpoll_work.work);
+       if (!codec->jackpoll_interval)
+               return;
+
+       snd_hda_jack_set_dirty_all(codec);
+       snd_hda_jack_poll_all(codec);
+       queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
+                          codec->jackpoll_interval);
+}
+
 static void init_hda_cache(struct hda_cache_rec *cache,
                           unsigned int record_size);
 static void free_hda_cache(struct hda_cache_rec *cache);
 
-/* restore the initial pin cfgs and release all pincfg lists */
-static void restore_init_pincfgs(struct hda_codec *codec)
+/* release all pincfg lists */
+static void free_init_pincfgs(struct hda_codec *codec)
 {
-       /* first free driver_pins and user_pins, then call restore_pincfg
-        * so that only the values in init_pins are restored
-        */
        snd_array_free(&codec->driver_pins);
 #ifdef CONFIG_SND_HDA_HWDEP
        snd_array_free(&codec->user_pins);
 #endif
-       restore_pincfgs(codec);
        snd_array_free(&codec->init_pins);
 }
 
@@ -1192,8 +1168,9 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 {
        if (!codec)
                return;
+       cancel_delayed_work_sync(&codec->jackpoll_work);
        snd_hda_jack_tbl_clear(codec);
-       restore_init_pincfgs(codec);
+       free_init_pincfgs(codec);
 #ifdef CONFIG_PM
        cancel_delayed_work(&codec->power_work);
        flush_workqueue(codec->bus->workq);
@@ -1235,7 +1212,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
  *
  * Returns 0 if successful, or a negative error code.
  */
-int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
+int snd_hda_codec_new(struct hda_bus *bus,
                                unsigned int codec_addr,
                                struct hda_codec **codecp)
 {
@@ -1275,6 +1252,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
        snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
        snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
        snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
+       snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
+       INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
 
 #ifdef CONFIG_PM
        spin_lock_init(&codec->power_lock);
@@ -1588,7 +1567,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec)
 #define INFO_AMP_VOL(ch)       (1 << (1 + (ch)))
 
 /* initialize the hash table */
-static void /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache,
+static void init_hda_cache(struct hda_cache_rec *cache,
                                     unsigned int record_size)
 {
        memset(cache, 0, sizeof(*cache));
@@ -2153,12 +2132,12 @@ EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv);
 
 /* find a mixer control element with the given name */
 static struct snd_kcontrol *
-_snd_hda_find_mixer_ctl(struct hda_codec *codec,
-                       const char *name, int idx)
+find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx)
 {
        struct snd_ctl_elem_id id;
        memset(&id, 0, sizeof(id));
        id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       id.device = dev;
        id.index = idx;
        if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
                return NULL;
@@ -2176,15 +2155,16 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec,
 struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
                                            const char *name)
 {
-       return _snd_hda_find_mixer_ctl(codec, name, 0);
+       return find_mixer_ctl(codec, name, 0, 0);
 }
 EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
 
-static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name)
+static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name,
+                                   int dev)
 {
        int idx;
        for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */
-               if (!_snd_hda_find_mixer_ctl(codec, name, idx))
+               if (!find_mixer_ctl(codec, name, dev, idx))
                        return idx;
        }
        return -EBUSY;
@@ -2351,7 +2331,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
                return -EBUSY;
 
        /* OK, let it free */
-
+       cancel_delayed_work_sync(&codec->jackpoll_work);
 #ifdef CONFIG_PM
        cancel_delayed_work_sync(&codec->power_work);
        codec->power_on = 0;
@@ -2380,7 +2360,6 @@ int snd_hda_codec_reset(struct hda_codec *codec)
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
        /* free only driver_pins so that init_pins + user_pins are restored */
        snd_array_free(&codec->driver_pins);
-       restore_pincfgs(codec);
        snd_array_free(&codec->cvt_setups);
        snd_array_free(&codec->spdif_out);
        codec->num_pcms = 0;
@@ -3135,26 +3114,48 @@ static struct snd_kcontrol_new dig_mixes[] = {
 };
 
 /**
- * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls
+ * snd_hda_create_dig_out_ctls - create Output SPDIF-related controls
  * @codec: the HDA codec
- * @nid: audio out widget NID
- *
- * Creates controls related with the SPDIF output.
- * Called from each patch supporting the SPDIF out.
+ * @associated_nid: NID that new ctls associated with
+ * @cvt_nid: converter NID
+ * @type: HDA_PCM_TYPE_*
+ * Creates controls related with the digital output.
+ * Called from each patch supporting the digital out.
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
-                                 hda_nid_t associated_nid,
-                                 hda_nid_t cvt_nid)
+int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
+                               hda_nid_t associated_nid,
+                               hda_nid_t cvt_nid,
+                               int type)
 {
        int err;
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_new *dig_mix;
-       int idx;
+       int idx, dev = 0;
+       const int spdif_pcm_dev = 1;
        struct hda_spdif_out *spdif;
 
-       idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch");
+       if (codec->primary_dig_out_type == HDA_PCM_TYPE_HDMI &&
+           type == HDA_PCM_TYPE_SPDIF) {
+               dev = spdif_pcm_dev;
+       } else if (codec->primary_dig_out_type == HDA_PCM_TYPE_SPDIF &&
+                  type == HDA_PCM_TYPE_HDMI) {
+               for (idx = 0; idx < codec->spdif_out.used; idx++) {
+                       spdif = snd_array_elem(&codec->spdif_out, idx);
+                       for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
+                               kctl = find_mixer_ctl(codec, dig_mix->name, 0, idx);
+                               if (!kctl)
+                                       break;
+                               kctl->id.device = spdif_pcm_dev;
+                       }
+               }
+               codec->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
+       }
+       if (!codec->primary_dig_out_type)
+               codec->primary_dig_out_type = type;
+
+       idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", dev);
        if (idx < 0) {
                printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
                return -EBUSY;
@@ -3164,6 +3165,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
                kctl = snd_ctl_new1(dig_mix, codec);
                if (!kctl)
                        return -ENOMEM;
+               kctl->id.device = dev;
                kctl->id.index = idx;
                kctl->private_value = codec->spdif_out.used - 1;
                err = snd_hda_ctl_add(codec, associated_nid, kctl);
@@ -3176,7 +3178,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
        spdif->status = convert_to_spdif_status(spdif->ctls);
        return 0;
 }
-EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
+EXPORT_SYMBOL_HDA(snd_hda_create_dig_out_ctls);
 
 /* get the hda_spdif_out entry from the given NID
  * call within spdif_mutex lock
@@ -3351,7 +3353,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
        struct snd_kcontrol_new *dig_mix;
        int idx;
 
-       idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch");
+       idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0);
        if (idx < 0) {
                printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
                return -EBUSY;
@@ -3650,10 +3652,8 @@ static void hda_call_codec_resume(struct hda_codec *codec)
         */
        hda_keep_power_on(codec);
        hda_set_power_state(codec, AC_PWRST_D0);
-       restore_pincfgs(codec); /* restore all current pin configs */
        restore_shutup_pins(codec);
        hda_exec_init_verbs(codec);
-       snd_hda_jack_set_dirty_all(codec);
        if (codec->patch_ops.resume)
                codec->patch_ops.resume(codec);
        else {
@@ -3662,7 +3662,13 @@ static void hda_call_codec_resume(struct hda_codec *codec)
                snd_hda_codec_resume_amp(codec);
                snd_hda_codec_resume_cache(codec);
        }
-       snd_hda_jack_report_sync(codec);
+
+       if (codec->jackpoll_interval)
+               hda_jackpoll_work(&codec->jackpoll_work.work);
+       else {
+               snd_hda_jack_set_dirty_all(codec);
+               snd_hda_jack_report_sync(codec);
+       }
 
        codec->in_pm = 0;
        snd_hda_power_down(codec); /* flag down before returning */
@@ -3678,7 +3684,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
  *
  * Returns 0 if successful, otherwise a negative error code.
  */
-int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
+int snd_hda_build_controls(struct hda_bus *bus)
 {
        struct hda_codec *codec;
 
@@ -3712,13 +3718,14 @@ static int add_std_chmaps(struct hda_codec *codec)
                        struct hda_pcm_stream *hinfo =
                                &codec->pcm_info[i].stream[str];
                        struct snd_pcm_chmap *chmap;
+                       const struct snd_pcm_chmap_elem *elem;
 
                        if (codec->pcm_info[i].own_chmap)
                                continue;
                        if (!pcm || !hinfo->substreams)
                                continue;
-                       err = snd_pcm_add_chmap_ctls(pcm, str,
-                                                    snd_pcm_std_chmaps,
+                       elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps;
+                       err = snd_pcm_add_chmap_ctls(pcm, str, elem,
                                                     hinfo->channels_max,
                                                     0, &chmap);
                        if (err < 0)
@@ -3729,6 +3736,19 @@ static int add_std_chmaps(struct hda_codec *codec)
        return 0;
 }
 
+/* default channel maps for 2.1 speakers;
+ * since HD-audio supports only stereo, odd number channels are omitted
+ */
+const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+       { .channels = 4,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_LFE, SNDRV_CHMAP_LFE } },
+       { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps);
+
 int snd_hda_codec_build_controls(struct hda_codec *codec)
 {
        int err = 0;
@@ -3746,7 +3766,10 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       snd_hda_jack_report_sync(codec); /* call at the last init point */
+       if (codec->jackpoll_interval)
+               hda_jackpoll_work(&codec->jackpoll_work.work);
+       else
+               snd_hda_jack_report_sync(codec); /* call at the last init point */
        return 0;
 }
 
@@ -4458,7 +4481,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
                                addr = codec->addr;
                        else if (!idx && !knew->index) {
                                idx = find_empty_mixer_ctl_idx(codec,
-                                                              knew->name);
+                                                              knew->name, 0);
                                if (idx <= 0)
                                        return err;
                        } else
@@ -4770,6 +4793,34 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
 EXPORT_SYMBOL_HDA(snd_hda_input_mux_put);
 
 
+/*
+ * process kcontrol info callback of a simple string enum array
+ * when @num_items is 0 or @texts is NULL, assume a boolean enum array
+ */
+int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo,
+                            int num_items, const char * const *texts)
+{
+       static const char * const texts_default[] = {
+               "Disabled", "Enabled"
+       };
+
+       if (!texts || !num_items) {
+               num_items = 2;
+               texts = texts_default;
+       }
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = num_items;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_enum_helper_info);
+
 /*
  * Multi-channel / digital-out PCM helper functions
  */
@@ -4778,10 +4829,20 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put);
 static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
                                 unsigned int stream_tag, unsigned int format)
 {
-       struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid);
-
-       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
+       struct hda_spdif_out *spdif;
+       unsigned int curr_fmt;
+       bool reset;
+
+       spdif = snd_hda_spdif_out_of_nid(codec, nid);
+       curr_fmt = snd_hda_codec_read(codec, nid, 0,
+                                     AC_VERB_GET_STREAM_FORMAT, 0);
+       reset = codec->spdif_status_reset &&
+               (spdif->ctls & AC_DIG1_ENABLE) &&
+               curr_fmt != format;
+
+       /* turn off SPDIF if needed; otherwise the IEC958 bits won't be
+          updated */
+       if (reset)
                set_dig_out_convert(codec, nid,
                                    spdif->ctls & ~AC_DIG1_ENABLE & 0xff,
                                    -1);
@@ -4793,7 +4854,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
                                                   format);
        }
        /* turn on again (if needed) */
-       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
+       if (reset)
                set_dig_out_convert(codec, nid,
                                    spdif->ctls & 0xff, -1);
 }
@@ -5137,6 +5198,7 @@ int snd_hda_suspend(struct hda_bus *bus)
        struct hda_codec *codec;
 
        list_for_each_entry(codec, &bus->codec_list, list) {
+               cancel_delayed_work_sync(&codec->jackpoll_work);
                if (hda_codec_is_power_on(codec))
                        hda_call_codec_suspend(codec, false);
        }