summaryrefslogtreecommitdiff
path: root/kernel/drv/oss_envy24ht/envy24ht_revo71.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
commit1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch)
tree4495d23e7b54ab5700e3839081e797c1eafe0db9 /kernel/drv/oss_envy24ht/envy24ht_revo71.c
downloadoss4-upstream.tar.gz
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'kernel/drv/oss_envy24ht/envy24ht_revo71.c')
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_revo71.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/kernel/drv/oss_envy24ht/envy24ht_revo71.c b/kernel/drv/oss_envy24ht/envy24ht_revo71.c
new file mode 100644
index 0000000..fd3a9bb
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_revo71.c
@@ -0,0 +1,338 @@
+/*
+ * Purpose: Low level routines for M Audio Revolution 7.1
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+#include "oss_envy24ht_cfg.h"
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+#define BIT(x) (1<<(x))
+
+#define CCLK (1<<1)
+#define CDIN (1<<2) /* Currently not connected */
+#define CDTI (1<<3)
+#define CSDIG (1<<4)
+#define CSN1 (1<<5)
+#define CSN2 (1<<6)
+
+#define WRITEMASK (CSN1|CSN2|CDTI|CCLK)
+
+#define DAC1 0x01 /* 2ch Front DAC (AK4381) */
+#define DAC2 0x03 /* 6ch Surround DAC (AK4355) */
+
+
+static void
+writereg (envy24ht_devc * devc, int csn, int chip, unsigned char reg,
+ unsigned char val)
+{
+ int i;
+ unsigned short v, tmp;
+
+ tmp = INW (devc->osdev, devc->ccs_base + 0x14) & ~(csn | CCLK | CDTI);
+ OUTW (devc->osdev, tmp, devc->ccs_base + 0x14);
+
+ reg = (reg & 0x1f) | 0x20 | (chip << 6); /* Chip address (variable), write */
+ /* Address bits */
+
+ for (i = 7; i >= 0; i--)
+ {
+ v = (reg & (1 << i)) ? CDTI : 0;
+ OUTW (devc->osdev, v | tmp, devc->ccs_base + 0x14); /* Tack */
+ OUTW (devc->osdev, v | CCLK | tmp, devc->ccs_base + 0x14); /* Tick */
+ }
+
+ /* Data bits */
+
+ for (i = 7; i >= 0; i--)
+ {
+ v = (val & (1 << i)) ? CDTI : 0;
+ OUTW (devc->osdev, v | tmp, devc->ccs_base + 0x14); /* Tack */
+ OUTW (devc->osdev, v | CCLK | tmp, devc->ccs_base + 0x14); /* Tick */
+ }
+
+ OUTW (devc->osdev, v | tmp, devc->ccs_base + 0x14); /* Tack */
+ OUTW (devc->osdev, tmp | csn | CDTI | CCLK, devc->ccs_base + 0x14); /* Release */
+
+}
+
+static void
+writedac1 (envy24ht_devc * devc, unsigned char reg, unsigned char data)
+{
+ writereg (devc, CSN1, DAC1, reg, data);
+ devc->dac1val[reg] = data;
+}
+
+static void
+writedac2 (envy24ht_devc * devc, unsigned char reg, unsigned char data)
+{
+ writereg (devc, CSN2, DAC2, reg, data);
+ devc->dac2val[reg] = data;
+}
+
+static void
+revo71_mute (envy24ht_devc * devc, int mute)
+{
+ if (mute)
+ {
+ writedac1 (devc, 1, devc->dac1val[1] | BIT (0));
+ writedac2 (devc, 1, devc->dac2val[1] | BIT (1));
+ oss_udelay (1000);
+/* OUTB (devc->osdev, INB (devc->osdev, devc->ccs_base + 0x1e) & ~BIT(22-16), */
+/* devc->ccs_base + 0x1e); */
+ }
+ else
+ {
+/* OUTB (devc->osdev, INB (devc->osdev, devc->ccs_base + 0x1e) | ~BIT(22-16), */
+/* devc->ccs_base + 0x1e); */
+ oss_udelay (1000);
+ writedac1 (devc, 1, devc->dac1val[1] & ~BIT (0));
+ writedac2 (devc, 1, devc->dac2val[1] & ~BIT (1));
+ }
+}
+
+static void
+revo71_card_init (envy24ht_devc * devc)
+{
+ int i;
+
+ OUTL (devc->osdev, WRITEMASK | 0x400000, devc->ccs_base + 0x18); /* GPIO direction */
+ OUTW (devc->osdev, ~WRITEMASK, devc->ccs_base + 0x16); /* GPIO write mask */
+ OUTB (devc->osdev, 0x40, devc->ccs_base + 0x1f);
+ OUTW (devc->osdev, WRITEMASK, devc->ccs_base + 0x14); /* Initial bit state */
+
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1a); /* GPIO direction for bits 16:22 */
+ OUTB (devc->osdev, 0x00, devc->ccs_base + 0x1f); /* GPIO mask for bits 16:22 */
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1e); /* GPIO data for bits 16:22 */
+
+#if 0
+ for (i = 0; i < 7; i++)
+ {
+ OUTW (devc->osdev, 1 << i, devc->ccs_base + 0x14); /* Test bit */
+ OUTW (devc->osdev, 0, devc->ccs_base + 0x14); /* Test bit */
+ }
+#endif
+
+ OUTW (devc->osdev, WRITEMASK, devc->ccs_base + 0x14); /* Initial bit state */
+ oss_udelay (10);
+
+ revo71_mute (devc, 1);
+/*
+ * Init front DAC (AK4381)
+ */
+ writedac1 (devc, 0x00, 0x0c);
+ writedac1 (devc, 0x01, 0x03);
+ writedac1 (devc, 0x02, 0x00);
+
+ writedac1 (devc, 0x03, 0xff); /* Initial volume */
+ writedac1 (devc, 0x04, 0xff); /* Initial volume */
+
+ writedac1 (devc, 0x00, 0x0f);
+/*
+ * Init surround DAC (AK4355)
+ */
+ writedac2 (devc, 0x01, 0x02);
+ writedac2 (devc, 0x00, 0x06);
+ oss_udelay (10);
+ writedac2 (devc, 0x02, 0x0e);
+ writedac2 (devc, 0x03, 0x01);
+
+ for (i = 4; i < 10; i++)
+ writedac2 (devc, i, 0xff); /* Initial volumes */
+ writedac2 (devc, 0x0a, 0x00);
+
+ writedac2 (devc, 0x01, 0x01);
+ revo71_mute (devc, 0);
+}
+
+static void
+revo71_set_rate (envy24ht_devc * devc)
+{
+ int rate = devc->speed, i;
+ unsigned char tmp;
+
+ if (devc->speed == devc->prev_speed)
+ return;
+ devc->prev_speed = devc->speed;
+
+ revo71_mute (devc, 1);
+
+ /* Pulse the PRST# signal to reset converters */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x05) | 0x80,
+ devc->mt_base + 0x05);
+ oss_udelay (5000);
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x05) & ~0x80,
+ devc->mt_base + 0x05);
+ oss_udelay (5000);
+
+ tmp = 0x03;
+ if (rate <= 48000)
+ tmp |= 0x00;
+ else
+ {
+ if (rate <= 96000)
+ tmp |= 0x04;
+ else
+ tmp |= 0x08;
+ }
+
+ /* Front DAC */
+
+ writedac1 (devc, 0, 0x0c);
+ writedac1 (devc, 1, tmp);
+ writedac1 (devc, 2, 0x00);
+ writedac1 (devc, 3, devc->dac1val[3]);
+ writedac1 (devc, 4, devc->dac1val[4]);
+ writedac1 (devc, 0, 0x0f);
+
+ /* Surround DAC */
+ writedac2 (devc, 1, 0x02);
+ writedac2 (devc, 0, 0x06);
+
+ tmp = 0x0e;
+
+ if (devc->speed > 60000)
+ {
+ if (devc->speed > 120000)
+ tmp |= 0x20;
+ else
+ tmp |= 0x10;
+ }
+ writedac2 (devc, 2, tmp);
+ writedac2 (devc, 3, 0x01);
+
+ for (i = 4; i < 10; i++)
+ writedac2 (devc, i, devc->dac2val[i]);
+
+ writedac2 (devc, 0xa, 0x00);
+ writedac2 (devc, 1, 0x03);
+
+ revo71_mute (devc, 0);
+}
+
+static int
+revo71_set_akm (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ if (ctrl < 0 || ctrl > 4)
+ return OSS_EIO;
+
+ return devc->gains[ctrl];
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ int left, right;
+
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ switch (ctrl)
+ {
+ case 0: /* Front */
+ writedac1 (devc, 0x03, left);
+ writedac1 (devc, 0x04, right);
+ break;
+
+ case 1: /* Rear */
+ writedac2 (devc, 0x06, left);
+ writedac2 (devc, 0x07, right);
+ break;
+
+ case 2: /* Center */
+ writedac2 (devc, 0x04, left);
+ right = left;
+ break;
+
+ case 3: /* LFE */
+ writedac2 (devc, 0x05, left);
+ right = left;
+ break;
+
+ case 4: /* Surround */
+ writedac2 (devc, 0x08, left);
+ writedac2 (devc, 0x09, right);
+ break;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ value = left | (right << 8);
+ return devc->gains[ctrl] = value;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+revo71_mixer_init (envy24ht_devc * devc, int dev, int group)
+{
+ int i, err;
+
+ for (i = 0; i < 6; i++)
+ devc->gains[i] = 0xffff;
+
+ if ((group = mixer_ext_create_group (dev, 0, "ENVY24HT_GAIN")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, revo71_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_FRONT", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, revo71_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_REAR", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, revo71_set_akm,
+ MIXT_MONOSLIDER,
+ "GAIN_CENTER", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 3, revo71_set_akm,
+ MIXT_MONOSLIDER,
+ "GAIN_LFE", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 4, revo71_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_surround", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ return 0;
+}
+
+envy24ht_auxdrv_t envy24ht_revo71_auxdrv = {
+ revo71_card_init,
+ revo71_mixer_init,
+ revo71_set_rate,
+ NULL,
+ NULL,
+ NULL, /* revo71_private1 */
+};