| From 3293c7b8ec213a640f5ea2e5efeaa2b7559b1e19 Mon Sep 17 00:00:00 2001 |
| From: Mika Westerberg <mika.westerberg@linux.intel.com> |
| Date: Wed, 18 Feb 2015 13:50:16 +0200 |
| Subject: ACPI / LPSS: Always disable I2C host controllers |
| |
| From: Mika Westerberg <mika.westerberg@linux.intel.com> |
| |
| commit 3293c7b8ec213a640f5ea2e5efeaa2b7559b1e19 upstream. |
| |
| On Baytrail and Braswell the BIOS might leave the I2C host controllers |
| enabled, probably because it uses them for its own purposes. This is fine |
| in normal cases because the I2C driver will disable the hardware when it |
| is probed anyway. |
| |
| However, in case of suspend to disk it is different story. If the driver |
| happens to be compiled as a module the boot kernel never loads the driver |
| thus leaving host controllers enabled upon loading the hibernation image. |
| |
| The I2C host controller interrupt mask register has default value of 0x8ff, |
| in other words it has most of the interrupts unmasked. When combined with |
| the fact that the host controller is enabled, the driver immediately starts |
| getting interrupts even before its resume hook is called (once IO-APIC is |
| resumed). Since the driver is not prepared for this it will crash the |
| kernel due to NULL pointer derefence because dev->msgs is NULL. |
| |
| Unfortunately we were not able to get full backtrace to from the console |
| which could be reproduced here. |
| |
| In order to fix this even when the driver is compiled as module, we disable |
| the I2C host controllers in byt_i2c_setup() before devices are created. |
| |
| Reported-by: Yu Chen <yu.c.chen@intel.com> |
| Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> |
| Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/acpi/acpi_lpss.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/drivers/acpi/acpi_lpss.c |
| +++ b/drivers/acpi/acpi_lpss.c |
| @@ -105,6 +105,8 @@ static void lpss_uart_setup(struct lpss_ |
| } |
| } |
| |
| +#define LPSS_I2C_ENABLE 0x6c |
| + |
| static void byt_i2c_setup(struct lpss_private_data *pdata) |
| { |
| unsigned int offset; |
| @@ -117,6 +119,8 @@ static void byt_i2c_setup(struct lpss_pr |
| |
| if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset)) |
| pdata->fixed_clk_rate = 133000000; |
| + |
| + writel(0, pdata->mmio_base + LPSS_I2C_ENABLE); |
| } |
| |
| static struct lpss_device_desc lpt_dev_desc = { |