Commit 81d91acf authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (36 commits)
  ALSA: hda - Add VREF powerdown sequence for another board
  ALSA: oss - volume control for CSWITCH and CROUTE
  ALSA: hda - add missing comma in ad1884_slave_vols
  sound: usb-audio: allow period sizes less than 1 ms
  sound: usb-audio: save data packet interval in audioformat structure
  sound: usb-audio: remove check_hw_params_convention()
  sound: usb-audio: show sample format width in proc file
  ASoC: fsl_dma: Pass the proper device for dma mapping routines
  ASoC: Fix null dereference in ak4535_remove()
  ALSA: hda - enable SPDIF output for Intel DX58SO board
  ALSA: snd-atmel-abdac: increase periods_min to 6 instead of 4
  ALSA: snd-atmel-abdac: replace bus_id with dev_name()
  ALSA: snd-atmel-ac97c: replace bus_id with dev_name()
  ALSA: snd-atmel-ac97c: cleanup registers when removing driver
  ALSA: snd-atmel-ac97c: do a proper reset of the external codec
  ALSA: snd-atmel-ac97c: enable interrupts to catch events for error reporting
  ALSA: snd-atmel-ac97c: set correct size for buffer hardware parameter
  ALSA: snd-atmel-ac97c: do not overwrite OCA and ICA when assigning channels
  ALSA: snd-atmel-ac97c: remove dead break statements after return in switch case
  ALSA: snd-atmel-ac97c: cleanup register definitions
  ...
parents 132ea5e9 0dd7b0cb
ASoC jack detection
===================
ALSA has a standard API for representing physical jacks to user space,
the kernel side of which can be seen in include/sound/jack.h. ASoC
provides a version of this API adding two additional features:
- It allows more than one jack detection method to work together on one
user visible jack. In embedded systems it is common for multiple
to be present on a single jack but handled by separate bits of
hardware.
- Integration with DAPM, allowing DAPM endpoints to be updated
automatically based on the detected jack status (eg, turning off the
headphone outputs if no headphones are present).
This is done by splitting the jacks up into three things working
together: the jack itself represented by a struct snd_soc_jack, sets of
snd_soc_jack_pins representing DAPM endpoints to update and blocks of
code providing jack reporting mechanisms.
For example, a system may have a stereo headset jack with two reporting
mechanisms, one for the headphone and one for the microphone. Some
systems won't be able to use their speaker output while a headphone is
connected and so will want to make sure to update both speaker and
headphone when the headphone jack status changes.
The jack - struct snd_soc_jack
==============================
This represents a physical jack on the system and is what is visible to
user space. The jack itself is completely passive, it is set up by the
machine driver and updated by jack detection methods.
Jacks are created by the machine driver calling snd_soc_jack_new().
snd_soc_jack_pin
================
These represent a DAPM pin to update depending on some of the status
bits supported by the jack. Each snd_soc_jack has zero or more of these
which are updated automatically. They are created by the machine driver
and associated with the jack using snd_soc_jack_add_pins(). The status
of the endpoint may configured to be the opposite of the jack status if
required (eg, enabling a built in microphone if a microphone is not
connected via a jack).
Jack detection methods
======================
Actual jack detection is done by code which is able to monitor some
input to the system and update a jack by calling snd_soc_jack_report(),
specifying a subset of bits to update. The jack detection code should
be set up by the machine driver, taking configuration for the jack to
update and the set of things to report when the jack is connected.
Often this is done based on the status of a GPIO - a handler for this is
provided by the snd_soc_jack_add_gpio() function. Other methods are
also available, for example integrated into CODECs. One example of
CODEC integrated jack detection can be see in the WM8350 driver.
Each jack may have multiple reporting mechanisms, though it will need at
least one to be useful.
Machine drivers
===============
These are all hooked together by the machine driver depending on the
system hardware. The machine driver will set up the snd_soc_jack and
the list of pins to update then set up one or more jack detection
mechanisms to update that jack based on their current status.
...@@ -238,6 +238,8 @@ static inline void pxa_ac97_cold_pxa3xx(void) ...@@ -238,6 +238,8 @@ static inline void pxa_ac97_cold_pxa3xx(void)
bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
{ {
unsigned long gsr;
#ifdef CONFIG_PXA25x #ifdef CONFIG_PXA25x
if (cpu_is_pxa25x()) if (cpu_is_pxa25x())
pxa_ac97_warm_pxa25x(); pxa_ac97_warm_pxa25x();
...@@ -254,10 +256,10 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) ...@@ -254,10 +256,10 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
else else
#endif #endif
BUG(); BUG();
gsr = GSR | gsr_bits;
if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { if (!(gsr & (GSR_PCR | GSR_SCR))) {
printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
__func__, gsr_bits); __func__, gsr);
return false; return false;
} }
...@@ -268,6 +270,8 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); ...@@ -268,6 +270,8 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
{ {
unsigned long gsr;
#ifdef CONFIG_PXA25x #ifdef CONFIG_PXA25x
if (cpu_is_pxa25x()) if (cpu_is_pxa25x())
pxa_ac97_cold_pxa25x(); pxa_ac97_cold_pxa25x();
...@@ -285,9 +289,10 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) ...@@ -285,9 +289,10 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
#endif #endif
BUG(); BUG();
if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { gsr = GSR | gsr_bits;
if (!(gsr & (GSR_PCR | GSR_SCR))) {
printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
__func__, gsr_bits); __func__, gsr);
return false; return false;
} }
......
...@@ -165,7 +165,7 @@ static struct snd_pcm_hardware atmel_abdac_hw = { ...@@ -165,7 +165,7 @@ static struct snd_pcm_hardware atmel_abdac_hw = {
.buffer_bytes_max = 64 * 4096, .buffer_bytes_max = 64 * 4096,
.period_bytes_min = 4096, .period_bytes_min = 4096,
.period_bytes_max = 4096, .period_bytes_max = 4096,
.periods_min = 4, .periods_min = 6,
.periods_max = 64, .periods_max = 64,
}; };
...@@ -502,7 +502,7 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev) ...@@ -502,7 +502,7 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card); platform_set_drvdata(pdev, card);
dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n", dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n",
dac->regs, dac->dma.chan->dev->device.bus_id); dac->regs, dev_name(&dac->dma.chan->dev->device));
return retval; return retval;
......
/* /*
* Driver for the Atmel AC97C controller * Driver for Atmel AC97C
* *
* Copyright (C) 2005-2009 Atmel Corporation * Copyright (C) 2005-2009 Atmel Corporation
* *
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/device.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -65,6 +66,7 @@ struct atmel_ac97c { ...@@ -65,6 +66,7 @@ struct atmel_ac97c {
/* Serialize access to opened variable */ /* Serialize access to opened variable */
spinlock_t lock; spinlock_t lock;
void __iomem *regs; void __iomem *regs;
int irq;
int opened; int opened;
int reset_pin; int reset_pin;
}; };
...@@ -150,10 +152,10 @@ static struct snd_pcm_hardware atmel_ac97c_hw = { ...@@ -150,10 +152,10 @@ static struct snd_pcm_hardware atmel_ac97c_hw = {
.rate_max = 48000, .rate_max = 48000,
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 2,
.buffer_bytes_max = 64 * 4096, .buffer_bytes_max = 2 * 2 * 64 * 2048,
.period_bytes_min = 4096, .period_bytes_min = 4096,
.period_bytes_max = 4096, .period_bytes_max = 4096,
.periods_min = 4, .periods_min = 6,
.periods_max = 64, .periods_max = 64,
}; };
...@@ -297,9 +299,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) ...@@ -297,9 +299,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
{ {
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long word = 0; unsigned long word = ac97c_readl(chip, OCA);
int retval; int retval;
word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */ /* assign channels to AC97C channel A */
switch (runtime->channels) { switch (runtime->channels) {
case 1: case 1:
...@@ -312,7 +316,6 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) ...@@ -312,7 +316,6 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
default: default:
/* TODO: support more than two channels */ /* TODO: support more than two channels */
return -EINVAL; return -EINVAL;
break;
} }
ac97c_writel(chip, OCA, word); ac97c_writel(chip, OCA, word);
...@@ -324,13 +327,25 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) ...@@ -324,13 +327,25 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
word |= AC97C_CMR_CEM_LITTLE; word |= AC97C_CMR_CEM_LITTLE;
break; break;
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
default:
word &= ~(AC97C_CMR_CEM_LITTLE); word &= ~(AC97C_CMR_CEM_LITTLE);
break; 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); 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 */ /* set variable rate if needed */
if (runtime->rate != 48000) { if (runtime->rate != 48000) {
word = ac97c_readl(chip, MR); word = ac97c_readl(chip, MR);
...@@ -359,9 +374,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) ...@@ -359,9 +374,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
{ {
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long word = 0; unsigned long word = ac97c_readl(chip, ICA);
int retval; int retval;
word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */ /* assign channels to AC97C channel A */
switch (runtime->channels) { switch (runtime->channels) {
case 1: case 1:
...@@ -374,7 +391,6 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) ...@@ -374,7 +391,6 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
default: default:
/* TODO: support more than two channels */ /* TODO: support more than two channels */
return -EINVAL; return -EINVAL;
break;
} }
ac97c_writel(chip, ICA, word); ac97c_writel(chip, ICA, word);
...@@ -386,13 +402,25 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) ...@@ -386,13 +402,25 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
word |= AC97C_CMR_CEM_LITTLE; word |= AC97C_CMR_CEM_LITTLE;
break; break;
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
default:
word &= ~(AC97C_CMR_CEM_LITTLE); word &= ~(AC97C_CMR_CEM_LITTLE);
break; break;
default:
word = ac97c_readl(chip, ICA);
word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
ac97c_writel(chip, ICA, word);
return -EINVAL;
} }
/* Enable overrun interrupt on channel A */
word |= AC97C_CSR_OVRUN;
ac97c_writel(chip, CAMR, word); 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 */ /* set variable rate if needed */
if (runtime->rate != 48000) { if (runtime->rate != 48000) {
word = ac97c_readl(chip, MR); word = ac97c_readl(chip, MR);
...@@ -543,6 +571,43 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = { ...@@ -543,6 +571,43 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = {
.pointer = atmel_ac97c_capture_pointer, .pointer = atmel_ac97c_capture_pointer,
}; };
static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
{
struct atmel_ac97c *chip = (struct atmel_ac97c *)dev;
irqreturn_t retval = IRQ_NONE;
u32 sr = ac97c_readl(chip, SR);
u32 casr = ac97c_readl(chip, CASR);
u32 cosr = ac97c_readl(chip, COSR);
if (sr & AC97C_SR_CAEVT) {
dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
casr & AC97C_CSR_OVRUN ? " OVRUN" : "",
casr & AC97C_CSR_RXRDY ? " RXRDY" : "",
casr & AC97C_CSR_UNRUN ? " UNRUN" : "",
casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
casr & AC97C_CSR_TXRDY ? " TXRDY" : "",
!casr ? " NONE" : "");
retval = IRQ_HANDLED;
}
if (sr & AC97C_SR_COEVT) {
dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
cosr & AC97C_CSR_OVRUN ? " OVRUN" : "",
cosr & AC97C_CSR_RXRDY ? " RXRDY" : "",
cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
cosr & AC97C_CSR_TXRDY ? " TXRDY" : "",
!cosr ? " NONE" : "");
retval = IRQ_HANDLED;
}
if (retval == IRQ_NONE) {
dev_err(&chip->pdev->dev, "spurious interrupt sr 0x%08x "
"casr 0x%08x cosr 0x%08x\n", sr, casr, cosr);
}
return retval;
}
static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
{ {
struct snd_pcm *pcm; struct snd_pcm *pcm;
...@@ -665,17 +730,17 @@ static bool filter(struct dma_chan *chan, void *slave) ...@@ -665,17 +730,17 @@ static bool filter(struct dma_chan *chan, void *slave)
static void atmel_ac97c_reset(struct atmel_ac97c *chip) static void atmel_ac97c_reset(struct atmel_ac97c *chip)
{ {
ac97c_writel(chip, MR, AC97C_MR_WRST); ac97c_writel(chip, MR, 0);
ac97c_writel(chip, MR, AC97C_MR_ENA);
ac97c_writel(chip, CAMR, 0);
ac97c_writel(chip, COMR, 0);
if (gpio_is_valid(chip->reset_pin)) { if (gpio_is_valid(chip->reset_pin)) {
gpio_set_value(chip->reset_pin, 0); gpio_set_value(chip->reset_pin, 0);
/* AC97 v2.2 specifications says minimum 1 us. */ /* AC97 v2.2 specifications says minimum 1 us. */
udelay(10); udelay(2);
gpio_set_value(chip->reset_pin, 1); gpio_set_value(chip->reset_pin, 1);
} }
udelay(1);
ac97c_writel(chip, MR, AC97C_MR_ENA);
} }
static int __devinit atmel_ac97c_probe(struct platform_device *pdev) static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
...@@ -690,6 +755,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -690,6 +755,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
.read = atmel_ac97c_read, .read = atmel_ac97c_read,
}; };
int retval; int retval;
int irq;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) { if (!regs) {
...@@ -703,6 +769,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -703,6 +769,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
} }
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_dbg(&pdev->dev, "could not get irq\n");
return -ENXIO;
}
pclk = clk_get(&pdev->dev, "pclk"); pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(pclk)) { if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "no peripheral clock\n"); dev_dbg(&pdev->dev, "no peripheral clock\n");
...@@ -719,6 +791,13 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -719,6 +791,13 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
chip = get_chip(card); chip = get_chip(card);
retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
if (retval) {
dev_dbg(&pdev->dev, "unable to request irq %d\n", irq);
goto err_request_irq;
}
chip->irq = irq;
spin_lock_init(&chip->lock); spin_lock_init(&chip->lock);
strcpy(card->driver, "Atmel AC97C"); strcpy(card->driver, "Atmel AC97C");
...@@ -747,14 +826,18 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -747,14 +826,18 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
snd_card_set_dev(card, &pdev->dev); snd_card_set_dev(card, &pdev->dev);
atmel_ac97c_reset(chip);
/* Enable overrun interrupt from codec channel */
ac97c_writel(chip, COMR, AC97C_CSR_OVRUN);
ac97c_writel(chip, IER, ac97c_readl(chip, IMR) | AC97C_SR_COEVT);
retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus); retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
if (retval) { if (retval) {
dev_dbg(&pdev->dev, "could not register on ac97 bus\n"); dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
goto err_ac97_bus; goto err_ac97_bus;
} }
atmel_ac97c_reset(chip);
retval = atmel_ac97c_mixer_new(chip); retval = atmel_ac97c_mixer_new(chip);
if (retval) { if (retval) {
dev_dbg(&pdev->dev, "could not register ac97 mixer\n"); dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
...@@ -773,7 +856,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -773,7 +856,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
chip->dma.rx_chan = dma_request_channel(mask, filter, dws); chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
dev_info(&chip->pdev->dev, "using %s for DMA RX\n", dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
chip->dma.rx_chan->dev->device.bus_id); dev_name(&chip->dma.rx_chan->dev->device));
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
} }
...@@ -789,7 +872,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -789,7 +872,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
chip->dma.tx_chan = dma_request_channel(mask, filter, dws); chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
dev_info(&chip->pdev->dev, "using %s for DMA TX\n", dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
chip->dma.tx_chan->dev->device.bus_id); dev_name(&chip->dma.tx_chan->dev->device));
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
} }
...@@ -809,7 +892,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -809,7 +892,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
retval = snd_card_register(card); retval = snd_card_register(card);
if (retval) { if (retval) {
dev_dbg(&pdev->dev, "could not register sound card\n"); dev_dbg(&pdev->dev, "could not register sound card\n");
goto err_ac97_bus; goto err_dma;
} }
platform_set_drvdata(pdev, card); platform_set_drvdata(pdev, card);
...@@ -836,6 +919,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) ...@@ -836,6 +919,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
iounmap(chip->regs); iounmap(chip->regs);
err_ioremap: err_ioremap:
free_irq(irq, chip);
err_request_irq:
snd_card_free(card); snd_card_free(card);
err_snd_card_new: err_snd_card_new:
clk_disable(pclk); clk_disable(pclk);
...@@ -884,9 +969,14 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) ...@@ -884,9 +969,14 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
if (gpio_is_valid(chip->reset_pin)) if (gpio_is_valid(chip->reset_pin))
gpio_free(chip->reset_pin); gpio_free(chip->reset_pin);
ac97c_writel(chip, CAMR, 0);
ac97c_writel(chip, COMR, 0);
ac97c_writel(chip, MR, 0);
clk_disable(chip->pclk); clk_disable(chip->pclk);
clk_put(chip->pclk); clk_put(chip->pclk);
iounmap(chip->regs); iounmap(chip->regs);
free_irq(chip->irq, chip);
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan); dma_release_channel(chip->dma.rx_chan);
......
/* /*
* Register definitions for the Atmel AC97C controller * Register definitions for Atmel AC97C
* *
* Copyright (C) 2005-2009 Atmel Corporation * Copyright (C) 2005-2009 Atmel Corporation
* *
...@@ -17,10 +17,6 @@ ...@@ -17,10 +17,6 @@
#define AC97C_CATHR 0x24 #define AC97C_CATHR 0x24
#define AC97C_CASR 0x28 #define AC97C_CASR 0x28
#define AC97C_CAMR 0x2c #define AC97C_CAMR 0x2c
#define AC97C_CBRHR 0x30
#define AC97C_CBTHR 0x34
#define AC97C_CBSR 0x38
#define AC97C_CBMR 0x3c
#define AC97C_CORHR 0x40 #define AC97C_CORHR 0x40
#define AC97C_COTHR 0x44 #define AC97C_COTHR 0x44
#define AC97C_COSR 0x48 #define AC97C_COSR 0x48
...@@ -46,8 +42,10 @@ ...@@ -46,8 +42,10 @@
#define AC97C_MR_VRA (1 << 2) #define AC97C_MR_VRA (1 << 2)
#define AC97C_CSR_TXRDY (1 << 0) #define AC97C_CSR_TXRDY (1 << 0)
#define AC97C_CSR_TXEMPTY (1 << 1)
#define AC97C_CSR_UNRUN (1 << 2) #define AC97C_CSR_UNRUN (1 << 2)
#define AC97C_CSR_RXRDY (1 << 4) #define AC97C_CSR_RXRDY (1 << 4)
#define AC97C_CSR_OVRUN (1 << 5)
#define AC97C_CSR_ENDTX (1 << 10) #define AC97C_CSR_ENDTX (1 << 10)
#define AC97C_CSR_ENDRX (1 << 14) #define AC97C_CSR_ENDRX (1 << 14)
...@@ -61,11 +59,15 @@ ...@@ -61,11 +59,15 @@
#define AC97C_CMR_DMAEN (1 << 22) #define AC97C_CMR_DMAEN (1 << 22)
#define AC97C_SR_CAEVT (1 << 3) #define AC97C_SR_CAEVT (1 << 3)
#define AC97C_SR_COEVT (1 << 2)
#define AC97C_SR_WKUP (1 << 1)
#define AC97C_SR_SOF (1 << 0)
#define AC97C_CH_MASK(slot) \
(0x7 << (3 * (AC97_SLOT_##slot - 3)))
#define AC97C_CH_ASSIGN(slot, channel) \ #define AC97C_CH_ASSIGN(slot, channel) \
(AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3))) (AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3)))
#define AC97C_CHANNEL_NONE 0x0 #define AC97C_CHANNEL_NONE 0x0
#define AC97C_CHANNEL_A 0x1 #define AC97C_CHANNEL_A 0x1
#define AC97C_CHANNEL_B 0x2
#endif /* __SOUND_ATMEL_AC97C_H */ #endif /* __SOUND_ATMEL_AC97C_H */
...@@ -703,19 +703,27 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, ...@@ -703,19 +703,27 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
if (left || right) { if (left || right) {
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
} else { } else {
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
} }
......
...@@ -481,6 +481,7 @@ OPL3SA2_DOUBLE_TLV("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1, ...@@ -481,6 +481,7 @@ OPL3SA2_DOUBLE_TLV("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1,
OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1), OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1),
OPL3SA2_SINGLE_TLV("Mic Playback Volume", 0, 0x09, 0, 31, 1, OPL3SA2_SINGLE_TLV("Mic Playback Volume", 0, 0x09, 0, 31, 1,
db_scale_5bit_12db_max), db_scale_5bit_12db_max),
OPL3SA2_SINGLE("ZV Port Switch", 0, 0x02, 0, 1, 0),
}; };
static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = { static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = {
......
...@@ -3256,7 +3256,7 @@ static const char *ad1884_slave_vols[] = { ...@@ -3256,7 +3256,7 @@ static const char *ad1884_slave_vols[] = {
"Mic Playback Volume", "Mic Playback Volume",
"CD Playback Volume", "CD Playback Volume",
"Internal Mic Playback Volume", "Internal Mic Playback Volume",
"Docking Mic Playback Volume" "Docking Mic Playback Volume",
/* "Beep Playback Volume", */ /* "Beep Playback Volume", */
"IEC958 Playback Volume", "IEC958 Playback Volume",
NULL NULL
......
...@@ -8764,6 +8764,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ...@@ -8764,6 +8764,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
{} {}
}; };
static hda_nid_t alc883_slave_dig_outs[] = {
ALC1200_DIGOUT_NID, 0,
};
static hda_nid_t alc1200_slave_dig_outs[] = { static hda_nid_t alc1200_slave_dig_outs[] = {
ALC883_DIGOUT_NID, 0, ALC883_DIGOUT_NID, 0,
}; };
...@@ -8809,6 +8813,7 @@ static struct alc_config_preset alc883_presets[] = { ...@@ -8809,6 +8813,7 @@ static struct alc_config_preset alc883_presets[] = {
.dac_nids = alc883_dac_nids, .dac_nids = alc883_dac_nids,
.dig_out_nid = ALC883_DIGOUT_NID, .dig_out_nid = ALC883_DIGOUT_NID,
.dig_in_nid = ALC883_DIGIN_NID, .dig_in_nid = ALC883_DIGIN_NID,
.slave_dig_outs = alc883_slave_dig_outs,
.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
.channel_mode = alc883_3ST_6ch_intel_modes, .channel_mode = alc883_3ST_6ch_intel_modes,
.need_dac_fix = 1, .need_dac_fix = 1,
......
...@@ -4413,6 +4413,24 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) ...@@ -4413,6 +4413,24 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
if (spec->num_pwrs > 0) if (spec->num_pwrs > 0)
stac92xx_pin_sense(codec, event->nid); stac92xx_pin_sense(codec, event->nid);
stac92xx_report_jack(codec, event->nid); stac92xx_report_jack(codec, event->nid);
switch (codec->subsystem_id) {
case 0x103c308f:
if (event->nid == 0xb) {
int pin = AC_PINCTL_IN_EN;
if (get_pin_presence(codec, 0xa)
&& get_pin_presence(codec, 0xb))
pin |= AC_PINCTL_VREF_80;
if (!get_pin_presence(codec, 0xb))
pin |= AC_PINCTL_VREF_80;
/* toggle VREF state based on mic + hp pin
* status
*/
stac92xx_auto_set_pinctl(codec, 0x0a, pin);
}
}
break; break;
case STAC_VREF_EVENT: case STAC_VREF_EVENT:
data = snd_hda_codec_read(codec, codec->afg, 0, data = snd_hda_codec_read(codec, codec->afg, 0,
...@@ -4895,6 +4913,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) ...@@ -4895,6 +4913,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
switch (codec->vendor_id) { switch (codec->vendor_id) {
case 0x111d7604: case 0x111d7604:
case 0x111d7605: case 0x111d7605:
case 0x111d76d5:
if (spec->board_config == STAC_92HD83XXX_PWR_REF) if (spec->board_config == STAC_92HD83XXX_PWR_REF)
break; break;
spec->num_pwrs = 0; spec->num_pwrs = 0;
...@@ -5707,6 +5726,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { ...@@ -5707,6 +5726,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
{ .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
{ .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
......
...@@ -51,7 +51,7 @@ static struct platform_device *device; ...@@ -51,7 +51,7 @@ static struct platform_device *device;
/* /*
*/ */
static int __init snd_pmac_probe(struct platform_device *devptr) static int __devinit snd_pmac_probe(struct platform_device *devptr)
{ {
struct snd_card *card; struct snd_card *card;
struct snd_pmac *chip; struct snd_pmac *chip;
......
...@@ -659,7 +659,8 @@ static int ak4535_remove(struct platform_device *pdev) ...@@ -659,7 +659,8 @@ static int ak4535_remove(struct platform_device *pdev)
snd_soc_free_pcms(socdev); snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev); snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_unregister_device(codec->control_data); if (codec->control_data)
i2c_unregister_device(codec->control_data);
i2c_del_driver(&ak4535_i2c_driver); i2c_del_driver(&ak4535_i2c_driver);
#endif #endif
kfree(codec->private_data); kfree(codec->private_data);
......
...@@ -122,6 +122,9 @@ struct twl4030_priv { ...@@ -122,6 +122,9 @@ struct twl4030_priv {
unsigned int bypass_state; unsigned int bypass_state;
unsigned int codec_powered; unsigned int codec_powered;
unsigned int codec_muted; unsigned int codec_muted;
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
}; };
/* /*
...@@ -1217,6 +1220,50 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, ...@@ -1217,6 +1220,50 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
return 0; return 0;
} }
static int twl4030_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
struct twl4030_priv *twl4030 = codec->private_data;
/* If we already have a playback or capture going then constrain
* this substream to match it.
*/
if (twl4030->master_substream) {
struct snd_pcm_runtime *master_runtime;
master_runtime = twl4030->master_substream->runtime;
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
master_runtime->rate,
master_runtime->rate);
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
master_runtime->sample_bits,
master_runtime->sample_bits);
twl4030->slave_substream = substream;
} else
twl4030->master_substream = substream;
return 0;
}
static void twl4030_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
struct twl4030_priv *twl4030 = codec->private_data;
if (twl4030->master_substream == substream)
twl4030->master_substream = twl4030->slave_substream;
twl4030->slave_substream = NULL;
}
static int twl4030_hw_params(struct snd_pcm_substream *substream, static int twl4030_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
...@@ -1224,8 +1271,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, ...@@ -1224,8 +1271,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
struct twl4030_priv *twl4030 = codec->private_data;
u8 mode, old_mode, format, old_format; u8 mode, old_mode, format, old_format;
if (substream == twl4030->slave_substream)
/* Ignoring hw_params for slave substream */
return 0;
/* bit rate */ /* bit rate */
old_mode = twl4030_read_reg_cache(codec, old_mode = twl4030_read_reg_cache(codec,
TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
...@@ -1259,6 +1311,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, ...@@ -1259,6 +1311,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
case 48000: case 48000:
mode |= TWL4030_APLL_RATE_48000; mode |= TWL4030_APLL_RATE_48000;
break; break;
case 96000:
mode |= TWL4030_APLL_RATE_96000;
break;
default: default:
printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n",
params_rate(params)); params_rate(params));
...@@ -1384,6 +1439,8 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, ...@@ -1384,6 +1439,8 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
static struct snd_soc_dai_ops twl4030_dai_ops = { static struct snd_soc_dai_ops twl4030_dai_ops = {
.startup = twl4030_startup,
.shutdown = twl4030_shutdown,
.hw_params = twl4030_hw_params, .hw_params = twl4030_hw_params,
.set_sysclk = twl4030_set_dai_sysclk, .set_sysclk = twl4030_set_dai_sysclk,
.set_fmt = twl4030_set_dai_fmt, .set_fmt = twl4030_set_dai_fmt,
...@@ -1395,7 +1452,7 @@ struct snd_soc_dai twl4030_dai = { ...@@ -1395,7 +1452,7 @@ struct snd_soc_dai twl4030_dai = {
.stream_name = "Playback", .stream_name = "Playback",
.channels_min = 2, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.rates = TWL4030_RATES, .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
.formats = TWL4030_FORMATS,}, .formats = TWL4030_FORMATS,},
.capture = { .capture = {
.stream_name = "Capture", .stream_name = "Capture",
......
...@@ -109,6 +109,7 @@ ...@@ -109,6 +109,7 @@
#define TWL4030_APLL_RATE_32000 0x80 #define TWL4030_APLL_RATE_32000 0x80
#define TWL4030_APLL_RATE_44100 0x90 #define TWL4030_APLL_RATE_44100 0x90
#define TWL4030_APLL_RATE_48000 0xA0 #define TWL4030_APLL_RATE_48000 0xA0
#define TWL4030_APLL_RATE_96000 0xE0
#define TWL4030_SEL_16K 0x04 #define TWL4030_SEL_16K 0x04
#define TWL4030_CODECPDZ 0x02 #define TWL4030_CODECPDZ 0x02
#define TWL4030_OPT_MODE 0x01 #define TWL4030_OPT_MODE 0x01
......
...@@ -317,6 +317,41 @@ static int wm9705_reset(struct snd_soc_codec *codec) ...@@ -317,6 +317,41 @@ static int wm9705_reset(struct snd_soc_codec *codec)
return -EIO; return -EIO;
} }
#ifdef CONFIG_PM
static int wm9705_soc_suspend(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
return 0;
}
static int wm9705_soc_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
int i, ret;
u16 *cache = codec->reg_cache;
ret = wm9705_reset(codec);
if (ret < 0) {
printk(KERN_ERR "could not reset AC97 codec\n");
return ret;
}
for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) {
soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
}
return 0;
}
#else
#define wm9705_soc_suspend NULL
#define wm9705_soc_resume NULL
#endif
static int wm9705_soc_probe(struct platform_device *pdev) static int wm9705_soc_probe(struct platform_device *pdev)
{ {
struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_device *socdev = platform_get_drvdata(pdev);
...@@ -407,6 +442,8 @@ static int wm9705_soc_remove(struct platform_device *pdev) ...@@ -407,6 +442,8 @@ static int wm9705_soc_remove(struct platform_device *pdev)
struct snd_soc_codec_device soc_codec_dev_wm9705 = { struct snd_soc_codec_device soc_codec_dev_wm9705 = {
.probe = wm9705_soc_probe, .probe = wm9705_soc_probe,
.remove = wm9705_soc_remove, .remove = wm9705_soc_remove,
.suspend = wm9705_soc_suspend,
.resume = wm9705_soc_resume,
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705); EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705);
......
...@@ -300,7 +300,7 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, ...@@ -300,7 +300,7 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask) if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = fsl_dma_dmamask; card->dev->coherent_dma_mask = fsl_dma_dmamask;
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
fsl_dma_hardware.buffer_bytes_max, fsl_dma_hardware.buffer_bytes_max,
&pcm->streams[0].substream->dma_buffer); &pcm->streams[0].substream->dma_buffer);
if (ret) { if (ret) {
...@@ -310,7 +310,7 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, ...@@ -310,7 +310,7 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
return -ENOMEM; return -ENOMEM;
} }
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
fsl_dma_hardware.buffer_bytes_max, fsl_dma_hardware.buffer_bytes_max,
&pcm->streams[1].substream->dma_buffer); &pcm->streams[1].substream->dma_buffer);
if (ret) { if (ret) {
...@@ -418,7 +418,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) ...@@ -418,7 +418,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
return -EBUSY; return -EBUSY;
} }
dma_private = dma_alloc_coherent(substream->pcm->dev, dma_private = dma_alloc_coherent(substream->pcm->card->dev,
sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL); sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL);
if (!dma_private) { if (!dma_private) {
dev_err(substream->pcm->card->dev, dev_err(substream->pcm->card->dev,
...@@ -445,7 +445,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) ...@@ -445,7 +445,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
dev_err(substream->pcm->card->dev, dev_err(substream->pcm->card->dev,
"can't register ISR for IRQ %u (ret=%i)\n", "can't register ISR for IRQ %u (ret=%i)\n",
dma_private->irq, ret); dma_private->irq, ret);
dma_free_coherent(substream->pcm->dev, dma_free_coherent(substream->pcm->card->dev,
sizeof(struct fsl_dma_private), sizeof(struct fsl_dma_private),
dma_private, dma_private->ld_buf_phys); dma_private, dma_private->ld_buf_phys);
return ret; return ret;
...@@ -697,6 +697,23 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream) ...@@ -697,6 +697,23 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
else else
position = in_be32(&dma_channel->dar); position = in_be32(&dma_channel->dar);
/*
* When capture is started, the SSI immediately starts to fill its FIFO.
* This means that the DMA controller is not started until the FIFO is
* full. However, ALSA calls this function before that happens, when
* MR.DAR is still zero. In this case, just return zero to indicate
* that nothing has been received yet.
*/
if (!position)
return 0;
if ((position < dma_private->dma_buf_phys) ||
(position > dma_private->dma_buf_end)) {
dev_err(substream->pcm->card->dev,
"dma pointer is out of range, halting stream\n");
return SNDRV_PCM_POS_XRUN;
}
frames = bytes_to_frames(runtime, position - dma_private->dma_buf_phys); frames = bytes_to_frames(runtime, position - dma_private->dma_buf_phys);
/* /*
...@@ -761,13 +778,13 @@ static int fsl_dma_close(struct snd_pcm_substream *substream) ...@@ -761,13 +778,13 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
free_irq(dma_private->irq, dma_private); free_irq(dma_private->irq, dma_private);
if (dma_private->ld_buf_phys) { if (dma_private->ld_buf_phys) {
dma_unmap_single(substream->pcm->dev, dma_unmap_single(substream->pcm->card->dev,
dma_private->ld_buf_phys, dma_private->ld_buf_phys,
sizeof(dma_private->link), DMA_TO_DEVICE); sizeof(dma_private->link), DMA_TO_DEVICE);
} }
/* Deallocate the fsl_dma_private structure */ /* Deallocate the fsl_dma_private structure */
dma_free_coherent(substream->pcm->dev, dma_free_coherent(substream->pcm->card->dev,
sizeof(struct fsl_dma_private), sizeof(struct fsl_dma_private),
dma_private, dma_private->ld_buf_phys); dma_private, dma_private->ld_buf_phys);
substream->runtime->private_data = NULL; substream->runtime->private_data = NULL;
......
...@@ -60,6 +60,13 @@ ...@@ -60,6 +60,13 @@
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
#endif #endif
/* SIER bitflag of interrupts to enable */
#define SIER_FLAGS (CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE | \
CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN | \
CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN | \
CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \
CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN)
/** /**
* fsl_ssi_private: per-SSI private data * fsl_ssi_private: per-SSI private data
* *
...@@ -140,7 +147,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) ...@@ -140,7 +147,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
were interrupted for. We mask it with the Interrupt Enable register were interrupted for. We mask it with the Interrupt Enable register
so that we only check for events that we're interested in. so that we only check for events that we're interested in.
*/ */
sisr = in_be32(&ssi->sisr) & in_be32(&ssi->sier); sisr = in_be32(&ssi->sisr) & SIER_FLAGS;
if (sisr & CCSR_SSI_SISR_RFRC) { if (sisr & CCSR_SSI_SISR_RFRC) {
ssi_private->stats.rfrc++; ssi_private->stats.rfrc++;
...@@ -324,12 +331,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, ...@@ -324,12 +331,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
*/ */
/* 4. Enable the interrupts and DMA requests */ /* 4. Enable the interrupts and DMA requests */
out_be32(&ssi->sier, out_be32(&ssi->sier, SIER_FLAGS);
CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE |
CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN |
CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN |
CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE |
CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN);
/* /*
* Set the watermark for transmit FIFI 0 and receive FIFO 0. We * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
...@@ -466,28 +468,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -466,28 +468,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
setbits32(&ssi->scr, setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
} else { else
long timeout = jiffies + 10;
setbits32(&ssi->scr, setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
/* Wait until the SSI has filled its FIFO. Without this
* delay, ALSA complains about overruns. When the FIFO
* is full, the DMA controller initiates its first
* transfer. Until then, however, the DMA's DAR
* register is zero, which translates to an
* out-of-bounds pointer. This makes ALSA think an
* overrun has occurred.
*/
while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) &&
(jiffies < timeout));
if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0))
return -EIO;
}
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
...@@ -606,39 +592,52 @@ static struct snd_soc_dai fsl_ssi_dai_template = { ...@@ -606,39 +592,52 @@ static struct snd_soc_dai fsl_ssi_dai_template = {
.ops = &fsl_ssi_dai_ops, .ops = &fsl_ssi_dai_ops,
}; };
/* Show the statistics of a flag only if its interrupt is enabled. The
* compiler will optimze this code to a no-op if the interrupt is not
* enabled.
*/
#define SIER_SHOW(flag, name) \
do { \
if (SIER_FLAGS & CCSR_SSI_SIER_##flag) \
length += sprintf(buf + length, #name "=%u\n", \
ssi_private->stats.name); \
} while (0)
/** /**
* fsl_sysfs_ssi_show: display SSI statistics * fsl_sysfs_ssi_show: display SSI statistics
* *
* Display the statistics for the current SSI device. * Display the statistics for the current SSI device. To avoid confusion,
* we only show those counts that are enabled.
*/ */
static ssize_t fsl_sysfs_ssi_show(struct device *dev, static ssize_t fsl_sysfs_ssi_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct fsl_ssi_private *ssi_private = struct fsl_ssi_private *ssi_private =
container_of(attr, struct fsl_ssi_private, dev_attr); container_of(attr, struct fsl_ssi_private, dev_attr);
ssize_t length; ssize_t length = 0;
length = sprintf(buf, "rfrc=%u", ssi_private->stats.rfrc); SIER_SHOW(RFRC_EN, rfrc);
length += sprintf(buf + length, "\ttfrc=%u", ssi_private->stats.tfrc); SIER_SHOW(TFRC_EN, tfrc);
length += sprintf(buf + length, "\tcmdau=%u", ssi_private->stats.cmdau); SIER_SHOW(CMDAU_EN, cmdau);
length += sprintf(buf + length, "\tcmddu=%u", ssi_private->stats.cmddu); SIER_SHOW(CMDDU_EN, cmddu);
length += sprintf(buf + length, "\trxt=%u", ssi_private->stats.rxt); SIER_SHOW(RXT_EN, rxt);
length += sprintf(buf + length, "\trdr1=%u", ssi_private->stats.rdr1); SIER_SHOW(RDR1_EN, rdr1);
length += sprintf(buf + length, "\trdr0=%u", ssi_private->stats.rdr0); SIER_SHOW(RDR0_EN, rdr0);
length += sprintf(buf + length, "\ttde1=%u", ssi_private->stats.tde1); SIER_SHOW(TDE1_EN, tde1);
length += sprintf(buf + length, "\ttde0=%u", ssi_private->stats.tde0); SIER_SHOW(TDE0_EN, tde0);
length += sprintf(buf + length, "\troe1=%u", ssi_private->stats.roe1); SIER_SHOW(ROE1_EN, roe1);
length += sprintf(buf + length, "\troe0=%u", ssi_private->stats.roe0); SIER_SHOW(ROE0_EN, roe0);
length += sprintf(buf + length, "\ttue1=%u", ssi_private->stats.tue1); SIER_SHOW(TUE1_EN, tue1);
length += sprintf(buf + length, "\ttue0=%u", ssi_private->stats.tue0); SIER_SHOW(TUE0_EN, tue0);
length += sprintf(buf + length, "\ttfs=%u", ssi_private->stats.tfs); SIER_SHOW(TFS_EN, tfs);
length += sprintf(buf + length, "\trfs=%u", ssi_private->stats.rfs); SIER_SHOW(RFS_EN, rfs);
length += sprintf(buf + length, "\ttls=%u", ssi_private->stats.tls); SIER_SHOW(TLS_EN, tls);
length += sprintf(buf + length, "\trls=%u", ssi_private->stats.rls); SIER_SHOW(RLS_EN, rls);
length += sprintf(buf + length, "\trff1=%u", ssi_private->stats.rff1); SIER_SHOW(RFF1_EN, rff1);
length += sprintf(buf + length, "\trff0=%u", ssi_private->stats.rff0); SIER_SHOW(RFF0_EN, rff0);
length += sprintf(buf + length, "\ttfe1=%u", ssi_private->stats.tfe1); SIER_SHOW(TFE1_EN, tfe1);
length += sprintf(buf + length, "\ttfe0=%u\n", ssi_private->stats.tfe0); SIER_SHOW(TFE0_EN, tfe0);
return length; return length;
} }
......
...@@ -146,6 +146,17 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, ...@@ -146,6 +146,17 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
int err = 0; int err = 0;
if (cpu_is_omap343x() && mcbsp_data->bus_id == 1) {
/*
* McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer.
* Set constraint for minimum buffer size to the same than FIFO
* size in order to avoid underruns in playback startup because
* HW is keeping the DMA request active until FIFO is filled.
*/
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX);
}
if (!cpu_dai->active) if (!cpu_dai->active)
err = omap_mcbsp_request(mcbsp_data->bus_id); err = omap_mcbsp_request(mcbsp_data->bus_id);
......
...@@ -116,6 +116,16 @@ config SND_SOC_ZYLONITE ...@@ -116,6 +116,16 @@ config SND_SOC_ZYLONITE
Say Y if you want to add support for SoC audio on the Say Y if you want to add support for SoC audio on the
Marvell Zylonite reference platform. Marvell Zylonite reference platform.
config SND_PXA2XX_SOC_MAGICIAN
tristate "SoC Audio support for HTC Magician"
depends on SND_PXA2XX_SOC && MACH_MAGICIAN
select SND_PXA2XX_SOC_I2S
select SND_PXA_SOC_SSP
select SND_SOC_UDA1380
help
Say Y if you want to add support for SoC audio on the
HTC Magician.
config SND_PXA2XX_SOC_MIOA701 config SND_PXA2XX_SOC_MIOA701
tristate "SoC Audio support for MIO A701" tristate "SoC Audio support for MIO A701"
depends on SND_PXA2XX_SOC && MACH_MIOA701 depends on SND_PXA2XX_SOC && MACH_MIOA701
......
...@@ -20,6 +20,7 @@ snd-soc-spitz-objs := spitz.o ...@@ -20,6 +20,7 @@ snd-soc-spitz-objs := spitz.o
snd-soc-em-x270-objs := em-x270.o snd-soc-em-x270-objs := em-x270.o
snd-soc-palm27x-objs := palm27x.o snd-soc-palm27x-objs := palm27x.o
snd-soc-zylonite-objs := zylonite.o snd-soc-zylonite-objs := zylonite.o
snd-soc-magician-objs := magician.o
snd-soc-mioa701-objs := mioa701_wm9713.o snd-soc-mioa701-objs := mioa701_wm9713.o
obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
...@@ -31,5 +32,6 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o ...@@ -31,5 +32,6 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
This diff is collapsed.
...@@ -627,12 +627,18 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, ...@@ -627,12 +627,18 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
u32 sscr0; u32 sscr0;
u32 sspsp; u32 sspsp;
int width = snd_pcm_format_physical_width(params_format(params)); int width = snd_pcm_format_physical_width(params_format(params));
int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
/* select correct DMA params */ /* select correct DMA params */
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
dma = 1; /* capture DMA offset is 1,3 */ dma = 1; /* capture DMA offset is 1,3 */
if (chn == 2) /* Network mode with one active slot (ttsa == 1) can be used
dma += 2; /* stereo DMA offset is 2, mono is 0 */ * to force 16-bit frame width on the wire (for S16_LE), even
* with two channels. Use 16-bit DMA transfers for this case.
*/
if (((chn == 2) && (ttsa != 1)) || (width == 32))
dma += 2; /* 32-bit DMA offset is 2, 16-bit is 0 */
cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma]; cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma];
dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma); dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma);
...@@ -712,7 +718,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, ...@@ -712,7 +718,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
/* When we use a network mode, we always require TDM slots /* When we use a network mode, we always require TDM slots
* - complain loudly and fail if they've not been set up yet. * - complain loudly and fail if they've not been set up yet.
*/ */
if ((sscr0 & SSCR0_MOD) && !(ssp_read_reg(ssp, SSTSA) & 0xf)) { if ((sscr0 & SSCR0_MOD) && !ttsa) {
dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -98,7 +98,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) ...@@ -98,7 +98,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
int err; int err;
codec->ac97->dev.bus = &ac97_bus_type; codec->ac97->dev.bus = &ac97_bus_type;
codec->ac97->dev.parent = NULL; codec->ac97->dev.parent = codec->card->dev;
codec->ac97->dev.release = soc_ac97_device_release; codec->ac97->dev.release = soc_ac97_device_release;
dev_set_name(&codec->ac97->dev, "%d-%d:%s", dev_set_name(&codec->ac97->dev, "%d-%d:%s",
...@@ -767,11 +767,21 @@ static int soc_resume(struct platform_device *pdev) ...@@ -767,11 +767,21 @@ static int soc_resume(struct platform_device *pdev)
{ {
struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_card *card = socdev->card; struct snd_soc_card *card = socdev->card;
struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
dev_dbg(socdev->dev, "scheduling resume work\n"); /* AC97 devices might have other drivers hanging off them so
* need to resume immediately. Other drivers don't have that
if (!schedule_work(&card->deferred_resume_work)) * problem and may take a substantial amount of time to resume
dev_err(socdev->dev, "resume work item may be lost\n"); * due to I/O costs and anti-pop so handle them out of line.
*/
if (cpu_dai->ac97_control) {
dev_dbg(socdev->dev, "Resuming AC97 immediately\n");
soc_resume_deferred(&card->deferred_resume_work);
} else {
dev_dbg(socdev->dev, "Scheduling resume work\n");
if (!schedule_work(&card->deferred_resume_work))
dev_err(socdev->dev, "resume work item may be lost\n");
}
return 0; return 0;
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment