Home | History | Annotate | Line # | Download | only in sociox
      1 /*	$NetBSD: sni_i2c.c,v 1.17 2025/09/16 11:55:17 thorpej 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.17 2025/09/16 11:55:17 thorpej 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
    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
    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 #if 0
    199 	iicbus_attach(self, &sc->sc_ic);
    200 #endif
    201 	return;
    202  fail:
    203 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
    204 	return;
    205 }
    206 
    207 static int
    208 sniiic_acpi_match(device_t parent, struct cfdata *match, void *aux)
    209 {
    210 	struct acpi_attach_args *aa = aux;
    211 
    212 	return acpi_compatible_match(aa, compatible);
    213 }
    214 
    215 static void
    216 sniiic_acpi_attach(device_t parent, device_t self, void *aux)
    217 {
    218 	struct sniiic_softc * const sc = device_private(self);
    219 	struct acpi_attach_args *aa = aux;
    220 	ACPI_HANDLE handle = aa->aa_node->ad_handle;
    221 	bus_space_handle_t ioh;
    222 	struct i2cbus_attach_args iba;
    223 	struct acpi_resources res;
    224 	struct acpi_mem *mem;
    225 	struct acpi_irq *irq;
    226 	ACPI_STATUS rv;
    227 
    228 	aprint_naive("\n");
    229 	aprint_normal(": Socionext I2C controller\n");
    230 
    231 	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
    232 	    &res, &acpi_resource_parse_ops_default);
    233 	if (ACPI_FAILURE(rv)) {
    234 		aprint_error_dev(self, "missing crs resources\n");
    235 		return;
    236 	}
    237 	mem = acpi_res_mem(&res, 0);
    238 	irq = acpi_res_irq(&res, 0);
    239 	if (mem == NULL || irq == NULL || mem->ar_length == 0) {
    240 		aprint_error_dev(self, "incomplete resources\n");
    241 		return;
    242 	}
    243 	if (bus_space_map(aa->aa_memt, mem->ar_base, mem->ar_length, 0,
    244 	    &ioh)) {
    245 		aprint_error_dev(self, "couldn't map registers\n");
    246 		return;
    247 	}
    248 	sc->sc_ih = acpi_intr_establish(self, (uint64_t)handle,
    249 	    IPL_BIO, false, sni_i2c_intr, sc, device_xname(self));
    250 	if (sc->sc_ih == NULL) {
    251 		aprint_error_dev(self, "couldn't establish interrupt\n");
    252 		goto fail;
    253 	}
    254 
    255 	sc->sc_dev = self;
    256 	sc->sc_iot = aa->aa_memt;
    257 	sc->sc_ioh = ioh;
    258 	sc->sc_ios = mem->ar_length;
    259 	sc->sc_phandle = 0;
    260 
    261 	sni_i2c_common_i(sc);
    262 
    263 	memset(&iba, 0, sizeof(iba));
    264 	iba.iba_tag = &sc->sc_ic;
    265 #if 0
    266 	config_found(sc->sc_dev, &iba, iicbus_print, CFARGS_NONE);
    267 #endif
    268 
    269 	acpi_resource_cleanup(&res);
    270 
    271 	return;
    272  fail:
    273 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
    274 	acpi_resource_cleanup(&res);
    275 	return;
    276 }
    277 
    278 void
    279 sni_i2c_common_i(struct sniiic_softc *sc)
    280 {
    281 
    282 	iic_tag_init(&sc->sc_ic);
    283 	sc->sc_ic.ic_cookie = sc;
    284 	sc->sc_ic.ic_acquire_bus = sni_i2c_acquire_bus;
    285 	sc->sc_ic.ic_release_bus = sni_i2c_release_bus;
    286 	sc->sc_ic.ic_exec = sni_i2c_exec;
    287 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    288 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_BIO);
    289 	cv_init(&sc->sc_cv, device_xname(sc->sc_dev));
    290 
    291 	/* no attach here */
    292 }
    293 
    294 static int
    295 sni_i2c_acquire_bus(void *opaque, int flags)
    296 {
    297 	struct sniiic_softc *sc = opaque;
    298 
    299 	mutex_enter(&sc->sc_lock);
    300 	while (sc->sc_busy)
    301 		cv_wait(&sc->sc_cv, &sc->sc_lock);
    302 	sc->sc_busy = true;
    303 	mutex_exit(&sc->sc_lock);
    304 
    305 	return 0;
    306 }
    307 
    308 static void
    309 sni_i2c_release_bus(void *opaque, int flags)
    310 {
    311 	struct sniiic_softc *sc = opaque;
    312 
    313 	mutex_enter(&sc->sc_lock);
    314 	sc->sc_busy = false;
    315 	cv_broadcast(&sc->sc_cv);
    316 	mutex_exit(&sc->sc_lock);
    317 }
    318 
    319 static int
    320 sni_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
    321     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
    322 {
    323 	struct sniiic_softc *sc = opaque;
    324 	int err;
    325 #if 0
    326 	printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
    327 	    device_xname(sc->sc_dev), op, addr, (int)cmdlen, (int)len, flags);
    328 #endif
    329 
    330 	err = 0;
    331 	/* AAA */
    332 	goto done;
    333  done:
    334 	if (err)
    335 		sni_i2c_reset(sc);
    336 	sni_i2c_flush(sc);
    337 	return err;
    338 }
    339 
    340 static int
    341 sni_i2c_intr(void *arg)
    342 {
    343 	struct sniiic_softc * const sc = arg;
    344 	uint32_t stat = 0;
    345 
    346 	(void)stat;
    347 	mutex_enter(&sc->sc_mtx);
    348 	cv_broadcast(&sc->sc_cv);
    349 	mutex_exit(&sc->sc_mtx);
    350 	return 1;
    351 }
    352 
    353 static void
    354 sni_i2c_reset(struct sniiic_softc *sc)
    355 {
    356 	/* AAA */
    357 }
    358 
    359 static void
    360 sni_i2c_flush(struct sniiic_softc *sc)
    361 {
    362 	/* AAA */
    363 }
    364