Commit 1134ca26 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge branch 'next' into for-linus

Prepare second round of input updates for 4.9 merge window.
parents c758f96a 930e1924
* 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>;
};
};
......@@ -143,6 +143,7 @@ marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
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
......@@ -1409,7 +1409,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
......
......@@ -7155,6 +7155,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: Eugenia Emantayev <eugenia@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;
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) {
(byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
byte[5] == 0x00) {
pkt_id = SS4_PACKET_ID_IDLE;
} else if (!(byte[3] & 0x10)) {
} else {
pkt_id = SS4_PACKET_ID_ONE;
} else if (!(byte[3] & 0x20)) {
}
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,17 +1266,41 @@ 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;
}
/* 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
/* Honor module parameter when value is not default */
if (i8042_reset == I8042_RESET_DEFAULT) {
if (dmi_check_system(i8042_dmi_reset_table))
i8042_reset = true;
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)
......@@ -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");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment