Commit 8421c604 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v4.10-2' of...

Merge tag 'platform-drivers-x86-v4.10-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86

Pull more x86 platform driver updates from Darren Hart:
 "Move and add registration for the mlx-platform driver. Introduce
  button and lid drivers for the surface3 (different from the
  surface3-pro). Add BXT PMIC TMU support. Add Y700 to existing
  ideapad-laptop quirk.

  Summary:

  ideapad-laptop:
   - Add Y700 15-ACZ to no_hw_rfkill DMI list

  surface3_button:
   - Introduce button support for the Surface 3

  surface3-wmi:
   - Add custom surface3 platform device for controlling LID
   - Balance locking on error path

  mlx-platform:
   - Add mlxcpld-hotplug driver registration
   - Fix semicolon.cocci warnings
   - Move module from arch/x86

  platform/x86:
   - Add Whiskey Cove PMIC TMU support"

* tag 'platform-drivers-x86-v4.10-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86:
  platform/x86: surface3-wmi: Balance locking on error path
  platform/x86: Add Whiskey Cove PMIC TMU support
  platform/x86: ideapad-laptop: Add Y700 15-ACZ to no_hw_rfkill DMI list
  platform/x86: Introduce button support for the Surface 3
  platform/x86: Add custom surface3 platform device for controlling LID
  platform/x86: mlx-platform: Add mlxcpld-hotplug driver registration
  platform/x86: mlx-platform: Fix semicolon.cocci warnings
  platform/x86: mlx-platform: Move module from arch/x86
parents f7dd3b17 83da6b59
...@@ -8070,7 +8070,7 @@ MELLANOX PLATFORM DRIVER ...@@ -8070,7 +8070,7 @@ MELLANOX PLATFORM DRIVER
M: Vadim Pasternak <vadimp@mellanox.com> M: Vadim Pasternak <vadimp@mellanox.com>
L: platform-driver-x86@vger.kernel.org L: platform-driver-x86@vger.kernel.org
S: Supported S: Supported
F: arch/x86/platform/mellanox/mlx-platform.c F: drivers/platform/x86/mlx-platform.c
MELLANOX MLX CPLD HOTPLUG DRIVER MELLANOX MLX CPLD HOTPLUG DRIVER
M: Vadim Pasternak <vadimp@mellanox.com> M: Vadim Pasternak <vadimp@mellanox.com>
......
...@@ -555,18 +555,6 @@ config X86_INTEL_QUARK ...@@ -555,18 +555,6 @@ config X86_INTEL_QUARK
Say Y here if you have a Quark based system such as the Arduino Say Y here if you have a Quark based system such as the Arduino
compatible Intel Galileo. compatible Intel Galileo.
config MLX_PLATFORM
tristate "Mellanox Technologies platform support"
depends on X86_64
depends on X86_EXTENDED_PLATFORM
---help---
This option enables system support for the Mellanox Technologies
platform.
Say Y here if you are building a kernel for Mellanox system.
Otherwise, say N.
config X86_INTEL_LPSS config X86_INTEL_LPSS
bool "Intel Low Power Subsystem Support" bool "Intel Low Power Subsystem Support"
depends on X86 && ACPI depends on X86 && ACPI
......
...@@ -8,7 +8,6 @@ obj-y += iris/ ...@@ -8,7 +8,6 @@ obj-y += iris/
obj-y += intel/ obj-y += intel/
obj-y += intel-mid/ obj-y += intel-mid/
obj-y += intel-quark/ obj-y += intel-quark/
obj-y += mellanox/
obj-y += olpc/ obj-y += olpc/
obj-y += scx200/ obj-y += scx200/
obj-y += sfi/ obj-y += sfi/
......
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#define BXTWC_GPIOIRQ0 0x4E0B #define BXTWC_GPIOIRQ0 0x4E0B
#define BXTWC_GPIOIRQ1 0x4E0C #define BXTWC_GPIOIRQ1 0x4E0C
#define BXTWC_CRITIRQ 0x4E0D #define BXTWC_CRITIRQ 0x4E0D
#define BXTWC_TMUIRQ 0x4FB6
/* Interrupt MASK Registers */ /* Interrupt MASK Registers */
#define BXTWC_MIRQLVL1 0x4E0E #define BXTWC_MIRQLVL1 0x4E0E
...@@ -59,6 +60,7 @@ ...@@ -59,6 +60,7 @@
#define BXTWC_MGPIO0IRQ 0x4E19 #define BXTWC_MGPIO0IRQ 0x4E19
#define BXTWC_MGPIO1IRQ 0x4E1A #define BXTWC_MGPIO1IRQ 0x4E1A
#define BXTWC_MCRITIRQ 0x4E1B #define BXTWC_MCRITIRQ 0x4E1B
#define BXTWC_MTMUIRQ 0x4FB7
/* Whiskey Cove PMIC share same ACPI ID between different platforms */ /* Whiskey Cove PMIC share same ACPI ID between different platforms */
#define BROXTON_PMIC_WC_HRV 4 #define BROXTON_PMIC_WC_HRV 4
...@@ -92,6 +94,7 @@ enum bxtwc_irqs_level2 { ...@@ -92,6 +94,7 @@ enum bxtwc_irqs_level2 {
BXTWC_GPIO0_IRQ, BXTWC_GPIO0_IRQ,
BXTWC_GPIO1_IRQ, BXTWC_GPIO1_IRQ,
BXTWC_CRIT_IRQ, BXTWC_CRIT_IRQ,
BXTWC_TMU_IRQ,
}; };
static const struct regmap_irq bxtwc_regmap_irqs[] = { static const struct regmap_irq bxtwc_regmap_irqs[] = {
...@@ -120,6 +123,10 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = { ...@@ -120,6 +123,10 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03), REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03),
}; };
static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = {
REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06),
};
static struct regmap_irq_chip bxtwc_regmap_irq_chip = { static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
.name = "bxtwc_irq_chip", .name = "bxtwc_irq_chip",
.status_base = BXTWC_IRQLVL1, .status_base = BXTWC_IRQLVL1,
...@@ -138,6 +145,15 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = { ...@@ -138,6 +145,15 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = {
.num_regs = 10, .num_regs = 10,
}; };
static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
.name = "bxtwc_irq_chip_tmu",
.status_base = BXTWC_TMUIRQ,
.mask_base = BXTWC_MTMUIRQ,
.irqs = bxtwc_regmap_irqs_tmu,
.num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu),
.num_regs = 1,
};
static struct resource gpio_resources[] = { static struct resource gpio_resources[] = {
DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"), DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"),
DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"), DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"),
...@@ -166,6 +182,10 @@ static struct resource bcu_resources[] = { ...@@ -166,6 +182,10 @@ static struct resource bcu_resources[] = {
DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"), DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"),
}; };
static struct resource tmu_resources[] = {
DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"),
};
static struct mfd_cell bxt_wc_dev[] = { static struct mfd_cell bxt_wc_dev[] = {
{ {
.name = "bxt_wcove_gpadc", .name = "bxt_wcove_gpadc",
...@@ -192,6 +212,12 @@ static struct mfd_cell bxt_wc_dev[] = { ...@@ -192,6 +212,12 @@ static struct mfd_cell bxt_wc_dev[] = {
.num_resources = ARRAY_SIZE(bcu_resources), .num_resources = ARRAY_SIZE(bcu_resources),
.resources = bcu_resources, .resources = bcu_resources,
}, },
{
.name = "bxt_wcove_tmu",
.num_resources = ARRAY_SIZE(tmu_resources),
.resources = tmu_resources,
},
{ {
.name = "bxt_wcove_gpio", .name = "bxt_wcove_gpio",
.num_resources = ARRAY_SIZE(gpio_resources), .num_resources = ARRAY_SIZE(gpio_resources),
...@@ -402,6 +428,15 @@ static int bxtwc_probe(struct platform_device *pdev) ...@@ -402,6 +428,15 @@ static int bxtwc_probe(struct platform_device *pdev)
goto err_irq_chip_level2; goto err_irq_chip_level2;
} }
ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
IRQF_ONESHOT | IRQF_SHARED,
0, &bxtwc_regmap_irq_chip_tmu,
&pmic->irq_chip_data_tmu);
if (ret) {
dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n");
goto err_irq_chip_tmu;
}
ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
ARRAY_SIZE(bxt_wc_dev), NULL, 0, ARRAY_SIZE(bxt_wc_dev), NULL, 0,
NULL); NULL);
...@@ -431,6 +466,8 @@ static int bxtwc_probe(struct platform_device *pdev) ...@@ -431,6 +466,8 @@ static int bxtwc_probe(struct platform_device *pdev)
err_sysfs: err_sysfs:
mfd_remove_devices(&pdev->dev); mfd_remove_devices(&pdev->dev);
err_mfd: err_mfd:
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
err_irq_chip_tmu:
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
err_irq_chip_level2: err_irq_chip_level2:
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
...@@ -446,6 +483,7 @@ static int bxtwc_remove(struct platform_device *pdev) ...@@ -446,6 +483,7 @@ static int bxtwc_remove(struct platform_device *pdev)
mfd_remove_devices(&pdev->dev); mfd_remove_devices(&pdev->dev);
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
return 0; return 0;
} }
......
...@@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP ...@@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP
This is a driver for Lenovo IdeaPad netbooks contains drivers for This is a driver for Lenovo IdeaPad netbooks contains drivers for
rfkill switch, hotkey, fan control and backlight control. rfkill switch, hotkey, fan control and backlight control.
config SURFACE3_WMI
tristate "Surface 3 WMI Driver"
depends on ACPI_WMI
depends on DMI
depends on INPUT
depends on SPI
---help---
Say Y here if you have a Surface 3.
To compile this driver as a module, choose M here: the module will
be called surface3-wmi.
config THINKPAD_ACPI config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras" tristate "ThinkPad ACPI Laptop Extras"
depends on ACPI depends on ACPI
...@@ -1005,12 +1017,27 @@ config INTEL_PMC_IPC ...@@ -1005,12 +1017,27 @@ config INTEL_PMC_IPC
The PMC is an ARC processor which defines IPC commands for communication The PMC is an ARC processor which defines IPC commands for communication
with other entities in the CPU. with other entities in the CPU.
config INTEL_BXTWC_PMIC_TMU
tristate "Intel BXT Whiskey Cove TMU Driver"
depends on REGMAP
depends on INTEL_SOC_PMIC && INTEL_PMC_IPC
---help---
Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature.
This driver enables the alarm wakeup functionality in the TMU unit
of Whiskey Cove PMIC.
config SURFACE_PRO3_BUTTON config SURFACE_PRO3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet" tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
depends on ACPI && INPUT depends on ACPI && INPUT
---help--- ---help---
This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet. This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
config SURFACE_3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet"
depends on ACPI && KEYBOARD_GPIO
---help---
This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
config INTEL_PUNIT_IPC config INTEL_PUNIT_IPC
tristate "Intel P-Unit IPC Driver" tristate "Intel P-Unit IPC Driver"
---help--- ---help---
...@@ -1028,10 +1055,21 @@ config INTEL_TELEMETRY ...@@ -1028,10 +1055,21 @@ config INTEL_TELEMETRY
directly via debugfs files. Various tools may use directly via debugfs files. Various tools may use
this interface for SoC state monitoring. this interface for SoC state monitoring.
config MLX_PLATFORM
tristate "Mellanox Technologies platform support"
depends on X86_64
---help---
This option enables system support for the Mellanox Technologies
platform. The Mellanox systems provide data center networking
solutions based on Virtual Protocol Interconnect (VPI) technology
enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE
connection.
If you have a Mellanox system, say Y or M here.
config MLX_CPLD_PLATFORM config MLX_CPLD_PLATFORM
tristate "Mellanox platform hotplug driver support" tristate "Mellanox platform hotplug driver support"
default n default n
depends on MLX_PLATFORM
select HWMON select HWMON
select I2C select I2C
---help--- ---help---
......
...@@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o ...@@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_ACPI_WMI) += wmi.o
obj-$(CONFIG_MSI_WMI) += msi-wmi.o obj-$(CONFIG_MSI_WMI) += msi-wmi.o
obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
# toshiba_acpi must link after wmi to ensure that wmi devices are found # toshiba_acpi must link after wmi to ensure that wmi devices are found
...@@ -66,9 +67,12 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o ...@@ -66,9 +67,12 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o
obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
intel_telemetry_pltdrv.o \ intel_telemetry_pltdrv.o \
intel_telemetry_debugfs.o intel_telemetry_debugfs.o
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
...@@ -870,6 +870,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { ...@@ -870,6 +870,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"), DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
}, },
}, },
{
.ident = "Lenovo ideapad Y700-15ACZ",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
},
},
{ {
.ident = "Lenovo ideapad Y700-15ISK", .ident = "Lenovo ideapad Y700-15ISK",
.matches = { .matches = {
......
/*
* intel_bxtwc_tmu.c - Intel BXT Whiskey Cove PMIC TMU driver
*
* Copyright (C) 2016 Intel Corporation. All rights reserved.
*
* This driver adds TMU (Time Management Unit) support for Intel BXT platform.
* It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove
* PMIC.
*
* 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/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mfd/intel_soc_pmic.h>
#define BXTWC_TMUIRQ 0x4fb6
#define BXTWC_MIRQLVL1 0x4e0e
#define BXTWC_MTMUIRQ_REG 0x4fb7
#define BXTWC_MIRQLVL1_MTMU BIT(1)
#define BXTWC_TMU_WK_ALRM BIT(1)
#define BXTWC_TMU_SYS_ALRM BIT(2)
#define BXTWC_TMU_ALRM_MASK (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
#define BXTWC_TMU_ALRM_IRQ (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
struct wcove_tmu {
int irq;
struct device *dev;
struct regmap *regmap;
};
static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data)
{
struct wcove_tmu *wctmu = data;
unsigned int tmu_irq;
/* Read TMU interrupt reg */
regmap_read(wctmu->regmap, BXTWC_TMUIRQ, &tmu_irq);
if (tmu_irq & BXTWC_TMU_ALRM_IRQ) {
/* clear TMU irq */
regmap_write(wctmu->regmap, BXTWC_TMUIRQ, tmu_irq);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int bxt_wcove_tmu_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
struct regmap_irq_chip_data *regmap_irq_chip;
struct wcove_tmu *wctmu;
int ret, virq, irq;
wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL);
if (!wctmu)
return -ENOMEM;
wctmu->dev = &pdev->dev;
wctmu->regmap = pmic->regmap;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "invalid irq %d\n", irq);
return irq;
}
regmap_irq_chip = pmic->irq_chip_data_tmu;
virq = regmap_irq_get_virq(regmap_irq_chip, irq);
if (virq < 0) {
dev_err(&pdev->dev,
"failed to get virtual interrupt=%d\n", irq);
return virq;
}
ret = devm_request_threaded_irq(&pdev->dev, virq,
NULL, bxt_wcove_tmu_irq_handler,
IRQF_ONESHOT, "bxt_wcove_tmu", wctmu);
if (ret) {
dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n",
ret, virq);
return ret;
}
wctmu->irq = virq;
/* Enable TMU interrupts */
regmap_update_bits(wctmu->regmap, BXTWC_MIRQLVL1,
BXTWC_MIRQLVL1_MTMU, 0);
/* Unmask TMU second level Wake & System alarm */
regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG,
BXTWC_TMU_ALRM_MASK, 0);
platform_set_drvdata(pdev, wctmu);
return 0;
}
static int bxt_wcove_tmu_remove(struct platform_device *pdev)
{
struct wcove_tmu *wctmu = platform_get_drvdata(pdev);
unsigned int val;
/* Mask TMU interrupts */
regmap_read(wctmu->regmap, BXTWC_MIRQLVL1, &val);
regmap_write(wctmu->regmap, BXTWC_MIRQLVL1,
val | BXTWC_MIRQLVL1_MTMU);
regmap_read(wctmu->regmap, BXTWC_MTMUIRQ_REG, &val);
regmap_write(wctmu->regmap, BXTWC_MTMUIRQ_REG,
val | BXTWC_TMU_ALRM_MASK);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int bxtwc_tmu_suspend(struct device *dev)
{
struct wcove_tmu *wctmu = dev_get_drvdata(dev);
enable_irq_wake(wctmu->irq);
return 0;
}
static int bxtwc_tmu_resume(struct device *dev)
{
struct wcove_tmu *wctmu = dev_get_drvdata(dev);
disable_irq_wake(wctmu->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume);
static const struct platform_device_id bxt_wcove_tmu_id_table[] = {
{ .name = "bxt_wcove_tmu" },
{},
};
MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table);
static struct platform_driver bxt_wcove_tmu_driver = {
.probe = bxt_wcove_tmu_probe,
.remove = bxt_wcove_tmu_remove,
.driver = {
.name = "bxt_wcove_tmu",
.pm = &bxtwc_tmu_pm_ops,
},
.id_table = bxt_wcove_tmu_id_table,
};
module_platform_driver(bxt_wcove_tmu_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Nilesh Bacchewar <nilesh.bacchewar@intel.com>");
MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver");
/* /*
* arch/x86/platform/mellanox/mlx-platform.c
* Copyright (c) 2016 Mellanox Technologies. All rights reserved. * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com> * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
* *
...@@ -39,6 +38,7 @@ ...@@ -39,6 +38,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/i2c-mux-reg.h> #include <linux/platform_data/i2c-mux-reg.h>
#include <linux/platform_data/mlxcpld-hotplug.h>
#define MLX_PLAT_DEVICE_NAME "mlxplat" #define MLX_PLAT_DEVICE_NAME "mlxplat"
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
struct mlxplat_priv { struct mlxplat_priv {
struct platform_device *pdev_i2c; struct platform_device *pdev_i2c;
struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
struct platform_device *pdev_hotplug;
}; };
/* Regions for LPC I2C controller and LPC base register space */ /* Regions for LPC I2C controller and LPC base register space */
...@@ -121,7 +122,87 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { ...@@ -121,7 +122,87 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
}; };
static struct platform_device *mlxplat_dev; /* Platform hotplug devices */
static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = {
{
.brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
.bus = 10,
},
{
.brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
.bus = 10,
},
};
static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = {
{
.brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
.bus = 10,
},
{
.brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
.bus = 10,
},
};
static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = {
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
.bus = 11,
},
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
.bus = 12,
},
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
.bus = 13,
},
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
.bus = 14,
},
};
/* Platform hotplug default data */
static
struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = {
.top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
.top_aggr_mask = 0x48,
.top_aggr_psu_mask = 0x08,
.psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58),
.psu_mask = 0x03,
.psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu),
.psu = mlxplat_mlxcpld_hotplug_psu,
.top_aggr_pwr_mask = 0x08,
.pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
.pwr_mask = 0x03,
.pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
.pwr = mlxplat_mlxcpld_hotplug_pwr,
.top_aggr_fan_mask = 0x40,
.fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88),
.fan_mask = 0x0f,
.fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan),
.fan = mlxplat_mlxcpld_hotplug_fan,
};
/* Platform hotplug MSN21xx system family data */
static
struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = {
.top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
.top_aggr_mask = 0x04,
.top_aggr_pwr_mask = 0x04,
.pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
.pwr_mask = 0x03,
.pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
};
static struct resource mlxplat_mlxcpld_hotplug_resources[] = {
[0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
};
struct platform_device *mlxplat_dev;
struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{ {
...@@ -132,6 +213,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) ...@@ -132,6 +213,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
mlxplat_mux_data[i].n_values = mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_default_channels[i]); ARRAY_SIZE(mlxplat_default_channels[i]);
} }
mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data;
return 1; return 1;
}; };
...@@ -145,6 +227,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) ...@@ -145,6 +227,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
mlxplat_mux_data[i].n_values = mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels); ARRAY_SIZE(mlxplat_msn21xx_channels);
} }
mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data;
return 1; return 1;
}; };
...@@ -216,7 +299,7 @@ static int __init mlxplat_init(void) ...@@ -216,7 +299,7 @@ static int __init mlxplat_init(void)
if (IS_ERR(priv->pdev_i2c)) { if (IS_ERR(priv->pdev_i2c)) {
err = PTR_ERR(priv->pdev_i2c); err = PTR_ERR(priv->pdev_i2c);
goto fail_alloc; goto fail_alloc;
}; }
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
priv->pdev_mux[i] = platform_device_register_resndata( priv->pdev_mux[i] = platform_device_register_resndata(
...@@ -230,6 +313,16 @@ static int __init mlxplat_init(void) ...@@ -230,6 +313,16 @@ static int __init mlxplat_init(void)
} }
} }
priv->pdev_hotplug = platform_device_register_resndata(
&mlxplat_dev->dev, "mlxcpld-hotplug", -1,
mlxplat_mlxcpld_hotplug_resources,
ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources),
mlxplat_hotplug, sizeof(*mlxplat_hotplug));
if (IS_ERR(priv->pdev_hotplug)) {
err = PTR_ERR(priv->pdev_hotplug);
goto fail_platform_mux_register;
}
return 0; return 0;
fail_platform_mux_register: fail_platform_mux_register:
...@@ -248,6 +341,8 @@ static void __exit mlxplat_exit(void) ...@@ -248,6 +341,8 @@ static void __exit mlxplat_exit(void)
struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
int i; int i;
platform_device_unregister(priv->pdev_hotplug);
for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
platform_device_unregister(priv->pdev_mux[i]); platform_device_unregister(priv->pdev_mux[i]);
......
/*
* Driver for the LID cover switch of the Surface 3
*
* Copyright (c) 2016 Red Hat Inc.
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; version 2 of the License.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
MODULE_DESCRIPTION("Surface 3 platform driver");
MODULE_LICENSE("GPL");
#define ACPI_BUTTON_HID_LID "PNP0C0D"
#define SPI_CTL_OBJ_NAME "SPI"
#define SPI_TS_OBJ_NAME "NTRG"
#define SURFACE3_LID_GUID "F7CC25EC-D20B-404C-8903-0ED4359C18AE"
MODULE_ALIAS("wmi:" SURFACE3_LID_GUID);
static const struct dmi_system_id surface3_dmi_table[] = {
#if defined(CONFIG_X86)
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
},
},
#endif
{ }
};
struct surface3_wmi {
struct acpi_device *touchscreen_adev;
struct acpi_device *pnp0c0d_adev;
struct acpi_hotplug_context hp;
struct input_dev *input;
};
static struct platform_device *s3_wmi_pdev;
static struct surface3_wmi s3_wmi;
static DEFINE_MUTEX(s3_wmi_lock);
static int s3_wmi_query_block(const char *guid, int instance, int *ret)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status;
union acpi_object *obj;
int error = 0;
mutex_lock(&s3_wmi_lock);
status = wmi_query_block(guid, instance, &output);
obj = output.pointer;
if (!obj || obj->type != ACPI_TYPE_INTEGER) {
if (obj) {
pr_err("query block returned object type: %d - buffer length:%d\n",
obj->type,
obj->type == ACPI_TYPE_BUFFER ?
obj->buffer.length : 0);
}
error = -EINVAL;
goto out_free_unlock;
}
*ret = obj->integer.value;
out_free_unlock:
kfree(obj);
mutex_unlock(&s3_wmi_lock);
return error;
}
static inline int s3_wmi_query_lid(int *ret)
{
return s3_wmi_query_block(SURFACE3_LID_GUID, 0, ret);
}
static int s3_wmi_send_lid_state(void)
{
int ret, lid_sw;
ret = s3_wmi_query_lid(&lid_sw);
if (ret)
return ret;
input_report_switch(s3_wmi.input, SW_LID, lid_sw);
input_sync(s3_wmi.input);
return 0;
}
static int s3_wmi_hp_notify(struct acpi_device *adev, u32 value)
{
return s3_wmi_send_lid_state();
}
static acpi_status s3_wmi_attach_spi_device(acpi_handle handle,
u32 level,
void *data,
void **return_value)
{
struct acpi_device *adev, **ts_adev;
if (acpi_bus_get_device(handle, &adev))
return AE_OK;
ts_adev = data;
if (strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME,
strlen(SPI_TS_OBJ_NAME)))
return AE_OK;
if (*ts_adev) {
pr_err("duplicate entry %s\n", SPI_TS_OBJ_NAME);
return AE_OK;
}
*ts_adev = adev;
return AE_OK;
}
static int s3_wmi_check_platform_device(struct device *dev, void *data)
{
struct acpi_device *adev, *ts_adev;
acpi_handle handle;
acpi_status status;
/* ignore non ACPI devices */
handle = ACPI_HANDLE(dev);
if (!handle || acpi_bus_get_device(handle, &adev))
return 0;
/* check for LID ACPI switch */
if (!strcmp(ACPI_BUTTON_HID_LID, acpi_device_hid(adev))) {
s3_wmi.pnp0c0d_adev = adev;
return 0;
}
/* ignore non SPI controllers */
if (strncmp(acpi_device_bid(adev), SPI_CTL_OBJ_NAME,
strlen(SPI_CTL_OBJ_NAME)))
return 0;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
s3_wmi_attach_spi_device, NULL,
&ts_adev, NULL);
if (ACPI_FAILURE(status))
dev_warn(dev, "failed to enumerate SPI slaves\n");
if (!ts_adev)
return 0;
s3_wmi.touchscreen_adev = ts_adev;
return 0;
}
static int s3_wmi_create_and_register_input(struct platform_device *pdev)
{
struct input_dev *input;
int error;
input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
input->name = "Lid Switch";
input->phys = "button/input0";
input->id.bustype = BUS_HOST;
input->id.product = 0x0005;
input_set_capability(input, EV_SW, SW_LID);
error = input_register_device(input);
if (error)
goto out_err;
s3_wmi.input = input;
return 0;
out_err:
input_free_device(s3_wmi.input);
return error;
}
static int __init s3_wmi_probe(struct platform_device *pdev)
{
int error;
if (!dmi_check_system(surface3_dmi_table))
return -ENODEV;
memset(&s3_wmi, 0, sizeof(s3_wmi));
bus_for_each_dev(&platform_bus_type, NULL, NULL,
s3_wmi_check_platform_device);
if (!s3_wmi.touchscreen_adev)
return -ENODEV;
acpi_bus_trim(s3_wmi.pnp0c0d_adev);
error = s3_wmi_create_and_register_input(pdev);
if (error)
goto restore_acpi_lid;
acpi_initialize_hp_context(s3_wmi.touchscreen_adev, &s3_wmi.hp,
s3_wmi_hp_notify, NULL);
s3_wmi_send_lid_state();
return 0;
restore_acpi_lid:
acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
return error;
}
static int s3_wmi_remove(struct platform_device *device)
{
/* remove the hotplug context from the acpi device */
s3_wmi.touchscreen_adev->hp = NULL;
/* reinstall the actual PNPC0C0D LID default handle */
acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
return 0;
}
#ifdef CONFIG_PM
static int s3_wmi_resume(struct device *dev)
{
s3_wmi_send_lid_state();
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume);
static struct platform_driver s3_wmi_driver = {
.driver = {
.name = "surface3-wmi",
.pm = &s3_wmi_pm,
},
.remove = s3_wmi_remove,
};
static int __init s3_wmi_init(void)
{
int error;
s3_wmi_pdev = platform_device_alloc("surface3-wmi", -1);
if (!s3_wmi_pdev)
return -ENOMEM;
error = platform_device_add(s3_wmi_pdev);
if (error)
goto err_device_put;
error = platform_driver_probe(&s3_wmi_driver, s3_wmi_probe);
if (error)
goto err_device_del;
pr_info("Surface 3 WMI Extras loaded\n");
return 0;
err_device_del:
platform_device_del(s3_wmi_pdev);
err_device_put:
platform_device_put(s3_wmi_pdev);
return error;
}
static void __exit s3_wmi_exit(void)
{
platform_device_unregister(s3_wmi_pdev);
platform_driver_unregister(&s3_wmi_driver);
}
module_init(s3_wmi_init);
module_exit(s3_wmi_exit);
/*
* Supports for the button array on the Surface tablets.
*
* (C) Copyright 2016 Red Hat, Inc
*
* Based on soc_button_array.c:
*
* {C} Copyright 2014 Intel Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#define SURFACE_BUTTON_OBJ_NAME "TEV2"
#define MAX_NBUTTONS 4
/*
* Some of the buttons like volume up/down are auto repeat, while others
* are not. To support both, we register two platform devices, and put
* buttons into them based on whether the key should be auto repeat.
*/
#define BUTTON_TYPES 2
/*
* Power button, Home button, Volume buttons support is supposed to
* be covered by drivers/input/misc/soc_button_array.c, which is implemented
* according to "Windows ACPI Design Guide for SoC Platforms".
* However surface 3 seems not to obey the specs, instead it uses
* device TEV2(MSHW0028) for declaring the GPIOs. The gpios are also slightly
* different in which the Home button is active high.
* Compared to surfacepro3_button.c which also handles MSHW0028, the Surface 3
* is a reduce platform and thus uses GPIOs, not ACPI events.
* We choose an I2C driver here because we need to access the resources
* declared under the device node, while surfacepro3_button.c only needs
* the ACPI companion node.
*/
static const struct acpi_device_id surface3_acpi_match[] = {
{ "MSHW0028", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, surface3_acpi_match);
struct surface3_button_info {
const char *name;
int acpi_index;
unsigned int event_type;
unsigned int event_code;
bool autorepeat;
bool wakeup;
bool active_low;
};
struct surface3_button_data {
struct platform_device *children[BUTTON_TYPES];
};
/*
* Get the Nth GPIO number from the ACPI object.
*/
static int surface3_button_lookup_gpio(struct device *dev, int acpi_index)
{
struct gpio_desc *desc;
int gpio;
desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
if (IS_ERR(desc))
return PTR_ERR(desc);
gpio = desc_to_gpio(desc);
gpiod_put(desc);
return gpio;
}
static struct platform_device *
surface3_button_device_create(struct i2c_client *client,
const struct surface3_button_info *button_info,
bool autorepeat)
{
const struct surface3_button_info *info;
struct platform_device *pd;
struct gpio_keys_button *gpio_keys;
struct gpio_keys_platform_data *gpio_keys_pdata;
int n_buttons = 0;
int gpio;
int error;
gpio_keys_pdata = devm_kzalloc(&client->dev,
sizeof(*gpio_keys_pdata) +
sizeof(*gpio_keys) * MAX_NBUTTONS,
GFP_KERNEL);
if (!gpio_keys_pdata)
return ERR_PTR(-ENOMEM);
gpio_keys = (void *)(gpio_keys_pdata + 1);
for (info = button_info; info->name; info++) {
if (info->autorepeat != autorepeat)
continue;
gpio = surface3_button_lookup_gpio(&client->dev,
info->acpi_index);
if (!gpio_is_valid(gpio))
continue;
gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code;
gpio_keys[n_buttons].gpio = gpio;
gpio_keys[n_buttons].active_low = info->active_low;
gpio_keys[n_buttons].desc = info->name;
gpio_keys[n_buttons].wakeup = info->wakeup;
n_buttons++;
}
if (n_buttons == 0) {
error = -ENODEV;
goto err_free_mem;
}
gpio_keys_pdata->buttons = gpio_keys;
gpio_keys_pdata->nbuttons = n_buttons;
gpio_keys_pdata->rep = autorepeat;
pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
if (!pd) {
error = -ENOMEM;
goto err_free_mem;
}
error = platform_device_add_data(pd, gpio_keys_pdata,
sizeof(*gpio_keys_pdata));
if (error)
goto err_free_pdev;
error = platform_device_add(pd);
if (error)
goto err_free_pdev;
return pd;
err_free_pdev:
platform_device_put(pd);
err_free_mem:
devm_kfree(&client->dev, gpio_keys_pdata);
return ERR_PTR(error);
}
static int surface3_button_remove(struct i2c_client *client)
{
struct surface3_button_data *priv = i2c_get_clientdata(client);
int i;
for (i = 0; i < BUTTON_TYPES; i++)
if (priv->children[i])
platform_device_unregister(priv->children[i]);
return 0;
}
static struct surface3_button_info surface3_button_surface3[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true, true },
{ "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
{ }
};
static int surface3_button_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct surface3_button_data *priv;
struct platform_device *pd;
int i;
int error;
if (strncmp(acpi_device_bid(ACPI_COMPANION(&client->dev)),
SURFACE_BUTTON_OBJ_NAME,
strlen(SURFACE_BUTTON_OBJ_NAME)))
return -ENODEV;
if (gpiod_count(dev, KBUILD_MODNAME) <= 0) {
dev_dbg(dev, "no GPIO attached, ignoring...\n");
return -ENODEV;
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
i2c_set_clientdata(client, priv);
for (i = 0; i < BUTTON_TYPES; i++) {
pd = surface3_button_device_create(client,
surface3_button_surface3,
i == 0);
if (IS_ERR(pd)) {
error = PTR_ERR(pd);
if (error != -ENODEV) {
surface3_button_remove(client);
return error;
}
continue;
}
priv->children[i] = pd;
}
if (!priv->children[0] && !priv->children[1])
return -ENODEV;
return 0;
}
static const struct i2c_device_id surface3_id[] = {
{ }
};
MODULE_DEVICE_TABLE(i2c, surface3_id);
static struct i2c_driver surface3_driver = {
.probe = surface3_button_probe,
.remove = surface3_button_remove,
.id_table = surface3_id,
.driver = {
.name = "surface3",
.acpi_match_table = ACPI_PTR(surface3_acpi_match),
},
};
module_i2c_driver(surface3_driver);
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_DESCRIPTION("surface3 button array driver");
MODULE_LICENSE("GPL v2");
...@@ -26,6 +26,7 @@ struct intel_soc_pmic { ...@@ -26,6 +26,7 @@ struct intel_soc_pmic {
struct regmap *regmap; struct regmap *regmap;
struct regmap_irq_chip_data *irq_chip_data; struct regmap_irq_chip_data *irq_chip_data;
struct regmap_irq_chip_data *irq_chip_data_level2; struct regmap_irq_chip_data *irq_chip_data_level2;
struct regmap_irq_chip_data *irq_chip_data_tmu;
struct device *dev; struct device *dev;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment