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