blob: fc5ec17fe37e2e2854df5ec073e4cb995f1786aa [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,
85 rsnd_get_adinr_bit(mod, io));
86 rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
87 rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val);
88 }
89
90 return 0;
91}
92
93static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
94 struct rsnd_dai_stream *io,
95 struct rsnd_priv *priv)
96{
97 if (rsnd_ssi_use_busif(io))
98 rsnd_mod_write(mod, SSI_CTRL, 0x1);
99
100 return 0;
101}
102
103static int rsnd_ssiu_stop_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, 0);
109
110 return 0;
111}
112
113static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
114 .name = SSIU_NAME,
115 .init = rsnd_ssiu_init_gen2,
116 .start = rsnd_ssiu_start_gen2,
117 .stop = rsnd_ssiu_stop_gen2,
118};
119
120static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
121{
122 if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
123 id = 0;
124
125 return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
126}
127
128int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
129 struct rsnd_mod *ssi_mod)
130{
131 struct rsnd_priv *priv = rsnd_io_to_priv(io);
132 struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
133
134 rsnd_mod_confirm_ssi(ssi_mod);
135
136 return rsnd_dai_connect(mod, io, mod->type);
137}
138
139int rsnd_ssiu_probe(struct platform_device *pdev,
140 const struct rsnd_of_data *of_data,
141 struct rsnd_priv *priv)
142{
143 struct device *dev = rsnd_priv_to_dev(priv);
144 struct rsnd_ssiu *ssiu;
145 static struct rsnd_mod_ops *ops;
146 int i, nr, ret;
147
148 /* same number to SSI */
149 nr = priv->ssi_nr;
150 ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
151 if (!ssiu)
152 return -ENOMEM;
153
154 priv->ssiu = ssiu;
155 priv->ssiu_nr = nr;
156
157 if (rsnd_is_gen1(priv))
158 ops = &rsnd_ssiu_ops_gen1;
159 else
160 ops = &rsnd_ssiu_ops_gen2;
161
162 for_each_rsnd_ssiu(ssiu, priv, i) {
163 ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
164 ops, NULL, RSND_MOD_SSIU, i);
165 if (ret)
166 return ret;
167 }
168
169 return 0;
170}
171
172void rsnd_ssiu_remove(struct platform_device *pdev,
173 struct rsnd_priv *priv)
174{
175 struct rsnd_ssiu *ssiu;
176 int i;
177
178 for_each_rsnd_ssiu(ssiu, priv, i) {
179 rsnd_mod_quit(rsnd_mod_get(ssiu));
180 }
181}