root/sound/pci/aw2/aw2-saa7146.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_aw2_saa7146_free
  2. snd_aw2_saa7146_setup
  3. snd_aw2_saa7146_pcm_init_playback
  4. snd_aw2_saa7146_pcm_init_capture
  5. snd_aw2_saa7146_define_it_playback_callback
  6. snd_aw2_saa7146_define_it_capture_callback
  7. snd_aw2_saa7146_pcm_trigger_start_playback
  8. snd_aw2_saa7146_pcm_trigger_stop_playback
  9. snd_aw2_saa7146_pcm_trigger_start_capture
  10. snd_aw2_saa7146_pcm_trigger_stop_capture
  11. snd_aw2_saa7146_interrupt
  12. snd_aw2_saa7146_get_hw_ptr_playback
  13. snd_aw2_saa7146_get_hw_ptr_capture
  14. snd_aw2_saa7146_use_digital_input
  15. snd_aw2_saa7146_is_using_digital_input
  16. snd_aw2_saa7146_get_limit

   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         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 }

/* [<][>][^][v][top][bottom][index][help] */