diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-01-13 02:32:53 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-01-13 02:32:53 -0500 |
commit | 47e91348459901c30cc1bb4897e62ced21ca243a (patch) | |
tree | ebc855a2f3686726fb68b6b173af54ee75b44c61 | |
parent | 6b98515a620592636d2f8e0d3e2942d1cb4847ec (diff) | |
parent | ed69c6a8eef679f2783848ed624897a937a434ac (diff) |
Merge branch 'devel' of git.alsa-project.org:alsa-kernel into topic/misc
-rw-r--r-- | sound/core/pcm_lib.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 48 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 51 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 71 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 12 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 382 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 73 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 113 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 3 |
13 files changed, 591 insertions, 183 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 0403a7d55f0c..720019560794 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -394,6 +394,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
394 | + HZ/100); | 394 | + HZ/100); |
395 | /* move new_hw_ptr according jiffies not pos variable */ | 395 | /* move new_hw_ptr according jiffies not pos variable */ |
396 | new_hw_ptr = old_hw_ptr; | 396 | new_hw_ptr = old_hw_ptr; |
397 | hw_base = delta; | ||
397 | /* use loop to avoid checks for delta overflows */ | 398 | /* use loop to avoid checks for delta overflows */ |
398 | /* the delta value is small or zero in most cases */ | 399 | /* the delta value is small or zero in most cases */ |
399 | while (delta > 0) { | 400 | while (delta > 0) { |
@@ -403,8 +404,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
403 | delta--; | 404 | delta--; |
404 | } | 405 | } |
405 | /* align hw_base to buffer_size */ | 406 | /* align hw_base to buffer_size */ |
406 | hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); | ||
407 | delta = 0; | ||
408 | hw_ptr_error(substream, | 407 | hw_ptr_error(substream, |
409 | "hw_ptr skipping! %s" | 408 | "hw_ptr skipping! %s" |
410 | "(pos=%ld, delta=%ld, period=%ld, " | 409 | "(pos=%ld, delta=%ld, period=%ld, " |
@@ -412,9 +411,12 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
412 | in_interrupt ? "[Q] " : "", | 411 | in_interrupt ? "[Q] " : "", |
413 | (long)pos, (long)hdelta, | 412 | (long)pos, (long)hdelta, |
414 | (long)runtime->period_size, jdelta, | 413 | (long)runtime->period_size, jdelta, |
415 | ((hdelta * HZ) / runtime->rate), delta, | 414 | ((hdelta * HZ) / runtime->rate), hw_base, |
416 | (unsigned long)old_hw_ptr, | 415 | (unsigned long)old_hw_ptr, |
417 | (unsigned long)new_hw_ptr); | 416 | (unsigned long)new_hw_ptr); |
417 | /* reset values to proper state */ | ||
418 | delta = 0; | ||
419 | hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); | ||
418 | } | 420 | } |
419 | no_jiffies_check: | 421 | no_jiffies_check: |
420 | if (delta > runtime->period_size + runtime->period_size / 2) { | 422 | if (delta > runtime->period_size + runtime->period_size / 2) { |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d2f10b1c3a8a..d02ea8926e7e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | |||
824 | struct hda_pincfg *pin; | 824 | struct hda_pincfg *pin; |
825 | unsigned int oldcfg; | 825 | unsigned int oldcfg; |
826 | 826 | ||
827 | if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) | ||
828 | return -EINVAL; | ||
829 | |||
827 | oldcfg = snd_hda_codec_get_pincfg(codec, nid); | 830 | oldcfg = snd_hda_codec_get_pincfg(codec, nid); |
828 | pin = look_up_pincfg(codec, list, nid); | 831 | pin = look_up_pincfg(codec, list, nid); |
829 | if (!pin) { | 832 | if (!pin) { |
@@ -899,6 +902,25 @@ static void restore_pincfgs(struct hda_codec *codec) | |||
899 | } | 902 | } |
900 | } | 903 | } |
901 | 904 | ||
905 | /** | ||
906 | * snd_hda_shutup_pins - Shut up all pins | ||
907 | * @codec: the HDA codec | ||
908 | * | ||
909 | * Clear all pin controls to shup up before suspend for avoiding click noise. | ||
910 | * The controls aren't cached so that they can be resumed properly. | ||
911 | */ | ||
912 | void snd_hda_shutup_pins(struct hda_codec *codec) | ||
913 | { | ||
914 | int i; | ||
915 | for (i = 0; i < codec->init_pins.used; i++) { | ||
916 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
917 | /* use read here for syncing after issuing each verb */ | ||
918 | snd_hda_codec_read(codec, pin->nid, 0, | ||
919 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
920 | } | ||
921 | } | ||
922 | EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); | ||
923 | |||
902 | static void init_hda_cache(struct hda_cache_rec *cache, | 924 | static void init_hda_cache(struct hda_cache_rec *cache, |
903 | unsigned int record_size); | 925 | unsigned int record_size); |
904 | static void free_hda_cache(struct hda_cache_rec *cache); | 926 | static void free_hda_cache(struct hda_cache_rec *cache); |
@@ -3537,32 +3559,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | |||
3537 | } | 3559 | } |
3538 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); | 3560 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); |
3539 | 3561 | ||
3540 | /** | ||
3541 | * snd_hda_add_nids - assign nids to controls from the array | ||
3542 | * @codec: the HDA codec | ||
3543 | * @kctl: struct snd_kcontrol | ||
3544 | * @index: index to kctl | ||
3545 | * @nids: the array of hda_nid_t | ||
3546 | * @size: count of hda_nid_t items | ||
3547 | * | ||
3548 | * This helper function assigns NIDs in the given array to a control element. | ||
3549 | * | ||
3550 | * Returns 0 if successful, or a negative error code. | ||
3551 | */ | ||
3552 | int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
3553 | unsigned int index, hda_nid_t *nids, unsigned int size) | ||
3554 | { | ||
3555 | int err; | ||
3556 | |||
3557 | for ( ; size > 0; size--, nids++) { | ||
3558 | err = snd_hda_add_nid(codec, kctl, index, *nids); | ||
3559 | if (err < 0) | ||
3560 | return err; | ||
3561 | } | ||
3562 | return 0; | ||
3563 | } | ||
3564 | EXPORT_SYMBOL_HDA(snd_hda_add_nids); | ||
3565 | |||
3566 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3562 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3567 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | 3563 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, |
3568 | unsigned int power_state); | 3564 | unsigned int power_state); |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 0d08ad5bd898..11c4aa8ee996 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -898,6 +898,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, | |||
898 | unsigned int cfg); | 898 | unsigned int cfg); |
899 | int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | 899 | int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, |
900 | hda_nid_t nid, unsigned int cfg); /* for hwdep */ | 900 | hda_nid_t nid, unsigned int cfg); /* for hwdep */ |
901 | void snd_hda_shutup_pins(struct hda_codec *codec); | ||
901 | 902 | ||
902 | /* | 903 | /* |
903 | * Mixer | 904 | * Mixer |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 40ccb419b6e9..b36919c0d363 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -293,8 +293,11 @@ static ssize_t type##_store(struct device *dev, \ | |||
293 | { \ | 293 | { \ |
294 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ | 294 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ |
295 | struct hda_codec *codec = hwdep->private_data; \ | 295 | struct hda_codec *codec = hwdep->private_data; \ |
296 | char *after; \ | 296 | unsigned long val; \ |
297 | codec->type = simple_strtoul(buf, &after, 0); \ | 297 | int err = strict_strtoul(buf, 0, &val); \ |
298 | if (err < 0) \ | ||
299 | return err; \ | ||
300 | codec->type = val; \ | ||
298 | return count; \ | 301 | return count; \ |
299 | } | 302 | } |
300 | 303 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ff8ad46cc50e..1f516e668d88 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -356,6 +356,7 @@ struct azx_dev { | |||
356 | */ | 356 | */ |
357 | unsigned char stream_tag; /* assigned stream */ | 357 | unsigned char stream_tag; /* assigned stream */ |
358 | unsigned char index; /* stream index */ | 358 | unsigned char index; /* stream index */ |
359 | int device; /* last device number assigned to */ | ||
359 | 360 | ||
360 | unsigned int opened :1; | 361 | unsigned int opened :1; |
361 | unsigned int running :1; | 362 | unsigned int running :1; |
@@ -1441,10 +1442,13 @@ static int __devinit azx_codec_configure(struct azx *chip) | |||
1441 | */ | 1442 | */ |
1442 | 1443 | ||
1443 | /* assign a stream for the PCM */ | 1444 | /* assign a stream for the PCM */ |
1444 | static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) | 1445 | static inline struct azx_dev * |
1446 | azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) | ||
1445 | { | 1447 | { |
1446 | int dev, i, nums; | 1448 | int dev, i, nums; |
1447 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1449 | struct azx_dev *res = NULL; |
1450 | |||
1451 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1448 | dev = chip->playback_index_offset; | 1452 | dev = chip->playback_index_offset; |
1449 | nums = chip->playback_streams; | 1453 | nums = chip->playback_streams; |
1450 | } else { | 1454 | } else { |
@@ -1453,10 +1457,15 @@ static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) | |||
1453 | } | 1457 | } |
1454 | for (i = 0; i < nums; i++, dev++) | 1458 | for (i = 0; i < nums; i++, dev++) |
1455 | if (!chip->azx_dev[dev].opened) { | 1459 | if (!chip->azx_dev[dev].opened) { |
1456 | chip->azx_dev[dev].opened = 1; | 1460 | res = &chip->azx_dev[dev]; |
1457 | return &chip->azx_dev[dev]; | 1461 | if (res->device == substream->pcm->device) |
1462 | break; | ||
1458 | } | 1463 | } |
1459 | return NULL; | 1464 | if (res) { |
1465 | res->opened = 1; | ||
1466 | res->device = substream->pcm->device; | ||
1467 | } | ||
1468 | return res; | ||
1460 | } | 1469 | } |
1461 | 1470 | ||
1462 | /* release the assigned stream */ | 1471 | /* release the assigned stream */ |
@@ -1505,7 +1514,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) | |||
1505 | int err; | 1514 | int err; |
1506 | 1515 | ||
1507 | mutex_lock(&chip->open_mutex); | 1516 | mutex_lock(&chip->open_mutex); |
1508 | azx_dev = azx_assign_device(chip, substream->stream); | 1517 | azx_dev = azx_assign_device(chip, substream); |
1509 | if (azx_dev == NULL) { | 1518 | if (azx_dev == NULL) { |
1510 | mutex_unlock(&chip->open_mutex); | 1519 | mutex_unlock(&chip->open_mutex); |
1511 | return -EBUSY; | 1520 | return -EBUSY; |
@@ -2695,32 +2704,10 @@ static struct pci_device_id azx_ids[] = { | |||
2695 | /* ULI M5461 */ | 2704 | /* ULI M5461 */ |
2696 | { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, | 2705 | { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, |
2697 | /* NVIDIA MCP */ | 2706 | /* NVIDIA MCP */ |
2698 | { PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA }, | 2707 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), |
2699 | { PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA }, | 2708 | .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, |
2700 | { PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA }, | 2709 | .class_mask = 0xffffff, |
2701 | { PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA }, | 2710 | .driver_data = AZX_DRIVER_NVIDIA }, |
2702 | { PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2703 | { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2704 | { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2705 | { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2706 | { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2707 | { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2708 | { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2709 | { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2710 | { PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2711 | { PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2712 | { PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2713 | { PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2714 | { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2715 | { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2716 | { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2717 | { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2718 | { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2719 | { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2720 | { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2721 | { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2722 | { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2723 | { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2724 | /* Teradici */ | 2711 | /* Teradici */ |
2725 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | 2712 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, |
2726 | /* Creative X-Fi (CA0110-IBG) */ | 2713 | /* Creative X-Fi (CA0110-IBG) */ |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d505d052972e..7cee364976ff 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -343,8 +343,6 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, | |||
343 | const struct snd_pci_quirk *tbl); | 343 | const struct snd_pci_quirk *tbl); |
344 | int snd_hda_add_new_ctls(struct hda_codec *codec, | 344 | int snd_hda_add_new_ctls(struct hda_codec *codec, |
345 | struct snd_kcontrol_new *knew); | 345 | struct snd_kcontrol_new *knew); |
346 | int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
347 | unsigned int index, hda_nid_t *nids, unsigned int size); | ||
348 | 346 | ||
349 | /* | 347 | /* |
350 | * unsolicited event handler | 348 | * unsolicited event handler |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 92b72d4f3984..cecd3c108990 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -244,8 +244,7 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
244 | if (!kctl) | 244 | if (!kctl) |
245 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | 245 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); |
246 | for (i = 0; kctl && i < kctl->count; i++) { | 246 | for (i = 0; kctl && i < kctl->count; i++) { |
247 | err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, | 247 | err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); |
248 | spec->input_mux->num_items); | ||
249 | if (err < 0) | 248 | if (err < 0) |
250 | return err; | 249 | return err; |
251 | } | 250 | } |
@@ -442,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
442 | return 0; | 441 | return 0; |
443 | } | 442 | } |
444 | 443 | ||
444 | static inline void ad198x_shutup(struct hda_codec *codec) | ||
445 | { | ||
446 | snd_hda_shutup_pins(codec); | ||
447 | } | ||
448 | |||
445 | static void ad198x_free_kctls(struct hda_codec *codec) | 449 | static void ad198x_free_kctls(struct hda_codec *codec) |
446 | { | 450 | { |
447 | struct ad198x_spec *spec = codec->spec; | 451 | struct ad198x_spec *spec = codec->spec; |
@@ -455,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec) | |||
455 | snd_array_free(&spec->kctls); | 459 | snd_array_free(&spec->kctls); |
456 | } | 460 | } |
457 | 461 | ||
462 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, | ||
463 | hda_nid_t hp) | ||
464 | { | ||
465 | struct ad198x_spec *spec = codec->spec; | ||
466 | snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
467 | !spec->inv_eapd ? 0x00 : 0x02); | ||
468 | snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
469 | !spec->inv_eapd ? 0x00 : 0x02); | ||
470 | } | ||
471 | |||
472 | static void ad198x_power_eapd(struct hda_codec *codec) | ||
473 | { | ||
474 | /* We currently only handle front, HP */ | ||
475 | switch (codec->vendor_id) { | ||
476 | case 0x11d41882: | ||
477 | case 0x11d4882a: | ||
478 | case 0x11d41884: | ||
479 | case 0x11d41984: | ||
480 | case 0x11d41883: | ||
481 | case 0x11d4184a: | ||
482 | case 0x11d4194a: | ||
483 | case 0x11d4194b: | ||
484 | ad198x_power_eapd_write(codec, 0x12, 0x11); | ||
485 | break; | ||
486 | case 0x11d41981: | ||
487 | case 0x11d41983: | ||
488 | ad198x_power_eapd_write(codec, 0x05, 0x06); | ||
489 | break; | ||
490 | case 0x11d41986: | ||
491 | ad198x_power_eapd_write(codec, 0x1b, 0x1a); | ||
492 | break; | ||
493 | case 0x11d41988: | ||
494 | case 0x11d4198b: | ||
495 | case 0x11d4989a: | ||
496 | case 0x11d4989b: | ||
497 | ad198x_power_eapd_write(codec, 0x29, 0x22); | ||
498 | break; | ||
499 | } | ||
500 | } | ||
501 | |||
458 | static void ad198x_free(struct hda_codec *codec) | 502 | static void ad198x_free(struct hda_codec *codec) |
459 | { | 503 | { |
460 | struct ad198x_spec *spec = codec->spec; | 504 | struct ad198x_spec *spec = codec->spec; |
@@ -462,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec) | |||
462 | if (!spec) | 506 | if (!spec) |
463 | return; | 507 | return; |
464 | 508 | ||
509 | ad198x_shutup(codec); | ||
465 | ad198x_free_kctls(codec); | 510 | ad198x_free_kctls(codec); |
466 | kfree(spec); | 511 | kfree(spec); |
467 | snd_hda_detach_beep_device(codec); | 512 | snd_hda_detach_beep_device(codec); |
468 | } | 513 | } |
469 | 514 | ||
515 | #ifdef SND_HDA_NEEDS_RESUME | ||
516 | static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) | ||
517 | { | ||
518 | ad198x_shutup(codec); | ||
519 | ad198x_power_eapd(codec); | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int ad198x_resume(struct hda_codec *codec) | ||
524 | { | ||
525 | ad198x_init(codec); | ||
526 | snd_hda_codec_resume_amp(codec); | ||
527 | snd_hda_codec_resume_cache(codec); | ||
528 | return 0; | ||
529 | } | ||
530 | #endif | ||
531 | |||
470 | static struct hda_codec_ops ad198x_patch_ops = { | 532 | static struct hda_codec_ops ad198x_patch_ops = { |
471 | .build_controls = ad198x_build_controls, | 533 | .build_controls = ad198x_build_controls, |
472 | .build_pcms = ad198x_build_pcms, | 534 | .build_pcms = ad198x_build_pcms, |
@@ -475,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
475 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 537 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
476 | .check_power_status = ad198x_check_power_status, | 538 | .check_power_status = ad198x_check_power_status, |
477 | #endif | 539 | #endif |
540 | #ifdef SND_HDA_NEEDS_RESUME | ||
541 | .suspend = ad198x_suspend, | ||
542 | .resume = ad198x_resume, | ||
543 | #endif | ||
544 | .reboot_notify = ad198x_shutup, | ||
478 | }; | 545 | }; |
479 | 546 | ||
480 | 547 | ||
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 093cfbb55e9e..7de782a5b8f4 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -753,6 +753,7 @@ static int build_input(struct hda_codec *codec) | |||
753 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); | 753 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); |
754 | for (i = 0; i < 2; i++) { | 754 | for (i = 0; i < 2; i++) { |
755 | struct snd_kcontrol *kctl; | 755 | struct snd_kcontrol *kctl; |
756 | int n; | ||
756 | if (!spec->capture_bind[i]) | 757 | if (!spec->capture_bind[i]) |
757 | return -ENOMEM; | 758 | return -ENOMEM; |
758 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); | 759 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); |
@@ -762,10 +763,13 @@ static int build_input(struct hda_codec *codec) | |||
762 | err = snd_hda_ctl_add(codec, 0, kctl); | 763 | err = snd_hda_ctl_add(codec, 0, kctl); |
763 | if (err < 0) | 764 | if (err < 0) |
764 | return err; | 765 | return err; |
765 | err = snd_hda_add_nids(codec, kctl, 0, spec->adc_nid, | 766 | for (n = 0; n < AUTO_PIN_LAST; n++) { |
766 | spec->num_inputs); | 767 | if (!spec->adc_nid[n]) |
767 | if (err < 0) | 768 | continue; |
768 | return err; | 769 | err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[i]); |
770 | if (err < 0) | ||
771 | return err; | ||
772 | } | ||
769 | } | 773 | } |
770 | 774 | ||
771 | if (spec->num_inputs > 1 && !spec->mic_detect) { | 775 | if (spec->num_inputs > 1 && !spec->mic_detect) { |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index cc1c22370a60..ff60908f4554 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -345,8 +345,7 @@ static int cmi9880_build_controls(struct hda_codec *codec) | |||
345 | /* assign Capture Source enums to NID */ | 345 | /* assign Capture Source enums to NID */ |
346 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | 346 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); |
347 | for (i = 0; kctl && i < kctl->count; i++) { | 347 | for (i = 0; kctl && i < kctl->count; i++) { |
348 | err = snd_hda_add_nids(codec, kctl, i, spec->adc_nids, | 348 | err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]); |
349 | spec->input_mux->num_items); | ||
350 | if (err < 0) | 349 | if (err < 0) |
351 | return err; | 350 | return err; |
352 | } | 351 | } |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 947785f43b28..685015a53292 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -111,8 +111,22 @@ struct conexant_spec { | |||
111 | 111 | ||
112 | unsigned int dell_automute; | 112 | unsigned int dell_automute; |
113 | unsigned int port_d_mode; | 113 | unsigned int port_d_mode; |
114 | unsigned char ext_mic_bias; | ||
115 | unsigned int dell_vostro; | 114 | unsigned int dell_vostro; |
115 | |||
116 | unsigned int ext_mic_present; | ||
117 | unsigned int recording; | ||
118 | void (*capture_prepare)(struct hda_codec *codec); | ||
119 | void (*capture_cleanup)(struct hda_codec *codec); | ||
120 | |||
121 | /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) | ||
122 | * through the microphone jack. | ||
123 | * When the user enables this through a mixer switch, both internal and | ||
124 | * external microphones are disabled. Gain is fixed at 0dB. In this mode, | ||
125 | * we also allow the bias to be configured through a separate mixer | ||
126 | * control. */ | ||
127 | unsigned int dc_enable; | ||
128 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ | ||
129 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ | ||
116 | }; | 130 | }; |
117 | 131 | ||
118 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 132 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -185,6 +199,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
185 | struct snd_pcm_substream *substream) | 199 | struct snd_pcm_substream *substream) |
186 | { | 200 | { |
187 | struct conexant_spec *spec = codec->spec; | 201 | struct conexant_spec *spec = codec->spec; |
202 | if (spec->capture_prepare) | ||
203 | spec->capture_prepare(codec); | ||
188 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 204 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], |
189 | stream_tag, 0, format); | 205 | stream_tag, 0, format); |
190 | return 0; | 206 | return 0; |
@@ -196,6 +212,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
196 | { | 212 | { |
197 | struct conexant_spec *spec = codec->spec; | 213 | struct conexant_spec *spec = codec->spec; |
198 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); | 214 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); |
215 | if (spec->capture_cleanup) | ||
216 | spec->capture_cleanup(codec); | ||
199 | return 0; | 217 | return 0; |
200 | } | 218 | } |
201 | 219 | ||
@@ -1723,6 +1741,22 @@ static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | |||
1723 | {} | 1741 | {} |
1724 | }; | 1742 | }; |
1725 | 1743 | ||
1744 | static struct snd_kcontrol_new cxt5051_f700_mixers[] = { | ||
1745 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1746 | HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1747 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1748 | { | ||
1749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1750 | .name = "Master Playback Switch", | ||
1751 | .info = cxt_eapd_info, | ||
1752 | .get = cxt_eapd_get, | ||
1753 | .put = cxt5051_hp_master_sw_put, | ||
1754 | .private_value = 0x1a, | ||
1755 | }, | ||
1756 | |||
1757 | {} | ||
1758 | }; | ||
1759 | |||
1726 | static struct hda_verb cxt5051_init_verbs[] = { | 1760 | static struct hda_verb cxt5051_init_verbs[] = { |
1727 | /* Line in, Mic */ | 1761 | /* Line in, Mic */ |
1728 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | 1762 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, |
@@ -1813,6 +1847,32 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
1813 | { } /* end */ | 1847 | { } /* end */ |
1814 | }; | 1848 | }; |
1815 | 1849 | ||
1850 | static struct hda_verb cxt5051_f700_init_verbs[] = { | ||
1851 | /* Line in, Mic */ | ||
1852 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03}, | ||
1853 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1854 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
1855 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
1856 | /* SPK */ | ||
1857 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1858 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1859 | /* HP, Amp */ | ||
1860 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1861 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1862 | /* DAC1 */ | ||
1863 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1864 | /* Record selector: Int mic */ | ||
1865 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||
1866 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1867 | /* SPDIF route: PCM */ | ||
1868 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1869 | /* EAPD */ | ||
1870 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
1871 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||
1872 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1873 | { } /* end */ | ||
1874 | }; | ||
1875 | |||
1816 | /* initialize jack-sensing, too */ | 1876 | /* initialize jack-sensing, too */ |
1817 | static int cxt5051_init(struct hda_codec *codec) | 1877 | static int cxt5051_init(struct hda_codec *codec) |
1818 | { | 1878 | { |
@@ -1832,6 +1892,7 @@ enum { | |||
1832 | CXT5051_HP, /* no docking */ | 1892 | CXT5051_HP, /* no docking */ |
1833 | CXT5051_HP_DV6736, /* HP without mic switch */ | 1893 | CXT5051_HP_DV6736, /* HP without mic switch */ |
1834 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ | 1894 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ |
1895 | CXT5051_F700, /* HP Compaq Presario F700 */ | ||
1835 | CXT5051_MODELS | 1896 | CXT5051_MODELS |
1836 | }; | 1897 | }; |
1837 | 1898 | ||
@@ -1840,6 +1901,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
1840 | [CXT5051_HP] = "hp", | 1901 | [CXT5051_HP] = "hp", |
1841 | [CXT5051_HP_DV6736] = "hp-dv6736", | 1902 | [CXT5051_HP_DV6736] = "hp-dv6736", |
1842 | [CXT5051_LENOVO_X200] = "lenovo-x200", | 1903 | [CXT5051_LENOVO_X200] = "lenovo-x200", |
1904 | [CXT5051_F700] = "hp 700" | ||
1843 | }; | 1905 | }; |
1844 | 1906 | ||
1845 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1907 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
@@ -1849,6 +1911,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | |||
1849 | CXT5051_LAPTOP), | 1911 | CXT5051_LAPTOP), |
1850 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | 1912 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), |
1851 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), | 1913 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), |
1914 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), | ||
1852 | {} | 1915 | {} |
1853 | }; | 1916 | }; |
1854 | 1917 | ||
@@ -1899,6 +1962,11 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1899 | case CXT5051_LENOVO_X200: | 1962 | case CXT5051_LENOVO_X200: |
1900 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; | 1963 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; |
1901 | break; | 1964 | break; |
1965 | case CXT5051_F700: | ||
1966 | spec->init_verbs[0] = cxt5051_f700_init_verbs; | ||
1967 | spec->mixers[0] = cxt5051_f700_mixers; | ||
1968 | spec->no_auto_mic = 1; | ||
1969 | break; | ||
1902 | } | 1970 | } |
1903 | 1971 | ||
1904 | return 0; | 1972 | return 0; |
@@ -1966,53 +2034,97 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1966 | return 1; | 2034 | return 1; |
1967 | } | 2035 | } |
1968 | 2036 | ||
1969 | /* toggle input of built-in and mic jack appropriately */ | 2037 | static const struct hda_input_mux cxt5066_olpc_dc_bias = { |
1970 | static void cxt5066_automic(struct hda_codec *codec) | 2038 | .num_items = 3, |
2039 | .items = { | ||
2040 | { "Off", PIN_IN }, | ||
2041 | { "50%", PIN_VREF50 }, | ||
2042 | { "80%", PIN_VREF80 }, | ||
2043 | }, | ||
2044 | }; | ||
2045 | |||
2046 | static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) | ||
1971 | { | 2047 | { |
1972 | struct conexant_spec *spec = codec->spec; | 2048 | struct conexant_spec *spec = codec->spec; |
1973 | struct hda_verb ext_mic_present[] = { | 2049 | /* Even though port F is the DC input, the bias is controlled on port B. |
1974 | /* enable external mic, port B */ | 2050 | * we also leave that port as an active input (but unselected) in DC mode |
1975 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | 2051 | * just in case that is necessary to make the bias setting take effect. */ |
2052 | return snd_hda_codec_write_cache(codec, 0x1a, 0, | ||
2053 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2054 | cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); | ||
2055 | } | ||
1976 | 2056 | ||
1977 | /* switch to external mic input */ | 2057 | /* OLPC defers mic widget control until when capture is started because the |
1978 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2058 | * microphone LED comes on as soon as these settings are put in place. if we |
2059 | * did this before recording, it would give the false indication that recording | ||
2060 | * is happening when it is not. */ | ||
2061 | static void cxt5066_olpc_select_mic(struct hda_codec *codec) | ||
2062 | { | ||
2063 | struct conexant_spec *spec = codec->spec; | ||
2064 | if (!spec->recording) | ||
2065 | return; | ||
1979 | 2066 | ||
1980 | /* disable internal mic, port C */ | 2067 | if (spec->dc_enable) { |
1981 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2068 | /* in DC mode we ignore presence detection and just use the jack |
1982 | {} | 2069 | * through our special DC port */ |
1983 | }; | 2070 | const struct hda_verb enable_dc_mode[] = { |
1984 | static struct hda_verb ext_mic_absent[] = { | 2071 | /* disble internal mic, port C */ |
1985 | /* enable internal mic, port C */ | 2072 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
1986 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2073 | |
2074 | /* enable DC capture, port F */ | ||
2075 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2076 | {}, | ||
2077 | }; | ||
2078 | |||
2079 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
2080 | /* port B input disabled (and bias set) through the following call */ | ||
2081 | cxt5066_set_olpc_dc_bias(codec); | ||
2082 | return; | ||
2083 | } | ||
1987 | 2084 | ||
1988 | /* switch to internal mic input */ | 2085 | /* disable DC (port F) */ |
1989 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | 2086 | snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); |
1990 | 2087 | ||
1991 | /* disable external mic, port B */ | 2088 | /* external mic, port B */ |
1992 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2089 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
1993 | {} | 2090 | spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); |
1994 | }; | 2091 | |
2092 | /* internal mic, port C */ | ||
2093 | snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2094 | spec->ext_mic_present ? 0 : PIN_VREF80); | ||
2095 | } | ||
2096 | |||
2097 | /* toggle input of built-in and mic jack appropriately */ | ||
2098 | static void cxt5066_olpc_automic(struct hda_codec *codec) | ||
2099 | { | ||
2100 | struct conexant_spec *spec = codec->spec; | ||
1995 | unsigned int present; | 2101 | unsigned int present; |
1996 | 2102 | ||
1997 | present = snd_hda_jack_detect(codec, 0x1a); | 2103 | if (spec->dc_enable) /* don't do presence detection in DC mode */ |
1998 | if (present) { | 2104 | return; |
2105 | |||
2106 | present = snd_hda_codec_read(codec, 0x1a, 0, | ||
2107 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2108 | if (present) | ||
1999 | snd_printdd("CXT5066: external microphone detected\n"); | 2109 | snd_printdd("CXT5066: external microphone detected\n"); |
2000 | snd_hda_sequence_write(codec, ext_mic_present); | 2110 | else |
2001 | } else { | ||
2002 | snd_printdd("CXT5066: external microphone absent\n"); | 2111 | snd_printdd("CXT5066: external microphone absent\n"); |
2003 | snd_hda_sequence_write(codec, ext_mic_absent); | 2112 | |
2004 | } | 2113 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, |
2114 | present ? 0 : 1); | ||
2115 | spec->ext_mic_present = !!present; | ||
2116 | |||
2117 | cxt5066_olpc_select_mic(codec); | ||
2005 | } | 2118 | } |
2006 | 2119 | ||
2007 | /* toggle input of built-in digital mic and mic jack appropriately */ | 2120 | /* toggle input of built-in digital mic and mic jack appropriately */ |
2008 | static void cxt5066_vostro_automic(struct hda_codec *codec) | 2121 | static void cxt5066_vostro_automic(struct hda_codec *codec) |
2009 | { | 2122 | { |
2010 | struct conexant_spec *spec = codec->spec; | ||
2011 | unsigned int present; | 2123 | unsigned int present; |
2012 | 2124 | ||
2013 | struct hda_verb ext_mic_present[] = { | 2125 | struct hda_verb ext_mic_present[] = { |
2014 | /* enable external mic, port B */ | 2126 | /* enable external mic, port B */ |
2015 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | 2127 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
2016 | 2128 | ||
2017 | /* switch to external mic input */ | 2129 | /* switch to external mic input */ |
2018 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2130 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
@@ -2063,15 +2175,18 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
2063 | } | 2175 | } |
2064 | 2176 | ||
2065 | /* unsolicited event for jack sensing */ | 2177 | /* unsolicited event for jack sensing */ |
2066 | static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) | 2178 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) |
2067 | { | 2179 | { |
2180 | struct conexant_spec *spec = codec->spec; | ||
2068 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | 2181 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); |
2069 | switch (res >> 26) { | 2182 | switch (res >> 26) { |
2070 | case CONEXANT_HP_EVENT: | 2183 | case CONEXANT_HP_EVENT: |
2071 | cxt5066_hp_automute(codec); | 2184 | cxt5066_hp_automute(codec); |
2072 | break; | 2185 | break; |
2073 | case CONEXANT_MIC_EVENT: | 2186 | case CONEXANT_MIC_EVENT: |
2074 | cxt5066_automic(codec); | 2187 | /* ignore mic events in DC mode; we're always using the jack */ |
2188 | if (!spec->dc_enable) | ||
2189 | cxt5066_olpc_automic(codec); | ||
2075 | break; | 2190 | break; |
2076 | } | 2191 | } |
2077 | } | 2192 | } |
@@ -2101,6 +2216,15 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = { | |||
2101 | }, | 2216 | }, |
2102 | }; | 2217 | }; |
2103 | 2218 | ||
2219 | static int cxt5066_set_mic_boost(struct hda_codec *codec) | ||
2220 | { | ||
2221 | struct conexant_spec *spec = codec->spec; | ||
2222 | return snd_hda_codec_write_cache(codec, 0x17, 0, | ||
2223 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2224 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | | ||
2225 | cxt5066_analog_mic_boost.items[spec->mic_boost].index); | ||
2226 | } | ||
2227 | |||
2104 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, | 2228 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, |
2105 | struct snd_ctl_elem_info *uinfo) | 2229 | struct snd_ctl_elem_info *uinfo) |
2106 | { | 2230 | { |
@@ -2111,15 +2235,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, | |||
2111 | struct snd_ctl_elem_value *ucontrol) | 2235 | struct snd_ctl_elem_value *ucontrol) |
2112 | { | 2236 | { |
2113 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2237 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2114 | int val; | 2238 | struct conexant_spec *spec = codec->spec; |
2115 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2239 | ucontrol->value.enumerated.item[0] = spec->mic_boost; |
2116 | int inout = (kcontrol->private_value & 0x100) ? | ||
2117 | AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT; | ||
2118 | |||
2119 | val = snd_hda_codec_read(codec, nid, 0, | ||
2120 | AC_VERB_GET_AMP_GAIN_MUTE, inout); | ||
2121 | |||
2122 | ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; | ||
2123 | return 0; | 2240 | return 0; |
2124 | } | 2241 | } |
2125 | 2242 | ||
@@ -2127,26 +2244,132 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
2127 | struct snd_ctl_elem_value *ucontrol) | 2244 | struct snd_ctl_elem_value *ucontrol) |
2128 | { | 2245 | { |
2129 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2246 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2247 | struct conexant_spec *spec = codec->spec; | ||
2130 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | 2248 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; |
2131 | unsigned int idx; | 2249 | unsigned int idx; |
2132 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2250 | idx = ucontrol->value.enumerated.item[0]; |
2133 | int inout = (kcontrol->private_value & 0x100) ? | 2251 | if (idx >= imux->num_items) |
2134 | AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; | 2252 | idx = imux->num_items - 1; |
2253 | |||
2254 | spec->mic_boost = idx; | ||
2255 | if (!spec->dc_enable) | ||
2256 | cxt5066_set_mic_boost(codec); | ||
2257 | return 1; | ||
2258 | } | ||
2259 | |||
2260 | static void cxt5066_enable_dc(struct hda_codec *codec) | ||
2261 | { | ||
2262 | const struct hda_verb enable_dc_mode[] = { | ||
2263 | /* disable gain */ | ||
2264 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2265 | |||
2266 | /* switch to DC input */ | ||
2267 | {0x17, AC_VERB_SET_CONNECT_SEL, 3}, | ||
2268 | {} | ||
2269 | }; | ||
2270 | |||
2271 | /* configure as input source */ | ||
2272 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
2273 | cxt5066_olpc_select_mic(codec); /* also sets configured bias */ | ||
2274 | } | ||
2275 | |||
2276 | static void cxt5066_disable_dc(struct hda_codec *codec) | ||
2277 | { | ||
2278 | /* reconfigure input source */ | ||
2279 | cxt5066_set_mic_boost(codec); | ||
2280 | /* automic also selects the right mic if we're recording */ | ||
2281 | cxt5066_olpc_automic(codec); | ||
2282 | } | ||
2283 | |||
2284 | static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, | ||
2285 | struct snd_ctl_elem_value *ucontrol) | ||
2286 | { | ||
2287 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2288 | struct conexant_spec *spec = codec->spec; | ||
2289 | ucontrol->value.integer.value[0] = spec->dc_enable; | ||
2290 | return 0; | ||
2291 | } | ||
2292 | |||
2293 | static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, | ||
2294 | struct snd_ctl_elem_value *ucontrol) | ||
2295 | { | ||
2296 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2297 | struct conexant_spec *spec = codec->spec; | ||
2298 | int dc_enable = !!ucontrol->value.integer.value[0]; | ||
2135 | 2299 | ||
2136 | if (!imux->num_items) | 2300 | if (dc_enable == spec->dc_enable) |
2137 | return 0; | 2301 | return 0; |
2302 | |||
2303 | spec->dc_enable = dc_enable; | ||
2304 | if (dc_enable) | ||
2305 | cxt5066_enable_dc(codec); | ||
2306 | else | ||
2307 | cxt5066_disable_dc(codec); | ||
2308 | |||
2309 | return 1; | ||
2310 | } | ||
2311 | |||
2312 | static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, | ||
2313 | struct snd_ctl_elem_info *uinfo) | ||
2314 | { | ||
2315 | return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); | ||
2316 | } | ||
2317 | |||
2318 | static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, | ||
2319 | struct snd_ctl_elem_value *ucontrol) | ||
2320 | { | ||
2321 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2322 | struct conexant_spec *spec = codec->spec; | ||
2323 | ucontrol->value.enumerated.item[0] = spec->dc_input_bias; | ||
2324 | return 0; | ||
2325 | } | ||
2326 | |||
2327 | static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, | ||
2328 | struct snd_ctl_elem_value *ucontrol) | ||
2329 | { | ||
2330 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2331 | struct conexant_spec *spec = codec->spec; | ||
2332 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | ||
2333 | unsigned int idx; | ||
2334 | |||
2138 | idx = ucontrol->value.enumerated.item[0]; | 2335 | idx = ucontrol->value.enumerated.item[0]; |
2139 | if (idx >= imux->num_items) | 2336 | if (idx >= imux->num_items) |
2140 | idx = imux->num_items - 1; | 2337 | idx = imux->num_items - 1; |
2141 | 2338 | ||
2142 | snd_hda_codec_write_cache(codec, nid, 0, | 2339 | spec->dc_input_bias = idx; |
2143 | AC_VERB_SET_AMP_GAIN_MUTE, | 2340 | if (spec->dc_enable) |
2144 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | | 2341 | cxt5066_set_olpc_dc_bias(codec); |
2145 | imux->items[idx].index); | ||
2146 | |||
2147 | return 1; | 2342 | return 1; |
2148 | } | 2343 | } |
2149 | 2344 | ||
2345 | static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) | ||
2346 | { | ||
2347 | struct conexant_spec *spec = codec->spec; | ||
2348 | /* mark as recording and configure the microphone widget so that the | ||
2349 | * recording LED comes on. */ | ||
2350 | spec->recording = 1; | ||
2351 | cxt5066_olpc_select_mic(codec); | ||
2352 | } | ||
2353 | |||
2354 | static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) | ||
2355 | { | ||
2356 | struct conexant_spec *spec = codec->spec; | ||
2357 | const struct hda_verb disable_mics[] = { | ||
2358 | /* disable external mic, port B */ | ||
2359 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2360 | |||
2361 | /* disble internal mic, port C */ | ||
2362 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2363 | |||
2364 | /* disable DC capture, port F */ | ||
2365 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2366 | {}, | ||
2367 | }; | ||
2368 | |||
2369 | snd_hda_sequence_write(codec, disable_mics); | ||
2370 | spec->recording = 0; | ||
2371 | } | ||
2372 | |||
2150 | static struct hda_input_mux cxt5066_capture_source = { | 2373 | static struct hda_input_mux cxt5066_capture_source = { |
2151 | .num_items = 4, | 2374 | .num_items = 4, |
2152 | .items = { | 2375 | .items = { |
@@ -2199,6 +2422,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2199 | {} | 2422 | {} |
2200 | }; | 2423 | }; |
2201 | 2424 | ||
2425 | static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | ||
2426 | { | ||
2427 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2428 | .name = "DC Mode Enable Switch", | ||
2429 | .info = snd_ctl_boolean_mono_info, | ||
2430 | .get = cxt5066_olpc_dc_get, | ||
2431 | .put = cxt5066_olpc_dc_put, | ||
2432 | }, | ||
2433 | { | ||
2434 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2435 | .name = "DC Input Bias Enum", | ||
2436 | .info = cxt5066_olpc_dc_bias_enum_info, | ||
2437 | .get = cxt5066_olpc_dc_bias_enum_get, | ||
2438 | .put = cxt5066_olpc_dc_bias_enum_put, | ||
2439 | }, | ||
2440 | {} | ||
2441 | }; | ||
2442 | |||
2202 | static struct snd_kcontrol_new cxt5066_mixers[] = { | 2443 | static struct snd_kcontrol_new cxt5066_mixers[] = { |
2203 | { | 2444 | { |
2204 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2445 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -2211,11 +2452,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
2211 | 2452 | ||
2212 | { | 2453 | { |
2213 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2454 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2214 | .name = "Ext Mic Boost Capture Enum", | 2455 | .name = "Analog Mic Boost Capture Enum", |
2215 | .info = cxt5066_mic_boost_mux_enum_info, | 2456 | .info = cxt5066_mic_boost_mux_enum_info, |
2216 | .get = cxt5066_mic_boost_mux_enum_get, | 2457 | .get = cxt5066_mic_boost_mux_enum_get, |
2217 | .put = cxt5066_mic_boost_mux_enum_put, | 2458 | .put = cxt5066_mic_boost_mux_enum_put, |
2218 | .private_value = 0x17, | ||
2219 | }, | 2459 | }, |
2220 | 2460 | ||
2221 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), | 2461 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), |
@@ -2297,10 +2537,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2297 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2537 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
2298 | 2538 | ||
2299 | /* Port B: external microphone */ | 2539 | /* Port B: external microphone */ |
2300 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, | 2540 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2301 | 2541 | ||
2302 | /* Port C: internal microphone */ | 2542 | /* Port C: internal microphone */ |
2303 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2543 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2304 | 2544 | ||
2305 | /* Port D: unused */ | 2545 | /* Port D: unused */ |
2306 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2546 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -2309,7 +2549,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2309 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2549 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2310 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 2550 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
2311 | 2551 | ||
2312 | /* Port F: unused */ | 2552 | /* Port F: external DC input through microphone port */ |
2313 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2553 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2314 | 2554 | ||
2315 | /* Port G: internal speakers */ | 2555 | /* Port G: internal speakers */ |
@@ -2429,8 +2669,22 @@ static int cxt5066_init(struct hda_codec *codec) | |||
2429 | cxt5066_hp_automute(codec); | 2669 | cxt5066_hp_automute(codec); |
2430 | if (spec->dell_vostro) | 2670 | if (spec->dell_vostro) |
2431 | cxt5066_vostro_automic(codec); | 2671 | cxt5066_vostro_automic(codec); |
2432 | else | 2672 | } |
2433 | cxt5066_automic(codec); | 2673 | cxt5066_set_mic_boost(codec); |
2674 | return 0; | ||
2675 | } | ||
2676 | |||
2677 | static int cxt5066_olpc_init(struct hda_codec *codec) | ||
2678 | { | ||
2679 | struct conexant_spec *spec = codec->spec; | ||
2680 | snd_printdd("CXT5066: init\n"); | ||
2681 | conexant_init(codec); | ||
2682 | cxt5066_hp_automute(codec); | ||
2683 | if (!spec->dc_enable) { | ||
2684 | cxt5066_set_mic_boost(codec); | ||
2685 | cxt5066_olpc_automic(codec); | ||
2686 | } else { | ||
2687 | cxt5066_enable_dc(codec); | ||
2434 | } | 2688 | } |
2435 | return 0; | 2689 | return 0; |
2436 | } | 2690 | } |
@@ -2471,7 +2725,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2471 | codec->spec = spec; | 2725 | codec->spec = spec; |
2472 | 2726 | ||
2473 | codec->patch_ops = conexant_patch_ops; | 2727 | codec->patch_ops = conexant_patch_ops; |
2474 | codec->patch_ops.init = cxt5066_init; | 2728 | codec->patch_ops.init = conexant_init; |
2475 | 2729 | ||
2476 | spec->dell_automute = 0; | 2730 | spec->dell_automute = 0; |
2477 | spec->multiout.max_channels = 2; | 2731 | spec->multiout.max_channels = 2; |
@@ -2484,7 +2738,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2484 | spec->input_mux = &cxt5066_capture_source; | 2738 | spec->input_mux = &cxt5066_capture_source; |
2485 | 2739 | ||
2486 | spec->port_d_mode = PIN_HP; | 2740 | spec->port_d_mode = PIN_HP; |
2487 | spec->ext_mic_bias = PIN_VREF80; | ||
2488 | 2741 | ||
2489 | spec->num_init_verbs = 1; | 2742 | spec->num_init_verbs = 1; |
2490 | spec->init_verbs[0] = cxt5066_init_verbs; | 2743 | spec->init_verbs[0] = cxt5066_init_verbs; |
@@ -2511,20 +2764,28 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2511 | spec->dell_automute = 1; | 2764 | spec->dell_automute = 1; |
2512 | break; | 2765 | break; |
2513 | case CXT5066_OLPC_XO_1_5: | 2766 | case CXT5066_OLPC_XO_1_5: |
2514 | codec->patch_ops.unsol_event = cxt5066_unsol_event; | 2767 | codec->patch_ops.init = cxt5066_olpc_init; |
2768 | codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; | ||
2515 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; | 2769 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; |
2516 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2770 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
2771 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; | ||
2517 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 2772 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
2518 | spec->port_d_mode = 0; | 2773 | spec->port_d_mode = 0; |
2519 | spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; | 2774 | spec->mic_boost = 3; /* default 30dB gain */ |
2520 | 2775 | ||
2521 | /* no S/PDIF out */ | 2776 | /* no S/PDIF out */ |
2522 | spec->multiout.dig_out_nid = 0; | 2777 | spec->multiout.dig_out_nid = 0; |
2523 | 2778 | ||
2524 | /* input source automatically selected */ | 2779 | /* input source automatically selected */ |
2525 | spec->input_mux = NULL; | 2780 | spec->input_mux = NULL; |
2781 | |||
2782 | /* our capture hooks which allow us to turn on the microphone LED | ||
2783 | * at the right time */ | ||
2784 | spec->capture_prepare = cxt5066_olpc_capture_prepare; | ||
2785 | spec->capture_cleanup = cxt5066_olpc_capture_cleanup; | ||
2526 | break; | 2786 | break; |
2527 | case CXT5066_DELL_VOSTO: | 2787 | case CXT5066_DELL_VOSTO: |
2788 | codec->patch_ops.init = cxt5066_init; | ||
2528 | codec->patch_ops.unsol_event = cxt5066_vostro_event; | 2789 | codec->patch_ops.unsol_event = cxt5066_vostro_event; |
2529 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; | 2790 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; |
2530 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2791 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
@@ -2532,6 +2793,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2532 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; | 2793 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; |
2533 | spec->port_d_mode = 0; | 2794 | spec->port_d_mode = 0; |
2534 | spec->dell_vostro = 1; | 2795 | spec->dell_vostro = 1; |
2796 | spec->mic_boost = 3; /* default 30dB gain */ | ||
2535 | snd_hda_attach_beep_device(codec, 0x13); | 2797 | snd_hda_attach_beep_device(codec, 0x13); |
2536 | 2798 | ||
2537 | /* no S/PDIF out */ | 2799 | /* no S/PDIF out */ |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index aeb23ef6afe5..141ff446104a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -338,7 +338,7 @@ struct alc_spec { | |||
338 | void (*init_hook)(struct hda_codec *codec); | 338 | void (*init_hook)(struct hda_codec *codec); |
339 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | 339 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); |
340 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 340 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
341 | void (*power_hook)(struct hda_codec *codec, int power); | 341 | void (*power_hook)(struct hda_codec *codec); |
342 | #endif | 342 | #endif |
343 | 343 | ||
344 | /* for pin sensing */ | 344 | /* for pin sensing */ |
@@ -391,7 +391,7 @@ struct alc_config_preset { | |||
391 | void (*init_hook)(struct hda_codec *); | 391 | void (*init_hook)(struct hda_codec *); |
392 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 392 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
393 | struct hda_amp_list *loopbacks; | 393 | struct hda_amp_list *loopbacks; |
394 | void (*power_hook)(struct hda_codec *codec, int power); | 394 | void (*power_hook)(struct hda_codec *codec); |
395 | #endif | 395 | #endif |
396 | }; | 396 | }; |
397 | 397 | ||
@@ -1835,16 +1835,6 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) | |||
1835 | spec->autocfg.speaker_pins[2] = 0x1b; | 1835 | spec->autocfg.speaker_pins[2] = 0x1b; |
1836 | } | 1836 | } |
1837 | 1837 | ||
1838 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1839 | static void alc889_power_eapd(struct hda_codec *codec, int power) | ||
1840 | { | ||
1841 | snd_hda_codec_write(codec, 0x14, 0, | ||
1842 | AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0); | ||
1843 | snd_hda_codec_write(codec, 0x15, 0, | ||
1844 | AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0); | ||
1845 | } | ||
1846 | #endif | ||
1847 | |||
1848 | /* | 1838 | /* |
1849 | * ALC880 3-stack model | 1839 | * ALC880 3-stack model |
1850 | * | 1840 | * |
@@ -2548,8 +2538,10 @@ static int alc_build_controls(struct hda_codec *codec) | |||
2548 | if (!kctl) | 2538 | if (!kctl) |
2549 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | 2539 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); |
2550 | for (i = 0; kctl && i < kctl->count; i++) { | 2540 | for (i = 0; kctl && i < kctl->count; i++) { |
2551 | err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, | 2541 | hda_nid_t *nids = spec->capsrc_nids; |
2552 | spec->input_mux->num_items); | 2542 | if (!nids) |
2543 | nids = spec->adc_nids; | ||
2544 | err = snd_hda_add_nid(codec, kctl, i, nids[i]); | ||
2553 | if (err < 0) | 2545 | if (err < 0) |
2554 | return err; | 2546 | return err; |
2555 | } | 2547 | } |
@@ -3691,6 +3683,11 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
3691 | return 0; | 3683 | return 0; |
3692 | } | 3684 | } |
3693 | 3685 | ||
3686 | static inline void alc_shutup(struct hda_codec *codec) | ||
3687 | { | ||
3688 | snd_hda_shutup_pins(codec); | ||
3689 | } | ||
3690 | |||
3694 | static void alc_free_kctls(struct hda_codec *codec) | 3691 | static void alc_free_kctls(struct hda_codec *codec) |
3695 | { | 3692 | { |
3696 | struct alc_spec *spec = codec->spec; | 3693 | struct alc_spec *spec = codec->spec; |
@@ -3711,17 +3708,47 @@ static void alc_free(struct hda_codec *codec) | |||
3711 | if (!spec) | 3708 | if (!spec) |
3712 | return; | 3709 | return; |
3713 | 3710 | ||
3711 | alc_shutup(codec); | ||
3714 | alc_free_kctls(codec); | 3712 | alc_free_kctls(codec); |
3715 | kfree(spec); | 3713 | kfree(spec); |
3716 | snd_hda_detach_beep_device(codec); | 3714 | snd_hda_detach_beep_device(codec); |
3717 | } | 3715 | } |
3718 | 3716 | ||
3719 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3717 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3718 | static void alc_power_eapd(struct hda_codec *codec) | ||
3719 | { | ||
3720 | /* We currently only handle front, HP */ | ||
3721 | switch (codec->vendor_id) { | ||
3722 | case 0x10ec0260: | ||
3723 | snd_hda_codec_write(codec, 0x0f, 0, | ||
3724 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
3725 | snd_hda_codec_write(codec, 0x10, 0, | ||
3726 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
3727 | break; | ||
3728 | case 0x10ec0262: | ||
3729 | case 0x10ec0267: | ||
3730 | case 0x10ec0268: | ||
3731 | case 0x10ec0269: | ||
3732 | case 0x10ec0272: | ||
3733 | case 0x10ec0660: | ||
3734 | case 0x10ec0662: | ||
3735 | case 0x10ec0663: | ||
3736 | case 0x10ec0862: | ||
3737 | case 0x10ec0889: | ||
3738 | snd_hda_codec_write(codec, 0x14, 0, | ||
3739 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
3740 | snd_hda_codec_write(codec, 0x15, 0, | ||
3741 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
3742 | break; | ||
3743 | } | ||
3744 | } | ||
3745 | |||
3720 | static int alc_suspend(struct hda_codec *codec, pm_message_t state) | 3746 | static int alc_suspend(struct hda_codec *codec, pm_message_t state) |
3721 | { | 3747 | { |
3722 | struct alc_spec *spec = codec->spec; | 3748 | struct alc_spec *spec = codec->spec; |
3749 | alc_shutup(codec); | ||
3723 | if (spec && spec->power_hook) | 3750 | if (spec && spec->power_hook) |
3724 | spec->power_hook(codec, 0); | 3751 | spec->power_hook(codec); |
3725 | return 0; | 3752 | return 0; |
3726 | } | 3753 | } |
3727 | #endif | 3754 | #endif |
@@ -3729,16 +3756,9 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) | |||
3729 | #ifdef SND_HDA_NEEDS_RESUME | 3756 | #ifdef SND_HDA_NEEDS_RESUME |
3730 | static int alc_resume(struct hda_codec *codec) | 3757 | static int alc_resume(struct hda_codec *codec) |
3731 | { | 3758 | { |
3732 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3733 | struct alc_spec *spec = codec->spec; | ||
3734 | #endif | ||
3735 | codec->patch_ops.init(codec); | 3759 | codec->patch_ops.init(codec); |
3736 | snd_hda_codec_resume_amp(codec); | 3760 | snd_hda_codec_resume_amp(codec); |
3737 | snd_hda_codec_resume_cache(codec); | 3761 | snd_hda_codec_resume_cache(codec); |
3738 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3739 | if (spec && spec->power_hook) | ||
3740 | spec->power_hook(codec, 1); | ||
3741 | #endif | ||
3742 | return 0; | 3762 | return 0; |
3743 | } | 3763 | } |
3744 | #endif | 3764 | #endif |
@@ -3758,6 +3778,7 @@ static struct hda_codec_ops alc_patch_ops = { | |||
3758 | .suspend = alc_suspend, | 3778 | .suspend = alc_suspend, |
3759 | .check_power_status = alc_check_power_status, | 3779 | .check_power_status = alc_check_power_status, |
3760 | #endif | 3780 | #endif |
3781 | .reboot_notify = alc_shutup, | ||
3761 | }; | 3782 | }; |
3762 | 3783 | ||
3763 | 3784 | ||
@@ -9538,7 +9559,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
9538 | .setup = alc889_acer_aspire_8930g_setup, | 9559 | .setup = alc889_acer_aspire_8930g_setup, |
9539 | .init_hook = alc_automute_amp, | 9560 | .init_hook = alc_automute_amp, |
9540 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 9561 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
9541 | .power_hook = alc889_power_eapd, | 9562 | .power_hook = alc_power_eapd, |
9542 | #endif | 9563 | #endif |
9543 | }, | 9564 | }, |
9544 | [ALC888_ACER_ASPIRE_7730G] = { | 9565 | [ALC888_ACER_ASPIRE_7730G] = { |
@@ -14975,9 +14996,13 @@ static int patch_alc861(struct hda_codec *codec) | |||
14975 | spec->vmaster_nid = 0x03; | 14996 | spec->vmaster_nid = 0x03; |
14976 | 14997 | ||
14977 | codec->patch_ops = alc_patch_ops; | 14998 | codec->patch_ops = alc_patch_ops; |
14978 | if (board_config == ALC861_AUTO) | 14999 | if (board_config == ALC861_AUTO) { |
14979 | spec->init_hook = alc861_auto_init; | 15000 | spec->init_hook = alc861_auto_init; |
14980 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 15001 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
15002 | spec->power_hook = alc_power_eapd; | ||
15003 | #endif | ||
15004 | } | ||
15005 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
14981 | if (!spec->loopback.amplist) | 15006 | if (!spec->loopback.amplist) |
14982 | spec->loopback.amplist = alc861_loopbacks; | 15007 | spec->loopback.amplist = alc861_loopbacks; |
14983 | #endif | 15008 | #endif |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 74d5d333ed6c..e28c810bc00c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -4159,34 +4159,52 @@ static void stac92xx_power_down(struct hda_codec *codec) | |||
4159 | static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, | 4159 | static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, |
4160 | int enable); | 4160 | int enable); |
4161 | 4161 | ||
4162 | static inline int get_int_hint(struct hda_codec *codec, const char *key, | ||
4163 | int *valp) | ||
4164 | { | ||
4165 | const char *p; | ||
4166 | p = snd_hda_get_hint(codec, key); | ||
4167 | if (p) { | ||
4168 | unsigned long val; | ||
4169 | if (!strict_strtoul(p, 0, &val)) { | ||
4170 | *valp = val; | ||
4171 | return 1; | ||
4172 | } | ||
4173 | } | ||
4174 | return 0; | ||
4175 | } | ||
4176 | |||
4162 | /* override some hints from the hwdep entry */ | 4177 | /* override some hints from the hwdep entry */ |
4163 | static void stac_store_hints(struct hda_codec *codec) | 4178 | static void stac_store_hints(struct hda_codec *codec) |
4164 | { | 4179 | { |
4165 | struct sigmatel_spec *spec = codec->spec; | 4180 | struct sigmatel_spec *spec = codec->spec; |
4166 | const char *p; | ||
4167 | int val; | 4181 | int val; |
4168 | 4182 | ||
4169 | val = snd_hda_get_bool_hint(codec, "hp_detect"); | 4183 | val = snd_hda_get_bool_hint(codec, "hp_detect"); |
4170 | if (val >= 0) | 4184 | if (val >= 0) |
4171 | spec->hp_detect = val; | 4185 | spec->hp_detect = val; |
4172 | p = snd_hda_get_hint(codec, "gpio_mask"); | 4186 | if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { |
4173 | if (p) { | ||
4174 | spec->gpio_mask = simple_strtoul(p, NULL, 0); | ||
4175 | spec->eapd_mask = spec->gpio_dir = spec->gpio_data = | 4187 | spec->eapd_mask = spec->gpio_dir = spec->gpio_data = |
4176 | spec->gpio_mask; | 4188 | spec->gpio_mask; |
4177 | } | 4189 | } |
4178 | p = snd_hda_get_hint(codec, "gpio_dir"); | 4190 | if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) |
4179 | if (p) | 4191 | spec->gpio_mask &= spec->gpio_mask; |
4180 | spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | 4192 | if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) |
4181 | p = snd_hda_get_hint(codec, "gpio_data"); | 4193 | spec->gpio_dir &= spec->gpio_mask; |
4182 | if (p) | 4194 | if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) |
4183 | spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | 4195 | spec->eapd_mask &= spec->gpio_mask; |
4184 | p = snd_hda_get_hint(codec, "eapd_mask"); | 4196 | if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) |
4185 | if (p) | 4197 | spec->gpio_mute &= spec->gpio_mask; |
4186 | spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | ||
4187 | val = snd_hda_get_bool_hint(codec, "eapd_switch"); | 4198 | val = snd_hda_get_bool_hint(codec, "eapd_switch"); |
4188 | if (val >= 0) | 4199 | if (val >= 0) |
4189 | spec->eapd_switch = val; | 4200 | spec->eapd_switch = val; |
4201 | get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity); | ||
4202 | if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { | ||
4203 | spec->gpio_mask |= spec->gpio_led; | ||
4204 | spec->gpio_dir |= spec->gpio_led; | ||
4205 | if (spec->gpio_led_polarity) | ||
4206 | spec->gpio_data |= spec->gpio_led; | ||
4207 | } | ||
4190 | } | 4208 | } |
4191 | 4209 | ||
4192 | static int stac92xx_init(struct hda_codec *codec) | 4210 | static int stac92xx_init(struct hda_codec *codec) |
@@ -4371,18 +4389,8 @@ static void stac92xx_free_kctls(struct hda_codec *codec) | |||
4371 | static void stac92xx_shutup(struct hda_codec *codec) | 4389 | static void stac92xx_shutup(struct hda_codec *codec) |
4372 | { | 4390 | { |
4373 | struct sigmatel_spec *spec = codec->spec; | 4391 | struct sigmatel_spec *spec = codec->spec; |
4374 | int i; | ||
4375 | hda_nid_t nid; | ||
4376 | 4392 | ||
4377 | /* reset each pin before powering down DAC/ADC to avoid click noise */ | 4393 | snd_hda_shutup_pins(codec); |
4378 | nid = codec->start_nid; | ||
4379 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
4380 | unsigned int wcaps = get_wcaps(codec, nid); | ||
4381 | unsigned int wid_type = get_wcaps_type(wcaps); | ||
4382 | if (wid_type == AC_WID_PIN) | ||
4383 | snd_hda_codec_read(codec, nid, 0, | ||
4384 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
4385 | } | ||
4386 | 4394 | ||
4387 | if (spec->eapd_mask) | 4395 | if (spec->eapd_mask) |
4388 | stac_gpio_set(codec, spec->gpio_mask, | 4396 | stac_gpio_set(codec, spec->gpio_mask, |
@@ -5406,6 +5414,54 @@ static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, | |||
5406 | return 0; | 5414 | return 0; |
5407 | } | 5415 | } |
5408 | 5416 | ||
5417 | /* HP dv7 bass switch - GPIO5 */ | ||
5418 | #define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info | ||
5419 | static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, | ||
5420 | struct snd_ctl_elem_value *ucontrol) | ||
5421 | { | ||
5422 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5423 | struct sigmatel_spec *spec = codec->spec; | ||
5424 | ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); | ||
5425 | return 0; | ||
5426 | } | ||
5427 | |||
5428 | static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, | ||
5429 | struct snd_ctl_elem_value *ucontrol) | ||
5430 | { | ||
5431 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5432 | struct sigmatel_spec *spec = codec->spec; | ||
5433 | unsigned int gpio_data; | ||
5434 | |||
5435 | gpio_data = (spec->gpio_data & ~0x20) | | ||
5436 | (ucontrol->value.integer.value[0] ? 0x20 : 0); | ||
5437 | if (gpio_data == spec->gpio_data) | ||
5438 | return 0; | ||
5439 | spec->gpio_data = gpio_data; | ||
5440 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); | ||
5441 | return 1; | ||
5442 | } | ||
5443 | |||
5444 | static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { | ||
5445 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5446 | .info = stac_hp_bass_gpio_info, | ||
5447 | .get = stac_hp_bass_gpio_get, | ||
5448 | .put = stac_hp_bass_gpio_put, | ||
5449 | }; | ||
5450 | |||
5451 | static int stac_add_hp_bass_switch(struct hda_codec *codec) | ||
5452 | { | ||
5453 | struct sigmatel_spec *spec = codec->spec; | ||
5454 | |||
5455 | if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl, | ||
5456 | "Bass Speaker Playback Switch", 0)) | ||
5457 | return -ENOMEM; | ||
5458 | |||
5459 | spec->gpio_mask |= 0x20; | ||
5460 | spec->gpio_dir |= 0x20; | ||
5461 | spec->gpio_data |= 0x20; | ||
5462 | return 0; | ||
5463 | } | ||
5464 | |||
5409 | static int patch_stac92hd71bxx(struct hda_codec *codec) | 5465 | static int patch_stac92hd71bxx(struct hda_codec *codec) |
5410 | { | 5466 | { |
5411 | struct sigmatel_spec *spec; | 5467 | struct sigmatel_spec *spec; |
@@ -5646,6 +5702,15 @@ again: | |||
5646 | return err; | 5702 | return err; |
5647 | } | 5703 | } |
5648 | 5704 | ||
5705 | /* enable bass on HP dv7 */ | ||
5706 | if (spec->board_config == STAC_HP_DV5) { | ||
5707 | unsigned int cap; | ||
5708 | cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); | ||
5709 | cap &= AC_GPIO_IO_COUNT; | ||
5710 | if (cap >= 6) | ||
5711 | stac_add_hp_bass_switch(codec); | ||
5712 | } | ||
5713 | |||
5649 | codec->proc_widget_hook = stac92hd7x_proc_hook; | 5714 | codec->proc_widget_hook = stac92hd7x_proc_hook; |
5650 | 5715 | ||
5651 | return 0; | 5716 | return 0; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index de4839e46762..9ddc37300f6b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -1907,8 +1907,7 @@ static int via_build_controls(struct hda_codec *codec) | |||
1907 | /* assign Capture Source enums to NID */ | 1907 | /* assign Capture Source enums to NID */ |
1908 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | 1908 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); |
1909 | for (i = 0; kctl && i < kctl->count; i++) { | 1909 | for (i = 0; kctl && i < kctl->count; i++) { |
1910 | err = snd_hda_add_nids(codec, kctl, i, spec->mux_nids, | 1910 | err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); |
1911 | spec->input_mux->num_items); | ||
1912 | if (err < 0) | 1911 | if (err < 0) |
1913 | return err; | 1912 | return err; |
1914 | } | 1913 | } |