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 dev_err(ac97
->bus
->card
->dev
,
40 "setting High Pass Filter - %d\n", err
);
44 /* set Analog Input through GPIO */
45 gpio_set_value(OLPC_GPIO_MIC_AC
, on
);
49 * OLPC XO-1's V_REFOUT is a mic bias enable.
51 void olpc_mic_bias(struct snd_ac97
*ac97
, int on
)
55 if (!machine_is_olpc())
59 err
= snd_ac97_update_bits(ac97
, AC97_AD_MISC
,
60 1 << AC97_AD_VREFD_SHIFT
, on
<< AC97_AD_VREFD_SHIFT
);
62 dev_err(ac97
->bus
->card
->dev
, "setting MIC Bias - %d\n", err
);
65 static int olpc_dc_info(struct snd_kcontrol
*kctl
,
66 struct snd_ctl_elem_info
*uinfo
)
68 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
70 uinfo
->value
.integer
.min
= 0;
71 uinfo
->value
.integer
.max
= 1;
75 static int olpc_dc_get(struct snd_kcontrol
*kctl
, struct snd_ctl_elem_value
*v
)
77 v
->value
.integer
.value
[0] = gpio_get_value(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
[] = {
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 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 olpc_quirks(struct snd_card
*card
, struct snd_ac97
*ac97
)
150 struct snd_ctl_elem_id elem
;
153 if (!machine_is_olpc())
156 if (gpio_request(OLPC_GPIO_MIC_AC
, DRV_NAME
)) {
157 dev_err(card
->dev
, "unable to allocate MIC GPIO\n");
160 gpio_direction_output(OLPC_GPIO_MIC_AC
, 0);
162 /* drop the original AD1888 HPF control */
163 memset(&elem
, 0, sizeof(elem
));
164 elem
.iface
= SNDRV_CTL_ELEM_IFACE_MIXER
;
165 strlcpy(elem
.name
, "High Pass Filter Enable", sizeof(elem
.name
));
166 snd_ctl_remove_id(card
, &elem
);
168 /* drop the original V_REFOUT control */
169 memset(&elem
, 0, sizeof(elem
));
170 elem
.iface
= SNDRV_CTL_ELEM_IFACE_MIXER
;
171 strlcpy(elem
.name
, "V_REFOUT Enable", sizeof(elem
.name
));
172 snd_ctl_remove_id(card
, &elem
);
174 /* add the OLPC-specific controls */
175 for (i
= 0; i
< ARRAY_SIZE(olpc_cs5535audio_ctls
); i
++) {
176 err
= snd_ctl_add(card
, snd_ctl_new1(&olpc_cs5535audio_ctls
[i
],
177 ac97
->private_data
));
179 gpio_free(OLPC_GPIO_MIC_AC
);
184 /* turn off the mic by default */
185 olpc_mic_bias(ac97
, 0);
189 void olpc_quirks_cleanup(void)
191 gpio_free(OLPC_GPIO_MIC_AC
);