Merge branch 'for-2.6.38' into for-2.6.39
[cascardo/linux.git] / sound / soc / tegra / tegra_asoc_utils.c
1 /*
2  * tegra_asoc_utils.c - Harmony machine ASoC driver
3  *
4  * Author: Stephen Warren <swarren@nvidia.com>
5  * Copyright (C) 2010 - NVIDIA, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  *
21  */
22
23 #include <linux/clk.h>
24 #include <linux/err.h>
25 #include <linux/kernel.h>
26
27 #include "tegra_asoc_utils.h"
28
29 #define PREFIX "ASoC Tegra: "
30
31 static struct clk *clk_pll_a;
32 static struct clk *clk_pll_a_out0;
33 static struct clk *clk_cdev1;
34
35 static int set_baseclock, set_mclk;
36
37 int tegra_asoc_utils_set_rate(int srate, int mclk, int *mclk_change)
38 {
39         int new_baseclock;
40         int err;
41
42         switch (srate) {
43         case 11025:
44         case 22050:
45         case 44100:
46         case 88200:
47                 new_baseclock = 56448000;
48                 break;
49         case 8000:
50         case 16000:
51         case 32000:
52         case 48000:
53         case 64000:
54         case 96000:
55                 new_baseclock = 73728000;
56                 break;
57         default:
58                 return -EINVAL;
59         }
60
61         *mclk_change = ((new_baseclock != set_baseclock) ||
62                         (mclk != set_mclk));
63         if (!*mclk_change)
64             return 0;
65
66         set_baseclock = 0;
67         set_mclk = 0;
68
69         clk_disable(clk_cdev1);
70         clk_disable(clk_pll_a_out0);
71         clk_disable(clk_pll_a);
72
73         err = clk_set_rate(clk_pll_a, new_baseclock);
74         if (err) {
75                 pr_err(PREFIX "Can't set pll_a rate: %d\n", err);
76                 return err;
77         }
78
79         err = clk_set_rate(clk_pll_a_out0, mclk);
80         if (err) {
81                 pr_err(PREFIX "Can't set pll_a_out0 rate: %d\n", err);
82                 return err;
83         }
84
85         /* Don't set cdev1 rate; its locked to pll_a_out0 */
86
87         err = clk_enable(clk_pll_a);
88         if (err) {
89                 pr_err(PREFIX "Can't enable pll_a: %d\n", err);
90                 return err;
91         }
92
93         err = clk_enable(clk_pll_a_out0);
94         if (err) {
95                 pr_err(PREFIX "Can't enable pll_a_out0: %d\n", err);
96                 return err;
97         }
98
99         err = clk_enable(clk_cdev1);
100         if (err) {
101                 pr_err(PREFIX "Can't enable cdev1: %d\n", err);
102                 return err;
103         }
104
105         set_baseclock = new_baseclock;
106         set_mclk = mclk;
107
108         return 0;
109 }
110
111 int tegra_asoc_utils_init(void)
112 {
113         int ret;
114
115         clk_pll_a = clk_get_sys(NULL, "pll_a");
116         if (IS_ERR(clk_pll_a)) {
117                 pr_err(PREFIX "Can't retrieve clk pll_a\n");
118                 ret = PTR_ERR(clk_pll_a);
119                 goto err;
120         }
121
122         clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
123         if (IS_ERR(clk_pll_a_out0)) {
124                 pr_err(PREFIX "Can't retrieve clk pll_a_out0\n");
125                 ret = PTR_ERR(clk_pll_a_out0);
126                 goto err_put_pll_a;
127         }
128
129         clk_cdev1 = clk_get_sys(NULL, "cdev1");
130         if (IS_ERR(clk_cdev1)) {
131                 pr_err(PREFIX "Can't retrieve clk cdev1\n");
132                 ret = PTR_ERR(clk_cdev1);
133                 goto err_put_pll_a_out0;
134         }
135
136         return 0;
137
138 err_put_pll_a_out0:
139         clk_put(clk_pll_a_out0);
140 err_put_pll_a:
141         clk_put(clk_pll_a);
142 err:
143         return ret;
144 }
145
146 void tegra_asoc_utils_fini(void)
147 {
148         clk_put(clk_cdev1);
149         clk_put(clk_pll_a_out0);
150         clk_put(clk_pll_a);
151 }
152