Commit 875783fc authored by Adya's avatar Adya

Split Touchscreen and Stylus devices (and their code)

parent 7872ee67
......@@ -40,6 +40,7 @@ struct goodix_chip_data {
struct goodix_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct input_dev *pen_dev;
const struct goodix_chip_data *chip;
struct touchscreen_properties prop;
unsigned int max_touch_num;
......@@ -55,6 +56,37 @@ struct goodix_ts_data {
unsigned long irq_flags;
};
#define GOODIX_STYLUS_BTN1 0
#define GOODIX_STYLUS_BTN2 1
#define GOODIX_IS_STYLUS_BTN_DOWN(byte, btn) \
((byte & 0x40) || (byte & (0b1 << btn)))
#define GOODIX_TOOL_FINGER 1
#define GOODIX_TOOL_PEN 2
#define GOODIX_TOOL_TYPE(id_byte) \
(id_byte & 0x80 ? GOODIX_TOOL_PEN : GOODIX_TOOL_FINGER)
#define GOODIX_TOOL_TYPE_TO_STRING(tool_type) \
(tool_type == GOODIX_TOOL_FINGER ? "Finger" : \
(tool_type == GOODIX_TOOL_PEN ? "Pen" : "" ))
struct goodix_point {
u8 id :4; /* ID of the point: 4 bits */
u8 tool_type :4; /* Tool type (Finger or Pen) */
u16 x, y; /* X and Y coordinates */
u16 w; /* Width/Pressure of the contact */
};
struct goodix_input_report {
u8 flags :4;
u8 touch_num :4;
u8 keys;
struct goodix_point *points;
};
#define GOODIX_IS_READY(report) (report->flags & 0x8)
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
......@@ -235,6 +267,49 @@ static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
}
}
static void goodix_populate_report(u8 *data, struct goodix_input_report *report)
{
int i;
u8 *point_data;
report->flags = data[0] >> 4;
report->touch_num = data[0] & 0x0f;
report->keys = data[1 + report->touch_num * GOODIX_CONTACT_SIZE];
for (i = 0; i < report->touch_num; i++) {
point_data = &data[1 + i * GOODIX_CONTACT_SIZE];
report->points[i] = (struct goodix_point){
.id = point_data[0] & 0x0f,
.tool_type = GOODIX_TOOL_TYPE(point_data[0]),
.x = point_data[1] | (point_data[2] << 8),
.y = point_data[3] | (point_data[4] << 8),
.w = point_data[5] | (point_data[6] << 8),
};
}
}
static void goodix_dump_report(struct goodix_ts_data *ts,
struct goodix_input_report *report)
{
int i;
struct goodix_point *point;
dev_info(&ts->client->dev, "Report dump");
dev_info(&ts->client->dev, "|-- Flags: %x", report->flags);
dev_info(&ts->client->dev, "|-- Number of touches: %u", report->touch_num);
dev_info(&ts->client->dev, "|-- Keys: %x", report->keys);
dev_info(&ts->client->dev, "|-- Touches:");
for (i = 0; i < report->touch_num; i++) {
point = &report->points[i];
dev_info(&ts->client->dev, "|---- ID: %u", point->id);
dev_info(&ts->client->dev, "|---- Tool: %s",
GOODIX_TOOL_TYPE_TO_STRING(point->tool_type));
dev_info(&ts->client->dev, "|---- X coor: %u", point->x);
dev_info(&ts->client->dev, "|---- Y coor: %u", point->y);
dev_info(&ts->client->dev, "|---- Width: %u", point->w);
}
dev_info(&ts->client->dev, "=============");
}
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
{
unsigned long max_timeout;
......@@ -286,19 +361,28 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
return 0;
}
static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
static void goodix_ts_report_touch(struct goodix_ts_data *ts,
struct goodix_point *point)
{
int id = coor_data[0] & 0x0F;
int input_x = get_unaligned_le16(&coor_data[1]);
int input_y = get_unaligned_le16(&coor_data[3]);
int input_w = get_unaligned_le16(&coor_data[5]);
input_mt_slot(ts->input_dev, id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
touchscreen_report_pos(ts->input_dev, &ts->prop,
input_x, input_y, true);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
switch (point->tool_type) {
case GOODIX_TOOL_PEN:
input_report_key(ts->pen_dev, BTN_TOOL_PEN, 1);
input_report_key(ts->pen_dev, BTN_TOUCH, point->w > 0 ? 1 : 0);
input_report_abs(ts->pen_dev, ABS_X, point->x);
input_report_abs(ts->pen_dev, ABS_Y, point->y);
input_report_abs(ts->pen_dev, ABS_PRESSURE, point->w);
break;
case GOODIX_TOOL_FINGER:
default:
input_mt_slot(ts->input_dev, point->id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
touchscreen_report_pos(ts->input_dev, &ts->prop,
point->x, point->y, true);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, point->w);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, point->w);
break;
}
}
/**
......@@ -312,24 +396,36 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
static void goodix_process_events(struct goodix_ts_data *ts)
{
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
struct goodix_point points[GOODIX_MAX_CONTACTS];
struct goodix_input_report report = { .points = points };
int touch_num;
int i;
dev_info(&ts->client->dev, "Goodix --> Processing events...");
touch_num = goodix_ts_read_input_report(ts, point_data);
if (touch_num < 0)
return;
goodix_populate_report(point_data, &report);
// goodix_dump_report(ts, &report);
/*
* Bit 4 of the first byte reports the status of the capacitive
* Windows/Home button.
*/
*
input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
for (i = 0; i < touch_num; i++)
goodix_ts_report_touch(ts,
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
*/
input_report_key(ts->pen_dev, BTN_STYLUS,
GOODIX_IS_STYLUS_BTN_DOWN(report.keys, GOODIX_STYLUS_BTN1));
input_report_key(ts->pen_dev, BTN_STYLUS2,
GOODIX_IS_STYLUS_BTN_DOWN(report.keys, GOODIX_STYLUS_BTN2));
for (i = 0; i < touch_num; i++)
goodix_ts_report_touch(ts, &report.points[i]);
input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev);
......@@ -698,6 +794,8 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
ts->input_dev->id.product = ts->id;
ts->input_dev->id.version = ts->version;
ts->input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
/* Capacitive Windows/Home button on some devices */
input_set_capability(ts->input_dev, EV_KEY, KEY_LEFTMETA);
......@@ -706,6 +804,28 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
/* Active stylus pen */
ts->pen_dev = devm_input_allocate_device(&ts->client->dev);
if (!ts->pen_dev) {
dev_err(&ts->client->dev, "Failed to allocate pen device.");
return -ENOMEM;
}
ts->pen_dev->name = "Goodix Active Stylus Pen";
ts->pen_dev->phys = "input/pen";
ts->pen_dev->id.bustype = BUS_I2C;
ts->pen_dev->id.vendor = 0x0416;
ts->pen_dev->id.product = ts->id;
ts->pen_dev->id.version = ts->version;
__set_bit(BTN_TOOL_PEN, ts->pen_dev->keybit);
__set_bit(BTN_STYLUS, ts->pen_dev->keybit);
__set_bit(BTN_STYLUS2, ts->pen_dev->keybit);
__set_bit(BTN_TOUCH, ts->pen_dev->keybit);
input_set_abs_params(ts->pen_dev, ABS_PRESSURE,
0, 1024, 0, 0);
/* Read configuration and apply touchscreen parameters */
goodix_read_config(ts);
......@@ -723,6 +843,10 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
ABS_MT_POSITION_X, ts->prop.max_x);
input_abs_set_max(ts->input_dev,
ABS_MT_POSITION_Y, ts->prop.max_y);
input_set_abs_params(ts->pen_dev, ABS_X, 0,
ts->prop.max_x, 0, 0);
input_set_abs_params(ts->pen_dev, ABS_Y, 0,
ts->prop.max_y, 0, 0);
}
if (dmi_check_system(rotated_screen)) {
......@@ -747,6 +871,14 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
return error;
}
error = input_register_device(ts->pen_dev);
if (error) {
dev_err(&ts->client->dev,
"Failed to register pen device: %d", error);
input_free_device(ts->input_dev);
return error;
}
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
error = goodix_request_irq(ts);
if (error) {
......
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