diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-08-29 12:09:41 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-08-29 12:09:41 +0000 |
commit | d69dcb89d1667dca186992e439f921bf57a0a701 (patch) | |
tree | 0b97fa8280da54291117ae350117fb582241812f /sys/dev | |
parent | 920a33a08a33559d739497e514a087de42d3b2bf (diff) |
Add FDT support for dwiic(4)
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/fdt/dwiic_fdt.c | 168 | ||||
-rw-r--r-- | sys/dev/fdt/files.fdt | 5 | ||||
-rw-r--r-- | sys/dev/ic/dwiic.c | 4 | ||||
-rw-r--r-- | sys/dev/ic/dwiicvar.h | 7 |
4 files changed, 179 insertions, 5 deletions
diff --git a/sys/dev/fdt/dwiic_fdt.c b/sys/dev/fdt/dwiic_fdt.c new file mode 100644 index 00000000000..5f4de8d448c --- /dev/null +++ b/sys/dev/fdt/dwiic_fdt.c @@ -0,0 +1,168 @@ +/* $OpenBSD: dwiic_fdt.c,v 1.1 2023/08/29 12:09:40 kettenis Exp $ */ +/* + * Copyright (c) 2023 Patrick Wildt <patrick@blueri.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/systm.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_clock.h> +#include <dev/ofw/ofw_pinctrl.h> +#include <dev/ofw/fdt.h> + +#include <dev/ic/dwiicvar.h> + +static inline uint32_t +round_closest(uint64_t num, uint64_t den) +{ + return (num + (den / 2)) / den; +} + +struct dwiic_fdt_softc { + struct dwiic_softc sc_sc; + int sc_node; +}; + +int dwiic_fdt_match(struct device *, void *, void *); +void dwiic_fdt_attach(struct device *, struct device *, void *); + +const struct cfattach dwiic_fdt_ca = { + sizeof(struct dwiic_fdt_softc), dwiic_fdt_match, dwiic_fdt_attach +}; + +void dwiic_fdt_bus_scan(struct device *, struct i2cbus_attach_args *, + void *); + +int +dwiic_fdt_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "snps,designware-i2c"); +} + +void +dwiic_fdt_attach(struct device *parent, struct device *self, void *aux) +{ + struct dwiic_fdt_softc *fsc = (struct dwiic_fdt_softc *)self; + struct dwiic_softc *sc = &fsc->sc_sc; + struct fdt_attach_args *faa = aux; + struct i2cbus_attach_args iba; + uint32_t sda_hold, sda_fall, scl_fall; + uint64_t freq; + + if (faa->fa_nreg < 1) + return; + + sc->sc_iot = faa->fa_iot; + fsc->sc_node = faa->fa_node; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + + pinctrl_byname(faa->fa_node, "default"); + reset_deassert_all(faa->fa_node); + clock_enable(faa->fa_node, NULL); + + freq = clock_get_frequency(faa->fa_node, NULL); + sda_hold = OF_getpropint(faa->fa_node, "i2c-sda-hold-time-ns", 300); + sda_fall = OF_getpropint(faa->fa_node, "i2c-sda-falling-time-ns", 300); + scl_fall = OF_getpropint(faa->fa_node, "i2c-scl-falling-time-ns", 300); + + sc->sda_hold_time = round_closest(freq * sda_hold, 1000000000); + + /* Standard-mode: tHIGH = 4.0 us; tLOW = 4.7 us */ + sc->ss_hcnt = round_closest(freq * (4000 + sda_fall), 1000000000) - 3; + sc->ss_lcnt = round_closest(freq * (4700 + scl_fall), 1000000000) - 1; + /* Fast-mode: tHIGH = 0.6 us; tLOW = 1.3 us */ + sc->fs_hcnt = round_closest(freq * (600 + sda_fall), 1000000000) - 3; + sc->fs_lcnt = round_closest(freq * (1300 + scl_fall), 1000000000) - 1; + + if (dwiic_init(sc)) { + printf(": can't initialize\n"); + bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); + return; + } + + /* leave the controller disabled */ + dwiic_write(sc, DW_IC_INTR_MASK, 0); + dwiic_enable(sc, 0); + dwiic_read(sc, DW_IC_CLR_INTR); + + sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, + dwiic_intr, sc, sc->sc_dev.dv_xname); + + printf("\n"); + + rw_init(&sc->sc_i2c_lock, "dwiic"); + + sc->sc_i2c_tag.ic_cookie = sc; + sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus; + sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus; + sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec; + + bzero(&iba, sizeof iba); + iba.iba_name = "iic"; + iba.iba_tag = &sc->sc_i2c_tag; + iba.iba_bus_scan = dwiic_fdt_bus_scan; + iba.iba_bus_scan_arg = &fsc->sc_node; + config_found(&sc->sc_dev, &iba, iicbus_print); +} + +void +dwiic_fdt_bus_scan(struct device *self, struct i2cbus_attach_args *iba, + void *aux) +{ + int iba_node = *(int *)aux; + extern int iic_print(void *, const char *); + struct i2c_attach_args ia; + char name[32], status[32]; + uint32_t reg[1]; + int node; + + for (node = OF_child(iba_node); node; node = OF_peer(node)) { + memset(name, 0, sizeof(name)); + memset(status, 0, sizeof(status)); + memset(reg, 0, sizeof(reg)); + + if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) + continue; + if (name[0] == '\0') + continue; + + if (OF_getprop(node, "status", status, sizeof(status)) > 0 && + strcmp(status, "disabled") == 0) + continue; + + if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) + continue; + + memset(&ia, 0, sizeof(ia)); + ia.ia_tag = iba->iba_tag; + ia.ia_addr = bemtoh32(®[0]); + ia.ia_name = name; + ia.ia_cookie = &node; + + config_found(self, &ia, iic_print); + } +} diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 22b5ed8023e..c8c340c1267 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.197 2023/07/31 09:00:43 kettenis Exp $ +# $OpenBSD: files.fdt,v 1.198 2023/08/29 12:09:40 kettenis Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -422,6 +422,9 @@ device rkvop attach rkvop at fdt file dev/fdt/rkvop.c rkvop +attach dwiic at fdt with dwiic_fdt +file dev/fdt/dwiic_fdt.c dwiic_fdt + device dwmmc: sdmmcbus attach dwmmc at fdt file dev/fdt/dwmmc.c dwmmc diff --git a/sys/dev/ic/dwiic.c b/sys/dev/ic/dwiic.c index 5076de0c274..13663ba78e6 100644 --- a/sys/dev/ic/dwiic.c +++ b/sys/dev/ic/dwiic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwiic.c,v 1.14 2022/01/09 05:42:38 jsg Exp $ */ +/* $OpenBSD: dwiic.c,v 1.15 2023/08/29 12:09:40 kettenis Exp $ */ /* * Synopsys DesignWare I2C controller * @@ -21,11 +21,13 @@ #include <sys/systm.h> #include <sys/kernel.h> +#ifdef __HAVE_ACPI #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> #include <dev/acpi/acpidev.h> #include <dev/acpi/amltypes.h> #include <dev/acpi/dsdt.h> +#endif #include <dev/i2c/i2cvar.h> diff --git a/sys/dev/ic/dwiicvar.h b/sys/dev/ic/dwiicvar.h index ea718914a30..95dc18a8f10 100644 --- a/sys/dev/ic/dwiicvar.h +++ b/sys/dev/ic/dwiicvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dwiicvar.h,v 1.5 2022/08/31 15:14:01 kettenis Exp $ */ +/* $OpenBSD: dwiicvar.h,v 1.6 2023/08/29 12:09:40 kettenis Exp $ */ /* * Synopsys DesignWare I2C controller * @@ -21,11 +21,14 @@ #include <sys/systm.h> #include <sys/kernel.h> +#ifdef __HAVE_ACPI +#include "acpi.h" #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> #include <dev/acpi/acpidev.h> #include <dev/acpi/amltypes.h> #include <dev/acpi/dsdt.h> +#endif #include <dev/pci/pcivar.h> @@ -33,8 +36,6 @@ #include <dev/ic/dwiicreg.h> -#include "acpi.h" - /* #define DWIIC_DEBUG */ #ifdef DWIIC_DEBUG |