]> asedeno.scripts.mit.edu Git - linux.git/blob - sound/soc/tegra/tegra_asoc_utils.c
Merge tag 'drm-misc-fixes-2019-12-31' of git://anongit.freedesktop.org/drm/drm-misc...
[linux.git] / sound / soc / tegra / tegra_asoc_utils.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * tegra_asoc_utils.c - Harmony machine ASoC driver
4  *
5  * Author: Stephen Warren <swarren@nvidia.com>
6  * Copyright (C) 2010,2012 - NVIDIA, Inc.
7  */
8
9 #include <linux/clk.h>
10 #include <linux/device.h>
11 #include <linux/err.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15
16 #include "tegra_asoc_utils.h"
17
18 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
19                               int mclk)
20 {
21         int new_baseclock;
22         bool clk_change;
23         int err;
24
25         switch (srate) {
26         case 11025:
27         case 22050:
28         case 44100:
29         case 88200:
30                 if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
31                         new_baseclock = 56448000;
32                 else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
33                         new_baseclock = 564480000;
34                 else
35                         new_baseclock = 282240000;
36                 break;
37         case 8000:
38         case 16000:
39         case 32000:
40         case 48000:
41         case 64000:
42         case 96000:
43                 if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
44                         new_baseclock = 73728000;
45                 else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
46                         new_baseclock = 552960000;
47                 else
48                         new_baseclock = 368640000;
49                 break;
50         default:
51                 return -EINVAL;
52         }
53
54         clk_change = ((new_baseclock != data->set_baseclock) ||
55                         (mclk != data->set_mclk));
56         if (!clk_change)
57                 return 0;
58
59         data->set_baseclock = 0;
60         data->set_mclk = 0;
61
62         clk_disable_unprepare(data->clk_cdev1);
63         clk_disable_unprepare(data->clk_pll_a_out0);
64         clk_disable_unprepare(data->clk_pll_a);
65
66         err = clk_set_rate(data->clk_pll_a, new_baseclock);
67         if (err) {
68                 dev_err(data->dev, "Can't set pll_a rate: %d\n", err);
69                 return err;
70         }
71
72         err = clk_set_rate(data->clk_pll_a_out0, mclk);
73         if (err) {
74                 dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err);
75                 return err;
76         }
77
78         /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
79
80         err = clk_prepare_enable(data->clk_pll_a);
81         if (err) {
82                 dev_err(data->dev, "Can't enable pll_a: %d\n", err);
83                 return err;
84         }
85
86         err = clk_prepare_enable(data->clk_pll_a_out0);
87         if (err) {
88                 dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
89                 return err;
90         }
91
92         err = clk_prepare_enable(data->clk_cdev1);
93         if (err) {
94                 dev_err(data->dev, "Can't enable cdev1: %d\n", err);
95                 return err;
96         }
97
98         data->set_baseclock = new_baseclock;
99         data->set_mclk = mclk;
100
101         return 0;
102 }
103 EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate);
104
105 int tegra_asoc_utils_set_ac97_rate(struct tegra_asoc_utils_data *data)
106 {
107         const int pll_rate = 73728000;
108         const int ac97_rate = 24576000;
109         int err;
110
111         clk_disable_unprepare(data->clk_cdev1);
112         clk_disable_unprepare(data->clk_pll_a_out0);
113         clk_disable_unprepare(data->clk_pll_a);
114
115         /*
116          * AC97 rate is fixed at 24.576MHz and is used for both the host
117          * controller and the external codec
118          */
119         err = clk_set_rate(data->clk_pll_a, pll_rate);
120         if (err) {
121                 dev_err(data->dev, "Can't set pll_a rate: %d\n", err);
122                 return err;
123         }
124
125         err = clk_set_rate(data->clk_pll_a_out0, ac97_rate);
126         if (err) {
127                 dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err);
128                 return err;
129         }
130
131         /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
132
133         err = clk_prepare_enable(data->clk_pll_a);
134         if (err) {
135                 dev_err(data->dev, "Can't enable pll_a: %d\n", err);
136                 return err;
137         }
138
139         err = clk_prepare_enable(data->clk_pll_a_out0);
140         if (err) {
141                 dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
142                 return err;
143         }
144
145         err = clk_prepare_enable(data->clk_cdev1);
146         if (err) {
147                 dev_err(data->dev, "Can't enable cdev1: %d\n", err);
148                 return err;
149         }
150
151         data->set_baseclock = pll_rate;
152         data->set_mclk = ac97_rate;
153
154         return 0;
155 }
156 EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_ac97_rate);
157
158 int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
159                           struct device *dev)
160 {
161         int ret;
162
163         data->dev = dev;
164
165         if (of_machine_is_compatible("nvidia,tegra20"))
166                 data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
167         else if (of_machine_is_compatible("nvidia,tegra30"))
168                 data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
169         else if (of_machine_is_compatible("nvidia,tegra114"))
170                 data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114;
171         else if (of_machine_is_compatible("nvidia,tegra124"))
172                 data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA124;
173         else {
174                 dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n");
175                 return -EINVAL;
176         }
177
178         data->clk_pll_a = clk_get(dev, "pll_a");
179         if (IS_ERR(data->clk_pll_a)) {
180                 dev_err(data->dev, "Can't retrieve clk pll_a\n");
181                 ret = PTR_ERR(data->clk_pll_a);
182                 goto err;
183         }
184
185         data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
186         if (IS_ERR(data->clk_pll_a_out0)) {
187                 dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
188                 ret = PTR_ERR(data->clk_pll_a_out0);
189                 goto err_put_pll_a;
190         }
191
192         data->clk_cdev1 = clk_get(dev, "mclk");
193         if (IS_ERR(data->clk_cdev1)) {
194                 dev_err(data->dev, "Can't retrieve clk cdev1\n");
195                 ret = PTR_ERR(data->clk_cdev1);
196                 goto err_put_pll_a_out0;
197         }
198
199         ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
200         if (ret)
201                 goto err_put_cdev1;
202
203         return 0;
204
205 err_put_cdev1:
206         clk_put(data->clk_cdev1);
207 err_put_pll_a_out0:
208         clk_put(data->clk_pll_a_out0);
209 err_put_pll_a:
210         clk_put(data->clk_pll_a);
211 err:
212         return ret;
213 }
214 EXPORT_SYMBOL_GPL(tegra_asoc_utils_init);
215
216 void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data)
217 {
218         clk_put(data->clk_cdev1);
219         clk_put(data->clk_pll_a_out0);
220         clk_put(data->clk_pll_a);
221 }
222 EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini);
223
224 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
225 MODULE_DESCRIPTION("Tegra ASoC utility code");
226 MODULE_LICENSE("GPL");