cs4231.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,248 行 · 第 1/5 页
C
2,248 行
return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;}static int snd_cs4231_timer_start(snd_timer_t *timer){ unsigned long flags; unsigned int ticks; cs4231_t *chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->lock, flags); ticks = timer->sticks; if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 || (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] || (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) { snd_cs4231_out(chip, CS4231_TIMER_HIGH, chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8)); snd_cs4231_out(chip, CS4231_TIMER_LOW, chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks); snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE); } spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_cs4231_timer_stop(snd_timer_t *timer){ unsigned long flags; cs4231_t *chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static void snd_cs4231_init(cs4231_t *chip){ unsigned long flags; snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printk("init: (1)\n");#endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | CS4231_RECORD_ENABLE | CS4231_RECORD_PIO | CS4231_CALIB_MODE); chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printk("init: (2)\n");#endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);#endif spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printk("init: (4)\n");#endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printk("init: (5)\n");#endif}static int snd_cs4231_open(cs4231_t *chip, unsigned int mode){ unsigned long flags; down(&chip->open_mutex); if ((chip->mode & mode)) { up(&chip->open_mutex); return -EAGAIN; } if (chip->mode & CS4231_MODE_OPEN) { chip->mode |= mode; up(&chip->open_mutex); return 0; } /* ok. now enable and ack CODEC IRQ */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); spin_unlock_irqrestore(&chip->lock, flags); chip->mode = mode; up(&chip->open_mutex); return 0;}static void snd_cs4231_close(cs4231_t *chip, unsigned int mode){ unsigned long flags; down(&chip->open_mutex); chip->mode &= ~mode; if (chip->mode & CS4231_MODE_OPEN) { up(&chip->open_mutex); return; } snd_cs4231_calibrate_mute(chip, 1); /* disable IRQ */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ /* now disable record & playback */ if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) { spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); spin_lock_irqsave(&chip->lock, flags); } /* clear IRQ again */ snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_calibrate_mute(chip, 0); chip->mode = 0; up(&chip->open_mutex);}/* * timer open/close */static int snd_cs4231_timer_open(snd_timer_t *timer){ cs4231_t *chip = snd_timer_chip(timer); snd_cs4231_open(chip, CS4231_MODE_TIMER); return 0;}static int snd_cs4231_timer_close(snd_timer_t * timer){ cs4231_t *chip = snd_timer_chip(timer); snd_cs4231_close(chip, CS4231_MODE_TIMER); return 0;}static struct _snd_timer_hardware snd_cs4231_timer_table ={ .flags = SNDRV_TIMER_HW_AUTO, .resolution = 9945, .ticks = 65535, .open = snd_cs4231_timer_open, .close = snd_cs4231_timer_close, .c_resolution = snd_cs4231_timer_resolution, .start = snd_cs4231_timer_start, .stop = snd_cs4231_timer_stop,};/* * ok.. exported functions.. */static int snd_cs4231_playback_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params){ cs4231_t *chip = snd_pcm_substream_chip(substream); unsigned char new_pdfr; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | snd_cs4231_get_rate(params_rate(hw_params)); snd_cs4231_playback_format(chip, hw_params, new_pdfr); return 0;}static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream){ return snd_pcm_lib_free_pages(substream);}static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_cs4231_capture_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params){ cs4231_t *chip = snd_pcm_substream_chip(substream); unsigned char new_cdfr; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | snd_cs4231_get_rate(params_rate(hw_params)); snd_cs4231_capture_format(chip, hw_params, new_cdfr); return 0;}static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream){ return snd_pcm_lib_free_pages(substream);}static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static void snd_cs4231_overrange(cs4231_t *chip){ unsigned long flags; unsigned char res; spin_lock_irqsave(&chip->lock, flags); res = snd_cs4231_in(chip, CS4231_TEST_INIT); spin_unlock_irqrestore(&chip->lock, flags); if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */ chip->capture_substream->runtime->overrange++;}static void snd_cs4231_generic_interrupt(cs4231_t *chip){ unsigned long flags; unsigned char status; status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); if (!status) return; if (status & CS4231_TIMER_IRQ) { if (chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); } if (status & CS4231_PLAYBACK_IRQ) snd_pcm_period_elapsed(chip->playback_substream); if (status & CS4231_RECORD_IRQ) { snd_cs4231_overrange(chip); snd_pcm_period_elapsed(chip->capture_substream); } /* ACK the CS4231 interrupt. */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); spin_unlock_irqrestore(&chip->lock, flags);}#ifdef SBUS_SUPPORTstatic irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs){ cs4231_t *chip = dev_id; u32 csr; csr = sbus_readl(chip->port + APCCSR); if (!(csr & (APC_INT_PENDING | APC_PLAY_INT | APC_CAPT_INT | APC_GENL_INT | APC_XINT_PEMP | APC_XINT_CEMP))) return IRQ_NONE; /* ACK the APC interrupt. */ sbus_writel(csr, chip->port + APCCSR); snd_cs4231_generic_interrupt(chip); return IRQ_HANDLED;}#endif#ifdef EBUS_SUPPORTstatic void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie){ cs4231_t *chip = cookie; if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) { snd_pcm_period_elapsed(chip->playback_substream); snd_cs4231_ebus_advance_dma(p, chip->playback_substream, &chip->p_periods_sent); }}static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie){ cs4231_t *chip = cookie; if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) { snd_pcm_period_elapsed(chip->capture_substream); snd_cs4231_ebus_advance_dma(p, chip->capture_substream, &chip->c_periods_sent); }}#endifstatic snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); size_t ptr, residue, period_bytes; if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) return 0; period_bytes = snd_pcm_lib_period_bytes(substream); ptr = period_bytes * chip->p_periods_sent;#ifdef EBUS_SUPPORT if (chip->flags & CS4231_FLAG_EBUS) { residue = ebus_dma_residue(&chip->eb2p); } else {#endif#ifdef SBUS_SUPPORT residue = sbus_readl(chip->port + APCPC);#endif#ifdef EBUS_SUPPORT }#endif ptr += (period_bytes - residue); return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); size_t ptr, residue, period_bytes; if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) return 0; period_bytes = snd_pcm_lib_period_bytes(substream); ptr = period_bytes * chip->c_periods_sent;#ifdef EBUS_SUPPORT if (chip->flags & CS4231_FLAG_EBUS) { residue = ebus_dma_residue(&chip->eb2c); } else {#endif#ifdef SBUS_SUPPORT residue = sbus_readl(chip->port + APCCC);#endif#ifdef EBUS_SUPPORT }#endif ptr += (period_bytes - residue); return bytes_to_frames(substream->runtime, ptr);}/* */static int snd_cs4231_probe(cs4231_t *chip){ unsigned long flags; int i, id, vers; unsigned char *ptr;#if 0 snd_cs4231_debug(chip);#endif id = vers = 0; for (i = 0; i < 50; i++) { mb(); if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) udelay(2000); else { spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2); id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f; vers = snd_cs4231_in(chip, CS4231_VERSION); spin_unlock_irqrestore(&chip->lock, flags); if (id == 0x0a) break; /* this is valid value */ } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?