aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/cs5535audio/Makefile4
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c7
-rw-r--r--sound/pci/cs5535audio/cs5535audio.h9
-rw-r--r--sound/pci/cs5535audio/cs5535audio_olpc.c113
4 files changed, 133 insertions, 0 deletions
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile
index bb3d57e6a3cb..3e41fd39780d 100644
--- a/sound/pci/cs5535audio/Makefile
+++ b/sound/pci/cs5535audio/Makefile
@@ -5,5 +5,9 @@
5snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o 5snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
6snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o 6snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
7 7
8ifdef CONFIG_OLPC
9snd-cs5535audio-objs += cs5535audio_olpc.o
10endif
11
8# Toplevel Module Dependency 12# Toplevel Module Dependency
9obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o 13obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 6c886edd06db..50333bb9242c 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -171,6 +171,13 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
171 171
172 snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk); 172 snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
173 173
174 /* olpc_quirks is dummied out if not olpc */
175 err = olpc_quirks(card, cs5535au->ac97);
176 if (err < 0) {
177 snd_printk(KERN_ERR "olpc quirks failed\n");
178 return err;
179 }
180
174 return 0; 181 return 0;
175} 182}
176 183
diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h
index 1aa1e2bbdf74..adcb213eb276 100644
--- a/sound/pci/cs5535audio/cs5535audio.h
+++ b/sound/pci/cs5535audio/cs5535audio.h
@@ -92,6 +92,9 @@ struct cs5535audio {
92 struct snd_pcm_substream *playback_substream; 92 struct snd_pcm_substream *playback_substream;
93 struct snd_pcm_substream *capture_substream; 93 struct snd_pcm_substream *capture_substream;
94 struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; 94 struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
95#ifdef CONFIG_OLPC
96 int ec_analog_input_mode;
97#endif
95}; 98};
96 99
97#ifdef CONFIG_PM 100#ifdef CONFIG_PM
@@ -99,6 +102,12 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
99int snd_cs5535audio_resume(struct pci_dev *pci); 102int snd_cs5535audio_resume(struct pci_dev *pci);
100#endif 103#endif
101 104
105#ifdef CONFIG_OLPC
106int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97);
107#else
108#define olpc_quirks(arg, arg2) (0)
109#endif
110
102int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); 111int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
103 112
104#endif /* __SOUND_CS5535AUDIO_H */ 113#endif /* __SOUND_CS5535AUDIO_H */
diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c
new file mode 100644
index 000000000000..4b72d8662ec9
--- /dev/null
+++ b/sound/pci/cs5535audio/cs5535audio_olpc.c
@@ -0,0 +1,113 @@
1#include <linux/olpc.h>
2#include <sound/driver.h>
3#include <sound/core.h>
4#include <sound/info.h>
5#include <sound/control.h>
6#include <sound/ac97_codec.h>
7#include "cs5535audio.h"
8
9/* OLPC has an additional feature on top of regular AD1888 codec
10features. This is support for an analog input mode. This is a
112 step process. First, to turn off the AD1888 codec bias voltage
12and high pass filter. Second, to tell the embedded controller to
13reroute from a capacitive trace to a direct trace using an analog
14switch. The *_ec()s are what talk to that controller */
15
16static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol,
17 struct snd_ctl_elem_info *uinfo)
18{
19 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
20 uinfo->count = 1;
21 uinfo->value.integer.min = 0;
22 uinfo->value.integer.max = 1;
23 return 0;
24}
25
26#define AD1888_VREFOUT_EN_BIT (1 << 2)
27#define AD1888_HPF_EN_BIT (1 << 12)
28static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol,
29 struct snd_ctl_elem_value *ucontrol)
30{
31 struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol);
32 u16 reg1, reg2;
33
34 /* if either AD1888 VRef Bias and High Pass Filter are enabled
35 or the EC is not in analog mode then flag as not in analog mode.
36 No EC command to read current analog state so we cache that. */
37 reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC);
38 reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2);
39
40 if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT) &&
41 cs5535au->ec_analog_input_mode)
42 ucontrol->value.integer.value[0] = 1;
43 else
44 ucontrol->value.integer.value[0] = 0;
45
46 return 0;
47}
48
49static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol,
50 struct snd_ctl_elem_value *ucontrol)
51{
52 int err;
53 struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol);
54 u8 value;
55 struct snd_ac97 *ac97 = cs5535au->ac97;
56
57 /* value is 1 if analog input is desired */
58 value = ucontrol->value.integer.value[0];
59
60 /* use ec mode as flag to determine if any change needed */
61 if (cs5535au->ec_analog_input_mode == value)
62 return 0;
63
64 /* sets High Z on VREF Bias if 1 */
65 if (value)
66 err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
67 AD1888_VREFOUT_EN_BIT, AD1888_VREFOUT_EN_BIT);
68 else
69 err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
70 AD1888_VREFOUT_EN_BIT, 0);
71 if (err < 0)
72 snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err);
73
74 /* turns off High Pass Filter if 1 */
75 if (value)
76 err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
77 AD1888_HPF_EN_BIT, AD1888_HPF_EN_BIT);
78 else
79 err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
80 AD1888_HPF_EN_BIT, 0);
81 if (err < 0)
82 snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err);
83
84 if (value)
85 err = write_ec_command(0x01); /* activate MIC_AC_OFF */
86 else
87 err = write_ec_command(0x02); /* deactivates MIC_AC_OFF */
88
89 if (err < 0)
90 snd_printk(KERN_ERR "Error talking to EC %d\n", err);
91
92 cs5535au->ec_analog_input_mode = value;
93
94 return 1;
95}
96
97static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata =
98{
99 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
100 .name = "Analog Input Switch",
101 .info = snd_cs5535audio_ctl_info,
102 .get = snd_cs5535audio_ctl_get,
103 .put = snd_cs5535audio_ctl_put,
104 .private_value = 0
105};
106
107int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
108{
109 /* setup callback for mixer control that does analog input mode */
110 return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls,
111 ac97->private_data));
112}
113