diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index e026bf2..0f937eb 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -16,11 +16,44 @@
 #define asoc_simple_init_mic(card, sjack, prefix) \
 	asoc_simple_init_jack(card, sjack, 0, prefix, NULL)
 
+/*
+ * External audio Codecs for their system clock (sysclk) may use one
+ * of the following:
+ *
+ *   - MCLK provided by SoC (already "system-clock-frequency" or
+ *     "mclk-fs" bindings exist)
+ *
+ *   - Codec internal PLL which can take reference from SoC audio
+ *     interface bit clock (BCLK) and generate required sysclk for
+ *     the Codec.
+ *
+ *   - Codec internal PLL taking reference from onboard crystal and
+ *     generate required sysclk for the Codec.
+ *
+ * BCLK depends on PCM parameters (rate, channels and bits) and has
+ * to be calculated at runtime. So is MCLK, sometimes it depends on
+ * sample rate and a scaling factor. So whenever PLL is used for
+ * sysclk, input and output references/rates need to be provided.
+ *
+ * Following macros can be used to setup input/output frequency
+ * requirements for the PLL.
+ */
+
+#define SND_SOC_DAI_PLL_REF_FIXED		0
+#define SND_SOC_DAI_PLL_REF_MCLK		(1 << 0)
+#define SND_SOC_DAI_PLL_REF_BCLK		(1 << 1)
+
 struct asoc_simple_dai {
 	const char *name;
 	unsigned int sysclk;
 	int sysclk_id;
 	int sysclk_source;
+	unsigned int pll_id;
+	unsigned int pll_source;
+	unsigned int pll_in_freq;
+	unsigned int pll_out_freq;
+	unsigned int pll_in_ref;
+	unsigned int pll_out_ref;
 	int clk_direction;
 	int slots;
 	int slot_width;
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index bbbf891..6bfde08 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -12,6 +12,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_graph.h>
 #include <sound/jack.h>
+#include <sound/pcm_params.h>
 #include <sound/simple_card_utils.h>
 
 void asoc_simple_convert_fixup(struct asoc_simple_data *data,
@@ -190,6 +191,30 @@ int asoc_simple_parse_clk(struct device *dev,
 
 	of_property_read_u32(node, "system-clock-source", &simple_dai->sysclk_source);
 
+	of_property_read_u32(node, "pll-id", &simple_dai->pll_id);
+
+	of_property_read_u32(node, "pll-source", &simple_dai->pll_source);
+
+	if (of_property_read_u32(node, "pll-input-reference",
+				 &simple_dai->pll_in_ref)) {
+		/*
+		 * Look for "pll-input-frequency" if no explicit reference
+		 * is provided.
+		 */
+		of_property_read_u32(node, "pll-input-frequency",
+				     &simple_dai->pll_in_freq);
+	}
+
+	if (of_property_read_u32(node, "pll-output-reference",
+				 &simple_dai->pll_out_ref)) {
+		/*
+		 * Look for "pll-output-frequency" if no explicit reference
+		 * is provided.
+		 */
+		of_property_read_u32(node, "pll-output-frequency",
+				     &simple_dai->pll_out_freq);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
@@ -217,6 +242,82 @@ static int asoc_simple_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static int asoc_simple_enable_pll(struct snd_soc_dai *dai,
+				  struct asoc_simple_dai *simple_dai,
+				  struct snd_pcm_hw_params *params,
+				  unsigned int mclk_fs)
+{
+	int ret;
+
+	if (!simple_dai)
+		return 0;
+
+	switch (simple_dai->pll_in_ref) {
+	case SND_SOC_DAI_PLL_REF_FIXED:
+		break;
+	case SND_SOC_DAI_PLL_REF_MCLK:
+		simple_dai->pll_in_freq = params_rate(params) * mclk_fs;
+		break;
+	case SND_SOC_DAI_PLL_REF_BCLK:
+		simple_dai->pll_in_freq = params_rate(params) *
+					  params_channels(params) *
+					  params_width(params);
+		break;
+	default:
+		dev_err(dai->dev, "pll input reference is invalid!\n");
+		return -EINVAL;
+	}
+
+	switch (simple_dai->pll_out_ref) {
+	case SND_SOC_DAI_PLL_REF_FIXED:
+		break;
+	case SND_SOC_DAI_PLL_REF_MCLK:
+		simple_dai->pll_out_freq = params_rate(params) * mclk_fs;
+		break;
+	case SND_SOC_DAI_PLL_REF_BCLK:
+		simple_dai->pll_out_freq = params_rate(params) *
+					   params_channels(params) *
+					   params_width(params);
+		break;
+	default:
+		dev_err(dai->dev, "pll output reference is invalid!\n");
+		return -EINVAL;
+	}
+
+	if (!simple_dai->pll_in_freq && !simple_dai->pll_out_freq) {
+		/* There is nothing to be configured */
+		return 0;
+	} else if ((!simple_dai->pll_in_freq && simple_dai->pll_out_freq) ||
+		   (simple_dai->pll_in_freq && !simple_dai->pll_out_freq)) {
+		dev_err(dai->dev, "Invalid pll input/output rates!\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev,
+		"pll config: id = %d, source = %d, in_freq = %u, out_freq = %u\n",
+		simple_dai->pll_id, simple_dai->pll_source,
+		simple_dai->pll_in_freq, simple_dai->pll_out_freq);
+
+	ret = snd_soc_dai_set_pll(dai, simple_dai->pll_id,
+				  simple_dai->pll_source,
+				  simple_dai->pll_in_freq,
+				  simple_dai->pll_out_freq);
+
+	if (ret && ret != -ENOTSUPP)
+		return ret;
+
+	return 0;
+}
+
+static int asoc_simple_disable_pll(struct snd_soc_dai *dai,
+				   struct asoc_simple_dai *simple_dai)
+{
+	if (!simple_dai)
+		return 0;
+
+	return snd_soc_dai_set_pll(dai, simple_dai->pll_id, 0, 0, 0);
+}
+
 int asoc_simple_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
@@ -252,6 +353,9 @@ void asoc_simple_shutdown(struct snd_pcm_substream *substream)
 				       SND_SOC_CLOCK_OUT);
 	}
 
+	asoc_simple_disable_pll(codec_dai, dai_props->codec_dai);
+	asoc_simple_disable_pll(cpu_dai, dai_props->cpu_dai);
+
 	asoc_simple_clk_disable(dai_props->cpu_dai);
 
 	asoc_simple_clk_disable(dai_props->codec_dai);
@@ -310,6 +414,16 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream,
 			return ret;
 	}
 
+	ret = asoc_simple_enable_pll(codec_dai, dai_props->codec_dai, params,
+				     mclk_fs);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_enable_pll(cpu_dai, dai_props->cpu_dai, params,
+				     mclk_fs);
+	if (ret < 0)
+		return ret;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
