summaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorJochen Voss <voss@seehuhn.de>2006-10-04 18:08:43 +0200
committerJaroslav Kysela <perex@suse.cz>2007-02-09 09:00:05 +0100
commitfeaa6a74d852be40c0e717471aa92eead012052c (patch)
tree9ad326bb90037ebc10375e75f6b86c6ab74a0d2c /sound/pci
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')
-rw-r--r--sound/pci/ice1712/ice1712.h14
-rw-r--r--sound/pci/ice1712/revo.c132
-rw-r--r--sound/pci/ice1712/revo.h6
3 files changed, 140 insertions, 12 deletions
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index ce27eac40d4..064542bf3af 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -28,6 +28,7 @@
#include <sound/i2c.h>
#include <sound/ak4xxx-adda.h>
#include <sound/ak4114.h>
+#include <sound/pt2258.h>
#include <sound/pcm.h>
#include <sound/mpu401.h>
@@ -381,6 +382,11 @@ struct snd_ice1712 {
unsigned short master[2];
unsigned short vol[8];
} phase28;
+ /* a non-standard I2C device for revo51 */
+ struct revo51_spec {
+ struct snd_i2c_device *dev;
+ struct snd_pt2258 *pt2258;
+ } revo51;
/* Hoontech-specific setting */
struct hoontech_spec {
unsigned char boxbits[4];
@@ -462,6 +468,14 @@ static inline void snd_ice1712_gpio_write_bits(struct snd_ice1712 *ice,
snd_ice1712_gpio_write(ice, mask & bits);
}
+static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice,
+ unsigned int mask)
+{
+ ice->gpio.direction &= ~mask;
+ snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+ return (snd_ice1712_gpio_read(ice) & mask);
+}
+
int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template,
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index d556de59b9a..233e9a5a2e7 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)
}
/*
+ * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1)
+ */
+
+static void revo_i2c_start(struct snd_i2c_bus *bus)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ snd_ice1712_save_gpio_status(ice);
+}
+
+static void revo_i2c_stop(struct snd_i2c_bus *bus)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ snd_ice1712_restore_gpio_status(ice);
+}
+
+static void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ unsigned int mask, val;
+
+ val = 0;
+ if (clock)
+ val |= VT1724_REVO_I2C_CLOCK; /* write SCL */
+ if (data)
+ val |= VT1724_REVO_I2C_DATA; /* write SDA */
+ mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA;
+ ice->gpio.direction &= ~mask;
+ ice->gpio.direction |= val;
+ snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+ snd_ice1712_gpio_set_mask(ice, ~mask);
+}
+
+static void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ unsigned int val = 0;
+
+ if (clk)
+ val |= VT1724_REVO_I2C_CLOCK;
+ if (data)
+ val |= VT1724_REVO_I2C_DATA;
+ snd_ice1712_gpio_write_bits(ice,
+ VT1724_REVO_I2C_DATA |
+ VT1724_REVO_I2C_CLOCK, val);
+ udelay(5);
+}
+
+static int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ int bit;
+
+ if (ack)
+ udelay(5);
+ bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0;
+ return bit;
+}
+
+static struct snd_i2c_bit_ops revo51_bit_ops = {
+ .start = revo_i2c_start,
+ .stop = revo_i2c_stop,
+ .direction = revo_i2c_direction,
+ .setlines = revo_i2c_setlines,
+ .getdata = revo_i2c_getdata,
+};
+
+static int revo51_i2c_init(struct snd_ice1712 *ice,
+ struct snd_pt2258 *pt)
+{
+ int err;
+
+ /* create the I2C bus */
+ err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
+ if (err < 0)
+ return err;
+
+ ice->i2c->private_data = ice;
+ ice->i2c->hw_ops.bit = &revo51_bit_ops;
+
+ /* create the I2C device */
+ err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40,
+ &ice->spec.revo51.dev);
+ if (err < 0)
+ return err;
+
+ pt->card = ice->card;
+ pt->i2c_bus = ice->i2c;
+ pt->i2c_dev = ice->spec.revo51.dev;
+ ice->spec.revo51.pt2258 = pt;
+
+ snd_pt2258_reset(pt);
+
+ return 0;
+}
+
+/*
* initialize the chips on M-Audio Revolution cards
*/
@@ -180,9 +276,9 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
.clk_mask = VT1724_REVO_CCLK,
- .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .cs_addr = VT1724_REVO_CS1,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
.add_flags = VT1724_REVO_CCLK, /* high at init */
.mask_flags = 0,
};
@@ -198,13 +294,15 @@ static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
.clk_mask = VT1724_REVO_CCLK,
- .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
- .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .cs_addr = VT1724_REVO_CS0,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
.add_flags = VT1724_REVO_CCLK, /* high at init */
.mask_flags = 0,
};
+static struct snd_pt2258 ptc_revo51_volume;
+
static int __devinit revo_init(struct snd_ice1712 *ice)
{
struct snd_akm4xxx *ak;
@@ -243,14 +341,20 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
break;
case VT1724_SUBDEVICE_REVOLUTION51:
ice->akm_codecs = 2;
- if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0)
+ err = snd_ice1712_akm4xxx_init(ak, &akm_revo51,
+ &akm_revo51_priv, ice);
+ if (err < 0)
return err;
- err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc,
+ err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc,
&akm_revo51_adc_priv, ice);
if (err < 0)
return err;
- /* unmute all codecs - needed! */
- snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+ err = revo51_i2c_init(ice, &ptc_revo51_volume);
+ if (err < 0)
+ return err;
+ /* unmute all codecs */
+ snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
+ VT1724_REVO_MUTE);
break;
}
@@ -264,10 +368,18 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice)
switch (ice->eeprom.subvendor) {
case VT1724_SUBDEVICE_REVOLUTION71:
+ err = snd_ice1712_akm4xxx_build_controls(ice);
+ if (err < 0)
+ return err;
+ break;
case VT1724_SUBDEVICE_REVOLUTION51:
err = snd_ice1712_akm4xxx_build_controls(ice);
if (err < 0)
return err;
+ err = snd_pt2258_build_controls(ice->spec.revo51.pt2258);
+ if (err < 0)
+ return err;
+ break;
}
return 0;
}
diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h
index efbb86ec328..c70adaf017c 100644
--- a/sound/pci/ice1712/revo.h
+++ b/sound/pci/ice1712/revo.h
@@ -42,9 +42,11 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
#define VT1724_REVO_CCLK 0x02
#define VT1724_REVO_CDIN 0x04 /* not used */
#define VT1724_REVO_CDOUT 0x08
-#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */
+#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for (revo51) */
#define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */
-#define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */
+#define VT1724_REVO_CS2 0x40 /* surround AKM4355 CS (revo71) */
+#define VT1724_REVO_I2C_DATA 0x40 /* I2C: PT 2258 SDA (on revo51) */
+#define VT1724_REVO_I2C_CLOCK 0x80 /* I2C: PT 2258 SCL (on revo51) */
#define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */
#endif /* __SOUND_REVO_H */