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

📄 cs4270.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			    CS4270_PWRCTL_PDN);	if (ret < 0) {		printk(KERN_ERR "cs4270: I2C write failed\n");		return ret;	}	/* Program the mode control register */	reg = snd_soc_read(codec, CS4270_MODE);	reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK);	reg |= cs4270_mode_ratios[i].speed_mode | cs4270_mode_ratios[i].mclk;	ret = snd_soc_write(codec, CS4270_MODE, reg);	if (ret < 0) {		printk(KERN_ERR "cs4270: I2C write failed\n");		return ret;	}	/* Program the format register */	reg = snd_soc_read(codec, CS4270_FORMAT);	reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK);	switch (cs4270->mode) {	case SND_SOC_DAIFMT_I2S:		reg |= CS4270_FORMAT_DAC_I2S | CS4270_FORMAT_ADC_I2S;		break;	case SND_SOC_DAIFMT_LEFT_J:		reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ;		break;	default:		printk(KERN_ERR "cs4270: unknown format\n");		return -EINVAL;	}	ret = snd_soc_write(codec, CS4270_FORMAT, reg);	if (ret < 0) {		printk(KERN_ERR "cs4270: I2C write failed\n");		return ret;	}	/* Disable auto-mute.  This feature appears to be buggy, because in	   some situations, auto-mute will not deactivate when it should. */	reg = snd_soc_read(codec, CS4270_MUTE);	reg &= ~CS4270_MUTE_AUTO;	ret = snd_soc_write(codec, CS4270_MUTE, reg);	if (ret < 0) {		printk(KERN_ERR "cs4270: I2C write failed\n");		return ret;	}	/* Thaw and power-up the codec */	ret = snd_soc_write(codec, CS4270_PWRCTL, 0);	if (ret < 0) {		printk(KERN_ERR "cs4270: I2C write failed\n");		return ret;	}	return ret;}#ifdef CONFIG_SND_SOC_CS4270_HWMUTE/* * Set the CS4270 external mute * * This function toggles the mute bits in the MUTE register.  The CS4270's * mute capability is intended for external muting circuitry, so if the * board does not have the MUTEA or MUTEB pins connected to such circuitry, * then this function will do nothing. */static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute){	struct snd_soc_codec *codec = dai->codec;	int reg6;	reg6 = snd_soc_read(codec, CS4270_MUTE);	if (mute)		reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B |			CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;	else		reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B |			  CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);	return snd_soc_write(codec, CS4270_MUTE, reg6);}#endifstatic int cs4270_i2c_probe(struct i2c_adapter *adap, int addr, int kind);/* * Notify the driver that a new I2C bus has been found. * * This function is called for each I2C bus in the system.  The function * then asks the I2C subsystem to probe that bus at the addresses on which * our device (the CS4270) could exist.  If a device is found at one of * those addresses, then our probe function (cs4270_i2c_probe) is called. */static int cs4270_i2c_attach(struct i2c_adapter *adapter){	return i2c_probe(adapter, &addr_data, cs4270_i2c_probe);}static int cs4270_i2c_detach(struct i2c_client *client){	struct snd_soc_codec *codec = i2c_get_clientdata(client);	i2c_detach_client(client);	codec->control_data = NULL;	kfree(codec->reg_cache);	codec->reg_cache = NULL;	kfree(client);	return 0;}/* A list of non-DAPM controls that the CS4270 supports */static const struct snd_kcontrol_new cs4270_snd_controls[] = {	SOC_DOUBLE_R("Master Playback Volume",		CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1)};static struct i2c_driver cs4270_i2c_driver = {	.driver = {		.name = "CS4270 I2C",		.owner = THIS_MODULE,	},	.id =             I2C_DRIVERID_CS4270,	.attach_adapter = cs4270_i2c_attach,	.detach_client =  cs4270_i2c_detach,};/* * Global variable to store socdev for i2c probe function. * * If struct i2c_driver had a private_data field, we wouldn't need to use * cs4270_socdec.  This is the only way to pass the socdev structure to * cs4270_i2c_probe(). * * The real solution to cs4270_socdev is to create a mechanism * that maps I2C addresses to snd_soc_device structures.  Perhaps the * creation of the snd_soc_device object should be moved out of * cs4270_probe() and into cs4270_i2c_probe(), but that would make this * driver dependent on I2C.  The CS4270 supports "stand-alone" mode, whereby * the chip is *not* connected to the I2C bus, but is instead configured via * input pins. */static struct snd_soc_device *cs4270_socdev;/* * Initialize the I2C interface of the CS4270 * * This function is called for whenever the I2C subsystem finds a device * at a particular address. * * Note: snd_soc_new_pcms() must be called before this function can be called, * because of snd_ctl_add(). */static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind){	struct snd_soc_device *socdev = cs4270_socdev;	struct snd_soc_codec *codec = socdev->codec;	struct i2c_client *i2c_client = NULL;	int i;	int ret = 0;	/* Probing all possible addresses has one drawback: if there are	   multiple CS4270s on the bus, then you cannot specify which	   socdev is matched with which CS4270.  For now, we just reject	   this I2C device if the socdev already has one attached. */	if (codec->control_data)		return -ENODEV;	/* Note: codec_dai->codec is NULL here */	i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);	if (!i2c_client) {		printk(KERN_ERR "cs4270: could not allocate I2C client\n");		return -ENOMEM;	}	codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL);	if (!codec->reg_cache) {		printk(KERN_ERR "cs4270: could not allocate register cache\n");		ret = -ENOMEM;		goto error;	}	i2c_set_clientdata(i2c_client, codec);	strcpy(i2c_client->name, "CS4270");	i2c_client->driver = &cs4270_i2c_driver;	i2c_client->adapter = adapter;	i2c_client->addr = addr;	/* Verify that we have a CS4270 */	ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);	if (ret < 0) {		printk(KERN_ERR "cs4270: failed to read I2C\n");		goto error;	}	/* The top four bits of the chip ID should be 1100. */	if ((ret & 0xF0) != 0xC0) {		/* The device at this address is not a CS4270 codec */		ret = -ENODEV;		goto error;	}	printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr);	printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF);	/* Tell the I2C layer a new client has arrived */	ret = i2c_attach_client(i2c_client);	if (ret) {		printk(KERN_ERR "cs4270: could not attach codec, "			"I2C address %x, error code %i\n", addr, ret);		goto error;	}	codec->control_data = i2c_client;	codec->read = cs4270_read_reg_cache;	codec->write = cs4270_i2c_write;	codec->reg_cache_size = CS4270_NUMREGS;	/* The I2C interface is set up, so pre-fill our register cache */	ret = cs4270_fill_cache(codec);	if (ret < 0) {		printk(KERN_ERR "cs4270: failed to fill register cache\n");		goto error;	}	/* Add the non-DAPM controls */	for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) {		struct snd_kcontrol *kctrl =		snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);		ret = snd_ctl_add(codec->card, kctrl);		if (ret < 0)			goto error;	}	return 0;error:	if (codec->control_data) {		i2c_detach_client(i2c_client);		codec->control_data = NULL;	}	kfree(codec->reg_cache);	codec->reg_cache = NULL;	codec->reg_cache_size = 0;	kfree(i2c_client);	return ret;}#endifstruct snd_soc_codec_dai cs4270_dai = {	.name = "CS4270",	.playback = {		.stream_name = "Playback",		.channels_min = 1,		.channels_max = 2,		.rates = 0,		.formats = CS4270_FORMATS,	},	.capture = {		.stream_name = "Capture",		.channels_min = 1,		.channels_max = 2,		.rates = 0,		.formats = CS4270_FORMATS,	},	.dai_ops = {		.set_sysclk = cs4270_set_dai_sysclk,		.set_fmt = cs4270_set_dai_fmt,	}};EXPORT_SYMBOL_GPL(cs4270_dai);/* * ASoC probe function * * This function is called when the machine driver calls * platform_device_add(). */static int cs4270_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 "CS4270 ALSA SoC Codec\n");	/* Allocate enough space for the snd_soc_codec structure	   and our private data together. */	codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) +			sizeof(struct cs4270_private), GFP_KERNEL);	if (!codec) {		printk(KERN_ERR "cs4270: Could not allocate codec structure\n");		return -ENOMEM;	}	mutex_init(&codec->mutex);	INIT_LIST_HEAD(&codec->dapm_widgets);	INIT_LIST_HEAD(&codec->dapm_paths);	codec->name = "CS4270";	codec->owner = THIS_MODULE;	codec->dai = &cs4270_dai;	codec->num_dai = 1;	codec->private_data = (void *) codec +		ALIGN(sizeof(struct snd_soc_codec), 4);	socdev->codec = codec;	/* Register PCMs */	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);	if (ret < 0) {		printk(KERN_ERR "cs4270: failed to create PCMs\n");		return ret;	}#ifdef USE_I2C	cs4270_socdev = socdev;	ret = i2c_add_driver(&cs4270_i2c_driver);	if (ret) {		printk(KERN_ERR "cs4270: failed to attach driver");		snd_soc_free_pcms(socdev);		return ret;	}	/* Did we find a CS4270 on the I2C bus? */	if (codec->control_data) {		/* Initialize codec ops */		cs4270_dai.ops.hw_params = cs4270_hw_params;#ifdef CONFIG_SND_SOC_CS4270_HWMUTE		cs4270_dai.dai_ops.digital_mute = cs4270_mute;#endif	} else		printk(KERN_INFO "cs4270: no I2C device found, "			"using stand-alone mode\n");#else	printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n");#endif	ret = snd_soc_register_card(socdev);	if (ret < 0) {		printk(KERN_ERR "cs4270: failed to register card\n");		snd_soc_free_pcms(socdev);		return ret;	}	return ret;}static int cs4270_remove(struct platform_device *pdev){	struct snd_soc_device *socdev = platform_get_drvdata(pdev);	snd_soc_free_pcms(socdev);#ifdef USE_I2C	if (socdev->codec->control_data)		i2c_del_driver(&cs4270_i2c_driver);#endif	kfree(socdev->codec);	socdev->codec = NULL;	return 0;}/* * ASoC codec device structure * * Assign this variable to the codec_dev field of the machine driver's * snd_soc_device structure. */struct snd_soc_codec_device soc_codec_device_cs4270 = {	.probe = 	cs4270_probe,	.remove = 	cs4270_remove};EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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