/** Sets the sampling rate. * \par Description: * Sets the sampling rate. * \param nCodec - Codec. * \param nReg - Register. * \param nRate - Sampling rate. * \author Arno Klenke *****************************************************************************/ status_t ac97_set_rate( AC97AudioDriver_s* psDriver, int nCodec, uint8 nReg, uint nRate ) { /* Check double-rate rates */ printk("Set rate %i\n", nRate ); if( ( psDriver->nExtID[nCodec] & AC97_EI_DRA ) && nReg == AC97_PCM_FRONT_DAC_RATE ) { uint16 nVal = ac97_read( psDriver, nCodec, AC97_EXTENDED_STATUS ); nVal &= ~AC97_EA_DRA; if( nRate > 48000 ) nVal |= AC97_EA_DRA; ac97_write( psDriver, nCodec, AC97_EXTENDED_STATUS, nVal ); } if( nReg == AC97_SPDIF_CONTROL ) { /* TODO: Check if this is right */ uint16 nVal = AC97_SC_COPY; switch( nRate ) { case 44100: nVal |= AC97_SC_SPSR_44K; break; case 48000: nVal |= AC97_SC_SPSR_48K; break; case 32000: nVal |= AC97_SC_SPSR_32K; break; default: ac97_enable_spdif( psDriver, nCodec, false ); return( -EINVAL ); break; } /* Disable SPDIF */ ac97_enable_spdif( psDriver, nCodec, false ); /* Write value */ ac97_write( psDriver, nCodec, nReg, nVal ); /* Enable spdif */ ac97_enable_spdif( psDriver, nCodec, true ); printk( "SPDIF programmed\n" ); return( 0 ); } ac97_write( psDriver, nCodec, nReg, nRate ); uint16 nNewRate = ac97_read( psDriver, nCodec, nReg ); if( nRate != nNewRate ) { printk( "AC97SetRate(): Wanted %i, Got %i\n", (int)nRate, (int)nNewRate ); return( -EINVAL ); } return( 0 ); }
/** Test the resolution of one volume control. * \par Description: * Test the resolution of one volume control. * \param nCodec - Codec. * \param nReg - Register. * \internal * \author Arno Klenke *****************************************************************************/ static int ac97_test_resolution( AC97AudioDriver_s* psDriver, int nCodec, uint8 nReg ) { int nRes = 0; if( ac97_write( psDriver, nCodec, nReg, 0x0008 ) == 0 && ac97_read( psDriver, nCodec, nReg ) == 0x0008 ) nRes = 4; if( ac97_write( psDriver, nCodec, nReg, 0x0010 ) == 0 && ac97_read( psDriver, nCodec, nReg ) == 0x0010 ) nRes = 5; if( ac97_write( psDriver, nCodec, nReg, 0x0020 ) == 0 && ac97_read( psDriver, nCodec, nReg ) == 0x0020 ) nRes = 6; //printk( "Register %x resolution %i\n", (uint)nReg, nRes ); return( nRes ); }
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) { u16 retry_cnt = 0; retry: if (try_warm && soc_ac97_ops.warm_reset) { soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, AC97_RESET) == 0x0090) return 1; } soc_ac97_ops.reset(codec->ac97); ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); if (ac97_read(codec, AC97_RESET) != 0x0090) goto err; return 0; err: while (retry_cnt++ < 10) goto retry; printk(KERN_ERR "AD1980 AC97 reset failed\n"); return -EIO; }
/** Writes a volume to the microphone mixer. * \par Description: * Writes a volume to the microphone mixer. * \param nCodec - Codec. * \param nValue - Volume. Value between 0 and 100. * \author Arno Klenke *****************************************************************************/ static void ac97_write_mic_mixer( AC97AudioDriver_s* psDriver, int nCodec, int nValue ) { /* Find mixer */ int nScale = 32; AC97Mixer_s* psMixer = NULL; uint i; for( i = 0; i < psDriver->nNumMixer; i++ ) { if( ( psDriver->asMixer[i].nCodec == nCodec ) && ( psDriver->asMixer[i].nReg == AC97_MIC_VOL ) ) { nScale = ( 1 << psDriver->asMixer[i].nScale ); psMixer = &psDriver->asMixer[i]; break; } } if( psMixer == NULL ) { printk("Error: Could not find mixer %i:%x\n", nCodec, AC97_MIC_VOL ); return; } if( nValue == 0 ) psMixer->nValue = AC97_MUTE; else { /* Calculate value */ psMixer->nValue = psMixer->nValue & ~0x801f; nValue = ( ( 100 - nValue ) * nScale ) / 100; if( nValue >= nScale ) nValue = nScale - 1; psMixer->nValue |= nValue; } //printk( "Write mixer %x::%x\n", AC97_MIC_VOL, (uint)psMixer->nValue ); ac97_write( psDriver, nCodec, AC97_MIC_VOL, psMixer->nValue ); }
/** Handle ac97 driver ioctl. * \par Description: * Handle ac97 driver ioctl. * \param psDriver - AC97 driver structure. * \param nCommand - Command. * \param pArgs - Args. * \param bFromKernel - Ioctl from kernel. * \author Arno Klenke *****************************************************************************/ status_t ac97_ioctl( AC97AudioDriver_s* psDriver, uint32 nCommand, void *pArgs, bool bFromKernel ) { switch( nCommand ) { case AC97_GET_CODEC_INFO: memcpy_to_user( pArgs, psDriver, sizeof( AC97AudioDriver_s ) ); break; case AC97_WAIT: { AC97RegOp_s sOp; memcpy_from_user( &sOp, pArgs, sizeof( AC97RegOp_s ) ); psDriver->pfWait( psDriver->pDriverData, sOp.nCodec ); } break; case AC97_READ: { AC97RegOp_s sOp; memcpy_from_user( &sOp, pArgs, sizeof( AC97RegOp_s ) ); sOp.nVal = ac97_read( psDriver, sOp.nCodec, sOp.nReg ); memcpy_to_user( pArgs, &sOp, sizeof( AC97RegOp_s ) ); } break; case AC97_WRITE: { AC97RegOp_s sOp; memcpy_from_user( &sOp, pArgs, sizeof( AC97RegOp_s ) ); ac97_write( psDriver, sOp.nCodec, sOp.nReg, sOp.nVal ); } break; default: return( -EINVAL ); } return( 0 ); }
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) { u16 retry_cnt = 0; retry: if (try_warm && soc_ac97_ops.warm_reset) { soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, AC97_RESET) == 0x0090) return 1; } soc_ac97_ops.reset(codec->ac97); /* Set bit 16slot in register 74h, then every slot will has only 16 * bits. This command is sent out in 20bit mode, in which case the * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); if (ac97_read(codec, AC97_RESET) != 0x0090) goto err; return 0; err: while (retry_cnt++ < 10) goto retry; printk(KERN_ERR "AD1980 AC97 reset failed\n"); return -EIO; }
/** Writes a volume to a mono mixer. * \par Description: * Writes a volume to a mono mixer. * \param nCodec - Codec. * \param nReg - Register. * \param nVolume - Volume. Value between 0 and 100. * \author Arno Klenke *****************************************************************************/ static void ac97_write_mono_mixer( AC97AudioDriver_s* psDriver, int nCodec, uint8 nReg, int nVolume ) { /* Find mixer */ int nScale = 32; AC97Mixer_s* psMixer = NULL; uint i; for( i = 0; i < psDriver->nNumMixer; i++ ) { if( ( psDriver->asMixer[i].nCodec == nCodec ) && ( psDriver->asMixer[i].nReg == nReg ) ) { nScale = ( 1 << psDriver->asMixer[i].nScale ); psMixer = &psDriver->asMixer[i]; break; } } if( psMixer == NULL ) { printk("Error: Could not find mixer %i:%x\n", nCodec, (uint)nReg ); return; } if( nVolume == 0 ) psMixer->nValue = AC97_MUTE; else { /* Calculate value */ nVolume = ( ( 100 - nVolume ) * nScale ) / 100; if( nVolume >= nScale ) nVolume = nScale - 1; psMixer->nValue = nVolume; } //printf( "Write mixer %x::%x\n", (uint)nReg, (uint)pcMixer->m_nValue ); ac97_write( psDriver, nCodec, nReg, psMixer->nValue ); }
status_t ac97_resume_codec( AC97AudioDriver_s* psDriver, int nCodec ) { printk( "Resume AC97 codec #%i\n", nCodec ); int i; ac97_wait( psDriver, nCodec ); /* Powerup codec */ ac97_write( psDriver, nCodec, AC97_POWER_CONTROL, 0 ); ac97_write( psDriver, nCodec, AC97_RESET, 0 ); snooze( 100 ); ac97_write( psDriver, nCodec, AC97_POWER_CONTROL, 0 ); ac97_write( psDriver, nCodec, AC97_GENERAL_PURPOSE, 0 ); /* Restore status */ ac97_write( psDriver, nCodec, AC97_EXTENDED_ID, psDriver->nExtID[nCodec] ); ac97_write( psDriver, nCodec, AC97_EXTENDED_STATUS,psDriver->nExtStat[nCodec] ); /* Restore mixer */ for( i = 0; i < psDriver->nNumMixer; i++ ) { AC97Mixer_s* psMixer = &psDriver->asMixer[i]; ac97_write( psDriver, psMixer->nCodec, psMixer->nReg, psMixer->nValue ); } return( 0 ); }
static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; u16 status, rate; BUG_ON(event != SND_SOC_DAPM_PRE_PMD); /* Gracefully shut down the voice interface. */ status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000; rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); schedule_timeout_interruptible(msecs_to_jiffies(1)); ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); ac97_write(codec, AC97_EXTENDED_MID, status); return 0; }
/**Suspends one card. * \par Description: * Suspends one card. * \param psDriver - AC97 driver structure. * \author Arno Klenke *****************************************************************************/ status_t ac97_suspend( AC97AudioDriver_s* psDriver ) { int nCodec; for( nCodec = 0; nCodec < psDriver->nCodecs; nCodec++ ) { ac97_write( psDriver, nCodec, AC97_POWER_CONTROL, AC97_PWR_D3 ); } return( 0 ); }
void init_wm9714(void) { //Register 04h controls the headphone output pins, HPL and HPR. ac97_write(0x04, (1 << 14) | (10 << 8) | (1 << 6) |10); //Register 0Ch controls the audio DACs ac97_write(0x0c, 0); ac97_write(0x1c, (2 << 6) | (2 << 4)); ac97_write(0x24, 1 << 4); ac97_write(0x26, 0); ac97_write(0x2a, 1); ac97_write(0x2c, 0xac44); ac97_write(0x3c, 0); ac97_write(0x3e, 0); }
static int ad1980_soc_probe(struct snd_soc_codec *codec) { int ret; u16 vendor_id2; u16 ext_status; printk(KERN_INFO "AD1980 SoC Audio Codec\n"); ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); return ret; } ret = ad1980_reset(codec, 0); if (ret < 0) { printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); goto reset_err; } if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) { ret = -ENODEV; goto reset_err; } vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); if (vendor_id2 != 0x5370) { if (vendor_id2 != 0x5374) { ret = -ENODEV; goto reset_err; } else { printk(KERN_WARNING "ad1980: " "Found AD1981 - only 2/2 IN/OUT Channels " "supported\n"); } } ac97_write(codec, AC97_MASTER, 0x0000); ac97_write(codec, AC97_PCM, 0x0000); ac97_write(codec, AC97_REC_GAIN, 0x0000); ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls, ARRAY_SIZE(ad1980_snd_ac97_controls)); return 0; reset_err: snd_soc_free_ac97_codec(codec); return ret; }
/** Enables or disables the spdif output. * \par Description: * Enables or disables the spdif output. * \par Note: * Use the AC97SupportsSPDIF() method first. * \param nCodec - Codec. * \param bEnable - Enable or disable. * \author Arno Klenke *****************************************************************************/ status_t ac97_enable_spdif( AC97AudioDriver_s* psDriver, int nCodec, bool bEnable ) { if( !ac97_supports_spdif( psDriver, nCodec ) ) return( -EINVAL ); uint16 nVal = ac97_read( psDriver, nCodec, AC97_EXTENDED_STATUS ); nVal &= ~AC97_EA_SPDIF; if( bEnable ) nVal |= AC97_EA_SPDIF; ac97_write( psDriver, nCodec, AC97_EXTENDED_STATUS, nVal ); printk( "EXT %x\n", (uint)nVal ); return( 0 ); }
static int ad1980_soc_probe(struct snd_soc_codec *codec) { int ret; u16 vendor_id2; u16 ext_status; ; ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { ; return ret; } ret = ad1980_reset(codec, 0); if (ret < 0) { ; goto reset_err; } /* Read out vendor ID to make sure it is ad1980 */ if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) goto reset_err; vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); if (vendor_id2 != 0x5370) { if (vendor_id2 != 0x5374) goto reset_err; else // printk(KERN_WARNING "ad1980: " // "Found AD1981 - only 2/2 IN/OUT Channels " ; } /* unmute captures and playbacks volume */ ac97_write(codec, AC97_MASTER, 0x0000); ac97_write(codec, AC97_PCM, 0x0000); ac97_write(codec, AC97_REC_GAIN, 0x0000); ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); /*power on LFE/CENTER/Surround DACs*/ ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); snd_soc_add_controls(codec, ad1980_snd_ac97_controls, ARRAY_SIZE(ad1980_snd_ac97_controls)); return 0; reset_err: snd_soc_free_ac97_codec(codec); return ret; }
/* We have to create a fake left and right HP mixers because * the codec only has a single control that is shared by both channels. * This makes it impossible to determine the audio path using the current * register map, thus we add a new (virtual) register to help determine the * audio route within the device. */ static int mixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { u16 l, r, beep, tone, phone, rec, pcm, aux; l = ac97_read(w->codec, HPL_MIXER); r = ac97_read(w->codec, HPR_MIXER); beep = ac97_read(w->codec, AC97_PC_BEEP); tone = ac97_read(w->codec, AC97_MASTER_TONE); phone = ac97_read(w->codec, AC97_PHONE); rec = ac97_read(w->codec, AC97_REC_SEL); pcm = ac97_read(w->codec, AC97_PCM); aux = ac97_read(w->codec, AC97_AUX); if (event & SND_SOC_DAPM_PRE_REG) return 0; if ((l & 0x1) || (r & 0x1)) ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); else ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); if ((l & 0x2) || (r & 0x2)) ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff); else ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000); if ((l & 0x4) || (r & 0x4)) ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); else ac97_write(w->codec, AC97_PHONE, phone | 0x8000); if ((l & 0x8) || (r & 0x8)) ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff); else ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000); if ((l & 0x10) || (r & 0x10)) ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); else ac97_write(w->codec, AC97_PCM, pcm | 0x8000); if ((l & 0x20) || (r & 0x20)) ac97_write(w->codec, AC97_AUX, aux & 0x7fff); else ac97_write(w->codec, AC97_AUX, aux | 0x8000); return 0; }
static int ad1980_soc_probe(struct snd_soc_codec *codec) { int ret; u16 vendor_id2; u16 ext_status; #ifdef CONFIG_DEBUG_PRINTK printk(KERN_INFO "AD1980 SoC Audio Codec\n"); #else ; #endif ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); return ret; } ret = ad1980_reset(codec, 0); if (ret < 0) { printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); goto reset_err; } /* Read out vendor ID to make sure it is ad1980 */ if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) goto reset_err; vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); if (vendor_id2 != 0x5370) { if (vendor_id2 != 0x5374) goto reset_err; else #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING "ad1980: " "Found AD1981 - only 2/2 IN/OUT Channels " "supported\n"); #else ; #endif } /* unmute captures and playbacks volume */ ac97_write(codec, AC97_MASTER, 0x0000); ac97_write(codec, AC97_PCM, 0x0000); ac97_write(codec, AC97_REC_GAIN, 0x0000); ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); /*power on LFE/CENTER/Surround DACs*/ ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); snd_soc_add_controls(codec, ad1980_snd_ac97_controls, ARRAY_SIZE(ad1980_snd_ac97_controls)); return 0; reset_err: snd_soc_free_ac97_codec(codec); return ret; }
/** Initializes one codec * \par Description: * Initializes one codec * \param nCodec - Codec. * \internal * \author Arno Klenke *****************************************************************************/ status_t ac97_initialize_codec( AC97AudioDriver_s* psDriver, int nCodec ) { AC97Mixer_s sMixer; printk( "Initialize AC97 codec #%i\n", nCodec ); ac97_wait( psDriver, nCodec ); psDriver->nID[nCodec] = ac97_read( psDriver, nCodec, AC97_VENDOR_ID1 ) << 16; psDriver->nID[nCodec] |= ac97_read( psDriver, nCodec, AC97_VENDOR_ID2 ); printk( "AC97 codec id: 0x%x\n", psDriver->nID[nCodec] ); /* Check if this is a modem codec */ uint16 nExtM = ac97_read( psDriver, nCodec, AC97_EXTENDED_MODEM_ID ); if( nExtM & 1 ) { printk( "Found AC97 modem codec\n" ); return( -ENODEV ); } /* Read caps */ psDriver->nBasicID[nCodec] = ac97_read( psDriver, nCodec, AC97_RESET ); psDriver->nExtID[nCodec] = ac97_read( psDriver, nCodec, AC97_EXTENDED_ID ); /* Powerup codec */ ac97_write( psDriver, nCodec, AC97_POWER_CONTROL, 0 ); ac97_write( psDriver, nCodec, AC97_RESET, 0 ); snooze( 100 ); ac97_write( psDriver, nCodec, AC97_POWER_CONTROL, 0 ); ac97_write( psDriver, nCodec, AC97_GENERAL_PURPOSE, 0 ); /* Show version */ if( psDriver->nExtID[nCodec] & AC97_EI_REV_23 ) printk( "AC97 2.2 codec\n" ); else if( psDriver->nExtID[nCodec] & AC97_EI_REV_22 ) printk( "AC97 2.2 codec\n" ); else printk( "AC97 2.0 codec\n" ); /* Check for VRA */ uint16 nExtStatus = ac97_read( psDriver, nCodec, AC97_EXTENDED_STATUS ); if( psDriver->nExtID[nCodec] & ( AC97_EI_VRA | AC97_EI_VRM ) ) { printk( "Variable bitrates supported\n" ); nExtStatus |= psDriver->nExtID[nCodec] & ( AC97_EI_VRA | AC97_EI_VRM ); } /* Check for Surround DAC */ if( psDriver->nExtID[nCodec] & AC97_EI_SDAC ) { printk( "Found surround DAC\n" ); nExtStatus |= AC97_EA_SDAC; nExtStatus &= ~AC97_EA_PRJ; } /* Check for Center/LFE DAC */ if( ( psDriver->nExtID[nCodec] & ( AC97_EI_CDAC | AC97_EI_LDAC ) ) == ( AC97_EI_CDAC | AC97_EI_LDAC ) ) { printk( "Found center/LFE DAC\n" ); nExtStatus |= psDriver->nExtID[nCodec] & ( AC97_EI_CDAC | AC97_EI_LDAC ); nExtStatus &= ~( AC97_EA_PRI| AC97_EA_PRK ); } bool bSurroundPossible = false; /* Configure AC97 2.2 codecs to emulate AMAP behaviour */ if( psDriver->nExtID[nCodec] & AC97_EI_REV_22 ) { psDriver->nExtID[nCodec] &= ~AC97_EI_DACS_SLOT_MASK; switch( nCodec ) { case 1: case 2: psDriver->nExtID[nCodec] |= ( 1 << AC97_EI_DACS_SLOT_SHIFT ); break; case 3: psDriver->nExtID[nCodec]|= ( 2 << AC97_EI_DACS_SLOT_SHIFT ); break; } ac97_write( psDriver, nCodec, AC97_EXTENDED_ID, psDriver->nExtID[nCodec] ); bSurroundPossible = true; } /* Check for AMAP support */ else if( psDriver->nExtID[nCodec] & AC97_EI_AMAP ) { printk( "Codec supports AMAP\n" ); bSurroundPossible = true; } /* We would need codec specific code to configure this */ if( nCodec != 0 && !bSurroundPossible ) { printk( "Cannot use this codec\n" ); return( -ENODEV ); } psDriver->nChannels[nCodec] = 2; /* Add surround channels */ if( bSurroundPossible ) { if( psDriver->nExtID[nCodec] & AC97_EI_SDAC ) { psDriver->nMaxChannels += 2; psDriver->nChannels[nCodec] += 2; } if( ( psDriver->nExtID[nCodec] & ( AC97_EI_CDAC | AC97_EI_LDAC ) ) == ( AC97_EI_CDAC | AC97_EI_LDAC ) ) { psDriver->nMaxChannels += 2; psDriver->nChannels[nCodec] += 2; } } else { psDriver->nExtID[nCodec] &= ~( AC97_EI_SDAC | AC97_EI_CDAC | AC97_EI_LDAC ); } /* Check for SPDIF */ if( psDriver->nExtID[nCodec] & AC97_EI_SPDIF ) printk( "SPDIF output supported\n" ); psDriver->nExtStat[nCodec] = nExtStatus; ac97_write( psDriver, nCodec, AC97_EXTENDED_STATUS, nExtStatus ); /* Master */ psDriver->nNumMixer = 0; ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_MASTER_VOL_STEREO, ac97_test_resolution( psDriver, nCodec, AC97_MASTER_VOL_STEREO ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_MASTER_VOL_STEREO, 0x43, 0x43 ); /* Headphone */ if( psDriver->nBasicID[nCodec] & AC97_BC_HEADPHONE ) { ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_HEADPHONE_VOL, ac97_test_resolution( psDriver, nCodec, AC97_HEADPHONE_VOL ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_HEADPHONE_VOL, 0x43, 0x43 ); } /* Sourround */ if( psDriver->nExtID[nCodec] & AC97_EI_SDAC ) { ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_SURROUND_MASTER, ac97_test_resolution( psDriver, nCodec, AC97_SURROUND_MASTER ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_SURROUND_MASTER, 0x43, 0x43 ); } /* Center/LFE */ if( ( psDriver->nExtID[nCodec] & ( AC97_EI_CDAC | AC97_EI_LDAC ) ) == ( AC97_EI_CDAC | AC97_EI_LDAC ) ) { ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_CENTER_LFE_MASTER, ac97_test_resolution( psDriver, nCodec, AC97_CENTER_LFE_MASTER ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_CENTER_LFE_MASTER, 0x43, 0x43 ); } /* PCM */ ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_PCMOUT_VOL, ac97_test_resolution( psDriver, nCodec, AC97_PCMOUT_VOL ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_PCMOUT_VOL, 0x43, 0x43 ); /* LineIn */ ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_LINEIN_VOL, ac97_test_resolution( psDriver, nCodec, AC97_LINEIN_VOL ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_LINEIN_VOL, 0x43, 0x43 ); /* CD */ ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_CD_VOL, ac97_test_resolution( psDriver, nCodec, AC97_CD_VOL ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_CD_VOL, 0x43, 0x43 ); /* AUX */ ac97_add_mixer( psDriver, sMixer, true, true, nCodec, AC97_AUX_VOL, ac97_test_resolution( psDriver, nCodec, AC97_AUX_VOL ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_AUX_VOL, 0x43, 0x43 ); /* Mic */ ac97_add_mixer( psDriver, sMixer, false, true, nCodec, AC97_MIC_VOL, ac97_test_resolution( psDriver, nCodec, AC97_MIC_VOL ) ); ac97_write_mic_mixer( psDriver, nCodec, 0x00 ); /* Record Gain */ ac97_add_mixer( psDriver, sMixer, true, false, nCodec, AC97_RECORD_GAIN, ac97_test_resolution( psDriver, nCodec, AC97_RECORD_GAIN ) ); ac97_write_stereo_mixer( psDriver, nCodec, AC97_RECORD_GAIN, 0x43, 0x43 ); /* Record Gain Mic */ ac97_add_mixer( psDriver, sMixer, false, false, nCodec, AC97_RECORD_GAIN_MIC, ac97_test_resolution( psDriver, nCodec, AC97_RECORD_GAIN_MIC ) ); ac97_write_mono_mixer( psDriver, nCodec, AC97_RECORD_GAIN_MIC, 0x43 ); return( 0 ); }
static int ad1980_soc_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec; int ret = 0; u16 vendor_id2; u16 ext_status; printk(KERN_INFO "AD1980 SoC Audio Codec\n"); socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (socdev->codec == NULL) return -ENOMEM; codec = socdev->codec; mutex_init(&codec->mutex); codec->reg_cache = kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL); if (codec->reg_cache == NULL) { ret = -ENOMEM; goto cache_err; } memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \ ARRAY_SIZE(ad1980_reg)); codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg); codec->reg_cache_step = 2; codec->name = "AD1980"; codec->owner = THIS_MODULE; codec->dai = &ad1980_dai; codec->num_dai = 1; codec->write = ac97_write; codec->read = ac97_read; INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); goto codec_err; } /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) goto pcm_err; ret = ad1980_reset(codec, 0); if (ret < 0) { printk(KERN_ERR "AC97 link error\n"); goto reset_err; } /* Read out vendor ID to make sure it is ad1980 */ if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) goto reset_err; vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); if (vendor_id2 != 0x5370) { if (vendor_id2 != 0x5374) goto reset_err; else printk(KERN_WARNING "ad1980: " "Found AD1981 - only 2/2 IN/OUT Channels " "supported\n"); } /* unmute captures and playbacks volume */ ac97_write(codec, AC97_MASTER, 0x0000); ac97_write(codec, AC97_PCM, 0x0000); ac97_write(codec, AC97_REC_GAIN, 0x0000); ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); /*power on LFE/CENTER/Surround DACs*/ ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); ad1980_add_controls(codec); ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register card\n"); goto reset_err; } return 0; reset_err: snd_soc_free_pcms(socdev); pcm_err: snd_soc_free_ac97_codec(codec); codec_err: kfree(codec->reg_cache); cache_err: kfree(socdev->codec); socdev->codec = NULL; return ret; }