Merge branch 'for-2.6.37' into for-2.6.38
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 6 Dec 2010 14:14:47 +0000 (14:14 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 6 Dec 2010 14:14:47 +0000 (14:14 +0000)
Conflicts:
include/linux/mfd/wm8994/pdata.h

1  2 
include/linux/mfd/wm8994/pdata.h
sound/soc/codecs/wm_hubs.c
sound/soc/soc-core.c

index 882b51aefbc07b76c1a507534802d4ffa8f6b271,add8a1b8bcf0057c3f328c51dc96a4d82ae331a5..9eab263658beb99b043b2cc2c2f441cc25e120d8
@@@ -29,9 -29,7 +29,9 @@@ struct wm8994_ldo_pdata 
  #define WM8994_CONFIGURE_GPIO 0x8000
  
  #define WM8994_DRC_REGS 5
- #define WM8994_EQ_REGS  19
+ #define WM8994_EQ_REGS  20
 +#define WM8958_MBC_CUTOFF_REGS 20
 +#define WM8958_MBC_COEFF_REGS  48
  
  /**
   * DRC configurations are specified with a label and a set of register
@@@ -61,18 -59,6 +61,18 @@@ struct wm8994_retune_mobile_cfg 
          u16 regs[WM8994_EQ_REGS];
  };
  
 +/**
 + * Multiband compressor configurations are specified with a label and
 + * two sets of values to write.  Configurations are expected to be
 + * generated using the multiband compressor configuration panel in
 + * WISCE - see http://www.wolfsonmicro.com/wisce/
 + */
 +struct wm8958_mbc_cfg {
 +      const char *name;
 +      u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
 +      u16 coeff_regs[WM8958_MBC_COEFF_REGS];
 +};
 +
  struct wm8994_pdata {
        int gpio_base;
  
@@@ -92,9 -78,6 +92,9 @@@
          int num_retune_mobile_cfgs;
          struct wm8994_retune_mobile_cfg *retune_mobile_cfgs;
  
 +      int num_mbc_cfgs;
 +      struct wm8958_mbc_cfg *mbc_cfgs;
 +
          /* LINEOUT can be differential or single ended */
          unsigned int lineout1_diff:1;
          unsigned int lineout2_diff:1;
index b24ba9fa7ef7675d935fb893a625191becb4cace,0e24092722c39522d85980a71f8a3727d01cf63f..c466982eed2336706b48c697c39fe53b191376fc
@@@ -22,6 -22,7 +22,6 @@@
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/soc.h>
 -#include <sound/soc-dapm.h>
  #include <sound/initval.h>
  #include <sound/tlv.h>
  
@@@ -93,61 -94,41 +93,61 @@@ static void calibrate_dc_servo(struct s
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        u16 reg, reg_l, reg_r, dcs_cfg;
  
 -      /* Set for 32 series updates */
 -      snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
 -                          WM8993_DCS_SERIES_NO_01_MASK,
 -                          32 << WM8993_DCS_SERIES_NO_01_SHIFT);
 -      wait_for_dc_servo(codec,
 -                        WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1);
 +      /* If we're using a digital only path and have a previously
 +       * callibrated DC servo offset stored then use that. */
 +      if (hubs->class_w && hubs->class_w_dcs) {
 +              dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
 +                      hubs->class_w_dcs);
 +              snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs);
 +              wait_for_dc_servo(codec,
 +                                WM8993_DCS_TRIG_DAC_WR_0 |
 +                                WM8993_DCS_TRIG_DAC_WR_1);
 +              return;
 +      }
 +
 +      /* Devices not using a DCS code correction have startup mode */
 +      if (hubs->dcs_codes) {
 +              /* Set for 32 series updates */
 +              snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
 +                                  WM8993_DCS_SERIES_NO_01_MASK,
 +                                  32 << WM8993_DCS_SERIES_NO_01_SHIFT);
 +              wait_for_dc_servo(codec,
 +                                WM8993_DCS_TRIG_SERIES_0 |
 +                                WM8993_DCS_TRIG_SERIES_1);
 +      } else {
 +              wait_for_dc_servo(codec,
 +                                WM8993_DCS_TRIG_STARTUP_0 |
 +                                WM8993_DCS_TRIG_STARTUP_1);
 +      }
 +
 +      /* Different chips in the family support different readback
 +       * methods.
 +       */
 +      switch (hubs->dcs_readback_mode) {
 +      case 0:
 +              reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
 +                      & WM8993_DCS_INTEG_CHAN_0_MASK;
 +              reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
 +                      & WM8993_DCS_INTEG_CHAN_1_MASK;
 +              break;
 +      case 1:
 +              reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
 +              reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
 +                      >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 +              reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
 +              break;
 +      default:
 +              WARN(1, "Unknown DCS readback method\n");
 +              break;
 +      }
 +
 +      dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
  
        /* Apply correction to DC servo result */
        if (hubs->dcs_codes) {
                dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
                        hubs->dcs_codes);
  
 -              /* Different chips in the family support different
 -               * readback methods.
 -               */
 -              switch (hubs->dcs_readback_mode) {
 -              case 0:
 -                      reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
 -                              & WM8993_DCS_INTEG_CHAN_0_MASK;;
 -                      reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
 -                              & WM8993_DCS_INTEG_CHAN_1_MASK;
 -                      break;
 -              case 1:
 -                      reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
 -                      reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
 -                              >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 -                      reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
 -                      break;
 -              default:
 -                      WARN(1, "Unknown DCS readback method\n");
 -                      break;
 -              }
 -
 -              dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 -
                /* HPOUT1L */
                if (reg_l + hubs->dcs_codes > 0 &&
                    reg_l + hubs->dcs_codes < 0xff)
                wait_for_dc_servo(codec,
                                  WM8993_DCS_TRIG_DAC_WR_0 |
                                  WM8993_DCS_TRIG_DAC_WR_1);
 +      } else {
 +              dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 +              dcs_cfg |= reg_r;
        }
 +
 +      /* Save the callibrated offset if we're in class W mode and
 +       * therefore don't have any analogue signal mixed in. */
 +      if (hubs->class_w)
 +              hubs->class_w_dcs = dcs_cfg;
  }
  
  /*
@@@ -190,9 -163,6 +190,9 @@@ static int wm8993_put_dc_servo(struct s
  
        ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
  
 +      /* Updating the analogue gains invalidates the DC servo cache */
 +      hubs->class_w_dcs = 0;
 +
        /* If we're applying an offset correction then updating the
         * callibration would be likely to introduce further offsets. */
        if (hubs->dcs_codes)
@@@ -323,7 -293,7 +323,7 @@@ SOC_DOUBLE_R("Speaker Switch"
  SOC_DOUBLE_R("Speaker ZC Switch",
             WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
             7, 1, 0),
- SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0,
+ SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
               spkboost_tlv),
  SOC_ENUM("Speaker Reference", speaker_ref),
  SOC_ENUM("Speaker Mode", speaker_mode),
@@@ -821,8 -791,6 +821,8 @@@ static const struct snd_soc_dapm_route 
  
  int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
  {
 +      struct snd_soc_dapm_context *dapm = &codec->dapm;
 +
        /* Latch volume update bits & default ZC on */
        snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
                            WM8993_IN1_VU, WM8993_IN1_VU);
        snd_soc_add_controls(codec, analogue_snd_controls,
                             ARRAY_SIZE(analogue_snd_controls));
  
 -      snd_soc_dapm_new_controls(codec, analogue_dapm_widgets,
 +      snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
                                  ARRAY_SIZE(analogue_dapm_widgets));
        return 0;
  }
@@@ -860,26 -828,24 +860,26 @@@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_
  int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
                                int lineout1_diff, int lineout2_diff)
  {
 -      snd_soc_dapm_add_routes(codec, analogue_routes,
 +      struct snd_soc_dapm_context *dapm = &codec->dapm;
 +
 +      snd_soc_dapm_add_routes(dapm, analogue_routes,
                                ARRAY_SIZE(analogue_routes));
  
        if (lineout1_diff)
 -              snd_soc_dapm_add_routes(codec,
 +              snd_soc_dapm_add_routes(dapm,
                                        lineout1_diff_routes,
                                        ARRAY_SIZE(lineout1_diff_routes));
        else
 -              snd_soc_dapm_add_routes(codec,
 +              snd_soc_dapm_add_routes(dapm,
                                        lineout1_se_routes,
                                        ARRAY_SIZE(lineout1_se_routes));
  
        if (lineout2_diff)
 -              snd_soc_dapm_add_routes(codec,
 +              snd_soc_dapm_add_routes(dapm,
                                        lineout2_diff_routes,
                                        ARRAY_SIZE(lineout2_diff_routes));
        else
 -              snd_soc_dapm_add_routes(codec,
 +              snd_soc_dapm_add_routes(dapm,
                                        lineout2_se_routes,
                                        ARRAY_SIZE(lineout2_se_routes));
  
@@@ -906,7 -872,7 +906,7 @@@ int wm_hubs_handle_analogue_pdata(struc
         * VMID as an output and can disable it.
         */
        if (lineout1_diff && lineout2_diff)
 -              codec->idle_bias_off = 1;
 +              codec->dapm.idle_bias_off = 1;
  
        if (lineout1fb)
                snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
diff --combined sound/soc/soc-core.c
index a90e067fb0abe1943a41c8db24ced4f5f43f0c68,02ae7bea3b50401fbace05991b7472f6d6633c92..17dcd56a2520205c366a8dfd4d1b2a0994a40ee0
  #include <linux/slab.h>
  #include <sound/ac97_codec.h>
  #include <sound/core.h>
 +#include <sound/jack.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/soc.h>
 -#include <sound/soc-dapm.h>
  #include <sound/initval.h>
  
 +#define CREATE_TRACE_POINTS
 +#include <trace/events/asoc.h>
 +
  #define NAME_SIZE     32
  
  static DEFINE_MUTEX(pcm_mutex);
@@@ -241,10 -238,8 +241,10 @@@ static const struct file_operations cod
  
  static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
  {
 -      codec->debugfs_codec_root = debugfs_create_dir(codec->name ,
 -                                                     debugfs_root);
 +      struct dentry *debugfs_card_root = codec->card->debugfs_card_root;
 +
 +      codec->debugfs_codec_root = debugfs_create_dir(codec->name,
 +                                                     debugfs_card_root);
        if (!codec->debugfs_codec_root) {
                printk(KERN_WARNING
                       "ASoC: Failed to create codec debugfs directory\n");
                printk(KERN_WARNING
                       "ASoC: Failed to create codec register debugfs file\n");
  
 -      codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
 -                                                   codec->debugfs_codec_root,
 -                                                   &codec->pop_time);
 -      if (!codec->debugfs_pop_time)
 -              printk(KERN_WARNING
 -                     "Failed to create pop time debugfs file\n");
 -
 -      codec->debugfs_dapm = debugfs_create_dir("dapm",
 +      codec->dapm.debugfs_dapm = debugfs_create_dir("dapm",
                                                 codec->debugfs_codec_root);
 -      if (!codec->debugfs_dapm)
 +      if (!codec->dapm.debugfs_dapm)
                printk(KERN_WARNING
                       "Failed to create DAPM debugfs directory\n");
  
 -      snd_soc_dapm_debugfs_init(codec);
 +      snd_soc_dapm_debugfs_init(&codec->dapm);
  }
  
  static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
@@@ -372,29 -374,6 +372,29 @@@ static const struct file_operations pla
        .llseek = default_llseek,/* read accesses f_pos */
  };
  
 +static void soc_init_card_debugfs(struct snd_soc_card *card)
 +{
 +      card->debugfs_card_root = debugfs_create_dir(card->name,
 +                                                   debugfs_root);
 +      if (!card->debugfs_card_root) {
 +              dev_warn(card->dev,
 +                       "ASoC: Failed to create codec debugfs directory\n");
 +              return;
 +      }
 +
 +      card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
 +                                                  card->debugfs_card_root,
 +                                                  &card->pop_time);
 +      if (!card->debugfs_pop_time)
 +              dev_warn(card->dev,
 +                     "Failed to create pop time debugfs file\n");
 +}
 +
 +static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
 +{
 +      debugfs_remove_recursive(card->debugfs_card_root);
 +}
 +
  #else
  
  static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
  static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
  {
  }
 +
 +static inline void soc_init_card_debugfs(struct snd_soc_card *card)
 +{
 +}
 +
 +static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
 +{
 +}
  #endif
  
  #ifdef CONFIG_SND_SOC_AC97_BUS
@@@ -526,7 -497,7 +526,7 @@@ static int soc_pcm_open(struct snd_pcm_
                }
        }
  
 -      /* Check that the codec and cpu DAI's are compatible */
 +      /* Check that the codec and cpu DAIs are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                runtime->hw.rate_min =
                        max(codec_dai_drv->playback.rate_min,
@@@ -875,7 -846,7 +875,7 @@@ codec_err
  }
  
  /*
 - * Free's resources allocated by hw_params, can be called multiple times
 + * Frees resources allocated by hw_params, can be called multiple times
   */
  static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
  {
        if (platform->driver->ops->hw_free)
                platform->driver->ops->hw_free(substream);
  
 -      /* now free hw params for the DAI's  */
 +      /* now free hw params for the DAIs  */
        if (codec_dai->driver->ops->hw_free)
                codec_dai->driver->ops->hw_free(substream, codec_dai);
  
@@@ -987,7 -958,6 +987,7 @@@ static int soc_suspend(struct device *d
  {
        struct platform_device *pdev = to_platform_device(dev);
        struct snd_soc_card *card = platform_get_drvdata(pdev);
 +      struct snd_soc_codec *codec;
        int i;
  
        /* If the initialization of this soc device failed, there is no codec
        /* we're going to block userspace touching us until resume completes */
        snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
  
 -      /* mute any active DAC's */
 +      /* mute any active DACs */
        for (i = 0; i < card->num_rtd; i++) {
                struct snd_soc_dai *dai = card->rtd[i].codec_dai;
                struct snd_soc_dai_driver *drv = dai->driver;
        /* close any waiting streams and save state */
        for (i = 0; i < card->num_rtd; i++) {
                run_delayed_work(&card->rtd[i].delayed_work);
 -              card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level;
 +              card->rtd[i].codec->dapm.suspend_bias_level = card->rtd[i].codec->dapm.bias_level;
        }
  
        for (i = 0; i < card->num_rtd; i++) {
        }
  
        /* suspend all CODECs */
 -      for (i = 0; i < card->num_rtd; i++) {
 -              struct snd_soc_codec *codec = card->rtd[i].codec;
 +      list_for_each_entry(codec, &card->codec_dev_list, card_list) {
                /* If there are paths active then the CODEC will be held with
                 * bias _ON and should not be suspended. */
                if (!codec->suspended && codec->driver->suspend) {
 -                      switch (codec->bias_level) {
 +                      switch (codec->dapm.bias_level) {
                        case SND_SOC_BIAS_STANDBY:
                        case SND_SOC_BIAS_OFF:
                                codec->driver->suspend(codec, PMSG_SUSPEND);
@@@ -1107,7 -1078,6 +1107,7 @@@ static void soc_resume_deferred(struct 
        struct snd_soc_card *card =
                        container_of(work, struct snd_soc_card, deferred_resume_work);
        struct platform_device *pdev = to_platform_device(card->dev);
 +      struct snd_soc_codec *codec;
        int i;
  
        /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
                        cpu_dai->driver->resume(cpu_dai);
        }
  
 -      for (i = 0; i < card->num_rtd; i++) {
 -              struct snd_soc_codec *codec = card->rtd[i].codec;
 +      list_for_each_entry(codec, &card->codec_dev_list, card_list) {
                /* If the CODEC was idle over suspend then it will have been
                 * left with bias OFF or STANDBY and suspended so we must now
                 * resume.  Otherwise the suspend was suppressed.
                 */
                if (codec->driver->resume && codec->suspended) {
 -                      switch (codec->bias_level) {
 +                      switch (codec->dapm.bias_level) {
                        case SND_SOC_BIAS_STANDBY:
                        case SND_SOC_BIAS_OFF:
                                codec->driver->resume(codec);
@@@ -1375,7 -1346,7 +1375,7 @@@ static void soc_remove_dai_link(struct 
                }
  
                /* Make sure all DAPM widgets are freed */
 -              snd_soc_dapm_free(codec);
 +              snd_soc_dapm_free(&codec->dapm);
  
                soc_cleanup_codec_debugfs(codec);
                device_remove_file(&rtd->dev, &dev_attr_codec_reg);
        }
  }
  
 +static void soc_set_name_prefix(struct snd_soc_card *card,
 +                              struct snd_soc_codec *codec)
 +{
 +      int i;
 +
 +      if (card->codec_conf == NULL)
 +              return;
 +
 +      for (i = 0; i < card->num_configs; i++) {
 +              struct snd_soc_codec_conf *map = &card->codec_conf[i];
 +              if (map->dev_name && !strcmp(codec->name, map->dev_name)) {
 +                      codec->name_prefix = map->name_prefix;
 +                      break;
 +              }
 +      }
 +}
 +
  static void rtd_release(struct device *dev) {}
  
  static int soc_probe_dai_link(struct snd_soc_card *card, int num)
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
 +      const char *temp;
        int ret;
  
        dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num);
  
        /* probe the CODEC */
        if (!codec->probed) {
 +              codec->dapm.card = card;
 +              soc_set_name_prefix(card, codec);
                if (codec->driver->probe) {
                        ret = codec->driver->probe(codec);
                        if (ret < 0) {
  
        /* now that all clients have probed, initialise the DAI link */
        if (dai_link->init) {
 +              /* machine controls, routes and widgets are not prefixed */
 +              temp = rtd->codec->name_prefix;
 +              rtd->codec->name_prefix = NULL;
                ret = dai_link->init(rtd);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name);
                        return ret;
                }
 +              rtd->codec->name_prefix = temp;
        }
  
        /* Make sure all DAPM widgets are instantiated */
 -      snd_soc_dapm_new_widgets(codec);
 -      snd_soc_dapm_sync(codec);
 +      snd_soc_dapm_new_widgets(&codec->dapm);
 +      snd_soc_dapm_sync(&codec->dapm);
  
        /* register the rtd device */
        rtd->dev.release = rtd_release;
@@@ -1604,160 -1551,9 +1604,160 @@@ static void soc_unregister_ac97_dai_lin
  }
  #endif
  
 +static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 +{
 +      struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
 +      struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
 +      struct snd_soc_codec *codec;
 +      const char *temp;
 +      int ret = -ENODEV;
 +
 +      /* find CODEC from registered CODECs*/
 +      list_for_each_entry(codec, &codec_list, list) {
 +              if (!strcmp(codec->name, aux_dev->codec_name)) {
 +                      if (codec->probed) {
 +                              dev_err(codec->dev,
 +                                      "asoc: codec already probed");
 +                              ret = -EBUSY;
 +                              goto out;
 +                      }
 +                      goto found;
 +              }
 +      }
 +      /* codec not found */
 +      dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
 +      goto out;
 +
 +found:
 +      if (!try_module_get(codec->dev->driver->owner))
 +              return -ENODEV;
 +
 +      codec->card = card;
 +      codec->dapm.card = card;
 +
 +      soc_set_name_prefix(card, codec);
 +      if (codec->driver->probe) {
 +              ret = codec->driver->probe(codec);
 +              if (ret < 0) {
 +                      dev_err(codec->dev, "asoc: failed to probe CODEC");
 +                      return ret;
 +              }
 +      }
 +
 +      soc_init_codec_debugfs(codec);
 +
 +      /* mark codec as probed and add to card codec list */
 +      codec->probed = 1;
 +      list_add(&codec->card_list, &card->codec_dev_list);
 +
 +      /* now that all clients have probed, initialise the DAI link */
 +      if (aux_dev->init) {
 +              /* machine controls, routes and widgets are not prefixed */
 +              temp = codec->name_prefix;
 +              codec->name_prefix = NULL;
 +              ret = aux_dev->init(&codec->dapm);
 +              if (ret < 0) {
 +                      dev_err(codec->dev,
 +                              "asoc: failed to init %s\n", aux_dev->name);
 +                      return ret;
 +              }
 +              codec->name_prefix = temp;
 +      }
 +
 +      /* Make sure all DAPM widgets are instantiated */
 +      snd_soc_dapm_new_widgets(&codec->dapm);
 +      snd_soc_dapm_sync(&codec->dapm);
 +
 +      /* register the rtd device */
 +      rtd->codec = codec;
 +      rtd->card = card;
 +      rtd->dev.parent = card->dev;
 +      rtd->dev.release = rtd_release;
 +      rtd->dev.init_name = aux_dev->name;
 +      ret = device_register(&rtd->dev);
 +      if (ret < 0) {
 +              dev_err(codec->dev,
 +                      "asoc: failed to register aux runtime device %d\n",
 +                      ret);
 +              return ret;
 +      }
 +      rtd->dev_registered = 1;
 +
 +      /* add DAPM sysfs entries for this codec */
 +      ret = snd_soc_dapm_sys_add(&rtd->dev);
 +      if (ret < 0)
 +              dev_err(codec->dev,
 +                      "asoc: failed to add codec dapm sysfs entries\n");
 +
 +      /* add codec sysfs entries */
 +      ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
 +      if (ret < 0)
 +              dev_err(codec->dev, "asoc: failed to add codec sysfs files\n");
 +
 +out:
 +      return ret;
 +}
 +
 +static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
 +{
 +      struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
 +      struct snd_soc_codec *codec = rtd->codec;
 +      int err;
 +
 +      /* unregister the rtd device */
 +      if (rtd->dev_registered) {
 +              device_unregister(&rtd->dev);
 +              rtd->dev_registered = 0;
 +      }
 +
 +      /* remove the CODEC */
 +      if (codec && codec->probed) {
 +              if (codec->driver->remove) {
 +                      err = codec->driver->remove(codec);
 +                      if (err < 0)
 +                              dev_err(codec->dev,
 +                                      "asoc: failed to remove %s\n",
 +                                      codec->name);
 +              }
 +
 +              /* Make sure all DAPM widgets are freed */
 +              snd_soc_dapm_free(&codec->dapm);
 +
 +              soc_cleanup_codec_debugfs(codec);
 +              device_remove_file(&rtd->dev, &dev_attr_codec_reg);
 +              codec->probed = 0;
 +              list_del(&codec->card_list);
 +              module_put(codec->dev->driver->owner);
 +      }
 +}
 +
 +static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
 +                                  enum snd_soc_compress_type compress_type)
 +{
 +      int ret;
 +
 +      if (codec->cache_init)
 +              return 0;
 +
 +      /* override the compress_type if necessary */
 +      if (compress_type && codec->compress_type != compress_type)
 +              codec->compress_type = compress_type;
 +      ret = snd_soc_cache_init(codec);
 +      if (ret < 0) {
 +              dev_err(codec->dev, "Failed to set cache compression type: %d\n",
 +                      ret);
 +              return ret;
 +      }
 +      codec->cache_init = 1;
 +      return 0;
 +}
 +
  static void snd_soc_instantiate_card(struct snd_soc_card *card)
  {
        struct platform_device *pdev = to_platform_device(card->dev);
 +      struct snd_soc_codec *codec;
 +      struct snd_soc_codec_conf *codec_conf;
 +      enum snd_soc_compress_type compress_type;
        int ret, i;
  
        mutex_lock(&card->mutex);
                return;
        }
  
 +      /* initialize the register cache for each available codec */
 +      list_for_each_entry(codec, &codec_list, list) {
 +              if (codec->cache_init)
 +                      continue;
 +              /* check to see if we need to override the compress_type */
 +              for (i = 0; i < card->num_configs; ++i) {
 +                      codec_conf = &card->codec_conf[i];
 +                      if (!strcmp(codec->name, codec_conf->dev_name)) {
 +                              compress_type = codec_conf->compress_type;
 +                              if (compress_type && compress_type
 +                                  != codec->compress_type)
 +                                      break;
 +                      }
 +              }
 +              if (i == card->num_configs) {
 +                      /* no need to override the compress_type so
 +                       * go ahead and do the standard thing */
 +                      ret = snd_soc_init_codec_cache(codec, 0);
 +                      if (ret < 0) {
 +                              mutex_unlock(&card->mutex);
 +                              return;
 +                      }
 +                      continue;
 +              }
 +              /* override the compress_type with the one supplied in
 +               * the machine driver */
 +              ret = snd_soc_init_codec_cache(codec, compress_type);
 +              if (ret < 0) {
 +                      mutex_unlock(&card->mutex);
 +                      return;
 +              }
 +      }
 +
        /* card bind complete so register a sound card */
        ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        card->owner, 0, &card->snd_card);
                }
        }
  
 +      for (i = 0; i < card->num_aux_devs; i++) {
 +              ret = soc_probe_aux_dev(card, i);
 +              if (ret < 0) {
 +                      pr_err("asoc: failed to add auxiliary devices %s: %d\n",
 +                             card->name, ret);
 +                      goto probe_aux_dev_err;
 +              }
 +      }
 +
        snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
                 "%s",  card->name);
        snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
        mutex_unlock(&card->mutex);
        return;
  
 +probe_aux_dev_err:
 +      for (i = 0; i < card->num_aux_devs; i++)
 +              soc_remove_aux_dev(card, i);
 +
  probe_dai_err:
        for (i = 0; i < card->num_links; i++)
                soc_remove_dai_link(card, i);
@@@ -1917,8 -1667,6 +1917,8 @@@ static int soc_probe(struct platform_de
        INIT_LIST_HEAD(&card->codec_dev_list);
        INIT_LIST_HEAD(&card->platform_dev_list);
  
 +      soc_init_card_debugfs(card);
 +
        ret = snd_soc_register_card(card);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to register card\n");
@@@ -1942,16 -1690,10 +1942,16 @@@ static int soc_remove(struct platform_d
                        run_delayed_work(&rtd->delayed_work);
                }
  
 +              /* remove auxiliary devices */
 +              for (i = 0; i < card->num_aux_devs; i++)
 +                      soc_remove_aux_dev(card, i);
 +
                /* remove and free each DAI */
                for (i = 0; i < card->num_rtd; i++)
                        soc_remove_dai_link(card, i);
  
 +              soc_cleanup_card_debugfs(card);
 +
                /* remove the card */
                if (card->remove)
                        card->remove(pdev);
@@@ -2135,27 -1877,6 +2135,27 @@@ void snd_soc_free_ac97_codec(struct snd
  }
  EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
  
 +unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
 +{
 +      unsigned int ret;
 +
 +      ret = codec->read(codec, reg);
 +      dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
 +      trace_snd_soc_reg_read(codec, reg, ret);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(snd_soc_read);
 +
 +unsigned int snd_soc_write(struct snd_soc_codec *codec,
 +                         unsigned int reg, unsigned int val)
 +{
 +      dev_dbg(codec->dev, "write %x = %x\n", reg, val);
 +      trace_snd_soc_reg_write(codec, reg, val);
 +      return codec->write(codec, reg, val);
 +}
 +EXPORT_SYMBOL_GPL(snd_soc_write);
 +
  /**
   * snd_soc_update_bits - update codec register bits
   * @codec: audio codec
@@@ -2296,22 -2017,14 +2296,22 @@@ int snd_soc_add_controls(struct snd_soc
        const struct snd_kcontrol_new *controls, int num_controls)
  {
        struct snd_card *card = codec->card->snd_card;
 +      char prefixed_name[44], *name;
        int err, i;
  
        for (i = 0; i < num_controls; i++) {
                const struct snd_kcontrol_new *control = &controls[i];
 -              err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
 +              if (codec->name_prefix) {
 +                      snprintf(prefixed_name, sizeof(prefixed_name), "%s %s",
 +                               codec->name_prefix, control->name);
 +                      name = prefixed_name;
 +              } else {
 +                      name = control->name;
 +              }
 +              err = snd_ctl_add(card, snd_soc_cnew(control, codec, name));
                if (err < 0) {
                        dev_err(codec->dev, "%s: Failed to add %s: %d\n",
 -                              codec->name, control->name, err);
 +                              codec->name, name, err);
                        return err;
                }
        }
@@@ -3148,12 -2861,10 +3148,12 @@@ static int snd_soc_register_card(struc
        if (!card->name || !card->dev)
                return -EINVAL;
  
 -      card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
 -                      GFP_KERNEL);
 +      card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
 +                          (card->num_links + card->num_aux_devs),
 +                          GFP_KERNEL);
        if (card->rtd == NULL)
                return -ENOMEM;
 +      card->rtd_aux = &card->rtd[card->num_links];
  
        for (i = 0; i < card->num_links; i++)
                card->rtd[i].dai_link = &card->dai_link[i];
@@@ -3361,7 -3072,9 +3361,9 @@@ int snd_soc_register_dais(struct devic
                pr_debug("Registered DAI '%s'\n", dai->name);
        }
  
+       mutex_lock(&client_mutex);
        snd_soc_instantiate_cards();
+       mutex_unlock(&client_mutex);
        return 0;
  
  err:
@@@ -3489,11 -3202,9 +3491,11 @@@ static void fixup_codec_formats(struct 
   * @codec: codec to register
   */
  int snd_soc_register_codec(struct device *dev,
 -              struct snd_soc_codec_driver *codec_drv,
 -              struct snd_soc_dai_driver *dai_drv, int num_dai)
 +                         const struct snd_soc_codec_driver *codec_drv,
 +                         struct snd_soc_dai_driver *dai_drv,
 +                         int num_dai)
  {
 +      size_t reg_size;
        struct snd_soc_codec *codec;
        int ret, i;
  
                return -ENOMEM;
        }
  
 -      /* allocate CODEC register cache */
 -      if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
 -
 -              if (codec_drv->reg_cache_default)
 -                      codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
 -                              codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL);
 -              else
 -                      codec->reg_cache = kzalloc(codec_drv->reg_cache_size *
 -                              codec_drv->reg_word_size, GFP_KERNEL);
 -
 -              if (codec->reg_cache == NULL) {
 -                      kfree(codec->name);
 -                      kfree(codec);
 -                      return -ENOMEM;
 -              }
 -      }
 -
 +      if (codec_drv->compress_type)
 +              codec->compress_type = codec_drv->compress_type;
 +      else
 +              codec->compress_type = SND_SOC_FLAT_COMPRESSION;
 +
 +      INIT_LIST_HEAD(&codec->dapm.widgets);
 +      INIT_LIST_HEAD(&codec->dapm.paths);
 +      codec->write = codec_drv->write;
 +      codec->read = codec_drv->read;
 +      codec->dapm.bias_level = SND_SOC_BIAS_OFF;
 +      codec->dapm.dev = dev;
 +      codec->dapm.codec = codec;
        codec->dev = dev;
        codec->driver = codec_drv;
 -      codec->bias_level = SND_SOC_BIAS_OFF;
        codec->num_dai = num_dai;
        mutex_init(&codec->mutex);
 -      INIT_LIST_HEAD(&codec->dapm_widgets);
 -      INIT_LIST_HEAD(&codec->dapm_paths);
 +
 +      /* allocate CODEC register cache */
 +      if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
 +              reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
 +              /* it is necessary to make a copy of the default register cache
 +               * because in the case of using a compression type that requires
 +               * the default register cache to be marked as __devinitconst the
 +               * kernel might have freed the array by the time we initialize
 +               * the cache.
 +               */
 +              codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
 +                                            reg_size, GFP_KERNEL);
 +              if (!codec->reg_def_copy) {
 +                      ret = -ENOMEM;
 +                      goto fail;
 +              }
 +      }
  
        for (i = 0; i < num_dai; i++) {
                fixup_codec_formats(&dai_drv[i].playback);
        if (num_dai) {
                ret = snd_soc_register_dais(dev, dai_drv, num_dai);
                if (ret < 0)
 -                      goto error;
 +                      goto fail;
        }
  
        mutex_lock(&client_mutex);
        pr_debug("Registered codec '%s'\n", codec->name);
        return 0;
  
 -error:
 -      if (codec->reg_cache)
 -              kfree(codec->reg_cache);
 +fail:
 +      kfree(codec->reg_def_copy);
 +      codec->reg_def_copy = NULL;
        kfree(codec->name);
        kfree(codec);
        return ret;
@@@ -3600,8 -3302,8 +3602,8 @@@ found
  
        pr_debug("Unregistered codec '%s'\n", codec->name);
  
 -      if (codec->reg_cache)
 -              kfree(codec->reg_cache);
 +      snd_soc_cache_exit(codec);
 +      kfree(codec->reg_def_copy);
        kfree(codec->name);
        kfree(codec);
  }