Commit | Line | Data |
---|---|---|
d683d0b6 KMD |
1 | /* |
2 | * arndale_rt5631.c | |
3 | * | |
4 | * Copyright (c) 2014, Insignal Co., Ltd. | |
5 | * | |
6 | * Author: Claude <claude@insginal.co.kr> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2 of the License, or (at your | |
11 | * option) any later version. | |
12 | */ | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/clk.h> | |
17 | ||
18 | #include <sound/soc.h> | |
19 | #include <sound/soc-dapm.h> | |
20 | #include <sound/pcm.h> | |
21 | #include <sound/pcm_params.h> | |
22 | ||
23 | #include "i2s.h" | |
24 | ||
25 | static int arndale_hw_params(struct snd_pcm_substream *substream, | |
26 | struct snd_pcm_hw_params *params) | |
27 | { | |
28 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
29 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | |
30 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | |
31 | int rfs, ret; | |
32 | unsigned long rclk; | |
33 | ||
34 | rfs = 256; | |
35 | ||
36 | rclk = params_rate(params) * rfs; | |
37 | ||
38 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, | |
39 | 0, SND_SOC_CLOCK_OUT); | |
40 | if (ret < 0) | |
41 | return ret; | |
42 | ||
43 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, | |
44 | 0, SND_SOC_CLOCK_OUT); | |
45 | ||
46 | if (ret < 0) | |
47 | return ret; | |
48 | ||
49 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT); | |
50 | if (ret < 0) | |
51 | return ret; | |
52 | ||
53 | return 0; | |
54 | } | |
55 | ||
56 | static struct snd_soc_ops arndale_ops = { | |
57 | .hw_params = arndale_hw_params, | |
58 | }; | |
59 | ||
60 | static struct snd_soc_dai_link arndale_rt5631_dai[] = { | |
61 | { | |
62 | .name = "RT5631 HiFi", | |
63 | .stream_name = "Primary", | |
64 | .codec_dai_name = "rt5631-hifi", | |
65 | .dai_fmt = SND_SOC_DAIFMT_I2S | |
66 | | SND_SOC_DAIFMT_NB_NF | |
67 | | SND_SOC_DAIFMT_CBS_CFS, | |
68 | .ops = &arndale_ops, | |
69 | }, | |
70 | }; | |
71 | ||
72 | static struct snd_soc_card arndale_rt5631 = { | |
73 | .name = "Arndale RT5631", | |
74 | .dai_link = arndale_rt5631_dai, | |
75 | .num_links = ARRAY_SIZE(arndale_rt5631_dai), | |
76 | }; | |
77 | ||
78 | static int arndale_audio_probe(struct platform_device *pdev) | |
79 | { | |
80 | int n, ret; | |
81 | struct device_node *np = pdev->dev.of_node; | |
82 | struct snd_soc_card *card = &arndale_rt5631; | |
83 | ||
84 | card->dev = &pdev->dev; | |
85 | ||
86 | for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) { | |
87 | if (!arndale_rt5631_dai[n].cpu_dai_name) { | |
88 | arndale_rt5631_dai[n].cpu_of_node = of_parse_phandle(np, | |
89 | "samsung,audio-cpu", n); | |
90 | ||
91 | if (!arndale_rt5631_dai[n].cpu_of_node) { | |
92 | dev_err(&pdev->dev, | |
93 | "Property 'samsung,audio-cpu' missing or invalid\n"); | |
94 | return -EINVAL; | |
95 | } | |
96 | } | |
97 | if (!arndale_rt5631_dai[n].platform_name) | |
98 | arndale_rt5631_dai[n].platform_of_node = | |
99 | arndale_rt5631_dai[n].cpu_of_node; | |
100 | ||
101 | arndale_rt5631_dai[n].codec_name = NULL; | |
102 | arndale_rt5631_dai[n].codec_of_node = of_parse_phandle(np, | |
103 | "samsung,audio-codec", n); | |
104 | if (!arndale_rt5631_dai[0].codec_of_node) { | |
105 | dev_err(&pdev->dev, | |
106 | "Property 'samsung,audio-codec' missing or invalid\n"); | |
107 | return -EINVAL; | |
108 | } | |
109 | } | |
110 | ||
111 | ret = devm_snd_soc_register_card(card->dev, card); | |
112 | ||
113 | if (ret) | |
114 | dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); | |
115 | ||
116 | return ret; | |
117 | } | |
118 | ||
119 | static int arndale_audio_remove(struct platform_device *pdev) | |
120 | { | |
121 | struct snd_soc_card *card = platform_get_drvdata(pdev); | |
122 | ||
123 | snd_soc_unregister_card(card); | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = { | |
129 | { .compatible = "samsung,arndale-rt5631", }, | |
130 | { .compatible = "samsung,arndale-alc5631", }, | |
131 | {}, | |
132 | }; | |
133 | MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); | |
134 | ||
135 | static struct platform_driver arndale_audio_driver = { | |
136 | .driver = { | |
137 | .name = "arndale-audio", | |
138 | .owner = THIS_MODULE, | |
139 | .pm = &snd_soc_pm_ops, | |
140 | .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), | |
141 | }, | |
142 | .probe = arndale_audio_probe, | |
143 | .remove = arndale_audio_remove, | |
144 | }; | |
145 | ||
146 | module_platform_driver(arndale_audio_driver); | |
147 | ||
148 | MODULE_AUTHOR("Claude <claude@insignal.co.kr>"); | |
149 | MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board"); | |
150 | MODULE_LICENSE("GPL"); |