summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/acpi_lpss.c118
-rw-r--r--drivers/acpi/acpi_processor.c7
-rw-r--r--drivers/acpi/acpi_tad.c201
-rw-r--r--drivers/acpi/pmic/intel_pmic_bxtwc.c12
-rw-r--r--drivers/acpi/pmic/intel_pmic_chtdc_ti.c1
-rw-r--r--drivers/acpi/pmic/intel_pmic_chtwc.c10
-rw-r--r--drivers/acpi/pmic/intel_pmic_crc.c16
-rw-r--r--drivers/acpi/pmic/intel_pmic_xpower.c16
-rw-r--r--drivers/acpi/pmic/tps68470_pmic.c2
9 files changed, 321 insertions, 62 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index bf64cfa..10adb8c 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mutex.h>
+#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_data/x86/pmc_atom.h>
@@ -83,6 +84,7 @@ struct lpss_device_desc {
size_t prv_size_override;
struct property_entry *properties;
void (*setup)(struct lpss_private_data *pdata);
+ bool resume_from_noirq;
};
static const struct lpss_device_desc lpss_dma_desc = {
@@ -99,6 +101,9 @@ struct lpss_private_data {
u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
};
+/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */
+static u32 pmc_atom_d3_mask = 0xfe000ffe;
+
/* LPSS run time quirks */
static unsigned int lpss_quirks;
@@ -175,6 +180,21 @@ static void byt_pwm_setup(struct lpss_private_data *pdata)
static void byt_i2c_setup(struct lpss_private_data *pdata)
{
+ const char *uid_str = acpi_device_uid(pdata->adev);
+ acpi_handle handle = pdata->adev->handle;
+ unsigned long long shared_host = 0;
+ acpi_status status;
+ long uid = 0;
+
+ /* Expected to always be true, but better safe then sorry */
+ if (uid_str)
+ uid = simple_strtol(uid_str, NULL, 10);
+
+ /* Detect I2C bus shared with PUNIT and ignore its d3 status */
+ status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
+ if (ACPI_SUCCESS(status) && shared_host && uid)
+ pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1));
+
lpss_deassert_reset(pdata);
if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
@@ -274,12 +294,14 @@ static const struct lpss_device_desc byt_i2c_dev_desc = {
.flags = LPSS_CLK | LPSS_SAVE_CTX,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
+ .resume_from_noirq = true,
};
static const struct lpss_device_desc bsw_i2c_dev_desc = {
.flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
+ .resume_from_noirq = true,
};
static const struct lpss_device_desc bsw_spi_dev_desc = {
@@ -327,9 +349,11 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT33FC", },
/* Braswell LPSS devices */
+ { "80862286", LPSS_ADDR(lpss_dma_desc) },
{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) },
{ "8086228A", LPSS_ADDR(bsw_uart_dev_desc) },
{ "8086228E", LPSS_ADDR(bsw_spi_dev_desc) },
+ { "808622C0", LPSS_ADDR(lpss_dma_desc) },
{ "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) },
/* Broadwell LPSS devices */
@@ -451,26 +475,35 @@ struct lpss_device_links {
*/
static const struct lpss_device_links lpss_device_links[] = {
{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
+ {"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
+ {"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
};
-static bool hid_uid_match(const char *hid1, const char *uid1,
+static bool hid_uid_match(struct acpi_device *adev,
const char *hid2, const char *uid2)
{
- return !strcmp(hid1, hid2) && uid1 && uid2 && !strcmp(uid1, uid2);
+ const char *hid1 = acpi_device_hid(adev);
+ const char *uid1 = acpi_device_uid(adev);
+
+ if (strcmp(hid1, hid2))
+ return false;
+
+ if (!uid2)
+ return true;
+
+ return uid1 && !strcmp(uid1, uid2);
}
static bool acpi_lpss_is_supplier(struct acpi_device *adev,
const struct lpss_device_links *link)
{
- return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
- link->supplier_hid, link->supplier_uid);
+ return hid_uid_match(adev, link->supplier_hid, link->supplier_uid);
}
static bool acpi_lpss_is_consumer(struct acpi_device *adev,
const struct lpss_device_links *link)
{
- return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
- link->consumer_hid, link->consumer_uid);
+ return hid_uid_match(adev, link->consumer_hid, link->consumer_uid);
}
struct hid_uid {
@@ -486,18 +519,23 @@ static int match_hid_uid(struct device *dev, void *data)
if (!adev)
return 0;
- return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
- id->hid, id->uid);
+ return hid_uid_match(adev, id->hid, id->uid);
}
static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
{
+ struct device *dev;
+
struct hid_uid data = {
.hid = hid,
.uid = uid,
};
- return bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
+ dev = bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
+ if (dev)
+ return dev;
+
+ return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid);
}
static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
@@ -892,7 +930,7 @@ static void lpss_iosf_enter_d3_state(void)
* Here we read the values related to LPSS power island, i.e. LPSS
* devices, excluding both LPSS DMA controllers, along with SCC domain.
*/
- u32 func_dis, d3_sts_0, pmc_status, pmc_mask = 0xfe000ffe;
+ u32 func_dis, d3_sts_0, pmc_status;
int ret;
ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis);
@@ -910,7 +948,7 @@ static void lpss_iosf_enter_d3_state(void)
* Shutdown both LPSS DMA controllers if and only if all other devices
* are already in D3hot.
*/
- pmc_status = (~(d3_sts_0 | func_dis)) & pmc_mask;
+ pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask;
if (pmc_status)
goto exit;
@@ -1004,7 +1042,7 @@ static int acpi_lpss_resume(struct device *dev)
}
#ifdef CONFIG_PM_SLEEP
-static int acpi_lpss_suspend_late(struct device *dev)
+static int acpi_lpss_do_suspend_late(struct device *dev)
{
int ret;
@@ -1015,12 +1053,62 @@ static int acpi_lpss_suspend_late(struct device *dev)
return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
}
-static int acpi_lpss_resume_early(struct device *dev)
+static int acpi_lpss_suspend_late(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (pdata->dev_desc->resume_from_noirq)
+ return 0;
+
+ return acpi_lpss_do_suspend_late(dev);
+}
+
+static int acpi_lpss_suspend_noirq(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ if (pdata->dev_desc->resume_from_noirq) {
+ ret = acpi_lpss_do_suspend_late(dev);
+ if (ret)
+ return ret;
+ }
+
+ return acpi_subsys_suspend_noirq(dev);
+}
+
+static int acpi_lpss_do_resume_early(struct device *dev)
{
int ret = acpi_lpss_resume(dev);
return ret ? ret : pm_generic_resume_early(dev);
}
+
+static int acpi_lpss_resume_early(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (pdata->dev_desc->resume_from_noirq)
+ return 0;
+
+ return acpi_lpss_do_resume_early(dev);
+}
+
+static int acpi_lpss_resume_noirq(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ ret = acpi_subsys_resume_noirq(dev);
+ if (ret)
+ return ret;
+
+ if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq)
+ ret = acpi_lpss_do_resume_early(dev);
+
+ return ret;
+}
+
#endif /* CONFIG_PM_SLEEP */
static int acpi_lpss_runtime_suspend(struct device *dev)
@@ -1050,8 +1138,8 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
.complete = acpi_subsys_complete,
.suspend = acpi_subsys_suspend,
.suspend_late = acpi_lpss_suspend_late,
- .suspend_noirq = acpi_subsys_suspend_noirq,
- .resume_noirq = acpi_subsys_resume_noirq,
+ .suspend_noirq = acpi_lpss_suspend_noirq,
+ .resume_noirq = acpi_lpss_resume_noirq,
.resume_early = acpi_lpss_resume_early,
.freeze = acpi_subsys_freeze,
.freeze_late = acpi_subsys_freeze_late,
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 449d86d..fc44741 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -643,7 +643,7 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
status = acpi_get_type(handle, &acpi_type);
if (ACPI_FAILURE(status))
- return false;
+ return status;
switch (acpi_type) {
case ACPI_TYPE_PROCESSOR:
@@ -663,11 +663,12 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
}
processor_validated_ids_update(uid);
- return true;
+ return AE_OK;
err:
+ /* Exit on error, but don't abort the namespace walk */
acpi_handle_info(handle, "Invalid processor object\n");
- return false;
+ return AE_OK;
}
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index e99c4ed..33a4bcd 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -52,6 +52,201 @@ struct acpi_tad_driver_data {
u32 capabilities;
};
+struct acpi_tad_rt {
+ u16 year; /* 1900 - 9999 */
+ u8 month; /* 1 - 12 */
+ u8 day; /* 1 - 31 */
+ u8 hour; /* 0 - 23 */
+ u8 minute; /* 0 - 59 */
+ u8 second; /* 0 - 59 */
+ u8 valid; /* 0 (failed) or 1 (success) for reads, 0 for writes */
+ u16 msec; /* 1 - 1000 */
+ s16 tz; /* -1440 to 1440 or 2047 (unspecified) */
+ u8 daylight;
+ u8 padding[3]; /* must be 0 */
+} __packed;
+
+static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+ union acpi_object args[] = {
+ { .type = ACPI_TYPE_BUFFER, },
+ };
+ struct acpi_object_list arg_list = {
+ .pointer = args,
+ .count = ARRAY_SIZE(args),
+ };
+ unsigned long long retval;
+ acpi_status status;
+
+ if (rt->year < 1900 || rt->year > 9999 ||
+ rt->month < 1 || rt->month > 12 ||
+ rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
+ rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) ||
+ rt->daylight > 3)
+ return -ERANGE;
+
+ args[0].buffer.pointer = (u8 *)rt;
+ args[0].buffer.length = sizeof(*rt);
+
+ pm_runtime_get_sync(dev);
+
+ status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval);
+
+ pm_runtime_put_sync(dev);
+
+ if (ACPI_FAILURE(status) || retval)
+ return -EIO;
+
+ return 0;
+}
+
+static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER };
+ union acpi_object *out_obj;
+ struct acpi_tad_rt *data;
+ acpi_status status;
+ int ret = -EIO;
+
+ pm_runtime_get_sync(dev);
+
+ status = acpi_evaluate_object(handle, "_GRT", NULL, &output);
+
+ pm_runtime_put_sync(dev);
+
+ if (ACPI_FAILURE(status))
+ goto out_free;
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER)
+ goto out_free;
+
+ if (out_obj->buffer.length != sizeof(*rt))
+ goto out_free;
+
+ data = (struct acpi_tad_rt *)(out_obj->buffer.pointer);
+ if (!data->valid)
+ goto out_free;
+
+ memcpy(rt, data, sizeof(*rt));
+ ret = 0;
+
+out_free:
+ ACPI_FREE(output.pointer);
+ return ret;
+}
+
+static char *acpi_tad_rt_next_field(char *s, int *val)
+{
+ char *p;
+
+ p = strchr(s, ':');
+ if (!p)
+ return NULL;
+
+ *p = '\0';
+ if (kstrtoint(s, 10, val))
+ return NULL;
+
+ return p + 1;
+}
+
+static ssize_t time_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acpi_tad_rt rt;
+ char *str, *s;
+ int val, ret = -ENODATA;
+
+ str = kmemdup_nul(buf, count, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+
+ s = acpi_tad_rt_next_field(str, &val);
+ if (!s)
+ goto out_free;
+
+ rt.year = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.month = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.day = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.hour = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.minute = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.second = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.tz = val;
+
+ if (kstrtoint(s, 10, &val))
+ goto out_free;
+
+ rt.daylight = val;
+
+ rt.valid = 0;
+ rt.msec = 0;
+ memset(rt.padding, 0, 3);
+
+ ret = acpi_tad_set_real_time(dev, &rt);
+
+out_free:
+ kfree(str);
+ return ret ? ret : count;
+}
+
+static ssize_t time_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_tad_rt rt;
+ int ret;
+
+ ret = acpi_tad_get_real_time(dev, &rt);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n",
+ rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second,
+ rt.tz, rt.daylight);
+}
+
+static DEVICE_ATTR(time, S_IRUSR | S_IWUSR, time_show, time_store);
+
+static struct attribute *acpi_tad_time_attrs[] = {
+ &dev_attr_time.attr,
+ NULL,
+};
+static const struct attribute_group acpi_tad_time_attr_group = {
+ .attrs = acpi_tad_time_attrs,
+};
+
static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
u32 value)
{
@@ -448,6 +643,12 @@ static int acpi_tad_probe(struct platform_device *pdev)
goto fail;
}
+ if (caps & ACPI_TAD_RT) {
+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group);
+ if (ret)
+ goto fail;
+ }
+
return 0;
fail:
diff --git a/drivers/acpi/pmic/intel_pmic_bxtwc.c b/drivers/acpi/pmic/intel_pmic_bxtwc.c
index 886ac8b..bd7621e 100644
--- a/drivers/acpi/pmic/intel_pmic_bxtwc.c
+++ b/drivers/acpi/pmic/intel_pmic_bxtwc.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_pmic_bxtwc.c - Intel BXT WhiskeyCove PMIC operation region driver
+ * Intel BXT WhiskeyCove PMIC operation region driver
*
* Copyright (C) 2015 Intel Corporation. All rights reserved.
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
index f6d73a2..7ccd7d9 100644
--- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
+++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Dollar Cove TI PMIC operation region driver
* Copyright (C) 2014 Intel Corporation. All rights reserved.
diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c
index 9912422..078b044 100644
--- a/drivers/acpi/pmic/intel_pmic_chtwc.c
+++ b/drivers/acpi/pmic/intel_pmic_chtwc.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel CHT Whiskey Cove PMIC operation region driver
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
*
* Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
* Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c
index 22c9e37..a0f411a 100644
--- a/drivers/acpi/pmic/intel_pmic_crc.c
+++ b/drivers/acpi/pmic/intel_pmic_crc.c
@@ -1,23 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_pmic_crc.c - Intel CrystalCove PMIC operation region driver
+ * Intel CrystalCove PMIC operation region driver
*
* Copyright (C) 2014 Intel Corporation. All rights reserved.
- *
- * 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.
*/
-#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/init.h>
#include <linux/mfd/intel_soc_pmic.h>
-#include <linux/regmap.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include "intel_pmic.h"
#define PWR_SOURCE_SELECT BIT(1)
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c
index 316e551..aadc86d 100644
--- a/drivers/acpi/pmic/intel_pmic_xpower.c
+++ b/drivers/acpi/pmic/intel_pmic_xpower.c
@@ -1,23 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
+ * XPower AXP288 PMIC operation region driver
*
* Copyright (C) 2014 Intel Corporation. All rights reserved.
- *
- * 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.
*/
-#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/init.h>
#include <linux/mfd/axp20x.h>
-#include <linux/regmap.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include "intel_pmic.h"
#define XPOWER_GPADC_LOW 0x5b
diff --git a/drivers/acpi/pmic/tps68470_pmic.c b/drivers/acpi/pmic/tps68470_pmic.c
index a083de5..ebd03e4 100644
--- a/drivers/acpi/pmic/tps68470_pmic.c
+++ b/drivers/acpi/pmic/tps68470_pmic.c
@@ -10,8 +10,8 @@
*/
#include <linux/acpi.h>
-#include <linux/mfd/tps68470.h>
#include <linux/init.h>
+#include <linux/mfd/tps68470.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
OpenPOWER on IntegriCloud