Home | History | Annotate | Line # | Download | only in sociox
      1  1.17   thorpej /*	$NetBSD: sni_i2c.c,v 1.17 2025/09/16 11:55:17 thorpej Exp $	*/
      2   1.1  nisimura 
      3   1.1  nisimura /*-
      4   1.1  nisimura  * Copyright (c) 2020 The NetBSD Foundation, Inc.
      5   1.1  nisimura  * All rights reserved.
      6   1.1  nisimura  *
      7   1.1  nisimura  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  nisimura  * by Tohru Nishimura.
      9   1.1  nisimura  *
     10   1.1  nisimura  * Redistribution and use in source and binary forms, with or without
     11   1.1  nisimura  * modification, are permitted provided that the following conditions
     12   1.1  nisimura  * are met:
     13   1.1  nisimura  * 1. Redistributions of source code must retain the above copyright
     14   1.1  nisimura  *    notice, this list of conditions and the following disclaimer.
     15   1.1  nisimura  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  nisimura  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  nisimura  *    documentation and/or other materials provided with the distribution.
     18   1.1  nisimura  *
     19   1.1  nisimura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  nisimura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  nisimura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  nisimura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  nisimura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  nisimura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  nisimura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  nisimura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  nisimura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  nisimura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  nisimura  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  nisimura  */
     31   1.1  nisimura 
     32   1.1  nisimura /*
     33   1.1  nisimura  * Socionext SC2A11 SynQuacer I2C driver
     34   1.1  nisimura  */
     35   1.1  nisimura 
     36   1.1  nisimura #include <sys/cdefs.h>
     37  1.17   thorpej __KERNEL_RCSID(0, "$NetBSD: sni_i2c.c,v 1.17 2025/09/16 11:55:17 thorpej Exp $");
     38   1.1  nisimura 
     39   1.1  nisimura #include <sys/param.h>
     40   1.1  nisimura #include <sys/bus.h>
     41   1.1  nisimura #include <sys/intr.h>
     42   1.1  nisimura #include <sys/device.h>
     43   1.3  nisimura #include <sys/mutex.h>
     44   1.3  nisimura #include <sys/condvar.h>
     45   1.1  nisimura #include <sys/errno.h>
     46   1.1  nisimura #include <sys/kernel.h>
     47   1.1  nisimura #include <sys/systm.h>
     48   1.1  nisimura 
     49   1.3  nisimura #include <dev/i2c/i2cvar.h>
     50   1.1  nisimura 
     51   1.1  nisimura #include <dev/fdt/fdtvar.h>
     52   1.1  nisimura #include <dev/acpi/acpireg.h>
     53   1.1  nisimura #include <dev/acpi/acpivar.h>
     54   1.3  nisimura #include <dev/acpi/acpi_intr.h>
     55   1.1  nisimura 
     56  1.14  nisimura #define BSR		0x00		/* status */
     57  1.14  nisimura #define  BSR_BB		(1U<<7)		/* busy */
     58  1.14  nisimura #define  BSR_RSC	(1U<<6)		/* repeated cycle condition */
     59  1.14  nisimura #define  BSR_AL		(1U<<5)		/* arbitration lost */
     60  1.14  nisimura #define  BSR_LRB	(1U<<4)		/* last bit received */
     61  1.14  nisimura #define  BSR_XFR	(1U<<3)		/* start transfer */
     62  1.14  nisimura #define  BSR_AAS	(1U<<2)		/* ??? address as slave */
     63  1.14  nisimura #define  BSR_GCA	(1U<<1)		/* ??? general call address */
     64  1.14  nisimura #define  BSR_FBT	(1U<<0)		/* first byte transfer detected */
     65  1.14  nisimura #define BCR		0x04		/* control */
     66  1.14  nisimura #define  BCR_BERR	(1U<<7)		/* bus error report; W0C */
     67  1.14  nisimura #define  BCR_BEIEN	(1U<<6)		/* enable bus error interrupt */
     68  1.14  nisimura #define  BCR_SCC	(1U<<5)		/* make start condition */
     69  1.14  nisimura #define  BCR_MSS	(1U<<4)		/* 1: xmit, 0: recv */
     70  1.14  nisimura #define  BCR_ACK	(1U<<3)		/* make acknowledge at last byte */
     71  1.14  nisimura #define  BCR_GCAA	(1U<<2)		/* ??? general call access ack */
     72  1.15    andvar #define  BCR_IEN	(1U<<1)		/* enable interrupt */
     73  1.14  nisimura #define  BCR_INT	(1U<<0)		/* interrupt report; W0C */
     74  1.14  nisimura #define CCR		0x08
     75  1.14  nisimura #define  CCR_FM		(1U<<6)		/* speed; 1: fast, 0: standard */
     76  1.14  nisimura #define  CCR_EN		(1U<<5)		/* enable clock feed */
     77  1.14  nisimura /* 4:0 clock rate select */
     78  1.14  nisimura #define ADR		0x0c		/* 6:0 my own address */
     79  1.14  nisimura #define DAR		0x10		/* 7:0 data port */
     80  1.14  nisimura #define CSR		0x14		/* 5:0 clock divisor */
     81  1.14  nisimura #define FSR		0x18		/* bus clock frequency */
     82  1.14  nisimura #define BC2R		0x1c		/* control 2 */
     83  1.14  nisimura #define  BC2R_SDA	(1U<<5)		/* detected SDA signal */
     84  1.14  nisimura #define  BC2R_SCL	(1U<<5)		/* detected SCL signal */
     85  1.14  nisimura #define  BC2R_SDA_L	(1U<<1)		/* make SDA signal low */
     86  1.14  nisimura #define  BC2R_SCL_L	(1U<<1)		/* make SCL signal low */
     87  1.14  nisimura 
     88   1.1  nisimura static int sniiic_fdt_match(device_t, struct cfdata *, void *);
     89   1.1  nisimura static void sniiic_fdt_attach(device_t, device_t, void *);
     90   1.1  nisimura static int sniiic_acpi_match(device_t, struct cfdata *, void *);
     91   1.1  nisimura static void sniiic_acpi_attach(device_t, device_t, void *);
     92   1.1  nisimura 
     93  1.14  nisimura typedef enum {
     94  1.14  nisimura 	EXEC_IDLE	= 0,	/* sane and idle */
     95  1.14  nisimura 	EXEC_ADDR	= 1,	/* send address bits */
     96  1.14  nisimura 	EXEC_CMD	= 2,	/* send command bits */
     97  1.14  nisimura 	EXEC_SEND	= 3,	/* data xmit */
     98  1.14  nisimura 	EXEC_RECV	= 4,	/* data recv */
     99  1.14  nisimura 	EXEC_DONE	= 5,	/* xter done */
    100  1.14  nisimura 	EXEC_ERR	= 6,	/* recover error */
    101  1.14  nisimura } state_t;
    102  1.14  nisimura 
    103   1.1  nisimura struct sniiic_softc {
    104   1.3  nisimura 	device_t		sc_dev;
    105   1.3  nisimura 	struct i2c_controller	sc_ic;
    106   1.3  nisimura 	bus_space_tag_t		sc_iot;
    107   1.3  nisimura 	bus_space_handle_t	sc_ioh;
    108   1.3  nisimura 	bus_size_t		sc_ios;
    109   1.3  nisimura 	void			*sc_ih;
    110   1.3  nisimura 	kmutex_t		sc_lock;
    111   1.3  nisimura 	kmutex_t		sc_mtx;
    112   1.3  nisimura 	kcondvar_t		sc_cv;
    113   1.6  nisimura 	volatile bool		sc_busy;
    114  1.14  nisimura 	state_t			sc_state;
    115  1.14  nisimura 	u_int			sc_frequency;
    116  1.14  nisimura 	u_int			sc_clkrate;
    117   1.4  nisimura 	int			sc_phandle;
    118   1.1  nisimura };
    119   1.1  nisimura 
    120   1.1  nisimura CFATTACH_DECL_NEW(sniiic_fdt, sizeof(struct sniiic_softc),
    121   1.1  nisimura     sniiic_fdt_match, sniiic_fdt_attach, NULL, NULL);
    122   1.1  nisimura 
    123   1.1  nisimura CFATTACH_DECL_NEW(sniiic_acpi, sizeof(struct sniiic_softc),
    124   1.1  nisimura     sniiic_acpi_match, sniiic_acpi_attach, NULL, NULL);
    125   1.1  nisimura 
    126   1.6  nisimura void sni_i2c_common_i(struct sniiic_softc *);
    127   1.6  nisimura 
    128   1.4  nisimura static int sni_i2c_acquire_bus(void *, int);
    129   1.4  nisimura static void sni_i2c_release_bus(void *, int);
    130   1.4  nisimura static int sni_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
    131   1.3  nisimura 			size_t, void *, size_t, int);
    132   1.3  nisimura 
    133   1.4  nisimura static int sni_i2c_intr(void *);
    134   1.4  nisimura static void sni_i2c_reset(struct sniiic_softc *);
    135   1.4  nisimura static void sni_i2c_flush(struct sniiic_softc *);
    136   1.4  nisimura 
    137  1.14  nisimura #define CSR_READ(sc, reg) \
    138   1.4  nisimura     bus_space_read_4((sc)->sc_ioh,(sc)->sc_ioh,(reg))
    139  1.14  nisimura #define CSR_WRITE(sc, reg, val) \
    140   1.4  nisimura     bus_space_write_4((sc)->sc_ioh,(sc)->sc_ioh,(reg),(val))
    141   1.4  nisimura 
    142  1.10   thorpej static const struct device_compatible_entry compat_data[] = {
    143  1.10   thorpej 	{ .compat = "socionext,synquacer-i2c" },
    144  1.10   thorpej 	DEVICE_COMPAT_EOL
    145  1.10   thorpej };
    146  1.13  nisimura static const struct device_compatible_entry compatible[] = {
    147  1.13  nisimura 	{ .compat = "SCX0003" },
    148  1.13  nisimura 	DEVICE_COMPAT_EOL
    149  1.13  nisimura };
    150  1.10   thorpej 
    151   1.1  nisimura static int
    152   1.1  nisimura sniiic_fdt_match(device_t parent, struct cfdata *match, void *aux)
    153   1.1  nisimura {
    154   1.1  nisimura 	struct fdt_attach_args * const faa = aux;
    155   1.1  nisimura 
    156  1.10   thorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
    157   1.1  nisimura }
    158   1.1  nisimura 
    159   1.1  nisimura static void
    160   1.1  nisimura sniiic_fdt_attach(device_t parent, device_t self, void *aux)
    161   1.1  nisimura {
    162   1.1  nisimura 	struct sniiic_softc * const sc = device_private(self);
    163   1.3  nisimura 	struct fdt_attach_args * const faa = aux;
    164   1.3  nisimura 	const int phandle = faa->faa_phandle;
    165   1.3  nisimura 	bus_space_handle_t ioh;
    166   1.3  nisimura 	bus_addr_t addr;
    167   1.3  nisimura 	bus_size_t size;
    168   1.3  nisimura 	char intrstr[128];
    169   1.1  nisimura 
    170  1.13  nisimura 	aprint_naive("\n");
    171  1.13  nisimura 	aprint_normal(": Socionext I2C controller\n");
    172  1.13  nisimura 
    173   1.4  nisimura 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0
    174   1.4  nisimura 	    || bus_space_map(faa->faa_bst, addr, size, 0, &ioh) != 0) {
    175  1.13  nisimura 		aprint_error_dev(self, "unable to map device\n");
    176   1.3  nisimura 		return;
    177   1.3  nisimura 	}
    178   1.4  nisimura 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
    179  1.13  nisimura 		aprint_error_dev(self, "failed to decode interrupt\n");
    180   1.4  nisimura 		goto fail;
    181   1.4  nisimura 	}
    182   1.4  nisimura 	sc->sc_ih = fdtbus_intr_establish(phandle,
    183   1.4  nisimura 			0, IPL_BIO, 0, sni_i2c_intr, sc);
    184   1.4  nisimura 	if (sc->sc_ih == NULL) {
    185   1.4  nisimura 		aprint_error_dev(self, "couldn't establish interrupt\n");
    186   1.4  nisimura 		goto fail;
    187   1.3  nisimura 	}
    188   1.5  nisimura 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
    189   1.3  nisimura 
    190   1.3  nisimura 	sc->sc_dev = self;
    191   1.3  nisimura 	sc->sc_iot = faa->faa_bst;
    192   1.3  nisimura 	sc->sc_ioh = ioh;
    193   1.3  nisimura 	sc->sc_ios = size;
    194  1.13  nisimura 	sc->sc_phandle = phandle;
    195   1.4  nisimura 
    196   1.6  nisimura 	sni_i2c_common_i(sc);
    197   1.3  nisimura 
    198   1.4  nisimura #if 0
    199  1.16   thorpej 	iicbus_attach(self, &sc->sc_ic);
    200   1.4  nisimura #endif
    201   1.3  nisimura 	return;
    202   1.3  nisimura  fail:
    203   1.3  nisimura 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
    204   1.3  nisimura 	return;
    205   1.1  nisimura }
    206   1.1  nisimura 
    207   1.1  nisimura static int
    208   1.1  nisimura sniiic_acpi_match(device_t parent, struct cfdata *match, void *aux)
    209   1.1  nisimura {
    210   1.1  nisimura 	struct acpi_attach_args *aa = aux;
    211   1.1  nisimura 
    212  1.13  nisimura 	return acpi_compatible_match(aa, compatible);
    213   1.1  nisimura }
    214   1.1  nisimura 
    215   1.1  nisimura static void
    216   1.1  nisimura sniiic_acpi_attach(device_t parent, device_t self, void *aux)
    217   1.1  nisimura {
    218   1.1  nisimura 	struct sniiic_softc * const sc = device_private(self);
    219   1.3  nisimura 	struct acpi_attach_args *aa = aux;
    220  1.13  nisimura 	ACPI_HANDLE handle = aa->aa_node->ad_handle;
    221   1.3  nisimura 	bus_space_handle_t ioh;
    222   1.4  nisimura 	struct i2cbus_attach_args iba;
    223   1.3  nisimura 	struct acpi_resources res;
    224   1.3  nisimura 	struct acpi_mem *mem;
    225   1.3  nisimura 	struct acpi_irq *irq;
    226   1.3  nisimura 	ACPI_STATUS rv;
    227   1.3  nisimura 
    228  1.13  nisimura 	aprint_naive("\n");
    229  1.13  nisimura 	aprint_normal(": Socionext I2C controller\n");
    230  1.13  nisimura 
    231   1.3  nisimura 	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
    232   1.3  nisimura 	    &res, &acpi_resource_parse_ops_default);
    233  1.13  nisimura 	if (ACPI_FAILURE(rv)) {
    234  1.13  nisimura 		aprint_error_dev(self, "missing crs resources\n");
    235   1.3  nisimura 		return;
    236  1.13  nisimura 	}
    237   1.3  nisimura 	mem = acpi_res_mem(&res, 0);
    238   1.3  nisimura 	irq = acpi_res_irq(&res, 0);
    239   1.4  nisimura 	if (mem == NULL || irq == NULL || mem->ar_length == 0) {
    240  1.13  nisimura 		aprint_error_dev(self, "incomplete resources\n");
    241   1.3  nisimura 		return;
    242   1.3  nisimura 	}
    243   1.3  nisimura 	if (bus_space_map(aa->aa_memt, mem->ar_base, mem->ar_length, 0,
    244   1.3  nisimura 	    &ioh)) {
    245  1.13  nisimura 		aprint_error_dev(self, "couldn't map registers\n");
    246   1.3  nisimura 		return;
    247   1.3  nisimura 	}
    248  1.13  nisimura 	sc->sc_ih = acpi_intr_establish(self, (uint64_t)handle,
    249   1.4  nisimura 	    IPL_BIO, false, sni_i2c_intr, sc, device_xname(self));
    250   1.4  nisimura 	if (sc->sc_ih == NULL) {
    251   1.4  nisimura 		aprint_error_dev(self, "couldn't establish interrupt\n");
    252   1.4  nisimura 		goto fail;
    253   1.4  nisimura 	}
    254   1.3  nisimura 
    255   1.3  nisimura 	sc->sc_dev = self;
    256   1.3  nisimura 	sc->sc_iot = aa->aa_memt;
    257   1.3  nisimura 	sc->sc_ioh = ioh;
    258   1.3  nisimura 	sc->sc_ios = mem->ar_length;
    259  1.13  nisimura 	sc->sc_phandle = 0;
    260   1.4  nisimura 
    261   1.6  nisimura 	sni_i2c_common_i(sc);
    262   1.4  nisimura 
    263   1.4  nisimura 	memset(&iba, 0, sizeof(iba));
    264   1.4  nisimura 	iba.iba_tag = &sc->sc_ic;
    265   1.4  nisimura #if 0
    266  1.12   thorpej 	config_found(sc->sc_dev, &iba, iicbus_print, CFARGS_NONE);
    267   1.4  nisimura #endif
    268   1.3  nisimura 
    269   1.3  nisimura 	acpi_resource_cleanup(&res);
    270   1.3  nisimura 
    271   1.3  nisimura 	return;
    272   1.3  nisimura  fail:
    273   1.3  nisimura 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
    274   1.3  nisimura 	acpi_resource_cleanup(&res);
    275   1.3  nisimura 	return;
    276   1.3  nisimura }
    277   1.3  nisimura 
    278   1.6  nisimura void
    279   1.6  nisimura sni_i2c_common_i(struct sniiic_softc *sc)
    280   1.6  nisimura {
    281   1.6  nisimura 
    282   1.6  nisimura 	iic_tag_init(&sc->sc_ic);
    283   1.6  nisimura 	sc->sc_ic.ic_cookie = sc;
    284   1.6  nisimura 	sc->sc_ic.ic_acquire_bus = sni_i2c_acquire_bus;
    285   1.6  nisimura 	sc->sc_ic.ic_release_bus = sni_i2c_release_bus;
    286   1.6  nisimura 	sc->sc_ic.ic_exec = sni_i2c_exec;
    287   1.6  nisimura 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    288   1.6  nisimura 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_BIO);
    289   1.6  nisimura 	cv_init(&sc->sc_cv, device_xname(sc->sc_dev));
    290   1.6  nisimura 
    291   1.6  nisimura 	/* no attach here */
    292   1.6  nisimura }
    293   1.6  nisimura 
    294   1.3  nisimura static int
    295   1.4  nisimura sni_i2c_acquire_bus(void *opaque, int flags)
    296   1.3  nisimura {
    297   1.3  nisimura 	struct sniiic_softc *sc = opaque;
    298   1.3  nisimura 
    299   1.3  nisimura 	mutex_enter(&sc->sc_lock);
    300   1.3  nisimura 	while (sc->sc_busy)
    301   1.3  nisimura 		cv_wait(&sc->sc_cv, &sc->sc_lock);
    302   1.3  nisimura 	sc->sc_busy = true;
    303   1.3  nisimura 	mutex_exit(&sc->sc_lock);
    304   1.3  nisimura 
    305   1.3  nisimura 	return 0;
    306   1.3  nisimura }
    307   1.3  nisimura 
    308   1.3  nisimura static void
    309   1.4  nisimura sni_i2c_release_bus(void *opaque, int flags)
    310   1.3  nisimura {
    311   1.3  nisimura 	struct sniiic_softc *sc = opaque;
    312   1.3  nisimura 
    313   1.3  nisimura 	mutex_enter(&sc->sc_lock);
    314   1.3  nisimura 	sc->sc_busy = false;
    315   1.3  nisimura 	cv_broadcast(&sc->sc_cv);
    316   1.3  nisimura 	mutex_exit(&sc->sc_lock);
    317   1.3  nisimura }
    318   1.3  nisimura 
    319   1.3  nisimura static int
    320   1.4  nisimura sni_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
    321   1.3  nisimura     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
    322   1.3  nisimura {
    323   1.3  nisimura 	struct sniiic_softc *sc = opaque;
    324   1.3  nisimura 	int err;
    325   1.4  nisimura #if 0
    326   1.4  nisimura 	printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
    327   1.4  nisimura 	    device_xname(sc->sc_dev), op, addr, (int)cmdlen, (int)len, flags);
    328   1.4  nisimura #endif
    329   1.1  nisimura 
    330   1.3  nisimura 	err = 0;
    331   1.3  nisimura 	/* AAA */
    332   1.3  nisimura 	goto done;
    333   1.3  nisimura  done:
    334   1.3  nisimura 	if (err)
    335   1.4  nisimura 		sni_i2c_reset(sc);
    336   1.4  nisimura 	sni_i2c_flush(sc);
    337   1.3  nisimura 	return err;
    338   1.1  nisimura }
    339   1.1  nisimura 
    340   1.1  nisimura static int
    341   1.4  nisimura sni_i2c_intr(void *arg)
    342   1.1  nisimura {
    343   1.3  nisimura 	struct sniiic_softc * const sc = arg;
    344   1.3  nisimura 	uint32_t stat = 0;
    345   1.3  nisimura 
    346   1.4  nisimura 	(void)stat;
    347   1.3  nisimura 	mutex_enter(&sc->sc_mtx);
    348   1.4  nisimura 	cv_broadcast(&sc->sc_cv);
    349   1.3  nisimura 	mutex_exit(&sc->sc_mtx);
    350   1.3  nisimura 	return 1;
    351   1.3  nisimura }
    352   1.3  nisimura 
    353   1.3  nisimura static void
    354   1.4  nisimura sni_i2c_reset(struct sniiic_softc *sc)
    355   1.3  nisimura {
    356   1.3  nisimura 	/* AAA */
    357   1.3  nisimura }
    358   1.3  nisimura 
    359   1.3  nisimura static void
    360   1.4  nisimura sni_i2c_flush(struct sniiic_softc *sc)
    361   1.3  nisimura {
    362   1.3  nisimura 	/* AAA */
    363   1.3  nisimura }
    364