xref: /openbmc/linux/sound/atmel/ac97c.c (revision b2522f92)
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 #include <mach/gpio.h>
387177395fSSedji Gaouaou 
39fd76804fSHans-Christian Egtvedt #ifdef CONFIG_ARCH_AT91
40fd76804fSHans-Christian Egtvedt #include <mach/hardware.h>
41fd76804fSHans-Christian Egtvedt #endif
42fd76804fSHans-Christian Egtvedt 
434ede028fSHans-Christian Egtvedt #include "ac97c.h"
444ede028fSHans-Christian Egtvedt 
454ede028fSHans-Christian Egtvedt enum {
464ede028fSHans-Christian Egtvedt 	DMA_TX_READY = 0,
474ede028fSHans-Christian Egtvedt 	DMA_RX_READY,
484ede028fSHans-Christian Egtvedt 	DMA_TX_CHAN_PRESENT,
494ede028fSHans-Christian Egtvedt 	DMA_RX_CHAN_PRESENT,
504ede028fSHans-Christian Egtvedt };
514ede028fSHans-Christian Egtvedt 
524ede028fSHans-Christian Egtvedt /* Serialize access to opened variable */
534ede028fSHans-Christian Egtvedt static DEFINE_MUTEX(opened_mutex);
544ede028fSHans-Christian Egtvedt 
554ede028fSHans-Christian Egtvedt struct atmel_ac97c_dma {
564ede028fSHans-Christian Egtvedt 	struct dma_chan			*rx_chan;
574ede028fSHans-Christian Egtvedt 	struct dma_chan			*tx_chan;
584ede028fSHans-Christian Egtvedt };
594ede028fSHans-Christian Egtvedt 
604ede028fSHans-Christian Egtvedt struct atmel_ac97c {
614ede028fSHans-Christian Egtvedt 	struct clk			*pclk;
624ede028fSHans-Christian Egtvedt 	struct platform_device		*pdev;
634ede028fSHans-Christian Egtvedt 	struct atmel_ac97c_dma		dma;
644ede028fSHans-Christian Egtvedt 
654ede028fSHans-Christian Egtvedt 	struct snd_pcm_substream	*playback_substream;
664ede028fSHans-Christian Egtvedt 	struct snd_pcm_substream	*capture_substream;
674ede028fSHans-Christian Egtvedt 	struct snd_card			*card;
684ede028fSHans-Christian Egtvedt 	struct snd_pcm			*pcm;
694ede028fSHans-Christian Egtvedt 	struct snd_ac97			*ac97;
704ede028fSHans-Christian Egtvedt 	struct snd_ac97_bus		*ac97_bus;
714ede028fSHans-Christian Egtvedt 
724ede028fSHans-Christian Egtvedt 	u64				cur_format;
734ede028fSHans-Christian Egtvedt 	unsigned int			cur_rate;
744ede028fSHans-Christian Egtvedt 	unsigned long			flags;
757177395fSSedji Gaouaou 	int				playback_period, capture_period;
764ede028fSHans-Christian Egtvedt 	/* Serialize access to opened variable */
774ede028fSHans-Christian Egtvedt 	spinlock_t			lock;
784ede028fSHans-Christian Egtvedt 	void __iomem			*regs;
79df163587SHans-Christian Egtvedt 	int				irq;
804ede028fSHans-Christian Egtvedt 	int				opened;
814ede028fSHans-Christian Egtvedt 	int				reset_pin;
824ede028fSHans-Christian Egtvedt };
834ede028fSHans-Christian Egtvedt 
844ede028fSHans-Christian Egtvedt #define get_chip(card) ((struct atmel_ac97c *)(card)->private_data)
854ede028fSHans-Christian Egtvedt 
864ede028fSHans-Christian Egtvedt #define ac97c_writel(chip, reg, val)			\
874ede028fSHans-Christian Egtvedt 	__raw_writel((val), (chip)->regs + AC97C_##reg)
884ede028fSHans-Christian Egtvedt #define ac97c_readl(chip, reg)				\
894ede028fSHans-Christian Egtvedt 	__raw_readl((chip)->regs + AC97C_##reg)
904ede028fSHans-Christian Egtvedt 
914ede028fSHans-Christian Egtvedt /* This function is called by the DMA driver. */
924ede028fSHans-Christian Egtvedt static void atmel_ac97c_dma_playback_period_done(void *arg)
934ede028fSHans-Christian Egtvedt {
944ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = arg;
954ede028fSHans-Christian Egtvedt 	snd_pcm_period_elapsed(chip->playback_substream);
964ede028fSHans-Christian Egtvedt }
974ede028fSHans-Christian Egtvedt 
984ede028fSHans-Christian Egtvedt static void atmel_ac97c_dma_capture_period_done(void *arg)
994ede028fSHans-Christian Egtvedt {
1004ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = arg;
1014ede028fSHans-Christian Egtvedt 	snd_pcm_period_elapsed(chip->capture_substream);
1024ede028fSHans-Christian Egtvedt }
1034ede028fSHans-Christian Egtvedt 
1044ede028fSHans-Christian Egtvedt static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
1054ede028fSHans-Christian Egtvedt 		struct snd_pcm_substream *substream,
10635e16581SVinod Koul 		enum dma_transfer_direction direction)
1074ede028fSHans-Christian Egtvedt {
1084ede028fSHans-Christian Egtvedt 	struct dma_chan			*chan;
1094ede028fSHans-Christian Egtvedt 	struct dw_cyclic_desc		*cdesc;
1104ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime		*runtime = substream->runtime;
1114ede028fSHans-Christian Egtvedt 	unsigned long			buffer_len, period_len;
1124ede028fSHans-Christian Egtvedt 
1134ede028fSHans-Christian Egtvedt 	/*
1144ede028fSHans-Christian Egtvedt 	 * We don't do DMA on "complex" transfers, i.e. with
1154ede028fSHans-Christian Egtvedt 	 * non-halfword-aligned buffers or lengths.
1164ede028fSHans-Christian Egtvedt 	 */
1174ede028fSHans-Christian Egtvedt 	if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
1184ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "too complex transfer\n");
1194ede028fSHans-Christian Egtvedt 		return -EINVAL;
1204ede028fSHans-Christian Egtvedt 	}
1214ede028fSHans-Christian Egtvedt 
12235e16581SVinod Koul 	if (direction == DMA_MEM_TO_DEV)
1234ede028fSHans-Christian Egtvedt 		chan = chip->dma.tx_chan;
1244ede028fSHans-Christian Egtvedt 	else
1254ede028fSHans-Christian Egtvedt 		chan = chip->dma.rx_chan;
1264ede028fSHans-Christian Egtvedt 
1274ede028fSHans-Christian Egtvedt 	buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
1284ede028fSHans-Christian Egtvedt 	period_len = frames_to_bytes(runtime, runtime->period_size);
1294ede028fSHans-Christian Egtvedt 
1304ede028fSHans-Christian Egtvedt 	cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
1314ede028fSHans-Christian Egtvedt 			period_len, direction);
1324ede028fSHans-Christian Egtvedt 	if (IS_ERR(cdesc)) {
1334ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n");
1344ede028fSHans-Christian Egtvedt 		return PTR_ERR(cdesc);
1354ede028fSHans-Christian Egtvedt 	}
1364ede028fSHans-Christian Egtvedt 
13735e16581SVinod Koul 	if (direction == DMA_MEM_TO_DEV) {
1384ede028fSHans-Christian Egtvedt 		cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
1394ede028fSHans-Christian Egtvedt 		set_bit(DMA_TX_READY, &chip->flags);
1404ede028fSHans-Christian Egtvedt 	} else {
1414ede028fSHans-Christian Egtvedt 		cdesc->period_callback = atmel_ac97c_dma_capture_period_done;
1424ede028fSHans-Christian Egtvedt 		set_bit(DMA_RX_READY, &chip->flags);
1434ede028fSHans-Christian Egtvedt 	}
1444ede028fSHans-Christian Egtvedt 
1454ede028fSHans-Christian Egtvedt 	cdesc->period_callback_param = chip;
1464ede028fSHans-Christian Egtvedt 
1474ede028fSHans-Christian Egtvedt 	return 0;
1484ede028fSHans-Christian Egtvedt }
1494ede028fSHans-Christian Egtvedt 
1504ede028fSHans-Christian Egtvedt static struct snd_pcm_hardware atmel_ac97c_hw = {
1514ede028fSHans-Christian Egtvedt 	.info			= (SNDRV_PCM_INFO_MMAP
1524ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_MMAP_VALID
1534ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_INTERLEAVED
1544ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_BLOCK_TRANSFER
1554ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_JOINT_DUPLEX
1564ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_RESUME
1574ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_INFO_PAUSE),
1584ede028fSHans-Christian Egtvedt 	.formats		= (SNDRV_PCM_FMTBIT_S16_BE
1594ede028fSHans-Christian Egtvedt 				  | SNDRV_PCM_FMTBIT_S16_LE),
1604ede028fSHans-Christian Egtvedt 	.rates			= (SNDRV_PCM_RATE_CONTINUOUS),
1614ede028fSHans-Christian Egtvedt 	.rate_min		= 4000,
1624ede028fSHans-Christian Egtvedt 	.rate_max		= 48000,
1634ede028fSHans-Christian Egtvedt 	.channels_min		= 1,
1644ede028fSHans-Christian Egtvedt 	.channels_max		= 2,
165c42eec0fSHans-Christian Egtvedt 	.buffer_bytes_max	= 2 * 2 * 64 * 2048,
1664ede028fSHans-Christian Egtvedt 	.period_bytes_min	= 4096,
1674ede028fSHans-Christian Egtvedt 	.period_bytes_max	= 4096,
168c42eec0fSHans-Christian Egtvedt 	.periods_min		= 6,
1694ede028fSHans-Christian Egtvedt 	.periods_max		= 64,
1704ede028fSHans-Christian Egtvedt };
1714ede028fSHans-Christian Egtvedt 
1724ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
1734ede028fSHans-Christian Egtvedt {
1744ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
1754ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
1764ede028fSHans-Christian Egtvedt 
1774ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
1784ede028fSHans-Christian Egtvedt 	chip->opened++;
1794ede028fSHans-Christian Egtvedt 	runtime->hw = atmel_ac97c_hw;
1804ede028fSHans-Christian Egtvedt 	if (chip->cur_rate) {
1814ede028fSHans-Christian Egtvedt 		runtime->hw.rate_min = chip->cur_rate;
1824ede028fSHans-Christian Egtvedt 		runtime->hw.rate_max = chip->cur_rate;
1834ede028fSHans-Christian Egtvedt 	}
1844ede028fSHans-Christian Egtvedt 	if (chip->cur_format)
1854ede028fSHans-Christian Egtvedt 		runtime->hw.formats = (1ULL << chip->cur_format);
1864ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
1874ede028fSHans-Christian Egtvedt 	chip->playback_substream = substream;
1884ede028fSHans-Christian Egtvedt 	return 0;
1894ede028fSHans-Christian Egtvedt }
1904ede028fSHans-Christian Egtvedt 
1914ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
1924ede028fSHans-Christian Egtvedt {
1934ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
1944ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
1954ede028fSHans-Christian Egtvedt 
1964ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
1974ede028fSHans-Christian Egtvedt 	chip->opened++;
1984ede028fSHans-Christian Egtvedt 	runtime->hw = atmel_ac97c_hw;
1994ede028fSHans-Christian Egtvedt 	if (chip->cur_rate) {
2004ede028fSHans-Christian Egtvedt 		runtime->hw.rate_min = chip->cur_rate;
2014ede028fSHans-Christian Egtvedt 		runtime->hw.rate_max = chip->cur_rate;
2024ede028fSHans-Christian Egtvedt 	}
2034ede028fSHans-Christian Egtvedt 	if (chip->cur_format)
2044ede028fSHans-Christian Egtvedt 		runtime->hw.formats = (1ULL << chip->cur_format);
2054ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2064ede028fSHans-Christian Egtvedt 	chip->capture_substream = substream;
2074ede028fSHans-Christian Egtvedt 	return 0;
2084ede028fSHans-Christian Egtvedt }
2094ede028fSHans-Christian Egtvedt 
2104ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream)
2114ede028fSHans-Christian Egtvedt {
2124ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2134ede028fSHans-Christian Egtvedt 
2144ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2154ede028fSHans-Christian Egtvedt 	chip->opened--;
2164ede028fSHans-Christian Egtvedt 	if (!chip->opened) {
2174ede028fSHans-Christian Egtvedt 		chip->cur_rate = 0;
2184ede028fSHans-Christian Egtvedt 		chip->cur_format = 0;
2194ede028fSHans-Christian Egtvedt 	}
2204ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2214ede028fSHans-Christian Egtvedt 
2224ede028fSHans-Christian Egtvedt 	chip->playback_substream = NULL;
2234ede028fSHans-Christian Egtvedt 
2244ede028fSHans-Christian Egtvedt 	return 0;
2254ede028fSHans-Christian Egtvedt }
2264ede028fSHans-Christian Egtvedt 
2274ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream)
2284ede028fSHans-Christian Egtvedt {
2294ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2304ede028fSHans-Christian Egtvedt 
2314ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2324ede028fSHans-Christian Egtvedt 	chip->opened--;
2334ede028fSHans-Christian Egtvedt 	if (!chip->opened) {
2344ede028fSHans-Christian Egtvedt 		chip->cur_rate = 0;
2354ede028fSHans-Christian Egtvedt 		chip->cur_format = 0;
2364ede028fSHans-Christian Egtvedt 	}
2374ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2384ede028fSHans-Christian Egtvedt 
2394ede028fSHans-Christian Egtvedt 	chip->capture_substream = NULL;
2404ede028fSHans-Christian Egtvedt 
2414ede028fSHans-Christian Egtvedt 	return 0;
2424ede028fSHans-Christian Egtvedt }
2434ede028fSHans-Christian Egtvedt 
2444ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
2454ede028fSHans-Christian Egtvedt 		struct snd_pcm_hw_params *hw_params)
2464ede028fSHans-Christian Egtvedt {
2474ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2484ede028fSHans-Christian Egtvedt 	int retval;
2494ede028fSHans-Christian Egtvedt 
2504ede028fSHans-Christian Egtvedt 	retval = snd_pcm_lib_malloc_pages(substream,
2514ede028fSHans-Christian Egtvedt 					params_buffer_bytes(hw_params));
2524ede028fSHans-Christian Egtvedt 	if (retval < 0)
2534ede028fSHans-Christian Egtvedt 		return retval;
2544ede028fSHans-Christian Egtvedt 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
2557177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
2567177395fSSedji Gaouaou 		/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
2574ede028fSHans-Christian Egtvedt 		if (retval == 1)
2584ede028fSHans-Christian Egtvedt 			if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
2594ede028fSHans-Christian Egtvedt 				dw_dma_cyclic_free(chip->dma.tx_chan);
2607177395fSSedji Gaouaou 	}
2614ede028fSHans-Christian Egtvedt 	/* Set restrictions to params. */
2624ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2634ede028fSHans-Christian Egtvedt 	chip->cur_rate = params_rate(hw_params);
2644ede028fSHans-Christian Egtvedt 	chip->cur_format = params_format(hw_params);
2654ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2664ede028fSHans-Christian Egtvedt 
2674ede028fSHans-Christian Egtvedt 	return retval;
2684ede028fSHans-Christian Egtvedt }
2694ede028fSHans-Christian Egtvedt 
2704ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
2714ede028fSHans-Christian Egtvedt 		struct snd_pcm_hw_params *hw_params)
2724ede028fSHans-Christian Egtvedt {
2734ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
2744ede028fSHans-Christian Egtvedt 	int retval;
2754ede028fSHans-Christian Egtvedt 
2764ede028fSHans-Christian Egtvedt 	retval = snd_pcm_lib_malloc_pages(substream,
2774ede028fSHans-Christian Egtvedt 					params_buffer_bytes(hw_params));
2784ede028fSHans-Christian Egtvedt 	if (retval < 0)
2794ede028fSHans-Christian Egtvedt 		return retval;
2804ede028fSHans-Christian Egtvedt 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
2817177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
2827177395fSSedji Gaouaou 		if (retval < 0)
2837177395fSSedji Gaouaou 			return retval;
2847177395fSSedji Gaouaou 		/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
2854ede028fSHans-Christian Egtvedt 		if (retval == 1)
2864ede028fSHans-Christian Egtvedt 			if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
2874ede028fSHans-Christian Egtvedt 				dw_dma_cyclic_free(chip->dma.rx_chan);
2887177395fSSedji Gaouaou 	}
2894ede028fSHans-Christian Egtvedt 
2904ede028fSHans-Christian Egtvedt 	/* Set restrictions to params. */
2914ede028fSHans-Christian Egtvedt 	mutex_lock(&opened_mutex);
2924ede028fSHans-Christian Egtvedt 	chip->cur_rate = params_rate(hw_params);
2934ede028fSHans-Christian Egtvedt 	chip->cur_format = params_format(hw_params);
2944ede028fSHans-Christian Egtvedt 	mutex_unlock(&opened_mutex);
2954ede028fSHans-Christian Egtvedt 
2964ede028fSHans-Christian Egtvedt 	return retval;
2974ede028fSHans-Christian Egtvedt }
2984ede028fSHans-Christian Egtvedt 
2994ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
3004ede028fSHans-Christian Egtvedt {
3014ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
3027177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
3034ede028fSHans-Christian Egtvedt 		if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
3044ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_free(chip->dma.tx_chan);
3057177395fSSedji Gaouaou 	}
3064ede028fSHans-Christian Egtvedt 	return snd_pcm_lib_free_pages(substream);
3074ede028fSHans-Christian Egtvedt }
3084ede028fSHans-Christian Egtvedt 
3094ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
3104ede028fSHans-Christian Egtvedt {
3114ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
3127177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
3134ede028fSHans-Christian Egtvedt 		if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
3144ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_free(chip->dma.rx_chan);
3157177395fSSedji Gaouaou 	}
3164ede028fSHans-Christian Egtvedt 	return snd_pcm_lib_free_pages(substream);
3174ede028fSHans-Christian Egtvedt }
3184ede028fSHans-Christian Egtvedt 
3194ede028fSHans-Christian Egtvedt static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
3204ede028fSHans-Christian Egtvedt {
3214ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
3224ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
3237177395fSSedji Gaouaou 	int block_size = frames_to_bytes(runtime, runtime->period_size);
324128ed6a9SHans-Christian Egtvedt 	unsigned long word = ac97c_readl(chip, OCA);
3254ede028fSHans-Christian Egtvedt 	int retval;
3264ede028fSHans-Christian Egtvedt 
3277177395fSSedji Gaouaou 	chip->playback_period = 0;
328128ed6a9SHans-Christian Egtvedt 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
329128ed6a9SHans-Christian Egtvedt 
3304ede028fSHans-Christian Egtvedt 	/* assign channels to AC97C channel A */
3314ede028fSHans-Christian Egtvedt 	switch (runtime->channels) {
3324ede028fSHans-Christian Egtvedt 	case 1:
3334ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
3344ede028fSHans-Christian Egtvedt 		break;
3354ede028fSHans-Christian Egtvedt 	case 2:
3364ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
3374ede028fSHans-Christian Egtvedt 			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
3384ede028fSHans-Christian Egtvedt 		break;
3394ede028fSHans-Christian Egtvedt 	default:
3404ede028fSHans-Christian Egtvedt 		/* TODO: support more than two channels */
3414ede028fSHans-Christian Egtvedt 		return -EINVAL;
3424ede028fSHans-Christian Egtvedt 	}
3434ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, OCA, word);
3444ede028fSHans-Christian Egtvedt 
3454ede028fSHans-Christian Egtvedt 	/* configure sample format and size */
346ec2755a9SSedji Gaouaou 	word = ac97c_readl(chip, CAMR);
347ec2755a9SSedji Gaouaou 	if (chip->opened <= 1)
3484ede028fSHans-Christian Egtvedt 		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
349ec2755a9SSedji Gaouaou 	else
350ec2755a9SSedji Gaouaou 		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
3514ede028fSHans-Christian Egtvedt 
3524ede028fSHans-Christian Egtvedt 	switch (runtime->format) {
3534ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_LE:
3547177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
3554ede028fSHans-Christian Egtvedt 			word |= AC97C_CMR_CEM_LITTLE;
3564ede028fSHans-Christian Egtvedt 		break;
3574ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
3584ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_CMR_CEM_LITTLE);
3594ede028fSHans-Christian Egtvedt 		break;
360128ed6a9SHans-Christian Egtvedt 	default:
361128ed6a9SHans-Christian Egtvedt 		word = ac97c_readl(chip, OCA);
362128ed6a9SHans-Christian Egtvedt 		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
363128ed6a9SHans-Christian Egtvedt 		ac97c_writel(chip, OCA, word);
364128ed6a9SHans-Christian Egtvedt 		return -EINVAL;
3654ede028fSHans-Christian Egtvedt 	}
3664ede028fSHans-Christian Egtvedt 
367df163587SHans-Christian Egtvedt 	/* Enable underrun interrupt on channel A */
368df163587SHans-Christian Egtvedt 	word |= AC97C_CSR_UNRUN;
369df163587SHans-Christian Egtvedt 
3704ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, word);
3714ede028fSHans-Christian Egtvedt 
372df163587SHans-Christian Egtvedt 	/* Enable channel A event interrupt */
373df163587SHans-Christian Egtvedt 	word = ac97c_readl(chip, IMR);
374df163587SHans-Christian Egtvedt 	word |= AC97C_SR_CAEVT;
375df163587SHans-Christian Egtvedt 	ac97c_writel(chip, IER, word);
376df163587SHans-Christian Egtvedt 
3774ede028fSHans-Christian Egtvedt 	/* set variable rate if needed */
3784ede028fSHans-Christian Egtvedt 	if (runtime->rate != 48000) {
3794ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
3804ede028fSHans-Christian Egtvedt 		word |= AC97C_MR_VRA;
3814ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
3824ede028fSHans-Christian Egtvedt 	} else {
3834ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
3844ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_MR_VRA);
3854ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
3864ede028fSHans-Christian Egtvedt 	}
3874ede028fSHans-Christian Egtvedt 
3884ede028fSHans-Christian Egtvedt 	retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
3894ede028fSHans-Christian Egtvedt 			runtime->rate);
3904ede028fSHans-Christian Egtvedt 	if (retval)
3914ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
3924ede028fSHans-Christian Egtvedt 				runtime->rate);
3934ede028fSHans-Christian Egtvedt 
3947177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
3954ede028fSHans-Christian Egtvedt 		if (!test_bit(DMA_TX_READY, &chip->flags))
3964ede028fSHans-Christian Egtvedt 			retval = atmel_ac97c_prepare_dma(chip, substream,
39735e16581SVinod Koul 					DMA_MEM_TO_DEV);
3987177395fSSedji Gaouaou 	} else {
3997177395fSSedji Gaouaou 		/* Initialize and start the PDC */
4007177395fSSedji Gaouaou 		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
4017177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
4027177395fSSedji Gaouaou 		writel(runtime->dma_addr + block_size,
4037177395fSSedji Gaouaou 				chip->regs + ATMEL_PDC_TNPR);
4047177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
4057177395fSSedji Gaouaou 	}
4064ede028fSHans-Christian Egtvedt 
4074ede028fSHans-Christian Egtvedt 	return retval;
4084ede028fSHans-Christian Egtvedt }
4094ede028fSHans-Christian Egtvedt 
4104ede028fSHans-Christian Egtvedt static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
4114ede028fSHans-Christian Egtvedt {
4124ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
4134ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime *runtime = substream->runtime;
4147177395fSSedji Gaouaou 	int block_size = frames_to_bytes(runtime, runtime->period_size);
415128ed6a9SHans-Christian Egtvedt 	unsigned long word = ac97c_readl(chip, ICA);
4164ede028fSHans-Christian Egtvedt 	int retval;
4174ede028fSHans-Christian Egtvedt 
4187177395fSSedji Gaouaou 	chip->capture_period = 0;
419128ed6a9SHans-Christian Egtvedt 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
420128ed6a9SHans-Christian Egtvedt 
4214ede028fSHans-Christian Egtvedt 	/* assign channels to AC97C channel A */
4224ede028fSHans-Christian Egtvedt 	switch (runtime->channels) {
4234ede028fSHans-Christian Egtvedt 	case 1:
4244ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
4254ede028fSHans-Christian Egtvedt 		break;
4264ede028fSHans-Christian Egtvedt 	case 2:
4274ede028fSHans-Christian Egtvedt 		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
4284ede028fSHans-Christian Egtvedt 			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
4294ede028fSHans-Christian Egtvedt 		break;
4304ede028fSHans-Christian Egtvedt 	default:
4314ede028fSHans-Christian Egtvedt 		/* TODO: support more than two channels */
4324ede028fSHans-Christian Egtvedt 		return -EINVAL;
4334ede028fSHans-Christian Egtvedt 	}
4344ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, ICA, word);
4354ede028fSHans-Christian Egtvedt 
4364ede028fSHans-Christian Egtvedt 	/* configure sample format and size */
437ec2755a9SSedji Gaouaou 	word = ac97c_readl(chip, CAMR);
438ec2755a9SSedji Gaouaou 	if (chip->opened <= 1)
4394ede028fSHans-Christian Egtvedt 		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
440ec2755a9SSedji Gaouaou 	else
441ec2755a9SSedji Gaouaou 		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
4424ede028fSHans-Christian Egtvedt 
4434ede028fSHans-Christian Egtvedt 	switch (runtime->format) {
4444ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_LE:
4457177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
4464ede028fSHans-Christian Egtvedt 			word |= AC97C_CMR_CEM_LITTLE;
4474ede028fSHans-Christian Egtvedt 		break;
4484ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
4494ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_CMR_CEM_LITTLE);
4504ede028fSHans-Christian Egtvedt 		break;
451128ed6a9SHans-Christian Egtvedt 	default:
452128ed6a9SHans-Christian Egtvedt 		word = ac97c_readl(chip, ICA);
453128ed6a9SHans-Christian Egtvedt 		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
454128ed6a9SHans-Christian Egtvedt 		ac97c_writel(chip, ICA, word);
455128ed6a9SHans-Christian Egtvedt 		return -EINVAL;
4564ede028fSHans-Christian Egtvedt 	}
4574ede028fSHans-Christian Egtvedt 
458df163587SHans-Christian Egtvedt 	/* Enable overrun interrupt on channel A */
459df163587SHans-Christian Egtvedt 	word |= AC97C_CSR_OVRUN;
460df163587SHans-Christian Egtvedt 
4614ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, word);
4624ede028fSHans-Christian Egtvedt 
463df163587SHans-Christian Egtvedt 	/* Enable channel A event interrupt */
464df163587SHans-Christian Egtvedt 	word = ac97c_readl(chip, IMR);
465df163587SHans-Christian Egtvedt 	word |= AC97C_SR_CAEVT;
466df163587SHans-Christian Egtvedt 	ac97c_writel(chip, IER, word);
467df163587SHans-Christian Egtvedt 
4684ede028fSHans-Christian Egtvedt 	/* set variable rate if needed */
4694ede028fSHans-Christian Egtvedt 	if (runtime->rate != 48000) {
4704ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
4714ede028fSHans-Christian Egtvedt 		word |= AC97C_MR_VRA;
4724ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
4734ede028fSHans-Christian Egtvedt 	} else {
4744ede028fSHans-Christian Egtvedt 		word = ac97c_readl(chip, MR);
4754ede028fSHans-Christian Egtvedt 		word &= ~(AC97C_MR_VRA);
4764ede028fSHans-Christian Egtvedt 		ac97c_writel(chip, MR, word);
4774ede028fSHans-Christian Egtvedt 	}
4784ede028fSHans-Christian Egtvedt 
4794ede028fSHans-Christian Egtvedt 	retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE,
4804ede028fSHans-Christian Egtvedt 			runtime->rate);
4814ede028fSHans-Christian Egtvedt 	if (retval)
4824ede028fSHans-Christian Egtvedt 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
4834ede028fSHans-Christian Egtvedt 				runtime->rate);
4844ede028fSHans-Christian Egtvedt 
4857177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
4864ede028fSHans-Christian Egtvedt 		if (!test_bit(DMA_RX_READY, &chip->flags))
4874ede028fSHans-Christian Egtvedt 			retval = atmel_ac97c_prepare_dma(chip, substream,
48835e16581SVinod Koul 					DMA_DEV_TO_MEM);
4897177395fSSedji Gaouaou 	} else {
4907177395fSSedji Gaouaou 		/* Initialize and start the PDC */
4917177395fSSedji Gaouaou 		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
4927177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
4937177395fSSedji Gaouaou 		writel(runtime->dma_addr + block_size,
4947177395fSSedji Gaouaou 				chip->regs + ATMEL_PDC_RNPR);
4957177395fSSedji Gaouaou 		writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
4967177395fSSedji Gaouaou 	}
4974ede028fSHans-Christian Egtvedt 
4984ede028fSHans-Christian Egtvedt 	return retval;
4994ede028fSHans-Christian Egtvedt }
5004ede028fSHans-Christian Egtvedt 
5014ede028fSHans-Christian Egtvedt static int
5024ede028fSHans-Christian Egtvedt atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
5034ede028fSHans-Christian Egtvedt {
5044ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
5057177395fSSedji Gaouaou 	unsigned long camr, ptcr = 0;
5064ede028fSHans-Christian Egtvedt 	int retval = 0;
5074ede028fSHans-Christian Egtvedt 
5084ede028fSHans-Christian Egtvedt 	camr = ac97c_readl(chip, CAMR);
5094ede028fSHans-Christian Egtvedt 
5104ede028fSHans-Christian Egtvedt 	switch (cmd) {
5114ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
5124ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
5134ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_START:
5147177395fSSedji Gaouaou 		if (cpu_is_at32ap7000()) {
5154ede028fSHans-Christian Egtvedt 			retval = dw_dma_cyclic_start(chip->dma.tx_chan);
5164ede028fSHans-Christian Egtvedt 			if (retval)
5174ede028fSHans-Christian Egtvedt 				goto out;
5187177395fSSedji Gaouaou 		} else {
5197177395fSSedji Gaouaou 			ptcr = ATMEL_PDC_TXTEN;
5207177395fSSedji Gaouaou 		}
521ec2755a9SSedji Gaouaou 		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
5224ede028fSHans-Christian Egtvedt 		break;
5234ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
5244ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
5254ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_STOP:
5267177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
5274ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.tx_chan);
5287177395fSSedji Gaouaou 		else
5297177395fSSedji Gaouaou 			ptcr |= ATMEL_PDC_TXTDIS;
5304ede028fSHans-Christian Egtvedt 		if (chip->opened <= 1)
5314ede028fSHans-Christian Egtvedt 			camr &= ~AC97C_CMR_CENA;
5324ede028fSHans-Christian Egtvedt 		break;
5334ede028fSHans-Christian Egtvedt 	default:
5344ede028fSHans-Christian Egtvedt 		retval = -EINVAL;
5354ede028fSHans-Christian Egtvedt 		goto out;
5364ede028fSHans-Christian Egtvedt 	}
5374ede028fSHans-Christian Egtvedt 
5384ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, camr);
5397177395fSSedji Gaouaou 	if (!cpu_is_at32ap7000())
5407177395fSSedji Gaouaou 		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
5414ede028fSHans-Christian Egtvedt out:
5424ede028fSHans-Christian Egtvedt 	return retval;
5434ede028fSHans-Christian Egtvedt }
5444ede028fSHans-Christian Egtvedt 
5454ede028fSHans-Christian Egtvedt static int
5464ede028fSHans-Christian Egtvedt atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
5474ede028fSHans-Christian Egtvedt {
5484ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
5497177395fSSedji Gaouaou 	unsigned long camr, ptcr = 0;
5504ede028fSHans-Christian Egtvedt 	int retval = 0;
5514ede028fSHans-Christian Egtvedt 
5524ede028fSHans-Christian Egtvedt 	camr = ac97c_readl(chip, CAMR);
5537177395fSSedji Gaouaou 	ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
5544ede028fSHans-Christian Egtvedt 
5554ede028fSHans-Christian Egtvedt 	switch (cmd) {
5564ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
5574ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
5584ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_START:
5597177395fSSedji Gaouaou 		if (cpu_is_at32ap7000()) {
5604ede028fSHans-Christian Egtvedt 			retval = dw_dma_cyclic_start(chip->dma.rx_chan);
5614ede028fSHans-Christian Egtvedt 			if (retval)
5624ede028fSHans-Christian Egtvedt 				goto out;
5637177395fSSedji Gaouaou 		} else {
5647177395fSSedji Gaouaou 			ptcr = ATMEL_PDC_RXTEN;
5657177395fSSedji Gaouaou 		}
566ec2755a9SSedji Gaouaou 		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
5674ede028fSHans-Christian Egtvedt 		break;
5684ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
5694ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
5704ede028fSHans-Christian Egtvedt 	case SNDRV_PCM_TRIGGER_STOP:
5717177395fSSedji Gaouaou 		if (cpu_is_at32ap7000())
5724ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.rx_chan);
5737177395fSSedji Gaouaou 		else
5747177395fSSedji Gaouaou 			ptcr |= (ATMEL_PDC_RXTDIS);
5754ede028fSHans-Christian Egtvedt 		if (chip->opened <= 1)
5764ede028fSHans-Christian Egtvedt 			camr &= ~AC97C_CMR_CENA;
5774ede028fSHans-Christian Egtvedt 		break;
5784ede028fSHans-Christian Egtvedt 	default:
5794ede028fSHans-Christian Egtvedt 		retval = -EINVAL;
5804ede028fSHans-Christian Egtvedt 		break;
5814ede028fSHans-Christian Egtvedt 	}
5824ede028fSHans-Christian Egtvedt 
5834ede028fSHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, camr);
5847177395fSSedji Gaouaou 	if (!cpu_is_at32ap7000())
5857177395fSSedji Gaouaou 		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
5864ede028fSHans-Christian Egtvedt out:
5874ede028fSHans-Christian Egtvedt 	return retval;
5884ede028fSHans-Christian Egtvedt }
5894ede028fSHans-Christian Egtvedt 
5904ede028fSHans-Christian Egtvedt static snd_pcm_uframes_t
5914ede028fSHans-Christian Egtvedt atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
5924ede028fSHans-Christian Egtvedt {
5934ede028fSHans-Christian Egtvedt 	struct atmel_ac97c	*chip = snd_pcm_substream_chip(substream);
5944ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime	*runtime = substream->runtime;
5954ede028fSHans-Christian Egtvedt 	snd_pcm_uframes_t	frames;
5964ede028fSHans-Christian Egtvedt 	unsigned long		bytes;
5974ede028fSHans-Christian Egtvedt 
5987177395fSSedji Gaouaou 	if (cpu_is_at32ap7000())
5994ede028fSHans-Christian Egtvedt 		bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
6007177395fSSedji Gaouaou 	else
6017177395fSSedji Gaouaou 		bytes = readl(chip->regs + ATMEL_PDC_TPR);
6024ede028fSHans-Christian Egtvedt 	bytes -= runtime->dma_addr;
6034ede028fSHans-Christian Egtvedt 
6044ede028fSHans-Christian Egtvedt 	frames = bytes_to_frames(runtime, bytes);
6054ede028fSHans-Christian Egtvedt 	if (frames >= runtime->buffer_size)
6064ede028fSHans-Christian Egtvedt 		frames -= runtime->buffer_size;
6074ede028fSHans-Christian Egtvedt 	return frames;
6084ede028fSHans-Christian Egtvedt }
6094ede028fSHans-Christian Egtvedt 
6104ede028fSHans-Christian Egtvedt static snd_pcm_uframes_t
6114ede028fSHans-Christian Egtvedt atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
6124ede028fSHans-Christian Egtvedt {
6134ede028fSHans-Christian Egtvedt 	struct atmel_ac97c	*chip = snd_pcm_substream_chip(substream);
6144ede028fSHans-Christian Egtvedt 	struct snd_pcm_runtime	*runtime = substream->runtime;
6154ede028fSHans-Christian Egtvedt 	snd_pcm_uframes_t	frames;
6164ede028fSHans-Christian Egtvedt 	unsigned long		bytes;
6174ede028fSHans-Christian Egtvedt 
6187177395fSSedji Gaouaou 	if (cpu_is_at32ap7000())
6194ede028fSHans-Christian Egtvedt 		bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
6207177395fSSedji Gaouaou 	else
6217177395fSSedji Gaouaou 		bytes = readl(chip->regs + ATMEL_PDC_RPR);
6224ede028fSHans-Christian Egtvedt 	bytes -= runtime->dma_addr;
6234ede028fSHans-Christian Egtvedt 
6244ede028fSHans-Christian Egtvedt 	frames = bytes_to_frames(runtime, bytes);
6254ede028fSHans-Christian Egtvedt 	if (frames >= runtime->buffer_size)
6264ede028fSHans-Christian Egtvedt 		frames -= runtime->buffer_size;
6274ede028fSHans-Christian Egtvedt 	return frames;
6284ede028fSHans-Christian Egtvedt }
6294ede028fSHans-Christian Egtvedt 
6304ede028fSHans-Christian Egtvedt static struct snd_pcm_ops atmel_ac97_playback_ops = {
6314ede028fSHans-Christian Egtvedt 	.open		= atmel_ac97c_playback_open,
6324ede028fSHans-Christian Egtvedt 	.close		= atmel_ac97c_playback_close,
6334ede028fSHans-Christian Egtvedt 	.ioctl		= snd_pcm_lib_ioctl,
6344ede028fSHans-Christian Egtvedt 	.hw_params	= atmel_ac97c_playback_hw_params,
6354ede028fSHans-Christian Egtvedt 	.hw_free	= atmel_ac97c_playback_hw_free,
6364ede028fSHans-Christian Egtvedt 	.prepare	= atmel_ac97c_playback_prepare,
6374ede028fSHans-Christian Egtvedt 	.trigger	= atmel_ac97c_playback_trigger,
6384ede028fSHans-Christian Egtvedt 	.pointer	= atmel_ac97c_playback_pointer,
6394ede028fSHans-Christian Egtvedt };
6404ede028fSHans-Christian Egtvedt 
6414ede028fSHans-Christian Egtvedt static struct snd_pcm_ops atmel_ac97_capture_ops = {
6424ede028fSHans-Christian Egtvedt 	.open		= atmel_ac97c_capture_open,
6434ede028fSHans-Christian Egtvedt 	.close		= atmel_ac97c_capture_close,
6444ede028fSHans-Christian Egtvedt 	.ioctl		= snd_pcm_lib_ioctl,
6454ede028fSHans-Christian Egtvedt 	.hw_params	= atmel_ac97c_capture_hw_params,
6464ede028fSHans-Christian Egtvedt 	.hw_free	= atmel_ac97c_capture_hw_free,
6474ede028fSHans-Christian Egtvedt 	.prepare	= atmel_ac97c_capture_prepare,
6484ede028fSHans-Christian Egtvedt 	.trigger	= atmel_ac97c_capture_trigger,
6494ede028fSHans-Christian Egtvedt 	.pointer	= atmel_ac97c_capture_pointer,
6504ede028fSHans-Christian Egtvedt };
6514ede028fSHans-Christian Egtvedt 
652df163587SHans-Christian Egtvedt static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
653df163587SHans-Christian Egtvedt {
654df163587SHans-Christian Egtvedt 	struct atmel_ac97c	*chip  = (struct atmel_ac97c *)dev;
655df163587SHans-Christian Egtvedt 	irqreturn_t		retval = IRQ_NONE;
656df163587SHans-Christian Egtvedt 	u32			sr     = ac97c_readl(chip, SR);
657df163587SHans-Christian Egtvedt 	u32			casr   = ac97c_readl(chip, CASR);
658df163587SHans-Christian Egtvedt 	u32			cosr   = ac97c_readl(chip, COSR);
6597177395fSSedji Gaouaou 	u32			camr   = ac97c_readl(chip, CAMR);
660df163587SHans-Christian Egtvedt 
661df163587SHans-Christian Egtvedt 	if (sr & AC97C_SR_CAEVT) {
6627177395fSSedji Gaouaou 		struct snd_pcm_runtime *runtime;
6637177395fSSedji Gaouaou 		int offset, next_period, block_size;
664f5341163SYegor Yefremov 		dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
665df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
666df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
667df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_UNRUN   ? " UNRUN"   : "",
668df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
669df163587SHans-Christian Egtvedt 				casr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
670df163587SHans-Christian Egtvedt 				!casr                    ? " NONE"    : "");
6717177395fSSedji Gaouaou 		if (!cpu_is_at32ap7000()) {
6727177395fSSedji Gaouaou 			if ((casr & camr) & AC97C_CSR_ENDTX) {
6737177395fSSedji Gaouaou 				runtime = chip->playback_substream->runtime;
6747177395fSSedji Gaouaou 				block_size = frames_to_bytes(runtime,
6757177395fSSedji Gaouaou 						runtime->period_size);
6767177395fSSedji Gaouaou 				chip->playback_period++;
6777177395fSSedji Gaouaou 
6787177395fSSedji Gaouaou 				if (chip->playback_period == runtime->periods)
6797177395fSSedji Gaouaou 					chip->playback_period = 0;
6807177395fSSedji Gaouaou 				next_period = chip->playback_period + 1;
6817177395fSSedji Gaouaou 				if (next_period == runtime->periods)
6827177395fSSedji Gaouaou 					next_period = 0;
6837177395fSSedji Gaouaou 
6847177395fSSedji Gaouaou 				offset = block_size * next_period;
6857177395fSSedji Gaouaou 
6867177395fSSedji Gaouaou 				writel(runtime->dma_addr + offset,
6877177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_TNPR);
6887177395fSSedji Gaouaou 				writel(block_size / 2,
6897177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_TNCR);
6907177395fSSedji Gaouaou 
6917177395fSSedji Gaouaou 				snd_pcm_period_elapsed(
6927177395fSSedji Gaouaou 						chip->playback_substream);
6937177395fSSedji Gaouaou 			}
6947177395fSSedji Gaouaou 			if ((casr & camr) & AC97C_CSR_ENDRX) {
6957177395fSSedji Gaouaou 				runtime = chip->capture_substream->runtime;
6967177395fSSedji Gaouaou 				block_size = frames_to_bytes(runtime,
6977177395fSSedji Gaouaou 						runtime->period_size);
6987177395fSSedji Gaouaou 				chip->capture_period++;
6997177395fSSedji Gaouaou 
7007177395fSSedji Gaouaou 				if (chip->capture_period == runtime->periods)
7017177395fSSedji Gaouaou 					chip->capture_period = 0;
7027177395fSSedji Gaouaou 				next_period = chip->capture_period + 1;
7037177395fSSedji Gaouaou 				if (next_period == runtime->periods)
7047177395fSSedji Gaouaou 					next_period = 0;
7057177395fSSedji Gaouaou 
7067177395fSSedji Gaouaou 				offset = block_size * next_period;
7077177395fSSedji Gaouaou 
7087177395fSSedji Gaouaou 				writel(runtime->dma_addr + offset,
7097177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_RNPR);
7107177395fSSedji Gaouaou 				writel(block_size / 2,
7117177395fSSedji Gaouaou 						chip->regs + ATMEL_PDC_RNCR);
7127177395fSSedji Gaouaou 				snd_pcm_period_elapsed(chip->capture_substream);
7137177395fSSedji Gaouaou 			}
7147177395fSSedji Gaouaou 		}
715df163587SHans-Christian Egtvedt 		retval = IRQ_HANDLED;
716df163587SHans-Christian Egtvedt 	}
717df163587SHans-Christian Egtvedt 
718df163587SHans-Christian Egtvedt 	if (sr & AC97C_SR_COEVT) {
719df163587SHans-Christian Egtvedt 		dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
720df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
721df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
722df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
723df163587SHans-Christian Egtvedt 				cosr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
724df163587SHans-Christian Egtvedt 				!cosr                    ? " NONE"    : "");
725df163587SHans-Christian Egtvedt 		retval = IRQ_HANDLED;
726df163587SHans-Christian Egtvedt 	}
727df163587SHans-Christian Egtvedt 
728df163587SHans-Christian Egtvedt 	if (retval == IRQ_NONE) {
729df163587SHans-Christian Egtvedt 		dev_err(&chip->pdev->dev, "spurious interrupt sr 0x%08x "
730df163587SHans-Christian Egtvedt 				"casr 0x%08x cosr 0x%08x\n", sr, casr, cosr);
731df163587SHans-Christian Egtvedt 	}
732df163587SHans-Christian Egtvedt 
733df163587SHans-Christian Egtvedt 	return retval;
734df163587SHans-Christian Egtvedt }
735df163587SHans-Christian Egtvedt 
7367177395fSSedji Gaouaou static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = {
7377177395fSSedji Gaouaou 	/* Playback */
7387177395fSSedji Gaouaou 	{
7397177395fSSedji Gaouaou 		.exclusive = 1,
7407177395fSSedji Gaouaou 		.r = { {
7417177395fSSedji Gaouaou 			.slots = ((1 << AC97_SLOT_PCM_LEFT)
7427177395fSSedji Gaouaou 				  | (1 << AC97_SLOT_PCM_RIGHT)),
7437177395fSSedji Gaouaou 		} },
7447177395fSSedji Gaouaou 	},
7457177395fSSedji Gaouaou 	/* PCM in */
7467177395fSSedji Gaouaou 	{
7477177395fSSedji Gaouaou 		.stream = 1,
7487177395fSSedji Gaouaou 		.exclusive = 1,
7497177395fSSedji Gaouaou 		.r = { {
7507177395fSSedji Gaouaou 			.slots = ((1 << AC97_SLOT_PCM_LEFT)
7517177395fSSedji Gaouaou 					| (1 << AC97_SLOT_PCM_RIGHT)),
7527177395fSSedji Gaouaou 		} }
7537177395fSSedji Gaouaou 	},
7547177395fSSedji Gaouaou 	/* Mic in */
7557177395fSSedji Gaouaou 	{
7567177395fSSedji Gaouaou 		.stream = 1,
7577177395fSSedji Gaouaou 		.exclusive = 1,
7587177395fSSedji Gaouaou 		.r = { {
7597177395fSSedji Gaouaou 			.slots = (1<<AC97_SLOT_MIC),
7607177395fSSedji Gaouaou 		} }
7617177395fSSedji Gaouaou 	},
7627177395fSSedji Gaouaou };
7637177395fSSedji Gaouaou 
7644ede028fSHans-Christian Egtvedt static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
7654ede028fSHans-Christian Egtvedt {
7664ede028fSHans-Christian Egtvedt 	struct snd_pcm		*pcm;
7674ede028fSHans-Christian Egtvedt 	struct snd_pcm_hardware	hw = atmel_ac97c_hw;
7687177395fSSedji Gaouaou 	int			capture, playback, retval, err;
7694ede028fSHans-Christian Egtvedt 
7704ede028fSHans-Christian Egtvedt 	capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
7714ede028fSHans-Christian Egtvedt 	playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
7724ede028fSHans-Christian Egtvedt 
7737177395fSSedji Gaouaou 	if (!cpu_is_at32ap7000()) {
7747177395fSSedji Gaouaou 		err = snd_ac97_pcm_assign(chip->ac97_bus,
7757177395fSSedji Gaouaou 				ARRAY_SIZE(at91_ac97_pcm_defs),
7767177395fSSedji Gaouaou 				at91_ac97_pcm_defs);
7777177395fSSedji Gaouaou 		if (err)
7787177395fSSedji Gaouaou 			return err;
7797177395fSSedji Gaouaou 	}
7804ede028fSHans-Christian Egtvedt 	retval = snd_pcm_new(chip->card, chip->card->shortname,
7814ede028fSHans-Christian Egtvedt 			chip->pdev->id, playback, capture, &pcm);
7824ede028fSHans-Christian Egtvedt 	if (retval)
7834ede028fSHans-Christian Egtvedt 		return retval;
7844ede028fSHans-Christian Egtvedt 
7854ede028fSHans-Christian Egtvedt 	if (capture)
7864ede028fSHans-Christian Egtvedt 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
7874ede028fSHans-Christian Egtvedt 				&atmel_ac97_capture_ops);
7884ede028fSHans-Christian Egtvedt 	if (playback)
7894ede028fSHans-Christian Egtvedt 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
7904ede028fSHans-Christian Egtvedt 				&atmel_ac97_playback_ops);
7914ede028fSHans-Christian Egtvedt 
7924ede028fSHans-Christian Egtvedt 	retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
7934ede028fSHans-Christian Egtvedt 			&chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
7944ede028fSHans-Christian Egtvedt 			hw.buffer_bytes_max);
7954ede028fSHans-Christian Egtvedt 	if (retval)
7964ede028fSHans-Christian Egtvedt 		return retval;
7974ede028fSHans-Christian Egtvedt 
7984ede028fSHans-Christian Egtvedt 	pcm->private_data = chip;
7994ede028fSHans-Christian Egtvedt 	pcm->info_flags = 0;
8004ede028fSHans-Christian Egtvedt 	strcpy(pcm->name, chip->card->shortname);
8014ede028fSHans-Christian Egtvedt 	chip->pcm = pcm;
8024ede028fSHans-Christian Egtvedt 
8034ede028fSHans-Christian Egtvedt 	return 0;
8044ede028fSHans-Christian Egtvedt }
8054ede028fSHans-Christian Egtvedt 
8064ede028fSHans-Christian Egtvedt static int atmel_ac97c_mixer_new(struct atmel_ac97c *chip)
8074ede028fSHans-Christian Egtvedt {
8084ede028fSHans-Christian Egtvedt 	struct snd_ac97_template template;
8094ede028fSHans-Christian Egtvedt 	memset(&template, 0, sizeof(template));
8104ede028fSHans-Christian Egtvedt 	template.private_data = chip;
8114ede028fSHans-Christian Egtvedt 	return snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
8124ede028fSHans-Christian Egtvedt }
8134ede028fSHans-Christian Egtvedt 
8144ede028fSHans-Christian Egtvedt static void atmel_ac97c_write(struct snd_ac97 *ac97, unsigned short reg,
8154ede028fSHans-Christian Egtvedt 		unsigned short val)
8164ede028fSHans-Christian Egtvedt {
8174ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = get_chip(ac97);
8184ede028fSHans-Christian Egtvedt 	unsigned long word;
8194ede028fSHans-Christian Egtvedt 	int timeout = 40;
8204ede028fSHans-Christian Egtvedt 
8214ede028fSHans-Christian Egtvedt 	word = (reg & 0x7f) << 16 | val;
8224ede028fSHans-Christian Egtvedt 
8234ede028fSHans-Christian Egtvedt 	do {
8244ede028fSHans-Christian Egtvedt 		if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
8254ede028fSHans-Christian Egtvedt 			ac97c_writel(chip, COTHR, word);
8264ede028fSHans-Christian Egtvedt 			return;
8274ede028fSHans-Christian Egtvedt 		}
8284ede028fSHans-Christian Egtvedt 		udelay(1);
8294ede028fSHans-Christian Egtvedt 	} while (--timeout);
8304ede028fSHans-Christian Egtvedt 
8314ede028fSHans-Christian Egtvedt 	dev_dbg(&chip->pdev->dev, "codec write timeout\n");
8324ede028fSHans-Christian Egtvedt }
8334ede028fSHans-Christian Egtvedt 
8344ede028fSHans-Christian Egtvedt static unsigned short atmel_ac97c_read(struct snd_ac97 *ac97,
8354ede028fSHans-Christian Egtvedt 		unsigned short reg)
8364ede028fSHans-Christian Egtvedt {
8374ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = get_chip(ac97);
8384ede028fSHans-Christian Egtvedt 	unsigned long word;
8394ede028fSHans-Christian Egtvedt 	int timeout = 40;
8404ede028fSHans-Christian Egtvedt 	int write = 10;
8414ede028fSHans-Christian Egtvedt 
8424ede028fSHans-Christian Egtvedt 	word = (0x80 | (reg & 0x7f)) << 16;
8434ede028fSHans-Christian Egtvedt 
8444ede028fSHans-Christian Egtvedt 	if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
8454ede028fSHans-Christian Egtvedt 		ac97c_readl(chip, CORHR);
8464ede028fSHans-Christian Egtvedt 
8474ede028fSHans-Christian Egtvedt retry_write:
8484ede028fSHans-Christian Egtvedt 	timeout = 40;
8494ede028fSHans-Christian Egtvedt 
8504ede028fSHans-Christian Egtvedt 	do {
8514ede028fSHans-Christian Egtvedt 		if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
8524ede028fSHans-Christian Egtvedt 			ac97c_writel(chip, COTHR, word);
8534ede028fSHans-Christian Egtvedt 			goto read_reg;
8544ede028fSHans-Christian Egtvedt 		}
8554ede028fSHans-Christian Egtvedt 		udelay(10);
8564ede028fSHans-Christian Egtvedt 	} while (--timeout);
8574ede028fSHans-Christian Egtvedt 
8584ede028fSHans-Christian Egtvedt 	if (!--write)
8594ede028fSHans-Christian Egtvedt 		goto timed_out;
8604ede028fSHans-Christian Egtvedt 	goto retry_write;
8614ede028fSHans-Christian Egtvedt 
8624ede028fSHans-Christian Egtvedt read_reg:
8634ede028fSHans-Christian Egtvedt 	do {
8644ede028fSHans-Christian Egtvedt 		if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) {
8654ede028fSHans-Christian Egtvedt 			unsigned short val = ac97c_readl(chip, CORHR);
8664ede028fSHans-Christian Egtvedt 			return val;
8674ede028fSHans-Christian Egtvedt 		}
8684ede028fSHans-Christian Egtvedt 		udelay(10);
8694ede028fSHans-Christian Egtvedt 	} while (--timeout);
8704ede028fSHans-Christian Egtvedt 
8714ede028fSHans-Christian Egtvedt 	if (!--write)
8724ede028fSHans-Christian Egtvedt 		goto timed_out;
8734ede028fSHans-Christian Egtvedt 	goto retry_write;
8744ede028fSHans-Christian Egtvedt 
8754ede028fSHans-Christian Egtvedt timed_out:
8764ede028fSHans-Christian Egtvedt 	dev_dbg(&chip->pdev->dev, "codec read timeout\n");
8774ede028fSHans-Christian Egtvedt 	return 0xffff;
8784ede028fSHans-Christian Egtvedt }
8794ede028fSHans-Christian Egtvedt 
8804ede028fSHans-Christian Egtvedt static bool filter(struct dma_chan *chan, void *slave)
8814ede028fSHans-Christian Egtvedt {
8824ede028fSHans-Christian Egtvedt 	struct dw_dma_slave *dws = slave;
8834ede028fSHans-Christian Egtvedt 
8844ede028fSHans-Christian Egtvedt 	if (dws->dma_dev == chan->device->dev) {
8854ede028fSHans-Christian Egtvedt 		chan->private = dws;
8864ede028fSHans-Christian Egtvedt 		return true;
8874ede028fSHans-Christian Egtvedt 	} else
8884ede028fSHans-Christian Egtvedt 		return false;
8894ede028fSHans-Christian Egtvedt }
8904ede028fSHans-Christian Egtvedt 
8914ede028fSHans-Christian Egtvedt static void atmel_ac97c_reset(struct atmel_ac97c *chip)
8924ede028fSHans-Christian Egtvedt {
89381baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, MR,   0);
89481baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, MR,   AC97C_MR_ENA);
89581baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, 0);
89681baf3a7SHans-Christian Egtvedt 	ac97c_writel(chip, COMR, 0);
8974ede028fSHans-Christian Egtvedt 
8984ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(chip->reset_pin)) {
8994ede028fSHans-Christian Egtvedt 		gpio_set_value(chip->reset_pin, 0);
9004ede028fSHans-Christian Egtvedt 		/* AC97 v2.2 specifications says minimum 1 us. */
90181baf3a7SHans-Christian Egtvedt 		udelay(2);
9024ede028fSHans-Christian Egtvedt 		gpio_set_value(chip->reset_pin, 1);
9038015e3deSBo Shen 	} else {
9048015e3deSBo Shen 		ac97c_writel(chip, MR, AC97C_MR_WRST | AC97C_MR_ENA);
9058015e3deSBo Shen 		udelay(2);
9068015e3deSBo Shen 		ac97c_writel(chip, MR, AC97C_MR_ENA);
9074ede028fSHans-Christian Egtvedt 	}
9084ede028fSHans-Christian Egtvedt }
9094ede028fSHans-Christian Egtvedt 
9104ede028fSHans-Christian Egtvedt static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
9114ede028fSHans-Christian Egtvedt {
9124ede028fSHans-Christian Egtvedt 	struct snd_card			*card;
9134ede028fSHans-Christian Egtvedt 	struct atmel_ac97c		*chip;
9144ede028fSHans-Christian Egtvedt 	struct resource			*regs;
9154ede028fSHans-Christian Egtvedt 	struct ac97c_platform_data	*pdata;
9164ede028fSHans-Christian Egtvedt 	struct clk			*pclk;
9174ede028fSHans-Christian Egtvedt 	static struct snd_ac97_bus_ops	ops = {
9184ede028fSHans-Christian Egtvedt 		.write	= atmel_ac97c_write,
9194ede028fSHans-Christian Egtvedt 		.read	= atmel_ac97c_read,
9204ede028fSHans-Christian Egtvedt 	};
9214ede028fSHans-Christian Egtvedt 	int				retval;
922df163587SHans-Christian Egtvedt 	int				irq;
9234ede028fSHans-Christian Egtvedt 
9244ede028fSHans-Christian Egtvedt 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9254ede028fSHans-Christian Egtvedt 	if (!regs) {
9264ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "no memory resource\n");
9274ede028fSHans-Christian Egtvedt 		return -ENXIO;
9284ede028fSHans-Christian Egtvedt 	}
9294ede028fSHans-Christian Egtvedt 
9304ede028fSHans-Christian Egtvedt 	pdata = pdev->dev.platform_data;
9314ede028fSHans-Christian Egtvedt 	if (!pdata) {
9324ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "no platform data\n");
9334ede028fSHans-Christian Egtvedt 		return -ENXIO;
9344ede028fSHans-Christian Egtvedt 	}
9354ede028fSHans-Christian Egtvedt 
936df163587SHans-Christian Egtvedt 	irq = platform_get_irq(pdev, 0);
937df163587SHans-Christian Egtvedt 	if (irq < 0) {
938df163587SHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not get irq\n");
939df163587SHans-Christian Egtvedt 		return -ENXIO;
940df163587SHans-Christian Egtvedt 	}
941df163587SHans-Christian Egtvedt 
9427177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
9434ede028fSHans-Christian Egtvedt 		pclk = clk_get(&pdev->dev, "pclk");
9447177395fSSedji Gaouaou 	} else {
9457177395fSSedji Gaouaou 		pclk = clk_get(&pdev->dev, "ac97_clk");
9467177395fSSedji Gaouaou 	}
9477177395fSSedji Gaouaou 
9484ede028fSHans-Christian Egtvedt 	if (IS_ERR(pclk)) {
9494ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "no peripheral clock\n");
9504ede028fSHans-Christian Egtvedt 		return PTR_ERR(pclk);
9514ede028fSHans-Christian Egtvedt 	}
9524ede028fSHans-Christian Egtvedt 	clk_enable(pclk);
9534ede028fSHans-Christian Egtvedt 
9544ede028fSHans-Christian Egtvedt 	retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
9554ede028fSHans-Christian Egtvedt 			THIS_MODULE, sizeof(struct atmel_ac97c), &card);
9564ede028fSHans-Christian Egtvedt 	if (retval) {
9574ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not create sound card device\n");
9584ede028fSHans-Christian Egtvedt 		goto err_snd_card_new;
9594ede028fSHans-Christian Egtvedt 	}
9604ede028fSHans-Christian Egtvedt 
9614ede028fSHans-Christian Egtvedt 	chip = get_chip(card);
9624ede028fSHans-Christian Egtvedt 
963df163587SHans-Christian Egtvedt 	retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
964df163587SHans-Christian Egtvedt 	if (retval) {
965df163587SHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "unable to request irq %d\n", irq);
966df163587SHans-Christian Egtvedt 		goto err_request_irq;
967df163587SHans-Christian Egtvedt 	}
968df163587SHans-Christian Egtvedt 	chip->irq = irq;
969df163587SHans-Christian Egtvedt 
9704ede028fSHans-Christian Egtvedt 	spin_lock_init(&chip->lock);
9714ede028fSHans-Christian Egtvedt 
9724ede028fSHans-Christian Egtvedt 	strcpy(card->driver, "Atmel AC97C");
9734ede028fSHans-Christian Egtvedt 	strcpy(card->shortname, "Atmel AC97C");
9744ede028fSHans-Christian Egtvedt 	sprintf(card->longname, "Atmel AC97 controller");
9754ede028fSHans-Christian Egtvedt 
9764ede028fSHans-Christian Egtvedt 	chip->card = card;
9774ede028fSHans-Christian Egtvedt 	chip->pclk = pclk;
9784ede028fSHans-Christian Egtvedt 	chip->pdev = pdev;
97928f65c11SJoe Perches 	chip->regs = ioremap(regs->start, resource_size(regs));
9804ede028fSHans-Christian Egtvedt 
9814ede028fSHans-Christian Egtvedt 	if (!chip->regs) {
9824ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not remap register memory\n");
9834ede028fSHans-Christian Egtvedt 		goto err_ioremap;
9844ede028fSHans-Christian Egtvedt 	}
9854ede028fSHans-Christian Egtvedt 
9864ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(pdata->reset_pin)) {
9874ede028fSHans-Christian Egtvedt 		if (gpio_request(pdata->reset_pin, "reset_pin")) {
9884ede028fSHans-Christian Egtvedt 			dev_dbg(&pdev->dev, "reset pin not available\n");
9894ede028fSHans-Christian Egtvedt 			chip->reset_pin = -ENODEV;
9904ede028fSHans-Christian Egtvedt 		} else {
9914ede028fSHans-Christian Egtvedt 			gpio_direction_output(pdata->reset_pin, 1);
9924ede028fSHans-Christian Egtvedt 			chip->reset_pin = pdata->reset_pin;
9934ede028fSHans-Christian Egtvedt 		}
994b2522f92SBo Shen 	} else {
995b2522f92SBo Shen 		chip->reset_pin = -EINVAL;
9964ede028fSHans-Christian Egtvedt 	}
9974ede028fSHans-Christian Egtvedt 
9984ede028fSHans-Christian Egtvedt 	snd_card_set_dev(card, &pdev->dev);
9994ede028fSHans-Christian Egtvedt 
100081baf3a7SHans-Christian Egtvedt 	atmel_ac97c_reset(chip);
100181baf3a7SHans-Christian Egtvedt 
1002df163587SHans-Christian Egtvedt 	/* Enable overrun interrupt from codec channel */
1003df163587SHans-Christian Egtvedt 	ac97c_writel(chip, COMR, AC97C_CSR_OVRUN);
1004df163587SHans-Christian Egtvedt 	ac97c_writel(chip, IER, ac97c_readl(chip, IMR) | AC97C_SR_COEVT);
1005df163587SHans-Christian Egtvedt 
10064ede028fSHans-Christian Egtvedt 	retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
10074ede028fSHans-Christian Egtvedt 	if (retval) {
10084ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
10094ede028fSHans-Christian Egtvedt 		goto err_ac97_bus;
10104ede028fSHans-Christian Egtvedt 	}
10114ede028fSHans-Christian Egtvedt 
10124ede028fSHans-Christian Egtvedt 	retval = atmel_ac97c_mixer_new(chip);
10134ede028fSHans-Christian Egtvedt 	if (retval) {
10144ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
10154ede028fSHans-Christian Egtvedt 		goto err_ac97_bus;
10164ede028fSHans-Christian Egtvedt 	}
10174ede028fSHans-Christian Egtvedt 
10187177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
10194ede028fSHans-Christian Egtvedt 		if (pdata->rx_dws.dma_dev) {
10204ede028fSHans-Christian Egtvedt 			dma_cap_mask_t mask;
10214ede028fSHans-Christian Egtvedt 
10224ede028fSHans-Christian Egtvedt 			dma_cap_zero(mask);
10234ede028fSHans-Christian Egtvedt 			dma_cap_set(DMA_SLAVE, mask);
10244ede028fSHans-Christian Egtvedt 
10257177395fSSedji Gaouaou 			chip->dma.rx_chan = dma_request_channel(mask, filter,
1026e2b35f3dSViresh Kumar 								&pdata->rx_dws);
1027e2b35f3dSViresh Kumar 			if (chip->dma.rx_chan) {
1028e2b35f3dSViresh Kumar 				struct dma_slave_config dma_conf = {
1029e2b35f3dSViresh Kumar 					.src_addr = regs->start + AC97C_CARHR +
1030e2b35f3dSViresh Kumar 						2,
1031e2b35f3dSViresh Kumar 					.src_addr_width =
1032e2b35f3dSViresh Kumar 						DMA_SLAVE_BUSWIDTH_2_BYTES,
1033e2b35f3dSViresh Kumar 					.src_maxburst = 1,
1034e2b35f3dSViresh Kumar 					.dst_maxburst = 1,
1035e2b35f3dSViresh Kumar 					.direction = DMA_DEV_TO_MEM,
1036e2b35f3dSViresh Kumar 					.device_fc = false,
1037e2b35f3dSViresh Kumar 				};
1038e2b35f3dSViresh Kumar 
1039e2b35f3dSViresh Kumar 				dmaengine_slave_config(chip->dma.rx_chan,
1040e2b35f3dSViresh Kumar 						&dma_conf);
1041e2b35f3dSViresh Kumar 			}
10424ede028fSHans-Christian Egtvedt 
10434ede028fSHans-Christian Egtvedt 			dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
104423572856SHans-Christian Egtvedt 				dev_name(&chip->dma.rx_chan->dev->device));
10454ede028fSHans-Christian Egtvedt 			set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
10464ede028fSHans-Christian Egtvedt 		}
10474ede028fSHans-Christian Egtvedt 
10484ede028fSHans-Christian Egtvedt 		if (pdata->tx_dws.dma_dev) {
10494ede028fSHans-Christian Egtvedt 			dma_cap_mask_t mask;
10504ede028fSHans-Christian Egtvedt 
10514ede028fSHans-Christian Egtvedt 			dma_cap_zero(mask);
10524ede028fSHans-Christian Egtvedt 			dma_cap_set(DMA_SLAVE, mask);
10534ede028fSHans-Christian Egtvedt 
10547177395fSSedji Gaouaou 			chip->dma.tx_chan = dma_request_channel(mask, filter,
1055e2b35f3dSViresh Kumar 								&pdata->tx_dws);
1056e2b35f3dSViresh Kumar 			if (chip->dma.tx_chan) {
1057e2b35f3dSViresh Kumar 				struct dma_slave_config dma_conf = {
1058e2b35f3dSViresh Kumar 					.dst_addr = regs->start + AC97C_CATHR +
1059e2b35f3dSViresh Kumar 						2,
1060e2b35f3dSViresh Kumar 					.dst_addr_width =
1061e2b35f3dSViresh Kumar 						DMA_SLAVE_BUSWIDTH_2_BYTES,
1062e2b35f3dSViresh Kumar 					.src_maxburst = 1,
1063e2b35f3dSViresh Kumar 					.dst_maxburst = 1,
1064e2b35f3dSViresh Kumar 					.direction = DMA_MEM_TO_DEV,
1065e2b35f3dSViresh Kumar 					.device_fc = false,
1066e2b35f3dSViresh Kumar 				};
1067e2b35f3dSViresh Kumar 
1068e2b35f3dSViresh Kumar 				dmaengine_slave_config(chip->dma.tx_chan,
1069e2b35f3dSViresh Kumar 						&dma_conf);
1070e2b35f3dSViresh Kumar 			}
10714ede028fSHans-Christian Egtvedt 
10724ede028fSHans-Christian Egtvedt 			dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
107323572856SHans-Christian Egtvedt 				dev_name(&chip->dma.tx_chan->dev->device));
10744ede028fSHans-Christian Egtvedt 			set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
10754ede028fSHans-Christian Egtvedt 		}
10764ede028fSHans-Christian Egtvedt 
10774ede028fSHans-Christian Egtvedt 		if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
10784ede028fSHans-Christian Egtvedt 				!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
10794ede028fSHans-Christian Egtvedt 			dev_dbg(&pdev->dev, "DMA not available\n");
10804ede028fSHans-Christian Egtvedt 			retval = -ENODEV;
10814ede028fSHans-Christian Egtvedt 			goto err_dma;
10824ede028fSHans-Christian Egtvedt 		}
10837177395fSSedji Gaouaou 	} else {
10847177395fSSedji Gaouaou 		/* Just pretend that we have DMA channel(for at91 i is actually
10857177395fSSedji Gaouaou 		 * the PDC) */
10867177395fSSedji Gaouaou 		set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
10877177395fSSedji Gaouaou 		set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
10887177395fSSedji Gaouaou 	}
10894ede028fSHans-Christian Egtvedt 
10904ede028fSHans-Christian Egtvedt 	retval = atmel_ac97c_pcm_new(chip);
10914ede028fSHans-Christian Egtvedt 	if (retval) {
10924ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
10934ede028fSHans-Christian Egtvedt 		goto err_dma;
10944ede028fSHans-Christian Egtvedt 	}
10954ede028fSHans-Christian Egtvedt 
10964ede028fSHans-Christian Egtvedt 	retval = snd_card_register(card);
10974ede028fSHans-Christian Egtvedt 	if (retval) {
10984ede028fSHans-Christian Egtvedt 		dev_dbg(&pdev->dev, "could not register sound card\n");
1099df163587SHans-Christian Egtvedt 		goto err_dma;
11004ede028fSHans-Christian Egtvedt 	}
11014ede028fSHans-Christian Egtvedt 
11024ede028fSHans-Christian Egtvedt 	platform_set_drvdata(pdev, card);
11034ede028fSHans-Christian Egtvedt 
11047177395fSSedji Gaouaou 	dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n",
11057177395fSSedji Gaouaou 			chip->regs, irq);
11064ede028fSHans-Christian Egtvedt 
11074ede028fSHans-Christian Egtvedt 	return 0;
11084ede028fSHans-Christian Egtvedt 
11094ede028fSHans-Christian Egtvedt err_dma:
11107177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11114ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
11124ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.rx_chan);
11134ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
11144ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.tx_chan);
11154ede028fSHans-Christian Egtvedt 		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
11164ede028fSHans-Christian Egtvedt 		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
11174ede028fSHans-Christian Egtvedt 		chip->dma.rx_chan = NULL;
11184ede028fSHans-Christian Egtvedt 		chip->dma.tx_chan = NULL;
11197177395fSSedji Gaouaou 	}
11204ede028fSHans-Christian Egtvedt err_ac97_bus:
11214ede028fSHans-Christian Egtvedt 	snd_card_set_dev(card, NULL);
11224ede028fSHans-Christian Egtvedt 
11234ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(chip->reset_pin))
11244ede028fSHans-Christian Egtvedt 		gpio_free(chip->reset_pin);
11254ede028fSHans-Christian Egtvedt 
11264ede028fSHans-Christian Egtvedt 	iounmap(chip->regs);
11274ede028fSHans-Christian Egtvedt err_ioremap:
1128df163587SHans-Christian Egtvedt 	free_irq(irq, chip);
1129df163587SHans-Christian Egtvedt err_request_irq:
11304ede028fSHans-Christian Egtvedt 	snd_card_free(card);
11314ede028fSHans-Christian Egtvedt err_snd_card_new:
11324ede028fSHans-Christian Egtvedt 	clk_disable(pclk);
11334ede028fSHans-Christian Egtvedt 	clk_put(pclk);
11344ede028fSHans-Christian Egtvedt 	return retval;
11354ede028fSHans-Christian Egtvedt }
11364ede028fSHans-Christian Egtvedt 
11374ede028fSHans-Christian Egtvedt #ifdef CONFIG_PM
11384ede028fSHans-Christian Egtvedt static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg)
11394ede028fSHans-Christian Egtvedt {
11404ede028fSHans-Christian Egtvedt 	struct snd_card *card = platform_get_drvdata(pdev);
11414ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = card->private_data;
11424ede028fSHans-Christian Egtvedt 
11437177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11444ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_READY, &chip->flags))
11454ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.rx_chan);
11464ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_READY, &chip->flags))
11474ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_stop(chip->dma.tx_chan);
11487177395fSSedji Gaouaou 	}
11494ede028fSHans-Christian Egtvedt 	clk_disable(chip->pclk);
11504ede028fSHans-Christian Egtvedt 
11514ede028fSHans-Christian Egtvedt 	return 0;
11524ede028fSHans-Christian Egtvedt }
11534ede028fSHans-Christian Egtvedt 
11544ede028fSHans-Christian Egtvedt static int atmel_ac97c_resume(struct platform_device *pdev)
11554ede028fSHans-Christian Egtvedt {
11564ede028fSHans-Christian Egtvedt 	struct snd_card *card = platform_get_drvdata(pdev);
11574ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = card->private_data;
11584ede028fSHans-Christian Egtvedt 
11594ede028fSHans-Christian Egtvedt 	clk_enable(chip->pclk);
11607177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11614ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_READY, &chip->flags))
11624ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_start(chip->dma.rx_chan);
11634ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_READY, &chip->flags))
11644ede028fSHans-Christian Egtvedt 			dw_dma_cyclic_start(chip->dma.tx_chan);
11657177395fSSedji Gaouaou 	}
11664ede028fSHans-Christian Egtvedt 	return 0;
11674ede028fSHans-Christian Egtvedt }
11684ede028fSHans-Christian Egtvedt #else
11694ede028fSHans-Christian Egtvedt #define atmel_ac97c_suspend NULL
11704ede028fSHans-Christian Egtvedt #define atmel_ac97c_resume NULL
11714ede028fSHans-Christian Egtvedt #endif
11724ede028fSHans-Christian Egtvedt 
11734ede028fSHans-Christian Egtvedt static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
11744ede028fSHans-Christian Egtvedt {
11754ede028fSHans-Christian Egtvedt 	struct snd_card *card = platform_get_drvdata(pdev);
11764ede028fSHans-Christian Egtvedt 	struct atmel_ac97c *chip = get_chip(card);
11774ede028fSHans-Christian Egtvedt 
11784ede028fSHans-Christian Egtvedt 	if (gpio_is_valid(chip->reset_pin))
11794ede028fSHans-Christian Egtvedt 		gpio_free(chip->reset_pin);
11804ede028fSHans-Christian Egtvedt 
1181bd74a184SHans-Christian Egtvedt 	ac97c_writel(chip, CAMR, 0);
1182bd74a184SHans-Christian Egtvedt 	ac97c_writel(chip, COMR, 0);
1183bd74a184SHans-Christian Egtvedt 	ac97c_writel(chip, MR,   0);
1184bd74a184SHans-Christian Egtvedt 
11854ede028fSHans-Christian Egtvedt 	clk_disable(chip->pclk);
11864ede028fSHans-Christian Egtvedt 	clk_put(chip->pclk);
11874ede028fSHans-Christian Egtvedt 	iounmap(chip->regs);
1188df163587SHans-Christian Egtvedt 	free_irq(chip->irq, chip);
11894ede028fSHans-Christian Egtvedt 
11907177395fSSedji Gaouaou 	if (cpu_is_at32ap7000()) {
11914ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
11924ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.rx_chan);
11934ede028fSHans-Christian Egtvedt 		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
11944ede028fSHans-Christian Egtvedt 			dma_release_channel(chip->dma.tx_chan);
11954ede028fSHans-Christian Egtvedt 		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
11964ede028fSHans-Christian Egtvedt 		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
11974ede028fSHans-Christian Egtvedt 		chip->dma.rx_chan = NULL;
11984ede028fSHans-Christian Egtvedt 		chip->dma.tx_chan = NULL;
11997177395fSSedji Gaouaou 	}
12004ede028fSHans-Christian Egtvedt 
12014ede028fSHans-Christian Egtvedt 	snd_card_set_dev(card, NULL);
12024ede028fSHans-Christian Egtvedt 	snd_card_free(card);
12034ede028fSHans-Christian Egtvedt 
12044ede028fSHans-Christian Egtvedt 	platform_set_drvdata(pdev, NULL);
12054ede028fSHans-Christian Egtvedt 
12064ede028fSHans-Christian Egtvedt 	return 0;
12074ede028fSHans-Christian Egtvedt }
12084ede028fSHans-Christian Egtvedt 
12094ede028fSHans-Christian Egtvedt static struct platform_driver atmel_ac97c_driver = {
12104ede028fSHans-Christian Egtvedt 	.remove		= __devexit_p(atmel_ac97c_remove),
12114ede028fSHans-Christian Egtvedt 	.driver		= {
12124ede028fSHans-Christian Egtvedt 		.name	= "atmel_ac97c",
12134ede028fSHans-Christian Egtvedt 	},
12144ede028fSHans-Christian Egtvedt 	.suspend	= atmel_ac97c_suspend,
12154ede028fSHans-Christian Egtvedt 	.resume		= atmel_ac97c_resume,
12164ede028fSHans-Christian Egtvedt };
12174ede028fSHans-Christian Egtvedt 
12184ede028fSHans-Christian Egtvedt static int __init atmel_ac97c_init(void)
12194ede028fSHans-Christian Egtvedt {
12204ede028fSHans-Christian Egtvedt 	return platform_driver_probe(&atmel_ac97c_driver,
12214ede028fSHans-Christian Egtvedt 			atmel_ac97c_probe);
12224ede028fSHans-Christian Egtvedt }
12234ede028fSHans-Christian Egtvedt module_init(atmel_ac97c_init);
12244ede028fSHans-Christian Egtvedt 
12254ede028fSHans-Christian Egtvedt static void __exit atmel_ac97c_exit(void)
12264ede028fSHans-Christian Egtvedt {
12274ede028fSHans-Christian Egtvedt 	platform_driver_unregister(&atmel_ac97c_driver);
12284ede028fSHans-Christian Egtvedt }
12294ede028fSHans-Christian Egtvedt module_exit(atmel_ac97c_exit);
12304ede028fSHans-Christian Egtvedt 
12314ede028fSHans-Christian Egtvedt MODULE_LICENSE("GPL");
12324ede028fSHans-Christian Egtvedt MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
12330cfae7c9SHans-Christian Egtvedt MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
1234