1cb5a6ffcSRussell King /* 2cb5a6ffcSRussell King * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver 3cb5a6ffcSRussell King * 4cb5a6ffcSRussell King * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. 5cb5a6ffcSRussell King * 6cb5a6ffcSRussell King * This program is free software; you can redistribute it and/or modify 7cb5a6ffcSRussell King * it under the terms of the GNU General Public License version 2 as 8cb5a6ffcSRussell King * published by the Free Software Foundation. 9cb5a6ffcSRussell King * 10cb5a6ffcSRussell King * Documentation: ARM DDI 0173B 11cb5a6ffcSRussell King */ 12cb5a6ffcSRussell King #include <linux/module.h> 13cb5a6ffcSRussell King #include <linux/delay.h> 14cb5a6ffcSRussell King #include <linux/init.h> 15cb5a6ffcSRussell King #include <linux/ioport.h> 16cb5a6ffcSRussell King #include <linux/device.h> 17cb5a6ffcSRussell King #include <linux/spinlock.h> 18cb5a6ffcSRussell King #include <linux/interrupt.h> 19cb5a6ffcSRussell King #include <linux/err.h> 20a62c80e5SRussell King #include <linux/amba/bus.h> 2188cdca9cSRussell King #include <linux/io.h> 22cb5a6ffcSRussell King 23cb5a6ffcSRussell King #include <sound/core.h> 24cb5a6ffcSRussell King #include <sound/initval.h> 25cb5a6ffcSRussell King #include <sound/ac97_codec.h> 26cb5a6ffcSRussell King #include <sound/pcm.h> 27cb5a6ffcSRussell King #include <sound/pcm_params.h> 28cb5a6ffcSRussell King 29cb5a6ffcSRussell King #include "aaci.h" 30cb5a6ffcSRussell King 31cb5a6ffcSRussell King #define DRIVER_NAME "aaci-pl041" 32cb5a6ffcSRussell King 33250c7a61SRussell King #define FRAME_PERIOD_US 21 34250c7a61SRussell King 35cb5a6ffcSRussell King /* 36cb5a6ffcSRussell King * PM support is not complete. Turn it off. 37cb5a6ffcSRussell King */ 38cb5a6ffcSRussell King #undef CONFIG_PM 39cb5a6ffcSRussell King 40ceb9e476STakashi Iwai static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97) 41cb5a6ffcSRussell King { 42cb5a6ffcSRussell King u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num); 43cb5a6ffcSRussell King 44cb5a6ffcSRussell King /* 45cb5a6ffcSRussell King * Ensure that the slot 1/2 RX registers are empty. 46cb5a6ffcSRussell King */ 47cb5a6ffcSRussell King v = readl(aaci->base + AACI_SLFR); 48cb5a6ffcSRussell King if (v & SLFR_2RXV) 49cb5a6ffcSRussell King readl(aaci->base + AACI_SL2RX); 50cb5a6ffcSRussell King if (v & SLFR_1RXV) 51cb5a6ffcSRussell King readl(aaci->base + AACI_SL1RX); 52cb5a6ffcSRussell King 537c289385SRussell King if (maincr != readl(aaci->base + AACI_MAINCR)) { 54cb5a6ffcSRussell King writel(maincr, aaci->base + AACI_MAINCR); 557c289385SRussell King readl(aaci->base + AACI_MAINCR); 567c289385SRussell King udelay(1); 577c289385SRussell King } 58cb5a6ffcSRussell King } 59cb5a6ffcSRussell King 60cb5a6ffcSRussell King /* 61cb5a6ffcSRussell King * P29: 62cb5a6ffcSRussell King * The recommended use of programming the external codec through slot 1 63cb5a6ffcSRussell King * and slot 2 data is to use the channels during setup routines and the 64cb5a6ffcSRussell King * slot register at any other time. The data written into slot 1, slot 2 65cb5a6ffcSRussell King * and slot 12 registers is transmitted only when their corresponding 66cb5a6ffcSRussell King * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR 67cb5a6ffcSRussell King * register. 68cb5a6ffcSRussell King */ 6914d178a1SKevin Hilman static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, 7014d178a1SKevin Hilman unsigned short val) 71cb5a6ffcSRussell King { 72cb5a6ffcSRussell King struct aaci *aaci = ac97->private_data; 73250c7a61SRussell King int timeout; 74cb5a6ffcSRussell King u32 v; 75cb5a6ffcSRussell King 76cb5a6ffcSRussell King if (ac97->num >= 4) 77cb5a6ffcSRussell King return; 78cb5a6ffcSRussell King 7912aa7579SIngo Molnar mutex_lock(&aaci->ac97_sem); 80cb5a6ffcSRussell King 81cb5a6ffcSRussell King aaci_ac97_select_codec(aaci, ac97); 82cb5a6ffcSRussell King 83cb5a6ffcSRussell King /* 84cb5a6ffcSRussell King * P54: You must ensure that AACI_SL2TX is always written 85cb5a6ffcSRussell King * to, if required, before data is written to AACI_SL1TX. 86cb5a6ffcSRussell King */ 87cb5a6ffcSRussell King writel(val << 4, aaci->base + AACI_SL2TX); 88cb5a6ffcSRussell King writel(reg << 12, aaci->base + AACI_SL1TX); 89cb5a6ffcSRussell King 90250c7a61SRussell King /* Initially, wait one frame period */ 91250c7a61SRussell King udelay(FRAME_PERIOD_US); 92250c7a61SRussell King 93250c7a61SRussell King /* And then wait an additional eight frame periods for it to be sent */ 94250c7a61SRussell King timeout = FRAME_PERIOD_US * 8; 95cb5a6ffcSRussell King do { 96250c7a61SRussell King udelay(1); 97cb5a6ffcSRussell King v = readl(aaci->base + AACI_SLFR); 98f6f35bbeSRoel Kluin } while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout); 9914d178a1SKevin Hilman 10069058cd6SRussell King if (v & (SLFR_1TXB|SLFR_2TXB)) 10114d178a1SKevin Hilman dev_err(&aaci->dev->dev, 10214d178a1SKevin Hilman "timeout waiting for write to complete\n"); 103cb5a6ffcSRussell King 10412aa7579SIngo Molnar mutex_unlock(&aaci->ac97_sem); 105cb5a6ffcSRussell King } 106cb5a6ffcSRussell King 107cb5a6ffcSRussell King /* 108cb5a6ffcSRussell King * Read an AC'97 register. 109cb5a6ffcSRussell King */ 110ceb9e476STakashi Iwai static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 111cb5a6ffcSRussell King { 112cb5a6ffcSRussell King struct aaci *aaci = ac97->private_data; 113250c7a61SRussell King int timeout, retries = 10; 114cb5a6ffcSRussell King u32 v; 115cb5a6ffcSRussell King 116cb5a6ffcSRussell King if (ac97->num >= 4) 117cb5a6ffcSRussell King return ~0; 118cb5a6ffcSRussell King 11912aa7579SIngo Molnar mutex_lock(&aaci->ac97_sem); 120cb5a6ffcSRussell King 121cb5a6ffcSRussell King aaci_ac97_select_codec(aaci, ac97); 122cb5a6ffcSRussell King 123cb5a6ffcSRussell King /* 124cb5a6ffcSRussell King * Write the register address to slot 1. 125cb5a6ffcSRussell King */ 126cb5a6ffcSRussell King writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX); 127cb5a6ffcSRussell King 128250c7a61SRussell King /* Initially, wait one frame period */ 129250c7a61SRussell King udelay(FRAME_PERIOD_US); 130250c7a61SRussell King 131250c7a61SRussell King /* And then wait an additional eight frame periods for it to be sent */ 132250c7a61SRussell King timeout = FRAME_PERIOD_US * 8; 133cb5a6ffcSRussell King do { 134250c7a61SRussell King udelay(1); 135cb5a6ffcSRussell King v = readl(aaci->base + AACI_SLFR); 136f6f35bbeSRoel Kluin } while ((v & SLFR_1TXB) && --timeout); 13714d178a1SKevin Hilman 13869058cd6SRussell King if (v & SLFR_1TXB) { 13914d178a1SKevin Hilman dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n"); 14014d178a1SKevin Hilman v = ~0; 14114d178a1SKevin Hilman goto out; 14214d178a1SKevin Hilman } 143cb5a6ffcSRussell King 144250c7a61SRussell King /* Now wait for the response frame */ 145250c7a61SRussell King udelay(FRAME_PERIOD_US); 146cb5a6ffcSRussell King 147250c7a61SRussell King /* And then wait an additional eight frame periods for data */ 148250c7a61SRussell King timeout = FRAME_PERIOD_US * 8; 149cb5a6ffcSRussell King do { 150250c7a61SRussell King udelay(1); 151cb5a6ffcSRussell King cond_resched(); 152cb5a6ffcSRussell King v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); 153f6f35bbeSRoel Kluin } while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout); 154cb5a6ffcSRussell King 15569058cd6SRussell King if (v != (SLFR_1RXV|SLFR_2RXV)) { 15614d178a1SKevin Hilman dev_err(&aaci->dev->dev, "timeout on RX valid\n"); 15714d178a1SKevin Hilman v = ~0; 15814d178a1SKevin Hilman goto out; 15914d178a1SKevin Hilman } 16014d178a1SKevin Hilman 16114d178a1SKevin Hilman do { 162cb5a6ffcSRussell King v = readl(aaci->base + AACI_SL1RX) >> 12; 163cb5a6ffcSRussell King if (v == reg) { 164cb5a6ffcSRussell King v = readl(aaci->base + AACI_SL2RX) >> 4; 16514d178a1SKevin Hilman break; 16614d178a1SKevin Hilman } else if (--retries) { 16714d178a1SKevin Hilman dev_warn(&aaci->dev->dev, 16814d178a1SKevin Hilman "ac97 read back fail. retry\n"); 16914d178a1SKevin Hilman continue; 170cb5a6ffcSRussell King } else { 17114d178a1SKevin Hilman dev_warn(&aaci->dev->dev, 172cb5a6ffcSRussell King "wrong ac97 register read back (%x != %x)\n", 173cb5a6ffcSRussell King v, reg); 174cb5a6ffcSRussell King v = ~0; 175cb5a6ffcSRussell King } 17614d178a1SKevin Hilman } while (retries); 17714d178a1SKevin Hilman out: 17812aa7579SIngo Molnar mutex_unlock(&aaci->ac97_sem); 179cb5a6ffcSRussell King return v; 180cb5a6ffcSRussell King } 181cb5a6ffcSRussell King 182d6a89fefSRussell King static inline void 183d6a89fefSRussell King aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask) 184cb5a6ffcSRussell King { 185cb5a6ffcSRussell King u32 val; 186cb5a6ffcSRussell King int timeout = 5000; 187cb5a6ffcSRussell King 188cb5a6ffcSRussell King do { 189250c7a61SRussell King udelay(1); 190cb5a6ffcSRussell King val = readl(aacirun->base + AACI_SR); 191d6a89fefSRussell King } while (val & mask && timeout--); 192cb5a6ffcSRussell King } 193cb5a6ffcSRussell King 194cb5a6ffcSRussell King 195cb5a6ffcSRussell King 196cb5a6ffcSRussell King /* 197cb5a6ffcSRussell King * Interrupt support. 198cb5a6ffcSRussell King */ 19962578cbfSKevin Hilman static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) 200cb5a6ffcSRussell King { 20141762b8cSKevin Hilman if (mask & ISR_ORINTR) { 20241762b8cSKevin Hilman dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel); 20341762b8cSKevin Hilman writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR); 20441762b8cSKevin Hilman } 20541762b8cSKevin Hilman 20641762b8cSKevin Hilman if (mask & ISR_RXTOINTR) { 20741762b8cSKevin Hilman dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel); 20841762b8cSKevin Hilman writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR); 20941762b8cSKevin Hilman } 21041762b8cSKevin Hilman 21141762b8cSKevin Hilman if (mask & ISR_RXINTR) { 21241762b8cSKevin Hilman struct aaci_runtime *aacirun = &aaci->capture; 21341762b8cSKevin Hilman void *ptr; 21441762b8cSKevin Hilman 21541762b8cSKevin Hilman if (!aacirun->substream || !aacirun->start) { 216898eb71cSJoe Perches dev_warn(&aaci->dev->dev, "RX interrupt???\n"); 21741762b8cSKevin Hilman writel(0, aacirun->base + AACI_IE); 21841762b8cSKevin Hilman return; 21941762b8cSKevin Hilman } 22041762b8cSKevin Hilman 221d6a89fefSRussell King spin_lock(&aacirun->lock); 222d6a89fefSRussell King 223d6a89fefSRussell King ptr = aacirun->ptr; 22441762b8cSKevin Hilman do { 22541762b8cSKevin Hilman unsigned int len = aacirun->fifosz; 22641762b8cSKevin Hilman u32 val; 22741762b8cSKevin Hilman 22841762b8cSKevin Hilman if (aacirun->bytes <= 0) { 22941762b8cSKevin Hilman aacirun->bytes += aacirun->period; 23041762b8cSKevin Hilman aacirun->ptr = ptr; 231d6a89fefSRussell King spin_unlock(&aacirun->lock); 23241762b8cSKevin Hilman snd_pcm_period_elapsed(aacirun->substream); 233d6a89fefSRussell King spin_lock(&aacirun->lock); 23441762b8cSKevin Hilman } 23541762b8cSKevin Hilman if (!(aacirun->cr & CR_EN)) 23641762b8cSKevin Hilman break; 23741762b8cSKevin Hilman 23841762b8cSKevin Hilman val = readl(aacirun->base + AACI_SR); 23941762b8cSKevin Hilman if (!(val & SR_RXHF)) 24041762b8cSKevin Hilman break; 24141762b8cSKevin Hilman if (!(val & SR_RXFF)) 24241762b8cSKevin Hilman len >>= 1; 24341762b8cSKevin Hilman 24441762b8cSKevin Hilman aacirun->bytes -= len; 24541762b8cSKevin Hilman 24641762b8cSKevin Hilman /* reading 16 bytes at a time */ 24741762b8cSKevin Hilman for( ; len > 0; len -= 16) { 24841762b8cSKevin Hilman asm( 24941762b8cSKevin Hilman "ldmia %1, {r0, r1, r2, r3}\n\t" 25041762b8cSKevin Hilman "stmia %0!, {r0, r1, r2, r3}" 25141762b8cSKevin Hilman : "+r" (ptr) 25241762b8cSKevin Hilman : "r" (aacirun->fifo) 25341762b8cSKevin Hilman : "r0", "r1", "r2", "r3", "cc"); 25441762b8cSKevin Hilman 25541762b8cSKevin Hilman if (ptr >= aacirun->end) 25641762b8cSKevin Hilman ptr = aacirun->start; 25741762b8cSKevin Hilman } 25841762b8cSKevin Hilman } while(1); 259d6a89fefSRussell King 26041762b8cSKevin Hilman aacirun->ptr = ptr; 261d6a89fefSRussell King 262d6a89fefSRussell King spin_unlock(&aacirun->lock); 26341762b8cSKevin Hilman } 26441762b8cSKevin Hilman 265cb5a6ffcSRussell King if (mask & ISR_URINTR) { 26662578cbfSKevin Hilman dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel); 26762578cbfSKevin Hilman writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR); 268cb5a6ffcSRussell King } 269cb5a6ffcSRussell King 270cb5a6ffcSRussell King if (mask & ISR_TXINTR) { 271cb5a6ffcSRussell King struct aaci_runtime *aacirun = &aaci->playback; 272cb5a6ffcSRussell King void *ptr; 273cb5a6ffcSRussell King 274cb5a6ffcSRussell King if (!aacirun->substream || !aacirun->start) { 275898eb71cSJoe Perches dev_warn(&aaci->dev->dev, "TX interrupt???\n"); 276cb5a6ffcSRussell King writel(0, aacirun->base + AACI_IE); 277cb5a6ffcSRussell King return; 278cb5a6ffcSRussell King } 279cb5a6ffcSRussell King 280d6a89fefSRussell King spin_lock(&aacirun->lock); 281d6a89fefSRussell King 282cb5a6ffcSRussell King ptr = aacirun->ptr; 283cb5a6ffcSRussell King do { 284cb5a6ffcSRussell King unsigned int len = aacirun->fifosz; 285cb5a6ffcSRussell King u32 val; 286cb5a6ffcSRussell King 287cb5a6ffcSRussell King if (aacirun->bytes <= 0) { 288cb5a6ffcSRussell King aacirun->bytes += aacirun->period; 289cb5a6ffcSRussell King aacirun->ptr = ptr; 290d6a89fefSRussell King spin_unlock(&aacirun->lock); 291cb5a6ffcSRussell King snd_pcm_period_elapsed(aacirun->substream); 292d6a89fefSRussell King spin_lock(&aacirun->lock); 293cb5a6ffcSRussell King } 29441762b8cSKevin Hilman if (!(aacirun->cr & CR_EN)) 295cb5a6ffcSRussell King break; 296cb5a6ffcSRussell King 297cb5a6ffcSRussell King val = readl(aacirun->base + AACI_SR); 298cb5a6ffcSRussell King if (!(val & SR_TXHE)) 299cb5a6ffcSRussell King break; 300cb5a6ffcSRussell King if (!(val & SR_TXFE)) 301cb5a6ffcSRussell King len >>= 1; 302cb5a6ffcSRussell King 303cb5a6ffcSRussell King aacirun->bytes -= len; 304cb5a6ffcSRussell King 305cb5a6ffcSRussell King /* writing 16 bytes at a time */ 306cb5a6ffcSRussell King for ( ; len > 0; len -= 16) { 307cb5a6ffcSRussell King asm( 308cb5a6ffcSRussell King "ldmia %0!, {r0, r1, r2, r3}\n\t" 309cb5a6ffcSRussell King "stmia %1, {r0, r1, r2, r3}" 310cb5a6ffcSRussell King : "+r" (ptr) 311cb5a6ffcSRussell King : "r" (aacirun->fifo) 312cb5a6ffcSRussell King : "r0", "r1", "r2", "r3", "cc"); 313cb5a6ffcSRussell King 314cb5a6ffcSRussell King if (ptr >= aacirun->end) 315cb5a6ffcSRussell King ptr = aacirun->start; 316cb5a6ffcSRussell King } 317cb5a6ffcSRussell King } while (1); 318cb5a6ffcSRussell King 319cb5a6ffcSRussell King aacirun->ptr = ptr; 320d6a89fefSRussell King 321d6a89fefSRussell King spin_unlock(&aacirun->lock); 322cb5a6ffcSRussell King } 323cb5a6ffcSRussell King } 324cb5a6ffcSRussell King 3257d12e780SDavid Howells static irqreturn_t aaci_irq(int irq, void *devid) 326cb5a6ffcSRussell King { 327cb5a6ffcSRussell King struct aaci *aaci = devid; 328cb5a6ffcSRussell King u32 mask; 329cb5a6ffcSRussell King int i; 330cb5a6ffcSRussell King 331cb5a6ffcSRussell King mask = readl(aaci->base + AACI_ALLINTS); 332cb5a6ffcSRussell King if (mask) { 333cb5a6ffcSRussell King u32 m = mask; 334cb5a6ffcSRussell King for (i = 0; i < 4; i++, m >>= 7) { 335cb5a6ffcSRussell King if (m & 0x7f) { 33662578cbfSKevin Hilman aaci_fifo_irq(aaci, i, m); 337cb5a6ffcSRussell King } 338cb5a6ffcSRussell King } 339cb5a6ffcSRussell King } 340cb5a6ffcSRussell King 341cb5a6ffcSRussell King return mask ? IRQ_HANDLED : IRQ_NONE; 342cb5a6ffcSRussell King } 343cb5a6ffcSRussell King 344cb5a6ffcSRussell King 345cb5a6ffcSRussell King 346cb5a6ffcSRussell King /* 347cb5a6ffcSRussell King * ALSA support. 348cb5a6ffcSRussell King */ 349ceb9e476STakashi Iwai static struct snd_pcm_hardware aaci_hw_info = { 350cb5a6ffcSRussell King .info = SNDRV_PCM_INFO_MMAP | 351cb5a6ffcSRussell King SNDRV_PCM_INFO_MMAP_VALID | 352cb5a6ffcSRussell King SNDRV_PCM_INFO_INTERLEAVED | 353cb5a6ffcSRussell King SNDRV_PCM_INFO_BLOCK_TRANSFER | 354cb5a6ffcSRussell King SNDRV_PCM_INFO_RESUME, 355cb5a6ffcSRussell King 356cb5a6ffcSRussell King /* 357cb5a6ffcSRussell King * ALSA doesn't support 18-bit or 20-bit packed into 32-bit 358cb5a6ffcSRussell King * words. It also doesn't support 12-bit at all. 359cb5a6ffcSRussell King */ 360cb5a6ffcSRussell King .formats = SNDRV_PCM_FMTBIT_S16_LE, 361cb5a6ffcSRussell King 3626ca867c8SRussell King /* rates are setup from the AC'97 codec */ 363cb5a6ffcSRussell King .channels_min = 2, 364cb5a6ffcSRussell King .channels_max = 6, 365cb5a6ffcSRussell King .buffer_bytes_max = 64 * 1024, 366cb5a6ffcSRussell King .period_bytes_min = 256, 367cb5a6ffcSRussell King .period_bytes_max = PAGE_SIZE, 368cb5a6ffcSRussell King .periods_min = 4, 369cb5a6ffcSRussell King .periods_max = PAGE_SIZE / 16, 370cb5a6ffcSRussell King }; 371cb5a6ffcSRussell King 37241762b8cSKevin Hilman static int __aaci_pcm_open(struct aaci *aaci, 37341762b8cSKevin Hilman struct snd_pcm_substream *substream, 374cb5a6ffcSRussell King struct aaci_runtime *aacirun) 375cb5a6ffcSRussell King { 376ceb9e476STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 377cb5a6ffcSRussell King int ret; 378cb5a6ffcSRussell King 379cb5a6ffcSRussell King aacirun->substream = substream; 380cb5a6ffcSRussell King runtime->private_data = aacirun; 381cb5a6ffcSRussell King runtime->hw = aaci_hw_info; 3826ca867c8SRussell King runtime->hw.rates = aacirun->pcm->rates; 3836ca867c8SRussell King snd_pcm_limit_hw_rates(runtime); 384cb5a6ffcSRussell King 385a08d5658SRussell King if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 386a08d5658SRussell King aacirun->pcm->r[1].slots) 387a08d5658SRussell King snd_ac97_pcm_double_rate_rules(runtime); 388a08d5658SRussell King 389cb5a6ffcSRussell King /* 390cb5a6ffcSRussell King * FIXME: ALSA specifies fifo_size in bytes. If we're in normal 391cb5a6ffcSRussell King * mode, each 32-bit word contains one sample. If we're in 392cb5a6ffcSRussell King * compact mode, each 32-bit word contains two samples, effectively 393cb5a6ffcSRussell King * halving the FIFO size. However, we don't know for sure which 394cb5a6ffcSRussell King * we'll be using at this point. We set this to the lower limit. 395cb5a6ffcSRussell King */ 396cb5a6ffcSRussell King runtime->hw.fifo_size = aaci->fifosize * 2; 397cb5a6ffcSRussell King 39865ca68b3SThomas Gleixner ret = request_irq(aaci->dev->irq[0], aaci_irq, IRQF_SHARED|IRQF_DISABLED, 399cb5a6ffcSRussell King DRIVER_NAME, aaci); 400cb5a6ffcSRussell King if (ret) 401cb5a6ffcSRussell King goto out; 402cb5a6ffcSRussell King 403cb5a6ffcSRussell King return 0; 404cb5a6ffcSRussell King 405cb5a6ffcSRussell King out: 406cb5a6ffcSRussell King return ret; 407cb5a6ffcSRussell King } 408cb5a6ffcSRussell King 409cb5a6ffcSRussell King 410cb5a6ffcSRussell King /* 411cb5a6ffcSRussell King * Common ALSA stuff 412cb5a6ffcSRussell King */ 413ceb9e476STakashi Iwai static int aaci_pcm_close(struct snd_pcm_substream *substream) 414cb5a6ffcSRussell King { 415cb5a6ffcSRussell King struct aaci *aaci = substream->private_data; 416cb5a6ffcSRussell King struct aaci_runtime *aacirun = substream->runtime->private_data; 417cb5a6ffcSRussell King 41841762b8cSKevin Hilman WARN_ON(aacirun->cr & CR_EN); 419cb5a6ffcSRussell King 420cb5a6ffcSRussell King aacirun->substream = NULL; 421cb5a6ffcSRussell King free_irq(aaci->dev->irq[0], aaci); 422cb5a6ffcSRussell King 423cb5a6ffcSRussell King return 0; 424cb5a6ffcSRussell King } 425cb5a6ffcSRussell King 426ceb9e476STakashi Iwai static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) 427cb5a6ffcSRussell King { 428cb5a6ffcSRussell King struct aaci_runtime *aacirun = substream->runtime->private_data; 429cb5a6ffcSRussell King 430cb5a6ffcSRussell King /* 431cb5a6ffcSRussell King * This must not be called with the device enabled. 432cb5a6ffcSRussell King */ 43341762b8cSKevin Hilman WARN_ON(aacirun->cr & CR_EN); 434cb5a6ffcSRussell King 435cb5a6ffcSRussell King if (aacirun->pcm_open) 436cb5a6ffcSRussell King snd_ac97_pcm_close(aacirun->pcm); 437cb5a6ffcSRussell King aacirun->pcm_open = 0; 438cb5a6ffcSRussell King 439cb5a6ffcSRussell King /* 440cb5a6ffcSRussell King * Clear out the DMA and any allocated buffers. 441cb5a6ffcSRussell King */ 442d6797322STakashi Iwai snd_pcm_lib_free_pages(substream); 443cb5a6ffcSRussell King 444cb5a6ffcSRussell King return 0; 445cb5a6ffcSRussell King } 446cb5a6ffcSRussell King 447ceb9e476STakashi Iwai static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, 448cb5a6ffcSRussell King struct aaci_runtime *aacirun, 449ceb9e476STakashi Iwai struct snd_pcm_hw_params *params) 450cb5a6ffcSRussell King { 451cb5a6ffcSRussell King int err; 452903b0eb3SPeter Huewe struct aaci *aaci = substream->private_data; 453cb5a6ffcSRussell King 454cb5a6ffcSRussell King aaci_pcm_hw_free(substream); 4554acd57c3SRussell King if (aacirun->pcm_open) { 4564acd57c3SRussell King snd_ac97_pcm_close(aacirun->pcm); 4574acd57c3SRussell King aacirun->pcm_open = 0; 4584acd57c3SRussell King } 459cb5a6ffcSRussell King 460d6797322STakashi Iwai err = snd_pcm_lib_malloc_pages(substream, 461cb5a6ffcSRussell King params_buffer_bytes(params)); 4624e30b691SRussell King if (err >= 0) { 463a08d5658SRussell King unsigned int rate = params_rate(params); 464a08d5658SRussell King int dbl = rate > 48000; 465a08d5658SRussell King 466a08d5658SRussell King err = snd_ac97_pcm_open(aacirun->pcm, rate, 467cb5a6ffcSRussell King params_channels(params), 468a08d5658SRussell King aacirun->pcm->r[dbl].slots); 469cb5a6ffcSRussell King 4704e30b691SRussell King aacirun->pcm_open = err == 0; 471d3aee799SRussell King aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; 472d3aee799SRussell King aacirun->fifosz = aaci->fifosize * 4; 473d3aee799SRussell King 474d3aee799SRussell King if (aacirun->cr & CR_COMPACT) 475d3aee799SRussell King aacirun->fifosz >>= 1; 4764e30b691SRussell King } 477cb5a6ffcSRussell King 478cb5a6ffcSRussell King return err; 479cb5a6ffcSRussell King } 480cb5a6ffcSRussell King 481ceb9e476STakashi Iwai static int aaci_pcm_prepare(struct snd_pcm_substream *substream) 482cb5a6ffcSRussell King { 483ceb9e476STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 484cb5a6ffcSRussell King struct aaci_runtime *aacirun = runtime->private_data; 485cb5a6ffcSRussell King 4864e30b691SRussell King aacirun->start = runtime->dma_area; 48788cdca9cSRussell King aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream); 488cb5a6ffcSRussell King aacirun->ptr = aacirun->start; 489cb5a6ffcSRussell King aacirun->period = 490cb5a6ffcSRussell King aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); 491cb5a6ffcSRussell King 492cb5a6ffcSRussell King return 0; 493cb5a6ffcSRussell King } 494cb5a6ffcSRussell King 495ceb9e476STakashi Iwai static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream) 496cb5a6ffcSRussell King { 497ceb9e476STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 498cb5a6ffcSRussell King struct aaci_runtime *aacirun = runtime->private_data; 499cb5a6ffcSRussell King ssize_t bytes = aacirun->ptr - aacirun->start; 500cb5a6ffcSRussell King 501cb5a6ffcSRussell King return bytes_to_frames(runtime, bytes); 502cb5a6ffcSRussell King } 503cb5a6ffcSRussell King 504cb5a6ffcSRussell King 505cb5a6ffcSRussell King /* 506cb5a6ffcSRussell King * Playback specific ALSA stuff 507cb5a6ffcSRussell King */ 508cb5a6ffcSRussell King static const u32 channels_to_txmask[] = { 50941762b8cSKevin Hilman [2] = CR_SL3 | CR_SL4, 51041762b8cSKevin Hilman [4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8, 51141762b8cSKevin Hilman [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9, 512cb5a6ffcSRussell King }; 513cb5a6ffcSRussell King 514cb5a6ffcSRussell King /* 515cb5a6ffcSRussell King * We can support two and four channel audio. Unfortunately 516cb5a6ffcSRussell King * six channel audio requires a non-standard channel ordering: 517cb5a6ffcSRussell King * 2 -> FL(3), FR(4) 518cb5a6ffcSRussell King * 4 -> FL(3), FR(4), SL(7), SR(8) 519cb5a6ffcSRussell King * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required) 520cb5a6ffcSRussell King * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual) 521cb5a6ffcSRussell King * This requires an ALSA configuration file to correct. 522cb5a6ffcSRussell King */ 523cb5a6ffcSRussell King static unsigned int channel_list[] = { 2, 4, 6 }; 524cb5a6ffcSRussell King 525cb5a6ffcSRussell King static int 526ceb9e476STakashi Iwai aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule) 527cb5a6ffcSRussell King { 528cb5a6ffcSRussell King struct aaci *aaci = rule->private; 529cb5a6ffcSRussell King unsigned int chan_mask = 1 << 0, slots; 530cb5a6ffcSRussell King 531cb5a6ffcSRussell King /* 532cb5a6ffcSRussell King * pcms[0] is the our 5.1 PCM instance. 533cb5a6ffcSRussell King */ 534cb5a6ffcSRussell King slots = aaci->ac97_bus->pcms[0].r[0].slots; 535cb5a6ffcSRussell King if (slots & (1 << AC97_SLOT_PCM_SLEFT)) { 536cb5a6ffcSRussell King chan_mask |= 1 << 1; 537cb5a6ffcSRussell King if (slots & (1 << AC97_SLOT_LFE)) 538cb5a6ffcSRussell King chan_mask |= 1 << 2; 539cb5a6ffcSRussell King } 540cb5a6ffcSRussell King 541cb5a6ffcSRussell King return snd_interval_list(hw_param_interval(p, rule->var), 542cb5a6ffcSRussell King ARRAY_SIZE(channel_list), channel_list, 543cb5a6ffcSRussell King chan_mask); 544cb5a6ffcSRussell King } 545cb5a6ffcSRussell King 54641762b8cSKevin Hilman static int aaci_pcm_open(struct snd_pcm_substream *substream) 547cb5a6ffcSRussell King { 548cb5a6ffcSRussell King struct aaci *aaci = substream->private_data; 549cb5a6ffcSRussell King int ret; 550cb5a6ffcSRussell King 551cb5a6ffcSRussell King /* 552cb5a6ffcSRussell King * Add rule describing channel dependency. 553cb5a6ffcSRussell King */ 554cb5a6ffcSRussell King ret = snd_pcm_hw_rule_add(substream->runtime, 0, 555cb5a6ffcSRussell King SNDRV_PCM_HW_PARAM_CHANNELS, 556cb5a6ffcSRussell King aaci_rule_channels, aaci, 557cb5a6ffcSRussell King SNDRV_PCM_HW_PARAM_CHANNELS, -1); 558cb5a6ffcSRussell King if (ret) 559cb5a6ffcSRussell King return ret; 560cb5a6ffcSRussell King 56141762b8cSKevin Hilman if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 56241762b8cSKevin Hilman ret = __aaci_pcm_open(aaci, substream, &aaci->playback); 56341762b8cSKevin Hilman } else { 56441762b8cSKevin Hilman ret = __aaci_pcm_open(aaci, substream, &aaci->capture); 56541762b8cSKevin Hilman } 56641762b8cSKevin Hilman return ret; 567cb5a6ffcSRussell King } 568cb5a6ffcSRussell King 569ceb9e476STakashi Iwai static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, 570ceb9e476STakashi Iwai struct snd_pcm_hw_params *params) 571cb5a6ffcSRussell King { 572cb5a6ffcSRussell King struct aaci_runtime *aacirun = substream->runtime->private_data; 573cb5a6ffcSRussell King unsigned int channels = params_channels(params); 574cb5a6ffcSRussell King int ret; 575cb5a6ffcSRussell King 576cb5a6ffcSRussell King WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) || 577cb5a6ffcSRussell King !channels_to_txmask[channels]); 578cb5a6ffcSRussell King 579cb5a6ffcSRussell King ret = aaci_pcm_hw_params(substream, aacirun, params); 580cb5a6ffcSRussell King 581cb5a6ffcSRussell King /* 582cb5a6ffcSRussell King * Enable FIFO, compact mode, 16 bits per sample. 583cb5a6ffcSRussell King * FIXME: double rate slots? 584cb5a6ffcSRussell King */ 585d3aee799SRussell King if (ret >= 0) 586cb5a6ffcSRussell King aacirun->cr |= channels_to_txmask[channels]; 587cb5a6ffcSRussell King 588cb5a6ffcSRussell King return ret; 589cb5a6ffcSRussell King } 590cb5a6ffcSRussell King 591cb5a6ffcSRussell King static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) 592cb5a6ffcSRussell King { 593cb5a6ffcSRussell King u32 ie; 594cb5a6ffcSRussell King 595cb5a6ffcSRussell King ie = readl(aacirun->base + AACI_IE); 596cb5a6ffcSRussell King ie &= ~(IE_URIE|IE_TXIE); 597cb5a6ffcSRussell King writel(ie, aacirun->base + AACI_IE); 59841762b8cSKevin Hilman aacirun->cr &= ~CR_EN; 599d6a89fefSRussell King aaci_chan_wait_ready(aacirun, SR_TXB); 600cb5a6ffcSRussell King writel(aacirun->cr, aacirun->base + AACI_TXCR); 601cb5a6ffcSRussell King } 602cb5a6ffcSRussell King 603cb5a6ffcSRussell King static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) 604cb5a6ffcSRussell King { 605cb5a6ffcSRussell King u32 ie; 606cb5a6ffcSRussell King 607d6a89fefSRussell King aaci_chan_wait_ready(aacirun, SR_TXB); 60841762b8cSKevin Hilman aacirun->cr |= CR_EN; 609cb5a6ffcSRussell King 610cb5a6ffcSRussell King ie = readl(aacirun->base + AACI_IE); 611cb5a6ffcSRussell King ie |= IE_URIE | IE_TXIE; 612cb5a6ffcSRussell King writel(ie, aacirun->base + AACI_IE); 613cb5a6ffcSRussell King writel(aacirun->cr, aacirun->base + AACI_TXCR); 614cb5a6ffcSRussell King } 615cb5a6ffcSRussell King 616ceb9e476STakashi Iwai static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) 617cb5a6ffcSRussell King { 618cb5a6ffcSRussell King struct aaci_runtime *aacirun = substream->runtime->private_data; 619cb5a6ffcSRussell King unsigned long flags; 620cb5a6ffcSRussell King int ret = 0; 621cb5a6ffcSRussell King 622d6a89fefSRussell King spin_lock_irqsave(&aacirun->lock, flags); 623d6a89fefSRussell King 624cb5a6ffcSRussell King switch (cmd) { 625cb5a6ffcSRussell King case SNDRV_PCM_TRIGGER_START: 626cb5a6ffcSRussell King aaci_pcm_playback_start(aacirun); 627cb5a6ffcSRussell King break; 628cb5a6ffcSRussell King 629cb5a6ffcSRussell King case SNDRV_PCM_TRIGGER_RESUME: 630cb5a6ffcSRussell King aaci_pcm_playback_start(aacirun); 631cb5a6ffcSRussell King break; 632cb5a6ffcSRussell King 633cb5a6ffcSRussell King case SNDRV_PCM_TRIGGER_STOP: 634cb5a6ffcSRussell King aaci_pcm_playback_stop(aacirun); 635cb5a6ffcSRussell King break; 636cb5a6ffcSRussell King 637cb5a6ffcSRussell King case SNDRV_PCM_TRIGGER_SUSPEND: 638cb5a6ffcSRussell King aaci_pcm_playback_stop(aacirun); 639cb5a6ffcSRussell King break; 640cb5a6ffcSRussell King 641cb5a6ffcSRussell King case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 642cb5a6ffcSRussell King break; 643cb5a6ffcSRussell King 644cb5a6ffcSRussell King case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 645cb5a6ffcSRussell King break; 646cb5a6ffcSRussell King 647cb5a6ffcSRussell King default: 648cb5a6ffcSRussell King ret = -EINVAL; 649cb5a6ffcSRussell King } 650d6a89fefSRussell King 651d6a89fefSRussell King spin_unlock_irqrestore(&aacirun->lock, flags); 652cb5a6ffcSRussell King 653cb5a6ffcSRussell King return ret; 654cb5a6ffcSRussell King } 655cb5a6ffcSRussell King 656ceb9e476STakashi Iwai static struct snd_pcm_ops aaci_playback_ops = { 65741762b8cSKevin Hilman .open = aaci_pcm_open, 658cb5a6ffcSRussell King .close = aaci_pcm_close, 659cb5a6ffcSRussell King .ioctl = snd_pcm_lib_ioctl, 660cb5a6ffcSRussell King .hw_params = aaci_pcm_playback_hw_params, 661cb5a6ffcSRussell King .hw_free = aaci_pcm_hw_free, 662cb5a6ffcSRussell King .prepare = aaci_pcm_prepare, 663cb5a6ffcSRussell King .trigger = aaci_pcm_playback_trigger, 664cb5a6ffcSRussell King .pointer = aaci_pcm_pointer, 665cb5a6ffcSRussell King }; 666cb5a6ffcSRussell King 6678a371840SRussell King static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream, 6688a371840SRussell King struct snd_pcm_hw_params *params) 66941762b8cSKevin Hilman { 67041762b8cSKevin Hilman struct aaci_runtime *aacirun = substream->runtime->private_data; 67141762b8cSKevin Hilman int ret; 672cb5a6ffcSRussell King 67341762b8cSKevin Hilman ret = aaci_pcm_hw_params(substream, aacirun, params); 674d3aee799SRussell King if (ret >= 0) 67541762b8cSKevin Hilman /* Line in record: slot 3 and 4 */ 67641762b8cSKevin Hilman aacirun->cr |= CR_SL3 | CR_SL4; 67741762b8cSKevin Hilman 67841762b8cSKevin Hilman return ret; 67941762b8cSKevin Hilman } 68041762b8cSKevin Hilman 68141762b8cSKevin Hilman static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun) 68241762b8cSKevin Hilman { 68341762b8cSKevin Hilman u32 ie; 68441762b8cSKevin Hilman 685d6a89fefSRussell King aaci_chan_wait_ready(aacirun, SR_RXB); 68641762b8cSKevin Hilman 68741762b8cSKevin Hilman ie = readl(aacirun->base + AACI_IE); 68841762b8cSKevin Hilman ie &= ~(IE_ORIE | IE_RXIE); 68941762b8cSKevin Hilman writel(ie, aacirun->base+AACI_IE); 69041762b8cSKevin Hilman 69141762b8cSKevin Hilman aacirun->cr &= ~CR_EN; 69241762b8cSKevin Hilman 69341762b8cSKevin Hilman writel(aacirun->cr, aacirun->base + AACI_RXCR); 69441762b8cSKevin Hilman } 69541762b8cSKevin Hilman 69641762b8cSKevin Hilman static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) 69741762b8cSKevin Hilman { 69841762b8cSKevin Hilman u32 ie; 69941762b8cSKevin Hilman 700d6a89fefSRussell King aaci_chan_wait_ready(aacirun, SR_RXB); 70141762b8cSKevin Hilman 70241762b8cSKevin Hilman #ifdef DEBUG 70341762b8cSKevin Hilman /* RX Timeout value: bits 28:17 in RXCR */ 70441762b8cSKevin Hilman aacirun->cr |= 0xf << 17; 70541762b8cSKevin Hilman #endif 70641762b8cSKevin Hilman 70741762b8cSKevin Hilman aacirun->cr |= CR_EN; 70841762b8cSKevin Hilman writel(aacirun->cr, aacirun->base + AACI_RXCR); 70941762b8cSKevin Hilman 71041762b8cSKevin Hilman ie = readl(aacirun->base + AACI_IE); 71141762b8cSKevin Hilman ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full 71241762b8cSKevin Hilman writel(ie, aacirun->base + AACI_IE); 71341762b8cSKevin Hilman } 71441762b8cSKevin Hilman 7158a371840SRussell King static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) 7168a371840SRussell King { 71741762b8cSKevin Hilman struct aaci_runtime *aacirun = substream->runtime->private_data; 71841762b8cSKevin Hilman unsigned long flags; 71941762b8cSKevin Hilman int ret = 0; 72041762b8cSKevin Hilman 721d6a89fefSRussell King spin_lock_irqsave(&aacirun->lock, flags); 72241762b8cSKevin Hilman 72341762b8cSKevin Hilman switch (cmd) { 72441762b8cSKevin Hilman case SNDRV_PCM_TRIGGER_START: 72541762b8cSKevin Hilman aaci_pcm_capture_start(aacirun); 72641762b8cSKevin Hilman break; 72741762b8cSKevin Hilman 72841762b8cSKevin Hilman case SNDRV_PCM_TRIGGER_RESUME: 72941762b8cSKevin Hilman aaci_pcm_capture_start(aacirun); 73041762b8cSKevin Hilman break; 73141762b8cSKevin Hilman 73241762b8cSKevin Hilman case SNDRV_PCM_TRIGGER_STOP: 73341762b8cSKevin Hilman aaci_pcm_capture_stop(aacirun); 73441762b8cSKevin Hilman break; 73541762b8cSKevin Hilman 73641762b8cSKevin Hilman case SNDRV_PCM_TRIGGER_SUSPEND: 73741762b8cSKevin Hilman aaci_pcm_capture_stop(aacirun); 73841762b8cSKevin Hilman break; 73941762b8cSKevin Hilman 74041762b8cSKevin Hilman case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 74141762b8cSKevin Hilman break; 74241762b8cSKevin Hilman 74341762b8cSKevin Hilman case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 74441762b8cSKevin Hilman break; 74541762b8cSKevin Hilman 74641762b8cSKevin Hilman default: 74741762b8cSKevin Hilman ret = -EINVAL; 74841762b8cSKevin Hilman } 74941762b8cSKevin Hilman 750d6a89fefSRussell King spin_unlock_irqrestore(&aacirun->lock, flags); 75141762b8cSKevin Hilman 75241762b8cSKevin Hilman return ret; 75341762b8cSKevin Hilman } 75441762b8cSKevin Hilman 7558a371840SRussell King static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream) 75641762b8cSKevin Hilman { 75741762b8cSKevin Hilman struct snd_pcm_runtime *runtime = substream->runtime; 75841762b8cSKevin Hilman struct aaci *aaci = substream->private_data; 75941762b8cSKevin Hilman 76041762b8cSKevin Hilman aaci_pcm_prepare(substream); 76141762b8cSKevin Hilman 76241762b8cSKevin Hilman /* allow changing of sample rate */ 76341762b8cSKevin Hilman aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */ 76441762b8cSKevin Hilman aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); 76541762b8cSKevin Hilman aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate); 76641762b8cSKevin Hilman 76741762b8cSKevin Hilman /* Record select: Mic: 0, Aux: 3, Line: 4 */ 76841762b8cSKevin Hilman aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404); 76941762b8cSKevin Hilman 77041762b8cSKevin Hilman return 0; 77141762b8cSKevin Hilman } 77241762b8cSKevin Hilman 7738a371840SRussell King static struct snd_pcm_ops aaci_capture_ops = { 77441762b8cSKevin Hilman .open = aaci_pcm_open, 77541762b8cSKevin Hilman .close = aaci_pcm_close, 77641762b8cSKevin Hilman .ioctl = snd_pcm_lib_ioctl, 77741762b8cSKevin Hilman .hw_params = aaci_pcm_capture_hw_params, 77841762b8cSKevin Hilman .hw_free = aaci_pcm_hw_free, 77941762b8cSKevin Hilman .prepare = aaci_pcm_capture_prepare, 78041762b8cSKevin Hilman .trigger = aaci_pcm_capture_trigger, 78141762b8cSKevin Hilman .pointer = aaci_pcm_pointer, 78241762b8cSKevin Hilman }; 783cb5a6ffcSRussell King 784cb5a6ffcSRussell King /* 785cb5a6ffcSRussell King * Power Management. 786cb5a6ffcSRussell King */ 787cb5a6ffcSRussell King #ifdef CONFIG_PM 788ceb9e476STakashi Iwai static int aaci_do_suspend(struct snd_card *card, unsigned int state) 789cb5a6ffcSRussell King { 790cb5a6ffcSRussell King struct aaci *aaci = card->private_data; 791792a6c51STakashi Iwai snd_power_change_state(card, SNDRV_CTL_POWER_D3cold); 792cb5a6ffcSRussell King snd_pcm_suspend_all(aaci->pcm); 793cb5a6ffcSRussell King return 0; 794cb5a6ffcSRussell King } 795cb5a6ffcSRussell King 796ceb9e476STakashi Iwai static int aaci_do_resume(struct snd_card *card, unsigned int state) 797cb5a6ffcSRussell King { 798792a6c51STakashi Iwai snd_power_change_state(card, SNDRV_CTL_POWER_D0); 799cb5a6ffcSRussell King return 0; 800cb5a6ffcSRussell King } 801cb5a6ffcSRussell King 802e36d394dSRichard Purdie static int aaci_suspend(struct amba_device *dev, pm_message_t state) 803cb5a6ffcSRussell King { 804ceb9e476STakashi Iwai struct snd_card *card = amba_get_drvdata(dev); 805cb5a6ffcSRussell King return card ? aaci_do_suspend(card) : 0; 806cb5a6ffcSRussell King } 807cb5a6ffcSRussell King 808cb5a6ffcSRussell King static int aaci_resume(struct amba_device *dev) 809cb5a6ffcSRussell King { 810ceb9e476STakashi Iwai struct snd_card *card = amba_get_drvdata(dev); 811cb5a6ffcSRussell King return card ? aaci_do_resume(card) : 0; 812cb5a6ffcSRussell King } 813cb5a6ffcSRussell King #else 814cb5a6ffcSRussell King #define aaci_do_suspend NULL 815cb5a6ffcSRussell King #define aaci_do_resume NULL 816cb5a6ffcSRussell King #define aaci_suspend NULL 817cb5a6ffcSRussell King #define aaci_resume NULL 818cb5a6ffcSRussell King #endif 819cb5a6ffcSRussell King 820cb5a6ffcSRussell King 821cb5a6ffcSRussell King static struct ac97_pcm ac97_defs[] __devinitdata = { 822cb5a6ffcSRussell King [0] = { /* Front PCM */ 823cb5a6ffcSRussell King .exclusive = 1, 824cb5a6ffcSRussell King .r = { 825cb5a6ffcSRussell King [0] = { 826cb5a6ffcSRussell King .slots = (1 << AC97_SLOT_PCM_LEFT) | 827cb5a6ffcSRussell King (1 << AC97_SLOT_PCM_RIGHT) | 828cb5a6ffcSRussell King (1 << AC97_SLOT_PCM_CENTER) | 829cb5a6ffcSRussell King (1 << AC97_SLOT_PCM_SLEFT) | 830cb5a6ffcSRussell King (1 << AC97_SLOT_PCM_SRIGHT) | 831cb5a6ffcSRussell King (1 << AC97_SLOT_LFE), 832cb5a6ffcSRussell King }, 833a08d5658SRussell King [1] = { 834a08d5658SRussell King .slots = (1 << AC97_SLOT_PCM_LEFT) | 835a08d5658SRussell King (1 << AC97_SLOT_PCM_RIGHT) | 836a08d5658SRussell King (1 << AC97_SLOT_PCM_LEFT_0) | 837a08d5658SRussell King (1 << AC97_SLOT_PCM_RIGHT_0), 838a08d5658SRussell King }, 839cb5a6ffcSRussell King }, 840cb5a6ffcSRussell King }, 841cb5a6ffcSRussell King [1] = { /* PCM in */ 842cb5a6ffcSRussell King .stream = 1, 843cb5a6ffcSRussell King .exclusive = 1, 844cb5a6ffcSRussell King .r = { 845cb5a6ffcSRussell King [0] = { 846cb5a6ffcSRussell King .slots = (1 << AC97_SLOT_PCM_LEFT) | 847cb5a6ffcSRussell King (1 << AC97_SLOT_PCM_RIGHT), 848cb5a6ffcSRussell King }, 849cb5a6ffcSRussell King }, 850cb5a6ffcSRussell King }, 851cb5a6ffcSRussell King [2] = { /* Mic in */ 852cb5a6ffcSRussell King .stream = 1, 853cb5a6ffcSRussell King .exclusive = 1, 854cb5a6ffcSRussell King .r = { 855cb5a6ffcSRussell King [0] = { 856cb5a6ffcSRussell King .slots = (1 << AC97_SLOT_MIC), 857cb5a6ffcSRussell King }, 858cb5a6ffcSRussell King }, 859cb5a6ffcSRussell King } 860cb5a6ffcSRussell King }; 861cb5a6ffcSRussell King 862ceb9e476STakashi Iwai static struct snd_ac97_bus_ops aaci_bus_ops = { 863cb5a6ffcSRussell King .write = aaci_ac97_write, 864cb5a6ffcSRussell King .read = aaci_ac97_read, 865cb5a6ffcSRussell King }; 866cb5a6ffcSRussell King 867cb5a6ffcSRussell King static int __devinit aaci_probe_ac97(struct aaci *aaci) 868cb5a6ffcSRussell King { 869ceb9e476STakashi Iwai struct snd_ac97_template ac97_template; 870ceb9e476STakashi Iwai struct snd_ac97_bus *ac97_bus; 871ceb9e476STakashi Iwai struct snd_ac97 *ac97; 872cb5a6ffcSRussell King int ret; 873cb5a6ffcSRussell King 874cb5a6ffcSRussell King /* 875cb5a6ffcSRussell King * Assert AACIRESET for 2us 876cb5a6ffcSRussell King */ 877cb5a6ffcSRussell King writel(0, aaci->base + AACI_RESET); 878cb5a6ffcSRussell King udelay(2); 879cb5a6ffcSRussell King writel(RESET_NRST, aaci->base + AACI_RESET); 880cb5a6ffcSRussell King 881cb5a6ffcSRussell King /* 882cb5a6ffcSRussell King * Give the AC'97 codec more than enough time 883cb5a6ffcSRussell King * to wake up. (42us = ~2 frames at 48kHz.) 884cb5a6ffcSRussell King */ 885250c7a61SRussell King udelay(FRAME_PERIOD_US * 2); 886cb5a6ffcSRussell King 887cb5a6ffcSRussell King ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus); 888cb5a6ffcSRussell King if (ret) 889cb5a6ffcSRussell King goto out; 890cb5a6ffcSRussell King 891cb5a6ffcSRussell King ac97_bus->clock = 48000; 892cb5a6ffcSRussell King aaci->ac97_bus = ac97_bus; 893cb5a6ffcSRussell King 894ceb9e476STakashi Iwai memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); 895cb5a6ffcSRussell King ac97_template.private_data = aaci; 896cb5a6ffcSRussell King ac97_template.num = 0; 897cb5a6ffcSRussell King ac97_template.scaps = AC97_SCAP_SKIP_MODEM; 898cb5a6ffcSRussell King 899cb5a6ffcSRussell King ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); 900cb5a6ffcSRussell King if (ret) 901cb5a6ffcSRussell King goto out; 90241762b8cSKevin Hilman aaci->ac97 = ac97; 903cb5a6ffcSRussell King 904cb5a6ffcSRussell King /* 905cb5a6ffcSRussell King * Disable AC97 PC Beep input on audio codecs. 906cb5a6ffcSRussell King */ 907cb5a6ffcSRussell King if (ac97_is_audio(ac97)) 908cb5a6ffcSRussell King snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e); 909cb5a6ffcSRussell King 910cb5a6ffcSRussell King ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs); 911cb5a6ffcSRussell King if (ret) 912cb5a6ffcSRussell King goto out; 913cb5a6ffcSRussell King 914cb5a6ffcSRussell King aaci->playback.pcm = &ac97_bus->pcms[0]; 91541762b8cSKevin Hilman aaci->capture.pcm = &ac97_bus->pcms[1]; 916cb5a6ffcSRussell King 917cb5a6ffcSRussell King out: 918cb5a6ffcSRussell King return ret; 919cb5a6ffcSRussell King } 920cb5a6ffcSRussell King 921ceb9e476STakashi Iwai static void aaci_free_card(struct snd_card *card) 922cb5a6ffcSRussell King { 923cb5a6ffcSRussell King struct aaci *aaci = card->private_data; 924cb5a6ffcSRussell King if (aaci->base) 925cb5a6ffcSRussell King iounmap(aaci->base); 926cb5a6ffcSRussell King } 927cb5a6ffcSRussell King 928cb5a6ffcSRussell King static struct aaci * __devinit aaci_init_card(struct amba_device *dev) 929cb5a6ffcSRussell King { 930cb5a6ffcSRussell King struct aaci *aaci; 931ceb9e476STakashi Iwai struct snd_card *card; 932bd7dd77cSTakashi Iwai int err; 933cb5a6ffcSRussell King 934bd7dd77cSTakashi Iwai err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, 935bd7dd77cSTakashi Iwai THIS_MODULE, sizeof(struct aaci), &card); 936bd7dd77cSTakashi Iwai if (err < 0) 937631e8ad4STakashi Iwai return NULL; 938cb5a6ffcSRussell King 939cb5a6ffcSRussell King card->private_free = aaci_free_card; 940cb5a6ffcSRussell King 941cb5a6ffcSRussell King strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); 942cb5a6ffcSRussell King strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname)); 943cb5a6ffcSRussell King snprintf(card->longname, sizeof(card->longname), 944aa0a2ddcSGreg Kroah-Hartman "%s at 0x%016llx, irq %d", 945aa0a2ddcSGreg Kroah-Hartman card->shortname, (unsigned long long)dev->res.start, 946aa0a2ddcSGreg Kroah-Hartman dev->irq[0]); 947cb5a6ffcSRussell King 948cb5a6ffcSRussell King aaci = card->private_data; 94912aa7579SIngo Molnar mutex_init(&aaci->ac97_sem); 950cb5a6ffcSRussell King aaci->card = card; 951cb5a6ffcSRussell King aaci->dev = dev; 952cb5a6ffcSRussell King 953cb5a6ffcSRussell King /* Set MAINCR to allow slot 1 and 2 data IO */ 954cb5a6ffcSRussell King aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN | 955cb5a6ffcSRussell King MAINCR_SL2RXEN | MAINCR_SL2TXEN; 956cb5a6ffcSRussell King 957cb5a6ffcSRussell King return aaci; 958cb5a6ffcSRussell King } 959cb5a6ffcSRussell King 960cb5a6ffcSRussell King static int __devinit aaci_init_pcm(struct aaci *aaci) 961cb5a6ffcSRussell King { 962ceb9e476STakashi Iwai struct snd_pcm *pcm; 963cb5a6ffcSRussell King int ret; 964cb5a6ffcSRussell King 96541762b8cSKevin Hilman ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm); 966cb5a6ffcSRussell King if (ret == 0) { 967cb5a6ffcSRussell King aaci->pcm = pcm; 968cb5a6ffcSRussell King pcm->private_data = aaci; 969cb5a6ffcSRussell King pcm->info_flags = 0; 970cb5a6ffcSRussell King 971cb5a6ffcSRussell King strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); 972cb5a6ffcSRussell King 973cb5a6ffcSRussell King snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); 97441762b8cSKevin Hilman snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); 975d6797322STakashi Iwai snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 976d4946431STakashi Iwai NULL, 0, 64 * 1024); 977cb5a6ffcSRussell King } 978cb5a6ffcSRussell King 979cb5a6ffcSRussell King return ret; 980cb5a6ffcSRussell King } 981cb5a6ffcSRussell King 982cb5a6ffcSRussell King static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) 983cb5a6ffcSRussell King { 98441762b8cSKevin Hilman struct aaci_runtime *aacirun = &aaci->playback; 985cb5a6ffcSRussell King int i; 986cb5a6ffcSRussell King 98741762b8cSKevin Hilman writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR); 988cb5a6ffcSRussell King 98941762b8cSKevin Hilman for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++) 99041762b8cSKevin Hilman writel(0, aacirun->fifo); 991cb5a6ffcSRussell King 99241762b8cSKevin Hilman writel(0, aacirun->base + AACI_TXCR); 993cb5a6ffcSRussell King 994cb5a6ffcSRussell King /* 995cb5a6ffcSRussell King * Re-initialise the AACI after the FIFO depth test, to 996cb5a6ffcSRussell King * ensure that the FIFOs are empty. Unfortunately, merely 997cb5a6ffcSRussell King * disabling the channel doesn't clear the FIFO. 998cb5a6ffcSRussell King */ 999cb5a6ffcSRussell King writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR); 10007c289385SRussell King readl(aaci->base + AACI_MAINCR); 10017c289385SRussell King udelay(1); 1002cb5a6ffcSRussell King writel(aaci->maincr, aaci->base + AACI_MAINCR); 1003cb5a6ffcSRussell King 1004cb5a6ffcSRussell King /* 1005cb5a6ffcSRussell King * If we hit 4096, we failed. Go back to the specified 1006cb5a6ffcSRussell King * fifo depth. 1007cb5a6ffcSRussell King */ 1008cb5a6ffcSRussell King if (i == 4096) 1009cb5a6ffcSRussell King i = 8; 1010cb5a6ffcSRussell King 1011cb5a6ffcSRussell King return i; 1012cb5a6ffcSRussell King } 1013cb5a6ffcSRussell King 1014aa25afadSRussell King static int __devinit aaci_probe(struct amba_device *dev, 1015aa25afadSRussell King const struct amba_id *id) 1016cb5a6ffcSRussell King { 1017cb5a6ffcSRussell King struct aaci *aaci; 1018cb5a6ffcSRussell King int ret, i; 1019cb5a6ffcSRussell King 1020cb5a6ffcSRussell King ret = amba_request_regions(dev, NULL); 1021cb5a6ffcSRussell King if (ret) 1022cb5a6ffcSRussell King return ret; 1023cb5a6ffcSRussell King 1024cb5a6ffcSRussell King aaci = aaci_init_card(dev); 1025631e8ad4STakashi Iwai if (!aaci) { 1026631e8ad4STakashi Iwai ret = -ENOMEM; 1027cb5a6ffcSRussell King goto out; 1028cb5a6ffcSRussell King } 1029cb5a6ffcSRussell King 1030dc890c2dSLinus Walleij aaci->base = ioremap(dev->res.start, resource_size(&dev->res)); 1031cb5a6ffcSRussell King if (!aaci->base) { 1032cb5a6ffcSRussell King ret = -ENOMEM; 1033cb5a6ffcSRussell King goto out; 1034cb5a6ffcSRussell King } 1035cb5a6ffcSRussell King 1036cb5a6ffcSRussell King /* 1037cb5a6ffcSRussell King * Playback uses AACI channel 0 1038cb5a6ffcSRussell King */ 1039d6a89fefSRussell King spin_lock_init(&aaci->playback.lock); 1040cb5a6ffcSRussell King aaci->playback.base = aaci->base + AACI_CSCH1; 1041cb5a6ffcSRussell King aaci->playback.fifo = aaci->base + AACI_DR1; 1042cb5a6ffcSRussell King 104341762b8cSKevin Hilman /* 104441762b8cSKevin Hilman * Capture uses AACI channel 0 104541762b8cSKevin Hilman */ 1046d6a89fefSRussell King spin_lock_init(&aaci->capture.lock); 104741762b8cSKevin Hilman aaci->capture.base = aaci->base + AACI_CSCH1; 104841762b8cSKevin Hilman aaci->capture.fifo = aaci->base + AACI_DR1; 104941762b8cSKevin Hilman 1050cb5a6ffcSRussell King for (i = 0; i < 4; i++) { 1051e12ba644Sviro@ZenIV.linux.org.uk void __iomem *base = aaci->base + i * 0x14; 1052cb5a6ffcSRussell King 1053cb5a6ffcSRussell King writel(0, base + AACI_IE); 1054cb5a6ffcSRussell King writel(0, base + AACI_TXCR); 1055cb5a6ffcSRussell King writel(0, base + AACI_RXCR); 1056cb5a6ffcSRussell King } 1057cb5a6ffcSRussell King 1058cb5a6ffcSRussell King writel(0x1fff, aaci->base + AACI_INTCLR); 1059cb5a6ffcSRussell King writel(aaci->maincr, aaci->base + AACI_MAINCR); 1060b68b58fdSPhilby John /* 1061b68b58fdSPhilby John * Fix: ac97 read back fail errors by reading 1062b68b58fdSPhilby John * from any arbitrary aaci register. 1063b68b58fdSPhilby John */ 1064b68b58fdSPhilby John readl(aaci->base + AACI_CSCH1); 1065cb5a6ffcSRussell King ret = aaci_probe_ac97(aaci); 1066cb5a6ffcSRussell King if (ret) 1067cb5a6ffcSRussell King goto out; 1068cb5a6ffcSRussell King 1069f27f218cSCatalin Marinas /* 1070f27f218cSCatalin Marinas * Size the FIFOs (must be multiple of 16). 1071f27f218cSCatalin Marinas */ 1072f27f218cSCatalin Marinas aaci->fifosize = aaci_size_fifo(aaci); 1073f27f218cSCatalin Marinas if (aaci->fifosize & 15) { 1074f27f218cSCatalin Marinas printk(KERN_WARNING "AACI: fifosize = %d not supported\n", 1075f27f218cSCatalin Marinas aaci->fifosize); 1076f27f218cSCatalin Marinas ret = -ENODEV; 1077f27f218cSCatalin Marinas goto out; 1078f27f218cSCatalin Marinas } 1079f27f218cSCatalin Marinas 1080cb5a6ffcSRussell King ret = aaci_init_pcm(aaci); 1081cb5a6ffcSRussell King if (ret) 1082cb5a6ffcSRussell King goto out; 1083cb5a6ffcSRussell King 1084a76af199STakashi Iwai snd_card_set_dev(aaci->card, &dev->dev); 1085a76af199STakashi Iwai 1086cb5a6ffcSRussell King ret = snd_card_register(aaci->card); 1087cb5a6ffcSRussell King if (ret == 0) { 1088cb5a6ffcSRussell King dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, 1089cb5a6ffcSRussell King aaci->fifosize); 1090cb5a6ffcSRussell King amba_set_drvdata(dev, aaci->card); 1091cb5a6ffcSRussell King return ret; 1092cb5a6ffcSRussell King } 1093cb5a6ffcSRussell King 1094cb5a6ffcSRussell King out: 1095cb5a6ffcSRussell King if (aaci) 1096cb5a6ffcSRussell King snd_card_free(aaci->card); 1097cb5a6ffcSRussell King amba_release_regions(dev); 1098cb5a6ffcSRussell King return ret; 1099cb5a6ffcSRussell King } 1100cb5a6ffcSRussell King 1101cb5a6ffcSRussell King static int __devexit aaci_remove(struct amba_device *dev) 1102cb5a6ffcSRussell King { 1103ceb9e476STakashi Iwai struct snd_card *card = amba_get_drvdata(dev); 1104cb5a6ffcSRussell King 1105cb5a6ffcSRussell King amba_set_drvdata(dev, NULL); 1106cb5a6ffcSRussell King 1107cb5a6ffcSRussell King if (card) { 1108cb5a6ffcSRussell King struct aaci *aaci = card->private_data; 1109cb5a6ffcSRussell King writel(0, aaci->base + AACI_MAINCR); 1110cb5a6ffcSRussell King 1111cb5a6ffcSRussell King snd_card_free(card); 1112cb5a6ffcSRussell King amba_release_regions(dev); 1113cb5a6ffcSRussell King } 1114cb5a6ffcSRussell King 1115cb5a6ffcSRussell King return 0; 1116cb5a6ffcSRussell King } 1117cb5a6ffcSRussell King 1118cb5a6ffcSRussell King static struct amba_id aaci_ids[] = { 1119cb5a6ffcSRussell King { 1120cb5a6ffcSRussell King .id = 0x00041041, 1121cb5a6ffcSRussell King .mask = 0x000fffff, 1122cb5a6ffcSRussell King }, 1123cb5a6ffcSRussell King { 0, 0 }, 1124cb5a6ffcSRussell King }; 1125cb5a6ffcSRussell King 1126cb5a6ffcSRussell King static struct amba_driver aaci_driver = { 1127cb5a6ffcSRussell King .drv = { 1128cb5a6ffcSRussell King .name = DRIVER_NAME, 1129cb5a6ffcSRussell King }, 1130cb5a6ffcSRussell King .probe = aaci_probe, 1131cb5a6ffcSRussell King .remove = __devexit_p(aaci_remove), 1132cb5a6ffcSRussell King .suspend = aaci_suspend, 1133cb5a6ffcSRussell King .resume = aaci_resume, 1134cb5a6ffcSRussell King .id_table = aaci_ids, 1135cb5a6ffcSRussell King }; 1136cb5a6ffcSRussell King 1137cb5a6ffcSRussell King static int __init aaci_init(void) 1138cb5a6ffcSRussell King { 1139cb5a6ffcSRussell King return amba_driver_register(&aaci_driver); 1140cb5a6ffcSRussell King } 1141cb5a6ffcSRussell King 1142cb5a6ffcSRussell King static void __exit aaci_exit(void) 1143cb5a6ffcSRussell King { 1144cb5a6ffcSRussell King amba_driver_unregister(&aaci_driver); 1145cb5a6ffcSRussell King } 1146cb5a6ffcSRussell King 1147cb5a6ffcSRussell King module_init(aaci_init); 1148cb5a6ffcSRussell King module_exit(aaci_exit); 1149cb5a6ffcSRussell King 1150cb5a6ffcSRussell King MODULE_LICENSE("GPL"); 1151cb5a6ffcSRussell King MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver"); 1152