/* * Override for the CS4231 capture format function. * The AD1845 has much simpler format and rate selection. */ static void ad1845_capture_format(struct snd_wss *chip, struct snd_pcm_hw_params *params, unsigned char format) { unsigned long flags; unsigned rate = params_rate(params); /* * The AD1845 can't handle sample frequencies * outside of 4 kHZ to 50 kHZ */ if (rate > 50000) rate = 50000; else if (rate < 4000) rate = 4000; spin_lock_irqsave(&chip->reg_lock, flags); /* * Program the AD1845 correctly for the playback stream. * Note that we do NOT need to toggle the MCE bit because * the CAPTURE_ENABLE bit of the Interface Configuration * register is set. * * NOTE: We seem to need to write to the MSB before the LSB * to get the correct sample frequency. */ snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0)); snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8)); snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate); spin_unlock_irqrestore(&chip->reg_lock, flags); }
static int snd_sgalaxy_resume(struct device *pdev, unsigned int n) { struct snd_card *card = dev_get_drvdata(pdev); struct snd_wss *chip = card->private_data; chip->resume(chip); snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; }
static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; int shift_right = (kcontrol->private_value >> 19) & 0x07; int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; int change; unsigned short val1, val2; val1 = ucontrol->value.integer.value[0] & mask; val2 = ucontrol->value.integer.value[1] & mask; if (invert) { val1 = mask - val1; val2 = mask - val2; } val1 <<= shift_left; val2 <<= shift_right; spin_lock_irqsave(&chip->reg_lock, flags); val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)]; snd_wss_out(chip, left_reg, val1); snd_cs4236_ext_out(chip, right_reg, val2); spin_unlock_irqrestore(&chip->reg_lock, flags); return change; }
static void snd_cs4236_resume(struct snd_wss *chip) { int reg; unsigned long flags; snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); for (reg = 0; reg < 32; reg++) { switch (reg) { case CS4236_EXT_REG: case CS4231_VERSION: case 27: /* why? CS4235 - master left */ case 29: /* why? CS4235 - master right */ break; default: snd_wss_out(chip, reg, chip->image[reg]); break; } } for (reg = 0; reg < 18; reg++) snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]); for (reg = 2; reg < 9; reg++) { switch (reg) { case 7: break; default: snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]); } } spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); }
static void snd_cs4236_capture_format(struct snd_wss *chip, struct snd_pcm_hw_params *params, unsigned char cdfr) { unsigned long flags; unsigned char rate = divisor_to_rate_register(params->rate_den); spin_lock_irqsave(&chip->reg_lock, flags); /* set fast capture format change and clean capture FIFO */ snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20); snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0); snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x20); snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate); spin_unlock_irqrestore(&chip->reg_lock, flags); }
static void snd_cs4236_playback_format(struct snd_wss *chip, struct snd_pcm_hw_params *params, unsigned char pdfr) { unsigned long flags; unsigned char rate = divisor_to_rate_register(params->rate_den); spin_lock_irqsave(&chip->reg_lock, flags); /* set fast playback format change and clean playback FIFO */ snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10); snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0); snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x10); snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate); spin_unlock_irqrestore(&chip->reg_lock, flags); }
static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned short val1, val2; val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]); val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]); spin_lock_irqsave(&chip->reg_lock, flags); val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1; val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2; change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER]; snd_wss_out(chip, CS4235_LEFT_MASTER, val1); snd_wss_out(chip, CS4235_RIGHT_MASTER, val2); spin_unlock_irqrestore(&chip->reg_lock, flags); return change; }
static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned short enable, val; enable = ucontrol->value.integer.value[0] & 1; mutex_lock(&chip->mce_mutex); snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1); change = val != chip->image[CS4231_ALT_FEATURE_1]; snd_wss_out(chip, CS4231_ALT_FEATURE_1, val); val = snd_cs4236_ctrl_in(chip, 4) | 0xc0; snd_cs4236_ctrl_out(chip, 4, val); udelay(100); val &= ~0x40; snd_cs4236_ctrl_out(chip, 4, val); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); mutex_unlock(&chip->mce_mutex); #if 0 printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, " "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", snd_wss_in(chip, CS4231_ALT_FEATURE_1), snd_cs4236_ctrl_in(chip, 3), snd_cs4236_ctrl_in(chip, 4), snd_cs4236_ctrl_in(chip, 5), snd_cs4236_ctrl_in(chip, 6), snd_cs4236_ctrl_in(chip, 8)); #endif return change; }
int snd_cs4236_create(struct snd_card *card, unsigned long port, unsigned long cport, int irq, int dma1, int dma2, unsigned short hardware, unsigned short hwshare, struct snd_wss **rchip) { struct snd_wss *chip; unsigned char ver1, ver2; unsigned int reg; int err; *rchip = NULL; if (hardware == WSS_HW_DETECT) hardware = WSS_HW_DETECT3; if (cport < 0x100) { snd_printk(KERN_ERR "please, specify control port " "for CS4236+ chips\n"); return -ENODEV; } err = snd_wss_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip); if (err < 0) return err; if (!(chip->hardware & WSS_HW_CS4236B_MASK)) { snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers " "not available, hardware=0x%x\n", chip->hardware); snd_device_free(card, chip); return -ENODEV; } #if 0 { int idx; for (idx = 0; idx < 8; idx++) snd_printk(KERN_DEBUG "CD%i = 0x%x\n", idx, inb(chip->cport + idx)); for (idx = 0; idx < 9; idx++) snd_printk(KERN_DEBUG "C%i = 0x%x\n", idx, snd_cs4236_ctrl_in(chip, idx)); } #endif ver1 = snd_cs4236_ctrl_in(chip, 1); ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2); if (ver1 != ver2) { snd_printk(KERN_ERR "CS4236+ chip detected, but " "control port 0x%lx is not valid\n", cport); snd_device_free(card, chip); return -ENODEV; } snd_cs4236_ctrl_out(chip, 0, 0x00); snd_cs4236_ctrl_out(chip, 2, 0xff); snd_cs4236_ctrl_out(chip, 3, 0x00); snd_cs4236_ctrl_out(chip, 4, 0x80); snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE); snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); snd_cs4236_ctrl_out(chip, 7, 0x00); /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */ /* is working with this setup, other hardware should have */ /* different signal paths and this value should be selectable */ /* in the future */ snd_cs4236_ctrl_out(chip, 8, 0x8c); chip->rate_constraint = snd_cs4236_xrate; chip->set_playback_format = snd_cs4236_playback_format; chip->set_capture_format = snd_cs4236_capture_format; #ifdef CONFIG_PM chip->suspend = snd_cs4236_suspend; chip->resume = snd_cs4236_resume; #endif /* initialize extended registers */ for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); /* initialize compatible but more featured registers */ snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff); snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf); snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf); snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff); snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); switch (chip->hardware) { case WSS_HW_CS4235: case WSS_HW_CS4239: snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff); snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff); break; } *rchip = chip; return 0; }
int snd_cs4236_create(struct snd_card *card, unsigned long port, unsigned long cport, int irq, int dma1, int dma2, unsigned short hardware, unsigned short hwshare, struct snd_wss **rchip) { struct snd_wss *chip; unsigned char ver1, ver2; unsigned int reg; int err; *rchip = NULL; if (hardware == WSS_HW_DETECT) hardware = WSS_HW_DETECT3; err = snd_wss_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip); if (err < 0) return err; if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) { snd_printd("chip is not CS4236+, hardware=0x%x\n", chip->hardware); *rchip = chip; return 0; } #if 0 { int idx; for (idx = 0; idx < 8; idx++) snd_printk(KERN_DEBUG "CD%i = 0x%x\n", idx, inb(chip->cport + idx)); for (idx = 0; idx < 9; idx++) snd_printk(KERN_DEBUG "C%i = 0x%x\n", idx, snd_cs4236_ctrl_in(chip, idx)); } #endif if (cport < 0x100 || cport == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR "please, specify control port " "for CS4236+ chips\n"); snd_device_free(card, chip); return -ENODEV; } ver1 = snd_cs4236_ctrl_in(chip, 1); ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2); if (ver1 != ver2) { snd_printk(KERN_ERR "CS4236+ chip detected, but " "control port 0x%lx is not valid\n", cport); snd_device_free(card, chip); return -ENODEV; } snd_cs4236_ctrl_out(chip, 0, 0x00); snd_cs4236_ctrl_out(chip, 2, 0xff); snd_cs4236_ctrl_out(chip, 3, 0x00); snd_cs4236_ctrl_out(chip, 4, 0x80); reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE; snd_cs4236_ctrl_out(chip, 5, reg); snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); snd_cs4236_ctrl_out(chip, 7, 0x00); snd_cs4236_ctrl_out(chip, 8, 0x8c); chip->rate_constraint = snd_cs4236_xrate; chip->set_playback_format = snd_cs4236_playback_format; chip->set_capture_format = snd_cs4236_capture_format; #ifdef CONFIG_PM chip->suspend = snd_cs4236_suspend; chip->resume = snd_cs4236_resume; #endif for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff); snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf); snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf); snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff); snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); switch (chip->hardware) { case WSS_HW_CS4235: case WSS_HW_CS4239: snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff); snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff); break; } *rchip = chip; return 0; }
/* * Create an AD1845 PCM subdevice on the SoundScape. The AD1845 * is very much like a CS4231, with a few extra bits. We will * try to support at least some of the extra bits by overriding * some of the CS4231 callback. */ static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq, int dma1, int dma2) { register struct soundscape *sscape = get_card_soundscape(card); struct snd_wss *chip; int err; if (sscape->type == SSCAPE_VIVO) port += 4; if (dma1 == dma2) dma2 = -1; err = snd_wss_create(card, port, -1, irq, dma1, dma2, WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; struct snd_pcm *pcm; #define AD1845_FREQ_SEL_ENABLE 0x08 #define AD1845_PWR_DOWN_CTRL 0x1b #define AD1845_CRYS_CLOCK_SEL 0x1d /* * It turns out that the PLAYBACK_ENABLE bit is set * by the lowlevel driver ... * #define AD1845_IFACE_CONFIG \ (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE) snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); */ if (sscape->type != SSCAPE_VIVO) { int val; /* * The input clock frequency on the SoundScape must * be 14.31818 MHz, because we must set this register * to get the playback to sound correct ... */ snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); /* * More custom configuration: * a) select "mode 2" and provide a current drive of 8mA * b) enable frequency selection (for capture/playback) */ spin_lock_irqsave(&chip->reg_lock, flags); snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2 | 0x10); val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL); snd_wss_out(chip, AD1845_PWR_DOWN_CTRL, val | AD1845_FREQ_SEL_ENABLE); spin_unlock_irqrestore(&chip->reg_lock, flags); } err = snd_wss_pcm(chip, 0, &pcm); if (err < 0) { snd_printk(KERN_ERR "sscape: No PCM device " "for AD1845 chip\n"); goto _error; } err = snd_wss_mixer(chip); if (err < 0) { snd_printk(KERN_ERR "sscape: No mixer device " "for AD1845 chip\n"); goto _error; } err = snd_wss_timer(chip, 0, NULL); if (err < 0) { snd_printk(KERN_ERR "sscape: No timer device " "for AD1845 chip\n"); goto _error; } if (sscape->type != SSCAPE_VIVO) { err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip)); if (err < 0) { snd_printk(KERN_ERR "sscape: Could not create " "MIDI mixer control\n"); goto _error; } chip->set_playback_format = ad1845_playback_format; chip->set_capture_format = ad1845_capture_format; } strcpy(card->driver, "SoundScape"); strcpy(card->shortname, pcm->name); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", pcm->name, chip->port, chip->irq, chip->dma1, chip->dma2); sscape->chip = chip; } _error: return err; }
/* * Create an AD1845 PCM subdevice on the SoundScape. The AD1845 * is very much like a CS4231, with a few extra bits. We will * try to support at least some of the extra bits by overriding * some of the CS4231 callback. */ static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq, int dma1, int dma2) { register struct soundscape *sscape = get_card_soundscape(card); struct snd_wss *chip; int err; if (sscape->type == SSCAPE_VIVO) port += 4; if (dma1 == dma2) dma2 = -1; err = snd_wss_create(card, port, -1, irq, dma1, dma2, WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; struct snd_pcm *pcm; /* * It turns out that the PLAYBACK_ENABLE bit is set * by the lowlevel driver ... * #define AD1845_IFACE_CONFIG \ (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE) snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); */ if (sscape->type != SSCAPE_VIVO) { /* * The input clock frequency on the SoundScape must * be 14.31818 MHz, because we must set this register * to get the playback to sound correct ... */ snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); snd_wss_out(chip, AD1845_CLOCK, 0x20); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); } err = snd_wss_pcm(chip, 0, &pcm); if (err < 0) { snd_printk(KERN_ERR "sscape: No PCM device " "for AD1845 chip\n"); goto _error; } err = snd_wss_mixer(chip); if (err < 0) { snd_printk(KERN_ERR "sscape: No mixer device " "for AD1845 chip\n"); goto _error; } if (chip->hardware != WSS_HW_AD1848) { err = snd_wss_timer(chip, 0, NULL); if (err < 0) { snd_printk(KERN_ERR "sscape: No timer device " "for AD1845 chip\n"); goto _error; } } if (sscape->type != SSCAPE_VIVO) { err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip)); if (err < 0) { snd_printk(KERN_ERR "sscape: Could not create " "MIDI mixer control\n"); goto _error; } } strcpy(card->driver, "SoundScape"); strcpy(card->shortname, pcm->name); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", pcm->name, chip->port, chip->irq, chip->dma1, chip->dma2); sscape->chip = chip; } _error: return err; }