diff --git a/0001-platform-x86-Add-driver-for-ACPI-INT0002-Virtual-GPI.patch b/0001-platform-x86-Add-driver-for-ACPI-INT0002-Virtual-GPI.patch new file mode 100644 index 000000000..a0b6ff03e --- /dev/null +++ b/0001-platform-x86-Add-driver-for-ACPI-INT0002-Virtual-GPI.patch @@ -0,0 +1,339 @@ +From 3bbfe49a1d965b951527cde0da48f5d7677db264 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 21 May 2017 13:15:11 +0200 +Subject: [PATCH 01/16] platform/x86: Add driver for ACPI INT0002 Virtual GPIO + device + +Some peripherals on Bay Trail and Cherry Trail platforms signal a +Power Management Event (PME) to the Power Management Controller (PMC) +to wakeup the system. When this happens software needs to explicitly +clear the PME bus 0 status bit in the GPE0a_STS register to avoid an +IRQ storm on IRQ 9. + +This is modelled in ACPI through the INT0002 ACPI device, which is +called a "Virtual GPIO controller" in ACPI because it defines the +event handler to call when the PME triggers through _AEI and _L02 +methods as would be done for a real GPIO interrupt in ACPI. + +This commit adds a driver which registers the Virtual GPIOs expected +by the DSDT on these devices, letting gpiolib-acpi claim the +virtual GPIO and install a GPIO-interrupt handler which call the _L02 +handler as it would for a real GPIO controller. + +Cc: joeyli +Cc: Takashi Iwai +Signed-off-by: Hans de Goede +Reviewed-by: Andy Shevchenko +Acked-by: Rafael J. Wysocki +Reviewed-by: Linus Walleij +--- +Changes in v2: +-Remove dev_err after malloc failure +-Remove unused empty runtime pm callbacks +-s/GPE0A_PME_/GPE0A_PME_B0_/ +-Fixed some checkpatch warnings (I forgot to run checkpatch on v1) + +Changes in v3: +-Rewrite as gpiochip driver letting gpiolib-acpi deal with claiming the pin + 0x0002 and calling the _L02 event handler when the virtual gpio-irq triggers +-Rebase on 4.12-rc1 + +Changes in v4: +-Drop device_init_wakeup() from _probe(), use pm_system_wakeup() instead + of pm_wakeup_hard_event(chip->parent) +-Improve commit message + +Changes in v5: +-Use BIT() macro for FOO_BIT defines +-Drop unneeded ACPI_PTR macro usage + +Changes in v6: +-Move back to drivers/platform/x86 +-Expand certain acronyms (PME, PMC) +-Use linux/gpio/driver.h include instead of linux/gpio.h +-Document why the get / set / direction_output functions are dummys +-No functional changes + +Changes in v7: +-Some minor cleanups from Andy: + -Move asm/ includes below linux/ includes + -s/APCI/ACPI/ + -Use bitmap_clear on chip->irq_valid_mask +-Add Linus Walleij's Reviewed-by +--- + drivers/platform/x86/Kconfig | 19 +++ + drivers/platform/x86/Makefile | 1 + + drivers/platform/x86/intel_int0002_vgpio.c | 219 +++++++++++++++++++++++++++++ + 3 files changed, 239 insertions(+) + create mode 100644 drivers/platform/x86/intel_int0002_vgpio.c + +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index 8489020ecf44..a3ccc3c795a5 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -794,6 +794,25 @@ config INTEL_CHT_INT33FE + This driver instantiates i2c-clients for these, so that standard + i2c drivers for these chips can bind to the them. + ++config INTEL_INT0002_VGPIO ++ tristate "Intel ACPI INT0002 Virtual GPIO driver" ++ depends on GPIOLIB && ACPI ++ select GPIOLIB_IRQCHIP ++ ---help--- ++ Some peripherals on Bay Trail and Cherry Trail platforms signal a ++ Power Management Event (PME) to the Power Management Controller (PMC) ++ to wakeup the system. When this happens software needs to explicitly ++ clear the PME bus 0 status bit in the GPE0a_STS register to avoid an ++ IRQ storm on IRQ 9. ++ ++ This is modelled in ACPI through the INT0002 ACPI device, which is ++ called a "Virtual GPIO controller" in ACPI because it defines the ++ event handler to call when the PME triggers through _AEI and _L02 ++ methods as would be done for a real GPIO interrupt in ACPI. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called intel_int0002_vgpio. ++ + config INTEL_HID_EVENT + tristate "INTEL HID Event" + depends on ACPI +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index 182a3ed6605a..ab22ce77fb66 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -46,6 +46,7 @@ obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o + obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o + obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o + obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o ++obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o + obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o + obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o + obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o +diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c +new file mode 100644 +index 000000000000..92dc230ef5b2 +--- /dev/null ++++ b/drivers/platform/x86/intel_int0002_vgpio.c +@@ -0,0 +1,219 @@ ++/* ++ * Intel INT0002 "Virtual GPIO" driver ++ * ++ * Copyright (C) 2017 Hans de Goede ++ * ++ * Loosely based on android x86 kernel code which is: ++ * ++ * Copyright (c) 2014, Intel Corporation. ++ * ++ * Author: Dyut Kumar Sil ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Some peripherals on Bay Trail and Cherry Trail platforms signal a Power ++ * Management Event (PME) to the Power Management Controller (PMC) to wakeup ++ * the system. When this happens software needs to clear the PME bus 0 status ++ * bit in the GPE0a_STS register to avoid an IRQ storm on IRQ 9. ++ * ++ * This is modelled in ACPI through the INT0002 ACPI device, which is ++ * called a "Virtual GPIO controller" in ACPI because it defines the event ++ * handler to call when the PME triggers through _AEI and _L02 / _E02 ++ * methods as would be done for a real GPIO interrupt in ACPI. Note this ++ * is a hack to define an AML event handler for the PME while using existing ++ * ACPI mechanisms, this is not a real GPIO at all. ++ * ++ * This driver will bind to the INT0002 device, and register as a GPIO ++ * controller, letting gpiolib-acpi.c call the _L02 handler as it would ++ * for a real GPIO controller. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define DRV_NAME "INT0002 Virtual GPIO" ++ ++/* For some reason the virtual GPIO pin tied to the GPE is numbered pin 2 */ ++#define GPE0A_PME_B0_VIRT_GPIO_PIN 2 ++ ++#define GPE0A_PME_B0_STS_BIT BIT(13) ++#define GPE0A_PME_B0_EN_BIT BIT(13) ++#define GPE0A_STS_PORT 0x420 ++#define GPE0A_EN_PORT 0x428 ++ ++#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } ++ ++static const struct x86_cpu_id int0002_cpu_ids[] = { ++/* ++ * Limit ourselves to Cherry Trail for now, until testing shows we ++ * need to handle the INT0002 device on Baytrail too. ++ * ICPU(INTEL_FAM6_ATOM_SILVERMONT1), * Valleyview, Bay Trail * ++ */ ++ ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */ ++ {} ++}; ++ ++/* ++ * As this is not a real GPIO at all, but just a hack to model an event in ++ * ACPI the get / set functions are dummy functions. ++ */ ++ ++static int int0002_gpio_get(struct gpio_chip *chip, unsigned int offset) ++{ ++ return 0; ++} ++ ++static void int0002_gpio_set(struct gpio_chip *chip, unsigned int offset, ++ int value) ++{ ++} ++ ++static int int0002_gpio_direction_output(struct gpio_chip *chip, ++ unsigned int offset, int value) ++{ ++ return 0; ++} ++ ++static void int0002_irq_ack(struct irq_data *data) ++{ ++ outl(GPE0A_PME_B0_STS_BIT, GPE0A_STS_PORT); ++} ++ ++static void int0002_irq_unmask(struct irq_data *data) ++{ ++ u32 gpe_en_reg; ++ ++ gpe_en_reg = inl(GPE0A_EN_PORT); ++ gpe_en_reg |= GPE0A_PME_B0_EN_BIT; ++ outl(gpe_en_reg, GPE0A_EN_PORT); ++} ++ ++static void int0002_irq_mask(struct irq_data *data) ++{ ++ u32 gpe_en_reg; ++ ++ gpe_en_reg = inl(GPE0A_EN_PORT); ++ gpe_en_reg &= ~GPE0A_PME_B0_EN_BIT; ++ outl(gpe_en_reg, GPE0A_EN_PORT); ++} ++ ++static irqreturn_t int0002_irq(int irq, void *data) ++{ ++ struct gpio_chip *chip = data; ++ u32 gpe_sts_reg; ++ ++ gpe_sts_reg = inl(GPE0A_STS_PORT); ++ if (!(gpe_sts_reg & GPE0A_PME_B0_STS_BIT)) ++ return IRQ_NONE; ++ ++ generic_handle_irq(irq_find_mapping(chip->irqdomain, ++ GPE0A_PME_B0_VIRT_GPIO_PIN)); ++ ++ pm_system_wakeup(); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irq_chip int0002_irqchip = { ++ .name = DRV_NAME, ++ .irq_ack = int0002_irq_ack, ++ .irq_mask = int0002_irq_mask, ++ .irq_unmask = int0002_irq_unmask, ++}; ++ ++static int int0002_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct x86_cpu_id *cpu_id; ++ struct gpio_chip *chip; ++ int irq, ret; ++ ++ /* Menlow has a different INT0002 device? */ ++ cpu_id = x86_match_cpu(int0002_cpu_ids); ++ if (!cpu_id) ++ return -ENODEV; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "Error getting IRQ: %d\n", irq); ++ return irq; ++ } ++ ++ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ chip->label = DRV_NAME; ++ chip->parent = dev; ++ chip->owner = THIS_MODULE; ++ chip->get = int0002_gpio_get; ++ chip->set = int0002_gpio_set; ++ chip->direction_input = int0002_gpio_get; ++ chip->direction_output = int0002_gpio_direction_output; ++ chip->base = -1; ++ chip->ngpio = GPE0A_PME_B0_VIRT_GPIO_PIN + 1; ++ chip->irq_need_valid_mask = true; ++ ++ ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL); ++ if (ret) { ++ dev_err(dev, "Error adding gpio chip: %d\n", ret); ++ return ret; ++ } ++ ++ bitmap_clear(chip->irq_valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN); ++ ++ /* ++ * We manually request the irq here instead of passing a flow-handler ++ * to gpiochip_set_chained_irqchip, because the irq is shared. ++ */ ++ ret = devm_request_irq(dev, irq, int0002_irq, ++ IRQF_SHARED | IRQF_NO_THREAD, "INT0002", chip); ++ if (ret) { ++ dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret); ++ return ret; ++ } ++ ++ ret = gpiochip_irqchip_add(chip, &int0002_irqchip, 0, handle_edge_irq, ++ IRQ_TYPE_NONE); ++ if (ret) { ++ dev_err(dev, "Error adding irqchip: %d\n", ret); ++ return ret; ++ } ++ ++ gpiochip_set_chained_irqchip(chip, &int0002_irqchip, irq, NULL); ++ ++ return 0; ++} ++ ++static const struct acpi_device_id int0002_acpi_ids[] = { ++ { "INT0002", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, int0002_acpi_ids); ++ ++static struct platform_driver int0002_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ .acpi_match_table = int0002_acpi_ids, ++ }, ++ .probe = int0002_probe, ++}; ++ ++module_platform_driver(int0002_driver); ++ ++MODULE_AUTHOR("Hans de Goede "); ++MODULE_DESCRIPTION("Intel INT0002 Virtual GPIO driver"); ++MODULE_LICENSE("GPL"); +-- +2.13.0 + diff --git a/0002-mfd-Add-Cherry-Trail-Whiskey-Cove-PMIC-driver.patch b/0002-mfd-Add-Cherry-Trail-Whiskey-Cove-PMIC-driver.patch new file mode 100644 index 000000000..49975811b --- /dev/null +++ b/0002-mfd-Add-Cherry-Trail-Whiskey-Cove-PMIC-driver.patch @@ -0,0 +1,355 @@ +From c0f9254fdd0703ade018b2ff3a8cca433f781a11 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 26 Feb 2017 21:07:29 +0100 +Subject: [PATCH 02/16] mfd: Add Cherry Trail Whiskey Cove PMIC driver + +Add mfd driver for Intel CHT Whiskey Cove PMIC, based on various non +upstreamed CHT Whiskey Cove PMIC patches. + +This is a somewhat minimal version which adds irqchip support and cells +for: ACPI PMIC opregion support, the i2c-controller driving the external +charger irc and the pwrsrc/extcon block. + +Further cells can be added in the future if/when drivers are upstreamed +for them. + +Cc: Bin Gao +Cc: Felipe Balbi +Cc: Andy Shevchenko +Signed-off-by: Hans de Goede +Reviewed-by: Andy Shevchenko +--- +Changes in v2: +-Since this uses plain mfd and not the intel_soc_pmic stuff give it + its own Kconfig and allow this to be built as a module +-Add missing #include + +Changes in v3: +-Drop #include again, not the right fix for the build errors +-Error out when the upper byte of the register-address passed to the regmap + functions is 0 rather then hardcoding an address in that case +-Various minor style tweaks / cleanups +-Move defines of regulator register addresses to intel_pmic_chtwc.c, + it is the only place where they are used +-Drop now empty include/linux/mfd/intel_chtwc.h +-Rename intel_soc_pmic_chtwc.c to intel_cht_wc.c to match Kconfig option name +-Add irqchip support +-Add external charger cell +-Add pwrsrc cell + +Changes in v4: +-Use PLATFORM_DEVID_NONE + +Changes in v5: +-Change Kconfig option from tristate to boolean and add a select for the + i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI + OPRegion handler, which must be available before other drivers using it + are loaded, which can only be ensured if the mfd, opregion and i2c-bus + drivers are built in. This fixes errors like these during boot: + mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA + ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] (20170119/evregion-166) + ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-299) + ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93543b0cde10), AE_NOT_EXIST (20170119/psparse-543) + ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b0b5cd0), AE_NOT_EXIST (20170119/psparse-543) + acpi 80860F14:02: Failed to change power state to D0 +-Some minor style and capitalization fixes from review by Lee Jones + +Changes in v6: +-Fix Kconfig depends and selects to fix warning reported by kbuild test robot + +Changes in v7: +-Add explanation why this is a bool and why it selects i2c-designwaree + to the help text rather then as comments in the Kconfig + +Changes in v8: +-Remove MODULE macros, etc. now that this driver is a bool in Kconfig + +Changes in v9: +-Some whitespace tweaks +-Return -EINVAL from probe on invalid irq +-Use probe_new i2c_driver callback +--- + drivers/mfd/Kconfig | 16 +++ + drivers/mfd/Makefile | 1 + + drivers/mfd/intel_soc_pmic_chtwc.c | 230 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 247 insertions(+) + create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 3eb5c93595f6..5203a86b8f6c 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -470,6 +470,22 @@ config INTEL_SOC_PMIC_BXTWC + thermal, charger and related power management functions + on these systems. + ++config INTEL_SOC_PMIC_CHTWC ++ bool "Support for Intel Cherry Trail Whiskey Cove PMIC" ++ depends on ACPI && HAS_IOMEM && I2C=y && COMMON_CLK ++ depends on X86 || COMPILE_TEST ++ select MFD_CORE ++ select REGMAP_I2C ++ select REGMAP_IRQ ++ select I2C_DESIGNWARE_PLATFORM ++ help ++ Select this option to enable support for the Intel Cherry Trail ++ Whiskey Cove PMIC found on some Intel Cherry Trail systems. ++ ++ This option is a bool as it provides an ACPI OpRegion which must be ++ available before any devices using it are probed. This option also ++ causes the designware-i2c driver to be builtin for the same reason. ++ + config MFD_INTEL_LPSS + tristate + select COMMON_CLK +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index c16bf1ea0ea9..6f6aed8cfccc 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -214,6 +214,7 @@ obj-$(CONFIG_MFD_SKY81452) += sky81452.o + intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o + obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o + obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o ++obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o + obj-$(CONFIG_MFD_MT6397) += mt6397-core.o + + obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o +diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c +new file mode 100644 +index 000000000000..b35da01d5bcf +--- /dev/null ++++ b/drivers/mfd/intel_soc_pmic_chtwc.c +@@ -0,0 +1,230 @@ ++/* ++ * MFD core driver for Intel Cherrytrail Whiskey Cove PMIC ++ * ++ * Copyright (C) 2017 Hans de Goede ++ * ++ * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: ++ * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* PMIC device registers */ ++#define REG_OFFSET_MASK GENMASK(7, 0) ++#define REG_ADDR_MASK GENMASK(15, 8) ++#define REG_ADDR_SHIFT 8 ++ ++#define CHT_WC_IRQLVL1 0x6e02 ++#define CHT_WC_IRQLVL1_MASK 0x6e0e ++ ++/* Whiskey Cove PMIC share same ACPI ID between different platforms */ ++#define CHT_WC_HRV 3 ++ ++/* Level 1 IRQs (level 2 IRQs are handled in the child device drivers) */ ++enum { ++ CHT_WC_PWRSRC_IRQ = 0, ++ CHT_WC_THRM_IRQ, ++ CHT_WC_BCU_IRQ, ++ CHT_WC_ADC_IRQ, ++ CHT_WC_EXT_CHGR_IRQ, ++ CHT_WC_GPIO_IRQ, ++ /* There is no irq 6 */ ++ CHT_WC_CRIT_IRQ = 7, ++}; ++ ++static struct resource cht_wc_pwrsrc_resources[] = { ++ DEFINE_RES_IRQ(CHT_WC_PWRSRC_IRQ), ++}; ++ ++static struct resource cht_wc_ext_charger_resources[] = { ++ DEFINE_RES_IRQ(CHT_WC_EXT_CHGR_IRQ), ++}; ++ ++static struct mfd_cell cht_wc_dev[] = { ++ { ++ .name = "cht_wcove_pwrsrc", ++ .num_resources = ARRAY_SIZE(cht_wc_pwrsrc_resources), ++ .resources = cht_wc_pwrsrc_resources, ++ }, { ++ .name = "cht_wcove_ext_chgr", ++ .num_resources = ARRAY_SIZE(cht_wc_ext_charger_resources), ++ .resources = cht_wc_ext_charger_resources, ++ }, ++ { .name = "cht_wcove_region", }, ++}; ++ ++/* ++ * The CHT Whiskey Cove covers multiple I2C addresses, with a 1 Byte ++ * register address space per I2C address, so we use 16 bit register ++ * addresses where the high 8 bits contain the I2C client address. ++ */ ++static int cht_wc_byte_reg_read(void *context, unsigned int reg, ++ unsigned int *val) ++{ ++ struct i2c_client *client = context; ++ int ret, orig_addr = client->addr; ++ ++ if (!(reg & REG_ADDR_MASK)) { ++ dev_err(&client->dev, "Error I2C address not specified\n"); ++ return -EINVAL; ++ } ++ ++ client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; ++ ret = i2c_smbus_read_byte_data(client, reg & REG_OFFSET_MASK); ++ client->addr = orig_addr; ++ ++ if (ret < 0) ++ return ret; ++ ++ *val = ret; ++ return 0; ++} ++ ++static int cht_wc_byte_reg_write(void *context, unsigned int reg, ++ unsigned int val) ++{ ++ struct i2c_client *client = context; ++ int ret, orig_addr = client->addr; ++ ++ if (!(reg & REG_ADDR_MASK)) { ++ dev_err(&client->dev, "Error I2C address not specified\n"); ++ return -EINVAL; ++ } ++ ++ client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; ++ ret = i2c_smbus_write_byte_data(client, reg & REG_OFFSET_MASK, val); ++ client->addr = orig_addr; ++ ++ return ret; ++} ++ ++static const struct regmap_config cht_wc_regmap_cfg = { ++ .reg_bits = 16, ++ .val_bits = 8, ++ .reg_write = cht_wc_byte_reg_write, ++ .reg_read = cht_wc_byte_reg_read, ++}; ++ ++static const struct regmap_irq cht_wc_regmap_irqs[] = { ++ REGMAP_IRQ_REG(CHT_WC_PWRSRC_IRQ, 0, BIT(CHT_WC_PWRSRC_IRQ)), ++ REGMAP_IRQ_REG(CHT_WC_THRM_IRQ, 0, BIT(CHT_WC_THRM_IRQ)), ++ REGMAP_IRQ_REG(CHT_WC_BCU_IRQ, 0, BIT(CHT_WC_BCU_IRQ)), ++ REGMAP_IRQ_REG(CHT_WC_ADC_IRQ, 0, BIT(CHT_WC_ADC_IRQ)), ++ REGMAP_IRQ_REG(CHT_WC_EXT_CHGR_IRQ, 0, BIT(CHT_WC_EXT_CHGR_IRQ)), ++ REGMAP_IRQ_REG(CHT_WC_GPIO_IRQ, 0, BIT(CHT_WC_GPIO_IRQ)), ++ REGMAP_IRQ_REG(CHT_WC_CRIT_IRQ, 0, BIT(CHT_WC_CRIT_IRQ)), ++}; ++ ++static const struct regmap_irq_chip cht_wc_regmap_irq_chip = { ++ .name = "cht_wc_irq_chip", ++ .status_base = CHT_WC_IRQLVL1, ++ .mask_base = CHT_WC_IRQLVL1_MASK, ++ .irqs = cht_wc_regmap_irqs, ++ .num_irqs = ARRAY_SIZE(cht_wc_regmap_irqs), ++ .num_regs = 1, ++}; ++ ++static int cht_wc_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct intel_soc_pmic *pmic; ++ acpi_status status; ++ unsigned long long hrv; ++ int ret; ++ ++ status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); ++ if (ACPI_FAILURE(status)) { ++ dev_err(dev, "Failed to get PMIC hardware revision\n"); ++ return -ENODEV; ++ } ++ if (hrv != CHT_WC_HRV) { ++ dev_err(dev, "Invalid PMIC hardware revision: %llu\n", hrv); ++ return -ENODEV; ++ } ++ if (client->irq < 0) { ++ dev_err(dev, "Invalid IRQ\n"); ++ return -EINVAL; ++ } ++ ++ pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); ++ if (!pmic) ++ return -ENOMEM; ++ ++ pmic->irq = client->irq; ++ pmic->dev = dev; ++ i2c_set_clientdata(client, pmic); ++ ++ pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg); ++ if (IS_ERR(pmic->regmap)) ++ return PTR_ERR(pmic->regmap); ++ ++ ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, ++ IRQF_ONESHOT | IRQF_SHARED, 0, ++ &cht_wc_regmap_irq_chip, ++ &pmic->irq_chip_data); ++ if (ret) ++ return ret; ++ ++ return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, ++ cht_wc_dev, ARRAY_SIZE(cht_wc_dev), NULL, 0, ++ regmap_irq_get_domain(pmic->irq_chip_data)); ++} ++ ++static void cht_wc_shutdown(struct i2c_client *client) ++{ ++ struct intel_soc_pmic *pmic = i2c_get_clientdata(client); ++ ++ disable_irq(pmic->irq); ++} ++ ++static int __maybe_unused cht_wc_suspend(struct device *dev) ++{ ++ struct intel_soc_pmic *pmic = dev_get_drvdata(dev); ++ ++ disable_irq(pmic->irq); ++ ++ return 0; ++} ++ ++static int __maybe_unused cht_wc_resume(struct device *dev) ++{ ++ struct intel_soc_pmic *pmic = dev_get_drvdata(dev); ++ ++ enable_irq(pmic->irq); ++ ++ return 0; ++} ++static SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume); ++ ++static const struct i2c_device_id cht_wc_i2c_id[] = { ++ { } ++}; ++ ++static const struct acpi_device_id cht_wc_acpi_ids[] = { ++ { "INT34D3", }, ++ { } ++}; ++ ++static struct i2c_driver cht_wc_driver = { ++ .driver = { ++ .name = "CHT Whiskey Cove PMIC", ++ .pm = &cht_wc_pm_ops, ++ .acpi_match_table = cht_wc_acpi_ids, ++ }, ++ .probe_new = cht_wc_probe, ++ .shutdown = cht_wc_shutdown, ++ .id_table = cht_wc_i2c_id, ++}; ++builtin_i2c_driver(cht_wc_driver); +-- +2.13.0 + diff --git a/0003-power-supply-core-Add-support-for-supplied-from-devi.patch b/0003-power-supply-core-Add-support-for-supplied-from-devi.patch new file mode 100644 index 000000000..ab646e2e5 --- /dev/null +++ b/0003-power-supply-core-Add-support-for-supplied-from-devi.patch @@ -0,0 +1,57 @@ +From 69dd0606a0d8680fe0a5e9b959f6662e582e1674 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 2 May 2017 13:43:34 +0200 +Subject: [PATCH 03/16] power: supply: core: Add support for supplied-from + device-property + +On devicetree using platforms the devicetree can provide info on which +power-supplies supply another power-supply through phandles. + +This commit adds support for providing this info on non devicetree +platforms through the platform code setting a supplied-from +device-property on the power-supplies parent device. + +Signed-off-by: Hans de Goede +--- + drivers/power/supply/power_supply_core.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c +index 7ec7c7c202bd..0c09144193a6 100644 +--- a/drivers/power/supply/power_supply_core.c ++++ b/drivers/power/supply/power_supply_core.c +@@ -274,8 +274,30 @@ static int power_supply_check_supplies(struct power_supply *psy) + return power_supply_populate_supplied_from(psy); + } + #else +-static inline int power_supply_check_supplies(struct power_supply *psy) ++static int power_supply_check_supplies(struct power_supply *psy) + { ++ int nval, ret; ++ ++ if (!psy->dev.parent) ++ return 0; ++ ++ nval = device_property_read_string_array(psy->dev.parent, ++ "supplied-from", NULL, 0); ++ if (nval <= 0) ++ return 0; ++ ++ psy->supplied_from = devm_kmalloc_array(&psy->dev, nval, ++ sizeof(char *), GFP_KERNEL); ++ if (!psy->supplied_from) ++ return -ENOMEM; ++ ++ ret = device_property_read_string_array(psy->dev.parent, ++ "supplied-from", (const char **)psy->supplied_from, nval); ++ if (ret < 0) ++ return ret; ++ ++ psy->num_supplies = nval; ++ + return 0; + } + #endif +-- +2.13.0 + diff --git a/0004-platform-x86-intel_cht_int33fe-Set-supplied-from-pro.patch b/0004-platform-x86-intel_cht_int33fe-Set-supplied-from-pro.patch new file mode 100644 index 000000000..342a48c54 --- /dev/null +++ b/0004-platform-x86-intel_cht_int33fe-Set-supplied-from-pro.patch @@ -0,0 +1,48 @@ +From 99c44df299d96db6a170ccce9b8108fc2e7f8bae Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 2 May 2017 13:40:44 +0200 +Subject: [PATCH 04/16] platform/x86: intel_cht_int33fe: Set supplied-from + property on max17047 dev + +Devices with the intel_cht_int33fe ACPI device use a max17047 fuel-gauge +combined with a bq24272i charger, in order for the fuel-gauge driver to +correctly display charging / discharging status it needs to know which +charger is supplying the battery. + +This commit sets the supplied-from device property to the name of the +bq24272i charger for this. + +Signed-off-by: Hans de Goede +--- + drivers/platform/x86/intel_cht_int33fe.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c +index 6a1b2ca5b6fe..da706e2c4232 100644 +--- a/drivers/platform/x86/intel_cht_int33fe.c ++++ b/drivers/platform/x86/intel_cht_int33fe.c +@@ -34,6 +34,13 @@ struct cht_int33fe_data { + struct i2c_client *pi3usb30532; + }; + ++static const char * const max17047_suppliers[] = { "bq24190-charger" }; ++ ++static const struct property_entry max17047_props[] = { ++ PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers), ++ { } ++}; ++ + static int cht_int33fe_probe(struct i2c_client *client) + { + struct device *dev = &client->dev; +@@ -70,6 +77,7 @@ static int cht_int33fe_probe(struct i2c_client *client) + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); ++ board_info.properties = max17047_props; + + data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); + if (!data->max17047) +-- +2.13.0 + diff --git a/0005-ACPI-PMIC-xpower-Add-support-for-the-GPI1-regulator-.patch b/0005-ACPI-PMIC-xpower-Add-support-for-the-GPI1-regulator-.patch new file mode 100644 index 000000000..c6f299c29 --- /dev/null +++ b/0005-ACPI-PMIC-xpower-Add-support-for-the-GPI1-regulator-.patch @@ -0,0 +1,80 @@ +From cc2b0e2c164d02ab42efa736f91f53baf8d8bc36 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 20 Apr 2017 22:41:20 +0200 +Subject: [PATCH 05/16] ACPI / PMIC: xpower: Add support for the GPI1 regulator + to the OpRegion handler + +Some Bay Trail devices use a GPI1 regulator field (address 0x4c) in +their 0x8d power OpRegion, add support for this. + +This fixes AE_BAD_PARAMETER errors getting thrown on these devices and +fixes these errors causing these devices to not suspend. + +Signed-off-by: Hans de Goede +Reviewed-by: Andy Shevchenko +--- +Changes in v2: +-Simplify reg == 0x92 handling (suggested by Andy Shevchenko) +-Add special handling for reg == 0x92 to intel_xpower_pmic_get_power() too +Changes in v3: +-Use defines for GPI1 reg and bits, rather then hardcoded hex values +--- + drivers/acpi/pmic/intel_pmic_xpower.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c +index 1a76c784cd4c..3b7d5be5b7ed 100644 +--- a/drivers/acpi/pmic/intel_pmic_xpower.c ++++ b/drivers/acpi/pmic/intel_pmic_xpower.c +@@ -21,6 +21,11 @@ + #include "intel_pmic.h" + + #define XPOWER_GPADC_LOW 0x5b ++#define XPOWER_GPI1_CTRL 0x92 ++ ++#define GPI1_LDO_MASK GENMASK(2, 0) ++#define GPI1_LDO_ON (3 << 0) ++#define GPI1_LDO_OFF (4 << 0) + + static struct pmic_table power_table[] = { + { +@@ -118,6 +123,10 @@ static struct pmic_table power_table[] = { + .reg = 0x10, + .bit = 0x00 + }, /* BUC6 */ ++ { ++ .address = 0x4c, ++ .reg = 0x92, ++ }, /* GPI1 */ + }; + + /* TMP0 - TMP5 are the same, all from GPADC */ +@@ -156,7 +165,12 @@ static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg, + if (regmap_read(regmap, reg, &data)) + return -EIO; + +- *value = (data & BIT(bit)) ? 1 : 0; ++ /* GPIO1 LDO regulator needs special handling */ ++ if (reg == XPOWER_GPI1_CTRL) ++ *value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON); ++ else ++ *value = (data & BIT(bit)) ? 1 : 0; ++ + return 0; + } + +@@ -165,6 +179,11 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, + { + int data; + ++ /* GPIO1 LDO regulator needs special handling */ ++ if (reg == XPOWER_GPI1_CTRL) ++ return regmap_update_bits(regmap, reg, GPI1_LDO_MASK, ++ on ? GPI1_LDO_ON : GPI1_LDO_OFF); ++ + if (regmap_read(regmap, reg, &data)) + return -EIO; + +-- +2.13.0 + diff --git a/0006-Input-axp20x-pek-Add-wakeup-support.patch b/0006-Input-axp20x-pek-Add-wakeup-support.patch new file mode 100644 index 000000000..1ec9659bd --- /dev/null +++ b/0006-Input-axp20x-pek-Add-wakeup-support.patch @@ -0,0 +1,67 @@ +From fbac4c05ec1d7c2d949f50baf1e934cbfbb6a494 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 17 Apr 2017 22:06:25 +0200 +Subject: [PATCH 06/16] Input: axp20x-pek - Add wakeup support + +At least on devices with the AXP288 PMIC the device is expected to +wakeup from suspend when the power-button gets pressed, add support +for this. + +Signed-off-by: Hans de Goede +--- + drivers/input/misc/axp20x-pek.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c +index 400869e61a06..5f16fceaae83 100644 +--- a/drivers/input/misc/axp20x-pek.c ++++ b/drivers/input/misc/axp20x-pek.c +@@ -253,6 +253,9 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, + return error; + } + ++ if (axp20x_pek->axp20x->variant == AXP288_ID) ++ enable_irq_wake(axp20x_pek->irq_dbr); ++ + return 0; + } + +@@ -331,10 +334,35 @@ static int axp20x_pek_probe(struct platform_device *pdev) + return 0; + } + ++static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev) ++{ ++ struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); ++ ++ if (axp20x_pek->axp20x->variant != AXP288_ID) ++ return 0; ++ ++ /* ++ * Clear interrupts from button presses during suspend, to avoid ++ * a wakeup power-button press getting reported to userspace. ++ */ ++ regmap_write(axp20x_pek->axp20x->regmap, ++ AXP20X_IRQ1_STATE + AXP288_IRQ_POKN / 8, ++ BIT(AXP288_IRQ_POKN % 8)); ++ ++ return 0; ++} ++ ++const struct dev_pm_ops axp20x_pek_pm_ops = { ++#ifdef CONFIG_PM_SLEEP ++ .resume_noirq = axp20x_pek_resume_noirq, ++#endif ++}; ++ + static struct platform_driver axp20x_pek_driver = { + .probe = axp20x_pek_probe, + .driver = { + .name = "axp20x-pek", ++ .pm = &axp20x_pek_pm_ops, + }, + }; + module_platform_driver(axp20x_pek_driver); +-- +2.13.0 + diff --git a/0007-platform-x86-silead_dmi-Add-touchscreen-info-for-GP-.patch b/0007-platform-x86-silead_dmi-Add-touchscreen-info-for-GP-.patch new file mode 100644 index 000000000..0b7633459 --- /dev/null +++ b/0007-platform-x86-silead_dmi-Add-touchscreen-info-for-GP-.patch @@ -0,0 +1,56 @@ +From d95c127c48ef784214671359a41ac505ac30098a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 7 May 2017 12:32:11 +0200 +Subject: [PATCH 07/16] platform/x86: silead_dmi: Add touchscreen info for + GP-electronic T701 + +Add touchscreen info for the GP-electronic T701 tablet. + +Signed-off-by: Hans de Goede +--- + drivers/platform/x86/silead_dmi.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c +index a3a57d93cf06..db3a877d2160 100644 +--- a/drivers/platform/x86/silead_dmi.c ++++ b/drivers/platform/x86/silead_dmi.c +@@ -80,6 +80,19 @@ static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = { + .properties = surftab_wintron70_st70416_6_props, + }; + ++static const struct property_entry gp_electronic_t701_props[] = { ++ PROPERTY_ENTRY_U32("touchscreen-size-x", 960), ++ PROPERTY_ENTRY_U32("touchscreen-size-y", 640), ++ PROPERTY_ENTRY_STRING("firmware-name", ++ "gsl1680-gp-electronic-t701.fw"), ++ { } ++}; ++ ++static const struct silead_ts_dmi_data gp_electronic_t701_data = { ++ .acpi_name = "MSSL1680:00", ++ .properties = gp_electronic_t701_props, ++}; ++ + static const struct dmi_system_id silead_ts_dmi_table[] = { + { + /* CUBE iwork8 Air */ +@@ -117,6 +130,15 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), + }, + }, ++ { ++ /* GP-electronic T701 */ ++ .driver_data = (void *)&gp_electronic_t701_data, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "T701"), ++ DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), ++ }, ++ }, + { }, + }; + +-- +2.13.0 + diff --git a/0008-platform-x86-silead_dmi-Add-touchscreen-info-for-PoV.patch b/0008-platform-x86-silead_dmi-Add-touchscreen-info-for-PoV.patch new file mode 100644 index 000000000..975deb8f0 --- /dev/null +++ b/0008-platform-x86-silead_dmi-Add-touchscreen-info-for-PoV.patch @@ -0,0 +1,59 @@ +From 55b347c61b2850d1e11e159ab02dc71f13b06481 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 11 Jun 2017 17:42:31 +0200 +Subject: [PATCH 08/16] platform/x86: silead_dmi: Add touchscreen info for PoV + mobii wintab p800w + +Add touchscreen info for the Point of View mobii wintab p800w tablet. + +Signed-off-by: Hans de Goede +--- + drivers/platform/x86/silead_dmi.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c +index db3a877d2160..46c5e1ebfb53 100644 +--- a/drivers/platform/x86/silead_dmi.c ++++ b/drivers/platform/x86/silead_dmi.c +@@ -93,6 +93,20 @@ static const struct silead_ts_dmi_data gp_electronic_t701_data = { + .properties = gp_electronic_t701_props, + }; + ++static const struct property_entry pov_mobii_wintab_p800w_props[] = { ++ PROPERTY_ENTRY_U32("touchscreen-size-x", 1800), ++ PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), ++ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), ++ PROPERTY_ENTRY_STRING("firmware-name", ++ "gsl3692-pov-mobii-wintab-p800w.fw"), ++ { } ++}; ++ ++static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_data = { ++ .acpi_name = "MSSL1680:00", ++ .properties = pov_mobii_wintab_p800w_props, ++}; ++ + static const struct dmi_system_id silead_ts_dmi_table[] = { + { + /* CUBE iwork8 Air */ +@@ -139,6 +153,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { + DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), + }, + }, ++ { ++ /* Point of View mobii wintab p800w */ ++ .driver_data = (void *)&pov_mobii_wintab_p800w_data, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), ++ DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), ++ DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), ++ /* Above matches are too generic, add bios-date match */ ++ DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), ++ }, ++ }, + { }, + }; + +-- +2.13.0 + diff --git a/0009-platform-x86-silead_dmi-Add-touchscreen-info-for-Pip.patch b/0009-platform-x86-silead_dmi-Add-touchscreen-info-for-Pip.patch new file mode 100644 index 000000000..0770395d9 --- /dev/null +++ b/0009-platform-x86-silead_dmi-Add-touchscreen-info-for-Pip.patch @@ -0,0 +1,57 @@ +From b239a7a0c2a1435aa5cbab3f233e0c37e82943dd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 13 Jun 2017 18:17:07 +0200 +Subject: [PATCH 09/16] platform/x86: silead_dmi: Add touchscreen info for Pipo + W2S tablet + +Add touchscreen info for Pipo W2S tablet. + +Signed-off-by: Hans de Goede +--- + drivers/platform/x86/silead_dmi.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c +index 46c5e1ebfb53..25cbea307a5e 100644 +--- a/drivers/platform/x86/silead_dmi.c ++++ b/drivers/platform/x86/silead_dmi.c +@@ -107,6 +107,21 @@ static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_data = { + .properties = pov_mobii_wintab_p800w_props, + }; + ++static const struct property_entry pipo_w2s_props[] = { ++ PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), ++ PROPERTY_ENTRY_U32("touchscreen-size-y", 880), ++ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), ++ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), ++ PROPERTY_ENTRY_STRING("firmware-name", ++ "gsl1680-pipo-w2s.fw"), ++ { } ++}; ++ ++static const struct silead_ts_dmi_data pipo_w2s_data = { ++ .acpi_name = "MSSL1680:00", ++ .properties = pipo_w2s_props, ++}; ++ + static const struct dmi_system_id silead_ts_dmi_table[] = { + { + /* CUBE iwork8 Air */ +@@ -164,6 +179,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { + DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), + }, + }, ++ { ++ /* Pipo W2S */ ++ .driver_data = (void *)&pipo_w2s_data, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "PIPO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "W2S"), ++ }, ++ }, + { }, + }; + +-- +2.13.0 + diff --git a/0010-Input-silead-Add-support-for-capactive-home-button-f.patch b/0010-Input-silead-Add-support-for-capactive-home-button-f.patch new file mode 100644 index 000000000..ce9be3760 --- /dev/null +++ b/0010-Input-silead-Add-support-for-capactive-home-button-f.patch @@ -0,0 +1,114 @@ +From 33fc16fd8aa3684e19b1d1f0a712593e2e570ab1 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 11 Jun 2017 21:24:50 +0200 +Subject: [PATCH 10/16] Input: silead: Add support for capactive home button + found on some x86 tablets + +On some x86 tablets with a silead touchscreen the windows logo on the +front is a capacitive home button. Touching this button results in a touch +with bits 12-15 of the Y coordinates set, while normally only the lower 12 +are used. + +Detect this and report a KEY_LEFTMETA press when this happens. Note for +now we only respond to the Y coordinate bits 12-15 containing 0x01, on some +tablets *without* a capacative button I've noticed these bits containing +0x04 when crossing the edges of the screen. + +Signed-off-by: Hans de Goede +--- + drivers/input/touchscreen/silead.c | 45 ++++++++++++++++++++++++++++---------- + 1 file changed, 34 insertions(+), 11 deletions(-) + +diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c +index 0dbcf105f7db..c0ba40c09699 100644 +--- a/drivers/input/touchscreen/silead.c ++++ b/drivers/input/touchscreen/silead.c +@@ -56,7 +56,7 @@ + #define SILEAD_POINT_Y_MSB_OFF 0x01 + #define SILEAD_POINT_X_OFF 0x02 + #define SILEAD_POINT_X_MSB_OFF 0x03 +-#define SILEAD_TOUCH_ID_MASK 0xF0 ++#define SILEAD_EXTRA_DATA_MASK 0xF0 + + #define SILEAD_CMD_SLEEP_MIN 10000 + #define SILEAD_CMD_SLEEP_MAX 20000 +@@ -109,6 +109,8 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data) + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED | + INPUT_MT_TRACK); + ++ input_set_capability(data->input, EV_KEY, KEY_LEFTMETA); ++ + data->input->name = SILEAD_TS_NAME; + data->input->phys = "input/ts"; + data->input->id.bustype = BUS_I2C; +@@ -139,7 +141,8 @@ static void silead_ts_read_data(struct i2c_client *client) + struct input_dev *input = data->input; + struct device *dev = &client->dev; + u8 *bufp, buf[SILEAD_TS_DATA_LEN]; +- int touch_nr, error, i; ++ int touch_nr, softbutton, error, i; ++ bool softbutton_pressed = false; + + error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_DATA, + SILEAD_TS_DATA_LEN, buf); +@@ -148,21 +151,40 @@ static void silead_ts_read_data(struct i2c_client *client) + return; + } + +- touch_nr = buf[0]; +- if (touch_nr > data->max_fingers) { ++ if (buf[0] > data->max_fingers) { + dev_warn(dev, "More touches reported then supported %d > %d\n", +- touch_nr, data->max_fingers); +- touch_nr = data->max_fingers; ++ buf[0], data->max_fingers); ++ buf[0] = data->max_fingers; + } + ++ touch_nr = 0; + bufp = buf + SILEAD_POINT_DATA_LEN; +- for (i = 0; i < touch_nr; i++, bufp += SILEAD_POINT_DATA_LEN) { +- /* Bits 4-7 are the touch id */ +- data->id[i] = (bufp[SILEAD_POINT_X_MSB_OFF] & +- SILEAD_TOUCH_ID_MASK) >> 4; +- touchscreen_set_mt_pos(&data->pos[i], &data->prop, ++ for (i = 0; i < buf[0]; i++, bufp += SILEAD_POINT_DATA_LEN) { ++ softbutton = (bufp[SILEAD_POINT_Y_MSB_OFF] & ++ SILEAD_EXTRA_DATA_MASK) >> 4; ++ ++ if (softbutton) { ++ /* ++ * For now only respond to softbutton == 0x01, some ++ * tablets *without* a capacative button send 0x04 ++ * when crossing the edges of the screen. ++ */ ++ if (softbutton == 0x01) ++ softbutton_pressed = true; ++ ++ continue; ++ } ++ ++ /* ++ * Bits 4-7 are the touch id, note not all models have ++ * hardware touch ids so atm we don't use these. ++ */ ++ data->id[touch_nr] = (bufp[SILEAD_POINT_X_MSB_OFF] & ++ SILEAD_EXTRA_DATA_MASK) >> 4; ++ touchscreen_set_mt_pos(&data->pos[touch_nr], &data->prop, + get_unaligned_le16(&bufp[SILEAD_POINT_X_OFF]) & 0xfff, + get_unaligned_le16(&bufp[SILEAD_POINT_Y_OFF]) & 0xfff); ++ touch_nr++; + } + + input_mt_assign_slots(input, data->slots, data->pos, touch_nr, 0); +@@ -178,6 +200,7 @@ static void silead_ts_read_data(struct i2c_client *client) + } + + input_mt_sync_frame(input); ++ input_report_key(input, KEY_LEFTMETA, softbutton_pressed); + input_sync(input); + } + +-- +2.13.0 + diff --git a/0011-Input-goodix-Add-support-for-capacitive-home-button.patch b/0011-Input-goodix-Add-support-for-capacitive-home-button.patch new file mode 100644 index 000000000..162357c21 --- /dev/null +++ b/0011-Input-goodix-Add-support-for-capacitive-home-button.patch @@ -0,0 +1,53 @@ +From 2a99775c336303d2efc43eab4f24b34722a28faa Mon Sep 17 00:00:00 2001 +From: "Sergei A. Trusov" +Date: Tue, 20 Jun 2017 18:08:35 +0200 +Subject: [PATCH 11/16] Input: goodix: Add support for capacitive home button + +On some x86 tablets with a Goodix touchscreen, the Windows logo on the +front is a capacitive home button. Touching this button results in a touch +with bit 4 of the first byte set, while only the lower 4 bits (0-3) are +used to indicate the number of touches. + +Report a KEY_LEFTMETA press when this happens. + +Note that the hardware might support more than one button, in which +case the "id" byte of coor_data would identify the button in question. +This is not implemented as we don't have access to hardware with +multiple buttons. + +Signed-off-by: Sergei A. Trusov +Acked-by: Bastien Nocera +--- + drivers/input/touchscreen/goodix.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c +index 240b16f3ee97..903137d9cf7d 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -267,6 +267,12 @@ static void goodix_process_events(struct goodix_ts_data *ts) + if (touch_num < 0) + return; + ++ /* ++ * Bit 4 of the first byte reports the status of the capacitive ++ * Windows/Home button. ++ */ ++ input_report_key(ts->input_dev, KEY_LEFTMETA, !!(point_data[0] & BIT(4))); ++ + for (i = 0; i < touch_num; i++) + goodix_ts_report_touch(ts, + &point_data[1 + GOODIX_CONTACT_SIZE * i]); +@@ -612,6 +618,9 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts) + ts->input_dev->id.product = ts->id; + ts->input_dev->id.version = ts->version; + ++ /* Capacitive Windows/Home button on some devices */ ++ input_set_capability(ts->input_dev, EV_KEY, KEY_LEFTMETA); ++ + error = input_register_device(ts->input_dev); + if (error) { + dev_err(&ts->client->dev, +-- +2.13.0 + diff --git a/0012-Input-gpio_keys-Do-not-report-wake-button-presses-as.patch b/0012-Input-gpio_keys-Do-not-report-wake-button-presses-as.patch new file mode 100644 index 000000000..9b52e3908 --- /dev/null +++ b/0012-Input-gpio_keys-Do-not-report-wake-button-presses-as.patch @@ -0,0 +1,150 @@ +From 02b823a4d28ffb5fde5192799abd934d9de95630 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 6 Jan 2017 20:08:11 +0100 +Subject: [PATCH 12/16] Input: gpio_keys - Do not report wake button presses as + evdev events + +If a button is a wake button, it may still be bouncing from the press +to wakeup the device by the time the gpio interrupts get enabled again +and / or the gpio_keys_report_state call from gpio_keys_resume may +find the button still pressed and report this as a new press. + +This is undesirable, esp. since the powerbutton on tablets is typically +a wakeup source and uses the gpio_keys driver on some tablets, leading +to userspace immediately re-suspending the tablet after the powerbutton +is pressed, due to it seeing a powerbutton press. + +This commit ignores wakeup button presses for the first 1 second after +resume (and while resumed, as the workqueue may run before the resume +function runs), avoiding this problem. + +Signed-off-by: Hans de Goede +--- +Note: maybe we should make WAKE_DEBOUNCE part of gpio_keys_button and +only do this when drivers / platform-data set this to a non-zero value ? +--- + drivers/input/keyboard/gpio_keys.c | 49 ++++++++++++++++++++++++++++++++++++-- + 1 file changed, 47 insertions(+), 2 deletions(-) + +diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c +index da3d362f21b1..e1488b534e7d 100644 +--- a/drivers/input/keyboard/gpio_keys.c ++++ b/drivers/input/keyboard/gpio_keys.c +@@ -31,6 +31,8 @@ + #include + #include + ++#define WAKE_DEBOUNCE msecs_to_jiffies(1000) ++ + struct gpio_button_data { + const struct gpio_keys_button *button; + struct input_dev *input; +@@ -44,10 +46,14 @@ struct gpio_button_data { + struct delayed_work work; + unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */ + ++ unsigned long resume_time; /* in jiffies, for wakeup buttons */ ++ + unsigned int irq; + spinlock_t lock; + bool disabled; + bool key_pressed; ++ bool suspended; ++ bool resume_time_valid; + }; + + struct gpio_keys_drvdata { +@@ -356,6 +362,27 @@ static struct attribute_group gpio_keys_attr_group = { + .attrs = gpio_keys_attrs, + }; + ++static bool gpio_keys_ignore_wakeup_button_press(struct gpio_button_data *bdata) ++{ ++ unsigned long flags; ++ bool ret = false; ++ ++ if (!bdata->button->wakeup) ++ return ret; ++ ++ spin_lock_irqsave(&bdata->lock, flags); ++ ++ if (bdata->suspended) ++ ret = true; /* Our resume method did not run yet */ ++ else if (bdata->resume_time_valid && ++ time_before(jiffies, bdata->resume_time + WAKE_DEBOUNCE)) ++ ret = true; /* Assume this is a wakeup press and ignore */ ++ ++ spin_unlock_irqrestore(&bdata->lock, flags); ++ ++ return ret; ++} ++ + static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) + { + const struct gpio_keys_button *button = bdata->button; +@@ -370,6 +397,9 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) + return; + } + ++ if (state && gpio_keys_ignore_wakeup_button_press(bdata)) ++ return; ++ + if (type == EV_ABS) { + if (state) + input_event(input, type, button->code, button->value); +@@ -429,6 +459,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) + + BUG_ON(irq != bdata->irq); + ++ if (gpio_keys_ignore_wakeup_button_press(bdata)) ++ return IRQ_HANDLED; ++ + spin_lock_irqsave(&bdata->lock, flags); + + if (!bdata->key_pressed) { +@@ -848,13 +881,18 @@ static int __maybe_unused gpio_keys_suspend(struct device *dev) + { + struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct input_dev *input = ddata->input; ++ unsigned long flags; + int i; + + if (device_may_wakeup(dev)) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; +- if (bdata->button->wakeup) ++ if (bdata->button->wakeup) { ++ spin_lock_irqsave(&bdata->lock, flags); ++ bdata->suspended = true; ++ spin_unlock_irqrestore(&bdata->lock, flags); + enable_irq_wake(bdata->irq); ++ } + } + } else { + mutex_lock(&input->mutex); +@@ -870,14 +908,21 @@ static int __maybe_unused gpio_keys_resume(struct device *dev) + { + struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct input_dev *input = ddata->input; ++ unsigned long flags; + int error = 0; + int i; + + if (device_may_wakeup(dev)) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; +- if (bdata->button->wakeup) ++ if (bdata->button->wakeup) { + disable_irq_wake(bdata->irq); ++ spin_lock_irqsave(&bdata->lock, flags); ++ bdata->resume_time = jiffies; ++ bdata->resume_time_valid = true; ++ bdata->suspended = false; ++ spin_unlock_irqrestore(&bdata->lock, flags); ++ } + } + } else { + mutex_lock(&input->mutex); +-- +2.13.0 + diff --git a/0013-iio-accel-bmc150-Add-support-for-BOSC0200-ACPI-devic.patch b/0013-iio-accel-bmc150-Add-support-for-BOSC0200-ACPI-devic.patch new file mode 100644 index 000000000..8eb41ee3f --- /dev/null +++ b/0013-iio-accel-bmc150-Add-support-for-BOSC0200-ACPI-devic.patch @@ -0,0 +1,32 @@ +From bf3e9581e10a19b2ce77a45fe001116d269b4c7f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 18 Jun 2017 12:47:38 +0200 +Subject: [PATCH 13/16] iio: accel: bmc150: Add support for BOSC0200 ACPI + device id + +Add support for the BOSC0200 ACPI device id used on some x86 tablets. +note driver_data is not set to a specific model, driver_data is not +used anyways (instead detection is done on the chip_id reg) and the +2 tablets with a BOSC0200 ACPI device id I've have 2 different chips, +one has a BMA250E, the other a BMA222E. + +Signed-off-by: Hans de Goede +--- + drivers/iio/accel/bmc150-accel-i2c.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c +index 8ca8041267ef..f85014fbaa12 100644 +--- a/drivers/iio/accel/bmc150-accel-i2c.c ++++ b/drivers/iio/accel/bmc150-accel-i2c.c +@@ -64,6 +64,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { + {"BMA250E", bma250e}, + {"BMA222E", bma222e}, + {"BMA0280", bma280}, ++ {"BOSC0200"}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); +-- +2.13.0 + diff --git a/0014-mmc-sdhci-acpi-Workaround-conflict-with-PCI-wifi-on-.patch b/0014-mmc-sdhci-acpi-Workaround-conflict-with-PCI-wifi-on-.patch new file mode 100644 index 000000000..b5c717c64 --- /dev/null +++ b/0014-mmc-sdhci-acpi-Workaround-conflict-with-PCI-wifi-on-.patch @@ -0,0 +1,143 @@ +From 51eb7454942c68c84b82782e47637de3ba37f113 Mon Sep 17 00:00:00 2001 +From: Adrian Hunter +Date: Wed, 21 Jun 2017 15:08:39 +0300 +Subject: [PATCH 14/16] mmc: sdhci-acpi: Workaround conflict with PCI wifi on + GPD Win handheld + +GPDwin uses PCI wifi which conflicts with SDIO's use of +acpi_device_fix_up_power() on child device nodes. Specifically +acpi_device_fix_up_power() causes the wifi module to get turned off. +Identifying GPDwin is problematic, but since SDIO is only used for wifi, +the presence of the PCI wifi card in the expected slot with an ACPI +companion node, is used to indicate that acpi_device_fix_up_power() should +be avoided. + +Signed-off-by: Adrian Hunter +Acked-by: Hans de Goede +Tested-by: Hans de Goede +Cc: stable@vger.kernel.org +--- + drivers/mmc/host/sdhci-acpi.c | 70 +++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 64 insertions(+), 6 deletions(-) + +diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c +index c6a9a1bfaa22..b3fb155f50e4 100644 +--- a/drivers/mmc/host/sdhci-acpi.c ++++ b/drivers/mmc/host/sdhci-acpi.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #endif + + #include "sdhci.h" +@@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void) + return x86_match_cpu(byt); + } + ++static bool sdhci_acpi_cht(void) ++{ ++ static const struct x86_cpu_id cht[] = { ++ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, ++ {} ++ }; ++ ++ return x86_match_cpu(cht); ++} ++ + #define BYT_IOSF_SCCEP 0x63 + #define BYT_IOSF_OCP_NETCTRL0 0x1078 + #define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) +@@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev) + return false; + } + ++static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device, ++ unsigned int slot, unsigned int parent_slot) ++{ ++ struct pci_dev *dev, *parent, *from = NULL; ++ ++ while (1) { ++ dev = pci_get_device(vendor, device, from); ++ pci_dev_put(from); ++ if (!dev) ++ break; ++ parent = pci_upstream_bridge(dev); ++ if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot && ++ parent && PCI_SLOT(parent->devfn) == parent_slot && ++ !pci_upstream_bridge(parent)) { ++ pci_dev_put(dev); ++ return true; ++ } ++ from = dev; ++ } ++ ++ return false; ++} ++ ++/* ++ * GPDwin uses PCI wifi which conflicts with SDIO's use of ++ * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is ++ * problematic, but since SDIO is only used for wifi, the presence of the PCI ++ * wifi card in the expected slot with an ACPI companion node, is used to ++ * indicate that acpi_device_fix_up_power() should be avoided. ++ */ ++static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, ++ const char *uid) ++{ ++ return sdhci_acpi_cht() && ++ !strcmp(hid, "80860F14") && ++ !strcmp(uid, "2") && ++ sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28); ++} ++ + #else + + static inline void sdhci_acpi_byt_setting(struct device *dev) +@@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev) + return false; + } + ++static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, ++ const char *uid) ++{ ++ return false; ++} ++ + #endif + + static int bxt_get_cd(struct mmc_host *mmc) +@@ -390,11 +446,16 @@ static int sdhci_acpi_probe(struct platform_device *pdev) + if (acpi_bus_get_device(handle, &device)) + return -ENODEV; + ++ hid = acpi_device_hid(device); ++ uid = device->pnp.unique_id; ++ + /* Power on the SDHCI controller and its children */ + acpi_device_fix_up_power(device); +- list_for_each_entry(child, &device->children, node) +- if (child->status.present && child->status.enabled) +- acpi_device_fix_up_power(child); ++ if (!sdhci_acpi_no_fixup_child_power(hid, uid)) { ++ list_for_each_entry(child, &device->children, node) ++ if (child->status.present && child->status.enabled) ++ acpi_device_fix_up_power(child); ++ } + + if (acpi_bus_get_status(device) || !device->status.present) + return -ENODEV; +@@ -402,9 +463,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev) + if (sdhci_acpi_byt_defer(dev)) + return -EPROBE_DEFER; + +- hid = acpi_device_hid(device); +- uid = device->pnp.unique_id; +- + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) + return -ENOMEM; +-- +2.13.0 + diff --git a/0015-i2c-cht-wc-Add-Intel-Cherry-Trail-Whiskey-Cove-SMBUS.patch b/0015-i2c-cht-wc-Add-Intel-Cherry-Trail-Whiskey-Cove-SMBUS.patch new file mode 100644 index 000000000..5d7497ce1 --- /dev/null +++ b/0015-i2c-cht-wc-Add-Intel-Cherry-Trail-Whiskey-Cove-SMBUS.patch @@ -0,0 +1,410 @@ +From bd0d7169342e47919f68e75d659968f02b62f84b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 3 Mar 2017 23:48:50 +0100 +Subject: [PATCH 15/16] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS + controller driver + +The Intel Cherry Trail Whiskey Cove PMIC does not contain a builtin +battery charger, instead boards with this PMIC use an external TI +bq24292i charger IC, which is connected to a SMBUS controller built into +the PMIC. + +This commit adds an i2c-bus driver for the PMIC's builtin SMBUS +controller. The probe function for this i2c-bus will also register an +i2c-client for the TI bq24292i charger after the i2c-bus has been +registered. + +Note that several device-properties are set on the client-device to +tell the bq24190 power-supply driver to integrate the Whiskey Cove PMIC +and e.g. use the PMIC's BC1.2 detection (through extcon) to determine +the maximum input current. + +Cc: Andy Shevchenko +Signed-off-by: Hans de Goede +--- +Changes in v2: +-Various style (mostly captialization and variable name) fixes +-Use device-properties instead of platform_data for the i2c_board_info +--- + drivers/i2c/busses/Kconfig | 8 + + drivers/i2c/busses/Makefile | 1 + + drivers/i2c/busses/i2c-cht-wc.c | 336 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 345 insertions(+) + create mode 100644 drivers/i2c/busses/i2c-cht-wc.c + +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index 144cbadc7c72..18c96178b177 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -187,6 +187,14 @@ config I2C_PIIX4 + This driver can also be built as a module. If so, the module + will be called i2c-piix4. + ++config I2C_CHT_WC ++ tristate "Intel Cherry Trail Whiskey Cove PMIC smbus controller" ++ depends on INTEL_SOC_PMIC_CHTWC ++ help ++ If you say yes to this option, support will be included for the ++ SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC ++ found on some Intel Cherry Trail systems. ++ + config I2C_NFORCE2 + tristate "Nvidia nForce2, nForce3 and nForce4" + depends on PCI +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index 30b60855fbcd..f6443fa44f61 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o + obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o + obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o + obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o ++obj-$(CONFIG_I2C_CHT_WC) += i2c-cht-wc.o + obj-$(CONFIG_I2C_I801) += i2c-i801.o + obj-$(CONFIG_I2C_ISCH) += i2c-isch.o + obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o +diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c +new file mode 100644 +index 000000000000..ccf0785bcb75 +--- /dev/null ++++ b/drivers/i2c/busses/i2c-cht-wc.c +@@ -0,0 +1,336 @@ ++/* ++ * Intel CHT Whiskey Cove PMIC I2C Master driver ++ * Copyright (C) 2017 Hans de Goede ++ * ++ * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: ++ * Copyright (C) 2011 - 2014 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version ++ * 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CHT_WC_I2C_CTRL 0x5e24 ++#define CHT_WC_I2C_CTRL_WR BIT(0) ++#define CHT_WC_I2C_CTRL_RD BIT(1) ++#define CHT_WC_I2C_CLIENT_ADDR 0x5e25 ++#define CHT_WC_I2C_REG_OFFSET 0x5e26 ++#define CHT_WC_I2C_WRDATA 0x5e27 ++#define CHT_WC_I2C_RDDATA 0x5e28 ++ ++#define CHT_WC_EXTCHGRIRQ 0x6e0a ++#define CHT_WC_EXTCHGRIRQ_CLIENT_IRQ BIT(0) ++#define CHT_WC_EXTCHGRIRQ_WRITE_IRQ BIT(1) ++#define CHT_WC_EXTCHGRIRQ_READ_IRQ BIT(2) ++#define CHT_WC_EXTCHGRIRQ_NACK_IRQ BIT(3) ++#define CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK ((u8)GENMASK(3, 1)) ++#define CHT_WC_EXTCHGRIRQ_MSK 0x6e17 ++ ++struct cht_wc_i2c_adap { ++ struct i2c_adapter adapter; ++ wait_queue_head_t wait; ++ struct irq_chip irqchip; ++ struct mutex irqchip_lock; ++ struct regmap *regmap; ++ struct irq_domain *irq_domain; ++ struct i2c_client *client; ++ int client_irq; ++ u8 irq_mask; ++ u8 old_irq_mask; ++ bool nack; ++ bool done; ++}; ++ ++static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data) ++{ ++ struct cht_wc_i2c_adap *adap = data; ++ int ret, reg; ++ ++ /* Read IRQs */ ++ ret = regmap_read(adap->regmap, CHT_WC_EXTCHGRIRQ, ®); ++ if (ret) { ++ dev_err(&adap->adapter.dev, "Error reading extchgrirq reg\n"); ++ return IRQ_NONE; ++ } ++ ++ reg &= ~adap->irq_mask; ++ ++ /* ++ * Immediately ack IRQs, so that if new IRQs arrives while we're ++ * handling the previous ones our irq will re-trigger when we're done. ++ */ ++ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg); ++ if (ret) ++ dev_err(&adap->adapter.dev, "Error writing extchgrirq reg\n"); ++ ++ /* ++ * Do NOT use handle_nested_irq here, the client irq handler will ++ * likely want to do i2c transfers and the i2c controller uses this ++ * interrupt handler as well, so running the client irq handler from ++ * this thread will cause things to lock up. ++ */ ++ if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) { ++ /* ++ * generic_handle_irq expects local IRQs to be disabled ++ * as normally it is called from interrupt context. ++ */ ++ local_irq_disable(); ++ generic_handle_irq(adap->client_irq); ++ local_irq_enable(); ++ } ++ ++ if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK) { ++ adap->nack = !!(reg & CHT_WC_EXTCHGRIRQ_NACK_IRQ); ++ adap->done = true; ++ wake_up(&adap->wait); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap) ++{ ++ /* This i2c adapter only supports SMBUS byte transfers */ ++ return I2C_FUNC_SMBUS_BYTE_DATA; ++} ++ ++static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr, ++ unsigned short flags, char read_write, ++ u8 command, int size, ++ union i2c_smbus_data *data) ++{ ++ struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap); ++ int ret, reg; ++ ++ adap->nack = false; ++ adap->done = false; ++ ++ ret = regmap_write(adap->regmap, CHT_WC_I2C_CLIENT_ADDR, addr); ++ if (ret) ++ return ret; ++ ++ if (read_write == I2C_SMBUS_WRITE) { ++ ret = regmap_write(adap->regmap, CHT_WC_I2C_WRDATA, data->byte); ++ if (ret) ++ return ret; ++ } ++ ++ ret = regmap_write(adap->regmap, CHT_WC_I2C_REG_OFFSET, command); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(adap->regmap, CHT_WC_I2C_CTRL, ++ (read_write == I2C_SMBUS_WRITE) ? ++ CHT_WC_I2C_CTRL_WR : CHT_WC_I2C_CTRL_RD); ++ if (ret) ++ return ret; ++ ++ /* 3 second timeout, during cable plug the PMIC responds quite slow */ ++ ret = wait_event_timeout(adap->wait, adap->done, 3 * HZ); ++ if (ret == 0) ++ return -ETIMEDOUT; ++ if (adap->nack) ++ return -EIO; ++ ++ if (read_write == I2C_SMBUS_READ) { ++ ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, ®); ++ if (ret) ++ return ret; ++ ++ data->byte = reg; ++ } ++ ++ return 0; ++} ++ ++static const struct i2c_algorithm cht_wc_i2c_adap_algo = { ++ .functionality = cht_wc_i2c_adap_master_func, ++ .smbus_xfer = cht_wc_i2c_adap_smbus_xfer, ++}; ++ ++/**** irqchip for the client connected to the extchgr i2c adapter ****/ ++static void cht_wc_i2c_irq_lock(struct irq_data *data) ++{ ++ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data); ++ ++ mutex_lock(&adap->irqchip_lock); ++} ++ ++static void cht_wc_i2c_irq_sync_unlock(struct irq_data *data) ++{ ++ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data); ++ int ret; ++ ++ if (adap->irq_mask != adap->old_irq_mask) { ++ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK, ++ adap->irq_mask); ++ if (ret == 0) ++ adap->old_irq_mask = adap->irq_mask; ++ else ++ dev_err(&adap->adapter.dev, "Error writing EXTCHGRIRQ_MSK\n"); ++ } ++ ++ mutex_unlock(&adap->irqchip_lock); ++} ++ ++static void cht_wc_i2c_irq_enable(struct irq_data *data) ++{ ++ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data); ++ ++ adap->irq_mask &= ~CHT_WC_EXTCHGRIRQ_CLIENT_IRQ; ++} ++ ++static void cht_wc_i2c_irq_disable(struct irq_data *data) ++{ ++ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data); ++ ++ adap->irq_mask |= CHT_WC_EXTCHGRIRQ_CLIENT_IRQ; ++} ++ ++static const struct irq_chip cht_wc_i2c_irq_chip = { ++ .irq_bus_lock = cht_wc_i2c_irq_lock, ++ .irq_bus_sync_unlock = cht_wc_i2c_irq_sync_unlock, ++ .irq_disable = cht_wc_i2c_irq_disable, ++ .irq_enable = cht_wc_i2c_irq_enable, ++ .name = "cht_wc_ext_chrg_irq_chip", ++}; ++ ++static const struct property_entry bq24190_props[] = { ++ PROPERTY_ENTRY_STRING("extcon-name", "cht_wcove_pwrsrc"), ++ PROPERTY_ENTRY_BOOL("omit-battery-class"), ++ PROPERTY_ENTRY_BOOL("disable-reset"), ++ { } ++}; ++ ++static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) ++{ ++ struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); ++ struct cht_wc_i2c_adap *adap; ++ struct i2c_board_info board_info = { ++ .type = "bq24190", ++ .addr = 0x6b, ++ .properties = bq24190_props, ++ }; ++ int ret, irq; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "Error missing irq resource\n"); ++ return -EINVAL; ++ } ++ ++ adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL); ++ if (!adap) ++ return -ENOMEM; ++ ++ init_waitqueue_head(&adap->wait); ++ mutex_init(&adap->irqchip_lock); ++ adap->irqchip = cht_wc_i2c_irq_chip; ++ adap->regmap = pmic->regmap; ++ adap->adapter.owner = THIS_MODULE; ++ adap->adapter.class = I2C_CLASS_HWMON; ++ adap->adapter.algo = &cht_wc_i2c_adap_algo; ++ strlcpy(adap->adapter.name, "PMIC I2C Adapter", ++ sizeof(adap->adapter.name)); ++ adap->adapter.dev.parent = &pdev->dev; ++ ++ /* Clear and activate i2c-adapter interrupts, disable client IRQ */ ++ adap->old_irq_mask = adap->irq_mask = ~CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK; ++ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, ~adap->irq_mask); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK, adap->irq_mask); ++ if (ret) ++ return ret; ++ ++ /* Alloc and register client IRQ */ ++ adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 1, ++ &irq_domain_simple_ops, NULL); ++ if (!adap->irq_domain) ++ return -ENOMEM; ++ ++ adap->client_irq = irq_create_mapping(adap->irq_domain, 0); ++ if (!adap->client_irq) { ++ ret = -ENOMEM; ++ goto remove_irq_domain; ++ } ++ ++ irq_set_chip_data(adap->client_irq, adap); ++ irq_set_chip_and_handler(adap->client_irq, &adap->irqchip, ++ handle_simple_irq); ++ ++ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ++ cht_wc_i2c_adap_thread_handler, ++ IRQF_ONESHOT, "PMIC I2C Adapter", adap); ++ if (ret) ++ goto remove_irq_domain; ++ ++ i2c_set_adapdata(&adap->adapter, adap); ++ ret = i2c_add_adapter(&adap->adapter); ++ if (ret) ++ goto remove_irq_domain; ++ ++ board_info.irq = adap->client_irq; ++ adap->client = i2c_new_device(&adap->adapter, &board_info); ++ if (!adap->client) { ++ ret = -ENOMEM; ++ goto del_adapter; ++ } ++ ++ platform_set_drvdata(pdev, adap); ++ return 0; ++ ++del_adapter: ++ i2c_del_adapter(&adap->adapter); ++remove_irq_domain: ++ irq_domain_remove(adap->irq_domain); ++ return ret; ++} ++ ++static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev) ++{ ++ struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev); ++ ++ i2c_unregister_device(adap->client); ++ i2c_del_adapter(&adap->adapter); ++ irq_domain_remove(adap->irq_domain); ++ ++ return 0; ++} ++ ++static struct platform_device_id cht_wc_i2c_adap_id_table[] = { ++ { .name = "cht_wcove_ext_chgr" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table); ++ ++struct platform_driver cht_wc_i2c_adap_driver = { ++ .probe = cht_wc_i2c_adap_i2c_probe, ++ .remove = cht_wc_i2c_adap_i2c_remove, ++ .driver = { ++ .name = "cht_wcove_ext_chgr", ++ }, ++ .id_table = cht_wc_i2c_adap_id_table, ++}; ++module_platform_driver(cht_wc_i2c_adap_driver); ++ ++MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC I2C Master driver"); ++MODULE_AUTHOR("Hans de Goede "); ++MODULE_LICENSE("GPL"); +-- +2.13.0 + diff --git a/0016-Input-silead-Do-not-try-to-directly-access-the-GPIO-.patch b/0016-Input-silead-Do-not-try-to-directly-access-the-GPIO-.patch new file mode 100644 index 000000000..14b4c27bf --- /dev/null +++ b/0016-Input-silead-Do-not-try-to-directly-access-the-GPIO-.patch @@ -0,0 +1,54 @@ +From fd4fb1f6633b21042ff084868323e15e708fe1cd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 1 Jan 2017 22:11:20 +0100 +Subject: [PATCH 16/16] Input: silead: Do not try to directly access the GPIO + when using ACPI pm + +On some x86 tablets we cannot directly access the GPIOs as they are +claimed by the ACPI tables, so check it the i2c client is not being +power-managed by ACPI before trying to get the power pin GPIO. + +Note this is a workaround patch to fix this until Andy' gpiolib-ACPI +patches which make gpiolib more strict land, once those are landed this +patch is no longer needed. + +Signed-off-by: Hans de Goede +--- + drivers/input/touchscreen/silead.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c +index c0ba40c09699..30fba3cbe277 100644 +--- a/drivers/input/touchscreen/silead.c ++++ b/drivers/input/touchscreen/silead.c +@@ -517,12 +518,21 @@ static int silead_ts_probe(struct i2c_client *client, + if (error) + return error; + +- /* Power GPIO pin */ +- data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); +- if (IS_ERR(data->gpio_power)) { +- if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER) +- dev_err(dev, "Shutdown GPIO request failed\n"); +- return PTR_ERR(data->gpio_power); ++ /* ++ * If device power is not managed by ACPI, get the power_gpio ++ * and manage it ourselves. ++ */ ++#ifdef CONFIG_ACPI ++ if (!acpi_bus_power_manageable(ACPI_HANDLE(dev))) ++#endif ++ { ++ data->gpio_power = devm_gpiod_get_optional(dev, "power", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(data->gpio_power)) { ++ if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER) ++ dev_err(dev, "Power GPIO request failed\n"); ++ return PTR_ERR(data->gpio_power); ++ } + } + + error = silead_ts_setup(client); +-- +2.13.0 + diff --git a/KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch b/KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch new file mode 100644 index 000000000..1cc1e5370 --- /dev/null +++ b/KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch @@ -0,0 +1,95 @@ +From fb2ac204a70da565de9ef9a9d6d69a40c2d59727 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Fri, 5 May 2017 08:21:56 +0100 +Subject: [PATCH] KEYS: Allow unrestricted boot-time addition of keys to + secondary keyring + +Allow keys to be added to the system secondary certificates keyring during +kernel initialisation in an unrestricted fashion. Such keys are implicitly +trusted and don't have their trust chains checked on link. + +This allows keys in the UEFI database to be added in secure boot mode for +the purposes of module signing. + +Signed-off-by: David Howells +--- + certs/internal.h | 18 ++++++++++++++++++ + certs/system_keyring.c | 33 +++++++++++++++++++++++++++++++++ + 2 files changed, 51 insertions(+) + create mode 100644 certs/internal.h + +diff --git a/certs/internal.h b/certs/internal.h +new file mode 100644 +index 0000000..5dcbefb +--- /dev/null ++++ b/certs/internal.h +@@ -0,0 +1,18 @@ ++/* Internal definitions ++ * ++ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++/* ++ * system_keyring.c ++ */ ++#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING ++extern void __init add_trusted_secondary_key(const char *source, ++ const void *data, size_t len); ++#endif +diff --git a/certs/system_keyring.c b/certs/system_keyring.c +index 6251d1b..5ac8ba6 100644 +--- a/certs/system_keyring.c ++++ b/certs/system_keyring.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include "internal.h" + + static struct key *builtin_trusted_keys; + #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING +@@ -265,3 +266,35 @@ int verify_pkcs7_signature(const void *data, size_t len, + EXPORT_SYMBOL_GPL(verify_pkcs7_signature); + + #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ ++ ++#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING ++/** ++ * add_trusted_secondary_key - Add to secondary keyring with no validation ++ * @source: Source of key ++ * @data: The blob holding the key ++ * @len: The length of the data blob ++ * ++ * Add a key to the secondary keyring without checking its trust chain. This ++ * is available only during kernel initialisation. ++ */ ++void __init add_trusted_secondary_key(const char *source, ++ const void *data, size_t len) ++{ ++ key_ref_t key; ++ ++ key = key_create_or_update(make_key_ref(secondary_trusted_keys, 1), ++ "asymmetric", ++ NULL, data, len, ++ (KEY_POS_ALL & ~KEY_POS_SETATTR) | ++ KEY_USR_VIEW, ++ KEY_ALLOC_NOT_IN_QUOTA | ++ KEY_ALLOC_BYPASS_RESTRICTION); ++ ++ if (IS_ERR(key)) ++ pr_err("Problem loading %s X.509 certificate (%ld)\n", ++ source, PTR_ERR(key)); ++ else ++ pr_notice("Loaded %s cert '%s' linked to secondary sys keyring\n", ++ source, key_ref_to_ptr(key)->description); ++} ++#endif /* CONFIG_SECONDARY_TRUSTED_KEYRING */ +-- +2.9.3 + diff --git a/RFC-audit-fix-a-race-condition-with-the-auditd-tracking-code.patch b/RFC-audit-fix-a-race-condition-with-the-auditd-tracking-code.patch new file mode 100644 index 000000000..d79fd256f --- /dev/null +++ b/RFC-audit-fix-a-race-condition-with-the-auditd-tracking-code.patch @@ -0,0 +1,156 @@ +From patchwork Thu Jun 15 15:28:58 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [RFC] audit: fix a race condition with the auditd tracking code +From: Paul Moore +X-Patchwork-Id: 9789009 +Message-Id: <149754053819.11365.5047864735077505545.stgit@sifl> +To: linux-audit@redhat.com +Cc: Dusty Mabe +Date: Thu, 15 Jun 2017 11:28:58 -0400 + +From: Paul Moore + +Originally reported by Adam and Dusty, it appears we have a small +race window in kauditd_thread(), as documented in the Fedora BZ: + + * https://bugzilla.redhat.com/show_bug.cgi?id=1459326#c35 + + "This issue is partly due to the read-copy nature of RCU, and + partly due to how we sync the auditd_connection state across + kauditd_thread and the audit control channel. The kauditd_thread + thread is always running so it can service the record queues and + emit the multicast messages, if it happens to be just past the + "main_queue" label, but before the "if (sk == NULL || ...)" + if-statement which calls auditd_reset() when the new auditd + connection is registered it could end up resetting the auditd + connection, regardless of if it is valid or not. This is a rather + small window and the variable nature of multi-core scheduling + explains why this is proving rather difficult to reproduce." + +The fix is to have functions only call auditd_reset() when they +believe that the kernel/auditd connection is still valid, e.g. +non-NULL, and to have these callers pass their local copy of the +auditd_connection pointer to auditd_reset() where it can be compared +with the current connection state before resetting. If the caller +has a stale state tracking pointer then the reset is ignored. + +We also make a small change to kauditd_thread() so that if the +kernel/auditd connection is dead we skip the retry queue and send the +records straight to the hold queue. This is necessary as we used to +rely on auditd_reset() to occasionally purge the retry queue but we +are going to be calling the reset function much less now and we want +to make sure the retry queue doesn't grow unbounded. + +Reported-by: Adam Williamson +Reported-by: Dusty Mabe +Signed-off-by: Paul Moore +Reviewed-by: Richard Guy Briggs +--- + kernel/audit.c | 36 +++++++++++++++++++++++------------- + 1 file changed, 23 insertions(+), 13 deletions(-) + + +-- +Linux-audit mailing list +Linux-audit@redhat.com +https://www.redhat.com/mailman/listinfo/linux-audit + +diff --git a/kernel/audit.c b/kernel/audit.c +index b2e877100242..e1e2b3abfb93 100644 +--- a/kernel/audit.c ++++ b/kernel/audit.c +@@ -575,12 +575,16 @@ static void kauditd_retry_skb(struct sk_buff *skb) + + /** + * auditd_reset - Disconnect the auditd connection ++ * @ac: auditd connection state + * + * Description: + * Break the auditd/kauditd connection and move all the queued records into the +- * hold queue in case auditd reconnects. ++ * hold queue in case auditd reconnects. It is important to note that the @ac ++ * pointer should never be dereferenced inside this function as it may be NULL ++ * or invalid, you can only compare the memory address! If @ac is NULL then ++ * the connection will always be reset. + */ +-static void auditd_reset(void) ++static void auditd_reset(const struct auditd_connection *ac) + { + unsigned long flags; + struct sk_buff *skb; +@@ -590,6 +594,11 @@ static void auditd_reset(void) + spin_lock_irqsave(&auditd_conn_lock, flags); + ac_old = rcu_dereference_protected(auditd_conn, + lockdep_is_held(&auditd_conn_lock)); ++ if (ac && ac != ac_old) { ++ /* someone already registered a new auditd connection */ ++ spin_unlock_irqrestore(&auditd_conn_lock, flags); ++ return; ++ } + rcu_assign_pointer(auditd_conn, NULL); + spin_unlock_irqrestore(&auditd_conn_lock, flags); + +@@ -649,8 +658,8 @@ static int auditd_send_unicast_skb(struct sk_buff *skb) + return rc; + + err: +- if (rc == -ECONNREFUSED) +- auditd_reset(); ++ if (ac && rc == -ECONNREFUSED) ++ auditd_reset(ac); + return rc; + } + +@@ -795,9 +804,9 @@ static int kauditd_thread(void *dummy) + rc = kauditd_send_queue(sk, portid, + &audit_hold_queue, UNICAST_RETRIES, + NULL, kauditd_rehold_skb); +- if (rc < 0) { ++ if (ac && rc < 0) { + sk = NULL; +- auditd_reset(); ++ auditd_reset(ac); + goto main_queue; + } + +@@ -805,9 +814,9 @@ static int kauditd_thread(void *dummy) + rc = kauditd_send_queue(sk, portid, + &audit_retry_queue, UNICAST_RETRIES, + NULL, kauditd_hold_skb); +- if (rc < 0) { ++ if (ac && rc < 0) { + sk = NULL; +- auditd_reset(); ++ auditd_reset(ac); + goto main_queue; + } + +@@ -815,12 +824,13 @@ static int kauditd_thread(void *dummy) + /* process the main queue - do the multicast send and attempt + * unicast, dump failed record sends to the retry queue; if + * sk == NULL due to previous failures we will just do the +- * multicast send and move the record to the retry queue */ ++ * multicast send and move the record to the hold queue */ + rc = kauditd_send_queue(sk, portid, &audit_queue, 1, + kauditd_send_multicast_skb, +- kauditd_retry_skb); +- if (sk == NULL || rc < 0) +- auditd_reset(); ++ (sk ? ++ kauditd_retry_skb : kauditd_hold_skb)); ++ if (ac && rc < 0) ++ auditd_reset(ac); + sk = NULL; + + /* drop our netns reference, no auditd sends past this line */ +@@ -1230,7 +1240,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + auditd_pid, 1); + + /* unregister the auditd connection */ +- auditd_reset(); ++ auditd_reset(NULL); + } + } + if (s.mask & AUDIT_STATUS_RATE_LIMIT) { diff --git a/arm-dts-boneblack-wireless-add-WL1835-Bluetooth-device-node.patch b/arm-dts-boneblack-wireless-add-WL1835-Bluetooth-device-node.patch new file mode 100644 index 000000000..b4c945697 --- /dev/null +++ b/arm-dts-boneblack-wireless-add-WL1835-Bluetooth-device-node.patch @@ -0,0 +1,40 @@ +From patchwork Mon May 22 14:51:38 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: arm: dts: boneblack-wireless: add WL1835 Bluetooth device node +From: Ricardo Salveti +X-Patchwork-Id: 9740719 +Message-Id: <1495464701-12046-1-git-send-email-ricardo.salveti@linaro.org> +To: linux-omap@vger.kernel.org +Cc: Mark Rutland , + Ricardo Salveti , devicetree@vger.kernel.org, + Tony Lindgren , Russell King , + linux-kernel@vger.kernel.org, Rob Herring , + =?UTF-8?q?Beno=C3=AEt=20Cousson?= , + robertcnelson@gmail.com, linux-arm-kernel@lists.infradead.org +Date: Mon, 22 May 2017 11:51:38 -0300 + +This adds the serial slave device for the WL1835 Bluetooth interface. + +Signed-off-by: Ricardo Salveti +--- + arch/arm/boot/dts/am335x-boneblack-wireless.dts | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm/boot/dts/am335x-boneblack-wireless.dts b/arch/arm/boot/dts/am335x-boneblack-wireless.dts +index 105bd10..83f49f6 100644 +--- a/arch/arm/boot/dts/am335x-boneblack-wireless.dts ++++ b/arch/arm/boot/dts/am335x-boneblack-wireless.dts +@@ -97,6 +97,11 @@ + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins &bt_pins>; + status = "okay"; ++ ++ bluetooth { ++ compatible = "ti,wl1835-st"; ++ enable-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; ++ }; + }; + + &gpio3 { diff --git a/bcm2835-clk-audio-jitter-issues.patch b/bcm2835-clk-audio-jitter-issues.patch new file mode 100644 index 000000000..91304d64b --- /dev/null +++ b/bcm2835-clk-audio-jitter-issues.patch @@ -0,0 +1,206 @@ +From patchwork Thu Jun 1 14:14:16 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v4,1/2] clk: bcm2835: Limit PCM clock to OSC and PLLD_PER +From: Phil Elwell +X-Patchwork-Id: 9759641 +Message-Id: <8cc0ba82-d33e-127b-7b86-ac595ef416d1@raspberrypi.org> +To: Michael Turquette , + Stephen Boyd , Eric Anholt , + Stefan Wahren , + Florian Fainelli , + linux-clk@vger.kernel.org, linux-rpi-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org +Date: Thu, 1 Jun 2017 15:14:16 +0100 + +Restrict clock sources for the PCM peripheral to the oscillator and +PLLD_PER because other source may have varying rates or be switched off. +Prevent other sources from being selected by replacing their names in +the list of potential parents with dummy entries (entry index is +significant). + +Signed-off-by: Phil Elwell +Reviewed-by: Eric Anholt +Acked-by: Stefan Wahren +--- + drivers/clk/bcm/clk-bcm2835.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 0258538..49867d2 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1516,6 +1516,31 @@ struct bcm2835_clk_desc { + .parents = bcm2835_clock_per_parents, \ + __VA_ARGS__) + ++/* ++ * Restrict clock sources for the PCM peripheral to the oscillator and ++ * PLLD_PER because other source may have varying rates or be switched ++ * off. ++ * ++ * Prevent other sources from being selected by replacing their names in ++ * the list of potential parents with dummy entries (entry index is ++ * significant). ++ */ ++static const char *const bcm2835_pcm_per_parents[] = { ++ "-", ++ "xosc", ++ "-", ++ "-", ++ "-", ++ "-", ++ "plld_per", ++ "-", ++}; ++ ++#define REGISTER_PCM_CLK(...) REGISTER_CLK( \ ++ .num_mux_parents = ARRAY_SIZE(bcm2835_pcm_per_parents), \ ++ .parents = bcm2835_pcm_per_parents, \ ++ __VA_ARGS__) ++ + /* main vpu parent mux */ + static const char *const bcm2835_clock_vpu_parents[] = { + "gnd", +@@ -1993,7 +2018,7 @@ struct bcm2835_clk_desc { + .int_bits = 4, + .frac_bits = 8, + .tcnt_mux = 22), +- [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK( ++ [BCM2835_CLOCK_PCM] = REGISTER_PCM_CLK( + .name = "pcm", + .ctl_reg = CM_PCMCTL, + .div_reg = CM_PCMDIV, +From patchwork Thu Jun 1 14:14:22 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v4,2/2] clk: bcm2835: Minimise clock jitter for PCM clock +From: Phil Elwell +X-Patchwork-Id: 9759643 +Message-Id: <9989244b-ca4d-9081-95d9-b24f51099222@raspberrypi.org> +To: Michael Turquette , + Stephen Boyd , Eric Anholt , + Stefan Wahren , + Florian Fainelli , + linux-clk@vger.kernel.org, linux-rpi-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org +Date: Thu, 1 Jun 2017 15:14:22 +0100 + +Fractional clock dividers generate accurate average frequencies but +with jitter, particularly when the integer divisor is small. + +Introduce a new metric of clock accuracy to penalise clocks with a good +average but worse jitter compared to clocks with an average which is no +better but with lower jitter. The metric is the ideal rate minus the +worse deviation from that ideal using the nearest integer divisors. + +Use this metric for parent selection for clocks requiring low jitter +(currently just PCM). + +Signed-off-by: Phil Elwell +Reviewed-by: Eric Anholt +Acked-by: Stefan Wahren +--- + drivers/clk/bcm/clk-bcm2835.c | 34 +++++++++++++++++++++++++++++----- + 1 file changed, 29 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 49867d2..0bc56a0 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -530,6 +530,7 @@ struct bcm2835_clock_data { + + bool is_vpu_clock; + bool is_mash_clock; ++ bool low_jitter; + + u32 tcnt_mux; + }; +@@ -1124,7 +1125,8 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, + int parent_idx, + unsigned long rate, + u32 *div, +- unsigned long *prate) ++ unsigned long *prate, ++ unsigned long *avgrate) + { + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; +@@ -1139,8 +1141,25 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, + *prate = clk_hw_get_rate(parent); + *div = bcm2835_clock_choose_div(hw, rate, *prate, true); + +- return bcm2835_clock_rate_from_divisor(clock, *prate, +- *div); ++ *avgrate = bcm2835_clock_rate_from_divisor(clock, *prate, *div); ++ ++ if (data->low_jitter && (*div & CM_DIV_FRAC_MASK)) { ++ unsigned long high, low; ++ u32 int_div = *div & ~CM_DIV_FRAC_MASK; ++ ++ high = bcm2835_clock_rate_from_divisor(clock, *prate, ++ int_div); ++ int_div += CM_DIV_FRAC_MASK + 1; ++ low = bcm2835_clock_rate_from_divisor(clock, *prate, ++ int_div); ++ ++ /* ++ * Return a value which is the maximum deviation ++ * below the ideal rate, for use as a metric. ++ */ ++ return *avgrate - max(*avgrate - low, high - *avgrate); ++ } ++ return *avgrate; + } + + if (data->frac_bits) +@@ -1167,6 +1186,7 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, + + *div = curdiv << CM_DIV_FRAC_BITS; + *prate = curdiv * best_rate; ++ *avgrate = best_rate; + + return best_rate; + } +@@ -1178,6 +1198,7 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, + bool current_parent_is_pllc; + unsigned long rate, best_rate = 0; + unsigned long prate, best_prate = 0; ++ unsigned long avgrate, best_avgrate = 0; + size_t i; + u32 div; + +@@ -1202,11 +1223,13 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, + continue; + + rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate, +- &div, &prate); ++ &div, &prate, ++ &avgrate); + if (rate > best_rate && rate <= req->rate) { + best_parent = parent; + best_prate = prate; + best_rate = rate; ++ best_avgrate = avgrate; + } + } + +@@ -1216,7 +1239,7 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, + req->best_parent_hw = best_parent; + req->best_parent_rate = best_prate; + +- req->rate = best_rate; ++ req->rate = best_avgrate; + + return 0; + } +@@ -2025,6 +2048,7 @@ struct bcm2835_clk_desc { + .int_bits = 12, + .frac_bits = 12, + .is_mash_clock = true, ++ .low_jitter = true, + .tcnt_mux = 23), + [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( + .name = "pwm", diff --git a/bcm2835-fix-potential-null-pointer-dereferences.patch b/bcm2835-fix-potential-null-pointer-dereferences.patch new file mode 100644 index 000000000..862e77fe8 --- /dev/null +++ b/bcm2835-fix-potential-null-pointer-dereferences.patch @@ -0,0 +1,70 @@ +From patchwork Thu May 25 17:04:55 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v2] mmc: bcm2835: fix potential null pointer dereferences +From: "Gustavo A. R. Silva" +X-Patchwork-Id: 9748761 +Message-Id: <20170525170455.GA6904@embeddedgus> +To: Stefan Wahren , + Ulf Hansson , + Florian Fainelli , + Ray Jui , Scott Branden , + bcm-kernel-feedback-list@broadcom.com, Eric Anholt +Cc: "Gustavo A. R. Silva" , + linux-mmc@vger.kernel.org, linux-rpi-kernel@lists.infradead.org, + linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org +Date: Thu, 25 May 2017 12:04:55 -0500 + +Null check at line 1165: if (mrq->cmd), implies that mrq->cmd might +be NULL. +Add null checks before dereferencing pointer mrq->cmd in order to avoid +any potential NULL pointer dereference. + +Addresses-Coverity-ID: 1408740 +Tested-by: Stefan Wahren +Signed-off-by: Gustavo A. R. Silva +--- +Changes in v2: + Change subject to make it clear the patch is bcm2835 related. + + drivers/mmc/host/bcm2835.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c +index 1f343a4..abba9a2 100644 +--- a/drivers/mmc/host/bcm2835.c ++++ b/drivers/mmc/host/bcm2835.c +@@ -1172,7 +1172,10 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) + if (mrq->data && !is_power_of_2(mrq->data->blksz)) { + dev_err(dev, "unsupported block size (%d bytes)\n", + mrq->data->blksz); +- mrq->cmd->error = -EINVAL; ++ ++ if (mrq->cmd) ++ mrq->cmd->error = -EINVAL; ++ + mmc_request_done(mmc, mrq); + return; + } +@@ -1194,7 +1197,10 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) + readl(host->ioaddr + SDCMD) & SDCMD_CMD_MASK, + edm); + bcm2835_dumpregs(host); +- mrq->cmd->error = -EILSEQ; ++ ++ if (mrq->cmd) ++ mrq->cmd->error = -EILSEQ; ++ + bcm2835_finish_request(host); + mutex_unlock(&host->mutex); + return; +@@ -1207,7 +1213,7 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) + if (!host->use_busy) + bcm2835_finish_command(host); + } +- } else if (bcm2835_send_command(host, mrq->cmd)) { ++ } else if (mrq->cmd && bcm2835_send_command(host, mrq->cmd)) { + if (host->data && host->dma_desc) { + /* DMA transfer starts now, PIO starts after irq */ + bcm2835_start_dma(host); diff --git a/bcm283x-vc4-fix-vblank.patch b/bcm283x-vc4-fix-vblank.patch new file mode 100644 index 000000000..ce4f8b16f --- /dev/null +++ b/bcm283x-vc4-fix-vblank.patch @@ -0,0 +1,123 @@ +From d40a5938a10a3ba73bce6395729fefd8b8bb1c07 Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Thu, 29 Jun 2017 10:05:05 +0100 +Subject: [PATCH] drm/vc4: Fix VBLANK handling in crtc->enable() path + +When we are enabling a CRTC, drm_crtc_vblank_get() is called before +drm_crtc_vblank_on(), which is not supposed to happen (hence the +WARN_ON() in the code). To solve the problem, we delay the 'update +display list' operation after the CRTC is actually enabled. + +Signed-off-by: Boris Brezillon +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 66 +++++++++++++++++++++++++++--------------- + 1 file changed, 43 insertions(+), 23 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index d86c8cce3182..316bd6210d69 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -530,6 +530,34 @@ static void vc4_crtc_disable(struct drm_crtc *crtc) + SCALER_DISPSTATX_EMPTY); + } + ++static void vc4_crtc_update_dlist(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); ++ ++ if (crtc->state->event) { ++ unsigned long flags; ++ ++ crtc->state->event->pipe = drm_crtc_index(crtc); ++ ++ WARN_ON(drm_crtc_vblank_get(crtc) != 0); ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ vc4_crtc->event = crtc->state->event; ++ crtc->state->event = NULL; ++ ++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), ++ vc4_state->mm.start); ++ ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ } else { ++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), ++ vc4_state->mm.start); ++ } ++} ++ + static void vc4_crtc_enable(struct drm_crtc *crtc) + { + struct drm_device *dev = crtc->dev; +@@ -540,6 +568,12 @@ static void vc4_crtc_enable(struct drm_crtc *crtc) + + require_hvs_enabled(dev); + ++ /* Enable vblank irq handling before crtc is started otherwise ++ * drm_crtc_get_vblank() fails in vc4_crtc_update_dlist(). ++ */ ++ drm_crtc_vblank_on(crtc); ++ vc4_crtc_update_dlist(crtc); ++ + /* Turn on the scaler, which will wait for vstart to start + * compositing. + */ +@@ -551,9 +585,6 @@ static void vc4_crtc_enable(struct drm_crtc *crtc) + /* Turn on the pixel valve, which will emit the vstart signal. */ + CRTC_WRITE(PV_V_CONTROL, + CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); +- +- /* Enable vblank irq handling after crtc is started. */ +- drm_crtc_vblank_on(crtc); + } + + static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc, +@@ -608,7 +639,6 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, + { + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + struct drm_plane *plane; + bool debug_dump_regs = false; +@@ -630,25 +660,15 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, + + WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); + +- if (crtc->state->event) { +- unsigned long flags; +- +- crtc->state->event->pipe = drm_crtc_index(crtc); +- +- WARN_ON(drm_crtc_vblank_get(crtc) != 0); +- +- spin_lock_irqsave(&dev->event_lock, flags); +- vc4_crtc->event = crtc->state->event; +- crtc->state->event = NULL; +- +- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), +- vc4_state->mm.start); +- +- spin_unlock_irqrestore(&dev->event_lock, flags); +- } else { +- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), +- vc4_state->mm.start); +- } ++ /* Only update DISPLIST if the CRTC was already running and is not ++ * being disabled. ++ * vc4_crtc_enable() takes care of updating the dlist just after ++ * re-enabling VBLANK interrupts and before enabling the engine. ++ * If the CRTC is being disabled, there's no point in updating this ++ * information. ++ */ ++ if (crtc->state->active && old_state->active) ++ vc4_crtc_update_dlist(crtc); + + if (debug_dump_regs) { + DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); +-- +2.13.0 + diff --git a/qcom-msm89xx-fixes.patch b/qcom-msm89xx-fixes.patch new file mode 100644 index 000000000..fc2f16dc3 --- /dev/null +++ b/qcom-msm89xx-fixes.patch @@ -0,0 +1,285 @@ +From 83b8b93188114e1a39b3475d9429a2ee8977a398 Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Wed, 28 Jun 2017 14:53:23 -0700 +Subject: [PATCH 1/6] rpmsg: Make modalias work for DeviceTree based devices + +When rpmsg devices are expected to be matched based on their compatible +the modalias should reflect this, so that module autoloading has a +chance to match and load the appropriate module. + +Tested-by: Rob Clark +Reported-by: Rob Clark +Signed-off-by: Bjorn Andersson +--- + drivers/rpmsg/rpmsg_core.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c +index 600f5f9f7431..62580ad1b1f1 100644 +--- a/drivers/rpmsg/rpmsg_core.c ++++ b/drivers/rpmsg/rpmsg_core.c +@@ -342,6 +342,11 @@ static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) + { + struct rpmsg_device *rpdev = to_rpmsg_device(dev); ++ ssize_t len; ++ ++ len = of_device_modalias(dev, buf, PAGE_SIZE); ++ if (len != -ENODEV) ++ return len; + + return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name); + } +@@ -384,6 +389,11 @@ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv) + static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) + { + struct rpmsg_device *rpdev = to_rpmsg_device(dev); ++ int ret; ++ ++ ret = of_device_uevent_modalias(dev, env); ++ if (ret != -ENODEV) ++ return ret; + + return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT, + rpdev->id.name); +-- +2.13.0 + +From ccdf75f90484a87ddb29649304156a503bf5a829 Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Wed, 28 Jun 2017 16:44:58 -0700 +Subject: [PATCH 2/6] spmi: Include OF based modalias in device uevent + +Include the OF-based modalias in the uevent sent when registering SPMI +devices, so that user space has a chance to autoload the kernel module +for the device. + +Reported-by: Rob Clark +Signed-off-by: Bjorn Andersson +Tested-by: Rob Clark +Reviewed-by: Stephen Boyd +--- + drivers/spmi/spmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c +index 2b9b0941d9eb..6d23226e5f69 100644 +--- a/drivers/spmi/spmi.c ++++ b/drivers/spmi/spmi.c +@@ -365,11 +365,23 @@ static int spmi_drv_remove(struct device *dev) + return 0; + } + ++static int spmi_drv_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ int ret; ++ ++ ret = of_device_uevent_modalias(dev, env); ++ if (ret != -ENODEV) ++ return ret; ++ ++ return 0; ++} ++ + static struct bus_type spmi_bus_type = { + .name = "spmi", + .match = spmi_device_match, + .probe = spmi_drv_probe, + .remove = spmi_drv_remove, ++ .uevent = spmi_drv_uevent, + }; + + /** +-- +2.13.0 + +From 283d0e00a18b294ec56f1fb904896a546704faaf Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Fri, 30 Jun 2017 11:47:21 -0400 +Subject: [PATCH 3/6] soc: qcom: smsm: fix of_node refcnting problem + +of_find_node_with_property() drops the reference to the 'from' node, +which eventually (after enough -EPROBE_DEFERs) drops the last reference +to the node causing all sorts of fun problems, and this nice splat. + + BUG: sleeping function called from invalid context at ../kernel/locking/mutex.c:747 + in_atomic(): 1, irqs_disabled(): 128, pid: 33, name: kworker/0:1 + 4 locks held by kworker/0:1/33: + #0: ("events"){.+.+.+}, at: [] process_one_work+0x1a4/0x728 + #1: (deferred_probe_work){+.+.+.}, at: [] process_one_work+0x1a4/0x728 + #2: (&dev->mutex){......}, at: [] __device_attach+0x30/0x168 + #3: (devtree_lock){......}, at: [] of_find_node_with_property+0x30/0xe0 + irq event stamp: 18976 + hardirqs last enabled at (18975): [] __down_trylock_console_sem+0x74/0xb8 + hardirqs last disabled at (18976): [] _raw_spin_lock_irqsave+0x2c/0x78 + softirqs last enabled at (16880): [] __do_softirq+0x580/0x640 + softirqs last disabled at (16871): [] irq_exit+0xe4/0x138 + CPU: 0 PID: 33 Comm: kworker/0:1 Tainted: G E 4.12.0-rc5+ #1455 + Hardware name: qualcomm dragonboard410c/dragonboard410c, BIOS 2017.07-rc1-00234-g22fa70a-dirty 06/26/2017 + Workqueue: events deferred_probe_work_func + Call trace: + [] dump_backtrace+0x0/0x230 + [] show_stack+0x24/0x30 + [] dump_stack+0xac/0xe8 + [] ___might_sleep+0x150/0x230 + [] __might_sleep+0x58/0x90 + [] __mutex_lock+0x50/0x870 + [] mutex_lock_nested+0x3c/0x50 + [] kernfs_remove+0x30/0x50 + [] sysfs_remove_dir+0x58/0x70 + [] kobject_del+0x1c/0x58 + [] kobject_put+0xb4/0x208 + [] of_node_put+0x24/0x30 + [] of_find_node_with_property+0x78/0xe0 + [] qcom_smsm_probe+0x194/0x720 [smsm] + [] platform_drv_probe+0x74/0x110 + [] driver_probe_device+0x2b4/0x420 + [] __device_attach_driver+0xd0/0x150 + [] bus_for_each_drv+0x68/0xa8 + [] __device_attach+0xd4/0x168 + [] device_initial_probe+0x24/0x30 + [] bus_probe_device+0xa0/0xa8 + [] deferred_probe_work_func+0xb8/0xf8 + [] process_one_work+0x25c/0x728 + [] worker_thread+0x54/0x3d8 + [] kthread+0x110/0x140 + [] ret_from_fork+0x10/0x40 + OF: ERROR: Bad of_node_put() on /smsm + CPU: 0 PID: 33 Comm: kworker/0:1 Tainted: G W E 4.12.0-rc5+ #1455 + Hardware name: qualcomm dragonboard410c/dragonboard410c, BIOS 2017.07-rc1-00234-g22fa70a-dirty 06/26/2017 + Workqueue: events deferred_probe_work_func + +Signed-off-by: Rob Clark +--- + drivers/soc/qcom/smsm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c +index d0337b2a71c8..a64ecd597a22 100644 +--- a/drivers/soc/qcom/smsm.c ++++ b/drivers/soc/qcom/smsm.c +@@ -495,7 +495,8 @@ static int qcom_smsm_probe(struct platform_device *pdev) + if (!smsm->hosts) + return -ENOMEM; + +- local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,smem-state-cells"); ++ local_node = of_find_node_with_property(of_node_get(pdev->dev.of_node), ++ "#qcom,smem-state-cells"); + if (!local_node) { + dev_err(&pdev->dev, "no state entry\n"); + return -EINVAL; +-- +2.13.0 + +From 40cb129048e5d2456da8d9d6468f292da3071b91 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Fri, 30 Jun 2017 16:40:23 -0400 +Subject: [PATCH 4/6] thermal: qcom: tsens: fix crash due to incorrect __init + +init_common() is called from probe, which can happen after the __init +section is already unloaded in the case of -EPROBE_DEFER. Causing a +later probe to attempt to branch to hyperspace. + +Cc: +Signed-off-by: Rob Clark +Acked-by: Bjorn Andersson +--- + drivers/thermal/qcom/tsens-common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c +index b1449ad67fc0..22ad37c9808c 100644 +--- a/drivers/thermal/qcom/tsens-common.c ++++ b/drivers/thermal/qcom/tsens-common.c +@@ -123,7 +123,7 @@ static const struct regmap_config tsens_config = { + .reg_stride = 4, + }; + +-int __init init_common(struct tsens_device *tmdev) ++int init_common(struct tsens_device *tmdev) + { + void __iomem *base; + +-- +2.13.0 + +From ae9b4fa55748cc9ce3c8ac039e46feab7257eff9 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sun, 2 Jul 2017 09:23:36 -0400 +Subject: [PATCH 5/6] soc: qcom: wcnss_ctrl: add missing MODULE_DEVICE_TABLE() + +This fixes a problem of wifi module not loading on db410c. + +Signed-off-by: Rob Clark +Reviewed-by: Bjorn Andersson +--- + drivers/soc/qcom/wcnss_ctrl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c +index b9069184df19..d008e5b82db4 100644 +--- a/drivers/soc/qcom/wcnss_ctrl.c ++++ b/drivers/soc/qcom/wcnss_ctrl.c +@@ -347,6 +347,7 @@ static const struct of_device_id wcnss_ctrl_of_match[] = { + { .compatible = "qcom,wcnss", }, + {} + }; ++MODULE_DEVICE_TABLE(of, wcnss_ctrl_of_match); + + static struct rpmsg_driver wcnss_ctrl_driver = { + .probe = wcnss_ctrl_probe, +-- +2.13.0 + +From 173c1207986956ea4c00601a67c952751a1985e6 Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Mon, 3 Jul 2017 10:10:21 +0100 +Subject: [PATCH 6/6] wcn36xx: check dma_mapping_error() + +Fixes splat: + + wcn36xx a204000.wcnss:smd-edge:wcnss:wifi: DMA-API: device driver failed to check map error[device address=0x00000000b45ba000] [size=3872 bytes] [mapped as single] + ------------[ cut here ]------------ + WARNING: CPU: 0 PID: 0 at ../lib/dma-debug.c:1167 check_unmap+0x474/0x8d0 + Modules linked in: bnep(E) arc4(E) wcn36xx(E) mac80211(E) btqcomsmd(E) btqca(E) bluetooth(E) cfg80211(E) ecdh_generic(E) rfkill(E) vfat(E) fat(E) wcnss_ctrl qcom_wcnss_pil(E) mdt_loader(E) qcom_common(E) remoteproc(E) crc32_ce(E) virtio_ring(E) snd_soc_lpass_apq8016(E) snd_soc_lpass_cpu(E) virtio(E) snd_soc_lpass_platform(E) leds_gpio(E) snd_soc_hdmi_codec(E) snd_soc_apq8016_sbc(E) snd_soc_msm8916_digital(E) snd_soc_core(E) qcom_spmi_temp_alarm(E) ac97_bus(E) snd_pcm_dmaengine(E) snd_seq(E) snd_seq_device(E) snd_pcm(E) spi_qup(E) nvmem_qfprom(E) snd_timer(E) snd(E) soundcore(E) msm_rng(E) qcom_tsens(E) nvmem_core(E) uas(E) usb_storage(E) dm9601(E) cdc_ether(E) usbnet(E) mii(E) mmc_block(E) sdhci_msm(E) sdhci_pltfm(E) qcom_spmi_vadc(E) qcom_vadc_common(PE) clk_smd_rpm(E) industrialio(E) + qcom_smd_regulator(E) pinctrl_spmi_mpp(E) pinctrl_spmi_gpio(E) rtc_pm8xxx(E) adv7511(E) smd_rpm(E) qcom_spmi_pmic(E) regmap_spmi(E) phy_msm_usb(E) usb3503(E) extcon_usb_gpio(E) ci_hdrc_msm(E) ci_hdrc(E) qcom_hwspinlock(E) udc_core(E) extcon_core(E) ehci_msm(E) i2c_qup(E) sdhci(E) msm(E) mmc_core(E) drm_kms_helper(E) syscopyarea(E) sysfillrect(E) sysimgblt(E) fb_sys_fops(E) spmi_pmic_arb(E) drm(E) spmi(E) qcom_smd(E) rpmsg_core smsm(E) gpio_keys(E) smp2p(E) smem(E) hwspinlock_core(E) sunrpc(E) scsi_transport_iscsi(E) + CPU: 0 PID: 0 Comm: swapper/0 Tainted: P E 4.12.0-rc7+ #1476 + Hardware name: qualcomm dragonboard410c/dragonboard410c, BIOS 2017.07-rc1-00234-g22fa70a-dirty 06/26/2017 + task: ffff000009049780 task.stack: ffff000009030000 + PC is at check_unmap+0x474/0x8d0 + LR is at check_unmap+0x474/0x8d0 + ... + Mapped at: + dma_entry_alloc+0x68/0xa8 + debug_dma_map_page+0x94/0x148 + wcn36xx_dxe_fill_skb.isra.1+0xbc/0xf8 [wcn36xx] + wcn36xx_dxe_init+0x244/0x398 [wcn36xx] + wcn36xx_start+0xf4/0x298 [wcn36xx] + +v2: pbrobinson: add kfree_skb(skb); + +Signed-off-by: Rob Clark +Signed-off-by: Peter Robinson +--- + drivers/net/wireless/ath/wcn36xx/dxe.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c +index 87dfdaf9044c..d5c810a8cc52 100644 +--- a/drivers/net/wireless/ath/wcn36xx/dxe.c ++++ b/drivers/net/wireless/ath/wcn36xx/dxe.c +@@ -289,6 +289,11 @@ static int wcn36xx_dxe_fill_skb(struct device *dev, struct wcn36xx_dxe_ctl *ctl) + skb_tail_pointer(skb), + WCN36XX_PKT_SIZE, + DMA_FROM_DEVICE); ++ if (dma_mapping_error(dev, dxe->dst_addr_l)) { ++ dev_err(dev, "unable to map skb\n"); ++ kfree_skb(skb); ++ return -ENOMEM; ++ } + ctl->skb = skb; + + return 0; +-- +2.13.0 +