aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/Kconfig19
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/intel_int0002_vgpio.c219
3 files changed, 239 insertions, 0 deletions
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
794 This driver instantiates i2c-clients for these, so that standard 794 This driver instantiates i2c-clients for these, so that standard
795 i2c drivers for these chips can bind to the them. 795 i2c drivers for these chips can bind to the them.
796 796
797config INTEL_INT0002_VGPIO
798 tristate "Intel ACPI INT0002 Virtual GPIO driver"
799 depends on GPIOLIB && ACPI
800 select GPIOLIB_IRQCHIP
801 ---help---
802 Some peripherals on Bay Trail and Cherry Trail platforms signal a
803 Power Management Event (PME) to the Power Management Controller (PMC)
804 to wakeup the system. When this happens software needs to explicitly
805 clear the PME bus 0 status bit in the GPE0a_STS register to avoid an
806 IRQ storm on IRQ 9.
807
808 This is modelled in ACPI through the INT0002 ACPI device, which is
809 called a "Virtual GPIO controller" in ACPI because it defines the
810 event handler to call when the PME triggers through _AEI and _L02
811 methods as would be done for a real GPIO interrupt in ACPI.
812
813 To compile this driver as a module, choose M here: the module will
814 be called intel_int0002_vgpio.
815
797config INTEL_HID_EVENT 816config INTEL_HID_EVENT
798 tristate "INTEL HID Event" 817 tristate "INTEL HID Event"
799 depends on ACPI 818 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
46obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o 46obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o
47obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o 47obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
48obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o 48obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o
49obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o
49obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o 50obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o
50obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o 51obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o
51obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 52obj-$(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 @@
1/*
2 * Intel INT0002 "Virtual GPIO" driver
3 *
4 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
5 *
6 * Loosely based on android x86 kernel code which is:
7 *
8 * Copyright (c) 2014, Intel Corporation.
9 *
10 * Author: Dyut Kumar Sil <dyut.k.sil@intel.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * Some peripherals on Bay Trail and Cherry Trail platforms signal a Power
17 * Management Event (PME) to the Power Management Controller (PMC) to wakeup
18 * the system. When this happens software needs to clear the PME bus 0 status
19 * bit in the GPE0a_STS register to avoid an IRQ storm on IRQ 9.
20 *
21 * This is modelled in ACPI through the INT0002 ACPI device, which is
22 * called a "Virtual GPIO controller" in ACPI because it defines the event
23 * handler to call when the PME triggers through _AEI and _L02 / _E02
24 * methods as would be done for a real GPIO interrupt in ACPI. Note this
25 * is a hack to define an AML event handler for the PME while using existing
26 * ACPI mechanisms, this is not a real GPIO at all.
27 *
28 * This driver will bind to the INT0002 device, and register as a GPIO
29 * controller, letting gpiolib-acpi.c call the _L02 handler as it would
30 * for a real GPIO controller.
31 */
32
33#include <linux/acpi.h>
34#include <linux/bitmap.h>
35#include <linux/gpio/driver.h>
36#include <linux/interrupt.h>
37#include <linux/io.h>
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/platform_device.h>
41#include <linux/slab.h>
42#include <linux/suspend.h>
43
44#include <asm/cpu_device_id.h>
45#include <asm/intel-family.h>
46
47#define DRV_NAME "INT0002 Virtual GPIO"
48
49/* For some reason the virtual GPIO pin tied to the GPE is numbered pin 2 */
50#define GPE0A_PME_B0_VIRT_GPIO_PIN 2
51
52#define GPE0A_PME_B0_STS_BIT BIT(13)
53#define GPE0A_PME_B0_EN_BIT BIT(13)
54#define GPE0A_STS_PORT 0x420
55#define GPE0A_EN_PORT 0x428
56
57#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
58
59static const struct x86_cpu_id int0002_cpu_ids[] = {
60/*
61 * Limit ourselves to Cherry Trail for now, until testing shows we
62 * need to handle the INT0002 device on Baytrail too.
63 * ICPU(INTEL_FAM6_ATOM_SILVERMONT1), * Valleyview, Bay Trail *
64 */
65 ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */
66 {}
67};
68
69/*
70 * As this is not a real GPIO at all, but just a hack to model an event in
71 * ACPI the get / set functions are dummy functions.
72 */
73
74static int int0002_gpio_get(struct gpio_chip *chip, unsigned int offset)
75{
76 return 0;
77}
78
79static void int0002_gpio_set(struct gpio_chip *chip, unsigned int offset,
80 int value)
81{
82}
83
84static int int0002_gpio_direction_output(struct gpio_chip *chip,
85 unsigned int offset, int value)
86{
87 return 0;
88}
89
90static void int0002_irq_ack(struct irq_data *data)
91{
92 outl(GPE0A_PME_B0_STS_BIT, GPE0A_STS_PORT);
93}
94
95static void int0002_irq_unmask(struct irq_data *data)
96{
97 u32 gpe_en_reg;
98
99 gpe_en_reg = inl(GPE0A_EN_PORT);
100 gpe_en_reg |= GPE0A_PME_B0_EN_BIT;
101 outl(gpe_en_reg, GPE0A_EN_PORT);
102}
103
104static void int0002_irq_mask(struct irq_data *data)
105{
106 u32 gpe_en_reg;
107
108 gpe_en_reg = inl(GPE0A_EN_PORT);
109 gpe_en_reg &= ~GPE0A_PME_B0_EN_BIT;
110 outl(gpe_en_reg, GPE0A_EN_PORT);
111}
112
113static irqreturn_t int0002_irq(int irq, void *data)
114{
115 struct gpio_chip *chip = data;
116 u32 gpe_sts_reg;
117
118 gpe_sts_reg = inl(GPE0A_STS_PORT);
119 if (!(gpe_sts_reg & GPE0A_PME_B0_STS_BIT))
120 return IRQ_NONE;
121
122 generic_handle_irq(irq_find_mapping(chip->irqdomain,
123 GPE0A_PME_B0_VIRT_GPIO_PIN));
124
125 pm_system_wakeup();
126
127 return IRQ_HANDLED;
128}
129
130static struct irq_chip int0002_irqchip = {
131 .name = DRV_NAME,
132 .irq_ack = int0002_irq_ack,
133 .irq_mask = int0002_irq_mask,
134 .irq_unmask = int0002_irq_unmask,
135};
136
137static int int0002_probe(struct platform_device *pdev)
138{
139 struct device *dev = &pdev->dev;
140 const struct x86_cpu_id *cpu_id;
141 struct gpio_chip *chip;
142 int irq, ret;
143
144 /* Menlow has a different INT0002 device? <sigh> */
145 cpu_id = x86_match_cpu(int0002_cpu_ids);
146 if (!cpu_id)
147 return -ENODEV;
148
149 irq = platform_get_irq(pdev, 0);
150 if (irq < 0) {
151 dev_err(dev, "Error getting IRQ: %d\n", irq);
152 return irq;
153 }
154
155 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
156 if (!chip)
157 return -ENOMEM;
158
159 chip->label = DRV_NAME;
160 chip->parent = dev;