diff options
| -rw-r--r-- | sound/soc/codecs/twl6040.c | 72 |
1 files changed, 27 insertions, 45 deletions
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index c72268bf663a..bd364c3a97c8 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
| @@ -1343,9 +1343,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
| 1343 | break; | 1343 | break; |
| 1344 | } | 1344 | } |
| 1345 | 1345 | ||
| 1346 | /* get PLL and sysclk after power transition */ | ||
| 1347 | priv->pll = twl6040_get_pll(twl6040); | ||
| 1348 | priv->sysclk = twl6040_get_sysclk(twl6040); | ||
| 1349 | codec->dapm.bias_level = level; | 1346 | codec->dapm.bias_level = level; |
| 1350 | 1347 | ||
| 1351 | return 0; | 1348 | return 0; |
| @@ -1371,14 +1368,8 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream, | |||
| 1371 | { | 1368 | { |
| 1372 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1369 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 1373 | struct snd_soc_codec *codec = rtd->codec; | 1370 | struct snd_soc_codec *codec = rtd->codec; |
| 1374 | struct twl6040 *twl6040 = codec->control_data; | ||
| 1375 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 1371 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
| 1376 | unsigned int sysclk; | 1372 | int rate; |
| 1377 | int rate, ret; | ||
| 1378 | |||
| 1379 | /* nothing to do for high-perf pll, it supports only 48 kHz */ | ||
| 1380 | if (priv->pll == TWL6040_HPPLL_ID) | ||
| 1381 | return 0; | ||
| 1382 | 1373 | ||
| 1383 | rate = params_rate(params); | 1374 | rate = params_rate(params); |
| 1384 | switch (rate) { | 1375 | switch (rate) { |
| @@ -1386,26 +1377,33 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream, | |||
| 1386 | case 22500: | 1377 | case 22500: |
| 1387 | case 44100: | 1378 | case 44100: |
| 1388 | case 88200: | 1379 | case 88200: |
| 1389 | sysclk = 17640000; | 1380 | /* These rates are not supported when HPPLL is in use */ |
| 1381 | if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) { | ||
| 1382 | dev_err(codec->dev, "HPPLL does not support rate %d\n", | ||
| 1383 | rate); | ||
| 1384 | return -EINVAL; | ||
| 1385 | } | ||
| 1386 | /* Capture is not supported with 17.64MHz sysclk */ | ||
| 1387 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
| 1388 | dev_err(codec->dev, | ||
| 1389 | "capture mode is not supported at %dHz\n", | ||
| 1390 | rate); | ||
| 1391 | return -EINVAL; | ||
| 1392 | } | ||
| 1393 | priv->sysclk = 17640000; | ||
| 1390 | break; | 1394 | break; |
| 1391 | case 8000: | 1395 | case 8000: |
| 1392 | case 16000: | 1396 | case 16000: |
| 1393 | case 32000: | 1397 | case 32000: |
| 1394 | case 48000: | 1398 | case 48000: |
| 1395 | case 96000: | 1399 | case 96000: |
| 1396 | sysclk = 19200000; | 1400 | priv->sysclk = 19200000; |
| 1397 | break; | 1401 | break; |
| 1398 | default: | 1402 | default: |
| 1399 | dev_err(codec->dev, "unsupported rate %d\n", rate); | 1403 | dev_err(codec->dev, "unsupported rate %d\n", rate); |
| 1400 | return -EINVAL; | 1404 | return -EINVAL; |
| 1401 | } | 1405 | } |
| 1402 | 1406 | ||
| 1403 | ret = twl6040_set_pll(twl6040, TWL6040_LPPLL_ID, priv->clk_in, sysclk); | ||
| 1404 | if (ret) | ||
| 1405 | return ret; | ||
| 1406 | |||
| 1407 | priv->sysclk = twl6040_get_sysclk(twl6040); | ||
| 1408 | |||
| 1409 | return 0; | 1407 | return 0; |
| 1410 | } | 1408 | } |
| 1411 | 1409 | ||
| @@ -1414,7 +1412,9 @@ static int twl6040_prepare(struct snd_pcm_substream *substream, | |||
| 1414 | { | 1412 | { |
| 1415 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1413 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 1416 | struct snd_soc_codec *codec = rtd->codec; | 1414 | struct snd_soc_codec *codec = rtd->codec; |
| 1415 | struct twl6040 *twl6040 = codec->control_data; | ||
| 1417 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 1416 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
| 1417 | int ret; | ||
| 1418 | 1418 | ||
| 1419 | if (!priv->sysclk) { | 1419 | if (!priv->sysclk) { |
| 1420 | dev_err(codec->dev, | 1420 | dev_err(codec->dev, |
| @@ -1422,24 +1422,19 @@ static int twl6040_prepare(struct snd_pcm_substream *substream, | |||
| 1422 | return -EINVAL; | 1422 | return -EINVAL; |
| 1423 | } | 1423 | } |
| 1424 | 1424 | ||
| 1425 | /* | ||
| 1426 | * capture is not supported at 17.64 MHz, | ||
| 1427 | * it's reserved for headset low-power playback scenario | ||
| 1428 | */ | ||
| 1429 | if ((priv->sysclk == 17640000) && | ||
| 1430 | substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
| 1431 | dev_err(codec->dev, | ||
| 1432 | "capture mode is not supported at %dHz\n", | ||
| 1433 | priv->sysclk); | ||
| 1434 | return -EINVAL; | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | if ((priv->sysclk == 17640000) && priv->non_lp) { | 1425 | if ((priv->sysclk == 17640000) && priv->non_lp) { |
| 1438 | dev_err(codec->dev, | 1426 | dev_err(codec->dev, |
| 1439 | "some enabled paths aren't supported at %dHz\n", | 1427 | "some enabled paths aren't supported at %dHz\n", |
| 1440 | priv->sysclk); | 1428 | priv->sysclk); |
| 1441 | return -EPERM; | 1429 | return -EPERM; |
| 1442 | } | 1430 | } |
| 1431 | |||
| 1432 | ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk); | ||
| 1433 | if (ret) { | ||
| 1434 | dev_err(codec->dev, "Can not set PLL (%d)\n", ret); | ||
| 1435 | return -EPERM; | ||
| 1436 | } | ||
| 1437 | |||
| 1443 | return 0; | 1438 | return 0; |
| 1444 | } | 1439 | } |
| 1445 | 1440 | ||
| @@ -1447,32 +1442,19 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
| 1447 | int clk_id, unsigned int freq, int dir) | 1442 | int clk_id, unsigned int freq, int dir) |
| 1448 | { | 1443 | { |
| 1449 | struct snd_soc_codec *codec = codec_dai->codec; | 1444 | struct snd_soc_codec *codec = codec_dai->codec; |
| 1450 | struct twl6040 *twl6040 = codec->control_data; | ||
| 1451 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 1445 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
| 1452 | int ret = 0; | ||
| 1453 | 1446 | ||
| 1454 | switch (clk_id) { | 1447 | switch (clk_id) { |
| 1455 | case TWL6040_SYSCLK_SEL_LPPLL: | 1448 | case TWL6040_SYSCLK_SEL_LPPLL: |
| 1456 | ret = twl6040_set_pll(twl6040, TWL6040_LPPLL_ID, | ||
| 1457 | freq, priv->sysclk); | ||
| 1458 | if (ret) | ||
| 1459 | return ret; | ||
| 1460 | break; | ||
| 1461 | case TWL6040_SYSCLK_SEL_HPPLL: | 1449 | case TWL6040_SYSCLK_SEL_HPPLL: |
| 1462 | ret = twl6040_set_pll(twl6040, TWL6040_HPPLL_ID, | 1450 | priv->pll = clk_id; |
| 1463 | freq, priv->sysclk); | 1451 | priv->clk_in = freq; |
| 1464 | if (ret) | ||
| 1465 | return ret; | ||
| 1466 | break; | 1452 | break; |
| 1467 | default: | 1453 | default: |
| 1468 | dev_err(codec->dev, "unknown clk_id %d\n", clk_id); | 1454 | dev_err(codec->dev, "unknown clk_id %d\n", clk_id); |
| 1469 | return -EINVAL; | 1455 | return -EINVAL; |
| 1470 | } | 1456 | } |
| 1471 | 1457 | ||
| 1472 | priv->pll = twl6040_get_pll(twl6040); | ||
| 1473 | priv->clk_in = freq; | ||
| 1474 | priv->sysclk = twl6040_get_sysclk(twl6040); | ||
| 1475 | |||
| 1476 | return 0; | 1458 | return 0; |
| 1477 | } | 1459 | } |
| 1478 | 1460 | ||
