diff options
author | Matthias Reichl <hias@horus.com> | 2018-01-17 07:50:50 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-01-18 06:21:17 -0500 |
commit | 8d5737a5f53902a916ee1e1cb248c9b8b883b2ea (patch) | |
tree | 6190a3acc8c0355222550a611829e8261828614e | |
parent | 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff) |
ASoC: bcm2835: fix hw_params error when device is in prepared state
If bcm2835 is configured as bitclock master calling hw_params()
after prepare() fails with EBUSY. This also makes it impossible to
use bcm2835 in full duplex mode.
The error is caused by the split clock setup: clk_set_rate
is called in hw_params, clk_prepare_enable in prepare. As hw_params
doesn't check if the clock was already enabled clk_set_rate
fails with EBUSY.
Fix this by moving clock startup from prepare to hw_params and
let hw_params properly deal with an already set up or enabled
clock.
Signed-off-by: Matthias Reichl <hias@horus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/bcm/bcm2835-i2s.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 2e449d7173fc..d5f73a8ab893 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c | |||
@@ -130,6 +130,7 @@ struct bcm2835_i2s_dev { | |||
130 | struct regmap *i2s_regmap; | 130 | struct regmap *i2s_regmap; |
131 | struct clk *clk; | 131 | struct clk *clk; |
132 | bool clk_prepared; | 132 | bool clk_prepared; |
133 | int clk_rate; | ||
133 | }; | 134 | }; |
134 | 135 | ||
135 | static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) | 136 | static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) |
@@ -419,10 +420,19 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, | |||
419 | } | 420 | } |
420 | 421 | ||
421 | /* Clock should only be set up here if CPU is clock master */ | 422 | /* Clock should only be set up here if CPU is clock master */ |
422 | if (bit_clock_master) { | 423 | if (bit_clock_master && |
423 | ret = clk_set_rate(dev->clk, bclk_rate); | 424 | (!dev->clk_prepared || dev->clk_rate != bclk_rate)) { |
424 | if (ret) | 425 | if (dev->clk_prepared) |
425 | return ret; | 426 | bcm2835_i2s_stop_clock(dev); |
427 | |||
428 | if (dev->clk_rate != bclk_rate) { | ||
429 | ret = clk_set_rate(dev->clk, bclk_rate); | ||
430 | if (ret) | ||
431 | return ret; | ||
432 | dev->clk_rate = bclk_rate; | ||
433 | } | ||
434 | |||
435 | bcm2835_i2s_start_clock(dev); | ||
426 | } | 436 | } |
427 | 437 | ||
428 | /* Setup the frame format */ | 438 | /* Setup the frame format */ |
@@ -618,8 +628,6 @@ static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream, | |||
618 | struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | 628 | struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); |
619 | uint32_t cs_reg; | 629 | uint32_t cs_reg; |
620 | 630 | ||
621 | bcm2835_i2s_start_clock(dev); | ||
622 | |||
623 | /* | 631 | /* |
624 | * Clear both FIFOs if the one that should be started | 632 | * Clear both FIFOs if the one that should be started |
625 | * is not empty at the moment. This should only happen | 633 | * is not empty at the moment. This should only happen |