diff options
author | Krzysztof Kozlowski <krzk@kernel.org> | 2017-07-27 13:13:38 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-07-28 05:58:31 -0400 |
commit | 6f187f7ef1c15dca9f720b18a7e928718fd1a8b3 (patch) | |
tree | b7945f5dac6ea2100fa75f962ea86a378c665b00 | |
parent | 81ea6cc73c384e4093519e0c75394aa2a1941a10 (diff) |
ASoC: samsung: Add proper error paths to s3c24xx I2S driver
s3c2412_i2s_probe() might fail so driver has to revert work done by
s3c_i2sv2_probe() (clock enabling). Missing doing this would lead to
clock enable in-balance.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Acked-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/samsung/s3c-i2s-v2.c | 9 | ||||
-rw-r--r-- | sound/soc/samsung/s3c-i2s-v2.h | 7 | ||||
-rw-r--r-- | sound/soc/samsung/s3c2412-i2s.c | 13 |
3 files changed, 25 insertions, 4 deletions
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index 3894bda06ebb..58c3e9bfc6b7 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c | |||
@@ -651,6 +651,15 @@ int s3c_i2sv2_probe(struct snd_soc_dai *dai, | |||
651 | } | 651 | } |
652 | EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); | 652 | EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); |
653 | 653 | ||
654 | void s3c_i2sv2_cleanup(struct snd_soc_dai *dai, | ||
655 | struct s3c_i2sv2_info *i2s) | ||
656 | { | ||
657 | clk_disable_unprepare(i2s->iis_pclk); | ||
658 | clk_put(i2s->iis_pclk); | ||
659 | i2s->iis_pclk = NULL; | ||
660 | } | ||
661 | EXPORT_SYMBOL_GPL(s3c_i2sv2_cleanup); | ||
662 | |||
654 | #ifdef CONFIG_PM | 663 | #ifdef CONFIG_PM |
655 | static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) | 664 | static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) |
656 | { | 665 | { |
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index 182d80564e37..3fca20f7a853 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h | |||
@@ -92,6 +92,13 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, | |||
92 | unsigned long base); | 92 | unsigned long base); |
93 | 93 | ||
94 | /** | 94 | /** |
95 | * s3c_i2sv2_cleanup - cleanup resources allocated in s3c_i2sv2_probe | ||
96 | * @dai: The ASoC DAI structure supplied to the original probe. | ||
97 | * @i2s: Our local i2s structure to fill in. | ||
98 | */ | ||
99 | extern void s3c_i2sv2_cleanup(struct snd_soc_dai *dai, | ||
100 | struct s3c_i2sv2_info *i2s); | ||
101 | /** | ||
95 | * s3c_i2sv2_register_component - register component and dai with soc core | 102 | * s3c_i2sv2_register_component - register component and dai with soc core |
96 | * @dev: DAI device | 103 | * @dev: DAI device |
97 | * @id: DAI ID | 104 | * @id: DAI ID |
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index bcd1cbdeac93..cc0840fff5aa 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c | |||
@@ -65,7 +65,8 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai) | |||
65 | s3c2412_i2s.iis_cclk = devm_clk_get(dai->dev, "i2sclk"); | 65 | s3c2412_i2s.iis_cclk = devm_clk_get(dai->dev, "i2sclk"); |
66 | if (IS_ERR(s3c2412_i2s.iis_cclk)) { | 66 | if (IS_ERR(s3c2412_i2s.iis_cclk)) { |
67 | pr_err("failed to get i2sclk clock\n"); | 67 | pr_err("failed to get i2sclk clock\n"); |
68 | return PTR_ERR(s3c2412_i2s.iis_cclk); | 68 | ret = PTR_ERR(s3c2412_i2s.iis_cclk); |
69 | goto err; | ||
69 | } | 70 | } |
70 | 71 | ||
71 | /* Set MPLL as the source for IIS CLK */ | 72 | /* Set MPLL as the source for IIS CLK */ |
@@ -73,20 +74,24 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai) | |||
73 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); | 74 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); |
74 | ret = clk_prepare_enable(s3c2412_i2s.iis_cclk); | 75 | ret = clk_prepare_enable(s3c2412_i2s.iis_cclk); |
75 | if (ret) | 76 | if (ret) |
76 | return ret; | 77 | goto err; |
77 | |||
78 | s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; | ||
79 | 78 | ||
80 | /* Configure the I2S pins (GPE0...GPE4) in correct mode */ | 79 | /* Configure the I2S pins (GPE0...GPE4) in correct mode */ |
81 | s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), | 80 | s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), |
82 | S3C_GPIO_PULL_NONE); | 81 | S3C_GPIO_PULL_NONE); |
83 | 82 | ||
84 | return 0; | 83 | return 0; |
84 | |||
85 | err: | ||
86 | s3c_i2sv2_cleanup(dai, &s3c2412_i2s); | ||
87 | |||
88 | return ret; | ||
85 | } | 89 | } |
86 | 90 | ||
87 | static int s3c2412_i2s_remove(struct snd_soc_dai *dai) | 91 | static int s3c2412_i2s_remove(struct snd_soc_dai *dai) |
88 | { | 92 | { |
89 | clk_disable_unprepare(s3c2412_i2s.iis_cclk); | 93 | clk_disable_unprepare(s3c2412_i2s.iis_cclk); |
94 | s3c_i2sv2_cleanup(dai, &s3c2412_i2s); | ||
90 | 95 | ||
91 | return 0; | 96 | return 0; |
92 | } | 97 | } |