static void snd_cs4236_suspend(struct snd_wss *chip) { int reg; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); for (reg = 0; reg < 32; reg++) chip->image[reg] = snd_wss_in(chip, reg); for (reg = 0; reg < 18; reg++) chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg)); for (reg = 2; reg < 9; reg++) chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg); spin_unlock_irqrestore(&chip->reg_lock, flags); }
static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0; #if 0 printk(KERN_DEBUG "get 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 spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; }
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; }
/* * 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; }