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>
18 #include "cs5535audio.h"
21 * OLPC has an additional feature on top of the regular AD1888 codec features.
22 * It has an Analog Input mode that is switched into (after disabling the
23 * High Pass Filter) via GPIO. It is supported on B2 and later models.
25 void olpc_analog_input(struct snd_ac97
*ac97
, int on
)
29 if (!machine_is_olpc())
32 /* update the High Pass Filter (via AC97_AD_TEST2) */
33 err
= snd_ac97_update_bits(ac97
, AC97_AD_TEST2
,
34 1 << AC97_AD_HPFD_SHIFT
, on
<< AC97_AD_HPFD_SHIFT
);
36 snd_printk(KERN_ERR
"setting High Pass Filter - %d\n", err
);
40 /* set Analog Input through GPIO */
42 geode_gpio_set(OLPC_GPIO_MIC_AC
, GPIO_OUTPUT_VAL
);
44 geode_gpio_clear(OLPC_GPIO_MIC_AC
, GPIO_OUTPUT_VAL
);
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] = geode_gpio_isset(OLPC_GPIO_MIC_AC
,
81 static int olpc_dc_put(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
83 struct cs5535audio
*cs5535au
= snd_kcontrol_chip(kctl
);
85 olpc_analog_input(cs5535au
->ac97
, v
->value
.integer
.value
[0]);
89 static int olpc_mic_info(struct snd_kcontrol
*kctl
,
90 struct snd_ctl_elem_info
*uinfo
)
92 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
94 uinfo
->value
.integer
.min
= 0;
95 uinfo
->value
.integer
.max
= 1;
99 static int olpc_mic_get(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
101 struct cs5535audio
*cs5535au
= snd_kcontrol_chip(kctl
);
102 struct snd_ac97
*ac97
= cs5535au
->ac97
;
105 i
= (snd_ac97_read(ac97
, AC97_AD_MISC
) >> AC97_AD_VREFD_SHIFT
) & 0x1;
106 v
->value
.integer
.value
[0] = i
? 0 : 1;
110 static int olpc_mic_put(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
112 struct cs5535audio
*cs5535au
= snd_kcontrol_chip(kctl
);
114 olpc_mic_bias(cs5535au
->ac97
, v
->value
.integer
.value
[0]);
118 static struct snd_kcontrol_new olpc_cs5535audio_ctls
[] __devinitdata
= {
120 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
121 .name
= "DC Mode Enable",
122 .info
= olpc_dc_info
,
128 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
129 .name
= "MIC Bias Enable",
130 .info
= olpc_mic_info
,
137 void __devinit
olpc_prequirks(struct snd_card
*card
,
138 struct snd_ac97_template
*ac97
)
140 if (!machine_is_olpc())
143 /* invert EAPD if on an OLPC B3 or higher */
144 if (olpc_board_at_least(olpc_board_pre(0xb3)))
145 ac97
->scaps
|= AC97_SCAP_INV_EAPD
;
148 int __devinit
olpc_quirks(struct snd_card
*card
, struct snd_ac97
*ac97
)
150 struct snd_ctl_elem_id elem
;
153 if (!machine_is_olpc())
156 /* drop the original AD1888 HPF control */
157 memset(&elem
, 0, sizeof(elem
));
158 elem
.iface
= SNDRV_CTL_ELEM_IFACE_MIXER
;
159 strncpy(elem
.name
, "High Pass Filter Enable", sizeof(elem
.name
));
160 snd_ctl_remove_id(card
, &elem
);
162 /* drop the original V_REFOUT control */
163 memset(&elem
, 0, sizeof(elem
));
164 elem
.iface
= SNDRV_CTL_ELEM_IFACE_MIXER
;
165 strncpy(elem
.name
, "V_REFOUT Enable", sizeof(elem
.name
));
166 snd_ctl_remove_id(card
, &elem
);
168 /* add the OLPC-specific controls */
169 for (i
= 0; i
< ARRAY_SIZE(olpc_cs5535audio_ctls
); i
++) {
170 err
= snd_ctl_add(card
, snd_ctl_new1(&olpc_cs5535audio_ctls
[i
],
171 ac97
->private_data
));
176 /* turn off the mic by default */
177 olpc_mic_bias(ac97
, 0);