summaryrefslogtreecommitdiff
path: root/kernel/drv/oss_envy24/envy24_ews88d.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_envy24/envy24_ews88d.c
downloadoss4-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.c377
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
+};