Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull some more input subsystem updates from Dmitry Torokhov: "An update to the ALPS driver to support the V8 protocol with touchstick, a change for i8042 to skip selftest on many Asus laptops which helps to keep their touchpads working after resume, and a couple other driver fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: i8042 - skip selftest on ASUS laptops Input: melfas_mip4 - add ic_name sysfs attribute Input: melfas_mip4 - add maintainer information Input: melfas_mip4 - add devicetree binding documentations Input: elantech - add Fujitsu Lifebook E556 to force crc_enabled Input: synaptics-rmi4 - fix error handling in I2C transport driver Input: synaptics-rmi4 - fix error handling in SPI transport driver Input: ALPS - add V8 protocol documentation Input: ALPS - set DualPoint flag for 74 03 28 devices Input: ALPS - allow touchsticks to report pressure Input: ALPS - handle 0-pressure 1F events Input: ALPS - add touchstick support for SS5 hardware Input: elantech - force needed quirks on Fujitsu H760 Input: elantech - fix Lenovo version typo
This commit is contained in:
commit
689f891c98
@ -0,0 +1,21 @@
|
||||
* MELFAS MIP4 Touchscreen
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "melfas,mip4_ts"
|
||||
- reg: I2C slave address of the chip (0x48 or 0x34)
|
||||
- interrupt-parent: interrupt controller to which the chip is connected
|
||||
- interrupts: interrupt to which the chip is connected
|
||||
|
||||
Optional properties:
|
||||
- ce-gpios: GPIO connected to the CE (chip enable) pin of the chip
|
||||
|
||||
Example:
|
||||
i2c@00000000 {
|
||||
touchscreen: melfas_mip4@48 {
|
||||
compatible = "melfas,mip4_ts";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
|
||||
ce-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
@ -163,6 +163,7 @@ maxim Maxim Integrated Products
|
||||
meas Measurement Specialties
|
||||
mediatek MediaTek Inc.
|
||||
melexis Melexis N.V.
|
||||
melfas MELFAS Inc.
|
||||
merrii Merrii Technology Co., Ltd.
|
||||
micrel Micrel Inc.
|
||||
microchip Microchip Technology Inc.
|
||||
|
@ -319,3 +319,60 @@ For touchpad packet, the format is:
|
||||
otherwise byte 0 bit 4 must be set and byte 0/4/5 are
|
||||
in NEW fmt
|
||||
F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ...
|
||||
|
||||
|
||||
ALPS Absolute Mode - Protocol Version 8
|
||||
---------------------------------------
|
||||
|
||||
Spoken by SS4 (73 03 14) and SS5 (73 03 28) hardware.
|
||||
|
||||
The packet type is given by the APD field, bits 4-5 of byte 3.
|
||||
|
||||
Touchpad packet (APD = 0x2):
|
||||
|
||||
b7 b6 b5 b4 b3 b2 b1 b0
|
||||
byte 0: SWM SWR SWL 1 1 0 0 X7
|
||||
byte 1: 0 X6 X5 X4 X3 X2 X1 X0
|
||||
byte 2: 0 Y6 Y5 Y4 Y3 Y2 Y1 Y0
|
||||
byte 3: 0 T&P 1 0 1 0 0 Y7
|
||||
byte 4: 0 Z6 Z5 Z4 Z3 Z2 Z1 Z0
|
||||
byte 5: 0 0 0 0 0 0 0 0
|
||||
|
||||
SWM, SWR, SWL: Middle, Right, and Left button states
|
||||
|
||||
Touchpad 1 Finger packet (APD = 0x0):
|
||||
|
||||
b7 b6 b5 b4 b3 b2 b1 b0
|
||||
byte 0: SWM SWR SWL 1 1 X2 X1 X0
|
||||
byte 1: X9 X8 X7 1 X6 X5 X4 X3
|
||||
byte 2: 0 X11 X10 LFB Y3 Y2 Y1 Y0
|
||||
byte 3: Y5 Y4 0 0 1 TAPF2 TAPF1 TAPF0
|
||||
byte 4: Zv7 Y11 Y10 1 Y9 Y8 Y7 Y6
|
||||
byte 5: Zv6 Zv5 Zv4 0 Zv3 Zv2 Zv1 Zv0
|
||||
|
||||
TAPF: ???
|
||||
LFB: ???
|
||||
|
||||
Touchpad 2 Finger packet (APD = 0x1):
|
||||
|
||||
b7 b6 b5 b4 b3 b2 b1 b0
|
||||
byte 0: SWM SWR SWL 1 1 AX6 AX5 AX4
|
||||
byte 1: AX11 AX10 AX9 AX8 AX7 AZ1 AY4 AZ0
|
||||
byte 2: AY11 AY10 AY9 CONT AY8 AY7 AY6 AY5
|
||||
byte 3: 0 0 0 1 1 BX6 BX5 BX4
|
||||
byte 4: BX11 BX10 BX9 BX8 BX7 BZ1 BY4 BZ0
|
||||
byte 5: BY11 BY10 BY9 0 BY8 BY7 BY5 BY5
|
||||
|
||||
CONT: A 3-or-4 Finger packet is to follow
|
||||
|
||||
Touchpad 3-or-4 Finger packet (APD = 0x3):
|
||||
|
||||
b7 b6 b5 b4 b3 b2 b1 b0
|
||||
byte 0: SWM SWR SWL 1 1 AX6 AX5 AX4
|
||||
byte 1: AX11 AX10 AX9 AX8 AX7 AZ1 AY4 AZ0
|
||||
byte 2: AY11 AY10 AY9 OVF AY8 AY7 AY6 AY5
|
||||
byte 3: 0 0 1 1 1 BX6 BX5 BX4
|
||||
byte 4: BX11 BX10 BX9 BX8 BX7 BZ1 BY4 BZ0
|
||||
byte 5: BY11 BY10 BY9 0 BY8 BY7 BY5 BY5
|
||||
|
||||
OVF: 5th finger detected
|
||||
|
@ -1511,7 +1511,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
|
||||
controllers
|
||||
i8042.notimeout [HW] Ignore timeout condition signalled by controller
|
||||
i8042.reset [HW] Reset the controller during init and cleanup
|
||||
i8042.reset [HW] Reset the controller during init, cleanup and
|
||||
suspend-to-ram transitions, only during s2r
|
||||
transitions, or never reset
|
||||
Format: { 1 | Y | y | 0 | N | n }
|
||||
1, Y, y: always reset controller
|
||||
0, N, n: don't ever reset controller
|
||||
Default: only on s2r transitions on x86; most other
|
||||
architectures force reset to be always executed
|
||||
i8042.unlock [HW] Unlock (ignore) the keylock
|
||||
i8042.kbdreset [HW] Reset device connected to KBD port
|
||||
|
||||
|
@ -7829,6 +7829,13 @@ F: Documentation/scsi/megaraid.txt
|
||||
F: drivers/scsi/megaraid.*
|
||||
F: drivers/scsi/megaraid/
|
||||
|
||||
MELFAS MIP4 TOUCHSCREEN DRIVER
|
||||
M: Sangwon Jee <jeesw@melfas.com>
|
||||
W: http://www.melfas.com
|
||||
S: Supported
|
||||
F: drivers/input/touchscreen/melfas_mip4.c
|
||||
F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
|
||||
|
||||
MELLANOX ETHERNET DRIVER (mlx4_en)
|
||||
M: Tariq Toukan <tariqt@mellanox.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -103,6 +103,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
|
||||
6-byte ALPS packet */
|
||||
#define ALPS_STICK_BITS 0x100 /* separate stick button bits */
|
||||
#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
|
||||
#define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */
|
||||
|
||||
static const struct alps_model_info alps_model_data[] = {
|
||||
{ { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */
|
||||
@ -1156,15 +1157,28 @@ static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte)
|
||||
{
|
||||
unsigned char pkt_id = SS4_PACKET_ID_IDLE;
|
||||
|
||||
if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
|
||||
(byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) {
|
||||
pkt_id = SS4_PACKET_ID_IDLE;
|
||||
} else if (!(byte[3] & 0x10)) {
|
||||
pkt_id = SS4_PACKET_ID_ONE;
|
||||
} else if (!(byte[3] & 0x20)) {
|
||||
switch (byte[3] & 0x30) {
|
||||
case 0x00:
|
||||
if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
|
||||
(byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
|
||||
byte[5] == 0x00) {
|
||||
pkt_id = SS4_PACKET_ID_IDLE;
|
||||
} else {
|
||||
pkt_id = SS4_PACKET_ID_ONE;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
/* two-finger finger positions */
|
||||
pkt_id = SS4_PACKET_ID_TWO;
|
||||
} else {
|
||||
break;
|
||||
case 0x20:
|
||||
/* stick pointer */
|
||||
pkt_id = SS4_PACKET_ID_STICK;
|
||||
break;
|
||||
case 0x30:
|
||||
/* third and fourth finger positions */
|
||||
pkt_id = SS4_PACKET_ID_MULTI;
|
||||
break;
|
||||
}
|
||||
|
||||
return pkt_id;
|
||||
@ -1185,7 +1199,13 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
|
||||
f->mt[0].x = SS4_1F_X_V2(p);
|
||||
f->mt[0].y = SS4_1F_Y_V2(p);
|
||||
f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f;
|
||||
f->fingers = 1;
|
||||
/*
|
||||
* When a button is held the device will give us events
|
||||
* with x, y, and pressure of 0. This causes annoying jumps
|
||||
* if a touch is released while the button is held.
|
||||
* Handle this by claiming zero contacts.
|
||||
*/
|
||||
f->fingers = f->pressure > 0 ? 1 : 0;
|
||||
f->first_mp = 0;
|
||||
f->is_mp = 0;
|
||||
break;
|
||||
@ -1246,16 +1266,40 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
|
||||
}
|
||||
break;
|
||||
|
||||
case SS4_PACKET_ID_STICK:
|
||||
if (!(priv->flags & ALPS_DUALPOINT)) {
|
||||
psmouse_warn(psmouse,
|
||||
"Rejected trackstick packet from non DualPoint device");
|
||||
} else {
|
||||
int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f));
|
||||
int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f));
|
||||
int pressure = (s8)(p[4] & 0x7f);
|
||||
|
||||
input_report_rel(priv->dev2, REL_X, x);
|
||||
input_report_rel(priv->dev2, REL_Y, -y);
|
||||
input_report_abs(priv->dev2, ABS_PRESSURE, pressure);
|
||||
}
|
||||
break;
|
||||
|
||||
case SS4_PACKET_ID_IDLE:
|
||||
default:
|
||||
memset(f, 0, sizeof(struct alps_fields));
|
||||
break;
|
||||
}
|
||||
|
||||
f->left = !!(SS4_BTN_V2(p) & 0x01);
|
||||
if (!(priv->flags & ALPS_BUTTONPAD)) {
|
||||
f->right = !!(SS4_BTN_V2(p) & 0x02);
|
||||
f->middle = !!(SS4_BTN_V2(p) & 0x04);
|
||||
/* handle buttons */
|
||||
if (pkt_id == SS4_PACKET_ID_STICK) {
|
||||
f->ts_left = !!(SS4_BTN_V2(p) & 0x01);
|
||||
if (!(priv->flags & ALPS_BUTTONPAD)) {
|
||||
f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
|
||||
f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
|
||||
}
|
||||
} else {
|
||||
f->left = !!(SS4_BTN_V2(p) & 0x01);
|
||||
if (!(priv->flags & ALPS_BUTTONPAD)) {
|
||||
f->right = !!(SS4_BTN_V2(p) & 0x02);
|
||||
f->middle = !!(SS4_BTN_V2(p) & 0x04);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1266,6 +1310,7 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
|
||||
struct alps_data *priv = psmouse->private;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct input_dev *dev2 = priv->dev2;
|
||||
struct alps_fields *f = &priv->f;
|
||||
|
||||
memset(f, 0, sizeof(struct alps_fields));
|
||||
@ -1311,6 +1356,13 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
|
||||
|
||||
input_report_abs(dev, ABS_PRESSURE, f->pressure);
|
||||
input_sync(dev);
|
||||
|
||||
if (priv->flags & ALPS_DUALPOINT) {
|
||||
input_report_key(dev2, BTN_LEFT, f->ts_left);
|
||||
input_report_key(dev2, BTN_RIGHT, f->ts_right);
|
||||
input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
|
||||
input_sync(dev2);
|
||||
}
|
||||
}
|
||||
|
||||
static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
|
||||
@ -2695,6 +2747,10 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
||||
if (alps_set_defaults_ss4_v2(psmouse, priv))
|
||||
return -EIO;
|
||||
|
||||
if (priv->fw_ver[1] == 0x1)
|
||||
priv->flags |= ALPS_DUALPOINT |
|
||||
ALPS_DUALPOINT_WITH_PRESSURE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2767,6 +2823,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
|
||||
} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
|
||||
e7[2] == 0x14 && ec[1] == 0x02) {
|
||||
protocol = &alps_v8_protocol_data;
|
||||
} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
|
||||
e7[2] == 0x28 && ec[1] == 0x01) {
|
||||
protocol = &alps_v8_protocol_data;
|
||||
} else {
|
||||
psmouse_dbg(psmouse,
|
||||
"Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
|
||||
@ -2949,6 +3008,10 @@ int alps_init(struct psmouse *psmouse)
|
||||
|
||||
input_set_capability(dev2, EV_REL, REL_X);
|
||||
input_set_capability(dev2, EV_REL, REL_Y);
|
||||
if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) {
|
||||
input_set_capability(dev2, EV_ABS, ABS_PRESSURE);
|
||||
input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0);
|
||||
}
|
||||
input_set_capability(dev2, EV_KEY, BTN_LEFT);
|
||||
input_set_capability(dev2, EV_KEY, BTN_RIGHT);
|
||||
input_set_capability(dev2, EV_KEY, BTN_MIDDLE);
|
||||
|
@ -37,12 +37,14 @@
|
||||
* or there's button activities.
|
||||
* SS4_PACKET_ID_TWO: There's two or more fingers on touchpad
|
||||
* SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad
|
||||
* SS4_PACKET_ID_STICK: A stick pointer packet
|
||||
*/
|
||||
enum SS4_PACKET_ID {
|
||||
SS4_PACKET_ID_IDLE = 0,
|
||||
SS4_PACKET_ID_ONE,
|
||||
SS4_PACKET_ID_TWO,
|
||||
SS4_PACKET_ID_MULTI,
|
||||
SS4_PACKET_ID_STICK,
|
||||
};
|
||||
|
||||
#define SS4_COUNT_PER_ELECTRODE 256
|
||||
|
@ -1134,7 +1134,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
|
||||
* System76 Pangolin 0x250f01 ? 2 hw buttons
|
||||
* (*) + 3 trackpoint buttons
|
||||
* (**) + 0 trackpoint buttons
|
||||
* Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps
|
||||
* Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
|
||||
*/
|
||||
static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
|
||||
{
|
||||
@ -1159,6 +1159,13 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu H760 also has a middle button */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
@ -1503,10 +1510,10 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */
|
||||
/* Fujitsu H760 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1516,6 +1523,20 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK E556 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E556"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
|
@ -221,6 +221,21 @@ static const struct of_device_id rmi_i2c_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, rmi_i2c_of_match);
|
||||
#endif
|
||||
|
||||
static void rmi_i2c_regulator_bulk_disable(void *data)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = data;
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
|
||||
rmi_i2c->supplies);
|
||||
}
|
||||
|
||||
static void rmi_i2c_unregister_transport(void *data)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = data;
|
||||
|
||||
rmi_unregister_transport_device(&rmi_i2c->xport);
|
||||
}
|
||||
|
||||
static int rmi_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -264,6 +279,12 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
retval = devm_add_action_or_reset(&client->dev,
|
||||
rmi_i2c_regulator_bulk_disable,
|
||||
rmi_i2c);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
of_property_read_u32(client->dev.of_node, "syna,startup-delay-ms",
|
||||
&rmi_i2c->startup_delay);
|
||||
|
||||
@ -294,6 +315,11 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
client->addr);
|
||||
return retval;
|
||||
}
|
||||
retval = devm_add_action_or_reset(&client->dev,
|
||||
rmi_i2c_unregister_transport,
|
||||
rmi_i2c);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = rmi_i2c_init_irq(client);
|
||||
if (retval < 0)
|
||||
@ -304,17 +330,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
|
||||
|
||||
rmi_unregister_transport_device(&rmi_i2c->xport);
|
||||
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
|
||||
rmi_i2c->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int rmi_i2c_suspend(struct device *dev)
|
||||
{
|
||||
@ -431,7 +446,6 @@ static struct i2c_driver rmi_i2c_driver = {
|
||||
},
|
||||
.id_table = rmi_id,
|
||||
.probe = rmi_i2c_probe,
|
||||
.remove = rmi_i2c_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(rmi_i2c_driver);
|
||||
|
@ -396,6 +396,13 @@ static inline int rmi_spi_of_probe(struct spi_device *spi,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rmi_spi_unregister_transport(void *data)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi = data;
|
||||
|
||||
rmi_unregister_transport_device(&rmi_spi->xport);
|
||||
}
|
||||
|
||||
static int rmi_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi;
|
||||
@ -464,6 +471,11 @@ static int rmi_spi_probe(struct spi_device *spi)
|
||||
dev_err(&spi->dev, "failed to register transport.\n");
|
||||
return retval;
|
||||
}
|
||||
retval = devm_add_action_or_reset(&spi->dev,
|
||||
rmi_spi_unregister_transport,
|
||||
rmi_spi);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = rmi_spi_init_irq(spi);
|
||||
if (retval < 0)
|
||||
@ -473,15 +485,6 @@ static int rmi_spi_probe(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
|
||||
|
||||
rmi_unregister_transport_device(&rmi_spi->xport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int rmi_spi_suspend(struct device *dev)
|
||||
{
|
||||
@ -577,7 +580,6 @@ static struct spi_driver rmi_spi_driver = {
|
||||
},
|
||||
.id_table = rmi_id,
|
||||
.probe = rmi_spi_probe,
|
||||
.remove = rmi_spi_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(rmi_spi_driver);
|
||||
|
@ -81,7 +81,7 @@ static inline int i8042_platform_init(void)
|
||||
return -EBUSY;
|
||||
#endif
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
|
||||
return -EBUSY;
|
||||
#endif
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ static inline void i8042_write_command(int val)
|
||||
|
||||
static inline int i8042_platform_init(void)
|
||||
{
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ static int __init i8042_platform_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
|
||||
if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
|
||||
return -EBUSY;
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -510,6 +510,90 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* On some Asus laptops, just running self tests cause problems.
|
||||
*/
|
||||
static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
|
||||
{
|
||||
/* MSI Wind U-100 */
|
||||
@ -1072,12 +1156,18 @@ static int __init i8042_platform_init(void)
|
||||
return retval;
|
||||
|
||||
#if defined(__ia64__)
|
||||
i8042_reset = true;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
if (dmi_check_system(i8042_dmi_reset_table))
|
||||
i8042_reset = true;
|
||||
/* Honor module parameter when value is not default */
|
||||
if (i8042_reset == I8042_RESET_DEFAULT) {
|
||||
if (dmi_check_system(i8042_dmi_reset_table))
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
|
||||
if (dmi_check_system(i8042_dmi_noselftest_table))
|
||||
i8042_reset = I8042_RESET_NEVER;
|
||||
}
|
||||
|
||||
if (dmi_check_system(i8042_dmi_noloop_table))
|
||||
i8042_noloop = true;
|
||||
|
@ -48,9 +48,39 @@ static bool i8042_unlock;
|
||||
module_param_named(unlock, i8042_unlock, bool, 0);
|
||||
MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
|
||||
|
||||
static bool i8042_reset;
|
||||
module_param_named(reset, i8042_reset, bool, 0);
|
||||
MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
|
||||
enum i8042_controller_reset_mode {
|
||||
I8042_RESET_NEVER,
|
||||
I8042_RESET_ALWAYS,
|
||||
I8042_RESET_ON_S2RAM,
|
||||
#define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM
|
||||
};
|
||||
static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
|
||||
static int i8042_set_reset(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
enum i8042_controller_reset_mode *arg = kp->arg;
|
||||
int error;
|
||||
bool reset;
|
||||
|
||||
if (val) {
|
||||
error = kstrtobool(val, &reset);
|
||||
if (error)
|
||||
return error;
|
||||
} else {
|
||||
reset = true;
|
||||
}
|
||||
|
||||
*arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops param_ops_reset_param = {
|
||||
.flags = KERNEL_PARAM_OPS_FL_NOARG,
|
||||
.set = i8042_set_reset,
|
||||
};
|
||||
#define param_check_reset_param(name, p) \
|
||||
__param_check(name, p, enum i8042_controller_reset_mode)
|
||||
module_param_named(reset, i8042_reset, reset_param, 0);
|
||||
MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
|
||||
|
||||
static bool i8042_direct;
|
||||
module_param_named(direct, i8042_direct, bool, 0);
|
||||
@ -1019,7 +1049,7 @@ static int i8042_controller_init(void)
|
||||
* Reset the controller and reset CRT to the original value set by BIOS.
|
||||
*/
|
||||
|
||||
static void i8042_controller_reset(bool force_reset)
|
||||
static void i8042_controller_reset(bool s2r_wants_reset)
|
||||
{
|
||||
i8042_flush();
|
||||
|
||||
@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
|
||||
* Reset the controller if requested.
|
||||
*/
|
||||
|
||||
if (i8042_reset || force_reset)
|
||||
if (i8042_reset == I8042_RESET_ALWAYS ||
|
||||
(i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
|
||||
i8042_controller_selftest();
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the original control register setting.
|
||||
@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void)
|
||||
* before suspending.
|
||||
*/
|
||||
|
||||
static int i8042_controller_resume(bool force_reset)
|
||||
static int i8042_controller_resume(bool s2r_wants_reset)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (i8042_reset || force_reset) {
|
||||
if (i8042_reset == I8042_RESET_ALWAYS ||
|
||||
(i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev)
|
||||
|
||||
static int i8042_pm_resume(struct device *dev)
|
||||
{
|
||||
bool force_reset;
|
||||
bool want_reset;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I8042_NUM_PORTS; i++) {
|
||||
@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev)
|
||||
* off control to the platform firmware, otherwise we can simply restore
|
||||
* the mode.
|
||||
*/
|
||||
force_reset = pm_resume_via_firmware();
|
||||
want_reset = pm_resume_via_firmware();
|
||||
|
||||
return i8042_controller_resume(force_reset);
|
||||
return i8042_controller_resume(want_reset);
|
||||
}
|
||||
|
||||
static int i8042_pm_thaw(struct device *dev)
|
||||
@ -1482,7 +1515,7 @@ static int __init i8042_probe(struct platform_device *dev)
|
||||
|
||||
i8042_platform_device = dev;
|
||||
|
||||
if (i8042_reset) {
|
||||
if (i8042_reset == I8042_RESET_ALWAYS) {
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
|
@ -157,6 +157,7 @@ struct mip4_ts {
|
||||
|
||||
char phys[32];
|
||||
char product_name[16];
|
||||
char ic_name[4];
|
||||
|
||||
unsigned int max_x;
|
||||
unsigned int max_y;
|
||||
@ -263,6 +264,18 @@ static int mip4_query_device(struct mip4_ts *ts)
|
||||
dev_dbg(&ts->client->dev, "product name: %.*s\n",
|
||||
(int)sizeof(ts->product_name), ts->product_name);
|
||||
|
||||
/* IC name */
|
||||
cmd[0] = MIP4_R0_INFO;
|
||||
cmd[1] = MIP4_R1_INFO_IC_NAME;
|
||||
error = mip4_i2c_xfer(ts, cmd, sizeof(cmd),
|
||||
ts->ic_name, sizeof(ts->ic_name));
|
||||
if (error)
|
||||
dev_warn(&ts->client->dev,
|
||||
"Failed to retrieve IC name: %d\n", error);
|
||||
else
|
||||
dev_dbg(&ts->client->dev, "IC name: %.*s\n",
|
||||
(int)sizeof(ts->ic_name), ts->ic_name);
|
||||
|
||||
/* Firmware version */
|
||||
error = mip4_get_fw_version(ts);
|
||||
if (error)
|
||||
@ -1326,7 +1339,7 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
|
||||
* paired with current firmware in the chip.
|
||||
*/
|
||||
count = snprintf(buf, PAGE_SIZE, "%.*s\n",
|
||||
(int)sizeof(ts->product_name), ts->product_name);
|
||||
(int)sizeof(ts->product_name), ts->product_name);
|
||||
|
||||
mutex_unlock(&ts->input->mutex);
|
||||
|
||||
@ -1335,9 +1348,30 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
|
||||
|
||||
static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct mip4_ts *ts = i2c_get_clientdata(client);
|
||||
size_t count;
|
||||
|
||||
mutex_lock(&ts->input->mutex);
|
||||
|
||||
count = snprintf(buf, PAGE_SIZE, "%.*s\n",
|
||||
(int)sizeof(ts->ic_name), ts->ic_name);
|
||||
|
||||
mutex_unlock(&ts->input->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
|
||||
|
||||
static struct attribute *mip4_attrs[] = {
|
||||
&dev_attr_fw_version.attr,
|
||||
&dev_attr_hw_version.attr,
|
||||
&dev_attr_ic_name.attr,
|
||||
&dev_attr_update_fw.attr,
|
||||
NULL,
|
||||
};
|
||||
@ -1538,6 +1572,6 @@ static struct i2c_driver mip4_driver = {
|
||||
module_i2c_driver(mip4_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
|
||||
MODULE_VERSION("2016.03.12");
|
||||
MODULE_VERSION("2016.09.28");
|
||||
MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
Loading…
Reference in New Issue
Block a user