From e2681a1bf5ae053426a6c5c1daaed17b2f95efe6 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Thu, 27 Mar 2014 19:06:59 +0800 Subject: ASoC: fsl_sai: Add isr to deal with error flag It's quite cricial to clear error flags because SAI might hang if getting FIFO underrun during playback (I haven't confirmed the same issue on Rx overflow though). So this patch enables those irq and adds isr() to clear the flags so as to keep playback entirely safe. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/fsl/fsl_sai.h | 15 +++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index c4a4231..0bc98bb 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -23,6 +23,71 @@ #include "fsl_sai.h" +#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ + FSL_SAI_CSR_FEIE) + +static irqreturn_t fsl_sai_isr(int irq, void *devid) +{ + struct fsl_sai *sai = (struct fsl_sai *)devid; + struct device *dev = &sai->pdev->dev; + u32 xcsr, mask; + + /* Only handle those what we enabled */ + mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT; + + /* Tx IRQ */ + regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr); + xcsr &= mask; + + if (xcsr & FSL_SAI_CSR_WSF) + dev_dbg(dev, "isr: Start of Tx word detected\n"); + + if (xcsr & FSL_SAI_CSR_SEF) + dev_warn(dev, "isr: Tx Frame sync error detected\n"); + + if (xcsr & FSL_SAI_CSR_FEF) { + dev_warn(dev, "isr: Transmit underrun detected\n"); + /* FIFO reset for safety */ + xcsr |= FSL_SAI_CSR_FR; + } + + if (xcsr & FSL_SAI_CSR_FWF) + dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n"); + + if (xcsr & FSL_SAI_CSR_FRF) + dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n"); + + regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr); + + /* Rx IRQ */ + regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr); + xcsr &= mask; + + if (xcsr & FSL_SAI_CSR_WSF) + dev_dbg(dev, "isr: Start of Rx word detected\n"); + + if (xcsr & FSL_SAI_CSR_SEF) + dev_warn(dev, "isr: Rx Frame sync error detected\n"); + + if (xcsr & FSL_SAI_CSR_FEF) { + dev_warn(dev, "isr: Receive overflow detected\n"); + /* FIFO reset for safety */ + xcsr |= FSL_SAI_CSR_FR; + } + + if (xcsr & FSL_SAI_CSR_FWF) + dev_dbg(dev, "isr: Enabled receive FIFO is full\n"); + + if (xcsr & FSL_SAI_CSR_FRF) + dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n"); + + regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr); + + return IRQ_HANDLED; +} + static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int fsl_dir) { @@ -373,8 +438,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); + regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS); + regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS); regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_TX * 2); regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, @@ -490,12 +555,14 @@ static int fsl_sai_probe(struct platform_device *pdev) struct fsl_sai *sai; struct resource *res; void __iomem *base; - int ret; + int irq, ret; sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); if (!sai) return -ENOMEM; + sai->pdev = pdev; + sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); if (sai->big_endian_regs) fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; @@ -514,6 +581,18 @@ static int fsl_sai_probe(struct platform_device *pdev) return PTR_ERR(sai->regmap); } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai); + if (ret) { + dev_err(&pdev->dev, "failed to claim irq %u\n", irq); + return ret; + } + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index e432260..a264185 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -37,7 +37,21 @@ /* SAI Transmit/Recieve Control Register */ #define FSL_SAI_CSR_TERE BIT(31) +#define FSL_SAI_CSR_FR BIT(25) +#define FSL_SAI_CSR_xF_SHIFT 16 +#define FSL_SAI_CSR_xF_W_SHIFT 18 +#define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT) +#define FSL_SAI_CSR_xF_W_MASK (0x7 << FSL_SAI_CSR_xF_W_SHIFT) +#define FSL_SAI_CSR_WSF BIT(20) +#define FSL_SAI_CSR_SEF BIT(19) +#define FSL_SAI_CSR_FEF BIT(18) #define FSL_SAI_CSR_FWF BIT(17) +#define FSL_SAI_CSR_FRF BIT(16) +#define FSL_SAI_CSR_xIE_SHIFT 8 +#define FSL_SAI_CSR_WSIE BIT(12) +#define FSL_SAI_CSR_SEIE BIT(11) +#define FSL_SAI_CSR_FEIE BIT(10) +#define FSL_SAI_CSR_FWIE BIT(9) #define FSL_SAI_CSR_FRIE BIT(8) #define FSL_SAI_CSR_FRDE BIT(0) @@ -99,6 +113,7 @@ #define FSL_SAI_MAXBURST_RX 6 struct fsl_sai { + struct platform_device *pdev; struct regmap *regmap; bool big_endian_regs; -- cgit v1.1 From e3efe3bedb6592465d9a2bd116d5e611dae362c3 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 31 Mar 2014 12:25:24 -0600 Subject: ASoC: alc5632: fix uninit var in alc5632_probe() alc5632_probe() returns ret, yet it is not initialized or set anywhere. This ends up causing the function to appear to fail, and audio not to work on the Toshiba AC100, with my compiler at least. This function used to set ret in all cases, but recent cleanup removed that. Fixes: 5d6be5aa6bec ("ASoC: codec: Simplify ASoC probe code.") Signed-off-by: Stephen Warren Reviewed-by: Thierry Reding Signed-off-by: Mark Brown --- sound/soc/codecs/alc5632.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index ec071a6..3ee8d4e 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1061,7 +1061,6 @@ static int alc5632_resume(struct snd_soc_codec *codec) static int alc5632_probe(struct snd_soc_codec *codec) { struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); - int ret; /* power on device */ alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1075,7 +1074,7 @@ static int alc5632_probe(struct snd_soc_codec *codec) return -EINVAL; } - return ret; + return 0; } /* power down chip */ -- cgit v1.1 From c31b0cb1f1a19bc551875e07e9dd7c531ac3580e Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 31 Mar 2014 12:38:16 -0600 Subject: ASoC: alc5632: add an of_match table Add a device tree match table. This serves to make the driver's support of device tree more explicit. Perhaps the fallback for DT matching to using the i2c_device_id table will go away one day, since it fails in face of devices from different vendors with the same name. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/codecs/alc5632.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 3ee8d4e..85942ca 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1190,11 +1190,18 @@ static const struct i2c_device_id alc5632_i2c_table[] = { }; MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table); +static const struct of_device_id alc5632_of_match[] = { + { .compatible = "realtek,alc5632", }, + { } +}; +MODULE_DEVICE_TABLE(of, alc5632_of_match); + /* i2c codec control layer */ static struct i2c_driver alc5632_i2c_driver = { .driver = { .name = "alc5632", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(alc5632_of_match), }, .probe = alc5632_i2c_probe, .remove = alc5632_i2c_remove, -- cgit v1.1 From 2951f93f431a2fc8956a3b13882dc07cb5b8b2b9 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 31 Mar 2014 12:38:18 -0600 Subject: ASoC: max98090: add an of_match table Add a device tree match table. This serves to make the driver's support of device tree more explicit. Perhaps the fallback for DT matching to using the i2c_device_id table will go away one day, since it fails in face of devices from different vendors with the same name. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 361862d..83a773c 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2406,11 +2406,18 @@ static const struct i2c_device_id max98090_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); +static const struct of_device_id max98090_of_match[] = { + { .compatible = "maxim,max98090", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98090_of_match); + static struct i2c_driver max98090_i2c_driver = { .driver = { .name = "max98090", .owner = THIS_MODULE, .pm = &max98090_pm, + .of_match_table = of_match_ptr(max98090_of_match), }, .probe = max98090_i2c_probe, .remove = max98090_i2c_remove, -- cgit v1.1 From 06b4b813058f6092ded5d7e0d92d4c34d92975bd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 4 Apr 2014 11:04:35 +0800 Subject: ASoC: cs42xx8: Check return value of regmap_read and report correct chipid value Fix checking return value of regmap_read(). Also fix reporting the chip_id value. CS42XX8_CHIPID_CHIP_ID_MASK is 0xF0, so the chip_id value is (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4). Signed-off-by: Axel Lin Acked-by: Paul Handrigan Acked-by: Brian Austin Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/codecs/cs42xx8.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 082299a..8502032 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -495,17 +495,16 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) regcache_cache_bypass(cs42xx8->regmap, true); /* Validate the chip ID */ - regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val); - if (val < 0) { - dev_err(dev, "failed to get device ID: %x", val); - ret = -EINVAL; + ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val); + if (ret < 0) { + dev_err(dev, "failed to get device ID, ret = %d", ret); goto err_enable; } /* The top four bits of the chip ID should be 0000 */ - if ((val & CS42XX8_CHIPID_CHIP_ID_MASK) != 0x00) { + if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) { dev_err(dev, "unmatched chip ID: %d\n", - val & CS42XX8_CHIPID_CHIP_ID_MASK); + (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4); ret = -EINVAL; goto err_enable; } -- cgit v1.1 From a14bf88749c5b54bb9c636bcd47c26ea79560ce5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 6 Apr 2014 00:04:35 +0800 Subject: ASoC: cs42l52: Fix mask for REVID BIT[0:2] of register 01h is REVID, so the mask for REVID should be 0x7. Also updates the code to use CS42L52_CHIP_REV_MASK. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 2 +- sound/soc/codecs/cs42l52.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index f0ca6be..460d355 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1259,7 +1259,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, } dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n", - reg & 0xFF); + reg & CS42L52_CHIP_REV_MASK); /* Set Platform Data */ if (cs42l52->pdata.mica_diff_cfg) diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h index 6fb8f00..ac445993 100644 --- a/sound/soc/codecs/cs42l52.h +++ b/sound/soc/codecs/cs42l52.h @@ -37,7 +37,7 @@ #define CS42L52_CHIP_REV_A0 0x00 #define CS42L52_CHIP_REV_A1 0x01 #define CS42L52_CHIP_REV_B0 0x02 -#define CS42L52_CHIP_REV_MASK 0x03 +#define CS42L52_CHIP_REV_MASK 0x07 #define CS42L52_PWRCTL1 0x02 #define CS42L52_PWRCTL1_PDN_ALL 0x9F -- cgit v1.1 From 05b0006734f2aa728331bfe169f105c4b386858a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 3 Apr 2014 19:56:32 +0800 Subject: ASoC: da732x: Print correct major id DA732X_ID_MAJOR_MASK is 0xF0, so the major id is (reg & DA732X_ID_MAJOR_MASK) >> 4. Signed-off-by: Axel Lin Acked-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da732x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 7d168ec..48f3fef 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1571,7 +1571,8 @@ static int da732x_i2c_probe(struct i2c_client *i2c, } dev_info(&i2c->dev, "Revision: %d.%d\n", - (reg & DA732X_ID_MAJOR_MASK), (reg & DA732X_ID_MINOR_MASK)); + (reg & DA732X_ID_MAJOR_MASK) >> 4, + (reg & DA732X_ID_MINOR_MASK)); ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x, da732x_dai, ARRAY_SIZE(da732x_dai)); -- cgit v1.1 From ef33bc3217c7aa9868f497c4f797cc50ad3ce357 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 4 Apr 2014 15:09:47 +0800 Subject: ASoC: fsl_sai: Fix Bit Clock Polarity configurations The BCP bit in TCR4/RCR4 register rules as followings: 0 Bit clock is active high with drive outputs on rising edge and sample inputs on falling edge. 1 Bit clock is active low with drive outputs on falling edge and sample inputs on rising edge. For all formats currently supported in the fsl_sai driver, they're exactly sending data on the falling edge and sampling on the rising edge. However, the driver clears this BCP bit for all of them which results click noise when working with SGTL5000 and big noise with WM8962. Thus this patch corrects the BCP settings for all the formats here to fix the nosie issue. Signed-off-by: Nicolin Chen Acked-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 0bc98bb..56da8c8 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -179,7 +179,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * that is, together with the last bit of the previous * data word. */ - val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr2 |= FSL_SAI_CR2_BCP; val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP; break; case SND_SOC_DAIFMT_LEFT_J: @@ -187,7 +187,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * Frame high, one word length for frame sync, * frame sync asserts with the first bit of the frame. */ - val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr2 |= FSL_SAI_CR2_BCP; val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); break; case SND_SOC_DAIFMT_DSP_A: @@ -197,7 +197,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * that is, together with the last bit of the previous * data word. */ - val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr2 |= FSL_SAI_CR2_BCP; val_cr4 &= ~FSL_SAI_CR4_FSP; val_cr4 |= FSL_SAI_CR4_FSE; sai->is_dsp_mode = true; @@ -207,7 +207,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * Frame high, one bit for frame sync, * frame sync asserts with the first bit of the frame. */ - val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr2 |= FSL_SAI_CR2_BCP; val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); sai->is_dsp_mode = true; break; -- cgit v1.1 From 74ddd8c40d8ac747ec780be3da40b37641a9b396 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 4 Apr 2014 14:31:41 +0300 Subject: ASoC: davinci-mcasp: Fix bit clock polarity settings IB_NF, NB_IF and IB_IF configured the bc polarity incorrectly. The receive polarity was set to the same edge as the TX in these cases. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index a01ae97..4f75cac 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -336,7 +336,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); break; @@ -344,7 +344,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); + mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); break; @@ -352,7 +352,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); break; -- cgit v1.1