diff options
author | John Hsu <KCHSU0@nuvoton.com> | 2017-11-30 21:01:50 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-12-04 13:14:42 -0500 |
commit | 70424d8e6e15abd32e189130be220d0063e082bc (patch) | |
tree | aa415170b6f98fa07cac4810810c168600d27ca5 | |
parent | e3fee43a968fd39dcc56be3757fcdfe250964125 (diff) |
ASoC: nau8825: improve semaphore control
After reviewing the crosstalk protection, there are two flaws at
semaphore control. The first one is that the semaphore releases are
not enough; and the other is that down_interruptible has an risk to
make the ISR sleep.
Therefore, the driver add more releases before the funcitons return.
Take down_trylock to replace down_interruptible. The ISR can control
the protection as well and never sleep by semaphore.
Signed-off-by: John Hsu <KCHSU0@nuvoton.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/codecs/nau8825.c | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 603cd72c2a25..5778eadbf9e6 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c | |||
@@ -245,13 +245,14 @@ static const unsigned short logtable[256] = { | |||
245 | * tasks are allowed to acquire the semaphore, calling this function will | 245 | * tasks are allowed to acquire the semaphore, calling this function will |
246 | * put the task to sleep. If the semaphore is not released within the | 246 | * put the task to sleep. If the semaphore is not released within the |
247 | * specified number of jiffies, this function returns. | 247 | * specified number of jiffies, this function returns. |
248 | * Acquires the semaphore without jiffies. If no more tasks are allowed | ||
249 | * to acquire the semaphore, calling this function will put the task to | ||
250 | * sleep until the semaphore is released. | ||
251 | * If the semaphore is not released within the specified number of jiffies, | 248 | * If the semaphore is not released within the specified number of jiffies, |
252 | * this function returns -ETIME. | 249 | * this function returns -ETIME. If the sleep is interrupted by a signal, |
253 | * If the sleep is interrupted by a signal, this function will return -EINTR. | 250 | * this function will return -EINTR. It returns 0 if the semaphore was |
254 | * It returns 0 if the semaphore was acquired successfully. | 251 | * acquired successfully. |
252 | * | ||
253 | * Acquires the semaphore without jiffies. Try to acquire the semaphore | ||
254 | * atomically. Returns 0 if the semaphore has been acquired successfully | ||
255 | * or 1 if it it cannot be acquired. | ||
255 | */ | 256 | */ |
256 | static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) | 257 | static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) |
257 | { | 258 | { |
@@ -262,8 +263,8 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) | |||
262 | if (ret < 0) | 263 | if (ret < 0) |
263 | dev_warn(nau8825->dev, "Acquire semaphore timeout\n"); | 264 | dev_warn(nau8825->dev, "Acquire semaphore timeout\n"); |
264 | } else { | 265 | } else { |
265 | ret = down_interruptible(&nau8825->xtalk_sem); | 266 | ret = down_trylock(&nau8825->xtalk_sem); |
266 | if (ret < 0) | 267 | if (ret) |
267 | dev_warn(nau8825->dev, "Acquire semaphore fail\n"); | 268 | dev_warn(nau8825->dev, "Acquire semaphore fail\n"); |
268 | } | 269 | } |
269 | 270 | ||
@@ -1246,8 +1247,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, | |||
1246 | regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); | 1247 | regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); |
1247 | osr &= NAU8825_DAC_OVERSAMPLE_MASK; | 1248 | osr &= NAU8825_DAC_OVERSAMPLE_MASK; |
1248 | if (nau8825_clock_check(nau8825, substream->stream, | 1249 | if (nau8825_clock_check(nau8825, substream->stream, |
1249 | params_rate(params), osr)) | 1250 | params_rate(params), osr)) { |
1251 | nau8825_sema_release(nau8825); | ||
1250 | return -EINVAL; | 1252 | return -EINVAL; |
1253 | } | ||
1251 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, | 1254 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, |
1252 | NAU8825_CLK_DAC_SRC_MASK, | 1255 | NAU8825_CLK_DAC_SRC_MASK, |
1253 | osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); | 1256 | osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); |
@@ -1255,8 +1258,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, | |||
1255 | regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); | 1258 | regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); |
1256 | osr &= NAU8825_ADC_SYNC_DOWN_MASK; | 1259 | osr &= NAU8825_ADC_SYNC_DOWN_MASK; |
1257 | if (nau8825_clock_check(nau8825, substream->stream, | 1260 | if (nau8825_clock_check(nau8825, substream->stream, |
1258 | params_rate(params), osr)) | 1261 | params_rate(params), osr)) { |
1262 | nau8825_sema_release(nau8825); | ||
1259 | return -EINVAL; | 1263 | return -EINVAL; |
1264 | } | ||
1260 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, | 1265 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, |
1261 | NAU8825_CLK_ADC_SRC_MASK, | 1266 | NAU8825_CLK_ADC_SRC_MASK, |
1262 | osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); | 1267 | osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); |
@@ -1273,8 +1278,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, | |||
1273 | bclk_div = 1; | 1278 | bclk_div = 1; |
1274 | else if (bclk_fs <= 128) | 1279 | else if (bclk_fs <= 128) |
1275 | bclk_div = 0; | 1280 | bclk_div = 0; |
1276 | else | 1281 | else { |
1282 | nau8825_sema_release(nau8825); | ||
1277 | return -EINVAL; | 1283 | return -EINVAL; |
1284 | } | ||
1278 | regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, | 1285 | regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, |
1279 | NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK, | 1286 | NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK, |
1280 | ((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div); | 1287 | ((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div); |
@@ -1294,6 +1301,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, | |||
1294 | val_len |= NAU8825_I2S_DL_32; | 1301 | val_len |= NAU8825_I2S_DL_32; |
1295 | break; | 1302 | break; |
1296 | default: | 1303 | default: |
1304 | nau8825_sema_release(nau8825); | ||
1297 | return -EINVAL; | 1305 | return -EINVAL; |
1298 | } | 1306 | } |
1299 | 1307 | ||
@@ -1312,8 +1320,6 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1312 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); | 1320 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); |
1313 | unsigned int ctrl1_val = 0, ctrl2_val = 0; | 1321 | unsigned int ctrl1_val = 0, ctrl2_val = 0; |
1314 | 1322 | ||
1315 | nau8825_sema_acquire(nau8825, 3 * HZ); | ||
1316 | |||
1317 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1323 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
1318 | case SND_SOC_DAIFMT_CBM_CFM: | 1324 | case SND_SOC_DAIFMT_CBM_CFM: |
1319 | ctrl2_val |= NAU8825_I2S_MS_MASTER; | 1325 | ctrl2_val |= NAU8825_I2S_MS_MASTER; |
@@ -1355,6 +1361,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1355 | return -EINVAL; | 1361 | return -EINVAL; |
1356 | } | 1362 | } |
1357 | 1363 | ||
1364 | nau8825_sema_acquire(nau8825, 3 * HZ); | ||
1365 | |||
1358 | regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, | 1366 | regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, |
1359 | NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK | | 1367 | NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK | |
1360 | NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK, | 1368 | NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK, |
@@ -1701,7 +1709,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) | |||
1701 | int ret; | 1709 | int ret; |
1702 | nau8825->xtalk_protect = true; | 1710 | nau8825->xtalk_protect = true; |
1703 | ret = nau8825_sema_acquire(nau8825, 0); | 1711 | ret = nau8825_sema_acquire(nau8825, 0); |
1704 | if (ret < 0) | 1712 | if (ret) |
1705 | nau8825->xtalk_protect = false; | 1713 | nau8825->xtalk_protect = false; |
1706 | } | 1714 | } |
1707 | /* Startup cross talk detection process */ | 1715 | /* Startup cross talk detection process */ |
@@ -2383,7 +2391,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec) | |||
2383 | regcache_sync(nau8825->regmap); | 2391 | regcache_sync(nau8825->regmap); |
2384 | nau8825->xtalk_protect = true; | 2392 | nau8825->xtalk_protect = true; |
2385 | ret = nau8825_sema_acquire(nau8825, 0); | 2393 | ret = nau8825_sema_acquire(nau8825, 0); |
2386 | if (ret < 0) | 2394 | if (ret) |
2387 | nau8825->xtalk_protect = false; | 2395 | nau8825->xtalk_protect = false; |
2388 | enable_irq(nau8825->irq); | 2396 | enable_irq(nau8825->irq); |
2389 | 2397 | ||