1*471aeecfSnaddy /* $OpenBSD: imxiic_acpi.c,v 1.4 2022/04/06 18:59:27 naddy Exp $ */
24e98d9d9Spatrick /*
34e98d9d9Spatrick * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
44e98d9d9Spatrick * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
54e98d9d9Spatrick *
64e98d9d9Spatrick * Permission to use, copy, modify, and/or distribute this software for any
74e98d9d9Spatrick * purpose with or without fee is hereby granted, provided that the above
84e98d9d9Spatrick * copyright notice and this permission notice appear in all copies.
94e98d9d9Spatrick *
104e98d9d9Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114e98d9d9Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124e98d9d9Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134e98d9d9Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144e98d9d9Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154e98d9d9Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164e98d9d9Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174e98d9d9Spatrick */
184e98d9d9Spatrick
194e98d9d9Spatrick #include <sys/param.h>
204e98d9d9Spatrick #include <sys/systm.h>
214e98d9d9Spatrick #include <sys/kernel.h>
224e98d9d9Spatrick
234e98d9d9Spatrick #include <dev/acpi/acpireg.h>
244e98d9d9Spatrick #include <dev/acpi/acpivar.h>
254e98d9d9Spatrick #include <dev/acpi/acpidev.h>
264e98d9d9Spatrick #include <dev/acpi/amltypes.h>
274e98d9d9Spatrick #include <dev/acpi/dsdt.h>
284e98d9d9Spatrick
294e98d9d9Spatrick #include <dev/ic/imxiicvar.h>
304e98d9d9Spatrick
314e98d9d9Spatrick struct imxiic_acpi_softc {
324e98d9d9Spatrick struct imxiic_softc ac_sc;
334e98d9d9Spatrick struct acpi_softc *ac_acpi;
344e98d9d9Spatrick struct aml_node *ac_devnode;
354e98d9d9Spatrick struct device *ac_iic;
364e98d9d9Spatrick };
374e98d9d9Spatrick
384e98d9d9Spatrick struct imxiic_crs {
394e98d9d9Spatrick uint16_t i2c_addr;
404e98d9d9Spatrick struct aml_node *devnode;
414e98d9d9Spatrick };
424e98d9d9Spatrick
434e98d9d9Spatrick int imxiic_acpi_match(struct device *, void *, void *);
444e98d9d9Spatrick void imxiic_acpi_attach(struct device *, struct device *, void *);
454e98d9d9Spatrick
464e98d9d9Spatrick int imxiic_acpi_parse_crs(int, union acpi_resource *, void *);
474e98d9d9Spatrick void imxiic_acpi_bus_scan(struct device *, struct i2cbus_attach_args *,
484e98d9d9Spatrick void *);
494e98d9d9Spatrick int imxiic_acpi_found_hid(struct aml_node *, void *);
504e98d9d9Spatrick
51*471aeecfSnaddy const struct cfattach imxiic_acpi_ca = {
524e98d9d9Spatrick sizeof(struct imxiic_acpi_softc),
534e98d9d9Spatrick imxiic_acpi_match,
544e98d9d9Spatrick imxiic_acpi_attach,
554e98d9d9Spatrick NULL,
564e98d9d9Spatrick NULL,
574e98d9d9Spatrick };
584e98d9d9Spatrick
594e98d9d9Spatrick const char *imxiic_hids[] = {
604e98d9d9Spatrick "NXP0001",
614e98d9d9Spatrick NULL
624e98d9d9Spatrick };
634e98d9d9Spatrick
644e98d9d9Spatrick int
imxiic_acpi_match(struct device * parent,void * match,void * aux)654e98d9d9Spatrick imxiic_acpi_match(struct device *parent, void *match, void *aux)
664e98d9d9Spatrick {
674e98d9d9Spatrick struct acpi_attach_args *aaa = aux;
684e98d9d9Spatrick struct cfdata *cf = match;
694e98d9d9Spatrick
7057ec0946Skettenis if (aaa->aaa_naddr < 1)
7157ec0946Skettenis return 0;
724e98d9d9Spatrick return acpi_matchhids(aaa, imxiic_hids, cf->cf_driver->cd_name);
734e98d9d9Spatrick }
744e98d9d9Spatrick
754e98d9d9Spatrick void
imxiic_acpi_attach(struct device * parent,struct device * self,void * aux)764e98d9d9Spatrick imxiic_acpi_attach(struct device *parent, struct device *self, void *aux)
774e98d9d9Spatrick {
784e98d9d9Spatrick struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)self;
794e98d9d9Spatrick struct imxiic_softc *sc = &ac->ac_sc;
804e98d9d9Spatrick struct acpi_attach_args *aaa = aux;
814e98d9d9Spatrick struct i2cbus_attach_args iba;
824e98d9d9Spatrick
834e98d9d9Spatrick ac->ac_acpi = (struct acpi_softc *)parent;
844e98d9d9Spatrick ac->ac_devnode = aaa->aaa_node;
854e98d9d9Spatrick
864e98d9d9Spatrick printf(" %s", ac->ac_devnode->name);
874e98d9d9Spatrick
884e98d9d9Spatrick printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
894e98d9d9Spatrick
904e98d9d9Spatrick sc->sc_iot = aaa->aaa_bst[0];
914e98d9d9Spatrick if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0],
924e98d9d9Spatrick 0, &sc->sc_ioh)) {
934e98d9d9Spatrick printf(": can't map registers\n");
944e98d9d9Spatrick return;
954e98d9d9Spatrick }
964e98d9d9Spatrick
974e98d9d9Spatrick sc->sc_reg_shift = 0;
984e98d9d9Spatrick sc->sc_clk_div = imxiic_vf610_clk_div;
994e98d9d9Spatrick sc->sc_clk_ndiv = nitems(imxiic_vf610_clk_div);
1004e98d9d9Spatrick sc->sc_type = I2C_TYPE_VF610;
1014e98d9d9Spatrick
1024e98d9d9Spatrick /*
1030922e9b5Spatrick * Older versions of the ACPI tables for this device had the naming for
1040922e9b5Spatrick * the clkrate and bitrate confused. For those, keep the old value of
1050922e9b5Spatrick * 100 kHz.
1064e98d9d9Spatrick */
1074e98d9d9Spatrick sc->sc_clkrate = acpi_getpropint(ac->ac_devnode,
1080922e9b5Spatrick "uefi-clock-frequency", 0) / 1000;
1090922e9b5Spatrick sc->sc_bitrate = acpi_getpropint(ac->ac_devnode,
1100922e9b5Spatrick "clock-frequency", 0) / 1000;
1110922e9b5Spatrick if (sc->sc_clkrate == 0) {
1120922e9b5Spatrick sc->sc_clkrate = acpi_getpropint(ac->ac_devnode,
1134e98d9d9Spatrick "clock-frequency", 0) / 1000;
1144e98d9d9Spatrick sc->sc_bitrate = 100000 / 1000;
1150922e9b5Spatrick }
1164e98d9d9Spatrick if (sc->sc_clkrate == 0) {
1174e98d9d9Spatrick printf(": clock frequency unknown\n");
1184e98d9d9Spatrick return;
1194e98d9d9Spatrick }
1204e98d9d9Spatrick
1214e98d9d9Spatrick printf("\n");
1224e98d9d9Spatrick
1234e98d9d9Spatrick imxiic_setspeed(sc, sc->sc_bitrate);
1244e98d9d9Spatrick imxiic_enable(sc, 0);
1254e98d9d9Spatrick
1264e98d9d9Spatrick sc->stopped = 1;
1274e98d9d9Spatrick rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
1284e98d9d9Spatrick
1294e98d9d9Spatrick sc->i2c_tag.ic_cookie = sc;
1304e98d9d9Spatrick sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus;
1314e98d9d9Spatrick sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus;
1324e98d9d9Spatrick sc->i2c_tag.ic_exec = imxiic_i2c_exec;
1334e98d9d9Spatrick
1344e98d9d9Spatrick bzero(&iba, sizeof iba);
1354e98d9d9Spatrick iba.iba_name = "iic";
1364e98d9d9Spatrick iba.iba_tag = &sc->i2c_tag;
1374e98d9d9Spatrick iba.iba_bus_scan = imxiic_acpi_bus_scan;
1384e98d9d9Spatrick iba.iba_bus_scan_arg = sc;
1394e98d9d9Spatrick config_found(&sc->sc_dev, &iba, iicbus_print);
1404e98d9d9Spatrick
1414e98d9d9Spatrick #ifndef SMALL_KERNEL
1424e98d9d9Spatrick ac->ac_devnode->i2c = &sc->i2c_tag;
1434e98d9d9Spatrick acpi_register_gsb(ac->ac_acpi, ac->ac_devnode);
1444e98d9d9Spatrick #endif
1454e98d9d9Spatrick }
1464e98d9d9Spatrick
1474e98d9d9Spatrick int
imxiic_acpi_parse_crs(int crsidx,union acpi_resource * crs,void * arg)1484e98d9d9Spatrick imxiic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
1494e98d9d9Spatrick {
1504e98d9d9Spatrick struct imxiic_crs *sc_crs = arg;
1514e98d9d9Spatrick
1524e98d9d9Spatrick switch (AML_CRSTYPE(crs)) {
1534e98d9d9Spatrick case LR_SERBUS:
1544e98d9d9Spatrick if (crs->lr_serbus.type == LR_SERBUS_I2C)
1554e98d9d9Spatrick sc_crs->i2c_addr = crs->lr_i2cbus._adr;
1564e98d9d9Spatrick break;
1574e98d9d9Spatrick case SR_IRQ:
1584e98d9d9Spatrick case LR_EXTIRQ:
1594e98d9d9Spatrick case LR_MEM32:
1604e98d9d9Spatrick case LR_MEM32FIXED:
1614e98d9d9Spatrick break;
1624e98d9d9Spatrick default:
1634e98d9d9Spatrick printf("%s: unknown resource type %d\n", __func__,
1644e98d9d9Spatrick AML_CRSTYPE(crs));
1654e98d9d9Spatrick }
1664e98d9d9Spatrick
1674e98d9d9Spatrick return 0;
1684e98d9d9Spatrick }
1694e98d9d9Spatrick
1704e98d9d9Spatrick void
imxiic_acpi_bus_scan(struct device * iic,struct i2cbus_attach_args * iba,void * aux)1714e98d9d9Spatrick imxiic_acpi_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
1724e98d9d9Spatrick void *aux)
1734e98d9d9Spatrick {
1744e98d9d9Spatrick struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)aux;
1754e98d9d9Spatrick
1764e98d9d9Spatrick ac->ac_iic = iic;
1774e98d9d9Spatrick aml_find_node(ac->ac_devnode, "_HID", imxiic_acpi_found_hid, ac);
1784e98d9d9Spatrick }
1794e98d9d9Spatrick
1804e98d9d9Spatrick int
imxiic_acpi_found_hid(struct aml_node * node,void * arg)1814e98d9d9Spatrick imxiic_acpi_found_hid(struct aml_node *node, void *arg)
1824e98d9d9Spatrick {
1834e98d9d9Spatrick struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)arg;
1844e98d9d9Spatrick struct imxiic_softc *sc = &ac->ac_sc;
1854e98d9d9Spatrick struct imxiic_crs crs;
1864e98d9d9Spatrick struct aml_value res;
1874e98d9d9Spatrick int64_t sta;
1884e98d9d9Spatrick char cdev[16], dev[16];
1894e98d9d9Spatrick struct i2c_attach_args ia;
1904e98d9d9Spatrick
1914e98d9d9Spatrick /* Skip our own _HID. */
1924e98d9d9Spatrick if (node->parent == ac->ac_devnode)
1934e98d9d9Spatrick return 0;
1944e98d9d9Spatrick
1954e98d9d9Spatrick /* Only direct descendants, because of possible muxes. */
1964e98d9d9Spatrick if (node->parent && node->parent->parent != ac->ac_devnode)
1974e98d9d9Spatrick return 0;
1984e98d9d9Spatrick
1994e98d9d9Spatrick if (acpi_parsehid(node, arg, cdev, dev, 16) != 0)
2004e98d9d9Spatrick return 0;
2014e98d9d9Spatrick
2024e98d9d9Spatrick sta = acpi_getsta(acpi_softc, node->parent);
2034e98d9d9Spatrick if ((sta & STA_PRESENT) == 0)
2044e98d9d9Spatrick return 0;
2054e98d9d9Spatrick
2064e98d9d9Spatrick if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res))
2074e98d9d9Spatrick return 0;
2084e98d9d9Spatrick
2094e98d9d9Spatrick if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
2104e98d9d9Spatrick printf("%s: invalid _CRS object (type %d len %d)\n",
2114e98d9d9Spatrick sc->sc_dev.dv_xname, res.type, res.length);
2124e98d9d9Spatrick aml_freevalue(&res);
2134e98d9d9Spatrick return (0);
2144e98d9d9Spatrick }
2154e98d9d9Spatrick memset(&crs, 0, sizeof(crs));
2164e98d9d9Spatrick crs.devnode = ac->ac_devnode;
2174e98d9d9Spatrick aml_parse_resource(&res, imxiic_acpi_parse_crs, &crs);
2184e98d9d9Spatrick aml_freevalue(&res);
2194e98d9d9Spatrick
2204e98d9d9Spatrick acpi_attach_deps(acpi_softc, node->parent);
2214e98d9d9Spatrick
2224e98d9d9Spatrick memset(&ia, 0, sizeof(ia));
2234e98d9d9Spatrick ia.ia_tag = &sc->i2c_tag;
2244e98d9d9Spatrick ia.ia_name = dev;
2254e98d9d9Spatrick ia.ia_addr = crs.i2c_addr;
2264e98d9d9Spatrick ia.ia_cookie = node->parent;
2274e98d9d9Spatrick
2284e98d9d9Spatrick config_found(ac->ac_iic, &ia, iicbus_print);
2294e98d9d9Spatrick node->parent->attached = 1;
2304e98d9d9Spatrick
2314e98d9d9Spatrick return 0;
2324e98d9d9Spatrick }
233