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