Merge with git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[powerpc.git] / sound / pci / emu10k1 / emu10k1_main.c
index 175f8aa..3c7043b 100644 (file)
@@ -42,6 +42,7 @@
 #include "p16v.h"
 #include "tina2.h"
 
+
 /*************************************************************************
  * EMU10K1 init / done
  *************************************************************************/
@@ -91,6 +92,30 @@ void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch)
        }
 }
 
+static unsigned int spi_dac_init[] = {
+               0x00ff,
+               0x02ff,
+               0x0400,
+               0x0520,
+               0x0600,
+               0x08ff,
+               0x0aff,
+               0x0cff,
+               0x0eff,
+               0x10ff,
+               0x1200,
+               0x1400,
+               0x1480,
+               0x1800,
+               0x1aff,
+               0x1cff,
+               0x1e00,
+               0x0530,
+               0x0602,
+               0x0622,
+               0x1400,
+};
+       
 static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
 {
        unsigned int silent_page;
@@ -180,7 +205,28 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                tmp = inl(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */
                outl(tmp, emu->port + A_IOCFG);
        }
+       if (emu->card_capabilities->spi_dac) { /* Audigy 2 ZS Notebook with DAC Wolfson WM8768/WM8568 */
+               int size, n;
+
+               size = ARRAY_SIZE(spi_dac_init);
+               for (n=0; n < size; n++)
+                       snd_emu10k1_spi_write(emu, spi_dac_init[n]);
+
+               snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10);
+               /* Enable GPIOs
+                * GPIO0: Unknown
+                * GPIO1: Speakers-enabled.
+                * GPIO2: Unknown
+                * GPIO3: Unknown
+                * GPIO4: IEC958 Output on.
+                * GPIO5: Unknown
+                * GPIO6: Unknown
+                * GPIO7: Unknown
+                */
+               outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */
 
+       }
+       
        snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
        snd_emu10k1_ptr_write(emu, TCB, 0, 0);  /* taken from original driver */
        snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */
@@ -217,7 +263,9 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
 
        if (enable_ir) {        /* enable IR for SB Live */
-               if (emu->audigy) {
+               if ( emu->card_capabilities->emu1212m) {
+                       ;  /* Disable all access to A_IOCFG for the emu1212m */
+               } else if (emu->audigy) {
                        unsigned int reg = inl(emu->port + A_IOCFG);
                        outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
                        udelay(500);
@@ -234,7 +282,9 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                }
        }
        
-       if (emu->audigy) {      /* enable analog output */
+       if ( emu->card_capabilities->emu1212m) {
+               ;  /* Disable all access to A_IOCFG for the emu1212m */
+       } else if (emu->audigy) {       /* enable analog output */
                unsigned int reg = inl(emu->port + A_IOCFG);
                outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
        }
@@ -250,7 +300,9 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
        outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
 
        /* Enable analog/digital outs on audigy */
-       if (emu->audigy) {
+       if ( emu->card_capabilities->emu1212m) {
+               ;  /* Disable all access to A_IOCFG for the emu1212m */
+       } else if (emu->audigy) {
                outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
  
                if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
@@ -542,6 +594,136 @@ static int __devinit snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
        return 0;
 }
 
+static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
+{
+       if (reg<0 || 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);
+       outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+       outl(value, emu->port + A_IOCFG);
+       outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+
+       return 0;
+}
+
+static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
+{
+       if (reg<0 || reg>0x3f)
+               return 1;
+       reg+=0x40; /* 0x40 upwards are registers. */
+       outl(reg, emu->port + A_IOCFG);
+       outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+       *value = inl(emu->port + A_IOCFG);
+
+       return 0;
+}
+
+static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value)
+{
+       snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) );
+       snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) );
+       snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) );
+       snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) );
+
+       return 0;
+}
+
+static int __devinit snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu)
+{
+       unsigned int i;
+       int tmp;
+
+       snd_printk(KERN_ERR "emu1212m: Special config.\n");
+       outl(0x0005a00c, emu->port + HCFG);
+       outl(0x0005a004, emu->port + HCFG);
+       outl(0x0005a000, emu->port + HCFG);
+       outl(0x0005a000, emu->port + HCFG);
+
+       snd_emu1212m_fpga_read(emu, 0x22, &tmp );
+       snd_emu1212m_fpga_read(emu, 0x23, &tmp );
+       snd_emu1212m_fpga_read(emu, 0x24, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x04, 0x01 );
+       snd_emu1212m_fpga_read(emu, 0x0b, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x0b, 0x01 );
+       snd_emu1212m_fpga_read(emu, 0x10, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x10, 0x00 );
+       snd_emu1212m_fpga_read(emu, 0x11, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
+       snd_emu1212m_fpga_read(emu, 0x13, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x13, 0x0f );
+       snd_emu1212m_fpga_read(emu, 0x11, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
+       snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
+       snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
+       snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
+       snd_emu1212m_fpga_write(emu, 0x09, 0x0f );
+       snd_emu1212m_fpga_write(emu, 0x06, 0x00 );
+       snd_emu1212m_fpga_write(emu, 0x05, 0x00 );
+       snd_emu1212m_fpga_write(emu, 0x0e, 0x12 );
+       snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405);
+       snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406);
+       snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407);
+       snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100);
+       snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104);
+       snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200);
+       snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201);
+       for (i=0;i < 0x20;i++) {
+               snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000);
+       }
+       for (i=0;i < 4;i++) {
+               snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000);
+       }
+       for (i=0;i < 7;i++) {
+               snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000);
+       }
+       for (i=0;i < 7;i++) {
+               snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000);
+       }
+       snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c);
+       snd_emu1212m_fpga_write(emu, 0x07, 0x01 );
+
+       snd_emu1212m_fpga_read(emu, 0x21, &tmp );
+
+       outl(0x0000a000, emu->port + HCFG);
+       outl(0x0000a001, emu->port + HCFG);
+       /* Initial boot complete. Now patches */
+
+       snd_emu1212m_fpga_read(emu, 0x21, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
+       snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
+       snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
+       snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
+       snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
+       snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
+
+       snd_emu1212m_fpga_read(emu, 0x20, &tmp );
+       snd_emu1212m_fpga_read(emu, 0x21, &tmp );
+
+       snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302);
+       snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303);
+
+       return 0;
+}
 /*
  *  Create the EMU10K1 instance
  */
@@ -594,6 +776,12 @@ static int snd_emu10k1_dev_free(struct snd_device *device)
 static struct snd_emu_chip_details emu_chip_details[] = {
        /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
        /* Tested by James@superbug.co.uk 3rd July 2005 */
+       /* DSP: CA0108-IAT
+        * DAC: CS4382-KQ
+        * ADC: Philips 1361T
+        * AC97: STAC9750
+        * CA0151: None
+        */
        {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
         .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", 
         .id = "Audigy2",
@@ -602,14 +790,24 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .spk71 = 1,
         .ac97_chip = 1} ,
        /* Audigy 2 ZS Notebook Cardbus card.*/
-       /* Tested by James@superbug.co.uk 30th October 2005 */
-       /* Not working yet, but progressing. */
+       /* Tested by James@superbug.co.uk 22th December 2005 */
+       /* Audio output 7.1/Headphones working.
+        * Digital output working. (AC3 not checked, only PCM)
+        * Audio inputs not tested.
+        */ 
+       /* DSP: Tiny2
+        * DAC: Wolfson WM8768/WM8568
+        * ADC: Wolfson WM8775
+        * AC97: None
+        * CA0151: None
+        */
        {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
         .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", 
         .id = "Audigy2",
         .emu10k2_chip = 1,
         .ca0108_chip = 1,
         .ca_cardbus_chip = 1,
+        .spi_dac = 1,
         .spk71 = 1} ,
        {.vendor = 0x1102, .device = 0x0008, 
         .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
@@ -623,7 +821,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .id = "EMU1212m",
         .emu10k2_chip = 1,
         .ca0102_chip = 1,
-        .ecard = 1} ,
+        .emu1212m = 1} ,
        /* Tested by James@superbug.co.uk 3rd July 2005 */
        {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
         .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", 
@@ -662,6 +860,14 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .spk71 = 1,
         .spdif_bug = 1,
         .ac97_chip = 1} ,
+       /* Audigy 2 */
+       /* Tested by James@superbug.co.uk 3rd July 2005 */
+       /* DSP: CA0102-IAT
+        * DAC: CS4382-KQ
+        * ADC: Philips 1361T
+        * AC97: STAC9721
+        * CA0151: Yes
+        */
        {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102,
         .driver = "Audigy2", .name = "Audigy 2 [SB0240]", 
         .id = "Audigy2",
@@ -739,6 +945,14 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .emu10k1_chip = 1,
         .ac97_chip = 1,
         .sblive51 = 1} ,
+       /* Tested by ALSA bug#1680 26th December 2005 */
+       /* note: It really has SB0220 written on the card. */
+       {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80661102,
+        .driver = "EMU10K1", .name = "SB Live 5.1 Dell OEM [SB0220]", 
+        .id = "Live",
+        .emu10k1_chip = 1,
+        .ac97_chip = 1,
+        .sblive51 = 1} ,
        /* Tested by Thomas Zehetbauer 27th Aug 2005 */
        {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
         .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", 
@@ -746,6 +960,12 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .emu10k1_chip = 1,
         .ac97_chip = 1,
         .sblive51 = 1} ,
+       {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102,
+        .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", 
+        .id = "Live",
+        .emu10k1_chip = 1,
+        .ac97_chip = 1,
+        .sblive51 = 1} ,
        {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
         .driver = "EMU10K1", .name = "SB Live 5.1", 
         .id = "Live",
@@ -1013,6 +1233,11 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        } else if (emu->card_capabilities->ca_cardbus_chip) {
                if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
                        goto error;
+       } else if (emu->card_capabilities->emu1212m) {
+               if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) {
+                       snd_emu10k1_free(emu);
+                       return err;
+               }
        } else {
                /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version
                        does not support this, it shouldn't do any harm */