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

📄 wm8753.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		.set_fmt = wm8753_mode1v_set_dai_fmt,		.set_clkdiv = wm8753_set_dai_clkdiv,		.set_pll = wm8753_set_dai_pll,		.set_sysclk = wm8753_set_dai_sysclk,	},},/* DAI HiFi mode 2 - dummy */{	.name = "WM8753 HiFi",	.id = 2,},/* DAI Voice mode 2 */{	.name = "WM8753 Voice",	.id = 2,	.playback = {		.stream_name = "Voice Playback",		.channels_min = 1,		.channels_max = 1,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.capture = {		.stream_name = "Capture",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.ops = {		.hw_params = wm8753_pcm_hw_params,},	.dai_ops = {		.digital_mute = wm8753_mute,		.set_fmt = wm8753_mode2_set_dai_fmt,		.set_clkdiv = wm8753_set_dai_clkdiv,		.set_pll = wm8753_set_dai_pll,		.set_sysclk = wm8753_set_dai_sysclk,	},},/* DAI HiFi mode 3 */{	.name = "WM8753 HiFi",	.id = 3,	.playback = {		.stream_name = "HiFi Playback",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.capture = {		.stream_name = "Capture",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.ops = {		.hw_params = wm8753_i2s_hw_params,},	.dai_ops = {		.digital_mute = wm8753_mute,		.set_fmt = wm8753_mode3_4_set_dai_fmt,		.set_clkdiv = wm8753_set_dai_clkdiv,		.set_pll = wm8753_set_dai_pll,		.set_sysclk = wm8753_set_dai_sysclk,	},},/* DAI Voice mode 3 - dummy */{	.name = "WM8753 Voice",	.id = 3,},/* DAI HiFi mode 4 */{	.name = "WM8753 HiFi",	.id = 4,	.playback = {		.stream_name = "HiFi Playback",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.capture = {		.stream_name = "Capture",		.channels_min = 1,		.channels_max = 2,		.rates = WM8753_RATES,		.formats = WM8753_FORMATS,},	.ops = {		.hw_params = wm8753_i2s_hw_params,},	.dai_ops = {		.digital_mute = wm8753_mute,		.set_fmt = wm8753_mode3_4_set_dai_fmt,		.set_clkdiv = wm8753_set_dai_clkdiv,		.set_pll = wm8753_set_dai_pll,		.set_sysclk = wm8753_set_dai_sysclk,	},},/* DAI Voice mode 4 - dummy */{	.name = "WM8753 Voice",	.id = 4,},};struct snd_soc_codec_dai wm8753_dai[2];EXPORT_SYMBOL_GPL(wm8753_dai);static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode){	if (mode < 4) {		int playback_active, capture_active, codec_active, pop_wait;		void *private_data;		playback_active = wm8753_dai[0].playback.active;		capture_active = wm8753_dai[0].capture.active;		codec_active = wm8753_dai[0].active;		private_data = wm8753_dai[0].private_data;		pop_wait = wm8753_dai[0].pop_wait;		wm8753_dai[0] = wm8753_all_dai[mode << 1];		wm8753_dai[0].playback.active = playback_active;		wm8753_dai[0].capture.active = capture_active;		wm8753_dai[0].active = codec_active;		wm8753_dai[0].private_data = private_data;		wm8753_dai[0].pop_wait = pop_wait;		playback_active = wm8753_dai[1].playback.active;		capture_active = wm8753_dai[1].capture.active;		codec_active = wm8753_dai[1].active;		private_data = wm8753_dai[1].private_data;		pop_wait = wm8753_dai[1].pop_wait;		wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];		wm8753_dai[1].playback.active = playback_active;		wm8753_dai[1].capture.active = capture_active;		wm8753_dai[1].active = codec_active;		wm8753_dai[1].private_data = private_data;		wm8753_dai[1].pop_wait = pop_wait;	}	wm8753_dai[0].codec = codec;	wm8753_dai[1].codec = codec;}static void wm8753_work(struct work_struct *work){	struct snd_soc_codec *codec =		container_of(work, struct snd_soc_codec, delayed_work.work);	wm8753_dapm_event(codec, codec->dapm_state);}static int wm8753_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;	/* we only need to suspend if we are a valid card */	if(!codec->card)		return 0;			wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold);	return 0;}static int wm8753_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;	/* we only need to resume if we are a valid card */	if(!codec->card)		return 0;	/* Sync reg_cache with the hardware */	for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {		if (i + 1 == WM8753_RESET)			continue;		data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);		data[1] = cache[i] & 0x00ff;		codec->hw_write(codec->control_data, data, 2);	}	wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3hot);	/* charge wm8753 caps */	if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {		wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2);		codec->dapm_state = SNDRV_CTL_POWER_D0;		schedule_delayed_work(&codec->delayed_work,			msecs_to_jiffies(caps_charge));	}	return 0;}/* * initialise the WM8753 driver * register the mixer and dsp interfaces with the kernel */static int wm8753_init(struct snd_soc_device *socdev){	struct snd_soc_codec *codec = socdev->codec;	int reg, ret = 0;	codec->name = "WM8753";	codec->owner = THIS_MODULE;	codec->read = wm8753_read_reg_cache;	codec->write = wm8753_write;	codec->dapm_event = wm8753_dapm_event;	codec->dai = wm8753_dai;	codec->num_dai = 2;	codec->reg_cache_size = sizeof(wm8753_reg);	codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL);	if (codec->reg_cache == NULL)		return -ENOMEM;	wm8753_set_dai_mode(codec, 0);	wm8753_reset(codec);	/* register pcms */	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);	if (ret < 0) {		printk(KERN_ERR "wm8753: failed to create pcms\n");		goto pcm_err;	}	/* charge output caps */	wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2);	codec->dapm_state = SNDRV_CTL_POWER_D3hot;	schedule_delayed_work(&codec->delayed_work,		msecs_to_jiffies(caps_charge));	/* set the update bits */	reg = wm8753_read_reg_cache(codec, WM8753_LDAC);	wm8753_write(codec, WM8753_LDAC, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_RDAC);	wm8753_write(codec, WM8753_RDAC, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_LADC);	wm8753_write(codec, WM8753_LADC, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_RADC);	wm8753_write(codec, WM8753_RADC, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V);	wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V);	wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V);	wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V);	wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_LINVOL);	wm8753_write(codec, WM8753_LINVOL, reg | 0x0100);	reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);	wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);	wm8753_add_controls(codec);	wm8753_add_widgets(codec);	ret = snd_soc_register_card(socdev);	if (ret < 0) {      	printk(KERN_ERR "wm8753: 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;}/* If the i2c layer weren't so broken, we could pass this kind of data   around */static struct snd_soc_device *wm8753_socdev;#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)/* * WM8753 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 wm8753_i2c_driver;static struct i2c_client client_template;static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind){	struct snd_soc_device *socdev = wm8753_socdev;	struct wm8753_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 = wm8753_init(socdev);	if (ret < 0) {		err("failed to initialise WM8753\n");		goto err;	}	return ret;err:	kfree(codec);	kfree(i2c);	return ret;}static int wm8753_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 wm8753_i2c_attach(struct i2c_adapter *adap){	return i2c_probe(adap, &addr_data, wm8753_codec_probe);}/* corgi i2c codec control layer */static struct i2c_driver wm8753_i2c_driver = {	.driver = {		.name = "WM8753 I2C Codec",		.owner = THIS_MODULE,	},	.id =             I2C_DRIVERID_WM8753,	.attach_adapter = wm8753_i2c_attach,	.detach_client =  wm8753_i2c_detach,	.command =        NULL,};static struct i2c_client client_template = {	.name =   "WM8753",	.driver = &wm8753_i2c_driver,};#endifstatic int wm8753_probe(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	struct wm8753_setup_data *setup;	struct snd_soc_codec *codec;	struct wm8753_priv *wm8753;	int ret = 0;	info("WM8753 Audio Codec %s", WM8753_VERSION);	setup = socdev->codec_data;	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);	if (codec == NULL)		return -ENOMEM;	wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);	if (wm8753 == NULL) {		kfree(codec);		return -ENOMEM;	}	codec->private_data = wm8753;	socdev->codec = codec;	mutex_init(&codec->mutex);	INIT_LIST_HEAD(&codec->dapm_widgets);	INIT_LIST_HEAD(&codec->dapm_paths);	wm8753_socdev = socdev;	INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);#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(&wm8753_i2c_driver);		if (ret != 0)			printk(KERN_ERR "can't add i2c driver");	}#else		/* Add other interfaces here */#endif	return ret;}/* * This function forces any delayed work to be queued and run. */static int run_delayed_work(struct delayed_work *dwork){	int ret;	/* cancel any work waiting to be queued. */	ret = cancel_delayed_work(dwork);	/* if there was any work waiting then we run it now and	 * wait for it's completion */	if (ret) {		schedule_delayed_work(dwork, 0);		flush_scheduled_work();	}	return ret;}/* power down chip */static int wm8753_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)		wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold);	run_delayed_work(&codec->delayed_work);	snd_soc_free_pcms(socdev);	snd_soc_dapm_free(socdev);#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)	i2c_del_driver(&wm8753_i2c_driver);#endif	kfree(codec->private_data);	kfree(codec);	return 0;}struct snd_soc_codec_device soc_codec_dev_wm8753 = {	.probe = 	wm8753_probe,	.remove = 	wm8753_remove,	.suspend = 	wm8753_suspend,	.resume =	wm8753_resume,};EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);MODULE_DESCRIPTION("ASoC WM8753 driver");MODULE_AUTHOR("Liam Girdwood");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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