blob: 2bd6588b4353fcacfa5a74acb0bb9ced41159e3b [file] [log] [blame]
Jaya Kumar57d4bf62008-11-06 16:43:34 -05001#include <sound/driver.h>
2#include <sound/core.h>
3#include <sound/info.h>
4#include <sound/control.h>
5#include <sound/ac97_codec.h>
Jordan Crousec8974be2008-11-06 16:43:53 -05006
7#include <asm/olpc.h>
Jaya Kumar57d4bf62008-11-06 16:43:34 -05008#include "cs5535audio.h"
9
10/* OLPC has an additional feature on top of regular AD1888 codec
11features. This is support for an analog input mode. This is a
122 step process. First, to turn off the AD1888 codec bias voltage
13and high pass filter. Second, to tell the embedded controller to
14reroute from a capacitive trace to a direct trace using an analog
15switch. The *_ec()s are what talk to that controller */
16
17static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol,
18 struct snd_ctl_elem_info *uinfo)
19{
20 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
21 uinfo->count = 1;
22 uinfo->value.integer.min = 0;
23 uinfo->value.integer.max = 1;
24 return 0;
25}
26
27#define AD1888_VREFOUT_EN_BIT (1 << 2)
28#define AD1888_HPF_EN_BIT (1 << 12)
29static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol,
30 struct snd_ctl_elem_value *ucontrol)
31{
32 struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol);
33 u16 reg1, reg2;
34
35 /* if either AD1888 VRef Bias and High Pass Filter are enabled
36 or the EC is not in analog mode then flag as not in analog mode.
37 No EC command to read current analog state so we cache that. */
38 reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC);
39 reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2);
40
Andres Salomonb91254e2008-11-06 16:46:31 -050041 if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT))
Jaya Kumar57d4bf62008-11-06 16:43:34 -050042 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
Jaya Kumar57d4bf62008-11-06 16:43:34 -050060 /* sets High Z on VREF Bias if 1 */
61 if (value)
62 err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
63 AD1888_VREFOUT_EN_BIT, AD1888_VREFOUT_EN_BIT);
64 else
65 err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
66 AD1888_VREFOUT_EN_BIT, 0);
67 if (err < 0)
68 snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err);
69
70 /* turns off High Pass Filter if 1 */
71 if (value)
72 err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
73 AD1888_HPF_EN_BIT, AD1888_HPF_EN_BIT);
74 else
75 err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
76 AD1888_HPF_EN_BIT, 0);
77 if (err < 0)
78 snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err);
79
Jordan Crousec8974be2008-11-06 16:43:53 -050080 /* B2 and newer writes directly to a GPIO pin */
Jaya Kumar57d4bf62008-11-06 16:43:34 -050081 if (value)
Jordan Crousec8974be2008-11-06 16:43:53 -050082 geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
Jaya Kumar57d4bf62008-11-06 16:43:34 -050083 else
Jordan Crousec8974be2008-11-06 16:43:53 -050084 geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
Jaya Kumar57d4bf62008-11-06 16:43:34 -050085
Jaya Kumar57d4bf62008-11-06 16:43:34 -050086 return 1;
87}
88
89static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata =
90{
91 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
92 .name = "Analog Input Switch",
93 .info = snd_cs5535audio_ctl_info,
94 .get = snd_cs5535audio_ctl_get,
95 .put = snd_cs5535audio_ctl_put,
96 .private_value = 0
97};
98
Andres Salomon3556d182008-11-06 16:44:08 -050099void __devinit olpc_prequirks(struct snd_card *card,
100 struct snd_ac97_template *ac97)
101{
102 if (!machine_is_olpc())
103 return;
104
105 /* invert EAPD if on an OLPC B3 or higher */
106 if (olpc_board_at_least(olpc_board_pre(0xb3)))
107 ac97->scaps |= AC97_SCAP_INV_EAPD;
108}
109
Jaya Kumar57d4bf62008-11-06 16:43:34 -0500110int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
111{
Jordan Crousec8974be2008-11-06 16:43:53 -0500112 if (!machine_is_olpc())
113 return 0;
114
Jaya Kumar57d4bf62008-11-06 16:43:34 -0500115 /* setup callback for mixer control that does analog input mode */
116 return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls,
117 ac97->private_data));
118}
119