aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMylène Josserand <mylene.josserand@free-electrons.com>2017-02-02 04:24:16 -0500
committerMark Brown <broonie@kernel.org>2017-02-03 07:02:07 -0500
commit2ad6f30de7087515a0bc2a718fca6681a57739a0 (patch)
treee434ae7b37b89a7df38cd91060c0846c22fd7d36
parent164e372747ce7a8b97459e98ce258b6aa969cb2f (diff)
ASoC: sun4i-i2s: Add quirks to handle a31 compatible
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>
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c57
1 files changed, 55 insertions, 2 deletions
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index f24d19526603..268f2bf691b3 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -14,9 +14,11 @@
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/dmaengine.h> 15#include <linux/dmaengine.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/of_device.h>
17#include <linux/platform_device.h> 18#include <linux/platform_device.h>
18#include <linux/pm_runtime.h> 19#include <linux/pm_runtime.h>
19#include <linux/regmap.h> 20#include <linux/regmap.h>
21#include <linux/reset.h>
20 22
21#include <sound/dmaengine_pcm.h> 23#include <sound/dmaengine_pcm.h>
22#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
@@ -92,6 +94,7 @@ struct sun4i_i2s {
92 struct clk *bus_clk; 94 struct clk *bus_clk;
93 struct clk *mod_clk; 95 struct clk *mod_clk;
94 struct regmap *regmap; 96 struct regmap *regmap;
97 struct reset_control *rst;
95 98
96 unsigned int mclk_freq; 99 unsigned int mclk_freq;
97 100
@@ -651,9 +654,22 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
651 return 0; 654 return 0;
652} 655}
653 656
657struct sun4i_i2s_quirks {
658 bool has_reset;
659};
660
661static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
662 .has_reset = false,
663};
664
665static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
666 .has_reset = true,
667};
668
654static int sun4i_i2s_probe(struct platform_device *pdev) 669static int sun4i_i2s_probe(struct platform_device *pdev)
655{ 670{
656 struct sun4i_i2s *i2s; 671 struct sun4i_i2s *i2s;
672 const struct sun4i_i2s_quirks *quirks;
657 struct resource *res; 673 struct resource *res;
658 void __iomem *regs; 674 void __iomem *regs;
659 int irq, ret; 675 int irq, ret;
@@ -674,6 +690,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
674 return irq; 690 return irq;
675 } 691 }
676 692
693 quirks = of_device_get_match_data(&pdev->dev);
694 if (!quirks) {
695 dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
696 return -ENODEV;
697 }
698
677 i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); 699 i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
678 if (IS_ERR(i2s->bus_clk)) { 700 if (IS_ERR(i2s->bus_clk)) {
679 dev_err(&pdev->dev, "Can't get our bus clock\n"); 701 dev_err(&pdev->dev, "Can't get our bus clock\n");
@@ -692,7 +714,24 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
692 dev_err(&pdev->dev, "Can't get our mod clock\n"); 714 dev_err(&pdev->dev, "Can't get our mod clock\n");
693 return PTR_ERR(i2s->mod_clk); 715 return PTR_ERR(i2s->mod_clk);
694 } 716 }
695 717
718 if (quirks->has_reset) {
719 i2s->rst = devm_reset_control_get(&pdev->dev, NULL);
720 if (IS_ERR(i2s->rst)) {
721 dev_err(&pdev->dev, "Failed to get reset control\n");
722 return PTR_ERR(i2s->rst);
723 }
724 }
725
726 if (!IS_ERR(i2s->rst)) {
727 ret = reset_control_deassert(i2s->rst);
728 if (ret) {
729 dev_err(&pdev->dev,
730 "Failed to deassert the reset control\n");
731 return -EINVAL;
732 }
733 }
734
696 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; 735 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
697 i2s->playback_dma_data.maxburst = 4; 736 i2s->playback_dma_data.maxburst = 4;
698 737
@@ -727,23 +766,37 @@ err_suspend:
727 sun4i_i2s_runtime_suspend(&pdev->dev); 766 sun4i_i2s_runtime_suspend(&pdev->dev);
728err_pm_disable: 767err_pm_disable:
729 pm_runtime_disable(&pdev->dev); 768 pm_runtime_disable(&pdev->dev);
769 if (!IS_ERR(i2s->rst))
770 reset_control_assert(i2s->rst);
730 771
731 return ret; 772 return ret;
732} 773}
733 774
734static int sun4i_i2s_remove(struct platform_device *pdev) 775static int sun4i_i2s_remove(struct platform_device *pdev)
735{ 776{
777 struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
778
736 snd_dmaengine_pcm_unregister(&pdev->dev); 779 snd_dmaengine_pcm_unregister(&pdev->dev);
737 780
738 pm_runtime_disable(&pdev->dev); 781 pm_runtime_disable(&pdev->dev);
739 if (!pm_runtime_status_suspended(&pdev->dev)) 782 if (!pm_runtime_status_suspended(&pdev->dev))
740 sun4i_i2s_runtime_suspend(&pdev->dev); 783 sun4i_i2s_runtime_suspend(&pdev->dev);
741 784
785 if (!IS_ERR(i2s->rst))
786 reset_control_assert(i2s->rst);
787
742 return 0; 788 return 0;
743} 789}
744 790
745static const struct of_device_id sun4i_i2s_match[] = { 791static const struct of_device_id sun4i_i2s_match[] = {
746 { .compatible = "allwinner,sun4i-a10-i2s", }, 792 {
793 .compatible = "allwinner,sun4i-a10-i2s",
794 .data = &sun4i_a10_i2s_quirks,
795 },
796 {
797 .compatible = "allwinner,sun6i-a31-i2s",
798 .data = &sun6i_a31_i2s_quirks,
799 },
747 {} 800 {}
748}; 801};
749MODULE_DEVICE_TABLE(of, sun4i_i2s_match); 802MODULE_DEVICE_TABLE(of, sun4i_i2s_match);