Merge tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[sfrench/cifs-2.6.git] / sound / soc / fsl / fsl_sai.c
index e765da9a19e7e13846751eb7685eed9f09ac5de8..7523bb944b216da4c601e8c5332683fa669fa8cd 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
@@ -22,6 +23,7 @@
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 
 #include "fsl_sai.h"
+#include "fsl_utils.h"
 #include "imx-pcm.h"
 
 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
@@ -30,7 +32,8 @@
 static const unsigned int fsl_sai_rates[] = {
        8000, 11025, 12000, 16000, 22050,
        24000, 32000, 44100, 48000, 64000,
-       88200, 96000, 176400, 192000
+       88200, 96000, 176400, 192000, 352800,
+       384000, 705600, 768000, 1411200, 2822400,
 };
 
 static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
@@ -56,6 +59,31 @@ static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir)
        return !sai->synchronous[dir] && sai->synchronous[adir];
 }
 
+static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk)
+{
+       struct pinctrl_state *state = NULL;
+
+       if (sai->is_pdm_mode) {
+               /* DSD512@44.1kHz, DSD512@48kHz */
+               if (bclk >= 22579200)
+                       state = pinctrl_lookup_state(sai->pinctrl, "dsd512");
+
+               /* Get default DSD state */
+               if (IS_ERR_OR_NULL(state))
+                       state = pinctrl_lookup_state(sai->pinctrl, "dsd");
+       } else {
+               /* 706k32b2c, 768k32b2c, etc */
+               if (bclk >= 45158400)
+                       state = pinctrl_lookup_state(sai->pinctrl, "pcm_b2m");
+       }
+
+       /* Get default state */
+       if (IS_ERR_OR_NULL(state))
+               state = pinctrl_lookup_state(sai->pinctrl, "default");
+
+       return state;
+}
+
 static irqreturn_t fsl_sai_isr(int irq, void *devid)
 {
        struct fsl_sai *sai = (struct fsl_sai *)devid;
@@ -193,14 +221,48 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
+static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id, unsigned int freq)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       fsl_asoc_reparent_pll_clocks(dai->dev, sai->mclk_clk[clk_id],
+                                    sai->pll8k_clk, sai->pll11k_clk, freq);
+
+       ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
+       if (ret < 0)
+               dev_err(dai->dev, "failed to set clock rate (%u): %d\n", freq, ret);
+
+       return ret;
+}
+
 static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int dir)
 {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
        int ret;
 
        if (dir == SND_SOC_CLOCK_IN)
                return 0;
 
+       if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) {
+               if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
+                       dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
+                       return -EINVAL;
+               }
+
+               if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) {
+                       dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id);
+                       return -EINVAL;
+               }
+
+               if (sai->mclk_streams == 0) {
+                       ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, true);
        if (ret) {
                dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
@@ -224,6 +286,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
        if (!sai->is_lsb_first)
                val_cr4 |= FSL_SAI_CR4_MF;
 
+       sai->is_pdm_mode = false;
        /* DAI mode */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
@@ -262,6 +325,11 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                val_cr2 |= FSL_SAI_CR2_BCP;
                sai->is_dsp_mode = true;
                break;
+       case SND_SOC_DAIFMT_PDM:
+               val_cr2 |= FSL_SAI_CR2_BCP;
+               val_cr4 &= ~FSL_SAI_CR4_MF;
+               sai->is_pdm_mode = true;
+               break;
        case SND_SOC_DAIFMT_RIGHT_J:
                /* To be done */
        default:
@@ -292,19 +360,19 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
 
        /* DAI clock provider masks */
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
                sai->is_consumer_mode = false;
                break;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                sai->is_consumer_mode = true;
                break;
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BP_FC:
                val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
                sai->is_consumer_mode = false;
                break;
-       case SND_SOC_DAIFMT_CBP_CFC:
+       case SND_SOC_DAIFMT_BC_FP:
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
                sai->is_consumer_mode = true;
                break;
@@ -437,6 +505,12 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
                                   FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
                                   savediv / 2 - 1);
 
+       if (sai->soc_data->max_register >= FSL_SAI_MCTL) {
+               /* SAI is in master mode at this point, so enable MCLK */
+               regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
+                                  FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
+       }
+
        return 0;
 }
 
@@ -448,13 +522,18 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        unsigned int ofs = sai->soc_data->reg_offset;
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        unsigned int channels = params_channels(params);
+       struct snd_dmaengine_dai_dma_data *dma_params;
+       struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg;
        u32 word_width = params_width(params);
+       int trce_mask = 0, dl_cfg_idx = 0;
+       int dl_cfg_cnt = sai->dl_cfg_cnt;
+       u32 dl_type = FSL_SAI_DL_I2S;
        u32 val_cr4 = 0, val_cr5 = 0;
        u32 slots = (channels == 1) ? 2 : channels;
        u32 slot_width = word_width;
        int adir = tx ? RX : TX;
-       u32 pins;
-       int ret;
+       u32 pins, bclk;
+       int ret, i;
 
        if (sai->slots)
                slots = sai->slots;
@@ -464,15 +543,42 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
 
        pins = DIV_ROUND_UP(channels, slots);
 
+       /*
+        * PDM mode, channels are independent
+        * each channels are on one dataline/FIFO.
+        */
+       if (sai->is_pdm_mode) {
+               pins = channels;
+               dl_type = FSL_SAI_DL_PDM;
+       }
+
+       for (i = 0; i < dl_cfg_cnt; i++) {
+               if (dl_cfg[i].type == dl_type && dl_cfg[i].pins[tx] == pins) {
+                       dl_cfg_idx = i;
+                       break;
+               }
+       }
+
+       if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) < pins) {
+               dev_err(cpu_dai->dev, "channel not supported\n");
+               return -EINVAL;
+       }
+
+       bclk = params_rate(params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width);
+
+       if (!IS_ERR_OR_NULL(sai->pinctrl)) {
+               sai->pins_state = fsl_sai_get_pins_state(sai, bclk);
+               if (!IS_ERR_OR_NULL(sai->pins_state)) {
+                       ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+                       if (ret) {
+                               dev_err(cpu_dai->dev, "failed to set proper pins state: %d\n", ret);
+                               return ret;
+                       }
+               }
+       }
+
        if (!sai->is_consumer_mode) {
-               if (sai->bclk_ratio)
-                       ret = fsl_sai_set_bclk(cpu_dai, tx,
-                                              sai->bclk_ratio *
-                                              params_rate(params));
-               else
-                       ret = fsl_sai_set_bclk(cpu_dai, tx,
-                                              slots * slot_width *
-                                              params_rate(params));
+               ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
                if (ret)
                        return ret;
 
@@ -486,13 +592,13 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (!sai->is_dsp_mode)
+       if (!sai->is_dsp_mode && !sai->is_pdm_mode)
                val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
 
        val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
        val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
 
-       if (sai->is_lsb_first)
+       if (sai->is_lsb_first || sai->is_pdm_mode)
                val_cr5 |= FSL_SAI_CR5_FBT(0);
        else
                val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
@@ -519,13 +625,28 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
                                   FSL_SAI_CR5_FBT_MASK, val_cr5);
        }
 
-       if (sai->soc_data->pins > 1)
+       if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1)
+               regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
+                                  FSL_SAI_CR4_FCOMB_MASK, 0);
+       else
                regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
                                   FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
 
+       dma_params = tx ? &sai->dma_params_tx : &sai->dma_params_rx;
+       dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) +
+                          dl_cfg[dl_cfg_idx].start_off[tx] * 0x4;
+
+       /* Find a proper tcre setting */
+       for (i = 0; i < sai->soc_data->pins; i++) {
+               trce_mask = (1 << (i + 1)) - 1;
+               if (hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins)
+                       break;
+       }
+
        regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
                           FSL_SAI_CR3_TRCE_MASK,
-                          FSL_SAI_CR3_TRCE((1 << pins) - 1));
+                          FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
+
        regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
                           FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
                           FSL_SAI_CR4_CHMOD_MASK,
@@ -737,6 +858,23 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static int fsl_sai_dai_resume(struct snd_soc_component *component)
+{
+       struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
+       struct device *dev = &sai->pdev->dev;
+       int ret;
+
+       if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) {
+               ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+               if (ret) {
+                       dev_err(dev, "failed to set proper pins state: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static struct snd_soc_dai_driver fsl_sai_dai_template = {
        .probe = fsl_sai_dai_probe,
        .playback = {
@@ -744,7 +882,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
                .channels_min = 1,
                .channels_max = 32,
                .rate_min = 8000,
-               .rate_max = 192000,
+               .rate_max = 2822400,
                .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_SAI_FORMATS,
        },
@@ -753,7 +891,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
                .channels_min = 1,
                .channels_max = 32,
                .rate_min = 8000,
-               .rate_max = 192000,
+               .rate_max = 2822400,
                .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_SAI_FORMATS,
        },
@@ -761,7 +899,9 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
 };
 
 static const struct snd_soc_component_driver fsl_component = {
-       .name           = "fsl-sai",
+       .name                   = "fsl-sai",
+       .resume                 = fsl_sai_dai_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
@@ -998,30 +1138,142 @@ static int fsl_sai_check_version(struct device *dev)
        return 0;
 }
 
+/*
+ * Calculate the offset between first two datalines, don't
+ * different offset in one case.
+ */
+static unsigned int fsl_sai_calc_dl_off(unsigned long dl_mask)
+{
+       int fbidx, nbidx, offset;
+
+       fbidx = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
+       nbidx = find_next_bit(&dl_mask, FSL_SAI_DL_NUM, fbidx + 1);
+       offset = nbidx - fbidx - 1;
+
+       return (offset < 0 || offset >= (FSL_SAI_DL_NUM - 1) ? 0 : offset);
+}
+
+/*
+ * read the fsl,dataline property from dts file.
+ * It has 3 value for each configuration, first one means the type:
+ * I2S(1) or PDM(2), second one is dataline mask for 'rx', third one is
+ * dataline mask for 'tx'. for example
+ *
+ * fsl,dataline = <1 0xff 0xff 2 0xff 0x11>,
+ *
+ * It means I2S type rx mask is 0xff, tx mask is 0xff, PDM type
+ * rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled).
+ *
+ */
+static int fsl_sai_read_dlcfg(struct fsl_sai *sai)
+{
+       struct platform_device *pdev = sai->pdev;
+       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       int ret, elems, i, index, num_cfg;
+       char *propname = "fsl,dataline";
+       struct fsl_sai_dl_cfg *cfg;
+       unsigned long dl_mask;
+       unsigned int soc_dl;
+       u32 rx, tx, type;
+
+       elems = of_property_count_u32_elems(np, propname);
+
+       if (elems <= 0) {
+               elems = 0;
+       } else if (elems % 3) {
+               dev_err(dev, "Number of elements must be divisible to 3.\n");
+               return -EINVAL;
+       }
+
+       num_cfg = elems / 3;
+       /*  Add one more for default value */
+       cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL);
+       if (!cfg)
+               return -ENOMEM;
+
+       /* Consider default value "0 0xFF 0xFF" if property is missing */
+       soc_dl = BIT(sai->soc_data->pins) - 1;
+       cfg[0].type = FSL_SAI_DL_DEFAULT;
+       cfg[0].pins[0] = sai->soc_data->pins;
+       cfg[0].mask[0] = soc_dl;
+       cfg[0].start_off[0] = 0;
+       cfg[0].next_off[0] = 0;
+
+       cfg[0].pins[1] = sai->soc_data->pins;
+       cfg[0].mask[1] = soc_dl;
+       cfg[0].start_off[1] = 0;
+       cfg[0].next_off[1] = 0;
+       for (i = 1, index = 0; i < num_cfg + 1; i++) {
+               /*
+                * type of dataline
+                * 0 means default mode
+                * 1 means I2S mode
+                * 2 means PDM mode
+                */
+               ret = of_property_read_u32_index(np, propname, index++, &type);
+               if (ret)
+                       return -EINVAL;
+
+               ret = of_property_read_u32_index(np, propname, index++, &rx);
+               if (ret)
+                       return -EINVAL;
+
+               ret = of_property_read_u32_index(np, propname, index++, &tx);
+               if (ret)
+                       return -EINVAL;
+
+               if ((rx & ~soc_dl) || (tx & ~soc_dl)) {
+                       dev_err(dev, "dataline cfg[%d] setting error, mask is 0x%x\n", i, soc_dl);
+                       return -EINVAL;
+               }
+
+               rx = rx & soc_dl;
+               tx = tx & soc_dl;
+
+               cfg[i].type = type;
+               cfg[i].pins[0] = hweight8(rx);
+               cfg[i].mask[0] = rx;
+               dl_mask = rx;
+               cfg[i].start_off[0] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
+               cfg[i].next_off[0] = fsl_sai_calc_dl_off(rx);
+
+               cfg[i].pins[1] = hweight8(tx);
+               cfg[i].mask[1] = tx;
+               dl_mask = tx;
+               cfg[i].start_off[1] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
+               cfg[i].next_off[1] = fsl_sai_calc_dl_off(tx);
+       }
+
+       sai->dl_cfg = cfg;
+       sai->dl_cfg_cnt = num_cfg + 1;
+       return 0;
+}
+
 static int fsl_sai_runtime_suspend(struct device *dev);
 static int fsl_sai_runtime_resume(struct device *dev);
 
 static int fsl_sai_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
        struct fsl_sai *sai;
        struct regmap *gpr;
-       struct resource *res;
        void __iomem *base;
        char tmp[8];
        int irq, ret, i;
        int index;
 
-       sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+       sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL);
        if (!sai)
                return -ENOMEM;
 
        sai->pdev = pdev;
-       sai->soc_data = of_device_get_match_data(&pdev->dev);
+       sai->soc_data = of_device_get_match_data(dev);
 
        sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
 
-       base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       base = devm_platform_get_and_ioremap_resource(pdev, 0, &sai->res);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
@@ -1032,18 +1284,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
                        ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
        }
 
-       sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config);
+       sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config);
        if (IS_ERR(sai->regmap)) {
-               dev_err(&pdev->dev, "regmap init failed\n");
+               dev_err(dev, "regmap init failed\n");
                return PTR_ERR(sai->regmap);
        }
 
-       sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       sai->bus_clk = devm_clk_get(dev, "bus");
        /* Compatible with old DTB cases */
        if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER)
-               sai->bus_clk = devm_clk_get(&pdev->dev, "sai");
+               sai->bus_clk = devm_clk_get(dev, "sai");
        if (IS_ERR(sai->bus_clk)) {
-               dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
+               dev_err(dev, "failed to get bus clock: %ld\n",
                                PTR_ERR(sai->bus_clk));
                /* -EPROBE_DEFER */
                return PTR_ERR(sai->bus_clk);
@@ -1051,9 +1303,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
 
        for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
                sprintf(tmp, "mclk%d", i);
-               sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+               sai->mclk_clk[i] = devm_clk_get(dev, tmp);
                if (IS_ERR(sai->mclk_clk[i])) {
-                       dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
+                       dev_err(dev, "failed to get mclk%d clock: %ld\n",
                                        i + 1, PTR_ERR(sai->mclk_clk[i]));
                        sai->mclk_clk[i] = NULL;
                }
@@ -1064,14 +1316,24 @@ static int fsl_sai_probe(struct platform_device *pdev)
        else
                sai->mclk_clk[0] = sai->bus_clk;
 
+       fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk,
+                               &sai->pll11k_clk);
+
+       /* read dataline mask for rx and tx*/
+       ret = fsl_sai_read_dlcfg(sai);
+       if (ret < 0) {
+               dev_err(dev, "failed to read dlcfg %d\n", ret);
+               return ret;
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
 
-       ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED,
+       ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED,
                               np->name, sai);
        if (ret) {
-               dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+               dev_err(dev, "failed to claim irq %u\n", irq);
                return ret;
        }
 
@@ -1088,7 +1350,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
        if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
            of_find_property(np, "fsl,sai-asynchronous", NULL)) {
                /* error out if both synchronous and asynchronous are present */
-               dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
+               dev_err(dev, "invalid binding for synchronous mode\n");
                return -EINVAL;
        }
 
@@ -1109,7 +1371,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
            of_device_is_compatible(np, "fsl,imx6ul-sai")) {
                gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
                if (IS_ERR(gpr)) {
-                       dev_err(&pdev->dev, "cannot find iomuxc registers\n");
+                       dev_err(dev, "cannot find iomuxc registers\n");
                        return PTR_ERR(gpr);
                }
 
@@ -1121,29 +1383,29 @@ static int fsl_sai_probe(struct platform_device *pdev)
                                   MCLK_DIR(index));
        }
 
-       sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
-       sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
+       sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0;
+       sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0;
        sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
        sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
 
+       sai->pinctrl = devm_pinctrl_get(&pdev->dev);
+
        platform_set_drvdata(pdev, sai);
-       pm_runtime_enable(&pdev->dev);
-       if (!pm_runtime_enabled(&pdev->dev)) {
-               ret = fsl_sai_runtime_resume(&pdev->dev);
+       pm_runtime_enable(dev);
+       if (!pm_runtime_enabled(dev)) {
+               ret = fsl_sai_runtime_resume(dev);
                if (ret)
                        goto err_pm_disable;
        }
 
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(&pdev->dev);
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
                goto err_pm_get_sync;
-       }
 
        /* Get sai version */
-       ret = fsl_sai_check_version(&pdev->dev);
+       ret = fsl_sai_check_version(dev);
        if (ret < 0)
-               dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret);
+               dev_warn(dev, "Error reading SAI version: %d\n", ret);
 
        /* Select MCLK direction */
        if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
@@ -1152,7 +1414,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
                                   FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
        }
 
-       ret = pm_runtime_put_sync(&pdev->dev);
+       ret = pm_runtime_put_sync(dev);
        if (ret < 0)
                goto err_pm_get_sync;
 
@@ -1162,15 +1424,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
         */
        if (sai->soc_data->use_imx_pcm) {
                ret = imx_pcm_dma_init(pdev);
-               if (ret)
+               if (ret) {
+                       if (!IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA))
+                               dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n");
                        goto err_pm_get_sync;
+               }
        } else {
-               ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+               ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
                if (ret)
                        goto err_pm_get_sync;
        }
 
-       ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+       ret = devm_snd_soc_register_component(dev, &fsl_component,
                                              &sai->cpu_dai_drv, 1);
        if (ret)
                goto err_pm_get_sync;
@@ -1178,10 +1443,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
        return ret;
 
 err_pm_get_sync:
-       if (!pm_runtime_status_suspended(&pdev->dev))
-               fsl_sai_runtime_suspend(&pdev->dev);
+       if (!pm_runtime_status_suspended(dev))
+               fsl_sai_runtime_suspend(dev);
 err_pm_disable:
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_disable(dev);
 
        return ret;
 }