ASoC: sun4i-i2s: Add quirks to handle a31 compatible
authorMylène Josserand <mylene.josserand@free-electrons.com>
Thu, 2 Feb 2017 09:24:16 +0000 (10:24 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 3 Feb 2017 12:02:07 +0000 (13:02 +0100)
Some SoCs have a reset line that must be asserted/deasserted.
This patch adds a quirk to handle the new compatible
"allwinner,sun6i-a31-i2s" which will deassert the reset
line on probe function and assert it on remove's one.

This new compatible is useful in case of A33 codec driver, for example.

Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sunxi/sun4i-i2s.c

index f24d19526603c2d2a31ef9af1cff07ed4dd8d1ca..268f2bf691b33e6c1955d690f2e9bc4852686069 100644 (file)
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm_params.h>
@@ -92,6 +94,7 @@ struct sun4i_i2s {
        struct clk      *bus_clk;
        struct clk      *mod_clk;
        struct regmap   *regmap;
+       struct reset_control *rst;
 
        unsigned int    mclk_freq;
 
@@ -651,9 +654,22 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
        return 0;
 }
 
+struct sun4i_i2s_quirks {
+       bool has_reset;
+};
+
+static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
+       .has_reset      = false,
+};
+
+static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
+       .has_reset      = true,
+};
+
 static int sun4i_i2s_probe(struct platform_device *pdev)
 {
        struct sun4i_i2s *i2s;
+       const struct sun4i_i2s_quirks *quirks;
        struct resource *res;
        void __iomem *regs;
        int irq, ret;
@@ -674,6 +690,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
                return irq;
        }
 
+       quirks = of_device_get_match_data(&pdev->dev);
+       if (!quirks) {
+               dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
+               return -ENODEV;
+       }
+
        i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
        if (IS_ERR(i2s->bus_clk)) {
                dev_err(&pdev->dev, "Can't get our bus clock\n");
@@ -692,7 +714,24 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Can't get our mod clock\n");
                return PTR_ERR(i2s->mod_clk);
        }
-       
+
+       if (quirks->has_reset) {
+               i2s->rst = devm_reset_control_get(&pdev->dev, NULL);
+               if (IS_ERR(i2s->rst)) {
+                       dev_err(&pdev->dev, "Failed to get reset control\n");
+                       return PTR_ERR(i2s->rst);
+               }
+       }
+
+       if (!IS_ERR(i2s->rst)) {
+               ret = reset_control_deassert(i2s->rst);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Failed to deassert the reset control\n");
+                       return -EINVAL;
+               }
+       }
+
        i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
        i2s->playback_dma_data.maxburst = 4;
 
@@ -727,23 +766,37 @@ err_suspend:
                sun4i_i2s_runtime_suspend(&pdev->dev);
 err_pm_disable:
        pm_runtime_disable(&pdev->dev);
+       if (!IS_ERR(i2s->rst))
+               reset_control_assert(i2s->rst);
 
        return ret;
 }
 
 static int sun4i_i2s_remove(struct platform_device *pdev)
 {
+       struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
        snd_dmaengine_pcm_unregister(&pdev->dev);
 
        pm_runtime_disable(&pdev->dev);
        if (!pm_runtime_status_suspended(&pdev->dev))
                sun4i_i2s_runtime_suspend(&pdev->dev);
 
+       if (!IS_ERR(i2s->rst))
+               reset_control_assert(i2s->rst);
+
        return 0;
 }
 
 static const struct of_device_id sun4i_i2s_match[] = {
-       { .compatible = "allwinner,sun4i-a10-i2s", },
+       {
+               .compatible = "allwinner,sun4i-a10-i2s",
+               .data = &sun4i_a10_i2s_quirks,
+       },
+       {
+               .compatible = "allwinner,sun6i-a31-i2s",
+               .data = &sun6i_a31_i2s_quirks,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, sun4i_i2s_match);