summaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/cs4270.c252
1 files changed, 113 insertions, 139 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index e2130d7b1e41..2aa12fdbd2ca 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -31,12 +31,6 @@
#include "cs4270.h"
-/* Private data for the CS4270 */
-struct cs4270_private {
- unsigned int mclk; /* Input frequency of the MCLK pin */
- unsigned int mode; /* The mode (I2S or left-justified) */
-};
-
/*
* The codec isn't really big-endian or little-endian, since the I2S
* interface requires data to be sent serially with the MSbit first.
@@ -109,6 +103,14 @@ struct cs4270_private {
#define CS4270_MUTE_DAC_A 0x01
#define CS4270_MUTE_DAC_B 0x02
+/* Private data for the CS4270 */
+struct cs4270_private {
+ struct snd_soc_codec codec;
+ u8 reg_cache[CS4270_NUMREGS];
+ unsigned int mclk; /* Input frequency of the MCLK pin */
+ unsigned int mode; /* The mode (I2S or left-justified) */
+};
+
/*
* Clock Ratio Selection for Master Mode with I2C enabled
*
@@ -504,6 +506,31 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
*/
static struct snd_soc_device *cs4270_socdev;
+struct snd_soc_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,
+ },
+ .ops = {
+ .hw_params = cs4270_hw_params,
+ .set_sysclk = cs4270_set_dai_sysclk,
+ .set_fmt = cs4270_set_dai_fmt,
+ .digital_mute = cs4270_mute,
+ },
+};
+EXPORT_SYMBOL_GPL(cs4270_dai);
+
/*
* Initialize the I2C interface of the CS4270
*
@@ -517,47 +544,52 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = cs4270_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec;
+ struct cs4270_private *cs4270;
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 */
-
- 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;
- }
-
/* 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;
+ return ret;
}
/* 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_ERR "cs4270: device at addr %X is not a CS4270\n",
+ i2c_client->addr);
+ return -ENODEV;
}
printk(KERN_INFO "cs4270: found device at I2C address %X\n",
i2c_client->addr);
printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF);
+ /* Allocate enough space for the snd_soc_codec structure
+ and our private data together. */
+ cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+ if (!cs4270) {
+ printk(KERN_ERR "cs4270: Could not allocate codec structure\n");
+ return -ENOMEM;
+ }
+ codec = &cs4270->codec;
+ socdev->codec = codec;
+
+ 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 = cs4270;
codec->control_data = i2c_client;
codec->read = cs4270_read_reg_cache;
codec->write = cs4270_i2c_write;
+ codec->reg_cache = cs4270->reg_cache;
codec->reg_cache_size = CS4270_NUMREGS;
/* The I2C interface is set up, so pre-fill our register cache */
@@ -565,35 +597,72 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
ret = cs4270_fill_cache(codec);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to fill register cache\n");
- goto error;
+ goto error_free_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");
+ goto error_free_codec;
}
/* 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);
+ struct snd_kcontrol *kctrl;
+
+ kctrl = snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);
+ if (!kctrl) {
+ printk(KERN_ERR "cs4270: error creating control '%s'\n",
+ cs4270_snd_controls[i].name);
+ ret = -ENOMEM;
+ goto error_free_pcms;
+ }
ret = snd_ctl_add(codec->card, kctrl);
- if (ret < 0)
- goto error;
+ if (ret < 0) {
+ printk(KERN_ERR "cs4270: error adding control '%s'\n",
+ cs4270_snd_controls[i].name);
+ goto error_free_pcms;
+ }
}
- i2c_set_clientdata(i2c_client, codec);
+ /* Initialize the SOC device */
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "cs4270: failed to register card\n");
+ goto error_free_pcms;;
+ }
+
+ i2c_set_clientdata(i2c_client, socdev);
return 0;
-error:
- codec->control_data = NULL;
+error_free_pcms:
+ snd_soc_free_pcms(socdev);
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
- codec->reg_cache_size = 0;
+error_free_codec:
+ kfree(cs4270);
return ret;
}
-static const struct i2c_device_id cs4270_id[] = {
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct snd_soc_device *socdev = i2c_get_clientdata(i2c_client);
+ struct snd_soc_codec *codec = socdev->codec;
+ struct cs4270_private *cs4270 = codec->private_data;
+
+ snd_soc_free_pcms(socdev);
+ kfree(cs4270);
+
+ return 0;
+}
+
+static struct i2c_device_id cs4270_id[] = {
{"cs4270", 0},
{}
};
@@ -606,27 +675,9 @@ static struct i2c_driver cs4270_i2c_driver = {
},
.id_table = cs4270_id,
.probe = cs4270_i2c_probe,
+ .remove = cs4270_i2c_remove,
};
-struct snd_soc_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,
- },
-};
-EXPORT_SYMBOL_GPL(cs4270_dai);
-
/*
* ASoC probe function
*
@@ -635,94 +686,15 @@ EXPORT_SYMBOL_GPL(cs4270_dai);
*/
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");
- goto error_free_codec;
- }
-
- cs4270_socdev = socdev;
-
- ret = i2c_add_driver(&cs4270_i2c_driver);
- if (ret) {
- printk(KERN_ERR "cs4270: failed to attach driver");
- goto error_free_pcms;
- }
-
- /* Did we find a CS4270 on the I2C bus? */
- if (!codec->control_data) {
- printk(KERN_ERR "cs4270: failed to attach driver");
- goto error_del_driver;
- }
+ cs4270_socdev = platform_get_drvdata(pdev);;
- /* Initialize codec ops */
- cs4270_dai.ops.hw_params = cs4270_hw_params;
- cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
- cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
- cs4270_dai.ops.digital_mute = cs4270_mute;
-
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "cs4270: failed to register card\n");
- goto error_del_driver;
- }
-
- return 0;
-
-error_del_driver:
- i2c_del_driver(&cs4270_i2c_driver);
-
-error_free_pcms:
- snd_soc_free_pcms(socdev);
-
-error_free_codec:
- kfree(socdev->codec);
- socdev->codec = NULL;
-
- return ret;
+ return i2c_add_driver(&cs4270_i2c_driver);
}
static int cs4270_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
-
i2c_del_driver(&cs4270_i2c_driver);
- kfree(socdev->codec);
- socdev->codec = NULL;
-
return 0;
}
@@ -740,6 +712,8 @@ EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
static int __init cs4270_init(void)
{
+ printk(KERN_INFO "Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
+
return snd_soc_register_dai(&cs4270_dai);
}
module_init(cs4270_init);
OpenPOWER on IntegriCloud