Skip to content

Commit

Permalink
ACPI / LPSS: introduce a 'proxy' device to power on LPSS for DMA
Browse files Browse the repository at this point in the history
The LPSS DMA controller does not have _PS0 and _PS3 methods. Moreover it can be
powered off automatically whenever the last LPSS device goes down. In case of
no power any access to the DMA controller will hang the system. The behaviour
is reproduced on some HP laptops based on Intel Bay Trail [1] as well as on
Asus T100 transformer.

This patch introduces a so called 'proxy' device that has the knobs to handle a
power of the LPSS island. When the system needs to program the DMA controller
it calls to the ACPI LPSS power domain callbacks that wake or suspend the
'proxy' device.

[1] http://www.spinics.net/lists/dmaengine/msg01514.html

Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Scott Ashcroft <scott.ashcroft@talk21.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Andy Shevchenko authored and Rafael J. Wysocki committed Nov 11, 2014
1 parent 01ac170 commit 6c17ee4
Showing 1 changed file with 28 additions and 7 deletions.
35 changes: 28 additions & 7 deletions drivers/acpi/acpi_lpss.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ACPI support for Intel Lynxpoint LPSS.
*
* Copyright (C) 2013, Intel Corporation
* Copyright (C) 2013, 2014, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
Expand Down Expand Up @@ -60,6 +60,8 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_CLK_DIVIDER BIT(2)
#define LPSS_LTR BIT(3)
#define LPSS_SAVE_CTX BIT(4)
#define LPSS_DEV_PROXY BIT(5)
#define LPSS_PROXY_REQ BIT(6)

struct lpss_private_data;

Expand All @@ -70,8 +72,10 @@ struct lpss_device_desc {
void (*setup)(struct lpss_private_data *pdata);
};

static struct device *proxy_device;

static struct lpss_device_desc lpss_dma_desc = {
.flags = LPSS_CLK,
.flags = LPSS_CLK | LPSS_PROXY_REQ,
};

struct lpss_private_data {
Expand Down Expand Up @@ -146,22 +150,24 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
};

static struct lpss_device_desc byt_uart_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = lpss_uart_setup,
};

static struct lpss_device_desc byt_spi_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
LPSS_DEV_PROXY,
.prv_offset = 0x400,
};

static struct lpss_device_desc byt_sdio_dev_desc = {
.flags = LPSS_CLK,
.flags = LPSS_CLK | LPSS_DEV_PROXY,
};

static struct lpss_device_desc byt_i2c_dev_desc = {
.flags = LPSS_CLK | LPSS_SAVE_CTX,
.flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
};
Expand Down Expand Up @@ -368,6 +374,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
adev->driver_data = pdata;
pdev = acpi_create_platform_device(adev);
if (!IS_ERR_OR_NULL(pdev)) {
if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY)
proxy_device = &pdev->dev;
return 1;
}

Expand Down Expand Up @@ -593,14 +601,27 @@ static int acpi_lpss_runtime_suspend(struct device *dev)
if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
acpi_lpss_save_ctx(dev, pdata);

return acpi_dev_runtime_suspend(dev);
ret = acpi_dev_runtime_suspend(dev);
if (ret)
return ret;

if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device)
return pm_runtime_put_sync_suspend(proxy_device);

return 0;
}

static int acpi_lpss_runtime_resume(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
int ret;

if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) {
ret = pm_runtime_get_sync(proxy_device);
if (ret)
return ret;
}

ret = acpi_dev_runtime_resume(dev);
if (ret)
return ret;
Expand Down

0 comments on commit 6c17ee4

Please sign in to comment.