* [PATCH] ice1724: Add input switch for Aux-in on Aureon Universe
@ 2006-03-30 0:58 Maximilian Rehkopf
0 siblings, 0 replies; only message in thread
From: Maximilian Rehkopf @ 2006-03-30 0:58 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 1061 bytes --]
Hi,
Terratec Aureon 7.1 Universe cards (and maybe others?) allow the user to
switch the Aux input of the STAC9744 between three different sources
(on-board Aux jack, Wavetable from the front panel, Rear Line-In).
The diff adds a mixer control to switch between the three inputs.
For switching, a PCA9554 (8-line GPIO with I²C interface) and a 74HC4052
(dual 4-way mux/demux) are used. Output 0 and 1 of the PCA9554 are
connected to the select pins of the 74HC4052. The I²C interface of the
PCA9554 is connected to the card's internal SPI bus which is also used
to control the WM8770 and CS8415.
For additional notes see the diff.
Diff created against CVS source from two days ago.
Note: there are also lines connected to output 2 and 3 of the PCA9554,
which I believe control the on/off state of the "Line In" LED on the
front panel and the selection between Coaxial and Optical S/PDIF on the
front panel.
It's my first attempt at a half decent driver hack, I hope it doesn't
break too much...
Cheers,
--
Maximilian Rehkopf
[-- Attachment #2: aureon-inmux.diff --]
[-- Type: text/plain, Size: 7978 bytes --]
Summary: Add Aux input switch control for Aureon Universe
This patch adds a mixer control which allows the user to switch the Aux
playback between the internal Aux jack, Wavetable, and Rear Line-In on
Aureon Universe cards.
For switching, a PCA9554 (8-line GPIO with I²C interface) and a 74HC4052
(dual 4-way mux/demux) are used. Output 0 and 1 of the PCA9554 are
connected to the select pins of the 74HC4052. The I²C interface of the
PCA9554 is connected to the card's internal SPI bus which is also used
to control the WM8770 and CS8415. SPI and I²C on the same lines...
To communicate with the PCA9554 the WM8770 and CS8415 are disabled and
an I²C Stop Condition is generated before the Start Condition (needed
for synchronisation because other SPI traffic appear to confuse the
PCA9554). Then a normal I²C data transfer takes place. Programming must
be done ridiculously slow; in theory, 4.7µs is the minimum delay time
for normal-speed I²C according to the datasheet, but even with 10µs
switching was unreliable. The Windows driver from Terratec does the
programming very slowly, too (checked with an oscilloscope).
PCA9554 datasheet:
http://www.semiconductors.philips.com/acrobat/datasheets/PCA9554_9554A_6.pdf
74HC4052 datasheet:
http://www.semiconductors.philips.com/acrobat/datasheets/74HC_HCT4052_4.pdf
Signed-off-by: Maximilian Rehkopf <otakon@gmx.net>
--- alsa-kernel.vanilla/pci/ice1712/aureon.c 2006-03-20 19:31:57.000000000 +0100
+++ alsa-kernel.pca9554/pci/ice1712/aureon.c 2006-03-30 02:44:24.000000000 +0200
@@ -87,6 +87,150 @@
#define CS8415_C_BUFFER 0x20
#define CS8415_ID 0x7F
+/* PCA9554 registers */
+#define PCA9554_DEV 0x40 /* I2C device address */
+#define PCA9554_IN 0x00 /* input port */
+#define PCA9554_OUT 0x01 /* output port */
+#define PCA9554_INVERT 0x02 /* input invert */
+#define PCA9554_DIR 0x03 /* port directions */
+
+/*
+ * Aureon Universe additional controls using PCA9554
+ */
+
+/*
+ * Send data to pca9554
+ */
+static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg, unsigned char data)
+{
+ unsigned int tmp;
+ int i, j;
+ unsigned char dev=PCA9554_DEV; /* ID 0100000, write */
+ unsigned char val=0;
+
+ tmp = snd_ice1712_gpio_read(ice);
+
+ snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK|
+ AUREON_WM_RW|AUREON_WM_CS|
+ AUREON_CS8415_CS));
+ tmp |= AUREON_WM_RW;
+ tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */
+
+ tmp &= ~AUREON_SPI_MOSI;
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+
+/*
+ * send i2c stop condition and start condition
+ * to obtain sane state
+ */
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+ tmp |= AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(100);
+ tmp &= ~AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(100);
+/*
+ * send device address, command and value,
+ * skipping ack cycles inbetween
+ */
+ for(j = 0; j < 3; j++) {
+ switch(j) {
+ case 0: val=dev; break;
+ case 1: val=reg; break;
+ case 2: val=data; break;
+ }
+ for (i = 7; i >= 0; i--) {
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ if (val & (1 << i))
+ tmp |= AUREON_SPI_MOSI;
+ else
+ tmp &= ~AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ }
+
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ }
+ tmp &= ~AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp &= ~AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(40);
+ tmp |= AUREON_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(50);
+ tmp |= AUREON_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(100);
+}
+
+static int aureon_universe_inmux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+
+ char* texts[3]={"Internal Aux", "Wavetable", "Rear Line-In"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if(uinfo->value.enumerated.item >= uinfo->value.enumerated.items) {
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ }
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int aureon_universe_inmux_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+
+ val=ice->spec.aureon.pca9554_out;
+
+ ucontrol->value.integer.value[0]=val;
+ return 0;
+}
+
+static int aureon_universe_inmux_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char oval, nval;
+ int change;
+
+ snd_ice1712_save_gpio_status(ice);
+
+ oval=ice->spec.aureon.pca9554_out;
+ nval=ucontrol->value.integer.value[0];
+ if((change = (oval!=nval))) {
+ aureon_pca9554_write(ice, PCA9554_OUT, nval);
+ }
+ ice->spec.aureon.pca9554_out=nval;
+
+ snd_ice1712_restore_gpio_status(ice);
+
+ return change;
+}
+
+
static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, unsigned short val) {
unsigned int tmp;
@@ -1598,7 +1742,15 @@
.get = aureon_ac97_vol_get,
.put = aureon_ac97_vol_put,
.private_value = AC97_VIDEO|AUREON_AC97_STEREO
- }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Aux Source",
+ .info = aureon_universe_inmux_info,
+ .get = aureon_universe_inmux_get,
+ .put = aureon_universe_inmux_put
+ }
+
};
@@ -1856,6 +2008,10 @@
}
snd_ice1712_restore_gpio_status(ice);
+
+ /* initialize PCA9554 pin directions & set default input*/
+ aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
+ aureon_pca9554_write(ice, PCA9554_OUT, 0x00); // internal AUX
ice->spec.aureon.master[0] = WM_VOL_MUTE;
ice->spec.aureon.master[1] = WM_VOL_MUTE;
--- alsa-kernel.vanilla/pci/ice1712/ice1712.h 2006-02-08 08:40:33.000000000 +0100
+++ alsa-kernel.pca9554/pci/ice1712/ice1712.h 2006-03-28 11:15:53.000000000 +0200
@@ -373,6 +373,7 @@
unsigned int cs8415_mux;
unsigned short master[2];
unsigned short vol[8];
+ unsigned char pca9554_out;
} aureon;
/* AC97 register cache for Phase28 */
struct phase28_spec {
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2006-03-30 0:58 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-03-30 0:58 [PATCH] ice1724: Add input switch for Aux-in on Aureon Universe Maximilian Rehkopf
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.