diff options
author | Mylène Josserand <mylene.josserand@free-electrons.com> | 2017-02-02 04:24:16 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-02-03 07:02:07 -0500 |
commit | 2ad6f30de7087515a0bc2a718fca6681a57739a0 (patch) | |
tree | e434ae7b37b89a7df38cd91060c0846c22fd7d36 | |
parent | 164e372747ce7a8b97459e98ce258b6aa969cb2f (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.c | 57 |
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 | ||
657 | struct sun4i_i2s_quirks { | ||
658 | bool has_reset; | ||
659 | }; | ||
660 | |||
661 | static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { | ||
662 | .has_reset = false, | ||
663 | }; | ||
664 | |||
665 | static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { | ||
666 | .has_reset = true, | ||
667 | }; | ||
668 | |||
654 | static int sun4i_i2s_probe(struct platform_device *pdev) | 669 | static 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); |
728 | err_pm_disable: | 767 | err_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 | ||
734 | static int sun4i_i2s_remove(struct platform_device *pdev) | 775 | static 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 | ||
745 | static const struct of_device_id sun4i_i2s_match[] = { | 791 | static 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 | }; |
749 | MODULE_DEVICE_TABLE(of, sun4i_i2s_match); | 802 | MODULE_DEVICE_TABLE(of, sun4i_i2s_match); |