[PATCH v2 1/2] ASoC: atmel-i2s: Use devm_clk_get_enabled() for pclk
From: phucduc . bui
Date: Wed Nov 11 2026 - 05:07:06 EST
From: bui duc phuc <phucduc.bui@xxxxxxxxx>
The peripheral clock is only acquired and enabled once during
probe. Use devm_clk_get_enabled() to combine clock acquisition
and enabling into a single call.
Since the clock is now enabled during probe, request the IRQ
afterwards to ensure it is freed before the clock is disabled
during teardown.
This also removes the need for manual clock disable handling
on probe failures and in the remove callback, as the devm API
automatically handles clock cleanup.
Signed-off-by: bui duc phuc <phucduc.bui@xxxxxxxxx>
---
Changes in v2:
- Move the devm_request_irq() call below clock initialization and
dev->regmap setup, as suggested by Sashiko.
sound/soc/atmel/atmel-i2s.c | 43 +++++++++++++------------------------
1 file changed, 15 insertions(+), 28 deletions(-)
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index e1d8af056234..60e885980f4c 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -650,21 +650,16 @@ static int atmel_i2s_probe(struct platform_device *pdev)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- /* Request IRQ. */
+ /* Get the IRQ. */
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0,
- dev_name(&pdev->dev), dev);
- if (err)
- return err;
-
- /* Get the peripheral clock. */
- dev->pclk = devm_clk_get(&pdev->dev, "pclk");
+ /* Get and enable the peripheral clock. */
+ dev->pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
if (IS_ERR(dev->pclk))
return dev_err_probe(&pdev->dev, PTR_ERR(dev->pclk),
- "failed to get the peripheral clock\n");
+ "failed to get/enable the peripheral clock\n");
/* Get audio clock to generate the I2S Master Clock (I2S_MCK) */
dev->gclk = devm_clk_get_optional(&pdev->dev, "gclk");
@@ -675,6 +670,15 @@ static int atmel_i2s_probe(struct platform_device *pdev)
dev->regmap = regmap;
platform_set_drvdata(pdev, dev);
+ /*
+ * Request IRQ after initializing dev->regmap and enabling pclk,
+ * so devres frees the IRQ before disabling pclk.
+ */
+ err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0,
+ dev_name(&pdev->dev), dev);
+ if (err)
+ return err;
+
/* Do hardware specific settings to initialize I2S_MCK generator */
if (dev->caps && dev->caps->mck_init) {
err = dev->caps->mck_init(dev, np);
@@ -682,11 +686,6 @@ static int atmel_i2s_probe(struct platform_device *pdev)
return err;
}
- /* Enable the peripheral clock. */
- err = clk_prepare_enable(dev->pclk);
- if (err)
- return err;
-
/* Get IP version. */
regmap_read(dev->regmap, ATMEL_I2SC_VERSION, &version);
dev_info(&pdev->dev, "hw version: %#x\n", version);
@@ -698,10 +697,8 @@ static int atmel_i2s_probe(struct platform_device *pdev)
err = devm_snd_soc_register_component(&pdev->dev,
&atmel_i2s_component,
&atmel_i2s_dai, 1);
- if (err) {
- clk_disable_unprepare(dev->pclk);
+ if (err)
return err;
- }
/* Prepare DMA config. */
dev->playback.addr = (dma_addr_t)mem->start + ATMEL_I2SC_THR;
@@ -712,28 +709,18 @@ static int atmel_i2s_probe(struct platform_device *pdev)
if (of_property_match_string(np, "dma-names", "rx-tx") == 0)
pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags);
- if (err) {
- clk_disable_unprepare(dev->pclk);
+ if (err)
return err;
- }
return 0;
}
-static void atmel_i2s_remove(struct platform_device *pdev)
-{
- struct atmel_i2s_dev *dev = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(dev->pclk);
-}
-
static struct platform_driver atmel_i2s_driver = {
.driver = {
.name = "atmel_i2s",
.of_match_table = atmel_i2s_dt_ids,
},
.probe = atmel_i2s_probe,
- .remove = atmel_i2s_remove,
};
module_platform_driver(atmel_i2s_driver);
--
2.43.0