diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2013-07-22 00:36:21 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-07-28 14:34:09 -0400 |
commit | 3337744ac41bee00b0068ad5f926dd9c27540809 (patch) | |
tree | 3a7577c4e2d4c78b6f20ad922670e3abd38b0892 /sound/soc/sh/rcar/gen.c | |
parent | cdaa3cdfb4a710545a53740b1780a683b043618a (diff) |
ASoC: add Renesas R-Car Generation feature
Renesas R-Car series sound circuit consists of SSI and its peripheral.
But this peripheral circuit is different between
R-Car Generation1 (E1/M1/H1) and Generation2 (E2/M2/H2)
(Actually, there are many difference in Generation1 chips)
The main difference between Gen1 and Gen2 are
1) register offset, 2) data path
In order to control Gen1/Gen2 by same method,
this patch adds gen.c.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/sh/rcar/gen.c')
-rw-r--r-- | sound/soc/sh/rcar/gen.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c new file mode 100644 index 000000000000..ec67a796eca2 --- /dev/null +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -0,0 +1,154 @@ | |||
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 | #define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1) | ||
38 | #define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2) | ||
39 | |||
40 | /* | ||
41 | * Gen2 | ||
42 | * will be filled in the future | ||
43 | */ | ||
44 | |||
45 | /* | ||
46 | * Gen1 | ||
47 | */ | ||
48 | static int rsnd_gen1_probe(struct platform_device *pdev, | ||
49 | struct rcar_snd_info *info, | ||
50 | struct rsnd_priv *priv) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static void rsnd_gen1_remove(struct platform_device *pdev, | ||
56 | struct rsnd_priv *priv) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Gen | ||
62 | */ | ||
63 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
64 | struct rsnd_dai *rdai, | ||
65 | struct rsnd_dai_stream *io) | ||
66 | { | ||
67 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
68 | |||
69 | return gen->ops->path_init(priv, rdai, io); | ||
70 | } | ||
71 | |||
72 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
73 | struct rsnd_dai *rdai, | ||
74 | struct rsnd_dai_stream *io) | ||
75 | { | ||
76 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
77 | |||
78 | return gen->ops->path_exit(priv, rdai, io); | ||
79 | } | ||
80 | |||
81 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | ||
82 | struct rsnd_mod *mod, | ||
83 | enum rsnd_reg reg) | ||
84 | { | ||
85 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
86 | struct device *dev = rsnd_priv_to_dev(priv); | ||
87 | int index; | ||
88 | u32 offset_id, offset_adr; | ||
89 | |||
90 | if (reg >= RSND_REG_MAX) { | ||
91 | dev_err(dev, "rsnd_reg reg error\n"); | ||
92 | return NULL; | ||
93 | } | ||
94 | |||
95 | index = gen->reg_map[reg].index; | ||
96 | offset_id = gen->reg_map[reg].offset_id; | ||
97 | offset_adr = gen->reg_map[reg].offset_adr; | ||
98 | |||
99 | if (index < 0) { | ||
100 | dev_err(dev, "unsupported reg access %d\n", reg); | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | if (offset_id && mod) | ||
105 | offset_id *= rsnd_mod_id(mod); | ||
106 | |||
107 | /* | ||
108 | * index/offset were set on gen1/gen2 | ||
109 | */ | ||
110 | |||
111 | return gen->base[index] + offset_id + offset_adr; | ||
112 | } | ||
113 | |||
114 | int rsnd_gen_probe(struct platform_device *pdev, | ||
115 | struct rcar_snd_info *info, | ||
116 | struct rsnd_priv *priv) | ||
117 | { | ||
118 | struct device *dev = rsnd_priv_to_dev(priv); | ||
119 | struct rsnd_gen *gen; | ||
120 | int i; | ||
121 | |||
122 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); | ||
123 | if (!gen) { | ||
124 | dev_err(dev, "GEN allocate failed\n"); | ||
125 | return -ENOMEM; | ||
126 | } | ||
127 | |||
128 | priv->gen = gen; | ||
129 | |||
130 | /* | ||
131 | * see | ||
132 | * rsnd_reg_get() | ||
133 | * rsnd_gen_probe() | ||
134 | */ | ||
135 | for (i = 0; i < RSND_REG_MAX; i++) | ||
136 | gen->reg_map[i].index = -1; | ||
137 | |||
138 | /* | ||
139 | * init each module | ||
140 | */ | ||
141 | if (rsnd_is_gen1(priv)) | ||
142 | return rsnd_gen1_probe(pdev, info, priv); | ||
143 | |||
144 | dev_err(dev, "unknown generation R-Car sound device\n"); | ||
145 | |||
146 | return -ENODEV; | ||
147 | } | ||
148 | |||
149 | void rsnd_gen_remove(struct platform_device *pdev, | ||
150 | struct rsnd_priv *priv) | ||
151 | { | ||
152 | if (rsnd_is_gen1(priv)) | ||
153 | rsnd_gen1_remove(pdev, priv); | ||
154 | } | ||