aboutsummaryrefslogtreecommitdiffstats
path: root/sound/i2c
diff options
context:
space:
mode:
authorJochen Voss <voss@seehuhn.de>2006-10-04 12:08:43 -0400
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:00:05 -0500
commitfeaa6a74d852be40c0e717471aa92eead012052c (patch)
tree9ad326bb90037ebc10375e75f6b86c6ab74a0d2c /sound/i2c
parenta58e7cb16dfae8a3c1c98a7ab7ca02a9e9b38921 (diff)
[ALSA] Enable the analog loopback of the Revolution 5.1
Enable the analog loopback of the Revolution 5.1 card. This patch adds support for the PT2258 volume controller and modifies the Revolution 5.1 driver to make use of this facility. This allows to control the analog loopback of the card. Signed-off-by: Jochen Voss <voss@seehuhn.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/i2c')
-rw-r--r--sound/i2c/Makefile1
-rw-r--r--sound/i2c/other/Makefile4
-rw-r--r--sound/i2c/other/pt2258.c233
3 files changed, 236 insertions, 2 deletions
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile
index 816a2e7c88ca..45902d48c89c 100644
--- a/sound/i2c/Makefile
+++ b/sound/i2c/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SND) += other/
16# Toplevel Module Dependency 16# Toplevel Module Dependency
17obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o 17obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
18obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o 18obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
19obj-$(CONFIG_SND_ICE1724) += snd-i2c.o
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
index 2fe023ef00a7..77a8a7c75dd9 100644
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -6,11 +6,11 @@
6snd-ak4114-objs := ak4114.o 6snd-ak4114-objs := ak4114.o
7snd-ak4117-objs := ak4117.o 7snd-ak4117-objs := ak4117.o
8snd-ak4xxx-adda-objs := ak4xxx-adda.o 8snd-ak4xxx-adda-objs := ak4xxx-adda.o
9snd-pt2258-objs := pt2258.o
9snd-tea575x-tuner-objs := tea575x-tuner.o 10snd-tea575x-tuner-objs := tea575x-tuner.o
10 11
11# Module Dependency 12# Module Dependency
12obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o 13obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
13obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o 14obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
14obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o 15obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
15obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o
16obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o 16obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c
new file mode 100644
index 000000000000..50df1df2f2b9
--- /dev/null
+++ b/sound/i2c/other/pt2258.c
@@ -0,0 +1,233 @@
1/*
2 * ALSA Driver for the PT2258 volume controller.
3 *
4 * Copyright (c) 2006 Jochen Voss <voss@seehuhn.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <sound/core.h>
24#include <sound/control.h>
25#include <sound/tlv.h>
26#include <sound/i2c.h>
27#include <sound/pt2258.h>
28
29MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
30MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
31MODULE_LICENSE("GPL");
32
33#define PT2258_CMD_RESET 0xc0
34#define PT2258_CMD_UNMUTE 0xf8
35#define PT2258_CMD_MUTE 0xf9
36
37static const unsigned char pt2258_channel_code[12] = {
38 0x80, 0x90, /* channel 1: -10dB, -1dB */
39 0x40, 0x50, /* channel 2: -10dB, -1dB */
40 0x00, 0x10, /* channel 3: -10dB, -1dB */
41 0x20, 0x30, /* channel 4: -10dB, -1dB */
42 0x60, 0x70, /* channel 5: -10dB, -1dB */
43 0xa0, 0xb0 /* channel 6: -10dB, -1dB */
44};
45
46int snd_pt2258_reset(struct snd_pt2258 *pt)
47{
48 unsigned char bytes[2];
49 int i;
50
51 /* reset chip */
52 bytes[0] = PT2258_CMD_RESET;
53 snd_i2c_lock(pt->i2c_bus);
54 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
55 goto __error;
56 snd_i2c_unlock(pt->i2c_bus);
57
58 /* mute all channels */
59 pt->mute = 1;
60 bytes[0] = PT2258_CMD_MUTE;
61 snd_i2c_lock(pt->i2c_bus);
62 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
63 goto __error;
64 snd_i2c_unlock(pt->i2c_bus);
65
66 /* set all channels to 0dB */
67 for (i = 0; i < 6; ++i)
68 pt->volume[i] = 0;
69 bytes[0] = 0xd0;
70 bytes[1] = 0xe0;
71 snd_i2c_lock(pt->i2c_bus);
72 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
73 goto __error;
74 snd_i2c_unlock(pt->i2c_bus);
75
76 return 0;
77
78 __error:
79 snd_i2c_unlock(pt->i2c_bus);
80 snd_printk(KERN_ERR "PT2258 reset failed\n");
81 return -EIO;
82}
83
84static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
85 struct snd_ctl_elem_info *uinfo)
86{
87 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
88 uinfo->count = 2;
89 uinfo->value.integer.min = 0;
90 uinfo->value.integer.max = 79;
91 return 0;
92}
93
94static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
95 struct snd_ctl_elem_value *ucontrol)
96{
97 struct snd_pt2258 *pt = kcontrol->private_data;
98 int base = kcontrol->private_value;
99
100 /* chip does not support register reads */
101 ucontrol->value.integer.value[0] = 79 - pt->volume[base];
102 ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
103 return 0;
104}
105
106static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
107 struct snd_ctl_elem_value *ucontrol)
108{
109 struct snd_pt2258 *pt = kcontrol->private_data;
110 int base = kcontrol->private_value;
111 unsigned char bytes[2];
112 int val0, val1;
113
114 val0 = 79 - ucontrol->value.integer.value[0];
115 val1 = 79 - ucontrol->value.integer.value[1];
116 if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
117 return 0;
118
119 pt->volume[base] = val0;
120 bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
121 bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
122 snd_i2c_lock(pt->i2c_bus);
123 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
124 goto __error;
125 snd_i2c_unlock(pt->i2c_bus);
126
127 pt->volume[base + 1] = val1;
128 bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
129 bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
130 snd_i2c_lock(pt->i2c_bus);
131 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
132 goto __error;
133 snd_i2c_unlock(pt->i2c_bus);
134
135 return 1;
136
137 __error:
138 snd_i2c_unlock(pt->i2c_bus);
139 snd_printk(KERN_ERR "PT2258 access failed\n");
140 return -EIO;
141}
142
143static int pt2258_switch_info(struct snd_kcontrol *kcontrol,
144 struct snd_ctl_elem_info *uinfo)
145{
146 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
147 uinfo->count = 1;
148 uinfo->value.integer.min = 0;
149 uinfo->value.integer.max = 1;
150 return 0;
151}
152
153static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
154 struct snd_ctl_elem_value *ucontrol)
155{
156 struct snd_pt2258 *pt = kcontrol->private_data;
157
158 ucontrol->value.integer.value[0] = !pt->mute;
159 return 0;
160}
161
162static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
163 struct snd_ctl_elem_value *ucontrol)
164{
165 struct snd_pt2258 *pt = kcontrol->private_data;
166 unsigned char bytes[2];
167 int val;
168
169 val = !ucontrol->value.integer.value[0];
170 if (pt->mute == val)
171 return 0;
172
173 pt->mute = val;
174 bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
175 snd_i2c_lock(pt->i2c_bus);
176 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
177 goto __error;
178 snd_i2c_unlock(pt->i2c_bus);
179
180 return 1;
181
182 __error:
183 snd_i2c_unlock(pt->i2c_bus);
184 snd_printk(KERN_ERR "PT2258 access failed 2\n");
185 return -EIO;
186}
187
188static DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
189
190int snd_pt2258_build_controls(struct snd_pt2258 *pt)
191{
192 struct snd_kcontrol_new knew;
193 char *names[3] = {
194 "Mic Loopback Playback Volume",
195 "Line Loopback Playback Volume",
196 "CD Loopback Playback Volume"
197 };
198 int i, err;
199
200 for (i = 0; i < 3; ++i) {
201 memset(&knew, 0, sizeof(knew));
202 knew.name = names[i];
203 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
204 knew.count = 1;
205 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
206 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
207 knew.private_value = 2 * i;
208 knew.info = pt2258_stereo_volume_info;
209 knew.get = pt2258_stereo_volume_get;
210 knew.put = pt2258_stereo_volume_put;
211 knew.tlv.p = pt2258_db_scale;
212
213 err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
214 if (err < 0)
215 return err;
216 }
217
218 memset(&knew, 0, sizeof(knew));
219 knew.name = "Loopback Switch";
220 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
221 knew.info = pt2258_switch_info;
222 knew.get = pt2258_switch_get;
223 knew.put = pt2258_switch_put;
224 knew.access = 0;
225 err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
226 if (err < 0)
227 return err;
228
229 return 0;
230}
231
232EXPORT_SYMBOL(snd_pt2258_reset);
233EXPORT_SYMBOL(snd_pt2258_build_controls);