add untracked patches
This commit is contained in:
parent
0e84f13bb3
commit
0557a6fc2d
148
0001-ACPI-temporary-dep-solution-for-battery-support.patch
Normal file
148
0001-ACPI-temporary-dep-solution-for-battery-support.patch
Normal file
@ -0,0 +1,148 @@
|
||||
From bbadbc67de278123e28dd6f9ee7e88b6ada56ce4 Mon Sep 17 00:00:00 2001
|
||||
From: Lan Tianyu <tianyu.lan@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
|
||||
|
@ -0,0 +1,24 @@
|
||||
From 69968772071bb8632a57f42ec77a3acdddbe74d7 Mon Sep 17 00:00:00 2001
|
||||
From: Adam Williamson <awilliam@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
|
||||
|
461
V3-4-5-I2C-ACPI-Add-i2c-ACPI-operation-region-support.patch
Normal file
461
V3-4-5-I2C-ACPI-Add-i2c-ACPI-operation-region-support.patch
Normal file
@ -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@intel.com>
|
||||
X-Patchwork-Id: 4209471
|
||||
Message-Id: <1400590764-11108-5-git-send-email-tianyu.lan@intel.com>
|
||||
To: wsa@the-dreams.de, rjw@rjwysocki.net,
|
||||
mika.westerberg@linux.intel.com, awilliam@redhat.com, lenb@kernel.org
|
||||
Cc: Lan Tianyu <tianyu.lan@intel.com>, linux-i2c@vger.kernel.org,
|
||||
linux-kernel@vger.kernel.org, linux-acpi@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@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@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 */
|
@ -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@intel.com>
|
||||
X-Patchwork-Id: 4209461
|
||||
Message-Id: <1400590764-11108-6-git-send-email-tianyu.lan@intel.com>
|
||||
To: wsa@the-dreams.de, rjw@rjwysocki.net,
|
||||
mika.westerberg@linux.intel.com, awilliam@redhat.com, lenb@kernel.org
|
||||
Cc: Lan Tianyu <tianyu.lan@intel.com>, linux-i2c@vger.kernel.org,
|
||||
linux-kernel@vger.kernel.org, linux-acpi@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@linux.intel.com>
|
||||
Signed-off-by: Lan Tianyu <tianyu.lan@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)
|
87
baytrail_gpio_quirk_v3.patch
Normal file
87
baytrail_gpio_quirk_v3.patch
Normal file
@ -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 */
|
484
x86-new-Intel-Atom-SoC-power-management-controller-driver.patch
Normal file
484
x86-new-Intel-Atom-SoC-power-management-controller-driver.patch
Normal file
@ -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@linux.intel.com>
|
||||
X-Patchwork-Id: 3787341
|
||||
Message-Id: <5319374A.60308@linux.intel.com>
|
||||
To: Joe Perches <joe@perches.com>
|
||||
Cc: "H. Peter Anvin" <hpa@linux.intel.com>,
|
||||
Matthew Garrett <mjg59@srcf.ucam.org>, mingo@redhat.com,
|
||||
tglx@linutronix.de, linux-kernel@vger.kernel.org,
|
||||
"alan@linux.intel.com" <alan@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@intel.com>
|
||||
Reviewed-by: Joe Perches <joe@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@linux.intel.com>");
|
||||
+MODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface");
|
||||
+MODULE_LICENSE("GPL v2");
|
Loading…
Reference in New Issue
Block a user