Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f9c510e authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/atmel' into for-linus

parents c707e950 fa075ed2
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -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)
	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;


+109 −19
Original line number Original line Diff line number Diff line
/*
/*
 * 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 @@
#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 {
	/* 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 = {
	.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)
{
{
	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)
	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)
		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)
{
{
	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)
	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)
		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 = {
	.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)


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)
		.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)
		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)


	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)


	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)
		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)
		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)
	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)


	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)
	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);
+8 −6
Original line number Original line Diff line number Diff line
/*
/*
 * 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 @@
#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 @@
#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 @@
#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 */