2 * OLPC XO-1 additional sound features
4 * Copyright © 2006 Jaya Kumar <jayakumar.lkml@gmail.com>
5 * Copyright © 2007-2008 Andres Salomon <dilinger@debian.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 #include <sound/core.h>
13 #include <sound/info.h>
14 #include <sound/control.h>
15 #include <sound/ac97_codec.h>
16 #include <linux/gpio.h>
19 #include "cs5535audio.h"
21 #define DRV_NAME "cs5535audio-olpc"
24 * OLPC has an additional feature on top of the regular AD1888 codec features.
25 * It has an Analog Input mode that is switched into (after disabling the
26 * High Pass Filter) via GPIO. It is supported on B2 and later models.
28 void olpc_analog_input(struct snd_ac97
*ac97
, int on
)
32 if (!machine_is_olpc())
35 /* update the High Pass Filter (via AC97_AD_TEST2) */
36 err
= snd_ac97_update_bits(ac97
, AC97_AD_TEST2
,
37 1 << AC97_AD_HPFD_SHIFT
, on
<< AC97_AD_HPFD_SHIFT
);
39 snd_printk(KERN_ERR
"setting High Pass Filter - %d\n", err
);
43 /* set Analog Input through GPIO */
44 gpio_set_value(OLPC_GPIO_MIC_AC
, on
);
48 * OLPC XO-1's V_REFOUT is a mic bias enable.
50 void olpc_mic_bias(struct snd_ac97
*ac97
, int on
)
54 if (!machine_is_olpc())
58 err
= snd_ac97_update_bits(ac97
, AC97_AD_MISC
,
59 1 << AC97_AD_VREFD_SHIFT
, on
<< AC97_AD_VREFD_SHIFT
);
61 snd_printk(KERN_ERR
"setting MIC Bias - %d\n", err
);
64 static int olpc_dc_info(struct snd_kcontrol
*kctl
,
65 struct snd_ctl_elem_info
*uinfo
)
67 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
69 uinfo
->value
.integer
.min
= 0;
70 uinfo
->value
.integer
.max
= 1;
74 static int olpc_dc_get(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
76 v
->value
.integer
.value
[0] = gpio_get_value(OLPC_GPIO_MIC_AC
);
80 static int olpc_dc_put(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
82 struct cs5535audio
*cs5535au
= snd_kcontrol_chip(kctl
);
84 olpc_analog_input(cs5535au
->ac97
, v
->value
.integer
.value
[0]);
88 static int olpc_mic_info(struct snd_kcontrol
*kctl
,
89 struct snd_ctl_elem_info
*uinfo
)
91 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
93 uinfo
->value
.integer
.min
= 0;
94 uinfo
->value
.integer
.max
= 1;
98 static int olpc_mic_get(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
100 struct cs5535audio
*cs5535au
= snd_kcontrol_chip(kctl
);
101 struct snd_ac97
*ac97
= cs5535au
->ac97
;
104 i
= (snd_ac97_read(ac97
, AC97_AD_MISC
) >> AC97_AD_VREFD_SHIFT
) & 0x1;
105 v
->value
.integer
.value
[0] = i
? 0 : 1;
109 static int olpc_mic_put(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
111 struct cs5535audio
*cs5535au
= snd_kcontrol_chip(kctl
);
113 olpc_mic_bias(cs5535au
->ac97
, v
->value
.integer
.value
[0]);
117 static struct snd_kcontrol_new olpc_cs5535audio_ctls
[] = {
119 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
120 .name
= "DC Mode Enable",
121 .info
= olpc_dc_info
,
127 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
128 .name
= "MIC Bias Enable",
129 .info
= olpc_mic_info
,
136 void olpc_prequirks(struct snd_card
*card
,
137 struct snd_ac97_template
*ac97
)
139 if (!machine_is_olpc())
142 /* invert EAPD if on an OLPC B3 or higher */
143 if (olpc_board_at_least(olpc_board_pre(0xb3)))
144 ac97
->scaps
|= AC97_SCAP_INV_EAPD
;
147 int olpc_quirks(struct snd_card
*card
, struct snd_ac97
*ac97
)
149 struct snd_ctl_elem_id elem
;
152 if (!machine_is_olpc())
155 if (gpio_request(OLPC_GPIO_MIC_AC
, DRV_NAME
)) {
156 printk(KERN_ERR DRV_NAME
": unable to allocate MIC GPIO\n");
159 gpio_direction_output(OLPC_GPIO_MIC_AC
, 0);
161 /* drop the original AD1888 HPF control */
162 memset(&elem
, 0, sizeof(elem
));
163 elem
.iface
= SNDRV_CTL_ELEM_IFACE_MIXER
;
164 strncpy(elem
.name
, "High Pass Filter Enable", sizeof(elem
.name
));
165 snd_ctl_remove_id(card
, &elem
);
167 /* drop the original V_REFOUT control */
168 memset(&elem
, 0, sizeof(elem
));
169 elem
.iface
= SNDRV_CTL_ELEM_IFACE_MIXER
;
170 strncpy(elem
.name
, "V_REFOUT Enable", sizeof(elem
.name
));
171 snd_ctl_remove_id(card
, &elem
);
173 /* add the OLPC-specific controls */
174 for (i
= 0; i
< ARRAY_SIZE(olpc_cs5535audio_ctls
); i
++) {
175 err
= snd_ctl_add(card
, snd_ctl_new1(&olpc_cs5535audio_ctls
[i
],
176 ac97
->private_data
));
178 gpio_free(OLPC_GPIO_MIC_AC
);
183 /* turn off the mic by default */
184 olpc_mic_bias(ac97
, 0);
188 void olpc_quirks_cleanup(void)
190 gpio_free(OLPC_GPIO_MIC_AC
);