Merge tag 'v3.14.25' into backport/v3.14.24-ltsi-rc1+v3.14.25/snapshot-merge.wip
[platform/adaptation/renesas_rcar/renesas_kernel.git] / sound / soc / soc-core.c
index a66783e..c75d008 100644 (file)
@@ -1728,6 +1728,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        }
 
        snd_soc_dapm_link_dai_widgets(card);
+       snd_soc_dapm_connect_dai_link_widgets(card);
 
        if (card->controls)
                snd_soc_add_card_controls(card, card->controls, card->num_controls);
@@ -3484,7 +3485,7 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,
                                                      freq, dir);
        else
-               return -EINVAL;
+               return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 
@@ -3505,7 +3506,7 @@ int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                return codec->driver->set_sysclk(codec, clk_id, source,
                                                 freq, dir);
        else
-               return -EINVAL;
+               return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
 
@@ -3608,6 +3609,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
  * @tx_mask: bitmask representing active TX slots.
@@ -3621,6 +3646,12 @@ 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);
@@ -4416,6 +4447,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)
 {
@@ -4473,7 +4620,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
 
 unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
-                                    const char *prefix)
+                                    const char *prefix,
+                                    struct device_node **bitclkmaster,
+                                    struct device_node **framemaster)
 {
        int ret, i;
        char prop[128];
@@ -4556,9 +4705,13 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
         */
        snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
        bit = !!of_get_property(np, prop, NULL);
+       if (bit && bitclkmaster)
+               *bitclkmaster = of_parse_phandle(np, prop, 0);
 
        snprintf(prop, sizeof(prop), "%sframe-master", prefix);
        frame = !!of_get_property(np, prop, NULL);
+       if (frame && framemaster)
+               *framemaster = of_parse_phandle(np, prop, 0);
 
        switch ((bit << 4) + frame) {
        case 0x11:
@@ -4617,10 +4770,14 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
 
                        if (id < 0 || id >= pos->num_dai) {
                                ret = -EINVAL;
-                       } else {
-                               *dai_name = pos->dai_drv[id].name;
-                               ret = 0;
+                               break;
                        }
+
+                       ret = 0;
+
+                       *dai_name = pos->dai_drv[id].name;
+                       if (!*dai_name)
+                               *dai_name = pos->name;
                }
 
                break;