Merge remote-tracking branches 'asoc/topic/tdm' and 'asoc/topic/tegra' into asoc...
authorMark Brown <broonie@linaro.org>
Tue, 25 Mar 2014 21:22:15 +0000 (21:22 +0000)
committerMark Brown <broonie@linaro.org>
Tue, 25 Mar 2014 21:22:15 +0000 (21:22 +0000)
1  2  3 
sound/soc/soc-core.c
sound/soc/tegra/tegra20_ac97.c

diff --combined sound/soc/soc-core.c
@@@@ -56,6 -56,6 -56,7 +56,6 @@@@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root)
   #endif
   
   static DEFINE_MUTEX(client_mutex);
  -static LIST_HEAD(dai_list);
   static LIST_HEAD(platform_list);
   static LIST_HEAD(codec_list);
   static LIST_HEAD(component_list);
@@@@ -369,22 -369,22 -370,18 +369,22 @@@@ static ssize_t dai_list_read_file(struc
   {
        char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        ssize_t len, ret = 0;
  +     struct snd_soc_component *component;
        struct snd_soc_dai *dai;
   
        if (!buf)
                return -ENOMEM;
   
  -     list_for_each_entry(dai, &dai_list, list) {
  -             len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
  -             if (len >= 0)
  -                     ret += len;
  -             if (ret > PAGE_SIZE) {
  -                     ret = PAGE_SIZE;
  -                     break;
  +     list_for_each_entry(component, &component_list, list) {
  +             list_for_each_entry(dai, &component->dai_list, list) {
  +                     len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
  +                             dai->name);
  +                     if (len >= 0)
  +                             ret += len;
  +                     if (ret > PAGE_SIZE) {
  +                             ret = PAGE_SIZE;
  +                             break;
  +                     }
                }
        }
   
@@@@ -858,7 -858,7 -855,6 +858,7 @@@@ static int soc_bind_dai_link(struct snd
   {
        struct snd_soc_dai_link *dai_link = &card->dai_link[num];
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
  +     struct snd_soc_component *component;
        struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
        struct snd_soc_dai *codec_dai, *cpu_dai;
        dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
   
        /* Find CPU DAI from registered DAIs*/
  -     list_for_each_entry(cpu_dai, &dai_list, list) {
  +     list_for_each_entry(component, &component_list, list) {
                if (dai_link->cpu_of_node &&
  -                 (cpu_dai->dev->of_node != dai_link->cpu_of_node))
  +                     component->dev->of_node != dai_link->cpu_of_node)
                        continue;
                if (dai_link->cpu_name &&
  -                 strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
  -                     continue;
  -             if (dai_link->cpu_dai_name &&
  -                 strcmp(cpu_dai->name, dai_link->cpu_dai_name))
  +                     strcmp(dev_name(component->dev), dai_link->cpu_name))
                        continue;
  +             list_for_each_entry(cpu_dai, &component->dai_list, list) {
  +                     if (dai_link->cpu_dai_name &&
  +                             strcmp(cpu_dai->name, dai_link->cpu_dai_name))
  +                             continue;
   
  -             rtd->cpu_dai = cpu_dai;
  +                     rtd->cpu_dai = cpu_dai;
  +             }
        }
   
        if (!rtd->cpu_dai) {
                 * CODEC found, so find CODEC DAI from registered DAIs from
                 * this CODEC
                 */
  -             list_for_each_entry(codec_dai, &dai_list, list) {
  -                     if (codec->dev == codec_dai->dev &&
  -                             !strcmp(codec_dai->name,
  -                                     dai_link->codec_dai_name)) {
  -
  +             list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
  +                     if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) {
                                rtd->codec_dai = codec_dai;
  +                             break;
                        }
                }
   
@@@@ -1132,21 -1132,21 -1128,15 +1132,21 @@@@ static int soc_probe_codec(struct snd_s
                                          driver->num_dapm_widgets);
   
        /* Create DAPM widgets for each DAI stream */
  -     list_for_each_entry(dai, &dai_list, list) {
  -             if (dai->dev != codec->dev)
  -                     continue;
  -
  +     list_for_each_entry(dai, &codec->component.dai_list, list)
                snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
  -     }
   
        codec->dapm.idle_bias_off = driver->idle_bias_off;
   
  +     if (!codec->write && dev_get_regmap(codec->dev, NULL)) {
  +             /* Set the default I/O up try regmap */
  +             ret = snd_soc_codec_set_cache_io(codec, NULL);
  +             if (ret < 0) {
  +                     dev_err(codec->dev,
  +                             "Failed to set cache I/O: %d\n", ret);
  +                     goto err_probe;
  +             }
  +     }
  +
        if (driver->probe) {
                ret = driver->probe(codec);
                if (ret < 0) {
                        codec->name);
        }
   
  -     /* If the driver didn't set I/O up try regmap */
  -     if (!codec->write && dev_get_regmap(codec->dev, NULL))
  -             snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
  -
        if (driver->controls)
                snd_soc_add_codec_controls(codec, driver->controls,
                                     driver->num_controls);
@@@@ -1186,7 -1186,7 -1180,6 +1186,7 @@@@ static int soc_probe_platform(struct sn
   {
        int ret = 0;
        const struct snd_soc_platform_driver *driver = platform->driver;
  +     struct snd_soc_component *component;
        struct snd_soc_dai *dai;
   
        platform->card = card;
                        driver->dapm_widgets, driver->num_dapm_widgets);
   
        /* Create DAPM widgets for each DAI stream */
  -     list_for_each_entry(dai, &dai_list, list) {
  -             if (dai->dev != platform->dev)
  +     list_for_each_entry(component, &component_list, list) {
  +             if (component->dev != platform->dev)
                        continue;
  -
  -             snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
  +             list_for_each_entry(dai, &component->dai_list, list)
  +                     snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
        }
   
        platform->dapm.idle_bias_off = 1;
@@@@ -1253,7 -1253,7 -1246,7 +1253,7 @@@@ static int soc_post_component_init(stru
        struct snd_soc_dai_link *dai_link = NULL;
        struct snd_soc_aux_dev *aux_dev = NULL;
        struct snd_soc_pcm_runtime *rtd;
 --     const char *temp, *name;
 ++     const char *name;
        int ret = 0;
   
        if (!dailess) {
        }
        rtd->card = card;
   
 --     /* machine controls, routes and widgets are not prefixed */
 --     temp = codec->name_prefix;
 --     codec->name_prefix = NULL;
 --
        /* do machine specific initialization */
        if (!dailess && dai_link->init)
                ret = dai_link->init(rtd);
                dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret);
                return ret;
        }
 --     codec->name_prefix = temp;
   
        /* register the rtd device */
        rtd->codec = codec;
@@@@ -2573,10 -2578,10 -2571,10 +2573,10 @@@@ int snd_soc_info_enum_double(struct snd
   
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
  -     uinfo->value.enumerated.items = e->max;
  +     uinfo->value.enumerated.items = e->items;
   
  -     if (uinfo->value.enumerated.item > e->max - 1)
  -             uinfo->value.enumerated.item = e->max - 1;
  +     if (uinfo->value.enumerated.item >= e->items)
  +             uinfo->value.enumerated.item = e->items - 1;
        strlcpy(uinfo->value.enumerated.name,
                e->texts[uinfo->value.enumerated.item],
                sizeof(uinfo->value.enumerated.name));
@@@@ -2598,18 -2603,18 -2596,14 +2598,18 @@@@ int snd_soc_get_enum_double(struct snd_
   {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  -     unsigned int val;
  +     unsigned int val, item;
  +     unsigned int reg_val;
   
  -     val = snd_soc_read(codec, e->reg);
  -     ucontrol->value.enumerated.item[0]
  -             = (val >> e->shift_l) & e->mask;
  -     if (e->shift_l != e->shift_r)
  -             ucontrol->value.enumerated.item[1] =
  -                     (val >> e->shift_r) & e->mask;
  +     reg_val = snd_soc_read(codec, e->reg);
  +     val = (reg_val >> e->shift_l) & e->mask;
  +     item = snd_soc_enum_val_to_item(e, val);
  +     ucontrol->value.enumerated.item[0] = item;
  +     if (e->shift_l != e->shift_r) {
  +             val = (reg_val >> e->shift_l) & e->mask;
  +             item = snd_soc_enum_val_to_item(e, val);
  +             ucontrol->value.enumerated.item[1] = item;
  +     }
   
        return 0;
   }
@@@@ -2629,18 -2634,18 -2623,17 +2629,18 @@@@ int snd_soc_put_enum_double(struct snd_
   {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  +     unsigned int *item = ucontrol->value.enumerated.item;
        unsigned int val;
        unsigned int mask;
   
  -     if (ucontrol->value.enumerated.item[0] > e->max - 1)
  +     if (item[0] >= e->items)
                return -EINVAL;
  -     val = ucontrol->value.enumerated.item[0] << e->shift_l;
  +     val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
        mask = e->mask << e->shift_l;
        if (e->shift_l != e->shift_r) {
  -             if (ucontrol->value.enumerated.item[1] > e->max - 1)
  +             if (item[1] >= e->items)
                        return -EINVAL;
  -             val |= ucontrol->value.enumerated.item[1] << e->shift_r;
  +             val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
                mask |= e->mask << e->shift_r;
        }
   
   EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
   
   /**
  - * snd_soc_get_value_enum_double - semi enumerated double mixer get callback
  - * @kcontrol: mixer control
  - * @ucontrol: control element information
  - *
  - * Callback to get the value of a double semi enumerated mixer.
  + * snd_soc_read_signed - Read a codec register and interprete as signed value
  + * @codec: codec
  + * @reg: Register to read
  + * @mask: Mask to use after shifting the register value
  + * @shift: Right shift of register value
  + * @sign_bit: Bit that describes if a number is negative or not.
    *
  - * Semi enumerated mixer: the enumerated items are referred as values. Can be
  - * used for handling bitfield coded enumeration for example.
  + * This functions reads a codec register. The register value is shifted right
  + * by 'shift' bits and masked with the given 'mask'. Afterwards it translates
  + * the given registervalue into a signed integer if sign_bit is non-zero.
    *
  - * Returns 0 for success.
  + * Returns the register value as signed int.
    */
  -int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
  -     struct snd_ctl_elem_value *ucontrol)
  +static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
  +             unsigned int mask, unsigned int shift, unsigned int sign_bit)
   {
  -     struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  -     struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  -     unsigned int reg_val, val, mux;
  +     int ret;
  +     unsigned int val;
   
  -     reg_val = snd_soc_read(codec, e->reg);
  -     val = (reg_val >> e->shift_l) & e->mask;
  -     for (mux = 0; mux < e->max; mux++) {
  -             if (val == e->values[mux])
  -                     break;
  -     }
  -     ucontrol->value.enumerated.item[0] = mux;
  -     if (e->shift_l != e->shift_r) {
  -             val = (reg_val >> e->shift_r) & e->mask;
  -             for (mux = 0; mux < e->max; mux++) {
  -                     if (val == e->values[mux])
  -                             break;
  -             }
  -             ucontrol->value.enumerated.item[1] = mux;
  -     }
  +     val = (snd_soc_read(codec, reg) >> shift) & mask;
   
  -     return 0;
  -}
  -EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double);
  +     if (!sign_bit)
  +             return val;
   
  -/**
  - * snd_soc_put_value_enum_double - semi enumerated double mixer put callback
  - * @kcontrol: mixer control
  - * @ucontrol: control element information
  - *
  - * Callback to set the value of a double semi enumerated mixer.
  - *
  - * Semi enumerated mixer: the enumerated items are referred as values. Can be
  - * used for handling bitfield coded enumeration for example.
  - *
  - * Returns 0 for success.
  - */
  -int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
  -     struct snd_ctl_elem_value *ucontrol)
  -{
  -     struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  -     struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  -     unsigned int val;
  -     unsigned int mask;
  +     /* non-negative number */
  +     if (!(val & BIT(sign_bit)))
  +             return val;
   
  -     if (ucontrol->value.enumerated.item[0] > e->max - 1)
  -             return -EINVAL;
  -     val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
  -     mask = e->mask << e->shift_l;
  -     if (e->shift_l != e->shift_r) {
  -             if (ucontrol->value.enumerated.item[1] > e->max - 1)
  -                     return -EINVAL;
  -             val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
  -             mask |= e->mask << e->shift_r;
  -     }
  +     ret = val;
   
  -     return snd_soc_update_bits_locked(codec, e->reg, mask, val);
  +     /*
  +      * The register most probably does not contain a full-sized int.
  +      * Instead we have an arbitrary number of bits in a signed
  +      * representation which has to be translated into a full-sized int.
  +      * This is done by filling up all bits above the sign-bit.
  +      */
  +     ret |= ~((int)(BIT(sign_bit) - 1));
  +
  +     return ret;
   }
  -EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
   
   /**
    * snd_soc_info_volsw - single mixer info callback
@@@@ -2718,7 -2723,7 -2743,7 +2718,7 @@@@ int snd_soc_info_volsw(struct snd_kcont
   
        uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
        uinfo->value.integer.min = 0;
  -     uinfo->value.integer.max = platform_max;
  +     uinfo->value.integer.max = platform_max - mc->min;
        return 0;
   }
   EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@@@ -2744,16 -2749,16 -2769,11 +2744,16 @@@@ int snd_soc_get_volsw(struct snd_kcontr
        unsigned int shift = mc->shift;
        unsigned int rshift = mc->rshift;
        int max = mc->max;
  +     int min = mc->min;
  +     int sign_bit = mc->sign_bit;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
   
  -     ucontrol->value.integer.value[0] =
  -             (snd_soc_read(codec, reg) >> shift) & mask;
  +     if (sign_bit)
  +             mask = BIT(sign_bit + 1) - 1;
  +
  +     ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask,
  +                     shift, sign_bit) - min;
        if (invert)
                ucontrol->value.integer.value[0] =
                        max - ucontrol->value.integer.value[0];
        if (snd_soc_volsw_is_stereo(mc)) {
                if (reg == reg2)
                        ucontrol->value.integer.value[1] =
  -                             (snd_soc_read(codec, reg) >> rshift) & mask;
  +                             snd_soc_read_signed(codec, reg, mask, rshift,
  +                                             sign_bit) - min;
                else
                        ucontrol->value.integer.value[1] =
  -                             (snd_soc_read(codec, reg2) >> shift) & mask;
  +                             snd_soc_read_signed(codec, reg2, mask, shift,
  +                                             sign_bit) - min;
                if (invert)
                        ucontrol->value.integer.value[1] =
                                max - ucontrol->value.integer.value[1];
@@@@ -2797,25 -2802,25 -2815,20 +2797,25 @@@@ int snd_soc_put_volsw(struct snd_kcontr
        unsigned int shift = mc->shift;
        unsigned int rshift = mc->rshift;
        int max = mc->max;
  +     int min = mc->min;
  +     unsigned int sign_bit = mc->sign_bit;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
        int err;
  -     bool type_2r = 0;
  +     bool type_2r = false;
        unsigned int val2 = 0;
        unsigned int val, val_mask;
   
  -     val = (ucontrol->value.integer.value[0] & mask);
  +     if (sign_bit)
  +             mask = BIT(sign_bit + 1) - 1;
  +
  +     val = ((ucontrol->value.integer.value[0] + min) & mask);
        if (invert)
                val = max - val;
        val_mask = mask << shift;
        val = val << shift;
        if (snd_soc_volsw_is_stereo(mc)) {
  -             val2 = (ucontrol->value.integer.value[1] & mask);
  +             val2 = ((ucontrol->value.integer.value[1] + min) & mask);
                if (invert)
                        val2 = max - val2;
                if (reg == reg2) {
                        val |= val2 << rshift;
                } else {
                        val2 = val2 << shift;
  -                     type_2r = 1;
  +                     type_2r = true;
                }
        }
        err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
@@@@ -3221,7 -3226,7 -3234,7 +3221,7 @@@@ int snd_soc_bytes_put(struct snd_kcontr
        struct soc_bytes *params = (void *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        int ret, len;
  -     unsigned int val;
  +     unsigned int val, mask;
        void *data;
   
        if (!codec->using_regmap)
                        ((u8 *)data)[0] |= val;
                        break;
                case 2:
  -                     ((u16 *)data)[0] &= cpu_to_be16(~params->mask);
  -                     ((u16 *)data)[0] |= cpu_to_be16(val);
  +                     mask = ~params->mask;
  +                     ret = regmap_parse_val(codec->control_data,
  +                                                     &mask, &mask);
  +                     if (ret != 0)
  +                             goto out;
  +
  +                     ((u16 *)data)[0] &= mask;
  +
  +                     ret = regmap_parse_val(codec->control_data,
  +                                                     &val, &val);
  +                     if (ret != 0)
  +                             goto out;
  +
  +                     ((u16 *)data)[0] |= val;
                        break;
                case 4:
  -                     ((u32 *)data)[0] &= cpu_to_be32(~params->mask);
  -                     ((u32 *)data)[0] |= cpu_to_be32(val);
  +                     mask = ~params->mask;
  +                     ret = regmap_parse_val(codec->control_data,
  +                                                     &mask, &mask);
  +                     if (ret != 0)
  +                             goto out;
  +
  +                     ((u32 *)data)[0] &= mask;
  +
  +                     ret = regmap_parse_val(codec->control_data,
  +                                                     &val, &val);
  +                     if (ret != 0)
  +                             goto out;
  +
  +                     ((u32 *)data)[0] |= val;
                        break;
                default:
                        ret = -EINVAL;
@@@@ -3619,30 -3624,30 -3608,6 +3619,30 @@@@ int snd_soc_dai_set_fmt(struct snd_soc_
   }
   EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
   
-   * snd_soc_of_xlate_tdm_slot - generate tx/rx slot mask.
  +/**
-  static int snd_soc_of_xlate_tdm_slot_mask(unsigned int slots,
+ + * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
  + * @slots: Number of slots in use.
  + * @tx_mask: bitmask representing active TX slots.
  + * @rx_mask: bitmask representing active RX slots.
  + *
  + * Generates the TDM tx and rx slot default masks for DAI.
  + */
+ +static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
  +                                       unsigned int *tx_mask,
  +                                       unsigned int *rx_mask)
  +{
  +     if (*tx_mask || *rx_mask)
  +             return 0;
  +
  +     if (!slots)
  +             return -EINVAL;
  +
  +     *tx_mask = (1 << slots) - 1;
  +     *rx_mask = (1 << slots) - 1;
  +
  +     return 0;
  +}
  +
   /**
    * snd_soc_dai_set_tdm_slot - configure DAI TDM.
    * @dai: DAI
   int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
   {
-       if (dai->driver && dai->driver->ops->of_xlate_tdm_slot_mask)
-               dai->driver->ops->of_xlate_tdm_slot_mask(slots,
+ +     if (dai->driver && dai->driver->ops->xlate_tdm_slot_mask)
+ +             dai->driver->ops->xlate_tdm_slot_mask(slots,
  +                                             &tx_mask, &rx_mask);
  +     else
-               snd_soc_of_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ +             snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
  +
        if (dai->driver && dai->driver->ops->set_tdm_slot)
                return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
                                slots, slot_width);
        else
  -             return -EINVAL;
  +             return -ENOTSUPP;
   }
   EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
   
@@@@ -3923,42 -3928,42 -3882,95 +3923,42 @@@@ static inline char *fmt_multiple_name(s
   }
   
   /**
  - * snd_soc_register_dai - Register a DAI with the ASoC core
  + * snd_soc_unregister_dai - Unregister DAIs from the ASoC core
    *
  - * @dai: DAI to register
  + * @component: The component for which the DAIs should be unregistered
    */
  -static int snd_soc_register_dai(struct device *dev,
  -             struct snd_soc_dai_driver *dai_drv)
  +static void snd_soc_unregister_dais(struct snd_soc_component *component)
   {
  -     struct snd_soc_codec *codec;
  -     struct snd_soc_dai *dai;
  +     struct snd_soc_dai *dai, *_dai;
   
  -     dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev));
  -
  -     dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
  -     if (dai == NULL)
  -             return -ENOMEM;
  -
  -     /* create DAI component name */
  -     dai->name = fmt_single_name(dev, &dai->id);
  -     if (dai->name == NULL) {
  +     list_for_each_entry_safe(dai, _dai, &component->dai_list, list) {
  +             dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
  +                     dai->name);
  +             list_del(&dai->list);
  +             kfree(dai->name);
                kfree(dai);
  -             return -ENOMEM;
        }
  -
  -     dai->dev = dev;
  -     dai->driver = dai_drv;
  -     dai->dapm.dev = dev;
  -     if (!dai->driver->ops)
  -             dai->driver->ops = &null_dai_ops;
  -
  -     mutex_lock(&client_mutex);
  -
  -     list_for_each_entry(codec, &codec_list, list) {
  -             if (codec->dev == dev) {
  -                     dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n",
  -                             dai->name, codec->name);
  -                     dai->codec = codec;
  -                     break;
  -             }
  -     }
  -
  -     if (!dai->codec)
  -             dai->dapm.idle_bias_off = 1;
  -
  -     list_add(&dai->list, &dai_list);
  -
  -     mutex_unlock(&client_mutex);
  -
  -     dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
  -
  -     return 0;
  -}
  -
  -/**
  - * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
  - *
  - * @dai: DAI to unregister
  - */
  -static void snd_soc_unregister_dai(struct device *dev)
  -{
  -     struct snd_soc_dai *dai;
  -
  -     list_for_each_entry(dai, &dai_list, list) {
  -             if (dev == dai->dev)
  -                     goto found;
  -     }
  -     return;
  -
  -found:
  -     mutex_lock(&client_mutex);
  -     list_del(&dai->list);
  -     mutex_unlock(&client_mutex);
  -
  -     dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
  -     kfree(dai->name);
  -     kfree(dai);
   }
   
   /**
  - * snd_soc_register_dais - Register multiple DAIs with the ASoC core
  + * snd_soc_register_dais - Register a DAI with the ASoC core
    *
  - * @dai: Array of DAIs to register
  + * @component: The component the DAIs are registered for
  + * @codec: The CODEC that the DAIs are registered for, NULL if the component is
  + *         not a CODEC.
  + * @dai_drv: DAI driver to use for the DAIs
    * @count: Number of DAIs
  + * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the
  + *                     parent's name.
    */
  -static int snd_soc_register_dais(struct device *dev,
  -             struct snd_soc_dai_driver *dai_drv, size_t count)
  +static int snd_soc_register_dais(struct snd_soc_component *component,
  +     struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv,
  +     size_t count, bool legacy_dai_naming)
   {
  -     struct snd_soc_codec *codec;
  +     struct device *dev = component->dev;
        struct snd_soc_dai *dai;
  -     int i, ret = 0;
  +     unsigned int i;
  +     int ret;
   
        dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
   
                        goto err;
                }
   
  -             /* create DAI component name */
  -             dai->name = fmt_multiple_name(dev, &dai_drv[i]);
  +             /*
  +              * Back in the old days when we still had component-less DAIs,
  +              * instead of having a static name, component-less DAIs would
  +              * inherit the name of the parent device so it is possible to
  +              * register multiple instances of the DAI. We still need to keep
  +              * the same naming style even though those DAIs are not
  +              * component-less anymore.
  +              */
  +             if (count == 1 && legacy_dai_naming) {
  +                     dai->name = fmt_single_name(dev, &dai->id);
  +             } else {
  +                     dai->name = fmt_multiple_name(dev, &dai_drv[i]);
  +                     if (dai_drv[i].id)
  +                             dai->id = dai_drv[i].id;
  +                     else
  +                             dai->id = i;
  +             }
                if (dai->name == NULL) {
                        kfree(dai);
  -                     ret = -EINVAL;
  +                     ret = -ENOMEM;
                        goto err;
                }
   
  +             dai->component = component;
  +             dai->codec = codec;
                dai->dev = dev;
                dai->driver = &dai_drv[i];
  -             if (dai->driver->id)
  -                     dai->id = dai->driver->id;
  -             else
  -                     dai->id = i;
                dai->dapm.dev = dev;
                if (!dai->driver->ops)
                        dai->driver->ops = &null_dai_ops;
   
  -             mutex_lock(&client_mutex);
  -
  -             list_for_each_entry(codec, &codec_list, list) {
  -                     if (codec->dev == dev) {
  -                             dev_dbg(dev,
  -                                     "ASoC: Mapped DAI %s to CODEC %s\n",
  -                                     dai->name, codec->name);
  -                             dai->codec = codec;
  -                             break;
  -                     }
  -             }
  -
                if (!dai->codec)
                        dai->dapm.idle_bias_off = 1;
   
  -             list_add(&dai->list, &dai_list);
  -
  -             mutex_unlock(&client_mutex);
  +             list_add(&dai->list, &component->dai_list);
   
  -             dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name);
  +             dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
        }
   
        return 0;
   
   err:
  -     for (i--; i >= 0; i--)
  -             snd_soc_unregister_dai(dev);
  +     snd_soc_unregister_dais(component);
   
        return ret;
   }
   
  -/**
  - * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
  - *
  - * @dai: Array of DAIs to unregister
  - * @count: Number of DAIs
  - */
  -static void snd_soc_unregister_dais(struct device *dev, size_t count)
  -{
  -     int i;
  -
  -     for (i = 0; i < count; i++)
  -             snd_soc_unregister_dai(dev);
  -}
  -
   /**
    * snd_soc_register_component - Register a component with the ASoC core
    *
@@@@ -4025,7 -4030,7 -4053,6 +4025,7 @@@@ static in
   __snd_soc_register_component(struct device *dev,
                             struct snd_soc_component *cmpnt,
                             const struct snd_soc_component_driver *cmpnt_drv,
  +                          struct snd_soc_codec *codec,
                             struct snd_soc_dai_driver *dai_drv,
                             int num_dai, bool allow_single_dai)
   {
        cmpnt->driver   = cmpnt_drv;
        cmpnt->dai_drv  = dai_drv;
        cmpnt->num_dai  = num_dai;
  +     INIT_LIST_HEAD(&cmpnt->dai_list);
   
  -     /*
  -      * snd_soc_register_dai()  uses fmt_single_name(), and
  -      * snd_soc_register_dais() uses fmt_multiple_name()
  -      * for dai->name which is used for name based matching
  -      *
  -      * this function is used from cpu/codec.
  -      * allow_single_dai flag can ignore "codec" driver reworking
  -      * since it had been used snd_soc_register_dais(),
  -      */
  -     if ((1 == num_dai) && allow_single_dai)
  -             ret = snd_soc_register_dai(dev, dai_drv);
  -     else
  -             ret = snd_soc_register_dais(dev, dai_drv, num_dai);
  +     ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai,
  +             allow_single_dai);
        if (ret < 0) {
                dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
                goto error_component_name;
@@@@ -4084,9 -4089,9 -4121,7 +4084,9 @@@@ int snd_soc_register_component(struct d
                return -ENOMEM;
        }
   
  -     return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
  +     cmpnt->ignore_pmdown_time = true;
  +
  +     return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL,
                                            dai_drv, num_dai, true);
   }
   EXPORT_SYMBOL_GPL(snd_soc_register_component);
@@@@ -4106,7 -4111,7 -4141,7 +4106,7 @@@@ void snd_soc_unregister_component(struc
        return;
   
   found:
  -     snd_soc_unregister_dais(dev, cmpnt->num_dai);
  +     snd_soc_unregister_dais(cmpnt);
   
        mutex_lock(&client_mutex);
        list_del(&cmpnt->list);
@@@@ -4284,7 -4289,7 -4319,7 +4284,7 @@@@ int snd_soc_register_codec(struct devic
        codec->volatile_register = codec_drv->volatile_register;
        codec->readable_register = codec_drv->readable_register;
        codec->writable_register = codec_drv->writable_register;
  -     codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
  +     codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
        codec->dapm.dev = dev;
        codec->dapm.codec = codec;
        /* register component */
        ret = __snd_soc_register_component(dev, &codec->component,
                                           &codec_drv->component_driver,
  -                                        dai_drv, num_dai, false);
  +                                        codec, dai_drv, num_dai, false);
        if (ret < 0) {
                dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret);
                goto fail_codec_name;
@@@@ -4382,122 -4387,122 -4417,6 +4382,122 @@@@ int snd_soc_of_parse_card_name(struct s
   }
   EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
   
  +static const struct snd_soc_dapm_widget simple_widgets[] = {
  +     SND_SOC_DAPM_MIC("Microphone", NULL),
  +     SND_SOC_DAPM_LINE("Line", NULL),
  +     SND_SOC_DAPM_HP("Headphone", NULL),
  +     SND_SOC_DAPM_SPK("Speaker", NULL),
  +};
  +
  +int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
  +                                       const char *propname)
  +{
  +     struct device_node *np = card->dev->of_node;
  +     struct snd_soc_dapm_widget *widgets;
  +     const char *template, *wname;
  +     int i, j, num_widgets, ret;
  +
  +     num_widgets = of_property_count_strings(np, propname);
  +     if (num_widgets < 0) {
  +             dev_err(card->dev,
  +                     "ASoC: Property '%s' does not exist\n", propname);
  +             return -EINVAL;
  +     }
  +     if (num_widgets & 1) {
  +             dev_err(card->dev,
  +                     "ASoC: Property '%s' length is not even\n", propname);
  +             return -EINVAL;
  +     }
  +
  +     num_widgets /= 2;
  +     if (!num_widgets) {
  +             dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
  +                     propname);
  +             return -EINVAL;
  +     }
  +
  +     widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
  +                            GFP_KERNEL);
  +     if (!widgets) {
  +             dev_err(card->dev,
  +                     "ASoC: Could not allocate memory for widgets\n");
  +             return -ENOMEM;
  +     }
  +
  +     for (i = 0; i < num_widgets; i++) {
  +             ret = of_property_read_string_index(np, propname,
  +                     2 * i, &template);
  +             if (ret) {
  +                     dev_err(card->dev,
  +                             "ASoC: Property '%s' index %d read error:%d\n",
  +                             propname, 2 * i, ret);
  +                     return -EINVAL;
  +             }
  +
  +             for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) {
  +                     if (!strncmp(template, simple_widgets[j].name,
  +                                  strlen(simple_widgets[j].name))) {
  +                             widgets[i] = simple_widgets[j];
  +                             break;
  +                     }
  +             }
  +
  +             if (j >= ARRAY_SIZE(simple_widgets)) {
  +                     dev_err(card->dev,
  +                             "ASoC: DAPM widget '%s' is not supported\n",
  +                             template);
  +                     return -EINVAL;
  +             }
  +
  +             ret = of_property_read_string_index(np, propname,
  +                                                 (2 * i) + 1,
  +                                                 &wname);
  +             if (ret) {
  +                     dev_err(card->dev,
  +                             "ASoC: Property '%s' index %d read error:%d\n",
  +                             propname, (2 * i) + 1, ret);
  +                     return -EINVAL;
  +             }
  +
  +             widgets[i].name = wname;
  +     }
  +
  +     card->dapm_widgets = widgets;
  +     card->num_dapm_widgets = num_widgets;
  +
  +     return 0;
  +}
  +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
  +
  +int snd_soc_of_parse_tdm_slot(struct device_node *np,
  +                           unsigned int *slots,
  +                           unsigned int *slot_width)
  +{
  +     u32 val;
  +     int ret;
  +
  +     if (of_property_read_bool(np, "dai-tdm-slot-num")) {
  +             ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
  +             if (ret)
  +                     return ret;
  +
  +             if (slots)
  +                     *slots = val;
  +     }
  +
  +     if (of_property_read_bool(np, "dai-tdm-slot-width")) {
  +             ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
  +             if (ret)
  +                     return ret;
  +
  +             if (slot_width)
  +                     *slot_width = val;
  +     }
  +
  +     return 0;
  +}
  +EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
  +
   int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname)
   {
   #include <sound/soc.h>
   #include <sound/dmaengine_pcm.h>
   
-- #include "tegra_asoc_utils.h"
   #include "tegra20_ac97.h"
   
   #define DRV_NAME "tegra20-ac97"
@@@@ -306,7 -306,7 -305,7 +305,7 @@@@ static const struct regmap_config tegra
        .readable_reg = tegra20_ac97_wr_rd_reg,
        .volatile_reg = tegra20_ac97_volatile_reg,
        .precious_reg = tegra20_ac97_precious_reg,
  -     .cache_type = REGCACHE_RBTREE,
  +     .cache_type = REGCACHE_FLAT,
   };
   
   static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        ac97->playback_dma_data.maxburst = 4;
   
--      ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
--      if (ret)
--              goto err_clk_put;
-- 
--      ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data);
--      if (ret)
--              goto err_asoc_utils_fini;
-- 
        ret = clk_prepare_enable(ac97->clk_ac97);
        if (ret) {
                dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
--              goto err_asoc_utils_fini;
++              goto err;
        }
   
        ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
@@@@ -419,8 -419,8 -410,6 +410,6 @@@@ err_unregister_component
        snd_soc_unregister_component(&pdev->dev);
   err_clk_disable_unprepare:
        clk_disable_unprepare(ac97->clk_ac97);
-- err_asoc_utils_fini:
--      tegra_asoc_utils_fini(&ac97->util_data);
   err_clk_put:
   err:
        snd_soc_set_ac97_ops(NULL);
@@@@ -434,8 -434,8 -423,6 +423,6 @@@@ static int tegra20_ac97_platform_remove
        tegra_pcm_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
   
--      tegra_asoc_utils_fini(&ac97->util_data);
-- 
        clk_disable_unprepare(ac97->clk_ac97);
   
        snd_soc_set_ac97_ops(NULL);