xref: /OK3568_Linux_fs/kernel/drivers/media/pci/tw686x/tw686x-audio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Based on the audio support from the tw6869 driver:
6*4882a593Smuzhiyun  * Copyright 2015 www.starterkit.ru <info@starterkit.ru>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Based on:
9*4882a593Smuzhiyun  * Driver for Intersil|Techwell TW6869 based DVR cards
10*4882a593Smuzhiyun  * (c) 2011-12 liran <jli11@intersil.com> [Intersil|Techwell China]
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/types.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/init.h>
17*4882a593Smuzhiyun #include <linux/kmod.h>
18*4882a593Smuzhiyun #include <linux/mutex.h>
19*4882a593Smuzhiyun #include <linux/pci.h>
20*4882a593Smuzhiyun #include <linux/delay.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <sound/core.h>
23*4882a593Smuzhiyun #include <sound/initval.h>
24*4882a593Smuzhiyun #include <sound/pcm.h>
25*4882a593Smuzhiyun #include <sound/control.h>
26*4882a593Smuzhiyun #include "tw686x.h"
27*4882a593Smuzhiyun #include "tw686x-regs.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define AUDIO_CHANNEL_OFFSET 8
30*4882a593Smuzhiyun 
tw686x_audio_irq(struct tw686x_dev * dev,unsigned long requests,unsigned int pb_status)31*4882a593Smuzhiyun void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
32*4882a593Smuzhiyun 		      unsigned int pb_status)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	unsigned long flags;
35*4882a593Smuzhiyun 	unsigned int ch, pb;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	for_each_set_bit(ch, &requests, max_channels(dev)) {
38*4882a593Smuzhiyun 		struct tw686x_audio_channel *ac = &dev->audio_channels[ch];
39*4882a593Smuzhiyun 		struct tw686x_audio_buf *done = NULL;
40*4882a593Smuzhiyun 		struct tw686x_audio_buf *next = NULL;
41*4882a593Smuzhiyun 		struct tw686x_dma_desc *desc;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 		pb = !!(pb_status & BIT(AUDIO_CHANNEL_OFFSET + ch));
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 		spin_lock_irqsave(&ac->lock, flags);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 		/* Sanity check */
48*4882a593Smuzhiyun 		if (!ac->ss || !ac->curr_bufs[0] || !ac->curr_bufs[1]) {
49*4882a593Smuzhiyun 			spin_unlock_irqrestore(&ac->lock, flags);
50*4882a593Smuzhiyun 			continue;
51*4882a593Smuzhiyun 		}
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 		if (!list_empty(&ac->buf_list)) {
54*4882a593Smuzhiyun 			next = list_first_entry(&ac->buf_list,
55*4882a593Smuzhiyun 					struct tw686x_audio_buf, list);
56*4882a593Smuzhiyun 			list_move_tail(&next->list, &ac->buf_list);
57*4882a593Smuzhiyun 			done = ac->curr_bufs[!pb];
58*4882a593Smuzhiyun 			ac->curr_bufs[pb] = next;
59*4882a593Smuzhiyun 		}
60*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ac->lock, flags);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 		if (!done || !next)
63*4882a593Smuzhiyun 			continue;
64*4882a593Smuzhiyun 		/*
65*4882a593Smuzhiyun 		 * Checking for a non-nil dma_desc[pb]->virt buffer is
66*4882a593Smuzhiyun 		 * the same as checking for memcpy DMA mode.
67*4882a593Smuzhiyun 		 */
68*4882a593Smuzhiyun 		desc = &ac->dma_descs[pb];
69*4882a593Smuzhiyun 		if (desc->virt) {
70*4882a593Smuzhiyun 			memcpy(done->virt, desc->virt,
71*4882a593Smuzhiyun 			       dev->period_size);
72*4882a593Smuzhiyun 		} else {
73*4882a593Smuzhiyun 			u32 reg = pb ? ADMA_B_ADDR[ch] : ADMA_P_ADDR[ch];
74*4882a593Smuzhiyun 			reg_write(dev, reg, next->dma);
75*4882a593Smuzhiyun 		}
76*4882a593Smuzhiyun 		ac->ptr = done->dma - ac->buf[0].dma;
77*4882a593Smuzhiyun 		snd_pcm_period_elapsed(ac->ss);
78*4882a593Smuzhiyun 	}
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /*
82*4882a593Smuzhiyun  * Audio parameters are global and shared among all
83*4882a593Smuzhiyun  * capture channels. The driver prevents changes to
84*4882a593Smuzhiyun  * the parameters if any audio channel is capturing.
85*4882a593Smuzhiyun  */
86*4882a593Smuzhiyun static const struct snd_pcm_hardware tw686x_capture_hw = {
87*4882a593Smuzhiyun 	.info			= (SNDRV_PCM_INFO_MMAP |
88*4882a593Smuzhiyun 				   SNDRV_PCM_INFO_INTERLEAVED |
89*4882a593Smuzhiyun 				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
90*4882a593Smuzhiyun 				   SNDRV_PCM_INFO_MMAP_VALID),
91*4882a593Smuzhiyun 	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
92*4882a593Smuzhiyun 	.rates			= SNDRV_PCM_RATE_8000_48000,
93*4882a593Smuzhiyun 	.rate_min		= 8000,
94*4882a593Smuzhiyun 	.rate_max		= 48000,
95*4882a593Smuzhiyun 	.channels_min		= 1,
96*4882a593Smuzhiyun 	.channels_max		= 1,
97*4882a593Smuzhiyun 	.buffer_bytes_max	= TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX,
98*4882a593Smuzhiyun 	.period_bytes_min	= AUDIO_DMA_SIZE_MIN,
99*4882a593Smuzhiyun 	.period_bytes_max	= AUDIO_DMA_SIZE_MAX,
100*4882a593Smuzhiyun 	.periods_min		= TW686X_AUDIO_PERIODS_MIN,
101*4882a593Smuzhiyun 	.periods_max		= TW686X_AUDIO_PERIODS_MAX,
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun 
tw686x_pcm_open(struct snd_pcm_substream * ss)104*4882a593Smuzhiyun static int tw686x_pcm_open(struct snd_pcm_substream *ss)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
107*4882a593Smuzhiyun 	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
108*4882a593Smuzhiyun 	struct snd_pcm_runtime *rt = ss->runtime;
109*4882a593Smuzhiyun 	int err;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	ac->ss = ss;
112*4882a593Smuzhiyun 	rt->hw = tw686x_capture_hw;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
115*4882a593Smuzhiyun 	if (err < 0)
116*4882a593Smuzhiyun 		return err;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	return 0;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
tw686x_pcm_close(struct snd_pcm_substream * ss)121*4882a593Smuzhiyun static int tw686x_pcm_close(struct snd_pcm_substream *ss)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
124*4882a593Smuzhiyun 	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	ac->ss = NULL;
127*4882a593Smuzhiyun 	return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
tw686x_pcm_prepare(struct snd_pcm_substream * ss)130*4882a593Smuzhiyun static int tw686x_pcm_prepare(struct snd_pcm_substream *ss)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
133*4882a593Smuzhiyun 	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
134*4882a593Smuzhiyun 	struct snd_pcm_runtime *rt = ss->runtime;
135*4882a593Smuzhiyun 	unsigned int period_size = snd_pcm_lib_period_bytes(ss);
136*4882a593Smuzhiyun 	struct tw686x_audio_buf *p_buf, *b_buf;
137*4882a593Smuzhiyun 	unsigned long flags;
138*4882a593Smuzhiyun 	int i;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->lock, flags);
141*4882a593Smuzhiyun 	/*
142*4882a593Smuzhiyun 	 * Given the audio parameters are global (i.e. shared across
143*4882a593Smuzhiyun 	 * DMA channels), we need to check new params are allowed.
144*4882a593Smuzhiyun 	 */
145*4882a593Smuzhiyun 	if (((dev->audio_rate != rt->rate) ||
146*4882a593Smuzhiyun 	     (dev->period_size != period_size)) && dev->audio_enabled)
147*4882a593Smuzhiyun 		goto err_audio_busy;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
150*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev->lock, flags);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (dev->audio_rate != rt->rate) {
153*4882a593Smuzhiyun 		u32 reg;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		dev->audio_rate = rt->rate;
156*4882a593Smuzhiyun 		reg = ((125000000 / rt->rate) << 16) +
157*4882a593Smuzhiyun 		       ((125000000 % rt->rate) << 16) / rt->rate;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		reg_write(dev, AUDIO_CONTROL2, reg);
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	if (dev->period_size != period_size) {
163*4882a593Smuzhiyun 		u32 reg;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 		dev->period_size = period_size;
166*4882a593Smuzhiyun 		reg = reg_read(dev, AUDIO_CONTROL1);
167*4882a593Smuzhiyun 		reg &= ~(AUDIO_DMA_SIZE_MASK << AUDIO_DMA_SIZE_SHIFT);
168*4882a593Smuzhiyun 		reg |= period_size << AUDIO_DMA_SIZE_SHIFT;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 		reg_write(dev, AUDIO_CONTROL1, reg);
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (rt->periods < TW686X_AUDIO_PERIODS_MIN ||
174*4882a593Smuzhiyun 	    rt->periods > TW686X_AUDIO_PERIODS_MAX)
175*4882a593Smuzhiyun 		return -EINVAL;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	spin_lock_irqsave(&ac->lock, flags);
178*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ac->buf_list);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	for (i = 0; i < rt->periods; i++) {
181*4882a593Smuzhiyun 		ac->buf[i].dma = rt->dma_addr + period_size * i;
182*4882a593Smuzhiyun 		ac->buf[i].virt = rt->dma_area + period_size * i;
183*4882a593Smuzhiyun 		INIT_LIST_HEAD(&ac->buf[i].list);
184*4882a593Smuzhiyun 		list_add_tail(&ac->buf[i].list, &ac->buf_list);
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	p_buf =	list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
188*4882a593Smuzhiyun 	list_move_tail(&p_buf->list, &ac->buf_list);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	b_buf =	list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
191*4882a593Smuzhiyun 	list_move_tail(&b_buf->list, &ac->buf_list);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	ac->curr_bufs[0] = p_buf;
194*4882a593Smuzhiyun 	ac->curr_bufs[1] = b_buf;
195*4882a593Smuzhiyun 	ac->ptr = 0;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	if (dev->dma_mode != TW686X_DMA_MODE_MEMCPY) {
198*4882a593Smuzhiyun 		reg_write(dev, ADMA_P_ADDR[ac->ch], p_buf->dma);
199*4882a593Smuzhiyun 		reg_write(dev, ADMA_B_ADDR[ac->ch], b_buf->dma);
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ac->lock, flags);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	return 0;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun err_audio_busy:
207*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev->lock, flags);
208*4882a593Smuzhiyun 	return -EBUSY;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
tw686x_pcm_trigger(struct snd_pcm_substream * ss,int cmd)211*4882a593Smuzhiyun static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
214*4882a593Smuzhiyun 	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
215*4882a593Smuzhiyun 	unsigned long flags;
216*4882a593Smuzhiyun 	int err = 0;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	switch (cmd) {
219*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
220*4882a593Smuzhiyun 		if (ac->curr_bufs[0] && ac->curr_bufs[1]) {
221*4882a593Smuzhiyun 			spin_lock_irqsave(&dev->lock, flags);
222*4882a593Smuzhiyun 			dev->audio_enabled = 1;
223*4882a593Smuzhiyun 			tw686x_enable_channel(dev,
224*4882a593Smuzhiyun 				AUDIO_CHANNEL_OFFSET + ac->ch);
225*4882a593Smuzhiyun 			spin_unlock_irqrestore(&dev->lock, flags);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 			mod_timer(&dev->dma_delay_timer,
228*4882a593Smuzhiyun 				  jiffies + msecs_to_jiffies(100));
229*4882a593Smuzhiyun 		} else {
230*4882a593Smuzhiyun 			err = -EIO;
231*4882a593Smuzhiyun 		}
232*4882a593Smuzhiyun 		break;
233*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
234*4882a593Smuzhiyun 		spin_lock_irqsave(&dev->lock, flags);
235*4882a593Smuzhiyun 		dev->audio_enabled = 0;
236*4882a593Smuzhiyun 		tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
237*4882a593Smuzhiyun 		spin_unlock_irqrestore(&dev->lock, flags);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 		spin_lock_irqsave(&ac->lock, flags);
240*4882a593Smuzhiyun 		ac->curr_bufs[0] = NULL;
241*4882a593Smuzhiyun 		ac->curr_bufs[1] = NULL;
242*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ac->lock, flags);
243*4882a593Smuzhiyun 		break;
244*4882a593Smuzhiyun 	default:
245*4882a593Smuzhiyun 		err = -EINVAL;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	return err;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
tw686x_pcm_pointer(struct snd_pcm_substream * ss)250*4882a593Smuzhiyun static snd_pcm_uframes_t tw686x_pcm_pointer(struct snd_pcm_substream *ss)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
253*4882a593Smuzhiyun 	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return bytes_to_frames(ss->runtime, ac->ptr);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static const struct snd_pcm_ops tw686x_pcm_ops = {
259*4882a593Smuzhiyun 	.open = tw686x_pcm_open,
260*4882a593Smuzhiyun 	.close = tw686x_pcm_close,
261*4882a593Smuzhiyun 	.prepare = tw686x_pcm_prepare,
262*4882a593Smuzhiyun 	.trigger = tw686x_pcm_trigger,
263*4882a593Smuzhiyun 	.pointer = tw686x_pcm_pointer,
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun 
tw686x_snd_pcm_init(struct tw686x_dev * dev)266*4882a593Smuzhiyun static int tw686x_snd_pcm_init(struct tw686x_dev *dev)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	struct snd_card *card = dev->snd_card;
269*4882a593Smuzhiyun 	struct snd_pcm *pcm;
270*4882a593Smuzhiyun 	struct snd_pcm_substream *ss;
271*4882a593Smuzhiyun 	unsigned int i;
272*4882a593Smuzhiyun 	int err;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	err = snd_pcm_new(card, card->driver, 0, 0, max_channels(dev), &pcm);
275*4882a593Smuzhiyun 	if (err < 0)
276*4882a593Smuzhiyun 		return err;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tw686x_pcm_ops);
279*4882a593Smuzhiyun 	snd_pcm_chip(pcm) = dev;
280*4882a593Smuzhiyun 	pcm->info_flags = 0;
281*4882a593Smuzhiyun 	strscpy(pcm->name, "tw686x PCM", sizeof(pcm->name));
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
284*4882a593Smuzhiyun 	     ss; ss = ss->next, i++)
285*4882a593Smuzhiyun 		snprintf(ss->name, sizeof(ss->name), "vch%u audio", i);
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	snd_pcm_set_managed_buffer_all(pcm,
288*4882a593Smuzhiyun 				SNDRV_DMA_TYPE_DEV,
289*4882a593Smuzhiyun 				&dev->pci_dev->dev,
290*4882a593Smuzhiyun 				TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX,
291*4882a593Smuzhiyun 				TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX);
292*4882a593Smuzhiyun 	return 0;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
tw686x_audio_dma_free(struct tw686x_dev * dev,struct tw686x_audio_channel * ac)295*4882a593Smuzhiyun static void tw686x_audio_dma_free(struct tw686x_dev *dev,
296*4882a593Smuzhiyun 				  struct tw686x_audio_channel *ac)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	int pb;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	for (pb = 0; pb < 2; pb++) {
301*4882a593Smuzhiyun 		if (!ac->dma_descs[pb].virt)
302*4882a593Smuzhiyun 			continue;
303*4882a593Smuzhiyun 		pci_free_consistent(dev->pci_dev, ac->dma_descs[pb].size,
304*4882a593Smuzhiyun 				    ac->dma_descs[pb].virt,
305*4882a593Smuzhiyun 				    ac->dma_descs[pb].phys);
306*4882a593Smuzhiyun 		ac->dma_descs[pb].virt = NULL;
307*4882a593Smuzhiyun 	}
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
tw686x_audio_dma_alloc(struct tw686x_dev * dev,struct tw686x_audio_channel * ac)310*4882a593Smuzhiyun static int tw686x_audio_dma_alloc(struct tw686x_dev *dev,
311*4882a593Smuzhiyun 				  struct tw686x_audio_channel *ac)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	int pb;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/*
316*4882a593Smuzhiyun 	 * In the memcpy DMA mode we allocate a consistent buffer
317*4882a593Smuzhiyun 	 * and use it for the DMA capture. Otherwise, DMA
318*4882a593Smuzhiyun 	 * acts on the ALSA buffers as received in pcm_prepare.
319*4882a593Smuzhiyun 	 */
320*4882a593Smuzhiyun 	if (dev->dma_mode != TW686X_DMA_MODE_MEMCPY)
321*4882a593Smuzhiyun 		return 0;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	for (pb = 0; pb < 2; pb++) {
324*4882a593Smuzhiyun 		u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch];
325*4882a593Smuzhiyun 		void *virt;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 		virt = pci_alloc_consistent(dev->pci_dev, AUDIO_DMA_SIZE_MAX,
328*4882a593Smuzhiyun 					    &ac->dma_descs[pb].phys);
329*4882a593Smuzhiyun 		if (!virt) {
330*4882a593Smuzhiyun 			dev_err(&dev->pci_dev->dev,
331*4882a593Smuzhiyun 				"dma%d: unable to allocate audio DMA %s-buffer\n",
332*4882a593Smuzhiyun 				ac->ch, pb ? "B" : "P");
333*4882a593Smuzhiyun 			return -ENOMEM;
334*4882a593Smuzhiyun 		}
335*4882a593Smuzhiyun 		ac->dma_descs[pb].virt = virt;
336*4882a593Smuzhiyun 		ac->dma_descs[pb].size = AUDIO_DMA_SIZE_MAX;
337*4882a593Smuzhiyun 		reg_write(dev, reg, ac->dma_descs[pb].phys);
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 	return 0;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
tw686x_audio_free(struct tw686x_dev * dev)342*4882a593Smuzhiyun void tw686x_audio_free(struct tw686x_dev *dev)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	unsigned long flags;
345*4882a593Smuzhiyun 	u32 dma_ch_mask;
346*4882a593Smuzhiyun 	u32 dma_cmd;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->lock, flags);
349*4882a593Smuzhiyun 	dma_cmd = reg_read(dev, DMA_CMD);
350*4882a593Smuzhiyun 	dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE);
351*4882a593Smuzhiyun 	reg_write(dev, DMA_CMD, dma_cmd & ~0xff00);
352*4882a593Smuzhiyun 	reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask & ~0xff00);
353*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev->lock, flags);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	if (!dev->snd_card)
356*4882a593Smuzhiyun 		return;
357*4882a593Smuzhiyun 	snd_card_free(dev->snd_card);
358*4882a593Smuzhiyun 	dev->snd_card = NULL;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
tw686x_audio_init(struct tw686x_dev * dev)361*4882a593Smuzhiyun int tw686x_audio_init(struct tw686x_dev *dev)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	struct pci_dev *pci_dev = dev->pci_dev;
364*4882a593Smuzhiyun 	struct snd_card *card;
365*4882a593Smuzhiyun 	int err, ch;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	/* Enable external audio */
368*4882a593Smuzhiyun 	reg_write(dev, AUDIO_CONTROL1, BIT(0));
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1,
371*4882a593Smuzhiyun 			   SNDRV_DEFAULT_STR1,
372*4882a593Smuzhiyun 			   THIS_MODULE, 0, &card);
373*4882a593Smuzhiyun 	if (err < 0)
374*4882a593Smuzhiyun 		return err;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	dev->snd_card = card;
377*4882a593Smuzhiyun 	strscpy(card->driver, "tw686x", sizeof(card->driver));
378*4882a593Smuzhiyun 	strscpy(card->shortname, "tw686x", sizeof(card->shortname));
379*4882a593Smuzhiyun 	strscpy(card->longname, pci_name(pci_dev), sizeof(card->longname));
380*4882a593Smuzhiyun 	snd_card_set_dev(card, &pci_dev->dev);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	for (ch = 0; ch < max_channels(dev); ch++) {
383*4882a593Smuzhiyun 		struct tw686x_audio_channel *ac;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 		ac = &dev->audio_channels[ch];
386*4882a593Smuzhiyun 		spin_lock_init(&ac->lock);
387*4882a593Smuzhiyun 		ac->dev = dev;
388*4882a593Smuzhiyun 		ac->ch = ch;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 		err = tw686x_audio_dma_alloc(dev, ac);
391*4882a593Smuzhiyun 		if (err < 0)
392*4882a593Smuzhiyun 			goto err_cleanup;
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	err = tw686x_snd_pcm_init(dev);
396*4882a593Smuzhiyun 	if (err < 0)
397*4882a593Smuzhiyun 		goto err_cleanup;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	err = snd_card_register(card);
400*4882a593Smuzhiyun 	if (!err)
401*4882a593Smuzhiyun 		return 0;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun err_cleanup:
404*4882a593Smuzhiyun 	for (ch = 0; ch < max_channels(dev); ch++) {
405*4882a593Smuzhiyun 		if (!dev->audio_channels[ch].dev)
406*4882a593Smuzhiyun 			continue;
407*4882a593Smuzhiyun 		tw686x_audio_dma_free(dev, &dev->audio_channels[ch]);
408*4882a593Smuzhiyun 	}
409*4882a593Smuzhiyun 	snd_card_free(card);
410*4882a593Smuzhiyun 	dev->snd_card = NULL;
411*4882a593Smuzhiyun 	return err;
412*4882a593Smuzhiyun }
413