root/sound/i2c/other/pt2258.c

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

DEFINITIONS

This source file includes following definitions.
  1. snd_pt2258_reset
  2. pt2258_stereo_volume_info
  3. pt2258_stereo_volume_get
  4. pt2258_stereo_volume_put
  5. pt2258_switch_get
  6. pt2258_switch_put
  7. snd_pt2258_build_controls

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *   ALSA Driver for the PT2258 volume controller.
   4  *
   5  *      Copyright (c) 2006  Jochen Voss <voss@seehuhn.de>
   6  */      
   7 
   8 #include <sound/core.h>
   9 #include <sound/control.h>
  10 #include <sound/tlv.h>
  11 #include <sound/i2c.h>
  12 #include <sound/pt2258.h>
  13 #include <linux/module.h>
  14 
  15 MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
  16 MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
  17 MODULE_LICENSE("GPL");
  18 
  19 #define PT2258_CMD_RESET 0xc0
  20 #define PT2258_CMD_UNMUTE 0xf8
  21 #define PT2258_CMD_MUTE 0xf9
  22 
  23 static const unsigned char pt2258_channel_code[12] = {
  24         0x80, 0x90,             /* channel 1: -10dB, -1dB */
  25         0x40, 0x50,             /* channel 2: -10dB, -1dB */
  26         0x00, 0x10,             /* channel 3: -10dB, -1dB */
  27         0x20, 0x30,             /* channel 4: -10dB, -1dB */
  28         0x60, 0x70,             /* channel 5: -10dB, -1dB */
  29         0xa0, 0xb0              /* channel 6: -10dB, -1dB */
  30 };
  31 
  32 int snd_pt2258_reset(struct snd_pt2258 *pt)
  33 {
  34         unsigned char bytes[2];
  35         int i;
  36 
  37         /* reset chip */
  38         bytes[0] = PT2258_CMD_RESET;
  39         snd_i2c_lock(pt->i2c_bus);
  40         if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
  41                 goto __error;
  42         snd_i2c_unlock(pt->i2c_bus);
  43 
  44         /* mute all channels */
  45         pt->mute = 1;
  46         bytes[0] = PT2258_CMD_MUTE;
  47         snd_i2c_lock(pt->i2c_bus);
  48         if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
  49                 goto __error;
  50         snd_i2c_unlock(pt->i2c_bus);
  51 
  52         /* set all channels to 0dB */
  53         for (i = 0; i < 6; ++i)
  54                 pt->volume[i] = 0;
  55         bytes[0] = 0xd0;
  56         bytes[1] = 0xe0;
  57         snd_i2c_lock(pt->i2c_bus);
  58         if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
  59                 goto __error;
  60         snd_i2c_unlock(pt->i2c_bus);
  61 
  62         return 0;
  63 
  64       __error:
  65         snd_i2c_unlock(pt->i2c_bus);
  66         snd_printk(KERN_ERR "PT2258 reset failed\n");
  67         return -EIO;
  68 }
  69 
  70 static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
  71                                      struct snd_ctl_elem_info *uinfo)
  72 {
  73         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  74         uinfo->count = 2;
  75         uinfo->value.integer.min = 0;
  76         uinfo->value.integer.max = 79;
  77         return 0;
  78 }
  79 
  80 static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
  81                                     struct snd_ctl_elem_value *ucontrol)
  82 {
  83         struct snd_pt2258 *pt = kcontrol->private_data;
  84         int base = kcontrol->private_value;
  85 
  86         /* chip does not support register reads */
  87         ucontrol->value.integer.value[0] = 79 - pt->volume[base];
  88         ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
  89         return 0;
  90 }
  91 
  92 static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
  93                                     struct snd_ctl_elem_value *ucontrol)
  94 {
  95         struct snd_pt2258 *pt = kcontrol->private_data;
  96         int base = kcontrol->private_value;
  97         unsigned char bytes[2];
  98         int val0, val1;
  99 
 100         val0 = 79 - ucontrol->value.integer.value[0];
 101         val1 = 79 - ucontrol->value.integer.value[1];
 102         if (val0 < 0 || val0 > 79 || val1 < 0 || val1 > 79)
 103                 return -EINVAL;
 104         if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
 105                 return 0;
 106 
 107         pt->volume[base] = val0;
 108         bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
 109         bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
 110         snd_i2c_lock(pt->i2c_bus);
 111         if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
 112                 goto __error;
 113         snd_i2c_unlock(pt->i2c_bus);
 114 
 115         pt->volume[base + 1] = val1;
 116         bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
 117         bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
 118         snd_i2c_lock(pt->i2c_bus);
 119         if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
 120                 goto __error;
 121         snd_i2c_unlock(pt->i2c_bus);
 122 
 123         return 1;
 124 
 125       __error:
 126         snd_i2c_unlock(pt->i2c_bus);
 127         snd_printk(KERN_ERR "PT2258 access failed\n");
 128         return -EIO;
 129 }
 130 
 131 #define pt2258_switch_info      snd_ctl_boolean_mono_info
 132 
 133 static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
 134                              struct snd_ctl_elem_value *ucontrol)
 135 {
 136         struct snd_pt2258 *pt = kcontrol->private_data;
 137 
 138         ucontrol->value.integer.value[0] = !pt->mute;
 139         return 0;
 140 }
 141 
 142 static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
 143                              struct snd_ctl_elem_value *ucontrol)
 144 {
 145         struct snd_pt2258 *pt = kcontrol->private_data;
 146         unsigned char bytes[2];
 147         int val;
 148 
 149         val = !ucontrol->value.integer.value[0];
 150         if (pt->mute == val)
 151                 return 0;
 152 
 153         pt->mute = val;
 154         bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
 155         snd_i2c_lock(pt->i2c_bus);
 156         if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
 157                 goto __error;
 158         snd_i2c_unlock(pt->i2c_bus);
 159 
 160         return 1;
 161 
 162       __error:
 163         snd_i2c_unlock(pt->i2c_bus);
 164         snd_printk(KERN_ERR "PT2258 access failed 2\n");
 165         return -EIO;
 166 }
 167 
 168 static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
 169 
 170 int snd_pt2258_build_controls(struct snd_pt2258 *pt)
 171 {
 172         struct snd_kcontrol_new knew;
 173         char *names[3] = {
 174                 "Mic Loopback Playback Volume",
 175                 "Line Loopback Playback Volume",
 176                 "CD Loopback Playback Volume"
 177         };
 178         int i, err;
 179 
 180         for (i = 0; i < 3; ++i) {
 181                 memset(&knew, 0, sizeof(knew));
 182                 knew.name = names[i];
 183                 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 184                 knew.count = 1;
 185                 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 186                     SNDRV_CTL_ELEM_ACCESS_TLV_READ;
 187                 knew.private_value = 2 * i;
 188                 knew.info = pt2258_stereo_volume_info;
 189                 knew.get = pt2258_stereo_volume_get;
 190                 knew.put = pt2258_stereo_volume_put;
 191                 knew.tlv.p = pt2258_db_scale;
 192 
 193                 err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
 194                 if (err < 0)
 195                         return err;
 196         }
 197 
 198         memset(&knew, 0, sizeof(knew));
 199         knew.name = "Loopback Switch";
 200         knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 201         knew.info = pt2258_switch_info;
 202         knew.get = pt2258_switch_get;
 203         knew.put = pt2258_switch_put;
 204         knew.access = 0;
 205         err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
 206         if (err < 0)
 207                 return err;
 208 
 209         return 0;
 210 }
 211 
 212 EXPORT_SYMBOL(snd_pt2258_reset);
 213 EXPORT_SYMBOL(snd_pt2258_build_controls);

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