Home | History | Annotate | Line # | Download | only in fdt
fdt_i2c.c revision 1.16
      1  1.16   thorpej /* $NetBSD: fdt_i2c.c,v 1.16 2025/09/23 00:52:14 thorpej Exp $ */
      2  1.16   thorpej 
      3  1.16   thorpej /*
      4  1.16   thorpej  * Copyright (c) 2021, 2025 The NetBSD Foundation, Inc.
      5  1.16   thorpej  * All rights reserved.
      6  1.16   thorpej  *
      7  1.16   thorpej  * Redistribution and use in source and binary forms, with or without
      8  1.16   thorpej  * modification, are permitted provided that the following conditions
      9  1.16   thorpej  * are met:
     10  1.16   thorpej  * 1. Redistributions of source code must retain the above copyright
     11  1.16   thorpej  *    notice, this list of conditions and the following disclaimer.
     12  1.16   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.16   thorpej  *    notice, this list of conditions and the following disclaimer in the
     14  1.16   thorpej  *    documentation and/or other materials provided with the distribution.
     15  1.16   thorpej  *
     16  1.16   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.16   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.16   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.16   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.16   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.16   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.16   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.16   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.16   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.16   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.16   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     27  1.16   thorpej  */
     28   1.1  jmcneill 
     29   1.1  jmcneill /*-
     30   1.1  jmcneill  * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
     31   1.1  jmcneill  * All rights reserved.
     32   1.1  jmcneill  *
     33   1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
     34   1.1  jmcneill  * modification, are permitted provided that the following conditions
     35   1.1  jmcneill  * are met:
     36   1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     37   1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     38   1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     39   1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     40   1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     41   1.1  jmcneill  *
     42   1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     43   1.1  jmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     44   1.1  jmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     45   1.1  jmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     46   1.1  jmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     47   1.1  jmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     48   1.1  jmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     49   1.1  jmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     50   1.1  jmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     51   1.1  jmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     52   1.1  jmcneill  * SUCH DAMAGE.
     53   1.1  jmcneill  */
     54   1.1  jmcneill 
     55   1.1  jmcneill #include <sys/cdefs.h>
     56  1.16   thorpej __KERNEL_RCSID(0, "$NetBSD: fdt_i2c.c,v 1.16 2025/09/23 00:52:14 thorpej Exp $");
     57   1.1  jmcneill 
     58   1.1  jmcneill #include <sys/param.h>
     59   1.1  jmcneill #include <sys/bus.h>
     60   1.1  jmcneill #include <sys/kmem.h>
     61   1.3  jmcneill #include <sys/queue.h>
     62  1.16   thorpej #include <sys/systm.h>
     63   1.1  jmcneill 
     64   1.1  jmcneill #include <libfdt.h>
     65   1.1  jmcneill #include <dev/fdt/fdtvar.h>
     66   1.1  jmcneill 
     67  1.16   thorpej #include <dev/i2c/i2cvar.h>
     68  1.16   thorpej #include <dev/i2c/i2c_calls.h>
     69  1.16   thorpej #include <dev/i2c/i2c_enum.h>
     70  1.16   thorpej 
     71   1.1  jmcneill struct fdtbus_i2c_controller {
     72   1.9   thorpej 	i2c_tag_t i2c_tag;
     73   1.1  jmcneill 	int i2c_phandle;
     74   1.1  jmcneill 
     75   1.3  jmcneill 	LIST_ENTRY(fdtbus_i2c_controller) i2c_next;
     76   1.1  jmcneill };
     77   1.1  jmcneill 
     78   1.3  jmcneill static LIST_HEAD(, fdtbus_i2c_controller) fdtbus_i2c_controllers =
     79   1.3  jmcneill     LIST_HEAD_INITIALIZER(fdtbus_i2c_controllers);
     80   1.1  jmcneill 
     81  1.15   thorpej void
     82  1.15   thorpej fdtbus_register_i2c_controller(device_t dev, i2c_tag_t tag)
     83   1.1  jmcneill {
     84  1.15   thorpej 	int phandle = devhandle_to_of(device_handle(dev));
     85   1.1  jmcneill 	struct fdtbus_i2c_controller *i2c;
     86   1.1  jmcneill 
     87   1.1  jmcneill 	i2c = kmem_alloc(sizeof(*i2c), KM_SLEEP);
     88   1.9   thorpej 	i2c->i2c_tag = tag;
     89   1.1  jmcneill 	i2c->i2c_phandle = phandle;
     90   1.1  jmcneill 
     91   1.3  jmcneill 	LIST_INSERT_HEAD(&fdtbus_i2c_controllers, i2c, i2c_next);
     92   1.1  jmcneill }
     93   1.1  jmcneill 
     94   1.1  jmcneill static struct fdtbus_i2c_controller *
     95   1.1  jmcneill fdtbus_get_i2c_controller(int phandle)
     96   1.1  jmcneill {
     97   1.1  jmcneill 	struct fdtbus_i2c_controller *i2c;
     98   1.1  jmcneill 
     99   1.3  jmcneill 	LIST_FOREACH(i2c, &fdtbus_i2c_controllers, i2c_next) {
    100   1.3  jmcneill 		if (i2c->i2c_phandle == phandle)
    101   1.1  jmcneill 			return i2c;
    102   1.1  jmcneill 	}
    103   1.1  jmcneill 
    104   1.1  jmcneill 	return NULL;
    105   1.1  jmcneill }
    106   1.1  jmcneill 
    107   1.1  jmcneill i2c_tag_t
    108  1.12     skrll fdtbus_i2c_get_tag(int phandle)
    109   1.1  jmcneill {
    110   1.1  jmcneill 	struct fdtbus_i2c_controller *i2c;
    111   1.1  jmcneill 
    112   1.1  jmcneill 	i2c = fdtbus_get_i2c_controller(phandle);
    113   1.1  jmcneill 	if (i2c == NULL)
    114   1.1  jmcneill 		return NULL;
    115   1.1  jmcneill 
    116   1.9   thorpej 	return i2c->i2c_tag;
    117   1.1  jmcneill }
    118   1.4  jmcneill 
    119   1.6  jmcneill i2c_tag_t
    120   1.6  jmcneill fdtbus_i2c_acquire(int phandle, const char *prop)
    121   1.6  jmcneill {
    122   1.6  jmcneill 	int i2c_phandle;
    123   1.6  jmcneill 
    124   1.6  jmcneill 	i2c_phandle = fdtbus_get_phandle(phandle, prop);
    125   1.6  jmcneill 	if (i2c_phandle == -1)
    126   1.6  jmcneill 		return NULL;
    127   1.6  jmcneill 
    128  1.12     skrll 	return fdtbus_i2c_get_tag(i2c_phandle);
    129   1.6  jmcneill }
    130   1.6  jmcneill 
    131  1.16   thorpej static int
    132  1.16   thorpej fdtbus_i2c_enumerate_devices(device_t dev, devhandle_t call_handle, void *v)
    133  1.13   thorpej {
    134  1.16   thorpej 	struct i2c_enumerate_devices_args *args = v;
    135  1.16   thorpej 	int i2c_node, node;
    136  1.16   thorpej 	char name[32], compat_buf[32];
    137  1.16   thorpej 	bus_addr_t addr;
    138  1.16   thorpej 	char *clist;
    139  1.16   thorpej 	int clist_size;
    140  1.16   thorpej 	bool cbrv;
    141  1.16   thorpej 
    142  1.16   thorpej 	i2c_node = devhandle_to_of(call_handle);
    143  1.16   thorpej 
    144  1.16   thorpej 	/*
    145  1.16   thorpej 	 * The Device Tree bindings state that if a controller has a
    146  1.16   thorpej 	 * child node named "i2c-bus", then that is the node beneath
    147  1.16   thorpej 	 * which the child devices are populated.
    148  1.16   thorpej 	 */
    149  1.16   thorpej 	for (node = OF_child(i2c_node); node != 0; node = OF_peer(node)) {
    150  1.16   thorpej 		if (OF_getprop(node, "name", name, sizeof(name)) <= 0) {
    151  1.16   thorpej 			continue;
    152  1.16   thorpej 		}
    153  1.16   thorpej 		if (strcmp(name, "i2c-bus") == 0) {
    154  1.16   thorpej 			i2c_node = node;
    155  1.16   thorpej 			break;
    156  1.16   thorpej 		}
    157  1.16   thorpej 	}
    158   1.4  jmcneill 
    159  1.16   thorpej 	for (node = OF_child(i2c_node); node != 0; node = OF_peer(node)) {
    160  1.16   thorpej 		if (OF_getprop(node, "name", name, sizeof(name)) <= 0) {
    161  1.16   thorpej 			continue;
    162  1.16   thorpej 		}
    163  1.16   thorpej 		if (fdtbus_get_reg(node, 0, &addr, NULL) != 0) {
    164  1.16   thorpej 			continue;
    165  1.16   thorpej 		}
    166  1.16   thorpej 
    167  1.16   thorpej 		clist_size = OF_getproplen(node, "compatible");
    168  1.16   thorpej 		if (clist_size <= 0) {
    169  1.16   thorpej 			continue;
    170  1.16   thorpej 		}
    171  1.16   thorpej 		clist = kmem_tmpbuf_alloc(clist_size,
    172  1.16   thorpej 		    compat_buf, sizeof(compat_buf), KM_SLEEP);
    173  1.16   thorpej 		if (OF_getprop(node, "compatible", clist, clist_size)
    174  1.16   thorpej 			       < clist_size) {
    175  1.16   thorpej 			kmem_tmpbuf_free(clist, clist_size, compat_buf);
    176  1.16   thorpej 			continue;
    177  1.16   thorpej 		}
    178  1.16   thorpej 
    179  1.16   thorpej 		cbrv = i2c_enumerate_device(dev, args, name, clist,
    180  1.16   thorpej 		    clist_size, (i2c_addr_t)addr,
    181  1.16   thorpej 		    devhandle_from_of(call_handle, node));
    182  1.16   thorpej 
    183  1.16   thorpej 		kmem_tmpbuf_free(clist, clist_size, compat_buf);
    184  1.16   thorpej 
    185  1.16   thorpej 		if (!cbrv) {
    186  1.16   thorpej 			break;
    187  1.16   thorpej 		}
    188  1.13   thorpej 	}
    189   1.4  jmcneill 
    190  1.16   thorpej 	return 0;
    191   1.4  jmcneill }
    192  1.16   thorpej OF_DEVICE_CALL_REGISTER(I2C_ENUMERATE_DEVICES_STR,
    193  1.16   thorpej 			fdtbus_i2c_enumerate_devices);
    194