add missing patches from the 4.12 GA commit

This commit is contained in:
Peter Robinson 2017-07-12 10:22:44 +01:00
parent 272a38dcb8
commit 87fc2a45ad
23 changed files with 3049 additions and 0 deletions

View File

@ -0,0 +1,339 @@
From 3bbfe49a1d965b951527cde0da48f5d7677db264 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <jlee@suse.com>
Cc: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
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 <hdegoede@redhat.com>
+ *
+ * Loosely based on android x86 kernel code which is:
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * Author: Dyut Kumar Sil <dyut.k.sil@intel.com>
+ *
+ * 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 <linux/acpi.h>
+#include <linux/bitmap.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+#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? <sigh> */
+ 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 <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Intel INT0002 Virtual GPIO driver");
+MODULE_LICENSE("GPL");
--
2.13.0

View File

@ -0,0 +1,355 @@
From c0f9254fdd0703ade018b2ff3a8cca433f781a11 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <bin.gao@intel.com>
Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
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 <acpi/acpi_bus.h>
Changes in v3:
-Drop #include <acpi/acpi_bus.h> 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 <hdegoede@redhat.com>
+ *
+ * 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 <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/regmap.h>
+
+/* 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

View File

@ -0,0 +1,57 @@
From 69dd0606a0d8680fe0a5e9b959f6662e582e1674 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,48 @@
From 99c44df299d96db6a170ccce9b8108fc2e7f8bae Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,80 @@
From cc2b0e2c164d02ab42efa736f91f53baf8d8bc36 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
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

View File

@ -0,0 +1,67 @@
From fbac4c05ec1d7c2d949f50baf1e934cbfbb6a494 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,56 @@
From d95c127c48ef784214671359a41ac505ac30098a Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,59 @@
From 55b347c61b2850d1e11e159ab02dc71f13b06481 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,57 @@
From b239a7a0c2a1435aa5cbab3f233e0c37e82943dd Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,114 @@
From 33fc16fd8aa3684e19b1d1f0a712593e2e570ab1 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,53 @@
From 2a99775c336303d2efc43eab4f24b34722a28faa Mon Sep 17 00:00:00 2001
From: "Sergei A. Trusov" <sergei.a.trusov@ya.ru>
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 <sergei.a.trusov@ya.ru>
Acked-by: Bastien Nocera <hadess@hadess.net>
---
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

View File

@ -0,0 +1,150 @@
From 02b823a4d28ffb5fde5192799abd934d9de95630 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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 <linux/of_irq.h>
#include <linux/spinlock.h>
+#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

View File

@ -0,0 +1,32 @@
From bf3e9581e10a19b2ce77a45fe001116d269b4c7f Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,143 @@
From 51eb7454942c68c84b82782e47637de3ba37f113 Mon Sep 17 00:00:00 2001
From: Adrian Hunter <adrian.hunter@intel.com>
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 <adrian.hunter@intel.com>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Tested-by: Hans de Goede <hdegoede@redhat.com>
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 <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/iosf_mbi.h>
+#include <linux/pci.h>
#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

View File

@ -0,0 +1,410 @@
From bd0d7169342e47919f68e75d659968f02b62f84b Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <andriy.shevchenko@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
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 <hdegoede@redhat.com>
+ *
+ * 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 <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#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, &reg);
+ 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, &reg);
+ 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 <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
--
2.13.0

View File

@ -0,0 +1,54 @@
From fd4fb1f6633b21042ff084868323e15e708fe1cd Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
---
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

View File

@ -0,0 +1,95 @@
From fb2ac204a70da565de9ef9a9d6d69a40c2d59727 Mon Sep 17 00:00:00 2001
From: David Howells <dhowells@redhat.com>
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 <dhowells@redhat.com>
---
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 <keys/asymmetric-type.h>
#include <keys/system_keyring.h>
#include <crypto/pkcs7.h>
+#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

View File

@ -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 <pmoore@redhat.com>
X-Patchwork-Id: 9789009
Message-Id: <149754053819.11365.5047864735077505545.stgit@sifl>
To: linux-audit@redhat.com
Cc: Dusty Mabe <dustymabe@redhat.com>
Date: Thu, 15 Jun 2017 11:28:58 -0400
From: Paul Moore <paul@paul-moore.com>
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 <awilliam@redhat.com>
Reported-by: Dusty Mabe <dustymabe@redhat.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Richard Guy Briggs <rgb@redhat.com>
---
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) {

View File

@ -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 <ricardo.salveti@linaro.org>
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 <mark.rutland@arm.com>,
Ricardo Salveti <ricardo.salveti@linaro.org>, devicetree@vger.kernel.org,
Tony Lindgren <tony@atomide.com>, Russell King <linux@armlinux.org.uk>,
linux-kernel@vger.kernel.org, Rob Herring <robh+dt@kernel.org>,
=?UTF-8?q?Beno=C3=AEt=20Cousson?= <bcousson@baylibre.com>,
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 <ricardo.salveti@linaro.org>
---
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 {

View File

@ -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 <phil@raspberrypi.org>
X-Patchwork-Id: 9759641
Message-Id: <8cc0ba82-d33e-127b-7b86-ac595ef416d1@raspberrypi.org>
To: Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@codeaurora.org>, Eric Anholt <eric@anholt.net>,
Stefan Wahren <stefan.wahren@i2se.com>,
Florian Fainelli <f.fainelli@gmail.com>,
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 <phil@raspberrypi.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
---
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 <phil@raspberrypi.org>
X-Patchwork-Id: 9759643
Message-Id: <9989244b-ca4d-9081-95d9-b24f51099222@raspberrypi.org>
To: Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@codeaurora.org>, Eric Anholt <eric@anholt.net>,
Stefan Wahren <stefan.wahren@i2se.com>,
Florian Fainelli <f.fainelli@gmail.com>,
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 <phil@raspberrypi.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
---
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",

View File

@ -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" <garsilva@embeddedor.com>
X-Patchwork-Id: 9748761
Message-Id: <20170525170455.GA6904@embeddedgus>
To: Stefan Wahren <stefan.wahren@i2se.com>,
Ulf Hansson <ulf.hansson@linaro.org>,
Florian Fainelli <f.fainelli@gmail.com>,
Ray Jui <rjui@broadcom.com>, Scott Branden <sbranden@broadcom.com>,
bcm-kernel-feedback-list@broadcom.com, Eric Anholt <eric@anholt.net>
Cc: "Gustavo A. R. Silva" <garsilva@embeddedor.com>,
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 <stefan.wahren@i2se.com>
Signed-off-by: Gustavo A. R. Silva <garsilva@embeddedor.com>
---
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);

View File

@ -0,0 +1,123 @@
From d40a5938a10a3ba73bce6395729fefd8b8bb1c07 Mon Sep 17 00:00:00 2001
From: Peter Robinson <pbrobinson@gmail.com>
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 <boris.brezillon@free-electrons.com>
---
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

285
qcom-msm89xx-fixes.patch Normal file
View File

@ -0,0 +1,285 @@
From 83b8b93188114e1a39b3475d9429a2ee8977a398 Mon Sep 17 00:00:00 2001
From: Bjorn Andersson <bjorn.andersson@linaro.org>
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 <robdclark@gmail.com>
Reported-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
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 <bjorn.andersson@linaro.org>
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 <robdclark@gmail.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
---
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 <robdclark@gmail.com>
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: [<ffff0000080fa91c>] process_one_work+0x1a4/0x728
#1: (deferred_probe_work){+.+.+.}, at: [<ffff0000080fa91c>] process_one_work+0x1a4/0x728
#2: (&dev->mutex){......}, at: [<ffff000008676078>] __device_attach+0x30/0x168
#3: (devtree_lock){......}, at: [<ffff000008828fd0>] of_find_node_with_property+0x30/0xe0
irq event stamp: 18976
hardirqs last enabled at (18975): [<ffff00000815794c>] __down_trylock_console_sem+0x74/0xb8
hardirqs last disabled at (18976): [<ffff0000089e26d4>] _raw_spin_lock_irqsave+0x2c/0x78
softirqs last enabled at (16880): [<ffff0000080e0f00>] __do_softirq+0x580/0x640
softirqs last disabled at (16871): [<ffff0000080e13a4>] 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:
[<ffff000008089ee0>] dump_backtrace+0x0/0x230
[<ffff00000808a134>] show_stack+0x24/0x30
[<ffff0000084e1944>] dump_stack+0xac/0xe8
[<ffff00000810d7e0>] ___might_sleep+0x150/0x230
[<ffff00000810d918>] __might_sleep+0x58/0x90
[<ffff0000089dde18>] __mutex_lock+0x50/0x870
[<ffff0000089de674>] mutex_lock_nested+0x3c/0x50
[<ffff000008388ae0>] kernfs_remove+0x30/0x50
[<ffff00000838b720>] sysfs_remove_dir+0x58/0x70
[<ffff0000084e393c>] kobject_del+0x1c/0x58
[<ffff0000084e374c>] kobject_put+0xb4/0x208
[<ffff00000882c364>] of_node_put+0x24/0x30
[<ffff000008829018>] of_find_node_with_property+0x78/0xe0
[<ffff000000aff5f4>] qcom_smsm_probe+0x194/0x720 [smsm]
[<ffff0000086793b4>] platform_drv_probe+0x74/0x110
[<ffff0000086765bc>] driver_probe_device+0x2b4/0x420
[<ffff000008676920>] __device_attach_driver+0xd0/0x150
[<ffff000008673e78>] bus_for_each_drv+0x68/0xa8
[<ffff00000867611c>] __device_attach+0xd4/0x168
[<ffff000008676a1c>] device_initial_probe+0x24/0x30
[<ffff000008675380>] bus_probe_device+0xa0/0xa8
[<ffff000008675948>] deferred_probe_work_func+0xb8/0xf8
[<ffff0000080fa9d4>] process_one_work+0x25c/0x728
[<ffff0000080faef4>] worker_thread+0x54/0x3d8
[<ffff0000081031d8>] kthread+0x110/0x140
[<ffff000008082d90>] 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 <robdclark@gmail.com>
---
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 <robdclark@gmail.com>
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: <stable@vger.kernel.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
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 <robdclark@gmail.com>
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 <robdclark@gmail.com>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
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 <pbrobinson@gmail.com>
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 <robdclark@gmail.com>
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
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