xref: /openbsd/sys/dev/acpi/imxiic_acpi.c (revision 73471bf0)
1 /* $OpenBSD: imxiic_acpi.c,v 1.2 2021/07/24 10:52:07 patrick Exp $ */
2 /*
3  * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
4  * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 
23 #include <dev/acpi/acpireg.h>
24 #include <dev/acpi/acpivar.h>
25 #include <dev/acpi/acpidev.h>
26 #include <dev/acpi/amltypes.h>
27 #include <dev/acpi/dsdt.h>
28 
29 #include <dev/ic/imxiicvar.h>
30 
31 struct imxiic_acpi_softc {
32 	struct imxiic_softc	ac_sc;
33 	struct acpi_softc	*ac_acpi;
34 	struct aml_node		*ac_devnode;
35 	struct device		*ac_iic;
36 };
37 
38 struct imxiic_crs {
39 	uint16_t i2c_addr;
40 	struct aml_node *devnode;
41 };
42 
43 int	imxiic_acpi_match(struct device *, void *, void *);
44 void	imxiic_acpi_attach(struct device *, struct device *, void *);
45 
46 int	imxiic_acpi_parse_crs(int, union acpi_resource *, void *);
47 void	imxiic_acpi_bus_scan(struct device *, struct i2cbus_attach_args *,
48 	    void *);
49 int	imxiic_acpi_found_hid(struct aml_node *, void *);
50 
51 struct cfattach imxiic_acpi_ca = {
52 	sizeof(struct imxiic_acpi_softc),
53 	imxiic_acpi_match,
54 	imxiic_acpi_attach,
55 	NULL,
56 	NULL,
57 };
58 
59 const char *imxiic_hids[] = {
60 	"NXP0001",
61 	NULL
62 };
63 
64 int
65 imxiic_acpi_match(struct device *parent, void *match, void *aux)
66 {
67 	struct acpi_attach_args *aaa = aux;
68 	struct cfdata *cf = match;
69 
70 	return acpi_matchhids(aaa, imxiic_hids, cf->cf_driver->cd_name);
71 }
72 
73 void
74 imxiic_acpi_attach(struct device *parent, struct device *self, void *aux)
75 {
76 	struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)self;
77 	struct imxiic_softc *sc = &ac->ac_sc;
78 	struct acpi_attach_args *aaa = aux;
79 	struct i2cbus_attach_args iba;
80 
81 	ac->ac_acpi = (struct acpi_softc *)parent;
82 	ac->ac_devnode = aaa->aaa_node;
83 
84 	printf(" %s", ac->ac_devnode->name);
85 
86 	if (aaa->aaa_naddr < 1) {
87 		printf(": no registers\n");
88 		return;
89 	}
90 
91 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
92 
93 	sc->sc_iot = aaa->aaa_bst[0];
94 	if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0],
95 	    0, &sc->sc_ioh)) {
96 		printf(": can't map registers\n");
97 		return;
98 	}
99 
100 	sc->sc_reg_shift = 0;
101 	sc->sc_clk_div = imxiic_vf610_clk_div;
102 	sc->sc_clk_ndiv = nitems(imxiic_vf610_clk_div);
103 	sc->sc_type = I2C_TYPE_VF610;
104 
105 	/*
106 	 * Older versions of the ACPI tables for this device had the naming for
107 	 * the clkrate and bitrate confused.  For those, keep the old value of
108 	 * 100 kHz.
109 	 */
110 	sc->sc_clkrate = acpi_getpropint(ac->ac_devnode,
111 	    "uefi-clock-frequency", 0) / 1000;
112 	sc->sc_bitrate = acpi_getpropint(ac->ac_devnode,
113 	    "clock-frequency", 0) / 1000;
114 	if (sc->sc_clkrate == 0) {
115 		sc->sc_clkrate = acpi_getpropint(ac->ac_devnode,
116 		    "clock-frequency", 0) / 1000;
117 		sc->sc_bitrate = 100000 / 1000;
118 	}
119 	if (sc->sc_clkrate == 0) {
120 		printf(": clock frequency unknown\n");
121 		return;
122 	}
123 
124 	printf("\n");
125 
126 	imxiic_setspeed(sc, sc->sc_bitrate);
127 	imxiic_enable(sc, 0);
128 
129 	sc->stopped = 1;
130 	rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
131 
132 	sc->i2c_tag.ic_cookie = sc;
133 	sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus;
134 	sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus;
135 	sc->i2c_tag.ic_exec = imxiic_i2c_exec;
136 
137 	bzero(&iba, sizeof iba);
138 	iba.iba_name = "iic";
139 	iba.iba_tag = &sc->i2c_tag;
140 	iba.iba_bus_scan = imxiic_acpi_bus_scan;
141 	iba.iba_bus_scan_arg = sc;
142 	config_found(&sc->sc_dev, &iba, iicbus_print);
143 
144 #ifndef SMALL_KERNEL
145 	ac->ac_devnode->i2c = &sc->i2c_tag;
146 	acpi_register_gsb(ac->ac_acpi, ac->ac_devnode);
147 #endif
148 }
149 
150 int
151 imxiic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
152 {
153 	struct imxiic_crs *sc_crs = arg;
154 
155 	switch (AML_CRSTYPE(crs)) {
156 	case LR_SERBUS:
157 		if (crs->lr_serbus.type == LR_SERBUS_I2C)
158 			sc_crs->i2c_addr = crs->lr_i2cbus._adr;
159 		break;
160 	case SR_IRQ:
161 	case LR_EXTIRQ:
162 	case LR_MEM32:
163 	case LR_MEM32FIXED:
164 		break;
165 	default:
166 		printf("%s: unknown resource type %d\n", __func__,
167 		    AML_CRSTYPE(crs));
168 	}
169 
170 	return 0;
171 }
172 
173 void
174 imxiic_acpi_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
175     void *aux)
176 {
177 	struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)aux;
178 
179 	ac->ac_iic = iic;
180 	aml_find_node(ac->ac_devnode, "_HID", imxiic_acpi_found_hid, ac);
181 }
182 
183 int
184 imxiic_acpi_found_hid(struct aml_node *node, void *arg)
185 {
186 	struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)arg;
187 	struct imxiic_softc *sc = &ac->ac_sc;
188 	struct imxiic_crs crs;
189 	struct aml_value res;
190 	int64_t sta;
191 	char cdev[16], dev[16];
192 	struct i2c_attach_args ia;
193 
194 	/* Skip our own _HID. */
195 	if (node->parent == ac->ac_devnode)
196 		return 0;
197 
198 	/* Only direct descendants, because of possible muxes. */
199 	if (node->parent && node->parent->parent != ac->ac_devnode)
200 		return 0;
201 
202 	if (acpi_parsehid(node, arg, cdev, dev, 16) != 0)
203 		return 0;
204 
205 	sta = acpi_getsta(acpi_softc, node->parent);
206 	if ((sta & STA_PRESENT) == 0)
207 		return 0;
208 
209 	if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res))
210 		return 0;
211 
212 	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
213 		printf("%s: invalid _CRS object (type %d len %d)\n",
214 		    sc->sc_dev.dv_xname, res.type, res.length);
215 		aml_freevalue(&res);
216 		return (0);
217 	}
218 	memset(&crs, 0, sizeof(crs));
219 	crs.devnode = ac->ac_devnode;
220 	aml_parse_resource(&res, imxiic_acpi_parse_crs, &crs);
221 	aml_freevalue(&res);
222 
223 	acpi_attach_deps(acpi_softc, node->parent);
224 
225 	memset(&ia, 0, sizeof(ia));
226 	ia.ia_tag = &sc->i2c_tag;
227 	ia.ia_name = dev;
228 	ia.ia_addr = crs.i2c_addr;
229 	ia.ia_cookie = node->parent;
230 
231 	config_found(ac->ac_iic, &ia, iicbus_print);
232 	node->parent->attached = 1;
233 
234 	return 0;
235 }
236