ASoC: Samsung: Rename from s3c24xx to samsung
[deliverable/linux.git] / sound / soc / codecs / uda1380.c
index 1a51c816e54281c962a9b029ac53c4d78349a70a..800980e2e9ab5dd807a2c8529256cb691503ef75 100644 (file)
@@ -27,7 +27,6 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/uda1380.h>
 
@@ -39,6 +38,7 @@ struct uda1380_priv {
        u16 reg_cache[UDA1380_CACHEREGNUM];
        unsigned int dac_clk;
        struct work_struct work;
+       void *control_data;
 };
 
 /*
@@ -129,7 +129,46 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
-#define uda1380_reset(c)       uda1380_write(c, UDA1380_RESET, 0)
+static void uda1380_sync_cache(struct snd_soc_codec *codec)
+{
+       int reg;
+       u8 data[3];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (reg = 0; reg < UDA1380_MVOL; reg++) {
+               data[0] = reg;
+               data[1] = (cache[reg] & 0xff00) >> 8;
+               data[2] = cache[reg] & 0x00ff;
+               if (codec->hw_write(codec->control_data, data, 3) != 3)
+                       dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
+                               __func__, reg);
+       }
+}
+
+static int uda1380_reset(struct snd_soc_codec *codec)
+{
+       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+       if (gpio_is_valid(pdata->gpio_reset)) {
+               gpio_set_value(pdata->gpio_reset, 1);
+               mdelay(1);
+               gpio_set_value(pdata->gpio_reset, 0);
+       } else {
+               u8 data[3];
+
+               data[0] = UDA1380_RESET;
+               data[1] = 0;
+               data[2] = 0;
+
+               if (codec->hw_write(codec->control_data, data, 3) != 3) {
+                       dev_err(codec->dev, "%s: failed\n", __func__);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
 
 static void uda1380_flush_work(struct work_struct *work)
 {
@@ -374,10 +413,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int uda1380_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
-                                 ARRAY_SIZE(uda1380_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
+                                 ARRAY_SIZE(uda1380_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -560,20 +600,43 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
        int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+       int reg;
+       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+       if (codec->dapm.bias_level == level)
+               return 0;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
+               /* ADC, DAC on */
                uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
                break;
        case SND_SOC_BIAS_STANDBY:
-               uda1380_write(codec, UDA1380_PM, R02_PON_BIAS);
-               break;
-       case SND_SOC_BIAS_OFF:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       if (gpio_is_valid(pdata->gpio_power)) {
+                               gpio_set_value(pdata->gpio_power, 1);
+                               mdelay(1);
+                               uda1380_reset(codec);
+                       }
+
+                       uda1380_sync_cache(codec);
+               }
                uda1380_write(codec, UDA1380_PM, 0x0);
                break;
+       case SND_SOC_BIAS_OFF:
+               if (!gpio_is_valid(pdata->gpio_power))
+                       break;
+
+               gpio_set_value(pdata->gpio_power, 0);
+
+               /* Mark mixer regs cache dirty to sync them with
+                * codec regs on power on.
+                */
+               for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
+                       set_bit(reg - 0x10, &uda1380_cache_dirty);
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -651,16 +714,6 @@ static int uda1380_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int uda1380_resume(struct snd_soc_codec *codec)
 {
-       int i;
-       u8 data[2];
-       u16 *cache = codec->reg_cache;
-
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) {
-               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-               data[1] = cache[i] & 0x00ff;
-               codec->hw_write(codec->control_data, data, 2);
-       }
        uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
@@ -671,29 +724,36 @@ static int uda1380_probe(struct snd_soc_codec *codec)
        struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
+       uda1380->codec = codec;
+
        codec->hw_write = (hw_write_t)i2c_master_send;
+       codec->control_data = uda1380->control_data;
 
-       if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
+       if (!pdata)
                return -EINVAL;
 
-       ret = gpio_request(pdata->gpio_power, "uda1380 power");
-       if (ret)
-               return ret;
-       ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
-       if (ret)
-               goto err_gpio;
-
-       gpio_direction_output(pdata->gpio_power, 1);
-
-       /* we may need to have the clock running here - pH5 */
-       gpio_direction_output(pdata->gpio_reset, 1);
-       udelay(5);
-       gpio_set_value(pdata->gpio_reset, 0);
+       if (gpio_is_valid(pdata->gpio_reset)) {
+               ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+               if (ret)
+                       goto err_out;
+               ret = gpio_direction_output(pdata->gpio_reset, 0);
+               if (ret)
+                       goto err_gpio_reset_conf;
+       }
 
-       ret = uda1380_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_reset;
+       if (gpio_is_valid(pdata->gpio_power)) {
+               ret = gpio_request(pdata->gpio_power, "uda1380 power");
+               if (ret)
+                       goto err_gpio;
+               ret = gpio_direction_output(pdata->gpio_power, 0);
+               if (ret)
+                       goto err_gpio_power_conf;
+       } else {
+               ret = uda1380_reset(codec);
+               if (ret) {
+                       dev_err(codec->dev, "Failed to issue reset\n");
+                       goto err_reset;
+               }
        }
 
        INIT_WORK(&uda1380->work, uda1380_flush_work);
@@ -703,10 +763,11 @@ static int uda1380_probe(struct snd_soc_codec *codec)
        /* set clock input */
        switch (pdata->dac_clk) {
        case UDA1380_DAC_CLK_SYSCLK:
-               uda1380_write(codec, UDA1380_CLK, 0);
+               uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
                break;
        case UDA1380_DAC_CLK_WSPLL:
-               uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
+               uda1380_write_reg_cache(codec, UDA1380_CLK,
+                       R00_DAC_CLK);
                break;
        }
 
@@ -717,10 +778,15 @@ static int uda1380_probe(struct snd_soc_codec *codec)
        return 0;
 
 err_reset:
-       gpio_set_value(pdata->gpio_power, 0);
-       gpio_free(pdata->gpio_reset);
+err_gpio_power_conf:
+       if (gpio_is_valid(pdata->gpio_power))
+               gpio_free(pdata->gpio_power);
+
+err_gpio_reset_conf:
 err_gpio:
-       gpio_free(pdata->gpio_power);
+       if (gpio_is_valid(pdata->gpio_reset))
+               gpio_free(pdata->gpio_reset);
+err_out:
        return ret;
 }
 
@@ -731,7 +797,6 @@ static int uda1380_remove(struct snd_soc_codec *codec)
 
        uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       gpio_set_value(pdata->gpio_power, 0);
        gpio_free(pdata->gpio_reset);
        gpio_free(pdata->gpio_power);
 
@@ -743,8 +808,8 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
        .remove =       uda1380_remove,
        .suspend =      uda1380_suspend,
        .resume =       uda1380_resume,
-       .read = uda1380_read_reg_cache,
-       .write = uda1380_write,
+       .read =         uda1380_read_reg_cache,
+       .write =        uda1380_write,
        .set_bias_level = uda1380_set_bias_level,
        .reg_cache_size = ARRAY_SIZE(uda1380_reg),
        .reg_word_size = sizeof(u16),
@@ -764,6 +829,7 @@ static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, uda1380);
+       uda1380->control_data = i2c;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
This page took 0.028096 seconds and 5 git commands to generate.