⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wm9712.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	{"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"},	{"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"},	/* inputs */	{"Line PGA", NULL, "LINEINL"},	{"Line PGA", NULL, "LINEINR"},	{"Phone PGA", NULL, "PHONE"},	{"Mic PGA", NULL, "MIC1"},	{"Mic PGA", NULL, "MIC2"},	/* left capture selector */	{"Left Capture Select", "Mic", "MIC1"},	{"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},	{"Left Capture Select", "Line", "LINEINL"},	{"Left Capture Select", "Headphone Mixer", "Left HP Mixer"},	{"Left Capture Select", "Phone Mixer", "Phone Mixer"},	{"Left Capture Select", "Phone", "PHONE"},	/* right capture selector */	{"Right Capture Select", "Mic", "MIC2"},	{"Right Capture Select", "Speaker Mixer", "Speaker Mixer"},	{"Right Capture Select", "Line", "LINEINR"},	{"Right Capture Select", "Headphone Mixer", "Right HP Mixer"},	{"Right Capture Select", "Phone Mixer", "Phone Mixer"},	{"Right Capture Select", "Phone", "PHONE"},	/* ALC Sidetone */	{"ALC Sidetone Mux", "Stereo", "Left Capture Select"},	{"ALC Sidetone Mux", "Stereo", "Right Capture Select"},	{"ALC Sidetone Mux", "Left", "Left Capture Select"},	{"ALC Sidetone Mux", "Right", "Right Capture Select"},	/* ADC's */	{"Left ADC", NULL, "Left Capture Select"},	{"Right ADC", NULL, "Right Capture Select"},	/* outputs */	{"MONOOUT", NULL, "Phone Mixer"},	{"HPOUTL", NULL, "Headphone PGA"},	{"Headphone PGA", NULL, "Left HP Mixer"},	{"HPOUTR", NULL, "Headphone PGA"},	{"Headphone PGA", NULL, "Right HP Mixer"},	/* mono hp mixer */	{"Mono HP Mixer", NULL, "Left HP Mixer"},	{"Mono HP Mixer", NULL, "Right HP Mixer"},	/* Out3 Mux */	{"Out3 Mux", "Left", "Left HP Mixer"},	{"Out3 Mux", "Mono", "Phone Mixer"},	{"Out3 Mux", "Left + Right", "Mono HP Mixer"},	{"Out 3 PGA", NULL, "Out3 Mux"},	{"OUT3", NULL, "Out 3 PGA"},	/* speaker Mux */	{"Speaker Mux", "Speaker Mix", "Speaker Mixer"},	{"Speaker Mux", "Headphone Mix", "Mono HP Mixer"},	{"Speaker PGA", NULL, "Speaker Mux"},	{"LOUT2", NULL, "Speaker PGA"},	{"ROUT2", NULL, "Speaker PGA"},	{NULL, NULL, NULL},};static int wm9712_add_widgets(struct snd_soc_codec *codec){	int i;	for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) {		snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]);	}	/* set up audio path audio_mapnects */	for(i = 0; audio_map[i][0] != NULL; i++) {		snd_soc_dapm_connect_input(codec, audio_map[i][0],			audio_map[i][1], audio_map[i][2]);	}	snd_soc_dapm_new_widgets(codec);	return 0;}static unsigned int ac97_read(struct snd_soc_codec *codec,	unsigned int reg){	u16 *cache = codec->reg_cache;	if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||		reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||		reg == AC97_REC_GAIN)		return soc_ac97_ops.read(codec->ac97, reg);	else {		reg = reg >> 1;		if (reg > (ARRAY_SIZE(wm9712_reg)))			return -EIO;		return cache[reg];	}}static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,	unsigned int val){	u16 *cache = codec->reg_cache;	soc_ac97_ops.write(codec->ac97, reg, val);	reg = reg >> 1;	if (reg <= (ARRAY_SIZE(wm9712_reg)))		cache[reg] = val;	return 0;}static int ac97_prepare(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_soc_pcm_runtime *rtd = substream->private_data;	struct snd_soc_device *socdev = rtd->socdev;	struct snd_soc_codec *codec = socdev->codec;	int reg;	u16 vra;	vra = ac97_read(codec, AC97_EXTENDED_STATUS);	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)		reg = AC97_PCM_FRONT_DAC_RATE;	else		reg = AC97_PCM_LR_ADC_RATE;	return ac97_write(codec, reg, runtime->rate);}static int ac97_aux_prepare(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_soc_pcm_runtime *rtd = substream->private_data;	struct snd_soc_device *socdev = rtd->socdev;	struct snd_soc_codec *codec = socdev->codec;	u16 vra, xsle;	vra = ac97_read(codec, AC97_EXTENDED_STATUS);	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);	xsle = ac97_read(codec, AC97_PCI_SID);	ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)		return -ENODEV;	return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);}#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)struct snd_soc_codec_dai wm9712_dai[] = {{	.name = "AC97 HiFi",	.type = SND_SOC_DAI_AC97_BUS,	.playback = {		.stream_name = "HiFi Playback",		.channels_min = 1,		.channels_max = 2,		.rates = WM9712_AC97_RATES,		.formats = SNDRV_PCM_FMTBIT_S16_LE,},	.capture = {		.stream_name = "HiFi Capture",		.channels_min = 1,		.channels_max = 2,		.rates = WM9712_AC97_RATES,		.formats = SNDRV_PCM_FMTBIT_S16_LE,},	.ops = {		.prepare = ac97_prepare,},},{	.name = "AC97 Aux",	.playback = {		.stream_name = "Aux Playback",		.channels_min = 1,		.channels_max = 1,		.rates = WM9712_AC97_RATES,		.formats = SNDRV_PCM_FMTBIT_S16_LE,},	.ops = {		.prepare = ac97_aux_prepare,},}};EXPORT_SYMBOL_GPL(wm9712_dai);static int wm9712_dapm_event(struct snd_soc_codec *codec, int event){	u16 reg;	switch (event) {	case SNDRV_CTL_POWER_D0: /* full On */		/* liam - maybe enable thermal shutdown */		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff;		ac97_write(codec, AC97_EXTENDED_MID, reg);		break;	case SNDRV_CTL_POWER_D1: /* partial On */	case SNDRV_CTL_POWER_D2: /* partial On */		break;	case SNDRV_CTL_POWER_D3hot: /* Off, with power */		/* enable master bias and vmid */		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff;		ac97_write(codec, AC97_EXTENDED_MID, reg);		ac97_write(codec, AC97_POWERDOWN, 0x0000);		break;	case SNDRV_CTL_POWER_D3cold: /* Off, without power */		/* disable everything including AC link */		ac97_write(codec, AC97_EXTENDED_MID, 0xffff);		ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);		ac97_write(codec, AC97_POWERDOWN, 0xffff);		break;	}	codec->dapm_state = event;	return 0;}static int wm9712_reset(struct snd_soc_codec *codec, int try_warm){	if (try_warm && soc_ac97_ops.warm_reset) {		soc_ac97_ops.warm_reset(codec->ac97);		if (!(ac97_read(codec, 0) & 0x8000))			return 1;	}	soc_ac97_ops.reset(codec->ac97);	if (ac97_read(codec, 0) & 0x8000)		goto err;	return 0;err:	printk(KERN_ERR "WM9712 AC97 reset failed\n");	return -EIO;}static int wm9712_soc_suspend(struct platform_device *pdev,	pm_message_t state){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_codec *codec = socdev->codec;	wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold);	return 0;}static int wm9712_soc_resume(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_codec *codec = socdev->codec;	int i, ret;	u16 *cache = codec->reg_cache;	ret = wm9712_reset(codec, 1);	if (ret < 0){		printk(KERN_ERR "could not reset AC97 codec\n");		return ret;	}	wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);	if (ret == 0) {		/* Sync reg_cache with the hardware after cold reset */		for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) {			if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||				(i > 0x58 && i != 0x5c))				continue;			soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);		}	}	if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)		wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0);	return ret;}static int wm9712_soc_probe(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_codec *codec;	int ret = 0;	printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);	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 = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);	if (codec->reg_cache == NULL) {		ret = -ENOMEM;		goto cache_err;	}	codec->reg_cache_size = sizeof(wm9712_reg);	codec->reg_cache_step = 2;	codec->name = "WM9712";	codec->owner = THIS_MODULE;	codec->dai = wm9712_dai;	codec->num_dai = ARRAY_SIZE(wm9712_dai);	codec->write = ac97_write;	codec->read = ac97_read;	codec->dapm_event = wm9712_dapm_event;	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 "wm9712: 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 = wm9712_reset(codec, 0);	if (ret < 0) {		printk(KERN_ERR "AC97 link error\n");		goto reset_err;	}	/* set alc mux to none */	ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);	wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);	wm9712_add_controls(codec);	wm9712_add_widgets(codec);	ret = snd_soc_register_card(socdev);	if (ret < 0) {		printk(KERN_ERR "wm9712: 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;}static int wm9712_soc_remove(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_codec *codec = socdev->codec;	if (codec == NULL)		return 0;	snd_soc_dapm_free(socdev);	snd_soc_free_pcms(socdev);	snd_soc_free_ac97_codec(codec);	kfree(codec->reg_cache);	kfree(codec);	return 0;}struct snd_soc_codec_device soc_codec_dev_wm9712 = {	.probe = 	wm9712_soc_probe,	.remove = 	wm9712_soc_remove,	.suspend =	wm9712_soc_suspend,	.resume =	wm9712_soc_resume,};EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");MODULE_AUTHOR("Liam Girdwood");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -