linux/sound/pcmcia/vx/vxp_ops.c
<<
>>
Prefs
   1/*
   2 * Driver for Digigram VXpocket soundcards
   3 *
   4 * lowlevel routines for VXpocket soundcards
   5 *
   6 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
   7 *
   8 *   This program is free software; you can redistribute it and/or modify
   9 *   it under the terms of the GNU General Public License as published by
  10 *   the Free Software Foundation; either version 2 of the License, or
  11 *   (at your option) any later version.
  12 *
  13 *   This program is distributed in the hope that it will be useful,
  14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *   GNU General Public License for more details.
  17 *
  18 *   You should have received a copy of the GNU General Public License
  19 *   along with this program; if not, write to the Free Software
  20 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  21 */
  22
  23#include <linux/delay.h>
  24#include <linux/device.h>
  25#include <linux/firmware.h>
  26#include <linux/io.h>
  27#include <sound/core.h>
  28#include "vxpocket.h"
  29
  30
  31static int vxp_reg_offset[VX_REG_MAX] = {
  32        [VX_ICR]        = 0x00,         // ICR
  33        [VX_CVR]        = 0x01,         // CVR
  34        [VX_ISR]        = 0x02,         // ISR
  35        [VX_IVR]        = 0x03,         // IVR
  36        [VX_RXH]        = 0x05,         // RXH
  37        [VX_RXM]        = 0x06,         // RXM
  38        [VX_RXL]        = 0x07,         // RXL
  39        [VX_DMA]        = 0x04,         // DMA
  40        [VX_CDSP]       = 0x08,         // CDSP
  41        [VX_LOFREQ]     = 0x09,         // LFREQ
  42        [VX_HIFREQ]     = 0x0a,         // HFREQ
  43        [VX_DATA]       = 0x0b,         // DATA
  44        [VX_MICRO]      = 0x0c,         // MICRO
  45        [VX_DIALOG]     = 0x0d,         // DIALOG
  46        [VX_CSUER]      = 0x0e,         // CSUER
  47        [VX_RUER]       = 0x0f,         // RUER
  48};
  49
  50
  51static inline unsigned long vxp_reg_addr(struct vx_core *_chip, int reg)
  52{
  53        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
  54        return chip->port + vxp_reg_offset[reg];
  55}
  56
  57/*
  58 * snd_vx_inb - read a byte from the register
  59 * @offset: register offset
  60 */
  61static unsigned char vxp_inb(struct vx_core *chip, int offset)
  62{
  63        return inb(vxp_reg_addr(chip, offset));
  64}
  65
  66/*
  67 * snd_vx_outb - write a byte on the register
  68 * @offset: the register offset
  69 * @val: the value to write
  70 */
  71static void vxp_outb(struct vx_core *chip, int offset, unsigned char val)
  72{
  73        outb(val, vxp_reg_addr(chip, offset));
  74}
  75
  76/*
  77 * redefine macros to call directly
  78 */
  79#undef vx_inb
  80#define vx_inb(chip,reg)        vxp_inb((struct vx_core *)(chip), VX_##reg)
  81#undef vx_outb
  82#define vx_outb(chip,reg,val)   vxp_outb((struct vx_core *)(chip), VX_##reg,val)
  83
  84
  85/*
  86 * vx_check_magic - check the magic word on xilinx
  87 *
  88 * returns zero if a magic word is detected, or a negative error code.
  89 */
  90static int vx_check_magic(struct vx_core *chip)
  91{
  92        unsigned long end_time = jiffies + HZ / 5;
  93        int c;
  94        do {
  95                c = vx_inb(chip, CDSP);
  96                if (c == CDSP_MAGIC)
  97                        return 0;
  98                msleep(10);
  99        } while (time_after_eq(end_time, jiffies));
 100        snd_printk(KERN_ERR "cannot find xilinx magic word (%x)\n", c);
 101        return -EIO;
 102}
 103
 104
 105/*
 106 * vx_reset_dsp - reset the DSP
 107 */
 108
 109#define XX_DSP_RESET_WAIT_TIME          2       /* ms */
 110
 111static void vxp_reset_dsp(struct vx_core *_chip)
 112{
 113        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 114
 115        /* set the reset dsp bit to 1 */
 116        vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_DSP_RESET_MASK);
 117        vx_inb(chip, CDSP);
 118        mdelay(XX_DSP_RESET_WAIT_TIME);
 119        /* reset the bit */
 120        chip->regCDSP &= ~VXP_CDSP_DSP_RESET_MASK;
 121        vx_outb(chip, CDSP, chip->regCDSP);
 122        vx_inb(chip, CDSP);
 123        mdelay(XX_DSP_RESET_WAIT_TIME);
 124}
 125
 126/*
 127 * reset codec bit
 128 */
 129static void vxp_reset_codec(struct vx_core *_chip)
 130{
 131        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 132
 133        /* Set the reset CODEC bit to 1. */
 134        vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_CODEC_RESET_MASK);
 135        vx_inb(chip, CDSP);
 136        msleep(10);
 137        /* Set the reset CODEC bit to 0. */
 138        chip->regCDSP &= ~VXP_CDSP_CODEC_RESET_MASK;
 139        vx_outb(chip, CDSP, chip->regCDSP);
 140        vx_inb(chip, CDSP);
 141        msleep(1);
 142}
 143
 144/*
 145 * vx_load_xilinx_binary - load the xilinx binary image
 146 * the binary image is the binary array converted from the bitstream file.
 147 */
 148static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *fw)
 149{
 150        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 151        unsigned int i;
 152        int c;
 153        int regCSUER, regRUER;
 154        const unsigned char *image;
 155        unsigned char data;
 156
 157        /* Switch to programmation mode */
 158        chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK;
 159        vx_outb(chip, DIALOG, chip->regDIALOG);
 160
 161        /* Save register CSUER and RUER */
 162        regCSUER = vx_inb(chip, CSUER);
 163        regRUER = vx_inb(chip, RUER);
 164
 165        /* reset HF0 and HF1 */
 166        vx_outb(chip, ICR, 0);
 167
 168        /* Wait for answer HF2 equal to 1 */
 169        snd_printdd(KERN_DEBUG "check ISR_HF2\n");
 170        if (vx_check_isr(_chip, ISR_HF2, ISR_HF2, 20) < 0)
 171                goto _error;
 172
 173        /* set HF1 for loading xilinx binary */
 174        vx_outb(chip, ICR, ICR_HF1);
 175        image = fw->data;
 176        for (i = 0; i < fw->size; i++, image++) {
 177                data = *image;
 178                if (vx_wait_isr_bit(_chip, ISR_TX_EMPTY) < 0)
 179                        goto _error;
 180                vx_outb(chip, TXL, data);
 181                /* wait for reading */
 182                if (vx_wait_for_rx_full(_chip) < 0)
 183                        goto _error;
 184                c = vx_inb(chip, RXL);
 185                if (c != (int)data)
 186                        snd_printk(KERN_ERR "vxpocket: load xilinx mismatch at %d: 0x%x != 0x%x\n", i, c, (int)data);
 187        }
 188
 189        /* reset HF1 */
 190        vx_outb(chip, ICR, 0);
 191
 192        /* wait for HF3 */
 193        if (vx_check_isr(_chip, ISR_HF3, ISR_HF3, 20) < 0)
 194                goto _error;
 195
 196        /* read the number of bytes received */
 197        if (vx_wait_for_rx_full(_chip) < 0)
 198                goto _error;
 199
 200        c = (int)vx_inb(chip, RXH) << 16;
 201        c |= (int)vx_inb(chip, RXM) << 8;
 202        c |= vx_inb(chip, RXL);
 203
 204        snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%Zx\n", c, fw->size);
 205
 206        vx_outb(chip, ICR, ICR_HF0);
 207
 208        /* TEMPO 250ms : wait until Xilinx is downloaded */
 209        msleep(300);
 210
 211        /* test magical word */
 212        if (vx_check_magic(_chip) < 0)
 213                goto _error;
 214
 215        /* Restore register 0x0E and 0x0F (thus replacing COR and FCSR) */
 216        vx_outb(chip, CSUER, regCSUER);
 217        vx_outb(chip, RUER, regRUER);
 218
 219        /* Reset the Xilinx's signal enabling IO access */
 220        chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK;
 221        vx_outb(chip, DIALOG, chip->regDIALOG);
 222        vx_inb(chip, DIALOG);
 223        msleep(10);
 224        chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK;
 225        vx_outb(chip, DIALOG, chip->regDIALOG);
 226        vx_inb(chip, DIALOG);
 227
 228        /* Reset of the Codec */
 229        vxp_reset_codec(_chip);
 230        vx_reset_dsp(_chip);
 231
 232        return 0;
 233
 234 _error:
 235        vx_outb(chip, CSUER, regCSUER);
 236        vx_outb(chip, RUER, regRUER);
 237        chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK;
 238        vx_outb(chip, DIALOG, chip->regDIALOG);
 239        return -EIO;
 240}
 241
 242
 243/*
 244 * vxp_load_dsp - load_dsp callback
 245 */
 246static int vxp_load_dsp(struct vx_core *vx, int index, const struct firmware *fw)
 247{
 248        int err;
 249
 250        switch (index) {
 251        case 0:
 252                /* xilinx boot */
 253                if ((err = vx_check_magic(vx)) < 0)
 254                        return err;
 255                if ((err = snd_vx_load_boot_image(vx, fw)) < 0)
 256                        return err;
 257                return 0;
 258        case 1:
 259                /* xilinx image */
 260                return vxp_load_xilinx_binary(vx, fw);
 261        case 2:
 262                /* DSP boot */
 263                return snd_vx_dsp_boot(vx, fw);
 264        case 3:
 265                /* DSP image */
 266                return snd_vx_dsp_load(vx, fw);
 267        default:
 268                snd_BUG();
 269                return -EINVAL;
 270        }
 271}
 272                
 273
 274/*
 275 * vx_test_and_ack - test and acknowledge interrupt
 276 *
 277 * called from irq hander, too
 278 *
 279 * spinlock held!
 280 */
 281static int vxp_test_and_ack(struct vx_core *_chip)
 282{
 283        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 284
 285        /* not booted yet? */
 286        if (! (_chip->chip_status & VX_STAT_XILINX_LOADED))
 287                return -ENXIO;
 288
 289        if (! (vx_inb(chip, DIALOG) & VXP_DLG_MEMIRQ_MASK))
 290                return -EIO;
 291        
 292        /* ok, interrupts generated, now ack it */
 293        /* set ACQUIT bit up and down */
 294        vx_outb(chip, DIALOG, chip->regDIALOG | VXP_DLG_ACK_MEMIRQ_MASK);
 295        /* useless read just to spend some time and maintain
 296         * the ACQUIT signal up for a while ( a bus cycle )
 297         */
 298        vx_inb(chip, DIALOG);
 299        vx_outb(chip, DIALOG, chip->regDIALOG & ~VXP_DLG_ACK_MEMIRQ_MASK);
 300
 301        return 0;
 302}
 303
 304
 305/*
 306 * vx_validate_irq - enable/disable IRQ
 307 */
 308static void vxp_validate_irq(struct vx_core *_chip, int enable)
 309{
 310        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 311
 312        /* Set the interrupt enable bit to 1 in CDSP register */
 313        if (enable)
 314                chip->regCDSP |= VXP_CDSP_VALID_IRQ_MASK;
 315        else
 316                chip->regCDSP &= ~VXP_CDSP_VALID_IRQ_MASK;
 317        vx_outb(chip, CDSP, chip->regCDSP);
 318}
 319
 320/*
 321 * vx_setup_pseudo_dma - set up the pseudo dma read/write mode.
 322 * @do_write: 0 = read, 1 = set up for DMA write
 323 */
 324static void vx_setup_pseudo_dma(struct vx_core *_chip, int do_write)
 325{
 326        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 327
 328        /* Interrupt mode and HREQ pin enabled for host transmit / receive data transfers */
 329        vx_outb(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ);
 330        /* Reset the pseudo-dma register */
 331        vx_inb(chip, ISR);
 332        vx_outb(chip, ISR, 0);
 333
 334        /* Select DMA in read/write transfer mode and in 16-bit accesses */
 335        chip->regDIALOG |= VXP_DLG_DMA16_SEL_MASK;
 336        chip->regDIALOG |= do_write ? VXP_DLG_DMAWRITE_SEL_MASK : VXP_DLG_DMAREAD_SEL_MASK;
 337        vx_outb(chip, DIALOG, chip->regDIALOG);
 338
 339}
 340
 341/*
 342 * vx_release_pseudo_dma - disable the pseudo-DMA mode
 343 */
 344static void vx_release_pseudo_dma(struct vx_core *_chip)
 345{
 346        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 347
 348        /* Disable DMA and 16-bit accesses */
 349        chip->regDIALOG &= ~(VXP_DLG_DMAWRITE_SEL_MASK|
 350                             VXP_DLG_DMAREAD_SEL_MASK|
 351                             VXP_DLG_DMA16_SEL_MASK);
 352        vx_outb(chip, DIALOG, chip->regDIALOG);
 353        /* HREQ pin disabled. */
 354        vx_outb(chip, ICR, 0);
 355}
 356
 357/*
 358 * vx_pseudo_dma_write - write bulk data on pseudo-DMA mode
 359 * @count: data length to transfer in bytes
 360 *
 361 * data size must be aligned to 6 bytes to ensure the 24bit alignment on DSP.
 362 * NB: call with a certain lock!
 363 */
 364static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
 365                          struct vx_pipe *pipe, int count)
 366{
 367        long port = vxp_reg_addr(chip, VX_DMA);
 368        int offset = pipe->hw_ptr;
 369        unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
 370
 371        vx_setup_pseudo_dma(chip, 1);
 372        if (offset + count > pipe->buffer_bytes) {
 373                int length = pipe->buffer_bytes - offset;
 374                count -= length;
 375                length >>= 1; /* in 16bit words */
 376                /* Transfer using pseudo-dma. */
 377                while (length-- > 0) {
 378                        outw(cpu_to_le16(*addr), port);
 379                        addr++;
 380                }
 381                addr = (unsigned short *)runtime->dma_area;
 382                pipe->hw_ptr = 0;
 383        }
 384        pipe->hw_ptr += count;
 385        count >>= 1; /* in 16bit words */
 386        /* Transfer using pseudo-dma. */
 387        while (count-- > 0) {
 388                outw(cpu_to_le16(*addr), port);
 389                addr++;
 390        }
 391        vx_release_pseudo_dma(chip);
 392}
 393
 394
 395/*
 396 * vx_pseudo_dma_read - read bulk data on pseudo DMA mode
 397 * @offset: buffer offset in bytes
 398 * @count: data length to transfer in bytes
 399 *
 400 * the read length must be aligned to 6 bytes, as well as write.
 401 * NB: call with a certain lock!
 402 */
 403static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
 404                         struct vx_pipe *pipe, int count)
 405{
 406        struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip;
 407        long port = vxp_reg_addr(chip, VX_DMA);
 408        int offset = pipe->hw_ptr;
 409        unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
 410
 411        if (snd_BUG_ON(count % 2))
 412                return;
 413        vx_setup_pseudo_dma(chip, 0);
 414        if (offset + count > pipe->buffer_bytes) {
 415                int length = pipe->buffer_bytes - offset;
 416                count -= length;
 417                length >>= 1; /* in 16bit words */
 418                /* Transfer using pseudo-dma. */
 419                while (length-- > 0)
 420                        *addr++ = le16_to_cpu(inw(port));
 421                addr = (unsigned short *)runtime->dma_area;
 422                pipe->hw_ptr = 0;
 423        }
 424        pipe->hw_ptr += count;
 425        count >>= 1; /* in 16bit words */
 426        /* Transfer using pseudo-dma. */
 427        while (count-- > 1)
 428                *addr++ = le16_to_cpu(inw(port));
 429        /* Disable DMA */
 430        pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK;
 431        vx_outb(chip, DIALOG, pchip->regDIALOG);
 432        /* Read the last word (16 bits) */
 433        *addr = le16_to_cpu(inw(port));
 434        /* Disable 16-bit accesses */
 435        pchip->regDIALOG &= ~VXP_DLG_DMA16_SEL_MASK;
 436        vx_outb(chip, DIALOG, pchip->regDIALOG);
 437        /* HREQ pin disabled. */
 438        vx_outb(chip, ICR, 0);
 439}
 440
 441
 442/*
 443 * write a codec data (24bit)
 444 */
 445static void vxp_write_codec_reg(struct vx_core *chip, int codec, unsigned int data)
 446{
 447        int i;
 448
 449        /* Activate access to the corresponding codec register */
 450        if (! codec)
 451                vx_inb(chip, LOFREQ);
 452        else
 453                vx_inb(chip, CODEC2);
 454                
 455        /* We have to send 24 bits (3 x 8 bits). Start with most signif. Bit */
 456        for (i = 0; i < 24; i++, data <<= 1)
 457                vx_outb(chip, DATA, ((data & 0x800000) ? VX_DATA_CODEC_MASK : 0));
 458        
 459        /* Terminate access to codec registers */
 460        vx_inb(chip, HIFREQ);
 461}
 462
 463
 464/*
 465 * vx_set_mic_boost - set mic boost level (on vxp440 only)
 466 * @boost: 0 = 20dB, 1 = +38dB
 467 */
 468void vx_set_mic_boost(struct vx_core *chip, int boost)
 469{
 470        struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip;
 471
 472        if (chip->chip_status & VX_STAT_IS_STALE)
 473                return;
 474
 475        mutex_lock(&chip->lock);
 476        if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) {
 477                if (boost) {
 478                        /* boost: 38 dB */
 479                        pchip->regCDSP &= ~P24_CDSP_MIC20_SEL_MASK;
 480                        pchip->regCDSP |=  P24_CDSP_MIC38_SEL_MASK;
 481                } else {
 482                        /* minimum value: 20 dB */
 483                        pchip->regCDSP |=  P24_CDSP_MIC20_SEL_MASK;
 484                        pchip->regCDSP &= ~P24_CDSP_MIC38_SEL_MASK;
 485                }
 486                vx_outb(chip, CDSP, pchip->regCDSP);
 487        }
 488        mutex_unlock(&chip->lock);
 489}
 490
 491/*
 492 * remap the linear value (0-8) to the actual value (0-15)
 493 */
 494static int vx_compute_mic_level(int level)
 495{
 496        switch (level) {
 497        case 5: level = 6 ; break;
 498        case 6: level = 8 ; break;
 499        case 7: level = 11; break;
 500        case 8: level = 15; break;
 501        default: break ;
 502        }
 503        return level;
 504}
 505
 506/*
 507 * vx_set_mic_level - set mic level (on vxpocket only)
 508 * @level: the mic level = 0 - 8 (max)
 509 */
 510void vx_set_mic_level(struct vx_core *chip, int level)
 511{
 512        struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip;
 513
 514        if (chip->chip_status & VX_STAT_IS_STALE)
 515                return;
 516
 517        mutex_lock(&chip->lock);
 518        if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) {
 519                level = vx_compute_mic_level(level);
 520                vx_outb(chip, MICRO, level);
 521        }
 522        mutex_unlock(&chip->lock);
 523}
 524
 525
 526/*
 527 * change the input audio source
 528 */
 529static void vxp_change_audio_source(struct vx_core *_chip, int src)
 530{
 531        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 532
 533        switch (src) {
 534        case VX_AUDIO_SRC_DIGITAL:
 535                chip->regCDSP |= VXP_CDSP_DATAIN_SEL_MASK;
 536                vx_outb(chip, CDSP, chip->regCDSP);
 537                break;
 538        case VX_AUDIO_SRC_LINE:
 539                chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK;
 540                if (_chip->type == VX_TYPE_VXP440)
 541                        chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK;
 542                else
 543                        chip->regCDSP &= ~VXP_CDSP_MIC_SEL_MASK;
 544                vx_outb(chip, CDSP, chip->regCDSP);
 545                break;
 546        case VX_AUDIO_SRC_MIC:
 547                chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK;
 548                /* reset mic levels */
 549                if (_chip->type == VX_TYPE_VXP440) {
 550                        chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK;
 551                        if (chip->mic_level)
 552                                chip->regCDSP |=  P24_CDSP_MIC38_SEL_MASK;
 553                        else
 554                                chip->regCDSP |= P24_CDSP_MIC20_SEL_MASK;
 555                        vx_outb(chip, CDSP, chip->regCDSP);
 556                } else {
 557                        chip->regCDSP |= VXP_CDSP_MIC_SEL_MASK;
 558                        vx_outb(chip, CDSP, chip->regCDSP);
 559                        vx_outb(chip, MICRO, vx_compute_mic_level(chip->mic_level));
 560                }
 561                break;
 562        }
 563}
 564
 565/*
 566 * change the clock source
 567 * source = INTERNAL_QUARTZ or UER_SYNC
 568 */
 569static void vxp_set_clock_source(struct vx_core *_chip, int source)
 570{
 571        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 572
 573        if (source == INTERNAL_QUARTZ)
 574                chip->regCDSP &= ~VXP_CDSP_CLOCKIN_SEL_MASK;
 575        else
 576                chip->regCDSP |= VXP_CDSP_CLOCKIN_SEL_MASK;
 577        vx_outb(chip, CDSP, chip->regCDSP);
 578}
 579
 580
 581/*
 582 * reset the board
 583 */
 584static void vxp_reset_board(struct vx_core *_chip, int cold_reset)
 585{
 586        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
 587
 588        chip->regCDSP = 0;
 589        chip->regDIALOG = 0;
 590}
 591
 592
 593/*
 594 * callbacks
 595 */
 596/* exported */
 597struct snd_vx_ops snd_vxpocket_ops = {
 598        .in8 = vxp_inb,
 599        .out8 = vxp_outb,
 600        .test_and_ack = vxp_test_and_ack,
 601        .validate_irq = vxp_validate_irq,
 602        .write_codec = vxp_write_codec_reg,
 603        .reset_codec = vxp_reset_codec,
 604        .change_audio_source = vxp_change_audio_source,
 605        .set_clock_source = vxp_set_clock_source,
 606        .load_dsp = vxp_load_dsp,
 607        .add_controls = vxp_add_mic_controls,
 608        .reset_dsp = vxp_reset_dsp,
 609        .reset_board = vxp_reset_board,
 610        .dma_write = vxp_dma_write,
 611        .dma_read = vxp_dma_read,
 612};
 613