blob: 326550114299e16908beb6cfa148687868a2a901 [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
Kuninori Morimoto186fadc2015-11-30 08:54:03 +000081 if (rsnd_get_slot_runtime(io) >= 6) {
82 /*
83 * TDM Extend Mode
84 * see
85 * rsnd_ssi_config_init()
86 */
87 rsnd_mod_write(mod, SSI_MODE, 0x1);
88 }
89
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +000090 if (rsnd_ssi_use_busif(io)) {
91 u32 val = rsnd_get_dalign(mod, io);
92
93 rsnd_mod_write(mod, SSI_BUSIF_ADINR,
Kuninori Morimotoc45f7262015-11-30 08:49:33 +000094 rsnd_get_adinr_bit(mod, io) |
95 rsnd_get_adinr_chan(mod, io));
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +000096 rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
97 rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val);
98 }
99
100 return 0;
101}
102
103static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
104 struct rsnd_dai_stream *io,
105 struct rsnd_priv *priv)
106{
107 if (rsnd_ssi_use_busif(io))
108 rsnd_mod_write(mod, SSI_CTRL, 0x1);
109
110 return 0;
111}
112
113static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
114 struct rsnd_dai_stream *io,
115 struct rsnd_priv *priv)
116{
117 if (rsnd_ssi_use_busif(io))
118 rsnd_mod_write(mod, SSI_CTRL, 0);
119
120 return 0;
121}
122
123static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
124 .name = SSIU_NAME,
125 .init = rsnd_ssiu_init_gen2,
126 .start = rsnd_ssiu_start_gen2,
127 .stop = rsnd_ssiu_stop_gen2,
128};
129
130static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
131{
132 if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
133 id = 0;
134
135 return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
136}
137
138int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
139 struct rsnd_mod *ssi_mod)
140{
141 struct rsnd_priv *priv = rsnd_io_to_priv(io);
142 struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
143
144 rsnd_mod_confirm_ssi(ssi_mod);
145
146 return rsnd_dai_connect(mod, io, mod->type);
147}
148
Kuninori Morimoto2ea6b072015-11-10 05:14:12 +0000149int rsnd_ssiu_probe(struct rsnd_priv *priv)
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +0000150{
151 struct device *dev = rsnd_priv_to_dev(priv);
152 struct rsnd_ssiu *ssiu;
153 static struct rsnd_mod_ops *ops;
154 int i, nr, ret;
155
156 /* same number to SSI */
157 nr = priv->ssi_nr;
158 ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
159 if (!ssiu)
160 return -ENOMEM;
161
162 priv->ssiu = ssiu;
163 priv->ssiu_nr = nr;
164
165 if (rsnd_is_gen1(priv))
166 ops = &rsnd_ssiu_ops_gen1;
167 else
168 ops = &rsnd_ssiu_ops_gen2;
169
170 for_each_rsnd_ssiu(ssiu, priv, i) {
171 ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
172 ops, NULL, RSND_MOD_SSIU, i);
173 if (ret)
174 return ret;
175 }
176
177 return 0;
178}
179
Kuninori Morimoto2ea6b072015-11-10 05:14:12 +0000180void rsnd_ssiu_remove(struct rsnd_priv *priv)
Kuninori Morimotoc7f69ab2015-10-26 08:43:41 +0000181{
182 struct rsnd_ssiu *ssiu;
183 int i;
184
185 for_each_rsnd_ssiu(ssiu, priv, i) {
186 rsnd_mod_quit(rsnd_mod_get(ssiu));
187 }
188}