Merge branches 'pm-qos', 'pm-domains' and 'pm-drivers'

* pm-qos:
  PM / QoS: Add type to dev_pm_qos_add_ancestor_request() arguments
  ACPI / LPSS: Support for device latency tolerance PM QoS
  ACPI / scan: Add bind/unbind callbacks to struct acpi_scan_handler
  PM / QoS: Introcuce latency tolerance device PM QoS type
  PM / QoS: Add no_constraints_value field to struct pm_qos_constraints
  PM / QoS: Rename device resume latency QoS items

* pm-domains:
  PM / domains: Turn latency warning into debug message

* pm-drivers:
  PM: Add pm_runtime_suspend|resume_force functions
  PM / runtime: Fetch runtime PM callbacks using a macro
This commit is contained in:
Rafael J. Wysocki 2014-03-20 13:25:36 +01:00
20 changed files with 591 additions and 168 deletions

View file

@ -33,6 +33,13 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
#define LPSS_SW_LTR 0x10
#define LPSS_AUTO_LTR 0x14
#define LPSS_LTR_SNOOP_REQ BIT(15)
#define LPSS_LTR_SNOOP_MASK 0x0000FFFF
#define LPSS_LTR_SNOOP_LAT_1US 0x800
#define LPSS_LTR_SNOOP_LAT_32US 0xC00
#define LPSS_LTR_SNOOP_LAT_SHIFT 5
#define LPSS_LTR_SNOOP_LAT_CUTOFF 3000
#define LPSS_LTR_MAX_VAL 0x3FF
#define LPSS_TX_INT 0x20
#define LPSS_TX_INT_MASK BIT(1)
@ -326,6 +333,17 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
return ret;
}
static u32 __lpss_reg_read(struct lpss_private_data *pdata, unsigned int reg)
{
return readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
}
static void __lpss_reg_write(u32 val, struct lpss_private_data *pdata,
unsigned int reg)
{
writel(val, pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
}
static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
{
struct acpi_device *adev;
@ -347,7 +365,7 @@ static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
ret = -ENODEV;
goto out;
}
*val = readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
*val = __lpss_reg_read(pdata, reg);
out:
spin_unlock_irqrestore(&dev->power.lock, flags);
@ -400,6 +418,37 @@ static struct attribute_group lpss_attr_group = {
.name = "lpss_ltr",
};
static void acpi_lpss_set_ltr(struct device *dev, s32 val)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
u32 ltr_mode, ltr_val;
ltr_mode = __lpss_reg_read(pdata, LPSS_GENERAL);
if (val < 0) {
if (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) {
ltr_mode &= ~LPSS_GENERAL_LTR_MODE_SW;
__lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
}
return;
}
ltr_val = __lpss_reg_read(pdata, LPSS_SW_LTR) & ~LPSS_LTR_SNOOP_MASK;
if (val >= LPSS_LTR_SNOOP_LAT_CUTOFF) {
ltr_val |= LPSS_LTR_SNOOP_LAT_32US;
val = LPSS_LTR_MAX_VAL;
} else if (val > LPSS_LTR_MAX_VAL) {
ltr_val |= LPSS_LTR_SNOOP_LAT_32US | LPSS_LTR_SNOOP_REQ;
val >>= LPSS_LTR_SNOOP_LAT_SHIFT;
} else {
ltr_val |= LPSS_LTR_SNOOP_LAT_1US | LPSS_LTR_SNOOP_REQ;
}
ltr_val |= val;
__lpss_reg_write(ltr_val, pdata, LPSS_SW_LTR);
if (!(ltr_mode & LPSS_GENERAL_LTR_MODE_SW)) {
ltr_mode |= LPSS_GENERAL_LTR_MODE_SW;
__lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
}
}
static int acpi_lpss_platform_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
@ -437,9 +486,29 @@ static struct notifier_block acpi_lpss_nb = {
.notifier_call = acpi_lpss_platform_notify,
};
static void acpi_lpss_bind(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
return;
if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE)
dev->power.set_latency_tolerance = acpi_lpss_set_ltr;
else
dev_err(dev, "MMIO size insufficient to access LTR\n");
}
static void acpi_lpss_unbind(struct device *dev)
{
dev->power.set_latency_tolerance = NULL;
}
static struct acpi_scan_handler lpss_handler = {
.ids = acpi_lpss_device_ids,
.attach = acpi_lpss_create_device,
.bind = acpi_lpss_bind,
.unbind = acpi_lpss_unbind,
};
void __init acpi_lpss_init(void)

View file

@ -287,6 +287,7 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one);
static int acpi_platform_notify(struct device *dev)
{
struct acpi_bus_type *type = acpi_get_bus_type(dev);
struct acpi_device *adev;
int ret;
ret = acpi_bind_one(dev, NULL);
@ -303,9 +304,14 @@ static int acpi_platform_notify(struct device *dev)
if (ret)
goto out;
}
adev = ACPI_COMPANION(dev);
if (!adev)
goto out;
if (type && type->setup)
type->setup(dev);
else if (adev->handler && adev->handler->bind)
adev->handler->bind(dev);
out:
#if ACPI_GLUE_DEBUG
@ -324,11 +330,17 @@ static int acpi_platform_notify(struct device *dev)
static int acpi_platform_notify_remove(struct device *dev)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_bus_type *type;
if (!adev)
return 0;
type = acpi_get_bus_type(dev);
if (type && type->cleanup)
type->cleanup(dev);
else if (adev->handler && adev->handler->unbind)
adev->handler->unbind(dev);
acpi_unbind_one(dev);
return 0;

View file

@ -2072,13 +2072,14 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) {
device->handler = handler;
ret = handler->attach(device, devid);
if (ret > 0) {
device->handler = handler;
if (ret > 0)
break;
} else if (ret < 0) {
device->handler = NULL;
if (ret < 0)
break;
}
}
}
return ret;