aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpi_lpss.c
diff options
context:
space:
mode:
authorHeikki Krogerus <heikki.krogerus@linux.intel.com>2013-06-17 06:25:46 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-18 19:31:26 -0400
commit06d8641504726322fca54400bbac982bd44f9a27 (patch)
treeb1c6f8abf7251405fac6a683b283d0c48c76b110 /drivers/acpi/acpi_lpss.c
parentf627217064dbef1eef53ceb01edb9c94203991e0 (diff)
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>
Diffstat (limited to 'drivers/acpi/acpi_lpss.c')
-rw-r--r--drivers/acpi/acpi_lpss.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index f6d760581faa..bd9867f592b7 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -32,6 +32,8 @@ ACPI_MODULE_NAME("acpi_lpss");
32#define LPSS_GENERAL_LTR_MODE_SW BIT(2) 32#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
33#define LPSS_SW_LTR 0x10 33#define LPSS_SW_LTR 0x10
34#define LPSS_AUTO_LTR 0x14 34#define LPSS_AUTO_LTR 0x14
35#define LPSS_TX_INT 0x20
36#define LPSS_TX_INT_MASK BIT(1)
35 37
36struct lpss_shared_clock { 38struct lpss_shared_clock {
37 const char *name; 39 const char *name;
@@ -39,6 +41,8 @@ struct lpss_shared_clock {
39 struct clk *clk; 41 struct clk *clk;
40}; 42};
41 43
44struct lpss_private_data;
45
42struct lpss_device_desc { 46struct lpss_device_desc {
43 bool clk_required; 47 bool clk_required;
44 const char *clkdev_name; 48 const char *clkdev_name;
@@ -46,6 +50,7 @@ struct lpss_device_desc {
46 unsigned int prv_offset; 50 unsigned int prv_offset;
47 bool clk_gate; 51 bool clk_gate;
48 struct lpss_shared_clock *shared_clock; 52 struct lpss_shared_clock *shared_clock;
53 void (*setup)(struct lpss_private_data *pdata);
49}; 54};
50 55
51static struct lpss_device_desc lpss_dma_desc = { 56static struct lpss_device_desc lpss_dma_desc = {
@@ -60,6 +65,15 @@ struct lpss_private_data {
60 const struct lpss_device_desc *dev_desc; 65 const struct lpss_device_desc *dev_desc;
61}; 66};
62 67
68static void lpss_uart_setup(struct lpss_private_data *pdata)
69{
70 unsigned int tx_int_offset = pdata->dev_desc->prv_offset + LPSS_TX_INT;
71 u32 reg;
72
73 reg = readl(pdata->mmio_base + tx_int_offset);
74 writel(reg | LPSS_TX_INT_MASK, pdata->mmio_base + tx_int_offset);
75}
76
63static struct lpss_device_desc lpt_dev_desc = { 77static struct lpss_device_desc lpt_dev_desc = {
64 .clk_required = true, 78 .clk_required = true,
65 .prv_offset = 0x800, 79 .prv_offset = 0x800,
@@ -67,6 +81,14 @@ static struct lpss_device_desc lpt_dev_desc = {
67 .clk_gate = true, 81 .clk_gate = true,
68}; 82};
69 83
84static struct lpss_device_desc lpt_uart_dev_desc = {
85 .clk_required = true,
86 .prv_offset = 0x800,
87 .ltr_required = true,
88 .clk_gate = true,
89 .setup = lpss_uart_setup,
90};
91
70static struct lpss_device_desc lpt_sdio_dev_desc = { 92static struct lpss_device_desc lpt_sdio_dev_desc = {
71 .prv_offset = 0x1000, 93 .prv_offset = 0x1000,
72 .ltr_required = true, 94 .ltr_required = true,
@@ -82,6 +104,7 @@ static struct lpss_device_desc byt_uart_dev_desc = {
82 .prv_offset = 0x800, 104 .prv_offset = 0x800,
83 .clk_gate = true, 105 .clk_gate = true,
84 .shared_clock = &uart_clock, 106 .shared_clock = &uart_clock,
107 .setup = lpss_uart_setup,
85}; 108};
86 109
87static struct lpss_shared_clock spi_clock = { 110static struct lpss_shared_clock spi_clock = {
@@ -120,8 +143,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
120 { "INT33C1", (unsigned long)&lpt_dev_desc }, 143 { "INT33C1", (unsigned long)&lpt_dev_desc },
121 { "INT33C2", (unsigned long)&lpt_dev_desc }, 144 { "INT33C2", (unsigned long)&lpt_dev_desc },
122 { "INT33C3", (unsigned long)&lpt_dev_desc }, 145 { "INT33C3", (unsigned long)&lpt_dev_desc },
123 { "INT33C4", (unsigned long)&lpt_dev_desc }, 146 { "INT33C4", (unsigned long)&lpt_uart_dev_desc },
124 { "INT33C5", (unsigned long)&lpt_dev_desc }, 147 { "INT33C5", (unsigned long)&lpt_uart_dev_desc },
125 { "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, 148 { "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
126 { "INT33C7", }, 149 { "INT33C7", },
127 150
@@ -247,6 +270,9 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
247 } 270 }
248 } 271 }
249 272
273 if (dev_desc->setup)
274 dev_desc->setup(pdata);
275
250 adev->driver_data = pdata; 276 adev->driver_data = pdata;
251 ret = acpi_create_platform_device(adev, id); 277 ret = acpi_create_platform_device(adev, id);
252 if (ret > 0) 278 if (ret > 0)