2 * Copyright (c) 2016 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Imre Vadász <imre@vdsz.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 /* Register SMBUS device with ACPICA for ACPI-5.0 GPIO functionality */
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/errno.h>
47 #include <dev/acpica/acpivar.h>
48 #include <contrib/dev/acpica/source/include/amlcode.h>
50 #include <bus/smbus/smbconf.h>
60 struct acpi_i2c_handler_data {
61 struct acpi_connection_info info;
65 struct smbus_acpi_softc {
68 struct acpi_i2c_handler_data space_handler_data;
71 static int smbus_acpi_probe(device_t dev);
72 static int smbus_acpi_attach(device_t dev);
73 static int smbus_acpi_detach(device_t dev);
75 /* SMBUS Address Space Handler */
76 static void smbus_acpi_install_address_space_handler(
77 struct smbus_acpi_softc *sc);
78 static void smbus_acpi_remove_address_space_handler(
79 struct smbus_acpi_softc *sc);
80 static ACPI_STATUS smbus_acpi_space_handler(UINT32 Function,
81 ACPI_PHYSICAL_ADDRESS Address, UINT32 BitWidth,
82 UINT64 *Value, void *HandlerContext,
86 * SMBUS Address space handler
90 smbus_acpi_install_address_space_handler(struct smbus_acpi_softc *sc)
95 handle = acpi_get_handle(sc->parent);
96 sc->space_handler_data.dev = sc->parent;
97 s = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
98 &smbus_acpi_space_handler, NULL, &sc->space_handler_data);
99 if (ACPI_FAILURE(s)) {
100 device_printf(sc->dev,
101 "Failed to install GSBUS Address Space Handler in ACPI\n");
106 smbus_acpi_remove_address_space_handler(struct smbus_acpi_softc *sc)
111 handle = acpi_get_handle(sc->parent);
112 s = AcpiRemoveAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
113 &smbus_acpi_space_handler);
114 if (ACPI_FAILURE(s)) {
115 device_printf(sc->dev,
116 "Failed to remove GSBUS Address Space Handler from ACPI\n");
121 smbus_acpi_space_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address,
122 UINT32 BitWidth, UINT64 *Value, void *HandlerContext, void *RegionContext)
124 struct gsb_buffer *gsb = (struct gsb_buffer *)Value;
125 struct acpi_i2c_handler_data *data = HandlerContext;
126 device_t dev = data->dev;
127 struct acpi_connection_info *info = &data->info;
128 struct acpi_resource_i2c_serialbus *sb;
129 ACPI_RESOURCE *Resource;
130 UINT32 accessor_type = Function >> 16;
131 UINT8 action = Function & ACPI_IO_MASK;
132 ACPI_STATUS s = AE_OK;
141 return (AE_BAD_PARAMETER);
143 s = AcpiBufferToResource(info->Connection, info->Length,
147 if (Resource->Type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
148 s = AE_BAD_PARAMETER;
152 sb = &Resource->Data.I2cSerialBus;
153 if (sb->Type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
154 s = AE_BAD_PARAMETER;
158 /* XXX Ignore 10bit addressing for now */
159 if (sb->AccessMode == ACPI_I2C_10BIT_MODE) {
160 s = AE_BAD_PARAMETER;
164 switch (accessor_type) {
165 case AML_FIELD_ATTRIB_SEND_RCV:
166 if (action == ACPI_READ) {
167 val = SMBUS_RECVB(dev, sb->SlaveAddress, &byte);
171 val = SMBUS_SENDB(dev, sb->SlaveAddress,
175 case AML_FIELD_ATTRIB_BYTE:
176 if (action == ACPI_READ) {
177 val = SMBUS_READB(dev, sb->SlaveAddress, Address,
182 val = SMBUS_WRITEB(dev, sb->SlaveAddress, Address,
186 case AML_FIELD_ATTRIB_WORD:
187 wdata = (uint16_t *)gsb->data;
188 if (action == ACPI_READ) {
189 val = SMBUS_READW(dev, sb->SlaveAddress, Address,
194 val = SMBUS_WRITEW(dev, sb->SlaveAddress, Address,
198 case AML_FIELD_ATTRIB_BLOCK:
199 if (action == ACPI_READ) {
201 val = SMBUS_BREAD(dev, sb->SlaveAddress, Address,
205 memcpy(gsb->data, buf, count);
208 memcpy(buf, gsb->data, gsb->len);
210 val = SMBUS_BWRITE(dev, sb->SlaveAddress, Address,
214 case AML_FIELD_ATTRIB_MULTIBYTE:
215 if (action == ACPI_READ) {
217 val = SMBUS_TRANS(dev, sb->SlaveAddress, Address,
218 SMB_TRANS_NOCNT | SMB_TRANS_7BIT, NULL, 0,
219 buf, info->AccessLength, &cnt);
221 memcpy(gsb->data, buf, cnt);
223 memcpy(buf, gsb->data, info->AccessLength);
224 val = SMBUS_TRANS(dev, sb->SlaveAddress, Address,
225 SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
226 buf, info->AccessLength, NULL, 0, NULL);
230 device_printf(dev, "protocol(0x%02x) is not supported.\n",
232 s = AE_BAD_PARAMETER;
245 smbus_acpi_probe(device_t dev)
247 if (acpi_get_handle(device_get_parent(dev)) == NULL)
250 device_set_desc(dev, "ACPI I2cSerialBus backend");
256 smbus_acpi_attach(device_t dev)
258 struct smbus_acpi_softc *sc = device_get_softc(dev);
261 sc->parent = device_get_parent(dev);
263 smbus_acpi_install_address_space_handler(sc);
269 smbus_acpi_detach(device_t dev)
271 struct smbus_acpi_softc *sc = device_get_softc(dev);
273 smbus_acpi_remove_address_space_handler(sc);
278 static device_method_t smbacpi_methods[] = {
279 /* Device interface */
280 DEVMETHOD(device_probe, smbus_acpi_probe),
281 DEVMETHOD(device_attach, smbus_acpi_attach),
282 DEVMETHOD(device_detach, smbus_acpi_detach),
287 static driver_t smbacpi_driver = {
290 sizeof(struct smbus_acpi_softc)
293 static devclass_t smbacpi_devclass;
295 DRIVER_MODULE(smbacpi, ig4iic, smbacpi_driver, smbacpi_devclass,
297 MODULE_DEPEND(smbacpi, acpi, 1, 1, 1);
298 MODULE_DEPEND(smbacpi, smbus, 1, 1, 1);
299 MODULE_VERSION(smbacpi, 1);