Compare commits
10 Commits
master
...
rawhide/us
Author | SHA1 | Date |
---|---|---|
Bastien Nocera | 21b36d969b | |
Bastien Nocera | da075d68de | |
Bastien Nocera | 301ce22ee9 | |
Bastien Nocera | 4fb17af00d | |
Bastien Nocera | 47f491acca | |
Bastien Nocera | 983b6e8279 | |
Bastien Nocera | 6526ccbb68 | |
Bastien Nocera | d884e8fd12 | |
Bastien Nocera | 999484ba1d | |
Bastien Nocera | f0c45f08df |
|
@ -0,0 +1,187 @@
|
|||
From de1715d88a5e80cc14455db1cf758cdf970fff22 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Thu, 12 May 2016 15:47:27 +0200
|
||||
Subject: [PATCH 1/3] HID: input: rework HID_QUIRK_MULTI_INPUT
|
||||
|
||||
The purpose of HID_QUIRK_MULTI_INPUT is to have an input device per
|
||||
report id. This is useful when the HID device presents several HID
|
||||
collections of different device types.
|
||||
|
||||
The current implementation of hid-input creates one input node per id per
|
||||
type (input or output). This is problematic for the LEDs of a keyboard as
|
||||
they are often set through an output report. The current code creates
|
||||
one input node with all the keyboard keys, and one other with only the
|
||||
LEDs.
|
||||
|
||||
To solve this, we use a two-passes way:
|
||||
- first, we initialize all input nodes and associate one per report id
|
||||
- then, we register all the input nodes
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/hid/hid-input.c | 95 ++++++++++++++++++++++++++++---------------------
|
||||
include/linux/hid.h | 1 +
|
||||
2 files changed, 55 insertions(+), 41 deletions(-)
|
||||
|
||||
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
|
||||
index bcfaf32..bb2ec45 100644
|
||||
--- a/drivers/hid/hid-input.c
|
||||
+++ b/drivers/hid/hid-input.c
|
||||
@@ -1458,6 +1458,31 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid,
|
||||
kfree(hidinput);
|
||||
}
|
||||
|
||||
+static struct hid_input *hidinput_match(struct hid_report *report)
|
||||
+{
|
||||
+ struct hid_device *hid = report->device;
|
||||
+ struct hid_input *hidinput;
|
||||
+
|
||||
+ list_for_each_entry(hidinput, &hid->inputs, list) {
|
||||
+ if (hidinput->report &&
|
||||
+ hidinput->report->id == report->id)
|
||||
+ return hidinput;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static inline void hidinput_configure_usages(struct hid_input *hidinput,
|
||||
+ struct hid_report *report)
|
||||
+{
|
||||
+ int i, j;
|
||||
+
|
||||
+ for (i = 0; i < report->maxfield; i++)
|
||||
+ for (j = 0; j < report->field[i]->maxusage; j++)
|
||||
+ hidinput_configure_usage(hidinput, report->field[i],
|
||||
+ report->field[i]->usage + j);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Register the input device; print a message.
|
||||
* Configure the input layer interface
|
||||
@@ -1468,8 +1493,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
||||
{
|
||||
struct hid_driver *drv = hid->driver;
|
||||
struct hid_report *report;
|
||||
- struct hid_input *hidinput = NULL;
|
||||
- int i, j, k;
|
||||
+ struct hid_input *next, *hidinput = NULL;
|
||||
+ int i, k;
|
||||
|
||||
INIT_LIST_HEAD(&hid->inputs);
|
||||
INIT_WORK(&hid->led_work, hidinput_led_worker);
|
||||
@@ -1499,43 +1524,40 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
||||
if (!report->maxfield)
|
||||
continue;
|
||||
|
||||
+ /*
|
||||
+ * Find the previous hidinput report attached
|
||||
+ * to this report id.
|
||||
+ */
|
||||
+ if (hid->quirks & HID_QUIRK_MULTI_INPUT)
|
||||
+ hidinput = hidinput_match(report);
|
||||
+
|
||||
if (!hidinput) {
|
||||
hidinput = hidinput_allocate(hid);
|
||||
if (!hidinput)
|
||||
goto out_unwind;
|
||||
}
|
||||
|
||||
- for (i = 0; i < report->maxfield; i++)
|
||||
- for (j = 0; j < report->field[i]->maxusage; j++)
|
||||
- hidinput_configure_usage(hidinput, report->field[i],
|
||||
- report->field[i]->usage + j);
|
||||
-
|
||||
- if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
|
||||
- !hidinput_has_been_populated(hidinput))
|
||||
- continue;
|
||||
+ hidinput_configure_usages(hidinput, report);
|
||||
|
||||
- if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
|
||||
- /* This will leave hidinput NULL, so that it
|
||||
- * allocates another one if we have more inputs on
|
||||
- * the same interface. Some devices (e.g. Happ's
|
||||
- * UGCI) cram a lot of unrelated inputs into the
|
||||
- * same interface. */
|
||||
+ if (hid->quirks & HID_QUIRK_MULTI_INPUT)
|
||||
hidinput->report = report;
|
||||
- if (drv->input_configured &&
|
||||
- drv->input_configured(hid, hidinput))
|
||||
- goto out_cleanup;
|
||||
- if (input_register_device(hidinput->input))
|
||||
- goto out_cleanup;
|
||||
- hidinput = NULL;
|
||||
- }
|
||||
}
|
||||
}
|
||||
|
||||
- if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
|
||||
- !hidinput_has_been_populated(hidinput)) {
|
||||
- /* no need to register an input device not populated */
|
||||
- hidinput_cleanup_hidinput(hid, hidinput);
|
||||
- hidinput = NULL;
|
||||
+ list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
|
||||
+ if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
|
||||
+ !hidinput_has_been_populated(hidinput)) {
|
||||
+ /* no need to register an input device not populated */
|
||||
+ hidinput_cleanup_hidinput(hid, hidinput);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (drv->input_configured &&
|
||||
+ drv->input_configured(hid, hidinput))
|
||||
+ goto out_unwind;
|
||||
+ if (input_register_device(hidinput->input))
|
||||
+ goto out_unwind;
|
||||
+ hidinput->registered = true;
|
||||
}
|
||||
|
||||
if (list_empty(&hid->inputs)) {
|
||||
@@ -1543,20 +1565,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
||||
goto out_unwind;
|
||||
}
|
||||
|
||||
- if (hidinput) {
|
||||
- if (drv->input_configured &&
|
||||
- drv->input_configured(hid, hidinput))
|
||||
- goto out_cleanup;
|
||||
- if (input_register_device(hidinput->input))
|
||||
- goto out_cleanup;
|
||||
- }
|
||||
-
|
||||
return 0;
|
||||
|
||||
-out_cleanup:
|
||||
- list_del(&hidinput->list);
|
||||
- input_free_device(hidinput->input);
|
||||
- kfree(hidinput);
|
||||
out_unwind:
|
||||
/* unwind the ones we already registered */
|
||||
hidinput_disconnect(hid);
|
||||
@@ -1573,7 +1583,10 @@ void hidinput_disconnect(struct hid_device *hid)
|
||||
|
||||
list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
|
||||
list_del(&hidinput->list);
|
||||
- input_unregister_device(hidinput->input);
|
||||
+ if (hidinput->registered)
|
||||
+ input_unregister_device(hidinput->input);
|
||||
+ else
|
||||
+ input_free_device(hidinput->input);
|
||||
kfree(hidinput);
|
||||
}
|
||||
|
||||
diff --git a/include/linux/hid.h b/include/linux/hid.h
|
||||
index 75b66ec..8a5d697 100644
|
||||
--- a/include/linux/hid.h
|
||||
+++ b/include/linux/hid.h
|
||||
@@ -479,6 +479,7 @@ struct hid_input {
|
||||
struct list_head list;
|
||||
struct hid_report *report;
|
||||
struct input_dev *input;
|
||||
+ bool registered;
|
||||
};
|
||||
|
||||
enum hid_type {
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
From 4feacbc24eea0c5f36728017575cc0ad28d8758b Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Thu, 19 May 2016 09:24:06 -0700
|
||||
Subject: [PATCH] Input: add new driver for the Surface 3
|
||||
|
||||
This is a basic driver for the Surface 3. I am not so sure it will work
|
||||
with any firmwares as most values are encoded, but given that I only have
|
||||
access to my current device with its firmware and I don't have the
|
||||
datasheet, it should be OK for now.
|
||||
|
||||
The Surface Pen is not supported (if it is supposed to be). I'll work on
|
||||
this when I get one.
|
||||
|
||||
Tested-by: Bastien Nocera <hadess@hadess.net>
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
||||
---
|
||||
drivers/input/touchscreen/Kconfig | 13 ++
|
||||
drivers/input/touchscreen/Makefile | 1 +
|
||||
drivers/input/touchscreen/surface3_spi.c | 304 +++++++++++++++++++++++++++++++
|
||||
3 files changed, 318 insertions(+)
|
||||
create mode 100644 drivers/input/touchscreen/surface3_spi.c
|
||||
|
||||
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
|
||||
index 75443bb..c3880b9 100644
|
||||
--- a/drivers/input/touchscreen/Kconfig
|
||||
+++ b/drivers/input/touchscreen/Kconfig
|
||||
@@ -1085,6 +1085,19 @@ config TOUCHSCREEN_SUR40
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sur40.
|
||||
|
||||
+config TOUCHSCREEN_SURFACE3_SPI
|
||||
+ tristate "Ntrig/Microsoft Surface 3 SPI touchscreen"
|
||||
+ depends on SPI
|
||||
+ depends on GPIOLIB || COMPILE_TEST
|
||||
+ help
|
||||
+ Say Y here if you have the Ntrig/Microsoft SPI touchscreen
|
||||
+ controller chip as found on the Surface 3 in your system.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the
|
||||
+ module will be called surface3_spi.
|
||||
+
|
||||
config TOUCHSCREEN_SX8654
|
||||
tristate "Semtech SX8654 touchscreen"
|
||||
depends on I2C
|
||||
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
|
||||
index 4b518c7..75af04d 100644
|
||||
--- a/drivers/input/touchscreen/Makefile
|
||||
+++ b/drivers/input/touchscreen/Makefile
|
||||
@@ -66,6 +66,7 @@ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
|
||||
+obj-$(CONFIG_TOUCHSCREEN_SURFACE3_SPI) += surface3_spi.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
|
||||
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
|
||||
new file mode 100644
|
||||
index 0000000..e18e742
|
||||
--- /dev/null
|
||||
+++ b/drivers/input/touchscreen/surface3_spi.c
|
||||
@@ -0,0 +1,304 @@
|
||||
+/*
|
||||
+ * Driver for Ntrig/Microsoft Touchscreens over SPI
|
||||
+ *
|
||||
+ * 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/delay.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/input/mt.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+#include <linux/acpi.h>
|
||||
+
|
||||
+#include <asm/unaligned.h>
|
||||
+
|
||||
+#define SURFACE3_PACKET_SIZE 264
|
||||
+
|
||||
+struct surface3_ts_data {
|
||||
+ struct spi_device *spi;
|
||||
+ struct gpio_desc *gpiod_rst[2];
|
||||
+ struct input_dev *input_dev;
|
||||
+
|
||||
+ u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned;
|
||||
+};
|
||||
+
|
||||
+struct surface3_ts_data_finger {
|
||||
+ u8 status;
|
||||
+ __le16 tracking_id;
|
||||
+ __le16 x;
|
||||
+ __le16 cx;
|
||||
+ __le16 y;
|
||||
+ __le16 cy;
|
||||
+ __le16 width;
|
||||
+ __le16 height;
|
||||
+ u32 padding;
|
||||
+} __packed;
|
||||
+
|
||||
+static int surface3_spi_read(struct surface3_ts_data *ts_data)
|
||||
+{
|
||||
+ struct spi_device *spi = ts_data->spi;
|
||||
+
|
||||
+ memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf));
|
||||
+ return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf));
|
||||
+}
|
||||
+
|
||||
+static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
|
||||
+ struct surface3_ts_data_finger *finger)
|
||||
+{
|
||||
+ int st = finger->status & 0x01;
|
||||
+ int slot;
|
||||
+
|
||||
+ slot = input_mt_get_slot_by_key(ts_data->input_dev,
|
||||
+ get_unaligned_le16(&finger->tracking_id));
|
||||
+ if (slot < 0)
|
||||
+ return;
|
||||
+
|
||||
+ input_mt_slot(ts_data->input_dev, slot);
|
||||
+ input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st);
|
||||
+ if (st) {
|
||||
+ input_report_abs(ts_data->input_dev,
|
||||
+ ABS_MT_POSITION_X,
|
||||
+ get_unaligned_le16(&finger->x));
|
||||
+ input_report_abs(ts_data->input_dev,
|
||||
+ ABS_MT_POSITION_Y,
|
||||
+ get_unaligned_le16(&finger->y));
|
||||
+ input_report_abs(ts_data->input_dev,
|
||||
+ ABS_MT_WIDTH_MAJOR,
|
||||
+ get_unaligned_le16(&finger->width));
|
||||
+ input_report_abs(ts_data->input_dev,
|
||||
+ ABS_MT_WIDTH_MINOR,
|
||||
+ get_unaligned_le16(&finger->height));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void surface3_spi_process(struct surface3_ts_data *ts_data)
|
||||
+{
|
||||
+ const char header[] = {0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e,
|
||||
+ 0x01, 0xd2, 0x00, 0x80, 0x01, 0x03, 0x03};
|
||||
+ u8 *data = ts_data->rd_buf;
|
||||
+ u16 timestamp;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ if (memcmp(header, data, sizeof(header)))
|
||||
+ dev_err(&ts_data->spi->dev,
|
||||
+ "%s header error: %*ph, ignoring...\n",
|
||||
+ __func__, (int)sizeof(header), data);
|
||||
+
|
||||
+ timestamp = get_unaligned_le16(&data[15]);
|
||||
+
|
||||
+ for (i = 0; i < 13; i++) {
|
||||
+ struct surface3_ts_data_finger *finger;
|
||||
+
|
||||
+ finger = (struct surface3_ts_data_finger *)&data[17 +
|
||||
+ i * sizeof(struct surface3_ts_data_finger)];
|
||||
+
|
||||
+ /*
|
||||
+ * When bit 5 of status is 1, it marks the end of the report:
|
||||
+ * - touch present: 0xe7
|
||||
+ * - touch released: 0xe4
|
||||
+ * - nothing valuable: 0xff
|
||||
+ */
|
||||
+ if (finger->status & 0x10)
|
||||
+ break;
|
||||
+
|
||||
+ surface3_spi_report_touch(ts_data, finger);
|
||||
+ }
|
||||
+
|
||||
+ input_mt_sync_frame(ts_data->input_dev);
|
||||
+ input_sync(ts_data->input_dev);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct surface3_ts_data *data = dev_id;
|
||||
+
|
||||
+ if (surface3_spi_read(data))
|
||||
+ return IRQ_HANDLED;
|
||||
+
|
||||
+ dev_dbg(&data->spi->dev, "%s received -> %*ph\n",
|
||||
+ __func__, SURFACE3_PACKET_SIZE, data->rd_buf);
|
||||
+ surface3_spi_process(data);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static void surface3_spi_power(struct surface3_ts_data *data, bool on)
|
||||
+{
|
||||
+ gpiod_set_value(data->gpiod_rst[0], on);
|
||||
+ gpiod_set_value(data->gpiod_rst[1], on);
|
||||
+ /* let the device settle a little */
|
||||
+ msleep(20);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
|
||||
+ *
|
||||
+ * @ts: surface3_spi_ts_data pointer
|
||||
+ */
|
||||
+static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
|
||||
+{
|
||||
+ int error;
|
||||
+ struct device *dev;
|
||||
+ struct gpio_desc *gpiod;
|
||||
+ int i;
|
||||
+
|
||||
+ dev = &data->spi->dev;
|
||||
+
|
||||
+ /* Get the reset lines GPIO pin number */
|
||||
+ for (i = 0; i < 2; i++) {
|
||||
+ gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(gpiod)) {
|
||||
+ error = PTR_ERR(gpiod);
|
||||
+ if (error != -EPROBE_DEFER)
|
||||
+ dev_err(dev,
|
||||
+ "Failed to get power GPIO %d: %d\n",
|
||||
+ i,
|
||||
+ error);
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ data->gpiod_rst[i] = gpiod;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int surface3_spi_create_input(struct surface3_ts_data *data)
|
||||
+{
|
||||
+ struct input_dev *input;
|
||||
+ int error;
|
||||
+
|
||||
+ input = devm_input_allocate_device(&data->spi->dev);
|
||||
+ if (!input)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data->input_dev = input;
|
||||
+
|
||||
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0);
|
||||
+ input_abs_set_res(input, ABS_MT_POSITION_X, 40);
|
||||
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0);
|
||||
+ input_abs_set_res(input, ABS_MT_POSITION_Y, 48);
|
||||
+ input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0);
|
||||
+ input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0);
|
||||
+ input_mt_init_slots(input, 10, INPUT_MT_DIRECT);
|
||||
+
|
||||
+ input->name = "Surface3 SPI Capacitive TouchScreen";
|
||||
+ input->phys = "input/ts";
|
||||
+ input->id.bustype = BUS_SPI;
|
||||
+ input->id.vendor = 0x045e; /* Microsoft */
|
||||
+ input->id.product = 0x0000;
|
||||
+ input->id.version = 0x0000;
|
||||
+
|
||||
+ error = input_register_device(input);
|
||||
+ if (error) {
|
||||
+ dev_err(&data->spi->dev,
|
||||
+ "Failed to register input device: %d", error);
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int surface3_spi_probe(struct spi_device *spi)
|
||||
+{
|
||||
+ struct surface3_ts_data *data;
|
||||
+ int error;
|
||||
+
|
||||
+ /* Set up SPI*/
|
||||
+ spi->bits_per_word = 8;
|
||||
+ spi->mode = SPI_MODE_0;
|
||||
+ error = spi_setup(spi);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data->spi = spi;
|
||||
+ spi_set_drvdata(spi, data);
|
||||
+
|
||||
+ error = surface3_spi_get_gpio_config(data);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ surface3_spi_power(data, true);
|
||||
+ surface3_spi_power(data, false);
|
||||
+ surface3_spi_power(data, true);
|
||||
+
|
||||
+ error = surface3_spi_create_input(data);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ error = devm_request_threaded_irq(&spi->dev, spi->irq,
|
||||
+ NULL, surface3_spi_irq_handler,
|
||||
+ IRQF_ONESHOT,
|
||||
+ "Surface3-irq", data);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __maybe_unused surface3_spi_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct spi_device *spi = to_spi_device(dev);
|
||||
+ struct surface3_ts_data *data = spi_get_drvdata(spi);
|
||||
+
|
||||
+ disable_irq(data->spi->irq);
|
||||
+
|
||||
+ surface3_spi_power(data, false);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __maybe_unused surface3_spi_resume(struct device *dev)
|
||||
+{
|
||||
+ struct spi_device *spi = to_spi_device(dev);
|
||||
+ struct surface3_ts_data *data = spi_get_drvdata(spi);
|
||||
+
|
||||
+ surface3_spi_power(data, true);
|
||||
+
|
||||
+ enable_irq(data->spi->irq);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
|
||||
+ surface3_spi_suspend,
|
||||
+ surface3_spi_resume);
|
||||
+
|
||||
+#ifdef CONFIG_ACPI
|
||||
+static const struct acpi_device_id surface3_spi_acpi_match[] = {
|
||||
+ { "MSHW0037", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match);
|
||||
+#endif
|
||||
+
|
||||
+static struct spi_driver surface3_spi_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "Surface3-spi",
|
||||
+ .acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
|
||||
+ .pm = &surface3_spi_pm_ops,
|
||||
+ },
|
||||
+ .probe = surface3_spi_probe,
|
||||
+};
|
||||
+
|
||||
+module_spi_driver(surface3_spi_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
|
||||
+MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
From 7e990a7b8f8bd62a806c4804608d00640352841f Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Thu, 12 May 2016 11:21:13 +0200
|
||||
Subject: [PATCH 1/6] Input - soc_button_array: use gpio_is_valid()
|
||||
|
||||
gpio_keys will later use gpio_is_valid(). To match the actual
|
||||
behavior, we should use it here too.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/input/misc/soc_button_array.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
|
||||
index c14b827..bbd433c 100644
|
||||
--- a/drivers/input/misc/soc_button_array.c
|
||||
+++ b/drivers/input/misc/soc_button_array.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
+#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev,
|
||||
continue;
|
||||
|
||||
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
|
||||
- if (gpio < 0)
|
||||
+ if (!gpio_is_valid(gpio))
|
||||
continue;
|
||||
|
||||
gpio_keys[n_buttons].type = info->event_type;
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
From 427ee20610a7c252e99d08e08e70a4203c6059d0 Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Just <stephenjust@gmail.com>
|
||||
Date: Fri, 27 May 2016 16:28:09 -0700
|
||||
Subject: [PATCH] Input: surface3_spi - Prepare to add support for Surface Pen
|
||||
|
||||
Surface Pens can be supported by handling a second report type. Prepare
|
||||
for this change.
|
||||
|
||||
Signed-off-by: Stephen Just <stephenjust@gmail.com>
|
||||
Reviewed-and-tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
||||
---
|
||||
drivers/input/touchscreen/surface3_spi.c | 39 +++++++++++++++++++++-----------
|
||||
1 file changed, 26 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
|
||||
index e18e742..e6cea7e 100644
|
||||
--- a/drivers/input/touchscreen/surface3_spi.c
|
||||
+++ b/drivers/input/touchscreen/surface3_spi.c
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#define SURFACE3_PACKET_SIZE 264
|
||||
|
||||
+#define SURFACE3_REPORT_TOUCH 0xd2
|
||||
+
|
||||
struct surface3_ts_data {
|
||||
struct spi_device *spi;
|
||||
struct gpio_desc *gpiod_rst[2];
|
||||
@@ -83,19 +85,10 @@ static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
|
||||
}
|
||||
}
|
||||
|
||||
-static void surface3_spi_process(struct surface3_ts_data *ts_data)
|
||||
+static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
|
||||
{
|
||||
- const char header[] = {0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e,
|
||||
- 0x01, 0xd2, 0x00, 0x80, 0x01, 0x03, 0x03};
|
||||
- u8 *data = ts_data->rd_buf;
|
||||
u16 timestamp;
|
||||
unsigned int i;
|
||||
-
|
||||
- if (memcmp(header, data, sizeof(header)))
|
||||
- dev_err(&ts_data->spi->dev,
|
||||
- "%s header error: %*ph, ignoring...\n",
|
||||
- __func__, (int)sizeof(header), data);
|
||||
-
|
||||
timestamp = get_unaligned_le16(&data[15]);
|
||||
|
||||
for (i = 0; i < 13; i++) {
|
||||
@@ -120,6 +113,26 @@ static void surface3_spi_process(struct surface3_ts_data *ts_data)
|
||||
input_sync(ts_data->input_dev);
|
||||
}
|
||||
|
||||
+static void surface3_spi_process(struct surface3_ts_data *ts_data)
|
||||
+{
|
||||
+ const char header[] = {
|
||||
+ 0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01
|
||||
+ };
|
||||
+ u8 *data = ts_data->rd_buf;
|
||||
+
|
||||
+ if (memcmp(header, data, sizeof(header)))
|
||||
+ dev_err(&ts_data->spi->dev,
|
||||
+ "%s header error: %*ph, ignoring...\n",
|
||||
+ __func__, (int)sizeof(header), data);
|
||||
+
|
||||
+ if (data[9] == SURFACE3_REPORT_TOUCH)
|
||||
+ surface3_spi_process_touch(ts_data, data);
|
||||
+ else
|
||||
+ dev_err(&ts_data->spi->dev,
|
||||
+ "%s unknown packet type: %x, ignoring...\n",
|
||||
+ __func__, data[9]);
|
||||
+}
|
||||
+
|
||||
static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct surface3_ts_data *data = dev_id;
|
||||
@@ -175,7 +188,7 @@ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int surface3_spi_create_input(struct surface3_ts_data *data)
|
||||
+static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
|
||||
{
|
||||
struct input_dev *input;
|
||||
int error;
|
||||
@@ -198,7 +211,7 @@ static int surface3_spi_create_input(struct surface3_ts_data *data)
|
||||
input->phys = "input/ts";
|
||||
input->id.bustype = BUS_SPI;
|
||||
input->id.vendor = 0x045e; /* Microsoft */
|
||||
- input->id.product = 0x0000;
|
||||
+ input->id.product = 0x0001;
|
||||
input->id.version = 0x0000;
|
||||
|
||||
error = input_register_device(input);
|
||||
@@ -238,7 +251,7 @@ static int surface3_spi_probe(struct spi_device *spi)
|
||||
surface3_spi_power(data, false);
|
||||
surface3_spi_power(data, true);
|
||||
|
||||
- error = surface3_spi_create_input(data);
|
||||
+ error = surface3_spi_create_touch_input(data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
From 72fb4765ac9eea56a94282f29cdc70706f21494e Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Just <stephenjust@gmail.com>
|
||||
Date: Fri, 27 May 2016 16:29:39 -0700
|
||||
Subject: [PATCH] Input: surface3_spi - add surface pen support for Surface 3
|
||||
|
||||
This change creates a second input device which will handle input from
|
||||
a Surface Pen. The Surface Pen supplies a different packet header than
|
||||
touch events, so it is simple to handle one or the other.
|
||||
|
||||
This patch handles both the newer Surface Pen with one button, and the
|
||||
older variant with a second button to switch to Eraser mode.
|
||||
|
||||
Signed-off-by: Stephen Just <stephenjust@gmail.com>
|
||||
Reviewed-and-tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
||||
---
|
||||
drivers/input/touchscreen/surface3_spi.c | 114 ++++++++++++++++++++++++++++++-
|
||||
1 file changed, 112 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
|
||||
index e6cea7e..e12fb9b 100644
|
||||
--- a/drivers/input/touchscreen/surface3_spi.c
|
||||
+++ b/drivers/input/touchscreen/surface3_spi.c
|
||||
@@ -27,11 +27,14 @@
|
||||
#define SURFACE3_PACKET_SIZE 264
|
||||
|
||||
#define SURFACE3_REPORT_TOUCH 0xd2
|
||||
+#define SURFACE3_REPORT_PEN 0x16
|
||||
|
||||
struct surface3_ts_data {
|
||||
struct spi_device *spi;
|
||||
struct gpio_desc *gpiod_rst[2];
|
||||
struct input_dev *input_dev;
|
||||
+ struct input_dev *pen_input_dev;
|
||||
+ int pen_tool;
|
||||
|
||||
u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned;
|
||||
};
|
||||
@@ -48,6 +51,14 @@ struct surface3_ts_data_finger {
|
||||
u32 padding;
|
||||
} __packed;
|
||||
|
||||
+struct surface3_ts_data_pen {
|
||||
+ u8 status;
|
||||
+ __le16 x;
|
||||
+ __le16 y;
|
||||
+ __le16 pressure;
|
||||
+ u8 padding;
|
||||
+} __packed;
|
||||
+
|
||||
static int surface3_spi_read(struct surface3_ts_data *ts_data)
|
||||
{
|
||||
struct spi_device *spi = ts_data->spi;
|
||||
@@ -113,6 +124,53 @@ static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *dat
|
||||
input_sync(ts_data->input_dev);
|
||||
}
|
||||
|
||||
+static void surface3_spi_report_pen(struct surface3_ts_data *ts_data,
|
||||
+ struct surface3_ts_data_pen *pen)
|
||||
+{
|
||||
+ struct input_dev *dev = ts_data->pen_input_dev;
|
||||
+ int st = pen->status;
|
||||
+ int prox = st & 0x01;
|
||||
+ int rubber = st & 0x18;
|
||||
+ int tool = (prox && rubber) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
|
||||
+
|
||||
+ /* fake proximity out to switch tools */
|
||||
+ if (ts_data->pen_tool != tool) {
|
||||
+ input_report_key(dev, ts_data->pen_tool, 0);
|
||||
+ input_sync(dev);
|
||||
+ ts_data->pen_tool = tool;
|
||||
+ }
|
||||
+
|
||||
+ input_report_key(dev, BTN_TOUCH, st & 0x12);
|
||||
+
|
||||
+ input_report_key(dev, ts_data->pen_tool, prox);
|
||||
+
|
||||
+ if (st) {
|
||||
+ input_report_key(dev,
|
||||
+ BTN_STYLUS,
|
||||
+ st & 0x04);
|
||||
+
|
||||
+ input_report_abs(dev,
|
||||
+ ABS_X,
|
||||
+ get_unaligned_le16(&pen->x));
|
||||
+ input_report_abs(dev,
|
||||
+ ABS_Y,
|
||||
+ get_unaligned_le16(&pen->y));
|
||||
+ input_report_abs(dev,
|
||||
+ ABS_PRESSURE,
|
||||
+ get_unaligned_le16(&pen->pressure));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data)
|
||||
+{
|
||||
+ struct surface3_ts_data_pen *pen;
|
||||
+
|
||||
+ pen = (struct surface3_ts_data_pen *)&data[15];
|
||||
+
|
||||
+ surface3_spi_report_pen(ts_data, pen);
|
||||
+ input_sync(ts_data->pen_input_dev);
|
||||
+}
|
||||
+
|
||||
static void surface3_spi_process(struct surface3_ts_data *ts_data)
|
||||
{
|
||||
const char header[] = {
|
||||
@@ -125,12 +183,19 @@ static void surface3_spi_process(struct surface3_ts_data *ts_data)
|
||||
"%s header error: %*ph, ignoring...\n",
|
||||
__func__, (int)sizeof(header), data);
|
||||
|
||||
- if (data[9] == SURFACE3_REPORT_TOUCH)
|
||||
+ switch (data[9]) {
|
||||
+ case SURFACE3_REPORT_TOUCH:
|
||||
surface3_spi_process_touch(ts_data, data);
|
||||
- else
|
||||
+ break;
|
||||
+ case SURFACE3_REPORT_PEN:
|
||||
+ surface3_spi_process_pen(ts_data, data);
|
||||
+ break;
|
||||
+ default:
|
||||
dev_err(&ts_data->spi->dev,
|
||||
"%s unknown packet type: %x, ignoring...\n",
|
||||
__func__, data[9]);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
|
||||
static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
|
||||
@@ -224,6 +289,47 @@ static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int surface3_spi_create_pen_input(struct surface3_ts_data *data)
|
||||
+{
|
||||
+ struct input_dev *input;
|
||||
+ int error;
|
||||
+
|
||||
+ input = devm_input_allocate_device(&data->spi->dev);
|
||||
+ if (!input)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data->pen_input_dev = input;
|
||||
+ data->pen_tool = BTN_TOOL_PEN;
|
||||
+
|
||||
+ __set_bit(INPUT_PROP_DIRECT, input->propbit);
|
||||
+ __set_bit(INPUT_PROP_POINTER, input->propbit);
|
||||
+ input_set_abs_params(input, ABS_X, 0, 9600, 0, 0);
|
||||
+ input_abs_set_res(input, ABS_X, 40);
|
||||
+ input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0);
|
||||
+ input_abs_set_res(input, ABS_Y, 48);
|
||||
+ input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0);
|
||||
+ input_set_capability(input, EV_KEY, BTN_TOUCH);
|
||||
+ input_set_capability(input, EV_KEY, BTN_STYLUS);
|
||||
+ input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
|
||||
+ input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
|
||||
+
|
||||
+ input->name = "Surface3 SPI Pen Input";
|
||||
+ input->phys = "input/ts";
|
||||
+ input->id.bustype = BUS_SPI;
|
||||
+ input->id.vendor = 0x045e; /* Microsoft */
|
||||
+ input->id.product = 0x0002;
|
||||
+ input->id.version = 0x0000;
|
||||
+
|
||||
+ error = input_register_device(input);
|
||||
+ if (error) {
|
||||
+ dev_err(&data->spi->dev,
|
||||
+ "Failed to register input device: %d", error);
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int surface3_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct surface3_ts_data *data;
|
||||
@@ -255,6 +361,10 @@ static int surface3_spi_probe(struct spi_device *spi)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
+ error = surface3_spi_create_pen_input(data);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
error = devm_request_threaded_irq(&spi->dev, spi->irq,
|
||||
NULL, surface3_spi_irq_handler,
|
||||
IRQF_ONESHOT,
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
From a3df5bf1d383e45c54875355556bc8b3bb2889c5 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Tue, 31 May 2016 10:34:45 +0200
|
||||
Subject: [PATCH 1/2] WIP: acpi/button: remove pointer to old lid_sysfs on
|
||||
unbind
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/acpi/button.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
|
||||
index 5c3b091..e413599 100644
|
||||
--- a/drivers/acpi/button.c
|
||||
+++ b/drivers/acpi/button.c
|
||||
@@ -188,9 +188,11 @@ done:
|
||||
remove_dev_dir:
|
||||
remove_proc_entry(acpi_device_bid(device),
|
||||
acpi_lid_dir);
|
||||
+ acpi_lid_dir = NULL;
|
||||
acpi_device_dir(device) = NULL;
|
||||
remove_lid_dir:
|
||||
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
|
||||
+ acpi_button_dir = NULL;
|
||||
remove_button_dir:
|
||||
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
|
||||
goto done;
|
||||
@@ -207,8 +209,10 @@ static int acpi_button_remove_fs(struct acpi_device *device)
|
||||
acpi_device_dir(device));
|
||||
remove_proc_entry(acpi_device_bid(device),
|
||||
acpi_lid_dir);
|
||||
+ acpi_lid_dir = NULL;
|
||||
acpi_device_dir(device) = NULL;
|
||||
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
|
||||
+ acpi_button_dir = NULL;
|
||||
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
|
||||
|
||||
return 0;
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
From 72023d2508fdd513a92e9dd25d1cc0999a0f32ee Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Fri, 27 May 2016 17:13:50 +0200
|
||||
Subject: [PATCH] WIP: i2c-hid enabled S0 S3
|
||||
|
||||
---
|
||||
drivers/hid/i2c-hid/i2c-hid.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 37 insertions(+)
|
||||
|
||||
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
|
||||
index b3ec4f2..d0b1355 100644
|
||||
--- a/drivers/hid/i2c-hid/i2c-hid.c
|
||||
+++ b/drivers/hid/i2c-hid/i2c-hid.c
|
||||
@@ -154,6 +154,8 @@ struct i2c_hid {
|
||||
struct mutex reset_lock;
|
||||
};
|
||||
|
||||
+static int i2c_hid_acpi_power(struct i2c_client *client, int lvl);
|
||||
+
|
||||
static int __i2c_hid_command(struct i2c_client *client,
|
||||
const struct i2c_hid_cmd *command, u8 reportID,
|
||||
u8 reportType, u8 *args, int args_len,
|
||||
@@ -245,6 +247,7 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
|
||||
|
||||
i2c_hid_dbg(ihid, "%s\n", __func__);
|
||||
|
||||
+ pm_runtime_get_sync(&client->dev);
|
||||
if (reportID >= 0x0F) {
|
||||
args[args_len++] = reportID;
|
||||
reportID = 0x0F;
|
||||
@@ -261,6 +264,7 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ pm_runtime_put(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -584,6 +588,9 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
|
||||
|
||||
ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8);
|
||||
|
||||
+ i2c_hid_dbg(ihid, "report (len=%d): %*ph\n",
|
||||
+ (int)ask_count, (int)ask_count, ihid->rawbuf);
|
||||
+
|
||||
if (ret_count <= 2)
|
||||
return 0;
|
||||
|
||||
@@ -789,6 +796,8 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
|
||||
pm_runtime_put(&client->dev);
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ i2c_hid_acpi_power(client, lvl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -909,12 +918,38 @@ static const struct acpi_device_id i2c_hid_acpi_match[] = {
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match);
|
||||
+
|
||||
+static int i2c_hid_acpi_power(struct i2c_client *client, int lvl)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+
|
||||
+ pr_err("%s lvl: %d %s:%d\n", __func__, lvl, __FILE__, __LINE__);
|
||||
+
|
||||
+ switch (lvl) {
|
||||
+ case PM_HINT_FULLON:
|
||||
+ error = acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D0);
|
||||
+ break;
|
||||
+ case PM_HINT_NORMAL:
|
||||
+ error = acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D3);
|
||||
+ break;
|
||||
+ }
|
||||
+ if (error)
|
||||
+ dev_warn(&client->dev, "%s: error changing power state: %d\n", __func__, error);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
#else
|
||||
static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
|
||||
struct i2c_hid_platform_data *pdata)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
+
|
||||
+static inline int i2c_hid_acpi_power(struct i2c_client *client, int lvl)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@@ -1004,6 +1039,8 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
|
||||
ihid->client = client;
|
||||
|
||||
+ i2c_hid_acpi_power(client, PM_HINT_FULLON);
|
||||
+
|
||||
hidRegister = ihid->pdata.hid_descriptor_address;
|
||||
ihid->wHIDDescRegister = cpu_to_le16(hidRegister);
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
From 5144a26d49d40c1847e0af496d78c54eb29f570f Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Thu, 26 May 2016 15:29:10 +0200
|
||||
Subject: [PATCH] gpiolib-acpi: make sure we trigger the events at least once
|
||||
on boot
|
||||
|
||||
The Surface 3 has its _LID state controlled by an ACPI operation region
|
||||
triggered by a GPIO event:
|
||||
|
||||
OperationRegion (GPOR, GeneralPurposeIo, Zero, One)
|
||||
Field (GPOR, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
Connection (
|
||||
GpioIo (Shared, PullNone, 0x0000, 0x0000, IoRestrictionNone,
|
||||
"\\_SB.GPO0", 0x00, ResourceConsumer, ,
|
||||
)
|
||||
{ // Pin list
|
||||
0x004C
|
||||
}
|
||||
),
|
||||
HELD, 1
|
||||
}
|
||||
|
||||
Method (_E4C, 0, Serialized) // _Exx: Edge-Triggered GPE
|
||||
{
|
||||
If ((HELD == One))
|
||||
{
|
||||
^^LID.LIDB = One
|
||||
}
|
||||
Else
|
||||
{
|
||||
^^LID.LIDB = Zero
|
||||
Notify (LID, 0x80) // Status Change
|
||||
}
|
||||
|
||||
Notify (^^PCI0.SPI1.NTRG, One) // Device Check
|
||||
}
|
||||
|
||||
Currently, the state of LIDB is wrong until the user actually closes or
|
||||
open the cover. We need to trigger the GPIO event once to update the
|
||||
internal ACPI state.
|
||||
|
||||
Coincidentally, this also enables the integrated HID sensor hub which also
|
||||
requires an ACPI gpio operation region to start initialization.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/gpio/gpiolib-acpi.c | 13 ++++++++++++-
|
||||
1 file changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
|
||||
index 2dc5258..71775a0 100644
|
||||
--- a/drivers/gpio/gpiolib-acpi.c
|
||||
+++ b/drivers/gpio/gpiolib-acpi.c
|
||||
@@ -175,7 +175,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
irq_handler_t handler = NULL;
|
||||
struct gpio_desc *desc;
|
||||
unsigned long irqflags;
|
||||
- int ret, pin, irq;
|
||||
+ int ret, pin, irq, value;
|
||||
|
||||
if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
|
||||
return AE_OK;
|
||||
@@ -214,6 +214,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
|
||||
gpiod_direction_input(desc);
|
||||
|
||||
+ value = gpiod_get_value(desc);
|
||||
+
|
||||
ret = gpiochip_lock_as_irq(chip, pin);
|
||||
if (ret) {
|
||||
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
|
||||
@@ -266,6 +268,15 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
}
|
||||
|
||||
list_add_tail(&event->node, &acpi_gpio->events);
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure we trigger the initial state of the IRQ when
|
||||
+ * using RISING or FALLING.
|
||||
+ */
|
||||
+ if (((irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
|
||||
+ ((irqflags & IRQF_TRIGGER_FALLING) && value == 0))
|
||||
+ handler(-1, event);
|
||||
+
|
||||
return AE_OK;
|
||||
|
||||
fail_free_event:
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,756 @@
|
|||
From c4827e382726f31e069860af7a9af9bdef4b8bfb Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Tue, 24 May 2016 22:30:49 +0200
|
||||
Subject: [PATCH] power: MSHW0011 rev-eng implementation
|
||||
|
||||
MSHW0011 replaces the battery firmware by using ACPI operation regions.
|
||||
The values have been obtained by reverse engineering, and are subject to
|
||||
errors. Looks like it works on overall pretty well.
|
||||
|
||||
I couldn't manage to get the IRQ correctly triggered, so I am using a
|
||||
good old polling thread to check for changes.
|
||||
|
||||
The acpica bits need their own patch with a little more love.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/acpi/acpica/exfield.c | 11 +
|
||||
drivers/power/Kconfig | 8 +
|
||||
drivers/power/Makefile | 1 +
|
||||
drivers/power/surface3_power.c | 674 +++++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 694 insertions(+)
|
||||
create mode 100644 drivers/power/surface3_power.c
|
||||
|
||||
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
|
||||
index d5d8020..f386675 100644
|
||||
--- a/drivers/acpi/acpica/exfield.c
|
||||
+++ b/drivers/acpi/acpica/exfield.c
|
||||
@@ -413,6 +413,17 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
|
||||
* Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
|
||||
*/
|
||||
length += 2;
|
||||
+
|
||||
+ /*
|
||||
+ * bug? in the MS Surface 3: length is 2 but the command
|
||||
+ * needs 3 parameters.
|
||||
+ * Functions like BIX requires a lot of in/out data,
|
||||
+ * so just take the incoming buffer length as the
|
||||
+ * reference.
|
||||
+ */
|
||||
+ if (accessor_type == 0xf)
|
||||
+ length = source_desc->buffer.length;
|
||||
+
|
||||
function = ACPI_WRITE | (accessor_type << 16);
|
||||
} else { /* IPMI */
|
||||
|
||||
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
|
||||
index 421770d..fb54d8b 100644
|
||||
--- a/drivers/power/Kconfig
|
||||
+++ b/drivers/power/Kconfig
|
||||
@@ -509,6 +509,14 @@ config AXP20X_POWER
|
||||
This driver provides support for the power supply features of
|
||||
AXP20x PMIC.
|
||||
|
||||
+config SURFACE3_POWER
|
||||
+ tristate "Surface 3 power management driver"
|
||||
+ depends on I2C
|
||||
+ depends on GPIOLIB
|
||||
+ help
|
||||
+ This driver provides support for the power supply features of
|
||||
+ the Surface 3.
|
||||
+
|
||||
endif # POWER_SUPPLY
|
||||
|
||||
source "drivers/power/reset/Kconfig"
|
||||
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
|
||||
index e46b75d..a147a0e 100644
|
||||
--- a/drivers/power/Makefile
|
||||
+++ b/drivers/power/Makefile
|
||||
@@ -74,3 +74,4 @@ obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
|
||||
obj-$(CONFIG_POWER_RESET) += reset/
|
||||
obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
|
||||
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
|
||||
+obj-$(CONFIG_SURFACE3_POWER) += surface3_power.o
|
||||
diff --git a/drivers/power/surface3_power.c b/drivers/power/surface3_power.c
|
||||
new file mode 100644
|
||||
index 0000000..eee21d3
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/surface3_power.c
|
||||
@@ -0,0 +1,674 @@
|
||||
+/*
|
||||
+ * Supports for the power IC on the Surface 3 tablet.
|
||||
+ *
|
||||
+ * (C) Copyright 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.
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * This driver has been reverse-engineered by parsing the DSDT of the Surface 3
|
||||
+ * and looking at the registers of the chips.
|
||||
+ *
|
||||
+ * The DSDT allowed to find out that:
|
||||
+ * - the driver is required for the ACPI BAT0 device to communicate to the chip
|
||||
+ * through an operation region.
|
||||
+ * - the various defines for the operation region functions to communicate with
|
||||
+ * this driver
|
||||
+ * - the DSM 3f99e367-6220-4955-8b0f-06ef2ae79412 allows to trigger ACPI
|
||||
+ * events to BAT0 (the code is all available in the DSDT).
|
||||
+ *
|
||||
+ * Further findings regarding the 2 chips declared in the MSHW0011 are:
|
||||
+ * - there are 2 chips declared:
|
||||
+ * . 0x22 seems to control the ADP1 line status (and probably the charger)
|
||||
+ * . 0x55 controls the battery directly
|
||||
+ * - the battery chip uses a SMBus protocol (using plain SMBus allows non
|
||||
+ * destructive commands):
|
||||
+ * . the commands/registers used are in the range 0x00..0x7F
|
||||
+ * . if bit 8 (0x80) is set in the SMBus command, the returned value is the
|
||||
+ * same as when it is not set. There is a high chance this bit is the
|
||||
+ * read/write
|
||||
+ * . the various registers semantic as been deduced by observing the register
|
||||
+ * dumps.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/acpi.h>
|
||||
+#include <linux/kthread.h>
|
||||
+#include <linux/freezer.h>
|
||||
+
|
||||
+#include <asm/unaligned.h>
|
||||
+
|
||||
+#define POLL_INTERVAL (HZ * 2)
|
||||
+
|
||||
+static bool dump_registers;
|
||||
+module_param_named(dump_registers, dump_registers, bool, 0644);
|
||||
+MODULE_PARM_DESC(dump_registers,
|
||||
+ "Dump the SMBus register at probe (debugging only).");
|
||||
+
|
||||
+struct mshw0011_data {
|
||||
+ struct i2c_client *adp1;
|
||||
+ struct i2c_client *bat0;
|
||||
+ unsigned short notify_version;
|
||||
+ struct task_struct *poll_task;
|
||||
+ bool kthread_running;
|
||||
+
|
||||
+ bool charging;
|
||||
+ bool bat_charging;
|
||||
+ u8 trip_point;
|
||||
+};
|
||||
+
|
||||
+struct mshw0011_lookup {
|
||||
+ struct mshw0011_data *cdata;
|
||||
+ unsigned int n;
|
||||
+ unsigned int index;
|
||||
+ int addr;
|
||||
+};
|
||||
+
|
||||
+struct mshw0011_handler_data {
|
||||
+ struct acpi_connection_info info;
|
||||
+ struct i2c_client *client;
|
||||
+};
|
||||
+
|
||||
+struct bix {
|
||||
+ u32 revision;
|
||||
+ u32 power_unit;
|
||||
+ u32 design_capacity;
|
||||
+ u32 last_full_charg_capacity;
|
||||
+ u32 battery_technology;
|
||||
+ u32 design_voltage;
|
||||
+ u32 design_capacity_of_warning;
|
||||
+ u32 design_capacity_of_low;
|
||||
+ u32 cycle_count;
|
||||
+ u32 measurement_accuracy;
|
||||
+ u32 max_sampling_time;
|
||||
+ u32 min_sampling_time;
|
||||
+ u32 max_average_interval;
|
||||
+ u32 min_average_interval;
|
||||
+ u32 battery_capacity_granularity_1;
|
||||
+ u32 battery_capacity_granularity_2;
|
||||
+ char model[10];
|
||||
+ char serial[10];
|
||||
+ char type[10];
|
||||
+ char OEM[10];
|
||||
+} __packed;
|
||||
+
|
||||
+struct bst {
|
||||
+ u32 battery_state;
|
||||
+ s32 battery_present_rate;
|
||||
+ u32 battery_remaining_capacity;
|
||||
+ u32 battery_present_voltage;
|
||||
+} __packed;
|
||||
+
|
||||
+struct gsb_command {
|
||||
+ u8 arg0;
|
||||
+ u8 arg1;
|
||||
+ u8 arg2;
|
||||
+} __packed;
|
||||
+
|
||||
+struct gsb_buffer {
|
||||
+ u8 status;
|
||||
+ u8 len;
|
||||
+ u8 ret;
|
||||
+ union {
|
||||
+ struct gsb_command cmd;
|
||||
+ struct bst bst;
|
||||
+ struct bix bix;
|
||||
+ } __packed;
|
||||
+} __packed;
|
||||
+
|
||||
+#define MSHW0011_CMD_DEST_BAT0 0x01
|
||||
+#define MSHW0011_CMD_DEST_ADP1 0x03
|
||||
+
|
||||
+#define MSHW0011_CMD_BAT0_STA 0x01
|
||||
+#define MSHW0011_CMD_BAT0_BIX 0x02
|
||||
+#define MSHW0011_CMD_BAT0_BCT 0x03
|
||||
+#define MSHW0011_CMD_BAT0_BTM 0x04
|
||||
+#define MSHW0011_CMD_BAT0_BST 0x05
|
||||
+#define MSHW0011_CMD_BAT0_BTP 0x06
|
||||
+#define MSHW0011_CMD_ADP1_PSR 0x07
|
||||
+#define MSHW0011_CMD_BAT0_PSOC 0x09
|
||||
+#define MSHW0011_CMD_BAT0_PMAX 0x0A
|
||||
+#define MSHW0011_CMD_BAT0_PSRC 0x0B
|
||||
+#define MSHW0011_CMD_BAT0_CHGI 0x0C
|
||||
+#define MSHW0011_CMD_BAT0_ARTG 0x0D
|
||||
+
|
||||
+#define MSHW0011_NOTIFY_GET_VERSION 0x00
|
||||
+#define MSHW0011_NOTIFY_ADP1 0x01
|
||||
+#define MSHW0011_NOTIFY_BAT0 0x02
|
||||
+
|
||||
+#define MSHW0011_ADP1_REG_PSR 0x03
|
||||
+
|
||||
+#define MSHW0011_BAT0_REG_CAPACITY 0x0c
|
||||
+#define MSHW0011_BAT0_REG_VOLTAGE 0x08
|
||||
+#define MSHW0011_BAT0_REG_RATE 0x14
|
||||
+#define MSHW0011_BAT0_REG_OEM 0x45
|
||||
+#define MSHW0011_BAT0_REG_TYPE 0x4e
|
||||
+#define MSHW0011_BAT0_REG_SERIAL_NO 0x56
|
||||
+#define MSHW0011_BAT0_REG_CYCLE_CNT 0x6e
|
||||
+
|
||||
+#define MSHW0011_EV_2_5 0x1ff
|
||||
+
|
||||
+static int mshw0011_i2c_read_block(struct i2c_client *client, u8 reg, u8 *buf,
|
||||
+ int len)
|
||||
+{
|
||||
+ int status, i;
|
||||
+
|
||||
+ for (i = 0; i < len; i++) {
|
||||
+ status = i2c_smbus_read_byte_data(client, reg + i);
|
||||
+ if (status < 0) {
|
||||
+ buf[i] = 0xff;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ buf[i] = (u8)status;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mshw0011_notify(struct mshw0011_data *cdata, u8 arg1, u8 arg2,
|
||||
+ unsigned int *ret_value)
|
||||
+{
|
||||
+ static const u8 mshw0011_guid[] = {
|
||||
+ 0x67, 0xE3, 0x99, 0x3F, 0x20, 0x62, 0x55, 0x49,
|
||||
+ 0x8b, 0x0f, 0x06, 0xef, 0x2a, 0xe7, 0x94, 0x12,
|
||||
+ };
|
||||
+ union acpi_object *obj;
|
||||
+ struct acpi_device *adev;
|
||||
+ acpi_handle handle;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ handle = ACPI_HANDLE(&cdata->adp1->dev);
|
||||
+ if (!handle || acpi_bus_get_device(handle, &adev))
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ obj = acpi_evaluate_dsm_typed(handle, mshw0011_guid, arg1, arg2, NULL,
|
||||
+ ACPI_TYPE_BUFFER);
|
||||
+ if (!obj) {
|
||||
+ dev_err(&cdata->adp1->dev, "device _DSM execution failed\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ *ret_value = 0;
|
||||
+ for (i = 0; i < obj->buffer.length; i++)
|
||||
+ *ret_value |= obj->buffer.pointer[i] << (i * 8);
|
||||
+
|
||||
+ ACPI_FREE(obj);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct bix default_bix = {
|
||||
+ .revision = 0x00,
|
||||
+ .power_unit = 0x01,
|
||||
+ .design_capacity = 0x1dca,
|
||||
+ .last_full_charg_capacity = 0x1dca,
|
||||
+ .battery_technology = 0x01,
|
||||
+ .design_voltage = 0x10df,
|
||||
+ .design_capacity_of_warning = 0x8f,
|
||||
+ .design_capacity_of_low = 0x47,
|
||||
+ .cycle_count = 0xffffffff,
|
||||
+ .measurement_accuracy = 0x00015F90,
|
||||
+ .max_sampling_time = 0x03E8,
|
||||
+ .min_sampling_time = 0x03E8,
|
||||
+ .max_average_interval = 0x03E8,
|
||||
+ .min_average_interval = 0x03E8,
|
||||
+ .battery_capacity_granularity_1 = 0x45,
|
||||
+ .battery_capacity_granularity_2 = 0x11,
|
||||
+ .model = "P11G8M",
|
||||
+ .serial = "",
|
||||
+ .type = "LION",
|
||||
+ .OEM = "",
|
||||
+};
|
||||
+
|
||||
+static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
|
||||
+{
|
||||
+ struct i2c_client *client = cdata->bat0;
|
||||
+ int ret;
|
||||
+ char buf[10];
|
||||
+
|
||||
+ *bix = default_bix;
|
||||
+
|
||||
+ /* get serial number */
|
||||
+ ret = mshw0011_i2c_read_block(client, MSHW0011_BAT0_REG_SERIAL_NO,
|
||||
+ buf, 10);
|
||||
+ if (ret) {
|
||||
+ dev_err(&client->dev, "Error reading serial no: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ memcpy(bix->serial, buf + 7, 3);
|
||||
+ memcpy(bix->serial + 3, buf, 6);
|
||||
+ bix->serial[9] = '\0';
|
||||
+
|
||||
+ /* get cycle count */
|
||||
+ ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CYCLE_CNT);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ bix->cycle_count = le16_to_cpu(ret);
|
||||
+
|
||||
+ /* get OEM name */
|
||||
+ ret = mshw0011_i2c_read_block(client, MSHW0011_BAT0_REG_OEM, buf, 4);
|
||||
+ if (ret) {
|
||||
+ dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ memcpy(bix->OEM, buf, 3);
|
||||
+ bix->OEM[4] = '\0';
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
|
||||
+{
|
||||
+ struct i2c_client *client = cdata->bat0;
|
||||
+ int rate, capacity, voltage;
|
||||
+ s16 tmp;
|
||||
+
|
||||
+ rate = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_RATE);
|
||||
+ if (rate < 0)
|
||||
+ return rate;
|
||||
+
|
||||
+ capacity = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CAPACITY);
|
||||
+ if (capacity < 0)
|
||||
+ return capacity;
|
||||
+
|
||||
+ voltage = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_VOLTAGE);
|
||||
+ if (voltage < 0)
|
||||
+ return voltage;
|
||||
+
|
||||
+ tmp = le16_to_cpu(rate);
|
||||
+ bst->battery_present_rate = (s32)tmp;
|
||||
+ bst->battery_state = bst->battery_present_rate < 0 ? 0x01 : 0x02;
|
||||
+ bst->battery_remaining_capacity = le16_to_cpu(capacity);
|
||||
+ bst->battery_present_voltage = le16_to_cpu(voltage);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_adp_psr(struct mshw0011_data *cdata)
|
||||
+{
|
||||
+ struct i2c_client *client = cdata->adp1;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = i2c_smbus_read_byte_data(client, MSHW0011_ADP1_REG_PSR);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_isr(struct mshw0011_data *cdata)
|
||||
+{
|
||||
+ struct bst bst;
|
||||
+ int ret;
|
||||
+ bool status, bat_status;
|
||||
+
|
||||
+ ret = mshw0011_adp_psr(cdata);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ status = ret;
|
||||
+
|
||||
+ if (status != cdata->charging)
|
||||
+ mshw0011_notify(cdata, cdata->notify_version,
|
||||
+ MSHW0011_NOTIFY_ADP1, &ret);
|
||||
+
|
||||
+ cdata->charging = status;
|
||||
+
|
||||
+ ret = mshw0011_bst(cdata, &bst);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ bat_status = bst.battery_present_rate >= 0;
|
||||
+
|
||||
+ if (bat_status != cdata->bat_charging)
|
||||
+ mshw0011_notify(cdata, cdata->notify_version,
|
||||
+ MSHW0011_NOTIFY_BAT0, &ret);
|
||||
+
|
||||
+ cdata->bat_charging = bat_status;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_poll_task(void *data)
|
||||
+{
|
||||
+ struct mshw0011_data *cdata = data;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ cdata->kthread_running = true;
|
||||
+
|
||||
+ set_freezable();
|
||||
+
|
||||
+ while (!kthread_should_stop()) {
|
||||
+ schedule_timeout_interruptible(POLL_INTERVAL);
|
||||
+ try_to_freeze();
|
||||
+ ret = mshw0011_isr(data);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ cdata->kthread_running = false;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static acpi_status
|
||||
+mshw0011_space_handler(u32 function, acpi_physical_address command,
|
||||
+ u32 bits, u64 *value64,
|
||||
+ void *handler_context, void *region_context)
|
||||
+{
|
||||
+ struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
|
||||
+ struct mshw0011_handler_data *data = handler_context;
|
||||
+ struct acpi_connection_info *info = &data->info;
|
||||
+ struct acpi_resource_i2c_serialbus *sb;
|
||||
+ struct i2c_client *client = data->client;
|
||||
+ struct mshw0011_data *cdata = i2c_get_clientdata(client);
|
||||
+ struct acpi_resource *ares;
|
||||
+ u32 accessor_type = function >> 16;
|
||||
+ acpi_status ret;
|
||||
+ int status = 1;
|
||||
+
|
||||
+ ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
|
||||
+ if (ACPI_FAILURE(ret))
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
|
||||
+ ret = AE_BAD_PARAMETER;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ sb = &ares->data.i2c_serial_bus;
|
||||
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
|
||||
+ ret = AE_BAD_PARAMETER;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {
|
||||
+ ret = AE_BAD_PARAMETER;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ if (gsb->cmd.arg0 == MSHW0011_CMD_DEST_ADP1 &&
|
||||
+ gsb->cmd.arg1 == MSHW0011_CMD_ADP1_PSR) {
|
||||
+ ret = mshw0011_adp_psr(cdata);
|
||||
+ if (ret >= 0) {
|
||||
+ status = ret;
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (gsb->cmd.arg0 != MSHW0011_CMD_DEST_BAT0) {
|
||||
+ ret = AE_BAD_PARAMETER;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ switch (gsb->cmd.arg1) {
|
||||
+ case MSHW0011_CMD_BAT0_STA:
|
||||
+ status = 1;
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+ case MSHW0011_CMD_BAT0_BIX:
|
||||
+ status = 1;
|
||||
+ ret = mshw0011_bix(cdata, &gsb->bix);
|
||||
+ break;
|
||||
+ case MSHW0011_CMD_BAT0_BTP:
|
||||
+ status = 1;
|
||||
+ ret = 0;
|
||||
+ cdata->trip_point = gsb->cmd.arg2;
|
||||
+ break;
|
||||
+ case MSHW0011_CMD_BAT0_BST:
|
||||
+ status = 1;
|
||||
+ ret = mshw0011_bst(cdata, &gsb->bst);
|
||||
+ break;
|
||||
+ default:
|
||||
+ pr_info("command(0x%02x) is not supported.\n", gsb->cmd.arg1);
|
||||
+ ret = AE_BAD_PARAMETER;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ out:
|
||||
+ gsb->ret = status;
|
||||
+ gsb->status = 0;
|
||||
+
|
||||
+ err:
|
||||
+ ACPI_FREE(ares);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_install_space_handler(struct i2c_client *client)
|
||||
+{
|
||||
+ acpi_handle handle;
|
||||
+ struct mshw0011_handler_data *data;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ handle = ACPI_HANDLE(&client->dev);
|
||||
+
|
||||
+ if (!handle)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ data = kzalloc(sizeof(struct mshw0011_handler_data),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data->client = client;
|
||||
+ status = acpi_bus_attach_private_data(handle, (void *)data);
|
||||
+ if (ACPI_FAILURE(status)) {
|
||||
+ kfree(data);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ status = acpi_install_address_space_handler(handle,
|
||||
+ ACPI_ADR_SPACE_GSBUS,
|
||||
+ &mshw0011_space_handler,
|
||||
+ NULL,
|
||||
+ data);
|
||||
+ if (ACPI_FAILURE(status)) {
|
||||
+ dev_err(&client->dev, "Error installing i2c space handler\n");
|
||||
+ acpi_bus_detach_private_data(handle);
|
||||
+ kfree(data);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ acpi_walk_dep_device_list(handle);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void mshw0011_remove_space_handler(struct i2c_client *client)
|
||||
+{
|
||||
+ acpi_handle handle;
|
||||
+ struct mshw0011_handler_data *data;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ handle = ACPI_HANDLE(&client->dev);
|
||||
+
|
||||
+ if (!handle)
|
||||
+ return;
|
||||
+
|
||||
+ acpi_remove_address_space_handler(handle,
|
||||
+ ACPI_ADR_SPACE_GSBUS,
|
||||
+ &mshw0011_space_handler);
|
||||
+
|
||||
+ status = acpi_bus_get_private_data(handle, (void **)&data);
|
||||
+ if (ACPI_SUCCESS(status))
|
||||
+ kfree(data);
|
||||
+
|
||||
+ acpi_bus_detach_private_data(handle);
|
||||
+}
|
||||
+
|
||||
+static int acpi_find_i2c(struct acpi_resource *ares, void *data)
|
||||
+{
|
||||
+ struct mshw0011_lookup *lookup = data;
|
||||
+
|
||||
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (lookup->n++ == lookup->index && !lookup->addr)
|
||||
+ lookup->addr = ares->data.i2c_serial_bus.slave_address;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_i2c_resource_lookup(struct mshw0011_data *cdata,
|
||||
+ unsigned int index)
|
||||
+{
|
||||
+ struct i2c_client *client = cdata->adp1;
|
||||
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
|
||||
+ struct mshw0011_lookup lookup = {
|
||||
+ .cdata = cdata,
|
||||
+ .index = index,
|
||||
+ };
|
||||
+ struct list_head res_list;
|
||||
+ int ret;
|
||||
+
|
||||
+ INIT_LIST_HEAD(&res_list);
|
||||
+
|
||||
+ ret = acpi_dev_get_resources(adev, &res_list, acpi_find_i2c, &lookup);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ acpi_dev_free_resource_list(&res_list);
|
||||
+
|
||||
+ if (!lookup.addr)
|
||||
+ return -ENOENT;
|
||||
+
|
||||
+ return lookup.addr;
|
||||
+}
|
||||
+
|
||||
+static void mshw0011_dump_registers(struct i2c_client *client,
|
||||
+ struct i2c_client *bat0)
|
||||
+{
|
||||
+ char rd_buf[60];
|
||||
+ int error, i, c;
|
||||
+ char buff[17 * 3 * 2] = {0};
|
||||
+
|
||||
+ dev_info(&client->dev, "dumping registers 0x00 to 0x7F:\n");
|
||||
+
|
||||
+ for (i = 0; i < 0x80; i += 0x20) {
|
||||
+ memset(rd_buf, 0, sizeof(rd_buf));
|
||||
+ error = mshw0011_i2c_read_block(bat0, i, rd_buf, 0x20);
|
||||
+ dev_info(&client->dev, " read 0x%02x: %*ph|%*ph\n",
|
||||
+ i,
|
||||
+ 0x10, rd_buf,
|
||||
+ 0x10, rd_buf + 0x10);
|
||||
+ for (c = 0; c < 0x20; c++) {
|
||||
+ if (rd_buf[c] >= 0x20 && rd_buf[c] <= 0x7e) {
|
||||
+ buff[c * 3 + 0] = ' ';
|
||||
+ buff[c * 3 + 1] = rd_buf[c];
|
||||
+ } else {
|
||||
+ buff[c * 3 + 0] = '-';
|
||||
+ buff[c * 3 + 1] = '-';
|
||||
+ }
|
||||
+ buff[c * 3 + 2] = (c + 1) % 0x10 ? ' ' : '|';
|
||||
+ }
|
||||
+ buff[0x1f * 3 + 2] = '\0';
|
||||
+ dev_info(&client->dev, "ascii 0x%02x: %s\n", i, buff);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_probe(struct i2c_client *client,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ struct device *dev = &client->dev;
|
||||
+ struct i2c_client *bat0;
|
||||
+ struct mshw0011_data *data;
|
||||
+ int error, version, addr;
|
||||
+
|
||||
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data->adp1 = client;
|
||||
+ i2c_set_clientdata(client, data);
|
||||
+
|
||||
+ addr = mshw0011_i2c_resource_lookup(data, 1);
|
||||
+ if (addr < 0)
|
||||
+ return addr;
|
||||
+
|
||||
+ bat0 = i2c_new_dummy(client->adapter, addr);
|
||||
+ if (!bat0)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data->bat0 = bat0;
|
||||
+ i2c_set_clientdata(bat0, data);
|
||||
+
|
||||
+ if (dump_registers)
|
||||
+ mshw0011_dump_registers(client, bat0);
|
||||
+
|
||||
+ error = mshw0011_notify(data, 1, MSHW0011_NOTIFY_GET_VERSION, &version);
|
||||
+ if (error)
|
||||
+ goto out_err;
|
||||
+
|
||||
+ data->notify_version = version == MSHW0011_EV_2_5;
|
||||
+
|
||||
+ data->poll_task = kthread_run(mshw0011_poll_task, data, "mshw0011_adp");
|
||||
+ if (IS_ERR(data->poll_task)) {
|
||||
+ error = PTR_ERR(data->poll_task);
|
||||
+ dev_err(&client->dev, "Unable to run kthread err %d\n", error);
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+
|
||||
+ error = mshw0011_install_space_handler(client);
|
||||
+ if (error)
|
||||
+ goto out_err;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_err:
|
||||
+ if (data->kthread_running)
|
||||
+ kthread_stop(data->poll_task);
|
||||
+ i2c_unregister_device(data->bat0);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int mshw0011_remove(struct i2c_client *client)
|
||||
+{
|
||||
+ struct mshw0011_data *cdata = i2c_get_clientdata(client);
|
||||
+
|
||||
+ mshw0011_remove_space_handler(client);
|
||||
+
|
||||
+ if (cdata->kthread_running)
|
||||
+ kthread_stop(cdata->poll_task);
|
||||
+
|
||||
+ i2c_unregister_device(cdata->bat0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct i2c_device_id mshw0011_id[] = {
|
||||
+ { "MSHW0011:00", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, mshw0011_id);
|
||||
+
|
||||
+#ifdef CONFIG_ACPI
|
||||
+static const struct acpi_device_id mshw0011_acpi_match[] = {
|
||||
+ { "MSHW0011", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(acpi, mshw0011_acpi_match);
|
||||
+#endif
|
||||
+
|
||||
+static struct i2c_driver mshw0011_driver = {
|
||||
+ .probe = mshw0011_probe,
|
||||
+ .remove = mshw0011_remove,
|
||||
+ .id_table = mshw0011_id,
|
||||
+ .driver = {
|
||||
+ .name = "mshw0011",
|
||||
+ .acpi_match_table = ACPI_PTR(mshw0011_acpi_match),
|
||||
+ },
|
||||
+};
|
||||
+module_i2c_driver(mshw0011_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
|
||||
+MODULE_DESCRIPTION("mshw0011 driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.5.0
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
From 0e81c6dd0106dfb2ddb065077f596756ea429adc Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Thu, 12 May 2016 15:32:08 +0200
|
||||
Subject: [PATCH 2/3] HID: multitouch: enable the Surface 3 Type Cover to
|
||||
report multitouch data
|
||||
|
||||
There is no reasons to filter out keyboard and consumer control collections
|
||||
in hid-multitouch.
|
||||
With the previous hid-input fix, there is now a full support of the Type
|
||||
Cover and we can remove all specific bits from hid-core and hid-microsoft.
|
||||
|
||||
hid-multitouch will automatically set HID_QUIRK_NO_INIT_REPORTS so we can
|
||||
also remove it from the list of ushbid quirks.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/hid/hid-core.c | 2 --
|
||||
drivers/hid/hid-ids.h | 1 -
|
||||
drivers/hid/hid-microsoft.c | 2 --
|
||||
drivers/hid/hid-multitouch.c | 4 +++-
|
||||
drivers/hid/usbhid/hid-quirks.c | 1 -
|
||||
5 files changed, 3 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
||||
index efd8f8c..1bbbe6c 100644
|
||||
--- a/drivers/hid/hid-core.c
|
||||
+++ b/drivers/hid/hid-core.c
|
||||
@@ -727,7 +727,6 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
|
||||
(hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 ||
|
||||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 ||
|
||||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP ||
|
||||
- hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
|
||||
hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
|
||||
hid->group == HID_GROUP_MULTITOUCH)
|
||||
hid->group = HID_GROUP_GENERIC;
|
||||
@@ -1979,7 +1978,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
|
||||
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) },
|
||||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
||||
index 191c981..c54d0a9 100644
|
||||
--- a/drivers/hid/hid-ids.h
|
||||
+++ b/drivers/hid/hid-ids.h
|
||||
@@ -708,7 +708,6 @@
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd
|
||||
-#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de
|
||||
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
|
||||
|
||||
#define USB_VENDOR_ID_MOJO 0x8282
|
||||
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
|
||||
index e924d55..cf6920b 100644
|
||||
--- a/drivers/hid/hid-microsoft.c
|
||||
+++ b/drivers/hid/hid-microsoft.c
|
||||
@@ -288,8 +288,6 @@ static const struct hid_device_id ms_devices[] = {
|
||||
.driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP),
|
||||
.driver_data = MS_HIDINPUT },
|
||||
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
|
||||
- .driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER),
|
||||
.driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD),
|
||||
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
|
||||
index 95b7d61..dd279d7 100644
|
||||
--- a/drivers/hid/hid-multitouch.c
|
||||
+++ b/drivers/hid/hid-multitouch.c
|
||||
@@ -835,7 +835,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
if (!td->mtclass.export_all_inputs &&
|
||||
field->application != HID_DG_TOUCHSCREEN &&
|
||||
field->application != HID_DG_PEN &&
|
||||
- field->application != HID_DG_TOUCHPAD)
|
||||
+ field->application != HID_DG_TOUCHPAD &&
|
||||
+ field->application != HID_GD_KEYBOARD &&
|
||||
+ field->application != HID_CP_CONSUMER_CONTROL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
|
||||
index b4b8c6a..baf2bad 100644
|
||||
--- a/drivers/hid/usbhid/hid-quirks.c
|
||||
+++ b/drivers/hid/usbhid/hid-quirks.c
|
||||
@@ -98,7 +98,6 @@ static const struct hid_blacklist {
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS },
|
||||
- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
From dc16436c048a734bffabefb79508c39795f2a8bb Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Fri, 13 May 2016 15:52:20 +0200
|
||||
Subject: [PATCH 2/6] Input - soc_button_array: bail out earlier if gpiod_count
|
||||
is null
|
||||
|
||||
The PNP0C40 device of the Surface 3 doesn't have any GPIO attached to it.
|
||||
Instead of trying to access the GPIO, request the count beforehand and
|
||||
bail out if it is null or if an error is returned.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/input/misc/soc_button_array.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
|
||||
index bbd433c..5467d04 100644
|
||||
--- a/drivers/input/misc/soc_button_array.c
|
||||
+++ b/drivers/input/misc/soc_button_array.c
|
||||
@@ -167,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev)
|
||||
|
||||
button_info = (struct soc_button_info *)id->driver_data;
|
||||
|
||||
+ if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
|
||||
+ dev_info(&pdev->dev, "no GPIO attached, ignoring...\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,373 @@
|
|||
From 59131c2cc6f95e7517d73b2e8eefa890284ddf08 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Fri, 3 Jun 2016 18:41:02 +0200
|
||||
Subject: [PATCH 2/2] WIP: add custom surface3 platform device for controlling
|
||||
LID and hotplug
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/platform/x86/Kconfig | 12 ++
|
||||
drivers/platform/x86/Makefile | 1 +
|
||||
drivers/platform/x86/surface3-wmi.c | 315 ++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 328 insertions(+)
|
||||
create mode 100644 drivers/platform/x86/surface3-wmi.c
|
||||
|
||||
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
|
||||
index 3ec0025..376999b 100644
|
||||
--- a/drivers/platform/x86/Kconfig
|
||||
+++ b/drivers/platform/x86/Kconfig
|
||||
@@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP
|
||||
This is a driver for Lenovo IdeaPad netbooks contains drivers for
|
||||
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
|
||||
tristate "ThinkPad ACPI Laptop Extras"
|
||||
depends on ACPI
|
||||
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
|
||||
index 9b11b40..7324919 100644
|
||||
--- a/drivers/platform/x86/Makefile
|
||||
+++ b/drivers/platform/x86/Makefile
|
||||
@@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
|
||||
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi.o
|
||||
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
|
||||
+obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
|
||||
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
|
||||
|
||||
# toshiba_acpi must link after wmi to ensure that wmi devices are found
|
||||
diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c
|
||||
new file mode 100644
|
||||
index 0000000..92f7a38
|
||||
--- /dev/null
|
||||
+++ b/drivers/platform/x86/surface3-wmi.c
|
||||
@@ -0,0 +1,315 @@
|
||||
+/*
|
||||
+ * 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 platform_device *spi_master_pdev;
|
||||
+ struct acpi_device *spi_master_adev;
|
||||
+ 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)
|
||||
+{
|
||||
+ acpi_status status;
|
||||
+ union acpi_object *obj;
|
||||
+
|
||||
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
+
|
||||
+ 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);
|
||||
+ }
|
||||
+ kfree(obj);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ *ret = obj->integer.value;
|
||||
+ kfree(obj);
|
||||
+ mutex_unlock(&s3_wmi_lock);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+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(int *return_value)
|
||||
+{
|
||||
+ 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);
|
||||
+
|
||||
+ if (return_value)
|
||||
+ *return_value = lid_sw;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int s3_wmi_hp_notify(struct acpi_device *adev, u32 value)
|
||||
+{
|
||||
+ int ret, lid_sw;
|
||||
+ ret = s3_wmi_send_lid_state(&lid_sw);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (lid_sw) {
|
||||
+ platform_device_unregister(s3_wmi.spi_master_pdev);
|
||||
+ acpi_bus_trim(s3_wmi.spi_master_adev);
|
||||
+ } else {
|
||||
+ acpi_bus_scan(s3_wmi.spi_master_adev->handle);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+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.spi_master_pdev = to_platform_device(dev);
|
||||
+ s3_wmi.spi_master_adev = adev;
|
||||
+ 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(NULL);
|
||||
+
|
||||
+ 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(NULL);
|
||||
+ 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);
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
From bf221e0568393a86b1b41b5ceb313c2580976947 Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Just <stephenjust@gmail.com>
|
||||
Date: Tue, 28 Jun 2016 23:37:11 -0600
|
||||
Subject: [PATCH] power: surface3_power: Improve battery capacity reporting
|
||||
|
||||
Read additional registers from the battery device to get more
|
||||
accurate status reading. Also properly report battery (dis)charge
|
||||
state and current.
|
||||
---
|
||||
drivers/power/surface3_power.c | 55 ++++++++++++++++++++++++++++++++++++------
|
||||
1 file changed, 48 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/power/surface3_power.c b/drivers/power/surface3_power.c
|
||||
index eee21d3..ac8155b 100644
|
||||
--- a/drivers/power/surface3_power.c
|
||||
+++ b/drivers/power/surface3_power.c
|
||||
@@ -61,6 +61,7 @@ struct mshw0011_data {
|
||||
bool charging;
|
||||
bool bat_charging;
|
||||
u8 trip_point;
|
||||
+ s32 full_capacity;
|
||||
};
|
||||
|
||||
struct mshw0011_lookup {
|
||||
@@ -122,6 +123,10 @@ struct gsb_buffer {
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
+#define ACPI_BATTERY_STATE_DISCHARGING 0x1
|
||||
+#define ACPI_BATTERY_STATE_CHARGING 0x2
|
||||
+#define ACPI_BATTERY_STATE_CRITICAL 0x4
|
||||
+
|
||||
#define MSHW0011_CMD_DEST_BAT0 0x01
|
||||
#define MSHW0011_CMD_DEST_ADP1 0x03
|
||||
|
||||
@@ -140,11 +145,14 @@ struct gsb_buffer {
|
||||
|
||||
#define MSHW0011_NOTIFY_GET_VERSION 0x00
|
||||
#define MSHW0011_NOTIFY_ADP1 0x01
|
||||
-#define MSHW0011_NOTIFY_BAT0 0x02
|
||||
+#define MSHW0011_NOTIFY_BAT0_BST 0x02
|
||||
+#define MSHW0011_NOTIFY_BAT0_BIX 0x05
|
||||
|
||||
#define MSHW0011_ADP1_REG_PSR 0x03
|
||||
|
||||
-#define MSHW0011_BAT0_REG_CAPACITY 0x0c
|
||||
+#define MSHW0011_BAT0_REG_CAPACITY 0x0c
|
||||
+#define MSHW0011_BAT0_REG_FULL_CHG_CAPACITY 0x0e
|
||||
+#define MSHW0011_BAT0_REG_DESIGN_CAPACITY 0x40
|
||||
#define MSHW0011_BAT0_REG_VOLTAGE 0x08
|
||||
#define MSHW0011_BAT0_REG_RATE 0x14
|
||||
#define MSHW0011_BAT0_REG_OEM 0x45
|
||||
@@ -235,6 +243,22 @@ static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
|
||||
|
||||
*bix = default_bix;
|
||||
|
||||
+ /* get design capacity */
|
||||
+ ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_DESIGN_CAPACITY);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&client->dev, "Error reading design capacity: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ bix->design_capacity = le16_to_cpu(ret);
|
||||
+
|
||||
+ /* get last full charge capacity */
|
||||
+ ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_FULL_CHG_CAPACITY);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&client->dev, "Error reading last full charge capacity: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ bix->last_full_charg_capacity = le16_to_cpu(ret);
|
||||
+
|
||||
/* get serial number */
|
||||
ret = mshw0011_i2c_read_block(client, MSHW0011_BAT0_REG_SERIAL_NO,
|
||||
buf, 10);
|
||||
@@ -269,7 +293,7 @@ static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
|
||||
static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
|
||||
{
|
||||
struct i2c_client *client = cdata->bat0;
|
||||
- int rate, capacity, voltage;
|
||||
+ int rate, capacity, voltage, state;
|
||||
s16 tmp;
|
||||
|
||||
rate = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_RATE);
|
||||
@@ -285,8 +309,15 @@ static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
|
||||
return voltage;
|
||||
|
||||
tmp = le16_to_cpu(rate);
|
||||
- bst->battery_present_rate = (s32)tmp;
|
||||
- bst->battery_state = bst->battery_present_rate < 0 ? 0x01 : 0x02;
|
||||
+ bst->battery_present_rate = abs((s32)tmp);
|
||||
+
|
||||
+ state = 0;
|
||||
+ if ((s32) tmp > 0)
|
||||
+ state |= ACPI_BATTERY_STATE_CHARGING;
|
||||
+ else if ((s32) tmp < 0)
|
||||
+ state |= ACPI_BATTERY_STATE_DISCHARGING;
|
||||
+ bst->battery_state = state;
|
||||
+
|
||||
bst->battery_remaining_capacity = le16_to_cpu(capacity);
|
||||
bst->battery_present_voltage = le16_to_cpu(voltage);
|
||||
|
||||
@@ -308,6 +339,7 @@ static int mshw0011_adp_psr(struct mshw0011_data *cdata)
|
||||
static int mshw0011_isr(struct mshw0011_data *cdata)
|
||||
{
|
||||
struct bst bst;
|
||||
+ struct bix bix;
|
||||
int ret;
|
||||
bool status, bat_status;
|
||||
|
||||
@@ -327,14 +359,23 @@ static int mshw0011_isr(struct mshw0011_data *cdata)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- bat_status = bst.battery_present_rate >= 0;
|
||||
+ bat_status = bst.battery_state;
|
||||
|
||||
if (bat_status != cdata->bat_charging)
|
||||
mshw0011_notify(cdata, cdata->notify_version,
|
||||
- MSHW0011_NOTIFY_BAT0, &ret);
|
||||
+ MSHW0011_NOTIFY_BAT0_BST, &ret);
|
||||
|
||||
cdata->bat_charging = bat_status;
|
||||
|
||||
+ ret = mshw0011_bix(cdata, &bix);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ if (bix.last_full_charg_capacity != cdata->full_capacity)
|
||||
+ mshw0011_notify(cdata, cdata->notify_version,
|
||||
+ MSHW0011_NOTIFY_BAT0_BIX, &ret);
|
||||
+
|
||||
+ cdata->full_capacity = bix.last_full_charg_capacity;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From d4b0c0bfd2194496d7a72722829d4283ed5f3141 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Fri, 3 Jun 2016 11:49:17 +0200
|
||||
Subject: [PATCH 3/3] HID: multitouch: set correct class for Surface Type Cover
|
||||
3
|
||||
|
||||
Looks like Microsoft forgot to set the blob discriminating between Win 8
|
||||
and Win 7 devices...
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/hid/hid-multitouch.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
|
||||
index dd279d7..fa6622a 100644
|
||||
--- a/drivers/hid/hid-multitouch.c
|
||||
+++ b/drivers/hid/hid-multitouch.c
|
||||
@@ -1379,6 +1379,10 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
|
||||
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
|
||||
|
||||
+ /* Microsoft */
|
||||
+ { .driver_data = MT_CLS_WIN_8,
|
||||
+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x07cd) },
|
||||
+
|
||||
/* MosArt panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
From 3a6162d1b35218b4fc684a0c95e103ce68105bb5 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Mon, 9 May 2016 14:28:25 +0200
|
||||
Subject: [PATCH 3/6] Input - soc_button_array: make sure one GPIO is not
|
||||
assigned twice
|
||||
|
||||
The Surface 3 declares twice the GPIO as GpioInt and GpioIo in its
|
||||
ACPI table. Given that we do not keep the gpiod around, but the actual
|
||||
number associated to, there is a chance while enumerating the GPIOs that
|
||||
one gets assigned twice. Make sure a previous button has not been mapped
|
||||
already to the current button to prevent such failure.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/input/misc/soc_button_array.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
|
||||
index 5467d04..cb5cce3 100644
|
||||
--- a/drivers/input/misc/soc_button_array.c
|
||||
+++ b/drivers/input/misc/soc_button_array.c
|
||||
@@ -77,7 +77,7 @@ soc_button_device_create(struct platform_device *pdev,
|
||||
struct gpio_keys_platform_data *gpio_keys_pdata;
|
||||
int n_buttons = 0;
|
||||
int gpio;
|
||||
- int error;
|
||||
+ int i, error;
|
||||
|
||||
gpio_keys_pdata = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*gpio_keys_pdata) +
|
||||
@@ -96,6 +96,13 @@ soc_button_device_create(struct platform_device *pdev,
|
||||
if (!gpio_is_valid(gpio))
|
||||
continue;
|
||||
|
||||
+ for (i = 0; i < n_buttons; i++) {
|
||||
+ if (gpio_keys[i].gpio == gpio)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (i < n_buttons)
|
||||
+ continue; /* the GPIO has already been assigned */
|
||||
+
|
||||
gpio_keys[n_buttons].type = info->event_type;
|
||||
gpio_keys[n_buttons].code = info->event_code;
|
||||
gpio_keys[n_buttons].gpio = gpio;
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
From de9a764d3063d5c1743eab8b1a994b02119767a0 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Fri, 13 May 2016 15:54:15 +0200
|
||||
Subject: [PATCH 4/6] Input - soc_button_array: allow to specify active_low
|
||||
|
||||
The Surface 3 has the "Windows" key active high, and not low. We need
|
||||
a way to specify it in the description.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/input/misc/soc_button_array.c | 13 +++++++------
|
||||
1 file changed, 7 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
|
||||
index cb5cce3..077e06e4 100644
|
||||
--- a/drivers/input/misc/soc_button_array.c
|
||||
+++ b/drivers/input/misc/soc_button_array.c
|
||||
@@ -34,6 +34,7 @@ struct soc_button_info {
|
||||
unsigned int event_code;
|
||||
bool autorepeat;
|
||||
bool wakeup;
|
||||
+ bool active_low;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -106,7 +107,7 @@ soc_button_device_create(struct platform_device *pdev,
|
||||
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 = 1;
|
||||
+ 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++;
|
||||
@@ -206,11 +207,11 @@ static int soc_button_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static struct soc_button_info soc_button_PNP0C40[] = {
|
||||
- { "power", 0, EV_KEY, KEY_POWER, false, true },
|
||||
- { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
|
||||
- { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
|
||||
- { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
|
||||
- { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
|
||||
+ { "power", 0, EV_KEY, KEY_POWER, false, true, true },
|
||||
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
|
||||
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
|
||||
+ { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
|
||||
+ { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false, true },
|
||||
{ }
|
||||
};
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
From 7423522630722f7aad88afb097776e41b52d1b22 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Fri, 13 May 2016 15:56:56 +0200
|
||||
Subject: [PATCH 5/6] Input - soc_button_array: export part of the internals
|
||||
|
||||
The MS Surfaces are not directly using the PNP0C40 device for the buttons
|
||||
but instead a MSHW0028. This one is bound on a I2C bus and so we need to
|
||||
use a separate driver for it.
|
||||
|
||||
One noticeable change is that the original soc_button_array fails
|
||||
to rmmod and then modprobe when using KBUILD_MODNAME as the gpiod con_id
|
||||
with the Surface 3. Add this as a parameter of the new API.
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/input/misc/soc_button_array.c | 108 +++++++++++++++++++--------------
|
||||
include/linux/input/soc_button_array.h | 37 +++++++++++
|
||||
2 files changed, 98 insertions(+), 47 deletions(-)
|
||||
create mode 100644 include/linux/input/soc_button_array.h
|
||||
|
||||
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
|
||||
index 077e06e4..96012f9 100644
|
||||
--- a/drivers/input/misc/soc_button_array.c
|
||||
+++ b/drivers/input/misc/soc_button_array.c
|
||||
@@ -19,23 +19,7 @@
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
-
|
||||
-/*
|
||||
- * Definition of buttons on the tablet. The ACPI index of each button
|
||||
- * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
|
||||
- * Platforms"
|
||||
- */
|
||||
-#define MAX_NBUTTONS 5
|
||||
-
|
||||
-struct soc_button_info {
|
||||
- const char *name;
|
||||
- int acpi_index;
|
||||
- unsigned int event_type;
|
||||
- unsigned int event_code;
|
||||
- bool autorepeat;
|
||||
- bool wakeup;
|
||||
- bool active_low;
|
||||
-};
|
||||
+#include <linux/input/soc_button_array.h>
|
||||
|
||||
/*
|
||||
* Some of the buttons like volume up/down are auto repeat, while others
|
||||
@@ -51,12 +35,13 @@ struct soc_button_data {
|
||||
/*
|
||||
* Get the Nth GPIO number from the ACPI object.
|
||||
*/
|
||||
-static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
|
||||
+static int soc_button_lookup_gpio(struct device *dev, const char *con_id,
|
||||
+ int acpi_index)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
int gpio;
|
||||
|
||||
- desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index, GPIOD_ASIS);
|
||||
+ desc = gpiod_get_index(dev, con_id, acpi_index, GPIOD_ASIS);
|
||||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
|
||||
@@ -68,7 +53,8 @@ static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
|
||||
}
|
||||
|
||||
static struct platform_device *
|
||||
-soc_button_device_create(struct platform_device *pdev,
|
||||
+soc_button_device_create(struct device *dev,
|
||||
+ const char *gpiod_con_id,
|
||||
const struct soc_button_info *button_info,
|
||||
bool autorepeat)
|
||||
{
|
||||
@@ -80,7 +66,7 @@ soc_button_device_create(struct platform_device *pdev,
|
||||
int gpio;
|
||||
int i, error;
|
||||
|
||||
- gpio_keys_pdata = devm_kzalloc(&pdev->dev,
|
||||
+ gpio_keys_pdata = devm_kzalloc(dev,
|
||||
sizeof(*gpio_keys_pdata) +
|
||||
sizeof(*gpio_keys) * MAX_NBUTTONS,
|
||||
GFP_KERNEL);
|
||||
@@ -93,7 +79,9 @@ soc_button_device_create(struct platform_device *pdev,
|
||||
if (info->autorepeat != autorepeat)
|
||||
continue;
|
||||
|
||||
- gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
|
||||
+ gpio = soc_button_lookup_gpio(dev,
|
||||
+ gpiod_con_id,
|
||||
+ info->acpi_index);
|
||||
if (!gpio_is_valid(gpio))
|
||||
continue;
|
||||
|
||||
@@ -142,14 +130,12 @@ soc_button_device_create(struct platform_device *pdev,
|
||||
err_free_pdev:
|
||||
platform_device_put(pd);
|
||||
err_free_mem:
|
||||
- devm_kfree(&pdev->dev, gpio_keys_pdata);
|
||||
+ devm_kfree(dev, gpio_keys_pdata);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
-static int soc_button_remove(struct platform_device *pdev)
|
||||
+int soc_dev_button_remove(struct soc_button_data *priv)
|
||||
{
|
||||
- struct soc_button_data *priv = platform_get_drvdata(pdev);
|
||||
-
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUTTON_TYPES; i++)
|
||||
@@ -158,40 +144,28 @@ static int soc_button_remove(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(soc_dev_button_remove);
|
||||
|
||||
-static int soc_button_probe(struct platform_device *pdev)
|
||||
+int soc_dev_button_enumerate(struct device *dev, struct soc_button_data *priv,
|
||||
+ const char *gpiod_con_id,
|
||||
+ struct soc_button_info *button_info)
|
||||
{
|
||||
- struct device *dev = &pdev->dev;
|
||||
- const struct acpi_device_id *id;
|
||||
- struct soc_button_info *button_info;
|
||||
- struct soc_button_data *priv;
|
||||
struct platform_device *pd;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
- id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
- if (!id)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- button_info = (struct soc_button_info *)id->driver_data;
|
||||
-
|
||||
- if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
|
||||
- dev_info(&pdev->dev, "no GPIO attached, ignoring...\n");
|
||||
+ if (gpiod_count(dev, gpiod_con_id) <= 0) {
|
||||
+ dev_info(dev, "no GPIO attached, ignoring...\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
- if (!priv)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- platform_set_drvdata(pdev, priv);
|
||||
-
|
||||
for (i = 0; i < BUTTON_TYPES; i++) {
|
||||
- pd = soc_button_device_create(pdev, button_info, i == 0);
|
||||
+ pd = soc_button_device_create(dev, gpiod_con_id, button_info,
|
||||
+ i == 0);
|
||||
if (IS_ERR(pd)) {
|
||||
error = PTR_ERR(pd);
|
||||
if (error != -ENODEV) {
|
||||
- soc_button_remove(pdev);
|
||||
+ soc_dev_button_remove(priv);
|
||||
return error;
|
||||
}
|
||||
continue;
|
||||
@@ -205,6 +179,46 @@ static int soc_button_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(soc_dev_button_enumerate);
|
||||
+
|
||||
+struct soc_button_data *soc_dev_button_data_allocate(struct device *dev)
|
||||
+{
|
||||
+ return devm_kzalloc(dev, sizeof(struct soc_button_data), GFP_KERNEL);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(soc_dev_button_data_allocate);
|
||||
+
|
||||
+static int soc_button_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ const struct acpi_device_id *id;
|
||||
+ struct soc_button_info *button_info;
|
||||
+ struct soc_button_data *priv;
|
||||
+ int error;
|
||||
+
|
||||
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
+ if (!id)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ button_info = (struct soc_button_info *)id->driver_data;
|
||||
+
|
||||
+ priv = soc_dev_button_data_allocate(dev);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ error = soc_dev_button_enumerate(dev, priv, KBUILD_MODNAME,
|
||||
+ button_info);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int soc_button_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ return soc_dev_button_remove(platform_get_drvdata(pdev));
|
||||
+}
|
||||
|
||||
static struct soc_button_info soc_button_PNP0C40[] = {
|
||||
{ "power", 0, EV_KEY, KEY_POWER, false, true, true },
|
||||
diff --git a/include/linux/input/soc_button_array.h b/include/linux/input/soc_button_array.h
|
||||
new file mode 100644
|
||||
index 0000000..634ce90
|
||||
--- /dev/null
|
||||
+++ b/include/linux/input/soc_button_array.h
|
||||
@@ -0,0 +1,37 @@
|
||||
+/*
|
||||
+ * Supports for the button array on SoC tablets originally running
|
||||
+ * Windows 8.
|
||||
+ *
|
||||
+ * (C) Copyright 2014 Intel Corporation
|
||||
+ * (C) Copyright 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.
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * Definition of buttons on the tablet. The ACPI index of each button
|
||||
+ * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
|
||||
+ * Platforms"
|
||||
+ */
|
||||
+#define MAX_NBUTTONS 5
|
||||
+
|
||||
+struct soc_button_info {
|
||||
+ const char *name;
|
||||
+ int acpi_index;
|
||||
+ unsigned int event_type;
|
||||
+ unsigned int event_code;
|
||||
+ bool autorepeat;
|
||||
+ bool wakeup;
|
||||
+ bool active_low;
|
||||
+};
|
||||
+
|
||||
+struct soc_button_data;
|
||||
+
|
||||
+struct soc_button_data *soc_dev_button_data_allocate(struct device *dev);
|
||||
+int soc_dev_button_remove(struct soc_button_data *priv);
|
||||
+int soc_dev_button_enumerate(struct device *dev, struct soc_button_data *priv,
|
||||
+ const char *gpiod_con_id,
|
||||
+ struct soc_button_info *button_info);
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
From d25373cf47d005fbab3b363a32fa9d890ead1a51 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Fri, 13 May 2016 17:54:09 +0200
|
||||
Subject: [PATCH 6/6] Input - surface3_button_array: Introduce button support
|
||||
for the Surface 3
|
||||
|
||||
The Surface 3 is not following the ACPI spec for PNP0C40, but nearly.
|
||||
The device is connected to a I2C device that might have some magic
|
||||
but we don't know about.
|
||||
Just create the device after the enumeration and use the declared GPIOs
|
||||
to provide button support.
|
||||
|
||||
The Surface Pro 3 is using an ACPI driver and matches against the bid
|
||||
of the device ("VGBI") but I think it also could use this. To prevent
|
||||
this driver to be used on the Surface Pro, we add a match on the
|
||||
Surface 3 bid "TEV2".
|
||||
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
---
|
||||
drivers/input/misc/Kconfig | 9 +++
|
||||
drivers/input/misc/Makefile | 1 +
|
||||
drivers/input/misc/surface3_button_array.c | 115 +++++++++++++++++++++++++++++
|
||||
3 files changed, 125 insertions(+)
|
||||
create mode 100644 drivers/input/misc/surface3_button_array.c
|
||||
|
||||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
|
||||
index efb0ca8..6f99d3b 100644
|
||||
--- a/drivers/input/misc/Kconfig
|
||||
+++ b/drivers/input/misc/Kconfig
|
||||
@@ -776,6 +776,15 @@ config INPUT_SOC_BUTTON_ARRAY
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called soc_button_array.
|
||||
|
||||
+config INPUT_SURFACE3_BUTTON_ARRAY
|
||||
+ tristate "Microsoft Surface 3 SoC Button Array"
|
||||
+ depends on INPUT_SOC_BUTTON_ARRAY
|
||||
+ help
|
||||
+ Say Y here if you have a MS Surface tablet.
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the
|
||||
+ module will be called surface3_button_array.
|
||||
+
|
||||
config INPUT_DRV260X_HAPTICS
|
||||
tristate "TI DRV260X haptics support"
|
||||
depends on INPUT && I2C
|
||||
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
|
||||
index 6a1e5e2..020b24a 100644
|
||||
--- a/drivers/input/misc/Makefile
|
||||
+++ b/drivers/input/misc/Makefile
|
||||
@@ -67,6 +67,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
|
||||
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
|
||||
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
|
||||
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
|
||||
+obj-$(CONFIG_INPUT_SURFACE3_BUTTON_ARRAY) += surface3_button_array.o
|
||||
obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
|
||||
diff --git a/drivers/input/misc/surface3_button_array.c b/drivers/input/misc/surface3_button_array.c
|
||||
new file mode 100644
|
||||
index 0000000..b48307c
|
||||
--- /dev/null
|
||||
+++ b/drivers/input/misc/surface3_button_array.c
|
||||
@@ -0,0 +1,115 @@
|
||||
+/*
|
||||
+ * Supports for the button array on the Surface tablets.
|
||||
+ *
|
||||
+ * (C) Copyright 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/i2c.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/acpi.h>
|
||||
+#include <linux/input/soc_button_array.h>
|
||||
+#include <uapi/linux/input-event-codes.h>
|
||||
+
|
||||
+struct soc_device_info {
|
||||
+ const char * const *obj_names;
|
||||
+ struct soc_button_info *buttons;
|
||||
+};
|
||||
+
|
||||
+static int surface3_probe(struct i2c_client *client,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ const char *bid, *obj_name;
|
||||
+ struct soc_device_info *device_info;
|
||||
+ struct soc_button_data *priv;
|
||||
+ int error;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!id->driver_data)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ device_info = (struct soc_device_info *)id->driver_data;
|
||||
+
|
||||
+ if (device_info->obj_names) {
|
||||
+ bid = acpi_device_bid(ACPI_COMPANION(&client->dev));
|
||||
+ i = 0;
|
||||
+ do {
|
||||
+ obj_name = device_info->obj_names[i++];
|
||||
+ if (obj_name && !strcmp(bid, obj_name))
|
||||
+ break;
|
||||
+ } while (obj_name);
|
||||
+ /* no acpi_device_bid match, bail out */
|
||||
+ if (!obj_name)
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ priv = soc_dev_button_data_allocate(&client->dev);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ error = soc_dev_button_enumerate(&client->dev, priv, NULL,
|
||||
+ device_info->buttons);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ i2c_set_clientdata(client, priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int surface3_remove(struct i2c_client *client)
|
||||
+{
|
||||
+ return soc_dev_button_remove(i2c_get_clientdata(client));
|
||||
+}
|
||||
+
|
||||
+static struct soc_button_info soc_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 const char * const soc_device_obj_names_surface3[] = {
|
||||
+ "TEV2",
|
||||
+ 0,
|
||||
+};
|
||||
+
|
||||
+static const struct soc_device_info soc_device_surface3 = {
|
||||
+ .obj_names = soc_device_obj_names_surface3,
|
||||
+ .buttons = soc_button_surface3,
|
||||
+};
|
||||
+
|
||||
+static const struct i2c_device_id surface3_id[] = {
|
||||
+ { "MSHW0028:00", (unsigned long)&soc_device_surface3 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, surface3_id);
|
||||
+
|
||||
+#ifdef CONFIG_ACPI
|
||||
+static const struct acpi_device_id surface3_acpi_match[] = {
|
||||
+ { "MSHW0028", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(acpi, surface3_acpi_match);
|
||||
+#endif
|
||||
+
|
||||
+static struct i2c_driver surface3_driver = {
|
||||
+ .probe = surface3_probe,
|
||||
+ .remove = surface3_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");
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From 5d554ea4f287665b839975ecb11bd29d49a5c9b5 Mon Sep 17 00:00:00 2001
|
||||
From: Vinod Koul <vinod.koul@intel.com>
|
||||
Date: Fri, 8 Jul 2016 18:30:17 +0530
|
||||
Subject: ASoC: Intel: cht: fix uninit variable warning
|
||||
|
||||
Kbuild bot reports that we might use dai_index uninitialized.
|
||||
|
||||
sound/soc/intel/boards/cht_bsw_rt5645.c:391:37: warning: 'dai_index' may be used uninitialized in this function [-Wmaybe-uninitialized]
|
||||
|
||||
Since it is theoretically possible, set it while initializing.
|
||||
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
sound/soc/intel/boards/cht_bsw_rt5645.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
|
||||
index f26c7b8..56056ed 100644
|
||||
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
|
||||
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
|
||||
@@ -357,7 +357,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
char codec_name[16];
|
||||
struct sst_acpi_mach *mach;
|
||||
const char *i2c_name = NULL;
|
||||
- int dai_index;
|
||||
+ int dai_index = 0;
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
|
||||
if (!drv)
|
||||
--
|
||||
cgit v0.12
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
From patchwork Fri Jul 15 13:37:04 2016
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [1/2] mwifiex: fix PCIe legacy interrupt problem
|
||||
From: Amitkumar Karwar <akarwar@marvell.com>
|
||||
X-Patchwork-Id: 9232091
|
||||
Message-Id: <1468589825-9188-1-git-send-email-akarwar@marvell.com>
|
||||
To: <linux-wireless@vger.kernel.org>
|
||||
Cc: Cathy Luo <cluo@marvell.com>, Nishant Sarmukadam <nishants@marvell.com>,
|
||||
Amitkumar Karwar <akarwar@marvell.com>
|
||||
Date: Fri, 15 Jul 2016 19:07:04 +0530
|
||||
|
||||
In corner case, we may end up processing same interrupt twice.
|
||||
We have a logic to read pending interrupts at the end of interrupt
|
||||
processing routine. It has a race with interrupts read in interrupt
|
||||
handler. This patch solves the problem by ORing the interrupt bitmap
|
||||
in this case.
|
||||
|
||||
The symptom for this bug is below messages in dmesg log.
|
||||
|
||||
[ 11.522123] mwifiex_pcie 0000:01:00.0: CMD_RESP: invalid cmd resp
|
||||
[ 11.680412] mwifiex_pcie 0000:01:00.0: There is no command but got cmdrsp
|
||||
|
||||
Link: https://bugzilla.kernel.org/show_bug.cgi?id=109681
|
||||
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
|
||||
Signed-off-by: Cathy Luo <cluo@marvell.com>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index d61d4ad..38bd62e 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -2300,6 +2300,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
|
||||
}
|
||||
|
||||
}
|
||||
+ if (!card->msi_enable) {
|
||||
+ spin_lock_irqsave(&adapter->int_lock, flags);
|
||||
+ pcie_ireg |= adapter->int_status;
|
||||
+ adapter->int_status = 0;
|
||||
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||
+ }
|
||||
}
|
||||
mwifiex_dbg(adapter, INTR,
|
||||
"info: cmd_sent=%d data_sent=%d\n",
|
|
@ -0,0 +1,34 @@
|
|||
From patchwork Fri Jul 15 13:37:05 2016
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [2/2] mwifiex: update command response skb length correctly
|
||||
From: Amitkumar Karwar <akarwar@marvell.com>
|
||||
X-Patchwork-Id: 9232093
|
||||
Message-Id: <1468589825-9188-2-git-send-email-akarwar@marvell.com>
|
||||
To: <linux-wireless@vger.kernel.org>
|
||||
Cc: Cathy Luo <cluo@marvell.com>, Nishant Sarmukadam <nishants@marvell.com>,
|
||||
Amitkumar Karwar <akarwar@marvell.com>
|
||||
Date: Fri, 15 Jul 2016 19:07:05 +0530
|
||||
|
||||
Same skb is being reused for storing command response from firmware
|
||||
in PCIe chipsets. There was a bug while updating the skb length.
|
||||
This patch ensures skb length correctly gets updated based on rx_len.
|
||||
|
||||
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index 38bd62e..a6af85d 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -1616,6 +1616,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
|
||||
|
||||
pkt_len = *((__le16 *)skb->data);
|
||||
rx_len = le16_to_cpu(pkt_len);
|
||||
+ skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
|
||||
skb_trim(skb, rx_len);
|
||||
skb_pull(skb, INTF_HEADER_LEN);
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
From d41376ca8ba74e954ba931c69271d0b29546a202 Mon Sep 17 00:00:00 2001
|
||||
From: Brian Norris <briannorris@chromium.org>
|
||||
Date: Thu, 30 Jun 2016 15:21:02 -0700
|
||||
Subject: mwifiex: mask PCIe interrupts before removal
|
||||
|
||||
The PCIe driver didn't mask the host interrupts before trying to tear
|
||||
down. This causes lockups at reboot or rmmod when using MSI-X on 8997,
|
||||
since the MSI handler gets confused and locks up the system.
|
||||
|
||||
Also tested on 8897, which does not support MSI-X (and wasn't
|
||||
experiencing this same bug). No regressions seen there.
|
||||
|
||||
Signed-off-by: Brian Norris <briannorris@chromium.org>
|
||||
Tested-by: Douglas Anderson <dianders@chromium.org>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index 012733c..c7f5df8 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -440,6 +440,11 @@ static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void mwifiex_pcie_disable_host_int_noerr(struct mwifiex_adapter *adapter)
|
||||
+{
|
||||
+ WARN_ON(mwifiex_pcie_disable_host_int(adapter));
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* This function enables the host interrupt.
|
||||
*
|
||||
@@ -2946,6 +2951,7 @@ static struct mwifiex_if_ops pcie_ops = {
|
||||
.register_dev = mwifiex_register_dev,
|
||||
.unregister_dev = mwifiex_unregister_dev,
|
||||
.enable_int = mwifiex_pcie_enable_host_int,
|
||||
+ .disable_int = mwifiex_pcie_disable_host_int_noerr,
|
||||
.process_int_status = mwifiex_process_int_status,
|
||||
.host_to_card = mwifiex_pcie_host_to_card,
|
||||
.wakeup = mwifiex_pm_wakeup_card,
|
||||
--
|
||||
cgit v0.12
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From 24dad509ed5528bbbe31ff17f9fb39c0473ec8f4 Mon Sep 17 00:00:00 2001
|
||||
From: Vinod Koul <vinod.koul@intel.com>
|
||||
Date: Fri, 8 Jul 2016 18:30:18 +0530
|
||||
Subject: ASoC: Intel: atom: statify cht_quirk
|
||||
|
||||
Sparse rightly warns:
|
||||
sound/soc/intel/atom/sst/sst_acpi.c:353:22: warning: symbol 'cht_quirk' was not declared. Should it be static?
|
||||
|
||||
So statify this
|
||||
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
sound/soc/intel/atom/sst/sst_acpi.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
|
||||
index 82a374d..4d31849 100644
|
||||
--- a/sound/soc/intel/atom/sst/sst_acpi.c
|
||||
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
|
||||
@@ -350,7 +350,7 @@ static struct sst_acpi_mach cht_surface_mach = {
|
||||
"10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data };
|
||||
|
||||
-struct sst_acpi_mach *cht_quirk(void *arg)
|
||||
+static struct sst_acpi_mach *cht_quirk(void *arg)
|
||||
{
|
||||
struct sst_acpi_mach *mach = arg;
|
||||
|
||||
--
|
||||
cgit v0.12
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From 141bcf099076df1a74317a5b14dcd56c933b9de8 Mon Sep 17 00:00:00 2001
|
||||
From: Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
Date: Wed, 18 May 2016 01:16:01 +0200
|
||||
Subject: mwiflex: avoid possible null pointer dereference
|
||||
|
||||
Do not dereference card before checking against NULL value.
|
||||
|
||||
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index 9246ce8..a35db02 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -2901,10 +2901,11 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
const struct mwifiex_pcie_card_reg *reg;
|
||||
- struct pci_dev *pdev = card->dev;
|
||||
+ struct pci_dev *pdev;
|
||||
int i;
|
||||
|
||||
if (card) {
|
||||
+ pdev = card->dev;
|
||||
if (card->msix_enable) {
|
||||
for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
|
||||
synchronize_irq(card->msix_entries[i].vector);
|
||||
--
|
||||
cgit v0.12
|
||||
|
|
@ -0,0 +1,356 @@
|
|||
From vinod.koul@intel.com Fri Jul 8 12:03:22 2016
|
||||
Return-Path: <vinod.koul@intel.com>
|
||||
Delivered-To: hadess@hadess.net
|
||||
Received: from spool.mail.gandi.net (mspool1-d.mgt.gandi.net [10.0.21.131])
|
||||
by nmboxes111.sd2.0x35.net (Postfix) with ESMTP id 79E3B21C96
|
||||
for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
|
||||
Received: from mfilter40-d.gandi.net (mfilter40-d.gandi.net
|
||||
[217.70.178.171]) by spool.mail.gandi.net (Postfix) with ESMTP id
|
||||
700992260FC for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
|
||||
X-Virus-Scanned: Debian amavisd-new at mfilter40-d.gandi.net
|
||||
Received: from spool.mail.gandi.net ([IPv6:::ffff:10.0.21.131]) by
|
||||
mfilter40-d.gandi.net (mfilter40-d.gandi.net [::ffff:10.0.15.180])
|
||||
(amavisd-new, port 10024) with ESMTP id qK5K-waPj4Ol for
|
||||
<hadess@hadess.net>; Fri, 8 Jul 2016 12:03:20 +0200 (CEST)
|
||||
Received: from mga14.intel.com (mga14.intel.com [192.55.52.115])
|
||||
by spool.mail.gandi.net (Postfix) with ESMTP id D6DE42260D7
|
||||
for <bugzilla@hadess.net>; Fri, 8 Jul 2016 12:03:09 +0200 (CEST)
|
||||
Received: from fmsmga003.fm.intel.com ([10.253.24.29])
|
||||
by fmsmga103.fm.intel.com with ESMTP; 08 Jul 2016 03:02:59 -0700
|
||||
X-ExtLoop1: 1
|
||||
X-IronPort-AV: E=Sophos;i="5.28,329,1464678000";
|
||||
d="scan'208";a="731352416"
|
||||
Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143])
|
||||
by FMSMGA003.fm.intel.com with ESMTP; 08 Jul 2016 03:02:55 -0700
|
||||
From: Vinod Koul <vinod.koul@intel.com>
|
||||
To: alsa-devel@alsa-project.org
|
||||
Cc: broonie@kernel.org,
|
||||
liam.r.girdwood@linux.intel.com,
|
||||
patches.audio@intel.com,
|
||||
Stephen Just <stephenjust@gmail.com>,
|
||||
Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>,
|
||||
apterix@gmail.com,
|
||||
bugzilla@hadess.net,
|
||||
Vinod Koul <vinod.koul@intel.com>,
|
||||
Sachin Mokashi <sachinx.mokashi@intel.com>
|
||||
Subject: [PATCH 1/3] ASoC: Intel: Atom: Add quirk for Surface 3
|
||||
Date: Fri, 8 Jul 2016 15:39:49 +0530
|
||||
Message-Id: <1467972591-29175-2-git-send-email-vinod.koul@intel.com>
|
||||
X-Mailer: git-send-email 1.9.1
|
||||
In-Reply-To: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
|
||||
References: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
|
||||
X-Evolution-Source: 1353784233.13280.3@sirocco.hadess.net
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Mime-Version: 1.0
|
||||
|
||||
Surface 3 is CHT based device which shows up with RT5645 codec. But the
|
||||
BIOS reports ACPI ID as 5640!
|
||||
|
||||
To solve this, add a DMI overide for cht-5640 machine.
|
||||
|
||||
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=98001
|
||||
Signed-off-by: Sachin Mokashi <sachinx.mokashi@intel.com>
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
---
|
||||
sound/soc/intel/atom/sst/sst_acpi.c | 44 ++++++++++++++++++++++++++++++++++++-
|
||||
sound/soc/intel/common/sst-acpi.h | 2 +-
|
||||
2 files changed, 44 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
|
||||
index 3bc4b63b2f9d..82a374d885a7 100644
|
||||
--- a/sound/soc/intel/atom/sst/sst_acpi.c
|
||||
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_qos.h>
|
||||
+#include <linux/dmi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/platform_sst_audio.h>
|
||||
#include <sound/core.h>
|
||||
@@ -237,6 +238,9 @@ static int sst_acpi_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "No matching machine driver found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
+ if (mach->machine_quirk)
|
||||
+ mach = mach->machine_quirk(mach);
|
||||
+
|
||||
pdata = mach->pdata;
|
||||
|
||||
ret = kstrtouint(id->id, 16, &dev_id);
|
||||
@@ -320,6 +324,44 @@ static int sst_acpi_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static unsigned long cht_machine_id;
|
||||
+
|
||||
+#define CHT_SURFACE_MACH 1
|
||||
+
|
||||
+static int cht_surface_quirk_cb(const struct dmi_system_id *id)
|
||||
+{
|
||||
+ cht_machine_id = CHT_SURFACE_MACH;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const struct dmi_system_id cht_table[] = {
|
||||
+ {
|
||||
+ .callback = cht_surface_quirk_cb,
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static struct sst_acpi_mach cht_surface_mach = {
|
||||
+ "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
+ &chv_platform_data };
|
||||
+
|
||||
+struct sst_acpi_mach *cht_quirk(void *arg)
|
||||
+{
|
||||
+ struct sst_acpi_mach *mach = arg;
|
||||
+
|
||||
+ dmi_check_system(cht_table);
|
||||
+
|
||||
+ if (cht_machine_id == CHT_SURFACE_MACH)
|
||||
+ return &cht_surface_mach;
|
||||
+ else
|
||||
+ return mach;
|
||||
+}
|
||||
+
|
||||
static struct sst_acpi_mach sst_acpi_bytcr[] = {
|
||||
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
@@ -343,7 +385,7 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
|
||||
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
|
||||
- {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL,
|
||||
+ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
|
||||
&chv_platform_data },
|
||||
|
||||
{},
|
||||
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
|
||||
index 8398cb227ba9..504b0e4fedd4 100644
|
||||
--- a/sound/soc/intel/common/sst-acpi.h
|
||||
+++ b/sound/soc/intel/common/sst-acpi.h
|
||||
@@ -40,6 +40,6 @@ struct sst_acpi_mach {
|
||||
|
||||
/* board name */
|
||||
const char *board;
|
||||
- void (*machine_quirk)(void);
|
||||
+ struct sst_acpi_mach * (*machine_quirk)(void *arg);
|
||||
void *pdata;
|
||||
};
|
||||
--
|
||||
1.9.1
|
||||
|
||||
|
||||
From vinod.koul@intel.com Fri Jul 8 12:03:22 2016
|
||||
Return-Path: <vinod.koul@intel.com>
|
||||
Delivered-To: hadess@hadess.net
|
||||
Received: from spool.mail.gandi.net (mspool1-d.mgt.gandi.net [10.0.21.131])
|
||||
by nmboxes111.sd2.0x35.net (Postfix) with ESMTP id 94C7121C96
|
||||
for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
|
||||
Received: from mfilter49-d.gandi.net (mfilter49-d.gandi.net
|
||||
[217.70.178.180]) by spool.mail.gandi.net (Postfix) with ESMTP id
|
||||
9155C226069 for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
|
||||
X-Virus-Scanned: Debian amavisd-new at mfilter49-d.gandi.net
|
||||
Received: from spool.mail.gandi.net ([IPv6:::ffff:10.0.21.131]) by
|
||||
mfilter49-d.gandi.net (mfilter49-d.gandi.net [::ffff:10.0.15.180])
|
||||
(amavisd-new, port 10024) with ESMTP id DHVDC0Ilq6FQ for
|
||||
<hadess@hadess.net>; Fri, 8 Jul 2016 12:03:20 +0200 (CEST)
|
||||
Received: from mga14.intel.com (mga14.intel.com [192.55.52.115])
|
||||
by spool.mail.gandi.net (Postfix) with ESMTP id 709442260E5
|
||||
for <bugzilla@hadess.net>; Fri, 8 Jul 2016 12:03:10 +0200 (CEST)
|
||||
Received: from fmsmga003.fm.intel.com ([10.253.24.29])
|
||||
by fmsmga103.fm.intel.com with ESMTP; 08 Jul 2016 03:03:02 -0700
|
||||
X-ExtLoop1: 1
|
||||
X-IronPort-AV: E=Sophos;i="5.28,329,1464678000";
|
||||
d="scan'208";a="731352436"
|
||||
Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143])
|
||||
by FMSMGA003.fm.intel.com with ESMTP; 08 Jul 2016 03:02:58 -0700
|
||||
From: Vinod Koul <vinod.koul@intel.com>
|
||||
To: alsa-devel@alsa-project.org
|
||||
Cc: broonie@kernel.org,
|
||||
liam.r.girdwood@linux.intel.com,
|
||||
patches.audio@intel.com,
|
||||
Stephen Just <stephenjust@gmail.com>,
|
||||
Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>,
|
||||
apterix@gmail.com,
|
||||
bugzilla@hadess.net,
|
||||
Vinod Koul <vinod.koul@intel.com>,
|
||||
Sachin Mokashi <sachinx.mokashi@intel.com>
|
||||
Subject: [PATCH 2/3] ASoC: rt5645: Add ACPI ID 10EC5640
|
||||
Date: Fri, 8 Jul 2016 15:39:50 +0530
|
||||
Message-Id: <1467972591-29175-3-git-send-email-vinod.koul@intel.com>
|
||||
X-Mailer: git-send-email 1.9.1
|
||||
In-Reply-To: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
|
||||
References: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
|
||||
X-Evolution-Source: 1353784233.13280.3@sirocco.hadess.net
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Mime-Version: 1.0
|
||||
|
||||
Some CHT platforms use RT5645 codec which has entry 10EC5640 so add it.
|
||||
Also add DMI quirk for jack detection.
|
||||
|
||||
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=98001
|
||||
Signed-off-by: Sachin Mokashi <sachinx.mokashi@intel.com>
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
[Jack detection]
|
||||
Suggested-by: Stephen Just <stephenjust@gmail.com>
|
||||
---
|
||||
sound/soc/codecs/rt5645.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
|
||||
index 3c6594da6c9c..761ca88c4cdd 100644
|
||||
--- a/sound/soc/codecs/rt5645.c
|
||||
+++ b/sound/soc/codecs/rt5645.c
|
||||
@@ -3531,6 +3531,7 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
|
||||
static const struct acpi_device_id rt5645_acpi_match[] = {
|
||||
{ "10EC5645", 0 },
|
||||
{ "10EC5650", 0 },
|
||||
+ { "10EC5640", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
|
||||
@@ -3561,6 +3562,12 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"),
|
||||
},
|
||||
},
|
||||
+ {
|
||||
+ .ident = "Microsoft Surface 3",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
|
||||
+ },
|
||||
+ },
|
||||
{ }
|
||||
};
|
||||
|
||||
--
|
||||
1.9.1
|
||||
|
||||
|
||||
From vinod.koul@intel.com Fri Jul 8 12:03:25 2016
|
||||
Return-Path: <vinod.koul@intel.com>
|
||||
Delivered-To: hadess@hadess.net
|
||||
Received: from spool.mail.gandi.net (mspool7-d.mgt.gandi.net [10.0.21.138])
|
||||
by nmboxes111.sd2.0x35.net (Postfix) with ESMTP id E535621C96
|
||||
for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:25 +0200 (CEST)
|
||||
Received: from mfilter17-d.gandi.net (mfilter17-d.gandi.net
|
||||
[217.70.178.145]) by spool.mail.gandi.net (Postfix) with ESMTP id
|
||||
E2A5419F3BC for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:25 +0200 (CEST)
|
||||
X-Virus-Scanned: Debian amavisd-new at mfilter17-d.gandi.net
|
||||
Received: from spool.mail.gandi.net ([IPv6:::ffff:10.0.21.138]) by
|
||||
mfilter17-d.gandi.net (mfilter17-d.gandi.net [::ffff:10.0.15.180])
|
||||
(amavisd-new, port 10024) with ESMTP id iqTV1YWaYo1Y for
|
||||
<hadess@hadess.net>; Fri, 8 Jul 2016 12:03:24 +0200 (CEST)
|
||||
Received: from mga14.intel.com (mga14.intel.com [192.55.52.115])
|
||||
by spool.mail.gandi.net (Postfix) with ESMTP id E5E3A19F3E5
|
||||
for <bugzilla@hadess.net>; Fri, 8 Jul 2016 12:03:10 +0200 (CEST)
|
||||
Received: from fmsmga003.fm.intel.com ([10.253.24.29])
|
||||
by fmsmga103.fm.intel.com with ESMTP; 08 Jul 2016 03:03:05 -0700
|
||||
X-ExtLoop1: 1
|
||||
X-IronPort-AV: E=Sophos;i="5.28,329,1464678000";
|
||||
d="scan'208";a="731352499"
|
||||
Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143])
|
||||
by FMSMGA003.fm.intel.com with ESMTP; 08 Jul 2016 03:03:02 -0700
|
||||
From: Vinod Koul <vinod.koul@intel.com>
|
||||
To: alsa-devel@alsa-project.org
|
||||
Cc: broonie@kernel.org,
|
||||
liam.r.girdwood@linux.intel.com,
|
||||
patches.audio@intel.com,
|
||||
Stephen Just <stephenjust@gmail.com>,
|
||||
Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>,
|
||||
apterix@gmail.com,
|
||||
bugzilla@hadess.net,
|
||||
Vinod Koul <vinod.koul@intel.com>,
|
||||
Sachin Mokashi <sachinx.mokashi@intel.com>
|
||||
Subject: [PATCH 3/3] ASoC: Intel: Add surface3 entry in CHT-RT5645 machine
|
||||
Date: Fri, 8 Jul 2016 15:39:51 +0530
|
||||
Message-Id: <1467972591-29175-4-git-send-email-vinod.koul@intel.com>
|
||||
X-Mailer: git-send-email 1.9.1
|
||||
In-Reply-To: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
|
||||
References: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
|
||||
X-Evolution-Source: 1353784233.13280.3@sirocco.hadess.net
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Mime-Version: 1.0
|
||||
|
||||
Surface3 device is a CHT machine, so add entry for it.
|
||||
Also update the HID from BIOS.
|
||||
|
||||
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=98001
|
||||
Signed-off-by: Sachin Mokashi <sachinx.mokashi@intel.com>
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
---
|
||||
sound/soc/intel/boards/cht_bsw_rt5645.c | 20 +++++++++++++++++++-
|
||||
1 file changed, 19 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
|
||||
index d7ef292c402d..f26c7b8545ae 100644
|
||||
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
|
||||
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <sound/jack.h>
|
||||
#include "../../codecs/rt5645.h"
|
||||
#include "../atom/sst-atom-controls.h"
|
||||
+#include "../common/sst-acpi.h"
|
||||
|
||||
#define CHT_PLAT_CLK_3_HZ 19200000
|
||||
#define CHT_CODEC_DAI "rt5645-aif1"
|
||||
@@ -340,10 +341,13 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
|
||||
};
|
||||
|
||||
static struct cht_acpi_card snd_soc_cards[] = {
|
||||
+ {"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
|
||||
};
|
||||
|
||||
+static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
+
|
||||
static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret_val = 0;
|
||||
@@ -351,6 +355,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
struct cht_mc_private *drv;
|
||||
struct snd_soc_card *card = snd_soc_cards[0].soc_card;
|
||||
char codec_name[16];
|
||||
+ struct sst_acpi_mach *mach;
|
||||
+ const char *i2c_name = NULL;
|
||||
+ int dai_index;
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
|
||||
if (!drv)
|
||||
@@ -366,12 +373,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
card->dev = &pdev->dev;
|
||||
+ mach = card->dev->platform_data;
|
||||
sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
|
||||
|
||||
/* set correct codec name */
|
||||
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
|
||||
- if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00"))
|
||||
+ if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) {
|
||||
card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL);
|
||||
+ dai_index = i;
|
||||
+ }
|
||||
+
|
||||
+ /* fixup codec name based on HID */
|
||||
+ i2c_name = sst_acpi_find_name_from_hid(mach->id);
|
||||
+ if (i2c_name != NULL) {
|
||||
+ snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name),
|
||||
+ "%s%s", "i2c-", i2c_name);
|
||||
+ cht_dailink[dai_index].codec_name = cht_rt5640_codec_name;
|
||||
+ }
|
||||
|
||||
snd_soc_card_set_drvdata(card, drv);
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
--
|
||||
1.9.1
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
From 473dfbfa09934cea0d08cc9023c749a5fce10cb0 Mon Sep 17 00:00:00 2001
|
||||
From: Amitkumar Karwar <akarwar@marvell.com>
|
||||
Date: Thu, 30 Jun 2016 22:24:57 +0530
|
||||
Subject: mwifiex: Change default firmware for PCIe8997 chipset
|
||||
|
||||
PCIe-USB8997 variant is being used in the product. Let's change default
|
||||
firmware from PCIe-UART to PCIe-USB. So by default PCIe-USB firmware would
|
||||
be downloaded if version register doesn't give any information.
|
||||
|
||||
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 12 ++++++------
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.h | 4 ++--
|
||||
2 files changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index 1b1e266..012733c 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -2841,20 +2841,20 @@ static void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter)
|
||||
version &= 0x7;
|
||||
switch (revision_id) {
|
||||
case PCIE8997_V2:
|
||||
- if (version == CHIP_VER_PCIEUSB)
|
||||
+ if (version == CHIP_VER_PCIEUART)
|
||||
strcpy(adapter->fw_name,
|
||||
- PCIEUSB8997_FW_NAME_V2);
|
||||
+ PCIEUART8997_FW_NAME_V2);
|
||||
else
|
||||
strcpy(adapter->fw_name,
|
||||
- PCIEUART8997_FW_NAME_V2);
|
||||
+ PCIEUSB8997_FW_NAME_V2);
|
||||
break;
|
||||
case PCIE8997_Z:
|
||||
- if (version == CHIP_VER_PCIEUSB)
|
||||
+ if (version == CHIP_VER_PCIEUART)
|
||||
strcpy(adapter->fw_name,
|
||||
- PCIEUSB8997_FW_NAME_Z);
|
||||
+ PCIEUART8997_FW_NAME_Z);
|
||||
else
|
||||
strcpy(adapter->fw_name,
|
||||
- PCIEUART8997_FW_NAME_Z);
|
||||
+ PCIEUSB8997_FW_NAME_Z);
|
||||
break;
|
||||
default:
|
||||
strcpy(adapter->fw_name, PCIE8997_DEFAULT_FW_NAME);
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h
|
||||
index 9c00c7e..f05061c 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.h
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.h
|
||||
@@ -32,7 +32,7 @@
|
||||
#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin"
|
||||
#define PCIE8897_A0_FW_NAME "mrvl/pcie8897_uapsta_a0.bin"
|
||||
#define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin"
|
||||
-#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieuart8997_combo_v2.bin"
|
||||
+#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieusb8997_combo_v2.bin"
|
||||
#define PCIEUART8997_FW_NAME_Z "mrvl/pcieuart8997_combo.bin"
|
||||
#define PCIEUART8997_FW_NAME_V2 "mrvl/pcieuart8997_combo_v2.bin"
|
||||
#define PCIEUSB8997_FW_NAME_Z "mrvl/pcieusb8997_combo.bin"
|
||||
@@ -48,7 +48,7 @@
|
||||
#define PCIE8897_B0 0x1200
|
||||
#define PCIE8997_Z 0x0
|
||||
#define PCIE8997_V2 0x471
|
||||
-#define CHIP_VER_PCIEUSB 0x2
|
||||
+#define CHIP_VER_PCIEUART 0x3
|
||||
|
||||
/* Constants for Buffer Descriptor (BD) rings */
|
||||
#define MWIFIEX_MAX_TXRX_BD 0x20
|
||||
--
|
||||
cgit v0.12
|
||||
|
|
@ -1837,13 +1837,13 @@ CONFIG_B43=m
|
|||
CONFIG_B43_SDIO=y
|
||||
CONFIG_B43_BCMA=y
|
||||
CONFIG_B43_BCMA_PIO=y
|
||||
CONFIG_B43_DEBUG=y
|
||||
# CONFIG_B43_DEBUG is not set
|
||||
CONFIG_B43_PHY_LP=y
|
||||
CONFIG_B43_PHY_N=y
|
||||
CONFIG_B43_PHY_HT=y
|
||||
CONFIG_B43_PHY_G=y
|
||||
CONFIG_B43LEGACY=m
|
||||
CONFIG_B43LEGACY_DEBUG=y
|
||||
# CONFIG_B43LEGACY_DEBUG is not set
|
||||
CONFIG_B43LEGACY_DMA=y
|
||||
CONFIG_B43LEGACY_PIO=y
|
||||
CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
|
||||
|
@ -2520,6 +2520,7 @@ CONFIG_TOUCHSCREEN_MCS5000=m
|
|||
CONFIG_TOUCHSCREEN_MK712=m
|
||||
CONFIG_TOUCHSCREEN_PENMOUNT=m
|
||||
# CONFIG_TOUCHSCREEN_SUR40 is not set
|
||||
CONFIG_TOUCHSCREEN_SURFACE3_SPI=m
|
||||
# CONFIG_TOUCHSCREEN_TPS6507X is not set
|
||||
CONFIG_TOUCHSCREEN_TS4800=m
|
||||
CONFIG_TOUCHSCREEN_TSC_SERIO=m
|
||||
|
@ -2562,6 +2563,7 @@ CONFIG_INPUT_RETU_PWRBUTTON=m
|
|||
CONFIG_INPUT_UINPUT=m
|
||||
CONFIG_INPUT_WISTRON_BTNS=m
|
||||
CONFIG_INPUT_ATLAS_BTNS=m
|
||||
CONFIG_INPUT_SURFACE3_BUTTON_ARRAY=m
|
||||
|
||||
CONFIG_INPUT_ATI_REMOTE2=m
|
||||
CONFIG_INPUT_KEYSPAN_REMOTE=m
|
||||
|
@ -4525,6 +4527,7 @@ CONFIG_MFD_VIPERBOARD=m
|
|||
# CONFIG_TS4800_IRQ is not set
|
||||
# CONFIG_TWL4030_CORE is not set
|
||||
# CONFIG_TWL6040_CORE is not set
|
||||
# CONFIG_SURFACE3_POWER is not set
|
||||
|
||||
#
|
||||
# File systems
|
||||
|
@ -5218,7 +5221,7 @@ CONFIG_PM_DEBUG=y
|
|||
# CONFIG_DPM_WATCHDOG is not set # revisit this in debug
|
||||
CONFIG_PM_TRACE=y
|
||||
CONFIG_PM_TRACE_RTC=y
|
||||
CONFIG_PM_TEST_SUSPEND=y
|
||||
# CONFIG_PM_TEST_SUSPEND is not set
|
||||
# CONFIG_PM_OPP is not set
|
||||
# CONFIG_PM_AUTOSLEEP is not set
|
||||
# CONFIG_PM_WAKELOCKS is not set
|
||||
|
|
112
config-nodebug
112
config-nodebug
|
@ -2,102 +2,102 @@ CONFIG_SND_VERBOSE_PRINTK=y
|
|||
CONFIG_SND_DEBUG=y
|
||||
CONFIG_SND_PCM_XRUN_DEBUG=y
|
||||
|
||||
CONFIG_DEBUG_ATOMIC_SLEEP=y
|
||||
# CONFIG_DEBUG_ATOMIC_SLEEP is not set
|
||||
|
||||
CONFIG_DEBUG_MUTEXES=y
|
||||
CONFIG_DEBUG_RT_MUTEXES=y
|
||||
CONFIG_DEBUG_LOCK_ALLOC=y
|
||||
CONFIG_LOCK_TORTURE_TEST=m
|
||||
CONFIG_PROVE_LOCKING=y
|
||||
CONFIG_DEBUG_SPINLOCK=y
|
||||
CONFIG_PROVE_RCU=y
|
||||
# CONFIG_DEBUG_MUTEXES is not set
|
||||
# CONFIG_DEBUG_RT_MUTEXES is not set
|
||||
# CONFIG_DEBUG_LOCK_ALLOC is not set
|
||||
# CONFIG_LOCK_TORTURE_TEST is not set
|
||||
# CONFIG_PROVE_LOCKING is not set
|
||||
# CONFIG_DEBUG_SPINLOCK is not set
|
||||
# CONFIG_PROVE_RCU is not set
|
||||
# CONFIG_PROVE_RCU_REPEATEDLY is not set
|
||||
CONFIG_DEBUG_PER_CPU_MAPS=y
|
||||
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
||||
CONFIG_CPUMASK_OFFSTACK=y
|
||||
|
||||
CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
|
||||
# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
|
||||
|
||||
CONFIG_FAULT_INJECTION=y
|
||||
CONFIG_FAILSLAB=y
|
||||
CONFIG_FAIL_PAGE_ALLOC=y
|
||||
CONFIG_FAIL_MAKE_REQUEST=y
|
||||
CONFIG_FAULT_INJECTION_DEBUG_FS=y
|
||||
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
|
||||
CONFIG_FAIL_IO_TIMEOUT=y
|
||||
CONFIG_FAIL_MMC_REQUEST=y
|
||||
# CONFIG_FAULT_INJECTION is not set
|
||||
# CONFIG_FAILSLAB is not set
|
||||
# CONFIG_FAIL_PAGE_ALLOC is not set
|
||||
# CONFIG_FAIL_MAKE_REQUEST is not set
|
||||
# CONFIG_FAULT_INJECTION_DEBUG_FS is not set
|
||||
# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set
|
||||
# CONFIG_FAIL_IO_TIMEOUT is not set
|
||||
# CONFIG_FAIL_MMC_REQUEST is not set
|
||||
# CONFIG_F2FS_FAULT_INJECTION is not set
|
||||
|
||||
CONFIG_LOCK_STAT=y
|
||||
# CONFIG_LOCK_STAT is not set
|
||||
|
||||
CONFIG_DEBUG_STACK_USAGE=y
|
||||
# CONFIG_DEBUG_STACK_USAGE is not set
|
||||
|
||||
CONFIG_ACPI_DEBUG=y
|
||||
# CONFIG_ACPI_DEBUG is not set
|
||||
# CONFIG_ACPI_DEBUGGER is not set
|
||||
|
||||
CONFIG_DEBUG_SG=y
|
||||
CONFIG_DEBUG_PI_LIST=y
|
||||
# CONFIG_DEBUG_SG is not set
|
||||
# CONFIG_DEBUG_PI_LIST is not set
|
||||
|
||||
# CONFIG_PAGE_EXTENSION is not set
|
||||
# CONFIG_PAGE_OWNER is not set
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
|
||||
CONFIG_DEBUG_OBJECTS=y
|
||||
# CONFIG_DEBUG_OBJECTS is not set
|
||||
# CONFIG_DEBUG_OBJECTS_SELFTEST is not set
|
||||
CONFIG_DEBUG_OBJECTS_FREE=y
|
||||
CONFIG_DEBUG_OBJECTS_TIMERS=y
|
||||
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
|
||||
# CONFIG_DEBUG_OBJECTS_FREE is not set
|
||||
# CONFIG_DEBUG_OBJECTS_TIMERS is not set
|
||||
# CONFIG_DEBUG_OBJECTS_RCU_HEAD is not set
|
||||
CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
|
||||
|
||||
CONFIG_X86_PTDUMP=y
|
||||
CONFIG_ARM64_PTDUMP=y
|
||||
CONFIG_EFI_PGT_DUMP=y
|
||||
# CONFIG_ARM64_PTDUMP is not set
|
||||
# CONFIG_EFI_PGT_DUMP is not set
|
||||
|
||||
CONFIG_CAN_DEBUG_DEVICES=y
|
||||
# CONFIG_CAN_DEBUG_DEVICES is not set
|
||||
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
# CONFIG_MODULE_FORCE_UNLOAD is not set
|
||||
|
||||
|
||||
CONFIG_DEBUG_NOTIFIERS=y
|
||||
# CONFIG_DEBUG_NOTIFIERS is not set
|
||||
|
||||
CONFIG_DMA_API_DEBUG=y
|
||||
# CONFIG_DMA_API_DEBUG is not set
|
||||
|
||||
CONFIG_MMIOTRACE=y
|
||||
# CONFIG_MMIOTRACE is not set
|
||||
|
||||
CONFIG_DEBUG_CREDENTIALS=y
|
||||
# CONFIG_DEBUG_CREDENTIALS is not set
|
||||
|
||||
# off in both production debug and nodebug builds,
|
||||
# on in rawhide nodebug builds
|
||||
CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
|
||||
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
|
||||
|
||||
CONFIG_EXT4_DEBUG=y
|
||||
# CONFIG_EXT4_DEBUG is not set
|
||||
|
||||
# CONFIG_XFS_WARN is not set
|
||||
|
||||
CONFIG_DEBUG_PERF_USE_VMALLOC=y
|
||||
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
|
||||
|
||||
CONFIG_JBD2_DEBUG=y
|
||||
# CONFIG_JBD2_DEBUG is not set
|
||||
|
||||
CONFIG_NFSD_FAULT_INJECTION=y
|
||||
# CONFIG_NFSD_FAULT_INJECTION is not set
|
||||
|
||||
CONFIG_DEBUG_BLK_CGROUP=y
|
||||
# CONFIG_DEBUG_BLK_CGROUP is not set
|
||||
|
||||
CONFIG_DRBD_FAULT_INJECTION=y
|
||||
# CONFIG_DRBD_FAULT_INJECTION is not set
|
||||
|
||||
CONFIG_ATH_DEBUG=y
|
||||
CONFIG_CARL9170_DEBUGFS=y
|
||||
CONFIG_IWLWIFI_DEVICE_TRACING=y
|
||||
# CONFIG_ATH_DEBUG is not set
|
||||
# CONFIG_CARL9170_DEBUGFS is not set
|
||||
# CONFIG_IWLWIFI_DEVICE_TRACING is not set
|
||||
|
||||
# CONFIG_RTLWIFI_DEBUG is not set
|
||||
|
||||
CONFIG_DEBUG_OBJECTS_WORK=y
|
||||
# CONFIG_DEBUG_OBJECTS_WORK is not set
|
||||
|
||||
CONFIG_DMADEVICES_DEBUG=y
|
||||
# CONFIG_DMADEVICES_DEBUG is not set
|
||||
# CONFIG_DMADEVICES_VDEBUG is not set
|
||||
|
||||
CONFIG_PM_ADVANCED_DEBUG=y
|
||||
|
||||
CONFIG_CEPH_LIB_PRETTYDEBUG=y
|
||||
CONFIG_QUOTA_DEBUG=y
|
||||
# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
|
||||
# CONFIG_QUOTA_DEBUG is not set
|
||||
|
||||
|
||||
CONFIG_KGDB_KDB=y
|
||||
|
@ -105,19 +105,19 @@ CONFIG_KDB_DEFAULT_ENABLE=0x0
|
|||
CONFIG_KDB_KEYBOARD=y
|
||||
CONFIG_KDB_CONTINUE_CATASTROPHIC=0
|
||||
|
||||
CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
|
||||
# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set
|
||||
# CONFIG_PERCPU_TEST is not set
|
||||
CONFIG_TEST_LIST_SORT=y
|
||||
# CONFIG_TEST_LIST_SORT is not set
|
||||
# CONFIG_TEST_STRING_HELPERS is not set
|
||||
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
# CONFIG_DETECT_HUNG_TASK is not set
|
||||
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
|
||||
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
|
||||
CONFIG_WQ_WATCHDOG=y
|
||||
# CONFIG_WQ_WATCHDOG is not set
|
||||
|
||||
CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
|
||||
# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
|
||||
|
||||
CONFIG_DEBUG_KMEMLEAK=y
|
||||
# CONFIG_DEBUG_KMEMLEAK is not set
|
||||
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=1024
|
||||
# CONFIG_DEBUG_KMEMLEAK_TEST is not set
|
||||
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
|
||||
|
@ -128,4 +128,4 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
|
|||
|
||||
# CONFIG_SPI_DEBUG is not set
|
||||
|
||||
CONFIG_DEBUG_VM_PGFLAGS=y
|
||||
# CONFIG_DEBUG_VM_PGFLAGS is not set
|
||||
|
|
|
@ -120,6 +120,7 @@ CONFIG_GPIO_CRYSTAL_COVE=y
|
|||
CONFIG_AXP288_ADC=y
|
||||
CONFIG_AXP288_FUEL_GAUGE=y
|
||||
# CONFIG_PWM_CRC is not set
|
||||
CONFIG_SURFACE3_POWER=y
|
||||
|
||||
|
||||
CONFIG_X86_INTEL_PSTATE=y
|
||||
|
@ -249,6 +250,7 @@ CONFIG_PANASONIC_LAPTOP=m
|
|||
CONFIG_SAMSUNG_LAPTOP=m
|
||||
CONFIG_SONY_LAPTOP=m
|
||||
CONFIG_TOPSTAR_LAPTOP=m
|
||||
CONFIG_SURFACE3_WMI=m
|
||||
|
||||
CONFIG_ACPI_WMI=m
|
||||
CONFIG_ACER_WMI=m
|
||||
|
@ -381,7 +383,7 @@ CONFIG_SP5100_TCO=m
|
|||
|
||||
# CONFIG_MEMTEST is not set
|
||||
# CONFIG_DEBUG_TLBFLUSH is not set
|
||||
CONFIG_MAXSMP=y
|
||||
# CONFIG_MAXSMP is not set
|
||||
|
||||
|
||||
CONFIG_HP_ILO=m
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
From 5781fc29dbbd3ee5e11c1bf4fa6696ae89d19840 Mon Sep 17 00:00:00 2001
|
||||
From: Shengzhen Li <szli@marvell.com>
|
||||
Date: Fri, 1 Jul 2016 18:26:52 +0530
|
||||
Subject: mwifiex: fix interrupt processing corner case in MSI mode
|
||||
|
||||
As interrupt is read in interrupt handler as well as interrupt processing
|
||||
thread, we observed a corner case issue for MSI in which interrupt gets
|
||||
processed twice.
|
||||
|
||||
This patch moves interrupt reading code for MSI mode from
|
||||
mwifiex_interrupt_status() to mwifiex_pcie_process_int() to avoid the
|
||||
issue.
|
||||
|
||||
Signed-off-by: Shengzhen Li <szli@marvell.com>
|
||||
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 50 ++++++++++++++++++++++++++---
|
||||
1 file changed, 46 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index c7f5df8..22fe993 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -2091,6 +2091,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
|
||||
unsigned long flags;
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
|
||||
+ if (card->msi_enable) {
|
||||
+ spin_lock_irqsave(&adapter->int_lock, flags);
|
||||
+ adapter->int_status = 1;
|
||||
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!mwifiex_pcie_ok_to_access_hw(adapter))
|
||||
return;
|
||||
|
||||
@@ -2192,15 +2199,44 @@ exit:
|
||||
static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
int ret;
|
||||
- u32 pcie_ireg;
|
||||
+ u32 pcie_ireg = 0;
|
||||
unsigned long flags;
|
||||
+ struct pcie_service_card *card = adapter->card;
|
||||
|
||||
spin_lock_irqsave(&adapter->int_lock, flags);
|
||||
- /* Clear out unused interrupts */
|
||||
- pcie_ireg = adapter->int_status;
|
||||
+ if (!card->msi_enable) {
|
||||
+ /* Clear out unused interrupts */
|
||||
+ pcie_ireg = adapter->int_status;
|
||||
+ }
|
||||
adapter->int_status = 0;
|
||||
spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||
|
||||
+ if (card->msi_enable) {
|
||||
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
|
||||
+ if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
|
||||
+ &pcie_ireg)) {
|
||||
+ mwifiex_dbg(adapter, ERROR,
|
||||
+ "Read register failed\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
|
||||
+ if (mwifiex_write_reg(adapter,
|
||||
+ PCIE_HOST_INT_STATUS,
|
||||
+ ~pcie_ireg)) {
|
||||
+ mwifiex_dbg(adapter, ERROR,
|
||||
+ "Write register failed\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if (!adapter->pps_uapsd_mode &&
|
||||
+ adapter->ps_state == PS_STATE_SLEEP) {
|
||||
+ adapter->ps_state = PS_STATE_AWAKE;
|
||||
+ adapter->pm_wakeup_fw_try = false;
|
||||
+ del_timer(&adapter->wakeup_timer);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
while (pcie_ireg & HOST_INTR_MASK) {
|
||||
if (pcie_ireg & HOST_INTR_DNLD_DONE) {
|
||||
pcie_ireg &= ~HOST_INTR_DNLD_DONE;
|
||||
@@ -2240,6 +2276,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ if (card->msi_enable) {
|
||||
+ spin_lock_irqsave(&adapter->int_lock, flags);
|
||||
+ adapter->int_status = 0;
|
||||
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||
+ }
|
||||
+
|
||||
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
|
||||
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
|
||||
&pcie_ireg)) {
|
||||
@@ -2263,7 +2305,7 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
|
||||
mwifiex_dbg(adapter, INTR,
|
||||
"info: cmd_sent=%d data_sent=%d\n",
|
||||
adapter->cmd_sent, adapter->data_sent);
|
||||
- if (adapter->ps_state != PS_STATE_SLEEP)
|
||||
+ if (!card->msi_enable && adapter->ps_state != PS_STATE_SLEEP)
|
||||
mwifiex_pcie_enable_host_int(adapter);
|
||||
|
||||
return 0;
|
||||
--
|
||||
cgit v0.12
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
From 5c87a55adbd5eb3536893c40086253e15ea53cd5 Mon Sep 17 00:00:00 2001
|
||||
From: Mathias Krause <minipli@googlemail.com>
|
||||
Date: Sat, 21 May 2016 15:43:31 +0200
|
||||
Subject: mwifiex: remove misleading GFP_DMA flag in buffer allocations
|
||||
|
||||
The GFP_DMA flag is obviously misunderstood in the mwifiex driver. It's
|
||||
meant for legacy ISA DMA memory mappings only -- the lower 16MB on x86.
|
||||
That doesn't apply to PCIe or SDIO devices, I guess.
|
||||
|
||||
Remove the GFP_DMA flag to reduce the need to place the socket buffer
|
||||
allocation into the low mem DMA area, which might already be in use by
|
||||
other drivers.
|
||||
|
||||
This misuse was flagged by the PaX USERCOPY feature by chance, as it
|
||||
detected the user copy operation from a DMA buffer in the recvfrom()
|
||||
syscall path.
|
||||
|
||||
Signed-off-by: Mathias Krause <minipli@googlemail.com>
|
||||
Tested-by: Dennis Wassenberg <dennis.wassenberg@secunet.com>
|
||||
Cc: Amitkumar Karwar <akarwar@marvell.com>
|
||||
Cc: Nishant Sarmukadam <nishants@marvell.com>
|
||||
Cc: Xinming Hu <huxm@marvell.com>
|
||||
Cc: Kalle Valo <kvalo@codeaurora.org>
|
||||
Cc: Brad Spengler <spender@grsecurity.net>
|
||||
Cc: PaX Team <pageexec@freemail.hu>
|
||||
Acked-by: Amitkumar Karwar <akarwar@marvell.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 2 +-
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 4 ++--
|
||||
drivers/net/wireless/marvell/mwifiex/sdio.c | 4 ++--
|
||||
3 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
|
||||
index 1efef3b..dc49c3d 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
|
||||
@@ -184,7 +184,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
|
||||
|
||||
tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
|
||||
skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size,
|
||||
- GFP_ATOMIC | GFP_DMA);
|
||||
+ GFP_ATOMIC);
|
||||
if (!skb_aggr) {
|
||||
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
|
||||
ra_list_flags);
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index a35db02..1b1e266 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -507,7 +507,7 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
|
||||
for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
|
||||
/* Allocate skb here so that firmware can DMA data from it */
|
||||
skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
|
||||
- GFP_KERNEL | GFP_DMA);
|
||||
+ GFP_KERNEL);
|
||||
if (!skb) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"Unable to allocate skb for RX ring.\n");
|
||||
@@ -1319,7 +1319,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
|
||||
}
|
||||
|
||||
skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
|
||||
- GFP_KERNEL | GFP_DMA);
|
||||
+ GFP_KERNEL);
|
||||
if (!skb_tmp) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"Unable to allocate skb.\n");
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
|
||||
index bdc51ff..674465e 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
|
||||
@@ -1492,7 +1492,7 @@ rx_curr_single:
|
||||
mwifiex_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n",
|
||||
port, rx_len);
|
||||
|
||||
- skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
|
||||
+ skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"single skb allocated fail,\t"
|
||||
@@ -1597,7 +1597,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
|
||||
rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
|
||||
mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len);
|
||||
|
||||
- skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
|
||||
+ skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -1;
|
||||
|
||||
--
|
||||
cgit v0.12
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
From 2af86f9d954ee86e9b1c492e025de37a1b6d2db8 Mon Sep 17 00:00:00 2001
|
||||
From: Karthik D A <karthida@marvell.com>
|
||||
Date: Fri, 15 Jul 2016 18:18:39 +0530
|
||||
Subject: mwifiex: Fix request_irq() failure handling
|
||||
|
||||
It's been observed that request_irq() failure leads to a system crash
|
||||
due to a bug in mwifiex driver.
|
||||
When this failure happens, mwifiex_add_card() already takes care of
|
||||
clearing and freeing adapter->card pointer. This patch removes the
|
||||
redundant cleanup code causing crash.
|
||||
|
||||
Signed-off-by: Karthik D A <karthida@marvell.com>
|
||||
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/marvell/mwifiex/pcie.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
index 22fe993..0faf4a2 100644
|
||||
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
|
||||
@@ -202,7 +202,6 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
|
||||
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
|
||||
MWIFIEX_PCIE)) {
|
||||
pr_err("%s failed\n", __func__);
|
||||
- kfree(card);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2843,7 +2842,6 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
|
||||
"MRVL_PCIE", &card->share_irq_ctx);
|
||||
if (ret) {
|
||||
pr_err("request_irq failed: ret=%d\n", ret);
|
||||
- adapter->card = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
--
|
||||
cgit v0.12
|
||||
|
49
kernel.spec
49
kernel.spec
|
@ -42,7 +42,7 @@ Summary: The Linux kernel
|
|||
# For non-released -rc kernels, this will be appended after the rcX and
|
||||
# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
|
||||
#
|
||||
%global baserelease 1
|
||||
%global baserelease 4.surface3
|
||||
%global fedora_build %{baserelease}
|
||||
|
||||
# base_sublevel is the kernel version we're starting with and patching
|
||||
|
@ -630,6 +630,44 @@ Patch833: drm-nouveau-disp-sor-gf119-select-correct-sor-when.patch
|
|||
#rhbz 1346753
|
||||
Patch834: qla2xxx-Fix-NULL-pointer-deref-in-QLA-interrupt.patch
|
||||
|
||||
# Surface 3 patches
|
||||
Patch900: 0001-Input-add-new-driver-for-the-Surface-3.patch
|
||||
Patch901: 0001-Input-surface3_spi-Prepare-to-add-support-for-Surfac.patch
|
||||
Patch902: 0001-Input-surface3_spi-add-surface-pen-support-for-Surfa.patch
|
||||
|
||||
Patch903: 0001-HID-input-rework-HID_QUIRK_MULTI_INPUT.patch
|
||||
Patch904: 0002-HID-multitouch-enable-the-Surface-3-Type-Cover-to-re.patch
|
||||
Patch905: 0003-HID-multitouch-set-correct-class-for-Surface-Type-Co.patch
|
||||
|
||||
Patch906: 0001-Input-soc_button_array-use-gpio_is_valid.patch
|
||||
Patch907: 0002-Input-soc_button_array-bail-out-earlier-if-gpiod_cou.patch
|
||||
Patch908: 0003-Input-soc_button_array-make-sure-one-GPIO-is-not-ass.patch
|
||||
Patch909: 0004-Input-soc_button_array-allow-to-specify-active_low.patch
|
||||
Patch910: 0005-Input-soc_button_array-export-part-of-the-internals.patch
|
||||
Patch911: 0006-Input-surface3_button_array-Introduce-button-support.patch
|
||||
|
||||
Patch912: 0001-power-MSHW0011-rev-eng-implementation.patch
|
||||
Patch913: 0002-power-surface3_power-Improve-battery-capacity-report.patch
|
||||
|
||||
Patch914: 0001-gpiolib-acpi-make-sure-we-trigger-the-events-at-leas.patch
|
||||
|
||||
Patch915: 0001-WIP-acpi-button-remove-pointer-to-old-lid_sysfs-on-u.patch
|
||||
Patch916: 0001-WIP-i2c-hid-enabled-S0-S3.patch
|
||||
Patch917: 0002-WIP-add-custom-surface3-platform-device-for-controll.patch
|
||||
|
||||
Patch918: ASoC_Intel_Add_support_for_surface3_tablet.patch
|
||||
Patch919: 07d5c17b80f67d1b2cc2c8243590e2abed4bd7ae..5d554ea4f287665b839975ecb11bd29d49a5c9b5.patch
|
||||
Patch920: 5d554ea4f287665b839975ecb11bd29d49a5c9b5..24dad509ed5528bbbe31ff17f9fb39c0473ec8f4.patch
|
||||
|
||||
Patch921: 6b3c33e985f20e7de07fc4b9b1a96dc452e37cb4..141bcf099076df1a74317a5b14dcd56c933b9de8.patch
|
||||
Patch922: ee6e7aa383944ce62860f35c86f1ac7da7dd27b6..5c87a55adbd5eb3536893c40086253e15ea53cd5.patch
|
||||
Patch923: c18b104dd2495da60ec92f40e14559591644cc3a..473dfbfa09934cea0d08cc9023c749a5fce10cb0.patch
|
||||
Patch924: 473dfbfa09934cea0d08cc9023c749a5fce10cb0..d41376ca8ba74e954ba931c69271d0b29546a202.patch
|
||||
Patch925: d41376ca8ba74e954ba931c69271d0b29546a202..5781fc29dbbd3ee5e11c1bf4fa6696ae89d19840.patch
|
||||
Patch926: fd3ed33f51c2a586412d35b4f64803f019ab589f..2af86f9d954ee86e9b1c492e025de37a1b6d2db8.patch
|
||||
Patch927: 1-2-mwifiex-fix-PCIe-legacy-interrupt-problem.patch
|
||||
Patch928: 2-2-mwifiex-update-command-response-skb-length-correctly.patch
|
||||
|
||||
# END OF PATCH DEFINITIONS
|
||||
|
||||
%endif
|
||||
|
@ -2155,6 +2193,15 @@ fi
|
|||
#
|
||||
#
|
||||
%changelog
|
||||
* Wed Jul 20 2016 Bastien Nocera <bnocera@redhat.com> - 4.7.0-0.rc6.git1.4.surface3
|
||||
- Disable debugging options.
|
||||
|
||||
* Tue Jul 19 2016 Bastien Nocera <bnocera@redhat.com> - 4.7.0-0.rc6.git1.3.surface3
|
||||
- Disable debugging options.
|
||||
|
||||
* Tue Jul 19 2016 Bastien Nocera <bnocera@redhat.com> - 4.7.0-0.rc6.git1.2.surface3
|
||||
- Add Surface 3 patches
|
||||
|
||||
* Thu Jul 07 2016 Laura Abbott <labbott@redhat.com> - 4.7.0-0.rc6.git1.1
|
||||
- Linux v4.7-rc6-74-g076501f
|
||||
- Reenable debugging options.
|
||||
|
|
Loading…
Reference in New Issue