static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, OCA); int retval; chip->playback_period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT)); /* assign channels to AC97C channel A */ switch (runtime->channels) { case 1: word |= AC97C_CH_ASSIGN(PCM_LEFT, A); break; case 2: word |= AC97C_CH_ASSIGN(PCM_LEFT, A) | AC97C_CH_ASSIGN(PCM_RIGHT, A); break; default: /* TODO: support more than two channels */ return -EINVAL; } ac97c_writel(chip, OCA, word); /* configure sample format and size */ word = ac97c_readl(chip, CAMR); if (chip->opened <= 1) word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; else word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: if (cpu_is_at32ap7000()) word |= AC97C_CMR_CEM_LITTLE; break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE); break; default: word = ac97c_readl(chip, OCA); word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT)); ac97c_writel(chip, OCA, word); return -EINVAL; } /* Enable underrun interrupt on channel A */ word |= AC97C_CSR_UNRUN; ac97c_writel(chip, CAMR, word); /* Enable channel A event interrupt */ word = ac97c_readl(chip, IMR); word |= AC97C_SR_CAEVT; ac97c_writel(chip, IER, word); /* set variable rate if needed */ if (runtime->rate != 48000) { word = ac97c_readl(chip, MR); word |= AC97C_MR_VRA; ac97c_writel(chip, MR, word); } else { word = ac97c_readl(chip, MR); word &= ~(AC97C_MR_VRA); ac97c_writel(chip, MR, word); } retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); if (retval) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate); if (cpu_is_at32ap7000()) { if (!test_bit(DMA_TX_READY, &chip->flags)) retval = atmel_ac97c_prepare_dma(chip, substream, DMA_TO_DEVICE); } else { /* Initialize and start the PDC */ writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); writel(block_size / 2, chip->regs + ATMEL_PDC_TCR); writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_TNPR); writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); } return retval; }
static int snd_cs5535audio_capture_prepare(struct snd_pcm_substream *substream) { struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); return snd_ac97_set_rate(cs5535au->ac97, AC97_PCM_LR_ADC_RATE, substream->runtime->rate); }
int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, enum ac97_pcm_cfg cfg, unsigned short slots) { struct snd_ac97_bus *bus; int i, cidx, r, ok_flag; unsigned int reg_ok[4] = {0,0,0,0}; unsigned char reg; int err = 0; r = rate > 48000; bus = pcm->bus; if (cfg == AC97_PCM_CFG_SPDIF) { for (cidx = 0; cidx < 4; cidx++) if (bus->codec[cidx] && (bus->codec[cidx]->ext_id & AC97_EI_SPDIF)) { err = set_spdif_rate(bus->codec[cidx], rate); if (err < 0) return err; } } spin_lock_irq(&pcm->bus->bus_lock); for (i = 3; i < 12; i++) { if (!(slots & (1 << i))) continue; ok_flag = 0; for (cidx = 0; cidx < 4; cidx++) { if (bus->used_slots[pcm->stream][cidx] & (1 << i)) { spin_unlock_irq(&pcm->bus->bus_lock); err = -EBUSY; goto error; } if (pcm->r[r].rslots[cidx] & (1 << i)) { bus->used_slots[pcm->stream][cidx] |= (1 << i); ok_flag++; } } if (!ok_flag) { spin_unlock_irq(&pcm->bus->bus_lock); snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i); err = -EAGAIN; goto error; } } pcm->cur_dbl = r; spin_unlock_irq(&pcm->bus->bus_lock); for (i = 3; i < 12; i++) { if (!(slots & (1 << i))) continue; for (cidx = 0; cidx < 4; cidx++) { if (pcm->r[r].rslots[cidx] & (1 << i)) { reg = get_slot_reg(pcm, cidx, i, r); if (reg == 0xff) { snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i); continue; } if (reg_ok[cidx] & (1 << (reg - AC97_PCM_FRONT_DAC_RATE))) continue; //printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate); err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate); if (err < 0) snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err); else reg_ok[cidx] |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE)); } } } pcm->aslots = slots; return 0; error: pcm->aslots = slots; snd_ac97_pcm_close(pcm); return err; }
static int snd_cs5535audio_playback_prepare(struct snd_pcm_substream *substream) { struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); return snd_ac97_set_rate(cs5535au->ac97, AC97_PCM_FRONT_DAC_RATE, substream->runtime->rate); }