ASoC: improve I2C initialization code in CS4270 driver

Further improvements in the I2C initialization sequence of the CS4270 driver.
All ASoC initialization is now done in the I2C probe function.

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index e2130d7..2aa12fd 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 @@
 #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,112 +506,8 @@
  */
 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_client *i2c_client,
-	const struct i2c_device_id *id)
-{
-	struct snd_soc_device *socdev = cs4270_socdev;
-	struct snd_soc_codec *codec = socdev->codec;
-	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;
-	}
-	/* 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",
-		i2c_client->addr);
-	printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF);
-
-	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;
-	}
-
-	i2c_set_clientdata(i2c_client, codec);
-
-	return 0;
-
-error:
-	codec->control_data = NULL;
-
-	kfree(codec->reg_cache);
-	codec->reg_cache = NULL;
-	codec->reg_cache_size = 0;
-
-	return ret;
-}
-
-static const struct i2c_device_id cs4270_id[] = {
-	{"cs4270", 0},
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
-
-static struct i2c_driver cs4270_i2c_driver = {
-	.driver = {
-		.name = "cs4270",
-		.owner = THIS_MODULE,
-	},
-	.id_table = cs4270_id,
-	.probe = cs4270_i2c_probe,
-};
-
 struct snd_soc_dai cs4270_dai = {
-	.name = "CS4270",
+	.name = "cs4270",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -624,31 +522,60 @@
 		.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);
 
 /*
- * ASoC probe function
+ * Initialize the I2C interface of the CS4270
  *
- * This function is called when the machine driver calls
- * platform_device_add().
+ * 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_probe(struct platform_device *pdev)
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+	const struct i2c_device_id *id)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_device *socdev = cs4270_socdev;
 	struct snd_soc_codec *codec;
+	struct cs4270_private *cs4270;
+	int i;
 	int ret = 0;
 
-	printk(KERN_INFO "CS4270 ALSA SoC Codec\n");
+	/* 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");
+		return ret;
+	}
+	/* The top four bits of the chip ID should be 1100. */
+	if ((ret & 0xF0) != 0xC0) {
+		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. */
-	codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) +
-			sizeof(struct cs4270_private), GFP_KERNEL);
-	if (!codec) {
+	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);
@@ -658,10 +585,20 @@
 	codec->owner = THIS_MODULE;
 	codec->dai = &cs4270_dai;
 	codec->num_dai = 1;
-	codec->private_data = (void *) codec +
-		ALIGN(sizeof(struct snd_soc_codec), 4);
+	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;
 
-	socdev->codec = codec;
+	/* 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_free_codec;
+	}
 
 	/* Register PCMs */
 
@@ -671,58 +608,93 @@
 		goto error_free_codec;
 	}
 
-	cs4270_socdev = socdev;
+	/* Add the non-DAPM controls */
 
-	ret = i2c_add_driver(&cs4270_i2c_driver);
-	if (ret) {
-		printk(KERN_ERR "cs4270: failed to attach driver");
-		goto error_free_pcms;
+	for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) {
+		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) {
+			printk(KERN_ERR "cs4270: error adding control '%s'\n",
+			       cs4270_snd_controls[i].name);
+			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;
-	}
-
-	/* 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;
+	/* Initialize the SOC device */
 
 	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "cs4270: failed to register card\n");
-		goto error_del_driver;
+		goto error_free_pcms;;
 	}
 
-	return 0;
+	i2c_set_clientdata(i2c_client, socdev);
 
-error_del_driver:
-	i2c_del_driver(&cs4270_i2c_driver);
+	return 0;
 
 error_free_pcms:
 	snd_soc_free_pcms(socdev);
 
 error_free_codec:
-	kfree(socdev->codec);
-	socdev->codec = NULL;
+	kfree(cs4270);
 
 	return ret;
 }
 
-static int cs4270_remove(struct platform_device *pdev)
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	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},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
+static struct i2c_driver cs4270_i2c_driver = {
+	.driver = {
+		.name = "cs4270",
+		.owner = THIS_MODULE,
+	},
+	.id_table = cs4270_id,
+	.probe = cs4270_i2c_probe,
+	.remove = cs4270_i2c_remove,
+};
+
+/*
+ * ASoC probe function
+ *
+ * This function is called when the machine driver calls
+ * platform_device_add().
+ */
+static int cs4270_probe(struct platform_device *pdev)
+{
+	cs4270_socdev = platform_get_drvdata(pdev);;
+
+	return i2c_add_driver(&cs4270_i2c_driver);
+}
+
+static int cs4270_remove(struct platform_device *pdev)
+{
 	i2c_del_driver(&cs4270_i2c_driver);
 
-	kfree(socdev->codec);
-	socdev->codec = NULL;
-
 	return 0;
 }
 
@@ -740,6 +712,8 @@
 
 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);