xref: /openbmc/linux/sound/atmel/ac97c.c (revision a4f2473d)
14ede028fSHans-Christian Egtvedt /*
2128ed6a9SHans-Christian Egtvedt  * Driver for Atmel AC97C
34ede028fSHans-Christian Egtvedt  *
44ede028fSHans-Christian Egtvedt  * Copyright (C) 2005-2009 Atmel Corporation
54ede028fSHans-Christian Egtvedt  *
64ede028fSHans-Christian Egtvedt  * This program is free software; you can redistribute it and/or modify it
74ede028fSHans-Christian Egtvedt  * under the terms of the GNU General Public License version 2 as published by
84ede028fSHans-Christian Egtvedt  * the Free Software Foundation.
94ede028fSHans-Christian Egtvedt  */
104ede028fSHans-Christian Egtvedt #include <linux/clk.h>
114ede028fSHans-Christian Egtvedt #include <linux/delay.h>
124ede028fSHans-Christian Egtvedt #include <linux/bitmap.h>
13128ed6a9SHans-Christian Egtvedt #include <linux/device.h>
144ede028fSHans-Christian Egtvedt #include <linux/dmaengine.h>
154ede028fSHans-Christian Egtvedt #include <linux/dma-mapping.h>
167177395fSSedji Gaouaou #include <linux/atmel_pdc.h>
174ede028fSHans-Christian Egtvedt #include <linux/init.h>
184ede028fSHans-Christian Egtvedt #include <linux/interrupt.h>
194ede028fSHans-Christian Egtvedt #include <linux/module.h>
204ede028fSHans-Christian Egtvedt #include <linux/platform_device.h>
214ede028fSHans-Christian Egtvedt #include <linux/mutex.h>
224ede028fSHans-Christian Egtvedt #include <linux/gpio.h>
23e2b35f3dSViresh Kumar #include <linux/types.h>
244ede028fSHans-Christian Egtvedt #include <linux/io.h>
254ede028fSHans-Christian Egtvedt 
264ede028fSHans-Christian Egtvedt #include <sound/core.h>
274ede028fSHans-Christian Egtvedt #include <sound/initval.h>
284ede028fSHans-Christian Egtvedt #include <sound/pcm.h>
294ede028fSHans-Christian Egtvedt #include <sound/pcm_params.h>
304ede028fSHans-Christian Egtvedt #include <sound/ac97_codec.h>
314ede028fSHans-Christian Egtvedt #include <sound/atmel-ac97c.h>
324ede028fSHans-Christian Egtvedt #include <sound/memalloc.h>
334ede028fSHans-Christian Egtvedt 
344ede028fSHans-Christian Egtvedt #include <linux/dw_dmac.h>
354ede028fSHans-Christian Egtvedt 
367177395fSSedji Gaouaou #include <mach/cpu.h>
377177395fSSedji Gaouaou 
38fd76804fSHans-Christian Egtvedt #ifdef CONFIG_ARCH_AT91
39fd76804fSHans-Christian Egtvedt #include <mach/hardware.h>
40fd76804fSHans-Christian Egtvedt #endif
41fd76804fSHans-Christian Egtvedt 
424ede028fSHans-Christian Egtvedt #include "ac97c.h"
434ede028fSHans-Christian Egtvedt 
444ede028fSHans-Christian Egtvedt enum {
454ede028fSHans-Christian Egtvedt 	DMA_TX_READY = 0,
464ede028fSHans-Christian Egtvedt 	DMA_RX_READY,
474ede028fSHans-Christian Egtvedt 	DMA_TX_CHAN_PRESENT,
484ede028fSHans-Christian Egtvedt 	DMA_RX_CHAN_PRESENT,
494ede028fSHans-Christian Egtvedt };
504ede028fSHans-Christian Egtvedt 
514ede028fSHans-Christian Egtvedt /* Serialize access to opened variable */
524ede028fSHans-Christian Egtvedt static DEFINE_MUTEX(opened_mutex);
534ede028fSHans-Christian Egtvedt 
544ede028fSHans-Christian Egtvedt struct atmel_ac97c_dma {
554ede028fSHans-Christian Egtvedt 	struct dma_chan			*rx_chan;
564ede028fSHans-Christian Egtvedt 	struct dma_chan			*tx_chan;
574ede028fSHans-Christian Egtvedt };
584ede028fSHans-Christian Egtvedt 
594ede028fSHans-Christian Egtvedt struct atmel_ac97c {
604ede028fSHans-Christian Egtvedt 	struct clk			*pclk;
614ede028fSHans-Christian Egtvedt 	struct platform_device		*pdev;
624ede028fSHans-Christian Egtvedt 	struct atmel_ac97c_dma		dma;
634ede028fSHans-Christian Egtvedt 
644ede028fSHans-Christian Egtvedt 	struct snd_pcm_substream	*playback_substream;
654ede028fSHans-Christian Egtvedt 	struct snd_pcm_substream	*capture_substream;
664ede028fSHans-Christian Egtvedt 	struct snd_card			*card;
674ede028fSHans-Christian Egtvedt 	struct snd_pcm			*pcm;
684ede028fSHans-Christian Egtvedt 	struct snd_ac97			*ac97;
694ede028fSHans-Christian Egtvedt 	struct snd_ac97_bus		*ac97_bus;
704ede028fSHans-Christian Egtvedt 
714ede028fSHans-Christian Egtvedt 	u64				cur_format;
724ede028fSHans-Christian Egtvedt 	unsigned int			cur_rate;
734ede028fSHans-Christian Egtvedt 	unsigned long			flags;
747177395fSSedji Gaouaou 	int				playback_period, capture_period;
754ede028fSHans-Christian Egtvedt 	/* Serialize access to opened variable */
764ede028fSHans-Christian Egtvedt 	spinlock_t			lock;
774ede028fSHans-Christian Egtvedt 	void __iomem			*regs;
78df163587SHans-Christian Egtvedt 	int				irq;
794ede028fSHans-Christian Egtvedt 	int				opened;
804ede028fSHans-Christian Egtvedt 	int				reset_pin;
814ede028fSHans-Christian Egtvedt };
824ede028fSHans-Christian Egtvedt 
834ede028fSHans-Christian Egtvedt #define get_chip(card) ((struct atmel_ac97c *)(card)->private_data)
844ede028fSHans-Christian Egtvedt 
854ede028fSHans-Christian Egtvedt #define ac97c_writel(chip, reg, val)			\
864ede028fSHans-Christian Egtvedt 	__raw_writel((val), (chip)->regs + AC97C_##reg)
874ede028fSHans-Christian Egtvedt #define ac97c_readl(chip, reg)				\
884ede028fSHans-Christian Egtvedt 	__raw_readl((chip)->regs + AC97C_##reg)
894ede028fSHans-Christian Egtvedt 
904ede028fSHans-Christian Egtvedt /* This function is called by the DMA driver. */
914ede028fSHans-Christian Egtvedt static void atmel_ac97c_dma_playback_period_done(void *arg)
924ede028fSHans-Christian Egtvedt {
934ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = arg;
944ede028fSHans-Christian Egtvedt 	snd_pcm_period_elapsed(chip->playback_substream);
954ede028fSHans-Christian Egtvedt }
964ede028fSHans-Christian Egtvedt 
974ede028fSHans-Christian Egtvedt static void atmel_ac97c_dma_capture_period_done(void *arg)
984ede028fSHans-Christian Egtvedt {
994ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = arg;
1004ede028fSHans-Christian Egtvedt 	snd_pcm_period_elapsed(chip->capture_substream);
1014ede028fSHans-Christian Egtvedt }
1024ede028fSHans-Christian Egtvedt 
1034ede028fSHans-Christian Egtvedt static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
1044ede028fSHans-Christian Egtvedt 		struct snd_pcm_substream *substream,
10535e16581SVinod Koul 		enum dma_transfer_direction direction)
1064ede028fSHans-Christian Egtvedt {
1074ede028fSHans-Christian Egtvedt 	struct dma_chan			*chan;
1084ede028fSHans-Christian Egtvedt 	struct dw_cyclic_desc		*cdesc;
1094ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime		*runtime = substream->runtime;
1104ede028fSHans-Christian Egtvedt 	unsigned long			buffer_len, period_len;
1114ede028fSHans-Christian Egtvedt 
1124ede028fSHans-Christian Egtvedt 	/*
1134ede028fSHans-Christian Egtvedt 	 * We don't do DMA on "complex" transfers, i.e. with
1144ede028fSHans-Christian Egtvedt 	 * non-halfword-aligned buffers or lengths.
1154ede028fSHans-Christian Egtvedt 	 */
1164ede028fSHans-Christian Egtvedt 	if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
1174ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "too complex transfer\n");
1184ede028fSHans-Christian Egtvedt 		return -EINVAL;
1194ede028fSHans-Christian Egtvedt 	}
1204ede028fSHans-Christian Egtvedt 
12135e16581SVinod Koul 	if (direction == DMA_MEM_TO_DEV)
1224ede028fSHans-Christian Egtvedt 		chan = chip->dma.tx_chan;
1234ede028fSHans-Christian Egtvedt 	else
1244ede028fSHans-Christian Egtvedt 		chan = chip->dma.rx_chan;
1254ede028fSHans-Christian Egtvedt 
1264ede028fSHans-Christian Egtvedt 	buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
1274ede028fSHans-Christian Egtvedt 	period_len = frames_to_bytes(runtime, runtime->period_size);
1284ede028fSHans-Christian Egtvedt 
1294ede028fSHans-Christian Egtvedt 	cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
1304ede028fSHans-Christian Egtvedt 			period_len, direction);
1314ede028fSHans-Christian Egtvedt 	if (IS_ERR(cdesc)) {
1324ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n");
1334ede028fSHans-Christian Egtvedt 		return PTR_ERR(cdesc);
1344ede028fSHans-Christian Egtvedt 	}
1354ede028fSHans-Christian Egtvedt 
13635e16581SVinod Koul 	if (direction == DMA_MEM_TO_DEV) {
1374ede028fSHans-Christian Egtvedt 		cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
1384ede028fSHans-Christian Egtvedt 		set_bit(DMA_TX_READY, &chip->flags);
1394ede028fSHans-Christian Egtvedt 	} else {
1404ede028fSHans-Christian Egtvedt 		cdesc->period_callback = atmel_ac97c_dma_capture_period_done;
1414ede028fSHans-Christian Egtvedt 		set_bit(DMA_RX_READY, &chip->flags);
1424ede028fSHans-Christian Egtvedt 	}
1434ede028fSHans-Christian Egtvedt 
1444ede028fSHans-Christian Egtvedt 	cdesc->period_callback_param = chip;
1454ede028fSHans-Christian Egtvedt 
1464ede028fSHans-Christian Egtvedt 	return 0;
1474ede028fSHans-Christian Egtvedt }
1484ede028fSHans-Christian Egtvedt 
1494ede028fSHans-Christian Egtvedt static struct snd_pcm_hardware atmel_ac97c_hw = {
1504ede028fSHans-Christian Egtvedt 	.info			= (SNDRV_PCM_INFO_MMAP
1514ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_MMAP_VALID
1524ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_INTERLEAVED
1534ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_BLOCK_TRANSFER
1544ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_JOINT_DUPLEX
1554ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_RESUME
1564ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_PAUSE),
1574ede028fSHans-Christian Egtvedt 	.formats		= (SNDRV_PCM_FMTBIT_S16_BE
1584ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_FMTBIT_S16_LE),
1594ede028fSHans-Christian Egtvedt 	.rates			= (SNDRV_PCM_RATE_CONTINUOUS),
1604ede028fSHans-Christian Egtvedt 	.rate_min		= 4000,
1614ede028fSHans-Christian Egtvedt 	.rate_max		= 48000,
1624ede028fSHans-Christian Egtvedt 	.channels_min		= 1,
1634ede028fSHans-Christian Egtvedt 	.channels_max		= 2,
164c42eec0fSHans-Christian Egtvedt 	.buffer_bytes_max	= 2 * 2 * 64 * 2048,
1654ede028fSHans-Christian Egtvedt 	.period_bytes_min	= 4096,
1664ede028fSHans-Christian Egtvedt 	.period_bytes_max	= 4096,
167c42eec0fSHans-Christian Egtvedt 	.periods_min		= 6,
1684ede028fSHans-Christian Egtvedt 	.periods_max		= 64,
1694ede028fSHans-Christian Egtvedt };
1704ede028fSHans-Christian Egtvedt 
1714ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
1724ede028fSHans-Christian Egtvedt {
1734ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
1744ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
1754ede028fSHans-Christian Egtvedt 
1764ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
1774ede028fSHans-Christian Egtvedt 	chip->opened++;
1784ede028fSHans-Christian Egtvedt 	runtime->hw = atmel_ac97c_hw;
1794ede028fSHans-Christian Egtvedt 	if (chip->cur_rate) {
1804ede028fSHans-Christian Egtvedt 		runtime->hw.rate_min = chip->cur_rate;
1814ede028fSHans-Christian Egtvedt 		runtime->hw.rate_max = chip->cur_rate;
1824ede028fSHans-Christian Egtvedt 	}
1834ede028fSHans-Christian Egtvedt 	if (chip->cur_format)
18474c34ca1SEldad Zack 		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
1854ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
1864ede028fSHans-Christian Egtvedt 	chip->playback_substream = substream;
1874ede028fSHans-Christian Egtvedt 	return 0;
1884ede028fSHans-Christian Egtvedt }
1894ede028fSHans-Christian Egtvedt 
1904ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
1914ede028fSHans-Christian Egtvedt {
1924ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
1934ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
1944ede028fSHans-Christian Egtvedt 
1954ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
1964ede028fSHans-Christian Egtvedt 	chip->opened++;
1974ede028fSHans-Christian Egtvedt 	runtime->hw = atmel_ac97c_hw;
1984ede028fSHans-Christian Egtvedt 	if (chip->cur_rate) {
1994ede028fSHans-Christian Egtvedt 		runtime->hw.rate_min = chip->cur_rate;
2004ede028fSHans-Christian Egtvedt 		runtime->hw.rate_max = chip->cur_rate;
2014ede028fSHans-Christian Egtvedt 	}
2024ede028fSHans-Christian Egtvedt 	if (chip->cur_format)
20374c34ca1SEldad Zack 		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
2044ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2054ede028fSHans-Christian Egtvedt 	chip->capture_substream = substream;
2064ede028fSHans-Christian Egtvedt 	return 0;
2074ede028fSHans-Christian Egtvedt }
2084ede028fSHans-Christian Egtvedt 
2094ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream)
2104ede028fSHans-Christian Egtvedt {
2114ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2124ede028fSHans-Christian Egtvedt 
2134ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2144ede028fSHans-Christian Egtvedt 	chip->opened--;
2154ede028fSHans-Christian Egtvedt 	if (!chip->opened) {
2164ede028fSHans-Christian Egtvedt 		chip->cur_rate = 0;
2174ede028fSHans-Christian Egtvedt 		chip->cur_format = 0;
2184ede028fSHans-Christian Egtvedt 	}
2194ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2204ede028fSHans-Christian Egtvedt 
2214ede028fSHans-Christian Egtvedt 	chip->playback_substream = NULL;
2224ede028fSHans-Christian Egtvedt 
2234ede028fSHans-Christian Egtvedt 	return 0;
2244ede028fSHans-Christian Egtvedt }
2254ede028fSHans-Christian Egtvedt 
2264ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream)
2274ede028fSHans-Christian Egtvedt {
2284ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2294ede028fSHans-Christian Egtvedt 
2304ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2314ede028fSHans-Christian Egtvedt 	chip->opened--;
2324ede028fSHans-Christian Egtvedt 	if (!chip->opened) {
2334ede028fSHans-Christian Egtvedt 		chip->cur_rate = 0;
2344ede028fSHans-Christian Egtvedt 		chip->cur_format = 0;
2354ede028fSHans-Christian Egtvedt 	}
2364ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2374ede028fSHans-Christian Egtvedt 
2384ede028fSHans-Christian Egtvedt 	chip->capture_substream = NULL;
2394ede028fSHans-Christian Egtvedt 
2404ede028fSHans-Christian Egtvedt 	return 0;
2414ede028fSHans-Christian Egtvedt }
2424ede028fSHans-Christian Egtvedt 
2434ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
2444ede028fSHans-Christian Egtvedt 		struct snd_pcm_hw_params *hw_params)
2454ede028fSHans-Christian Egtvedt {
2464ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2474ede028fSHans-Christian Egtvedt 	int retval;
2484ede028fSHans-Christian Egtvedt 
2494ede028fSHans-Christian Egtvedt 	retval = snd_pcm_lib_malloc_pages(substream,
2504ede028fSHans-Christian Egtvedt 					params_buffer_bytes(hw_params));
2514ede028fSHans-Christian Egtvedt 	if (retval < 0)
2524ede028fSHans-Christian Egtvedt 		return retval;
2534ede028fSHans-Christian Egtvedt 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
2547177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
2557177395fSSedji Gaouaou 		/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
2564ede028fSHans-Christian Egtvedt 		if (retval == 1)
2574ede028fSHans-Christian Egtvedt 			if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
2584ede028fSHans-Christian Egtvedt 				dw_dma_cyclic_free(chip->dma.tx_chan);
2597177395fSSedji Gaouaou 	}
2604ede028fSHans-Christian Egtvedt 	/* Set restrictions to params. */
2614ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2624ede028fSHans-Christian Egtvedt 	chip->cur_rate = params_rate(hw_params);
2634ede028fSHans-Christian Egtvedt 	chip->cur_format = params_format(hw_params);
2644ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2654ede028fSHans-Christian Egtvedt 
2664ede028fSHans-Christian Egtvedt 	return retval;
2674ede028fSHans-Christian Egtvedt }
2684ede028fSHans-Christian Egtvedt 
2694ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
2704ede028fSHans-Christian Egtvedt 		struct snd_pcm_hw_params *hw_params)
2714ede028fSHans-Christian Egtvedt {
2724ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2734ede028fSHans-Christian Egtvedt 	int retval;
2744ede028fSHans-Christian Egtvedt 
2754ede028fSHans-Christian Egtvedt 	retval = snd_pcm_lib_malloc_pages(substream,
2764ede028fSHans-Christian Egtvedt 					params_buffer_bytes(hw_params));
2774ede028fSHans-Christian Egtvedt 	if (retval < 0)
2784ede028fSHans-Christian Egtvedt 		return retval;
2794ede028fSHans-Christian Egtvedt 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
2800c23e46eSJulia Lawall 	if (cpu_is_at32ap7000() && retval == 1)
2814ede028fSHans-Christian Egtvedt 		if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
2824ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_free(chip->dma.rx_chan);
2834ede028fSHans-Christian Egtvedt 
2844ede028fSHans-Christian Egtvedt 	/* Set restrictions to params. */
2854ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2864ede028fSHans-Christian Egtvedt 	chip->cur_rate = params_rate(hw_params);
2874ede028fSHans-Christian Egtvedt 	chip->cur_format = params_format(hw_params);
2884ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2894ede028fSHans-Christian Egtvedt 
2904ede028fSHans-Christian Egtvedt 	return retval;
2914ede028fSHans-Christian Egtvedt }
2924ede028fSHans-Christian Egtvedt 
2934ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
2944ede028fSHans-Christian Egtvedt {
2954ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2967177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
2974ede028fSHans-Christian Egtvedt 		if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
2984ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_free(chip->dma.tx_chan);
2997177395fSSedji Gaouaou 	}
3004ede028fSHans-Christian Egtvedt 	return snd_pcm_lib_free_pages(substream);
3014ede028fSHans-Christian Egtvedt }
3024ede028fSHans-Christian Egtvedt 
3034ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
3044ede028fSHans-Christian Egtvedt {
3054ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
3067177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
3074ede028fSHans-Christian Egtvedt 		if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
3084ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_free(chip->dma.rx_chan);
3097177395fSSedji Gaouaou 	}
3104ede028fSHans-Christian Egtvedt 	return snd_pcm_lib_free_pages(substream);
3114ede028fSHans-Christian Egtvedt }
3124ede028fSHans-Christian Egtvedt 
3134ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
3144ede028fSHans-Christian Egtvedt {
3154ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
3164ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
3177177395fSSedji Gaouaou 	int block_size = frames_to_bytes(runtime, runtime->period_size);
318128ed6a9SHans-Christian Egtvedt 	unsigned long word = ac97c_readl(chip, OCA);
3194ede028fSHans-Christian Egtvedt 	int retval;
3204ede028fSHans-Christian Egtvedt 
3217177395fSSedji Gaouaou 	chip->playback_period = 0;
322128ed6a9SHans-Christian Egtvedt 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
323128ed6a9SHans-Christian Egtvedt 
3244ede028fSHans-Christian Egtvedt 	/* assign channels to AC97C channel A */
3254ede028fSHans-Christian Egtvedt 	switch (runtime->channels) {
3264ede028fSHans-Christian Egtvedt 	case 1:
3274ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
3284ede028fSHans-Christian Egtvedt 		break;
3294ede028fSHans-Christian Egtvedt 	case 2:
3304ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
3314ede028fSHans-Christian Egtvedt 			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
3324ede028fSHans-Christian Egtvedt 		break;
3334ede028fSHans-Christian Egtvedt 	default:
3344ede028fSHans-Christian Egtvedt 		/* TODO: support more than two channels */
3354ede028fSHans-Christian Egtvedt 		return -EINVAL;
3364ede028fSHans-Christian Egtvedt 	}
3374ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, OCA, word);
3384ede028fSHans-Christian Egtvedt 
3394ede028fSHans-Christian Egtvedt 	/* configure sample format and size */
340ec2755a9SSedji Gaouaou 	word = ac97c_readl(chip, CAMR);
341ec2755a9SSedji Gaouaou 	if (chip->opened <= 1)
3424ede028fSHans-Christian Egtvedt 		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
343ec2755a9SSedji Gaouaou 	else
344ec2755a9SSedji Gaouaou 		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
3454ede028fSHans-Christian Egtvedt 
3464ede028fSHans-Christian Egtvedt 	switch (runtime->format) {
3474ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_LE:
3487177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
3494ede028fSHans-Christian Egtvedt 			word |= AC97C_CMR_CEM_LITTLE;
3504ede028fSHans-Christian Egtvedt 		break;
3514ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
3524ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_CMR_CEM_LITTLE);
3534ede028fSHans-Christian Egtvedt 		break;
354128ed6a9SHans-Christian Egtvedt 	default:
355128ed6a9SHans-Christian Egtvedt 		word = ac97c_readl(chip, OCA);
356128ed6a9SHans-Christian Egtvedt 		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
357128ed6a9SHans-Christian Egtvedt 		ac97c_writel(chip, OCA, word);
358128ed6a9SHans-Christian Egtvedt 		return -EINVAL;
3594ede028fSHans-Christian Egtvedt 	}
3604ede028fSHans-Christian Egtvedt 
361df163587SHans-Christian Egtvedt 	/* Enable underrun interrupt on channel A */
362df163587SHans-Christian Egtvedt 	word |= AC97C_CSR_UNRUN;
363df163587SHans-Christian Egtvedt 
3644ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, word);
3654ede028fSHans-Christian Egtvedt 
366df163587SHans-Christian Egtvedt 	/* Enable channel A event interrupt */
367df163587SHans-Christian Egtvedt 	word = ac97c_readl(chip, IMR);
368df163587SHans-Christian Egtvedt 	word |= AC97C_SR_CAEVT;
369df163587SHans-Christian Egtvedt 	ac97c_writel(chip, IER, word);
370df163587SHans-Christian Egtvedt 
3714ede028fSHans-Christian Egtvedt 	/* set variable rate if needed */
3724ede028fSHans-Christian Egtvedt 	if (runtime->rate != 48000) {
3734ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
3744ede028fSHans-Christian Egtvedt 		word |= AC97C_MR_VRA;
3754ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
3764ede028fSHans-Christian Egtvedt 	} else {
3774ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
3784ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_MR_VRA);
3794ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
3804ede028fSHans-Christian Egtvedt 	}
3814ede028fSHans-Christian Egtvedt 
3824ede028fSHans-Christian Egtvedt 	retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
3834ede028fSHans-Christian Egtvedt 			runtime->rate);
3844ede028fSHans-Christian Egtvedt 	if (retval)
3854ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
3864ede028fSHans-Christian Egtvedt 				runtime->rate);
3874ede028fSHans-Christian Egtvedt 
3887177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
3894ede028fSHans-Christian Egtvedt 		if (!test_bit(DMA_TX_READY, &chip->flags))
3904ede028fSHans-Christian Egtvedt 			retval = atmel_ac97c_prepare_dma(chip, substream,
39135e16581SVinod Koul 					DMA_MEM_TO_DEV);
3927177395fSSedji Gaouaou 	} else {
3937177395fSSedji Gaouaou 		/* Initialize and start the PDC */
3947177395fSSedji Gaouaou 		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
3957177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
3967177395fSSedji Gaouaou 		writel(runtime->dma_addr + block_size,
3977177395fSSedji Gaouaou 				chip->regs + ATMEL_PDC_TNPR);
3987177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
3997177395fSSedji Gaouaou 	}
4004ede028fSHans-Christian Egtvedt 
4014ede028fSHans-Christian Egtvedt 	return retval;
4024ede028fSHans-Christian Egtvedt }
4034ede028fSHans-Christian Egtvedt 
4044ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
4054ede028fSHans-Christian Egtvedt {
4064ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
4074ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
4087177395fSSedji Gaouaou 	int block_size = frames_to_bytes(runtime, runtime->period_size);
409128ed6a9SHans-Christian Egtvedt 	unsigned long word = ac97c_readl(chip, ICA);
4104ede028fSHans-Christian Egtvedt 	int retval;
4114ede028fSHans-Christian Egtvedt 
4127177395fSSedji Gaouaou 	chip->capture_period = 0;
413128ed6a9SHans-Christian Egtvedt 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
414128ed6a9SHans-Christian Egtvedt 
4154ede028fSHans-Christian Egtvedt 	/* assign channels to AC97C channel A */
4164ede028fSHans-Christian Egtvedt 	switch (runtime->channels) {
4174ede028fSHans-Christian Egtvedt 	case 1:
4184ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
4194ede028fSHans-Christian Egtvedt 		break;
4204ede028fSHans-Christian Egtvedt 	case 2:
4214ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
4224ede028fSHans-Christian Egtvedt 			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
4234ede028fSHans-Christian Egtvedt 		break;
4244ede028fSHans-Christian Egtvedt 	default:
4254ede028fSHans-Christian Egtvedt 		/* TODO: support more than two channels */
4264ede028fSHans-Christian Egtvedt 		return -EINVAL;
4274ede028fSHans-Christian Egtvedt 	}
4284ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, ICA, word);
4294ede028fSHans-Christian Egtvedt 
4304ede028fSHans-Christian Egtvedt 	/* configure sample format and size */
431ec2755a9SSedji Gaouaou 	word = ac97c_readl(chip, CAMR);
432ec2755a9SSedji Gaouaou 	if (chip->opened <= 1)
4334ede028fSHans-Christian Egtvedt 		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
434ec2755a9SSedji Gaouaou 	else
435ec2755a9SSedji Gaouaou 		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
4364ede028fSHans-Christian Egtvedt 
4374ede028fSHans-Christian Egtvedt 	switch (runtime->format) {
4384ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_LE:
4397177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
4404ede028fSHans-Christian Egtvedt 			word |= AC97C_CMR_CEM_LITTLE;
4414ede028fSHans-Christian Egtvedt 		break;
4424ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
4434ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_CMR_CEM_LITTLE);
4444ede028fSHans-Christian Egtvedt 		break;
445128ed6a9SHans-Christian Egtvedt 	default:
446128ed6a9SHans-Christian Egtvedt 		word = ac97c_readl(chip, ICA);
447128ed6a9SHans-Christian Egtvedt 		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
448128ed6a9SHans-Christian Egtvedt 		ac97c_writel(chip, ICA, word);
449128ed6a9SHans-Christian Egtvedt 		return -EINVAL;
4504ede028fSHans-Christian Egtvedt 	}
4514ede028fSHans-Christian Egtvedt 
452df163587SHans-Christian Egtvedt 	/* Enable overrun interrupt on channel A */
453df163587SHans-Christian Egtvedt 	word |= AC97C_CSR_OVRUN;
454df163587SHans-Christian Egtvedt 
4554ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, word);
4564ede028fSHans-Christian Egtvedt 
457df163587SHans-Christian Egtvedt 	/* Enable channel A event interrupt */
458df163587SHans-Christian Egtvedt 	word = ac97c_readl(chip, IMR);
459df163587SHans-Christian Egtvedt 	word |= AC97C_SR_CAEVT;
460df163587SHans-Christian Egtvedt 	ac97c_writel(chip, IER, word);
461df163587SHans-Christian Egtvedt 
4624ede028fSHans-Christian Egtvedt 	/* set variable rate if needed */
4634ede028fSHans-Christian Egtvedt 	if (runtime->rate != 48000) {
4644ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
4654ede028fSHans-Christian Egtvedt 		word |= AC97C_MR_VRA;
4664ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
4674ede028fSHans-Christian Egtvedt 	} else {
4684ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
4694ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_MR_VRA);
4704ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
4714ede028fSHans-Christian Egtvedt 	}
4724ede028fSHans-Christian Egtvedt 
4734ede028fSHans-Christian Egtvedt 	retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE,
4744ede028fSHans-Christian Egtvedt 			runtime->rate);
4754ede028fSHans-Christian Egtvedt 	if (retval)
4764ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
4774ede028fSHans-Christian Egtvedt 				runtime->rate);
4784ede028fSHans-Christian Egtvedt 
4797177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
4804ede028fSHans-Christian Egtvedt 		if (!test_bit(DMA_RX_READY, &chip->flags))
4814ede028fSHans-Christian Egtvedt 			retval = atmel_ac97c_prepare_dma(chip, substream,
48235e16581SVinod Koul 					DMA_DEV_TO_MEM);
4837177395fSSedji Gaouaou 	} else {
4847177395fSSedji Gaouaou 		/* Initialize and start the PDC */
4857177395fSSedji Gaouaou 		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
4867177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
4877177395fSSedji Gaouaou 		writel(runtime->dma_addr + block_size,
4887177395fSSedji Gaouaou 				chip->regs + ATMEL_PDC_RNPR);
4897177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
4907177395fSSedji Gaouaou 	}
4914ede028fSHans-Christian Egtvedt 
4924ede028fSHans-Christian Egtvedt 	return retval;
4934ede028fSHans-Christian Egtvedt }
4944ede028fSHans-Christian Egtvedt 
4954ede028fSHans-Christian Egtvedt static int
4964ede028fSHans-Christian Egtvedt atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
4974ede028fSHans-Christian Egtvedt {
4984ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
4997177395fSSedji Gaouaou 	unsigned long camr, ptcr = 0;
5004ede028fSHans-Christian Egtvedt 	int retval = 0;
5014ede028fSHans-Christian Egtvedt 
5024ede028fSHans-Christian Egtvedt 	camr = ac97c_readl(chip, CAMR);
5034ede028fSHans-Christian Egtvedt 
5044ede028fSHans-Christian Egtvedt 	switch (cmd) {
5054ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
5064ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
5074ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_START:
5087177395fSSedji Gaouaou 		if (cpu_is_at32ap7000()) {
5094ede028fSHans-Christian Egtvedt 			retval = dw_dma_cyclic_start(chip->dma.tx_chan);
5104ede028fSHans-Christian Egtvedt 			if (retval)
5114ede028fSHans-Christian Egtvedt 				goto out;
5127177395fSSedji Gaouaou 		} else {
5137177395fSSedji Gaouaou 			ptcr = ATMEL_PDC_TXTEN;
5147177395fSSedji Gaouaou 		}
515ec2755a9SSedji Gaouaou 		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
5164ede028fSHans-Christian Egtvedt 		break;
5174ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
5184ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
5194ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_STOP:
5207177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
5214ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.tx_chan);
5227177395fSSedji Gaouaou 		else
5237177395fSSedji Gaouaou 			ptcr |= ATMEL_PDC_TXTDIS;
5244ede028fSHans-Christian Egtvedt 		if (chip->opened <= 1)
5254ede028fSHans-Christian Egtvedt 			camr &= ~AC97C_CMR_CENA;
5264ede028fSHans-Christian Egtvedt 		break;
5274ede028fSHans-Christian Egtvedt 	default:
5284ede028fSHans-Christian Egtvedt 		retval = -EINVAL;
5294ede028fSHans-Christian Egtvedt 		goto out;
5304ede028fSHans-Christian Egtvedt 	}
5314ede028fSHans-Christian Egtvedt 
5324ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, camr);
5337177395fSSedji Gaouaou 	if (!cpu_is_at32ap7000())
5347177395fSSedji Gaouaou 		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
5354ede028fSHans-Christian Egtvedt out:
5364ede028fSHans-Christian Egtvedt 	return retval;
5374ede028fSHans-Christian Egtvedt }
5384ede028fSHans-Christian Egtvedt 
5394ede028fSHans-Christian Egtvedt static int
5404ede028fSHans-Christian Egtvedt atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
5414ede028fSHans-Christian Egtvedt {
5424ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
5437177395fSSedji Gaouaou 	unsigned long camr, ptcr = 0;
5444ede028fSHans-Christian Egtvedt 	int retval = 0;
5454ede028fSHans-Christian Egtvedt 
5464ede028fSHans-Christian Egtvedt 	camr = ac97c_readl(chip, CAMR);
5477177395fSSedji Gaouaou 	ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
5484ede028fSHans-Christian Egtvedt 
5494ede028fSHans-Christian Egtvedt 	switch (cmd) {
5504ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
5514ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
5524ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_START:
5537177395fSSedji Gaouaou 		if (cpu_is_at32ap7000()) {
5544ede028fSHans-Christian Egtvedt 			retval = dw_dma_cyclic_start(chip->dma.rx_chan);
5554ede028fSHans-Christian Egtvedt 			if (retval)
5564ede028fSHans-Christian Egtvedt 				goto out;
5577177395fSSedji Gaouaou 		} else {
5587177395fSSedji Gaouaou 			ptcr = ATMEL_PDC_RXTEN;
5597177395fSSedji Gaouaou 		}
560ec2755a9SSedji Gaouaou 		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
5614ede028fSHans-Christian Egtvedt 		break;
5624ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
5634ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
5644ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_STOP:
5657177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
5664ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.rx_chan);
5677177395fSSedji Gaouaou 		else
5687177395fSSedji Gaouaou 			ptcr |= (ATMEL_PDC_RXTDIS);
5694ede028fSHans-Christian Egtvedt 		if (chip->opened <= 1)
5704ede028fSHans-Christian Egtvedt 			camr &= ~AC97C_CMR_CENA;
5714ede028fSHans-Christian Egtvedt 		break;
5724ede028fSHans-Christian Egtvedt 	default:
5734ede028fSHans-Christian Egtvedt 		retval = -EINVAL;
5744ede028fSHans-Christian Egtvedt 		break;
5754ede028fSHans-Christian Egtvedt 	}
5764ede028fSHans-Christian Egtvedt 
5774ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, camr);
5787177395fSSedji Gaouaou 	if (!cpu_is_at32ap7000())
5797177395fSSedji Gaouaou 		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
5804ede028fSHans-Christian Egtvedt out:
5814ede028fSHans-Christian Egtvedt 	return retval;
5824ede028fSHans-Christian Egtvedt }
5834ede028fSHans-Christian Egtvedt 
5844ede028fSHans-Christian Egtvedt static snd_pcm_uframes_t
5854ede028fSHans-Christian Egtvedt atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
5864ede028fSHans-Christian Egtvedt {
5874ede028fSHans-Christian Egtvedt 	struct atmel_ac97c	*chip = snd_pcm_substream_chip(substream);
5884ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime	*runtime = substream->runtime;
5894ede028fSHans-Christian Egtvedt 	snd_pcm_uframes_t	frames;
5904ede028fSHans-Christian Egtvedt 	unsigned long		bytes;
5914ede028fSHans-Christian Egtvedt 
5927177395fSSedji Gaouaou 	if (cpu_is_at32ap7000())
5934ede028fSHans-Christian Egtvedt 		bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
5947177395fSSedji Gaouaou 	else
5957177395fSSedji Gaouaou 		bytes = readl(chip->regs + ATMEL_PDC_TPR);
5964ede028fSHans-Christian Egtvedt 	bytes -= runtime->dma_addr;
5974ede028fSHans-Christian Egtvedt 
5984ede028fSHans-Christian Egtvedt 	frames = bytes_to_frames(runtime, bytes);
5994ede028fSHans-Christian Egtvedt 	if (frames >= runtime->buffer_size)
6004ede028fSHans-Christian Egtvedt 		frames -= runtime->buffer_size;
6014ede028fSHans-Christian Egtvedt 	return frames;
6024ede028fSHans-Christian Egtvedt }
6034ede028fSHans-Christian Egtvedt 
6044ede028fSHans-Christian Egtvedt static snd_pcm_uframes_t
6054ede028fSHans-Christian Egtvedt atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
6064ede028fSHans-Christian Egtvedt {
6074ede028fSHans-Christian Egtvedt 	struct atmel_ac97c	*chip = snd_pcm_substream_chip(substream);
6084ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime	*runtime = substream->runtime;
6094ede028fSHans-Christian Egtvedt 	snd_pcm_uframes_t	frames;
6104ede028fSHans-Christian Egtvedt 	unsigned long		bytes;
6114ede028fSHans-Christian Egtvedt 
6127177395fSSedji Gaouaou 	if (cpu_is_at32ap7000())
6134ede028fSHans-Christian Egtvedt 		bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
6147177395fSSedji Gaouaou 	else
6157177395fSSedji Gaouaou 		bytes = readl(chip->regs + ATMEL_PDC_RPR);
6164ede028fSHans-Christian Egtvedt 	bytes -= runtime->dma_addr;
6174ede028fSHans-Christian Egtvedt 
6184ede028fSHans-Christian Egtvedt 	frames = bytes_to_frames(runtime, bytes);
6194ede028fSHans-Christian Egtvedt 	if (frames >= runtime->buffer_size)
6204ede028fSHans-Christian Egtvedt 		frames -= runtime->buffer_size;
6214ede028fSHans-Christian Egtvedt 	return frames;
6224ede028fSHans-Christian Egtvedt }
6234ede028fSHans-Christian Egtvedt 
6244ede028fSHans-Christian Egtvedt static struct snd_pcm_ops atmel_ac97_playback_ops = {
6254ede028fSHans-Christian Egtvedt 	.open		= atmel_ac97c_playback_open,
6264ede028fSHans-Christian Egtvedt 	.close		= atmel_ac97c_playback_close,
6274ede028fSHans-Christian Egtvedt 	.ioctl		= snd_pcm_lib_ioctl,
6284ede028fSHans-Christian Egtvedt 	.hw_params	= atmel_ac97c_playback_hw_params,
6294ede028fSHans-Christian Egtvedt 	.hw_free	= atmel_ac97c_playback_hw_free,
6304ede028fSHans-Christian Egtvedt 	.prepare	= atmel_ac97c_playback_prepare,
6314ede028fSHans-Christian Egtvedt 	.trigger	= atmel_ac97c_playback_trigger,
6324ede028fSHans-Christian Egtvedt 	.pointer	= atmel_ac97c_playback_pointer,
6334ede028fSHans-Christian Egtvedt };
6344ede028fSHans-Christian Egtvedt 
6354ede028fSHans-Christian Egtvedt static struct snd_pcm_ops atmel_ac97_capture_ops = {
6364ede028fSHans-Christian Egtvedt 	.open		= atmel_ac97c_capture_open,
6374ede028fSHans-Christian Egtvedt 	.close		= atmel_ac97c_capture_close,
6384ede028fSHans-Christian Egtvedt 	.ioctl		= snd_pcm_lib_ioctl,
6394ede028fSHans-Christian Egtvedt 	.hw_params	= atmel_ac97c_capture_hw_params,
6404ede028fSHans-Christian Egtvedt 	.hw_free	= atmel_ac97c_capture_hw_free,
6414ede028fSHans-Christian Egtvedt 	.prepare	= atmel_ac97c_capture_prepare,
6424ede028fSHans-Christian Egtvedt 	.trigger	= atmel_ac97c_capture_trigger,
6434ede028fSHans-Christian Egtvedt 	.pointer	= atmel_ac97c_capture_pointer,
6444ede028fSHans-Christian Egtvedt };
6454ede028fSHans-Christian Egtvedt 
646df163587SHans-Christian Egtvedt static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
647df163587SHans-Christian Egtvedt {
648df163587SHans-Christian Egtvedt 	struct atmel_ac97c	*chip  = (struct atmel_ac97c *)dev;
649df163587SHans-Christian Egtvedt 	irqreturn_t		retval = IRQ_NONE;
650df163587SHans-Christian Egtvedt 	u32			sr     = ac97c_readl(chip, SR);
651df163587SHans-Christian Egtvedt 	u32			casr   = ac97c_readl(chip, CASR);
652df163587SHans-Christian Egtvedt 	u32			cosr   = ac97c_readl(chip, COSR);
6537177395fSSedji Gaouaou 	u32			camr   = ac97c_readl(chip, CAMR);
654df163587SHans-Christian Egtvedt 
655df163587SHans-Christian Egtvedt 	if (sr & AC97C_SR_CAEVT) {
6567177395fSSedji Gaouaou 		struct snd_pcm_runtime *runtime;
6577177395fSSedji Gaouaou 		int offset, next_period, block_size;
658f5341163SYegor Yefremov 		dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
659df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
660df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
661df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_UNRUN   ? " UNRUN"   : "",
662df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
663df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
664df163587SHans-Christian Egtvedt 				!casr                    ? " NONE"    : "");
6657177395fSSedji Gaouaou 		if (!cpu_is_at32ap7000()) {
6667177395fSSedji Gaouaou 			if ((casr & camr) & AC97C_CSR_ENDTX) {
6677177395fSSedji Gaouaou 				runtime = chip->playback_substream->runtime;
6687177395fSSedji Gaouaou 				block_size = frames_to_bytes(runtime,
6697177395fSSedji Gaouaou 						runtime->period_size);
6707177395fSSedji Gaouaou 				chip->playback_period++;
6717177395fSSedji Gaouaou 
6727177395fSSedji Gaouaou 				if (chip->playback_period == runtime->periods)
6737177395fSSedji Gaouaou 					chip->playback_period = 0;
6747177395fSSedji Gaouaou 				next_period = chip->playback_period + 1;
6757177395fSSedji Gaouaou 				if (next_period == runtime->periods)
6767177395fSSedji Gaouaou 					next_period = 0;
6777177395fSSedji Gaouaou 
6787177395fSSedji Gaouaou 				offset = block_size * next_period;
6797177395fSSedji Gaouaou 
6807177395fSSedji Gaouaou 				writel(runtime->dma_addr + offset,
6817177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_TNPR);
6827177395fSSedji Gaouaou 				writel(block_size / 2,
6837177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_TNCR);
6847177395fSSedji Gaouaou 
6857177395fSSedji Gaouaou 				snd_pcm_period_elapsed(
6867177395fSSedji Gaouaou 						chip->playback_substream);
6877177395fSSedji Gaouaou 			}
6887177395fSSedji Gaouaou 			if ((casr & camr) & AC97C_CSR_ENDRX) {
6897177395fSSedji Gaouaou 				runtime = chip->capture_substream->runtime;
6907177395fSSedji Gaouaou 				block_size = frames_to_bytes(runtime,
6917177395fSSedji Gaouaou 						runtime->period_size);
6927177395fSSedji Gaouaou 				chip->capture_period++;
6937177395fSSedji Gaouaou 
6947177395fSSedji Gaouaou 				if (chip->capture_period == runtime->periods)
6957177395fSSedji Gaouaou 					chip->capture_period = 0;
6967177395fSSedji Gaouaou 				next_period = chip->capture_period + 1;
6977177395fSSedji Gaouaou 				if (next_period == runtime->periods)
6987177395fSSedji Gaouaou 					next_period = 0;
6997177395fSSedji Gaouaou 
7007177395fSSedji Gaouaou 				offset = block_size * next_period;
7017177395fSSedji Gaouaou 
7027177395fSSedji Gaouaou 				writel(runtime->dma_addr + offset,
7037177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_RNPR);
7047177395fSSedji Gaouaou 				writel(block_size / 2,
7057177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_RNCR);
7067177395fSSedji Gaouaou 				snd_pcm_period_elapsed(chip->capture_substream);
7077177395fSSedji Gaouaou 			}
7087177395fSSedji Gaouaou 		}
709df163587SHans-Christian Egtvedt 		retval = IRQ_HANDLED;
710df163587SHans-Christian Egtvedt 	}
711df163587SHans-Christian Egtvedt 
712df163587SHans-Christian Egtvedt 	if (sr & AC97C_SR_COEVT) {
713df163587SHans-Christian Egtvedt 		dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
714df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
715df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
716df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
717df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
718df163587SHans-Christian Egtvedt 				!cosr                    ? " NONE"    : "");
719df163587SHans-Christian Egtvedt 		retval = IRQ_HANDLED;
720df163587SHans-Christian Egtvedt 	}
721df163587SHans-Christian Egtvedt 
722df163587SHans-Christian Egtvedt 	if (retval == IRQ_NONE) {
723df163587SHans-Christian Egtvedt 		dev_err(&chip->pdev->dev, "spurious interrupt sr 0x%08x "
724df163587SHans-Christian Egtvedt 				"casr 0x%08x cosr 0x%08x\n", sr, casr, cosr);
725df163587SHans-Christian Egtvedt 	}
726df163587SHans-Christian Egtvedt 
727df163587SHans-Christian Egtvedt 	return retval;
728df163587SHans-Christian Egtvedt }
729df163587SHans-Christian Egtvedt 
73061dc674cSBill Pemberton static struct ac97_pcm at91_ac97_pcm_defs[] = {
7317177395fSSedji Gaouaou 	/* Playback */
7327177395fSSedji Gaouaou 	{
7337177395fSSedji Gaouaou 		.exclusive = 1,
7347177395fSSedji Gaouaou 		.r = { {
7357177395fSSedji Gaouaou 			.slots = ((1 << AC97_SLOT_PCM_LEFT)
7367177395fSSedji Gaouaou 				  | (1 << AC97_SLOT_PCM_RIGHT)),
7377177395fSSedji Gaouaou 		} },
7387177395fSSedji Gaouaou 	},
7397177395fSSedji Gaouaou 	/* PCM in */
7407177395fSSedji Gaouaou 	{
7417177395fSSedji Gaouaou 		.stream = 1,
7427177395fSSedji Gaouaou 		.exclusive = 1,
7437177395fSSedji Gaouaou 		.r = { {
7447177395fSSedji Gaouaou 			.slots = ((1 << AC97_SLOT_PCM_LEFT)
7457177395fSSedji Gaouaou 					| (1 << AC97_SLOT_PCM_RIGHT)),
7467177395fSSedji Gaouaou 		} }
7477177395fSSedji Gaouaou 	},
7487177395fSSedji Gaouaou 	/* Mic in */
7497177395fSSedji Gaouaou 	{
7507177395fSSedji Gaouaou 		.stream = 1,
7517177395fSSedji Gaouaou 		.exclusive = 1,
7527177395fSSedji Gaouaou 		.r = { {
7537177395fSSedji Gaouaou 			.slots = (1<<AC97_SLOT_MIC),
7547177395fSSedji Gaouaou 		} }
7557177395fSSedji Gaouaou 	},
7567177395fSSedji Gaouaou };
7577177395fSSedji Gaouaou 
75861dc674cSBill Pemberton static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
7594ede028fSHans-Christian Egtvedt {
7604ede028fSHans-Christian Egtvedt 	struct snd_pcm		*pcm;
7614ede028fSHans-Christian Egtvedt 	struct snd_pcm_hardware	hw = atmel_ac97c_hw;
7627177395fSSedji Gaouaou 	int			capture, playback, retval, err;
7634ede028fSHans-Christian Egtvedt 
7644ede028fSHans-Christian Egtvedt 	capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
7654ede028fSHans-Christian Egtvedt 	playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
7664ede028fSHans-Christian Egtvedt 
7677177395fSSedji Gaouaou 	if (!cpu_is_at32ap7000()) {
7687177395fSSedji Gaouaou 		err = snd_ac97_pcm_assign(chip->ac97_bus,
7697177395fSSedji Gaouaou 				ARRAY_SIZE(at91_ac97_pcm_defs),
7707177395fSSedji Gaouaou 				at91_ac97_pcm_defs);
7717177395fSSedji Gaouaou 		if (err)
7727177395fSSedji Gaouaou 			return err;
7737177395fSSedji Gaouaou 	}
7744ede028fSHans-Christian Egtvedt 	retval = snd_pcm_new(chip->card, chip->card->shortname,
7754ede028fSHans-Christian Egtvedt 			chip->pdev->id, playback, capture, &pcm);
7764ede028fSHans-Christian Egtvedt 	if (retval)
7774ede028fSHans-Christian Egtvedt 		return retval;
7784ede028fSHans-Christian Egtvedt 
7794ede028fSHans-Christian Egtvedt 	if (capture)
7804ede028fSHans-Christian Egtvedt 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
7814ede028fSHans-Christian Egtvedt 				&atmel_ac97_capture_ops);
7824ede028fSHans-Christian Egtvedt 	if (playback)
7834ede028fSHans-Christian Egtvedt 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
7844ede028fSHans-Christian Egtvedt 				&atmel_ac97_playback_ops);
7854ede028fSHans-Christian Egtvedt 
7864ede028fSHans-Christian Egtvedt 	retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
7874ede028fSHans-Christian Egtvedt 			&chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
7884ede028fSHans-Christian Egtvedt 			hw.buffer_bytes_max);
7894ede028fSHans-Christian Egtvedt 	if (retval)
7904ede028fSHans-Christian Egtvedt 		return retval;
7914ede028fSHans-Christian Egtvedt 
7924ede028fSHans-Christian Egtvedt 	pcm->private_data = chip;
7934ede028fSHans-Christian Egtvedt 	pcm->info_flags = 0;
7944ede028fSHans-Christian Egtvedt 	strcpy(pcm->name, chip->card->shortname);
7954ede028fSHans-Christian Egtvedt 	chip->pcm = pcm;
7964ede028fSHans-Christian Egtvedt 
7974ede028fSHans-Christian Egtvedt 	return 0;
7984ede028fSHans-Christian Egtvedt }
7994ede028fSHans-Christian Egtvedt 
8004ede028fSHans-Christian Egtvedt static int atmel_ac97c_mixer_new(struct atmel_ac97c *chip)
8014ede028fSHans-Christian Egtvedt {
8024ede028fSHans-Christian Egtvedt 	struct snd_ac97_template template;
8034ede028fSHans-Christian Egtvedt 	memset(&template, 0, sizeof(template));
8044ede028fSHans-Christian Egtvedt 	template.private_data = chip;
8054ede028fSHans-Christian Egtvedt 	return snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
8064ede028fSHans-Christian Egtvedt }
8074ede028fSHans-Christian Egtvedt 
8084ede028fSHans-Christian Egtvedt static void atmel_ac97c_write(struct snd_ac97 *ac97, unsigned short reg,
8094ede028fSHans-Christian Egtvedt 		unsigned short val)
8104ede028fSHans-Christian Egtvedt {
8114ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = get_chip(ac97);
8124ede028fSHans-Christian Egtvedt 	unsigned long word;
8134ede028fSHans-Christian Egtvedt 	int timeout = 40;
8144ede028fSHans-Christian Egtvedt 
8154ede028fSHans-Christian Egtvedt 	word = (reg & 0x7f) << 16 | val;
8164ede028fSHans-Christian Egtvedt 
8174ede028fSHans-Christian Egtvedt 	do {
8184ede028fSHans-Christian Egtvedt 		if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
8194ede028fSHans-Christian Egtvedt 			ac97c_writel(chip, COTHR, word);
8204ede028fSHans-Christian Egtvedt 			return;
8214ede028fSHans-Christian Egtvedt 		}
8224ede028fSHans-Christian Egtvedt 		udelay(1);
8234ede028fSHans-Christian Egtvedt 	} while (--timeout);
8244ede028fSHans-Christian Egtvedt 
8254ede028fSHans-Christian Egtvedt 	dev_dbg(&chip->pdev->dev, "codec write timeout\n");
8264ede028fSHans-Christian Egtvedt }
8274ede028fSHans-Christian Egtvedt 
8284ede028fSHans-Christian Egtvedt static unsigned short atmel_ac97c_read(struct snd_ac97 *ac97,
8294ede028fSHans-Christian Egtvedt 		unsigned short reg)
8304ede028fSHans-Christian Egtvedt {
8314ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = get_chip(ac97);
8324ede028fSHans-Christian Egtvedt 	unsigned long word;
8334ede028fSHans-Christian Egtvedt 	int timeout = 40;
8344ede028fSHans-Christian Egtvedt 	int write = 10;
8354ede028fSHans-Christian Egtvedt 
8364ede028fSHans-Christian Egtvedt 	word = (0x80 | (reg & 0x7f)) << 16;
8374ede028fSHans-Christian Egtvedt 
8384ede028fSHans-Christian Egtvedt 	if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
8394ede028fSHans-Christian Egtvedt 		ac97c_readl(chip, CORHR);
8404ede028fSHans-Christian Egtvedt 
8414ede028fSHans-Christian Egtvedt retry_write:
8424ede028fSHans-Christian Egtvedt 	timeout = 40;
8434ede028fSHans-Christian Egtvedt 
8444ede028fSHans-Christian Egtvedt 	do {
8454ede028fSHans-Christian Egtvedt 		if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
8464ede028fSHans-Christian Egtvedt 			ac97c_writel(chip, COTHR, word);
8474ede028fSHans-Christian Egtvedt 			goto read_reg;
8484ede028fSHans-Christian Egtvedt 		}
8494ede028fSHans-Christian Egtvedt 		udelay(10);
8504ede028fSHans-Christian Egtvedt 	} while (--timeout);
8514ede028fSHans-Christian Egtvedt 
8524ede028fSHans-Christian Egtvedt 	if (!--write)
8534ede028fSHans-Christian Egtvedt 		goto timed_out;
8544ede028fSHans-Christian Egtvedt 	goto retry_write;
8554ede028fSHans-Christian Egtvedt 
8564ede028fSHans-Christian Egtvedt read_reg:
8574ede028fSHans-Christian Egtvedt 	do {
8584ede028fSHans-Christian Egtvedt 		if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) {
8594ede028fSHans-Christian Egtvedt 			unsigned short val = ac97c_readl(chip, CORHR);
8604ede028fSHans-Christian Egtvedt 			return val;
8614ede028fSHans-Christian Egtvedt 		}
8624ede028fSHans-Christian Egtvedt 		udelay(10);
8634ede028fSHans-Christian Egtvedt 	} while (--timeout);
8644ede028fSHans-Christian Egtvedt 
8654ede028fSHans-Christian Egtvedt 	if (!--write)
8664ede028fSHans-Christian Egtvedt 		goto timed_out;
8674ede028fSHans-Christian Egtvedt 	goto retry_write;
8684ede028fSHans-Christian Egtvedt 
8694ede028fSHans-Christian Egtvedt timed_out:
8704ede028fSHans-Christian Egtvedt 	dev_dbg(&chip->pdev->dev, "codec read timeout\n");
8714ede028fSHans-Christian Egtvedt 	return 0xffff;
8724ede028fSHans-Christian Egtvedt }
8734ede028fSHans-Christian Egtvedt 
8744ede028fSHans-Christian Egtvedt static bool filter(struct dma_chan *chan, void *slave)
8754ede028fSHans-Christian Egtvedt {
8764ede028fSHans-Christian Egtvedt 	struct dw_dma_slave *dws = slave;
8774ede028fSHans-Christian Egtvedt 
8784ede028fSHans-Christian Egtvedt 	if (dws->dma_dev == chan->device->dev) {
8794ede028fSHans-Christian Egtvedt 		chan->private = dws;
8804ede028fSHans-Christian Egtvedt 		return true;
8814ede028fSHans-Christian Egtvedt 	} else
8824ede028fSHans-Christian Egtvedt 		return false;
8834ede028fSHans-Christian Egtvedt }
8844ede028fSHans-Christian Egtvedt 
8854ede028fSHans-Christian Egtvedt static void atmel_ac97c_reset(struct atmel_ac97c *chip)
8864ede028fSHans-Christian Egtvedt {
88781baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, MR,   0);
88881baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, MR,   AC97C_MR_ENA);
88981baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, 0);
89081baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, COMR, 0);
8914ede028fSHans-Christian Egtvedt 
8924ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(chip->reset_pin)) {
8934ede028fSHans-Christian Egtvedt 		gpio_set_value(chip->reset_pin, 0);
8944ede028fSHans-Christian Egtvedt 		/* AC97 v2.2 specifications says minimum 1 us. */
89581baf3a7SHans-Christian Egtvedt 		udelay(2);
8964ede028fSHans-Christian Egtvedt 		gpio_set_value(chip->reset_pin, 1);
8978015e3deSBo Shen 	} else {
8988015e3deSBo Shen 		ac97c_writel(chip, MR, AC97C_MR_WRST | AC97C_MR_ENA);
8998015e3deSBo Shen 		udelay(2);
9008015e3deSBo Shen 		ac97c_writel(chip, MR, AC97C_MR_ENA);
9014ede028fSHans-Christian Egtvedt 	}
9024ede028fSHans-Christian Egtvedt }
9034ede028fSHans-Christian Egtvedt 
90461dc674cSBill Pemberton static int atmel_ac97c_probe(struct platform_device *pdev)
9054ede028fSHans-Christian Egtvedt {
9064ede028fSHans-Christian Egtvedt 	struct snd_card			*card;
9074ede028fSHans-Christian Egtvedt 	struct atmel_ac97c		*chip;
9084ede028fSHans-Christian Egtvedt 	struct resource			*regs;
9094ede028fSHans-Christian Egtvedt 	struct ac97c_platform_data	*pdata;
9104ede028fSHans-Christian Egtvedt 	struct clk			*pclk;
9114ede028fSHans-Christian Egtvedt 	static struct snd_ac97_bus_ops	ops = {
9124ede028fSHans-Christian Egtvedt 		.write	= atmel_ac97c_write,
9134ede028fSHans-Christian Egtvedt 		.read	= atmel_ac97c_read,
9144ede028fSHans-Christian Egtvedt 	};
9154ede028fSHans-Christian Egtvedt 	int				retval;
916df163587SHans-Christian Egtvedt 	int				irq;
9174ede028fSHans-Christian Egtvedt 
9184ede028fSHans-Christian Egtvedt 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9194ede028fSHans-Christian Egtvedt 	if (!regs) {
9204ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "no memory resource\n");
9214ede028fSHans-Christian Egtvedt 		return -ENXIO;
9224ede028fSHans-Christian Egtvedt 	}
9234ede028fSHans-Christian Egtvedt 
9244ede028fSHans-Christian Egtvedt 	pdata = pdev->dev.platform_data;
9254ede028fSHans-Christian Egtvedt 	if (!pdata) {
9264ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "no platform data\n");
9274ede028fSHans-Christian Egtvedt 		return -ENXIO;
9284ede028fSHans-Christian Egtvedt 	}
9294ede028fSHans-Christian Egtvedt 
930df163587SHans-Christian Egtvedt 	irq = platform_get_irq(pdev, 0);
931df163587SHans-Christian Egtvedt 	if (irq < 0) {
932df163587SHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not get irq\n");
933df163587SHans-Christian Egtvedt 		return -ENXIO;
934df163587SHans-Christian Egtvedt 	}
935df163587SHans-Christian Egtvedt 
9367177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
9374ede028fSHans-Christian Egtvedt 		pclk = clk_get(&pdev->dev, "pclk");
9387177395fSSedji Gaouaou 	} else {
9397177395fSSedji Gaouaou 		pclk = clk_get(&pdev->dev, "ac97_clk");
9407177395fSSedji Gaouaou 	}
9417177395fSSedji Gaouaou 
9424ede028fSHans-Christian Egtvedt 	if (IS_ERR(pclk)) {
9434ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "no peripheral clock\n");
9444ede028fSHans-Christian Egtvedt 		return PTR_ERR(pclk);
9454ede028fSHans-Christian Egtvedt 	}
9464ede028fSHans-Christian Egtvedt 	clk_enable(pclk);
9474ede028fSHans-Christian Egtvedt 
948a4f2473dSTakashi Iwai 	retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
949a4f2473dSTakashi Iwai 			      SNDRV_DEFAULT_STR1, THIS_MODULE,
950a4f2473dSTakashi Iwai 			      sizeof(struct atmel_ac97c), &card);
9514ede028fSHans-Christian Egtvedt 	if (retval) {
9524ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not create sound card device\n");
9534ede028fSHans-Christian Egtvedt 		goto err_snd_card_new;
9544ede028fSHans-Christian Egtvedt 	}
9554ede028fSHans-Christian Egtvedt 
9564ede028fSHans-Christian Egtvedt 	chip = get_chip(card);
9574ede028fSHans-Christian Egtvedt 
958df163587SHans-Christian Egtvedt 	retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
959df163587SHans-Christian Egtvedt 	if (retval) {
960df163587SHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "unable to request irq %d\n", irq);
961df163587SHans-Christian Egtvedt 		goto err_request_irq;
962df163587SHans-Christian Egtvedt 	}
963df163587SHans-Christian Egtvedt 	chip->irq = irq;
964df163587SHans-Christian Egtvedt 
9654ede028fSHans-Christian Egtvedt 	spin_lock_init(&chip->lock);
9664ede028fSHans-Christian Egtvedt 
9674ede028fSHans-Christian Egtvedt 	strcpy(card->driver, "Atmel AC97C");
9684ede028fSHans-Christian Egtvedt 	strcpy(card->shortname, "Atmel AC97C");
9694ede028fSHans-Christian Egtvedt 	sprintf(card->longname, "Atmel AC97 controller");
9704ede028fSHans-Christian Egtvedt 
9714ede028fSHans-Christian Egtvedt 	chip->card = card;
9724ede028fSHans-Christian Egtvedt 	chip->pclk = pclk;
9734ede028fSHans-Christian Egtvedt 	chip->pdev = pdev;
97428f65c11SJoe Perches 	chip->regs = ioremap(regs->start, resource_size(regs));
9754ede028fSHans-Christian Egtvedt 
9764ede028fSHans-Christian Egtvedt 	if (!chip->regs) {
9774ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not remap register memory\n");
9780c23e46eSJulia Lawall 		retval = -ENOMEM;
9794ede028fSHans-Christian Egtvedt 		goto err_ioremap;
9804ede028fSHans-Christian Egtvedt 	}
9814ede028fSHans-Christian Egtvedt 
9824ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(pdata->reset_pin)) {
9834ede028fSHans-Christian Egtvedt 		if (gpio_request(pdata->reset_pin, "reset_pin")) {
9844ede028fSHans-Christian Egtvedt 			dev_dbg(&pdev->dev, "reset pin not available\n");
9854ede028fSHans-Christian Egtvedt 			chip->reset_pin = -ENODEV;
9864ede028fSHans-Christian Egtvedt 		} else {
9874ede028fSHans-Christian Egtvedt 			gpio_direction_output(pdata->reset_pin, 1);
9884ede028fSHans-Christian Egtvedt 			chip->reset_pin = pdata->reset_pin;
9894ede028fSHans-Christian Egtvedt 		}
990b2522f92SBo Shen 	} else {
991b2522f92SBo Shen 		chip->reset_pin = -EINVAL;
9924ede028fSHans-Christian Egtvedt 	}
9934ede028fSHans-Christian Egtvedt 
99481baf3a7SHans-Christian Egtvedt 	atmel_ac97c_reset(chip);
99581baf3a7SHans-Christian Egtvedt 
996df163587SHans-Christian Egtvedt 	/* Enable overrun interrupt from codec channel */
997df163587SHans-Christian Egtvedt 	ac97c_writel(chip, COMR, AC97C_CSR_OVRUN);
998df163587SHans-Christian Egtvedt 	ac97c_writel(chip, IER, ac97c_readl(chip, IMR) | AC97C_SR_COEVT);
999df163587SHans-Christian Egtvedt 
10004ede028fSHans-Christian Egtvedt 	retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
10014ede028fSHans-Christian Egtvedt 	if (retval) {
10024ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
10034ede028fSHans-Christian Egtvedt 		goto err_ac97_bus;
10044ede028fSHans-Christian Egtvedt 	}
10054ede028fSHans-Christian Egtvedt 
10064ede028fSHans-Christian Egtvedt 	retval = atmel_ac97c_mixer_new(chip);
10074ede028fSHans-Christian Egtvedt 	if (retval) {
10084ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
10094ede028fSHans-Christian Egtvedt 		goto err_ac97_bus;
10104ede028fSHans-Christian Egtvedt 	}
10114ede028fSHans-Christian Egtvedt 
10127177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
10134ede028fSHans-Christian Egtvedt 		if (pdata->rx_dws.dma_dev) {
10144ede028fSHans-Christian Egtvedt 			dma_cap_mask_t mask;
10154ede028fSHans-Christian Egtvedt 
10164ede028fSHans-Christian Egtvedt 			dma_cap_zero(mask);
10174ede028fSHans-Christian Egtvedt 			dma_cap_set(DMA_SLAVE, mask);
10184ede028fSHans-Christian Egtvedt 
10197177395fSSedji Gaouaou 			chip->dma.rx_chan = dma_request_channel(mask, filter,
1020e2b35f3dSViresh Kumar 								&pdata->rx_dws);
1021e2b35f3dSViresh Kumar 			if (chip->dma.rx_chan) {
1022e2b35f3dSViresh Kumar 				struct dma_slave_config dma_conf = {
1023e2b35f3dSViresh Kumar 					.src_addr = regs->start + AC97C_CARHR +
1024e2b35f3dSViresh Kumar 						2,
1025e2b35f3dSViresh Kumar 					.src_addr_width =
1026e2b35f3dSViresh Kumar 						DMA_SLAVE_BUSWIDTH_2_BYTES,
1027e2b35f3dSViresh Kumar 					.src_maxburst = 1,
1028e2b35f3dSViresh Kumar 					.dst_maxburst = 1,
1029e2b35f3dSViresh Kumar 					.direction = DMA_DEV_TO_MEM,
1030e2b35f3dSViresh Kumar 					.device_fc = false,
1031e2b35f3dSViresh Kumar 				};
1032e2b35f3dSViresh Kumar 
1033e2b35f3dSViresh Kumar 				dmaengine_slave_config(chip->dma.rx_chan,
1034e2b35f3dSViresh Kumar 						&dma_conf);
1035e2b35f3dSViresh Kumar 			}
10364ede028fSHans-Christian Egtvedt 
10374ede028fSHans-Christian Egtvedt 			dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
103823572856SHans-Christian Egtvedt 				dev_name(&chip->dma.rx_chan->dev->device));
10394ede028fSHans-Christian Egtvedt 			set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
10404ede028fSHans-Christian Egtvedt 		}
10414ede028fSHans-Christian Egtvedt 
10424ede028fSHans-Christian Egtvedt 		if (pdata->tx_dws.dma_dev) {
10434ede028fSHans-Christian Egtvedt 			dma_cap_mask_t mask;
10444ede028fSHans-Christian Egtvedt 
10454ede028fSHans-Christian Egtvedt 			dma_cap_zero(mask);
10464ede028fSHans-Christian Egtvedt 			dma_cap_set(DMA_SLAVE, mask);
10474ede028fSHans-Christian Egtvedt 
10487177395fSSedji Gaouaou 			chip->dma.tx_chan = dma_request_channel(mask, filter,
1049e2b35f3dSViresh Kumar 								&pdata->tx_dws);
1050e2b35f3dSViresh Kumar 			if (chip->dma.tx_chan) {
1051e2b35f3dSViresh Kumar 				struct dma_slave_config dma_conf = {
1052e2b35f3dSViresh Kumar 					.dst_addr = regs->start + AC97C_CATHR +
1053e2b35f3dSViresh Kumar 						2,
1054e2b35f3dSViresh Kumar 					.dst_addr_width =
1055e2b35f3dSViresh Kumar 						DMA_SLAVE_BUSWIDTH_2_BYTES,
1056e2b35f3dSViresh Kumar 					.src_maxburst = 1,
1057e2b35f3dSViresh Kumar 					.dst_maxburst = 1,
1058e2b35f3dSViresh Kumar 					.direction = DMA_MEM_TO_DEV,
1059e2b35f3dSViresh Kumar 					.device_fc = false,
1060e2b35f3dSViresh Kumar 				};
1061e2b35f3dSViresh Kumar 
1062e2b35f3dSViresh Kumar 				dmaengine_slave_config(chip->dma.tx_chan,
1063e2b35f3dSViresh Kumar 						&dma_conf);
1064e2b35f3dSViresh Kumar 			}
10654ede028fSHans-Christian Egtvedt 
10664ede028fSHans-Christian Egtvedt 			dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
106723572856SHans-Christian Egtvedt 				dev_name(&chip->dma.tx_chan->dev->device));
10684ede028fSHans-Christian Egtvedt 			set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
10694ede028fSHans-Christian Egtvedt 		}
10704ede028fSHans-Christian Egtvedt 
10714ede028fSHans-Christian Egtvedt 		if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
10724ede028fSHans-Christian Egtvedt 				!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
10734ede028fSHans-Christian Egtvedt 			dev_dbg(&pdev->dev, "DMA not available\n");
10744ede028fSHans-Christian Egtvedt 			retval = -ENODEV;
10754ede028fSHans-Christian Egtvedt 			goto err_dma;
10764ede028fSHans-Christian Egtvedt 		}
10777177395fSSedji Gaouaou 	} else {
10787177395fSSedji Gaouaou 		/* Just pretend that we have DMA channel(for at91 i is actually
10797177395fSSedji Gaouaou 		 * the PDC) */
10807177395fSSedji Gaouaou 		set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
10817177395fSSedji Gaouaou 		set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
10827177395fSSedji Gaouaou 	}
10834ede028fSHans-Christian Egtvedt 
10844ede028fSHans-Christian Egtvedt 	retval = atmel_ac97c_pcm_new(chip);
10854ede028fSHans-Christian Egtvedt 	if (retval) {
10864ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
10874ede028fSHans-Christian Egtvedt 		goto err_dma;
10884ede028fSHans-Christian Egtvedt 	}
10894ede028fSHans-Christian Egtvedt 
10904ede028fSHans-Christian Egtvedt 	retval = snd_card_register(card);
10914ede028fSHans-Christian Egtvedt 	if (retval) {
10924ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register sound card\n");
1093df163587SHans-Christian Egtvedt 		goto err_dma;
10944ede028fSHans-Christian Egtvedt 	}
10954ede028fSHans-Christian Egtvedt 
10964ede028fSHans-Christian Egtvedt 	platform_set_drvdata(pdev, card);
10974ede028fSHans-Christian Egtvedt 
10987177395fSSedji Gaouaou 	dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n",
10997177395fSSedji Gaouaou 			chip->regs, irq);
11004ede028fSHans-Christian Egtvedt 
11014ede028fSHans-Christian Egtvedt 	return 0;
11024ede028fSHans-Christian Egtvedt 
11034ede028fSHans-Christian Egtvedt err_dma:
11047177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11054ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
11064ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.rx_chan);
11074ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
11084ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.tx_chan);
11094ede028fSHans-Christian Egtvedt 		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
11104ede028fSHans-Christian Egtvedt 		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
11114ede028fSHans-Christian Egtvedt 		chip->dma.rx_chan = NULL;
11124ede028fSHans-Christian Egtvedt 		chip->dma.tx_chan = NULL;
11137177395fSSedji Gaouaou 	}
11144ede028fSHans-Christian Egtvedt err_ac97_bus:
11154ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(chip->reset_pin))
11164ede028fSHans-Christian Egtvedt 		gpio_free(chip->reset_pin);
11174ede028fSHans-Christian Egtvedt 
11184ede028fSHans-Christian Egtvedt 	iounmap(chip->regs);
11194ede028fSHans-Christian Egtvedt err_ioremap:
1120df163587SHans-Christian Egtvedt 	free_irq(irq, chip);
1121df163587SHans-Christian Egtvedt err_request_irq:
11224ede028fSHans-Christian Egtvedt 	snd_card_free(card);
11234ede028fSHans-Christian Egtvedt err_snd_card_new:
11244ede028fSHans-Christian Egtvedt 	clk_disable(pclk);
11254ede028fSHans-Christian Egtvedt 	clk_put(pclk);
11264ede028fSHans-Christian Egtvedt 	return retval;
11274ede028fSHans-Christian Egtvedt }
11284ede028fSHans-Christian Egtvedt 
1129d34e4e00STakashi Iwai #ifdef CONFIG_PM_SLEEP
1130284e7ca7STakashi Iwai static int atmel_ac97c_suspend(struct device *pdev)
11314ede028fSHans-Christian Egtvedt {
1132284e7ca7STakashi Iwai 	struct snd_card *card = dev_get_drvdata(pdev);
11334ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = card->private_data;
11344ede028fSHans-Christian Egtvedt 
11357177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11364ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_READY, &chip->flags))
11374ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.rx_chan);
11384ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_READY, &chip->flags))
11394ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.tx_chan);
11407177395fSSedji Gaouaou 	}
11414ede028fSHans-Christian Egtvedt 	clk_disable(chip->pclk);
11424ede028fSHans-Christian Egtvedt 
11434ede028fSHans-Christian Egtvedt 	return 0;
11444ede028fSHans-Christian Egtvedt }
11454ede028fSHans-Christian Egtvedt 
1146284e7ca7STakashi Iwai static int atmel_ac97c_resume(struct device *pdev)
11474ede028fSHans-Christian Egtvedt {
1148284e7ca7STakashi Iwai 	struct snd_card *card = dev_get_drvdata(pdev);
11494ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = card->private_data;
11504ede028fSHans-Christian Egtvedt 
11514ede028fSHans-Christian Egtvedt 	clk_enable(chip->pclk);
11527177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11534ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_READY, &chip->flags))
11544ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_start(chip->dma.rx_chan);
11554ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_READY, &chip->flags))
11564ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_start(chip->dma.tx_chan);
11577177395fSSedji Gaouaou 	}
11584ede028fSHans-Christian Egtvedt 	return 0;
11594ede028fSHans-Christian Egtvedt }
1160284e7ca7STakashi Iwai 
1161284e7ca7STakashi Iwai static SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume);
1162284e7ca7STakashi Iwai #define ATMEL_AC97C_PM_OPS	&atmel_ac97c_pm
11634ede028fSHans-Christian Egtvedt #else
1164284e7ca7STakashi Iwai #define ATMEL_AC97C_PM_OPS	NULL
11654ede028fSHans-Christian Egtvedt #endif
11664ede028fSHans-Christian Egtvedt 
116761dc674cSBill Pemberton static int atmel_ac97c_remove(struct platform_device *pdev)
11684ede028fSHans-Christian Egtvedt {
11694ede028fSHans-Christian Egtvedt 	struct snd_card *card = platform_get_drvdata(pdev);
11704ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = get_chip(card);
11714ede028fSHans-Christian Egtvedt 
11724ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(chip->reset_pin))
11734ede028fSHans-Christian Egtvedt 		gpio_free(chip->reset_pin);
11744ede028fSHans-Christian Egtvedt 
1175bd74a184SHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, 0);
1176bd74a184SHans-Christian Egtvedt 	ac97c_writel(chip, COMR, 0);
1177bd74a184SHans-Christian Egtvedt 	ac97c_writel(chip, MR,   0);
1178bd74a184SHans-Christian Egtvedt 
11794ede028fSHans-Christian Egtvedt 	clk_disable(chip->pclk);
11804ede028fSHans-Christian Egtvedt 	clk_put(chip->pclk);
11814ede028fSHans-Christian Egtvedt 	iounmap(chip->regs);
1182df163587SHans-Christian Egtvedt 	free_irq(chip->irq, chip);
11834ede028fSHans-Christian Egtvedt 
11847177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11854ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
11864ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.rx_chan);
11874ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
11884ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.tx_chan);
11894ede028fSHans-Christian Egtvedt 		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
11904ede028fSHans-Christian Egtvedt 		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
11914ede028fSHans-Christian Egtvedt 		chip->dma.rx_chan = NULL;
11924ede028fSHans-Christian Egtvedt 		chip->dma.tx_chan = NULL;
11937177395fSSedji Gaouaou 	}
11944ede028fSHans-Christian Egtvedt 
11954ede028fSHans-Christian Egtvedt 	snd_card_free(card);
11964ede028fSHans-Christian Egtvedt 
11974ede028fSHans-Christian Egtvedt 	return 0;
11984ede028fSHans-Christian Egtvedt }
11994ede028fSHans-Christian Egtvedt 
12004ede028fSHans-Christian Egtvedt static struct platform_driver atmel_ac97c_driver = {
120161dc674cSBill Pemberton 	.remove		= atmel_ac97c_remove,
12024ede028fSHans-Christian Egtvedt 	.driver		= {
12034ede028fSHans-Christian Egtvedt 		.name	= "atmel_ac97c",
12048bf01d8aSTakashi Iwai 		.owner	= THIS_MODULE,
1205284e7ca7STakashi Iwai 		.pm	= ATMEL_AC97C_PM_OPS,
12064ede028fSHans-Christian Egtvedt 	},
12074ede028fSHans-Christian Egtvedt };
12084ede028fSHans-Christian Egtvedt 
12094ede028fSHans-Christian Egtvedt static int __init atmel_ac97c_init(void)
12104ede028fSHans-Christian Egtvedt {
12114ede028fSHans-Christian Egtvedt 	return platform_driver_probe(&atmel_ac97c_driver,
12124ede028fSHans-Christian Egtvedt 			atmel_ac97c_probe);
12134ede028fSHans-Christian Egtvedt }
12144ede028fSHans-Christian Egtvedt module_init(atmel_ac97c_init);
12154ede028fSHans-Christian Egtvedt 
12164ede028fSHans-Christian Egtvedt static void __exit atmel_ac97c_exit(void)
12174ede028fSHans-Christian Egtvedt {
12184ede028fSHans-Christian Egtvedt 	platform_driver_unregister(&atmel_ac97c_driver);
12194ede028fSHans-Christian Egtvedt }
12204ede028fSHans-Christian Egtvedt module_exit(atmel_ac97c_exit);
12214ede028fSHans-Christian Egtvedt 
12224ede028fSHans-Christian Egtvedt MODULE_LICENSE("GPL");
12234ede028fSHans-Christian Egtvedt MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
12240cfae7c9SHans-Christian Egtvedt MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
1225