ASoC: atmel-i2s: Fix clock and slot width handling
v2 cover ASoC: atmel-i2s: Fix clock and slot width handling
From: bui duc phuc <[email protected]>
Hi all,
This series simplifies peripheral clock handling and fixes the I2SC_WS slot width configuration in the Atmel I2S driver.
Link v1:
https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Move the devm_request_irq() call below clock initialization and dev->regmap setup, as suggested by Sashiko.
- Add a patch to fix I2SC_WS slot width configuration, based on the SAMA5D2 Series datasheet (Inter-IC Sound Controller).
https://ww1.microchip.com/downloads/en/DeviceDoc/DS60001476B.pdf
Compile-tested only.
Best regards,
Phuc
bui duc phuc (2):
ASoC: atmel-i2s: Use devm_clk_get_enabled() for pclk
ASoC: atmel-i2s: Fix I2SC_WS slot width configuration
sound/soc/atmel/atmel-i2s.c | 45 +++++++++++++------------------------ 1 file changed, 16 insertions(+), 29 deletions(-)
Signature · 1 line
2.43.0
PATCH v2 1/2 ASoC: atmel-i2s: Use devm_clk_get_enabled() for pclk
From: bui duc phuc <[email protected]>
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.
---
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(-)
sound/soc/atmel/atmel-i2s.c +15 -28
@@ -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);
Signature · 1 line
2.43.0
PATCH v2 2/2 ASoC: atmel-i2s: Fix I2SC_WS slot width configuration
In reply to [email protected]From: bui duc phuc <[email protected]>
The atmel_i2s_hw_params() function configures the PCM formats S18_3LE, S20_3LE and S24_3LE, which require a 24-bit I2SC_WS slot width.
However, ATMEL_I2SC_MR_IWS is missing from the mask passed to regmap_update_bits() when updating ATMEL_I2SC_MR. As a result, the IWS bit is never updated, potentially leaving the slot width at 32 bits.
Add ATMEL_I2SC_MR_IWS to the mask to ensure the slot width is configured correctly.
--- sound/soc/atmel/atmel-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/atmel/atmel-i2s.c +1 -1
@@ -329,7 +329,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,int ret; mr_mask =ATMEL_I2SC_MR_FORMAT_MASK |ATMEL_I2SC_MR_MODE_MASK | -ATMEL_I2SC_MR_DATALENGTH_MASK ; +ATMEL_I2SC_MR_DATALENGTH_MASK |ATMEL_I2SC_MR_IWS ;if (is_playback) mr_mask |=ATMEL_I2SC_MR_TXMONO ;else
Signature · 1 line
2.43.0