bci: some more code for testing
[pandora-kernel.git] / sound / spi / at73c213.c
index fee869b..09802e8 100644 (file)
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <sound/driver.h>
 #include <sound/initval.h>
 #include <sound/control.h>
 #include <sound/core.h>
@@ -76,8 +76,10 @@ struct snd_at73c213 {
        u8                              spi_rbuffer[2];
        /* Image of the SPI registers in AT73C213. */
        u8                              reg_image[18];
-       /* Protect registers against concurrent access. */
+       /* Protect SSC registers against concurrent access. */
        spinlock_t                      lock;
+       /* Protect mixer registers against concurrent access. */
+       struct mutex                    mixer_lock;
 };
 
 #define get_chip(card) ((struct snd_at73c213 *)card->private_data)
@@ -116,7 +118,7 @@ static struct snd_pcm_hardware snd_at73c213_playback_hw = {
        .rates          = SNDRV_PCM_RATE_CONTINUOUS,
        .rate_min       = 8000,  /* Replaced by chip->bitrate later. */
        .rate_max       = 50000, /* Replaced by chip->bitrate later. */
-       .channels_min   = 2,
+       .channels_min   = 1,
        .channels_max   = 2,
        .buffer_bytes_max = 64 * 1024 - 1,
        .period_bytes_min = 512,
@@ -131,7 +133,8 @@ static struct snd_pcm_hardware snd_at73c213_playback_hw = {
 static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
 {
        unsigned long ssc_rate = clk_get_rate(chip->ssc->clk);
-       unsigned long dac_rate_new, ssc_div, status;
+       unsigned long dac_rate_new, ssc_div;
+       int status;
        unsigned long ssc_div_max, ssc_div_min;
        int max_tries;
 
@@ -207,7 +210,13 @@ static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
 
+       /* ensure buffer_size is a multiple of period_size */
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
+               return err;
        snd_at73c213_playback_hw.rate_min = chip->bitrate;
        snd_at73c213_playback_hw.rate_max = chip->bitrate;
        runtime->hw = snd_at73c213_playback_hw;
@@ -226,6 +235,14 @@ static int snd_at73c213_pcm_close(struct snd_pcm_substream *substream)
 static int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *hw_params)
 {
+       struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+       int channels = params_channels(hw_params);
+       int val;
+
+       val = ssc_readl(chip->ssc->regs, TFMR);
+       val = SSC_BFINS(TFMR_DATNB, channels - 1, val);
+       ssc_writel(chip->ssc->regs, TFMR, val);
+
        return snd_pcm_lib_malloc_pages(substream,
                                        params_buffer_bytes(hw_params));
 }
@@ -247,10 +264,12 @@ static int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream)
 
        ssc_writel(chip->ssc->regs, PDC_TPR,
                        (long)runtime->dma_addr);
-       ssc_writel(chip->ssc->regs, PDC_TCR, runtime->period_size * 2);
+       ssc_writel(chip->ssc->regs, PDC_TCR,
+                       runtime->period_size * runtime->channels);
        ssc_writel(chip->ssc->regs, PDC_TNPR,
                        (long)runtime->dma_addr + block_size);
-       ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
+       ssc_writel(chip->ssc->regs, PDC_TNCR,
+                       runtime->period_size * runtime->channels);
 
        return 0;
 }
@@ -312,15 +331,6 @@ static struct snd_pcm_ops at73c213_playback_ops = {
        .pointer        = snd_at73c213_pcm_pointer,
 };
 
-static void snd_at73c213_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_at73c213 *chip = snd_pcm_chip(pcm);
-       if (chip->pcm) {
-               snd_pcm_lib_preallocate_free_for_all(chip->pcm);
-               chip->pcm = NULL;
-       }
-}
-
 static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
 {
        struct snd_pcm *pcm;
@@ -332,7 +342,6 @@ static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
                goto out;
 
        pcm->private_data = chip;
-       pcm->private_free = snd_at73c213_pcm_free;
        pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER;
        strcpy(pcm->name, "at73c213");
        chip->pcm = pcm;
@@ -373,7 +382,8 @@ static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id)
 
                ssc_writel(chip->ssc->regs, PDC_TNPR,
                                (long)runtime->dma_addr + offset);
-               ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
+               ssc_writel(chip->ssc->regs, PDC_TNCR,
+                               runtime->period_size * runtime->channels);
                retval = IRQ_HANDLED;
        }
 
@@ -398,7 +408,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol,
        int mask = (kcontrol->private_value >> 16) & 0xff;
        int invert = (kcontrol->private_value >> 24) & 0xff;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        ucontrol->value.integer.value[0] =
                (chip->reg_image[reg] >> shift) & mask;
@@ -407,7 +417,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol,
                ucontrol->value.integer.value[0] =
                        mask - ucontrol->value.integer.value[0];
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return 0;
 }
@@ -428,13 +438,13 @@ static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol,
                val = mask - val;
        val <<= shift;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        val = (chip->reg_image[reg] & ~(mask << shift)) | val;
        change = val != chip->reg_image[reg];
        retval = snd_at73c213_write_reg(chip, reg, val);
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        if (retval)
                return retval;
@@ -470,7 +480,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol,
        int mask = (kcontrol->private_value >> 24) & 0xff;
        int invert = (kcontrol->private_value >> 22) & 1;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        ucontrol->value.integer.value[0] =
                (chip->reg_image[left_reg] >> shift_left) & mask;
@@ -484,7 +494,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol,
                        mask - ucontrol->value.integer.value[1];
        }
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return 0;
 }
@@ -511,7 +521,7 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol,
        val1 <<= shift_left;
        val2 <<= shift_right;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1;
        val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2;
@@ -519,16 +529,16 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol,
                || val2 != chip->reg_image[right_reg];
        retval = snd_at73c213_write_reg(chip, left_reg, val1);
        if (retval) {
-               spin_unlock_irq(&chip->lock);
+               mutex_unlock(&chip->mixer_lock);
                goto out;
        }
        retval = snd_at73c213_write_reg(chip, right_reg, val2);
        if (retval) {
-               spin_unlock_irq(&chip->lock);
+               mutex_unlock(&chip->mixer_lock);
                goto out;
        }
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return change;
 
@@ -536,16 +546,7 @@ out:
        return retval;
 }
 
-static int snd_at73c213_mono_switch_info(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-
-       return 0;
-}
+#define snd_at73c213_mono_switch_info  snd_ctl_boolean_mono_info
 
 static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
@@ -555,7 +556,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
        int shift = (kcontrol->private_value >> 8) & 0xff;
        int invert = (kcontrol->private_value >> 24) & 0xff;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        ucontrol->value.integer.value[0] =
                (chip->reg_image[reg] >> shift) & 0x01;
@@ -564,7 +565,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
                ucontrol->value.integer.value[0] =
                        0x01 - ucontrol->value.integer.value[0];
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return 0;
 }
@@ -589,14 +590,14 @@ static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol,
                val = mask - val;
        val <<= shift;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        val |= (chip->reg_image[reg] & ~(mask << shift));
        change = val != chip->reg_image[reg];
 
        retval = snd_at73c213_write_reg(chip, reg, val);
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        if (retval)
                return retval;
@@ -744,7 +745,7 @@ cleanup:
 /*
  * Device functions
  */
-static int snd_at73c213_ssc_init(struct snd_at73c213 *chip)
+static int __devinit snd_at73c213_ssc_init(struct snd_at73c213 *chip)
 {
        /*
         * Continuous clock output.
@@ -774,7 +775,7 @@ static int snd_at73c213_ssc_init(struct snd_at73c213 *chip)
        return 0;
 }
 
-static int snd_at73c213_chip_init(struct snd_at73c213 *chip)
+static int __devinit snd_at73c213_chip_init(struct snd_at73c213 *chip)
 {
        int retval;
        unsigned char dac_ctrl = 0;
@@ -893,6 +894,7 @@ static int __devinit snd_at73c213_dev_init(struct snd_card *card,
                return irq;
 
        spin_lock_init(&chip->lock);
+       mutex_init(&chip->mixer_lock);
        chip->card = card;
        chip->irq = -1;
 
@@ -939,7 +941,7 @@ out:
        return retval;
 }
 
-static int snd_at73c213_probe(struct spi_device *spi)
+static int __devinit snd_at73c213_probe(struct spi_device *spi)
 {
        struct snd_card                 *card;
        struct snd_at73c213             *chip;