diff options
author | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2011-07-02 19:06:07 -0400 |
---|---|---|
committer | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2011-07-07 07:23:45 -0400 |
commit | 753621c2155bd49bff7d5d3844b3ddc203e44a06 (patch) | |
tree | de6e77bf22a784b5662a0ab1a19bb18c7b73c680 /sound | |
parent | f53c346c08425b6448cf9729e882e4057ea505f0 (diff) |
ASoC: twl6040: Configure PLL only once
Avoid configuring the PLL several times during audio startup.
We can configure the PLL at prepare time with parameters collected
earlier hw_param, and set_dai_sysclk calls.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-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 | ||