aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-31 18:38:09 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-31 18:38:09 -0500
commit14864a52cd8189e8567df8351d9fc7e435133abd (patch)
tree2cc4548e503d36c56311ef9e1d1d644238e917ec
parent4e13c5d0212f25d69a97606b9d5a85edb52a7737 (diff)
parent75fae117a5dbde5ab984fa5c60705758cfbc6433 (diff)
Merge tag 'sound-fix-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai: "The big chunks here are the updates for oxygen driver for Xonar DG devices, which were slipped from the previous pull request. They are device-specific and thus not too dangerous. Other than that, all patches are small bug fixes, mainly for Samsung build fixes, a few HD-audio enhancements, and other misc ASoC fixes. (And this time ASoC merge is less than Octopus, lucky seven :)" * tag 'sound-fix-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (42 commits) ALSA: hda/hdmi - allow PIN_OUT to be dynamically enabled ALSA: hda - add headset mic detect quirks for another Dell laptop ALSA: oxygen: Xonar DG(X): cleanup and minor changes ALSA: oxygen: Xonar DG(X): modify high-pass filter control ALSA: oxygen: Xonar DG(X): modify input select functions ALSA: oxygen: Xonar DG(X): modify capture volume functions ALSA: oxygen: Xonar DG(X): use headphone volume control ALSA: oxygen: Xonar DG(X): modify playback output select ALSA: oxygen: Xonar DG(X): capture from I2S channel 1, not 2 ALSA: oxygen: Xonar DG(X): move the mixer code into another file ALSA: oxygen: modify CS4245 register dumping function ALSA: oxygen: modify adjust_dg_dac_routing function ALSA: oxygen: Xonar DG(X): modify DAC/ADC parameters function ALSA: oxygen: Xonar DG(X): modify initialization functions ALSA: oxygen: Xonar DG(X): add new CS4245 SPI functions ALSA: oxygen: additional definitions for the Xonar DG/DGX card ALSA: oxygen: change description of the xonar_dg.c file ALSA: oxygen: export oxygen_update_dac_routing symbol ALSA: oxygen: add mute mask for the OXYGEN_PLAY_ROUTING register ALSA: oxygen: modify the SPI writing function ...
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt2
-rw-r--r--sound/core/init.c57
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c1
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_proc.c34
-rw-r--r--sound/pci/hda/patch_hdmi.c40
-rw-r--r--sound/pci/hda/patch_realtek.c34
-rw-r--r--sound/pci/oxygen/Makefile2
-rw-r--r--sound/pci/oxygen/cs4245.h7
-rw-r--r--sound/pci/oxygen/oxygen.h2
-rw-r--r--sound/pci/oxygen/oxygen_io.c25
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c1
-rw-r--r--sound/pci/oxygen/oxygen_regs.h1
-rw-r--r--sound/pci/oxygen/xonar_dg.c651
-rw-r--r--sound/pci/oxygen/xonar_dg.h48
-rw-r--r--sound/pci/oxygen/xonar_dg_mixer.c477
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c28
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h3
-rw-r--r--sound/soc/codecs/wm5100.c2
-rw-r--r--sound/soc/codecs/wm5110.c48
-rw-r--r--sound/soc/fsl/fsl_ssi.c9
-rw-r--r--sound/soc/omap/Kconfig1
-rw-r--r--sound/soc/samsung/Kconfig4
-rw-r--r--sound/soc/samsung/h1940_uda1380.c1
-rw-r--r--sound/soc/samsung/i2s.c5
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c1
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c1
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c6
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c2
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c2
-rw-r--r--sound/soc/samsung/smartq_wm8987.c1
-rw-r--r--sound/soc/samsung/smdk_wm8994.c4
32 files changed, 935 insertions, 566 deletions
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index e9e20ec67d62..19c84df5fffa 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -43,7 +43,7 @@ Example:
43sound { 43sound {
44 compatible = "simple-audio-card"; 44 compatible = "simple-audio-card";
45 simple-audio-card,format = "left_j"; 45 simple-audio-card,format = "left_j";
46 simple-audio-routing = 46 simple-audio-card,routing =
47 "MIC_IN", "Mic Jack", 47 "MIC_IN", "Mic Jack",
48 "Headphone Jack", "HP_OUT", 48 "Headphone Jack", "HP_OUT",
49 "Ext Spk", "LINE_OUT"; 49 "Ext Spk", "LINE_OUT";
diff --git a/sound/core/init.c b/sound/core/init.c
index 1351f22f651c..0d42fcda0de2 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -131,6 +131,31 @@ static inline int init_info_for_card(struct snd_card *card)
131#define init_info_for_card(card) 131#define init_info_for_card(card)
132#endif 132#endif
133 133
134static int check_empty_slot(struct module *module, int slot)
135{
136 return !slots[slot] || !*slots[slot];
137}
138
139/* return an empty slot number (>= 0) found in the given bitmask @mask.
140 * @mask == -1 == 0xffffffff means: take any free slot up to 32
141 * when no slot is available, return the original @mask as is.
142 */
143static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
144 struct module *module)
145{
146 int slot;
147
148 for (slot = 0; slot < SNDRV_CARDS; slot++) {
149 if (slot < 32 && !(mask & (1U << slot)))
150 continue;
151 if (!test_bit(slot, snd_cards_lock)) {
152 if (check(module, slot))
153 return slot; /* found */
154 }
155 }
156 return mask; /* unchanged */
157}
158
134/** 159/**
135 * snd_card_create - create and initialize a soundcard structure 160 * snd_card_create - create and initialize a soundcard structure
136 * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] 161 * @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
@@ -152,7 +177,7 @@ int snd_card_create(int idx, const char *xid,
152 struct snd_card **card_ret) 177 struct snd_card **card_ret)
153{ 178{
154 struct snd_card *card; 179 struct snd_card *card;
155 int err, idx2; 180 int err;
156 181
157 if (snd_BUG_ON(!card_ret)) 182 if (snd_BUG_ON(!card_ret))
158 return -EINVAL; 183 return -EINVAL;
@@ -167,32 +192,10 @@ int snd_card_create(int idx, const char *xid,
167 strlcpy(card->id, xid, sizeof(card->id)); 192 strlcpy(card->id, xid, sizeof(card->id));
168 err = 0; 193 err = 0;
169 mutex_lock(&snd_card_mutex); 194 mutex_lock(&snd_card_mutex);
170 if (idx < 0) { 195 if (idx < 0) /* first check the matching module-name slot */
171 for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) { 196 idx = get_slot_from_bitmask(idx, module_slot_match, module);
172 /* idx == -1 == 0xffff means: take any free slot */ 197 if (idx < 0) /* if not matched, assign an empty slot */
173 if (idx2 < sizeof(int) && !(idx & (1U << idx2))) 198 idx = get_slot_from_bitmask(idx, check_empty_slot, module);
174 continue;
175 if (!test_bit(idx2, snd_cards_lock)) {
176 if (module_slot_match(module, idx2)) {
177 idx = idx2;
178 break;
179 }
180 }
181 }
182 }
183 if (idx < 0) {
184 for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
185 /* idx == -1 == 0xffff means: take any free slot */
186 if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
187 continue;
188 if (!test_bit(idx2, snd_cards_lock)) {
189 if (!slots[idx2] || !*slots[idx2]) {
190 idx = idx2;
191 break;
192 }
193 }
194 }
195 }
196 if (idx < 0) 199 if (idx < 0)
197 err = -ENODEV; 200 err = -ENODEV;
198 else if (idx < snd_ecards_limit) { 201 else if (idx < snd_ecards_limit) {
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index f18e5878f58b..062398ec5335 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -369,6 +369,7 @@ static void free_module_desc(struct dsp_module_desc *module)
369 kfree(module->segments[i].data); 369 kfree(module->segments[i].data);
370 kfree(module->segments); 370 kfree(module->segments);
371 } 371 }
372 kfree(module);
372} 373}
373 374
374/* firmware binary format: 375/* firmware binary format:
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 2b5d19e48a27..ab2a444ba501 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -361,6 +361,7 @@ struct hda_codec {
361 unsigned int epss:1; /* supporting EPSS? */ 361 unsigned int epss:1; /* supporting EPSS? */
362 unsigned int cached_write:1; /* write only to caches */ 362 unsigned int cached_write:1; /* write only to caches */
363 unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ 363 unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
364 unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
364#ifdef CONFIG_PM 365#ifdef CONFIG_PM
365 unsigned int power_on :1; /* current (global) power-state */ 366 unsigned int power_on :1; /* current (global) power-state */
366 unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ 367 unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index a8cb22eec89e..ce5a6da83419 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -24,9 +24,14 @@
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <sound/core.h> 26#include <sound/core.h>
27#include <linux/module.h>
27#include "hda_codec.h" 28#include "hda_codec.h"
28#include "hda_local.h" 29#include "hda_local.h"
29 30
31static int dump_coef = -1;
32module_param(dump_coef, int, 0644);
33MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1=auto, 0=disable, 1=enable)");
34
30static char *bits_names(unsigned int bits, char *names[], int size) 35static char *bits_names(unsigned int bits, char *names[], int size)
31{ 36{
32 int i, n; 37 int i, n;
@@ -488,14 +493,39 @@ static void print_unsol_cap(struct snd_info_buffer *buffer,
488 (unsol & AC_UNSOL_ENABLED) ? 1 : 0); 493 (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
489} 494}
490 495
496static inline bool can_dump_coef(struct hda_codec *codec)
497{
498 switch (dump_coef) {
499 case 0: return false;
500 case 1: return true;
501 default: return codec->dump_coef;
502 }
503}
504
491static void print_proc_caps(struct snd_info_buffer *buffer, 505static void print_proc_caps(struct snd_info_buffer *buffer,
492 struct hda_codec *codec, hda_nid_t nid) 506 struct hda_codec *codec, hda_nid_t nid)
493{ 507{
508 unsigned int i, ncoeff, oldindex;
494 unsigned int proc_caps = snd_hda_param_read(codec, nid, 509 unsigned int proc_caps = snd_hda_param_read(codec, nid,
495 AC_PAR_PROC_CAP); 510 AC_PAR_PROC_CAP);
511 ncoeff = (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT;
496 snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n", 512 snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n",
497 proc_caps & AC_PCAP_BENIGN, 513 proc_caps & AC_PCAP_BENIGN, ncoeff);
498 (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT); 514
515 if (!can_dump_coef(codec))
516 return;
517
518 /* Note: This is racy - another process could run in parallel and change
519 the coef index too. */
520 oldindex = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_COEF_INDEX, 0);
521 for (i = 0; i < ncoeff; i++) {
522 unsigned int val;
523 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, i);
524 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF,
525 0);
526 snd_iprintf(buffer, " Coeff 0x%02x: 0x%04x\n", i, val);
527 }
528 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, oldindex);
499} 529}
500 530
501static void print_conn_list(struct snd_info_buffer *buffer, 531static void print_conn_list(struct snd_info_buffer *buffer,
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 64f0a5e73a25..5ef95034d041 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -132,6 +132,9 @@ struct hdmi_spec {
132 132
133 struct hdmi_eld temp_eld; 133 struct hdmi_eld temp_eld;
134 struct hdmi_ops ops; 134 struct hdmi_ops ops;
135
136 bool dyn_pin_out;
137
135 /* 138 /*
136 * Non-generic VIA/NVIDIA specific 139 * Non-generic VIA/NVIDIA specific
137 */ 140 */
@@ -500,15 +503,25 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
500 503
501static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) 504static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
502{ 505{
506 struct hdmi_spec *spec = codec->spec;
507 int pin_out;
508
503 /* Unmute */ 509 /* Unmute */
504 if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) 510 if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
505 snd_hda_codec_write(codec, pin_nid, 0, 511 snd_hda_codec_write(codec, pin_nid, 0,
506 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 512 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
507 /* Enable pin out: some machines with GM965 gets broken output when 513
508 * the pin is disabled or changed while using with HDMI 514 if (spec->dyn_pin_out)
509 */ 515 /* Disable pin out until stream is active */
516 pin_out = 0;
517 else
518 /* Enable pin out: some machines with GM965 gets broken output
519 * when the pin is disabled or changed while using with HDMI
520 */
521 pin_out = PIN_OUT;
522
510 snd_hda_codec_write(codec, pin_nid, 0, 523 snd_hda_codec_write(codec, pin_nid, 0,
511 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 524 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
512} 525}
513 526
514static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) 527static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
@@ -1735,6 +1748,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1735 struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); 1748 struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
1736 hda_nid_t pin_nid = per_pin->pin_nid; 1749 hda_nid_t pin_nid = per_pin->pin_nid;
1737 bool non_pcm; 1750 bool non_pcm;
1751 int pinctl;
1738 1752
1739 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); 1753 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
1740 mutex_lock(&per_pin->lock); 1754 mutex_lock(&per_pin->lock);
@@ -1744,6 +1758,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1744 hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); 1758 hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
1745 mutex_unlock(&per_pin->lock); 1759 mutex_unlock(&per_pin->lock);
1746 1760
1761 if (spec->dyn_pin_out) {
1762 pinctl = snd_hda_codec_read(codec, pin_nid, 0,
1763 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1764 snd_hda_codec_write(codec, pin_nid, 0,
1765 AC_VERB_SET_PIN_WIDGET_CONTROL,
1766 pinctl | PIN_OUT);
1767 }
1768
1747 return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); 1769 return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
1748} 1770}
1749 1771
@@ -1763,6 +1785,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
1763 int cvt_idx, pin_idx; 1785 int cvt_idx, pin_idx;
1764 struct hdmi_spec_per_cvt *per_cvt; 1786 struct hdmi_spec_per_cvt *per_cvt;
1765 struct hdmi_spec_per_pin *per_pin; 1787 struct hdmi_spec_per_pin *per_pin;
1788 int pinctl;
1766 1789
1767 if (hinfo->nid) { 1790 if (hinfo->nid) {
1768 cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); 1791 cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
@@ -1779,6 +1802,14 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
1779 return -EINVAL; 1802 return -EINVAL;
1780 per_pin = get_pin(spec, pin_idx); 1803 per_pin = get_pin(spec, pin_idx);
1781 1804
1805 if (spec->dyn_pin_out) {
1806 pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
1807 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1808 snd_hda_codec_write(codec, per_pin->pin_nid, 0,
1809 AC_VERB_SET_PIN_WIDGET_CONTROL,
1810 pinctl & ~PIN_OUT);
1811 }
1812
1782 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1813 snd_hda_spdif_ctls_unassign(codec, pin_idx);
1783 1814
1784 mutex_lock(&per_pin->lock); 1815 mutex_lock(&per_pin->lock);
@@ -2840,6 +2871,7 @@ static int patch_nvhdmi(struct hda_codec *codec)
2840 return err; 2871 return err;
2841 2872
2842 spec = codec->spec; 2873 spec = codec->spec;
2874 spec->dyn_pin_out = true;
2843 2875
2844 spec->ops.chmap_cea_alloc_validate_get_type = 2876 spec->ops.chmap_cea_alloc_validate_get_type =
2845 nvhdmi_chmap_cea_alloc_validate_get_type; 2877 nvhdmi_chmap_cea_alloc_validate_get_type;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f9b22fb6dd0b..56a8f1876603 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1819,6 +1819,7 @@ enum {
1819 ALC889_FIXUP_DAC_ROUTE, 1819 ALC889_FIXUP_DAC_ROUTE,
1820 ALC889_FIXUP_MBP_VREF, 1820 ALC889_FIXUP_MBP_VREF,
1821 ALC889_FIXUP_IMAC91_VREF, 1821 ALC889_FIXUP_IMAC91_VREF,
1822 ALC889_FIXUP_MBA11_VREF,
1822 ALC889_FIXUP_MBA21_VREF, 1823 ALC889_FIXUP_MBA21_VREF,
1823 ALC882_FIXUP_INV_DMIC, 1824 ALC882_FIXUP_INV_DMIC,
1824 ALC882_FIXUP_NO_PRIMARY_HP, 1825 ALC882_FIXUP_NO_PRIMARY_HP,
@@ -1949,6 +1950,16 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec,
1949 alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); 1950 alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
1950} 1951}
1951 1952
1953/* Set VREF on speaker pins on mba11 */
1954static void alc889_fixup_mba11_vref(struct hda_codec *codec,
1955 const struct hda_fixup *fix, int action)
1956{
1957 static hda_nid_t nids[1] = { 0x18 };
1958
1959 if (action == HDA_FIXUP_ACT_INIT)
1960 alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
1961}
1962
1952/* Set VREF on speaker pins on mba21 */ 1963/* Set VREF on speaker pins on mba21 */
1953static void alc889_fixup_mba21_vref(struct hda_codec *codec, 1964static void alc889_fixup_mba21_vref(struct hda_codec *codec,
1954 const struct hda_fixup *fix, int action) 1965 const struct hda_fixup *fix, int action)
@@ -2167,6 +2178,12 @@ static const struct hda_fixup alc882_fixups[] = {
2167 .chained = true, 2178 .chained = true,
2168 .chain_id = ALC882_FIXUP_GPIO1, 2179 .chain_id = ALC882_FIXUP_GPIO1,
2169 }, 2180 },
2181 [ALC889_FIXUP_MBA11_VREF] = {
2182 .type = HDA_FIXUP_FUNC,
2183 .v.func = alc889_fixup_mba11_vref,
2184 .chained = true,
2185 .chain_id = ALC889_FIXUP_MBP_VREF,
2186 },
2170 [ALC889_FIXUP_MBA21_VREF] = { 2187 [ALC889_FIXUP_MBA21_VREF] = {
2171 .type = HDA_FIXUP_FUNC, 2188 .type = HDA_FIXUP_FUNC,
2172 .v.func = alc889_fixup_mba21_vref, 2189 .v.func = alc889_fixup_mba21_vref,
@@ -2242,7 +2259,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
2242 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), 2259 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
2243 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF), 2260 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
2244 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), 2261 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
2245 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF), 2262 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
2246 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF), 2263 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
2247 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF), 2264 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
2248 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), 2265 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
@@ -3833,6 +3850,7 @@ enum {
3833 ALC269_FIXUP_ACER_AC700, 3850 ALC269_FIXUP_ACER_AC700,
3834 ALC269_FIXUP_LIMIT_INT_MIC_BOOST, 3851 ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
3835 ALC269VB_FIXUP_ASUS_ZENBOOK, 3852 ALC269VB_FIXUP_ASUS_ZENBOOK,
3853 ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A,
3836 ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED, 3854 ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED,
3837 ALC269VB_FIXUP_ORDISSIMO_EVE2, 3855 ALC269VB_FIXUP_ORDISSIMO_EVE2,
3838 ALC283_FIXUP_CHROME_BOOK, 3856 ALC283_FIXUP_CHROME_BOOK,
@@ -4126,6 +4144,17 @@ static const struct hda_fixup alc269_fixups[] = {
4126 .chained = true, 4144 .chained = true,
4127 .chain_id = ALC269VB_FIXUP_DMIC, 4145 .chain_id = ALC269VB_FIXUP_DMIC,
4128 }, 4146 },
4147 [ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A] = {
4148 .type = HDA_FIXUP_VERBS,
4149 .v.verbs = (const struct hda_verb[]) {
4150 /* class-D output amp +5dB */
4151 { 0x20, AC_VERB_SET_COEF_INDEX, 0x12 },
4152 { 0x20, AC_VERB_SET_PROC_COEF, 0x2800 },
4153 {}
4154 },
4155 .chained = true,
4156 .chain_id = ALC269VB_FIXUP_ASUS_ZENBOOK,
4157 },
4129 [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = { 4158 [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = {
4130 .type = HDA_FIXUP_FUNC, 4159 .type = HDA_FIXUP_FUNC,
4131 .v.func = alc269_fixup_limit_int_mic_boost, 4160 .v.func = alc269_fixup_limit_int_mic_boost,
@@ -4265,6 +4294,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
4265 SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), 4294 SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
4266 SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), 4295 SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
4267 SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), 4296 SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
4297 SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
4268 SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), 4298 SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
4269 SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), 4299 SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
4270 SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), 4300 SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -4282,7 +4312,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
4282 SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), 4312 SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
4283 SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), 4313 SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
4284 SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), 4314 SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
4285 SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK), 4315 SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
4286 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), 4316 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
4287 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), 4317 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
4288 SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), 4318 SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index 0f8726551fde..8f4c409f7e45 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,5 +1,5 @@
1snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o 1snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
2snd-oxygen-objs := oxygen.o xonar_dg.o 2snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
3snd-virtuoso-objs := virtuoso.o xonar_lib.o \ 3snd-virtuoso-objs := virtuoso.o xonar_lib.o \
4 xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o 4 xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
5 5
diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h
index 5e0197e07dd1..99098657695a 100644
--- a/sound/pci/oxygen/cs4245.h
+++ b/sound/pci/oxygen/cs4245.h
@@ -102,6 +102,9 @@
102#define CS4245_ADC_OVFL 0x02 102#define CS4245_ADC_OVFL 0x02
103#define CS4245_ADC_UNDRFL 0x01 103#define CS4245_ADC_UNDRFL 0x01
104 104
105#define CS4245_SPI_ADDRESS_S (0x9e << 16)
106#define CS4245_SPI_WRITE_S (0 << 16)
105 107
106#define CS4245_SPI_ADDRESS (0x9e << 16) 108#define CS4245_SPI_ADDRESS 0x9e
107#define CS4245_SPI_WRITE (0 << 16) 109#define CS4245_SPI_WRITE 0
110#define CS4245_SPI_READ 1
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 09a24b24958b..c10ab077afd8 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -198,7 +198,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
198void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, 198void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
199 unsigned int index, u16 data, u16 mask); 199 unsigned int index, u16 data, u16 mask);
200 200
201void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); 201int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
202void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data); 202void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
203 203
204void oxygen_reset_uart(struct oxygen *chip); 204void oxygen_reset_uart(struct oxygen *chip);
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 521eae458348..3274907189fe 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -194,23 +194,36 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
194} 194}
195EXPORT_SYMBOL(oxygen_write_ac97_masked); 195EXPORT_SYMBOL(oxygen_write_ac97_masked);
196 196
197void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) 197static int oxygen_wait_spi(struct oxygen *chip)
198{ 198{
199 unsigned int count; 199 unsigned int count;
200 200
201 /* should not need more than 30.72 us (24 * 1.28 us) */ 201 /*
202 count = 10; 202 * Higher timeout to be sure: 200 us;
203 while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) 203 * actual transaction should not need more than 40 us.
204 && count > 0) { 204 */
205 for (count = 50; count > 0; count--) {
205 udelay(4); 206 udelay(4);
206 --count; 207 if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
208 OXYGEN_SPI_BUSY) == 0)
209 return 0;
207 } 210 }
211 snd_printk(KERN_ERR "oxygen: SPI wait timeout\n");
212 return -EIO;
213}
208 214
215int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
216{
217 /*
218 * We need to wait AFTER initiating the SPI transaction,
219 * otherwise read operations will not work.
220 */
209 oxygen_write8(chip, OXYGEN_SPI_DATA1, data); 221 oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
210 oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8); 222 oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
211 if (control & OXYGEN_SPI_DATA_LENGTH_3) 223 if (control & OXYGEN_SPI_DATA_LENGTH_3)
212 oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16); 224 oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
213 oxygen_write8(chip, OXYGEN_SPI_CONTROL, control); 225 oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
226 return oxygen_wait_spi(chip);
214} 227}
215EXPORT_SYMBOL(oxygen_write_spi); 228EXPORT_SYMBOL(oxygen_write_spi);
216 229
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index c0dbb52d45be..5988e044c519 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -190,6 +190,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
190 if (chip->model.update_center_lfe_mix) 190 if (chip->model.update_center_lfe_mix)
191 chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2); 191 chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
192} 192}
193EXPORT_SYMBOL(oxygen_update_dac_routing);
193 194
194static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 195static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
195{ 196{
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 63dc7a0ab555..8c191badaae8 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -318,6 +318,7 @@
318#define OXYGEN_PLAY_MUTE23 0x0002 318#define OXYGEN_PLAY_MUTE23 0x0002
319#define OXYGEN_PLAY_MUTE45 0x0004 319#define OXYGEN_PLAY_MUTE45 0x0004
320#define OXYGEN_PLAY_MUTE67 0x0008 320#define OXYGEN_PLAY_MUTE67 0x0008
321#define OXYGEN_PLAY_MUTE_MASK 0x000f
321#define OXYGEN_PLAY_MULTICH_MASK 0x0010 322#define OXYGEN_PLAY_MULTICH_MASK 0x0010
322#define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000 323#define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000
323#define OXYGEN_PLAY_MULTICH_AC97 0x0010 324#define OXYGEN_PLAY_MULTICH_AC97 0x0010
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 77acd790ea47..ed6f199f8a38 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -2,7 +2,7 @@
2 * card driver for the Xonar DG/DGX 2 * card driver for the Xonar DG/DGX
3 * 3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * 5 * Copyright (c) Roman Volkov <v1ron@mail.ru>
6 * 6 *
7 * This driver is free software; you can redistribute it and/or modify 7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2. 8 * it under the terms of the GNU General Public License, version 2.
@@ -20,27 +20,35 @@
20 * Xonar DG/DGX 20 * Xonar DG/DGX
21 * ------------ 21 * ------------
22 * 22 *
23 * CS4245 and CS4361 both will mute all outputs if any clock ratio
24 * is invalid.
25 *
23 * CMI8788: 26 * CMI8788:
24 * 27 *
25 * SPI 0 -> CS4245 28 * SPI 0 -> CS4245
26 * 29 *
30 * Playback:
27 * I²S 1 -> CS4245 31 * I²S 1 -> CS4245
28 * I²S 2 -> CS4361 (center/LFE) 32 * I²S 2 -> CS4361 (center/LFE)
29 * I²S 3 -> CS4361 (surround) 33 * I²S 3 -> CS4361 (surround)
30 * I²S 4 -> CS4361 (front) 34 * I²S 4 -> CS4361 (front)
35 * Capture:
36 * I²S ADC 1 <- CS4245
31 * 37 *
32 * GPIO 3 <- ? 38 * GPIO 3 <- ?
33 * GPIO 4 <- headphone detect 39 * GPIO 4 <- headphone detect
34 * GPIO 5 -> route input jack to line-in (0) or mic-in (1) 40 * GPIO 5 -> enable ADC analog circuit for the left channel
35 * GPIO 6 -> route input jack to line-in (0) or mic-in (1) 41 * GPIO 6 -> enable ADC analog circuit for the right channel
36 * GPIO 7 -> enable rear headphone amp 42 * GPIO 7 -> switch green rear output jack between CS4245 and and the first
43 * channel of CS4361 (mechanical relay)
37 * GPIO 8 -> enable output to speakers 44 * GPIO 8 -> enable output to speakers
38 * 45 *
39 * CS4245: 46 * CS4245:
40 * 47 *
48 * input 0 <- mic
41 * input 1 <- aux 49 * input 1 <- aux
42 * input 2 <- front mic 50 * input 2 <- front mic
43 * input 4 <- line/mic 51 * input 4 <- line
44 * DAC out -> headphones 52 * DAC out -> headphones
45 * aux out -> front panel headphones 53 * aux out -> front panel headphones
46 */ 54 */
@@ -56,553 +64,214 @@
56#include "xonar_dg.h" 64#include "xonar_dg.h"
57#include "cs4245.h" 65#include "cs4245.h"
58 66
59#define GPIO_MAGIC 0x0008 67int cs4245_write_spi(struct oxygen *chip, u8 reg)
60#define GPIO_HP_DETECT 0x0010
61#define GPIO_INPUT_ROUTE 0x0060
62#define GPIO_HP_REAR 0x0080
63#define GPIO_OUTPUT_ENABLE 0x0100
64
65struct dg {
66 unsigned int output_sel;
67 s8 input_vol[4][2];
68 unsigned int input_sel;
69 u8 hp_vol_att;
70 u8 cs4245_regs[0x11];
71};
72
73static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
74{ 68{
75 struct dg *data = chip->model_data; 69 struct dg *data = chip->model_data;
70 unsigned int packet;
76 71
77 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 72 packet = reg << 8;
78 OXYGEN_SPI_DATA_LENGTH_3 | 73 packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16;
79 OXYGEN_SPI_CLOCK_1280 | 74 packet |= data->cs4245_shadow[reg];
80 (0 << OXYGEN_SPI_CODEC_SHIFT) | 75
81 OXYGEN_SPI_CEN_LATCH_CLOCK_HI, 76 return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
82 CS4245_SPI_ADDRESS | 77 OXYGEN_SPI_DATA_LENGTH_3 |
83 CS4245_SPI_WRITE | 78 OXYGEN_SPI_CLOCK_1280 |
84 (reg << 8) | value); 79 (0 << OXYGEN_SPI_CODEC_SHIFT) |
85 data->cs4245_regs[reg] = value; 80 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
81 packet);
86} 82}
87 83
88static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) 84int cs4245_read_spi(struct oxygen *chip, u8 addr)
89{ 85{
90 struct dg *data = chip->model_data; 86 struct dg *data = chip->model_data;
87 int ret;
88
89 ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
90 OXYGEN_SPI_DATA_LENGTH_2 |
91 OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
92 OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
93 ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr);
94 if (ret < 0)
95 return ret;
96
97 ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
98 OXYGEN_SPI_DATA_LENGTH_2 |
99 OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
100 OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
101 (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
102 if (ret < 0)
103 return ret;
104
105 data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
91 106
92 if (value != data->cs4245_regs[reg]) 107 return 0;
93 cs4245_write(chip, reg, value);
94} 108}
95 109
96static void cs4245_registers_init(struct oxygen *chip) 110int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
97{ 111{
98 struct dg *data = chip->model_data; 112 struct dg *data = chip->model_data;
99 113 unsigned char addr;
100 cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN); 114 int ret;
101 cs4245_write(chip, CS4245_DAC_CTRL_1, 115
102 data->cs4245_regs[CS4245_DAC_CTRL_1]); 116 for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) {
103 cs4245_write(chip, CS4245_ADC_CTRL, 117 ret = (op == CS4245_SAVE_TO_SHADOW ?
104 data->cs4245_regs[CS4245_ADC_CTRL]); 118 cs4245_read_spi(chip, addr) :
105 cs4245_write(chip, CS4245_SIGNAL_SEL, 119 cs4245_write_spi(chip, addr));
106 data->cs4245_regs[CS4245_SIGNAL_SEL]); 120 if (ret < 0)
107 cs4245_write(chip, CS4245_PGA_B_CTRL, 121 return ret;
108 data->cs4245_regs[CS4245_PGA_B_CTRL]); 122 }
109 cs4245_write(chip, CS4245_PGA_A_CTRL, 123 return 0;
110 data->cs4245_regs[CS4245_PGA_A_CTRL]);
111 cs4245_write(chip, CS4245_ANALOG_IN,
112 data->cs4245_regs[CS4245_ANALOG_IN]);
113 cs4245_write(chip, CS4245_DAC_A_CTRL,
114 data->cs4245_regs[CS4245_DAC_A_CTRL]);
115 cs4245_write(chip, CS4245_DAC_B_CTRL,
116 data->cs4245_regs[CS4245_DAC_B_CTRL]);
117 cs4245_write(chip, CS4245_DAC_CTRL_2,
118 CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
119 cs4245_write(chip, CS4245_INT_MASK, 0);
120 cs4245_write(chip, CS4245_POWER_CTRL, 0);
121} 124}
122 125
123static void cs4245_init(struct oxygen *chip) 126static void cs4245_init(struct oxygen *chip)
124{ 127{
125 struct dg *data = chip->model_data; 128 struct dg *data = chip->model_data;
126 129
127 data->cs4245_regs[CS4245_DAC_CTRL_1] = 130 /* save the initial state: codec version, registers */
131 cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
132
133 /*
134 * Power up the CODEC internals, enable soft ramp & zero cross, work in
135 * async. mode, enable aux output from DAC. Invert DAC output as in the
136 * Windows driver.
137 */
138 data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
139 data->cs4245_shadow[CS4245_SIGNAL_SEL] =
140 CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH;
141 data->cs4245_shadow[CS4245_DAC_CTRL_1] =
128 CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST; 142 CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
129 data->cs4245_regs[CS4245_ADC_CTRL] = 143 data->cs4245_shadow[CS4245_DAC_CTRL_2] =
144 CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC;
145 data->cs4245_shadow[CS4245_ADC_CTRL] =
130 CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST; 146 CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
131 data->cs4245_regs[CS4245_SIGNAL_SEL] = 147 data->cs4245_shadow[CS4245_ANALOG_IN] =
132 CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH; 148 CS4245_PGA_SOFT | CS4245_PGA_ZERO;
133 data->cs4245_regs[CS4245_PGA_B_CTRL] = 0; 149 data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0;
134 data->cs4245_regs[CS4245_PGA_A_CTRL] = 0; 150 data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0;
135 data->cs4245_regs[CS4245_ANALOG_IN] = 151 data->cs4245_shadow[CS4245_DAC_A_CTRL] = 8;
136 CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4; 152 data->cs4245_shadow[CS4245_DAC_B_CTRL] = 8;
137 data->cs4245_regs[CS4245_DAC_A_CTRL] = 0; 153
138 data->cs4245_regs[CS4245_DAC_B_CTRL] = 0; 154 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
139 cs4245_registers_init(chip);
140 snd_component_add(chip->card, "CS4245"); 155 snd_component_add(chip->card, "CS4245");
141} 156}
142 157
143static void dg_output_enable(struct oxygen *chip) 158void dg_init(struct oxygen *chip)
144{
145 msleep(2500);
146 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
147}
148
149static void dg_init(struct oxygen *chip)
150{ 159{
151 struct dg *data = chip->model_data; 160 struct dg *data = chip->model_data;
152 161
153 data->output_sel = 0; 162 data->output_sel = PLAYBACK_DST_HP_FP;
154 data->input_sel = 3; 163 data->input_sel = CAPTURE_SRC_MIC;
155 data->hp_vol_att = 2 * 16;
156 164
157 cs4245_init(chip); 165 cs4245_init(chip);
158 166 oxygen_write16(chip, OXYGEN_GPIO_CONTROL,
159 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, 167 GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE);
160 GPIO_MAGIC | GPIO_HP_DETECT); 168 /* anti-pop delay, wait some time before enabling the output */
161 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 169 msleep(2500);
162 GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE); 170 oxygen_write16(chip, OXYGEN_GPIO_DATA,
163 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, 171 GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE);
164 GPIO_INPUT_ROUTE | GPIO_HP_REAR);
165 dg_output_enable(chip);
166} 172}
167 173
168static void dg_cleanup(struct oxygen *chip) 174void dg_cleanup(struct oxygen *chip)
169{ 175{
170 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 176 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
171} 177}
172 178
173static void dg_suspend(struct oxygen *chip) 179void dg_suspend(struct oxygen *chip)
174{ 180{
175 dg_cleanup(chip); 181 dg_cleanup(chip);
176} 182}
177 183
178static void dg_resume(struct oxygen *chip) 184void dg_resume(struct oxygen *chip)
179{ 185{
180 cs4245_registers_init(chip); 186 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
181 dg_output_enable(chip); 187 msleep(2500);
182} 188 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
183
184static void set_cs4245_dac_params(struct oxygen *chip,
185 struct snd_pcm_hw_params *params)
186{
187 struct dg *data = chip->model_data;
188 u8 value;
189
190 value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
191 if (params_rate(params) <= 50000)
192 value |= CS4245_DAC_FM_SINGLE;
193 else if (params_rate(params) <= 100000)
194 value |= CS4245_DAC_FM_DOUBLE;
195 else
196 value |= CS4245_DAC_FM_QUAD;
197 cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
198} 189}
199 190
200static void set_cs4245_adc_params(struct oxygen *chip, 191void set_cs4245_dac_params(struct oxygen *chip,
201 struct snd_pcm_hw_params *params) 192 struct snd_pcm_hw_params *params)
202{ 193{
203 struct dg *data = chip->model_data; 194 struct dg *data = chip->model_data;
204 u8 value; 195 unsigned char dac_ctrl;
205 196 unsigned char mclk_freq;
206 value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; 197
207 if (params_rate(params) <= 50000) 198 dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
208 value |= CS4245_ADC_FM_SINGLE; 199 mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
209 else if (params_rate(params) <= 100000) 200 if (params_rate(params) <= 50000) {
210 value |= CS4245_ADC_FM_DOUBLE; 201 dac_ctrl |= CS4245_DAC_FM_SINGLE;
211 else 202 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
212 value |= CS4245_ADC_FM_QUAD; 203 } else if (params_rate(params) <= 100000) {
213 cs4245_write_cached(chip, CS4245_ADC_CTRL, value); 204 dac_ctrl |= CS4245_DAC_FM_DOUBLE;
214} 205 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
215 206 } else {
216static inline unsigned int shift_bits(unsigned int value, 207 dac_ctrl |= CS4245_DAC_FM_QUAD;
217 unsigned int shift_from, 208 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
218 unsigned int shift_to,
219 unsigned int mask)
220{
221 if (shift_from < shift_to)
222 return (value << (shift_to - shift_from)) & mask;
223 else
224 return (value >> (shift_from - shift_to)) & mask;
225}
226
227static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
228 unsigned int play_routing)
229{
230 return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
231 shift_bits(play_routing,
232 OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
233 OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
234 OXYGEN_PLAY_DAC1_SOURCE_MASK) |
235 shift_bits(play_routing,
236 OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
237 OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
238 OXYGEN_PLAY_DAC2_SOURCE_MASK) |
239 shift_bits(play_routing,
240 OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
241 OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
242 OXYGEN_PLAY_DAC3_SOURCE_MASK);
243}
244
245static int output_switch_info(struct snd_kcontrol *ctl,
246 struct snd_ctl_elem_info *info)
247{
248 static const char *const names[3] = {
249 "Speakers", "Headphones", "FP Headphones"
250 };
251
252 return snd_ctl_enum_info(info, 1, 3, names);
253}
254
255static int output_switch_get(struct snd_kcontrol *ctl,
256 struct snd_ctl_elem_value *value)
257{
258 struct oxygen *chip = ctl->private_data;
259 struct dg *data = chip->model_data;
260
261 mutex_lock(&chip->mutex);
262 value->value.enumerated.item[0] = data->output_sel;
263 mutex_unlock(&chip->mutex);
264 return 0;
265}
266
267static int output_switch_put(struct snd_kcontrol *ctl,
268 struct snd_ctl_elem_value *value)
269{
270 struct oxygen *chip = ctl->private_data;
271 struct dg *data = chip->model_data;
272 u8 reg;
273 int changed;
274
275 if (value->value.enumerated.item[0] > 2)
276 return -EINVAL;
277
278 mutex_lock(&chip->mutex);
279 changed = value->value.enumerated.item[0] != data->output_sel;
280 if (changed) {
281 data->output_sel = value->value.enumerated.item[0];
282
283 reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
284 ~CS4245_A_OUT_SEL_MASK;
285 reg |= data->output_sel == 2 ?
286 CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
287 cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
288
289 cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
290 data->output_sel ? data->hp_vol_att : 0);
291 cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
292 data->output_sel ? data->hp_vol_att : 0);
293
294 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
295 data->output_sel == 1 ? GPIO_HP_REAR : 0,
296 GPIO_HP_REAR);
297 }
298 mutex_unlock(&chip->mutex);
299 return changed;
300}
301
302static int hp_volume_offset_info(struct snd_kcontrol *ctl,
303 struct snd_ctl_elem_info *info)
304{
305 static const char *const names[3] = {
306 "< 64 ohms", "64-150 ohms", "150-300 ohms"
307 };
308
309 return snd_ctl_enum_info(info, 1, 3, names);
310}
311
312static int hp_volume_offset_get(struct snd_kcontrol *ctl,
313 struct snd_ctl_elem_value *value)
314{
315 struct oxygen *chip = ctl->private_data;
316 struct dg *data = chip->model_data;
317
318 mutex_lock(&chip->mutex);
319 if (data->hp_vol_att > 2 * 7)
320 value->value.enumerated.item[0] = 0;
321 else if (data->hp_vol_att > 0)
322 value->value.enumerated.item[0] = 1;
323 else
324 value->value.enumerated.item[0] = 2;
325 mutex_unlock(&chip->mutex);
326 return 0;
327}
328
329static int hp_volume_offset_put(struct snd_kcontrol *ctl,
330 struct snd_ctl_elem_value *value)
331{
332 static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
333 struct oxygen *chip = ctl->private_data;
334 struct dg *data = chip->model_data;
335 s8 att;
336 int changed;
337
338 if (value->value.enumerated.item[0] > 2)
339 return -EINVAL;
340 att = atts[value->value.enumerated.item[0]];
341 mutex_lock(&chip->mutex);
342 changed = att != data->hp_vol_att;
343 if (changed) {
344 data->hp_vol_att = att;
345 if (data->output_sel) {
346 cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
347 cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
348 }
349 } 209 }
350 mutex_unlock(&chip->mutex); 210 data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl;
351 return changed; 211 data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
352} 212 cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
353 213 cs4245_write_spi(chip, CS4245_MCLK_FREQ);
354static int input_vol_info(struct snd_kcontrol *ctl,
355 struct snd_ctl_elem_info *info)
356{
357 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
358 info->count = 2;
359 info->value.integer.min = 2 * -12;
360 info->value.integer.max = 2 * 12;
361 return 0;
362}
363
364static int input_vol_get(struct snd_kcontrol *ctl,
365 struct snd_ctl_elem_value *value)
366{
367 struct oxygen *chip = ctl->private_data;
368 struct dg *data = chip->model_data;
369 unsigned int idx = ctl->private_value;
370
371 mutex_lock(&chip->mutex);
372 value->value.integer.value[0] = data->input_vol[idx][0];
373 value->value.integer.value[1] = data->input_vol[idx][1];
374 mutex_unlock(&chip->mutex);
375 return 0;
376}
377
378static int input_vol_put(struct snd_kcontrol *ctl,
379 struct snd_ctl_elem_value *value)
380{
381 struct oxygen *chip = ctl->private_data;
382 struct dg *data = chip->model_data;
383 unsigned int idx = ctl->private_value;
384 int changed = 0;
385
386 if (value->value.integer.value[0] < 2 * -12 ||
387 value->value.integer.value[0] > 2 * 12 ||
388 value->value.integer.value[1] < 2 * -12 ||
389 value->value.integer.value[1] > 2 * 12)
390 return -EINVAL;
391 mutex_lock(&chip->mutex);
392 changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
393 data->input_vol[idx][1] != value->value.integer.value[1];
394 if (changed) {
395 data->input_vol[idx][0] = value->value.integer.value[0];
396 data->input_vol[idx][1] = value->value.integer.value[1];
397 if (idx == data->input_sel) {
398 cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
399 data->input_vol[idx][0]);
400 cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
401 data->input_vol[idx][1]);
402 }
403 }
404 mutex_unlock(&chip->mutex);
405 return changed;
406}
407
408static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
409
410static int input_sel_info(struct snd_kcontrol *ctl,
411 struct snd_ctl_elem_info *info)
412{
413 static const char *const names[4] = {
414 "Mic", "Aux", "Front Mic", "Line"
415 };
416
417 return snd_ctl_enum_info(info, 1, 4, names);
418}
419
420static int input_sel_get(struct snd_kcontrol *ctl,
421 struct snd_ctl_elem_value *value)
422{
423 struct oxygen *chip = ctl->private_data;
424 struct dg *data = chip->model_data;
425
426 mutex_lock(&chip->mutex);
427 value->value.enumerated.item[0] = data->input_sel;
428 mutex_unlock(&chip->mutex);
429 return 0;
430} 214}
431 215
432static int input_sel_put(struct snd_kcontrol *ctl, 216void set_cs4245_adc_params(struct oxygen *chip,
433 struct snd_ctl_elem_value *value) 217 struct snd_pcm_hw_params *params)
434{ 218{
435 static const u8 sel_values[4] = {
436 CS4245_SEL_MIC,
437 CS4245_SEL_INPUT_1,
438 CS4245_SEL_INPUT_2,
439 CS4245_SEL_INPUT_4
440 };
441 struct oxygen *chip = ctl->private_data;
442 struct dg *data = chip->model_data; 219 struct dg *data = chip->model_data;
443 int changed; 220 unsigned char adc_ctrl;
444 221 unsigned char mclk_freq;
445 if (value->value.enumerated.item[0] > 3) 222
446 return -EINVAL; 223 adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
447 224 mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
448 mutex_lock(&chip->mutex); 225 if (params_rate(params) <= 50000) {
449 changed = value->value.enumerated.item[0] != data->input_sel; 226 adc_ctrl |= CS4245_ADC_FM_SINGLE;
450 if (changed) { 227 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
451 data->input_sel = value->value.enumerated.item[0]; 228 } else if (params_rate(params) <= 100000) {
452 229 adc_ctrl |= CS4245_ADC_FM_DOUBLE;
453 cs4245_write(chip, CS4245_ANALOG_IN, 230 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
454 (data->cs4245_regs[CS4245_ANALOG_IN] & 231 } else {
455 ~CS4245_SEL_MASK) | 232 adc_ctrl |= CS4245_ADC_FM_QUAD;
456 sel_values[data->input_sel]); 233 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
457
458 cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
459 data->input_vol[data->input_sel][0]);
460 cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
461 data->input_vol[data->input_sel][1]);
462
463 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
464 data->input_sel ? 0 : GPIO_INPUT_ROUTE,
465 GPIO_INPUT_ROUTE);
466 } 234 }
467 mutex_unlock(&chip->mutex); 235 data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl;
468 return changed; 236 data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
469} 237 cs4245_write_spi(chip, CS4245_ADC_CTRL);
470 238 cs4245_write_spi(chip, CS4245_MCLK_FREQ);
471static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
472{
473 static const char *const names[2] = { "Active", "Frozen" };
474
475 return snd_ctl_enum_info(info, 1, 2, names);
476} 239}
477 240
478static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 241unsigned int adjust_dg_dac_routing(struct oxygen *chip,
479{ 242 unsigned int play_routing)
480 struct oxygen *chip = ctl->private_data;
481 struct dg *data = chip->model_data;
482
483 value->value.enumerated.item[0] =
484 !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
485 return 0;
486}
487
488static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
489{ 243{
490 struct oxygen *chip = ctl->private_data;
491 struct dg *data = chip->model_data; 244 struct dg *data = chip->model_data;
492 u8 reg; 245 unsigned int routing = 0;
493 int changed; 246
494 247 switch (data->output_sel) {
495 mutex_lock(&chip->mutex); 248 case PLAYBACK_DST_HP:
496 reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 249 case PLAYBACK_DST_HP_FP:
497 if (value->value.enumerated.item[0]) 250 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
498 reg |= CS4245_HPF_FREEZE; 251 OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
499 changed = reg != data->cs4245_regs[CS4245_ADC_CTRL]; 252 OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
500 if (changed) 253 break;
501 cs4245_write(chip, CS4245_ADC_CTRL, reg); 254 case PLAYBACK_DST_MULTICH:
502 mutex_unlock(&chip->mutex); 255 routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
503 return changed; 256 (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
504} 257 (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
505 258 (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
506#define INPUT_VOLUME(xname, index) { \ 259 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
507 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 260 OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
508 .name = xname, \ 261 break;
509 .info = input_vol_info, \
510 .get = input_vol_get, \
511 .put = input_vol_put, \
512 .tlv = { .p = cs4245_pga_db_scale }, \
513 .private_value = index, \
514}
515static const struct snd_kcontrol_new dg_controls[] = {
516 {
517 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
518 .name = "Analog Output Playback Enum",
519 .info = output_switch_info,
520 .get = output_switch_get,
521 .put = output_switch_put,
522 },
523 {
524 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
525 .name = "Headphones Impedance Playback Enum",
526 .info = hp_volume_offset_info,
527 .get = hp_volume_offset_get,
528 .put = hp_volume_offset_put,
529 },
530 INPUT_VOLUME("Mic Capture Volume", 0),
531 INPUT_VOLUME("Aux Capture Volume", 1),
532 INPUT_VOLUME("Front Mic Capture Volume", 2),
533 INPUT_VOLUME("Line Capture Volume", 3),
534 {
535 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
536 .name = "Capture Source",
537 .info = input_sel_info,
538 .get = input_sel_get,
539 .put = input_sel_put,
540 },
541 {
542 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
543 .name = "ADC High-pass Filter Capture Enum",
544 .info = hpf_info,
545 .get = hpf_get,
546 .put = hpf_put,
547 },
548};
549
550static int dg_control_filter(struct snd_kcontrol_new *template)
551{
552 if (!strncmp(template->name, "Master Playback ", 16))
553 return 1;
554 return 0;
555}
556
557static int dg_mixer_init(struct oxygen *chip)
558{
559 unsigned int i;
560 int err;
561
562 for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
563 err = snd_ctl_add(chip->card,
564 snd_ctl_new1(&dg_controls[i], chip));
565 if (err < 0)
566 return err;
567 } 262 }
568 return 0; 263 return routing;
569} 264}
570 265
571static void dump_cs4245_registers(struct oxygen *chip, 266void dump_cs4245_registers(struct oxygen *chip,
572 struct snd_info_buffer *buffer) 267 struct snd_info_buffer *buffer)
573{ 268{
574 struct dg *data = chip->model_data; 269 struct dg *data = chip->model_data;
575 unsigned int i; 270 unsigned int addr;
576 271
577 snd_iprintf(buffer, "\nCS4245:"); 272 snd_iprintf(buffer, "\nCS4245:");
578 for (i = 1; i <= 0x10; ++i) 273 cs4245_read_spi(chip, CS4245_INT_STATUS);
579 snd_iprintf(buffer, " %02x", data->cs4245_regs[i]); 274 for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++)
275 snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]);
580 snd_iprintf(buffer, "\n"); 276 snd_iprintf(buffer, "\n");
581} 277}
582
583struct oxygen_model model_xonar_dg = {
584 .longname = "C-Media Oxygen HD Audio",
585 .chip = "CMI8786",
586 .init = dg_init,
587 .control_filter = dg_control_filter,
588 .mixer_init = dg_mixer_init,
589 .cleanup = dg_cleanup,
590 .suspend = dg_suspend,
591 .resume = dg_resume,
592 .set_dac_params = set_cs4245_dac_params,
593 .set_adc_params = set_cs4245_adc_params,
594 .adjust_dac_routing = adjust_dg_dac_routing,
595 .dump_registers = dump_cs4245_registers,
596 .model_data_size = sizeof(struct dg),
597 .device_config = PLAYBACK_0_TO_I2S |
598 PLAYBACK_1_TO_SPDIF |
599 CAPTURE_0_FROM_I2S_2 |
600 CAPTURE_1_FROM_SPDIF,
601 .dac_channels_pcm = 6,
602 .dac_channels_mixer = 0,
603 .function_flags = OXYGEN_FUNCTION_SPI,
604 .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
605 .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
606 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
607 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
608};
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
index 5688d78609a9..d461df357aa1 100644
--- a/sound/pci/oxygen/xonar_dg.h
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -3,6 +3,54 @@
3 3
4#include "oxygen.h" 4#include "oxygen.h"
5 5
6#define GPIO_MAGIC 0x0008
7#define GPIO_HP_DETECT 0x0010
8#define GPIO_INPUT_ROUTE 0x0060
9#define GPIO_HP_REAR 0x0080
10#define GPIO_OUTPUT_ENABLE 0x0100
11
12#define CAPTURE_SRC_MIC 0
13#define CAPTURE_SRC_FP_MIC 1
14#define CAPTURE_SRC_LINE 2
15#define CAPTURE_SRC_AUX 3
16
17#define PLAYBACK_DST_HP 0
18#define PLAYBACK_DST_HP_FP 1
19#define PLAYBACK_DST_MULTICH 2
20
21enum cs4245_shadow_operation {
22 CS4245_SAVE_TO_SHADOW,
23 CS4245_LOAD_FROM_SHADOW
24};
25
26struct dg {
27 /* shadow copy of the CS4245 register space */
28 unsigned char cs4245_shadow[17];
29 /* output select: headphone/speakers */
30 unsigned char output_sel;
31 /* volumes for all capture sources */
32 char input_vol[4][2];
33 /* input select: mic/fp mic/line/aux */
34 unsigned char input_sel;
35};
36
37/* Xonar DG control routines */
38int cs4245_write_spi(struct oxygen *chip, u8 reg);
39int cs4245_read_spi(struct oxygen *chip, u8 reg);
40int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op);
41void dg_init(struct oxygen *chip);
42void set_cs4245_dac_params(struct oxygen *chip,
43 struct snd_pcm_hw_params *params);
44void set_cs4245_adc_params(struct oxygen *chip,
45 struct snd_pcm_hw_params *params);
46unsigned int adjust_dg_dac_routing(struct oxygen *chip,
47 unsigned int play_routing);
48void dump_cs4245_registers(struct oxygen *chip,
49 struct snd_info_buffer *buffer);
50void dg_suspend(struct oxygen *chip);
51void dg_resume(struct oxygen *chip);
52void dg_cleanup(struct oxygen *chip);
53
6extern struct oxygen_model model_xonar_dg; 54extern struct oxygen_model model_xonar_dg;
7 55
8#endif 56#endif
diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c
new file mode 100644
index 000000000000..b885dac28a09
--- /dev/null
+++ b/sound/pci/oxygen/xonar_dg_mixer.c
@@ -0,0 +1,477 @@
1/*
2 * Mixer controls for the Xonar DG/DGX
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Copyright (c) Roman Volkov <v1ron@mail.ru>
6 *
7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2.
9 *
10 * This driver is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this driver; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/pci.h>
20#include <linux/delay.h>
21#include <sound/control.h>
22#include <sound/core.h>
23#include <sound/info.h>
24#include <sound/pcm.h>
25#include <sound/tlv.h>
26#include "oxygen.h"
27#include "xonar_dg.h"
28#include "cs4245.h"
29
30/* analog output select */
31
32static int output_select_apply(struct oxygen *chip)
33{
34 struct dg *data = chip->model_data;
35
36 data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK;
37 if (data->output_sel == PLAYBACK_DST_HP) {
38 /* mute FP (aux output) amplifier, switch rear jack to CS4245 */
39 oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
40 } else if (data->output_sel == PLAYBACK_DST_HP_FP) {
41 /*
42 * Unmute FP amplifier, switch rear jack to CS4361;
43 * I2S channels 2,3,4 should be inactive.
44 */
45 oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
46 data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC;
47 } else {
48 /*
49 * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp.,
50 * and change playback routing.
51 */
52 oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
53 }
54 return cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
55}
56
57static int output_select_info(struct snd_kcontrol *ctl,
58 struct snd_ctl_elem_info *info)
59{
60 static const char *const names[3] = {
61 "Stereo Headphones",
62 "Stereo Headphones FP",
63 "Multichannel",
64 };
65
66 return snd_ctl_enum_info(info, 1, 3, names);
67}
68
69static int output_select_get(struct snd_kcontrol *ctl,
70 struct snd_ctl_elem_value *value)
71{
72 struct oxygen *chip = ctl->private_data;
73 struct dg *data = chip->model_data;
74
75 mutex_lock(&chip->mutex);
76 value->value.enumerated.item[0] = data->output_sel;
77 mutex_unlock(&chip->mutex);
78 return 0;
79}
80
81static int output_select_put(struct snd_kcontrol *ctl,
82 struct snd_ctl_elem_value *value)
83{
84 struct oxygen *chip = ctl->private_data;
85 struct dg *data = chip->model_data;
86 unsigned int new = value->value.enumerated.item[0];
87 int changed = 0;
88 int ret;
89
90 mutex_lock(&chip->mutex);
91 if (data->output_sel != new) {
92 data->output_sel = new;
93 ret = output_select_apply(chip);
94 changed = ret >= 0 ? 1 : ret;
95 oxygen_update_dac_routing(chip);
96 }
97 mutex_unlock(&chip->mutex);
98
99 return changed;
100}
101
102/* CS4245 Headphone Channels A&B Volume Control */
103
104static int hp_stereo_volume_info(struct snd_kcontrol *ctl,
105 struct snd_ctl_elem_info *info)
106{
107 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
108 info->count = 2;
109 info->value.integer.min = 0;
110 info->value.integer.max = 255;
111 return 0;
112}
113
114static int hp_stereo_volume_get(struct snd_kcontrol *ctl,
115 struct snd_ctl_elem_value *val)
116{
117 struct oxygen *chip = ctl->private_data;
118 struct dg *data = chip->model_data;
119 unsigned int tmp;
120
121 mutex_lock(&chip->mutex);
122 tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
123 val->value.integer.value[0] = tmp;
124 tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
125 val->value.integer.value[1] = tmp;
126 mutex_unlock(&chip->mutex);
127 return 0;
128}
129
130static int hp_stereo_volume_put(struct snd_kcontrol *ctl,
131 struct snd_ctl_elem_value *val)
132{
133 struct oxygen *chip = ctl->private_data;
134 struct dg *data = chip->model_data;
135 int ret;
136 int changed = 0;
137 long new1 = val->value.integer.value[0];
138 long new2 = val->value.integer.value[1];
139
140 if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0))
141 return -EINVAL;
142
143 mutex_lock(&chip->mutex);
144 if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) ||
145 (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) {
146 data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1;
147 data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2;
148 ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL);
149 if (ret >= 0)
150 ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
151 changed = ret >= 0 ? 1 : ret;
152 }
153 mutex_unlock(&chip->mutex);
154
155 return changed;
156}
157
158/* Headphone Mute */
159
160static int hp_mute_get(struct snd_kcontrol *ctl,
161 struct snd_ctl_elem_value *val)
162{
163 struct oxygen *chip = ctl->private_data;
164 struct dg *data = chip->model_data;
165
166 mutex_lock(&chip->mutex);
167 val->value.integer.value[0] =
168 !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC);
169 mutex_unlock(&chip->mutex);
170 return 0;
171}
172
173static int hp_mute_put(struct snd_kcontrol *ctl,
174 struct snd_ctl_elem_value *val)
175{
176 struct oxygen *chip = ctl->private_data;
177 struct dg *data = chip->model_data;
178 int ret;
179 int changed;
180
181 if (val->value.integer.value[0] > 1)
182 return -EINVAL;
183 mutex_lock(&chip->mutex);
184 data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
185 data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
186 (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
187 ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
188 changed = ret >= 0 ? 1 : ret;
189 mutex_unlock(&chip->mutex);
190 return changed;
191}
192
193/* capture volume for all sources */
194
195static int input_volume_apply(struct oxygen *chip, char left, char right)
196{
197 struct dg *data = chip->model_data;
198 int ret;
199
200 data->cs4245_shadow[CS4245_PGA_A_CTRL] = left;
201 data->cs4245_shadow[CS4245_PGA_B_CTRL] = right;
202 ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL);
203 if (ret < 0)
204 return ret;
205 return cs4245_write_spi(chip, CS4245_PGA_B_CTRL);
206}
207
208static int input_vol_info(struct snd_kcontrol *ctl,
209 struct snd_ctl_elem_info *info)
210{
211 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
212 info->count = 2;
213 info->value.integer.min = 2 * -12;
214 info->value.integer.max = 2 * 12;
215 return 0;
216}
217
218static int input_vol_get(struct snd_kcontrol *ctl,
219 struct snd_ctl_elem_value *value)
220{
221 struct oxygen *chip = ctl->private_data;
222 struct dg *data = chip->model_data;
223 unsigned int idx = ctl->private_value;
224
225 mutex_lock(&chip->mutex);
226 value->value.integer.value[0] = data->input_vol[idx][0];
227 value->value.integer.value[1] = data->input_vol[idx][1];
228 mutex_unlock(&chip->mutex);
229 return 0;
230}
231
232static int input_vol_put(struct snd_kcontrol *ctl,
233 struct snd_ctl_elem_value *value)
234{
235 struct oxygen *chip = ctl->private_data;
236 struct dg *data = chip->model_data;
237 unsigned int idx = ctl->private_value;
238 int changed = 0;
239 int ret = 0;
240
241 if (value->value.integer.value[0] < 2 * -12 ||
242 value->value.integer.value[0] > 2 * 12 ||
243 value->value.integer.value[1] < 2 * -12 ||
244 value->value.integer.value[1] > 2 * 12)
245 return -EINVAL;
246 mutex_lock(&chip->mutex);
247 changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
248 data->input_vol[idx][1] != value->value.integer.value[1];
249 if (changed) {
250 data->input_vol[idx][0] = value->value.integer.value[0];
251 data->input_vol[idx][1] = value->value.integer.value[1];
252 if (idx == data->input_sel) {
253 ret = input_volume_apply(chip,
254 data->input_vol[idx][0],
255 data->input_vol[idx][1]);
256 }
257 changed = ret >= 0 ? 1 : ret;
258 }
259 mutex_unlock(&chip->mutex);
260 return changed;
261}
262
263/* Capture Source */
264
265static int input_source_apply(struct oxygen *chip)
266{
267 struct dg *data = chip->model_data;
268
269 data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK;
270 if (data->input_sel == CAPTURE_SRC_FP_MIC)
271 data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2;
272 else if (data->input_sel == CAPTURE_SRC_LINE)
273 data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4;
274 else if (data->input_sel != CAPTURE_SRC_MIC)
275 data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1;
276 return cs4245_write_spi(chip, CS4245_ANALOG_IN);
277}
278
279static int input_sel_info(struct snd_kcontrol *ctl,
280 struct snd_ctl_elem_info *info)
281{
282 static const char *const names[4] = {
283 "Mic", "Front Mic", "Line", "Aux"
284 };
285
286 return snd_ctl_enum_info(info, 1, 4, names);
287}
288
289static int input_sel_get(struct snd_kcontrol *ctl,
290 struct snd_ctl_elem_value *value)
291{
292 struct oxygen *chip = ctl->private_data;
293 struct dg *data = chip->model_data;
294
295 mutex_lock(&chip->mutex);
296 value->value.enumerated.item[0] = data->input_sel;
297 mutex_unlock(&chip->mutex);
298 return 0;
299}
300
301static int input_sel_put(struct snd_kcontrol *ctl,
302 struct snd_ctl_elem_value *value)
303{
304 struct oxygen *chip = ctl->private_data;
305 struct dg *data = chip->model_data;
306 int changed;
307 int ret;
308
309 if (value->value.enumerated.item[0] > 3)
310 return -EINVAL;
311
312 mutex_lock(&chip->mutex);
313 changed = value->value.enumerated.item[0] != data->input_sel;
314 if (changed) {
315 data->input_sel = value->value.enumerated.item[0];
316
317 ret = input_source_apply(chip);
318 if (ret >= 0)
319 ret = input_volume_apply(chip,
320 data->input_vol[data->input_sel][0],
321 data->input_vol[data->input_sel][1]);
322 changed = ret >= 0 ? 1 : ret;
323 }
324 mutex_unlock(&chip->mutex);
325 return changed;
326}
327
328/* ADC high-pass filter */
329
330static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
331{
332 static const char *const names[2] = { "Active", "Frozen" };
333
334 return snd_ctl_enum_info(info, 1, 2, names);
335}
336
337static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
338{
339 struct oxygen *chip = ctl->private_data;
340 struct dg *data = chip->model_data;
341
342 value->value.enumerated.item[0] =
343 !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
344 return 0;
345}
346
347static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
348{
349 struct oxygen *chip = ctl->private_data;
350 struct dg *data = chip->model_data;
351 u8 reg;
352 int changed;
353
354 mutex_lock(&chip->mutex);
355 reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
356 if (value->value.enumerated.item[0])
357 reg |= CS4245_HPF_FREEZE;
358 changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL];
359 if (changed) {
360 data->cs4245_shadow[CS4245_ADC_CTRL] = reg;
361 cs4245_write_spi(chip, CS4245_ADC_CTRL);
362 }
363 mutex_unlock(&chip->mutex);
364 return changed;
365}
366
367#define INPUT_VOLUME(xname, index) { \
368 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
369 .name = xname, \
370 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
371 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
372 .info = input_vol_info, \
373 .get = input_vol_get, \
374 .put = input_vol_put, \
375 .tlv = { .p = pga_db_scale }, \
376 .private_value = index, \
377}
378static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0);
379static const DECLARE_TLV_DB_MINMAX(pga_db_scale, -1200, 1200);
380static const struct snd_kcontrol_new dg_controls[] = {
381 {
382 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
383 .name = "Analog Output Playback Enum",
384 .info = output_select_info,
385 .get = output_select_get,
386 .put = output_select_put,
387 },
388 {
389 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
390 .name = "Headphone Playback Volume",
391 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
392 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
393 .info = hp_stereo_volume_info,
394 .get = hp_stereo_volume_get,
395 .put = hp_stereo_volume_put,
396 .tlv = { .p = hp_db_scale, },
397 },
398 {
399 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
400 .name = "Headphone Playback Switch",
401 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
402 .info = snd_ctl_boolean_mono_info,
403 .get = hp_mute_get,
404 .put = hp_mute_put,
405 },
406 INPUT_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC),
407 INPUT_VOLUME("Front Mic Capture Volume", CAPTURE_SRC_FP_MIC),
408 INPUT_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE),
409 INPUT_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX),
410 {
411 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
412 .name = "Capture Source",
413 .info = input_sel_info,
414 .get = input_sel_get,
415 .put = input_sel_put,
416 },
417 {
418 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
419 .name = "ADC High-pass Filter Capture Enum",
420 .info = hpf_info,
421 .get = hpf_get,
422 .put = hpf_put,
423 },
424};
425
426static int dg_control_filter(struct snd_kcontrol_new *template)
427{
428 if (!strncmp(template->name, "Master Playback ", 16))
429 return 1;
430 return 0;
431}
432
433static int dg_mixer_init(struct oxygen *chip)
434{
435 unsigned int i;
436 int err;
437
438 output_select_apply(chip);
439 input_source_apply(chip);
440 oxygen_update_dac_routing(chip);
441
442 for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
443 err = snd_ctl_add(chip->card,
444 snd_ctl_new1(&dg_controls[i], chip));
445 if (err < 0)
446 return err;
447 }
448
449 return 0;
450}
451
452struct oxygen_model model_xonar_dg = {
453 .longname = "C-Media Oxygen HD Audio",
454 .chip = "CMI8786",
455 .init = dg_init,
456 .control_filter = dg_control_filter,
457 .mixer_init = dg_mixer_init,
458 .cleanup = dg_cleanup,
459 .suspend = dg_suspend,
460 .resume = dg_resume,
461 .set_dac_params = set_cs4245_dac_params,
462 .set_adc_params = set_cs4245_adc_params,
463 .adjust_dac_routing = adjust_dg_dac_routing,
464 .dump_registers = dump_cs4245_registers,
465 .model_data_size = sizeof(struct dg),
466 .device_config = PLAYBACK_0_TO_I2S |
467 PLAYBACK_1_TO_SPDIF |
468 CAPTURE_0_FROM_I2S_1 |
469 CAPTURE_1_FROM_SPDIF,
470 .dac_channels_pcm = 6,
471 .dac_channels_mixer = 0,
472 .function_flags = OXYGEN_FUNCTION_SPI,
473 .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
474 .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
475 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
476 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
477};
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 385dec16eb8a..688151ba309a 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -450,6 +450,17 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
450 } 450 }
451 snd_soc_write(codec, AIC32X4_IFACE1, data); 451 snd_soc_write(codec, AIC32X4_IFACE1, data);
452 452
453 if (params_channels(params) == 1) {
454 data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
455 } else {
456 if (aic32x4->swapdacs)
457 data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
458 else
459 data = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
460 }
461 snd_soc_update_bits(codec, AIC32X4_DACSETUP, AIC32X4_DAC_CHAN_MASK,
462 data);
463
453 return 0; 464 return 0;
454} 465}
455 466
@@ -606,20 +617,15 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
606 } 617 }
607 snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg); 618 snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg);
608 619
609 /* Do DACs need to be swapped? */
610 if (aic32x4->swapdacs) {
611 snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2RCHN | AIC32X4_RDAC2LCHN);
612 } else {
613 snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN);
614 }
615
616 /* Mic PGA routing */ 620 /* Mic PGA routing */
617 if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) { 621 if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
618 snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K); 622 snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K);
619 } 623 else
620 if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) { 624 snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_CM1L_10K);
625 if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
621 snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K); 626 snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K);
622 } 627 else
628 snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_CM1R_10K);
623 629
624 aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 630 aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
625 631
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index 35774223fd91..995f033a855d 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -120,7 +120,9 @@
120#define AIC32X4_MICBIAS_2075V 0x60 120#define AIC32X4_MICBIAS_2075V 0x60
121 121
122#define AIC32X4_LMICPGANIN_IN2R_10K 0x10 122#define AIC32X4_LMICPGANIN_IN2R_10K 0x10
123#define AIC32X4_LMICPGANIN_CM1L_10K 0x40
123#define AIC32X4_RMICPGANIN_IN1L_10K 0x10 124#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
125#define AIC32X4_RMICPGANIN_CM1R_10K 0x40
124 126
125#define AIC32X4_LMICPGAVOL_NOGAIN 0x80 127#define AIC32X4_LMICPGAVOL_NOGAIN 0x80
126#define AIC32X4_RMICPGAVOL_NOGAIN 0x80 128#define AIC32X4_RMICPGAVOL_NOGAIN 0x80
@@ -138,6 +140,7 @@
138#define AIC32X4_LDAC2RCHN (0x02 << 4) 140#define AIC32X4_LDAC2RCHN (0x02 << 4)
139#define AIC32X4_LDAC2LCHN (0x01 << 4) 141#define AIC32X4_LDAC2LCHN (0x01 << 4)
140#define AIC32X4_RDAC2RCHN (0x01 << 2) 142#define AIC32X4_RDAC2RCHN (0x01 << 2)
143#define AIC32X4_DAC_CHAN_MASK 0x3c
141 144
142#define AIC32X4_SSTEP2WCLK 0x01 145#define AIC32X4_SSTEP2WCLK 0x01
143#define AIC32X4_MUTEON 0x0C 146#define AIC32X4_MUTEON 0x0C
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 4cf91deabc02..4e3e31aaf509 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -14,6 +14,7 @@
14#include <linux/moduleparam.h> 14#include <linux/moduleparam.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/delay.h> 16#include <linux/delay.h>
17#include <linux/export.h>
17#include <linux/pm.h> 18#include <linux/pm.h>
18#include <linux/gcd.h> 19#include <linux/gcd.h>
19#include <linux/gpio.h> 20#include <linux/gpio.h>
@@ -2141,6 +2142,7 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
2141 2142
2142 return 0; 2143 return 0;
2143} 2144}
2145EXPORT_SYMBOL_GPL(wm5100_detect);
2144 2146
2145static irqreturn_t wm5100_irq(int irq, void *data) 2147static irqreturn_t wm5100_irq(int irq, void *data)
2146{ 2148{
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index d862f76b59f9..2c3c962d9a85 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -81,6 +81,54 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = {
81 { 0x3133, 0x1201 }, 81 { 0x3133, 0x1201 },
82 { 0x3183, 0x1501 }, 82 { 0x3183, 0x1501 },
83 { 0x31D3, 0x1401 }, 83 { 0x31D3, 0x1401 },
84 { 0x0049, 0x01ea },
85 { 0x004a, 0x01f2 },
86 { 0x0057, 0x01e7 },
87 { 0x0058, 0x01fb },
88 { 0x33ce, 0xc4f5 },
89 { 0x33cf, 0x1361 },
90 { 0x33d0, 0x0402 },
91 { 0x33d1, 0x4700 },
92 { 0x33d2, 0x026d },
93 { 0x33d3, 0xff00 },
94 { 0x33d4, 0x026d },
95 { 0x33d5, 0x0101 },
96 { 0x33d6, 0xc4f5 },
97 { 0x33d7, 0x0361 },
98 { 0x33d8, 0x0402 },
99 { 0x33d9, 0x6701 },
100 { 0x33da, 0xc4f5 },
101 { 0x33db, 0x136f },
102 { 0x33dc, 0xc4f5 },
103 { 0x33dd, 0x134f },
104 { 0x33de, 0xc4f5 },
105 { 0x33df, 0x131f },
106 { 0x33e0, 0x026d },
107 { 0x33e1, 0x4f01 },
108 { 0x33e2, 0x026d },
109 { 0x33e3, 0xf100 },
110 { 0x33e4, 0x026d },
111 { 0x33e5, 0x0001 },
112 { 0x33e6, 0xc4f5 },
113 { 0x33e7, 0x0361 },
114 { 0x33e8, 0x0402 },
115 { 0x33e9, 0x6601 },
116 { 0x33ea, 0xc4f5 },
117 { 0x33eb, 0x136f },
118 { 0x33ec, 0xc4f5 },
119 { 0x33ed, 0x134f },
120 { 0x33ee, 0xc4f5 },
121 { 0x33ef, 0x131f },
122 { 0x33f0, 0x026d },
123 { 0x33f1, 0x4e01 },
124 { 0x33f2, 0x026d },
125 { 0x33f3, 0xf000 },
126 { 0x33f6, 0xc4f5 },
127 { 0x33f7, 0x1361 },
128 { 0x33f8, 0x0402 },
129 { 0x33f9, 0x4600 },
130 { 0x33fa, 0x026d },
131 { 0x33fb, 0xfe00 },
84}; 132};
85 133
86static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, 134static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 6404e1ef20d0..5428a1fda260 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1278,18 +1278,13 @@ static int fsl_ssi_probe(struct platform_device *pdev)
1278 return -EINVAL; 1278 return -EINVAL;
1279 hw_type = (enum fsl_ssi_type) of_id->data; 1279 hw_type = (enum fsl_ssi_type) of_id->data;
1280 1280
1281 /* We only support the SSI in "I2S Slave" mode */
1282 sprop = of_get_property(np, "fsl,mode", NULL); 1281 sprop = of_get_property(np, "fsl,mode", NULL);
1283 if (!sprop) { 1282 if (!sprop) {
1284 dev_err(&pdev->dev, "fsl,mode property is necessary\n"); 1283 dev_err(&pdev->dev, "fsl,mode property is necessary\n");
1285 return -EINVAL; 1284 return -EINVAL;
1286 } 1285 }
1287 if (!strcmp(sprop, "ac97-slave")) { 1286 if (!strcmp(sprop, "ac97-slave"))
1288 ac97 = true; 1287 ac97 = true;
1289 } else if (strcmp(sprop, "i2s-slave")) {
1290 dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
1291 return -ENODEV;
1292 }
1293 1288
1294 /* The DAI name is the last part of the full name of the node. */ 1289 /* The DAI name is the last part of the full name of the node. */
1295 p = strrchr(np->full_name, '/') + 1; 1290 p = strrchr(np->full_name, '/') + 1;
@@ -1407,7 +1402,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
1407 */ 1402 */
1408 ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud"); 1403 ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
1409 if (IS_ERR(ssi_private->baudclk)) 1404 if (IS_ERR(ssi_private->baudclk))
1410 dev_warn(&pdev->dev, "could not get baud clock: %ld\n", 1405 dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
1411 PTR_ERR(ssi_private->baudclk)); 1406 PTR_ERR(ssi_private->baudclk));
1412 else 1407 else
1413 clk_prepare_enable(ssi_private->baudclk); 1408 clk_prepare_enable(ssi_private->baudclk);
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 4a07f7179690..22ad9c5654b5 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -30,6 +30,7 @@ config SND_OMAP_SOC_RX51
30 select SND_OMAP_SOC_MCBSP 30 select SND_OMAP_SOC_MCBSP
31 select SND_SOC_TLV320AIC3X 31 select SND_SOC_TLV320AIC3X
32 select SND_SOC_TPA6130A2 32 select SND_SOC_TPA6130A2
33 depends on GPIOLIB
33 help 34 help
34 Say Y if you want to add support for SoC audio on Nokia RX-51 35 Say Y if you want to add support for SoC audio on Nokia RX-51
35 hardware. This is also known as Nokia N900 product. 36 hardware. This is also known as Nokia N900 product.
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 27930fc432dc..454f41cfc828 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -19,7 +19,7 @@ config SND_S3C_DMA_LEGACY
19 19
20config SND_S3C24XX_I2S 20config SND_S3C24XX_I2S
21 tristate 21 tristate
22 select S3C2410_DMA 22 select S3C24XX_DMA
23 23
24config SND_S3C_I2SV2_SOC 24config SND_S3C_I2SV2_SOC
25 tristate 25 tristate
@@ -210,7 +210,7 @@ config SND_SOC_TOBERMORY
210 210
211config SND_SOC_BELLS 211config SND_SOC_BELLS
212 tristate "Audio support for Wolfson Bells" 212 tristate "Audio support for Wolfson Bells"
213 depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 213 depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA
214 select SND_SAMSUNG_I2S 214 select SND_SAMSUNG_I2S
215 select SND_SOC_WM5102 215 select SND_SOC_WM5102
216 select SND_SOC_WM5110 216 select SND_SOC_WM5110
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index fa91376e323d..fbced589d077 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -23,6 +23,7 @@
23#include "regs-iis.h" 23#include "regs-iis.h"
24#include <asm/mach-types.h> 24#include <asm/mach-types.h>
25 25
26#include <mach/gpio-samsung.h>
26#include "s3c24xx-i2s.h" 27#include "s3c24xx-i2s.h"
27 28
28static unsigned int rates[] = { 29static unsigned int rates[] = {
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 92f64363427d..0a9b44c940ce 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -22,8 +22,6 @@
22#include <sound/soc.h> 22#include <sound/soc.h>
23#include <sound/pcm_params.h> 23#include <sound/pcm_params.h>
24 24
25#include <mach/dma.h>
26
27#include <linux/platform_data/asoc-s3c.h> 25#include <linux/platform_data/asoc-s3c.h>
28 26
29#include "dma.h" 27#include "dma.h"
@@ -1268,7 +1266,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
1268 1266
1269 return 0; 1267 return 0;
1270err: 1268err:
1271 release_mem_region(regs_base, resource_size(res)); 1269 if (res)
1270 release_mem_region(regs_base, resource_size(res));
1272 1271
1273 return ret; 1272 return ret;
1274} 1273}
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 807db417d234..98a04c11202d 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -20,6 +20,7 @@
20 20
21#include <sound/soc.h> 21#include <sound/soc.h>
22 22
23#include <mach/gpio-samsung.h>
23#include <asm/mach-types.h> 24#include <asm/mach-types.h>
24#include "regs-iis.h" 25#include "regs-iis.h"
25 26
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index 704460a37005..06ebdc061770 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -24,6 +24,7 @@
24#include <sound/soc.h> 24#include <sound/soc.h>
25#include <sound/jack.h> 25#include <sound/jack.h>
26 26
27#include <mach/gpio-samsung.h>
27#include "regs-iis.h" 28#include "regs-iis.h"
28#include <asm/mach-types.h> 29#include <asm/mach-types.h>
29 30
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index fefc56100349..79e7efb9283c 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -729,7 +729,7 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
729 struct snd_soc_component_driver *cmp_drv, 729 struct snd_soc_component_driver *cmp_drv,
730 struct snd_soc_dai_driver *dai_drv) 730 struct snd_soc_dai_driver *dai_drv)
731{ 731{
732 struct snd_soc_dai_ops *ops = drv->ops; 732 struct snd_soc_dai_ops *ops = dai_drv->ops;
733 733
734 ops->trigger = s3c2412_i2s_trigger; 734 ops->trigger = s3c2412_i2s_trigger;
735 if (!ops->hw_params) 735 if (!ops->hw_params)
@@ -742,8 +742,8 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
742 if (!ops->delay) 742 if (!ops->delay)
743 ops->delay = s3c2412_i2s_delay; 743 ops->delay = s3c2412_i2s_delay;
744 744
745 drv->suspend = s3c2412_i2s_suspend; 745 dai_drv->suspend = s3c2412_i2s_suspend;
746 drv->resume = s3c2412_i2s_resume; 746 dai_drv->resume = s3c2412_i2s_resume;
747 747
748 return snd_soc_register_component(dev, cmp_drv, dai_drv, 1); 748 return snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
749} 749}
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index ea885cb9f76c..d0794458963a 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -26,6 +26,8 @@
26#include <sound/pcm_params.h> 26#include <sound/pcm_params.h>
27 27
28#include <mach/dma.h> 28#include <mach/dma.h>
29#include <mach/gpio-samsung.h>
30#include <plat/gpio-cfg.h>
29 31
30#include "dma.h" 32#include "dma.h"
31#include "regs-i2s-v2.h" 33#include "regs-i2s-v2.h"
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 9c8ebd872fac..f31e916dd8c4 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -24,6 +24,8 @@
24#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
25 25
26#include <mach/dma.h> 26#include <mach/dma.h>
27#include <mach/gpio-samsung.h>
28#include <plat/gpio-cfg.h>
27#include "regs-iis.h" 29#include "regs-iis.h"
28 30
29#include "dma.h" 31#include "dma.h"
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index 58ae3237ef69..c3b2adafb7b5 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -19,6 +19,7 @@
19#include <sound/soc.h> 19#include <sound/soc.h>
20#include <sound/jack.h> 20#include <sound/jack.h>
21 21
22#include <mach/gpio-samsung.h>
22#include <asm/mach-types.h> 23#include <asm/mach-types.h>
23 24
24#include "i2s.h" 25#include "i2s.h"
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index b072bd107b31..d38ae98e2f32 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -152,13 +152,11 @@ static struct snd_soc_card smdk = {
152 .num_links = ARRAY_SIZE(smdk_dai), 152 .num_links = ARRAY_SIZE(smdk_dai),
153}; 153};
154 154
155#ifdef CONFIG_OF
156static const struct of_device_id samsung_wm8994_of_match[] = { 155static const struct of_device_id samsung_wm8994_of_match[] = {
157 { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data }, 156 { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
158 {}, 157 {},
159}; 158};
160MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); 159MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
161#endif /* CONFIG_OF */
162 160
163static int smdk_audio_probe(struct platform_device *pdev) 161static int smdk_audio_probe(struct platform_device *pdev)
164{ 162{
@@ -188,7 +186,7 @@ static int smdk_audio_probe(struct platform_device *pdev)
188 smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; 186 smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node;
189 } 187 }
190 188
191 id = of_match_device(samsung_wm8994_of_match, &pdev->dev); 189 id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev);
192 if (id) 190 if (id)
193 *board = *((struct smdk_wm8994_data *)id->data); 191 *board = *((struct smdk_wm8994_data *)id->data);
194 192