Skip to content

Commit

Permalink
Merge pull request #384 from flying-elephant/wacom_i2c_update_08042023
Browse files Browse the repository at this point in the history
wacom_i2c: Add the latest features
  • Loading branch information
Pinglinux authored Aug 7, 2023
2 parents 9da885b + 37734f3 commit 7b56df4
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 */
#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 */
#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",
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 7b56df4

Please sign in to comment.