cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sis_i2c.c (10021B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Touch Screen driver for SiS 9200 family I2C Touch panels
      4 *
      5 * Copyright (C) 2015 SiS, Inc.
      6 * Copyright (C) 2016 Nextfour Group
      7 */
      8
      9#include <linux/crc-itu-t.h>
     10#include <linux/delay.h>
     11#include <linux/i2c.h>
     12#include <linux/input.h>
     13#include <linux/input/mt.h>
     14#include <linux/interrupt.h>
     15#include <linux/gpio/consumer.h>
     16#include <linux/module.h>
     17#include <linux/slab.h>
     18#include <asm/unaligned.h>
     19
     20#define SIS_I2C_NAME		"sis_i2c_ts"
     21
     22/*
     23 * The I2C packet format:
     24 * le16		byte count
     25 * u8		Report ID
     26 * <contact data - variable length>
     27 * u8		Number of contacts
     28 * le16		Scan Time (optional)
     29 * le16		CRC
     30 *
     31 * One touch point information consists of 6+ bytes, the order is:
     32 * u8		contact state
     33 * u8		finger id
     34 * le16		x axis
     35 * le16		y axis
     36 * u8		contact width (optional)
     37 * u8		contact height (optional)
     38 * u8		pressure (optional)
     39 *
     40 * Maximum amount of data transmitted in one shot is 64 bytes, if controller
     41 * needs to report more contacts than fit in one packet it will send true
     42 * number of contacts in first packet and 0 as number of contacts in second
     43 * packet.
     44 */
     45
     46#define SIS_MAX_PACKET_SIZE		64
     47
     48#define SIS_PKT_LEN_OFFSET		0
     49#define SIS_PKT_REPORT_OFFSET		2 /* Report ID/type */
     50#define SIS_PKT_CONTACT_OFFSET		3 /* First contact */
     51
     52#define SIS_SCAN_TIME_LEN		2
     53
     54/* Supported report types */
     55#define SIS_ALL_IN_ONE_PACKAGE		0x10
     56#define SIS_PKT_IS_TOUCH(x)		(((x) & 0x0f) == 0x01)
     57#define SIS_PKT_IS_HIDI2C(x)		(((x) & 0x0f) == 0x06)
     58
     59/* Contact properties within report */
     60#define SIS_PKT_HAS_AREA(x)		((x) & BIT(4))
     61#define SIS_PKT_HAS_PRESSURE(x)		((x) & BIT(5))
     62#define SIS_PKT_HAS_SCANTIME(x)		((x) & BIT(6))
     63
     64/* Contact size */
     65#define SIS_BASE_LEN_PER_CONTACT	6
     66#define SIS_AREA_LEN_PER_CONTACT	2
     67#define SIS_PRESSURE_LEN_PER_CONTACT	1
     68
     69/* Offsets within contact data */
     70#define SIS_CONTACT_STATUS_OFFSET	0
     71#define SIS_CONTACT_ID_OFFSET		1 /* Contact ID */
     72#define SIS_CONTACT_X_OFFSET		2
     73#define SIS_CONTACT_Y_OFFSET		4
     74#define SIS_CONTACT_WIDTH_OFFSET	6
     75#define SIS_CONTACT_HEIGHT_OFFSET	7
     76#define SIS_CONTACT_PRESSURE_OFFSET(id)	(SIS_PKT_HAS_AREA(id) ? 8 : 6)
     77
     78/* Individual contact state */
     79#define SIS_STATUS_UP			0x0
     80#define SIS_STATUS_DOWN			0x3
     81
     82/* Touchscreen parameters */
     83#define SIS_MAX_FINGERS			10
     84#define SIS_MAX_X			4095
     85#define SIS_MAX_Y			4095
     86#define SIS_MAX_PRESSURE		255
     87
     88/* Resolution diagonal */
     89#define SIS_AREA_LENGTH_LONGER		5792
     90/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
     91#define SIS_AREA_LENGTH_SHORT		5792
     92#define SIS_AREA_UNIT			(5792 / 32)
     93
     94struct sis_ts_data {
     95	struct i2c_client *client;
     96	struct input_dev *input;
     97
     98	struct gpio_desc *attn_gpio;
     99	struct gpio_desc *reset_gpio;
    100
    101	u8 packet[SIS_MAX_PACKET_SIZE];
    102};
    103
    104static int sis_read_packet(struct i2c_client *client, u8 *buf,
    105			   unsigned int *num_contacts,
    106			   unsigned int *contact_size)
    107{
    108	int count_idx;
    109	int ret;
    110	u16 len;
    111	u16 crc, pkg_crc;
    112	u8 report_id;
    113
    114	ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE);
    115	if (ret <= 0)
    116		return -EIO;
    117
    118	len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]);
    119	if (len > SIS_MAX_PACKET_SIZE) {
    120		dev_err(&client->dev,
    121			"%s: invalid packet length (%d vs %d)\n",
    122			__func__, len, SIS_MAX_PACKET_SIZE);
    123		return -E2BIG;
    124	}
    125
    126	if (len < 10)
    127		return -EINVAL;
    128
    129	report_id = buf[SIS_PKT_REPORT_OFFSET];
    130	count_idx  = len - 1;
    131	*contact_size = SIS_BASE_LEN_PER_CONTACT;
    132
    133	if (report_id != SIS_ALL_IN_ONE_PACKAGE) {
    134		if (SIS_PKT_IS_TOUCH(report_id)) {
    135			/*
    136			 * Calculate CRC ignoring packet length
    137			 * in the beginning and CRC transmitted
    138			 * at the end of the packet.
    139			 */
    140			crc = crc_itu_t(0, buf + 2, len - 2 - 2);
    141			pkg_crc = get_unaligned_le16(&buf[len - 2]);
    142
    143			if (crc != pkg_crc) {
    144				dev_err(&client->dev,
    145					"%s: CRC Error (%d vs %d)\n",
    146					__func__, crc, pkg_crc);
    147				return -EINVAL;
    148			}
    149
    150			count_idx -= 2;
    151
    152		} else if (!SIS_PKT_IS_HIDI2C(report_id)) {
    153			dev_err(&client->dev,
    154				"%s: invalid packet ID %#02x\n",
    155				__func__, report_id);
    156			return -EINVAL;
    157		}
    158
    159		if (SIS_PKT_HAS_SCANTIME(report_id))
    160			count_idx -= SIS_SCAN_TIME_LEN;
    161
    162		if (SIS_PKT_HAS_AREA(report_id))
    163			*contact_size += SIS_AREA_LEN_PER_CONTACT;
    164		if (SIS_PKT_HAS_PRESSURE(report_id))
    165			*contact_size += SIS_PRESSURE_LEN_PER_CONTACT;
    166	}
    167
    168	*num_contacts = buf[count_idx];
    169	return 0;
    170}
    171
    172static int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id)
    173{
    174	struct input_dev *input = ts->input;
    175	int slot;
    176	u8 status = data[SIS_CONTACT_STATUS_OFFSET];
    177	u8 pressure;
    178	u8 height, width;
    179	u16 x, y;
    180
    181	if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) {
    182		dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n",
    183			data[SIS_CONTACT_STATUS_OFFSET]);
    184		return -EINVAL;
    185	}
    186
    187	slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]);
    188	if (slot < 0)
    189		return -ENOENT;
    190
    191	input_mt_slot(input, slot);
    192	input_mt_report_slot_state(input, MT_TOOL_FINGER,
    193				   status == SIS_STATUS_DOWN);
    194
    195	if (status == SIS_STATUS_DOWN) {
    196		pressure = height = width = 1;
    197		if (id != SIS_ALL_IN_ONE_PACKAGE) {
    198			if (SIS_PKT_HAS_AREA(id)) {
    199				width = data[SIS_CONTACT_WIDTH_OFFSET];
    200				height = data[SIS_CONTACT_HEIGHT_OFFSET];
    201			}
    202
    203			if (SIS_PKT_HAS_PRESSURE(id))
    204				pressure =
    205					data[SIS_CONTACT_PRESSURE_OFFSET(id)];
    206		}
    207
    208		x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]);
    209		y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]);
    210
    211		input_report_abs(input, ABS_MT_TOUCH_MAJOR,
    212				 width * SIS_AREA_UNIT);
    213		input_report_abs(input, ABS_MT_TOUCH_MINOR,
    214				 height * SIS_AREA_UNIT);
    215		input_report_abs(input, ABS_MT_PRESSURE, pressure);
    216		input_report_abs(input, ABS_MT_POSITION_X, x);
    217		input_report_abs(input, ABS_MT_POSITION_Y, y);
    218	}
    219
    220	return 0;
    221}
    222
    223static void sis_ts_handle_packet(struct sis_ts_data *ts)
    224{
    225	const u8 *contact;
    226	unsigned int num_to_report = 0;
    227	unsigned int num_contacts;
    228	unsigned int num_reported;
    229	unsigned int contact_size;
    230	int error;
    231	u8 report_id;
    232
    233	do {
    234		error = sis_read_packet(ts->client, ts->packet,
    235					&num_contacts, &contact_size);
    236		if (error)
    237			break;
    238
    239		if (num_to_report == 0) {
    240			num_to_report = num_contacts;
    241		} else if (num_contacts != 0) {
    242			dev_err(&ts->client->dev,
    243				"%s: nonzero (%d) point count in tail packet\n",
    244				__func__, num_contacts);
    245			break;
    246		}
    247
    248		report_id = ts->packet[SIS_PKT_REPORT_OFFSET];
    249		contact = &ts->packet[SIS_PKT_CONTACT_OFFSET];
    250		num_reported = 0;
    251
    252		while (num_to_report > 0) {
    253			error = sis_ts_report_contact(ts, contact, report_id);
    254			if (error)
    255				break;
    256
    257			contact += contact_size;
    258			num_to_report--;
    259			num_reported++;
    260
    261			if (report_id != SIS_ALL_IN_ONE_PACKAGE &&
    262			    num_reported >= 5) {
    263				/*
    264				 * The remainder of contacts is sent
    265				 * in the 2nd packet.
    266				 */
    267				break;
    268			}
    269		}
    270	} while (num_to_report > 0);
    271
    272	input_mt_sync_frame(ts->input);
    273	input_sync(ts->input);
    274}
    275
    276static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
    277{
    278	struct sis_ts_data *ts = dev_id;
    279
    280	do {
    281		sis_ts_handle_packet(ts);
    282	} while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio));
    283
    284	return IRQ_HANDLED;
    285}
    286
    287static void sis_ts_reset(struct sis_ts_data *ts)
    288{
    289	if (ts->reset_gpio) {
    290		/* Get out of reset */
    291		usleep_range(1000, 2000);
    292		gpiod_set_value(ts->reset_gpio, 1);
    293		usleep_range(1000, 2000);
    294		gpiod_set_value(ts->reset_gpio, 0);
    295		msleep(100);
    296	}
    297}
    298
    299static int sis_ts_probe(struct i2c_client *client,
    300			const struct i2c_device_id *id)
    301{
    302	struct sis_ts_data *ts;
    303	struct input_dev *input;
    304	int error;
    305
    306	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
    307	if (!ts)
    308		return -ENOMEM;
    309
    310	ts->client = client;
    311
    312	ts->attn_gpio = devm_gpiod_get_optional(&client->dev,
    313						"attn", GPIOD_IN);
    314	if (IS_ERR(ts->attn_gpio)) {
    315		error = PTR_ERR(ts->attn_gpio);
    316		if (error != -EPROBE_DEFER)
    317			dev_err(&client->dev,
    318				"Failed to get attention GPIO: %d\n", error);
    319		return error;
    320	}
    321
    322	ts->reset_gpio = devm_gpiod_get_optional(&client->dev,
    323						 "reset", GPIOD_OUT_LOW);
    324	if (IS_ERR(ts->reset_gpio)) {
    325		error = PTR_ERR(ts->reset_gpio);
    326		if (error != -EPROBE_DEFER)
    327			dev_err(&client->dev,
    328				"Failed to get reset GPIO: %d\n", error);
    329		return error;
    330	}
    331
    332	sis_ts_reset(ts);
    333
    334	ts->input = input = devm_input_allocate_device(&client->dev);
    335	if (!input) {
    336		dev_err(&client->dev, "Failed to allocate input device\n");
    337		return -ENOMEM;
    338	}
    339
    340	input->name = "SiS Touchscreen";
    341	input->id.bustype = BUS_I2C;
    342
    343	input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
    344	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
    345	input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0);
    346	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
    347			     0, SIS_AREA_LENGTH_LONGER, 0, 0);
    348	input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
    349			     0, SIS_AREA_LENGTH_SHORT, 0, 0);
    350
    351	error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT);
    352	if (error) {
    353		dev_err(&client->dev,
    354			"Failed to initialize MT slots: %d\n", error);
    355		return error;
    356	}
    357
    358	error = devm_request_threaded_irq(&client->dev, client->irq,
    359					  NULL, sis_ts_irq_handler,
    360					  IRQF_ONESHOT,
    361					  client->name, ts);
    362	if (error) {
    363		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
    364		return error;
    365	}
    366
    367	error = input_register_device(ts->input);
    368	if (error) {
    369		dev_err(&client->dev,
    370			"Failed to register input device: %d\n", error);
    371		return error;
    372	}
    373
    374	return 0;
    375}
    376
    377#ifdef CONFIG_OF
    378static const struct of_device_id sis_ts_dt_ids[] = {
    379	{ .compatible = "sis,9200-ts" },
    380	{ /* sentinel */ }
    381};
    382MODULE_DEVICE_TABLE(of, sis_ts_dt_ids);
    383#endif
    384
    385static const struct i2c_device_id sis_ts_id[] = {
    386	{ SIS_I2C_NAME,	0 },
    387	{ "9200-ts",	0 },
    388	{ /* sentinel */  }
    389};
    390MODULE_DEVICE_TABLE(i2c, sis_ts_id);
    391
    392static struct i2c_driver sis_ts_driver = {
    393	.driver = {
    394		.name	= SIS_I2C_NAME,
    395		.of_match_table = of_match_ptr(sis_ts_dt_ids),
    396	},
    397	.probe		= sis_ts_probe,
    398	.id_table	= sis_ts_id,
    399};
    400module_i2c_driver(sis_ts_driver);
    401
    402MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
    403MODULE_LICENSE("GPL v2");
    404MODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>");