1*84b6468dSjmcneill /* $NetBSD: acpi_i2c.c,v 1.19 2025/01/11 11:40:43 jmcneill Exp $ */ 2db8cbfd3Sbouyer 3db8cbfd3Sbouyer /*- 484eb440bSthorpej * Copyright (c) 2017, 2021 The NetBSD Foundation, Inc. 5db8cbfd3Sbouyer * All rights reserved. 6db8cbfd3Sbouyer * 7db8cbfd3Sbouyer * This code is derived from software contributed to The NetBSD Foundation 8db8cbfd3Sbouyer * by Manuel Bouyer. 9db8cbfd3Sbouyer * 10db8cbfd3Sbouyer * Redistribution and use in source and binary forms, with or without 11db8cbfd3Sbouyer * modification, are permitted provided that the following conditions 12db8cbfd3Sbouyer * are met: 13db8cbfd3Sbouyer * 1. Redistributions of source code must retain the above copyright 14db8cbfd3Sbouyer * notice, this list of conditions and the following disclaimer. 15db8cbfd3Sbouyer * 2. Redistributions in binary form must reproduce the above copyright 16db8cbfd3Sbouyer * notice, this list of conditions and the following disclaimer in the 17db8cbfd3Sbouyer * documentation and/or other materials provided with the distribution. 18db8cbfd3Sbouyer * 19db8cbfd3Sbouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20db8cbfd3Sbouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21db8cbfd3Sbouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22db8cbfd3Sbouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23db8cbfd3Sbouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24db8cbfd3Sbouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25db8cbfd3Sbouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26db8cbfd3Sbouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27db8cbfd3Sbouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28db8cbfd3Sbouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29db8cbfd3Sbouyer * POSSIBILITY OF SUCH DAMAGE. 30db8cbfd3Sbouyer */ 31db8cbfd3Sbouyer 320e37d484Sjmcneill #include "iic.h" 330e37d484Sjmcneill 34db8cbfd3Sbouyer #include <sys/cdefs.h> 35*84b6468dSjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_i2c.c,v 1.19 2025/01/11 11:40:43 jmcneill Exp $"); 366a650a48Sjmcneill 376a650a48Sjmcneill #include <sys/device.h> 38db8cbfd3Sbouyer 39db8cbfd3Sbouyer #include <dev/acpi/acpireg.h> 40db8cbfd3Sbouyer #include <dev/acpi/acpivar.h> 41db8cbfd3Sbouyer #include <dev/acpi/acpi_i2c.h> 4220086c25Sjmcneill #include <external/bsd/acpica/dist/include/acinterp.h> 439fabcb6aSjmcneill #include <external/bsd/acpica/dist/include/amlcode.h> 4402b41e14Sjmcneill #include <dev/i2c/i2cvar.h> 45db8cbfd3Sbouyer 4684eb440bSthorpej #include <sys/kmem.h> 4784eb440bSthorpej 48d8ae7995Sbouyer #define _COMPONENT ACPI_BUS_COMPONENT 49d8ae7995Sbouyer ACPI_MODULE_NAME ("acpi_i2c") 50d8ae7995Sbouyer 5120086c25Sjmcneill struct acpi_i2c_address_space_context { 5220086c25Sjmcneill ACPI_CONNECTION_INFO conn_info; /* must be first */ 5320086c25Sjmcneill i2c_tag_t tag; 5420086c25Sjmcneill }; 5520086c25Sjmcneill 566a650a48Sjmcneill static const struct device_compatible_entry hid_compat_data[] = { 576a650a48Sjmcneill { .compat = "PNP0C50" }, 586a650a48Sjmcneill DEVICE_COMPAT_EOL 596a650a48Sjmcneill }; 606a650a48Sjmcneill 610e37d484Sjmcneill #if NIIC > 0 62db8cbfd3Sbouyer struct acpi_i2c_context { 63db8cbfd3Sbouyer uint16_t i2c_addr; 646a650a48Sjmcneill struct acpi_devnode *res_src; 65db8cbfd3Sbouyer }; 660e37d484Sjmcneill #endif 67db8cbfd3Sbouyer 686a650a48Sjmcneill static struct acpi_devnode * 696a650a48Sjmcneill acpi_i2c_resource_find_source(ACPI_RESOURCE_SOURCE *rs) 706a650a48Sjmcneill { 716a650a48Sjmcneill ACPI_STATUS rv; 726a650a48Sjmcneill ACPI_HANDLE hdl; 736a650a48Sjmcneill struct acpi_devnode *ad; 746a650a48Sjmcneill 756a650a48Sjmcneill if (rs->StringPtr == NULL) { 766a650a48Sjmcneill return NULL; 776a650a48Sjmcneill } 786a650a48Sjmcneill 796a650a48Sjmcneill rv = AcpiGetHandle(NULL, rs->StringPtr, &hdl); 806a650a48Sjmcneill if (ACPI_FAILURE(rv)) { 816a650a48Sjmcneill printf("%s: couldn't lookup '%s': %s\n", __func__, 826a650a48Sjmcneill rs->StringPtr, AcpiFormatException(rv)); 836a650a48Sjmcneill return NULL; 846a650a48Sjmcneill } 856a650a48Sjmcneill 866a650a48Sjmcneill SIMPLEQ_FOREACH(ad, &acpi_softc->sc_head, ad_list) { 876a650a48Sjmcneill if (ad->ad_handle == hdl) { 886a650a48Sjmcneill return ad; 896a650a48Sjmcneill } 906a650a48Sjmcneill } 916a650a48Sjmcneill 926a650a48Sjmcneill printf("%s: no acpi devnode matching resource source '%s'\n", 936a650a48Sjmcneill __func__, rs->StringPtr); 946a650a48Sjmcneill return NULL; 956a650a48Sjmcneill } 966a650a48Sjmcneill 97db8cbfd3Sbouyer static ACPI_STATUS 98db8cbfd3Sbouyer acpi_i2c_resource_parse_callback(ACPI_RESOURCE *res, void *context) 99db8cbfd3Sbouyer { 100db8cbfd3Sbouyer struct acpi_i2c_context *i2cc = context; 101db8cbfd3Sbouyer 102db8cbfd3Sbouyer switch (res->Type) { 103db8cbfd3Sbouyer case ACPI_RESOURCE_TYPE_END_TAG: 104db8cbfd3Sbouyer break; 105db8cbfd3Sbouyer case ACPI_RESOURCE_TYPE_SERIAL_BUS: 106db8cbfd3Sbouyer switch (res->Data.I2cSerialBus.Type) { 107db8cbfd3Sbouyer case ACPI_RESOURCE_SERIAL_TYPE_I2C: 108db8cbfd3Sbouyer i2cc->i2c_addr = res->Data.I2cSerialBus.SlaveAddress; 1096a650a48Sjmcneill i2cc->res_src = acpi_i2c_resource_find_source( 1106a650a48Sjmcneill &res->Data.I2cSerialBus.ResourceSource); 111db8cbfd3Sbouyer break; 112db8cbfd3Sbouyer } 113db8cbfd3Sbouyer break; 114db8cbfd3Sbouyer case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 115db8cbfd3Sbouyer break; 116db8cbfd3Sbouyer default: 117a79639ceSjmcneill break; 118db8cbfd3Sbouyer } 119db8cbfd3Sbouyer return_ACPI_STATUS(AE_OK); 120db8cbfd3Sbouyer } 121db8cbfd3Sbouyer 122db8cbfd3Sbouyer static void 123db8cbfd3Sbouyer acpi_enter_i2c_device(struct acpi_devnode *ad, prop_array_t array) 124db8cbfd3Sbouyer { 125db8cbfd3Sbouyer prop_dictionary_t dev; 126db8cbfd3Sbouyer struct acpi_i2c_context i2cc; 127db8cbfd3Sbouyer ACPI_STATUS rv; 12884eb440bSthorpej char *clist; 12984eb440bSthorpej size_t clist_size; 130db8cbfd3Sbouyer 131db8cbfd3Sbouyer memset(&i2cc, 0, sizeof(i2cc)); 132db8cbfd3Sbouyer rv = AcpiWalkResources(ad->ad_handle, "_CRS", 133db8cbfd3Sbouyer acpi_i2c_resource_parse_callback, &i2cc); 134db8cbfd3Sbouyer if (ACPI_FAILURE(rv)) { 135db8cbfd3Sbouyer return; 136db8cbfd3Sbouyer } 137db8cbfd3Sbouyer if (i2cc.i2c_addr == 0) 138db8cbfd3Sbouyer return; 139db8cbfd3Sbouyer dev = prop_dictionary_create(); 140db8cbfd3Sbouyer if (dev == NULL) { 141db8cbfd3Sbouyer aprint_error("ignoring device %s (no memory)\n", 142db8cbfd3Sbouyer ad->ad_name); 143db8cbfd3Sbouyer return; 144db8cbfd3Sbouyer } 145568ac2aaSthorpej clist = acpi_pack_compat_list(ad, &clist_size); 14684eb440bSthorpej if (clist == NULL) { 14784eb440bSthorpej prop_object_release(dev); 14884eb440bSthorpej aprint_error("ignoring device %s (no _HID or _CID)\n", 14984eb440bSthorpej ad->ad_name); 15084eb440bSthorpej return; 15184eb440bSthorpej } 152568ac2aaSthorpej prop_dictionary_set_string(dev, "name", ad->ad_name); 153db8cbfd3Sbouyer prop_dictionary_set_uint32(dev, "addr", i2cc.i2c_addr); 154db8cbfd3Sbouyer prop_dictionary_set_uint64(dev, "cookie", (uintptr_t)ad->ad_handle); 15502b41e14Sjmcneill prop_dictionary_set_uint32(dev, "cookietype", I2C_COOKIE_ACPI); 15684eb440bSthorpej prop_dictionary_set_data(dev, "compatible", clist, clist_size); 15784eb440bSthorpej kmem_free(clist, clist_size); 15884eb440bSthorpej 159db8cbfd3Sbouyer prop_array_add(array, dev); 160db8cbfd3Sbouyer prop_object_release(dev); 161db8cbfd3Sbouyer } 162db8cbfd3Sbouyer 1636a650a48Sjmcneill static void 1646a650a48Sjmcneill acpi_enter_i2chid_devs(device_t dev, struct acpi_devnode *devnode, 1656a650a48Sjmcneill prop_array_t array) 1666a650a48Sjmcneill { 1676a650a48Sjmcneill struct acpi_devnode *ad; 1686a650a48Sjmcneill 1696a650a48Sjmcneill KASSERT(dev != NULL); 1706a650a48Sjmcneill 1716a650a48Sjmcneill SIMPLEQ_FOREACH(ad, &acpi_softc->sc_head, ad_list) { 1726a650a48Sjmcneill struct acpi_attach_args aa = { 1736a650a48Sjmcneill .aa_node = ad 1746a650a48Sjmcneill }; 1756a650a48Sjmcneill struct acpi_i2c_context i2cc; 1766a650a48Sjmcneill ACPI_STATUS rv; 1776a650a48Sjmcneill 1786a650a48Sjmcneill if (!acpi_device_present(ad->ad_handle)) 1796a650a48Sjmcneill continue; 1806a650a48Sjmcneill if (ad->ad_device != NULL) 1816a650a48Sjmcneill continue; 1826a650a48Sjmcneill if (acpi_compatible_match(&aa, hid_compat_data) == 0) 1836a650a48Sjmcneill continue; 1846a650a48Sjmcneill 1856a650a48Sjmcneill memset(&i2cc, 0, sizeof(i2cc)); 1866a650a48Sjmcneill rv = AcpiWalkResources(ad->ad_handle, "_CRS", 1876a650a48Sjmcneill acpi_i2c_resource_parse_callback, &i2cc); 1886a650a48Sjmcneill if (ACPI_SUCCESS(rv) && 1896a650a48Sjmcneill i2cc.i2c_addr != 0 && 1906a650a48Sjmcneill i2cc.res_src == devnode) { 1916a650a48Sjmcneill aprint_debug_dev(dev, "claiming %s\n", ad->ad_name); 192a93f58a9Sjmcneill ad->ad_device = dev; 193*84b6468dSjmcneill acpi_claim_childdevs(dev, ad, NULL); 1946a650a48Sjmcneill acpi_enter_i2c_device(ad, array); 1956a650a48Sjmcneill } 1966a650a48Sjmcneill } 1976a650a48Sjmcneill } 1986a650a48Sjmcneill 199db8cbfd3Sbouyer prop_array_t 200172e088eSjmcneill acpi_enter_i2c_devs(device_t dev, struct acpi_devnode *devnode) 201db8cbfd3Sbouyer { 202db8cbfd3Sbouyer struct acpi_devnode *ad; 203db8cbfd3Sbouyer prop_array_t array = prop_array_create(); 204db8cbfd3Sbouyer 205db8cbfd3Sbouyer if (array == NULL) 206db8cbfd3Sbouyer return NULL; 207db8cbfd3Sbouyer 208db8cbfd3Sbouyer SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) { 209db8cbfd3Sbouyer if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 210db8cbfd3Sbouyer continue; 211a2cf80f2Schristos if (!acpi_device_present(ad->ad_handle)) 212a2cf80f2Schristos continue; 213db8cbfd3Sbouyer acpi_enter_i2c_device(ad, array); 214db8cbfd3Sbouyer } 215172e088eSjmcneill 216172e088eSjmcneill if (dev != NULL) { 217*84b6468dSjmcneill acpi_claim_childdevs(dev, devnode, "_CRS"); 218*84b6468dSjmcneill acpi_claim_childdevs(dev, devnode, "_ADR"); 2196a650a48Sjmcneill acpi_enter_i2chid_devs(dev, devnode, array); 220172e088eSjmcneill } 221172e088eSjmcneill 222db8cbfd3Sbouyer return array; 223db8cbfd3Sbouyer } 22420086c25Sjmcneill 2250e37d484Sjmcneill #if NIIC > 0 22620086c25Sjmcneill static ACPI_STATUS 22720086c25Sjmcneill acpi_i2c_gsb_init(ACPI_HANDLE region_hdl, UINT32 function, 22820086c25Sjmcneill void *handler_ctx, void **region_ctx) 22920086c25Sjmcneill { 23020086c25Sjmcneill if (function == ACPI_REGION_DEACTIVATE) { 23120086c25Sjmcneill *region_ctx = NULL; 23220086c25Sjmcneill } else { 23320086c25Sjmcneill *region_ctx = region_hdl; 23420086c25Sjmcneill } 23520086c25Sjmcneill return AE_OK; 23620086c25Sjmcneill } 23720086c25Sjmcneill 23820086c25Sjmcneill static ACPI_STATUS 23920086c25Sjmcneill acpi_i2c_gsb_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address, 24020086c25Sjmcneill UINT32 bit_width, UINT64 *value, void *handler_ctx, 24120086c25Sjmcneill void *region_ctx) 24220086c25Sjmcneill { 24320086c25Sjmcneill ACPI_OPERAND_OBJECT *region_obj = region_ctx; 24420086c25Sjmcneill struct acpi_i2c_address_space_context *context = handler_ctx; 2459fabcb6aSjmcneill UINT8 *buf = ACPI_CAST_PTR(uint8_t, value); 24620086c25Sjmcneill ACPI_PHYSICAL_ADDRESS base_address; 24720086c25Sjmcneill ACPI_RESOURCE *res; 24820086c25Sjmcneill ACPI_STATUS rv; 24920086c25Sjmcneill ACPI_CONNECTION_INFO *conn_info = &context->conn_info; 25020086c25Sjmcneill i2c_tag_t tag = context->tag; 2519fabcb6aSjmcneill i2c_addr_t i2c_addr; 25220086c25Sjmcneill i2c_op_t op; 25320086c25Sjmcneill union { 25420086c25Sjmcneill uint8_t cmd8; 25520086c25Sjmcneill uint16_t cmd16; 2569fabcb6aSjmcneill uint32_t cmd32; 25720086c25Sjmcneill } cmd; 2589fabcb6aSjmcneill size_t buflen; 25920086c25Sjmcneill size_t cmdlen; 2609fabcb6aSjmcneill bool do_xfer = true; 26120086c25Sjmcneill 26220086c25Sjmcneill if (region_obj->Region.Type != ACPI_TYPE_REGION) { 26320086c25Sjmcneill return AE_OK; 26420086c25Sjmcneill } 26520086c25Sjmcneill 26620086c25Sjmcneill base_address = region_obj->Region.Address; 2679fabcb6aSjmcneill KASSERT(region_obj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS); 26820086c25Sjmcneill 26920086c25Sjmcneill rv = AcpiBufferToResource(conn_info->Connection, conn_info->Length, 27020086c25Sjmcneill &res); 27120086c25Sjmcneill if (ACPI_FAILURE(rv)) { 27220086c25Sjmcneill return rv; 27320086c25Sjmcneill } 27420086c25Sjmcneill if (res->Type != ACPI_RESOURCE_TYPE_SERIAL_BUS || 27520086c25Sjmcneill res->Data.CommonSerialBus.Type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { 27620086c25Sjmcneill return AE_TYPE; 27720086c25Sjmcneill } 27820086c25Sjmcneill 2799fabcb6aSjmcneill i2c_addr = res->Data.I2cSerialBus.SlaveAddress; 28020086c25Sjmcneill if ((function & ACPI_IO_MASK) != 0) { 28120086c25Sjmcneill op = I2C_OP_WRITE_WITH_STOP; 28220086c25Sjmcneill } else { 28320086c25Sjmcneill op = I2C_OP_READ_WITH_STOP; 28420086c25Sjmcneill } 28520086c25Sjmcneill 28620086c25Sjmcneill #ifdef ACPI_I2C_DEBUG 2879fabcb6aSjmcneill UINT32 length; 2889fabcb6aSjmcneill rv = AcpiExGetProtocolBufferLength(function >> 16, &length); 2899fabcb6aSjmcneill if (ACPI_FAILURE(rv)) { 2909fabcb6aSjmcneill printf("%s AcpiExGetProtocolBufferLength failed: %s\n", 2919fabcb6aSjmcneill __func__, AcpiFormatException(rv)); 2929fabcb6aSjmcneill length = UINT32_MAX; 2939fabcb6aSjmcneill } 29420086c25Sjmcneill printf("%s %s: %s Attr %X Addr %.4X BaseAddr %.4X Length %.2X BitWidth %X BufLen %X", 2959fabcb6aSjmcneill __func__, AcpiUtGetRegionName(region_obj->Region.SpaceId), 29620086c25Sjmcneill (function & ACPI_IO_MASK) ? "Write" : "Read ", 29720086c25Sjmcneill (UINT32) (function >> 16), 29820086c25Sjmcneill (UINT32) address, (UINT32) base_address, 2999fabcb6aSjmcneill length, bit_width, buf[1]); 30020086c25Sjmcneill printf(" [AccessLength %.2X Connection %p]\n", 30120086c25Sjmcneill conn_info->AccessLength, conn_info->Connection); 30220086c25Sjmcneill #endif 30320086c25Sjmcneill 3049fabcb6aSjmcneill switch ((UINT32)(function >> 16)) { 3059fabcb6aSjmcneill case AML_FIELD_ATTRIB_QUICK: 30620086c25Sjmcneill cmdlen = 0; 3079fabcb6aSjmcneill buflen = 0; 3089fabcb6aSjmcneill break; 3099fabcb6aSjmcneill case AML_FIELD_ATTRIB_SEND_RECEIVE: 3109fabcb6aSjmcneill cmdlen = 0; 3119fabcb6aSjmcneill buflen = 1; 3129fabcb6aSjmcneill break; 3139fabcb6aSjmcneill case AML_FIELD_ATTRIB_BYTE: 3149fabcb6aSjmcneill cmdlen = bit_width / NBBY; 3159fabcb6aSjmcneill buflen = 1; 3169fabcb6aSjmcneill break; 3179fabcb6aSjmcneill case AML_FIELD_ATTRIB_WORD: 3189fabcb6aSjmcneill cmdlen = bit_width / NBBY; 3199fabcb6aSjmcneill buflen = 2; 3209fabcb6aSjmcneill break; 3219fabcb6aSjmcneill case AML_FIELD_ATTRIB_BYTES: 3229fabcb6aSjmcneill cmdlen = bit_width / NBBY; 3239fabcb6aSjmcneill buflen = buf[1]; 3249fabcb6aSjmcneill break; 3259fabcb6aSjmcneill case AML_FIELD_ATTRIB_BLOCK: 3269fabcb6aSjmcneill cmdlen = bit_width / NBBY; 3279fabcb6aSjmcneill buflen = buf[1]; 3289fabcb6aSjmcneill op |= I2C_OPMASK_BLKMODE; 3299fabcb6aSjmcneill break; 3309fabcb6aSjmcneill case AML_FIELD_ATTRIB_RAW_BYTES: 3319fabcb6aSjmcneill case AML_FIELD_ATTRIB_RAW_PROCESS_BYTES: 3329fabcb6aSjmcneill case AML_FIELD_ATTRIB_PROCESS_CALL: 3339fabcb6aSjmcneill default: 3349fabcb6aSjmcneill cmdlen = 0; 3359fabcb6aSjmcneill do_xfer = false; 3369fabcb6aSjmcneill #ifdef ACPI_I2C_DEBUG 3379fabcb6aSjmcneill printf("field attrib 0x%x not supported\n", 3389fabcb6aSjmcneill (UINT32)(function >> 16)); 3399fabcb6aSjmcneill #endif 3409fabcb6aSjmcneill break; 34120086c25Sjmcneill } 3429fabcb6aSjmcneill 3439fabcb6aSjmcneill switch (cmdlen) { 3449fabcb6aSjmcneill case 0: 3459fabcb6aSjmcneill case 1: 3469fabcb6aSjmcneill cmd.cmd8 = (uint8_t)(base_address + address); 3479fabcb6aSjmcneill break; 3489fabcb6aSjmcneill case 2: 3499fabcb6aSjmcneill cmd.cmd16 = (uint16_t)(base_address + address); 3509fabcb6aSjmcneill break; 3519fabcb6aSjmcneill case 4: 3529fabcb6aSjmcneill cmd.cmd32 = (uint32_t)(base_address + address); 3539fabcb6aSjmcneill break; 3549fabcb6aSjmcneill default: 3559fabcb6aSjmcneill do_xfer = false; 3569fabcb6aSjmcneill #ifdef ACPI_I2C_DEBUG 3579fabcb6aSjmcneill printf("cmdlen %zu not supported\n", cmdlen); 3589fabcb6aSjmcneill #endif 3599fabcb6aSjmcneill break; 3609fabcb6aSjmcneill } 3619fabcb6aSjmcneill 3629fabcb6aSjmcneill if (!do_xfer) { 3639fabcb6aSjmcneill buf[0] = EINVAL; 36420086c25Sjmcneill } else { 36520086c25Sjmcneill const int flags = I2C_F_POLL; 36620086c25Sjmcneill iic_acquire_bus(tag, flags); 3679fabcb6aSjmcneill buf[0] = iic_exec(tag, op, i2c_addr, 3689fabcb6aSjmcneill &cmd, cmdlen, &buf[2], buflen, flags); 36920086c25Sjmcneill iic_release_bus(tag, flags); 3709fabcb6aSjmcneill if (buf[0] == 0) { 3719fabcb6aSjmcneill buf[1] = buflen; 37220086c25Sjmcneill } 37320086c25Sjmcneill #ifdef ACPI_I2C_DEBUG 3749fabcb6aSjmcneill printf("%s iic_exec op %u addr 0x%x len %zu/%zu returned %d\n", 3759fabcb6aSjmcneill __func__, op, res->Data.I2cSerialBus.SlaveAddress, cmdlen, 3769fabcb6aSjmcneill buflen, buf[0]); 37720086c25Sjmcneill #endif 37820086c25Sjmcneill } 37920086c25Sjmcneill 38020086c25Sjmcneill ACPI_FREE(res); 38120086c25Sjmcneill 38220086c25Sjmcneill return AE_OK; 38320086c25Sjmcneill } 3840e37d484Sjmcneill #endif 38520086c25Sjmcneill 38620086c25Sjmcneill ACPI_STATUS 38720086c25Sjmcneill acpi_i2c_register(struct acpi_devnode *devnode, device_t dev, i2c_tag_t tag) 38820086c25Sjmcneill { 3890e37d484Sjmcneill #if NIIC > 0 39020086c25Sjmcneill struct acpi_i2c_address_space_context *context; 39120086c25Sjmcneill ACPI_STATUS rv; 39220086c25Sjmcneill 39320086c25Sjmcneill context = kmem_zalloc(sizeof(*context), KM_SLEEP); 39420086c25Sjmcneill context->tag = tag; 39520086c25Sjmcneill 39620086c25Sjmcneill rv = AcpiInstallAddressSpaceHandler(devnode->ad_handle, 39720086c25Sjmcneill ACPI_ADR_SPACE_GSBUS, acpi_i2c_gsb_handler, acpi_i2c_gsb_init, 39820086c25Sjmcneill context); 39920086c25Sjmcneill if (ACPI_FAILURE(rv)) { 40020086c25Sjmcneill aprint_error_dev(dev, 40120086c25Sjmcneill "couldn't install address space handler: %s", 40220086c25Sjmcneill AcpiFormatException(rv)); 40320086c25Sjmcneill } 40420086c25Sjmcneill 40520086c25Sjmcneill return rv; 4060e37d484Sjmcneill #else 4070e37d484Sjmcneill return AE_NOT_CONFIGURED; 4080e37d484Sjmcneill #endif 40920086c25Sjmcneill } 410