ASoC: cs42l52: Correct MIC CTL mask
[linux-drm-fsl-dcu.git] / sound / soc / sh / rcar / gen.c
1 /*
2  * Renesas R-Car Gen1 SRU/SSI support
3  *
4  * Copyright (C) 2013 Renesas Solutions Corp.
5  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include "rsnd.h"
12
13 struct rsnd_gen_ops {
14         int (*path_init)(struct rsnd_priv *priv,
15                          struct rsnd_dai *rdai,
16                          struct rsnd_dai_stream *io);
17         int (*path_exit)(struct rsnd_priv *priv,
18                          struct rsnd_dai *rdai,
19                          struct rsnd_dai_stream *io);
20 };
21
22 struct rsnd_gen_reg_map {
23         int index;      /* -1 : not supported */
24         u32 offset_id;  /* offset of ssi0, ssi1, ssi2... */
25         u32 offset_adr; /* offset of SSICR, SSISR, ... */
26 };
27
28 struct rsnd_gen {
29         void __iomem *base[RSND_BASE_MAX];
30
31         struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
32         struct rsnd_gen_ops *ops;
33 };
34
35 #define rsnd_priv_to_gen(p)     ((struct rsnd_gen *)(p)->gen)
36
37 /*
38  *              Gen2
39  *              will be filled in the future
40  */
41
42 /*
43  *              Gen1
44  */
45 static int rsnd_gen1_path_init(struct rsnd_priv *priv,
46                                struct rsnd_dai *rdai,
47                                struct rsnd_dai_stream *io)
48 {
49         struct rsnd_mod *mod;
50         int ret;
51         int id;
52
53         /*
54          * Gen1 is created by SRU/SSI, and this SRU is base module of
55          * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
56          *
57          * Easy image is..
58          *      Gen1 SRU = Gen2 SCU + SSIU + etc
59          *
60          * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
61          * using fixed path.
62          *
63          * Then, SSI id = SCU id here
64          */
65
66         /* get SSI's ID */
67         mod = rsnd_ssi_mod_get_frm_dai(priv,
68                                        rsnd_dai_id(priv, rdai),
69                                        rsnd_dai_is_play(rdai, io));
70         id = rsnd_mod_id(mod);
71
72         /* SSI */
73         mod = rsnd_ssi_mod_get(priv, id);
74         ret = rsnd_dai_connect(rdai, mod, io);
75         if (ret < 0)
76                 return ret;
77
78         /* SCU */
79         mod = rsnd_scu_mod_get(priv, id);
80         ret = rsnd_dai_connect(rdai, mod, io);
81
82         return ret;
83 }
84
85 static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
86                                struct rsnd_dai *rdai,
87                                struct rsnd_dai_stream *io)
88 {
89         struct rsnd_mod *mod, *n;
90         int ret = 0;
91
92         /*
93          * remove all mod from rdai
94          */
95         for_each_rsnd_mod(mod, n, io)
96                 ret |= rsnd_dai_disconnect(mod);
97
98         return ret;
99 }
100
101 static struct rsnd_gen_ops rsnd_gen1_ops = {
102         .path_init      = rsnd_gen1_path_init,
103         .path_exit      = rsnd_gen1_path_exit,
104 };
105
106 #define RSND_GEN1_REG_MAP(g, s, i, oi, oa)                              \
107         do {                                                            \
108                 (g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;      \
109                 (g)->reg_map[RSND_REG_##i].offset_id = oi;              \
110                 (g)->reg_map[RSND_REG_##i].offset_adr = oa;             \
111         } while (0)
112
113 static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
114 {
115         RSND_GEN1_REG_MAP(gen, SRU,     SRC_ROUTE_SEL,  0x0,    0x00);
116         RSND_GEN1_REG_MAP(gen, SRU,     SRC_TMG_SEL0,   0x0,    0x08);
117         RSND_GEN1_REG_MAP(gen, SRU,     SRC_TMG_SEL1,   0x0,    0x0c);
118         RSND_GEN1_REG_MAP(gen, SRU,     SRC_TMG_SEL2,   0x0,    0x10);
119         RSND_GEN1_REG_MAP(gen, SRU,     SRC_CTRL,       0x0,    0xc0);
120         RSND_GEN1_REG_MAP(gen, SRU,     SSI_MODE0,      0x0,    0xD0);
121         RSND_GEN1_REG_MAP(gen, SRU,     SSI_MODE1,      0x0,    0xD4);
122         RSND_GEN1_REG_MAP(gen, SRU,     BUSIF_MODE,     0x4,    0x20);
123         RSND_GEN1_REG_MAP(gen, SRU,     BUSIF_ADINR,    0x40,   0x214);
124
125         RSND_GEN1_REG_MAP(gen, ADG,     BRRA,           0x0,    0x00);
126         RSND_GEN1_REG_MAP(gen, ADG,     BRRB,           0x0,    0x04);
127         RSND_GEN1_REG_MAP(gen, ADG,     SSICKR,         0x0,    0x08);
128         RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL0, 0x0,    0x0c);
129         RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL1, 0x0,    0x10);
130         RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL3, 0x0,    0x18);
131         RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL4, 0x0,    0x1c);
132         RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL5, 0x0,    0x20);
133
134         RSND_GEN1_REG_MAP(gen, SSI,     SSICR,          0x40,   0x00);
135         RSND_GEN1_REG_MAP(gen, SSI,     SSISR,          0x40,   0x04);
136         RSND_GEN1_REG_MAP(gen, SSI,     SSITDR,         0x40,   0x08);
137         RSND_GEN1_REG_MAP(gen, SSI,     SSIRDR,         0x40,   0x0c);
138         RSND_GEN1_REG_MAP(gen, SSI,     SSIWSR,         0x40,   0x20);
139 }
140
141 static int rsnd_gen1_probe(struct platform_device *pdev,
142                            struct rcar_snd_info *info,
143                            struct rsnd_priv *priv)
144 {
145         struct device *dev = rsnd_priv_to_dev(priv);
146         struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
147         struct resource *sru_res;
148         struct resource *adg_res;
149         struct resource *ssi_res;
150
151         /*
152          * map address
153          */
154         sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
155         adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
156         ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
157
158         gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
159         gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
160         gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
161         if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
162             IS_ERR(gen->base[RSND_GEN1_ADG]) ||
163             IS_ERR(gen->base[RSND_GEN1_SSI]))
164                 return -ENODEV;
165
166         gen->ops = &rsnd_gen1_ops;
167         rsnd_gen1_reg_map_init(gen);
168
169         dev_dbg(dev, "Gen1 device probed\n");
170         dev_dbg(dev, "SRU : %08x => %p\n",      sru_res->start,
171                                                 gen->base[RSND_GEN1_SRU]);
172         dev_dbg(dev, "ADG : %08x => %p\n",      adg_res->start,
173                                                 gen->base[RSND_GEN1_ADG]);
174         dev_dbg(dev, "SSI : %08x => %p\n",      ssi_res->start,
175                                                 gen->base[RSND_GEN1_SSI]);
176
177         return 0;
178
179 }
180
181 static void rsnd_gen1_remove(struct platform_device *pdev,
182                              struct rsnd_priv *priv)
183 {
184 }
185
186 /*
187  *              Gen
188  */
189 int rsnd_gen_path_init(struct rsnd_priv *priv,
190                        struct rsnd_dai *rdai,
191                        struct rsnd_dai_stream *io)
192 {
193         struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
194
195         return gen->ops->path_init(priv, rdai, io);
196 }
197
198 int rsnd_gen_path_exit(struct rsnd_priv *priv,
199                        struct rsnd_dai *rdai,
200                        struct rsnd_dai_stream *io)
201 {
202         struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
203
204         return gen->ops->path_exit(priv, rdai, io);
205 }
206
207 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
208                                struct rsnd_mod *mod,
209                                enum rsnd_reg reg)
210 {
211         struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
212         struct device *dev = rsnd_priv_to_dev(priv);
213         int index;
214         u32 offset_id, offset_adr;
215
216         if (reg >= RSND_REG_MAX) {
217                 dev_err(dev, "rsnd_reg reg error\n");
218                 return NULL;
219         }
220
221         index           = gen->reg_map[reg].index;
222         offset_id       = gen->reg_map[reg].offset_id;
223         offset_adr      = gen->reg_map[reg].offset_adr;
224
225         if (index < 0) {
226                 dev_err(dev, "unsupported reg access %d\n", reg);
227                 return NULL;
228         }
229
230         if (offset_id && mod)
231                 offset_id *= rsnd_mod_id(mod);
232
233         /*
234          * index/offset were set on gen1/gen2
235          */
236
237         return gen->base[index] + offset_id + offset_adr;
238 }
239
240 int rsnd_gen_probe(struct platform_device *pdev,
241                    struct rcar_snd_info *info,
242                    struct rsnd_priv *priv)
243 {
244         struct device *dev = rsnd_priv_to_dev(priv);
245         struct rsnd_gen *gen;
246         int i;
247
248         gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
249         if (!gen) {
250                 dev_err(dev, "GEN allocate failed\n");
251                 return -ENOMEM;
252         }
253
254         priv->gen = gen;
255
256         /*
257          * see
258          *      rsnd_reg_get()
259          *      rsnd_gen_probe()
260          */
261         for (i = 0; i < RSND_REG_MAX; i++)
262                 gen->reg_map[i].index = -1;
263
264         /*
265          *      init each module
266          */
267         if (rsnd_is_gen1(priv))
268                 return rsnd_gen1_probe(pdev, info, priv);
269
270         dev_err(dev, "unknown generation R-Car sound device\n");
271
272         return -ENODEV;
273 }
274
275 void rsnd_gen_remove(struct platform_device *pdev,
276                      struct rsnd_priv *priv)
277 {
278         if (rsnd_is_gen1(priv))
279                 rsnd_gen1_remove(pdev, priv);
280 }