writeback: fix break condition
[safe/jmp/linux-2.6] / sound / soc / codecs / cs4270.c
index dab22cc..f1aa0c3 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
@@ -48,12 +47,130 @@ struct cs4270_private {
        unsigned int mode; /* The mode (I2S or left-justified) */
 };
 
-/* The number of MCLK/LRCK ratios supported by the CS4270 */
-#define NUM_MCLK_RATIOS                9
+/*
+ * The codec isn't really big-endian or little-endian, since the I2S
+ * interface requires data to be sent serially with the MSbit first.
+ * However, to support BE and LE I2S devices, we specify both here.  That
+ * way, ALSA will always match the bit patterns.
+ */
+#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8      | \
+                       SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+                       SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+                       SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+                       SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
+
+#ifdef USE_I2C
+
+/* CS4270 registers addresses */
+#define CS4270_CHIPID  0x01    /* Chip ID */
+#define CS4270_PWRCTL  0x02    /* Power Control */
+#define CS4270_MODE    0x03    /* Mode Control */
+#define CS4270_FORMAT  0x04    /* Serial Format, ADC/DAC Control */
+#define CS4270_TRANS   0x05    /* Transition Control */
+#define CS4270_MUTE    0x06    /* Mute Control */
+#define CS4270_VOLA    0x07    /* DAC Channel A Volume Control */
+#define CS4270_VOLB    0x08    /* DAC Channel B Volume Control */
 
-/* The actual MCLK/LRCK ratios, in increasing numerical order */
-static unsigned int mclk_ratios[NUM_MCLK_RATIOS] =
-       {64, 96, 128, 192, 256, 384, 512, 768, 1024};
+#define CS4270_FIRSTREG        0x01
+#define CS4270_LASTREG 0x08
+#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
+
+/* Bit masks for the CS4270 registers */
+#define CS4270_CHIPID_ID       0xF0
+#define CS4270_CHIPID_REV      0x0F
+#define CS4270_PWRCTL_FREEZE   0x80
+#define CS4270_PWRCTL_PDN_ADC  0x20
+#define CS4270_PWRCTL_PDN_DAC  0x02
+#define CS4270_PWRCTL_PDN      0x01
+#define CS4270_MODE_SPEED_MASK 0x30
+#define CS4270_MODE_1X         0x00
+#define CS4270_MODE_2X         0x10
+#define CS4270_MODE_4X         0x20
+#define CS4270_MODE_SLAVE      0x30
+#define CS4270_MODE_DIV_MASK   0x0E
+#define CS4270_MODE_DIV1       0x00
+#define CS4270_MODE_DIV15      0x02
+#define CS4270_MODE_DIV2       0x04
+#define CS4270_MODE_DIV3       0x06
+#define CS4270_MODE_DIV4       0x08
+#define CS4270_MODE_POPGUARD   0x01
+#define CS4270_FORMAT_FREEZE_A 0x80
+#define CS4270_FORMAT_FREEZE_B 0x40
+#define CS4270_FORMAT_LOOPBACK 0x20
+#define CS4270_FORMAT_DAC_MASK 0x18
+#define CS4270_FORMAT_DAC_LJ   0x00
+#define CS4270_FORMAT_DAC_I2S  0x08
+#define CS4270_FORMAT_DAC_RJ16 0x18
+#define CS4270_FORMAT_DAC_RJ24 0x10
+#define CS4270_FORMAT_ADC_MASK 0x01
+#define CS4270_FORMAT_ADC_LJ   0x00
+#define CS4270_FORMAT_ADC_I2S  0x01
+#define CS4270_TRANS_ONE_VOL   0x80
+#define CS4270_TRANS_SOFT      0x40
+#define CS4270_TRANS_ZERO      0x20
+#define CS4270_TRANS_INV_ADC_A 0x08
+#define CS4270_TRANS_INV_ADC_B 0x10
+#define CS4270_TRANS_INV_DAC_A 0x02
+#define CS4270_TRANS_INV_DAC_B 0x04
+#define CS4270_TRANS_DEEMPH    0x01
+#define CS4270_MUTE_AUTO       0x20
+#define CS4270_MUTE_ADC_A      0x08
+#define CS4270_MUTE_ADC_B      0x10
+#define CS4270_MUTE_POLARITY   0x04
+#define CS4270_MUTE_DAC_A      0x01
+#define CS4270_MUTE_DAC_B      0x02
+
+/*
+ * Clock Ratio Selection for Master Mode with I2C enabled
+ *
+ * The data for this chart is taken from Table 5 of the CS4270 reference
+ * manual.
+ *
+ * This table is used to determine how to program the Mode Control register.
+ * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
+ * rates the CS4270 currently supports.
+ *
+ * Each element in this array corresponds to the ratios in mclk_ratios[].
+ * These two arrays need to be in sync.
+ *
+ * 'speed_mode' is the corresponding bit pattern to be written to the
+ * MODE bits of the Mode Control Register
+ *
+ * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
+ * the Mode Control Register.
+ *
+ * In situations where a single ratio is represented by multiple speed
+ * modes, we favor the slowest speed.  E.g, for a ratio of 128, we pick
+ * double-speed instead of quad-speed.  However, the CS4270 errata states
+ * that Divide-By-1.5 can cause failures, so we avoid that mode where
+ * possible.
+ *
+ * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
+ * work if VD = 3.3V.  If this effects you, select the
+ * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
+ * never select any sample rates that require divide-by-1.5.
+ */
+static struct {
+       unsigned int ratio;
+       u8 speed_mode;
+       u8 mclk;
+} cs4270_mode_ratios[] = {
+       {64, CS4270_MODE_4X, CS4270_MODE_DIV1},
+#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
+       {96, CS4270_MODE_4X, CS4270_MODE_DIV15},
+#endif
+       {128, CS4270_MODE_2X, CS4270_MODE_DIV1},
+       {192, CS4270_MODE_4X, CS4270_MODE_DIV3},
+       {256, CS4270_MODE_1X, CS4270_MODE_DIV1},
+       {384, CS4270_MODE_2X, CS4270_MODE_DIV3},
+       {512, CS4270_MODE_1X, CS4270_MODE_DIV2},
+       {768, CS4270_MODE_1X, CS4270_MODE_DIV3},
+       {1024, CS4270_MODE_1X, CS4270_MODE_DIV4}
+};
+
+/* The number of MCLK/LRCK ratios supported by the CS4270 */
+#define NUM_MCLK_RATIOS                ARRAY_SIZE(cs4270_mode_ratios)
 
 /*
  * Determine the CS4270 samples rates.
@@ -84,7 +201,7 @@ static unsigned int mclk_ratios[NUM_MCLK_RATIOS] =
  * driver what the input settings can be.  This would need to be implemented
  * for stand-alone mode to work.
  */
-static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                 int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -97,7 +214,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
        cs4270->mclk = freq;
 
        for (i = 0; i < NUM_MCLK_RATIOS; i++) {
-               unsigned int rate = freq / mclk_ratios[i];
+               unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
                rates |= snd_pcm_rate_to_rate_bit(rate);
                if (rate < rate_min)
                        rate_min = rate;
@@ -134,7 +251,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
  * data for playback only, but ASoC currently does not support different
  * formats for playback vs. record.
  */
-static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
                              unsigned int format)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -155,80 +272,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
 }
 
 /*
- * The codec isn't really big-endian or little-endian, since the I2S
- * interface requires data to be sent serially with the MSbit first.
- * However, to support BE and LE I2S devices, we specify both here.  That
- * way, ALSA will always match the bit patterns.
- */
-#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8      | \
-                       SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
-                       SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
-                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
-                       SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
-                       SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
-
-#ifdef USE_I2C
-
-/* CS4270 registers addresses */
-#define CS4270_CHIPID  0x01    /* Chip ID */
-#define CS4270_PWRCTL  0x02    /* Power Control */
-#define CS4270_MODE    0x03    /* Mode Control */
-#define CS4270_FORMAT  0x04    /* Serial Format, ADC/DAC Control */
-#define CS4270_TRANS   0x05    /* Transition Control */
-#define CS4270_MUTE    0x06    /* Mute Control */
-#define CS4270_VOLA    0x07    /* DAC Channel A Volume Control */
-#define CS4270_VOLB    0x08    /* DAC Channel B Volume Control */
-
-#define CS4270_FIRSTREG        0x01
-#define CS4270_LASTREG 0x08
-#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
-
-/* Bit masks for the CS4270 registers */
-#define CS4270_CHIPID_ID       0xF0
-#define CS4270_CHIPID_REV      0x0F
-#define CS4270_PWRCTL_FREEZE   0x80
-#define CS4270_PWRCTL_PDN_ADC  0x20
-#define CS4270_PWRCTL_PDN_DAC  0x02
-#define CS4270_PWRCTL_PDN      0x01
-#define CS4270_MODE_SPEED_MASK 0x30
-#define CS4270_MODE_1X         0x00
-#define CS4270_MODE_2X         0x10
-#define CS4270_MODE_4X         0x20
-#define CS4270_MODE_SLAVE      0x30
-#define CS4270_MODE_DIV_MASK   0x0E
-#define CS4270_MODE_DIV1       0x00
-#define CS4270_MODE_DIV15      0x02
-#define CS4270_MODE_DIV2       0x04
-#define CS4270_MODE_DIV3       0x06
-#define CS4270_MODE_DIV4       0x08
-#define CS4270_MODE_POPGUARD   0x01
-#define CS4270_FORMAT_FREEZE_A 0x80
-#define CS4270_FORMAT_FREEZE_B 0x40
-#define CS4270_FORMAT_LOOPBACK 0x20
-#define CS4270_FORMAT_DAC_MASK 0x18
-#define CS4270_FORMAT_DAC_LJ   0x00
-#define CS4270_FORMAT_DAC_I2S  0x08
-#define CS4270_FORMAT_DAC_RJ16 0x18
-#define CS4270_FORMAT_DAC_RJ24 0x10
-#define CS4270_FORMAT_ADC_MASK 0x01
-#define CS4270_FORMAT_ADC_LJ   0x00
-#define CS4270_FORMAT_ADC_I2S  0x01
-#define CS4270_TRANS_ONE_VOL   0x80
-#define CS4270_TRANS_SOFT      0x40
-#define CS4270_TRANS_ZERO      0x20
-#define CS4270_TRANS_INV_ADC_A 0x08
-#define CS4270_TRANS_INV_ADC_B 0x10
-#define CS4270_TRANS_INV_DAC_A 0x02
-#define CS4270_TRANS_INV_DAC_B 0x04
-#define CS4270_TRANS_DEEMPH    0x01
-#define CS4270_MUTE_AUTO       0x20
-#define CS4270_MUTE_ADC_A      0x08
-#define CS4270_MUTE_ADC_B      0x10
-#define CS4270_MUTE_POLARITY   0x04
-#define CS4270_MUTE_DAC_A      0x01
-#define CS4270_MUTE_DAC_B      0x02
-
-/*
  * A list of addresses on which this CS4270 could use.  I2C addresses are
  * 7 bits.  For the CS4270, the upper four bits are always 1001, and the
  * lower three bits are determined via the AD2, AD1, and AD0 pins
@@ -315,68 +358,22 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
 }
 
 /*
- * Clock Ratio Selection for Master Mode with I2C enabled
- *
- * The data for this chart is taken from Table 5 of the CS4270 reference
- * manual.
- *
- * This table is used to determine how to program the Mode Control register.
- * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
- * rates the CS4270 currently supports.
- *
- * Each element in this array corresponds to the ratios in mclk_ratios[].
- * These two arrays need to be in sync.
- *
- * 'speed_mode' is the corresponding bit pattern to be written to the
- * MODE bits of the Mode Control Register
- *
- * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
- * the Mode Control Register.
- *
- * In situations where a single ratio is represented by multiple speed
- * modes, we favor the slowest speed.  E.g, for a ratio of 128, we pick
- * double-speed instead of quad-speed.  However, the CS4270 errata states
- * that Divide-By-1.5 can cause failures, so we avoid that mode where
- * possible.
- *
- * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
- * work if VD = 3.3V.  If this effects you, select the
- * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
- * never select any sample rates that require divide-by-1.5.
- */
-static struct {
-       u8 speed_mode;
-       u8 mclk;
-} cs4270_mode_ratios[NUM_MCLK_RATIOS] = {
-       {CS4270_MODE_4X, CS4270_MODE_DIV1},     /* 64 */
-#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
-       {CS4270_MODE_4X, CS4270_MODE_DIV15},    /* 96 */
-#endif
-       {CS4270_MODE_2X, CS4270_MODE_DIV1},     /* 128 */
-       {CS4270_MODE_4X, CS4270_MODE_DIV3},     /* 192 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV1},     /* 256 */
-       {CS4270_MODE_2X, CS4270_MODE_DIV3},     /* 384 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV2},     /* 512 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV3},     /* 768 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV4}      /* 1024 */
-};
-
-/*
  * Program the CS4270 with the given hardware parameters.
  *
- * The .dai_ops functions are used to provide board-specific data, like
+ * The .ops functions are used to provide board-specific data, like
  * input frequencies, to this driver.  This function takes that information,
  * combines it with the hardware parameters provided, and programs the
  * hardware accordingly.
  */
 static int cs4270_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params)
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->codec;
        struct cs4270_private *cs4270 = codec->private_data;
-       unsigned int ret = 0;
+       int ret;
        unsigned int i;
        unsigned int rate;
        unsigned int ratio;
@@ -388,7 +385,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
        ratio = cs4270->mclk / rate;    /* MCLK/LRCK ratio */
 
        for (i = 0; i < NUM_MCLK_RATIOS; i++) {
-               if (mclk_ratios[i] == ratio)
+               if (cs4270_mode_ratios[i].ratio == ratio)
                        break;
        }
 
@@ -454,6 +451,19 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
+       /* Disable automatic volume control.  It's enabled by default, and
+        * it causes volume change commands to be delayed, sometimes until
+        * after playback has started.
+        */
+
+       reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
+       reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
+       ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
+       if (ret < 0) {
+               printk(KERN_ERR "I2C write failed\n");
+               return ret;
+       }
+
        /* Thaw and power-up the codec */
 
        ret = snd_soc_write(codec, CS4270_PWRCTL, 0);
@@ -475,7 +485,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
  * 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)
+static int cs4270_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        int reg6;
@@ -494,34 +504,7 @@ static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute)
 
 #endif
 
-static 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;
-}
+static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *);
 
 /* A list of non-DAPM controls that the CS4270 supports */
 static const struct snd_kcontrol_new cs4270_snd_controls[] = {
@@ -529,14 +512,19 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
                CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1)
 };
 
+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 I2C",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_CS4270,
-       .attach_adapter = cs4270_i2c_attach,
-       .detach_client =  cs4270_i2c_detach,
+       .id_table = cs4270_id,
+       .probe = cs4270_i2c_probe,
 };
 
 /*
@@ -565,11 +553,11 @@ static struct snd_soc_device *cs4270_socdev;
  * 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)
+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 i2c_client *i2c_client = NULL;
        int i;
        int ret = 0;
 
@@ -582,12 +570,6 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind)
 
        /* 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");
@@ -595,13 +577,6 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind)
                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);
@@ -616,18 +591,10 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind)
                goto error;
        }
 
-       printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr);
+       printk(KERN_INFO "cs4270: found device at I2C address %X\n",
+               i2c_client->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;
@@ -652,26 +619,23 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind)
                        goto error;
        }
 
+       i2c_set_clientdata(i2c_client, codec);
+
        return 0;
 
 error:
-       if (codec->control_data) {
-               i2c_detach_client(i2c_client);
-               codec->control_data = NULL;
-       }
+       codec->control_data = NULL;
 
        kfree(codec->reg_cache);
        codec->reg_cache = NULL;
        codec->reg_cache_size = 0;
 
-       kfree(i2c_client);
-
        return ret;
 }
 
-#endif
+#endif /* USE_I2C*/
 
-struct snd_soc_codec_dai cs4270_dai = {
+struct snd_soc_dai cs4270_dai = {
        .name = "CS4270",
        .playback = {
                .stream_name = "Playback",
@@ -687,10 +651,6 @@ struct snd_soc_codec_dai cs4270_dai = {
                .rates = 0,
                .formats = CS4270_FORMATS,
        },
-       .dai_ops = {
-               .set_sysclk = cs4270_set_dai_sysclk,
-               .set_fmt = cs4270_set_dai_fmt,
-       }
 };
 EXPORT_SYMBOL_GPL(cs4270_dai);
 
@@ -735,7 +695,7 @@ static int cs4270_probe(struct platform_device *pdev)
        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;
+               goto error_free_codec;
        }
 
 #ifdef USE_I2C
@@ -744,16 +704,17 @@ static int cs4270_probe(struct platform_device *pdev)
        ret = i2c_add_driver(&cs4270_i2c_driver);
        if (ret) {
                printk(KERN_ERR "cs4270: failed to attach driver");
-               snd_soc_free_pcms(socdev);
-               return ret;
+               goto error_free_pcms;
        }
 
        /* Did we find a CS4270 on the I2C bus? */
        if (codec->control_data) {
                /* 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;
 #ifdef CONFIG_SND_SOC_CS4270_HWMUTE
-               cs4270_dai.dai_ops.digital_mute = cs4270_mute;
+               cs4270_dai.ops.digital_mute = cs4270_mute;
 #endif
        } else
                printk(KERN_INFO "cs4270: no I2C device found, "
@@ -762,13 +723,26 @@ static int cs4270_probe(struct platform_device *pdev)
        printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n");
 #endif
 
-       ret = snd_soc_register_card(socdev);
+       ret = snd_soc_init_card(socdev);
        if (ret < 0) {
                printk(KERN_ERR "cs4270: failed to register card\n");
-               snd_soc_free_pcms(socdev);
-               return ret;
+               goto error_del_driver;
        }
 
+       return 0;
+
+error_del_driver:
+#ifdef USE_I2C
+       i2c_del_driver(&cs4270_i2c_driver);
+
+error_free_pcms:
+#endif
+       snd_soc_free_pcms(socdev);
+
+error_free_codec:
+       kfree(socdev->codec);
+       socdev->codec = NULL;
+
        return ret;
 }
 
@@ -779,8 +753,7 @@ static int cs4270_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
 
 #ifdef USE_I2C
-       if (socdev->codec->control_data)
-               i2c_del_driver(&cs4270_i2c_driver);
+       i2c_del_driver(&cs4270_i2c_driver);
 #endif
 
        kfree(socdev->codec);
@@ -801,6 +774,18 @@ struct snd_soc_codec_device soc_codec_device_cs4270 = {
 };
 EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
 
+static int __init cs4270_init(void)
+{
+       return snd_soc_register_dai(&cs4270_dai);
+}
+module_init(cs4270_init);
+
+static void __exit cs4270_exit(void)
+{
+       snd_soc_unregister_dai(&cs4270_dai);
+}
+module_exit(cs4270_exit);
+
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");
 MODULE_LICENSE("GPL");