diff options
Diffstat (limited to 'sound/soc/davinci/davinci-evm.c')
-rw-r--r-- | sound/soc/davinci/davinci-evm.c | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 70ff3772079f..621e9a997d4c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_data/edma.h> | 17 | #include <linux/platform_data/edma.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/of_platform.h> | 19 | #include <linux/of_platform.h> |
20 | #include <linux/clk.h> | ||
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
22 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
@@ -30,9 +31,34 @@ | |||
30 | #include "davinci-i2s.h" | 31 | #include "davinci-i2s.h" |
31 | 32 | ||
32 | struct snd_soc_card_drvdata_davinci { | 33 | struct snd_soc_card_drvdata_davinci { |
34 | struct clk *mclk; | ||
33 | unsigned sysclk; | 35 | unsigned sysclk; |
34 | }; | 36 | }; |
35 | 37 | ||
38 | static int evm_startup(struct snd_pcm_substream *substream) | ||
39 | { | ||
40 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
41 | struct snd_soc_card *soc_card = rtd->codec->card; | ||
42 | struct snd_soc_card_drvdata_davinci *drvdata = | ||
43 | snd_soc_card_get_drvdata(soc_card); | ||
44 | |||
45 | if (drvdata->mclk) | ||
46 | return clk_prepare_enable(drvdata->mclk); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static void evm_shutdown(struct snd_pcm_substream *substream) | ||
52 | { | ||
53 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
54 | struct snd_soc_card *soc_card = rtd->codec->card; | ||
55 | struct snd_soc_card_drvdata_davinci *drvdata = | ||
56 | snd_soc_card_get_drvdata(soc_card); | ||
57 | |||
58 | if (drvdata->mclk) | ||
59 | clk_disable_unprepare(drvdata->mclk); | ||
60 | } | ||
61 | |||
36 | static int evm_hw_params(struct snd_pcm_substream *substream, | 62 | static int evm_hw_params(struct snd_pcm_substream *substream, |
37 | struct snd_pcm_hw_params *params) | 63 | struct snd_pcm_hw_params *params) |
38 | { | 64 | { |
@@ -59,6 +85,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
59 | } | 85 | } |
60 | 86 | ||
61 | static struct snd_soc_ops evm_ops = { | 87 | static struct snd_soc_ops evm_ops = { |
88 | .startup = evm_startup, | ||
89 | .shutdown = evm_shutdown, | ||
62 | .hw_params = evm_hw_params, | 90 | .hw_params = evm_hw_params, |
63 | }; | 91 | }; |
64 | 92 | ||
@@ -348,6 +376,7 @@ static int davinci_evm_probe(struct platform_device *pdev) | |||
348 | of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); | 376 | of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); |
349 | struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; | 377 | struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; |
350 | struct snd_soc_card_drvdata_davinci *drvdata = NULL; | 378 | struct snd_soc_card_drvdata_davinci *drvdata = NULL; |
379 | struct clk *mclk; | ||
351 | int ret = 0; | 380 | int ret = 0; |
352 | 381 | ||
353 | evm_soc_card.dai_link = dai; | 382 | evm_soc_card.dai_link = dai; |
@@ -367,13 +396,38 @@ static int davinci_evm_probe(struct platform_device *pdev) | |||
367 | if (ret) | 396 | if (ret) |
368 | return ret; | 397 | return ret; |
369 | 398 | ||
399 | mclk = devm_clk_get(&pdev->dev, "mclk"); | ||
400 | if (PTR_ERR(mclk) == -EPROBE_DEFER) { | ||
401 | return -EPROBE_DEFER; | ||
402 | } else if (IS_ERR(mclk)) { | ||
403 | dev_dbg(&pdev->dev, "mclk not found.\n"); | ||
404 | mclk = NULL; | ||
405 | } | ||
406 | |||
370 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); | 407 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); |
371 | if (!drvdata) | 408 | if (!drvdata) |
372 | return -ENOMEM; | 409 | return -ENOMEM; |
373 | 410 | ||
411 | drvdata->mclk = mclk; | ||
412 | |||
374 | ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); | 413 | ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); |
375 | if (ret < 0) | 414 | |
376 | return -EINVAL; | 415 | if (ret < 0) { |
416 | if (!drvdata->mclk) { | ||
417 | dev_err(&pdev->dev, | ||
418 | "No clock or clock rate defined.\n"); | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | drvdata->sysclk = clk_get_rate(drvdata->mclk); | ||
422 | } else if (drvdata->mclk) { | ||
423 | unsigned int requestd_rate = drvdata->sysclk; | ||
424 | clk_set_rate(drvdata->mclk, drvdata->sysclk); | ||
425 | drvdata->sysclk = clk_get_rate(drvdata->mclk); | ||
426 | if (drvdata->sysclk != requestd_rate) | ||
427 | dev_warn(&pdev->dev, | ||
428 | "Could not get requested rate %u using %u.\n", | ||
429 | requestd_rate, drvdata->sysclk); | ||
430 | } | ||
377 | 431 | ||
378 | snd_soc_card_set_drvdata(&evm_soc_card, drvdata); | 432 | snd_soc_card_set_drvdata(&evm_soc_card, drvdata); |
379 | ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); | 433 | ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); |
@@ -399,6 +453,7 @@ static struct platform_driver davinci_evm_driver = { | |||
399 | .driver = { | 453 | .driver = { |
400 | .name = "davinci_evm", | 454 | .name = "davinci_evm", |
401 | .owner = THIS_MODULE, | 455 | .owner = THIS_MODULE, |
456 | .pm = &snd_soc_pm_ops, | ||
402 | .of_match_table = of_match_ptr(davinci_evm_dt_ids), | 457 | .of_match_table = of_match_ptr(davinci_evm_dt_ids), |
403 | }, | 458 | }, |
404 | }; | 459 | }; |