[kernel: 62/85] add untracked patches

Adam Williamson adamwill at fedoraproject.org
Wed Nov 26 20:53:57 UTC 2014


commit 0557a6fc2da5a17f8a88e164e7b40212db4ab9dd
Author: Adam Williamson <awilliam at redhat.com>
Date:   Sat Sep 13 10:09:20 2014 -0700

    add untracked patches

 ...emporary-dep-solution-for-battery-support.patch |  148 ++++++
 ...ID-for-Dell-Venue-8-Pro-s-wireless-adapte.patch |   24 +
 ...CPI-Add-i2c-ACPI-operation-region-support.patch |  461 +++++++++++++++++++
 ...-ACPI-code-and-Add-CONFIG_I2C_ACPI-config.patch |  310 +++++++++++++
 baytrail_gpio_quirk_v3.patch                       |   87 ++++
 ...om-SoC-power-management-controller-driver.patch |  484 ++++++++++++++++++++
 6 files changed, 1514 insertions(+), 0 deletions(-)
---
diff --git a/0001-ACPI-temporary-dep-solution-for-battery-support.patch b/0001-ACPI-temporary-dep-solution-for-battery-support.patch
new file mode 100644
index 0000000..737cd10
--- /dev/null
+++ b/0001-ACPI-temporary-dep-solution-for-battery-support.patch
@@ -0,0 +1,148 @@
+From bbadbc67de278123e28dd6f9ee7e88b6ada56ce4 Mon Sep 17 00:00:00 2001
+From: Lan Tianyu <tianyu.lan at intel.com>
+Date: Fri, 21 Mar 2014 16:42:12 +0800
+Subject: [PATCH] ACPI: temporary dep solution for battery support
+
+This is a dep workaround for battery support on Asus T100TA and the formal
+dep solution is under developing. This patch is just for test and will
+not be upstreamed.
+---
+ drivers/acpi/scan.c    | 64 +++++++++++++++++++++++++++++++++++++++++++++++---
+ drivers/i2c/i2c-acpi.c |  1 +
+ include/linux/acpi.h   |  1 +
+ 3 files changed, 63 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
+index 7efe546..254afb7 100644
+--- a/drivers/acpi/scan.c
++++ b/drivers/acpi/scan.c
+@@ -36,6 +36,7 @@ bool acpi_force_hot_remove;
+ 
+ static const char *dummy_hid = "device";
+ 
++static LIST_HEAD(acpi_bus_dep_device_list);
+ static LIST_HEAD(acpi_bus_id_list);
+ static DEFINE_MUTEX(acpi_scan_lock);
+ static LIST_HEAD(acpi_scan_handlers_list);
+@@ -43,6 +44,12 @@ DEFINE_MUTEX(acpi_device_lock);
+ LIST_HEAD(acpi_wakeup_device_list);
+ static DEFINE_MUTEX(acpi_hp_context_lock);
+ 
++
++struct acpi_dep_handle {
++	struct list_head node;
++	acpi_handle handle;
++};
++
+ struct acpi_device_bus_id{
+ 	char bus_id[15];
+ 	unsigned int instance_no;
+@@ -2027,10 +2034,22 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
+ 	}
+ }
+ 
++
++static int acpi_dep_device_check(acpi_handle handle)
++{
++	struct acpi_dep_handle *dep;
++
++	list_for_each_entry(dep, &acpi_bus_dep_device_list, node)
++		if (dep->handle == handle)
++			return -EEXIST;
++	return 0;
++}
++
+ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
+ 				      void *not_used, void **return_value)
+ {
+ 	struct acpi_device *device = NULL;
++	struct acpi_dep_handle *dep = NULL;
+ 	int type;
+ 	unsigned long long sta;
+ 	int result;
+@@ -2048,9 +2067,24 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
+ 		return AE_OK;
+ 	}
+ 
+-	acpi_add_single_object(&device, handle, type, sta);
+-	if (!device)
+-		return AE_CTRL_DEPTH;
++	if (!acpi_dep_device_check(handle)
++	   && acpi_has_method(handle, "_BIX")
++	   && acpi_has_method(handle, "_DEP")) {
++		dep = kmalloc(sizeof(struct acpi_dep_handle), GFP_KERNEL);
++		if (!dep)
++			return AE_CTRL_DEPTH;
++		dep->handle = handle;
++		list_add_tail(&dep->node , &acpi_bus_dep_device_list);
++
++		acpi_handle_info(dep->handle,
++				"is added to dep device list.\n");
++
++		return AE_OK;
++	} else {
++		acpi_add_single_object(&device, handle, type, sta);
++		if (!device)
++			return AE_CTRL_DEPTH;
++	}
+ 
+ 	acpi_scan_init_hotplug(device);
+ 
+@@ -2061,6 +2095,30 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
+ 	return AE_OK;
+ }
+ 
++int acpi_walk_dep_device_list(void)
++{
++	struct acpi_dep_handle *dep, *tmp;
++	acpi_status status;
++	unsigned long long sta;
++
++	list_for_each_entry_safe(dep, tmp, &acpi_bus_dep_device_list, node) {
++		status = acpi_evaluate_integer(dep->handle, "_STA", NULL, &sta);
++
++		if (ACPI_FAILURE(status)) {
++			acpi_handle_warn(dep->handle,
++				"Status check failed (0x%x)\n", status);
++		} else if (sta & ACPI_STA_DEVICE_ENABLED) {
++			acpi_bus_scan(dep->handle);
++			acpi_handle_info(dep->handle,
++				"Device is readly\n");
++			list_del(&dep->node);
++			kfree(dep);
++		}
++	}
++	return 0;
++}
++EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
++
+ static int acpi_scan_attach_handler(struct acpi_device *device)
+ {
+ 	struct acpi_hardware_id *hwid;
+diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c
+index a0ae867..471490a 100644
+--- a/drivers/i2c/i2c-acpi.c
++++ b/drivers/i2c/i2c-acpi.c
+@@ -349,6 +349,7 @@ int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
+ 		return -ENOMEM;
+ 	}
+ 
++	acpi_walk_dep_device_list();
+ 	return 0;
+ }
+ 
+diff --git a/include/linux/acpi.h b/include/linux/acpi.h
+index 667204c..66ad0dd 100644
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -115,6 +115,7 @@ int acpi_boot_init (void);
+ void acpi_boot_table_init (void);
+ int acpi_mps_check (void);
+ int acpi_numa_init (void);
++int acpi_walk_dep_device_list(void);
+ 
+ int acpi_table_init (void);
+ int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
+-- 
+1.8.3.1
+
diff --git a/0001-add-device-ID-for-Dell-Venue-8-Pro-s-wireless-adapte.patch b/0001-add-device-ID-for-Dell-Venue-8-Pro-s-wireless-adapte.patch
new file mode 100644
index 0000000..dc1c997
--- /dev/null
+++ b/0001-add-device-ID-for-Dell-Venue-8-Pro-s-wireless-adapte.patch
@@ -0,0 +1,24 @@
+From 69968772071bb8632a57f42ec77a3acdddbe74d7 Mon Sep 17 00:00:00 2001
+From: Adam Williamson <awilliam at redhat.com>
+Date: Mon, 14 Apr 2014 16:05:32 -0700
+Subject: [PATCH] add device ID for Dell Venue 8 Pro's wireless adapter
+
+---
+ drivers/net/wireless/ath/ath6kl/sdio.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
+index 7126bdd..f403ebb 100644
+--- a/drivers/net/wireless/ath/ath6kl/sdio.c
++++ b/drivers/net/wireless/ath/ath6kl/sdio.c
+@@ -1403,6 +1403,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
+ 	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
+ 	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
+ 	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
++	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x18))},
+ 	{},
+ };
+ 
+-- 
+1.9.0
+
diff --git a/V3-4-5-I2C-ACPI-Add-i2c-ACPI-operation-region-support.patch b/V3-4-5-I2C-ACPI-Add-i2c-ACPI-operation-region-support.patch
new file mode 100644
index 0000000..a8d0244
--- /dev/null
+++ b/V3-4-5-I2C-ACPI-Add-i2c-ACPI-operation-region-support.patch
@@ -0,0 +1,461 @@
+From patchwork Tue May 20 12:59:23 2014
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [V3,4/5] I2C/ACPI: Add i2c ACPI operation region support
+From: "lan,Tianyu" <tianyu.lan at intel.com>
+X-Patchwork-Id: 4209471
+Message-Id: <1400590764-11108-5-git-send-email-tianyu.lan at intel.com>
+To: wsa at the-dreams.de, rjw at rjwysocki.net,
+	mika.westerberg at linux.intel.com, awilliam at redhat.com, lenb at kernel.org
+Cc: Lan Tianyu <tianyu.lan at intel.com>, linux-i2c at vger.kernel.org,
+	linux-kernel at vger.kernel.org, linux-acpi at vger.kernel.org
+Date: Tue, 20 May 2014 20:59:23 +0800
+
+ACPI 5.0 spec(5.5.2.4.5) defines GenericSerialBus(i2c, spi, uart) operation region.
+It allows ACPI aml code able to access such kind of devices to implement
+some ACPI standard method.
+
+ACPI Spec defines some access attribute to associate with i2c protocol.
+AttribQuick 	       	       		Read/Write Quick Protocol
+AttribSendReceive			Send/Receive Byte Protocol
+AttribByte 			 	Read/Write Byte Protocol
+AttribWord				Read/Write Word Protocol
+AttribBlock				Read/Write Block Protocol
+AttribBytes				Read/Write N-Bytes Protocol
+AttribProcessCall			Process Call Protocol
+AttribBlockProcessCall			Write Block-Read Block Process Call Protocol
+AttribRawBytes 				Raw Read/Write N-BytesProtocol
+AttribRawProcessBytes			Raw Process Call Protocol
+
+On the Asus T100TA, Bios use GenericSerialBus operation region to access
+i2c device to get battery info.
+
+Sample code From Asus T100TA
+
+    Scope (_SB.I2C1)
+    {
+        Name (UMPC, ResourceTemplate ()
+        {
+            I2cSerialBus (0x0066, ControllerInitiated, 0x00061A80,
+                AddressingMode7Bit, "\\_SB.I2C1",
+                0x00, ResourceConsumer, ,
+                )
+        })
+
+	...
+
+        OperationRegion (DVUM, GenericSerialBus, Zero, 0x0100)
+        Field (DVUM, BufferAcc, NoLock, Preserve)
+        {
+            Connection (UMPC),
+            Offset (0x81),
+            AccessAs (BufferAcc, AttribBytes (0x3E)),
+            FGC0,   8
+        }
+	...
+     }
+
+     Device (BATC)
+     {
+         Name (_HID, EisaId ("PNP0C0A"))  // _HID: Hardware ID
+         Name (_UID, One)  // _UID: Unique ID
+	 ...
+
+            Method (_BST, 0, NotSerialized)  // _BST: Battery Status
+            {
+                If (LEqual (AVBL, One))
+                {
+                    Store (FGC0, BFFG)
+                    If (LNotEqual (STAT, One))
+                    {
+                        ShiftRight (CHST, 0x04, Local0)
+                        And (Local0, 0x03, Local0)
+                        If (LOr (LEqual (Local0, One), LEqual (Local0, 0x02)))
+                        {
+                            Store (0x02, Local1)
+                        }
+	...
+
+    }
+
+The i2c operation region is defined under I2C1 scope. _BST method under
+battery device BATC read battery status from the field "FCG0". The request
+would be sent to i2c operation region handler.
+
+This patch is to add i2c ACPI operation region support. Due to there are
+only "Byte" and "Bytes" protocol access on the Asus T100TA, other protocols
+have not been tested.
+
+About RawBytes and RawProcessBytes protocol, they needs specific drivers to interpret
+reference data from AML code according ACPI 5.0 SPEC(5.5.2.4.5.3.9 and 5.5.2.4.5.3.10).
+So far, not found such case and will add when find real case.
+
+Signed-off-by: Lan Tianyu <tianyu.lan at intel.com>
+
+---
+drivers/i2c/Makefile   |   5 +-
+ drivers/i2c/i2c-acpi.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/i2c/i2c-core.c |   2 +
+ include/linux/acpi.h   |  11 ++
+ include/linux/i2c.h    |  10 ++
+ 5 files changed, 300 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/i2c/i2c-acpi.c
+
+diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
+index 1722f50..80db307 100644
+--- a/drivers/i2c/Makefile
++++ b/drivers/i2c/Makefile
+@@ -2,8 +2,11 @@
+ # Makefile for the i2c core.
+ #
+ 
++i2ccore-y := i2c-core.o
++i2ccore-$(CONFIG_ACPI)		+= i2c-acpi.o
++
+ obj-$(CONFIG_I2C_BOARDINFO)	+= i2c-boardinfo.o
+-obj-$(CONFIG_I2C)		+= i2c-core.o
++obj-$(CONFIG_I2C)		+= i2ccore.o
+ obj-$(CONFIG_I2C_SMBUS)		+= i2c-smbus.o
+ obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
+ obj-$(CONFIG_I2C_MUX)		+= i2c-mux.o
+diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c
+new file mode 100644
+index 0000000..f7f4c89
+--- /dev/null
++++ b/drivers/i2c/i2c-acpi.c
+@@ -0,0 +1,273 @@
++/*
++ * I2C ACPI code
++ *
++ * Copyright (C) 2014 Intel Corp
++ *
++ * Author: Lan Tianyu <tianyu.lan at intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++#define pr_fmt(fmt) "I2C/ACPI : " fmt
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/acpi.h>
++
++struct acpi_i2c_handler_data {
++	struct acpi_connection_info info;
++	struct i2c_adapter *adapter;
++};
++
++struct gsb_buffer {
++	u8	status;
++	u8	len;
++	union {
++		u16	wdata;
++		u8	bdata;
++		u8	data[0];
++	};
++} __packed;
++
++static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
++		u8 cmd, u8 *data, u8 data_len)
++{
++
++	struct i2c_msg msgs[2];
++	int ret;
++	u8 *buffer;
++
++	buffer = kzalloc(data_len, GFP_KERNEL);
++	if (!buffer)
++		return AE_NO_MEMORY;
++
++	msgs[0].addr = client->addr;
++	msgs[0].flags = client->flags;
++	msgs[0].len = 1;
++	msgs[0].buf = &cmd;
++
++	msgs[1].addr = client->addr;
++	msgs[1].flags = client->flags | I2C_M_RD;
++	msgs[1].len = data_len;
++	msgs[1].buf = buffer;
++
++	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
++	if (ret < 0)
++		dev_err(&client->adapter->dev, "i2c read failed\n");
++	else
++		memcpy(data, buffer, data_len);
++
++	kfree(buffer);
++	return ret;
++}
++
++static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
++		u8 cmd, u8 *data, u8 data_len)
++{
++
++	struct i2c_msg msgs[1];
++	u8 *buffer;
++	int ret = AE_OK;
++
++	buffer = kzalloc(data_len + 1, GFP_KERNEL);
++	if (!buffer)
++		return AE_NO_MEMORY;
++
++	buffer[0] = cmd;
++	memcpy(buffer + 1, data, data_len);
++
++	msgs[0].addr = client->addr;
++	msgs[0].flags = client->flags;
++	msgs[0].len = data_len + 1;
++	msgs[0].buf = buffer;
++
++	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
++	if (ret < 0)
++		dev_err(&client->adapter->dev, "i2c write failed\n");
++
++	kfree(buffer);
++	return ret;
++}
++
++static acpi_status
++acpi_i2c_space_handler(u32 function, acpi_physical_address command,
++			u32 bits, u64 *value64,
++			void *handler_context, void *region_context)
++{
++	struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
++	struct acpi_i2c_handler_data *data = handler_context;
++	struct acpi_connection_info *info = &data->info;
++	struct acpi_resource_i2c_serialbus *sb;
++	struct i2c_adapter *adapter = data->adapter;
++	struct i2c_client client;
++	struct acpi_resource *ares;
++	u32 accessor_type = function >> 16;
++	u8 action = function & ACPI_IO_MASK;
++	acpi_status ret = AE_OK;
++	int status;
++
++	ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
++	if (ACPI_FAILURE(ret))
++		return ret;
++
++	if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++	sb = &ares->data.i2c_serial_bus;
++	if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++	memset(&client, 0, sizeof(client));
++	client.adapter = adapter;
++	client.addr = sb->slave_address;
++	client.flags = 0;
++
++	if (sb->access_mode == ACPI_I2C_10BIT_MODE)
++		client.flags |= I2C_CLIENT_TEN;
++
++	switch (accessor_type) {
++	case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV:
++		if (action == ACPI_READ) {
++			status = i2c_smbus_read_byte(&client);
++			if (status >= 0) {
++				gsb->bdata = status;
++				status = 0;
++			}
++		} else {
++			status = i2c_smbus_write_byte(&client, gsb->bdata);
++		}
++		break;
++
++	case ACPI_GSB_ACCESS_ATTRIB_BYTE:
++		if (action == ACPI_READ) {
++			status = i2c_smbus_read_byte_data(&client, command);
++			if (status >= 0) {
++				gsb->bdata = status;
++				status = 0;
++			}
++		} else {
++			status = i2c_smbus_write_byte_data(&client, command,
++					gsb->bdata);
++		}
++		break;
++
++	case ACPI_GSB_ACCESS_ATTRIB_WORD:
++		if (action == ACPI_READ) {
++			status = i2c_smbus_read_word_data(&client, command);
++			if (status >= 0) {
++				gsb->wdata = status;
++				status = 0;
++			}
++		} else {
++			status = i2c_smbus_write_word_data(&client, command,
++					gsb->wdata);
++		}
++		break;
++
++	case ACPI_GSB_ACCESS_ATTRIB_BLOCK:
++		if (action == ACPI_READ) {
++			status = i2c_smbus_read_block_data(&client, command,
++					gsb->data);
++			if (status >= 0) {
++				gsb->len = status;
++				status = 0;
++			}
++		} else {
++			status = i2c_smbus_write_block_data(&client, command,
++					gsb->len, gsb->data);
++		}
++		break;
++
++	case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE:
++		if (action == ACPI_READ) {
++			status = acpi_gsb_i2c_read_bytes(&client, command,
++					gsb->data, info->access_length);
++			if (status > 0)
++				status = 0;
++		} else {
++			status = acpi_gsb_i2c_write_bytes(&client, command,
++					gsb->data, info->access_length);
++		}
++		break;
++
++	default:
++		pr_info("protocol(0x%02x) is not supported.\n", accessor_type);
++		ret = AE_BAD_PARAMETER;
++		goto err;
++	}
++
++	gsb->status = status;
++
++ err:
++	ACPI_FREE(ares);
++	return ret;
++}
++
++
++int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
++{
++	acpi_handle handle = ACPI_HANDLE(adapter->dev.parent);
++	struct acpi_i2c_handler_data *data;
++	acpi_status status;
++
++	if (!handle)
++		return -ENODEV;
++
++	data = kzalloc(sizeof(struct acpi_i2c_handler_data),
++			    GFP_KERNEL);
++	if (!data)
++		return -ENOMEM;
++
++	data->adapter = adapter;
++	status = acpi_bus_attach_private_data(handle, (void *)data);
++	if (ACPI_FAILURE(status)) {
++		kfree(data);
++		return -ENOMEM;
++	}
++
++	status = acpi_install_address_space_handler(handle,
++				ACPI_ADR_SPACE_GSBUS,
++				&acpi_i2c_space_handler,
++				NULL,
++				data);
++	if (ACPI_FAILURE(status)) {
++		dev_err(&adapter->dev, "Error installing i2c space handler\n");
++		acpi_bus_detach_private_data(handle);
++		kfree(data);
++		return -ENOMEM;
++	}
++
++	return 0;
++}
++
++void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
++{
++	acpi_handle handle = ACPI_HANDLE(adapter->dev.parent);
++	struct acpi_i2c_handler_data *data;
++	acpi_status status;
++
++	if (!handle)
++		return;
++
++	acpi_remove_address_space_handler(handle,
++				ACPI_ADR_SPACE_GSBUS,
++				&acpi_i2c_space_handler);
++
++	status = acpi_bus_get_private_data(handle, (void **)&data);
++	if (ACPI_SUCCESS(status))
++		kfree(data);
++
++	acpi_bus_detach_private_data(handle);
++}
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index 7c7f4b8..e25cb84 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -1293,6 +1293,7 @@ exit_recovery:
+ 	/* create pre-declared device nodes */
+ 	of_i2c_register_devices(adap);
+ 	acpi_i2c_register_devices(adap);
++	acpi_i2c_install_space_handler(adap);
+ 
+ 	if (adap->nr < __i2c_first_dynamic_bus_num)
+ 		i2c_scan_static_board_info(adap);
+@@ -1466,6 +1467,7 @@ void i2c_del_adapter(struct i2c_adapter *adap)
+ 		return;
+ 	}
+ 
++	acpi_i2c_remove_space_handler(adap);
+ 	/* Tell drivers about this removal */
+ 	mutex_lock(&core_lock);
+ 	bus_for_each_drv(&i2c_bus_type, NULL, adap,
+diff --git a/include/linux/acpi.h b/include/linux/acpi.h
+index 7a8f2cd..ea53b9b 100644
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -361,6 +361,17 @@ extern bool osc_sb_apei_support_acked;
+ #define OSC_PCI_EXPRESS_CAPABILITY_CONTROL	0x00000010
+ #define OSC_PCI_CONTROL_MASKS			0x0000001f
+ 
++#define ACPI_GSB_ACCESS_ATTRIB_QUICK		0x00000002
++#define ACPI_GSB_ACCESS_ATTRIB_SEND_RCV         0x00000004
++#define ACPI_GSB_ACCESS_ATTRIB_BYTE		0x00000006
++#define ACPI_GSB_ACCESS_ATTRIB_WORD		0x00000008
++#define ACPI_GSB_ACCESS_ATTRIB_BLOCK		0x0000000A
++#define ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE	0x0000000B
++#define ACPI_GSB_ACCESS_ATTRIB_WORD_CALL	0x0000000C
++#define ACPI_GSB_ACCESS_ATTRIB_BLOCK_CALL	0x0000000D
++#define ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES	0x0000000E
++#define ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS	0x0000000F
++
+ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
+ 					     u32 *mask, u32 req);
+ 
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index b556e0a..f7a939a 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -577,4 +577,14 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
+ }
+ #endif /* CONFIG_OF */
+ 
++#ifdef CONFIG_ACPI
++int acpi_i2c_install_space_handler(struct i2c_adapter *adapter);
++void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter);
++#else
++static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
++{ }
++static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
++{ return 0; }
++#endif
++
+ #endif /* _LINUX_I2C_H */
diff --git a/V3-5-5-I2C-ACPI-Clean-up-I2C-ACPI-code-and-Add-CONFIG_I2C_ACPI-config.patch b/V3-5-5-I2C-ACPI-Clean-up-I2C-ACPI-code-and-Add-CONFIG_I2C_ACPI-config.patch
new file mode 100644
index 0000000..40f673e
--- /dev/null
+++ b/V3-5-5-I2C-ACPI-Clean-up-I2C-ACPI-code-and-Add-CONFIG_I2C_ACPI-config.patch
@@ -0,0 +1,310 @@
+From patchwork Tue May 20 12:59:24 2014
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [V3,
+	5/5] I2C/ACPI: Clean up I2C ACPI code and Add CONFIG_I2C_ACPI config
+From: "lan,Tianyu" <tianyu.lan at intel.com>
+X-Patchwork-Id: 4209461
+Message-Id: <1400590764-11108-6-git-send-email-tianyu.lan at intel.com>
+To: wsa at the-dreams.de, rjw at rjwysocki.net,
+	mika.westerberg at linux.intel.com, awilliam at redhat.com, lenb at kernel.org
+Cc: Lan Tianyu <tianyu.lan at intel.com>, linux-i2c at vger.kernel.org,
+	linux-kernel at vger.kernel.org, linux-acpi at vger.kernel.org
+Date: Tue, 20 May 2014 20:59:24 +0800
+
+Clean up ACPI related code in the i2c core and add CONFIG_I2C_ACPI
+to enable I2C ACPI code.
+
+Current there is a race between removing I2C ACPI operation region
+and ACPI AML code accessing. So make i2c core built-in if CONFIG_I2C_ACPI
+is set.
+
+Reviewed-by: Mika Westerberg <mika.westerberg at linux.intel.com>
+Signed-off-by: Lan Tianyu <tianyu.lan at intel.com>
+
+---
+drivers/i2c/Kconfig    | 18 +++++++++-
+ drivers/i2c/Makefile   |  2 +-
+ drivers/i2c/i2c-acpi.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/i2c/i2c-core.c | 95 --------------------------------------------------
+ include/linux/i2c.h    |  4 ++-
+ 5 files changed, 110 insertions(+), 98 deletions(-)
+
+diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
+index 7b7ea32..3e3b680 100644
+--- a/drivers/i2c/Kconfig
++++ b/drivers/i2c/Kconfig
+@@ -2,7 +2,9 @@
+ # I2C subsystem configuration
+ #
+ 
+-menuconfig I2C
++menu "I2C support"
++
++config I2C
+ 	tristate "I2C support"
+ 	select RT_MUTEXES
+ 	---help---
+@@ -21,6 +23,18 @@ menuconfig I2C
+ 	  This I2C support can also be built as a module.  If so, the module
+ 	  will be called i2c-core.
+ 
++config I2C_ACPI
++	bool "I2C ACPI support"
++	select I2C
++	depends on ACPI
++	default y
++	help
++	  Say Y here if you want to enable ACPI I2C support. This includes support
++	  for automatic enumeration of I2C slave devices and support for ACPI I2C
++	  Operation Regions. Operation Regions allow firmware (BIOS) code to
++	  access I2C slave devices, such as smart batteries through an I2C host
++	  controller driver.
++
+ if I2C
+ 
+ config I2C_BOARDINFO
+@@ -124,3 +138,5 @@ config I2C_DEBUG_BUS
+ 	  on.
+ 
+ endif # I2C
++
++endmenu
+diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
+index 80db307..a1f590c 100644
+--- a/drivers/i2c/Makefile
++++ b/drivers/i2c/Makefile
+@@ -3,7 +3,7 @@
+ #
+ 
+ i2ccore-y := i2c-core.o
+-i2ccore-$(CONFIG_ACPI)		+= i2c-acpi.o
++i2ccore-$(CONFIG_I2C_ACPI)	+= i2c-acpi.o
+ 
+ obj-$(CONFIG_I2C_BOARDINFO)	+= i2c-boardinfo.o
+ obj-$(CONFIG_I2C)		+= i2ccore.o
+diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c
+index f7f4c89..e8b6196 100644
+--- a/drivers/i2c/i2c-acpi.c
++++ b/drivers/i2c/i2c-acpi.c
+@@ -37,6 +37,95 @@ struct gsb_buffer {
+ 	};
+ } __packed;
+ 
++static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
++{
++	struct i2c_board_info *info = data;
++
++	if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
++		struct acpi_resource_i2c_serialbus *sb;
++
++		sb = &ares->data.i2c_serial_bus;
++		if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
++			info->addr = sb->slave_address;
++			if (sb->access_mode == ACPI_I2C_10BIT_MODE)
++				info->flags |= I2C_CLIENT_TEN;
++		}
++	} else if (info->irq < 0) {
++		struct resource r;
++
++		if (acpi_dev_resource_interrupt(ares, 0, &r))
++			info->irq = r.start;
++	}
++
++	/* Tell the ACPI core to skip this resource */
++	return 1;
++}
++
++static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
++				       void *data, void **return_value)
++{
++	struct i2c_adapter *adapter = data;
++	struct list_head resource_list;
++	struct i2c_board_info info;
++	struct acpi_device *adev;
++	int ret;
++
++	if (acpi_bus_get_device(handle, &adev))
++		return AE_OK;
++	if (acpi_bus_get_status(adev) || !adev->status.present)
++		return AE_OK;
++
++	memset(&info, 0, sizeof(info));
++	info.acpi_node.companion = adev;
++	info.irq = -1;
++
++	INIT_LIST_HEAD(&resource_list);
++	ret = acpi_dev_get_resources(adev, &resource_list,
++				     acpi_i2c_add_resource, &info);
++	acpi_dev_free_resource_list(&resource_list);
++
++	if (ret < 0 || !info.addr)
++		return AE_OK;
++
++	adev->power.flags.ignore_parent = true;
++	strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
++	if (!i2c_new_device(adapter, &info)) {
++		adev->power.flags.ignore_parent = false;
++		dev_err(&adapter->dev,
++			"failed to add I2C device %s from ACPI\n",
++			dev_name(&adev->dev));
++	}
++
++	return AE_OK;
++}
++
++/**
++ * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
++ * @adap: pointer to adapter
++ *
++ * Enumerate all I2C slave devices behind this adapter by walking the ACPI
++ * namespace. When a device is found it will be added to the Linux device
++ * model and bound to the corresponding ACPI handle.
++ */
++void acpi_i2c_register_devices(struct i2c_adapter *adap)
++{
++	acpi_handle handle;
++	acpi_status status;
++
++	if (!adap->dev.parent)
++		return;
++
++	handle = ACPI_HANDLE(adap->dev.parent);
++	if (!handle)
++		return;
++
++	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
++				     acpi_i2c_add_device, NULL,
++				     adap, NULL);
++	if (ACPI_FAILURE(status))
++		dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
++}
++
+ static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
+ 		u8 cmd, u8 *data, u8 data_len)
+ {
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index e25cb84..4ccff11 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -1092,101 +1092,6 @@ EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
+ static void of_i2c_register_devices(struct i2c_adapter *adap) { }
+ #endif /* CONFIG_OF */
+ 
+-/* ACPI support code */
+-
+-#if IS_ENABLED(CONFIG_ACPI)
+-static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
+-{
+-	struct i2c_board_info *info = data;
+-
+-	if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
+-		struct acpi_resource_i2c_serialbus *sb;
+-
+-		sb = &ares->data.i2c_serial_bus;
+-		if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+-			info->addr = sb->slave_address;
+-			if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+-				info->flags |= I2C_CLIENT_TEN;
+-		}
+-	} else if (info->irq < 0) {
+-		struct resource r;
+-
+-		if (acpi_dev_resource_interrupt(ares, 0, &r))
+-			info->irq = r.start;
+-	}
+-
+-	/* Tell the ACPI core to skip this resource */
+-	return 1;
+-}
+-
+-static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
+-				       void *data, void **return_value)
+-{
+-	struct i2c_adapter *adapter = data;
+-	struct list_head resource_list;
+-	struct i2c_board_info info;
+-	struct acpi_device *adev;
+-	int ret;
+-
+-	if (acpi_bus_get_device(handle, &adev))
+-		return AE_OK;
+-	if (acpi_bus_get_status(adev) || !adev->status.present)
+-		return AE_OK;
+-
+-	memset(&info, 0, sizeof(info));
+-	info.acpi_node.companion = adev;
+-	info.irq = -1;
+-
+-	INIT_LIST_HEAD(&resource_list);
+-	ret = acpi_dev_get_resources(adev, &resource_list,
+-				     acpi_i2c_add_resource, &info);
+-	acpi_dev_free_resource_list(&resource_list);
+-
+-	if (ret < 0 || !info.addr)
+-		return AE_OK;
+-
+-	adev->power.flags.ignore_parent = true;
+-	strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
+-	if (!i2c_new_device(adapter, &info)) {
+-		adev->power.flags.ignore_parent = false;
+-		dev_err(&adapter->dev,
+-			"failed to add I2C device %s from ACPI\n",
+-			dev_name(&adev->dev));
+-	}
+-
+-	return AE_OK;
+-}
+-
+-/**
+- * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
+- * @adap: pointer to adapter
+- *
+- * Enumerate all I2C slave devices behind this adapter by walking the ACPI
+- * namespace. When a device is found it will be added to the Linux device
+- * model and bound to the corresponding ACPI handle.
+- */
+-static void acpi_i2c_register_devices(struct i2c_adapter *adap)
+-{
+-	acpi_handle handle;
+-	acpi_status status;
+-
+-	if (!adap->dev.parent)
+-		return;
+-
+-	handle = ACPI_HANDLE(adap->dev.parent);
+-	if (!handle)
+-		return;
+-
+-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+-				     acpi_i2c_add_device, NULL,
+-				     adap, NULL);
+-	if (ACPI_FAILURE(status))
+-		dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
+-}
+-#else
+-static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
+-#endif /* CONFIG_ACPI */
+-
+ static int i2c_do_add_adapter(struct i2c_driver *driver,
+ 			      struct i2c_adapter *adap)
+ {
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index f7a939a..ea50766 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -577,10 +577,12 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
+ }
+ #endif /* CONFIG_OF */
+ 
+-#ifdef CONFIG_ACPI
++#ifdef CONFIG_I2C_ACPI
+ int acpi_i2c_install_space_handler(struct i2c_adapter *adapter);
+ void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter);
++void acpi_i2c_register_devices(struct i2c_adapter *adap);
+ #else
++static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { }
+ static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
+ { }
+ static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
diff --git a/baytrail_gpio_quirk_v3.patch b/baytrail_gpio_quirk_v3.patch
new file mode 100644
index 0000000..b294ff5
--- /dev/null
+++ b/baytrail_gpio_quirk_v3.patch
@@ -0,0 +1,87 @@
+diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
+index 69e29f4..d79c6d7 100644
+--- a/drivers/acpi/acpi_lpss.c
++++ b/drivers/acpi/acpi_lpss.c
+@@ -180,6 +180,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
+ 	{ "80860F14", (unsigned long)&byt_sdio_dev_desc },
+ 	{ "80860F41", (unsigned long)&byt_i2c_dev_desc },
+ 	{ "INT33B2", },
++	{ "INT33FC", },
+ 
+ 	{ "INT3430", (unsigned long)&lpt_dev_desc },
+ 	{ "INT3431", (unsigned long)&lpt_dev_desc },
+diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
+index ebb3f39..ebed2a0 100644
+--- a/drivers/mmc/host/sdhci-acpi.c
++++ b/drivers/mmc/host/sdhci-acpi.c
+@@ -123,7 +123,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
+ 
+ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
+ 	.quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+-	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
++	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | SDHCI_QUIRK2_BROKEN_POWER_ENABLE,
+ 	.caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
+ 	.flags   = SDHCI_ACPI_RUNTIME_PM,
+ 	.pm_caps = MMC_PM_KEEP_POWER,
+diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c
+index 6e8301f..6c8eda2 100644
+--- a/drivers/pinctrl/pinctrl-baytrail.c
++++ b/drivers/pinctrl/pinctrl-baytrail.c
+@@ -151,9 +151,9 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
+ 
+ static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+ {
+-	/* SCORE pin 92-93 */
++	/* SCORE pin 92-93; 41 for SDIO pwr_en bug  */
+ 	if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
+-		offset >= 92 && offset <= 93)
++	   ((offset >= 92 && offset <= 93) || (offset == 41)))
+ 		return true;
+ 
+ 	/* SUS pin 11-21 */
+@@ -176,6 +176,10 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
+ 	 * But, some pins may have func pin mux 001 represents
+ 	 * GPIO function. Only allow user to export pin with
+ 	 * func pin mux preset as GPIO function by BIOS/FW.
++	 *
++	 * We do make an exception, however, for pin 41 which
++	 * is needed in order to power up the SDIO bus (as per
++	 * the intel erratum)
+ 	 */
+ 	value = readl(reg) & BYT_PIN_MUX;
+ 	special = is_special_pin(vg, offset);
+@@ -185,6 +189,13 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
+ 		return -EINVAL;
+ 	}
+ 
++	/* This is an attempt to stop the SDHCI drivers from requesting IRQ lines
++	 * through the pinctrl driver. This may be a quirk in the hardware or it
++	 * may be a bug here in the IRQ handling
++	 */
++	if (offset == 38)
++		return -EINVAL;
++
+ 	pm_runtime_get(&vg->pdev->dev);
+ 
+ 	return 0;
+@@ -572,6 +583,7 @@ static const struct dev_pm_ops byt_gpio_pm_ops = {
+ 
+ static const struct acpi_device_id byt_gpio_acpi_match[] = {
+ 	{ "INT33B2", 0 },
++	{ "INT33FC", 0 },
+ 	{ }
+ };
+ MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match);
+diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
+index 7be12b8..3a7fd87 100644
+--- a/include/linux/mmc/sdhci.h
++++ b/include/linux/mmc/sdhci.h
+@@ -102,6 +102,8 @@ struct sdhci_host {
+ #define SDHCI_QUIRK2_BROKEN_HS200			(1<<6)
+ /* Controller does not support DDR50 */
+ #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
++/* Controller cannot initialize power (must use GPIO instead) */
++#define SDHCI_QUIRK2_BROKEN_POWER_ENABLE		(1<<8)
+ 
+ 	int irq;		/* Device IRQ */
+ 	void __iomem *ioaddr;	/* Mapped address */
diff --git a/x86-new-Intel-Atom-SoC-power-management-controller-driver.patch b/x86-new-Intel-Atom-SoC-power-management-controller-driver.patch
new file mode 100644
index 0000000..b138fe2
--- /dev/null
+++ b/x86-new-Intel-Atom-SoC-power-management-controller-driver.patch
@@ -0,0 +1,484 @@
+From patchwork Fri Mar  7 03:04:42 2014
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: x86: new Intel Atom SoC power management controller driver
+From: "Li, Aubrey" <aubrey.li at linux.intel.com>
+X-Patchwork-Id: 3787341
+Message-Id: <5319374A.60308 at linux.intel.com>
+To: Joe Perches <joe at perches.com>
+Cc: "H. Peter Anvin" <hpa at linux.intel.com>,
+	Matthew Garrett <mjg59 at srcf.ucam.org>, mingo at redhat.com,
+	tglx at linutronix.de, linux-kernel at vger.kernel.org,
+	"alan at linux.intel.com" <alan at linux.intel.com>
+Date: Fri, 07 Mar 2014 11:04:42 +0800
+
+On 2014/3/7 10:21, Joe Perches wrote:
+> On Fri, 2014-03-07 at 10:08 +0800, Li, Aubrey wrote:
+> 
+>> The Power Management Controller (PMC) controls many of the power
+>> management features present in the SoC. This driver provides
+>> interface to configure the Power Management Controller (PMC).
+> 
+> More trivial notes.
+> 
+> Nothing really that should stop this from being applied.
+>
+All make sense to me. Welcome your more comments, Joe!
+
+Thanks,
+-Aubrey
+
+[PATCH] X86 platform: New Intel Atom SOC power management controller driver
+
+The Power Management Controller (PMC) controls many of the power
+management features present in the SoC. This driver provides
+interface to configure the Power Management Controller (PMC).
+
+This driver exposes PMC device state and sleep state residency
+via debugfs:
+	/sys/kernel/debugfs/pmc_atom/dev_state
+	/sys/kernel/debugfs/pmc_atom/sleep_state
+
+This driver also provides a native power off function via PMC PCI
+IO port.
+
+Signed-off-by: Aubrey Li <aubrey.li at intel.com>
+Reviewed-by: Joe Perches <joe at perches.com>
+
+---
+arch/x86/Kconfig                |    4 +
+ arch/x86/include/asm/pmc_atom.h |   91 ++++++++++++
+ arch/x86/kernel/Makefile        |    1 +
+ arch/x86/kernel/pmc_atom.c      |  297 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 393 insertions(+)
+ create mode 100644 arch/x86/include/asm/pmc_atom.h
+ create mode 100644 arch/x86/kernel/pmc_atom.c
+
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index 0af5250..18f7d38 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -2413,6 +2413,10 @@
+ 	tristate
+ 	default m
+ 	depends on PCI
++	
++config PMC_ATOM
++	def_bool y
++        depends on PCI
+ 
+ source "net/Kconfig"
+ 
+diff --git a/arch/x86/include/asm/pmc_atom.h b/arch/x86/include/asm/pmc_atom.h
+new file mode 100644
+index 0000000..43b68fc
+--- /dev/null
++++ b/arch/x86/include/asm/pmc_atom.h
+@@ -0,0 +1,91 @@
++/*
++ * Intel Atom SOC Power Management Controller Header File
++ * Copyright (c) 2014, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++
++#ifndef PMC_ATOM_H
++#define PMC_ATOM_H
++
++/* ValleyView Power Control Unit PCI Device ID */
++#define	PCI_DEVICE_ID_VLV_PMC	0x0F1C
++
++/* PMC Memory mapped IO registers */
++#define	PMC_BASE_ADDR_OFFSET	0x44
++#define	PMC_BASE_ADDR_MASK	0xFFFFFE00
++#define	PMC_MMIO_REG_LEN	0x100
++#define	PMC_REG_BIT_WIDTH	32
++
++/* BIOS uses FUNC_DIS to disable specific function */
++#define	PMC_FUNC_DIS		0x34
++#define	PMC_FUNC_DIS_2		0x38
++/* The timers acumulate time spent in sleep state */
++#define	PMC_S0IR_TMR		0x80
++#define	PMC_S0I1_TMR		0x84
++#define	PMC_S0I2_TMR		0x88
++#define	PMC_S0I3_TMR		0x8C
++#define	PMC_S0_TMR		0x90
++/* Sleep state counter is in units of of 32us */
++#define	PMC_TMR_SHIFT		5
++
++/* These registers reflect D3 status of functions */
++#define	PMC_D3_STS_0		0xA0
++
++#define	BIT_LPSS1_F0_DMA	BIT(0)
++#define	BIT_LPSS1_F1_PWM1	BIT(1)
++#define	BIT_LPSS1_F2_PWM2	BIT(2)
++#define	BIT_LPSS1_F3_HSUART1	BIT(3)
++#define	BIT_LPSS1_F4_HSUART2	BIT(4)
++#define	BIT_LPSS1_F5_SPI	BIT(5)
++#define	BIT_LPSS1_F6_XXX	BIT(6)
++#define	BIT_LPSS1_F7_XXX	BIT(7)
++#define	BIT_SCC_EMMC		BIT(8)
++#define	BIT_SCC_SDIO		BIT(9)
++#define	BIT_SCC_SDCARD		BIT(10)
++#define	BIT_SCC_MIPI		BIT(11)
++#define	BIT_HDA			BIT(12)
++#define	BIT_LPE			BIT(13)
++#define	BIT_OTG			BIT(14)
++#define	BIT_USH			BIT(15)
++#define	BIT_GBE			BIT(16)
++#define	BIT_SATA		BIT(17)
++#define	BIT_USB_EHCI		BIT(18)
++#define	BIT_SEC			BIT(19)
++#define	BIT_PCIE_PORT0		BIT(20)
++#define	BIT_PCIE_PORT1		BIT(21)
++#define	BIT_PCIE_PORT2		BIT(22)
++#define	BIT_PCIE_PORT3		BIT(23)
++#define	BIT_LPSS2_F0_DMA	BIT(24)
++#define	BIT_LPSS2_F1_I2C1	BIT(25)
++#define	BIT_LPSS2_F2_I2C2	BIT(26)
++#define	BIT_LPSS2_F3_I2C3	BIT(27)
++#define	BIT_LPSS2_F4_I2C4	BIT(28)
++#define	BIT_LPSS2_F5_I2C5	BIT(29)
++#define	BIT_LPSS2_F6_I2C6	BIT(30)
++#define	BIT_LPSS2_F7_I2C7	BIT(31)
++
++#define	PMC_D3_STS_1		0xA4
++#define	BIT_SMB			BIT(0)
++#define	BIT_USH_SS_PHY		BIT(1)
++#define	BIT_OTG_SS_PHY		BIT(2)
++#define	BIT_DFX			BIT(3)
++
++/* PMC I/O Registers */
++#define	ACPI_BASE_ADDR_OFFSET	0x40
++#define	ACPI_BASE_ADDR_MASK	0xFFFFFE00
++#define	ACPI_MMIO_REG_LEN	0x100
++
++#define	PM1_CNT			0x4
++#define	SLEEP_TYPE_MASK		0xFFFFECFF
++#define	SLEEP_TYPE_S5		0x1C00
++#define	SLEEP_ENABLE		0x2000
++#endif /* PMC_ATOM_H */
+diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
+index cb648c8..b71a61a 100644
+--- a/arch/x86/kernel/Makefile
++++ b/arch/x86/kernel/Makefile
+@@ -104,6 +104,7 @@ obj-$(CONFIG_EFI)			+= sysfb_efi.o
+ obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
+ obj-$(CONFIG_TRACING)			+= tracepoint.o
+ obj-$(CONFIG_IOSF_MBI)			+= iosf_mbi.o
++obj-$(CONFIG_PMC_ATOM)			+= pmc_atom.o
+ 
+ ###
+ # 64 bit specific files
+diff --git a/arch/x86/kernel/pmc_atom.c b/arch/x86/kernel/pmc_atom.c
+new file mode 100644
+index 0000000..5991030
+--- /dev/null
++++ b/arch/x86/kernel/pmc_atom.c
+@@ -0,0 +1,297 @@
++/*
++ * Intel Atom SOC Power Management Controller Driver
++ * Copyright (c) 2014, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/device.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <linux/io.h>
++
++#include <asm/pmc_atom.h>
++
++#define	DRIVER_NAME	KBUILD_MODNAME
++
++struct pmc_dev {
++	struct pci_dev *pdev;
++	u32 base_addr;
++	void __iomem *regmap;
++#ifdef CONFIG_DEBUG_FS
++	struct dentry *dbgfs_dir;
++#endif /* CONFIG_DEBUG_FS */
++};
++
++static u32 acpi_base_addr;
++
++struct pmc_dev_map {
++	const char *name;
++	u32 bit_mask;
++};
++
++static const struct pmc_dev_map dev_map[] = {
++	{"0  - LPSS1_F0_DMA",		BIT_LPSS1_F0_DMA},
++	{"1  - LPSS1_F1_PWM1",		BIT_LPSS1_F1_PWM1},
++	{"2  - LPSS1_F2_PWM2",		BIT_LPSS1_F2_PWM2},
++	{"3  - LPSS1_F3_HSUART1",	BIT_LPSS1_F3_HSUART1},
++	{"4  - LPSS1_F4_HSUART2",	BIT_LPSS1_F4_HSUART2},
++	{"5  - LPSS1_F5_SPI",		BIT_LPSS1_F5_SPI},
++	{"6  - LPSS1_F6_Reserved",	BIT_LPSS1_F6_XXX},
++	{"7  - LPSS1_F7_Reserved",	BIT_LPSS1_F7_XXX},
++	{"8  - SCC_EMMC",		BIT_SCC_EMMC},
++	{"9  - SCC_SDIO",		BIT_SCC_SDIO},
++	{"10 - SCC_SDCARD",		BIT_SCC_SDCARD},
++	{"11 - SCC_MIPI",		BIT_SCC_MIPI},
++	{"12 - HDA",			BIT_HDA},
++	{"13 - LPE",			BIT_LPE},
++	{"14 - OTG",			BIT_OTG},
++	{"15 - USH",			BIT_USH},
++	{"16 - GBE",			BIT_GBE},
++	{"17 - SATA",			BIT_SATA},
++	{"18 - USB_EHCI",		BIT_USB_EHCI},
++	{"19 - SEC",			BIT_SEC},
++	{"20 - PCIE_PORT0",		BIT_PCIE_PORT0},
++	{"21 - PCIE_PORT1",		BIT_PCIE_PORT1},
++	{"22 - PCIE_PORT2",		BIT_PCIE_PORT2},
++	{"23 - PCIE_PORT3",		BIT_PCIE_PORT3},
++	{"24 - LPSS2_F0_DMA",		BIT_LPSS2_F0_DMA},
++	{"25 - LPSS2_F1_I2C1",		BIT_LPSS2_F1_I2C1},
++	{"26 - LPSS2_F2_I2C2",		BIT_LPSS2_F2_I2C2},
++	{"27 - LPSS2_F3_I2C3",		BIT_LPSS2_F3_I2C3},
++	{"28 - LPSS2_F3_I2C4",		BIT_LPSS2_F4_I2C4},
++	{"29 - LPSS2_F5_I2C5",		BIT_LPSS2_F5_I2C5},
++	{"30 - LPSS2_F6_I2C6",		BIT_LPSS2_F6_I2C6},
++	{"31 - LPSS2_F7_I2C7",		BIT_LPSS2_F7_I2C7},
++	{"32 - SMB",			BIT_SMB},
++	{"33 - USH_SS_PHY",		BIT_OTG_SS_PHY},
++	{"34 - OTG_SS_PHY",		BIT_USH_SS_PHY},
++	{"35 - DFX",			BIT_DFX},
++};
++
++static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset)
++{
++	return readl(pmc->regmap + reg_offset);
++}
++
++static void pmc_power_off(void)
++{
++	u16	pm1_cnt_port;
++	u32	pm1_cnt_value;
++
++	pr_info("Preparing to enter system sleep state S5\n");
++
++	pm1_cnt_port = acpi_base_addr + PM1_CNT;
++
++	pm1_cnt_value = inl(pm1_cnt_port);
++	pm1_cnt_value &= SLEEP_TYPE_MASK;
++	pm1_cnt_value |= SLEEP_TYPE_S5;
++	pm1_cnt_value |= SLEEP_ENABLE;
++
++	outl(pm1_cnt_value, pm1_cnt_port);
++}
++
++#ifdef CONFIG_DEBUG_FS
++static int pmc_dev_state_show(struct seq_file *s, void *unused)
++{
++	struct pmc_dev *pmc = (struct pmc_dev *)s->private;
++	u32 func_dis, func_dis_2, func_dis_index;
++	u32 d3_sts_0, d3_sts_1, d3_sts_index;
++	int dev_num, dev_index, reg_index;
++
++	func_dis = pmc_reg_read(pmc, PMC_FUNC_DIS);
++	func_dis_2 = pmc_reg_read(pmc, PMC_FUNC_DIS_2);
++	d3_sts_0 = pmc_reg_read(pmc, PMC_D3_STS_0);
++	d3_sts_1 = pmc_reg_read(pmc, PMC_D3_STS_1);
++
++	dev_num = sizeof(dev_map) / sizeof(struct pmc_dev_map);
++
++	for (dev_index = 0; dev_index < dev_num; dev_index++) {
++		reg_index = dev_index / PMC_REG_BIT_WIDTH;
++		if (reg_index) {
++			func_dis_index = func_dis_2;
++			d3_sts_index = d3_sts_1;
++		} else {
++			func_dis_index = func_dis;
++			d3_sts_index = d3_sts_0;
++		}
++
++		seq_printf(s, "Dev: %-32s\tState: %s [%s]\n",
++			dev_map[dev_index].name,
++			dev_map[dev_index].bit_mask & func_dis_index ?
++			"Disabled" : "Enabled ",
++			dev_map[dev_index].bit_mask & d3_sts_index ?
++			"D3" : "D0");
++	}
++	return 0;
++}
++
++static int pmc_dev_state_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, pmc_dev_state_show, inode->i_private);
++}
++
++static const struct file_operations pmc_dev_state_ops = {
++	.open		= pmc_dev_state_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
++{
++	struct pmc_dev *pmc = (struct pmc_dev *)s->private;
++	u64 s0ir_tmr, s0i1_tmr, s0i2_tmr, s0i3_tmr, s0_tmr;
++
++	s0ir_tmr = pmc_reg_read(pmc, PMC_S0IR_TMR) << PMC_TMR_SHIFT;
++	s0i1_tmr = pmc_reg_read(pmc, PMC_S0I1_TMR) << PMC_TMR_SHIFT;
++	s0i2_tmr = pmc_reg_read(pmc, PMC_S0I2_TMR) << PMC_TMR_SHIFT;
++	s0i3_tmr = pmc_reg_read(pmc, PMC_S0I3_TMR) << PMC_TMR_SHIFT;
++	s0_tmr = pmc_reg_read(pmc, PMC_S0_TMR) << PMC_TMR_SHIFT;
++
++	seq_printf(s, "S0IR Residency:\t%lldus\n", s0ir_tmr);
++	seq_printf(s, "S0I1 Residency:\t%lldus\n", s0i1_tmr);
++	seq_printf(s, "S0I2 Residency:\t%lldus\n", s0i2_tmr);
++	seq_printf(s, "S0I3 Residency:\t%lldus\n", s0i3_tmr);
++	seq_printf(s, "S0   Residency:\t%lldus\n", s0_tmr);
++	return 0;
++}
++
++static int pmc_sleep_tmr_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, pmc_sleep_tmr_show, inode->i_private);
++}
++
++static const struct file_operations pmc_sleep_tmr_ops = {
++	.open		= pmc_sleep_tmr_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static void pmc_dbgfs_unregister(struct pmc_dev *pmc)
++{
++	if (!pmc->dbgfs_dir)
++		return;
++
++	debugfs_remove_recursive(pmc->dbgfs_dir);
++	pmc->dbgfs_dir = NULL;
++}
++
++static int pmc_dbgfs_register(struct pmc_dev *pmc)
++{
++	struct dentry *dir, *f;
++
++	dir = debugfs_create_dir("pmc_atom", NULL);
++	if (!dir)
++		return -ENOMEM;
++
++	f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO,
++				dir, pmc, &pmc_dev_state_ops);
++	if (!f) {
++		dev_err(&pmc->pdev->dev, "dev_states register failed\n");
++		goto err;
++	}
++	f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO,
++				dir, pmc, &pmc_sleep_tmr_ops);
++	if (!f) {
++		dev_err(&pmc->pdev->dev, "sleep_state register failed\n");
++		goto err;
++	}
++	pmc->dbgfs_dir = dir;
++	return 0;
++err:
++	pmc_dbgfs_unregister(pmc);
++	return -ENODEV;
++}
++#endif /* CONFIG_DEBUG_FS */
++
++static int pmc_probe(struct pci_dev *pdev,
++			  const struct pci_device_id *unused)
++{
++	struct pmc_dev *pmc;
++	int ret;
++
++	ret = pci_enable_device(pdev);
++	if (ret < 0) {
++		dev_err(&pdev->dev, "error: could not enable device\n");
++		goto err_enable_device;
++	}
++
++	ret = pci_request_regions(pdev, DRIVER_NAME);
++	if (ret) {
++		dev_err(&pdev->dev, "error: could not request PCI region\n");
++		goto err_request_regions;
++	}
++
++	pmc = devm_kzalloc(&pdev->dev, sizeof(struct pmc_dev), GFP_KERNEL);
++	if (!pmc) {
++		ret = -ENOMEM;
++		goto err_devm_kzalloc;
++	}
++
++	pmc->pdev = pci_dev_get(pdev);
++
++	pci_read_config_dword(pdev, PMC_BASE_ADDR_OFFSET, &pmc->base_addr);
++	pmc->base_addr &= PMC_BASE_ADDR_MASK;
++
++	pmc->regmap = devm_ioremap_nocache(&pdev->dev,
++		pmc->base_addr, PMC_MMIO_REG_LEN);
++	if (!pmc->regmap) {
++		dev_err(&pdev->dev, "error: ioremap failed\n");
++		ret = -ENOMEM;
++		goto err_devm_ioremap;
++	}
++	pci_set_drvdata(pdev, pmc);
++#ifdef CONFIG_DEBUG_FS
++	pmc_dbgfs_register(pmc);
++#endif /* CONFIG_DEBUG_FS */
++
++	/* Install power off function */
++	pci_read_config_dword(pdev, ACPI_BASE_ADDR_OFFSET, &acpi_base_addr);
++	acpi_base_addr &= ACPI_BASE_ADDR_MASK;
++	if (acpi_base_addr != 0 && pm_power_off == NULL)
++		pm_power_off = pmc_power_off;
++	return 0;
++err_devm_ioremap:
++	pci_dev_put(pdev);
++err_devm_kzalloc:
++	pci_release_regions(pdev);
++err_request_regions:
++	pci_disable_device(pdev);
++err_enable_device:
++	dev_err(&pdev->dev, "error: probe failed\n");
++	return ret;
++}
++
++static const struct pci_device_id pmc_pci_ids[] = {
++	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VLV_PMC) },
++	{ 0, },
++};
++
++MODULE_DEVICE_TABLE(pci, pmc_pci_ids);
++
++static struct pci_driver pmc_pci_driver = {
++	.name		= DRIVER_NAME,
++	.probe		= pmc_probe,
++	.id_table	= pmc_pci_ids,
++};
++
++module_pci_driver(pmc_pci_driver);
++
++MODULE_AUTHOR("Aubrey Li <aubrey.li at linux.intel.com>");
++MODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface");
++MODULE_LICENSE("GPL v2");


More information about the scm-commits mailing list