[ALSA] hda - Add support for the ATI RS600 HDMI audio device
[pandora-kernel.git] / sound / pci / hda / hda_intel.c
index fd12b69..0154389 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "hda_codec.h"
@@ -53,6 +54,7 @@ static char *id = SNDRV_DEFAULT_STR1;
 static char *model;
 static int position_fix;
 static int probe_mask = -1;
+static int single_cmd;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -64,6 +66,8 @@ module_param(position_fix, int, 0444);
 MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
 module_param(probe_mask, int, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
+module_param(single_cmd, bool, 0444);
+MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
 
 
 /* just for backward compatibility */
@@ -77,6 +81,8 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ESB2},"
                         "{Intel, ICH8},"
                         "{ATI, SB450},"
+                        "{ATI, SB600},"
+                        "{ATI, RS600},"
                         "{VIA, VT8251},"
                         "{VIA, VT8237A},"
                         "{SiS, SIS966},"
@@ -162,6 +168,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define ULI_PLAYBACK_INDEX     5
 #define ULI_NUM_PLAYBACK       6
 
+/* ATI HDMI has 1 playback and 0 capture */
+#define ATIHDMI_CAPTURE_INDEX  0
+#define ATIHDMI_NUM_CAPTURE    0
+#define ATIHDMI_PLAYBACK_INDEX 0
+#define ATIHDMI_NUM_PLAYBACK   1
+
 /* this number is statically defined for simplicity */
 #define MAX_AZX_DEV            16
 
@@ -234,12 +246,6 @@ enum {
 #define NVIDIA_HDA_TRANSREG_ADDR      0x4e
 #define NVIDIA_HDA_ENABLE_COHBITS     0x0f
 
-/*
- * Use CORB/RIRB for communication from/to codecs.
- * This is the way recommended by Intel (see below).
- */
-#define USE_CORB_RIRB
-
 /*
  */
 
@@ -252,7 +258,6 @@ struct azx_dev {
        unsigned int fragsize;          /* size of each period in bytes */
        unsigned int frags;             /* number for period in the play buffer */
        unsigned int fifo_size;         /* FIFO size */
-       unsigned int last_pos;          /* last updated period position */
 
        void __iomem *sd_addr;          /* stream descriptor pointer */
 
@@ -263,10 +268,11 @@ struct azx_dev {
        unsigned int format_val;        /* format value to be set in the controller and the codec */
        unsigned char stream_tag;       /* assigned stream */
        unsigned char index;            /* stream index */
+       /* for sanity check of position buffer */
+       unsigned int period_intr;
 
        unsigned int opened: 1;
        unsigned int running: 1;
-       unsigned int period_updating: 1;
 };
 
 /* CORB/RIRB */
@@ -300,7 +306,7 @@ struct azx {
 
        /* locks */
        spinlock_t reg_lock;
-       struct semaphore open_mutex;
+       struct mutex open_mutex;
 
        /* streams (x num_streams) */
        struct azx_dev *azx_dev;
@@ -325,12 +331,14 @@ struct azx {
        /* flags */
        int position_fix;
        unsigned int initialized: 1;
+       unsigned int single_cmd: 1;
 };
 
 /* driver types */
 enum {
        AZX_DRIVER_ICH,
        AZX_DRIVER_ATI,
+       AZX_DRIVER_ATIHDMI,
        AZX_DRIVER_VIA,
        AZX_DRIVER_SIS,
        AZX_DRIVER_ULI,
@@ -340,6 +348,7 @@ enum {
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_ATI] = "HDA ATI SB",
+       [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
        [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
        [AZX_DRIVER_SIS] = "HDA SIS966",
        [AZX_DRIVER_ULI] = "HDA ULI M5461",
@@ -388,7 +397,6 @@ static char *driver_short_names[] __devinitdata = {
  * Interface for HD codec
  */
 
-#ifdef USE_CORB_RIRB
 /*
  * CORB / RIRB interface
  */
@@ -436,11 +444,7 @@ static void azx_init_cmd_io(struct azx *chip)
        /* set N=1, get RIRB response interrupt for new entry */
        azx_writew(chip, RINTCNT, 1);
        /* enable rirb dma and response irq */
-#ifdef USE_CORB_RIRB
        azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
-#else
-       azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN);
-#endif
        chip->rirb.rp = chip->rirb.cmds = 0;
 }
 
@@ -452,8 +456,8 @@ static void azx_free_cmd_io(struct azx *chip)
 }
 
 /* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-                       unsigned int verb, unsigned int para)
+static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+                            unsigned int verb, unsigned int para)
 {
        struct azx *chip = codec->bus->private_data;
        unsigned int wp;
@@ -509,18 +513,21 @@ static void azx_update_rirb(struct azx *chip)
 }
 
 /* receive a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 {
        struct azx *chip = codec->bus->private_data;
        int timeout = 50;
 
        while (chip->rirb.cmds) {
                if (! --timeout) {
-                       if (printk_ratelimit())
-                               snd_printk(KERN_ERR
-                                       "azx_get_response timeout\n");
+                       snd_printk(KERN_ERR
+                                  "hda_intel: azx_get_response timeout, "
+                                  "switching to single_cmd mode...\n");
                        chip->rirb.rp = azx_readb(chip, RIRBWP);
                        chip->rirb.cmds = 0;
+                       /* switch to single_cmd mode */
+                       chip->single_cmd = 1;
+                       azx_free_cmd_io(chip);
                        return -1;
                }
                msleep(1);
@@ -528,7 +535,6 @@ static unsigned int azx_get_response(struct hda_codec *codec)
        return chip->rirb.res; /* the last value */
 }
 
-#else
 /*
  * Use the single immediate command instead of CORB/RIRB for simplicity
  *
@@ -539,13 +545,10 @@ static unsigned int azx_get_response(struct hda_codec *codec)
  *       I left the codes, however, for debugging/testing purposes.
  */
 
-#define azx_alloc_cmd_io(chip) 0
-#define azx_init_cmd_io(chip)
-#define azx_free_cmd_io(chip)
-
 /* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-                       unsigned int verb, unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
+                              int direct, unsigned int verb,
+                              unsigned int para)
 {
        struct azx *chip = codec->bus->private_data;
        u32 val;
@@ -573,7 +576,7 @@ static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
 }
 
 /* receive a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_single_get_response(struct hda_codec *codec)
 {
        struct azx *chip = codec->bus->private_data;
        int timeout = 50;
@@ -588,9 +591,35 @@ static unsigned int azx_get_response(struct hda_codec *codec)
        return (unsigned int)-1;
 }
 
-#define azx_update_rirb(chip)
+/*
+ * The below are the main callbacks from hda_codec.
+ *
+ * They are just the skeleton to call sub-callbacks according to the
+ * current setting of chip->single_cmd.
+ */
+
+/* send a command */
+static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
+                       int direct, unsigned int verb,
+                       unsigned int para)
+{
+       struct azx *chip = codec->bus->private_data;
+       if (chip->single_cmd)
+               return azx_single_send_cmd(codec, nid, direct, verb, para);
+       else
+               return azx_corb_send_cmd(codec, nid, direct, verb, para);
+}
+
+/* get a response */
+static unsigned int azx_get_response(struct hda_codec *codec)
+{
+       struct azx *chip = codec->bus->private_data;
+       if (chip->single_cmd)
+               return azx_single_get_response(codec);
+       else
+               return azx_rirb_get_response(codec);
+}
 
-#endif /* USE_CORB_RIRB */
 
 /* reset codec link */
 static int azx_reset(struct azx *chip)
@@ -737,7 +766,8 @@ static void azx_init_chip(struct azx *chip)
        azx_int_enable(chip);
 
        /* initialize the codec command I/O */
-       azx_init_cmd_io(chip);
+       if (! chip->single_cmd)
+               azx_init_cmd_io(chip);
 
        /* program the position buffer */
        azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
@@ -784,11 +814,10 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
                if (status & azx_dev->sd_int_sta_mask) {
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
                        if (azx_dev->substream && azx_dev->running) {
-                               azx_dev->period_updating = 1;
+                               azx_dev->period_intr++;
                                spin_unlock(&chip->reg_lock);
                                snd_pcm_period_elapsed(azx_dev->substream);
                                spin_lock(&chip->reg_lock);
-                               azx_dev->period_updating = 0;
                        }
                }
        }
@@ -796,7 +825,7 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
        /* clear rirb int */
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
-               if (status & RIRB_INT_RESPONSE)
+               if (! chip->single_cmd && (status & RIRB_INT_RESPONSE))
                        azx_update_rirb(chip);
                azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
        }
@@ -1002,10 +1031,10 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        unsigned long flags;
        int err;
 
-       down(&chip->open_mutex);
+       mutex_lock(&chip->open_mutex);
        azx_dev = azx_assign_device(chip, substream->stream);
        if (azx_dev == NULL) {
-               up(&chip->open_mutex);
+               mutex_unlock(&chip->open_mutex);
                return -EBUSY;
        }
        runtime->hw = azx_pcm_hw;
@@ -1017,7 +1046,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
        if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) {
                azx_release_device(azx_dev);
-               up(&chip->open_mutex);
+               mutex_unlock(&chip->open_mutex);
                return err;
        }
        spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1026,7 +1055,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 
        runtime->private_data = azx_dev;
-       up(&chip->open_mutex);
+       mutex_unlock(&chip->open_mutex);
        return 0;
 }
 
@@ -1038,14 +1067,14 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
        struct azx_dev *azx_dev = get_azx_dev(substream);
        unsigned long flags;
 
-       down(&chip->open_mutex);
+       mutex_lock(&chip->open_mutex);
        spin_lock_irqsave(&chip->reg_lock, flags);
        azx_dev->substream = NULL;
        azx_dev->running = 0;
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        azx_release_device(azx_dev);
        hinfo->ops.close(hinfo, apcm->codec, substream);
-       up(&chip->open_mutex);
+       mutex_unlock(&chip->open_mutex);
        return 0;
 }
 
@@ -1099,7 +1128,6 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
                azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
        else
                azx_dev->fifo_size = 0;
-       azx_dev->last_pos = 0;
 
        return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,
                                  azx_dev->format_val, substream);
@@ -1147,10 +1175,20 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
        struct azx_dev *azx_dev = get_azx_dev(substream);
        unsigned int pos;
 
-       if (chip->position_fix == POS_FIX_POSBUF) {
+       if (chip->position_fix == POS_FIX_POSBUF ||
+           chip->position_fix == POS_FIX_AUTO) {
                /* use the position buffer */
                pos = *azx_dev->posbuf;
+               if (chip->position_fix == POS_FIX_AUTO &&
+                   azx_dev->period_intr == 1 && ! pos) {
+                       printk(KERN_WARNING
+                              "hda-intel: Invalid position buffer, "
+                              "using LPIB read method instead.\n");
+                       chip->position_fix = POS_FIX_NONE;
+                       goto read_lpib;
+               }
        } else {
+       read_lpib:
                /* read LPIB */
                pos = azx_sd_readl(azx_dev, SD_LPIB);
                if (chip->position_fix == POS_FIX_FIFO)
@@ -1415,13 +1453,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        }
 
        spin_lock_init(&chip->reg_lock);
-       init_MUTEX(&chip->open_mutex);
+       mutex_init(&chip->open_mutex);
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
        chip->driver_type = driver_type;
 
-       chip->position_fix = position_fix ? position_fix : POS_FIX_POSBUF;
+       chip->position_fix = position_fix;
+       chip->single_cmd = single_cmd;
 
 #if BITS_PER_LONG != 64
        /* Fix up base address on ULI M5461 */
@@ -1465,6 +1504,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                chip->playback_index_offset = ULI_PLAYBACK_INDEX;
                chip->capture_index_offset = ULI_CAPTURE_INDEX;
                break;
+       case AZX_DRIVER_ATIHDMI:
+               chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
+               chip->capture_streams = ATIHDMI_NUM_CAPTURE;
+               chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
+               chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
+               break;
        default:
                chip->playback_streams = ICH6_NUM_PLAYBACK;
                chip->capture_streams = ICH6_NUM_CAPTURE;
@@ -1492,8 +1537,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                goto errout;
        }
        /* allocate CORB/RIRB */
-       if ((err = azx_alloc_cmd_io(chip)) < 0)
-               goto errout;
+       if (! chip->single_cmd)
+               if ((err = azx_alloc_cmd_io(chip)) < 0)
+                       goto errout;
 
        /* initialize streams */
        azx_init_stream(chip);
@@ -1583,12 +1629,14 @@ static void __devexit azx_remove(struct pci_dev *pci)
 }
 
 /* PCI IDs */
-static struct pci_device_id azx_ids[] = {
+static struct pci_device_id azx_ids[] __devinitdata = {
        { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
        { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
        { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
        { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
        { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
+       { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
+       { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
        { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
        { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
        { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */