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

📄 wm8731.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		unsigned int fmt){	struct snd_soc_codec *codec = codec_dai->codec;	u16 iface = 0;	/* set master/slave audio interface */	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {	case SND_SOC_DAIFMT_CBM_CFM:		iface |= 0x0040;		break;	case SND_SOC_DAIFMT_CBS_CFS:		break;	default:		return -EINVAL;	}	/* interface format */	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {	case SND_SOC_DAIFMT_I2S:		iface |= 0x0002;		break;	case SND_SOC_DAIFMT_RIGHT_J:		break;	case SND_SOC_DAIFMT_LEFT_J:		iface |= 0x0001;		break;	case SND_SOC_DAIFMT_DSP_A:		iface |= 0x0003;		break;	case SND_SOC_DAIFMT_DSP_B:		iface |= 0x0013;		break;	default:		return -EINVAL;	}	/* clock inversion */	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {	case SND_SOC_DAIFMT_NB_NF:		break;	case SND_SOC_DAIFMT_IB_IF:		iface |= 0x0090;		break;	case SND_SOC_DAIFMT_IB_NF:		iface |= 0x0080;		break;	case SND_SOC_DAIFMT_NB_IF:		iface |= 0x0010;		break;	default:		return -EINVAL;	}	/* set iface */	wm8731_write(codec, WM8731_IFACE, iface);	return 0;}static int wm8731_dapm_event(struct snd_soc_codec *codec, int event){	u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;	switch (event) {	case SNDRV_CTL_POWER_D0: /* full On */		/* vref/mid, osc on, dac unmute */		wm8731_write(codec, WM8731_PWR, 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 */		/* everything off except vref/vmid, */		wm8731_write(codec, WM8731_PWR, reg | 0x0040);		break;	case SNDRV_CTL_POWER_D3cold: /* Off, without power */		/* everything off, dac mute, inactive */		wm8731_write(codec, WM8731_ACTIVE, 0x0);		wm8731_write(codec, WM8731_PWR, 0xffff);		break;	}	codec->dapm_state = event;	return 0;}#define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\		SNDRV_PCM_RATE_96000)#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\	SNDRV_PCM_FMTBIT_S24_LE)struct snd_soc_codec_dai wm8731_dai = {	.name = "WM8731",	.playback = {		.stream_name = "Playback",		.channels_min = 1,		.channels_max = 2,		.rates = WM8731_RATES,		.formats = WM8731_FORMATS,},	.capture = {		.stream_name = "Capture",		.channels_min = 1,		.channels_max = 2,		.rates = WM8731_RATES,		.formats = WM8731_FORMATS,},	.ops = {		.prepare = wm8731_pcm_prepare,		.hw_params = wm8731_hw_params,		.shutdown = wm8731_shutdown,	},	.dai_ops = {		.digital_mute = wm8731_mute,		.set_sysclk = wm8731_set_dai_sysclk,		.set_fmt = wm8731_set_dai_fmt,	}};EXPORT_SYMBOL_GPL(wm8731_dai);static int wm8731_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;	wm8731_write(codec, WM8731_ACTIVE, 0x0);	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);	return 0;}static int wm8731_resume(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_codec *codec = socdev->codec;	int i;	u8 data[2];	u16 *cache = codec->reg_cache;	/* Sync reg_cache with the hardware */	for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);		data[1] = cache[i] & 0x00ff;		codec->hw_write(codec->control_data, data, 2);	}	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);	wm8731_dapm_event(codec, codec->suspend_dapm_state);	return 0;}/* * initialise the WM8731 driver * register the mixer and dsp interfaces with the kernel */static int wm8731_init(struct snd_soc_device *socdev){	struct snd_soc_codec *codec = socdev->codec;	int reg, ret = 0;	codec->name = "WM8731";	codec->owner = THIS_MODULE;	codec->read = wm8731_read_reg_cache;	codec->write = wm8731_write;	codec->dapm_event = wm8731_dapm_event;	codec->dai = &wm8731_dai;	codec->num_dai = 1;	codec->reg_cache_size = sizeof(wm8731_reg);	codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL);	if (codec->reg_cache == NULL)		return -ENOMEM;	wm8731_reset(codec);	/* register pcms */	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);	if (ret < 0) {		printk(KERN_ERR "wm8731: failed to create pcms\n");		goto pcm_err;	}	/* power on device */	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);	/* set the update bits */	reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);	wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100);	reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);	wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100);	reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);	wm8731_write(codec, WM8731_LINVOL, reg | 0x0100);	reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);	wm8731_write(codec, WM8731_RINVOL, reg | 0x0100);	wm8731_add_controls(codec);	wm8731_add_widgets(codec);	ret = snd_soc_register_card(socdev);	if (ret < 0) {		printk(KERN_ERR "wm8731: failed to register card\n");		goto card_err;	}	return ret;card_err:	snd_soc_free_pcms(socdev);	snd_soc_dapm_free(socdev);pcm_err:	kfree(codec->reg_cache);	return ret;}static struct snd_soc_device *wm8731_socdev;#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)/* * WM8731 2 wire address is determined by GPIO5 * state during powerup. *    low  = 0x1a *    high = 0x1b */static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };/* Magic definition of all other variables and things */I2C_CLIENT_INSMOD;static struct i2c_driver wm8731_i2c_driver;static struct i2c_client client_template;/* If the i2c layer weren't so broken, we could pass this kind of data   around */static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind){	struct snd_soc_device *socdev = wm8731_socdev;	struct wm8731_setup_data *setup = socdev->codec_data;	struct snd_soc_codec *codec = socdev->codec;	struct i2c_client *i2c;	int ret;	if (addr != setup->i2c_address)		return -ENODEV;	client_template.adapter = adap;	client_template.addr = addr;	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);	if (i2c == NULL) {		kfree(codec);		return -ENOMEM;	}	i2c_set_clientdata(i2c, codec);	codec->control_data = i2c;	ret = i2c_attach_client(i2c);	if (ret < 0) {		err("failed to attach codec at addr %x\n", addr);		goto err;	}	ret = wm8731_init(socdev);	if (ret < 0) {		err("failed to initialise WM8731\n");		goto err;	}	return ret;err:	kfree(codec);	kfree(i2c);	return ret;}static int wm8731_i2c_detach(struct i2c_client *client){	struct snd_soc_codec* codec = i2c_get_clientdata(client);	i2c_detach_client(client);	kfree(codec->reg_cache);	kfree(client);	return 0;}static int wm8731_i2c_attach(struct i2c_adapter *adap){	return i2c_probe(adap, &addr_data, wm8731_codec_probe);}/* corgi i2c codec control layer */static struct i2c_driver wm8731_i2c_driver = {	.driver = {		.name = "WM8731 I2C Codec",		.owner = THIS_MODULE,	},	.id =             I2C_DRIVERID_WM8731,	.attach_adapter = wm8731_i2c_attach,	.detach_client =  wm8731_i2c_detach,	.command =        NULL,};static struct i2c_client client_template = {	.name =   "WM8731",	.driver = &wm8731_i2c_driver,};#endifstatic int wm8731_probe(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct wm8731_setup_data *setup;	struct snd_soc_codec *codec;	struct wm8731_priv *wm8731;	int ret = 0;	info("WM8731 Audio Codec %s", WM8731_VERSION);	setup = socdev->codec_data;	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);	if (codec == NULL)		return -ENOMEM;	wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);	if (wm8731 == NULL) {		kfree(codec);		return -ENOMEM;	}	codec->private_data = wm8731;	socdev->codec = codec;	mutex_init(&codec->mutex);	INIT_LIST_HEAD(&codec->dapm_widgets);	INIT_LIST_HEAD(&codec->dapm_paths);	wm8731_socdev = socdev;#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)	if (setup->i2c_address) {		normal_i2c[0] = setup->i2c_address;		codec->hw_write = (hw_write_t)i2c_master_send;		ret = i2c_add_driver(&wm8731_i2c_driver);		if (ret != 0)			printk(KERN_ERR "can't add i2c driver");	}#else	/* Add other interfaces here */#endif	return ret;}/* power down chip */static int wm8731_remove(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct snd_soc_codec *codec = socdev->codec;	if (codec->control_data)		wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);	snd_soc_free_pcms(socdev);	snd_soc_dapm_free(socdev);#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)	i2c_del_driver(&wm8731_i2c_driver);#endif	kfree(codec->private_data);	kfree(codec);	return 0;}struct snd_soc_codec_device soc_codec_dev_wm8731 = {	.probe = 	wm8731_probe,	.remove = 	wm8731_remove,	.suspend = 	wm8731_suspend,	.resume =	wm8731_resume,};EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);MODULE_DESCRIPTION("ASoC WM8731 driver");MODULE_AUTHOR("Richard Purdie");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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