xref: /netbsd-src/sys/arch/arm/sociox/sni_i2c.c (revision a960b269de05fcdb3d4672f4d2ae21629cf986c5)
1 /*	$NetBSD: sni_i2c.c,v 1.15 2022/03/24 08:08:05 andvar 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.15 2022/03/24 08:08:05 andvar Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/intr.h>
42 #include <sys/device.h>
43 #include <sys/mutex.h>
44 #include <sys/condvar.h>
45 #include <sys/errno.h>
46 #include <sys/kernel.h>
47 #include <sys/systm.h>
48 
49 #include <dev/i2c/i2cvar.h>
50 
51 #include <dev/fdt/fdtvar.h>
52 #include <dev/acpi/acpireg.h>
53 #include <dev/acpi/acpivar.h>
54 #include <dev/acpi/acpi_intr.h>
55 
56 #define BSR		0x00		/* status */
57 #define  BSR_BB		(1U<<7)		/* busy */
58 #define  BSR_RSC	(1U<<6)		/* repeated cycle condition */
59 #define  BSR_AL		(1U<<5)		/* arbitration lost */
60 #define  BSR_LRB	(1U<<4)		/* last bit received */
61 #define  BSR_XFR	(1U<<3)		/* start transfer */
62 #define  BSR_AAS	(1U<<2)		/* ??? address as slave */
63 #define  BSR_GCA	(1U<<1)		/* ??? general call address */
64 #define  BSR_FBT	(1U<<0)		/* first byte transfer detected */
65 #define BCR		0x04		/* control */
66 #define  BCR_BERR	(1U<<7)		/* bus error report; W0C */
67 #define  BCR_BEIEN	(1U<<6)		/* enable bus error interrupt */
68 #define  BCR_SCC	(1U<<5)		/* make start condition */
69 #define  BCR_MSS	(1U<<4)		/* 1: xmit, 0: recv */
70 #define  BCR_ACK	(1U<<3)		/* make acknowledge at last byte */
71 #define  BCR_GCAA	(1U<<2)		/* ??? general call access ack */
72 #define  BCR_IEN	(1U<<1)		/* enable interrupt */
73 #define  BCR_INT	(1U<<0)		/* interrupt report; W0C */
74 #define CCR		0x08
75 #define  CCR_FM		(1U<<6)		/* speed; 1: fast, 0: standard */
76 #define  CCR_EN		(1U<<5)		/* enable clock feed */
77 /* 4:0 clock rate select */
78 #define ADR		0x0c		/* 6:0 my own address */
79 #define DAR		0x10		/* 7:0 data port */
80 #define CSR		0x14		/* 5:0 clock divisor */
81 #define FSR		0x18		/* bus clock frequency */
82 #define BC2R		0x1c		/* control 2 */
83 #define  BC2R_SDA	(1U<<5)		/* detected SDA signal */
84 #define  BC2R_SCL	(1U<<5)		/* detected SCL signal */
85 #define  BC2R_SDA_L	(1U<<1)		/* make SDA signal low */
86 #define  BC2R_SCL_L	(1U<<1)		/* make SCL signal low */
87 
88 static int sniiic_fdt_match(device_t, struct cfdata *, void *);
89 static void sniiic_fdt_attach(device_t, device_t, void *);
90 static int sniiic_acpi_match(device_t, struct cfdata *, void *);
91 static void sniiic_acpi_attach(device_t, device_t, void *);
92 
93 typedef enum {
94 	EXEC_IDLE	= 0,	/* sane and idle */
95 	EXEC_ADDR	= 1,	/* send address bits */
96 	EXEC_CMD	= 2,	/* send command bits */
97 	EXEC_SEND	= 3,	/* data xmit */
98 	EXEC_RECV	= 4,	/* data recv */
99 	EXEC_DONE	= 5,	/* xter done */
100 	EXEC_ERR	= 6,	/* recover error */
101 } state_t;
102 
103 struct sniiic_softc {
104 	device_t		sc_dev;
105 	struct i2c_controller	sc_ic;
106 	bus_space_tag_t		sc_iot;
107 	bus_space_handle_t	sc_ioh;
108 	bus_size_t		sc_ios;
109 	void			*sc_ih;
110 	kmutex_t		sc_lock;
111 	kmutex_t		sc_mtx;
112 	kcondvar_t		sc_cv;
113 	volatile bool		sc_busy;
114 	state_t			sc_state;
115 	u_int			sc_frequency;
116 	u_int			sc_clkrate;
117 	int			sc_phandle;
118 };
119 
120 CFATTACH_DECL_NEW(sniiic_fdt, sizeof(struct sniiic_softc),
121     sniiic_fdt_match, sniiic_fdt_attach, NULL, NULL);
122 
123 CFATTACH_DECL_NEW(sniiic_acpi, sizeof(struct sniiic_softc),
124     sniiic_acpi_match, sniiic_acpi_attach, NULL, NULL);
125 
126 void sni_i2c_common_i(struct sniiic_softc *);
127 
128 static int sni_i2c_acquire_bus(void *, int);
129 static void sni_i2c_release_bus(void *, int);
130 static int sni_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
131 			size_t, void *, size_t, int);
132 
133 static int sni_i2c_intr(void *);
134 static void sni_i2c_reset(struct sniiic_softc *);
135 static void sni_i2c_flush(struct sniiic_softc *);
136 
137 #define CSR_READ(sc, reg) \
138     bus_space_read_4((sc)->sc_ioh,(sc)->sc_ioh,(reg))
139 #define CSR_WRITE(sc, reg, val) \
140     bus_space_write_4((sc)->sc_ioh,(sc)->sc_ioh,(reg),(val))
141 
142 static const struct device_compatible_entry compat_data[] = {
143 	{ .compat = "socionext,synquacer-i2c" },
144 	DEVICE_COMPAT_EOL
145 };
146 static const struct device_compatible_entry compatible[] = {
147 	{ .compat = "SCX0003" },
148 	DEVICE_COMPAT_EOL
149 };
150 
151 static int
sniiic_fdt_match(device_t parent,struct cfdata * match,void * aux)152 sniiic_fdt_match(device_t parent, struct cfdata *match, void *aux)
153 {
154 	struct fdt_attach_args * const faa = aux;
155 
156 	return of_compatible_match(faa->faa_phandle, compat_data);
157 }
158 
159 static void
sniiic_fdt_attach(device_t parent,device_t self,void * aux)160 sniiic_fdt_attach(device_t parent, device_t self, void *aux)
161 {
162 	struct sniiic_softc * const sc = device_private(self);
163 	struct fdt_attach_args * const faa = aux;
164 	const int phandle = faa->faa_phandle;
165 	bus_space_handle_t ioh;
166 	bus_addr_t addr;
167 	bus_size_t size;
168 	char intrstr[128];
169 
170 	aprint_naive("\n");
171 	aprint_normal(": Socionext I2C controller\n");
172 
173 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0
174 	    || bus_space_map(faa->faa_bst, addr, size, 0, &ioh) != 0) {
175 		aprint_error_dev(self, "unable to map device\n");
176 		return;
177 	}
178 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
179 		aprint_error_dev(self, "failed to decode interrupt\n");
180 		goto fail;
181 	}
182 	sc->sc_ih = fdtbus_intr_establish(phandle,
183 			0, IPL_BIO, 0, sni_i2c_intr, sc);
184 	if (sc->sc_ih == NULL) {
185 		aprint_error_dev(self, "couldn't establish interrupt\n");
186 		goto fail;
187 	}
188 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
189 
190 	sc->sc_dev = self;
191 	sc->sc_iot = faa->faa_bst;
192 	sc->sc_ioh = ioh;
193 	sc->sc_ios = size;
194 	sc->sc_phandle = phandle;
195 
196 	sni_i2c_common_i(sc);
197 
198 	fdtbus_register_i2c_controller(&sc->sc_ic, phandle);
199 #if 0
200 	fdtbus_attach_i2cbus(self, phandle, &sc->sc_ic, iicbus_print);
201 #endif
202 	return;
203  fail:
204 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
205 	return;
206 }
207 
208 static int
sniiic_acpi_match(device_t parent,struct cfdata * match,void * aux)209 sniiic_acpi_match(device_t parent, struct cfdata *match, void *aux)
210 {
211 	struct acpi_attach_args *aa = aux;
212 
213 	return acpi_compatible_match(aa, compatible);
214 }
215 
216 static void
sniiic_acpi_attach(device_t parent,device_t self,void * aux)217 sniiic_acpi_attach(device_t parent, device_t self, void *aux)
218 {
219 	struct sniiic_softc * const sc = device_private(self);
220 	struct acpi_attach_args *aa = aux;
221 	ACPI_HANDLE handle = aa->aa_node->ad_handle;
222 	bus_space_handle_t ioh;
223 	struct i2cbus_attach_args iba;
224 	struct acpi_resources res;
225 	struct acpi_mem *mem;
226 	struct acpi_irq *irq;
227 	ACPI_STATUS rv;
228 
229 	aprint_naive("\n");
230 	aprint_normal(": Socionext I2C controller\n");
231 
232 	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
233 	    &res, &acpi_resource_parse_ops_default);
234 	if (ACPI_FAILURE(rv)) {
235 		aprint_error_dev(self, "missing crs resources\n");
236 		return;
237 	}
238 	mem = acpi_res_mem(&res, 0);
239 	irq = acpi_res_irq(&res, 0);
240 	if (mem == NULL || irq == NULL || mem->ar_length == 0) {
241 		aprint_error_dev(self, "incomplete resources\n");
242 		return;
243 	}
244 	if (bus_space_map(aa->aa_memt, mem->ar_base, mem->ar_length, 0,
245 	    &ioh)) {
246 		aprint_error_dev(self, "couldn't map registers\n");
247 		return;
248 	}
249 	sc->sc_ih = acpi_intr_establish(self, (uint64_t)handle,
250 	    IPL_BIO, false, sni_i2c_intr, sc, device_xname(self));
251 	if (sc->sc_ih == NULL) {
252 		aprint_error_dev(self, "couldn't establish interrupt\n");
253 		goto fail;
254 	}
255 
256 	sc->sc_dev = self;
257 	sc->sc_iot = aa->aa_memt;
258 	sc->sc_ioh = ioh;
259 	sc->sc_ios = mem->ar_length;
260 	sc->sc_phandle = 0;
261 
262 	sni_i2c_common_i(sc);
263 
264 	memset(&iba, 0, sizeof(iba));
265 	iba.iba_tag = &sc->sc_ic;
266 #if 0
267 	config_found(sc->sc_dev, &iba, iicbus_print, CFARGS_NONE);
268 #endif
269 
270 	acpi_resource_cleanup(&res);
271 
272 	return;
273  fail:
274 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
275 	acpi_resource_cleanup(&res);
276 	return;
277 }
278 
279 void
sni_i2c_common_i(struct sniiic_softc * sc)280 sni_i2c_common_i(struct sniiic_softc *sc)
281 {
282 
283 	iic_tag_init(&sc->sc_ic);
284 	sc->sc_ic.ic_cookie = sc;
285 	sc->sc_ic.ic_acquire_bus = sni_i2c_acquire_bus;
286 	sc->sc_ic.ic_release_bus = sni_i2c_release_bus;
287 	sc->sc_ic.ic_exec = sni_i2c_exec;
288 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
289 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_BIO);
290 	cv_init(&sc->sc_cv, device_xname(sc->sc_dev));
291 
292 	/* no attach here */
293 }
294 
295 static int
sni_i2c_acquire_bus(void * opaque,int flags)296 sni_i2c_acquire_bus(void *opaque, int flags)
297 {
298 	struct sniiic_softc *sc = opaque;
299 
300 	mutex_enter(&sc->sc_lock);
301 	while (sc->sc_busy)
302 		cv_wait(&sc->sc_cv, &sc->sc_lock);
303 	sc->sc_busy = true;
304 	mutex_exit(&sc->sc_lock);
305 
306 	return 0;
307 }
308 
309 static void
sni_i2c_release_bus(void * opaque,int flags)310 sni_i2c_release_bus(void *opaque, int flags)
311 {
312 	struct sniiic_softc *sc = opaque;
313 
314 	mutex_enter(&sc->sc_lock);
315 	sc->sc_busy = false;
316 	cv_broadcast(&sc->sc_cv);
317 	mutex_exit(&sc->sc_lock);
318 }
319 
320 static int
sni_i2c_exec(void * opaque,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)321 sni_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
322     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
323 {
324 	struct sniiic_softc *sc = opaque;
325 	int err;
326 #if 0
327 	printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
328 	    device_xname(sc->sc_dev), op, addr, (int)cmdlen, (int)len, flags);
329 #endif
330 
331 	err = 0;
332 	/* AAA */
333 	goto done;
334  done:
335 	if (err)
336 		sni_i2c_reset(sc);
337 	sni_i2c_flush(sc);
338 	return err;
339 }
340 
341 static int
sni_i2c_intr(void * arg)342 sni_i2c_intr(void *arg)
343 {
344 	struct sniiic_softc * const sc = arg;
345 	uint32_t stat = 0;
346 
347 	(void)stat;
348 	mutex_enter(&sc->sc_mtx);
349 	cv_broadcast(&sc->sc_cv);
350 	mutex_exit(&sc->sc_mtx);
351 	return 1;
352 }
353 
354 static void
sni_i2c_reset(struct sniiic_softc * sc)355 sni_i2c_reset(struct sniiic_softc *sc)
356 {
357 	/* AAA */
358 }
359 
360 static void
sni_i2c_flush(struct sniiic_softc * sc)361 sni_i2c_flush(struct sniiic_softc *sc)
362 {
363 	/* AAA */
364 }
365