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