diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
commit | 1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch) | |
tree | 4495d23e7b54ab5700e3839081e797c1eafe0db9 /kernel/drv/oss_envy24ht/envy24ht_revo71.c | |
download | oss4-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.c | 338 |
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 */ +}; |