xref: /openbsd-src/sys/dev/acpi/imxiic_acpi.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
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