Commit | Line | Data |
---|---|---|
3337744a KM |
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 | ||
3337744a KM |
13 | struct rsnd_gen { |
14 | void __iomem *base[RSND_BASE_MAX]; | |
15 | ||
3337744a | 16 | struct rsnd_gen_ops *ops; |
55e5b6fd KM |
17 | |
18 | struct regmap *regmap; | |
19 | struct regmap_field *regs[RSND_REG_MAX]; | |
3337744a KM |
20 | }; |
21 | ||
22 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) | |
23 | ||
55e5b6fd KM |
24 | #define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size) \ |
25 | [id] = { \ | |
26 | .reg = (unsigned int)gen->base[reg_id] + offset, \ | |
27 | .lsb = 0, \ | |
28 | .msb = 31, \ | |
29 | .id_size = _id_size, \ | |
30 | .id_offset = _id_offset, \ | |
31 | } | |
32 | ||
33 | /* | |
34 | * basic function | |
35 | */ | |
36 | static int rsnd_regmap_write32(void *context, const void *_data, size_t count) | |
37 | { | |
38 | struct rsnd_priv *priv = context; | |
39 | struct device *dev = rsnd_priv_to_dev(priv); | |
40 | u32 *data = (u32 *)_data; | |
41 | u32 val = data[1]; | |
42 | void __iomem *reg = (void *)data[0]; | |
43 | ||
44 | iowrite32(val, reg); | |
45 | ||
46 | dev_dbg(dev, "w %p : %08x\n", reg, val); | |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | static int rsnd_regmap_read32(void *context, | |
52 | const void *_data, size_t reg_size, | |
53 | void *_val, size_t val_size) | |
54 | { | |
55 | struct rsnd_priv *priv = context; | |
56 | struct device *dev = rsnd_priv_to_dev(priv); | |
57 | u32 *data = (u32 *)_data; | |
58 | u32 *val = (u32 *)_val; | |
59 | void __iomem *reg = (void *)data[0]; | |
60 | ||
61 | *val = ioread32(reg); | |
62 | ||
63 | dev_dbg(dev, "r %p : %08x\n", reg, *val); | |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
68 | static struct regmap_bus rsnd_regmap_bus = { | |
69 | .write = rsnd_regmap_write32, | |
70 | .read = rsnd_regmap_read32, | |
71 | .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, | |
72 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | |
73 | }; | |
74 | ||
42ee5d22 KM |
75 | static int rsnd_is_accessible_reg(struct rsnd_priv *priv, |
76 | struct rsnd_gen *gen, enum rsnd_reg reg) | |
77 | { | |
78 | if (!gen->regs[reg]) { | |
79 | struct device *dev = rsnd_priv_to_dev(priv); | |
80 | ||
81 | dev_err(dev, "unsupported register access %x\n", reg); | |
82 | return 0; | |
83 | } | |
84 | ||
85 | return 1; | |
86 | } | |
87 | ||
55e5b6fd KM |
88 | u32 rsnd_read(struct rsnd_priv *priv, |
89 | struct rsnd_mod *mod, enum rsnd_reg reg) | |
90 | { | |
91 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | |
92 | u32 val; | |
93 | ||
42ee5d22 KM |
94 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
95 | return 0; | |
96 | ||
55e5b6fd KM |
97 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); |
98 | ||
99 | return val; | |
100 | } | |
101 | ||
102 | void rsnd_write(struct rsnd_priv *priv, | |
103 | struct rsnd_mod *mod, | |
104 | enum rsnd_reg reg, u32 data) | |
105 | { | |
106 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | |
107 | ||
42ee5d22 KM |
108 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
109 | return; | |
110 | ||
55e5b6fd KM |
111 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); |
112 | } | |
113 | ||
114 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | |
115 | enum rsnd_reg reg, u32 mask, u32 data) | |
116 | { | |
117 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | |
118 | ||
42ee5d22 KM |
119 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
120 | return; | |
121 | ||
55e5b6fd KM |
122 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), |
123 | mask, data); | |
124 | } | |
125 | ||
c1e6cc5e KM |
126 | static int rsnd_gen_regmap_init(struct rsnd_priv *priv, |
127 | struct rsnd_gen *gen, | |
128 | struct reg_field *regf) | |
129 | { | |
130 | int i; | |
131 | struct device *dev = rsnd_priv_to_dev(priv); | |
132 | struct regmap_config regc; | |
133 | ||
134 | memset(®c, 0, sizeof(regc)); | |
135 | regc.reg_bits = 32; | |
136 | regc.val_bits = 32; | |
137 | ||
138 | gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); | |
139 | if (IS_ERR(gen->regmap)) { | |
140 | dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); | |
141 | return PTR_ERR(gen->regmap); | |
142 | } | |
143 | ||
144 | for (i = 0; i < RSND_REG_MAX; i++) { | |
42ee5d22 KM |
145 | gen->regs[i] = NULL; |
146 | if (!regf[i].reg) | |
147 | continue; | |
148 | ||
c1e6cc5e KM |
149 | gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); |
150 | if (IS_ERR(gen->regs[i])) | |
151 | return PTR_ERR(gen->regs[i]); | |
152 | ||
153 | } | |
154 | ||
155 | return 0; | |
156 | } | |
3337744a | 157 | |
ad32d0c7 KM |
158 | /* |
159 | * DMA read/write register offset | |
160 | * | |
161 | * RSND_xxx_I_N for Audio DMAC input | |
162 | * RSND_xxx_O_N for Audio DMAC output | |
163 | * RSND_xxx_I_P for Audio DMAC peri peri input | |
164 | * RSND_xxx_O_P for Audio DMAC peri peri output | |
165 | * | |
166 | * ex) R-Car H2 case | |
167 | * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out | |
d9288d0b KM |
168 | * SSI : 0xec541000 / 0xec241008 / 0xec24100c |
169 | * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 | |
ad32d0c7 KM |
170 | * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 |
171 | * CMD : 0xec500000 / 0xec008000 0xec308000 | |
172 | */ | |
173 | #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) | |
174 | #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) | |
175 | ||
d9288d0b KM |
176 | #define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) |
177 | #define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) | |
178 | ||
179 | #define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) | |
180 | #define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) | |
ad32d0c7 KM |
181 | |
182 | #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) | |
183 | #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) | |
184 | ||
185 | #define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) | |
186 | #define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) | |
187 | ||
188 | #define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) | |
189 | #define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) | |
190 | ||
64eae986 | 191 | static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, |
ad32d0c7 KM |
192 | struct rsnd_dma *dma, |
193 | struct dma_slave_config *cfg, | |
194 | int is_play, int slave_id) | |
195 | { | |
196 | struct platform_device *pdev = rsnd_priv_to_pdev(priv); | |
197 | struct device *dev = rsnd_priv_to_dev(priv); | |
198 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | |
199 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | |
200 | dma_addr_t ssi_reg = platform_get_resource(pdev, | |
201 | IORESOURCE_MEM, RSND_GEN2_SSI)->start; | |
202 | dma_addr_t src_reg = platform_get_resource(pdev, | |
203 | IORESOURCE_MEM, RSND_GEN2_SCU)->start; | |
204 | int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); | |
205 | int use_src = !!rsnd_io_to_mod_src(io); | |
206 | int use_dvc = !!rsnd_io_to_mod_dvc(io); | |
207 | int id = rsnd_mod_id(mod); | |
208 | struct dma_addr { | |
209 | dma_addr_t src_addr; | |
210 | dma_addr_t dst_addr; | |
d9288d0b KM |
211 | } dma_addrs[3][2][3] = { |
212 | /* SRC */ | |
213 | {{{ 0, 0 }, | |
214 | /* Capture */ | |
215 | { RDMA_SRC_O_N(src, id), 0 }, | |
216 | { RDMA_CMD_O_N(src, id), 0 } }, | |
217 | /* Playback */ | |
218 | {{ 0, 0, }, | |
219 | { 0, RDMA_SRC_I_N(src, id) }, | |
220 | { 0, RDMA_SRC_I_N(src, id) } } | |
221 | }, | |
222 | /* SSI */ | |
223 | /* Capture */ | |
224 | {{{ RDMA_SSI_O_N(ssi, id), 0 }, | |
225 | { 0, 0 }, | |
226 | { 0, 0 } }, | |
227 | /* Playback */ | |
228 | {{ 0, RDMA_SSI_I_N(ssi, id) }, | |
229 | { 0, 0 }, | |
230 | { 0, 0 } } | |
231 | }, | |
232 | /* SSIU */ | |
233 | /* Capture */ | |
234 | {{{ RDMA_SSIU_O_N(ssi, id), 0 }, | |
235 | { RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, | |
236 | { RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) } }, | |
237 | /* Playback */ | |
238 | {{ 0, RDMA_SSIU_I_N(ssi, id) }, | |
239 | { RDMA_SRC_O_P(src, id), RDMA_SSIU_I_P(ssi, id) }, | |
240 | { RDMA_CMD_O_P(src, id), RDMA_SSIU_I_P(ssi, id) } } }, | |
ad32d0c7 KM |
241 | }; |
242 | ||
ad32d0c7 KM |
243 | /* it shouldn't happen */ |
244 | if (use_dvc & !use_src) { | |
245 | dev_err(dev, "DVC is selected without SRC\n"); | |
246 | return; | |
247 | } | |
248 | ||
d9288d0b KM |
249 | /* use SSIU or SSI ? */ |
250 | if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu"))) | |
251 | is_ssi++; | |
252 | ||
ad32d0c7 KM |
253 | cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; |
254 | cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; | |
255 | ||
256 | dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n", | |
257 | id, cfg->src_addr, cfg->dst_addr); | |
258 | } | |
259 | ||
64eae986 KM |
260 | void rsnd_gen_dma_addr(struct rsnd_priv *priv, |
261 | struct rsnd_dma *dma, | |
262 | struct dma_slave_config *cfg, | |
263 | int is_play, int slave_id) | |
264 | { | |
265 | cfg->slave_id = slave_id; | |
266 | cfg->src_addr = 0; | |
267 | cfg->dst_addr = 0; | |
268 | cfg->direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; | |
269 | ||
270 | /* | |
271 | * gen1 uses default DMA addr | |
272 | */ | |
273 | if (rsnd_is_gen1(priv)) | |
274 | return; | |
275 | ||
276 | rsnd_gen2_dma_addr(priv, dma, cfg, is_play, slave_id); | |
277 | } | |
278 | ||
279 | ||
994a9df1 KM |
280 | /* |
281 | * Gen2 | |
994a9df1 KM |
282 | */ |
283 | ||
507d466c KM |
284 | /* single address mapping */ |
285 | #define RSND_GEN2_S_REG(gen, reg, id, offset) \ | |
1a1c75a7 | 286 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 10) |
507d466c KM |
287 | |
288 | /* multi address mapping */ | |
289 | #define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset) \ | |
1a1c75a7 | 290 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 10) |
507d466c KM |
291 | |
292 | static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |
293 | { | |
294 | struct reg_field regf[RSND_REG_MAX] = { | |
295 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), | |
296 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), | |
297 | /* FIXME: it needs SSI_MODE2/3 in the future */ | |
629509c5 KM |
298 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_MODE, 0x0, 0x80), |
299 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_ADINR,0x4, 0x80), | |
300 | RSND_GEN2_M_REG(gen, SSIU, SSI_CTRL, 0x10, 0x80), | |
507d466c KM |
301 | RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), |
302 | ||
629509c5 KM |
303 | RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20), |
304 | RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20), | |
305 | RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20), | |
bff58ea4 KM |
306 | RSND_GEN2_M_REG(gen, SCU, CMD_ROUTE_SLCT, 0x18c, 0x20), |
307 | RSND_GEN2_M_REG(gen, SCU, CMD_CTRL, 0x190, 0x20), | |
629509c5 KM |
308 | RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40), |
309 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40), | |
310 | RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40), | |
311 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSCR, 0x21c, 0x40), | |
312 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSVR, 0x220, 0x40), | |
313 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40), | |
314 | RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40), | |
315 | RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40), | |
bff58ea4 KM |
316 | RSND_GEN2_M_REG(gen, SCU, DVC_SWRSR, 0xe00, 0x100), |
317 | RSND_GEN2_M_REG(gen, SCU, DVC_DVUIR, 0xe04, 0x100), | |
318 | RSND_GEN2_M_REG(gen, SCU, DVC_ADINR, 0xe08, 0x100), | |
319 | RSND_GEN2_M_REG(gen, SCU, DVC_DVUCR, 0xe10, 0x100), | |
320 | RSND_GEN2_M_REG(gen, SCU, DVC_ZCMCR, 0xe14, 0x100), | |
321 | RSND_GEN2_M_REG(gen, SCU, DVC_VOL0R, 0xe28, 0x100), | |
322 | RSND_GEN2_M_REG(gen, SCU, DVC_VOL1R, 0xe2c, 0x100), | |
323 | RSND_GEN2_M_REG(gen, SCU, DVC_DVUER, 0xe48, 0x100), | |
629509c5 | 324 | |
507d466c KM |
325 | RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), |
326 | RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), | |
327 | RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), | |
328 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), | |
329 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), | |
330 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), | |
ee2c828d | 331 | RSND_GEN2_S_REG(gen, ADG, DIV_EN, 0x30), |
629509c5 KM |
332 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL0, 0x34), |
333 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL1, 0x38), | |
334 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL2, 0x3c), | |
335 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL3, 0x40), | |
336 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL4, 0x44), | |
337 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL0, 0x48), | |
338 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL1, 0x4c), | |
339 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50), | |
340 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54), | |
341 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58), | |
bff58ea4 | 342 | RSND_GEN2_S_REG(gen, ADG, CMDOUT_TIMSEL, 0x5c), |
507d466c KM |
343 | |
344 | RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), | |
345 | RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), | |
346 | RSND_GEN2_M_REG(gen, SSI, SSITDR, 0x08, 0x40), | |
347 | RSND_GEN2_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), | |
348 | RSND_GEN2_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), | |
349 | }; | |
350 | ||
351 | return rsnd_gen_regmap_init(priv, gen, regf); | |
352 | } | |
353 | ||
354 | static int rsnd_gen2_probe(struct platform_device *pdev, | |
507d466c KM |
355 | struct rsnd_priv *priv) |
356 | { | |
357 | struct device *dev = rsnd_priv_to_dev(priv); | |
358 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | |
359 | struct resource *scu_res; | |
360 | struct resource *adg_res; | |
361 | struct resource *ssiu_res; | |
362 | struct resource *ssi_res; | |
363 | int ret; | |
364 | ||
365 | /* | |
366 | * map address | |
367 | */ | |
368 | scu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU); | |
369 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG); | |
370 | ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU); | |
371 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI); | |
372 | ||
373 | gen->base[RSND_GEN2_SCU] = devm_ioremap_resource(dev, scu_res); | |
374 | gen->base[RSND_GEN2_ADG] = devm_ioremap_resource(dev, adg_res); | |
375 | gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res); | |
376 | gen->base[RSND_GEN2_SSI] = devm_ioremap_resource(dev, ssi_res); | |
377 | if (IS_ERR(gen->base[RSND_GEN2_SCU]) || | |
378 | IS_ERR(gen->base[RSND_GEN2_ADG]) || | |
379 | IS_ERR(gen->base[RSND_GEN2_SSIU]) || | |
380 | IS_ERR(gen->base[RSND_GEN2_SSI])) | |
381 | return -ENODEV; | |
382 | ||
383 | ret = rsnd_gen2_regmap_init(priv, gen); | |
384 | if (ret < 0) | |
385 | return ret; | |
386 | ||
387 | dev_dbg(dev, "Gen2 device probed\n"); | |
e6b0d896 | 388 | dev_dbg(dev, "SCU : %pap => %p\n", &scu_res->start, |
507d466c | 389 | gen->base[RSND_GEN2_SCU]); |
e6b0d896 | 390 | dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, |
507d466c | 391 | gen->base[RSND_GEN2_ADG]); |
e6b0d896 | 392 | dev_dbg(dev, "SSIU : %pap => %p\n", &ssiu_res->start, |
507d466c | 393 | gen->base[RSND_GEN2_SSIU]); |
e6b0d896 | 394 | dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, |
507d466c KM |
395 | gen->base[RSND_GEN2_SSI]); |
396 | ||
397 | return 0; | |
398 | } | |
399 | ||
994a9df1 KM |
400 | /* |
401 | * Gen1 | |
402 | */ | |
403 | ||
55e5b6fd KM |
404 | /* single address mapping */ |
405 | #define RSND_GEN1_S_REG(gen, reg, id, offset) \ | |
406 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) | |
07539c1d | 407 | |
55e5b6fd KM |
408 | /* multi address mapping */ |
409 | #define RSND_GEN1_M_REG(gen, reg, id, offset, _id_offset) \ | |
410 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, _id_offset, 9) | |
411 | ||
412 | static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |
07539c1d | 413 | { |
55e5b6fd KM |
414 | struct reg_field regf[RSND_REG_MAX] = { |
415 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), | |
416 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), | |
417 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c), | |
418 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10), | |
690ef81e | 419 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), |
55e5b6fd KM |
420 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), |
421 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), | |
0290d2a4 | 422 | RSND_GEN1_M_REG(gen, SRU, SRC_BUSIF_MODE, 0x20, 0x4), |
ef749400 KM |
423 | RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), |
424 | RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), | |
425 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), | |
690ef81e | 426 | RSND_GEN1_M_REG(gen, SRU, SRC_ADINR, 0x214, 0x40), |
ef749400 KM |
427 | RSND_GEN1_M_REG(gen, SRU, SRC_IFSCR, 0x21c, 0x40), |
428 | RSND_GEN1_M_REG(gen, SRU, SRC_IFSVR, 0x220, 0x40), | |
429 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCCR, 0x224, 0x40), | |
430 | RSND_GEN1_M_REG(gen, SRU, SRC_MNFSR, 0x228, 0x40), | |
55e5b6fd KM |
431 | |
432 | RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), | |
433 | RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), | |
434 | RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), | |
435 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), | |
436 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), | |
ef749400 KM |
437 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18), |
438 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c), | |
439 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20), | |
55e5b6fd KM |
440 | |
441 | RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), | |
442 | RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), | |
443 | RSND_GEN1_M_REG(gen, SSI, SSITDR, 0x08, 0x40), | |
444 | RSND_GEN1_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), | |
445 | RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), | |
446 | }; | |
447 | ||
c1e6cc5e | 448 | return rsnd_gen_regmap_init(priv, gen, regf); |
07539c1d KM |
449 | } |
450 | ||
3337744a | 451 | static int rsnd_gen1_probe(struct platform_device *pdev, |
3337744a KM |
452 | struct rsnd_priv *priv) |
453 | { | |
07539c1d KM |
454 | struct device *dev = rsnd_priv_to_dev(priv); |
455 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | |
456 | struct resource *sru_res; | |
dfc9403b | 457 | struct resource *adg_res; |
ae5c3223 | 458 | struct resource *ssi_res; |
55e5b6fd | 459 | int ret; |
07539c1d KM |
460 | |
461 | /* | |
462 | * map address | |
463 | */ | |
464 | sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); | |
dfc9403b | 465 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); |
ae5c3223 | 466 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); |
07539c1d KM |
467 | |
468 | gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); | |
dfc9403b | 469 | gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); |
ae5c3223 | 470 | gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); |
70263cb4 WY |
471 | if (IS_ERR(gen->base[RSND_GEN1_SRU]) || |
472 | IS_ERR(gen->base[RSND_GEN1_ADG]) || | |
473 | IS_ERR(gen->base[RSND_GEN1_SSI])) | |
07539c1d | 474 | return -ENODEV; |
07539c1d | 475 | |
55e5b6fd KM |
476 | ret = rsnd_gen1_regmap_init(priv, gen); |
477 | if (ret < 0) | |
478 | return ret; | |
07539c1d KM |
479 | |
480 | dev_dbg(dev, "Gen1 device probed\n"); | |
e6b0d896 | 481 | dev_dbg(dev, "SRU : %pap => %p\n", &sru_res->start, |
07539c1d | 482 | gen->base[RSND_GEN1_SRU]); |
e6b0d896 | 483 | dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, |
dfc9403b | 484 | gen->base[RSND_GEN1_ADG]); |
e6b0d896 | 485 | dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, |
ae5c3223 | 486 | gen->base[RSND_GEN1_SSI]); |
07539c1d | 487 | |
3337744a | 488 | return 0; |
ae5c3223 | 489 | |
3337744a KM |
490 | } |
491 | ||
3337744a KM |
492 | /* |
493 | * Gen | |
494 | */ | |
90e8e50f KM |
495 | static void rsnd_of_parse_gen(struct platform_device *pdev, |
496 | const struct rsnd_of_data *of_data, | |
497 | struct rsnd_priv *priv) | |
498 | { | |
499 | struct rcar_snd_info *info = priv->info; | |
500 | ||
501 | if (!of_data) | |
502 | return; | |
503 | ||
504 | info->flags = of_data->flags; | |
505 | } | |
506 | ||
3337744a | 507 | int rsnd_gen_probe(struct platform_device *pdev, |
90e8e50f | 508 | const struct rsnd_of_data *of_data, |
3337744a KM |
509 | struct rsnd_priv *priv) |
510 | { | |
511 | struct device *dev = rsnd_priv_to_dev(priv); | |
512 | struct rsnd_gen *gen; | |
531eaf49 | 513 | int ret; |
3337744a | 514 | |
90e8e50f KM |
515 | rsnd_of_parse_gen(pdev, of_data, priv); |
516 | ||
3337744a KM |
517 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); |
518 | if (!gen) { | |
519 | dev_err(dev, "GEN allocate failed\n"); | |
520 | return -ENOMEM; | |
521 | } | |
522 | ||
531eaf49 | 523 | priv->gen = gen; |
072188b6 | 524 | |
507d466c KM |
525 | ret = -ENODEV; |
526 | if (rsnd_is_gen1(priv)) | |
5da39cf3 | 527 | ret = rsnd_gen1_probe(pdev, priv); |
507d466c | 528 | else if (rsnd_is_gen2(priv)) |
5da39cf3 | 529 | ret = rsnd_gen2_probe(pdev, priv); |
507d466c KM |
530 | |
531 | if (ret < 0) | |
072188b6 | 532 | dev_err(dev, "unknown generation R-Car sound device\n"); |
072188b6 | 533 | |
531eaf49 | 534 | return ret; |
3337744a | 535 | } |