diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index f1cfe7e..98b382c 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -14,4 +14,7 @@ config I2C_ALGOPCF
 config I2C_ALGOPCA
 	tristate "I2C PCA 9564 interfaces"
 
+config I2C_ALGOI801
+	tristate "I2C I801 interfaces"
+
 endmenu
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index 215303f..2c7cc99 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -5,5 +5,6 @@
 obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
+obj-$(CONFIG_I2C_ALGOI801)	+= i2c-algo-i801.o
 
 ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-i801.c b/drivers/i2c/algos/i2c-algo-i801.c
new file mode 100644
index 0000000..c7e615c3
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-i801.c
@@ -0,0 +1,211 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+
+/* From an ACPI dump the supported ACPI SBUS operations are:
+ *
+ * SSXB
+ *	transmit one byte
+ * SRXB
+ *	receive one byte
+ * SWRB
+ *	write one byte
+ * SRDB
+ *	read one byte
+ * SWRW
+ *	write one word
+ * SRDW
+ *	read one word
+ * SBLW
+ *	write block
+ * SBRW
+ *	read block
+ *
+ * A lot of this code is based on what the existing i2c-i801.c driver is
+ * doing.  Note that the i2c-i801.c driver also implements I2C_SMBUS_QUICK,
+ * and I2C_SMBUS_I2C_BLOCK_DATA which do not appear to be implemented in the
+ * ACPI driver.
+ */
+
+struct i2c_adapter i2c_acpi_sbus_adapter;
+
+/* all operations are noted as being serialized in the acpidump so no
+ * locking should be required.
+ */
+static s32 i2c_acpi_sbus_access(struct i2c_adapter *adap, u16 addr,
+				unsigned short flags, char read_write,
+				u8 command, int size,
+				union i2c_smbus_data *data)
+{
+	acpi_status status;
+	acpi_handle handle = adap->algo_data;
+	char *op;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_object_list args;
+	union acpi_object *buffer_obj;
+	union acpi_object objects[4];
+	unsigned long long value;
+
+	args.pointer = objects;
+	objects[0].type = ACPI_TYPE_INTEGER;
+	/* taken directly from i2c-smbus.c */
+	objects[0].integer.value = ((addr & 0x7f) << 1) | (read_write & 0x01);
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_WRITE) {
+			op = "SSXB";
+			args.count = 2;
+			objects[1].type = ACPI_TYPE_INTEGER;
+			objects[1].integer.value = command;
+		} else {
+			op = "SRXB";
+			args.count = 1;
+		}
+		status = acpi_evaluate_integer(handle, op, &args, &value);
+		data->byte = value;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		objects[1].type = ACPI_TYPE_INTEGER;
+		objects[1].integer.value = command;
+		if (read_write == I2C_SMBUS_WRITE) {
+			op = "SWRB";
+			args.count = 3;
+			objects[2].type = ACPI_TYPE_INTEGER;
+			objects[2].integer.value = data->byte;
+		} else {
+			op = "SRDB";
+			args.count = 2;
+		}
+		status = acpi_evaluate_integer(handle, op, &args, &value);
+		data->byte = value;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		objects[1].type = ACPI_TYPE_INTEGER;
+		objects[1].integer.value = command;
+		if (read_write == I2C_SMBUS_WRITE) {
+			op = "SWRW";
+			args.count = 3;
+			objects[2].type = ACPI_TYPE_INTEGER;
+			objects[2].integer.value = data->word;
+		} else {
+			op = "SRDW";
+			args.count = 2;
+		}
+		status = acpi_evaluate_integer(handle, op, &args, &value);
+		data->word = value;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		objects[1].type = ACPI_TYPE_INTEGER;
+		objects[1].integer.value = command;
+		if (read_write == I2C_SMBUS_WRITE) {
+			op = "SBLW";
+			args.count = 3;
+			objects[2].buffer.length = data->block[0];
+			objects[2].buffer.pointer = data->block + 1;
+			status = acpi_evaluate_integer(handle, op, &args,
+						       &value);
+			data->byte = value;
+		} else {
+			op = "SBLR";
+			args.count = 2;
+			status = acpi_evaluate_object(handle, op, &args,
+						      &buffer);
+			if (ACPI_SUCCESS(status)) {
+				buffer_obj = buffer.pointer;
+				memcpy(data->block,
+				       buffer_obj->buffer.pointer,
+				       buffer_obj->buffer.length);
+			}
+		}
+		break;
+	default:
+		pr_warn("%s: Unsupported transaction %d\n",
+			i2c_acpi_sbus_adapter.name, size);
+		return -EOPNOTSUPP;
+	}
+
+	if (ACPI_FAILURE(status)) {
+		pr_warn("%s: Transaction failure.\n",
+			i2c_acpi_sbus_adapter.name);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static u32 i2c_acpi_sbus_func(struct i2c_adapter *adapter)
+{
+	return (I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA);
+}
+
+static const struct i2c_algorithm i2c_acpi_sbus_algorithm = {
+	.smbus_xfer	= i2c_acpi_sbus_access,
+	.functionality	= i2c_acpi_sbus_func,
+};
+
+struct i2c_adapter i2c_acpi_sbus_adapter = {
+	.owner	= THIS_MODULE,
+	.class	= I2C_CLASS_HWMON,
+	.algo	= &i2c_acpi_sbus_algorithm,
+	.name	= "i2c ACPI(SBUS) SMBus",
+};
+
+static acpi_status i2c_acpi_sbus_find_device(acpi_handle handle, u32 level,
+					     void *context, void **return_value)
+{
+	acpi_status status;
+	char node_name[5];
+	struct acpi_buffer buffer = {sizeof(node_name), node_name};
+	struct acpi_device *device = NULL;
+	int ret;
+
+	status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+	if (ACPI_FAILURE(status) || strcmp("SBUS", node_name) != 0)
+		return AE_OK;
+
+	acpi_bus_get_device(handle, &device);
+	if (!device) {
+		pr_err("%s: SBUS name found but no matching device\n",
+		       i2c_acpi_sbus_adapter.name);
+		return AE_NOT_FOUND;
+	}
+
+	i2c_acpi_sbus_adapter.dev.parent = &device->dev;
+	i2c_acpi_sbus_adapter.algo_data = handle;
+
+	ret = i2c_add_adapter(&i2c_acpi_sbus_adapter);
+	if (ret)
+		pr_err("%s: i2c core failed to add i2c_sbus\n",
+		       i2c_acpi_sbus_adapter.name);
+		return AE_ERROR;
+	}
+
+	pr_info("%s device found.\n", i2c_acpi_sbus_adapter.name);
+	return AE_OK;
+}
+
+static int __init i2c_acpi_sbus_init(void)
+{
+	acpi_status status;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX, i2c_acpi_sbus_find_device,
+				     NULL, NULL, NULL);
+	if (ACPI_FAILURE(status)) {
+		pr_debug("%s no device found\n", i2c_acpi_sbus_adapter.name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit i2c_acpi_sbus_exit(void)
+{
+	i2c_del_adapter(&i2c_acpi_sbus_adapter);
+}
+
+module_init(i2c_acpi_sbus_init);
+module_exit(i2c_acpi_sbus_exit);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 014afab..a4d97ae 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -81,6 +81,7 @@ config I2C_I801
 	tristate "Intel 82801 (ICH/PCH)"
 	depends on PCI
 	select CHECK_SIGNATURE if X86 && DMI
+	select I2C_ALGOI801
 	help
 	  If you say yes to this option, support will be included for the Intel
 	  801 family of mainboard I2C interfaces.  Specifically, the following
