Merge branch 'topic/asoc' into for-linus
[safe/jmp/linux-2.6] / sound / soc / codecs / tlv320aic23.c
index bb7cfb8..b0bae35 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 
 #include "tlv320aic23.h"
 
-#define AUDIO_NAME "tlv320aic23"
 #define AIC23_VERSION "0.1"
 
-struct tlv320aic23_srate_reg_info {
-       u32 sample_rate;
-       u8 control;             /* SR3, SR2, SR1, SR0 and BOSR */
-       u8 divider;             /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
-};
-
 /*
  * AIC23 register cache
  */
@@ -85,27 +79,27 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
 
-       u8 data;
+       u8 data[2];
 
        /* TLV320AIC23 has 7 bit address and 9 bits of data
         * so we need to switch one data bit into reg and rest
         * of data into val
         */
 
-       if ((reg < 0 || reg > 9) && (reg != 15)) {
-               printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+       if (reg > 9 && reg != 15) {
+               printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg);
                return -1;
        }
 
-       data = (reg << 1) | (value >> 8 & 0x01);
+       data[0] = (reg << 1) | (value >> 8 & 0x01);
+       data[1] = value & 0xff;
 
        tlv320aic23_write_reg_cache(codec, reg, value);
 
-       if (codec->hw_write(codec->control_data, data,
-                           (value & 0xff)) == 0)
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
                return 0;
 
-       printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+       printk(KERN_ERR "%s cannot write %03x to register R%u\n", __func__,
               value, reg);
 
        return -EIO;
@@ -190,24 +184,6 @@ static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
        SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
 };
 
-/* add non dapm controls */
-static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
-{
-
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&tlv320aic23_snd_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-
-}
-
 /* PGA Mixer controls for Line and Mic switch */
 static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
        SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
@@ -262,19 +238,155 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 };
 
-/* tlv320aic23 related */
-static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
-       {4000, 0x06, 1},        /*  4000 */
-       {8000, 0x06, 0},        /*  8000 */
-       {16000, 0x0C, 1},       /* 16000 */
-       {22050, 0x11, 1},       /* 22050 */
-       {24000, 0x00, 1},       /* 24000 */
-       {32000, 0x0C, 0},       /* 32000 */
-       {44100, 0x11, 0},       /* 44100 */
-       {48000, 0x00, 0},       /* 48000 */
-       {88200, 0x1F, 0},       /* 88200 */
-       {96000, 0x0E, 0},       /* 96000 */
+/* AIC23 driver data */
+struct aic23 {
+       struct snd_soc_codec codec;
+       int mclk;
+       int requested_adc;
+       int requested_dac;
+};
+
+/*
+ * Common Crystals used
+ * 11.2896 Mhz /128 = *88.2k  /192 = 58.8k
+ * 12.0000 Mhz /125 = *96k    /136 = 88.235K
+ * 12.2880 Mhz /128 = *96k    /192 = 64k
+ * 16.9344 Mhz /128 = 132.3k /192 = *88.2k
+ * 18.4320 Mhz /128 = 144k   /192 = *96k
+ */
+
+/*
+ * Normal BOSR 0-256/2 = 128, 1-384/2 = 192
+ * USB BOSR 0-250/2 = 125, 1-272/2 = 136
+ */
+static const int bosr_usb_divisor_table[] = {
+       128, 125, 192, 136
+};
+#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7))
+#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11)        | (1<<15))
+static const unsigned short sr_valid_mask[] = {
+       LOWER_GROUP|UPPER_GROUP,        /* Normal, bosr - 0*/
+       LOWER_GROUP,                    /* Usb, bosr - 0*/
+       LOWER_GROUP|UPPER_GROUP,        /* Normal, bosr - 1*/
+       UPPER_GROUP,                    /* Usb, bosr - 1*/
 };
+/*
+ * Every divisor is a factor of 11*12
+ */
+#define SR_MULT (11*12)
+#define A(x) (SR_MULT/x)
+static const unsigned char sr_adc_mult_table[] = {
+       A(2), A(2), A(12), A(12),  0, 0, A(3), A(1),
+       A(2), A(2), A(11), A(11),  0, 0, 0, A(1)
+};
+static const unsigned char sr_dac_mult_table[] = {
+       A(2), A(12), A(2), A(12),  0, 0, A(3), A(1),
+       A(2), A(11), A(2), A(11),  0, 0, 0, A(1)
+};
+
+static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc,
+               int dac, int dac_l, int dac_h, int need_dac)
+{
+       if ((adc >= adc_l) && (adc <= adc_h) &&
+                       (dac >= dac_l) && (dac <= dac_h)) {
+               int diff_adc = need_adc - adc;
+               int diff_dac = need_dac - dac;
+               return abs(diff_adc) + abs(diff_dac);
+       }
+       return UINT_MAX;
+}
+
+static int find_rate(int mclk, u32 need_adc, u32 need_dac)
+{
+       int i, j;
+       int best_i = -1;
+       int best_j = -1;
+       int best_div = 0;
+       unsigned best_score = UINT_MAX;
+       int adc_l, adc_h, dac_l, dac_h;
+
+       need_adc *= SR_MULT;
+       need_dac *= SR_MULT;
+       /*
+        * rates given are +/- 1/32
+        */
+       adc_l = need_adc - (need_adc >> 5);
+       adc_h = need_adc + (need_adc >> 5);
+       dac_l = need_dac - (need_dac >> 5);
+       dac_h = need_dac + (need_dac >> 5);
+       for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) {
+               int base = mclk / bosr_usb_divisor_table[i];
+               int mask = sr_valid_mask[i];
+               for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table);
+                               j++, mask >>= 1) {
+                       int adc;
+                       int dac;
+                       int score;
+                       if ((mask & 1) == 0)
+                               continue;
+                       adc = base * sr_adc_mult_table[j];
+                       dac = base * sr_dac_mult_table[j];
+                       score = get_score(adc, adc_l, adc_h, need_adc,
+                                       dac, dac_l, dac_h, need_dac);
+                       if (best_score > score) {
+                               best_score = score;
+                               best_i = i;
+                               best_j = j;
+                               best_div = 0;
+                       }
+                       score = get_score((adc >> 1), adc_l, adc_h, need_adc,
+                                       (dac >> 1), dac_l, dac_h, need_dac);
+                       /* prefer to have a /2 */
+                       if ((score != UINT_MAX) && (best_score >= score)) {
+                               best_score = score;
+                               best_i = i;
+                               best_j = j;
+                               best_div = 1;
+                       }
+               }
+       }
+       return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT);
+}
+
+#ifdef DEBUG
+static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk,
+               u32 *sample_rate_adc, u32 *sample_rate_dac)
+{
+       int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE);
+       int sr = (src >> 2) & 0x0f;
+       int val = (mclk / bosr_usb_divisor_table[src & 3]);
+       int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
+       int dac = (val * sr_dac_mult_table[sr]) / SR_MULT;
+       if (src & TLV320AIC23_CLKIN_HALF) {
+               adc >>= 1;
+               dac >>= 1;
+       }
+       *sample_rate_adc = adc;
+       *sample_rate_dac = dac;
+}
+#endif
+
+static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
+               u32 sample_rate_adc, u32 sample_rate_dac)
+{
+       /* Search for the right sample rate */
+       int data = find_rate(mclk, sample_rate_adc, sample_rate_dac);
+       if (data < 0) {
+               printk(KERN_ERR "%s:Invalid rate %u,%u requested\n",
+                               __func__, sample_rate_adc, sample_rate_dac);
+               return -EINVAL;
+       }
+       tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+#ifdef DEBUG
+       {
+               u32 adc, dac;
+               get_current_sample_rates(codec, mclk, &adc, &dac);
+               printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n",
+                       adc, dac, data);
+       }
+#endif
+       return 0;
+}
 
 static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
 {
@@ -284,37 +396,40 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
        /* set up audio path interconnects */
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
 static int tlv320aic23_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;
-       u16 iface_reg, data;
-       u8 count = 0;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       u16 iface_reg;
+       int ret;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       u32 sample_rate_adc = aic23->requested_adc;
+       u32 sample_rate_dac = aic23->requested_dac;
+       u32 sample_rate = params_rate(params);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               aic23->requested_dac = sample_rate_dac = sample_rate;
+               if (!sample_rate_adc)
+                       sample_rate_adc = sample_rate;
+       } else {
+               aic23->requested_adc = sample_rate_adc = sample_rate;
+               if (!sample_rate_dac)
+                       sample_rate_dac = sample_rate;
+       }
+       ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc,
+                       sample_rate_dac);
+       if (ret < 0)
+               return ret;
 
        iface_reg =
            tlv320aic23_read_reg_cache(codec,
                                       TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
-
-       /* Search for the right sample rate */
-       /* Verify what happens if the rate is not supported
-        * now it goes to 96Khz */
-       while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
-              (count < ARRAY_SIZE(srate_reg_info))) {
-               count++;
-       }
-
-       data =  (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
-               (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
-               TLV320AIC23_USB_CLK_ON;
-
-       tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
-
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                break;
@@ -333,11 +448,12 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
+                                  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 snd_soc_codec *codec = socdev->card->codec;
 
        /* set active */
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -345,17 +461,23 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
+                                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 snd_soc_codec *codec = socdev->card->codec;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
        /* deactivate */
        if (!codec->active) {
                udelay(50);
                tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
        }
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               aic23->requested_dac = 0;
+       else
+               aic23->requested_adc = 0;
 }
 
 static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
@@ -402,6 +524,8 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
                iface_reg |= TLV320AIC23_FOR_I2S;
                break;
        case SND_SOC_DAIFMT_DSP_A:
+               iface_reg |= TLV320AIC23_LRP_ON;
+       case SND_SOC_DAIFMT_DSP_B:
                iface_reg |= TLV320AIC23_FOR_DSP;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
@@ -423,12 +547,9 @@ static int tlv320aic23_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;
-
-       switch (freq) {
-       case 12000000:
-               return 0;
-       }
-       return -EINVAL;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       aic23->mclk = freq;
+       return 0;
 }
 
 static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
@@ -461,6 +582,15 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
 #define AIC23_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
+       .prepare        = tlv320aic23_pcm_prepare,
+       .hw_params      = tlv320aic23_hw_params,
+       .shutdown       = tlv320aic23_shutdown,
+       .digital_mute   = tlv320aic23_mute,
+       .set_fmt        = tlv320aic23_set_dai_fmt,
+       .set_sysclk     = tlv320aic23_set_dai_sysclk,
+};
+
 struct snd_soc_dai tlv320aic23_dai = {
        .name = "tlv320aic23",
        .playback = {
@@ -475,16 +605,7 @@ struct snd_soc_dai tlv320aic23_dai = {
                    .channels_max = 2,
                    .rates = AIC23_RATES,
                    .formats = AIC23_FORMATS,},
-       .ops = {
-               .prepare = tlv320aic23_pcm_prepare,
-               .hw_params = tlv320aic23_hw_params,
-               .shutdown = tlv320aic23_shutdown,
-               },
-       .dai_ops = {
-                   .digital_mute = tlv320aic23_mute,
-                   .set_fmt = tlv320aic23_set_dai_fmt,
-                   .set_sysclk = tlv320aic23_set_dai_sysclk,
-                   }
+       .ops = &tlv320aic23_dai_ops,
 };
 EXPORT_SYMBOL_GPL(tlv320aic23_dai);
 
@@ -492,7 +613,7 @@ static int tlv320aic23_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;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -503,18 +624,16 @@ static int tlv320aic23_suspend(struct platform_device *pdev,
 static int tlv320aic23_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
-       int i;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
 
        /* Sync reg_cache with the hardware */
-       for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) {
+       for (reg = 0; reg <= TLV320AIC23_ACTIVE; reg++) {
                u16 val = tlv320aic23_read_reg_cache(codec, reg);
                tlv320aic23_write(codec, reg, val);
        }
 
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
 
        return 0;
 }
@@ -525,7 +644,7 @@ static int tlv320aic23_resume(struct platform_device *pdev)
  */
 static int tlv320aic23_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
        u16 reg;
 
@@ -583,19 +702,12 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
 
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
 
-       tlv320aic23_add_controls(codec);
+       snd_soc_add_controls(codec, tlv320aic23_snd_controls,
+                               ARRAY_SIZE(tlv320aic23_snd_controls));
        tlv320aic23_add_widgets(codec);
-       ret = snd_soc_register_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "tlv320aic23: 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;
@@ -611,7 +723,7 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
                                   const struct i2c_device_id *i2c_id)
 {
        struct snd_soc_device *socdev = tlv320aic23_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -660,22 +772,23 @@ static int tlv320aic23_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec;
+       struct aic23 *aic23;
        int ret = 0;
 
        printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
 
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
+       aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+       if (aic23 == NULL)
                return -ENOMEM;
-
-       socdev->codec = codec;
+       codec = &aic23->codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
        tlv320aic23_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data;
+       codec->hw_write = (hw_write_t) i2c_master_send;
        codec->hw_read = NULL;
        ret = i2c_add_driver(&tlv320aic23_i2c_driver);
        if (ret != 0)
@@ -687,7 +800,8 @@ static int tlv320aic23_probe(struct platform_device *pdev)
 static int tlv320aic23_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
        if (codec->control_data)
                tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -698,7 +812,7 @@ static int tlv320aic23_remove(struct platform_device *pdev)
        i2c_del_driver(&tlv320aic23_i2c_driver);
 #endif
        kfree(codec->reg_cache);
-       kfree(codec);
+       kfree(aic23);
 
        return 0;
 }
@@ -710,6 +824,18 @@ struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
 
+static int __init tlv320aic23_modinit(void)
+{
+       return snd_soc_register_dai(&tlv320aic23_dai);
+}
+module_init(tlv320aic23_modinit);
+
+static void __exit tlv320aic23_exit(void)
+{
+       snd_soc_unregister_dai(&tlv320aic23_dai);
+}
+module_exit(tlv320aic23_exit);
+
 MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
 MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
 MODULE_LICENSE("GPL");