]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - sound/pci/emu10k1/io.c
[ALSA] Changed Jaroslav Kysela's e-mail from perex@suse.cz to perex@perex.cz
[net-next-2.6.git] / sound / pci / emu10k1 / io.c
index 029e7856c43beaa7d171a22696d95410119b7b43..6702c15fefa3b52cbc95fc868ce278a161e9e219 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *                   Creative Labs, Inc.
  *  Routines for control of EMU10K1 chips
  *
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 #include <linux/delay.h>
+#include "p17v.h"
 
 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
 {
@@ -167,6 +168,109 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
        return 0;
 }
 
+/* The ADC does not support i2c read, so only write is implemented */
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
+                               u32 reg,
+                               u32 value)
+{
+       u32 tmp;
+       int timeout = 0;
+       int status;
+       int retry;
+       if ((reg > 0x7f) || (value > 0x1ff)) {
+               snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+               return -EINVAL;
+       }
+
+       tmp = reg << 25 | value << 16;
+       // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+       /* Not sure what this I2C channel controls. */
+       /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
+
+       /* This controls the I2C connected to the WM8775 ADC Codec */
+       snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
+       tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
+
+       for (retry = 0; retry < 10; retry++) {
+               /* Send the data to i2c */
+               //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
+               //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+               tmp = 0;
+               tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
+               snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
+
+               /* Wait till the transaction ends */
+               while (1) {
+                       udelay(10);
+                       status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
+                       // snd_printk("I2C:status=0x%x\n", status);
+                       timeout++;
+                       if ((status & I2C_A_ADC_START) == 0)
+                               break;
+
+                       if (timeout > 1000) {
+                               snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
+                               break;
+                       }
+               }
+               //Read back and see if the transaction is successful
+               if ((status & I2C_A_ADC_ABORT) == 0)
+                       break;
+       }
+
+       if (retry == 10) {
+               snd_printk(KERN_ERR "Writing to ADC failed!\n");
+               return -EINVAL;
+       }
+    
+       return 0;
+}
+
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
+{
+       if (reg > 0x3f)
+               return 1;
+       reg += 0x40; /* 0x40 upwards are registers. */
+       if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
+               return 1;
+       outl(reg, emu->port + A_IOCFG);
+       udelay(10);
+       outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+       udelay(10);
+       outl(value, emu->port + A_IOCFG);
+       udelay(10);
+       outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+
+       return 0;
+}
+
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
+{
+       if (reg > 0x3f)
+               return 1;
+       reg += 0x40; /* 0x40 upwards are registers. */
+       outl(reg, emu->port + A_IOCFG);
+       udelay(10);
+       outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+       udelay(10);
+       *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
+
+       return 0;
+}
+
+/* Each Destination has one and only one Source,
+ * but one Source can feed any number of Destinations simultaneously.
+ */
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
+{
+       snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
+       snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
+       snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
+       snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
+
+       return 0;
+}
+
 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
 {
        unsigned long flags;