aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2013-07-22 00:36:21 -0400
committerMark Brown <broonie@linaro.org>2013-07-28 14:34:09 -0400
commit3337744ac41bee00b0068ad5f926dd9c27540809 (patch)
tree3a7577c4e2d4c78b6f20ad922670e3abd38b0892
parentcdaa3cdfb4a710545a53740b1780a683b043618a (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>
-rw-r--r--include/sound/rcar_snd.h10
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/core.c58
-rw-r--r--sound/soc/sh/rcar/gen.c154
-rw-r--r--sound/soc/sh/rcar/rsnd.h47
5 files changed, 269 insertions, 2 deletions
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index 7272b2ea7108..14942a827fe5 100644
--- a/include/sound/rcar_snd.h
+++ b/include/sound/rcar_snd.h
@@ -22,6 +22,16 @@ struct rsnd_dai_platform_info {
22 int ssi_id_capture; 22 int ssi_id_capture;
23}; 23};
24 24
25/*
26 * flags
27 *
28 * 0x0000000A
29 *
30 * A : generation
31 */
32#define RSND_GEN1 (1 << 0) /* fixme */
33#define RSND_GEN2 (2 << 0) /* fixme */
34
25struct rcar_snd_info { 35struct rcar_snd_info {
26 u32 flags; 36 u32 flags;
27 struct rsnd_dai_platform_info *dai_info; 37 struct rsnd_dai_platform_info *dai_info;
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index cd8089f20c94..b2d313b1eb94 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,2 @@
1snd-soc-rcar-objs := core.o 1snd-soc-rcar-objs := core.o gen.o
2obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o 2obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index a47fda2aa600..bb8959f93a7d 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -108,6 +108,50 @@
108 108
109 109
110/* 110/*
111 * basic function
112 */
113u32 rsnd_read(struct rsnd_priv *priv,
114 struct rsnd_mod *mod, enum rsnd_reg reg)
115{
116 void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
117
118 BUG_ON(!base);
119
120 return ioread32(base);
121}
122
123void rsnd_write(struct rsnd_priv *priv,
124 struct rsnd_mod *mod,
125 enum rsnd_reg reg, u32 data)
126{
127 void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
128 struct device *dev = rsnd_priv_to_dev(priv);
129
130 BUG_ON(!base);
131
132 dev_dbg(dev, "w %p : %08x\n", base, data);
133
134 iowrite32(data, base);
135}
136
137void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
138 enum rsnd_reg reg, u32 mask, u32 data)
139{
140 void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
141 struct device *dev = rsnd_priv_to_dev(priv);
142 u32 val;
143
144 BUG_ON(!base);
145
146 val = ioread32(base);
147 val &= ~mask;
148 val |= data & mask;
149 iowrite32(val, base);
150
151 dev_dbg(dev, "s %p : %08x\n", base, val);
152}
153
154/*
111 * rsnd_mod functions 155 * rsnd_mod functions
112 */ 156 */
113char *rsnd_mod_name(struct rsnd_mod *mod) 157char *rsnd_mod_name(struct rsnd_mod *mod)
@@ -289,6 +333,10 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
289 if (ret < 0) 333 if (ret < 0)
290 goto dai_trigger_end; 334 goto dai_trigger_end;
291 335
336 ret = rsnd_gen_path_init(priv, rdai, io);
337 if (ret < 0)
338 goto dai_trigger_end;
339
292 ret = rsnd_dai_call(rdai, io, init); 340 ret = rsnd_dai_call(rdai, io, init);
293 if (ret < 0) 341 if (ret < 0)
294 goto dai_trigger_end; 342 goto dai_trigger_end;
@@ -306,10 +354,13 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
306 if (ret < 0) 354 if (ret < 0)
307 goto dai_trigger_end; 355 goto dai_trigger_end;
308 356
309 ret = rsnd_platform_call(priv, dai, stop, ssi_id); 357 ret = rsnd_gen_path_exit(priv, rdai, io);
310 if (ret < 0) 358 if (ret < 0)
311 goto dai_trigger_end; 359 goto dai_trigger_end;
312 360
361 ret = rsnd_platform_call(priv, dai, stop, ssi_id);
362 if (ret < 0)
363 goto dai_trigger_end;
313 break; 364 break;
314 default: 365 default:
315 ret = -EINVAL; 366 ret = -EINVAL;
@@ -572,6 +623,10 @@ static int rsnd_probe(struct platform_device *pdev)
572 /* 623 /*
573 * init each module 624 * init each module
574 */ 625 */
626 ret = rsnd_gen_probe(pdev, info, priv);
627 if (ret < 0)
628 return ret;
629
575 ret = rsnd_dai_probe(pdev, info, priv); 630 ret = rsnd_dai_probe(pdev, info, priv);
576 if (ret < 0) 631 if (ret < 0)
577 return ret; 632 return ret;
@@ -615,6 +670,7 @@ static int rsnd_remove(struct platform_device *pdev)
615 * remove each module 670 * remove each module
616 */ 671 */
617 rsnd_dai_remove(pdev, priv); 672 rsnd_dai_remove(pdev, priv);
673 rsnd_gen_remove(pdev, priv);
618 674
619 return 0; 675 return 0;
620} 676}
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
13struct 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
22struct 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
28struct 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 */
48static 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
55static void rsnd_gen1_remove(struct platform_device *pdev,
56 struct rsnd_priv *priv)
57{
58}
59
60/*
61 * Gen
62 */
63int 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
72int 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
81void __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
114int 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
149void 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}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 65d3835cffbc..8cc36416da25 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -27,12 +27,36 @@
27 * This driver uses pseudo register in order to hide it. 27 * This driver uses pseudo register in order to hide it.
28 * see gen1/gen2 for detail 28 * see gen1/gen2 for detail
29 */ 29 */
30enum rsnd_reg {
31 RSND_REG_MAX,
32};
33
30struct rsnd_priv; 34struct rsnd_priv;
31struct rsnd_mod; 35struct rsnd_mod;
32struct rsnd_dai; 36struct rsnd_dai;
33struct rsnd_dai_stream; 37struct rsnd_dai_stream;
34 38
35/* 39/*
40 * R-Car basic functions
41 */
42#define rsnd_mod_read(m, r) \
43 rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
44#define rsnd_mod_write(m, r, d) \
45 rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
46#define rsnd_mod_bset(m, r, s, d) \
47 rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
48
49#define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r)
50#define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d)
51#define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d)
52
53u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
54void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
55 enum rsnd_reg reg, u32 data);
56void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
57 u32 mask, u32 data);
58
59/*
36 * R-Car sound mod 60 * R-Car sound mod
37 */ 61 */
38 62
@@ -117,6 +141,24 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
117int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); 141int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
118 142
119/* 143/*
144 * R-Car Gen1/Gen2
145 */
146int rsnd_gen_probe(struct platform_device *pdev,
147 struct rcar_snd_info *info,
148 struct rsnd_priv *priv);
149void rsnd_gen_remove(struct platform_device *pdev,
150 struct rsnd_priv *priv);
151int rsnd_gen_path_init(struct rsnd_priv *priv,
152 struct rsnd_dai *rdai,
153 struct rsnd_dai_stream *io);
154int rsnd_gen_path_exit(struct rsnd_priv *priv,
155 struct rsnd_dai *rdai,
156 struct rsnd_dai_stream *io);
157void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
158 struct rsnd_mod *mod,
159 enum rsnd_reg reg);
160
161/*
120 * R-Car sound priv 162 * R-Car sound priv
121 */ 163 */
122struct rsnd_priv { 164struct rsnd_priv {
@@ -126,6 +168,11 @@ struct rsnd_priv {
126 spinlock_t lock; 168 spinlock_t lock;
127 169
128 /* 170 /*
171 * below value will be filled on rsnd_gen_probe()
172 */
173 void *gen;
174
175 /*
129 * below value will be filled on rsnd_dai_probe() 176 * below value will be filled on rsnd_dai_probe()
130 */ 177 */
131 struct snd_soc_dai_driver *daidrv; 178 struct snd_soc_dai_driver *daidrv;