Skip to content

Commit

Permalink
wacom_i2c: Add the latest features
Browse files Browse the repository at this point in the history
Latest Wacom EMR has new features. Specifically, those are tilts
and height events. The most recent EMR, G14, has a new pen type
too. This patch covers all those functionalities.

Signed-off-by: Tatsunosuke Tobita <[email protected]>
Reviewed-by: Ping Cheng <[email protected]>
  • Loading branch information
flying-elephant committed Aug 4, 2023
1 parent 9da885b commit 37734f3
Showing 1 changed file with 111 additions and 16 deletions.
127 changes: 111 additions & 16 deletions 4.5/wacom_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
/*
* Wacom Penabled Driver for I2C
*
* Copyright (c) 2011 - 2013 Tatsunosuke Tobita, Wacom.
* <tobita.tatsunosuke@wacom.co.jp>
* Copyright (c) 2011 - 2023 Tatsunosuke Tobita, Wacom.
* <tatsunosuke.tobita@wacom.com>
*/

#include "../config.h"
Expand Down Expand Up @@ -52,18 +52,44 @@
#define OPCODE_GET_REPORT 0x02

#define WACOM_QUERY_REPORT 3
#define WACOM_QUERY_SIZE 19
#define WACOM_QUERY_SIZE 22

/* Resolutions */
#define XY_RESOLUTION 100 /* Distance : SI Linear Unit with exponent -3 */
#define DIST_RESOLUTION 10 /* Distance : SI Linear Unit with exponent -2.
* This covers 'Z' resolution too */

Check failure on line 60 in 4.5/wacom_i2c.c

View workflow job for this annotation

GitHub Actions / checkpatch

WARNING: Block comments use a trailing */ on a separate line
#define TILT_RESOLUTION 5730 /* Degrees : English Rotation with exponent -2 */

/* Generation selction */
#define WACOM_BG9 0 /* G9 or earlier neither height nor tilt is supported */
#define WACOM_AG12 1 /* After G12 the IC supports "height"
* which is "ABS_DISTANCE" event */

Check failure on line 66 in 4.5/wacom_i2c.c

View workflow job for this annotation

GitHub Actions / checkpatch

WARNING: Block comments use a trailing */ on a separate line
#define MAX_LEN_BG9 10 /* Packet length for G9 or eralier */
#define MAX_LEN_G12 15 /* Length for G12 */
#define MAX_LEN_AG14 17 /* Length for G14 or later */

#define DISTANCE_MAX 255

struct feature_support {
bool distance;
bool tilt;
};

struct wacom_features {
struct feature_support support;
int x_max;
int y_max;
int pressure_max;
char fw_version;
int distance_max;
int tilt_x_max;
int tilt_y_max; char fw_version;
unsigned char generation;
};

struct wacom_i2c {
struct i2c_client *client;
struct input_dev *input;
struct wacom_features features;
u8 data[WACOM_QUERY_SIZE];
bool prox;
int tool;
Expand Down Expand Up @@ -107,24 +133,44 @@ static int wacom_query_device(struct i2c_client *client,

features->x_max = get_unaligned_le16(&data[3]);
features->y_max = get_unaligned_le16(&data[5]);
features->distance_max = data[16];
features->pressure_max = get_unaligned_le16(&data[11]);
features->fw_version = get_unaligned_le16(&data[13]);
features->tilt_x_max = get_unaligned_le16(&data[17]);
features->tilt_y_max = get_unaligned_le16(&data[19]);
features->distance_max = data[16];

if (features->distance_max)
features->support.distance = true;

if ((features->tilt_x_max && features->tilt_y_max))
features->support.tilt = true;

dev_dbg(&client->dev,
"x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
"x_max: %d, y_max: %d, pressure: %d, fw: %d, distance: %d,"
" tilt_x_max: %d, tilt_y_max: %d \n",

Check failure on line 151 in 4.5/wacom_i2c.c

View workflow job for this annotation

GitHub Actions / checkpatch

WARNING: quoted string split across lines

Check failure on line 151 in 4.5/wacom_i2c.c

View workflow job for this annotation

GitHub Actions / checkpatch

WARNING: unnecessary whitespace before a quoted newline
features->x_max, features->y_max,
features->pressure_max, features->fw_version);

features->pressure_max, features->fw_version,
features->distance_max,
features->tilt_x_max, features->tilt_y_max);

if (!features->support.distance && !features->support.tilt)
features->generation = WACOM_BG9;
else if (features->distance_max == DISTANCE_MAX)
features->generation = WACOM_AG12;
return 0;
}

static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
{
struct wacom_i2c *wac_i2c = dev_id;
struct input_dev *input = wac_i2c->input;
struct wacom_features *features = &wac_i2c->features;
u8 *data = wac_i2c->data;
unsigned int x, y, pressure;
unsigned char tsw, f1, f2, ers;
short tilt_x, tilt_y;
short distance = 0;
int error;

error = i2c_master_recv(wac_i2c->client,
Expand All @@ -146,6 +192,23 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)

wac_i2c->prox = data[3] & WACOM_IN_PROXIMITY;

if (features->generation) {
/* Tilt (signed) */
tilt_x = le16_to_cpup((__le16 *)&data[11]);
tilt_y = le16_to_cpup((__le16 *)&data[13]);
input_report_abs(input, ABS_TILT_X, tilt_x);
input_report_abs(input, ABS_TILT_Y, tilt_y);

/* Hover height */
if (data[0] == MAX_LEN_G12) {
distance = data[10];
} else if (data[0] >= MAX_LEN_AG14) {
distance = le16_to_cpup((__le16 *)&data[15]);
distance = -distance; /* The output is negative. Make it positive */
}
input_report_abs(input, ABS_DISTANCE, distance);
}

input_report_key(input, BTN_TOUCH, tsw || ers);
input_report_key(input, wac_i2c->tool, wac_i2c->prox);
input_report_key(input, BTN_STYLUS, f1);
Expand Down Expand Up @@ -187,22 +250,23 @@ static int wacom_i2c_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct wacom_i2c *wac_i2c;
struct input_dev *input;
struct wacom_features features = { 0 };
struct wacom_features *features;
int error;

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "i2c_check_functionality error\n");
return -EIO;
}

error = wacom_query_device(client, &features);
if (error)
return error;

wac_i2c = devm_kzalloc(dev, sizeof(*wac_i2c), GFP_KERNEL);
if (!wac_i2c)
return -ENOMEM;

features = &wac_i2c->features;
error = wacom_query_device(client, features);
if (error)
return error;

wac_i2c->client = client;

input = devm_input_allocate_device(dev);
Expand All @@ -214,22 +278,40 @@ static int wacom_i2c_probe(struct i2c_client *client)
input->name = "Wacom I2C Digitizer";
input->id.bustype = BUS_I2C;
input->id.vendor = 0x56a;
input->id.version = features.fw_version;
input->id.version = features->fw_version;
input->dev.parent = &client->dev;
input->open = wacom_i2c_open;
input->close = wacom_i2c_close;

input->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

__set_bit(INPUT_PROP_DIRECT, input->propbit);
__set_bit(BTN_TOOL_PEN, input->keybit);
__set_bit(BTN_TOOL_RUBBER, input->keybit);
__set_bit(BTN_STYLUS, input->keybit);
__set_bit(BTN_STYLUS2, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);

input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0);
input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0);
input_set_abs_params(input, ABS_X, 0, features->x_max, 0, 0);
input_set_abs_params(input, ABS_Y, 0, features->y_max, 0, 0);
input_set_abs_params(input, ABS_PRESSURE,
0, features.pressure_max, 0, 0);
0, features->pressure_max, 0, 0);
input_abs_set_res(input, ABS_X, XY_RESOLUTION);
input_abs_set_res(input, ABS_Y, XY_RESOLUTION);

if (features->generation & 0xff) { /* G12/G14 */
/* Tilt X & Y property setting */
input_set_abs_params(input, ABS_TILT_X, -features->tilt_x_max,
features->tilt_x_max, 0, 0);
input_set_abs_params(input, ABS_TILT_Y, -features->tilt_y_max,
features->tilt_y_max, 0, 0);
input_abs_set_res(input, ABS_TILT_X, TILT_RESOLUTION);
input_abs_set_res(input, ABS_TILT_Y, TILT_RESOLUTION);

/* Distance property setting follows Linux Input subsystem event */
input_set_abs_params(input, ABS_DISTANCE, 0, features->distance_max, 0, 0);
input_abs_set_res(input, ABS_DISTANCE, DIST_RESOLUTION);
}

input_set_drvdata(input, wac_i2c);

Expand Down Expand Up @@ -278,10 +360,23 @@ static const struct i2c_device_id wacom_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);

#ifdef CONFIG_OF
static const struct of_device_id wacom_i2c_of_match_table[] = {
{ .compatible = "emr,wacom_i2c" },
{}
};
MODULE_DEVICE_TABLE(of, wacom_i2c_of_match_table);
#endif

static struct i2c_driver wacom_i2c_driver = {
.driver = {
.name = "wacom_i2c",
.pm = &wacom_i2c_pm,

#ifdef CONFIG_OF
.of_match_table = of_match_ptr(wacom_i2c_of_match_table),
#endif

},

.probe = wacom_i2c_probe,
Expand Down

0 comments on commit 37734f3

Please sign in to comment.