1 /* $OpenBSD: imxiic_acpi.c,v 1.4 2022/04/06 18:59:27 naddy 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 const 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
imxiic_acpi_match(struct device * parent,void * match,void * aux)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 if (aaa->aaa_naddr < 1)
71 return 0;
72 return acpi_matchhids(aaa, imxiic_hids, cf->cf_driver->cd_name);
73 }
74
75 void
imxiic_acpi_attach(struct device * parent,struct device * self,void * aux)76 imxiic_acpi_attach(struct device *parent, struct device *self, void *aux)
77 {
78 struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)self;
79 struct imxiic_softc *sc = &ac->ac_sc;
80 struct acpi_attach_args *aaa = aux;
81 struct i2cbus_attach_args iba;
82
83 ac->ac_acpi = (struct acpi_softc *)parent;
84 ac->ac_devnode = aaa->aaa_node;
85
86 printf(" %s", ac->ac_devnode->name);
87
88 printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
89
90 sc->sc_iot = aaa->aaa_bst[0];
91 if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0],
92 0, &sc->sc_ioh)) {
93 printf(": can't map registers\n");
94 return;
95 }
96
97 sc->sc_reg_shift = 0;
98 sc->sc_clk_div = imxiic_vf610_clk_div;
99 sc->sc_clk_ndiv = nitems(imxiic_vf610_clk_div);
100 sc->sc_type = I2C_TYPE_VF610;
101
102 /*
103 * Older versions of the ACPI tables for this device had the naming for
104 * the clkrate and bitrate confused. For those, keep the old value of
105 * 100 kHz.
106 */
107 sc->sc_clkrate = acpi_getpropint(ac->ac_devnode,
108 "uefi-clock-frequency", 0) / 1000;
109 sc->sc_bitrate = acpi_getpropint(ac->ac_devnode,
110 "clock-frequency", 0) / 1000;
111 if (sc->sc_clkrate == 0) {
112 sc->sc_clkrate = acpi_getpropint(ac->ac_devnode,
113 "clock-frequency", 0) / 1000;
114 sc->sc_bitrate = 100000 / 1000;
115 }
116 if (sc->sc_clkrate == 0) {
117 printf(": clock frequency unknown\n");
118 return;
119 }
120
121 printf("\n");
122
123 imxiic_setspeed(sc, sc->sc_bitrate);
124 imxiic_enable(sc, 0);
125
126 sc->stopped = 1;
127 rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
128
129 sc->i2c_tag.ic_cookie = sc;
130 sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus;
131 sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus;
132 sc->i2c_tag.ic_exec = imxiic_i2c_exec;
133
134 bzero(&iba, sizeof iba);
135 iba.iba_name = "iic";
136 iba.iba_tag = &sc->i2c_tag;
137 iba.iba_bus_scan = imxiic_acpi_bus_scan;
138 iba.iba_bus_scan_arg = sc;
139 config_found(&sc->sc_dev, &iba, iicbus_print);
140
141 #ifndef SMALL_KERNEL
142 ac->ac_devnode->i2c = &sc->i2c_tag;
143 acpi_register_gsb(ac->ac_acpi, ac->ac_devnode);
144 #endif
145 }
146
147 int
imxiic_acpi_parse_crs(int crsidx,union acpi_resource * crs,void * arg)148 imxiic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
149 {
150 struct imxiic_crs *sc_crs = arg;
151
152 switch (AML_CRSTYPE(crs)) {
153 case LR_SERBUS:
154 if (crs->lr_serbus.type == LR_SERBUS_I2C)
155 sc_crs->i2c_addr = crs->lr_i2cbus._adr;
156 break;
157 case SR_IRQ:
158 case LR_EXTIRQ:
159 case LR_MEM32:
160 case LR_MEM32FIXED:
161 break;
162 default:
163 printf("%s: unknown resource type %d\n", __func__,
164 AML_CRSTYPE(crs));
165 }
166
167 return 0;
168 }
169
170 void
imxiic_acpi_bus_scan(struct device * iic,struct i2cbus_attach_args * iba,void * aux)171 imxiic_acpi_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
172 void *aux)
173 {
174 struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)aux;
175
176 ac->ac_iic = iic;
177 aml_find_node(ac->ac_devnode, "_HID", imxiic_acpi_found_hid, ac);
178 }
179
180 int
imxiic_acpi_found_hid(struct aml_node * node,void * arg)181 imxiic_acpi_found_hid(struct aml_node *node, void *arg)
182 {
183 struct imxiic_acpi_softc *ac = (struct imxiic_acpi_softc *)arg;
184 struct imxiic_softc *sc = &ac->ac_sc;
185 struct imxiic_crs crs;
186 struct aml_value res;
187 int64_t sta;
188 char cdev[16], dev[16];
189 struct i2c_attach_args ia;
190
191 /* Skip our own _HID. */
192 if (node->parent == ac->ac_devnode)
193 return 0;
194
195 /* Only direct descendants, because of possible muxes. */
196 if (node->parent && node->parent->parent != ac->ac_devnode)
197 return 0;
198
199 if (acpi_parsehid(node, arg, cdev, dev, 16) != 0)
200 return 0;
201
202 sta = acpi_getsta(acpi_softc, node->parent);
203 if ((sta & STA_PRESENT) == 0)
204 return 0;
205
206 if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res))
207 return 0;
208
209 if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
210 printf("%s: invalid _CRS object (type %d len %d)\n",
211 sc->sc_dev.dv_xname, res.type, res.length);
212 aml_freevalue(&res);
213 return (0);
214 }
215 memset(&crs, 0, sizeof(crs));
216 crs.devnode = ac->ac_devnode;
217 aml_parse_resource(&res, imxiic_acpi_parse_crs, &crs);
218 aml_freevalue(&res);
219
220 acpi_attach_deps(acpi_softc, node->parent);
221
222 memset(&ia, 0, sizeof(ia));
223 ia.ia_tag = &sc->i2c_tag;
224 ia.ia_name = dev;
225 ia.ia_addr = crs.i2c_addr;
226 ia.ia_cookie = node->parent;
227
228 config_found(ac->ac_iic, &ia, iicbus_print);
229 node->parent->attached = 1;
230
231 return 0;
232 }
233