sni_i2c.c revision 1.3 1 /* $NetBSD: sni_i2c.c,v 1.3 2020/03/18 07:49:01 nisimura Exp $ */
2
3 /*-
4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Socionext SC2A11 SynQuacer I2C driver
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: sni_i2c.c,v 1.3 2020/03/18 07:49:01 nisimura Exp $");
38
39 #ifdef I2CDEBUG
40 #define DPRINTF(args) printf args
41 #else
42 #define DPRINTF(args)
43 #endif
44
45 #include <sys/param.h>
46 #include <sys/bus.h>
47 #include <sys/intr.h>
48 #include <sys/device.h>
49 #include <sys/mutex.h>
50 #include <sys/condvar.h>
51 #include <sys/errno.h>
52 #include <sys/kernel.h>
53 #include <sys/systm.h>
54
55 #include <dev/i2c/i2cvar.h>
56
57 #include <dev/fdt/fdtvar.h>
58 #include <dev/acpi/acpireg.h>
59 #include <dev/acpi/acpivar.h>
60 #include <dev/acpi/acpi_intr.h>
61
62 static int sniiic_fdt_match(device_t, struct cfdata *, void *);
63 static void sniiic_fdt_attach(device_t, device_t, void *);
64 static int sniiic_acpi_match(device_t, struct cfdata *, void *);
65 static void sniiic_acpi_attach(device_t, device_t, void *);
66
67 struct sniiic_softc {
68 device_t sc_dev;
69 struct i2c_controller sc_ic;
70 device_t sc_i2cdev;
71 bus_space_tag_t sc_iot;
72 bus_space_handle_t sc_ioh;
73 bus_addr_t sc_iob;
74 bus_size_t sc_ios;
75 void *sc_ih;
76 kmutex_t sc_lock;
77 kmutex_t sc_mtx;
78 kcondvar_t sc_cv;
79 int sc_opflags;
80 bool sc_busy;
81 };
82
83 CFATTACH_DECL_NEW(sniiic_fdt, sizeof(struct sniiic_softc),
84 sniiic_fdt_match, sniiic_fdt_attach, NULL, NULL);
85
86 CFATTACH_DECL_NEW(sniiic_acpi, sizeof(struct sniiic_softc),
87 sniiic_acpi_match, sniiic_acpi_attach, NULL, NULL);
88
89 static int sniiic_acquire_bus(void *, int);
90 static void sniiic_release_bus(void *, int);
91 static int sniiic_exec(void *, i2c_op_t, i2c_addr_t, const void *,
92 size_t, void *, size_t, int);
93
94 static int sniiic_intr(void *);
95 static void sniiic_reset(struct sniiic_softc *);
96 static void sniiic_flush(struct sniiic_softc *);
97
98 static i2c_tag_t sniiic_get_tag(device_t);
99 static const struct fdtbus_i2c_controller_func sniiic_funcs = {
100 .get_tag = sniiic_get_tag,
101 };
102
103 static int
104 sniiic_fdt_match(device_t parent, struct cfdata *match, void *aux)
105 {
106 static const char * compatible[] = {
107 "socionext,synquacer-i2c",
108 NULL
109 };
110 struct fdt_attach_args * const faa = aux;
111
112 return of_match_compatible(faa->faa_phandle, compatible);
113 }
114
115 static void
116 sniiic_fdt_attach(device_t parent, device_t self, void *aux)
117 {
118 struct sniiic_softc * const sc = device_private(self);
119 struct fdt_attach_args * const faa = aux;
120 prop_dictionary_t dict = device_properties(self);
121 const int phandle = faa->faa_phandle;
122 bus_space_handle_t ioh;
123 bus_addr_t addr;
124 bus_size_t size;
125 void *ih;
126 char intrstr[128];
127 _Bool disable;
128 int error;
129
130 prop_dictionary_get_bool(dict, "disable", &disable);
131 if (disable) {
132 aprint_naive(": disabled\n");
133 aprint_normal(": disabled\n");
134 return;
135 }
136 error = fdtbus_get_reg(phandle, 0, &addr, &size);
137 if (error) {
138 aprint_error(": couldn't get registers\n");
139 return;
140 }
141 error = bus_space_map(faa->faa_bst, addr, size, 0, &ioh);
142 if (error) {
143 aprint_error(": unable to map device\n");
144 return;
145 }
146 error = fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr));
147 if (error) {
148 aprint_error(": failed to decode interrupt\n");
149 return;
150 }
151
152 aprint_naive(": I2C controller\n");
153 aprint_normal(": I2C controller\n");
154
155 sc->sc_dev = self;
156 sc->sc_iot = faa->faa_bst;
157 sc->sc_ioh = ioh;
158 sc->sc_iob = addr;
159 sc->sc_ios = size;
160 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
161 mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NET);
162 cv_init(&sc->sc_cv, "sniiic");
163 sc->sc_ic.ic_cookie = sc;
164 sc->sc_ic.ic_acquire_bus = sniiic_acquire_bus;
165 sc->sc_ic.ic_release_bus = sniiic_release_bus;
166 sc->sc_ic.ic_exec = sniiic_exec;
167
168 ih = fdtbus_intr_establish(phandle, 0, IPL_NET, 0, sniiic_intr, sc);
169 if (ih == NULL) {
170 aprint_error_dev(self, "couldn't establish interrupt\n");
171 goto fail;
172 }
173 sc->sc_ih = ih;
174
175 fdtbus_register_i2c_controller(self, phandle, &sniiic_funcs);
176 fdtbus_attach_i2cbus(self, phandle, &sc->sc_ic, iicbus_print);
177
178 return;
179 fail:
180 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
181 return;
182 }
183
184 static int
185 sniiic_acpi_match(device_t parent, struct cfdata *match, void *aux)
186 {
187 static const char * compatible[] = {
188 "SCX0003",
189 NULL
190 };
191 struct acpi_attach_args *aa = aux;
192
193 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
194 return 0;
195 return acpi_match_hid(aa->aa_node->ad_devinfo, compatible);
196 }
197
198 static void
199 sniiic_acpi_attach(device_t parent, device_t self, void *aux)
200 {
201 struct sniiic_softc * const sc = device_private(self);
202 struct acpi_attach_args *aa = aux;
203 bus_space_handle_t ioh;
204 struct acpi_resources res;
205 struct acpi_mem *mem;
206 struct acpi_irq *irq;
207 ACPI_STATUS rv;
208 void *ih;
209
210 rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
211 &res, &acpi_resource_parse_ops_default);
212 if (ACPI_FAILURE(rv))
213 return;
214
215 mem = acpi_res_mem(&res, 0);
216 irq = acpi_res_irq(&res, 0);
217 if (mem == NULL || irq == NULL) {
218 aprint_error(": incomplete resources\n");
219 return;
220 }
221 if (mem->ar_length == 0) {
222 aprint_error(": zero length memory resource\n");
223 return;
224 }
225 if (bus_space_map(aa->aa_memt, mem->ar_base, mem->ar_length, 0,
226 &ioh)) {
227 aprint_error(": couldn't map registers\n");
228 return;
229 }
230
231 aprint_naive(": I2C controller\n");
232 aprint_normal(": I2C controller\n");
233
234 sc->sc_dev = self;
235 sc->sc_iot = aa->aa_memt;
236 sc->sc_ioh = ioh;
237 sc->sc_iob = mem->ar_base;
238 sc->sc_ios = mem->ar_length;
239 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
240 mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NET);
241 cv_init(&sc->sc_cv, "sniiic");
242 sc->sc_ic.ic_cookie = sc;
243 sc->sc_ic.ic_acquire_bus = sniiic_acquire_bus;
244 sc->sc_ic.ic_release_bus = sniiic_release_bus;
245 sc->sc_ic.ic_exec = sniiic_exec;
246
247 ih = acpi_intr_establish(self,
248 (uint64_t)(uintptr_t)aa->aa_node->ad_handle,
249 IPL_BIO, false, sniiic_intr, sc, device_xname(self));
250 if (ih == NULL) {
251 aprint_error_dev(self, "couldn't establish interrupt\n");
252 goto fail;
253 }
254 sc->sc_ih = ih;
255
256 acpi_resource_cleanup(&res);
257
258 return;
259 fail:
260 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
261 acpi_resource_cleanup(&res);
262 return;
263 }
264
265 static int
266 sniiic_acquire_bus(void *opaque, int flags)
267 {
268 struct sniiic_softc *sc = opaque;
269
270 mutex_enter(&sc->sc_lock);
271 while (sc->sc_busy)
272 cv_wait(&sc->sc_cv, &sc->sc_lock);
273 sc->sc_busy = true;
274 mutex_exit(&sc->sc_lock);
275
276 return 0;
277 }
278
279 static void
280 sniiic_release_bus(void *opaque, int flags)
281 {
282 struct sniiic_softc *sc = opaque;
283
284 mutex_enter(&sc->sc_lock);
285 sc->sc_busy = false;
286 cv_broadcast(&sc->sc_cv);
287 mutex_exit(&sc->sc_lock);
288 }
289
290 static int
291 sniiic_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
292 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
293 {
294 struct sniiic_softc *sc = opaque;
295 int err;
296
297 DPRINTF(("sniic_exec: op 0x%x cmdlen %zd len %zd flags 0x%x\n",
298 op, cmdlen, len, flags));
299 err = 0;
300 /* AAA */
301 goto done;
302 done:
303 if (err)
304 sniiic_reset(sc);
305 sniiic_flush(sc);
306 DPRINTF(("sniiic_exec: done %d\n", err));
307 return err;
308 }
309
310 static int
311 sniiic_intr(void *arg)
312 {
313 struct sniiic_softc * const sc = arg;
314 uint32_t stat = 0;
315
316 mutex_enter(&sc->sc_mtx);
317 DPRINTF(("sniiic_intr opflags=%#x\n", sc->sc_opflags));
318 if ((sc->sc_opflags & I2C_F_POLL) == 0) {
319 /* AAA */
320 (void)stat;
321 cv_broadcast(&sc->sc_cv);
322 }
323 mutex_exit(&sc->sc_mtx);
324 DPRINTF(("sniiic_intr status 0x%x\n", stat));
325 return 1;
326 }
327
328 static void
329 sniiic_reset(struct sniiic_softc *sc)
330 {
331 /* AAA */
332 }
333
334 static void
335 sniiic_flush(struct sniiic_softc *sc)
336 {
337 /* AAA */
338 }
339
340 static i2c_tag_t
341 sniiic_get_tag(device_t dev)
342 {
343 struct sniiic_softc * const sc = device_private(dev);
344
345 return &sc->sc_ic;
346 }
347