aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ice1712/revo.c
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/pci/ice1712/revo.c
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/pci/ice1712/revo.c')
-rw-r--r--sound/pci/ice1712/revo.c132
1 files changed, 122 insertions, 10 deletions
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index d556de59b9ae..233e9a5a2e70 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -84,6 +84,102 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
84} 84}
85 85
86/* 86/*
87 * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1)
88 */
89
90static void revo_i2c_start(struct snd_i2c_bus *bus)
91{
92 struct snd_ice1712 *ice = bus->private_data;
93 snd_ice1712_save_gpio_status(ice);
94}
95
96static void revo_i2c_stop(struct snd_i2c_bus *bus)
97{
98 struct snd_ice1712 *ice = bus->private_data;
99 snd_ice1712_restore_gpio_status(ice);
100}
101
102static void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
103{
104 struct snd_ice1712 *ice = bus->private_data;
105 unsigned int mask, val;
106
107 val = 0;
108 if (clock)
109 val |= VT1724_REVO_I2C_CLOCK; /* write SCL */
110 if (data)
111 val |= VT1724_REVO_I2C_DATA; /* write SDA */
112 mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA;
113 ice->gpio.direction &= ~mask;
114 ice->gpio.direction |= val;
115 snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
116 snd_ice1712_gpio_set_mask(ice, ~mask);
117}
118
119static void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
120{
121 struct snd_ice1712 *ice = bus->private_data;
122 unsigned int val = 0;
123
124 if (clk)
125 val |= VT1724_REVO_I2C_CLOCK;
126 if (data)
127 val |= VT1724_REVO_I2C_DATA;
128 snd_ice1712_gpio_write_bits(ice,
129 VT1724_REVO_I2C_DATA |
130 VT1724_REVO_I2C_CLOCK, val);
131 udelay(5);
132}
133
134static int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack)
135{
136 struct snd_ice1712 *ice = bus->private_data;
137 int bit;
138
139 if (ack)
140 udelay(5);
141 bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0;
142 return bit;
143}
144
145static struct snd_i2c_bit_ops revo51_bit_ops = {
146 .start = revo_i2c_start,
147 .stop = revo_i2c_stop,
148 .direction = revo_i2c_direction,
149 .setlines = revo_i2c_setlines,
150 .getdata = revo_i2c_getdata,
151};
152
153static int revo51_i2c_init(struct snd_ice1712 *ice,
154 struct snd_pt2258 *pt)
155{
156 int err;
157
158 /* create the I2C bus */
159 err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
160 if (err < 0)
161 return err;
162
163 ice->i2c->private_data = ice;
164 ice->i2c->hw_ops.bit = &revo51_bit_ops;
165
166 /* create the I2C device */
167 err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40,
168 &ice->spec.revo51.dev);
169 if (err < 0)
170 return err;
171
172 pt->card = ice->card;
173 pt->i2c_bus = ice->i2c;
174 pt->i2c_dev = ice->spec.revo51.dev;
175 ice->spec.revo51.pt2258 = pt;
176
177 snd_pt2258_reset(pt);
178
179 return 0;
180}
181
182/*
87 * initialize the chips on M-Audio Revolution cards 183 * initialize the chips on M-Audio Revolution cards
88 */ 184 */
89 185
@@ -180,9 +276,9 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
180 .cif = 0, 276 .cif = 0,
181 .data_mask = VT1724_REVO_CDOUT, 277 .data_mask = VT1724_REVO_CDOUT,
182 .clk_mask = VT1724_REVO_CCLK, 278 .clk_mask = VT1724_REVO_CCLK,
183 .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 279 .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
184 .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2, 280 .cs_addr = VT1724_REVO_CS1,
185 .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 281 .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
186 .add_flags = VT1724_REVO_CCLK, /* high at init */ 282 .add_flags = VT1724_REVO_CCLK, /* high at init */
187 .mask_flags = 0, 283 .mask_flags = 0,
188}; 284};
@@ -198,13 +294,15 @@ static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
198 .cif = 0, 294 .cif = 0,
199 .data_mask = VT1724_REVO_CDOUT, 295 .data_mask = VT1724_REVO_CDOUT,
200 .clk_mask = VT1724_REVO_CCLK, 296 .clk_mask = VT1724_REVO_CCLK,
201 .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 297 .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
202 .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2, 298 .cs_addr = VT1724_REVO_CS0,
203 .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 299 .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
204 .add_flags = VT1724_REVO_CCLK, /* high at init */ 300 .add_flags = VT1724_REVO_CCLK, /* high at init */
205 .mask_flags = 0, 301 .mask_flags = 0,
206}; 302};
207 303
304static struct snd_pt2258 ptc_revo51_volume;
305
208static int __devinit revo_init(struct snd_ice1712 *ice) 306static int __devinit revo_init(struct snd_ice1712 *ice)
209{ 307{
210 struct snd_akm4xxx *ak; 308 struct snd_akm4xxx *ak;
@@ -243,14 +341,20 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
243 break; 341 break;
244 case VT1724_SUBDEVICE_REVOLUTION51: 342 case VT1724_SUBDEVICE_REVOLUTION51:
245 ice->akm_codecs = 2; 343 ice->akm_codecs = 2;
246 if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) 344 err = snd_ice1712_akm4xxx_init(ak, &akm_revo51,
345 &akm_revo51_priv, ice);
346 if (err < 0)
247 return err; 347 return err;
248 err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc, 348 err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc,
249 &akm_revo51_adc_priv, ice); 349 &akm_revo51_adc_priv, ice);
250 if (err < 0) 350 if (err < 0)
251 return err; 351 return err;
252 /* unmute all codecs - needed! */ 352 err = revo51_i2c_init(ice, &ptc_revo51_volume);
253 snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); 353 if (err < 0)
354 return err;
355 /* unmute all codecs */
356 snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
357 VT1724_REVO_MUTE);
254 break; 358 break;
255 } 359 }
256 360
@@ -264,10 +368,18 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice)
264 368
265 switch (ice->eeprom.subvendor) { 369 switch (ice->eeprom.subvendor) {
266 case VT1724_SUBDEVICE_REVOLUTION71: 370 case VT1724_SUBDEVICE_REVOLUTION71:
371 err = snd_ice1712_akm4xxx_build_controls(ice);
372 if (err < 0)
373 return err;
374 break;
267 case VT1724_SUBDEVICE_REVOLUTION51: 375 case VT1724_SUBDEVICE_REVOLUTION51:
268 err = snd_ice1712_akm4xxx_build_controls(ice); 376 err = snd_ice1712_akm4xxx_build_controls(ice);
269 if (err < 0) 377 if (err < 0)
270 return err; 378 return err;
379 err = snd_pt2258_build_controls(ice->spec.revo51.pt2258);
380 if (err < 0)
381 return err;
382 break;
271 } 383 }
272 return 0; 384 return 0;
273} 385}