cs4231.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,248 行 · 第 1/5 页
C
2,248 行
printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);#endif}static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg){ int timeout; unsigned char ret; for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) udelay(100);#ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);#endif __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); mb(); ret = __cs4231_readb(chip, CS4231P(chip, REG));#if 0 printk("codec in - reg 0x%x = 0x%x\n", chip->mce_bit | reg, ret);#endif return ret;}#ifdef CONFIG_SND_DEBUGvoid snd_cs4231_debug(cs4231_t *chip){ printk("CS4231 REGS: INDEX = 0x%02x ", __cs4231_readb(chip, CS4231P(chip, REGSEL))); printk(" STATUS = 0x%02x\n", __cs4231_readb(chip, CS4231P(chip, STATUS))); printk(" 0x00: left input = 0x%02x ", snd_cs4231_in(chip, 0x00)); printk(" 0x10: alt 1 (CFIG 2) = 0x%02x\n", snd_cs4231_in(chip, 0x10)); printk(" 0x01: right input = 0x%02x ", snd_cs4231_in(chip, 0x01)); printk(" 0x11: alt 2 (CFIG 3) = 0x%02x\n", snd_cs4231_in(chip, 0x11)); printk(" 0x02: GF1 left input = 0x%02x ", snd_cs4231_in(chip, 0x02)); printk(" 0x12: left line in = 0x%02x\n", snd_cs4231_in(chip, 0x12)); printk(" 0x03: GF1 right input = 0x%02x ", snd_cs4231_in(chip, 0x03)); printk(" 0x13: right line in = 0x%02x\n", snd_cs4231_in(chip, 0x13)); printk(" 0x04: CD left input = 0x%02x ", snd_cs4231_in(chip, 0x04)); printk(" 0x14: timer low = 0x%02x\n", snd_cs4231_in(chip, 0x14)); printk(" 0x05: CD right input = 0x%02x ", snd_cs4231_in(chip, 0x05)); printk(" 0x15: timer high = 0x%02x\n", snd_cs4231_in(chip, 0x15)); printk(" 0x06: left output = 0x%02x ", snd_cs4231_in(chip, 0x06)); printk(" 0x16: left MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x16)); printk(" 0x07: right output = 0x%02x ", snd_cs4231_in(chip, 0x07)); printk(" 0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17)); printk(" 0x08: playback format = 0x%02x ", snd_cs4231_in(chip, 0x08)); printk(" 0x18: IRQ status = 0x%02x\n", snd_cs4231_in(chip, 0x18)); printk(" 0x09: iface (CFIG 1) = 0x%02x ", snd_cs4231_in(chip, 0x09)); printk(" 0x19: left line out = 0x%02x\n", snd_cs4231_in(chip, 0x19)); printk(" 0x0a: pin control = 0x%02x ", snd_cs4231_in(chip, 0x0a)); printk(" 0x1a: mono control = 0x%02x\n", snd_cs4231_in(chip, 0x1a)); printk(" 0x0b: init & status = 0x%02x ", snd_cs4231_in(chip, 0x0b)); printk(" 0x1b: right line out = 0x%02x\n", snd_cs4231_in(chip, 0x1b)); printk(" 0x0c: revision & mode = 0x%02x ", snd_cs4231_in(chip, 0x0c)); printk(" 0x1c: record format = 0x%02x\n", snd_cs4231_in(chip, 0x1c)); printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d)); printk(" 0x1d: var freq (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x1d)); printk(" 0x0e: ply upr count = 0x%02x ", snd_cs4231_in(chip, 0x0e)); printk(" 0x1e: rec upr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e)); printk(" 0x0f: ply lwr count = 0x%02x ", snd_cs4231_in(chip, 0x0f)); printk(" 0x1f: rec lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1f));}#endif/* * CS4231 detection / MCE routines */static void snd_cs4231_busy_wait(cs4231_t *chip){ int timeout; /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */ for (timeout = 5; timeout > 0; timeout--) __cs4231_readb(chip, CS4231P(chip, REGSEL)); /* end of cleanup sequence */ for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) udelay(100);}static void snd_cs4231_mce_up(cs4231_t *chip){ unsigned long flags; int timeout; spin_lock_irqsave(&chip->lock, flags); for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) udelay(100);#ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) snd_printk("mce_up - auto calibration time out (0)\n");#endif chip->mce_bit |= CS4231_MCE; timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); if (timeout == 0x80) snd_printk("mce_up [%p]: serious init problem - codec still busy\n", chip->port); if (!(timeout & CS4231_MCE)) __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); spin_unlock_irqrestore(&chip->lock, flags);}static void snd_cs4231_mce_down(cs4231_t *chip){ unsigned long flags; int timeout; signed long time; spin_lock_irqsave(&chip->lock, flags); snd_cs4231_busy_wait(chip);#if 0 printk("(1) timeout = %i\n", timeout);#endif#ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));#endif chip->mce_bit &= ~CS4231_MCE; timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); if (timeout == 0x80) snd_printk("mce_down [%p]: serious init problem - codec still busy\n", chip->port); if ((timeout & CS4231_MCE) == 0) { spin_unlock_irqrestore(&chip->lock, flags); return; } snd_cs4231_busy_wait(chip); /* calibration process */ for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--) udelay(100); if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); spin_unlock_irqrestore(&chip->lock, flags); return; }#if 0 printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);#endif time = HZ / 4; while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { spin_unlock_irqrestore(&chip->lock, flags); if (time <= 0) { snd_printk("mce_down - auto calibration time out (2)\n"); return; } set_current_state(TASK_INTERRUPTIBLE); time = schedule_timeout(time); spin_lock_irqsave(&chip->lock, flags); }#if 0 printk("(3) jiffies = %li\n", jiffies);#endif time = HZ / 10; while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) { spin_unlock_irqrestore(&chip->lock, flags); if (time <= 0) { snd_printk("mce_down - auto calibration time out (3)\n"); return; } set_current_state(TASK_INTERRUPTIBLE); time = schedule_timeout(time); spin_lock_irqsave(&chip->lock, flags); } spin_unlock_irqrestore(&chip->lock, flags);#if 0 printk("(4) jiffies = %li\n", jiffies); snd_printk("mce_down - exit = 0x%x\n", __cs4231_readb(chip, CS4231P(chip, REGSEL)));#endif}#if 0 /* Unused for now... */static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size){ switch (format & 0xe0) { case CS4231_LINEAR_16: case CS4231_LINEAR_16_BIG: size >>= 1; break; case CS4231_ADPCM_16: return size >> 2; } if (format & CS4231_STEREO) size >>= 1; return size;}#endif#ifdef EBUS_SUPPORTstatic void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent){ snd_pcm_runtime_t *runtime = substream->runtime; while (1) { unsigned int dma_size = snd_pcm_lib_period_bytes(substream); unsigned int offset = dma_size * (*periods_sent); if (dma_size >= (1 << 24)) BUG(); if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size)) return;#if 0 printk("ebus_advance: Sent period %u (size[%x] offset[%x])\n", (*periods_sent), dma_size, offset);#endif (*periods_sent) = ((*periods_sent) + 1) % runtime->periods; }}#endifstatic void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on){#ifdef EBUS_SUPPORT if (chip->flags & CS4231_FLAG_EBUS) { if (what & CS4231_PLAYBACK_ENABLE) { if (on) { ebus_dma_prepare(&chip->eb2p, 0); ebus_dma_enable(&chip->eb2p, 1); snd_cs4231_ebus_advance_dma(&chip->eb2p, chip->playback_substream, &chip->p_periods_sent); } else { ebus_dma_enable(&chip->eb2p, 0); } } if (what & CS4231_RECORD_ENABLE) { if (on) { ebus_dma_prepare(&chip->eb2c, 1); ebus_dma_enable(&chip->eb2c, 1); snd_cs4231_ebus_advance_dma(&chip->eb2c, chip->capture_substream, &chip->c_periods_sent); } else { ebus_dma_enable(&chip->eb2c, 0); } } } else {#endif#ifdef SBUS_SUPPORT#endif#ifdef EBUS_SUPPORT }#endif}static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd){ cs4231_t *chip = snd_pcm_substream_chip(substream); int result = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: { unsigned int what = 0; snd_pcm_substream_t *s; struct list_head *pos; unsigned long flags; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); if (s == chip->playback_substream) { what |= CS4231_PLAYBACK_ENABLE; snd_pcm_trigger_done(s, substream); } else if (s == chip->capture_substream) { what |= CS4231_RECORD_ENABLE; snd_pcm_trigger_done(s, substream); } }#if 0 printk("TRIGGER: what[%x] on(%d)\n", what, (cmd == SNDRV_PCM_TRIGGER_START));#endif spin_lock_irqsave(&chip->lock, flags); if (cmd == SNDRV_PCM_TRIGGER_START) { cs4231_dma_trigger(chip, what, 1); chip->image[CS4231_IFACE_CTRL] |= what; if (what & CS4231_PLAYBACK_ENABLE) { snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, 0xff); snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, 0xff); } if (what & CS4231_RECORD_ENABLE) { snd_cs4231_out(chip, CS4231_REC_LWR_CNT, 0xff); snd_cs4231_out(chip, CS4231_REC_UPR_CNT, 0xff); } } else { cs4231_dma_trigger(chip, what, 0); chip->image[CS4231_IFACE_CTRL] &= ~what; } snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); spin_unlock_irqrestore(&chip->lock, flags); break; } default: result = -EINVAL; break; }#if 0 snd_cs4231_debug(chip);#endif return result;}/* * CODEC I/O */static unsigned char snd_cs4231_get_rate(unsigned int rate){ int i; for (i = 0; i < 14; i++) if (rate == rates[i]) return freq_bits[i]; // snd_BUG(); return freq_bits[13];}static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int channels){ unsigned char rformat; rformat = CS4231_LINEAR_8; switch (format) { case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break; case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break; case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break; case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break; case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break; } if (channels > 1) rformat |= CS4231_STEREO;#if 0 snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);#endif return rformat;}static void snd_cs4231_calibrate_mute(cs4231_t *chip, int mute){ unsigned long flags; mute = mute ? 1 : 0; spin_lock_irqsave(&chip->lock, flags); if (chip->calibrate_mute == mute) { spin_unlock_irqrestore(&chip->lock, flags); return; } if (!mute) { snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]); snd_cs4231_dout(chip, CS4231_RIGHT_INPUT, chip->image[CS4231_RIGHT_INPUT]); snd_cs4231_dout(chip, CS4231_LOOPBACK, chip->image[CS4231_LOOPBACK]); } snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]); snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]); snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]); snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]); snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]); snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]); snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN, mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]); snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN, mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]); snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]); chip->calibrate_mute = mute; spin_unlock_irqrestore(&chip->lock, flags);}static void snd_cs4231_playback_format(cs4231_t *chip, snd_pcm_hw_params_t *params, unsigned char pdfr){ unsigned long flags; down(&chip->mce_mutex); snd_cs4231_calibrate_mute(chip, 1); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ? (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) : pdfr); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); snd_cs4231_calibrate_mute(chip, 0); up(&chip->mce_mutex);}static void snd_cs4231_capture_format(cs4231_t *chip, snd_pcm_hw_params_t *params, unsigned char cdfr){ unsigned long flags; down(&chip->mce_mutex); snd_cs4231_calibrate_mute(chip, 1); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) { snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, ((chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) | (cdfr & 0x0f)); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); } snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); snd_cs4231_calibrate_mute(chip, 0); up(&chip->mce_mutex);}/* * Timer interface */static unsigned long snd_cs4231_timer_resolution(snd_timer_t *timer){ cs4231_t *chip = snd_timer_chip(timer);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?