~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/aw2/aw2-saa7146.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*****************************************************************************
  3  *
  4  * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
  5  * Jean-Christian Hassler <jhassler@free.fr>
  6  *
  7  * This file is part of the Audiowerk2 ALSA driver
  8  *
  9  *****************************************************************************/
 10 
 11 #define AW2_SAA7146_M
 12 
 13 #include <linux/init.h>
 14 #include <linux/pci.h>
 15 #include <linux/interrupt.h>
 16 #include <linux/delay.h>
 17 #include <linux/io.h>
 18 #include <sound/core.h>
 19 #include <sound/initval.h>
 20 #include <sound/pcm.h>
 21 #include <sound/pcm_params.h>
 22 
 23 #include "saa7146.h"
 24 #include "aw2-saa7146.h"
 25 
 26 #include "aw2-tsl.c"
 27 
 28 #define WRITEREG(value, addr) writel((value), chip->base_addr + (addr))
 29 #define READREG(addr) readl(chip->base_addr + (addr))
 30 
 31 static struct snd_aw2_saa7146_cb_param
 32  arr_substream_it_playback_cb[NB_STREAM_PLAYBACK];
 33 static struct snd_aw2_saa7146_cb_param
 34  arr_substream_it_capture_cb[NB_STREAM_CAPTURE];
 35 
 36 static int snd_aw2_saa7146_get_limit(int size);
 37 
 38 /* chip-specific destructor */
 39 int snd_aw2_saa7146_free(struct snd_aw2_saa7146 *chip)
 40 {
 41         /* disable all irqs */
 42         WRITEREG(0, IER);
 43 
 44         /* reset saa7146 */
 45         WRITEREG((MRST_N << 16), MC1);
 46 
 47         /* Unset base addr */
 48         chip->base_addr = NULL;
 49 
 50         return 0;
 51 }
 52 
 53 void snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip,
 54                            void __iomem *pci_base_addr)
 55 {
 56         /* set PCI burst/threshold
 57 
 58            Burst length definition
 59            VALUE    BURST LENGTH
 60            000      1 Dword
 61            001      2 Dwords
 62            010      4 Dwords
 63            011      8 Dwords
 64            100      16 Dwords
 65            101      32 Dwords
 66            110      64 Dwords
 67            111      128 Dwords
 68 
 69            Threshold definition
 70            VALUE    WRITE MODE              READ MODE
 71            00       1 Dword of valid data   1 empty Dword
 72            01       4 Dwords of valid data  4 empty Dwords
 73            10       8 Dwords of valid data  8 empty Dwords
 74            11       16 Dwords of valid data 16 empty Dwords */
 75 
 76         unsigned int acon2;
 77         unsigned int acon1 = 0;
 78         int i;
 79 
 80         /* Set base addr */
 81         chip->base_addr = pci_base_addr;
 82 
 83         /* disable all irqs */
 84         WRITEREG(0, IER);
 85 
 86         /* reset saa7146 */
 87         WRITEREG((MRST_N << 16), MC1);
 88 
 89         /* enable audio interface */
 90 #ifdef __BIG_ENDIAN
 91         acon1 |= A1_SWAP;
 92         acon1 |= A2_SWAP;
 93 #endif
 94         /* WS0_CTRL, WS0_SYNC: input TSL1, I2S */
 95 
 96         /* At initialization WS1 and WS2 are disabled (configured as input) */
 97         acon1 |= 0 * WS1_CTRL;
 98         acon1 |= 0 * WS2_CTRL;
 99 
100         /* WS4 is not used. So it must not restart A2.
101            This is why it is configured as output (force to low) */
102         acon1 |= 3 * WS4_CTRL;
103 
104         /* WS3_CTRL, WS3_SYNC: output TSL2, I2S */
105         acon1 |= 2 * WS3_CTRL;
106 
107         /* A1 and A2 are active and asynchronous */
108         acon1 |= 3 * AUDIO_MODE;
109         WRITEREG(acon1, ACON1);
110 
111         /* The following comes from original windows driver.
112            It is needed to have a correct behavior of input and output
113            simultenously, but I don't know why ! */
114         WRITEREG(3 * (BurstA1_in) + 3 * (ThreshA1_in) +
115                  3 * (BurstA1_out) + 3 * (ThreshA1_out) +
116                  3 * (BurstA2_out) + 3 * (ThreshA2_out), PCI_BT_A);
117 
118         /* enable audio port pins */
119         WRITEREG((EAP << 16) | EAP, MC1);
120 
121         /* enable I2C */
122         WRITEREG((EI2C << 16) | EI2C, MC1);
123         /* enable interrupts */
124         WRITEREG(A1_out | A2_out | A1_in | IIC_S | IIC_E, IER);
125 
126         /* audio configuration */
127         acon2 = A2_CLKSRC | BCLK1_OEN;
128         WRITEREG(acon2, ACON2);
129 
130         /* By default use analog input */
131         snd_aw2_saa7146_use_digital_input(chip, 0);
132 
133         /* TSL setup */
134         for (i = 0; i < 8; ++i) {
135                 WRITEREG(tsl1[i], TSL1 + (i * 4));
136                 WRITEREG(tsl2[i], TSL2 + (i * 4));
137         }
138 
139 }
140 
141 void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
142                                        int stream_number,
143                                        unsigned long dma_addr,
144                                        unsigned long period_size,
145                                        unsigned long buffer_size)
146 {
147         unsigned long dw_page, dw_limit;
148 
149         /* Configure DMA for substream
150            Configuration informations: ALSA has allocated continuous memory
151            pages. So we don't need to use MMU of saa7146.
152          */
153 
154         /* No MMU -> nothing to do with PageA1, we only configure the limit of
155            PageAx_out register */
156         /* Disable MMU */
157         dw_page = (0L << 11);
158 
159         /* Configure Limit for DMA access.
160            The limit register defines an address limit, which generates
161            an interrupt if passed by the actual PCI address pointer.
162            '0001' means an interrupt will be generated if the lower
163            6 bits (64 bytes) of the PCI address are zero. '0010'
164            defines a limit of 128 bytes, '0011' one of 256 bytes, and
165            so on up to 1 Mbyte defined by '1111'. This interrupt range
166            can be calculated as follows:
167            Range = 2^(5 + Limit) bytes.
168          */
169         dw_limit = snd_aw2_saa7146_get_limit(period_size);
170         dw_page |= (dw_limit << 4);
171 
172         if (stream_number == 0) {
173                 WRITEREG(dw_page, PageA2_out);
174 
175                 /* Base address for DMA transfert. */
176                 /* This address has been reserved by ALSA. */
177                 /* This is a physical address */
178                 WRITEREG(dma_addr, BaseA2_out);
179 
180                 /* Define upper limit for DMA access */
181                 WRITEREG(dma_addr + buffer_size, ProtA2_out);
182 
183         } else if (stream_number == 1) {
184                 WRITEREG(dw_page, PageA1_out);
185 
186                 /* Base address for DMA transfert. */
187                 /* This address has been reserved by ALSA. */
188                 /* This is a physical address */
189                 WRITEREG(dma_addr, BaseA1_out);
190 
191                 /* Define upper limit for DMA access */
192                 WRITEREG(dma_addr + buffer_size, ProtA1_out);
193         } else {
194                 pr_err("aw2: snd_aw2_saa7146_pcm_init_playback: "
195                        "Substream number is not 0 or 1 -> not managed\n");
196         }
197 }
198 
199 void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
200                                       int stream_number, unsigned long dma_addr,
201                                       unsigned long period_size,
202                                       unsigned long buffer_size)
203 {
204         unsigned long dw_page, dw_limit;
205 
206         /* Configure DMA for substream
207            Configuration informations: ALSA has allocated continuous memory
208            pages. So we don't need to use MMU of saa7146.
209          */
210 
211         /* No MMU -> nothing to do with PageA1, we only configure the limit of
212            PageAx_out register */
213         /* Disable MMU */
214         dw_page = (0L << 11);
215 
216         /* Configure Limit for DMA access.
217            The limit register defines an address limit, which generates
218            an interrupt if passed by the actual PCI address pointer.
219            '0001' means an interrupt will be generated if the lower
220            6 bits (64 bytes) of the PCI address are zero. '0010'
221            defines a limit of 128 bytes, '0011' one of 256 bytes, and
222            so on up to 1 Mbyte defined by '1111'. This interrupt range
223            can be calculated as follows:
224            Range = 2^(5 + Limit) bytes.
225          */
226         dw_limit = snd_aw2_saa7146_get_limit(period_size);
227         dw_page |= (dw_limit << 4);
228 
229         if (stream_number == 0) {
230                 WRITEREG(dw_page, PageA1_in);
231 
232                 /* Base address for DMA transfert. */
233                 /* This address has been reserved by ALSA. */
234                 /* This is a physical address */
235                 WRITEREG(dma_addr, BaseA1_in);
236 
237                 /* Define upper limit for DMA access  */
238                 WRITEREG(dma_addr + buffer_size, ProtA1_in);
239         } else {
240                 pr_err("aw2: snd_aw2_saa7146_pcm_init_capture: "
241                        "Substream number is not 0 -> not managed\n");
242         }
243 }
244 
245 void snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number,
246                                                  snd_aw2_saa7146_it_cb
247                                                  p_it_callback,
248                                                  void *p_callback_param)
249 {
250         if (stream_number < NB_STREAM_PLAYBACK) {
251                 arr_substream_it_playback_cb[stream_number].p_it_callback =
252                     (snd_aw2_saa7146_it_cb) p_it_callback;
253                 arr_substream_it_playback_cb[stream_number].p_callback_param =
254                     (void *)p_callback_param;
255         }
256 }
257 
258 void snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number,
259                                                 snd_aw2_saa7146_it_cb
260                                                 p_it_callback,
261                                                 void *p_callback_param)
262 {
263         if (stream_number < NB_STREAM_CAPTURE) {
264                 arr_substream_it_capture_cb[stream_number].p_it_callback =
265                     (snd_aw2_saa7146_it_cb) p_it_callback;
266                 arr_substream_it_capture_cb[stream_number].p_callback_param =
267                     (void *)p_callback_param;
268         }
269 }
270 
271 void snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146 *chip,
272                                                 int stream_number)
273 {
274         unsigned int acon1 = 0;
275         /* In aw8 driver, dma transfert is always active. It is
276            started and stopped in a larger "space" */
277         acon1 = READREG(ACON1);
278         if (stream_number == 0) {
279                 WRITEREG((TR_E_A2_OUT << 16) | TR_E_A2_OUT, MC1);
280 
281                 /* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
282                 acon1 |= 2 * WS2_CTRL;
283                 WRITEREG(acon1, ACON1);
284 
285         } else if (stream_number == 1) {
286                 WRITEREG((TR_E_A1_OUT << 16) | TR_E_A1_OUT, MC1);
287 
288                 /* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
289                 acon1 |= 1 * WS1_CTRL;
290                 WRITEREG(acon1, ACON1);
291         }
292 }
293 
294 void snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146 *chip,
295                                                int stream_number)
296 {
297         unsigned int acon1 = 0;
298         acon1 = READREG(ACON1);
299         if (stream_number == 0) {
300                 /* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
301                 acon1 &= ~(3 * WS2_CTRL);
302                 WRITEREG(acon1, ACON1);
303 
304                 WRITEREG((TR_E_A2_OUT << 16), MC1);
305         } else if (stream_number == 1) {
306                 /* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
307                 acon1 &= ~(3 * WS1_CTRL);
308                 WRITEREG(acon1, ACON1);
309 
310                 WRITEREG((TR_E_A1_OUT << 16), MC1);
311         }
312 }
313 
314 void snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146 *chip,
315                                                int stream_number)
316 {
317         /* In aw8 driver, dma transfert is always active. It is
318            started and stopped in a larger "space" */
319         if (stream_number == 0)
320                 WRITEREG((TR_E_A1_IN << 16) | TR_E_A1_IN, MC1);
321 }
322 
323 void snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146 *chip,
324                                               int stream_number)
325 {
326         if (stream_number == 0)
327                 WRITEREG((TR_E_A1_IN << 16), MC1);
328 }
329 
330 irqreturn_t snd_aw2_saa7146_interrupt(int irq, void *dev_id)
331 {
332         unsigned int isr;
333         __always_unused unsigned int iicsta;
334         struct snd_aw2_saa7146 *chip = dev_id;
335 
336         isr = READREG(ISR);
337         if (!isr)
338                 return IRQ_NONE;
339 
340         WRITEREG(isr, ISR);
341 
342         if (isr & (IIC_S | IIC_E)) {
343                 iicsta = READREG(IICSTA);
344                 WRITEREG(0x100, IICSTA);
345         }
346 
347         if (isr & A1_out) {
348                 if (arr_substream_it_playback_cb[1].p_it_callback != NULL) {
349                         arr_substream_it_playback_cb[1].
350                             p_it_callback(arr_substream_it_playback_cb[1].
351                                           p_callback_param);
352                 }
353         }
354         if (isr & A2_out) {
355                 if (arr_substream_it_playback_cb[0].p_it_callback != NULL) {
356                         arr_substream_it_playback_cb[0].
357                             p_it_callback(arr_substream_it_playback_cb[0].
358                                           p_callback_param);
359                 }
360 
361         }
362         if (isr & A1_in) {
363                 if (arr_substream_it_capture_cb[0].p_it_callback != NULL) {
364                         arr_substream_it_capture_cb[0].
365                             p_it_callback(arr_substream_it_capture_cb[0].
366                                           p_callback_param);
367                 }
368         }
369         return IRQ_HANDLED;
370 }
371 
372 unsigned int snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146 *chip,
373                                                  int stream_number,
374                                                  unsigned char *start_addr,
375                                                  unsigned int buffer_size)
376 {
377         long pci_adp = 0;
378         size_t ptr = 0;
379 
380         if (stream_number == 0) {
381                 pci_adp = READREG(PCI_ADP3);
382                 ptr = pci_adp - (long)start_addr;
383 
384                 if (ptr == buffer_size)
385                         ptr = 0;
386         }
387         if (stream_number == 1) {
388                 pci_adp = READREG(PCI_ADP1);
389                 ptr = pci_adp - (size_t) start_addr;
390 
391                 if (ptr == buffer_size)
392                         ptr = 0;
393         }
394         return ptr;
395 }
396 
397 unsigned int snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146 *chip,
398                                                 int stream_number,
399                                                 unsigned char *start_addr,
400                                                 unsigned int buffer_size)
401 {
402         size_t pci_adp = 0;
403         size_t ptr = 0;
404         if (stream_number == 0) {
405                 pci_adp = READREG(PCI_ADP2);
406                 ptr = pci_adp - (size_t) start_addr;
407 
408                 if (ptr == buffer_size)
409                         ptr = 0;
410         }
411         return ptr;
412 }
413 
414 void snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 *chip,
415                                        int use_digital)
416 {
417         /* FIXME: switch between analog and digital input does not always work.
418            It can produce a kind of white noise. It seams that received data
419            are inverted sometime (endian inversion). Why ? I don't know, maybe
420            a problem of synchronization... However for the time being I have
421            not found the problem. Workaround: switch again (and again) between
422            digital and analog input until it works. */
423         if (use_digital)
424                 WRITEREG(0x40, GPIO_CTRL);
425         else
426                 WRITEREG(0x50, GPIO_CTRL);
427 }
428 
429 int snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146 *chip)
430 {
431         unsigned int reg_val = READREG(GPIO_CTRL);
432         if ((reg_val & 0xFF) == 0x40)
433                 return 1;
434         else
435                 return 0;
436 }
437 
438 
439 static int snd_aw2_saa7146_get_limit(int size)
440 {
441         int limitsize = 32;
442         int limit = 0;
443         while (limitsize < size) {
444                 limitsize *= 2;
445                 limit++;
446         }
447         return limit;
448 }
449 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php