blob: c2a35a0a009afac99f45af801b96e966710a09a2 [file] [log] [blame]
From 196bcfdf4c6f897aeb47b8d364bd24550b4c90b7 Mon Sep 17 00:00:00 2001
From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Date: Mon, 17 Jun 2013 13:25:46 +0300
Subject: ACPI / LPSS: mask the UART TX completion interrupt
Intel LPSS provides an extra TX byte counter and an extra TX
completion interrupt for some of its bus controllers. However,
there is no use for the extra UART interrupt and it has to be
masked out during initialization.
Otherwise, if the firmware does not mask the interrupt and
the driver does not clear it, it may cause an interrupt flood
freezing the board to happen.
Add code masking that problematic interrupt to the ACPI LPSS driver.
[rjw: Changelog]
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
(cherry picked from commit 06d8641504726322fca54400bbac982bd44f9a27)
Conflicts:
drivers/acpi/acpi_lpss.c
Account for 3.10 backport:
b9e95fc ACPI / LPSS: Power up LPSS devices during enumeration
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
---
drivers/acpi/acpi_lpss.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 3a8167c99ba9..b3f36a8ce006 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -32,6 +32,8 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
#define LPSS_SW_LTR 0x10
#define LPSS_AUTO_LTR 0x14
+#define LPSS_TX_INT 0x20
+#define LPSS_TX_INT_MASK BIT(1)
struct lpss_shared_clock {
const char *name;
@@ -39,6 +41,8 @@ struct lpss_shared_clock {
struct clk *clk;
};
+struct lpss_private_data;
+
struct lpss_device_desc {
bool clk_required;
const char *clkdev_name;
@@ -46,6 +50,7 @@ struct lpss_device_desc {
unsigned int prv_offset;
bool clk_gate;
struct lpss_shared_clock *shared_clock;
+ void (*setup)(struct lpss_private_data *pdata);
};
static struct lpss_device_desc lpss_dma_desc = {
@@ -60,6 +65,15 @@ struct lpss_private_data {
const struct lpss_device_desc *dev_desc;
};
+static void lpss_uart_setup(struct lpss_private_data *pdata)
+{
+ unsigned int tx_int_offset = pdata->dev_desc->prv_offset + LPSS_TX_INT;
+ u32 reg;
+
+ reg = readl(pdata->mmio_base + tx_int_offset);
+ writel(reg | LPSS_TX_INT_MASK, pdata->mmio_base + tx_int_offset);
+}
+
static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
@@ -67,6 +81,14 @@ static struct lpss_device_desc lpt_dev_desc = {
.clk_gate = true,
};
+static struct lpss_device_desc lpt_uart_dev_desc = {
+ .clk_required = true,
+ .prv_offset = 0x800,
+ .ltr_required = true,
+ .clk_gate = true,
+ .setup = lpss_uart_setup,
+};
+
static struct lpss_device_desc lpt_sdio_dev_desc = {
.prv_offset = 0x1000,
.ltr_required = true,
@@ -82,6 +104,7 @@ static struct lpss_device_desc byt_uart_dev_desc = {
.prv_offset = 0x800,
.clk_gate = true,
.shared_clock = &uart_clock,
+ .setup = lpss_uart_setup,
};
static struct lpss_shared_clock spi_clock = {
@@ -120,8 +143,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT33C1", (unsigned long)&lpt_dev_desc },
{ "INT33C2", (unsigned long)&lpt_dev_desc },
{ "INT33C3", (unsigned long)&lpt_dev_desc },
- { "INT33C4", (unsigned long)&lpt_dev_desc },
- { "INT33C5", (unsigned long)&lpt_dev_desc },
+ { "INT33C4", (unsigned long)&lpt_uart_dev_desc },
+ { "INT33C5", (unsigned long)&lpt_uart_dev_desc },
{ "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
{ "INT33C7", },
@@ -257,6 +280,9 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
goto err_out;
}
+ if (dev_desc->setup)
+ dev_desc->setup(pdata);
+
adev->driver_data = pdata;
ret = acpi_create_platform_device(adev, id);
if (ret > 0)
--
1.8.5.rc3