blob: 6120b0a66958c7cbbf8acc05e2915ce5101d7268 [file] [log] [blame]
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +00001/*
2 * Renesas R-Car SSIU support
3 *
4 * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include "rsnd.h"
11
12#define SSIU_NAME "ssiu"
13
14struct rsnd_ssiu {
15 struct rsnd_mod mod;
16};
17
18#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
19#define for_each_rsnd_ssiu(pos, priv, i) \
20 for (i = 0; \
21 (i < rsnd_ssiu_nr(priv)) && \
22 ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
23 i++)
24
25static int rsnd_ssiu_init(struct rsnd_mod *mod,
26 struct rsnd_dai_stream *io,
27 struct rsnd_priv *priv)
28{
29 struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
30 int use_busif = rsnd_ssi_use_busif(io);
31 int id = rsnd_mod_id(mod);
32
33 /*
34 * SSI_MODE0
35 */
36 rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
37
38 /*
39 * SSI_MODE1
40 */
41 if (rsnd_ssi_is_pin_sharing(io)) {
42 int shift = -1;
43
44 switch (id) {
45 case 1:
46 shift = 0;
47 break;
48 case 2:
49 shift = 2;
50 break;
51 case 4:
52 shift = 16;
53 break;
54 }
55
56 if (shift >= 0)
57 rsnd_mod_bset(mod, SSI_MODE1,
58 0x3 << shift,
59 rsnd_rdai_is_clk_master(rdai) ?
60 0x2 << shift : 0x1 << shift);
61 }
62
63 return 0;
64}
65
66static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
67 .name = SSIU_NAME,
68 .init = rsnd_ssiu_init,
69};
70
71static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
72 struct rsnd_dai_stream *io,
73 struct rsnd_priv *priv)
74{
75 int ret;
76
77 ret = rsnd_ssiu_init(mod, io, priv);
78 if (ret < 0)
79 return ret;
80
81 if (rsnd_ssi_use_busif(io)) {
82 u32 val = rsnd_get_dalign(mod, io);
83
84 rsnd_mod_write(mod, SSI_BUSIF_ADINR,
Kuninori Morimotoc45f7262015-11-30 08:49:33 +000085 rsnd_get_adinr_bit(mod, io) |
86 rsnd_get_adinr_chan(mod, io));
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +000087 rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
88 rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val);
89 }
90
91 return 0;
92}
93
94static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
95 struct rsnd_dai_stream *io,
96 struct rsnd_priv *priv)
97{
98 if (rsnd_ssi_use_busif(io))
99 rsnd_mod_write(mod, SSI_CTRL, 0x1);
100
101 return 0;
102}
103
104static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
105 struct rsnd_dai_stream *io,
106 struct rsnd_priv *priv)
107{
108 if (rsnd_ssi_use_busif(io))
109 rsnd_mod_write(mod, SSI_CTRL, 0);
110
111 return 0;
112}
113
114static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
115 .name = SSIU_NAME,
116 .init = rsnd_ssiu_init_gen2,
117 .start = rsnd_ssiu_start_gen2,
118 .stop = rsnd_ssiu_stop_gen2,
119};
120
121static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
122{
123 if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
124 id = 0;
125
126 return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
127}
128
129int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
130 struct rsnd_mod *ssi_mod)
131{
132 struct rsnd_priv *priv = rsnd_io_to_priv(io);
133 struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
134
135 rsnd_mod_confirm_ssi(ssi_mod);
136
137 return rsnd_dai_connect(mod, io, mod->type);
138}
139
Kuninori Morimoto2ea6b072015-11-10 05:14:12 +0000140int rsnd_ssiu_probe(struct rsnd_priv *priv)
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +0000141{
142 struct device *dev = rsnd_priv_to_dev(priv);
143 struct rsnd_ssiu *ssiu;
144 static struct rsnd_mod_ops *ops;
145 int i, nr, ret;
146
147 /* same number to SSI */
148 nr = priv->ssi_nr;
149 ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
150 if (!ssiu)
151 return -ENOMEM;
152
153 priv->ssiu = ssiu;
154 priv->ssiu_nr = nr;
155
156 if (rsnd_is_gen1(priv))
157 ops = &rsnd_ssiu_ops_gen1;
158 else
159 ops = &rsnd_ssiu_ops_gen2;
160
161 for_each_rsnd_ssiu(ssiu, priv, i) {
162 ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
163 ops, NULL, RSND_MOD_SSIU, i);
164 if (ret)
165 return ret;
166 }
167
168 return 0;
169}
170
Kuninori Morimoto2ea6b072015-11-10 05:14:12 +0000171void rsnd_ssiu_remove(struct rsnd_priv *priv)
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +0000172{
173 struct rsnd_ssiu *ssiu;
174 int i;
175
176 for_each_rsnd_ssiu(ssiu, priv, i) {
177 rsnd_mod_quit(rsnd_mod_get(ssiu));
178 }
179}