root/sound/pci/cs5535audio/cs5535audio_olpc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. olpc_analog_input
  2. olpc_mic_bias
  3. olpc_dc_info
  4. olpc_dc_get
  5. olpc_dc_put
  6. olpc_mic_info
  7. olpc_mic_get
  8. olpc_mic_put
  9. olpc_prequirks
  10. olpc_quirks
  11. olpc_quirks_cleanup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * OLPC XO-1 additional sound features
   4  *
   5  * Copyright © 2006  Jaya Kumar <jayakumar.lkml@gmail.com>
   6  * Copyright © 2007-2008  Andres Salomon <dilinger@debian.org>
   7  */
   8 #include <sound/core.h>
   9 #include <sound/info.h>
  10 #include <sound/control.h>
  11 #include <sound/ac97_codec.h>
  12 #include <linux/gpio.h>
  13 
  14 #include <asm/olpc.h>
  15 #include "cs5535audio.h"
  16 
  17 #define DRV_NAME "cs5535audio-olpc"
  18 
  19 /*
  20  * OLPC has an additional feature on top of the regular AD1888 codec features.
  21  * It has an Analog Input mode that is switched into (after disabling the
  22  * High Pass Filter) via GPIO.  It is supported on B2 and later models.
  23  */
  24 void olpc_analog_input(struct snd_ac97 *ac97, int on)
  25 {
  26         int err;
  27 
  28         if (!machine_is_olpc())
  29                 return;
  30 
  31         /* update the High Pass Filter (via AC97_AD_TEST2) */
  32         err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
  33                         1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT);
  34         if (err < 0) {
  35                 dev_err(ac97->bus->card->dev,
  36                         "setting High Pass Filter - %d\n", err);
  37                 return;
  38         }
  39 
  40         /* set Analog Input through GPIO */
  41         gpio_set_value(OLPC_GPIO_MIC_AC, on);
  42 }
  43 
  44 /*
  45  * OLPC XO-1's V_REFOUT is a mic bias enable.
  46  */
  47 void olpc_mic_bias(struct snd_ac97 *ac97, int on)
  48 {
  49         int err;
  50 
  51         if (!machine_is_olpc())
  52                 return;
  53 
  54         on = on ? 0 : 1;
  55         err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
  56                         1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT);
  57         if (err < 0)
  58                 dev_err(ac97->bus->card->dev, "setting MIC Bias - %d\n", err);
  59 }
  60 
  61 static int olpc_dc_info(struct snd_kcontrol *kctl,
  62                 struct snd_ctl_elem_info *uinfo)
  63 {
  64         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  65         uinfo->count = 1;
  66         uinfo->value.integer.min = 0;
  67         uinfo->value.integer.max = 1;
  68         return 0;
  69 }
  70 
  71 static int olpc_dc_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
  72 {
  73         v->value.integer.value[0] = gpio_get_value(OLPC_GPIO_MIC_AC);
  74         return 0;
  75 }
  76 
  77 static int olpc_dc_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
  78 {
  79         struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl);
  80 
  81         olpc_analog_input(cs5535au->ac97, v->value.integer.value[0]);
  82         return 1;
  83 }
  84 
  85 static int olpc_mic_info(struct snd_kcontrol *kctl,
  86                 struct snd_ctl_elem_info *uinfo)
  87 {
  88         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  89         uinfo->count = 1;
  90         uinfo->value.integer.min = 0;
  91         uinfo->value.integer.max = 1;
  92         return 0;
  93 }
  94 
  95 static int olpc_mic_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
  96 {
  97         struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl);
  98         struct snd_ac97 *ac97 = cs5535au->ac97;
  99         int i;
 100 
 101         i = (snd_ac97_read(ac97, AC97_AD_MISC) >> AC97_AD_VREFD_SHIFT) & 0x1;
 102         v->value.integer.value[0] = i ? 0 : 1;
 103         return 0;
 104 }
 105 
 106 static int olpc_mic_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
 107 {
 108         struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl);
 109 
 110         olpc_mic_bias(cs5535au->ac97, v->value.integer.value[0]);
 111         return 1;
 112 }
 113 
 114 static struct snd_kcontrol_new olpc_cs5535audio_ctls[] = {
 115 {
 116         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 117         .name = "DC Mode Enable",
 118         .info = olpc_dc_info,
 119         .get = olpc_dc_get,
 120         .put = olpc_dc_put,
 121         .private_value = 0,
 122 },
 123 {
 124         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 125         .name = "MIC Bias Enable",
 126         .info = olpc_mic_info,
 127         .get = olpc_mic_get,
 128         .put = olpc_mic_put,
 129         .private_value = 0,
 130 },
 131 };
 132 
 133 void olpc_prequirks(struct snd_card *card,
 134                     struct snd_ac97_template *ac97)
 135 {
 136         if (!machine_is_olpc())
 137                 return;
 138 
 139         /* invert EAPD if on an OLPC B3 or higher */
 140         if (olpc_board_at_least(olpc_board_pre(0xb3)))
 141                 ac97->scaps |= AC97_SCAP_INV_EAPD;
 142 }
 143 
 144 int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
 145 {
 146         struct snd_ctl_elem_id elem;
 147         int i, err;
 148 
 149         if (!machine_is_olpc())
 150                 return 0;
 151 
 152         if (gpio_request(OLPC_GPIO_MIC_AC, DRV_NAME)) {
 153                 dev_err(card->dev, "unable to allocate MIC GPIO\n");
 154                 return -EIO;
 155         }
 156         gpio_direction_output(OLPC_GPIO_MIC_AC, 0);
 157 
 158         /* drop the original AD1888 HPF control */
 159         memset(&elem, 0, sizeof(elem));
 160         elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 161         strlcpy(elem.name, "High Pass Filter Enable", sizeof(elem.name));
 162         snd_ctl_remove_id(card, &elem);
 163 
 164         /* drop the original V_REFOUT control */
 165         memset(&elem, 0, sizeof(elem));
 166         elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 167         strlcpy(elem.name, "V_REFOUT Enable", sizeof(elem.name));
 168         snd_ctl_remove_id(card, &elem);
 169 
 170         /* add the OLPC-specific controls */
 171         for (i = 0; i < ARRAY_SIZE(olpc_cs5535audio_ctls); i++) {
 172                 err = snd_ctl_add(card, snd_ctl_new1(&olpc_cs5535audio_ctls[i],
 173                                 ac97->private_data));
 174                 if (err < 0) {
 175                         gpio_free(OLPC_GPIO_MIC_AC);
 176                         return err;
 177                 }
 178         }
 179 
 180         /* turn off the mic by default */
 181         olpc_mic_bias(ac97, 0);
 182         return 0;
 183 }
 184 
 185 void olpc_quirks_cleanup(void)
 186 {
 187         gpio_free(OLPC_GPIO_MIC_AC);
 188 }

/* [<][>][^][v][top][bottom][index][help] */