]> Pileus Git - ~andy/linux/blob - sound/soc/sh/rcar/adg.c
2e71a7bda4c250b32ff4371e99a5956d888c6eaf
[~andy/linux] / sound / soc / sh / rcar / adg.c
1 /*
2  * Helper routines for R-Car sound ADG.
3  *
4  *  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10 #include <linux/sh_clk.h>
11 #include "rsnd.h"
12
13 #define CLKA    0
14 #define CLKB    1
15 #define CLKC    2
16 #define CLKI    3
17 #define CLKMAX  4
18
19 struct rsnd_adg {
20         struct clk *clk[CLKMAX];
21
22         int rbga_rate_for_441khz_div_6; /* RBGA */
23         int rbgb_rate_for_48khz_div_6;  /* RBGB */
24         u32 ckr;
25 };
26
27 #define for_each_rsnd_clk(pos, adg, i)          \
28         for (i = 0, (pos) = adg->clk[i];        \
29              i < CLKMAX;                        \
30              i++, (pos) = adg->clk[i])
31 #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
32
33 static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
34 {
35         int id = rsnd_mod_id(mod);
36         int shift = (id % 4) * 8;
37         u32 mask = 0xFF << shift;
38
39         val = val << shift;
40
41         /*
42          * SSI 8 is not connected to ADG.
43          * it works with SSI 7
44          */
45         if (id == 8)
46                 return;
47
48         switch (id / 4) {
49         case 0:
50                 rsnd_mod_bset(mod, AUDIO_CLK_SEL0, mask, val);
51                 break;
52         case 1:
53                 rsnd_mod_bset(mod, AUDIO_CLK_SEL1, mask, val);
54                 break;
55         case 2:
56                 rsnd_mod_bset(mod, AUDIO_CLK_SEL2, mask, val);
57                 break;
58         }
59 }
60
61 int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
62 {
63         /*
64          * "mod" = "ssi" here.
65          * we can get "ssi id" from mod
66          */
67         rsnd_adg_set_ssi_clk(mod, 0);
68
69         return 0;
70 }
71
72 int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
73 {
74         struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
75         struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
76         struct device *dev = rsnd_priv_to_dev(priv);
77         struct clk *clk;
78         int i;
79         u32 data;
80         int sel_table[] = {
81                 [CLKA] = 0x1,
82                 [CLKB] = 0x2,
83                 [CLKC] = 0x3,
84                 [CLKI] = 0x0,
85         };
86
87         dev_dbg(dev, "request clock = %d\n", rate);
88
89         /*
90          * find suitable clock from
91          * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
92          */
93         data = 0;
94         for_each_rsnd_clk(clk, adg, i) {
95                 if (rate == clk_get_rate(clk)) {
96                         data = sel_table[i];
97                         goto found_clock;
98                 }
99         }
100
101         /*
102          * find 1/6 clock from BRGA/BRGB
103          */
104         if (rate == adg->rbga_rate_for_441khz_div_6) {
105                 data = 0x10;
106                 goto found_clock;
107         }
108
109         if (rate == adg->rbgb_rate_for_48khz_div_6) {
110                 data = 0x20;
111                 goto found_clock;
112         }
113
114         return -EIO;
115
116 found_clock:
117
118         /* see rsnd_adg_ssi_clk_init() */
119         rsnd_mod_bset(mod, SSICKR, 0x00FF0000, adg->ckr);
120         rsnd_mod_write(mod, BRRA,  0x00000002); /* 1/6 */
121         rsnd_mod_write(mod, BRRB,  0x00000002); /* 1/6 */
122
123         /*
124          * This "mod" = "ssi" here.
125          * we can get "ssi id" from mod
126          */
127         rsnd_adg_set_ssi_clk(mod, data);
128
129         dev_dbg(dev, "ADG: ssi%d selects clk%d = %d",
130                 rsnd_mod_id(mod), i, rate);
131
132         return 0;
133 }
134
135 static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
136 {
137         struct clk *clk;
138         unsigned long rate;
139         u32 ckr;
140         int i;
141         int brg_table[] = {
142                 [CLKA] = 0x0,
143                 [CLKB] = 0x1,
144                 [CLKC] = 0x4,
145                 [CLKI] = 0x2,
146         };
147
148         /*
149          * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
150          * have 44.1kHz or 48kHz base clocks for now.
151          *
152          * SSI itself can divide parent clock by 1/1 - 1/16
153          * So,  BRGA outputs 44.1kHz base parent clock 1/32,
154          * and, BRGB outputs 48.0kHz base parent clock 1/32 here.
155          * see
156          *      rsnd_adg_ssi_clk_try_start()
157          */
158         ckr = 0;
159         adg->rbga_rate_for_441khz_div_6 = 0;
160         adg->rbgb_rate_for_48khz_div_6  = 0;
161         for_each_rsnd_clk(clk, adg, i) {
162                 rate = clk_get_rate(clk);
163
164                 if (0 == rate) /* not used */
165                         continue;
166
167                 /* RBGA */
168                 if (!adg->rbga_rate_for_441khz_div_6 && (0 == rate % 44100)) {
169                         adg->rbga_rate_for_441khz_div_6 = rate / 6;
170                         ckr |= brg_table[i] << 20;
171                 }
172
173                 /* RBGB */
174                 if (!adg->rbgb_rate_for_48khz_div_6 && (0 == rate % 48000)) {
175                         adg->rbgb_rate_for_48khz_div_6 = rate / 6;
176                         ckr |= brg_table[i] << 16;
177                 }
178         }
179
180         adg->ckr = ckr;
181 }
182
183 int rsnd_adg_probe(struct platform_device *pdev,
184                    struct rcar_snd_info *info,
185                    struct rsnd_priv *priv)
186 {
187         struct rsnd_adg *adg;
188         struct device *dev = rsnd_priv_to_dev(priv);
189         struct clk *clk;
190         int i;
191
192         adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
193         if (!adg) {
194                 dev_err(dev, "ADG allocate failed\n");
195                 return -ENOMEM;
196         }
197
198         adg->clk[CLKA] = clk_get(NULL, "audio_clk_a");
199         adg->clk[CLKB] = clk_get(NULL, "audio_clk_b");
200         adg->clk[CLKC] = clk_get(NULL, "audio_clk_c");
201         adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal");
202         for_each_rsnd_clk(clk, adg, i) {
203                 if (IS_ERR(clk)) {
204                         dev_err(dev, "Audio clock failed\n");
205                         return -EIO;
206                 }
207         }
208
209         rsnd_adg_ssi_clk_init(priv, adg);
210
211         priv->adg = adg;
212
213         dev_dbg(dev, "adg probed\n");
214
215         return 0;
216 }
217
218 void rsnd_adg_remove(struct platform_device *pdev,
219                      struct rsnd_priv *priv)
220 {
221         struct rsnd_adg *adg = priv->adg;
222         struct clk *clk;
223         int i;
224
225         for_each_rsnd_clk(clk, adg, i)
226                 clk_put(clk);
227 }