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_envy24/envy24_ews88d.c | |
download | oss4-1058def8e7827e56ce4a70afb4aeacb5dc44148f.tar.gz |
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'kernel/drv/oss_envy24/envy24_ews88d.c')
-rw-r--r-- | kernel/drv/oss_envy24/envy24_ews88d.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/kernel/drv/oss_envy24/envy24_ews88d.c b/kernel/drv/oss_envy24/envy24_ews88d.c new file mode 100644 index 0000000..c68be60 --- /dev/null +++ b/kernel/drv/oss_envy24/envy24_ews88d.c @@ -0,0 +1,377 @@ +/* + * Purpose: Card specific routines for Terratec EWS88D. + */ +/* + * + * 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_config.h" +#include "ac97.h" +#include "envy24.h" + +#if 0 +# define PRT_STATUS(v) outb(v&0xff, 0x378) +#else +# define PRT_STATUS(v) +#endif + +/* PCF8575 pin assignment (default 0xffff) */ +#define PCF_SPDIN_SELECT 0x0001 /* 0=optical 1=coax */ +#define PCF_OPTOUT 0x0002 /* 0=SPDIF 1=ADAT */ +#define PCF_CLOCKSRC 0x0004 /* 0=ADAT 1=SPDIF */ +#define PCF_ADATEN 0x0008 /* 0=ADAT disabled 1=ADAT enabled */ +#define PCF_ADATLOOP_ 0x0010 /* 0=ADAT in->out loop, 1=no loop */ +#define PCF_CS8414_ERF_ 0x0020 /* Inverted CS8414 ERF */ +#define PCF_SPDIF_ERR 0x0040 /* OR'ed from CS8414 E0..E2 */ +#define PCF_ADAT_ERROR 0x0080 /* ADAT error input */ + +extern int envy24_gain_sliders; +extern int envy24_virtualout; +extern int envy24_zerolatency; /* Testing in progress */ +/* + * Terratec stuff + */ + +/*============================================================================= + Function : IIC_GetSDA +------------------------------------------------------------------------------- + Description : + Returns : unsigned char -> + Parameters : unsigned long dwPortAddr -> +------------------------------------------------------------------------------- + Notes : +=============================================================================*/ +static __inline__ unsigned char +IIC_GetSDA (envy24_devc * devc, unsigned long dwPortAddr) +{ + + unsigned char bReg, bSDA; + + /* FMB TEST: RW line */ + /* set write mask */ + bReg = ~(0x08); /* writeable */ + envy24_write_cci (devc, 0x21, bReg); + + /* set RW line LOW */ + bReg = 0; /* writeable */ + envy24_write_cci (devc, 0x20, bReg); + + /* Set direction: SDA to input and SCL to output */ + bReg = envy24_read_cci (devc, 0x22); + bReg |= 0x20; /* SCL output = 1 */ + bReg &= ~0x10; /* SDA input = 0 */ + envy24_write_cci (devc, 0x22, bReg); + + /* Get SDA line state */ + bSDA = envy24_read_cci (devc, 0x20); + + /* set RW line HIGH */ + bReg = 0x08; /* writeable */ + envy24_write_cci (devc, 0x20, bReg); + + return 1; + /* return ((bSDA & 0x10) == 0x10); */ + +} + +/*============================================================================= + Function : IIC_SetIic +------------------------------------------------------------------------------- + Description : + Returns : void -> + Parameters : unsigned int dwPortAddr -> + : unsigned char fSDA -> + : unsigned char fSCL -> +------------------------------------------------------------------------------- + Notes : +=============================================================================*/ +static __inline__ void +IIC_SetIic (envy24_devc * devc, unsigned int dwPortAddr, unsigned char fSDA, + unsigned char fSCL) +{ + unsigned char bReg; + + /* Set direction: SDA and SCL to output */ + bReg = envy24_read_cci (devc, 0x22); + bReg |= (0x20 | 0x10); /* 1 -> output */ + envy24_write_cci (devc, 0x22, bReg); + + /* set write mask */ + bReg = ~(0x20 | 0x10); /* writeable */ + envy24_write_cci (devc, 0x21, bReg); + + /* Set line state */ + /* FMB TEST: RW line */ + bReg = 0x08; +/* bReg = 0; */ + if (fSDA) + bReg += 0x10; + if (fSCL) + bReg += 0x20; + envy24_write_cci (devc, 0x20, bReg); + +} + +/*============================================================================= + Function : IIC_Start +------------------------------------------------------------------------------- + Description : + Returns : void -> + Parameters : unsigned int dwPortAddr -> +------------------------------------------------------------------------------- + Notes : +=============================================================================*/ +static __inline__ void +IIC_Start (envy24_devc * devc, unsigned int dwPortAddr) +{ + /* falling edge of SDA while SCL is HIGH */ + IIC_SetIic (devc, dwPortAddr, 1, 1); + IIC_SetIic (devc, dwPortAddr, 0, 1); +} + +/*============================================================================= + Function : IIC_Stop +------------------------------------------------------------------------------- + Description : + Returns : void -> + Parameters : unsigned int dwPortAddr -> +------------------------------------------------------------------------------- + Notes : +=============================================================================*/ +static __inline__ void +IIC_Stop (envy24_devc * devc, unsigned int dwPortAddr) +{ + /* rising edge of SDA while SCL is HIGH */ + IIC_SetIic (devc, dwPortAddr, 0, 1); + IIC_SetIic (devc, dwPortAddr, 1, 1); +} + + +/*============================================================================= + Function : IIC_SendByte +------------------------------------------------------------------------------- + Description : + Returns : unsigned char -> + Parameters : unsigned int dwPortAddr -> + : unsigned char bByte -> +------------------------------------------------------------------------------- + Notes : +=============================================================================*/ +/*__inline */ +static unsigned char +IIC_SendByte (envy24_devc * devc, unsigned int dwPortAddr, + unsigned char bByte) +{ + unsigned char bDataBit, bAck; + int i; + + for (i = 7; i >= 0; i--) /* send byte (MSB first) */ + { + bDataBit = (bByte >> i) & 0x01; + + IIC_SetIic (devc, dwPortAddr, bDataBit, 0); + IIC_SetIic (devc, dwPortAddr, bDataBit, 1); + } /* end for i */ + + IIC_SetIic (devc, dwPortAddr, 1, 0); + + /* Get acknowledge */ + IIC_SetIic (devc, dwPortAddr, 1, 1); + bAck = IIC_GetSDA (devc, dwPortAddr); + /* FMB this is a start condition but never mind */ + IIC_SetIic (devc, dwPortAddr, 0, 0); + return 1; + /* return (!bAck); *//* bAck = 0 --> success */ +} + +static unsigned char +IIC_WriteWord (envy24_devc * devc, int dwPortAddr, unsigned char bIicAddress, + unsigned short bByte) +{ + IIC_Start (devc, dwPortAddr); + + /* send IIC address and data byte */ + if (!IIC_SendByte (devc, dwPortAddr, bIicAddress)) + { + cmn_err (CE_CONT, "IIC_SendByte 1 failed\n"); + goto FAILED; + } + if (!IIC_SendByte (devc, dwPortAddr, bByte & 0xff)) + { + cmn_err (CE_CONT, "IIC_SendByte 3 failed\n"); + goto FAILED; + } + if (!IIC_SendByte (devc, dwPortAddr, (bByte >> 8) & 0xff)) + { + cmn_err (CE_CONT, "IIC_SendByte 2 failed\n"); + goto FAILED; + } + + IIC_Stop (devc, dwPortAddr); + return 1; + +FAILED: + IIC_Stop (devc, dwPortAddr); + return 0; +} + +static void +ews88d_set_pcf8575 (envy24_devc * devc, unsigned short d) +{ + if (!IIC_WriteWord (devc, devc->ccs_base, 0x40, d)) + { + cmn_err (CE_CONT, "IIC_WriteWord failed\n"); + } + devc->gpio_tmp = d; +} + +static void +ews88d_card_init (envy24_devc * devc) +{ + ews88d_set_pcf8575 (devc, 0xffff); +} + +static void +set_ews88d_speed (envy24_devc * devc) +{ + int tmp; + + tmp = devc->speedbits; + + switch (devc->syncsource) + { + case SYNC_INTERNAL: + OUTB (devc->osdev, tmp, devc->mt_base + 0x01); + break; + + case SYNC_SPDIF: + tmp |= 0x10; + OUTB (devc->osdev, tmp, devc->mt_base + 0x01); + devc->gpio_tmp &= ~PCF_CLOCKSRC; + ews88d_set_pcf8575 (devc, devc->gpio_tmp); + break; + + case SYNC_WCLOCK: + tmp |= 0x10; + OUTB (devc->osdev, tmp, devc->mt_base + 0x01); + devc->gpio_tmp |= PCF_CLOCKSRC; + ews88d_set_pcf8575 (devc, devc->gpio_tmp); + break; + } + + if (devc->speed > 48000) + { + devc->gpio_tmp &= ~PCF_ADATEN; + ews88d_set_pcf8575 (devc, devc->gpio_tmp); + } + else + { + devc->gpio_tmp |= PCF_ADATEN; + ews88d_set_pcf8575 (devc, devc->gpio_tmp); + } +} + +static int +ews88d_mixer_set (int dev, int ctrl, unsigned int cmd, int value) +{ + envy24_devc *devc = mixer_devs[dev]->devc; + + if (cmd == SNDCTL_MIX_READ) + switch (ctrl) + { + case 1: + return !!(devc->gpio_tmp & PCF_SPDIN_SELECT); + break; + + case 2: + return !!(devc->gpio_tmp & PCF_OPTOUT); + break; + + case 3: + return !(devc->gpio_tmp & PCF_ADATLOOP_); + break; + } + + if (cmd == SNDCTL_MIX_WRITE) + switch (ctrl) + { + case 1: + devc->gpio_tmp &= ~PCF_SPDIN_SELECT; + if (value) + devc->gpio_tmp |= PCF_SPDIN_SELECT; + ews88d_set_pcf8575 (devc, devc->gpio_tmp); + return !!(devc->gpio_tmp & PCF_SPDIN_SELECT); + break; + + case 2: + devc->gpio_tmp &= ~PCF_OPTOUT; + if (value) + devc->gpio_tmp |= PCF_OPTOUT; + ews88d_set_pcf8575 (devc, devc->gpio_tmp); + return !!(devc->gpio_tmp & PCF_OPTOUT); + break; + + case 3: + devc->gpio_tmp &= ~PCF_ADATLOOP_; + if (!value) + devc->gpio_tmp |= PCF_ADATLOOP_; + ews88d_set_pcf8575 (devc, devc->gpio_tmp); + return !(devc->gpio_tmp & PCF_ADATLOOP_); + break; + } + + return OSS_EINVAL; +} + +static int +ews88d_mix_init (envy24_devc * devc, int dev, int group) +{ + int err; + + if ((group = mixer_ext_create_group (dev, 0, "ENVY24_EWS88D")) < 0) + return group; + + if ((err = mixer_ext_create_control (dev, group, + 1, ews88d_mixer_set, + MIXT_ENUM, + "EWS88D_SPDIN", 2, + MIXF_READABLE | MIXF_WRITEABLE)) < 0) + return err; + + if ((err = mixer_ext_create_control (dev, group, + 2, ews88d_mixer_set, + MIXT_ENUM, + "EWS88D_OPTOUT", 2, + MIXF_READABLE | MIXF_WRITEABLE)) < 0) + return err; + + if ((err = mixer_ext_create_control (dev, group, + 3, ews88d_mixer_set, + MIXT_ONOFF, + "EWS88D_ADATLOOP", 2, + MIXF_READABLE | MIXF_WRITEABLE)) < 0) + return err; + + return 0; +} + +envy24_auxdrv_t ews88d_auxdrv = { + ews88d_card_init, + ews88d_mix_init, + NULL, + NULL, + NULL, + NULL, + NULL, + set_ews88d_speed, + NULL, + cs8427_spdif_mixer_init +}; |