18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Synaptics touchpad with I2C interface
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2009 Compulab, Ltd.
58c2ecf20Sopenharmony_ci * Mike Rapoport <mike@compulab.co.il>
68c2ecf20Sopenharmony_ci * Igor Grinberg <grinberg@compulab.co.il>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
98c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive for
108c2ecf20Sopenharmony_ci * more details.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/i2c.h>
158c2ecf20Sopenharmony_ci#include <linux/irq.h>
168c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
178c2ecf20Sopenharmony_ci#include <linux/input.h>
188c2ecf20Sopenharmony_ci#include <linux/delay.h>
198c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/pm.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define DRIVER_NAME		"synaptics_i2c"
248c2ecf20Sopenharmony_ci/* maximum product id is 15 characters */
258c2ecf20Sopenharmony_ci#define PRODUCT_ID_LENGTH	15
268c2ecf20Sopenharmony_ci#define REGISTER_LENGTH		8
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/*
298c2ecf20Sopenharmony_ci * after soft reset, we should wait for 1 ms
308c2ecf20Sopenharmony_ci * before the device becomes operational
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci#define SOFT_RESET_DELAY_US	3000
338c2ecf20Sopenharmony_ci/* and after hard reset, we should wait for max 500ms */
348c2ecf20Sopenharmony_ci#define HARD_RESET_DELAY_MS	500
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* Registers by SMBus address */
378c2ecf20Sopenharmony_ci#define PAGE_SEL_REG		0xff
388c2ecf20Sopenharmony_ci#define DEVICE_STATUS_REG	0x09
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Registers by RMI address */
418c2ecf20Sopenharmony_ci#define DEV_CONTROL_REG		0x0000
428c2ecf20Sopenharmony_ci#define INTERRUPT_EN_REG	0x0001
438c2ecf20Sopenharmony_ci#define ERR_STAT_REG		0x0002
448c2ecf20Sopenharmony_ci#define INT_REQ_STAT_REG	0x0003
458c2ecf20Sopenharmony_ci#define DEV_COMMAND_REG		0x0004
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define RMI_PROT_VER_REG	0x0200
488c2ecf20Sopenharmony_ci#define MANUFACT_ID_REG		0x0201
498c2ecf20Sopenharmony_ci#define PHYS_INT_VER_REG	0x0202
508c2ecf20Sopenharmony_ci#define PROD_PROPERTY_REG	0x0203
518c2ecf20Sopenharmony_ci#define INFO_QUERY_REG0		0x0204
528c2ecf20Sopenharmony_ci#define INFO_QUERY_REG1		(INFO_QUERY_REG0 + 1)
538c2ecf20Sopenharmony_ci#define INFO_QUERY_REG2		(INFO_QUERY_REG0 + 2)
548c2ecf20Sopenharmony_ci#define INFO_QUERY_REG3		(INFO_QUERY_REG0 + 3)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG0		0x0210
578c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG1		(PRODUCT_ID_REG0 + 1)
588c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG2		(PRODUCT_ID_REG0 + 2)
598c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG3		(PRODUCT_ID_REG0 + 3)
608c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG4		(PRODUCT_ID_REG0 + 4)
618c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG5		(PRODUCT_ID_REG0 + 5)
628c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG6		(PRODUCT_ID_REG0 + 6)
638c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG7		(PRODUCT_ID_REG0 + 7)
648c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG8		(PRODUCT_ID_REG0 + 8)
658c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG9		(PRODUCT_ID_REG0 + 9)
668c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG10	(PRODUCT_ID_REG0 + 10)
678c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG11	(PRODUCT_ID_REG0 + 11)
688c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG12	(PRODUCT_ID_REG0 + 12)
698c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG13	(PRODUCT_ID_REG0 + 13)
708c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG14	(PRODUCT_ID_REG0 + 14)
718c2ecf20Sopenharmony_ci#define PRODUCT_ID_REG15	(PRODUCT_ID_REG0 + 15)
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define DATA_REG0		0x0400
748c2ecf20Sopenharmony_ci#define ABS_PRESSURE_REG	0x0401
758c2ecf20Sopenharmony_ci#define ABS_MSB_X_REG		0x0402
768c2ecf20Sopenharmony_ci#define ABS_LSB_X_REG		(ABS_MSB_X_REG + 1)
778c2ecf20Sopenharmony_ci#define ABS_MSB_Y_REG		0x0404
788c2ecf20Sopenharmony_ci#define ABS_LSB_Y_REG		(ABS_MSB_Y_REG + 1)
798c2ecf20Sopenharmony_ci#define REL_X_REG		0x0406
808c2ecf20Sopenharmony_ci#define REL_Y_REG		0x0407
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define DEV_QUERY_REG0		0x1000
838c2ecf20Sopenharmony_ci#define DEV_QUERY_REG1		(DEV_QUERY_REG0 + 1)
848c2ecf20Sopenharmony_ci#define DEV_QUERY_REG2		(DEV_QUERY_REG0 + 2)
858c2ecf20Sopenharmony_ci#define DEV_QUERY_REG3		(DEV_QUERY_REG0 + 3)
868c2ecf20Sopenharmony_ci#define DEV_QUERY_REG4		(DEV_QUERY_REG0 + 4)
878c2ecf20Sopenharmony_ci#define DEV_QUERY_REG5		(DEV_QUERY_REG0 + 5)
888c2ecf20Sopenharmony_ci#define DEV_QUERY_REG6		(DEV_QUERY_REG0 + 6)
898c2ecf20Sopenharmony_ci#define DEV_QUERY_REG7		(DEV_QUERY_REG0 + 7)
908c2ecf20Sopenharmony_ci#define DEV_QUERY_REG8		(DEV_QUERY_REG0 + 8)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define GENERAL_2D_CONTROL_REG	0x1041
938c2ecf20Sopenharmony_ci#define SENSOR_SENSITIVITY_REG	0x1044
948c2ecf20Sopenharmony_ci#define SENS_MAX_POS_MSB_REG	0x1046
958c2ecf20Sopenharmony_ci#define SENS_MAX_POS_LSB_REG	(SENS_MAX_POS_UPPER_REG + 1)
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* Register bits */
988c2ecf20Sopenharmony_ci/* Device Control Register Bits */
998c2ecf20Sopenharmony_ci#define REPORT_RATE_1ST_BIT	6
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/* Interrupt Enable Register Bits (INTERRUPT_EN_REG) */
1028c2ecf20Sopenharmony_ci#define F10_ABS_INT_ENA		0
1038c2ecf20Sopenharmony_ci#define F10_REL_INT_ENA		1
1048c2ecf20Sopenharmony_ci#define F20_INT_ENA		2
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* Interrupt Request Register Bits (INT_REQ_STAT_REG | DEVICE_STATUS_REG) */
1078c2ecf20Sopenharmony_ci#define F10_ABS_INT_REQ		0
1088c2ecf20Sopenharmony_ci#define F10_REL_INT_REQ		1
1098c2ecf20Sopenharmony_ci#define F20_INT_REQ		2
1108c2ecf20Sopenharmony_ci/* Device Status Register Bits (DEVICE_STATUS_REG) */
1118c2ecf20Sopenharmony_ci#define STAT_CONFIGURED		6
1128c2ecf20Sopenharmony_ci#define STAT_ERROR		7
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* Device Command Register Bits (DEV_COMMAND_REG) */
1158c2ecf20Sopenharmony_ci#define RESET_COMMAND		0x01
1168c2ecf20Sopenharmony_ci#define REZERO_COMMAND		0x02
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* Data Register 0 Bits (DATA_REG0) */
1198c2ecf20Sopenharmony_ci#define GESTURE			3
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/* Device Query Registers Bits */
1228c2ecf20Sopenharmony_ci/* DEV_QUERY_REG3 */
1238c2ecf20Sopenharmony_ci#define HAS_PALM_DETECT		1
1248c2ecf20Sopenharmony_ci#define HAS_MULTI_FING		2
1258c2ecf20Sopenharmony_ci#define HAS_SCROLLER		4
1268c2ecf20Sopenharmony_ci#define HAS_2D_SCROLL		5
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* General 2D Control Register Bits (GENERAL_2D_CONTROL_REG) */
1298c2ecf20Sopenharmony_ci#define NO_DECELERATION		1
1308c2ecf20Sopenharmony_ci#define REDUCE_REPORTING	3
1318c2ecf20Sopenharmony_ci#define NO_FILTER		5
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/* Function Masks */
1348c2ecf20Sopenharmony_ci/* Device Control Register Masks (DEV_CONTROL_REG) */
1358c2ecf20Sopenharmony_ci#define REPORT_RATE_MSK		0xc0
1368c2ecf20Sopenharmony_ci#define SLEEP_MODE_MSK		0x07
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* Device Sleep Modes */
1398c2ecf20Sopenharmony_ci#define FULL_AWAKE		0x0
1408c2ecf20Sopenharmony_ci#define NORMAL_OP		0x1
1418c2ecf20Sopenharmony_ci#define LOW_PWR_OP		0x2
1428c2ecf20Sopenharmony_ci#define VERY_LOW_PWR_OP		0x3
1438c2ecf20Sopenharmony_ci#define SENS_SLEEP		0x4
1448c2ecf20Sopenharmony_ci#define SLEEP_MOD		0x5
1458c2ecf20Sopenharmony_ci#define DEEP_SLEEP		0x6
1468c2ecf20Sopenharmony_ci#define HIBERNATE		0x7
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/* Interrupt Register Mask */
1498c2ecf20Sopenharmony_ci/* (INT_REQ_STAT_REG | DEVICE_STATUS_REG | INTERRUPT_EN_REG) */
1508c2ecf20Sopenharmony_ci#define INT_ENA_REQ_MSK		0x07
1518c2ecf20Sopenharmony_ci#define INT_ENA_ABS_MSK		0x01
1528c2ecf20Sopenharmony_ci#define INT_ENA_REL_MSK		0x02
1538c2ecf20Sopenharmony_ci#define INT_ENA_F20_MSK		0x04
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/* Device Status Register Masks (DEVICE_STATUS_REG) */
1568c2ecf20Sopenharmony_ci#define CONFIGURED_MSK		0x40
1578c2ecf20Sopenharmony_ci#define ERROR_MSK		0x80
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/* Data Register 0 Masks */
1608c2ecf20Sopenharmony_ci#define FINGER_WIDTH_MSK	0xf0
1618c2ecf20Sopenharmony_ci#define GESTURE_MSK		0x08
1628c2ecf20Sopenharmony_ci#define SENSOR_STATUS_MSK	0x07
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/*
1658c2ecf20Sopenharmony_ci * MSB Position Register Masks
1668c2ecf20Sopenharmony_ci * ABS_MSB_X_REG | ABS_MSB_Y_REG | SENS_MAX_POS_MSB_REG |
1678c2ecf20Sopenharmony_ci * DEV_QUERY_REG3 | DEV_QUERY_REG5
1688c2ecf20Sopenharmony_ci */
1698c2ecf20Sopenharmony_ci#define MSB_POSITION_MSK	0x1f
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/* Device Query Registers Masks */
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* DEV_QUERY_REG2 */
1748c2ecf20Sopenharmony_ci#define NUM_EXTRA_POS_MSK	0x07
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/* When in IRQ mode read the device every THREAD_IRQ_SLEEP_SECS */
1778c2ecf20Sopenharmony_ci#define THREAD_IRQ_SLEEP_SECS	2
1788c2ecf20Sopenharmony_ci#define THREAD_IRQ_SLEEP_MSECS	(THREAD_IRQ_SLEEP_SECS * MSEC_PER_SEC)
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/*
1818c2ecf20Sopenharmony_ci * When in Polling mode and no data received for NO_DATA_THRES msecs
1828c2ecf20Sopenharmony_ci * reduce the polling rate to NO_DATA_SLEEP_MSECS
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_ci#define NO_DATA_THRES		(MSEC_PER_SEC)
1858c2ecf20Sopenharmony_ci#define NO_DATA_SLEEP_MSECS	(MSEC_PER_SEC / 4)
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/* Control touchpad's No Deceleration option */
1888c2ecf20Sopenharmony_cistatic bool no_decel = true;
1898c2ecf20Sopenharmony_cimodule_param(no_decel, bool, 0644);
1908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/* Control touchpad's Reduced Reporting option */
1938c2ecf20Sopenharmony_cistatic bool reduce_report;
1948c2ecf20Sopenharmony_cimodule_param(reduce_report, bool, 0644);
1958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)");
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci/* Control touchpad's No Filter option */
1988c2ecf20Sopenharmony_cistatic bool no_filter;
1998c2ecf20Sopenharmony_cimodule_param(no_filter, bool, 0644);
2008c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)");
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/*
2038c2ecf20Sopenharmony_ci * touchpad Attention line is Active Low and Open Drain,
2048c2ecf20Sopenharmony_ci * therefore should be connected to pulled up line
2058c2ecf20Sopenharmony_ci * and the irq configuration should be set to Falling Edge Trigger
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_ci/* Control IRQ / Polling option */
2088c2ecf20Sopenharmony_cistatic bool polling_req;
2098c2ecf20Sopenharmony_cimodule_param(polling_req, bool, 0444);
2108c2ecf20Sopenharmony_ciMODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)");
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/* Control Polling Rate */
2138c2ecf20Sopenharmony_cistatic int scan_rate = 80;
2148c2ecf20Sopenharmony_cimodule_param(scan_rate, int, 0644);
2158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 80");
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/* The main device structure */
2188c2ecf20Sopenharmony_cistruct synaptics_i2c {
2198c2ecf20Sopenharmony_ci	struct i2c_client	*client;
2208c2ecf20Sopenharmony_ci	struct input_dev	*input;
2218c2ecf20Sopenharmony_ci	struct delayed_work	dwork;
2228c2ecf20Sopenharmony_ci	int			no_data_count;
2238c2ecf20Sopenharmony_ci	int			no_decel_param;
2248c2ecf20Sopenharmony_ci	int			reduce_report_param;
2258c2ecf20Sopenharmony_ci	int			no_filter_param;
2268c2ecf20Sopenharmony_ci	int			scan_rate_param;
2278c2ecf20Sopenharmony_ci	int			scan_ms;
2288c2ecf20Sopenharmony_ci};
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic inline void set_scan_rate(struct synaptics_i2c *touch, int scan_rate)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	touch->scan_ms = MSEC_PER_SEC / scan_rate;
2338c2ecf20Sopenharmony_ci	touch->scan_rate_param = scan_rate;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/*
2378c2ecf20Sopenharmony_ci * Driver's initial design makes no race condition possible on i2c bus,
2388c2ecf20Sopenharmony_ci * so there is no need in any locking.
2398c2ecf20Sopenharmony_ci * Keep it in mind, while playing with the code.
2408c2ecf20Sopenharmony_ci */
2418c2ecf20Sopenharmony_cistatic s32 synaptics_i2c_reg_get(struct i2c_client *client, u16 reg)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	int ret;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
2468c2ecf20Sopenharmony_ci	if (ret == 0)
2478c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, reg & 0xff);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return ret;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	int ret;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
2578c2ecf20Sopenharmony_ci	if (ret == 0)
2588c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, reg & 0xff, val);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return ret;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	int ret;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
2688c2ecf20Sopenharmony_ci	if (ret == 0)
2698c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_word_data(client, reg & 0xff);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	return ret;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int synaptics_i2c_config(struct i2c_client *client)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int ret, control;
2778c2ecf20Sopenharmony_ci	u8 int_en;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* set Report Rate to Device Highest (>=80) and Sleep to normal */
2808c2ecf20Sopenharmony_ci	ret = synaptics_i2c_reg_set(client, DEV_CONTROL_REG, 0xc1);
2818c2ecf20Sopenharmony_ci	if (ret)
2828c2ecf20Sopenharmony_ci		return ret;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* set Interrupt Disable to Func20 / Enable to Func10) */
2858c2ecf20Sopenharmony_ci	int_en = (polling_req) ? 0 : INT_ENA_ABS_MSK | INT_ENA_REL_MSK;
2868c2ecf20Sopenharmony_ci	ret = synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, int_en);
2878c2ecf20Sopenharmony_ci	if (ret)
2888c2ecf20Sopenharmony_ci		return ret;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	control = synaptics_i2c_reg_get(client, GENERAL_2D_CONTROL_REG);
2918c2ecf20Sopenharmony_ci	/* No Deceleration */
2928c2ecf20Sopenharmony_ci	control |= no_decel ? 1 << NO_DECELERATION : 0;
2938c2ecf20Sopenharmony_ci	/* Reduced Reporting */
2948c2ecf20Sopenharmony_ci	control |= reduce_report ? 1 << REDUCE_REPORTING : 0;
2958c2ecf20Sopenharmony_ci	/* No Filter */
2968c2ecf20Sopenharmony_ci	control |= no_filter ? 1 << NO_FILTER : 0;
2978c2ecf20Sopenharmony_ci	ret = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control);
2988c2ecf20Sopenharmony_ci	if (ret)
2998c2ecf20Sopenharmony_ci		return ret;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int synaptics_i2c_reset_config(struct i2c_client *client)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	int ret;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/* Reset the Touchpad */
3098c2ecf20Sopenharmony_ci	ret = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND);
3108c2ecf20Sopenharmony_ci	if (ret) {
3118c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Unable to reset device\n");
3128c2ecf20Sopenharmony_ci	} else {
3138c2ecf20Sopenharmony_ci		usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100);
3148c2ecf20Sopenharmony_ci		ret = synaptics_i2c_config(client);
3158c2ecf20Sopenharmony_ci		if (ret)
3168c2ecf20Sopenharmony_ci			dev_err(&client->dev, "Unable to config device\n");
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return ret;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int synaptics_i2c_check_error(struct i2c_client *client)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	int status, ret = 0;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	status = i2c_smbus_read_byte_data(client, DEVICE_STATUS_REG) &
3278c2ecf20Sopenharmony_ci		(CONFIGURED_MSK | ERROR_MSK);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (status != CONFIGURED_MSK)
3308c2ecf20Sopenharmony_ci		ret = synaptics_i2c_reset_config(client);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return ret;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct input_dev *input = touch->input;
3388c2ecf20Sopenharmony_ci	int xy_delta, gesture;
3398c2ecf20Sopenharmony_ci	s32 data;
3408c2ecf20Sopenharmony_ci	s8 x_delta, y_delta;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* Deal with spontaneous resets and errors */
3438c2ecf20Sopenharmony_ci	if (synaptics_i2c_check_error(touch->client))
3448c2ecf20Sopenharmony_ci		return false;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* Get Gesture Bit */
3478c2ecf20Sopenharmony_ci	data = synaptics_i2c_reg_get(touch->client, DATA_REG0);
3488c2ecf20Sopenharmony_ci	gesture = (data >> GESTURE) & 0x1;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/*
3518c2ecf20Sopenharmony_ci	 * Get Relative axes. we have to get them in one shot,
3528c2ecf20Sopenharmony_ci	 * so we get 2 bytes starting from REL_X_REG.
3538c2ecf20Sopenharmony_ci	 */
3548c2ecf20Sopenharmony_ci	xy_delta = synaptics_i2c_word_get(touch->client, REL_X_REG) & 0xffff;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/* Separate X from Y */
3578c2ecf20Sopenharmony_ci	x_delta = xy_delta & 0xff;
3588c2ecf20Sopenharmony_ci	y_delta = (xy_delta >> REGISTER_LENGTH) & 0xff;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* Report the button event */
3618c2ecf20Sopenharmony_ci	input_report_key(input, BTN_LEFT, gesture);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* Report the deltas */
3648c2ecf20Sopenharmony_ci	input_report_rel(input, REL_X, x_delta);
3658c2ecf20Sopenharmony_ci	input_report_rel(input, REL_Y, -y_delta);
3668c2ecf20Sopenharmony_ci	input_sync(input);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	return xy_delta || gesture;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch = dev_id;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	mod_delayed_work(system_wq, &touch->dwork, 0);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void synaptics_i2c_check_params(struct synaptics_i2c *touch)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	bool reset = false;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (scan_rate != touch->scan_rate_param)
3858c2ecf20Sopenharmony_ci		set_scan_rate(touch, scan_rate);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (no_decel != touch->no_decel_param) {
3888c2ecf20Sopenharmony_ci		touch->no_decel_param = no_decel;
3898c2ecf20Sopenharmony_ci		reset = true;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (no_filter != touch->no_filter_param) {
3938c2ecf20Sopenharmony_ci		touch->no_filter_param = no_filter;
3948c2ecf20Sopenharmony_ci		reset = true;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (reduce_report != touch->reduce_report_param) {
3988c2ecf20Sopenharmony_ci		touch->reduce_report_param = reduce_report;
3998c2ecf20Sopenharmony_ci		reset = true;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (reset)
4038c2ecf20Sopenharmony_ci		synaptics_i2c_reset_config(touch->client);
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/* Control the Device polling rate / Work Handler sleep time */
4078c2ecf20Sopenharmony_cistatic unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch,
4088c2ecf20Sopenharmony_ci						bool have_data)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	unsigned long delay, nodata_count_thres;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (polling_req) {
4138c2ecf20Sopenharmony_ci		delay = touch->scan_ms;
4148c2ecf20Sopenharmony_ci		if (have_data) {
4158c2ecf20Sopenharmony_ci			touch->no_data_count = 0;
4168c2ecf20Sopenharmony_ci		} else {
4178c2ecf20Sopenharmony_ci			nodata_count_thres = NO_DATA_THRES / touch->scan_ms;
4188c2ecf20Sopenharmony_ci			if (touch->no_data_count < nodata_count_thres)
4198c2ecf20Sopenharmony_ci				touch->no_data_count++;
4208c2ecf20Sopenharmony_ci			else
4218c2ecf20Sopenharmony_ci				delay = NO_DATA_SLEEP_MSECS;
4228c2ecf20Sopenharmony_ci		}
4238c2ecf20Sopenharmony_ci		return msecs_to_jiffies(delay);
4248c2ecf20Sopenharmony_ci	} else {
4258c2ecf20Sopenharmony_ci		delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS);
4268c2ecf20Sopenharmony_ci		return round_jiffies_relative(delay);
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci/* Work Handler */
4318c2ecf20Sopenharmony_cistatic void synaptics_i2c_work_handler(struct work_struct *work)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	bool have_data;
4348c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch =
4358c2ecf20Sopenharmony_ci			container_of(work, struct synaptics_i2c, dwork.work);
4368c2ecf20Sopenharmony_ci	unsigned long delay;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	synaptics_i2c_check_params(touch);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	have_data = synaptics_i2c_get_input(touch);
4418c2ecf20Sopenharmony_ci	delay = synaptics_i2c_adjust_delay(touch, have_data);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/*
4448c2ecf20Sopenharmony_ci	 * While interrupt driven, there is no real need to poll the device.
4458c2ecf20Sopenharmony_ci	 * But touchpads are very sensitive, so there could be errors
4468c2ecf20Sopenharmony_ci	 * related to physical environment and the attention line isn't
4478c2ecf20Sopenharmony_ci	 * necessarily asserted. In such case we can lose the touchpad.
4488c2ecf20Sopenharmony_ci	 * We poll the device once in THREAD_IRQ_SLEEP_SECS and
4498c2ecf20Sopenharmony_ci	 * if error is detected, we try to reset and reconfigure the touchpad.
4508c2ecf20Sopenharmony_ci	 */
4518c2ecf20Sopenharmony_ci	mod_delayed_work(system_wq, &touch->dwork, delay);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int synaptics_i2c_open(struct input_dev *input)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch = input_get_drvdata(input);
4578c2ecf20Sopenharmony_ci	int ret;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	ret = synaptics_i2c_reset_config(touch->client);
4608c2ecf20Sopenharmony_ci	if (ret)
4618c2ecf20Sopenharmony_ci		return ret;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (polling_req)
4648c2ecf20Sopenharmony_ci		mod_delayed_work(system_wq, &touch->dwork,
4658c2ecf20Sopenharmony_ci				msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return 0;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic void synaptics_i2c_close(struct input_dev *input)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch = input_get_drvdata(input);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (!polling_req)
4758c2ecf20Sopenharmony_ci		synaptics_i2c_reg_set(touch->client, INTERRUPT_EN_REG, 0);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&touch->dwork);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	/* Save some power */
4808c2ecf20Sopenharmony_ci	synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP);
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic void synaptics_i2c_set_input_params(struct synaptics_i2c *touch)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct input_dev *input = touch->input;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	input->name = touch->client->name;
4888c2ecf20Sopenharmony_ci	input->phys = touch->client->adapter->name;
4898c2ecf20Sopenharmony_ci	input->id.bustype = BUS_I2C;
4908c2ecf20Sopenharmony_ci	input->id.version = synaptics_i2c_word_get(touch->client,
4918c2ecf20Sopenharmony_ci						   INFO_QUERY_REG0);
4928c2ecf20Sopenharmony_ci	input->dev.parent = &touch->client->dev;
4938c2ecf20Sopenharmony_ci	input->open = synaptics_i2c_open;
4948c2ecf20Sopenharmony_ci	input->close = synaptics_i2c_close;
4958c2ecf20Sopenharmony_ci	input_set_drvdata(input, touch);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/* Register the device as mouse */
4988c2ecf20Sopenharmony_ci	__set_bit(EV_REL, input->evbit);
4998c2ecf20Sopenharmony_ci	__set_bit(REL_X, input->relbit);
5008c2ecf20Sopenharmony_ci	__set_bit(REL_Y, input->relbit);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* Register device's buttons and keys */
5038c2ecf20Sopenharmony_ci	__set_bit(EV_KEY, input->evbit);
5048c2ecf20Sopenharmony_ci	__set_bit(BTN_LEFT, input->keybit);
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	touch = kzalloc(sizeof(struct synaptics_i2c), GFP_KERNEL);
5128c2ecf20Sopenharmony_ci	if (!touch)
5138c2ecf20Sopenharmony_ci		return NULL;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	touch->client = client;
5168c2ecf20Sopenharmony_ci	touch->no_decel_param = no_decel;
5178c2ecf20Sopenharmony_ci	touch->scan_rate_param = scan_rate;
5188c2ecf20Sopenharmony_ci	set_scan_rate(touch, scan_rate);
5198c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return touch;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic int synaptics_i2c_probe(struct i2c_client *client,
5258c2ecf20Sopenharmony_ci			       const struct i2c_device_id *dev_id)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	int ret;
5288c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	touch = synaptics_i2c_touch_create(client);
5318c2ecf20Sopenharmony_ci	if (!touch)
5328c2ecf20Sopenharmony_ci		return -ENOMEM;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	ret = synaptics_i2c_reset_config(client);
5358c2ecf20Sopenharmony_ci	if (ret)
5368c2ecf20Sopenharmony_ci		goto err_mem_free;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (client->irq < 1)
5398c2ecf20Sopenharmony_ci		polling_req = true;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	touch->input = input_allocate_device();
5428c2ecf20Sopenharmony_ci	if (!touch->input) {
5438c2ecf20Sopenharmony_ci		ret = -ENOMEM;
5448c2ecf20Sopenharmony_ci		goto err_mem_free;
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	synaptics_i2c_set_input_params(touch);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (!polling_req) {
5508c2ecf20Sopenharmony_ci		dev_dbg(&touch->client->dev,
5518c2ecf20Sopenharmony_ci			 "Requesting IRQ: %d\n", touch->client->irq);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		ret = request_irq(touch->client->irq, synaptics_i2c_irq,
5548c2ecf20Sopenharmony_ci				  IRQ_TYPE_EDGE_FALLING,
5558c2ecf20Sopenharmony_ci				  DRIVER_NAME, touch);
5568c2ecf20Sopenharmony_ci		if (ret) {
5578c2ecf20Sopenharmony_ci			dev_warn(&touch->client->dev,
5588c2ecf20Sopenharmony_ci				  "IRQ request failed: %d, "
5598c2ecf20Sopenharmony_ci				  "falling back to polling\n", ret);
5608c2ecf20Sopenharmony_ci			polling_req = true;
5618c2ecf20Sopenharmony_ci			synaptics_i2c_reg_set(touch->client,
5628c2ecf20Sopenharmony_ci					      INTERRUPT_EN_REG, 0);
5638c2ecf20Sopenharmony_ci		}
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (polling_req)
5678c2ecf20Sopenharmony_ci		dev_dbg(&touch->client->dev,
5688c2ecf20Sopenharmony_ci			 "Using polling at rate: %d times/sec\n", scan_rate);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	/* Register the device in input subsystem */
5718c2ecf20Sopenharmony_ci	ret = input_register_device(touch->input);
5728c2ecf20Sopenharmony_ci	if (ret) {
5738c2ecf20Sopenharmony_ci		dev_err(&client->dev,
5748c2ecf20Sopenharmony_ci			 "Input device register failed: %d\n", ret);
5758c2ecf20Sopenharmony_ci		goto err_input_free;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, touch);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	return 0;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cierr_input_free:
5838c2ecf20Sopenharmony_ci	input_free_device(touch->input);
5848c2ecf20Sopenharmony_cierr_mem_free:
5858c2ecf20Sopenharmony_ci	kfree(touch);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	return ret;
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic int synaptics_i2c_remove(struct i2c_client *client)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch = i2c_get_clientdata(client);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	if (!polling_req)
5958c2ecf20Sopenharmony_ci		free_irq(client->irq, touch);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	input_unregister_device(touch->input);
5988c2ecf20Sopenharmony_ci	kfree(touch);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	return 0;
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic int __maybe_unused synaptics_i2c_suspend(struct device *dev)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
6068c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch = i2c_get_clientdata(client);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&touch->dwork);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/* Save some power */
6118c2ecf20Sopenharmony_ci	synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	return 0;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic int __maybe_unused synaptics_i2c_resume(struct device *dev)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	int ret;
6198c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
6208c2ecf20Sopenharmony_ci	struct synaptics_i2c *touch = i2c_get_clientdata(client);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	ret = synaptics_i2c_reset_config(client);
6238c2ecf20Sopenharmony_ci	if (ret)
6248c2ecf20Sopenharmony_ci		return ret;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	mod_delayed_work(system_wq, &touch->dwork,
6278c2ecf20Sopenharmony_ci				msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	return 0;
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
6338c2ecf20Sopenharmony_ci			 synaptics_i2c_resume);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic const struct i2c_device_id synaptics_i2c_id_table[] = {
6368c2ecf20Sopenharmony_ci	{ "synaptics_i2c", 0 },
6378c2ecf20Sopenharmony_ci	{ },
6388c2ecf20Sopenharmony_ci};
6398c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
6428c2ecf20Sopenharmony_cistatic const struct of_device_id synaptics_i2c_of_match[] = {
6438c2ecf20Sopenharmony_ci	{ .compatible = "synaptics,synaptics_i2c", },
6448c2ecf20Sopenharmony_ci	{ },
6458c2ecf20Sopenharmony_ci};
6468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, synaptics_i2c_of_match);
6478c2ecf20Sopenharmony_ci#endif
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cistatic struct i2c_driver synaptics_i2c_driver = {
6508c2ecf20Sopenharmony_ci	.driver = {
6518c2ecf20Sopenharmony_ci		.name	= DRIVER_NAME,
6528c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(synaptics_i2c_of_match),
6538c2ecf20Sopenharmony_ci		.pm	= &synaptics_i2c_pm,
6548c2ecf20Sopenharmony_ci	},
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	.probe		= synaptics_i2c_probe,
6578c2ecf20Sopenharmony_ci	.remove		= synaptics_i2c_remove,
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	.id_table	= synaptics_i2c_id_table,
6608c2ecf20Sopenharmony_ci};
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_cimodule_i2c_driver(synaptics_i2c_driver);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Synaptics I2C touchpad driver");
6658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab");
6668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6678c2ecf20Sopenharmony_ci
668