1 // SPDX-License-Identifier: GPL-2.0-only 1 2 /********************************************* 3 * 4 * Copyright (C) 2008 Cedric Bregardis <cedric 5 * Jean-Christian Hassler <jhassler@free.fr> 6 * 7 * This file is part of the Audiowerk2 ALSA dr 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), 29 #define READREG(addr) readl(chip->base_addr + 30 31 static struct snd_aw2_saa7146_cb_param 32 arr_substream_it_playback_cb[NB_STREAM_PLAYBA 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_saa714 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_saa7 54 void __iomem *pci_b 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 RE 71 00 1 Dword of valid data 1 72 01 4 Dwords of valid data 4 73 10 8 Dwords of valid data 8 74 11 16 Dwords of valid data 16 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 d 97 acon1 |= 0 * WS1_CTRL; 98 acon1 |= 0 * WS2_CTRL; 99 100 /* WS4 is not used. So it must not res 101 This is why it is configured as out 102 acon1 |= 3 * WS4_CTRL; 103 104 /* WS3_CTRL, WS3_SYNC: output TSL2, I2 105 acon1 |= 2 * WS3_CTRL; 106 107 /* A1 and A2 are active and asynchrono 108 acon1 |= 3 * AUDIO_MODE; 109 WRITEREG(acon1, ACON1); 110 111 /* The following comes from original w 112 It is needed to have a correct beha 113 simultenously, but I don't know why 114 WRITEREG(3 * (BurstA1_in) + 3 * (Thres 115 3 * (BurstA1_out) + 3 * (Thre 116 3 * (BurstA2_out) + 3 * (Thre 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 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 132 133 /* TSL setup */ 134 for (i = 0; i < 8; ++i) { 135 WRITEREG(tsl1[i], TSL1 + (i * 136 WRITEREG(tsl2[i], TSL2 + (i * 137 } 138 139 } 140 141 void snd_aw2_saa7146_pcm_init_playback(struct 142 int str 143 unsigne 144 unsigne 145 unsigne 146 { 147 unsigned long dw_page, dw_limit; 148 149 /* Configure DMA for substream 150 Configuration informations: ALSA ha 151 pages. So we don't need to use MMU 152 */ 153 154 /* No MMU -> nothing to do with PageA1 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 addre 161 an interrupt if passed by the actua 162 '0001' means an interrupt will be g 163 6 bits (64 bytes) of the PCI addres 164 defines a limit of 128 bytes, '0011 165 so on up to 1 Mbyte defined by '111 166 can be calculated as follows: 167 Range = 2^(5 + Limit) bytes. 168 */ 169 dw_limit = snd_aw2_saa7146_get_limit(p 170 dw_page |= (dw_limit << 4); 171 172 if (stream_number == 0) { 173 WRITEREG(dw_page, PageA2_out); 174 175 /* Base address for DMA transf 176 /* This address has been reser 177 /* This is a physical address 178 WRITEREG(dma_addr, BaseA2_out) 179 180 /* Define upper limit for DMA 181 WRITEREG(dma_addr + buffer_siz 182 183 } else if (stream_number == 1) { 184 WRITEREG(dw_page, PageA1_out); 185 186 /* Base address for DMA transf 187 /* This address has been reser 188 /* This is a physical address 189 WRITEREG(dma_addr, BaseA1_out) 190 191 /* Define upper limit for DMA 192 WRITEREG(dma_addr + buffer_siz 193 } else { 194 pr_err("aw2: snd_aw2_saa7146_p 195 "Substream number is no 196 } 197 } 198 199 void snd_aw2_saa7146_pcm_init_capture(struct s 200 int stre 201 unsigned 202 unsigned 203 { 204 unsigned long dw_page, dw_limit; 205 206 /* Configure DMA for substream 207 Configuration informations: ALSA ha 208 pages. So we don't need to use MMU 209 */ 210 211 /* No MMU -> nothing to do with PageA1 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 addre 218 an interrupt if passed by the actua 219 '0001' means an interrupt will be g 220 6 bits (64 bytes) of the PCI addres 221 defines a limit of 128 bytes, '0011 222 so on up to 1 Mbyte defined by '111 223 can be calculated as follows: 224 Range = 2^(5 + Limit) bytes. 225 */ 226 dw_limit = snd_aw2_saa7146_get_limit(p 227 dw_page |= (dw_limit << 4); 228 229 if (stream_number == 0) { 230 WRITEREG(dw_page, PageA1_in); 231 232 /* Base address for DMA transf 233 /* This address has been reser 234 /* This is a physical address 235 WRITEREG(dma_addr, BaseA1_in); 236 237 /* Define upper limit for DMA 238 WRITEREG(dma_addr + buffer_siz 239 } else { 240 pr_err("aw2: snd_aw2_saa7146_p 241 "Substream number is no 242 } 243 } 244 245 void snd_aw2_saa7146_define_it_playback_callba 246 247 248 249 { 250 if (stream_number < NB_STREAM_PLAYBACK 251 arr_substream_it_playback_cb[s 252 (snd_aw2_saa7146_it_cb) p_ 253 arr_substream_it_playback_cb[s 254 (void *)p_callback_param; 255 } 256 } 257 258 void snd_aw2_saa7146_define_it_capture_callbac 259 260 261 262 { 263 if (stream_number < NB_STREAM_CAPTURE) 264 arr_substream_it_capture_cb[st 265 (snd_aw2_saa7146_it_cb) p_ 266 arr_substream_it_capture_cb[st 267 (void *)p_callback_param; 268 } 269 } 270 271 void snd_aw2_saa7146_pcm_trigger_start_playbac 272 273 { 274 unsigned int acon1 = 0; 275 /* In aw8 driver, dma transfert is alw 276 started and stopped in a larger "sp 277 acon1 = READREG(ACON1); 278 if (stream_number == 0) { 279 WRITEREG((TR_E_A2_OUT << 16) | 280 281 /* WS2_CTRL, WS2_SYNC: output 282 acon1 |= 2 * WS2_CTRL; 283 WRITEREG(acon1, ACON1); 284 285 } else if (stream_number == 1) { 286 WRITEREG((TR_E_A1_OUT << 16) | 287 288 /* WS1_CTRL, WS1_SYNC: output 289 acon1 |= 1 * WS1_CTRL; 290 WRITEREG(acon1, ACON1); 291 } 292 } 293 294 void snd_aw2_saa7146_pcm_trigger_stop_playback 295 296 { 297 unsigned int acon1 = 0; 298 acon1 = READREG(ACON1); 299 if (stream_number == 0) { 300 /* WS2_CTRL, WS2_SYNC: output 301 acon1 &= ~(3 * WS2_CTRL); 302 WRITEREG(acon1, ACON1); 303 304 WRITEREG((TR_E_A2_OUT << 16), 305 } else if (stream_number == 1) { 306 /* WS1_CTRL, WS1_SYNC: output 307 acon1 &= ~(3 * WS1_CTRL); 308 WRITEREG(acon1, ACON1); 309 310 WRITEREG((TR_E_A1_OUT << 16), 311 } 312 } 313 314 void snd_aw2_saa7146_pcm_trigger_start_capture 315 316 { 317 /* In aw8 driver, dma transfert is alw 318 started and stopped in a larger "sp 319 if (stream_number == 0) 320 WRITEREG((TR_E_A1_IN << 16) | 321 } 322 323 void snd_aw2_saa7146_pcm_trigger_stop_capture( 324 325 { 326 if (stream_number == 0) 327 WRITEREG((TR_E_A1_IN << 16), M 328 } 329 330 irqreturn_t snd_aw2_saa7146_interrupt(int irq, 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_ 349 arr_substream_it_playb 350 p_it_callback(arr_ 351 p_ca 352 } 353 } 354 if (isr & A2_out) { 355 if (arr_substream_it_playback_ 356 arr_substream_it_playb 357 p_it_callback(arr_ 358 p_ca 359 } 360 361 } 362 if (isr & A1_in) { 363 if (arr_substream_it_capture_c 364 arr_substream_it_captu 365 p_it_callback(arr_ 366 p_ca 367 } 368 } 369 return IRQ_HANDLED; 370 } 371 372 unsigned int snd_aw2_saa7146_get_hw_ptr_playba 373 374 375 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_ad 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 390 391 if (ptr == buffer_size) 392 ptr = 0; 393 } 394 return ptr; 395 } 396 397 unsigned int snd_aw2_saa7146_get_hw_ptr_captur 398 399 400 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 407 408 if (ptr == buffer_size) 409 ptr = 0; 410 } 411 return ptr; 412 } 413 414 void snd_aw2_saa7146_use_digital_input(struct 415 int use 416 { 417 /* FIXME: switch between analog and di 418 It can produce a kind of white nois 419 are inverted sometime (endian inver 420 a problem of synchronization... How 421 not found the problem. Workaround: 422 digital and analog input until it w 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(str 430 { 431 unsigned int reg_val = READREG(GPIO_CT 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.