892 lines · 20.4 KB · C
RawDownload
/* *  Driver for Goodix Touchscreens * *  Copyright (c) 2014 Red Hat Inc. *  Copyright (c) 2015 K. Merker <merker@debian.org> * *  This code is based on gt9xx.c authored by andrew@goodix.com: * *  2010 - 2012 Goodix Technology. */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2 of the License. */ #include <linux/kernel.h>#include <linux/dmi.h>#include <linux/firmware.h>#include <linux/gpio/consumer.h>#include <linux/i2c.h>#include <linux/input.h>#include <linux/input/mt.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/acpi.h>#include <linux/of.h>#include <asm/unaligned.h> struct goodix_ts_data {	struct i2c_client *client;	struct input_dev *input_dev;	int abs_x_max;	int abs_y_max;	bool swapped_x_y;	bool inverted_x;	bool inverted_y;	unsigned int max_touch_num;	unsigned int int_trigger_type;	int cfg_len;	struct gpio_desc *gpiod_int;	struct gpio_desc *gpiod_rst;	u16 id;	u16 version;	const char *cfg_name;	struct completion firmware_loading_complete;	unsigned long irq_flags;}; #define GOODIX_GPIO_INT_NAME		"irq"#define GOODIX_GPIO_RST_NAME		"reset" #define GOODIX_MAX_HEIGHT		4096#define GOODIX_MAX_WIDTH		4096#define GOODIX_INT_TRIGGER		1#define GOODIX_CONTACT_SIZE		8#define GOODIX_MAX_CONTACTS		10 #define GOODIX_CONFIG_MAX_LENGTH	240#define GOODIX_CONFIG_911_LENGTH	186#define GOODIX_CONFIG_967_LENGTH	228 /* Register defines */#define GOODIX_REG_COMMAND		0x8040#define GOODIX_CMD_SCREEN_OFF		0x05 #define GOODIX_READ_COOR_ADDR		0x814E#define GOODIX_REG_CONFIG_DATA		0x8047#define GOODIX_REG_ID			0x8140 #define RESOLUTION_LOC		1#define MAX_CONTACTS_LOC	5#define TRIGGER_LOC		6 static const unsigned long goodix_irq_flags[] = {	IRQ_TYPE_EDGE_RISING,	IRQ_TYPE_EDGE_FALLING,	IRQ_TYPE_LEVEL_LOW,	IRQ_TYPE_LEVEL_HIGH,}; /* * Those tablets have their coordinates origin at the bottom right * of the tablet, as if rotated 180 degrees */static const struct dmi_system_id rotated_screen[] = {#if defined(CONFIG_DMI) && defined(CONFIG_X86)	{		.ident = "WinBook TW100",		.matches = {			DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),			DMI_MATCH(DMI_PRODUCT_NAME, "TW100")		}	},	{		.ident = "WinBook TW700",		.matches = {			DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),			DMI_MATCH(DMI_PRODUCT_NAME, "TW700")		},	},#endif	{}}; /** * goodix_i2c_read - read data from a register of the i2c slave device. * * @client: i2c device. * @reg: the register to read from. * @buf: raw write data buffer. * @len: length of the buffer to write */static int goodix_i2c_read(struct i2c_client *client,			   u16 reg, u8 *buf, int len){	struct i2c_msg msgs[2];	u16 wbuf = cpu_to_be16(reg);	int ret; 	msgs[0].flags = 0;	msgs[0].addr  = client->addr;	msgs[0].len   = 2;	msgs[0].buf   = (u8 *)&wbuf; 	msgs[1].flags = I2C_M_RD;	msgs[1].addr  = client->addr;	msgs[1].len   = len;	msgs[1].buf   = buf; 	ret = i2c_transfer(client->adapter, msgs, 2);	return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);} /** * goodix_i2c_write - write data to a register of the i2c slave device. * * @client: i2c device. * @reg: the register to write to. * @buf: raw data buffer to write. * @len: length of the buffer to write */static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,			    unsigned len){	u8 *addr_buf;	struct i2c_msg msg;	int ret; 	addr_buf = kmalloc(len + 2, GFP_KERNEL);	if (!addr_buf)		return -ENOMEM; 	addr_buf[0] = reg >> 8;	addr_buf[1] = reg & 0xFF;	memcpy(&addr_buf[2], buf, len); 	msg.flags = 0;	msg.addr = client->addr;	msg.buf = addr_buf;	msg.len = len + 2; 	ret = i2c_transfer(client->adapter, &msg, 1);	kfree(addr_buf);	return ret < 0 ? ret : (ret != 1 ? -EIO : 0);} static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value){	return goodix_i2c_write(client, reg, &value, sizeof(value));} static int goodix_get_cfg_len(u16 id){	switch (id) {	case 911:	case 9271:	case 9110:	case 927:	case 928:		return GOODIX_CONFIG_911_LENGTH; 	case 912:	case 967:		return GOODIX_CONFIG_967_LENGTH; 	default:		return GOODIX_CONFIG_MAX_LENGTH;	}} static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data){	int touch_num;	int error; 	error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, data,				GOODIX_CONTACT_SIZE + 1);	if (error) {		dev_err(&ts->client->dev, "I2C transfer error: %d\n", error);		return error;	} 	if (!(data[0] & 0x80))		return -EAGAIN; 	touch_num = data[0] & 0x0f;	if (touch_num > ts->max_touch_num)		return -EPROTO; 	if (touch_num > 1) {		data += 1 + GOODIX_CONTACT_SIZE;		error = goodix_i2c_read(ts->client,					GOODIX_READ_COOR_ADDR +						1 + GOODIX_CONTACT_SIZE,					data,					GOODIX_CONTACT_SIZE * (touch_num - 1));		if (error)			return error;	} 	return touch_num;} static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data){	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]); 	/* Inversions have to happen before axis swapping */	if (ts->inverted_x)		input_x = ts->abs_x_max - input_x;	if (ts->inverted_y)		input_y = ts->abs_y_max - input_y;	if (ts->swapped_x_y)		swap(input_x, input_y); 	input_mt_slot(ts->input_dev, id);	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);	input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);	input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);} /** * goodix_process_events - Process incoming events * * @ts: our goodix_ts_data pointer * * Called when the IRQ is triggered. Read the current device state, and push * the input events to the user space. */static void goodix_process_events(struct goodix_ts_data *ts){	u8  point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];	int touch_num;	int i; 	touch_num = goodix_ts_read_input_report(ts, point_data);	if (touch_num < 0)		return; 	for (i = 0; i < touch_num; i++)		goodix_ts_report_touch(ts,				&point_data[1 + GOODIX_CONTACT_SIZE * i]); 	input_mt_sync_frame(ts->input_dev);	input_sync(ts->input_dev);} /** * goodix_ts_irq_handler - The IRQ handler * * @irq: interrupt number. * @dev_id: private data pointer. */static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id){	struct goodix_ts_data *ts = dev_id; 	goodix_process_events(ts); 	if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0)		dev_err(&ts->client->dev, "I2C write end_cmd error\n"); 	return IRQ_HANDLED;} static void goodix_free_irq(struct goodix_ts_data *ts){	devm_free_irq(&ts->client->dev, ts->client->irq, ts);} static int goodix_request_irq(struct goodix_ts_data *ts){	return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,					 NULL, goodix_ts_irq_handler,					 ts->irq_flags, ts->client->name, ts);} /** * goodix_check_cfg - Checks if config fw is valid * * @ts: goodix_ts_data pointer * @cfg: firmware config data */static int goodix_check_cfg(struct goodix_ts_data *ts,			    const struct firmware *cfg){	int i, raw_cfg_len;	u8 check_sum = 0; 	if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {		dev_err(&ts->client->dev,			"The length of the config fw is not correct");		return -EINVAL;	} 	raw_cfg_len = cfg->size - 2;	for (i = 0; i < raw_cfg_len; i++)		check_sum += cfg->data[i];	check_sum = (~check_sum) + 1;	if (check_sum != cfg->data[raw_cfg_len]) {		dev_err(&ts->client->dev,			"The checksum of the config fw is not correct");		return -EINVAL;	} 	if (cfg->data[raw_cfg_len + 1] != 1) {		dev_err(&ts->client->dev,			"Config fw must have Config_Fresh register set");		return -EINVAL;	} 	return 0;} /** * goodix_send_cfg - Write fw config to device * * @ts: goodix_ts_data pointer * @cfg: config firmware to write to device */static int goodix_send_cfg(struct goodix_ts_data *ts,			   const struct firmware *cfg){	int error; 	error = goodix_check_cfg(ts, cfg);	if (error)		return error; 	error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data,				 cfg->size);	if (error) {		dev_err(&ts->client->dev, "Failed to write config data: %d",			error);		return error;	}	dev_dbg(&ts->client->dev, "Config sent successfully."); 	/* Let the firmware reconfigure itself, so sleep for 10ms */	usleep_range(10000, 11000); 	return 0;} static int goodix_int_sync(struct goodix_ts_data *ts){	int error; 	error = gpiod_direction_output(ts->gpiod_int, 0);	if (error)		return error; 	msleep(50);				/* T5: 50ms */ 	error = gpiod_direction_input(ts->gpiod_int);	if (error)		return error; 	return 0;} /** * goodix_reset - Reset device during power on * * @ts: goodix_ts_data pointer */static int goodix_reset(struct goodix_ts_data *ts){	int error; 	/* begin select I2C slave addr */	error = gpiod_direction_output(ts->gpiod_rst, 0);	if (error)		return error; 	msleep(20);				/* T2: > 10ms */ 	/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */	error = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14);	if (error)		return error; 	usleep_range(100, 2000);		/* T3: > 100us */ 	error = gpiod_direction_output(ts->gpiod_rst, 1);	if (error)		return error; 	usleep_range(6000, 10000);		/* T4: > 5ms */ 	/* end select I2C slave addr */	error = gpiod_direction_input(ts->gpiod_rst);	if (error)		return error; 	error = goodix_int_sync(ts);	if (error)		return error; 	return 0;} /** * goodix_get_gpio_config - Get GPIO config from ACPI/DT * * @ts: goodix_ts_data pointer */static int goodix_get_gpio_config(struct goodix_ts_data *ts){	int error;	struct device *dev;	struct gpio_desc *gpiod; 	if (!ts->client)		return -EINVAL;	dev = &ts->client->dev; 	/* Get the interrupt GPIO pin number */	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);	if (IS_ERR(gpiod)) {		error = PTR_ERR(gpiod);		if (error != -EPROBE_DEFER)			dev_dbg(dev, "Failed to get %s GPIO: %d\n",				GOODIX_GPIO_INT_NAME, error);		return error;	} 	ts->gpiod_int = gpiod; 	/* Get the reset line GPIO pin number */	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);	if (IS_ERR(gpiod)) {		error = PTR_ERR(gpiod);		if (error != -EPROBE_DEFER)			dev_dbg(dev, "Failed to get %s GPIO: %d\n",				GOODIX_GPIO_RST_NAME, error);		return error;	} 	ts->gpiod_rst = gpiod; 	return 0;} /** * goodix_read_config - Read the embedded configuration of the panel * * @ts: our goodix_ts_data pointer * * Must be called during probe */static void goodix_read_config(struct goodix_ts_data *ts){	u8 config[GOODIX_CONFIG_MAX_LENGTH];	int error; 	error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,				config, ts->cfg_len);	if (error) {		dev_warn(&ts->client->dev,			 "Error reading config (%d), using defaults\n",			 error);		ts->abs_x_max = GOODIX_MAX_WIDTH;		ts->abs_y_max = GOODIX_MAX_HEIGHT;		if (ts->swapped_x_y)			swap(ts->abs_x_max, ts->abs_y_max);		ts->int_trigger_type = GOODIX_INT_TRIGGER;		ts->max_touch_num = GOODIX_MAX_CONTACTS;		return;	}

Lines 1–500 of 892.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t