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