Merge remote-tracking branches 'asoc/topic/ml26124', 'asoc/topic/of', 'asoc/topic...
[deliverable/linux.git] / sound / soc / soc-core.c
index fe1df50805a3035ea455d40771c55d4cb4f6585d..359c2849b364b3c78ec0824d864dadb3125b4294 100644 (file)
@@ -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);
@@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
 {
        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;
+                       }
                }
        }
 
@@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 {
        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;
@@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        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) {
@@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                 * 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;
                        }
                }
 
@@ -1128,12 +1132,8 @@ static int soc_probe_codec(struct snd_soc_card *card,
                                          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;
 
@@ -1180,6 +1180,7 @@ static int soc_probe_platform(struct snd_soc_card *card,
 {
        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;
@@ -1195,11 +1196,11 @@ static int soc_probe_platform(struct snd_soc_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;
@@ -2571,10 +2572,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
 
        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));
@@ -2596,14 +2597,18 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
 {
        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;
 }
@@ -2623,17 +2628,18 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
 {
        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;
        }
 
@@ -2642,78 +2648,46 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
 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
@@ -2743,7 +2717,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
 
        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);
@@ -2769,11 +2743,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        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];
@@ -2781,10 +2760,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        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];
@@ -2815,20 +2796,25 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        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) {
@@ -2836,7 +2822,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
                        val |= val2 << rshift;
                } else {
                        val2 = val2 << shift;
-                       type_2r = 1;
+                       type_2r = true;
                }
        }
        err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
@@ -3234,7 +3220,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
        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)
@@ -3264,12 +3250,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
                        ((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;
@@ -3608,6 +3618,30 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 
+/**
+ * snd_soc_of_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_of_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
@@ -3622,11 +3656,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 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,
+                                               &tx_mask, &rx_mask);
+       else
+               snd_soc_of_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);
 
@@ -3882,95 +3922,42 @@ static inline char *fmt_multiple_name(struct device *dev,
 }
 
 /**
- * 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;
-
-       dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev));
+       struct snd_soc_dai *dai, *_dai;
 
-       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
+ * snd_soc_register_dais - Register a DAI with 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
- *
- * @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);
 
@@ -3982,69 +3969,53 @@ static int snd_soc_register_dais(struct device *dev,
                        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);
+               list_add(&dai->list, &component->dai_list);
 
-               mutex_unlock(&client_mutex);
-
-               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
  *
@@ -4053,6 +4024,7 @@ static int
 __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)
 {
@@ -4075,20 +4047,10 @@ __snd_soc_register_component(struct device *dev,
        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;
@@ -4121,7 +4083,9 @@ int snd_soc_register_component(struct device *dev,
                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);
@@ -4141,7 +4105,7 @@ void snd_soc_unregister_component(struct device *dev)
        return;
 
 found:
-       snd_soc_unregister_dais(dev, cmpnt->num_dai);
+       snd_soc_unregister_dais(cmpnt);
 
        mutex_lock(&client_mutex);
        list_del(&cmpnt->list);
@@ -4319,7 +4283,7 @@ int snd_soc_register_codec(struct device *dev,
        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;
@@ -4342,7 +4306,7 @@ int snd_soc_register_codec(struct device *dev,
        /* 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;
@@ -4417,6 +4381,122 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 }
 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)
 {
This page took 0.063906 seconds and 5 git commands to generate.