aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/rcar_snd.h23
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/core.c5
-rw-r--r--sound/soc/sh/rcar/gen.c24
-rw-r--r--sound/soc/sh/rcar/rsnd.h23
-rw-r--r--sound/soc/sh/rcar/ssi.c588
6 files changed, 661 insertions, 4 deletions
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index 6babd6f7b537..99d8dd029906 100644
--- a/include/sound/rcar_snd.h
+++ b/include/sound/rcar_snd.h
@@ -16,11 +16,30 @@
16 16
17#define RSND_GEN1_SRU 0 17#define RSND_GEN1_SRU 0
18#define RSND_GEN1_ADG 1 18#define RSND_GEN1_ADG 1
19#define RSND_GEN1_SSI 2
19 20
20#define RSND_GEN2_SRU 0 21#define RSND_GEN2_SRU 0
21#define RSND_GEN2_ADG 1 22#define RSND_GEN2_ADG 1
23#define RSND_GEN2_SSIU 2
24#define RSND_GEN2_SSI 3
22 25
23#define RSND_BASE_MAX 2 26#define RSND_BASE_MAX 4
27
28/*
29 * flags
30 *
31 * 0xA0000000
32 *
33 * A : clock sharing settings
34 */
35#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
36#define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */
37#define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */
38
39struct rsnd_ssi_platform_info {
40 int pio_irq;
41 u32 flags;
42};
24 43
25struct rsnd_scu_platform_info { 44struct rsnd_scu_platform_info {
26 u32 flags; 45 u32 flags;
@@ -43,6 +62,8 @@ struct rsnd_dai_platform_info {
43 62
44struct rcar_snd_info { 63struct rcar_snd_info {
45 u32 flags; 64 u32 flags;
65 struct rsnd_ssi_platform_info *ssi_info;
66 int ssi_info_nr;
46 struct rsnd_scu_platform_info *scu_info; 67 struct rsnd_scu_platform_info *scu_info;
47 int scu_info_nr; 68 int scu_info_nr;
48 struct rsnd_dai_platform_info *dai_info; 69 struct rsnd_dai_platform_info *dai_info;
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index c11280cffcfe..0ff492df7929 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,2 @@
1snd-soc-rcar-objs := core.o gen.o scu.o adg.o 1snd-soc-rcar-objs := core.o gen.o scu.o adg.o ssi.o
2obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file 2obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index e588d8a8ae40..9a5469d3f352 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -639,6 +639,10 @@ static int rsnd_probe(struct platform_device *pdev)
639 if (ret < 0) 639 if (ret < 0)
640 return ret; 640 return ret;
641 641
642 ret = rsnd_ssi_probe(pdev, info, priv);
643 if (ret < 0)
644 return ret;
645
642 /* 646 /*
643 * asoc register 647 * asoc register
644 */ 648 */
@@ -677,6 +681,7 @@ static int rsnd_remove(struct platform_device *pdev)
677 /* 681 /*
678 * remove each module 682 * remove each module
679 */ 683 */
684 rsnd_ssi_remove(pdev, priv);
680 rsnd_adg_remove(pdev, priv); 685 rsnd_adg_remove(pdev, priv);
681 rsnd_scu_remove(pdev, priv); 686 rsnd_scu_remove(pdev, priv);
682 rsnd_dai_remove(pdev, priv); 687 rsnd_dai_remove(pdev, priv);
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index ed21a136354f..5e4ae0da4352 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -72,6 +72,12 @@ static int rsnd_gen1_path_init(struct rsnd_priv *priv,
72 else 72 else
73 id = info->ssi_id_capture; 73 id = info->ssi_id_capture;
74 74
75 /* SSI */
76 mod = rsnd_ssi_mod_get(priv, id);
77 ret = rsnd_dai_connect(rdai, mod, io);
78 if (ret < 0)
79 return ret;
80
75 /* SCU */ 81 /* SCU */
76 mod = rsnd_scu_mod_get(priv, id); 82 mod = rsnd_scu_mod_get(priv, id);
77 ret = rsnd_dai_connect(rdai, mod, io); 83 ret = rsnd_dai_connect(rdai, mod, io);
@@ -120,6 +126,12 @@ static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
120 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18); 126 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18);
121 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c); 127 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c);
122 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20); 128 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20);
129
130 RSND_GEN1_REG_MAP(gen, SSI, SSICR, 0x40, 0x00);
131 RSND_GEN1_REG_MAP(gen, SSI, SSISR, 0x40, 0x04);
132 RSND_GEN1_REG_MAP(gen, SSI, SSITDR, 0x40, 0x08);
133 RSND_GEN1_REG_MAP(gen, SSI, SSIRDR, 0x40, 0x0c);
134 RSND_GEN1_REG_MAP(gen, SSI, SSIWSR, 0x40, 0x20);
123} 135}
124 136
125static int rsnd_gen1_probe(struct platform_device *pdev, 137static int rsnd_gen1_probe(struct platform_device *pdev,
@@ -130,14 +142,17 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
130 struct rsnd_gen *gen = rsnd_priv_to_gen(priv); 142 struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
131 struct resource *sru_res; 143 struct resource *sru_res;
132 struct resource *adg_res; 144 struct resource *adg_res;
145 struct resource *ssi_res;
133 146
134 /* 147 /*
135 * map address 148 * map address
136 */ 149 */
137 sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); 150 sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
138 adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); 151 adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
152 ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
139 if (!sru_res || 153 if (!sru_res ||
140 !adg_res) { 154 !adg_res ||
155 !ssi_res) {
141 dev_err(dev, "Not enough SRU/SSI/ADG platform resources.\n"); 156 dev_err(dev, "Not enough SRU/SSI/ADG platform resources.\n");
142 return -ENODEV; 157 return -ENODEV;
143 } 158 }
@@ -146,8 +161,10 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
146 161
147 gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); 162 gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
148 gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); 163 gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
164 gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
149 if (!gen->base[RSND_GEN1_SRU] || 165 if (!gen->base[RSND_GEN1_SRU] ||
150 !gen->base[RSND_GEN1_ADG]) { 166 !gen->base[RSND_GEN1_ADG] ||
167 !gen->base[RSND_GEN1_SSI]) {
151 dev_err(dev, "SRU/SSI/ADG ioremap failed\n"); 168 dev_err(dev, "SRU/SSI/ADG ioremap failed\n");
152 return -ENODEV; 169 return -ENODEV;
153 } 170 }
@@ -159,8 +176,11 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
159 gen->base[RSND_GEN1_SRU]); 176 gen->base[RSND_GEN1_SRU]);
160 dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, 177 dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start,
161 gen->base[RSND_GEN1_ADG]); 178 gen->base[RSND_GEN1_ADG]);
179 dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start,
180 gen->base[RSND_GEN1_SSI]);
162 181
163 return 0; 182 return 0;
183
164} 184}
165 185
166static void rsnd_gen1_remove(struct platform_device *pdev, 186static void rsnd_gen1_remove(struct platform_device *pdev,
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 344fd59cb7fd..0e7727cc41db 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -43,6 +43,13 @@ enum rsnd_reg {
43 RSND_REG_AUDIO_CLK_SEL4, 43 RSND_REG_AUDIO_CLK_SEL4,
44 RSND_REG_AUDIO_CLK_SEL5, 44 RSND_REG_AUDIO_CLK_SEL5,
45 45
46 /* SSI */
47 RSND_REG_SSICR,
48 RSND_REG_SSISR,
49 RSND_REG_SSITDR,
50 RSND_REG_SSIRDR,
51 RSND_REG_SSIWSR,
52
46 RSND_REG_MAX, 53 RSND_REG_MAX,
47}; 54};
48 55
@@ -151,6 +158,7 @@ int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod,
151 struct rsnd_dai_stream *io); 158 struct rsnd_dai_stream *io);
152int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); 159int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
153#define rsnd_dai_get_platform_info(rdai) ((rdai)->info) 160#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
161#define rsnd_io_to_runtime(io) ((io)->substream->runtime)
154 162
155void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); 163void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
156int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); 164int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
@@ -210,6 +218,11 @@ struct rsnd_priv {
210 void *adg; 218 void *adg;
211 219
212 /* 220 /*
221 * below value will be filled on rsnd_ssi_probe()
222 */
223 void *ssiu;
224
225 /*
213 * below value will be filled on rsnd_dai_probe() 226 * below value will be filled on rsnd_dai_probe()
214 */ 227 */
215 struct snd_soc_dai_driver *daidrv; 228 struct snd_soc_dai_driver *daidrv;
@@ -232,4 +245,14 @@ void rsnd_scu_remove(struct platform_device *pdev,
232struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); 245struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
233#define rsnd_scu_nr(priv) ((priv)->scu_nr) 246#define rsnd_scu_nr(priv) ((priv)->scu_nr)
234 247
248/*
249 * R-Car SSI
250 */
251int rsnd_ssi_probe(struct platform_device *pdev,
252 struct rcar_snd_info *info,
253 struct rsnd_priv *priv);
254void rsnd_ssi_remove(struct platform_device *pdev,
255 struct rsnd_priv *priv);
256struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
257
235#endif 258#endif
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
new file mode 100644
index 000000000000..061ac7e88309
--- /dev/null
+++ b/sound/soc/sh/rcar/ssi.c
@@ -0,0 +1,588 @@
1/*
2 * Renesas R-Car SSIU/SSI support
3 *
4 * Copyright (C) 2013 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * Based on fsi.c
8 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14#include <linux/delay.h>
15#include "rsnd.h"
16#define RSND_SSI_NAME_SIZE 16
17
18/*
19 * SSICR
20 */
21#define FORCE (1 << 31) /* Fixed */
22#define UIEN (1 << 27) /* Underflow Interrupt Enable */
23#define OIEN (1 << 26) /* Overflow Interrupt Enable */
24#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */
25#define DIEN (1 << 24) /* Data Interrupt Enable */
26
27#define DWL_8 (0 << 19) /* Data Word Length */
28#define DWL_16 (1 << 19) /* Data Word Length */
29#define DWL_18 (2 << 19) /* Data Word Length */
30#define DWL_20 (3 << 19) /* Data Word Length */
31#define DWL_22 (4 << 19) /* Data Word Length */
32#define DWL_24 (5 << 19) /* Data Word Length */
33#define DWL_32 (6 << 19) /* Data Word Length */
34
35#define SWL_32 (3 << 16) /* R/W System Word Length */
36#define SCKD (1 << 15) /* Serial Bit Clock Direction */
37#define SWSD (1 << 14) /* Serial WS Direction */
38#define SCKP (1 << 13) /* Serial Bit Clock Polarity */
39#define SWSP (1 << 12) /* Serial WS Polarity */
40#define SDTA (1 << 10) /* Serial Data Alignment */
41#define DEL (1 << 8) /* Serial Data Delay */
42#define CKDV(v) (v << 4) /* Serial Clock Division Ratio */
43#define TRMD (1 << 1) /* Transmit/Receive Mode Select */
44#define EN (1 << 0) /* SSI Module Enable */
45
46/*
47 * SSISR
48 */
49#define UIRQ (1 << 27) /* Underflow Error Interrupt Status */
50#define OIRQ (1 << 26) /* Overflow Error Interrupt Status */
51#define IIRQ (1 << 25) /* Idle Mode Interrupt Status */
52#define DIRQ (1 << 24) /* Data Interrupt Status Flag */
53
54struct rsnd_ssi {
55 struct clk *clk;
56 struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
57 struct rsnd_ssi *parent;
58 struct rsnd_mod mod;
59
60 struct rsnd_dai *rdai;
61 struct rsnd_dai_stream *io;
62 u32 cr_own;
63 u32 cr_clk;
64 u32 cr_etc;
65 int err;
66 unsigned int usrcnt;
67 unsigned int rate;
68};
69
70struct rsnd_ssiu {
71 u32 ssi_mode0;
72 u32 ssi_mode1;
73
74 int ssi_nr;
75 struct rsnd_ssi *ssi;
76};
77
78#define for_each_rsnd_ssi(pos, priv, i) \
79 for (i = 0; \
80 (i < rsnd_ssi_nr(priv)) && \
81 ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \
82 i++)
83
84#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
85#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
86#define rsnd_ssi_is_pio(ssi) ((ssi)->info->pio_irq > 0)
87#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
88#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
89#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
90#define rsnd_ssi_to_ssiu(ssi)\
91 (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
92
93static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
94 struct rsnd_ssiu *ssiu)
95{
96 struct rsnd_ssi *ssi;
97 u32 flags;
98 u32 val;
99 int i;
100
101 /*
102 * SSI_MODE0
103 */
104 ssiu->ssi_mode0 = 0;
105 for_each_rsnd_ssi(ssi, priv, i)
106 ssiu->ssi_mode0 |= (1 << i);
107
108 /*
109 * SSI_MODE1
110 */
111#define ssi_parent_set(p, sync, adg, ext) \
112 do { \
113 ssi->parent = ssiu->ssi + p; \
114 if (flags & RSND_SSI_CLK_FROM_ADG) \
115 val = adg; \
116 else \
117 val = ext; \
118 if (flags & RSND_SSI_SYNC) \
119 val |= sync; \
120 } while (0)
121
122 ssiu->ssi_mode1 = 0;
123 for_each_rsnd_ssi(ssi, priv, i) {
124 flags = rsnd_ssi_mode_flags(ssi);
125
126 if (!(flags & RSND_SSI_CLK_PIN_SHARE))
127 continue;
128
129 val = 0;
130 switch (i) {
131 case 1:
132 ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
133 break;
134 case 2:
135 ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2));
136 break;
137 case 4:
138 ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16));
139 break;
140 case 8:
141 ssi_parent_set(7, 0, 0, 0);
142 break;
143 }
144
145 ssiu->ssi_mode1 |= val;
146 }
147}
148
149static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi)
150{
151 struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
152
153 rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
154 rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
155}
156
157static void rsnd_ssi_status_check(struct rsnd_mod *mod,
158 u32 bit)
159{
160 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
161 struct device *dev = rsnd_priv_to_dev(priv);
162 u32 status;
163 int i;
164
165 for (i = 0; i < 1024; i++) {
166 status = rsnd_mod_read(mod, SSISR);
167 if (status & bit)
168 return;
169
170 udelay(50);
171 }
172
173 dev_warn(dev, "status check failed\n");
174}
175
176static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
177 unsigned int rate)
178{
179 struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
180 struct device *dev = rsnd_priv_to_dev(priv);
181 int i, j, ret;
182 int adg_clk_div_table[] = {
183 1, 6, /* see adg.c */
184 };
185 int ssi_clk_mul_table[] = {
186 1, 2, 4, 8, 16, 6, 12,
187 };
188 unsigned int main_rate;
189
190 /*
191 * Find best clock, and try to start ADG
192 */
193 for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) {
194 for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
195
196 /*
197 * this driver is assuming that
198 * system word is 64fs (= 2 x 32bit)
199 * see rsnd_ssi_start()
200 */
201 main_rate = rate / adg_clk_div_table[i]
202 * 32 * 2 * ssi_clk_mul_table[j];
203
204 ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
205 if (0 == ret) {
206 ssi->rate = rate;
207 ssi->cr_clk = FORCE | SWL_32 |
208 SCKD | SWSD | CKDV(j);
209
210 dev_dbg(dev, "ssi%d outputs %u Hz\n",
211 rsnd_mod_id(&ssi->mod), rate);
212
213 return 0;
214 }
215 }
216 }
217
218 dev_err(dev, "unsupported clock rate\n");
219 return -EIO;
220}
221
222static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
223{
224 ssi->rate = 0;
225 ssi->cr_clk = 0;
226 rsnd_adg_ssi_clk_stop(&ssi->mod);
227}
228
229static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
230 struct rsnd_dai *rdai,
231 struct rsnd_dai_stream *io)
232{
233 struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
234 struct device *dev = rsnd_priv_to_dev(priv);
235 u32 cr;
236
237 if (0 == ssi->usrcnt) {
238 clk_enable(ssi->clk);
239
240 if (rsnd_rdai_is_clk_master(rdai)) {
241 struct snd_pcm_runtime *runtime;
242
243 runtime = rsnd_io_to_runtime(io);
244
245 if (rsnd_ssi_clk_from_parent(ssi))
246 rsnd_ssi_hw_start(ssi->parent, rdai, io);
247 else
248 rsnd_ssi_master_clk_start(ssi, runtime->rate);
249 }
250 }
251
252 cr = ssi->cr_own |
253 ssi->cr_clk |
254 ssi->cr_etc |
255 EN;
256
257 rsnd_mod_write(&ssi->mod, SSICR, cr);
258
259 ssi->usrcnt++;
260
261 dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod));
262}
263
264static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
265 struct rsnd_dai *rdai)
266{
267 struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
268 struct device *dev = rsnd_priv_to_dev(priv);
269 u32 cr;
270
271 if (0 == ssi->usrcnt) /* stop might be called without start */
272 return;
273
274 ssi->usrcnt--;
275
276 if (0 == ssi->usrcnt) {
277 /*
278 * disable all IRQ,
279 * and, wait all data was sent
280 */
281 cr = ssi->cr_own |
282 ssi->cr_clk;
283
284 rsnd_mod_write(&ssi->mod, SSICR, cr | EN);
285 rsnd_ssi_status_check(&ssi->mod, DIRQ);
286
287 /*
288 * disable SSI,
289 * and, wait idle state
290 */
291 rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */
292 rsnd_ssi_status_check(&ssi->mod, IIRQ);
293
294 if (rsnd_rdai_is_clk_master(rdai)) {
295 if (rsnd_ssi_clk_from_parent(ssi))
296 rsnd_ssi_hw_stop(ssi->parent, rdai);
297 else
298 rsnd_ssi_master_clk_stop(ssi);
299 }
300
301 clk_disable(ssi->clk);
302 }
303
304 dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
305}
306
307/*
308 * SSI mod common functions
309 */
310static int rsnd_ssi_init(struct rsnd_mod *mod,
311 struct rsnd_dai *rdai,
312 struct rsnd_dai_stream *io)
313{
314 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
315 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
316 struct device *dev = rsnd_priv_to_dev(priv);
317 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
318 u32 cr;
319
320 cr = FORCE;
321
322 /*
323 * always use 32bit system word for easy clock calculation.
324 * see also rsnd_ssi_master_clk_enable()
325 */
326 cr |= SWL_32;
327
328 /*
329 * init clock settings for SSICR
330 */
331 switch (runtime->sample_bits) {
332 case 16:
333 cr |= DWL_16;
334 break;
335 case 32:
336 cr |= DWL_24;
337 break;
338 default:
339 return -EIO;
340 }
341
342 if (rdai->bit_clk_inv)
343 cr |= SCKP;
344 if (rdai->frm_clk_inv)
345 cr |= SWSP;
346 if (rdai->data_alignment)
347 cr |= SDTA;
348 if (rdai->sys_delay)
349 cr |= DEL;
350 if (rsnd_dai_is_play(rdai, io))
351 cr |= TRMD;
352
353 /*
354 * set ssi parameter
355 */
356 ssi->rdai = rdai;
357 ssi->io = io;
358 ssi->cr_own = cr;
359 ssi->err = -1; /* ignore 1st error */
360
361 rsnd_ssi_mode_set(ssi);
362
363 dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
364
365 return 0;
366}
367
368static int rsnd_ssi_quit(struct rsnd_mod *mod,
369 struct rsnd_dai *rdai,
370 struct rsnd_dai_stream *io)
371{
372 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
373 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
374 struct device *dev = rsnd_priv_to_dev(priv);
375
376 dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
377
378 if (ssi->err > 0)
379 dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
380
381 ssi->rdai = NULL;
382 ssi->io = NULL;
383 ssi->cr_own = 0;
384 ssi->err = 0;
385
386 return 0;
387}
388
389static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
390{
391 /* under/over flow error */
392 if (status & (UIRQ | OIRQ)) {
393 ssi->err++;
394
395 /* clear error status */
396 rsnd_mod_write(&ssi->mod, SSISR, 0);
397 }
398}
399
400/*
401 * SSI PIO
402 */
403static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
404{
405 struct rsnd_ssi *ssi = data;
406 struct rsnd_dai_stream *io = ssi->io;
407 u32 status = rsnd_mod_read(&ssi->mod, SSISR);
408 irqreturn_t ret = IRQ_NONE;
409
410 if (io && (status & DIRQ)) {
411 struct rsnd_dai *rdai = ssi->rdai;
412 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
413 u32 *buf = (u32 *)(runtime->dma_area +
414 rsnd_dai_pointer_offset(io, 0));
415
416 rsnd_ssi_record_error(ssi, status);
417
418 /*
419 * 8/16/32 data can be assesse to TDR/RDR register
420 * directly as 32bit data
421 * see rsnd_ssi_init()
422 */
423 if (rsnd_dai_is_play(rdai, io))
424 rsnd_mod_write(&ssi->mod, SSITDR, *buf);
425 else
426 *buf = rsnd_mod_read(&ssi->mod, SSIRDR);
427
428 rsnd_dai_pointer_update(io, sizeof(*buf));
429
430 ret = IRQ_HANDLED;
431 }
432
433 return ret;
434}
435
436static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
437 struct rsnd_dai *rdai,
438 struct rsnd_dai_stream *io)
439{
440 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
441 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
442 struct device *dev = rsnd_priv_to_dev(priv);
443
444 /* enable PIO IRQ */
445 ssi->cr_etc = UIEN | OIEN | DIEN;
446
447 rsnd_ssi_hw_start(ssi, rdai, io);
448
449 dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
450
451 return 0;
452}
453
454static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
455 struct rsnd_dai *rdai,
456 struct rsnd_dai_stream *io)
457{
458 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
459 struct device *dev = rsnd_priv_to_dev(priv);
460 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
461
462 dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
463
464 ssi->cr_etc = 0;
465
466 rsnd_ssi_hw_stop(ssi, rdai);
467
468 return 0;
469}
470
471static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
472 .name = "ssi (pio)",
473 .init = rsnd_ssi_init,
474 .quit = rsnd_ssi_quit,
475 .start = rsnd_ssi_pio_start,
476 .stop = rsnd_ssi_pio_stop,
477};
478
479/*
480 * Non SSI
481 */
482static int rsnd_ssi_non(struct rsnd_mod *mod,
483 struct rsnd_dai *rdai,
484 struct rsnd_dai_stream *io)
485{
486 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
487 struct device *dev = rsnd_priv_to_dev(priv);
488
489 dev_dbg(dev, "%s\n", __func__);
490
491 return 0;
492}
493
494static struct rsnd_mod_ops rsnd_ssi_non_ops = {
495 .name = "ssi (non)",
496 .init = rsnd_ssi_non,
497 .quit = rsnd_ssi_non,
498 .start = rsnd_ssi_non,
499 .stop = rsnd_ssi_non,
500};
501
502/*
503 * ssi mod function
504 */
505struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
506{
507 BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv));
508
509 return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
510}
511
512int rsnd_ssi_probe(struct platform_device *pdev,
513 struct rcar_snd_info *info,
514 struct rsnd_priv *priv)
515{
516 struct rsnd_ssi_platform_info *pinfo;
517 struct device *dev = rsnd_priv_to_dev(priv);
518 struct rsnd_mod_ops *ops;
519 struct clk *clk;
520 struct rsnd_ssiu *ssiu;
521 struct rsnd_ssi *ssi;
522 char name[RSND_SSI_NAME_SIZE];
523 int i, nr, ret;
524
525 /*
526 * init SSI
527 */
528 nr = info->ssi_info_nr;
529 ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr),
530 GFP_KERNEL);
531 if (!ssiu) {
532 dev_err(dev, "SSI allocate failed\n");
533 return -ENOMEM;
534 }
535
536 priv->ssiu = ssiu;
537 ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1);
538 ssiu->ssi_nr = nr;
539
540 for_each_rsnd_ssi(ssi, priv, i) {
541 pinfo = &info->ssi_info[i];
542
543 snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
544
545 clk = clk_get(dev, name);
546 if (IS_ERR(clk))
547 return PTR_ERR(clk);
548
549 ssi->info = pinfo;
550 ssi->clk = clk;
551
552 ops = &rsnd_ssi_non_ops;
553
554 /*
555 * SSI PIO case
556 */
557 if (rsnd_ssi_is_pio(ssi)) {
558 ret = devm_request_irq(dev, pinfo->pio_irq,
559 &rsnd_ssi_pio_interrupt,
560 IRQF_SHARED,
561 dev_name(dev), ssi);
562 if (ret) {
563 dev_err(dev, "SSI request interrupt failed\n");
564 return ret;
565 }
566
567 ops = &rsnd_ssi_pio_ops;
568 }
569
570 rsnd_mod_init(priv, &ssi->mod, ops, i);
571 }
572
573 rsnd_ssi_mode_init(priv, ssiu);
574
575 dev_dbg(dev, "ssi probed\n");
576
577 return 0;
578}
579
580void rsnd_ssi_remove(struct platform_device *pdev,
581 struct rsnd_priv *priv)
582{
583 struct rsnd_ssi *ssi;
584 int i;
585
586 for_each_rsnd_ssi(ssi, priv, i)
587 clk_put(ssi->clk);
588}