14cf51c38SJoonyoung Shim /* 27686b108SIiro Valkonen * Atmel maXTouch Touchscreen driver 34cf51c38SJoonyoung Shim * 44cf51c38SJoonyoung Shim * Copyright (C) 2010 Samsung Electronics Co.Ltd 550a77c65SNick Dyer * Copyright (C) 2011-2014 Atmel Corporation 61e0c0c5bSDaniel Kurtz * Copyright (C) 2012 Google, Inc. 71e0c0c5bSDaniel Kurtz * 84cf51c38SJoonyoung Shim * Author: Joonyoung Shim <jy0922.shim@samsung.com> 94cf51c38SJoonyoung Shim * 104cf51c38SJoonyoung Shim * This program is free software; you can redistribute it and/or modify it 114cf51c38SJoonyoung Shim * under the terms of the GNU General Public License as published by the 124cf51c38SJoonyoung Shim * Free Software Foundation; either version 2 of the License, or (at your 134cf51c38SJoonyoung Shim * option) any later version. 144cf51c38SJoonyoung Shim * 154cf51c38SJoonyoung Shim */ 164cf51c38SJoonyoung Shim 174f8d8088SDmitry Torokhov #include <linux/acpi.h> 184f8d8088SDmitry Torokhov #include <linux/dmi.h> 194cf51c38SJoonyoung Shim #include <linux/module.h> 20d79e7e47SBenson Leung #include <linux/init.h> 21d79e7e47SBenson Leung #include <linux/completion.h> 224cf51c38SJoonyoung Shim #include <linux/delay.h> 234cf51c38SJoonyoung Shim #include <linux/firmware.h> 244cf51c38SJoonyoung Shim #include <linux/i2c.h> 257f3884f7SNick Dyer #include <linux/platform_data/atmel_mxt_ts.h> 268b86c1c2SJoonyoung Shim #include <linux/input/mt.h> 274cf51c38SJoonyoung Shim #include <linux/interrupt.h> 2878188be3SStephen Warren #include <linux/of.h> 294cf51c38SJoonyoung Shim #include <linux/slab.h> 30b23157dcSNick Dyer #include <asm/unaligned.h> 314cf51c38SJoonyoung Shim 3250a77c65SNick Dyer /* Firmware files */ 337686b108SIiro Valkonen #define MXT_FW_NAME "maxtouch.fw" 3450a77c65SNick Dyer #define MXT_CFG_NAME "maxtouch.cfg" 3550a77c65SNick Dyer #define MXT_CFG_MAGIC "OBP_RAW V1" 364cf51c38SJoonyoung Shim 374cf51c38SJoonyoung Shim /* Registers */ 387686b108SIiro Valkonen #define MXT_OBJECT_START 0x07 397686b108SIiro Valkonen #define MXT_OBJECT_SIZE 6 404ce6fa01SNick Dyer #define MXT_INFO_CHECKSUM_SIZE 3 414ce6fa01SNick Dyer #define MXT_MAX_BLOCK_WRITE 256 424cf51c38SJoonyoung Shim 434cf51c38SJoonyoung Shim /* Object types */ 4481c88a71SIiro Valkonen #define MXT_DEBUG_DIAGNOSTIC_T37 37 4581c88a71SIiro Valkonen #define MXT_GEN_MESSAGE_T5 5 4681c88a71SIiro Valkonen #define MXT_GEN_COMMAND_T6 6 4781c88a71SIiro Valkonen #define MXT_GEN_POWER_T7 7 4881c88a71SIiro Valkonen #define MXT_GEN_ACQUIRE_T8 8 4981c88a71SIiro Valkonen #define MXT_GEN_DATASOURCE_T53 53 5081c88a71SIiro Valkonen #define MXT_TOUCH_MULTI_T9 9 5181c88a71SIiro Valkonen #define MXT_TOUCH_KEYARRAY_T15 15 5281c88a71SIiro Valkonen #define MXT_TOUCH_PROXIMITY_T23 23 5381c88a71SIiro Valkonen #define MXT_TOUCH_PROXKEY_T52 52 5481c88a71SIiro Valkonen #define MXT_PROCI_GRIPFACE_T20 20 5581c88a71SIiro Valkonen #define MXT_PROCG_NOISE_T22 22 5681c88a71SIiro Valkonen #define MXT_PROCI_ONETOUCH_T24 24 5781c88a71SIiro Valkonen #define MXT_PROCI_TWOTOUCH_T27 27 5881c88a71SIiro Valkonen #define MXT_PROCI_GRIP_T40 40 5981c88a71SIiro Valkonen #define MXT_PROCI_PALM_T41 41 6081c88a71SIiro Valkonen #define MXT_PROCI_TOUCHSUPPRESSION_T42 42 6181c88a71SIiro Valkonen #define MXT_PROCI_STYLUS_T47 47 6281c88a71SIiro Valkonen #define MXT_PROCG_NOISESUPPRESSION_T48 48 6381c88a71SIiro Valkonen #define MXT_SPT_COMMSCONFIG_T18 18 6481c88a71SIiro Valkonen #define MXT_SPT_GPIOPWM_T19 19 6581c88a71SIiro Valkonen #define MXT_SPT_SELFTEST_T25 25 6681c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T28 28 6781c88a71SIiro Valkonen #define MXT_SPT_USERDATA_T38 38 6881c88a71SIiro Valkonen #define MXT_SPT_DIGITIZER_T43 43 6981c88a71SIiro Valkonen #define MXT_SPT_MESSAGECOUNT_T44 44 7081c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T46 46 71b23157dcSNick Dyer #define MXT_TOUCH_MULTITOUCHSCREEN_T100 100 724cf51c38SJoonyoung Shim 735f3f9bc2SNick Dyer /* MXT_GEN_MESSAGE_T5 object */ 745f3f9bc2SNick Dyer #define MXT_RPTID_NOMSG 0xff 755f3f9bc2SNick Dyer 7681c88a71SIiro Valkonen /* MXT_GEN_COMMAND_T6 field */ 777686b108SIiro Valkonen #define MXT_COMMAND_RESET 0 787686b108SIiro Valkonen #define MXT_COMMAND_BACKUPNV 1 797686b108SIiro Valkonen #define MXT_COMMAND_CALIBRATE 2 807686b108SIiro Valkonen #define MXT_COMMAND_REPORTALL 3 817686b108SIiro Valkonen #define MXT_COMMAND_DIAGNOSTIC 5 824cf51c38SJoonyoung Shim 83a4a2ef46SIiro Valkonen /* Define for T6 status byte */ 84a4a2ef46SIiro Valkonen #define MXT_T6_STATUS_RESET (1 << 7) 85497767d1SNick Dyer #define MXT_T6_STATUS_OFL (1 << 6) 86497767d1SNick Dyer #define MXT_T6_STATUS_SIGERR (1 << 5) 87497767d1SNick Dyer #define MXT_T6_STATUS_CAL (1 << 4) 88497767d1SNick Dyer #define MXT_T6_STATUS_CFGERR (1 << 3) 89497767d1SNick Dyer #define MXT_T6_STATUS_COMSERR (1 << 2) 90a4a2ef46SIiro Valkonen 9181c88a71SIiro Valkonen /* MXT_GEN_POWER_T7 field */ 927f3884f7SNick Dyer struct t7_config { 937f3884f7SNick Dyer u8 idle; 947f3884f7SNick Dyer u8 active; 957f3884f7SNick Dyer } __packed; 967f3884f7SNick Dyer 977f3884f7SNick Dyer #define MXT_POWER_CFG_RUN 0 987f3884f7SNick Dyer #define MXT_POWER_CFG_DEEPSLEEP 1 994cf51c38SJoonyoung Shim 10081c88a71SIiro Valkonen /* MXT_TOUCH_MULTI_T9 field */ 1017f3884f7SNick Dyer #define MXT_T9_CTRL 0 10261dc1abaSNick Dyer #define MXT_T9_ORIENT 9 10361dc1abaSNick Dyer #define MXT_T9_RANGE 18 10461dc1abaSNick Dyer 105f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 status */ 106f3889ed1SNick Dyer #define MXT_T9_UNGRIP (1 << 0) 107f3889ed1SNick Dyer #define MXT_T9_SUPPRESS (1 << 1) 108f3889ed1SNick Dyer #define MXT_T9_AMP (1 << 2) 109f3889ed1SNick Dyer #define MXT_T9_VECTOR (1 << 3) 110f3889ed1SNick Dyer #define MXT_T9_MOVE (1 << 4) 111f3889ed1SNick Dyer #define MXT_T9_RELEASE (1 << 5) 112f3889ed1SNick Dyer #define MXT_T9_PRESS (1 << 6) 113f3889ed1SNick Dyer #define MXT_T9_DETECT (1 << 7) 114f3889ed1SNick Dyer 11561dc1abaSNick Dyer struct t9_range { 1161c0276d5SNick Dyer __le16 x; 1171c0276d5SNick Dyer __le16 y; 11861dc1abaSNick Dyer } __packed; 11961dc1abaSNick Dyer 120f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 orient */ 121f3889ed1SNick Dyer #define MXT_T9_ORIENT_SWITCH (1 << 0) 1224cf51c38SJoonyoung Shim 12381c88a71SIiro Valkonen /* MXT_SPT_COMMSCONFIG_T18 */ 1247686b108SIiro Valkonen #define MXT_COMMS_CTRL 0 1257686b108SIiro Valkonen #define MXT_COMMS_CMD 1 1264cf51c38SJoonyoung Shim 127*d6a39404SNick Dyer /* MXT_DEBUG_DIAGNOSTIC_T37 */ 128*d6a39404SNick Dyer #define MXT_DIAGNOSTIC_PAGEUP 0x01 129*d6a39404SNick Dyer #define MXT_DIAGNOSTIC_DELTAS 0x10 130*d6a39404SNick Dyer #define MXT_DIAGNOSTIC_SIZE 128 131*d6a39404SNick Dyer 132*d6a39404SNick Dyer struct t37_debug { 133*d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 134*d6a39404SNick Dyer u8 mode; 135*d6a39404SNick Dyer u8 page; 136*d6a39404SNick Dyer u8 data[MXT_DIAGNOSTIC_SIZE]; 137*d6a39404SNick Dyer #endif 138*d6a39404SNick Dyer }; 139*d6a39404SNick Dyer 14081c88a71SIiro Valkonen /* Define for MXT_GEN_COMMAND_T6 */ 1417686b108SIiro Valkonen #define MXT_BOOT_VALUE 0xa5 142a4a2ef46SIiro Valkonen #define MXT_RESET_VALUE 0x01 1437686b108SIiro Valkonen #define MXT_BACKUP_VALUE 0x55 144a4a2ef46SIiro Valkonen 145b23157dcSNick Dyer /* T100 Multiple Touch Touchscreen */ 146b23157dcSNick Dyer #define MXT_T100_CTRL 0 147b23157dcSNick Dyer #define MXT_T100_CFG1 1 148b23157dcSNick Dyer #define MXT_T100_TCHAUX 3 149b23157dcSNick Dyer #define MXT_T100_XRANGE 13 150b23157dcSNick Dyer #define MXT_T100_YRANGE 24 151b23157dcSNick Dyer 152b23157dcSNick Dyer #define MXT_T100_CFG_SWITCHXY BIT(5) 153b23157dcSNick Dyer 154b23157dcSNick Dyer #define MXT_T100_TCHAUX_VECT BIT(0) 155b23157dcSNick Dyer #define MXT_T100_TCHAUX_AMPL BIT(1) 156b23157dcSNick Dyer #define MXT_T100_TCHAUX_AREA BIT(2) 157b23157dcSNick Dyer 158b23157dcSNick Dyer #define MXT_T100_DETECT BIT(7) 159b23157dcSNick Dyer #define MXT_T100_TYPE_MASK 0x70 160b23157dcSNick Dyer 161b23157dcSNick Dyer enum t100_type { 162b23157dcSNick Dyer MXT_T100_TYPE_FINGER = 1, 163b23157dcSNick Dyer MXT_T100_TYPE_PASSIVE_STYLUS = 2, 164b23157dcSNick Dyer MXT_T100_TYPE_HOVERING_FINGER = 4, 165b23157dcSNick Dyer MXT_T100_TYPE_GLOVE = 5, 166b23157dcSNick Dyer MXT_T100_TYPE_LARGE_TOUCH = 6, 167b23157dcSNick Dyer }; 168b23157dcSNick Dyer 169b23157dcSNick Dyer #define MXT_DISTANCE_ACTIVE_TOUCH 0 170b23157dcSNick Dyer #define MXT_DISTANCE_HOVERING 1 171b23157dcSNick Dyer 172b23157dcSNick Dyer #define MXT_TOUCH_MAJOR_DEFAULT 1 173b23157dcSNick Dyer #define MXT_PRESSURE_DEFAULT 1 174b23157dcSNick Dyer 175a4a2ef46SIiro Valkonen /* Delay times */ 1768343bce1SLinus Torvalds #define MXT_BACKUP_TIME 50 /* msec */ 1778343bce1SLinus Torvalds #define MXT_RESET_TIME 200 /* msec */ 178a4a2ef46SIiro Valkonen #define MXT_RESET_TIMEOUT 3000 /* msec */ 179c3f78043SNick Dyer #define MXT_CRC_TIMEOUT 1000 /* msec */ 180a0434b75SBenson Leung #define MXT_FW_RESET_TIME 3000 /* msec */ 181a0434b75SBenson Leung #define MXT_FW_CHG_TIMEOUT 300 /* msec */ 1824cf51c38SJoonyoung Shim 1834cf51c38SJoonyoung Shim /* Command to unlock bootloader */ 1847686b108SIiro Valkonen #define MXT_UNLOCK_CMD_MSB 0xaa 1857686b108SIiro Valkonen #define MXT_UNLOCK_CMD_LSB 0xdc 1864cf51c38SJoonyoung Shim 1874cf51c38SJoonyoung Shim /* Bootloader mode status */ 1887686b108SIiro Valkonen #define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ 1897686b108SIiro Valkonen #define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ 1907686b108SIiro Valkonen #define MXT_FRAME_CRC_CHECK 0x02 1917686b108SIiro Valkonen #define MXT_FRAME_CRC_FAIL 0x03 1927686b108SIiro Valkonen #define MXT_FRAME_CRC_PASS 0x04 1937686b108SIiro Valkonen #define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ 1947686b108SIiro Valkonen #define MXT_BOOT_STATUS_MASK 0x3f 195e57a66aaSNick Dyer #define MXT_BOOT_EXTENDED_ID (1 << 5) 196e57a66aaSNick Dyer #define MXT_BOOT_ID_MASK 0x1f 1974cf51c38SJoonyoung Shim 1984cf51c38SJoonyoung Shim /* Touchscreen absolute values */ 1997686b108SIiro Valkonen #define MXT_MAX_AREA 0xff 2004cf51c38SJoonyoung Shim 20122dfab7fSDaniel Kurtz #define MXT_PIXELS_PER_MM 20 20222dfab7fSDaniel Kurtz 2037686b108SIiro Valkonen struct mxt_info { 2044cf51c38SJoonyoung Shim u8 family_id; 2054cf51c38SJoonyoung Shim u8 variant_id; 2064cf51c38SJoonyoung Shim u8 version; 2074cf51c38SJoonyoung Shim u8 build; 2084cf51c38SJoonyoung Shim u8 matrix_xsize; 2094cf51c38SJoonyoung Shim u8 matrix_ysize; 2104cf51c38SJoonyoung Shim u8 object_num; 2114cf51c38SJoonyoung Shim }; 2124cf51c38SJoonyoung Shim 2137686b108SIiro Valkonen struct mxt_object { 2144cf51c38SJoonyoung Shim u8 type; 2154cf51c38SJoonyoung Shim u16 start_address; 2161e0c0c5bSDaniel Kurtz u8 size_minus_one; 2171e0c0c5bSDaniel Kurtz u8 instances_minus_one; 2184cf51c38SJoonyoung Shim u8 num_report_ids; 219333e5a9aSDaniel Kurtz } __packed; 2204cf51c38SJoonyoung Shim 221*d6a39404SNick Dyer struct mxt_dbg { 222*d6a39404SNick Dyer u16 t37_address; 223*d6a39404SNick Dyer u16 diag_cmd_address; 224*d6a39404SNick Dyer struct t37_debug *t37_buf; 225*d6a39404SNick Dyer unsigned int t37_pages; 226*d6a39404SNick Dyer unsigned int t37_nodes; 227*d6a39404SNick Dyer }; 228*d6a39404SNick Dyer 2294cf51c38SJoonyoung Shim /* Each client has this additional data */ 2307686b108SIiro Valkonen struct mxt_data { 2314cf51c38SJoonyoung Shim struct i2c_client *client; 2324cf51c38SJoonyoung Shim struct input_dev *input_dev; 233ec02ac2bSDaniel Kurtz char phys[64]; /* device physical location */ 2347686b108SIiro Valkonen const struct mxt_platform_data *pdata; 2357686b108SIiro Valkonen struct mxt_object *object_table; 2367686b108SIiro Valkonen struct mxt_info info; 2374cf51c38SJoonyoung Shim unsigned int irq; 238910d8051SJoonyoung Shim unsigned int max_x; 239910d8051SJoonyoung Shim unsigned int max_y; 2401c0276d5SNick Dyer bool xy_switch; 241d79e7e47SBenson Leung bool in_bootloader; 2424ce6fa01SNick Dyer u16 mem_size; 243b23157dcSNick Dyer u8 t100_aux_ampl; 244b23157dcSNick Dyer u8 t100_aux_area; 245b23157dcSNick Dyer u8 t100_aux_vect; 2469d8dc3e5SNick Dyer u8 max_reportid; 247c3f78043SNick Dyer u32 config_crc; 2484ce6fa01SNick Dyer u32 info_crc; 249f28a842dSNick Dyer u8 bootloader_addr; 2505f3f9bc2SNick Dyer u8 *msg_buf; 251497767d1SNick Dyer u8 t6_status; 252b9b05a89SNick Dyer bool update_input; 2539d8dc3e5SNick Dyer u8 last_message_count; 2549d8dc3e5SNick Dyer u8 num_touchids; 255b23157dcSNick Dyer u8 multitouch; 2567f3884f7SNick Dyer struct t7_config t7_cfg; 257*d6a39404SNick Dyer struct mxt_dbg dbg; 258333e5a9aSDaniel Kurtz 259333e5a9aSDaniel Kurtz /* Cached parameters from object table */ 260b9b05a89SNick Dyer u16 T5_address; 2615f3f9bc2SNick Dyer u8 T5_msg_size; 262fdf80421SDaniel Kurtz u8 T6_reportid; 263a4a2ef46SIiro Valkonen u16 T6_address; 2644ce6fa01SNick Dyer u16 T7_address; 265333e5a9aSDaniel Kurtz u8 T9_reportid_min; 266333e5a9aSDaniel Kurtz u8 T9_reportid_max; 26722dfab7fSDaniel Kurtz u8 T19_reportid; 2689d8dc3e5SNick Dyer u16 T44_address; 269b23157dcSNick Dyer u8 T100_reportid_min; 270b23157dcSNick Dyer u8 T100_reportid_max; 271d79e7e47SBenson Leung 272d79e7e47SBenson Leung /* for fw update in bootloader */ 273d79e7e47SBenson Leung struct completion bl_completion; 274a4a2ef46SIiro Valkonen 275a4a2ef46SIiro Valkonen /* for reset handling */ 276a4a2ef46SIiro Valkonen struct completion reset_completion; 277c3f78043SNick Dyer 278c3f78043SNick Dyer /* for config update handling */ 279c3f78043SNick Dyer struct completion crc_completion; 2804cf51c38SJoonyoung Shim }; 2814cf51c38SJoonyoung Shim 2821e0c0c5bSDaniel Kurtz static size_t mxt_obj_size(const struct mxt_object *obj) 2831e0c0c5bSDaniel Kurtz { 2841e0c0c5bSDaniel Kurtz return obj->size_minus_one + 1; 2851e0c0c5bSDaniel Kurtz } 2861e0c0c5bSDaniel Kurtz 2871e0c0c5bSDaniel Kurtz static size_t mxt_obj_instances(const struct mxt_object *obj) 2881e0c0c5bSDaniel Kurtz { 2891e0c0c5bSDaniel Kurtz return obj->instances_minus_one + 1; 2901e0c0c5bSDaniel Kurtz } 2911e0c0c5bSDaniel Kurtz 2927686b108SIiro Valkonen static bool mxt_object_readable(unsigned int type) 2934cf51c38SJoonyoung Shim { 2944cf51c38SJoonyoung Shim switch (type) { 29581c88a71SIiro Valkonen case MXT_GEN_COMMAND_T6: 29681c88a71SIiro Valkonen case MXT_GEN_POWER_T7: 29781c88a71SIiro Valkonen case MXT_GEN_ACQUIRE_T8: 29881c88a71SIiro Valkonen case MXT_GEN_DATASOURCE_T53: 29981c88a71SIiro Valkonen case MXT_TOUCH_MULTI_T9: 30081c88a71SIiro Valkonen case MXT_TOUCH_KEYARRAY_T15: 30181c88a71SIiro Valkonen case MXT_TOUCH_PROXIMITY_T23: 30281c88a71SIiro Valkonen case MXT_TOUCH_PROXKEY_T52: 30381c88a71SIiro Valkonen case MXT_PROCI_GRIPFACE_T20: 30481c88a71SIiro Valkonen case MXT_PROCG_NOISE_T22: 30581c88a71SIiro Valkonen case MXT_PROCI_ONETOUCH_T24: 30681c88a71SIiro Valkonen case MXT_PROCI_TWOTOUCH_T27: 30781c88a71SIiro Valkonen case MXT_PROCI_GRIP_T40: 30881c88a71SIiro Valkonen case MXT_PROCI_PALM_T41: 30981c88a71SIiro Valkonen case MXT_PROCI_TOUCHSUPPRESSION_T42: 31081c88a71SIiro Valkonen case MXT_PROCI_STYLUS_T47: 31181c88a71SIiro Valkonen case MXT_PROCG_NOISESUPPRESSION_T48: 31281c88a71SIiro Valkonen case MXT_SPT_COMMSCONFIG_T18: 31381c88a71SIiro Valkonen case MXT_SPT_GPIOPWM_T19: 31481c88a71SIiro Valkonen case MXT_SPT_SELFTEST_T25: 31581c88a71SIiro Valkonen case MXT_SPT_CTECONFIG_T28: 31681c88a71SIiro Valkonen case MXT_SPT_USERDATA_T38: 31781c88a71SIiro Valkonen case MXT_SPT_DIGITIZER_T43: 31881c88a71SIiro Valkonen case MXT_SPT_CTECONFIG_T46: 3194cf51c38SJoonyoung Shim return true; 3204cf51c38SJoonyoung Shim default: 3214cf51c38SJoonyoung Shim return false; 3224cf51c38SJoonyoung Shim } 3234cf51c38SJoonyoung Shim } 3244cf51c38SJoonyoung Shim 3255f3f9bc2SNick Dyer static void mxt_dump_message(struct mxt_data *data, u8 *message) 3264cf51c38SJoonyoung Shim { 3275f3f9bc2SNick Dyer dev_dbg(&data->client->dev, "message: %*ph\n", 3285f3f9bc2SNick Dyer data->T5_msg_size, message); 3294cf51c38SJoonyoung Shim } 3304cf51c38SJoonyoung Shim 331a4a2ef46SIiro Valkonen static int mxt_wait_for_completion(struct mxt_data *data, 332a4a2ef46SIiro Valkonen struct completion *comp, 333a4a2ef46SIiro Valkonen unsigned int timeout_ms) 3344cf51c38SJoonyoung Shim { 335d79e7e47SBenson Leung struct device *dev = &data->client->dev; 336d79e7e47SBenson Leung unsigned long timeout = msecs_to_jiffies(timeout_ms); 337d79e7e47SBenson Leung long ret; 338d79e7e47SBenson Leung 339d79e7e47SBenson Leung ret = wait_for_completion_interruptible_timeout(comp, timeout); 340d79e7e47SBenson Leung if (ret < 0) { 341d79e7e47SBenson Leung return ret; 342d79e7e47SBenson Leung } else if (ret == 0) { 343d79e7e47SBenson Leung dev_err(dev, "Wait for completion timed out.\n"); 344d79e7e47SBenson Leung return -ETIMEDOUT; 345d79e7e47SBenson Leung } 346d79e7e47SBenson Leung return 0; 347d79e7e47SBenson Leung } 348d79e7e47SBenson Leung 349f28a842dSNick Dyer static int mxt_bootloader_read(struct mxt_data *data, 350f28a842dSNick Dyer u8 *val, unsigned int count) 351f28a842dSNick Dyer { 352f28a842dSNick Dyer int ret; 353f28a842dSNick Dyer struct i2c_msg msg; 354f28a842dSNick Dyer 355f28a842dSNick Dyer msg.addr = data->bootloader_addr; 356f28a842dSNick Dyer msg.flags = data->client->flags & I2C_M_TEN; 357f28a842dSNick Dyer msg.flags |= I2C_M_RD; 358f28a842dSNick Dyer msg.len = count; 359f28a842dSNick Dyer msg.buf = val; 360f28a842dSNick Dyer 361f28a842dSNick Dyer ret = i2c_transfer(data->client->adapter, &msg, 1); 362f28a842dSNick Dyer if (ret == 1) { 363f28a842dSNick Dyer ret = 0; 364f28a842dSNick Dyer } else { 365f28a842dSNick Dyer ret = ret < 0 ? ret : -EIO; 366f28a842dSNick Dyer dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n", 367f28a842dSNick Dyer __func__, ret); 368f28a842dSNick Dyer } 369f28a842dSNick Dyer 370f28a842dSNick Dyer return ret; 371f28a842dSNick Dyer } 372f28a842dSNick Dyer 373f28a842dSNick Dyer static int mxt_bootloader_write(struct mxt_data *data, 374f28a842dSNick Dyer const u8 * const val, unsigned int count) 375f28a842dSNick Dyer { 376f28a842dSNick Dyer int ret; 377f28a842dSNick Dyer struct i2c_msg msg; 378f28a842dSNick Dyer 379f28a842dSNick Dyer msg.addr = data->bootloader_addr; 380f28a842dSNick Dyer msg.flags = data->client->flags & I2C_M_TEN; 381f28a842dSNick Dyer msg.len = count; 382f28a842dSNick Dyer msg.buf = (u8 *)val; 383f28a842dSNick Dyer 384f28a842dSNick Dyer ret = i2c_transfer(data->client->adapter, &msg, 1); 385f28a842dSNick Dyer if (ret == 1) { 386f28a842dSNick Dyer ret = 0; 387f28a842dSNick Dyer } else { 388f28a842dSNick Dyer ret = ret < 0 ? ret : -EIO; 389f28a842dSNick Dyer dev_err(&data->client->dev, "%s: i2c send failed (%d)\n", 390f28a842dSNick Dyer __func__, ret); 391f28a842dSNick Dyer } 392f28a842dSNick Dyer 393f28a842dSNick Dyer return ret; 394f28a842dSNick Dyer } 395f28a842dSNick Dyer 3968efaa5e5SNick Dyer static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry) 397f28a842dSNick Dyer { 398f28a842dSNick Dyer u8 appmode = data->client->addr; 399f28a842dSNick Dyer u8 bootloader; 400f28a842dSNick Dyer 401f28a842dSNick Dyer switch (appmode) { 402f28a842dSNick Dyer case 0x4a: 403f28a842dSNick Dyer case 0x4b: 40444a0bab2SNick Dyer /* Chips after 1664S use different scheme */ 4058efaa5e5SNick Dyer if (retry || data->info.family_id >= 0xa2) { 40644a0bab2SNick Dyer bootloader = appmode - 0x24; 40744a0bab2SNick Dyer break; 40844a0bab2SNick Dyer } 40944a0bab2SNick Dyer /* Fall through for normal case */ 410f28a842dSNick Dyer case 0x4c: 411f28a842dSNick Dyer case 0x4d: 412f28a842dSNick Dyer case 0x5a: 413f28a842dSNick Dyer case 0x5b: 414f28a842dSNick Dyer bootloader = appmode - 0x26; 415f28a842dSNick Dyer break; 4166cd1ab0fSDmitry Torokhov 417f28a842dSNick Dyer default: 418f28a842dSNick Dyer dev_err(&data->client->dev, 419f28a842dSNick Dyer "Appmode i2c address 0x%02x not found\n", 420f28a842dSNick Dyer appmode); 421f28a842dSNick Dyer return -EINVAL; 422f28a842dSNick Dyer } 423f28a842dSNick Dyer 424f28a842dSNick Dyer data->bootloader_addr = bootloader; 425f28a842dSNick Dyer return 0; 426f28a842dSNick Dyer } 427f28a842dSNick Dyer 4286cd1ab0fSDmitry Torokhov static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address) 429a9fdd1e6SNick Dyer { 430a9fdd1e6SNick Dyer struct device *dev = &data->client->dev; 4316cd1ab0fSDmitry Torokhov int error; 432a9fdd1e6SNick Dyer u8 val; 433a9fdd1e6SNick Dyer bool crc_failure; 434a9fdd1e6SNick Dyer 4356cd1ab0fSDmitry Torokhov error = mxt_lookup_bootloader_address(data, alt_address); 4366cd1ab0fSDmitry Torokhov if (error) 4376cd1ab0fSDmitry Torokhov return error; 438a9fdd1e6SNick Dyer 4396cd1ab0fSDmitry Torokhov error = mxt_bootloader_read(data, &val, 1); 4406cd1ab0fSDmitry Torokhov if (error) 4416cd1ab0fSDmitry Torokhov return error; 442a9fdd1e6SNick Dyer 443a9fdd1e6SNick Dyer /* Check app crc fail mode */ 444a9fdd1e6SNick Dyer crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL; 445a9fdd1e6SNick Dyer 446a9fdd1e6SNick Dyer dev_err(dev, "Detected bootloader, status:%02X%s\n", 447a9fdd1e6SNick Dyer val, crc_failure ? ", APP_CRC_FAIL" : ""); 448a9fdd1e6SNick Dyer 449a9fdd1e6SNick Dyer return 0; 450a9fdd1e6SNick Dyer } 451a9fdd1e6SNick Dyer 452e57a66aaSNick Dyer static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val) 453e57a66aaSNick Dyer { 454e57a66aaSNick Dyer struct device *dev = &data->client->dev; 455e57a66aaSNick Dyer u8 buf[3]; 456e57a66aaSNick Dyer 457e57a66aaSNick Dyer if (val & MXT_BOOT_EXTENDED_ID) { 458e57a66aaSNick Dyer if (mxt_bootloader_read(data, &buf[0], 3) != 0) { 459e57a66aaSNick Dyer dev_err(dev, "%s: i2c failure\n", __func__); 46068807a0cSNick Dyer return val; 461e57a66aaSNick Dyer } 462e57a66aaSNick Dyer 463e57a66aaSNick Dyer dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]); 464e57a66aaSNick Dyer 465e57a66aaSNick Dyer return buf[0]; 466e57a66aaSNick Dyer } else { 467e57a66aaSNick Dyer dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK); 468e57a66aaSNick Dyer 469e57a66aaSNick Dyer return val; 470e57a66aaSNick Dyer } 471e57a66aaSNick Dyer } 472e57a66aaSNick Dyer 473385deb96SNick Dyer static int mxt_check_bootloader(struct mxt_data *data, unsigned int state, 474385deb96SNick Dyer bool wait) 475d79e7e47SBenson Leung { 476f28a842dSNick Dyer struct device *dev = &data->client->dev; 4774cf51c38SJoonyoung Shim u8 val; 478d79e7e47SBenson Leung int ret; 4794cf51c38SJoonyoung Shim 4804cf51c38SJoonyoung Shim recheck: 481385deb96SNick Dyer if (wait) { 482d79e7e47SBenson Leung /* 483d79e7e47SBenson Leung * In application update mode, the interrupt 484d79e7e47SBenson Leung * line signals state transitions. We must wait for the 485d79e7e47SBenson Leung * CHG assertion before reading the status byte. 486d79e7e47SBenson Leung * Once the status byte has been read, the line is deasserted. 487d79e7e47SBenson Leung */ 488a4a2ef46SIiro Valkonen ret = mxt_wait_for_completion(data, &data->bl_completion, 489a4a2ef46SIiro Valkonen MXT_FW_CHG_TIMEOUT); 490d79e7e47SBenson Leung if (ret) { 491d79e7e47SBenson Leung /* 492d79e7e47SBenson Leung * TODO: handle -ERESTARTSYS better by terminating 493d79e7e47SBenson Leung * fw update process before returning to userspace 494d79e7e47SBenson Leung * by writing length 0x000 to device (iff we are in 495d79e7e47SBenson Leung * WAITING_FRAME_DATA state). 496d79e7e47SBenson Leung */ 497f28a842dSNick Dyer dev_err(dev, "Update wait error %d\n", ret); 498d79e7e47SBenson Leung return ret; 499d79e7e47SBenson Leung } 500d79e7e47SBenson Leung } 501d79e7e47SBenson Leung 502f28a842dSNick Dyer ret = mxt_bootloader_read(data, &val, 1); 503f28a842dSNick Dyer if (ret) 504f28a842dSNick Dyer return ret; 5054cf51c38SJoonyoung Shim 506e57a66aaSNick Dyer if (state == MXT_WAITING_BOOTLOAD_CMD) 507e57a66aaSNick Dyer val = mxt_get_bootloader_version(data, val); 508e57a66aaSNick Dyer 5094cf51c38SJoonyoung Shim switch (state) { 5107686b108SIiro Valkonen case MXT_WAITING_BOOTLOAD_CMD: 5117686b108SIiro Valkonen case MXT_WAITING_FRAME_DATA: 512a9fdd1e6SNick Dyer case MXT_APP_CRC_FAIL: 5137686b108SIiro Valkonen val &= ~MXT_BOOT_STATUS_MASK; 5144cf51c38SJoonyoung Shim break; 5157686b108SIiro Valkonen case MXT_FRAME_CRC_PASS: 516f943c74aSNick Dyer if (val == MXT_FRAME_CRC_CHECK) { 5174cf51c38SJoonyoung Shim goto recheck; 518f943c74aSNick Dyer } else if (val == MXT_FRAME_CRC_FAIL) { 519f943c74aSNick Dyer dev_err(dev, "Bootloader CRC fail\n"); 520f943c74aSNick Dyer return -EINVAL; 521f943c74aSNick Dyer } 5224cf51c38SJoonyoung Shim break; 5234cf51c38SJoonyoung Shim default: 5244cf51c38SJoonyoung Shim return -EINVAL; 5254cf51c38SJoonyoung Shim } 5264cf51c38SJoonyoung Shim 5274cf51c38SJoonyoung Shim if (val != state) { 528f28a842dSNick Dyer dev_err(dev, "Invalid bootloader state %02X != %02X\n", 5297bed6805SNick Dyer val, state); 5304cf51c38SJoonyoung Shim return -EINVAL; 5314cf51c38SJoonyoung Shim } 5324cf51c38SJoonyoung Shim 5334cf51c38SJoonyoung Shim return 0; 5344cf51c38SJoonyoung Shim } 5354cf51c38SJoonyoung Shim 5368efaa5e5SNick Dyer static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock) 5374cf51c38SJoonyoung Shim { 538f28a842dSNick Dyer int ret; 5394cf51c38SJoonyoung Shim u8 buf[2]; 5404cf51c38SJoonyoung Shim 5418efaa5e5SNick Dyer if (unlock) { 5427686b108SIiro Valkonen buf[0] = MXT_UNLOCK_CMD_LSB; 5437686b108SIiro Valkonen buf[1] = MXT_UNLOCK_CMD_MSB; 5448efaa5e5SNick Dyer } else { 5458efaa5e5SNick Dyer buf[0] = 0x01; 5468efaa5e5SNick Dyer buf[1] = 0x01; 5478efaa5e5SNick Dyer } 5484cf51c38SJoonyoung Shim 549f28a842dSNick Dyer ret = mxt_bootloader_write(data, buf, 2); 550f28a842dSNick Dyer if (ret) 551f28a842dSNick Dyer return ret; 5524cf51c38SJoonyoung Shim 5534cf51c38SJoonyoung Shim return 0; 5544cf51c38SJoonyoung Shim } 5554cf51c38SJoonyoung Shim 5567686b108SIiro Valkonen static int __mxt_read_reg(struct i2c_client *client, 5574cf51c38SJoonyoung Shim u16 reg, u16 len, void *val) 5584cf51c38SJoonyoung Shim { 5594cf51c38SJoonyoung Shim struct i2c_msg xfer[2]; 5604cf51c38SJoonyoung Shim u8 buf[2]; 561771733e3SDaniel Kurtz int ret; 5624cf51c38SJoonyoung Shim 5634cf51c38SJoonyoung Shim buf[0] = reg & 0xff; 5644cf51c38SJoonyoung Shim buf[1] = (reg >> 8) & 0xff; 5654cf51c38SJoonyoung Shim 5664cf51c38SJoonyoung Shim /* Write register */ 5674cf51c38SJoonyoung Shim xfer[0].addr = client->addr; 5684cf51c38SJoonyoung Shim xfer[0].flags = 0; 5694cf51c38SJoonyoung Shim xfer[0].len = 2; 5704cf51c38SJoonyoung Shim xfer[0].buf = buf; 5714cf51c38SJoonyoung Shim 5724cf51c38SJoonyoung Shim /* Read data */ 5734cf51c38SJoonyoung Shim xfer[1].addr = client->addr; 5744cf51c38SJoonyoung Shim xfer[1].flags = I2C_M_RD; 5754cf51c38SJoonyoung Shim xfer[1].len = len; 5764cf51c38SJoonyoung Shim xfer[1].buf = val; 5774cf51c38SJoonyoung Shim 578771733e3SDaniel Kurtz ret = i2c_transfer(client->adapter, xfer, 2); 579771733e3SDaniel Kurtz if (ret == 2) { 580771733e3SDaniel Kurtz ret = 0; 581771733e3SDaniel Kurtz } else { 582771733e3SDaniel Kurtz if (ret >= 0) 583771733e3SDaniel Kurtz ret = -EIO; 584771733e3SDaniel Kurtz dev_err(&client->dev, "%s: i2c transfer failed (%d)\n", 585771733e3SDaniel Kurtz __func__, ret); 5864cf51c38SJoonyoung Shim } 5874cf51c38SJoonyoung Shim 588771733e3SDaniel Kurtz return ret; 5894cf51c38SJoonyoung Shim } 5904cf51c38SJoonyoung Shim 5919638ab7cSDaniel Kurtz static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len, 5929638ab7cSDaniel Kurtz const void *val) 5934cf51c38SJoonyoung Shim { 5949638ab7cSDaniel Kurtz u8 *buf; 5959638ab7cSDaniel Kurtz size_t count; 596771733e3SDaniel Kurtz int ret; 5974cf51c38SJoonyoung Shim 5989638ab7cSDaniel Kurtz count = len + 2; 5999638ab7cSDaniel Kurtz buf = kmalloc(count, GFP_KERNEL); 6009638ab7cSDaniel Kurtz if (!buf) 6019638ab7cSDaniel Kurtz return -ENOMEM; 6024cf51c38SJoonyoung Shim 6034cf51c38SJoonyoung Shim buf[0] = reg & 0xff; 6044cf51c38SJoonyoung Shim buf[1] = (reg >> 8) & 0xff; 6059638ab7cSDaniel Kurtz memcpy(&buf[2], val, len); 6064cf51c38SJoonyoung Shim 6079638ab7cSDaniel Kurtz ret = i2c_master_send(client, buf, count); 6089638ab7cSDaniel Kurtz if (ret == count) { 609771733e3SDaniel Kurtz ret = 0; 610771733e3SDaniel Kurtz } else { 611771733e3SDaniel Kurtz if (ret >= 0) 612771733e3SDaniel Kurtz ret = -EIO; 613771733e3SDaniel Kurtz dev_err(&client->dev, "%s: i2c send failed (%d)\n", 614771733e3SDaniel Kurtz __func__, ret); 6154cf51c38SJoonyoung Shim } 6164cf51c38SJoonyoung Shim 6179638ab7cSDaniel Kurtz kfree(buf); 618771733e3SDaniel Kurtz return ret; 6194cf51c38SJoonyoung Shim } 6204cf51c38SJoonyoung Shim 6219638ab7cSDaniel Kurtz static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) 6224cf51c38SJoonyoung Shim { 6239638ab7cSDaniel Kurtz return __mxt_write_reg(client, reg, 1, &val); 6244cf51c38SJoonyoung Shim } 6254cf51c38SJoonyoung Shim 6267686b108SIiro Valkonen static struct mxt_object * 6277686b108SIiro Valkonen mxt_get_object(struct mxt_data *data, u8 type) 6284cf51c38SJoonyoung Shim { 6297686b108SIiro Valkonen struct mxt_object *object; 6304cf51c38SJoonyoung Shim int i; 6314cf51c38SJoonyoung Shim 6324cf51c38SJoonyoung Shim for (i = 0; i < data->info.object_num; i++) { 6334cf51c38SJoonyoung Shim object = data->object_table + i; 6344cf51c38SJoonyoung Shim if (object->type == type) 6354cf51c38SJoonyoung Shim return object; 6364cf51c38SJoonyoung Shim } 6374cf51c38SJoonyoung Shim 63850a77c65SNick Dyer dev_warn(&data->client->dev, "Invalid object type T%u\n", type); 6394cf51c38SJoonyoung Shim return NULL; 6404cf51c38SJoonyoung Shim } 6414cf51c38SJoonyoung Shim 642497767d1SNick Dyer static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg) 643497767d1SNick Dyer { 644497767d1SNick Dyer struct device *dev = &data->client->dev; 645497767d1SNick Dyer u8 status = msg[1]; 646497767d1SNick Dyer u32 crc = msg[2] | (msg[3] << 8) | (msg[4] << 16); 647497767d1SNick Dyer 648497767d1SNick Dyer complete(&data->crc_completion); 649497767d1SNick Dyer 650497767d1SNick Dyer if (crc != data->config_crc) { 651497767d1SNick Dyer data->config_crc = crc; 652497767d1SNick Dyer dev_dbg(dev, "T6 Config Checksum: 0x%06X\n", crc); 653497767d1SNick Dyer } 654497767d1SNick Dyer 655497767d1SNick Dyer /* Detect reset */ 656497767d1SNick Dyer if (status & MXT_T6_STATUS_RESET) 657497767d1SNick Dyer complete(&data->reset_completion); 658497767d1SNick Dyer 659497767d1SNick Dyer /* Output debug if status has changed */ 660497767d1SNick Dyer if (status != data->t6_status) 661497767d1SNick Dyer dev_dbg(dev, "T6 Status 0x%02X%s%s%s%s%s%s%s\n", 662497767d1SNick Dyer status, 663497767d1SNick Dyer status == 0 ? " OK" : "", 664497767d1SNick Dyer status & MXT_T6_STATUS_RESET ? " RESET" : "", 665497767d1SNick Dyer status & MXT_T6_STATUS_OFL ? " OFL" : "", 666497767d1SNick Dyer status & MXT_T6_STATUS_SIGERR ? " SIGERR" : "", 667497767d1SNick Dyer status & MXT_T6_STATUS_CAL ? " CAL" : "", 668497767d1SNick Dyer status & MXT_T6_STATUS_CFGERR ? " CFGERR" : "", 669497767d1SNick Dyer status & MXT_T6_STATUS_COMSERR ? " COMSERR" : ""); 670497767d1SNick Dyer 671497767d1SNick Dyer /* Save current status */ 672497767d1SNick Dyer data->t6_status = status; 673497767d1SNick Dyer } 674497767d1SNick Dyer 6757f405483SLinus Torvalds static int mxt_write_object(struct mxt_data *data, 6767f405483SLinus Torvalds u8 type, u8 offset, u8 val) 6777f405483SLinus Torvalds { 6787f405483SLinus Torvalds struct mxt_object *object; 6797f405483SLinus Torvalds u16 reg; 6807f405483SLinus Torvalds 6817f405483SLinus Torvalds object = mxt_get_object(data, type); 6827f405483SLinus Torvalds if (!object || offset >= mxt_obj_size(object)) 6837f405483SLinus Torvalds return -EINVAL; 6847f405483SLinus Torvalds 6857f405483SLinus Torvalds reg = object->start_address; 6867f405483SLinus Torvalds return mxt_write_reg(data->client, reg + offset, val); 6877f405483SLinus Torvalds } 6887f405483SLinus Torvalds 6895f3f9bc2SNick Dyer static void mxt_input_button(struct mxt_data *data, u8 *message) 69022dfab7fSDaniel Kurtz { 69122dfab7fSDaniel Kurtz struct input_dev *input = data->input_dev; 692fb5e4c3eSNick Dyer const struct mxt_platform_data *pdata = data->pdata; 69322dfab7fSDaniel Kurtz int i; 69422dfab7fSDaniel Kurtz 695fb5e4c3eSNick Dyer for (i = 0; i < pdata->t19_num_keys; i++) { 696fb5e4c3eSNick Dyer if (pdata->t19_keymap[i] == KEY_RESERVED) 69722dfab7fSDaniel Kurtz continue; 698c37f6d38SDmitry Torokhov 699c37f6d38SDmitry Torokhov /* Active-low switch */ 700c37f6d38SDmitry Torokhov input_report_key(input, pdata->t19_keymap[i], 701c37f6d38SDmitry Torokhov !(message[1] & BIT(i))); 70222dfab7fSDaniel Kurtz } 70322dfab7fSDaniel Kurtz } 70422dfab7fSDaniel Kurtz 705b735fbe0SBenson Leung static void mxt_input_sync(struct mxt_data *data) 706eef820dcSNick Dyer { 707b735fbe0SBenson Leung input_mt_report_pointer_emulation(data->input_dev, 708b735fbe0SBenson Leung data->pdata->t19_num_keys); 709b735fbe0SBenson Leung input_sync(data->input_dev); 710eef820dcSNick Dyer } 711eef820dcSNick Dyer 712b9b05a89SNick Dyer static void mxt_proc_t9_message(struct mxt_data *data, u8 *message) 7134cf51c38SJoonyoung Shim { 7144cf51c38SJoonyoung Shim struct device *dev = &data->client->dev; 715fba5bc31SDaniel Kurtz struct input_dev *input_dev = data->input_dev; 7165f3f9bc2SNick Dyer int id; 7175f3f9bc2SNick Dyer u8 status; 7184cf51c38SJoonyoung Shim int x; 7194cf51c38SJoonyoung Shim int y; 7204cf51c38SJoonyoung Shim int area; 721fea9e467SNick Dyer int amplitude; 7224cf51c38SJoonyoung Shim 7235f3f9bc2SNick Dyer id = message[0] - data->T9_reportid_min; 7245f3f9bc2SNick Dyer status = message[1]; 7255f3f9bc2SNick Dyer x = (message[2] << 4) | ((message[4] >> 4) & 0xf); 7265f3f9bc2SNick Dyer y = (message[3] << 4) | ((message[4] & 0xf)); 727eef820dcSNick Dyer 728eef820dcSNick Dyer /* Handle 10/12 bit switching */ 729910d8051SJoonyoung Shim if (data->max_x < 1024) 730eef820dcSNick Dyer x >>= 2; 731910d8051SJoonyoung Shim if (data->max_y < 1024) 732eef820dcSNick Dyer y >>= 2; 733910d8051SJoonyoung Shim 7345f3f9bc2SNick Dyer area = message[5]; 7355f3f9bc2SNick Dyer amplitude = message[6]; 7364cf51c38SJoonyoung Shim 737b2e459b8SDaniel Kurtz dev_dbg(dev, 738b2e459b8SDaniel Kurtz "[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n", 739b2e459b8SDaniel Kurtz id, 740f3889ed1SNick Dyer (status & MXT_T9_DETECT) ? 'D' : '.', 741f3889ed1SNick Dyer (status & MXT_T9_PRESS) ? 'P' : '.', 742f3889ed1SNick Dyer (status & MXT_T9_RELEASE) ? 'R' : '.', 743f3889ed1SNick Dyer (status & MXT_T9_MOVE) ? 'M' : '.', 744f3889ed1SNick Dyer (status & MXT_T9_VECTOR) ? 'V' : '.', 745f3889ed1SNick Dyer (status & MXT_T9_AMP) ? 'A' : '.', 746f3889ed1SNick Dyer (status & MXT_T9_SUPPRESS) ? 'S' : '.', 747f3889ed1SNick Dyer (status & MXT_T9_UNGRIP) ? 'U' : '.', 748fea9e467SNick Dyer x, y, area, amplitude); 7494cf51c38SJoonyoung Shim 750fba5bc31SDaniel Kurtz input_mt_slot(input_dev, id); 7514cf51c38SJoonyoung Shim 752f3889ed1SNick Dyer if (status & MXT_T9_DETECT) { 753eef820dcSNick Dyer /* 754eef820dcSNick Dyer * Multiple bits may be set if the host is slow to read 755eef820dcSNick Dyer * the status messages, indicating all the events that 756eef820dcSNick Dyer * have happened. 757eef820dcSNick Dyer */ 758eef820dcSNick Dyer if (status & MXT_T9_RELEASE) { 759eef820dcSNick Dyer input_mt_report_slot_state(input_dev, 760eef820dcSNick Dyer MT_TOOL_FINGER, 0); 761b735fbe0SBenson Leung mxt_input_sync(data); 762eef820dcSNick Dyer } 763eef820dcSNick Dyer 764eef820dcSNick Dyer /* Touch active */ 765eef820dcSNick Dyer input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1); 766fba5bc31SDaniel Kurtz input_report_abs(input_dev, ABS_MT_POSITION_X, x); 767fba5bc31SDaniel Kurtz input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 768fea9e467SNick Dyer input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude); 769fba5bc31SDaniel Kurtz input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); 770eef820dcSNick Dyer } else { 771eef820dcSNick Dyer /* Touch no longer active, close out slot */ 772eef820dcSNick Dyer input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0); 773fba5bc31SDaniel Kurtz } 774b9b05a89SNick Dyer 775b9b05a89SNick Dyer data->update_input = true; 7764cf51c38SJoonyoung Shim } 7774cf51c38SJoonyoung Shim 778b23157dcSNick Dyer static void mxt_proc_t100_message(struct mxt_data *data, u8 *message) 779b23157dcSNick Dyer { 780b23157dcSNick Dyer struct device *dev = &data->client->dev; 781b23157dcSNick Dyer struct input_dev *input_dev = data->input_dev; 782b23157dcSNick Dyer int id; 783b23157dcSNick Dyer u8 status; 784b23157dcSNick Dyer u8 type = 0; 785b23157dcSNick Dyer u16 x; 786b23157dcSNick Dyer u16 y; 787b23157dcSNick Dyer int distance = 0; 788b23157dcSNick Dyer int tool = 0; 789b23157dcSNick Dyer u8 major = 0; 790b23157dcSNick Dyer u8 pressure = 0; 791b23157dcSNick Dyer u8 orientation = 0; 792b23157dcSNick Dyer 793b23157dcSNick Dyer id = message[0] - data->T100_reportid_min - 2; 794b23157dcSNick Dyer 795b23157dcSNick Dyer /* ignore SCRSTATUS events */ 796b23157dcSNick Dyer if (id < 0) 797b23157dcSNick Dyer return; 798b23157dcSNick Dyer 799b23157dcSNick Dyer status = message[1]; 800b23157dcSNick Dyer x = get_unaligned_le16(&message[2]); 801b23157dcSNick Dyer y = get_unaligned_le16(&message[4]); 802b23157dcSNick Dyer 803b23157dcSNick Dyer if (status & MXT_T100_DETECT) { 804b23157dcSNick Dyer type = (status & MXT_T100_TYPE_MASK) >> 4; 805b23157dcSNick Dyer 806b23157dcSNick Dyer switch (type) { 807b23157dcSNick Dyer case MXT_T100_TYPE_HOVERING_FINGER: 808b23157dcSNick Dyer tool = MT_TOOL_FINGER; 809b23157dcSNick Dyer distance = MXT_DISTANCE_HOVERING; 810b23157dcSNick Dyer 811b23157dcSNick Dyer if (data->t100_aux_vect) 812b23157dcSNick Dyer orientation = message[data->t100_aux_vect]; 813b23157dcSNick Dyer 814b23157dcSNick Dyer break; 815b23157dcSNick Dyer 816b23157dcSNick Dyer case MXT_T100_TYPE_FINGER: 817b23157dcSNick Dyer case MXT_T100_TYPE_GLOVE: 818b23157dcSNick Dyer tool = MT_TOOL_FINGER; 819b23157dcSNick Dyer distance = MXT_DISTANCE_ACTIVE_TOUCH; 820b23157dcSNick Dyer 821b23157dcSNick Dyer if (data->t100_aux_area) 822b23157dcSNick Dyer major = message[data->t100_aux_area]; 823b23157dcSNick Dyer 824b23157dcSNick Dyer if (data->t100_aux_ampl) 825b23157dcSNick Dyer pressure = message[data->t100_aux_ampl]; 826b23157dcSNick Dyer 827b23157dcSNick Dyer if (data->t100_aux_vect) 828b23157dcSNick Dyer orientation = message[data->t100_aux_vect]; 829b23157dcSNick Dyer 830b23157dcSNick Dyer break; 831b23157dcSNick Dyer 832b23157dcSNick Dyer case MXT_T100_TYPE_PASSIVE_STYLUS: 833b23157dcSNick Dyer tool = MT_TOOL_PEN; 834b23157dcSNick Dyer 835b23157dcSNick Dyer /* 836b23157dcSNick Dyer * Passive stylus is reported with size zero so 837b23157dcSNick Dyer * hardcode. 838b23157dcSNick Dyer */ 839b23157dcSNick Dyer major = MXT_TOUCH_MAJOR_DEFAULT; 840b23157dcSNick Dyer 841b23157dcSNick Dyer if (data->t100_aux_ampl) 842b23157dcSNick Dyer pressure = message[data->t100_aux_ampl]; 843b23157dcSNick Dyer 844b23157dcSNick Dyer break; 845b23157dcSNick Dyer 846b23157dcSNick Dyer case MXT_T100_TYPE_LARGE_TOUCH: 847b23157dcSNick Dyer /* Ignore suppressed touch */ 848b23157dcSNick Dyer break; 849b23157dcSNick Dyer 850b23157dcSNick Dyer default: 851b23157dcSNick Dyer dev_dbg(dev, "Unexpected T100 type\n"); 852b23157dcSNick Dyer return; 853b23157dcSNick Dyer } 854b23157dcSNick Dyer } 855b23157dcSNick Dyer 856b23157dcSNick Dyer /* 857b23157dcSNick Dyer * Values reported should be non-zero if tool is touching the 858b23157dcSNick Dyer * device 859b23157dcSNick Dyer */ 860b23157dcSNick Dyer if (!pressure && type != MXT_T100_TYPE_HOVERING_FINGER) 861b23157dcSNick Dyer pressure = MXT_PRESSURE_DEFAULT; 862b23157dcSNick Dyer 863b23157dcSNick Dyer input_mt_slot(input_dev, id); 864b23157dcSNick Dyer 865b23157dcSNick Dyer if (status & MXT_T100_DETECT) { 866b23157dcSNick Dyer dev_dbg(dev, "[%u] type:%u x:%u y:%u a:%02X p:%02X v:%02X\n", 867b23157dcSNick Dyer id, type, x, y, major, pressure, orientation); 868b23157dcSNick Dyer 869b23157dcSNick Dyer input_mt_report_slot_state(input_dev, tool, 1); 870b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_POSITION_X, x); 871b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 872b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major); 873b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); 874b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_DISTANCE, distance); 875b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_ORIENTATION, orientation); 876b23157dcSNick Dyer } else { 877b23157dcSNick Dyer dev_dbg(dev, "[%u] release\n", id); 878b23157dcSNick Dyer 879b23157dcSNick Dyer /* close out slot */ 880b23157dcSNick Dyer input_mt_report_slot_state(input_dev, 0, 0); 881b23157dcSNick Dyer } 882b23157dcSNick Dyer 883b23157dcSNick Dyer data->update_input = true; 884b23157dcSNick Dyer } 885b23157dcSNick Dyer 886b9b05a89SNick Dyer static int mxt_proc_message(struct mxt_data *data, u8 *message) 88704a79181SDaniel Kurtz { 888b9b05a89SNick Dyer u8 report_id = message[0]; 889b9b05a89SNick Dyer 890b9b05a89SNick Dyer if (report_id == MXT_RPTID_NOMSG) 891b9b05a89SNick Dyer return 0; 892b9b05a89SNick Dyer 893b9b05a89SNick Dyer if (report_id == data->T6_reportid) { 894b9b05a89SNick Dyer mxt_proc_t6_messages(data, message); 895b9b05a89SNick Dyer } else if (!data->input_dev) { 896b9b05a89SNick Dyer /* 897b9b05a89SNick Dyer * Do not report events if input device 898b9b05a89SNick Dyer * is not yet registered. 899b9b05a89SNick Dyer */ 900b9b05a89SNick Dyer mxt_dump_message(data, message); 901b23157dcSNick Dyer } else if (report_id >= data->T9_reportid_min && 902b23157dcSNick Dyer report_id <= data->T9_reportid_max) { 903b9b05a89SNick Dyer mxt_proc_t9_message(data, message); 904b23157dcSNick Dyer } else if (report_id >= data->T100_reportid_min && 905b23157dcSNick Dyer report_id <= data->T100_reportid_max) { 906b23157dcSNick Dyer mxt_proc_t100_message(data, message); 907b9b05a89SNick Dyer } else if (report_id == data->T19_reportid) { 908b9b05a89SNick Dyer mxt_input_button(data, message); 909b9b05a89SNick Dyer data->update_input = true; 910b9b05a89SNick Dyer } else { 911b9b05a89SNick Dyer mxt_dump_message(data, message); 912b9b05a89SNick Dyer } 913b9b05a89SNick Dyer 914b9b05a89SNick Dyer return 1; 915b9b05a89SNick Dyer } 916b9b05a89SNick Dyer 9179d8dc3e5SNick Dyer static int mxt_read_and_process_messages(struct mxt_data *data, u8 count) 918b9b05a89SNick Dyer { 919b9b05a89SNick Dyer struct device *dev = &data->client->dev; 920b9b05a89SNick Dyer int ret; 9219d8dc3e5SNick Dyer int i; 9229d8dc3e5SNick Dyer u8 num_valid = 0; 923b9b05a89SNick Dyer 9249d8dc3e5SNick Dyer /* Safety check for msg_buf */ 9259d8dc3e5SNick Dyer if (count > data->max_reportid) 9269d8dc3e5SNick Dyer return -EINVAL; 9279d8dc3e5SNick Dyer 9289d8dc3e5SNick Dyer /* Process remaining messages if necessary */ 929b9b05a89SNick Dyer ret = __mxt_read_reg(data->client, data->T5_address, 9309d8dc3e5SNick Dyer data->T5_msg_size * count, data->msg_buf); 931b9b05a89SNick Dyer if (ret) { 9329d8dc3e5SNick Dyer dev_err(dev, "Failed to read %u messages (%d)\n", count, ret); 933b9b05a89SNick Dyer return ret; 934b9b05a89SNick Dyer } 935b9b05a89SNick Dyer 9369d8dc3e5SNick Dyer for (i = 0; i < count; i++) { 9379d8dc3e5SNick Dyer ret = mxt_proc_message(data, 9389d8dc3e5SNick Dyer data->msg_buf + data->T5_msg_size * i); 9399d8dc3e5SNick Dyer 9409d8dc3e5SNick Dyer if (ret == 1) 9419d8dc3e5SNick Dyer num_valid++; 9424cf51c38SJoonyoung Shim } 9434cf51c38SJoonyoung Shim 9449d8dc3e5SNick Dyer /* return number of messages read */ 9459d8dc3e5SNick Dyer return num_valid; 9469d8dc3e5SNick Dyer } 9474cf51c38SJoonyoung Shim 9489d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages_t44(struct mxt_data *data) 9499d8dc3e5SNick Dyer { 9509d8dc3e5SNick Dyer struct device *dev = &data->client->dev; 9519d8dc3e5SNick Dyer int ret; 9529d8dc3e5SNick Dyer u8 count, num_left; 9539d8dc3e5SNick Dyer 9549d8dc3e5SNick Dyer /* Read T44 and T5 together */ 9559d8dc3e5SNick Dyer ret = __mxt_read_reg(data->client, data->T44_address, 9569d8dc3e5SNick Dyer data->T5_msg_size + 1, data->msg_buf); 9579d8dc3e5SNick Dyer if (ret) { 9589d8dc3e5SNick Dyer dev_err(dev, "Failed to read T44 and T5 (%d)\n", ret); 9598d4e1639SNick Dyer return IRQ_NONE; 9609d8dc3e5SNick Dyer } 9619d8dc3e5SNick Dyer 9629d8dc3e5SNick Dyer count = data->msg_buf[0]; 9639d8dc3e5SNick Dyer 964651b4608SNick Dyer /* 965507584e2SNick Dyer * This condition may be caused by the CHG line being configured in 966507584e2SNick Dyer * Mode 0. It results in unnecessary I2C operations but it is benign. 967651b4608SNick Dyer */ 968507584e2SNick Dyer if (count == 0) 9699d8dc3e5SNick Dyer return IRQ_NONE; 970507584e2SNick Dyer 971507584e2SNick Dyer if (count > data->max_reportid) { 972507584e2SNick Dyer dev_warn(dev, "T44 count %d exceeded max report id\n", count); 9739d8dc3e5SNick Dyer count = data->max_reportid; 9749d8dc3e5SNick Dyer } 9759d8dc3e5SNick Dyer 9769d8dc3e5SNick Dyer /* Process first message */ 9779d8dc3e5SNick Dyer ret = mxt_proc_message(data, data->msg_buf + 1); 9789d8dc3e5SNick Dyer if (ret < 0) { 9799d8dc3e5SNick Dyer dev_warn(dev, "Unexpected invalid message\n"); 9809d8dc3e5SNick Dyer return IRQ_NONE; 9819d8dc3e5SNick Dyer } 9829d8dc3e5SNick Dyer 9839d8dc3e5SNick Dyer num_left = count - 1; 9849d8dc3e5SNick Dyer 9859d8dc3e5SNick Dyer /* Process remaining messages if necessary */ 9869d8dc3e5SNick Dyer if (num_left) { 9879d8dc3e5SNick Dyer ret = mxt_read_and_process_messages(data, num_left); 9889d8dc3e5SNick Dyer if (ret < 0) 9899d8dc3e5SNick Dyer goto end; 9909d8dc3e5SNick Dyer else if (ret != num_left) 9919d8dc3e5SNick Dyer dev_warn(dev, "Unexpected invalid message\n"); 9929d8dc3e5SNick Dyer } 9939d8dc3e5SNick Dyer 9949d8dc3e5SNick Dyer end: 9959d8dc3e5SNick Dyer if (data->update_input) { 9969d8dc3e5SNick Dyer mxt_input_sync(data); 9979d8dc3e5SNick Dyer data->update_input = false; 9989d8dc3e5SNick Dyer } 9999d8dc3e5SNick Dyer 10009d8dc3e5SNick Dyer return IRQ_HANDLED; 10019d8dc3e5SNick Dyer } 10029d8dc3e5SNick Dyer 10039d8dc3e5SNick Dyer static int mxt_process_messages_until_invalid(struct mxt_data *data) 10049d8dc3e5SNick Dyer { 10059d8dc3e5SNick Dyer struct device *dev = &data->client->dev; 10069d8dc3e5SNick Dyer int count, read; 10079d8dc3e5SNick Dyer u8 tries = 2; 10089d8dc3e5SNick Dyer 10099d8dc3e5SNick Dyer count = data->max_reportid; 10109d8dc3e5SNick Dyer 10119d8dc3e5SNick Dyer /* Read messages until we force an invalid */ 10129d8dc3e5SNick Dyer do { 10139d8dc3e5SNick Dyer read = mxt_read_and_process_messages(data, count); 10149d8dc3e5SNick Dyer if (read < count) 10159d8dc3e5SNick Dyer return 0; 10169d8dc3e5SNick Dyer } while (--tries); 10179d8dc3e5SNick Dyer 10189d8dc3e5SNick Dyer if (data->update_input) { 10199d8dc3e5SNick Dyer mxt_input_sync(data); 10209d8dc3e5SNick Dyer data->update_input = false; 10219d8dc3e5SNick Dyer } 10229d8dc3e5SNick Dyer 10239d8dc3e5SNick Dyer dev_err(dev, "CHG pin isn't cleared\n"); 10249d8dc3e5SNick Dyer return -EBUSY; 10259d8dc3e5SNick Dyer } 10269d8dc3e5SNick Dyer 10279d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages(struct mxt_data *data) 10289d8dc3e5SNick Dyer { 10299d8dc3e5SNick Dyer int total_handled, num_handled; 10309d8dc3e5SNick Dyer u8 count = data->last_message_count; 10319d8dc3e5SNick Dyer 10329d8dc3e5SNick Dyer if (count < 1 || count > data->max_reportid) 10339d8dc3e5SNick Dyer count = 1; 10349d8dc3e5SNick Dyer 10359d8dc3e5SNick Dyer /* include final invalid message */ 10369d8dc3e5SNick Dyer total_handled = mxt_read_and_process_messages(data, count + 1); 10379d8dc3e5SNick Dyer if (total_handled < 0) 10389d8dc3e5SNick Dyer return IRQ_NONE; 10399d8dc3e5SNick Dyer /* if there were invalid messages, then we are done */ 10409d8dc3e5SNick Dyer else if (total_handled <= count) 10419d8dc3e5SNick Dyer goto update_count; 10429d8dc3e5SNick Dyer 10439d8dc3e5SNick Dyer /* keep reading two msgs until one is invalid or reportid limit */ 10449d8dc3e5SNick Dyer do { 10459d8dc3e5SNick Dyer num_handled = mxt_read_and_process_messages(data, 2); 10469d8dc3e5SNick Dyer if (num_handled < 0) 10479d8dc3e5SNick Dyer return IRQ_NONE; 10489d8dc3e5SNick Dyer 10499d8dc3e5SNick Dyer total_handled += num_handled; 10509d8dc3e5SNick Dyer 10519d8dc3e5SNick Dyer if (num_handled < 2) 10529d8dc3e5SNick Dyer break; 10539d8dc3e5SNick Dyer } while (total_handled < data->num_touchids); 10549d8dc3e5SNick Dyer 10559d8dc3e5SNick Dyer update_count: 10569d8dc3e5SNick Dyer data->last_message_count = total_handled; 10574cf51c38SJoonyoung Shim 1058b9b05a89SNick Dyer if (data->update_input) { 1059b735fbe0SBenson Leung mxt_input_sync(data); 1060b9b05a89SNick Dyer data->update_input = false; 1061b9b05a89SNick Dyer } 106264464ae8SDaniel Kurtz 10634cf51c38SJoonyoung Shim return IRQ_HANDLED; 10644cf51c38SJoonyoung Shim } 10654cf51c38SJoonyoung Shim 1066d79e7e47SBenson Leung static irqreturn_t mxt_interrupt(int irq, void *dev_id) 1067d79e7e47SBenson Leung { 1068d79e7e47SBenson Leung struct mxt_data *data = dev_id; 1069d79e7e47SBenson Leung 1070d79e7e47SBenson Leung if (data->in_bootloader) { 1071d79e7e47SBenson Leung /* bootloader state transition completion */ 1072d79e7e47SBenson Leung complete(&data->bl_completion); 1073d79e7e47SBenson Leung return IRQ_HANDLED; 1074d79e7e47SBenson Leung } 1075d79e7e47SBenson Leung 1076dd24dcf5SNick Dyer if (!data->object_table) 1077dd24dcf5SNick Dyer return IRQ_HANDLED; 1078dd24dcf5SNick Dyer 10799d8dc3e5SNick Dyer if (data->T44_address) { 10809d8dc3e5SNick Dyer return mxt_process_messages_t44(data); 10819d8dc3e5SNick Dyer } else { 10829d8dc3e5SNick Dyer return mxt_process_messages(data); 10839d8dc3e5SNick Dyer } 1084d79e7e47SBenson Leung } 1085d79e7e47SBenson Leung 1086a4a2ef46SIiro Valkonen static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, 1087a4a2ef46SIiro Valkonen u8 value, bool wait) 1088a4a2ef46SIiro Valkonen { 1089a4a2ef46SIiro Valkonen u16 reg; 1090a4a2ef46SIiro Valkonen u8 command_register; 1091a4a2ef46SIiro Valkonen int timeout_counter = 0; 1092a4a2ef46SIiro Valkonen int ret; 1093a4a2ef46SIiro Valkonen 1094a4a2ef46SIiro Valkonen reg = data->T6_address + cmd_offset; 1095a4a2ef46SIiro Valkonen 1096a4a2ef46SIiro Valkonen ret = mxt_write_reg(data->client, reg, value); 1097a4a2ef46SIiro Valkonen if (ret) 1098a4a2ef46SIiro Valkonen return ret; 1099a4a2ef46SIiro Valkonen 1100a4a2ef46SIiro Valkonen if (!wait) 1101a4a2ef46SIiro Valkonen return 0; 1102a4a2ef46SIiro Valkonen 1103a4a2ef46SIiro Valkonen do { 1104a4a2ef46SIiro Valkonen msleep(20); 1105a4a2ef46SIiro Valkonen ret = __mxt_read_reg(data->client, reg, 1, &command_register); 1106a4a2ef46SIiro Valkonen if (ret) 1107a4a2ef46SIiro Valkonen return ret; 1108a4a2ef46SIiro Valkonen } while (command_register != 0 && timeout_counter++ <= 100); 1109a4a2ef46SIiro Valkonen 1110a4a2ef46SIiro Valkonen if (timeout_counter > 100) { 1111a4a2ef46SIiro Valkonen dev_err(&data->client->dev, "Command failed!\n"); 1112a4a2ef46SIiro Valkonen return -EIO; 1113a4a2ef46SIiro Valkonen } 1114a4a2ef46SIiro Valkonen 1115a4a2ef46SIiro Valkonen return 0; 1116a4a2ef46SIiro Valkonen } 1117a4a2ef46SIiro Valkonen 1118eb43335cSNick Dyer static int mxt_acquire_irq(struct mxt_data *data) 1119eb43335cSNick Dyer { 1120eb43335cSNick Dyer int error; 1121eb43335cSNick Dyer 1122eb43335cSNick Dyer enable_irq(data->irq); 1123eb43335cSNick Dyer 1124eb43335cSNick Dyer error = mxt_process_messages_until_invalid(data); 1125eb43335cSNick Dyer if (error) 1126eb43335cSNick Dyer return error; 1127eb43335cSNick Dyer 1128eb43335cSNick Dyer return 0; 1129eb43335cSNick Dyer } 1130eb43335cSNick Dyer 1131a4a2ef46SIiro Valkonen static int mxt_soft_reset(struct mxt_data *data) 1132a4a2ef46SIiro Valkonen { 1133a4a2ef46SIiro Valkonen struct device *dev = &data->client->dev; 1134a4a2ef46SIiro Valkonen int ret = 0; 1135a4a2ef46SIiro Valkonen 1136885f3fb9SNick Dyer dev_info(dev, "Resetting device\n"); 1137885f3fb9SNick Dyer 1138885f3fb9SNick Dyer disable_irq(data->irq); 1139a4a2ef46SIiro Valkonen 1140a4a2ef46SIiro Valkonen reinit_completion(&data->reset_completion); 1141a4a2ef46SIiro Valkonen 1142a4a2ef46SIiro Valkonen ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false); 1143a4a2ef46SIiro Valkonen if (ret) 1144a4a2ef46SIiro Valkonen return ret; 1145a4a2ef46SIiro Valkonen 1146885f3fb9SNick Dyer /* Ignore CHG line for 100ms after reset */ 1147885f3fb9SNick Dyer msleep(100); 1148885f3fb9SNick Dyer 1149eb43335cSNick Dyer mxt_acquire_irq(data); 1150885f3fb9SNick Dyer 1151a4a2ef46SIiro Valkonen ret = mxt_wait_for_completion(data, &data->reset_completion, 1152a4a2ef46SIiro Valkonen MXT_RESET_TIMEOUT); 1153a4a2ef46SIiro Valkonen if (ret) 1154a4a2ef46SIiro Valkonen return ret; 1155a4a2ef46SIiro Valkonen 1156a4a2ef46SIiro Valkonen return 0; 1157a4a2ef46SIiro Valkonen } 1158a4a2ef46SIiro Valkonen 1159c3f78043SNick Dyer static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value) 1160c3f78043SNick Dyer { 1161c3f78043SNick Dyer /* 1162c3f78043SNick Dyer * On failure, CRC is set to 0 and config will always be 1163c3f78043SNick Dyer * downloaded. 1164c3f78043SNick Dyer */ 1165c3f78043SNick Dyer data->config_crc = 0; 1166c3f78043SNick Dyer reinit_completion(&data->crc_completion); 1167c3f78043SNick Dyer 1168c3f78043SNick Dyer mxt_t6_command(data, cmd, value, true); 1169c3f78043SNick Dyer 1170c3f78043SNick Dyer /* 1171c3f78043SNick Dyer * Wait for crc message. On failure, CRC is set to 0 and config will 1172c3f78043SNick Dyer * always be downloaded. 1173c3f78043SNick Dyer */ 1174c3f78043SNick Dyer mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); 1175c3f78043SNick Dyer } 1176c3f78043SNick Dyer 11774ce6fa01SNick Dyer static void mxt_calc_crc24(u32 *crc, u8 firstbyte, u8 secondbyte) 11784ce6fa01SNick Dyer { 11794ce6fa01SNick Dyer static const unsigned int crcpoly = 0x80001B; 11804ce6fa01SNick Dyer u32 result; 11814ce6fa01SNick Dyer u32 data_word; 11824ce6fa01SNick Dyer 11834ce6fa01SNick Dyer data_word = (secondbyte << 8) | firstbyte; 11844ce6fa01SNick Dyer result = ((*crc << 1) ^ data_word); 11854ce6fa01SNick Dyer 11864ce6fa01SNick Dyer if (result & 0x1000000) 11874ce6fa01SNick Dyer result ^= crcpoly; 11884ce6fa01SNick Dyer 11894ce6fa01SNick Dyer *crc = result; 11904ce6fa01SNick Dyer } 11914ce6fa01SNick Dyer 11924ce6fa01SNick Dyer static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off) 11934ce6fa01SNick Dyer { 11944ce6fa01SNick Dyer u32 crc = 0; 11954ce6fa01SNick Dyer u8 *ptr = base + start_off; 11964ce6fa01SNick Dyer u8 *last_val = base + end_off - 1; 11974ce6fa01SNick Dyer 11984ce6fa01SNick Dyer if (end_off < start_off) 11994ce6fa01SNick Dyer return -EINVAL; 12004ce6fa01SNick Dyer 12014ce6fa01SNick Dyer while (ptr < last_val) { 12024ce6fa01SNick Dyer mxt_calc_crc24(&crc, *ptr, *(ptr + 1)); 12034ce6fa01SNick Dyer ptr += 2; 12044ce6fa01SNick Dyer } 12054ce6fa01SNick Dyer 12064ce6fa01SNick Dyer /* if len is odd, fill the last byte with 0 */ 12074ce6fa01SNick Dyer if (ptr == last_val) 12084ce6fa01SNick Dyer mxt_calc_crc24(&crc, *ptr, 0); 12094ce6fa01SNick Dyer 12104ce6fa01SNick Dyer /* Mask to 24-bit */ 12114ce6fa01SNick Dyer crc &= 0x00FFFFFF; 12124ce6fa01SNick Dyer 12134ce6fa01SNick Dyer return crc; 12144ce6fa01SNick Dyer } 12154ce6fa01SNick Dyer 1216efdbd7aeSDmitry Torokhov static int mxt_prepare_cfg_mem(struct mxt_data *data, 1217efdbd7aeSDmitry Torokhov const struct firmware *cfg, 1218efdbd7aeSDmitry Torokhov unsigned int data_pos, 1219efdbd7aeSDmitry Torokhov unsigned int cfg_start_ofs, 1220efdbd7aeSDmitry Torokhov u8 *config_mem, 1221efdbd7aeSDmitry Torokhov size_t config_mem_size) 12224cf51c38SJoonyoung Shim { 12234cf51c38SJoonyoung Shim struct device *dev = &data->client->dev; 122450a77c65SNick Dyer struct mxt_object *object; 1225efdbd7aeSDmitry Torokhov unsigned int type, instance, size, byte_offset; 122650a77c65SNick Dyer int offset; 1227efdbd7aeSDmitry Torokhov int ret; 122850a77c65SNick Dyer int i; 122950a77c65SNick Dyer u16 reg; 1230efdbd7aeSDmitry Torokhov u8 val; 123150a77c65SNick Dyer 12324ce6fa01SNick Dyer while (data_pos < cfg->size) { 123350a77c65SNick Dyer /* Read type, instance, length */ 12344ce6fa01SNick Dyer ret = sscanf(cfg->data + data_pos, "%x %x %x%n", 123550a77c65SNick Dyer &type, &instance, &size, &offset); 123650a77c65SNick Dyer if (ret == 0) { 123750a77c65SNick Dyer /* EOF */ 12384ce6fa01SNick Dyer break; 123950a77c65SNick Dyer } else if (ret != 3) { 124050a77c65SNick Dyer dev_err(dev, "Bad format: failed to parse object\n"); 1241efdbd7aeSDmitry Torokhov return -EINVAL; 124250a77c65SNick Dyer } 12434ce6fa01SNick Dyer data_pos += offset; 124450a77c65SNick Dyer 124550a77c65SNick Dyer object = mxt_get_object(data, type); 124650a77c65SNick Dyer if (!object) { 124750a77c65SNick Dyer /* Skip object */ 124850a77c65SNick Dyer for (i = 0; i < size; i++) { 12494ce6fa01SNick Dyer ret = sscanf(cfg->data + data_pos, "%hhx%n", 1250041fa159SDmitry Torokhov &val, &offset); 1251041fa159SDmitry Torokhov if (ret != 1) { 1252041fa159SDmitry Torokhov dev_err(dev, "Bad format in T%d at %d\n", 1253041fa159SDmitry Torokhov type, i); 1254041fa159SDmitry Torokhov return -EINVAL; 1255041fa159SDmitry Torokhov } 12564ce6fa01SNick Dyer data_pos += offset; 125750a77c65SNick Dyer } 125850a77c65SNick Dyer continue; 125950a77c65SNick Dyer } 126050a77c65SNick Dyer 126150a77c65SNick Dyer if (size > mxt_obj_size(object)) { 12624ce6fa01SNick Dyer /* 12634ce6fa01SNick Dyer * Either we are in fallback mode due to wrong 12644ce6fa01SNick Dyer * config or config from a later fw version, 12654ce6fa01SNick Dyer * or the file is corrupt or hand-edited. 12664ce6fa01SNick Dyer */ 12674ce6fa01SNick Dyer dev_warn(dev, "Discarding %zu byte(s) in T%u\n", 126850a77c65SNick Dyer size - mxt_obj_size(object), type); 12694ce6fa01SNick Dyer } else if (mxt_obj_size(object) > size) { 12704ce6fa01SNick Dyer /* 12714ce6fa01SNick Dyer * If firmware is upgraded, new bytes may be added to 12724ce6fa01SNick Dyer * end of objects. It is generally forward compatible 12734ce6fa01SNick Dyer * to zero these bytes - previous behaviour will be 12744ce6fa01SNick Dyer * retained. However this does invalidate the CRC and 12754ce6fa01SNick Dyer * will force fallback mode until the configuration is 12764ce6fa01SNick Dyer * updated. We warn here but do nothing else - the 12774ce6fa01SNick Dyer * malloc has zeroed the entire configuration. 12784ce6fa01SNick Dyer */ 12794ce6fa01SNick Dyer dev_warn(dev, "Zeroing %zu byte(s) in T%d\n", 12804ce6fa01SNick Dyer mxt_obj_size(object) - size, type); 128150a77c65SNick Dyer } 128250a77c65SNick Dyer 128350a77c65SNick Dyer if (instance >= mxt_obj_instances(object)) { 128450a77c65SNick Dyer dev_err(dev, "Object instances exceeded!\n"); 1285efdbd7aeSDmitry Torokhov return -EINVAL; 128650a77c65SNick Dyer } 128750a77c65SNick Dyer 128850a77c65SNick Dyer reg = object->start_address + mxt_obj_size(object) * instance; 128950a77c65SNick Dyer 129050a77c65SNick Dyer for (i = 0; i < size; i++) { 12914ce6fa01SNick Dyer ret = sscanf(cfg->data + data_pos, "%hhx%n", 129250a77c65SNick Dyer &val, 129350a77c65SNick Dyer &offset); 129450a77c65SNick Dyer if (ret != 1) { 1295041fa159SDmitry Torokhov dev_err(dev, "Bad format in T%d at %d\n", 1296041fa159SDmitry Torokhov type, i); 1297efdbd7aeSDmitry Torokhov return -EINVAL; 129850a77c65SNick Dyer } 12994ce6fa01SNick Dyer data_pos += offset; 130050a77c65SNick Dyer 130150a77c65SNick Dyer if (i > mxt_obj_size(object)) 13024cf51c38SJoonyoung Shim continue; 13034cf51c38SJoonyoung Shim 13044ce6fa01SNick Dyer byte_offset = reg + i - cfg_start_ofs; 130550a77c65SNick Dyer 1306041fa159SDmitry Torokhov if (byte_offset >= 0 && byte_offset < config_mem_size) { 13074ce6fa01SNick Dyer *(config_mem + byte_offset) = val; 13084ce6fa01SNick Dyer } else { 13094ce6fa01SNick Dyer dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n", 13104ce6fa01SNick Dyer reg, object->type, byte_offset); 1311efdbd7aeSDmitry Torokhov return -EINVAL; 1312efdbd7aeSDmitry Torokhov } 1313efdbd7aeSDmitry Torokhov } 1314efdbd7aeSDmitry Torokhov } 1315efdbd7aeSDmitry Torokhov 1316efdbd7aeSDmitry Torokhov return 0; 1317efdbd7aeSDmitry Torokhov } 1318efdbd7aeSDmitry Torokhov 1319efdbd7aeSDmitry Torokhov static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, 1320efdbd7aeSDmitry Torokhov u8 *config_mem, size_t config_mem_size) 1321efdbd7aeSDmitry Torokhov { 1322efdbd7aeSDmitry Torokhov unsigned int byte_offset = 0; 1323efdbd7aeSDmitry Torokhov int error; 1324efdbd7aeSDmitry Torokhov 1325efdbd7aeSDmitry Torokhov /* Write configuration as blocks */ 1326efdbd7aeSDmitry Torokhov while (byte_offset < config_mem_size) { 1327efdbd7aeSDmitry Torokhov unsigned int size = config_mem_size - byte_offset; 1328efdbd7aeSDmitry Torokhov 1329efdbd7aeSDmitry Torokhov if (size > MXT_MAX_BLOCK_WRITE) 1330efdbd7aeSDmitry Torokhov size = MXT_MAX_BLOCK_WRITE; 1331efdbd7aeSDmitry Torokhov 1332efdbd7aeSDmitry Torokhov error = __mxt_write_reg(data->client, 1333efdbd7aeSDmitry Torokhov cfg_start + byte_offset, 1334efdbd7aeSDmitry Torokhov size, config_mem + byte_offset); 1335efdbd7aeSDmitry Torokhov if (error) { 1336efdbd7aeSDmitry Torokhov dev_err(&data->client->dev, 1337efdbd7aeSDmitry Torokhov "Config write error, ret=%d\n", error); 1338efdbd7aeSDmitry Torokhov return error; 1339efdbd7aeSDmitry Torokhov } 1340efdbd7aeSDmitry Torokhov 1341efdbd7aeSDmitry Torokhov byte_offset += size; 1342efdbd7aeSDmitry Torokhov } 1343efdbd7aeSDmitry Torokhov 1344efdbd7aeSDmitry Torokhov return 0; 1345efdbd7aeSDmitry Torokhov } 1346efdbd7aeSDmitry Torokhov 13477f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data); 13487f3884f7SNick Dyer 1349efdbd7aeSDmitry Torokhov /* 1350efdbd7aeSDmitry Torokhov * mxt_update_cfg - download configuration to chip 1351efdbd7aeSDmitry Torokhov * 1352efdbd7aeSDmitry Torokhov * Atmel Raw Config File Format 1353efdbd7aeSDmitry Torokhov * 1354efdbd7aeSDmitry Torokhov * The first four lines of the raw config file contain: 1355efdbd7aeSDmitry Torokhov * 1) Version 1356efdbd7aeSDmitry Torokhov * 2) Chip ID Information (first 7 bytes of device memory) 1357efdbd7aeSDmitry Torokhov * 3) Chip Information Block 24-bit CRC Checksum 1358efdbd7aeSDmitry Torokhov * 4) Chip Configuration 24-bit CRC Checksum 1359efdbd7aeSDmitry Torokhov * 1360efdbd7aeSDmitry Torokhov * The rest of the file consists of one line per object instance: 1361efdbd7aeSDmitry Torokhov * <TYPE> <INSTANCE> <SIZE> <CONTENTS> 1362efdbd7aeSDmitry Torokhov * 1363efdbd7aeSDmitry Torokhov * <TYPE> - 2-byte object type as hex 1364efdbd7aeSDmitry Torokhov * <INSTANCE> - 2-byte object instance number as hex 1365efdbd7aeSDmitry Torokhov * <SIZE> - 2-byte object size as hex 1366efdbd7aeSDmitry Torokhov * <CONTENTS> - array of <SIZE> 1-byte hex values 1367efdbd7aeSDmitry Torokhov */ 1368efdbd7aeSDmitry Torokhov static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) 1369efdbd7aeSDmitry Torokhov { 1370efdbd7aeSDmitry Torokhov struct device *dev = &data->client->dev; 1371efdbd7aeSDmitry Torokhov struct mxt_info cfg_info; 1372efdbd7aeSDmitry Torokhov int ret; 1373efdbd7aeSDmitry Torokhov int offset; 1374efdbd7aeSDmitry Torokhov int data_pos; 1375efdbd7aeSDmitry Torokhov int i; 1376efdbd7aeSDmitry Torokhov int cfg_start_ofs; 1377efdbd7aeSDmitry Torokhov u32 info_crc, config_crc, calculated_crc; 1378efdbd7aeSDmitry Torokhov u8 *config_mem; 1379efdbd7aeSDmitry Torokhov size_t config_mem_size; 1380efdbd7aeSDmitry Torokhov 1381efdbd7aeSDmitry Torokhov mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); 1382efdbd7aeSDmitry Torokhov 1383efdbd7aeSDmitry Torokhov if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { 1384efdbd7aeSDmitry Torokhov dev_err(dev, "Unrecognised config file\n"); 1385efdbd7aeSDmitry Torokhov return -EINVAL; 1386efdbd7aeSDmitry Torokhov } 1387efdbd7aeSDmitry Torokhov 1388efdbd7aeSDmitry Torokhov data_pos = strlen(MXT_CFG_MAGIC); 1389efdbd7aeSDmitry Torokhov 1390efdbd7aeSDmitry Torokhov /* Load information block and check */ 1391efdbd7aeSDmitry Torokhov for (i = 0; i < sizeof(struct mxt_info); i++) { 1392efdbd7aeSDmitry Torokhov ret = sscanf(cfg->data + data_pos, "%hhx%n", 1393efdbd7aeSDmitry Torokhov (unsigned char *)&cfg_info + i, 1394efdbd7aeSDmitry Torokhov &offset); 1395efdbd7aeSDmitry Torokhov if (ret != 1) { 1396efdbd7aeSDmitry Torokhov dev_err(dev, "Bad format\n"); 1397efdbd7aeSDmitry Torokhov return -EINVAL; 1398efdbd7aeSDmitry Torokhov } 1399efdbd7aeSDmitry Torokhov 1400efdbd7aeSDmitry Torokhov data_pos += offset; 1401efdbd7aeSDmitry Torokhov } 1402efdbd7aeSDmitry Torokhov 1403efdbd7aeSDmitry Torokhov if (cfg_info.family_id != data->info.family_id) { 1404efdbd7aeSDmitry Torokhov dev_err(dev, "Family ID mismatch!\n"); 1405efdbd7aeSDmitry Torokhov return -EINVAL; 1406efdbd7aeSDmitry Torokhov } 1407efdbd7aeSDmitry Torokhov 1408efdbd7aeSDmitry Torokhov if (cfg_info.variant_id != data->info.variant_id) { 1409efdbd7aeSDmitry Torokhov dev_err(dev, "Variant ID mismatch!\n"); 1410efdbd7aeSDmitry Torokhov return -EINVAL; 1411efdbd7aeSDmitry Torokhov } 1412efdbd7aeSDmitry Torokhov 1413efdbd7aeSDmitry Torokhov /* Read CRCs */ 1414efdbd7aeSDmitry Torokhov ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset); 1415efdbd7aeSDmitry Torokhov if (ret != 1) { 1416efdbd7aeSDmitry Torokhov dev_err(dev, "Bad format: failed to parse Info CRC\n"); 1417efdbd7aeSDmitry Torokhov return -EINVAL; 1418efdbd7aeSDmitry Torokhov } 1419efdbd7aeSDmitry Torokhov data_pos += offset; 1420efdbd7aeSDmitry Torokhov 1421efdbd7aeSDmitry Torokhov ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset); 1422efdbd7aeSDmitry Torokhov if (ret != 1) { 1423efdbd7aeSDmitry Torokhov dev_err(dev, "Bad format: failed to parse Config CRC\n"); 1424efdbd7aeSDmitry Torokhov return -EINVAL; 1425efdbd7aeSDmitry Torokhov } 1426efdbd7aeSDmitry Torokhov data_pos += offset; 1427efdbd7aeSDmitry Torokhov 1428efdbd7aeSDmitry Torokhov /* 1429efdbd7aeSDmitry Torokhov * The Info Block CRC is calculated over mxt_info and the object 1430efdbd7aeSDmitry Torokhov * table. If it does not match then we are trying to load the 1431efdbd7aeSDmitry Torokhov * configuration from a different chip or firmware version, so 1432efdbd7aeSDmitry Torokhov * the configuration CRC is invalid anyway. 1433efdbd7aeSDmitry Torokhov */ 1434efdbd7aeSDmitry Torokhov if (info_crc == data->info_crc) { 1435efdbd7aeSDmitry Torokhov if (config_crc == 0 || data->config_crc == 0) { 1436efdbd7aeSDmitry Torokhov dev_info(dev, "CRC zero, attempting to apply config\n"); 1437efdbd7aeSDmitry Torokhov } else if (config_crc == data->config_crc) { 1438efdbd7aeSDmitry Torokhov dev_dbg(dev, "Config CRC 0x%06X: OK\n", 1439efdbd7aeSDmitry Torokhov data->config_crc); 1440efdbd7aeSDmitry Torokhov return 0; 1441efdbd7aeSDmitry Torokhov } else { 1442efdbd7aeSDmitry Torokhov dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", 1443efdbd7aeSDmitry Torokhov data->config_crc, config_crc); 1444efdbd7aeSDmitry Torokhov } 1445efdbd7aeSDmitry Torokhov } else { 1446efdbd7aeSDmitry Torokhov dev_warn(dev, 1447efdbd7aeSDmitry Torokhov "Warning: Info CRC error - device=0x%06X file=0x%06X\n", 1448efdbd7aeSDmitry Torokhov data->info_crc, info_crc); 1449efdbd7aeSDmitry Torokhov } 1450efdbd7aeSDmitry Torokhov 1451efdbd7aeSDmitry Torokhov /* Malloc memory to store configuration */ 1452efdbd7aeSDmitry Torokhov cfg_start_ofs = MXT_OBJECT_START + 1453efdbd7aeSDmitry Torokhov data->info.object_num * sizeof(struct mxt_object) + 1454efdbd7aeSDmitry Torokhov MXT_INFO_CHECKSUM_SIZE; 1455efdbd7aeSDmitry Torokhov config_mem_size = data->mem_size - cfg_start_ofs; 1456efdbd7aeSDmitry Torokhov config_mem = kzalloc(config_mem_size, GFP_KERNEL); 1457efdbd7aeSDmitry Torokhov if (!config_mem) { 1458efdbd7aeSDmitry Torokhov dev_err(dev, "Failed to allocate memory\n"); 1459efdbd7aeSDmitry Torokhov return -ENOMEM; 1460efdbd7aeSDmitry Torokhov } 1461efdbd7aeSDmitry Torokhov 1462efdbd7aeSDmitry Torokhov ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs, 1463efdbd7aeSDmitry Torokhov config_mem, config_mem_size); 1464efdbd7aeSDmitry Torokhov if (ret) 14654ce6fa01SNick Dyer goto release_mem; 14664cf51c38SJoonyoung Shim 14674ce6fa01SNick Dyer /* Calculate crc of the received configs (not the raw config file) */ 14684ce6fa01SNick Dyer if (data->T7_address < cfg_start_ofs) { 14694ce6fa01SNick Dyer dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n", 14704ce6fa01SNick Dyer data->T7_address, cfg_start_ofs); 14714ce6fa01SNick Dyer ret = 0; 14724ce6fa01SNick Dyer goto release_mem; 14734ce6fa01SNick Dyer } 14744ce6fa01SNick Dyer 14754ce6fa01SNick Dyer calculated_crc = mxt_calculate_crc(config_mem, 14764ce6fa01SNick Dyer data->T7_address - cfg_start_ofs, 14774ce6fa01SNick Dyer config_mem_size); 14784ce6fa01SNick Dyer 1479efdbd7aeSDmitry Torokhov if (config_crc > 0 && config_crc != calculated_crc) 14804ce6fa01SNick Dyer dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n", 14814ce6fa01SNick Dyer calculated_crc, config_crc); 14824ce6fa01SNick Dyer 1483efdbd7aeSDmitry Torokhov ret = mxt_upload_cfg_mem(data, cfg_start_ofs, 1484efdbd7aeSDmitry Torokhov config_mem, config_mem_size); 1485efdbd7aeSDmitry Torokhov if (ret) 14864ce6fa01SNick Dyer goto release_mem; 14874ce6fa01SNick Dyer 1488c3f78043SNick Dyer mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); 1489c3f78043SNick Dyer 1490c3f78043SNick Dyer ret = mxt_soft_reset(data); 1491c3f78043SNick Dyer if (ret) 14924ce6fa01SNick Dyer goto release_mem; 1493c3f78043SNick Dyer 1494c3f78043SNick Dyer dev_info(dev, "Config successfully updated\n"); 1495c3f78043SNick Dyer 14967f3884f7SNick Dyer /* T7 config may have changed */ 14977f3884f7SNick Dyer mxt_init_t7_power_cfg(data); 14987f3884f7SNick Dyer 14994ce6fa01SNick Dyer release_mem: 15004ce6fa01SNick Dyer kfree(config_mem); 150150a77c65SNick Dyer return ret; 15024cf51c38SJoonyoung Shim } 15034cf51c38SJoonyoung Shim 15047686b108SIiro Valkonen static int mxt_get_info(struct mxt_data *data) 15054cf51c38SJoonyoung Shim { 15064cf51c38SJoonyoung Shim struct i2c_client *client = data->client; 15077686b108SIiro Valkonen struct mxt_info *info = &data->info; 15084cf51c38SJoonyoung Shim int error; 15094cf51c38SJoonyoung Shim 151023003a84SDaniel Kurtz /* Read 7-byte info block starting at address 0 */ 1511146c6a66SNick Dyer error = __mxt_read_reg(client, 0, sizeof(*info), info); 15124cf51c38SJoonyoung Shim if (error) 15134cf51c38SJoonyoung Shim return error; 15144cf51c38SJoonyoung Shim 15154cf51c38SJoonyoung Shim return 0; 15164cf51c38SJoonyoung Shim } 15174cf51c38SJoonyoung Shim 151858e4aeeeSStephen Warren static void mxt_free_input_device(struct mxt_data *data) 15195f3f9bc2SNick Dyer { 152058e4aeeeSStephen Warren if (data->input_dev) { 15215f3f9bc2SNick Dyer input_unregister_device(data->input_dev); 15225f3f9bc2SNick Dyer data->input_dev = NULL; 152358e4aeeeSStephen Warren } 152458e4aeeeSStephen Warren } 15255f3f9bc2SNick Dyer 152658e4aeeeSStephen Warren static void mxt_free_object_table(struct mxt_data *data) 152758e4aeeeSStephen Warren { 15285f3f9bc2SNick Dyer kfree(data->object_table); 15295f3f9bc2SNick Dyer data->object_table = NULL; 15305f3f9bc2SNick Dyer kfree(data->msg_buf); 15315f3f9bc2SNick Dyer data->msg_buf = NULL; 1532b9b05a89SNick Dyer data->T5_address = 0; 15335f3f9bc2SNick Dyer data->T5_msg_size = 0; 15345f3f9bc2SNick Dyer data->T6_reportid = 0; 15355f3f9bc2SNick Dyer data->T7_address = 0; 15365f3f9bc2SNick Dyer data->T9_reportid_min = 0; 15375f3f9bc2SNick Dyer data->T9_reportid_max = 0; 15385f3f9bc2SNick Dyer data->T19_reportid = 0; 15399d8dc3e5SNick Dyer data->T44_address = 0; 1540b23157dcSNick Dyer data->T100_reportid_min = 0; 1541b23157dcSNick Dyer data->T100_reportid_max = 0; 15429d8dc3e5SNick Dyer data->max_reportid = 0; 15435f3f9bc2SNick Dyer } 15445f3f9bc2SNick Dyer 15457686b108SIiro Valkonen static int mxt_get_object_table(struct mxt_data *data) 15464cf51c38SJoonyoung Shim { 1547333e5a9aSDaniel Kurtz struct i2c_client *client = data->client; 1548333e5a9aSDaniel Kurtz size_t table_size; 1549dd24dcf5SNick Dyer struct mxt_object *object_table; 15504cf51c38SJoonyoung Shim int error; 15514cf51c38SJoonyoung Shim int i; 1552333e5a9aSDaniel Kurtz u8 reportid; 15534ce6fa01SNick Dyer u16 end_address; 15544cf51c38SJoonyoung Shim 1555333e5a9aSDaniel Kurtz table_size = data->info.object_num * sizeof(struct mxt_object); 1556dd24dcf5SNick Dyer object_table = kzalloc(table_size, GFP_KERNEL); 1557dd24dcf5SNick Dyer if (!object_table) { 1558dd24dcf5SNick Dyer dev_err(&data->client->dev, "Failed to allocate memory\n"); 1559dd24dcf5SNick Dyer return -ENOMEM; 1560dd24dcf5SNick Dyer } 1561dd24dcf5SNick Dyer 1562333e5a9aSDaniel Kurtz error = __mxt_read_reg(client, MXT_OBJECT_START, table_size, 1563dd24dcf5SNick Dyer object_table); 1564dd24dcf5SNick Dyer if (error) { 1565dd24dcf5SNick Dyer kfree(object_table); 15664cf51c38SJoonyoung Shim return error; 1567dd24dcf5SNick Dyer } 15684cf51c38SJoonyoung Shim 1569333e5a9aSDaniel Kurtz /* Valid Report IDs start counting from 1 */ 1570333e5a9aSDaniel Kurtz reportid = 1; 15714ce6fa01SNick Dyer data->mem_size = 0; 1572333e5a9aSDaniel Kurtz for (i = 0; i < data->info.object_num; i++) { 1573dd24dcf5SNick Dyer struct mxt_object *object = object_table + i; 1574333e5a9aSDaniel Kurtz u8 min_id, max_id; 1575333e5a9aSDaniel Kurtz 1576333e5a9aSDaniel Kurtz le16_to_cpus(&object->start_address); 15774cf51c38SJoonyoung Shim 15784cf51c38SJoonyoung Shim if (object->num_report_ids) { 1579333e5a9aSDaniel Kurtz min_id = reportid; 15804cf51c38SJoonyoung Shim reportid += object->num_report_ids * 15811e0c0c5bSDaniel Kurtz mxt_obj_instances(object); 1582333e5a9aSDaniel Kurtz max_id = reportid - 1; 1583333e5a9aSDaniel Kurtz } else { 1584333e5a9aSDaniel Kurtz min_id = 0; 1585333e5a9aSDaniel Kurtz max_id = 0; 1586333e5a9aSDaniel Kurtz } 1587333e5a9aSDaniel Kurtz 1588333e5a9aSDaniel Kurtz dev_dbg(&data->client->dev, 15897bed6805SNick Dyer "T%u Start:%u Size:%zu Instances:%zu Report IDs:%u-%u\n", 15901e0c0c5bSDaniel Kurtz object->type, object->start_address, 15911e0c0c5bSDaniel Kurtz mxt_obj_size(object), mxt_obj_instances(object), 15921e0c0c5bSDaniel Kurtz min_id, max_id); 1593333e5a9aSDaniel Kurtz 1594333e5a9aSDaniel Kurtz switch (object->type) { 15955f3f9bc2SNick Dyer case MXT_GEN_MESSAGE_T5: 1596437d4f37SNick Dyer if (data->info.family_id == 0x80 && 1597437d4f37SNick Dyer data->info.version < 0x20) { 15989d8dc3e5SNick Dyer /* 1599437d4f37SNick Dyer * On mXT224 firmware versions prior to V2.0 1600437d4f37SNick Dyer * read and discard unused CRC byte otherwise 1601437d4f37SNick Dyer * DMA reads are misaligned. 16029d8dc3e5SNick Dyer */ 16039d8dc3e5SNick Dyer data->T5_msg_size = mxt_obj_size(object); 16049d8dc3e5SNick Dyer } else { 16059d8dc3e5SNick Dyer /* CRC not enabled, so skip last byte */ 16065f3f9bc2SNick Dyer data->T5_msg_size = mxt_obj_size(object) - 1; 16079d8dc3e5SNick Dyer } 1608b9b05a89SNick Dyer data->T5_address = object->start_address; 1609041fa159SDmitry Torokhov break; 1610fdf80421SDaniel Kurtz case MXT_GEN_COMMAND_T6: 1611fdf80421SDaniel Kurtz data->T6_reportid = min_id; 1612a4a2ef46SIiro Valkonen data->T6_address = object->start_address; 1613fdf80421SDaniel Kurtz break; 16144ce6fa01SNick Dyer case MXT_GEN_POWER_T7: 16154ce6fa01SNick Dyer data->T7_address = object->start_address; 16164ce6fa01SNick Dyer break; 1617333e5a9aSDaniel Kurtz case MXT_TOUCH_MULTI_T9: 1618b23157dcSNick Dyer data->multitouch = MXT_TOUCH_MULTI_T9; 1619333e5a9aSDaniel Kurtz data->T9_reportid_min = min_id; 1620333e5a9aSDaniel Kurtz data->T9_reportid_max = max_id; 16219d8dc3e5SNick Dyer data->num_touchids = object->num_report_ids 16229d8dc3e5SNick Dyer * mxt_obj_instances(object); 16239d8dc3e5SNick Dyer break; 16249d8dc3e5SNick Dyer case MXT_SPT_MESSAGECOUNT_T44: 16259d8dc3e5SNick Dyer data->T44_address = object->start_address; 1626333e5a9aSDaniel Kurtz break; 162722dfab7fSDaniel Kurtz case MXT_SPT_GPIOPWM_T19: 162822dfab7fSDaniel Kurtz data->T19_reportid = min_id; 162922dfab7fSDaniel Kurtz break; 1630b23157dcSNick Dyer case MXT_TOUCH_MULTITOUCHSCREEN_T100: 1631b23157dcSNick Dyer data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100; 1632b23157dcSNick Dyer data->T100_reportid_min = min_id; 1633b23157dcSNick Dyer data->T100_reportid_max = max_id; 1634b23157dcSNick Dyer /* first two report IDs reserved */ 1635b23157dcSNick Dyer data->num_touchids = object->num_report_ids - 2; 1636b23157dcSNick Dyer break; 16374cf51c38SJoonyoung Shim } 16384ce6fa01SNick Dyer 16394ce6fa01SNick Dyer end_address = object->start_address 16404ce6fa01SNick Dyer + mxt_obj_size(object) * mxt_obj_instances(object) - 1; 16414ce6fa01SNick Dyer 16424ce6fa01SNick Dyer if (end_address >= data->mem_size) 16434ce6fa01SNick Dyer data->mem_size = end_address + 1; 16444cf51c38SJoonyoung Shim } 16454cf51c38SJoonyoung Shim 16469d8dc3e5SNick Dyer /* Store maximum reportid */ 16479d8dc3e5SNick Dyer data->max_reportid = reportid; 16489d8dc3e5SNick Dyer 16499d8dc3e5SNick Dyer /* If T44 exists, T5 position has to be directly after */ 16509d8dc3e5SNick Dyer if (data->T44_address && (data->T5_address != data->T44_address + 1)) { 16519d8dc3e5SNick Dyer dev_err(&client->dev, "Invalid T44 position\n"); 16529d8dc3e5SNick Dyer error = -EINVAL; 16539d8dc3e5SNick Dyer goto free_object_table; 16549d8dc3e5SNick Dyer } 16559d8dc3e5SNick Dyer 16569d8dc3e5SNick Dyer data->msg_buf = kcalloc(data->max_reportid, 16579d8dc3e5SNick Dyer data->T5_msg_size, GFP_KERNEL); 16585f3f9bc2SNick Dyer if (!data->msg_buf) { 16595f3f9bc2SNick Dyer dev_err(&client->dev, "Failed to allocate message buffer\n"); 16605f3f9bc2SNick Dyer error = -ENOMEM; 16615f3f9bc2SNick Dyer goto free_object_table; 16625f3f9bc2SNick Dyer } 16635f3f9bc2SNick Dyer 1664dd24dcf5SNick Dyer data->object_table = object_table; 1665dd24dcf5SNick Dyer 16664cf51c38SJoonyoung Shim return 0; 16674cf51c38SJoonyoung Shim 16685f3f9bc2SNick Dyer free_object_table: 16695f3f9bc2SNick Dyer mxt_free_object_table(data); 16705f3f9bc2SNick Dyer return error; 16717d4fa100SDaniel Kurtz } 16727d4fa100SDaniel Kurtz 167361dc1abaSNick Dyer static int mxt_read_t9_resolution(struct mxt_data *data) 167461dc1abaSNick Dyer { 167561dc1abaSNick Dyer struct i2c_client *client = data->client; 167661dc1abaSNick Dyer int error; 167761dc1abaSNick Dyer struct t9_range range; 167861dc1abaSNick Dyer unsigned char orient; 167961dc1abaSNick Dyer struct mxt_object *object; 168061dc1abaSNick Dyer 168161dc1abaSNick Dyer object = mxt_get_object(data, MXT_TOUCH_MULTI_T9); 168261dc1abaSNick Dyer if (!object) 168361dc1abaSNick Dyer return -EINVAL; 168461dc1abaSNick Dyer 168561dc1abaSNick Dyer error = __mxt_read_reg(client, 168661dc1abaSNick Dyer object->start_address + MXT_T9_RANGE, 168761dc1abaSNick Dyer sizeof(range), &range); 168861dc1abaSNick Dyer if (error) 168961dc1abaSNick Dyer return error; 169061dc1abaSNick Dyer 16911c0276d5SNick Dyer data->max_x = get_unaligned_le16(&range.x); 16921c0276d5SNick Dyer data->max_y = get_unaligned_le16(&range.y); 169361dc1abaSNick Dyer 169461dc1abaSNick Dyer error = __mxt_read_reg(client, 169561dc1abaSNick Dyer object->start_address + MXT_T9_ORIENT, 169661dc1abaSNick Dyer 1, &orient); 169761dc1abaSNick Dyer if (error) 169861dc1abaSNick Dyer return error; 169961dc1abaSNick Dyer 17001c0276d5SNick Dyer data->xy_switch = orient & MXT_T9_ORIENT_SWITCH; 170161dc1abaSNick Dyer 170261dc1abaSNick Dyer return 0; 170361dc1abaSNick Dyer } 170461dc1abaSNick Dyer 1705b23157dcSNick Dyer static int mxt_read_t100_config(struct mxt_data *data) 1706b23157dcSNick Dyer { 1707b23157dcSNick Dyer struct i2c_client *client = data->client; 1708b23157dcSNick Dyer int error; 1709b23157dcSNick Dyer struct mxt_object *object; 1710b23157dcSNick Dyer u16 range_x, range_y; 1711b23157dcSNick Dyer u8 cfg, tchaux; 1712b23157dcSNick Dyer u8 aux; 1713b23157dcSNick Dyer 1714b23157dcSNick Dyer object = mxt_get_object(data, MXT_TOUCH_MULTITOUCHSCREEN_T100); 1715b23157dcSNick Dyer if (!object) 1716b23157dcSNick Dyer return -EINVAL; 1717b23157dcSNick Dyer 17181c0276d5SNick Dyer /* read touchscreen dimensions */ 1719b23157dcSNick Dyer error = __mxt_read_reg(client, 1720b23157dcSNick Dyer object->start_address + MXT_T100_XRANGE, 1721b23157dcSNick Dyer sizeof(range_x), &range_x); 1722b23157dcSNick Dyer if (error) 1723b23157dcSNick Dyer return error; 1724b23157dcSNick Dyer 17251c0276d5SNick Dyer data->max_x = get_unaligned_le16(&range_x); 1726b23157dcSNick Dyer 1727b23157dcSNick Dyer error = __mxt_read_reg(client, 1728b23157dcSNick Dyer object->start_address + MXT_T100_YRANGE, 1729b23157dcSNick Dyer sizeof(range_y), &range_y); 1730b23157dcSNick Dyer if (error) 1731b23157dcSNick Dyer return error; 1732b23157dcSNick Dyer 17331c0276d5SNick Dyer data->max_y = get_unaligned_le16(&range_y); 1734b23157dcSNick Dyer 17351c0276d5SNick Dyer /* read orientation config */ 1736b23157dcSNick Dyer error = __mxt_read_reg(client, 1737b23157dcSNick Dyer object->start_address + MXT_T100_CFG1, 1738b23157dcSNick Dyer 1, &cfg); 1739b23157dcSNick Dyer if (error) 1740b23157dcSNick Dyer return error; 1741b23157dcSNick Dyer 17421c0276d5SNick Dyer data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY; 17431c0276d5SNick Dyer 17441c0276d5SNick Dyer /* allocate aux bytes */ 1745b23157dcSNick Dyer error = __mxt_read_reg(client, 1746b23157dcSNick Dyer object->start_address + MXT_T100_TCHAUX, 1747b23157dcSNick Dyer 1, &tchaux); 1748b23157dcSNick Dyer if (error) 1749b23157dcSNick Dyer return error; 1750b23157dcSNick Dyer 1751b23157dcSNick Dyer aux = 6; 1752b23157dcSNick Dyer 1753b23157dcSNick Dyer if (tchaux & MXT_T100_TCHAUX_VECT) 1754b23157dcSNick Dyer data->t100_aux_vect = aux++; 1755b23157dcSNick Dyer 1756b23157dcSNick Dyer if (tchaux & MXT_T100_TCHAUX_AMPL) 1757b23157dcSNick Dyer data->t100_aux_ampl = aux++; 1758b23157dcSNick Dyer 1759b23157dcSNick Dyer if (tchaux & MXT_T100_TCHAUX_AREA) 1760b23157dcSNick Dyer data->t100_aux_area = aux++; 1761b23157dcSNick Dyer 1762b23157dcSNick Dyer dev_dbg(&client->dev, 1763b23157dcSNick Dyer "T100 aux mappings vect:%u ampl:%u area:%u\n", 1764b23157dcSNick Dyer data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area); 1765b23157dcSNick Dyer 1766b23157dcSNick Dyer return 0; 1767b23157dcSNick Dyer } 1768b23157dcSNick Dyer 17697a53d609SNick Dyer static int mxt_input_open(struct input_dev *dev); 17707a53d609SNick Dyer static void mxt_input_close(struct input_dev *dev); 17717a53d609SNick Dyer 1772b6d2d328SSjoerd Simons static void mxt_set_up_as_touchpad(struct input_dev *input_dev, 1773b6d2d328SSjoerd Simons struct mxt_data *data) 1774b6d2d328SSjoerd Simons { 1775b6d2d328SSjoerd Simons const struct mxt_platform_data *pdata = data->pdata; 1776b6d2d328SSjoerd Simons int i; 1777b6d2d328SSjoerd Simons 1778b6d2d328SSjoerd Simons input_dev->name = "Atmel maXTouch Touchpad"; 1779b6d2d328SSjoerd Simons 1780b6d2d328SSjoerd Simons __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); 1781b6d2d328SSjoerd Simons 1782b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM); 1783b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM); 1784b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_MT_POSITION_X, 1785b6d2d328SSjoerd Simons MXT_PIXELS_PER_MM); 1786b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 1787b6d2d328SSjoerd Simons MXT_PIXELS_PER_MM); 1788b6d2d328SSjoerd Simons 1789b6d2d328SSjoerd Simons for (i = 0; i < pdata->t19_num_keys; i++) 1790b6d2d328SSjoerd Simons if (pdata->t19_keymap[i] != KEY_RESERVED) 1791b6d2d328SSjoerd Simons input_set_capability(input_dev, EV_KEY, 1792b6d2d328SSjoerd Simons pdata->t19_keymap[i]); 1793b6d2d328SSjoerd Simons } 1794b6d2d328SSjoerd Simons 1795b23157dcSNick Dyer static int mxt_initialize_input_device(struct mxt_data *data) 17967a53d609SNick Dyer { 17977a53d609SNick Dyer const struct mxt_platform_data *pdata = data->pdata; 1798b6d2d328SSjoerd Simons struct device *dev = &data->client->dev; 17997a53d609SNick Dyer struct input_dev *input_dev; 18007a53d609SNick Dyer int error; 18017a53d609SNick Dyer unsigned int num_mt_slots; 18027a53d609SNick Dyer unsigned int mt_flags = 0; 18037a53d609SNick Dyer 1804b23157dcSNick Dyer switch (data->multitouch) { 1805b23157dcSNick Dyer case MXT_TOUCH_MULTI_T9: 1806b23157dcSNick Dyer num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; 18077a53d609SNick Dyer error = mxt_read_t9_resolution(data); 18087a53d609SNick Dyer if (error) 18097a53d609SNick Dyer dev_warn(dev, "Failed to initialize T9 resolution\n"); 1810b23157dcSNick Dyer break; 1811b23157dcSNick Dyer 1812b23157dcSNick Dyer case MXT_TOUCH_MULTITOUCHSCREEN_T100: 1813b23157dcSNick Dyer num_mt_slots = data->num_touchids; 1814b23157dcSNick Dyer error = mxt_read_t100_config(data); 1815b23157dcSNick Dyer if (error) 1816b23157dcSNick Dyer dev_warn(dev, "Failed to read T100 config\n"); 1817b23157dcSNick Dyer break; 1818b23157dcSNick Dyer 1819b23157dcSNick Dyer default: 1820b23157dcSNick Dyer dev_err(dev, "Invalid multitouch object\n"); 1821b23157dcSNick Dyer return -EINVAL; 1822b23157dcSNick Dyer } 18237a53d609SNick Dyer 18241c0276d5SNick Dyer /* Handle default values and orientation switch */ 18251c0276d5SNick Dyer if (data->max_x == 0) 18261c0276d5SNick Dyer data->max_x = 1023; 18271c0276d5SNick Dyer 18281c0276d5SNick Dyer if (data->max_y == 0) 18291c0276d5SNick Dyer data->max_y = 1023; 18301c0276d5SNick Dyer 18311c0276d5SNick Dyer if (data->xy_switch) 18321c0276d5SNick Dyer swap(data->max_x, data->max_y); 18331c0276d5SNick Dyer 18341c0276d5SNick Dyer dev_info(dev, "Touchscreen size X%uY%u\n", data->max_x, data->max_y); 18351c0276d5SNick Dyer 18361c0276d5SNick Dyer /* Register input device */ 18377a53d609SNick Dyer input_dev = input_allocate_device(); 18387a53d609SNick Dyer if (!input_dev) { 18397a53d609SNick Dyer dev_err(dev, "Failed to allocate memory\n"); 18407a53d609SNick Dyer return -ENOMEM; 18417a53d609SNick Dyer } 18427a53d609SNick Dyer 18437a53d609SNick Dyer input_dev->name = "Atmel maXTouch Touchscreen"; 18447a53d609SNick Dyer input_dev->phys = data->phys; 18457a53d609SNick Dyer input_dev->id.bustype = BUS_I2C; 18467a53d609SNick Dyer input_dev->dev.parent = dev; 18477a53d609SNick Dyer input_dev->open = mxt_input_open; 18487a53d609SNick Dyer input_dev->close = mxt_input_close; 18497a53d609SNick Dyer 1850b23157dcSNick Dyer input_set_capability(input_dev, EV_KEY, BTN_TOUCH); 18517a53d609SNick Dyer 18527a53d609SNick Dyer /* For single touch */ 1853b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_X, 0, data->max_x, 0, 0); 1854b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_Y, 0, data->max_y, 0, 0); 1855b23157dcSNick Dyer 1856b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTI_T9 || 1857b23157dcSNick Dyer (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 1858b23157dcSNick Dyer data->t100_aux_ampl)) { 1859b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); 1860b23157dcSNick Dyer } 18617a53d609SNick Dyer 1862b6d2d328SSjoerd Simons /* If device has buttons we assume it is a touchpad */ 1863b6d2d328SSjoerd Simons if (pdata->t19_num_keys) { 1864b6d2d328SSjoerd Simons mxt_set_up_as_touchpad(input_dev, data); 1865b6d2d328SSjoerd Simons mt_flags |= INPUT_MT_POINTER; 1866eafc0c87SNick Dyer } else { 1867eafc0c87SNick Dyer mt_flags |= INPUT_MT_DIRECT; 1868b6d2d328SSjoerd Simons } 1869b6d2d328SSjoerd Simons 18707a53d609SNick Dyer /* For multi touch */ 18717a53d609SNick Dyer error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags); 18727a53d609SNick Dyer if (error) { 18737a53d609SNick Dyer dev_err(dev, "Error %d initialising slots\n", error); 18747a53d609SNick Dyer goto err_free_mem; 18757a53d609SNick Dyer } 18767a53d609SNick Dyer 1877b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100) { 1878b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 1879b23157dcSNick Dyer 0, MT_TOOL_MAX, 0, 0); 1880b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_DISTANCE, 1881b23157dcSNick Dyer MXT_DISTANCE_ACTIVE_TOUCH, 1882b23157dcSNick Dyer MXT_DISTANCE_HOVERING, 1883b23157dcSNick Dyer 0, 0); 1884b23157dcSNick Dyer } 1885b23157dcSNick Dyer 18867a53d609SNick Dyer input_set_abs_params(input_dev, ABS_MT_POSITION_X, 18877a53d609SNick Dyer 0, data->max_x, 0, 0); 18887a53d609SNick Dyer input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 18897a53d609SNick Dyer 0, data->max_y, 0, 0); 1890b23157dcSNick Dyer 1891b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTI_T9 || 1892b23157dcSNick Dyer (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 1893b23157dcSNick Dyer data->t100_aux_area)) { 1894b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 1895b23157dcSNick Dyer 0, MXT_MAX_AREA, 0, 0); 1896b23157dcSNick Dyer } 1897b23157dcSNick Dyer 1898b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTI_T9 || 1899b23157dcSNick Dyer (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 1900b23157dcSNick Dyer data->t100_aux_ampl)) { 19017a53d609SNick Dyer input_set_abs_params(input_dev, ABS_MT_PRESSURE, 19027a53d609SNick Dyer 0, 255, 0, 0); 1903b23157dcSNick Dyer } 1904b23157dcSNick Dyer 1905b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 1906b23157dcSNick Dyer data->t100_aux_vect) { 1907b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 1908b23157dcSNick Dyer 0, 255, 0, 0); 1909b23157dcSNick Dyer } 1910b23157dcSNick Dyer 1911b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 1912b23157dcSNick Dyer data->t100_aux_ampl) { 1913b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_PRESSURE, 1914b23157dcSNick Dyer 0, 255, 0, 0); 1915b23157dcSNick Dyer } 1916b23157dcSNick Dyer 1917b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 1918b23157dcSNick Dyer data->t100_aux_vect) { 1919b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 1920b23157dcSNick Dyer 0, 255, 0, 0); 1921b23157dcSNick Dyer } 19227a53d609SNick Dyer 19237a53d609SNick Dyer input_set_drvdata(input_dev, data); 19247a53d609SNick Dyer 19257a53d609SNick Dyer error = input_register_device(input_dev); 19267a53d609SNick Dyer if (error) { 19277a53d609SNick Dyer dev_err(dev, "Error %d registering input device\n", error); 19287a53d609SNick Dyer goto err_free_mem; 19297a53d609SNick Dyer } 19307a53d609SNick Dyer 19317a53d609SNick Dyer data->input_dev = input_dev; 19327a53d609SNick Dyer 19337a53d609SNick Dyer return 0; 19347a53d609SNick Dyer 19357a53d609SNick Dyer err_free_mem: 19367a53d609SNick Dyer input_free_device(input_dev); 19377a53d609SNick Dyer return error; 19387a53d609SNick Dyer } 19397a53d609SNick Dyer 194050a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data, 194150a77c65SNick Dyer const struct firmware *cfg); 194250a77c65SNick Dyer 194350a77c65SNick Dyer static void mxt_config_cb(const struct firmware *cfg, void *ctx) 194450a77c65SNick Dyer { 194550a77c65SNick Dyer mxt_configure_objects(ctx, cfg); 1946efdbd7aeSDmitry Torokhov release_firmware(cfg); 194750a77c65SNick Dyer } 194850a77c65SNick Dyer 19497686b108SIiro Valkonen static int mxt_initialize(struct mxt_data *data) 19504cf51c38SJoonyoung Shim { 19514cf51c38SJoonyoung Shim struct i2c_client *client = data->client; 19526cd1ab0fSDmitry Torokhov int recovery_attempts = 0; 19534cf51c38SJoonyoung Shim int error; 19544cf51c38SJoonyoung Shim 19556cd1ab0fSDmitry Torokhov while (1) { 19567686b108SIiro Valkonen error = mxt_get_info(data); 19576cd1ab0fSDmitry Torokhov if (!error) 19586cd1ab0fSDmitry Torokhov break; 19596cd1ab0fSDmitry Torokhov 19606cd1ab0fSDmitry Torokhov /* Check bootloader state */ 19616cd1ab0fSDmitry Torokhov error = mxt_probe_bootloader(data, false); 1962a9fdd1e6SNick Dyer if (error) { 19636cd1ab0fSDmitry Torokhov dev_info(&client->dev, "Trying alternate bootloader address\n"); 19646cd1ab0fSDmitry Torokhov error = mxt_probe_bootloader(data, true); 19658efaa5e5SNick Dyer if (error) { 19668efaa5e5SNick Dyer /* Chip is not in appmode or bootloader mode */ 19674cf51c38SJoonyoung Shim return error; 19688efaa5e5SNick Dyer } 19696cd1ab0fSDmitry Torokhov } 19704cf51c38SJoonyoung Shim 19716cd1ab0fSDmitry Torokhov /* OK, we are in bootloader, see if we can recover */ 19726cd1ab0fSDmitry Torokhov if (++recovery_attempts > 1) { 19738efaa5e5SNick Dyer dev_err(&client->dev, "Could not recover from bootloader mode\n"); 19748efaa5e5SNick Dyer /* 19758efaa5e5SNick Dyer * We can reflash from this state, so do not 19766cd1ab0fSDmitry Torokhov * abort initialization. 19778efaa5e5SNick Dyer */ 1978a9fdd1e6SNick Dyer data->in_bootloader = true; 1979a9fdd1e6SNick Dyer return 0; 1980a9fdd1e6SNick Dyer } 1981a9fdd1e6SNick Dyer 19828efaa5e5SNick Dyer /* Attempt to exit bootloader into app mode */ 19838efaa5e5SNick Dyer mxt_send_bootloader_cmd(data, false); 19848efaa5e5SNick Dyer msleep(MXT_FW_RESET_TIME); 19858efaa5e5SNick Dyer } 19868efaa5e5SNick Dyer 19874cf51c38SJoonyoung Shim /* Get object table information */ 19887686b108SIiro Valkonen error = mxt_get_object_table(data); 19897bed6805SNick Dyer if (error) { 19907bed6805SNick Dyer dev_err(&client->dev, "Error %d reading object table\n", error); 1991dd24dcf5SNick Dyer return error; 19927bed6805SNick Dyer } 19934cf51c38SJoonyoung Shim 1994041fa159SDmitry Torokhov error = mxt_acquire_irq(data); 1995dd24dcf5SNick Dyer if (error) 1996dd24dcf5SNick Dyer goto err_free_object_table; 1997dd24dcf5SNick Dyer 19986cd1ab0fSDmitry Torokhov error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME, 19996cd1ab0fSDmitry Torokhov &client->dev, GFP_KERNEL, data, 200050a77c65SNick Dyer mxt_config_cb); 20016cd1ab0fSDmitry Torokhov if (error) { 20026cd1ab0fSDmitry Torokhov dev_err(&client->dev, "Failed to invoke firmware loader: %d\n", 20036cd1ab0fSDmitry Torokhov error); 20046cd1ab0fSDmitry Torokhov goto err_free_object_table; 20056cd1ab0fSDmitry Torokhov } 20064cf51c38SJoonyoung Shim 20074cf51c38SJoonyoung Shim return 0; 20087d4fa100SDaniel Kurtz 20097d4fa100SDaniel Kurtz err_free_object_table: 20107d4fa100SDaniel Kurtz mxt_free_object_table(data); 20117d4fa100SDaniel Kurtz return error; 20124cf51c38SJoonyoung Shim } 20134cf51c38SJoonyoung Shim 20147f3884f7SNick Dyer static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) 20157f3884f7SNick Dyer { 20167f3884f7SNick Dyer struct device *dev = &data->client->dev; 20177f3884f7SNick Dyer int error; 20187f3884f7SNick Dyer struct t7_config *new_config; 20197f3884f7SNick Dyer struct t7_config deepsleep = { .active = 0, .idle = 0 }; 20207f3884f7SNick Dyer 20217f3884f7SNick Dyer if (sleep == MXT_POWER_CFG_DEEPSLEEP) 20227f3884f7SNick Dyer new_config = &deepsleep; 20237f3884f7SNick Dyer else 20247f3884f7SNick Dyer new_config = &data->t7_cfg; 20257f3884f7SNick Dyer 20267f3884f7SNick Dyer error = __mxt_write_reg(data->client, data->T7_address, 20277f3884f7SNick Dyer sizeof(data->t7_cfg), new_config); 20287f3884f7SNick Dyer if (error) 20297f3884f7SNick Dyer return error; 20307f3884f7SNick Dyer 20317f3884f7SNick Dyer dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n", 20327f3884f7SNick Dyer new_config->active, new_config->idle); 20337f3884f7SNick Dyer 20347f3884f7SNick Dyer return 0; 20357f3884f7SNick Dyer } 20367f3884f7SNick Dyer 20377f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data) 20387f3884f7SNick Dyer { 20397f3884f7SNick Dyer struct device *dev = &data->client->dev; 20407f3884f7SNick Dyer int error; 20417f3884f7SNick Dyer bool retry = false; 20427f3884f7SNick Dyer 20437f3884f7SNick Dyer recheck: 20447f3884f7SNick Dyer error = __mxt_read_reg(data->client, data->T7_address, 20457f3884f7SNick Dyer sizeof(data->t7_cfg), &data->t7_cfg); 20467f3884f7SNick Dyer if (error) 20477f3884f7SNick Dyer return error; 20487f3884f7SNick Dyer 20497f3884f7SNick Dyer if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) { 20507f3884f7SNick Dyer if (!retry) { 20517f3884f7SNick Dyer dev_dbg(dev, "T7 cfg zero, resetting\n"); 20527f3884f7SNick Dyer mxt_soft_reset(data); 20537f3884f7SNick Dyer retry = true; 20547f3884f7SNick Dyer goto recheck; 20557f3884f7SNick Dyer } else { 20567f3884f7SNick Dyer dev_dbg(dev, "T7 cfg zero after reset, overriding\n"); 20577f3884f7SNick Dyer data->t7_cfg.active = 20; 20587f3884f7SNick Dyer data->t7_cfg.idle = 100; 20597f3884f7SNick Dyer return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); 20607f3884f7SNick Dyer } 20617f3884f7SNick Dyer } 20627f3884f7SNick Dyer 20637f3884f7SNick Dyer dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n", 20647f3884f7SNick Dyer data->t7_cfg.active, data->t7_cfg.idle); 20657f3884f7SNick Dyer return 0; 20667f3884f7SNick Dyer } 20677f3884f7SNick Dyer 2068*d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 2069*d6a39404SNick Dyer static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x, 2070*d6a39404SNick Dyer unsigned int y) 2071*d6a39404SNick Dyer { 2072*d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2073*d6a39404SNick Dyer unsigned int ofs, page; 2074*d6a39404SNick Dyer 2075*d6a39404SNick Dyer ofs = (y + (x * data->info.matrix_ysize)) * sizeof(u16); 2076*d6a39404SNick Dyer page = ofs / MXT_DIAGNOSTIC_SIZE; 2077*d6a39404SNick Dyer ofs %= MXT_DIAGNOSTIC_SIZE; 2078*d6a39404SNick Dyer 2079*d6a39404SNick Dyer return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]); 2080*d6a39404SNick Dyer } 2081*d6a39404SNick Dyer 2082*d6a39404SNick Dyer static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf) 2083*d6a39404SNick Dyer { 2084*d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2085*d6a39404SNick Dyer unsigned int x = 0; 2086*d6a39404SNick Dyer unsigned int y = 0; 2087*d6a39404SNick Dyer unsigned int i; 2088*d6a39404SNick Dyer 2089*d6a39404SNick Dyer for (i = 0; i < dbg->t37_nodes; i++) { 2090*d6a39404SNick Dyer outbuf[i] = mxt_get_debug_value(data, x, y); 2091*d6a39404SNick Dyer 2092*d6a39404SNick Dyer /* Next value */ 2093*d6a39404SNick Dyer if (++x >= data->info.matrix_xsize) { 2094*d6a39404SNick Dyer x = 0; 2095*d6a39404SNick Dyer y++; 2096*d6a39404SNick Dyer } 2097*d6a39404SNick Dyer } 2098*d6a39404SNick Dyer 2099*d6a39404SNick Dyer return 0; 2100*d6a39404SNick Dyer } 2101*d6a39404SNick Dyer 2102*d6a39404SNick Dyer static int mxt_read_diagnostic_debug(struct mxt_data *data, u8 mode, 2103*d6a39404SNick Dyer u16 *outbuf) 2104*d6a39404SNick Dyer { 2105*d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2106*d6a39404SNick Dyer int retries = 0; 2107*d6a39404SNick Dyer int page; 2108*d6a39404SNick Dyer int ret; 2109*d6a39404SNick Dyer u8 cmd = mode; 2110*d6a39404SNick Dyer struct t37_debug *p; 2111*d6a39404SNick Dyer u8 cmd_poll; 2112*d6a39404SNick Dyer 2113*d6a39404SNick Dyer for (page = 0; page < dbg->t37_pages; page++) { 2114*d6a39404SNick Dyer p = dbg->t37_buf + page; 2115*d6a39404SNick Dyer 2116*d6a39404SNick Dyer ret = mxt_write_reg(data->client, dbg->diag_cmd_address, 2117*d6a39404SNick Dyer cmd); 2118*d6a39404SNick Dyer if (ret) 2119*d6a39404SNick Dyer return ret; 2120*d6a39404SNick Dyer 2121*d6a39404SNick Dyer retries = 0; 2122*d6a39404SNick Dyer msleep(20); 2123*d6a39404SNick Dyer wait_cmd: 2124*d6a39404SNick Dyer /* Read back command byte */ 2125*d6a39404SNick Dyer ret = __mxt_read_reg(data->client, dbg->diag_cmd_address, 2126*d6a39404SNick Dyer sizeof(cmd_poll), &cmd_poll); 2127*d6a39404SNick Dyer if (ret) 2128*d6a39404SNick Dyer return ret; 2129*d6a39404SNick Dyer 2130*d6a39404SNick Dyer /* Field is cleared once the command has been processed */ 2131*d6a39404SNick Dyer if (cmd_poll) { 2132*d6a39404SNick Dyer if (retries++ > 100) 2133*d6a39404SNick Dyer return -EINVAL; 2134*d6a39404SNick Dyer 2135*d6a39404SNick Dyer msleep(20); 2136*d6a39404SNick Dyer goto wait_cmd; 2137*d6a39404SNick Dyer } 2138*d6a39404SNick Dyer 2139*d6a39404SNick Dyer /* Read T37 page */ 2140*d6a39404SNick Dyer ret = __mxt_read_reg(data->client, dbg->t37_address, 2141*d6a39404SNick Dyer sizeof(struct t37_debug), p); 2142*d6a39404SNick Dyer if (ret) 2143*d6a39404SNick Dyer return ret; 2144*d6a39404SNick Dyer 2145*d6a39404SNick Dyer if (p->mode != mode || p->page != page) { 2146*d6a39404SNick Dyer dev_err(&data->client->dev, "T37 page mismatch\n"); 2147*d6a39404SNick Dyer return -EINVAL; 2148*d6a39404SNick Dyer } 2149*d6a39404SNick Dyer 2150*d6a39404SNick Dyer dev_dbg(&data->client->dev, "%s page:%d retries:%d\n", 2151*d6a39404SNick Dyer __func__, page, retries); 2152*d6a39404SNick Dyer 2153*d6a39404SNick Dyer /* For remaining pages, write PAGEUP rather than mode */ 2154*d6a39404SNick Dyer cmd = MXT_DIAGNOSTIC_PAGEUP; 2155*d6a39404SNick Dyer } 2156*d6a39404SNick Dyer 2157*d6a39404SNick Dyer return mxt_convert_debug_pages(data, outbuf); 2158*d6a39404SNick Dyer } 2159*d6a39404SNick Dyer 2160*d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data) 2161*d6a39404SNick Dyer { 2162*d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2163*d6a39404SNick Dyer struct mxt_object *object; 2164*d6a39404SNick Dyer 2165*d6a39404SNick Dyer object = mxt_get_object(data, MXT_GEN_COMMAND_T6); 2166*d6a39404SNick Dyer if (!object) 2167*d6a39404SNick Dyer goto error; 2168*d6a39404SNick Dyer 2169*d6a39404SNick Dyer dbg->diag_cmd_address = object->start_address + MXT_COMMAND_DIAGNOSTIC; 2170*d6a39404SNick Dyer 2171*d6a39404SNick Dyer object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37); 2172*d6a39404SNick Dyer if (!object) 2173*d6a39404SNick Dyer goto error; 2174*d6a39404SNick Dyer 2175*d6a39404SNick Dyer if (mxt_obj_size(object) != sizeof(struct t37_debug)) { 2176*d6a39404SNick Dyer dev_warn(&data->client->dev, "Bad T37 size"); 2177*d6a39404SNick Dyer goto error; 2178*d6a39404SNick Dyer } 2179*d6a39404SNick Dyer 2180*d6a39404SNick Dyer dbg->t37_address = object->start_address; 2181*d6a39404SNick Dyer 2182*d6a39404SNick Dyer /* Calculate size of data and allocate buffer */ 2183*d6a39404SNick Dyer dbg->t37_nodes = data->info.matrix_xsize * data->info.matrix_ysize; 2184*d6a39404SNick Dyer dbg->t37_pages = DIV_ROUND_UP(dbg->t37_nodes * sizeof(u16), 2185*d6a39404SNick Dyer sizeof(dbg->t37_buf->data)); 2186*d6a39404SNick Dyer 2187*d6a39404SNick Dyer dbg->t37_buf = devm_kmalloc_array(&data->client->dev, dbg->t37_pages, 2188*d6a39404SNick Dyer sizeof(struct t37_debug), GFP_KERNEL); 2189*d6a39404SNick Dyer if (!dbg->t37_buf) 2190*d6a39404SNick Dyer goto error; 2191*d6a39404SNick Dyer 2192*d6a39404SNick Dyer return; 2193*d6a39404SNick Dyer 2194*d6a39404SNick Dyer error: 2195*d6a39404SNick Dyer dev_warn(&data->client->dev, "Error initializing T37\n"); 2196*d6a39404SNick Dyer } 2197*d6a39404SNick Dyer #else 2198*d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data) 2199*d6a39404SNick Dyer { 2200*d6a39404SNick Dyer } 2201*d6a39404SNick Dyer #endif 2202*d6a39404SNick Dyer 220350a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data, 220450a77c65SNick Dyer const struct firmware *cfg) 220550a77c65SNick Dyer { 220650a77c65SNick Dyer struct device *dev = &data->client->dev; 220750a77c65SNick Dyer struct mxt_info *info = &data->info; 220850a77c65SNick Dyer int error; 220950a77c65SNick Dyer 22107f3884f7SNick Dyer error = mxt_init_t7_power_cfg(data); 22117f3884f7SNick Dyer if (error) { 22127f3884f7SNick Dyer dev_err(dev, "Failed to initialize power cfg\n"); 22137f3884f7SNick Dyer return error; 22147f3884f7SNick Dyer } 22157f3884f7SNick Dyer 221650a77c65SNick Dyer if (cfg) { 221750a77c65SNick Dyer error = mxt_update_cfg(data, cfg); 221850a77c65SNick Dyer if (error) 221950a77c65SNick Dyer dev_warn(dev, "Error %d updating config\n", error); 222050a77c65SNick Dyer } 222150a77c65SNick Dyer 2222b23157dcSNick Dyer if (data->multitouch) { 2223b23157dcSNick Dyer error = mxt_initialize_input_device(data); 222450a77c65SNick Dyer if (error) 222550a77c65SNick Dyer return error; 2226b23157dcSNick Dyer } else { 2227b23157dcSNick Dyer dev_warn(dev, "No touch object detected\n"); 2228b23157dcSNick Dyer } 222950a77c65SNick Dyer 2230*d6a39404SNick Dyer mxt_debug_init(data); 2231*d6a39404SNick Dyer 223250a77c65SNick Dyer dev_info(dev, 223350a77c65SNick Dyer "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", 223450a77c65SNick Dyer info->family_id, info->variant_id, info->version >> 4, 223550a77c65SNick Dyer info->version & 0xf, info->build, info->object_num); 223650a77c65SNick Dyer 223750a77c65SNick Dyer return 0; 223850a77c65SNick Dyer } 223950a77c65SNick Dyer 2240b19fc9ecSDaniel Kurtz /* Firmware Version is returned as Major.Minor.Build */ 2241b19fc9ecSDaniel Kurtz static ssize_t mxt_fw_version_show(struct device *dev, 2242b19fc9ecSDaniel Kurtz struct device_attribute *attr, char *buf) 2243b19fc9ecSDaniel Kurtz { 2244b19fc9ecSDaniel Kurtz struct mxt_data *data = dev_get_drvdata(dev); 2245b19fc9ecSDaniel Kurtz struct mxt_info *info = &data->info; 2246b19fc9ecSDaniel Kurtz return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n", 2247b19fc9ecSDaniel Kurtz info->version >> 4, info->version & 0xf, info->build); 2248b19fc9ecSDaniel Kurtz } 2249b19fc9ecSDaniel Kurtz 2250b19fc9ecSDaniel Kurtz /* Hardware Version is returned as FamilyID.VariantID */ 2251b19fc9ecSDaniel Kurtz static ssize_t mxt_hw_version_show(struct device *dev, 2252b19fc9ecSDaniel Kurtz struct device_attribute *attr, char *buf) 2253b19fc9ecSDaniel Kurtz { 2254b19fc9ecSDaniel Kurtz struct mxt_data *data = dev_get_drvdata(dev); 2255b19fc9ecSDaniel Kurtz struct mxt_info *info = &data->info; 2256b19fc9ecSDaniel Kurtz return scnprintf(buf, PAGE_SIZE, "%u.%u\n", 2257b19fc9ecSDaniel Kurtz info->family_id, info->variant_id); 2258b19fc9ecSDaniel Kurtz } 2259b19fc9ecSDaniel Kurtz 2260794eb67eSDaniel Kurtz static ssize_t mxt_show_instance(char *buf, int count, 2261794eb67eSDaniel Kurtz struct mxt_object *object, int instance, 2262794eb67eSDaniel Kurtz const u8 *val) 2263794eb67eSDaniel Kurtz { 2264794eb67eSDaniel Kurtz int i; 2265794eb67eSDaniel Kurtz 22661e0c0c5bSDaniel Kurtz if (mxt_obj_instances(object) > 1) 2267794eb67eSDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, 2268794eb67eSDaniel Kurtz "Instance %u\n", instance); 2269794eb67eSDaniel Kurtz 22701e0c0c5bSDaniel Kurtz for (i = 0; i < mxt_obj_size(object); i++) 2271794eb67eSDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, 2272794eb67eSDaniel Kurtz "\t[%2u]: %02x (%d)\n", i, val[i], val[i]); 2273794eb67eSDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); 2274794eb67eSDaniel Kurtz 2275794eb67eSDaniel Kurtz return count; 2276794eb67eSDaniel Kurtz } 2277794eb67eSDaniel Kurtz 22787686b108SIiro Valkonen static ssize_t mxt_object_show(struct device *dev, 22794cf51c38SJoonyoung Shim struct device_attribute *attr, char *buf) 22804cf51c38SJoonyoung Shim { 22817686b108SIiro Valkonen struct mxt_data *data = dev_get_drvdata(dev); 22827686b108SIiro Valkonen struct mxt_object *object; 22834cf51c38SJoonyoung Shim int count = 0; 22844cf51c38SJoonyoung Shim int i, j; 22854cf51c38SJoonyoung Shim int error; 228643a91d51SDaniel Kurtz u8 *obuf; 22874cf51c38SJoonyoung Shim 228843a91d51SDaniel Kurtz /* Pre-allocate buffer large enough to hold max sized object. */ 228943a91d51SDaniel Kurtz obuf = kmalloc(256, GFP_KERNEL); 229043a91d51SDaniel Kurtz if (!obuf) 229143a91d51SDaniel Kurtz return -ENOMEM; 229243a91d51SDaniel Kurtz 229343a91d51SDaniel Kurtz error = 0; 22944cf51c38SJoonyoung Shim for (i = 0; i < data->info.object_num; i++) { 22954cf51c38SJoonyoung Shim object = data->object_table + i; 22964cf51c38SJoonyoung Shim 229791630955SDaniel Kurtz if (!mxt_object_readable(object->type)) 22984cf51c38SJoonyoung Shim continue; 22994cf51c38SJoonyoung Shim 230091630955SDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, 230191630955SDaniel Kurtz "T%u:\n", object->type); 23024cf51c38SJoonyoung Shim 23031e0c0c5bSDaniel Kurtz for (j = 0; j < mxt_obj_instances(object); j++) { 23041e0c0c5bSDaniel Kurtz u16 size = mxt_obj_size(object); 2305794eb67eSDaniel Kurtz u16 addr = object->start_address + j * size; 2306794eb67eSDaniel Kurtz 2307794eb67eSDaniel Kurtz error = __mxt_read_reg(data->client, addr, size, obuf); 23084cf51c38SJoonyoung Shim if (error) 2309794eb67eSDaniel Kurtz goto done; 23104cf51c38SJoonyoung Shim 2311794eb67eSDaniel Kurtz count = mxt_show_instance(buf, count, object, j, obuf); 23124cf51c38SJoonyoung Shim } 23134cf51c38SJoonyoung Shim } 23144cf51c38SJoonyoung Shim 2315794eb67eSDaniel Kurtz done: 231643a91d51SDaniel Kurtz kfree(obuf); 231743a91d51SDaniel Kurtz return error ?: count; 23184cf51c38SJoonyoung Shim } 23194cf51c38SJoonyoung Shim 2320f2ac6cb9SNick Dyer static int mxt_check_firmware_format(struct device *dev, 2321f2ac6cb9SNick Dyer const struct firmware *fw) 2322f2ac6cb9SNick Dyer { 2323f2ac6cb9SNick Dyer unsigned int pos = 0; 2324f2ac6cb9SNick Dyer char c; 2325f2ac6cb9SNick Dyer 2326f2ac6cb9SNick Dyer while (pos < fw->size) { 2327f2ac6cb9SNick Dyer c = *(fw->data + pos); 2328f2ac6cb9SNick Dyer 2329f2ac6cb9SNick Dyer if (c < '0' || (c > '9' && c < 'A') || c > 'F') 2330f2ac6cb9SNick Dyer return 0; 2331f2ac6cb9SNick Dyer 2332f2ac6cb9SNick Dyer pos++; 2333f2ac6cb9SNick Dyer } 2334f2ac6cb9SNick Dyer 2335f2ac6cb9SNick Dyer /* 2336f2ac6cb9SNick Dyer * To convert file try: 2337f2ac6cb9SNick Dyer * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw 2338f2ac6cb9SNick Dyer */ 2339f2ac6cb9SNick Dyer dev_err(dev, "Aborting: firmware file must be in binary format\n"); 2340f2ac6cb9SNick Dyer 2341f2ac6cb9SNick Dyer return -EINVAL; 2342f2ac6cb9SNick Dyer } 2343f2ac6cb9SNick Dyer 23447686b108SIiro Valkonen static int mxt_load_fw(struct device *dev, const char *fn) 23454cf51c38SJoonyoung Shim { 23467686b108SIiro Valkonen struct mxt_data *data = dev_get_drvdata(dev); 23474cf51c38SJoonyoung Shim const struct firmware *fw = NULL; 23484cf51c38SJoonyoung Shim unsigned int frame_size; 23494cf51c38SJoonyoung Shim unsigned int pos = 0; 2350f943c74aSNick Dyer unsigned int retry = 0; 2351f477c758SNick Dyer unsigned int frame = 0; 23524cf51c38SJoonyoung Shim int ret; 23534cf51c38SJoonyoung Shim 23544cf51c38SJoonyoung Shim ret = request_firmware(&fw, fn, dev); 23554cf51c38SJoonyoung Shim if (ret) { 23564cf51c38SJoonyoung Shim dev_err(dev, "Unable to open firmware %s\n", fn); 23574cf51c38SJoonyoung Shim return ret; 23584cf51c38SJoonyoung Shim } 23594cf51c38SJoonyoung Shim 2360f2ac6cb9SNick Dyer /* Check for incorrect enc file */ 2361f2ac6cb9SNick Dyer ret = mxt_check_firmware_format(dev, fw); 2362f2ac6cb9SNick Dyer if (ret) 2363f2ac6cb9SNick Dyer goto release_firmware; 2364f2ac6cb9SNick Dyer 2365a9fdd1e6SNick Dyer if (!data->in_bootloader) { 23664cf51c38SJoonyoung Shim /* Change to the bootloader mode */ 2367d79e7e47SBenson Leung data->in_bootloader = true; 2368d79e7e47SBenson Leung 2369a9fdd1e6SNick Dyer ret = mxt_t6_command(data, MXT_COMMAND_RESET, 2370a9fdd1e6SNick Dyer MXT_BOOT_VALUE, false); 2371a4a2ef46SIiro Valkonen if (ret) 2372a4a2ef46SIiro Valkonen goto release_firmware; 2373a4a2ef46SIiro Valkonen 23747686b108SIiro Valkonen msleep(MXT_RESET_TIME); 23758efaa5e5SNick Dyer 23768efaa5e5SNick Dyer /* Do not need to scan since we know family ID */ 23778efaa5e5SNick Dyer ret = mxt_lookup_bootloader_address(data, 0); 23788efaa5e5SNick Dyer if (ret) 23798efaa5e5SNick Dyer goto release_firmware; 238058e4aeeeSStephen Warren 238158e4aeeeSStephen Warren mxt_free_input_device(data); 238258e4aeeeSStephen Warren mxt_free_object_table(data); 23838efaa5e5SNick Dyer } else { 23848efaa5e5SNick Dyer enable_irq(data->irq); 2385a9fdd1e6SNick Dyer } 23864cf51c38SJoonyoung Shim 2387d79e7e47SBenson Leung reinit_completion(&data->bl_completion); 2388d79e7e47SBenson Leung 2389385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false); 2390385deb96SNick Dyer if (ret) { 2391385deb96SNick Dyer /* Bootloader may still be unlocked from previous attempt */ 2392385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false); 23934cf51c38SJoonyoung Shim if (ret) 2394d79e7e47SBenson Leung goto disable_irq; 2395385deb96SNick Dyer } else { 2396385deb96SNick Dyer dev_info(dev, "Unlocking bootloader\n"); 23974cf51c38SJoonyoung Shim 23984cf51c38SJoonyoung Shim /* Unlock bootloader */ 23998efaa5e5SNick Dyer ret = mxt_send_bootloader_cmd(data, true); 2400385deb96SNick Dyer if (ret) 2401385deb96SNick Dyer goto disable_irq; 2402385deb96SNick Dyer } 24034cf51c38SJoonyoung Shim 24044cf51c38SJoonyoung Shim while (pos < fw->size) { 2405385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true); 24064cf51c38SJoonyoung Shim if (ret) 2407d79e7e47SBenson Leung goto disable_irq; 24084cf51c38SJoonyoung Shim 24094cf51c38SJoonyoung Shim frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); 24104cf51c38SJoonyoung Shim 2411f943c74aSNick Dyer /* Take account of CRC bytes */ 24124cf51c38SJoonyoung Shim frame_size += 2; 24134cf51c38SJoonyoung Shim 24144cf51c38SJoonyoung Shim /* Write one frame to device */ 2415f28a842dSNick Dyer ret = mxt_bootloader_write(data, fw->data + pos, frame_size); 2416f28a842dSNick Dyer if (ret) 2417f28a842dSNick Dyer goto disable_irq; 24184cf51c38SJoonyoung Shim 2419385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true); 2420f943c74aSNick Dyer if (ret) { 2421f943c74aSNick Dyer retry++; 24224cf51c38SJoonyoung Shim 2423f943c74aSNick Dyer /* Back off by 20ms per retry */ 2424f943c74aSNick Dyer msleep(retry * 20); 2425f943c74aSNick Dyer 2426f943c74aSNick Dyer if (retry > 20) { 2427f943c74aSNick Dyer dev_err(dev, "Retry count exceeded\n"); 2428f943c74aSNick Dyer goto disable_irq; 2429f943c74aSNick Dyer } 2430f943c74aSNick Dyer } else { 2431f943c74aSNick Dyer retry = 0; 24324cf51c38SJoonyoung Shim pos += frame_size; 2433f477c758SNick Dyer frame++; 2434f943c74aSNick Dyer } 24354cf51c38SJoonyoung Shim 2436f477c758SNick Dyer if (frame % 50 == 0) 2437f477c758SNick Dyer dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n", 2438f477c758SNick Dyer frame, pos, fw->size); 24394cf51c38SJoonyoung Shim } 24404cf51c38SJoonyoung Shim 2441a0434b75SBenson Leung /* Wait for flash. */ 2442a4a2ef46SIiro Valkonen ret = mxt_wait_for_completion(data, &data->bl_completion, 2443a4a2ef46SIiro Valkonen MXT_FW_RESET_TIME); 2444a0434b75SBenson Leung if (ret) 2445a0434b75SBenson Leung goto disable_irq; 2446a0434b75SBenson Leung 2447f477c758SNick Dyer dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos); 2448f477c758SNick Dyer 2449a0434b75SBenson Leung /* 2450a0434b75SBenson Leung * Wait for device to reset. Some bootloader versions do not assert 2451a0434b75SBenson Leung * the CHG line after bootloading has finished, so ignore potential 2452a0434b75SBenson Leung * errors. 2453a0434b75SBenson Leung */ 2454a4a2ef46SIiro Valkonen mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME); 2455a0434b75SBenson Leung 2456d79e7e47SBenson Leung data->in_bootloader = false; 2457d79e7e47SBenson Leung 2458d79e7e47SBenson Leung disable_irq: 2459d79e7e47SBenson Leung disable_irq(data->irq); 2460a4a2ef46SIiro Valkonen release_firmware: 24614cf51c38SJoonyoung Shim release_firmware(fw); 24624cf51c38SJoonyoung Shim return ret; 24634cf51c38SJoonyoung Shim } 24644cf51c38SJoonyoung Shim 24657686b108SIiro Valkonen static ssize_t mxt_update_fw_store(struct device *dev, 24664cf51c38SJoonyoung Shim struct device_attribute *attr, 24674cf51c38SJoonyoung Shim const char *buf, size_t count) 24684cf51c38SJoonyoung Shim { 24697686b108SIiro Valkonen struct mxt_data *data = dev_get_drvdata(dev); 24704cf51c38SJoonyoung Shim int error; 24714cf51c38SJoonyoung Shim 24727686b108SIiro Valkonen error = mxt_load_fw(dev, MXT_FW_NAME); 24734cf51c38SJoonyoung Shim if (error) { 24744cf51c38SJoonyoung Shim dev_err(dev, "The firmware update failed(%d)\n", error); 24754cf51c38SJoonyoung Shim count = error; 24764cf51c38SJoonyoung Shim } else { 24777bed6805SNick Dyer dev_info(dev, "The firmware update succeeded\n"); 24787bed6805SNick Dyer 2479dd24dcf5SNick Dyer error = mxt_initialize(data); 248008960a07SIiro Valkonen if (error) 248108960a07SIiro Valkonen return error; 2482d79e7e47SBenson Leung } 248308960a07SIiro Valkonen 24844cf51c38SJoonyoung Shim return count; 24854cf51c38SJoonyoung Shim } 24864cf51c38SJoonyoung Shim 2487b19fc9ecSDaniel Kurtz static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL); 2488b19fc9ecSDaniel Kurtz static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL); 248971b3e938SDaniel Kurtz static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL); 249071b3e938SDaniel Kurtz static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store); 24914cf51c38SJoonyoung Shim 24927686b108SIiro Valkonen static struct attribute *mxt_attrs[] = { 2493b19fc9ecSDaniel Kurtz &dev_attr_fw_version.attr, 2494b19fc9ecSDaniel Kurtz &dev_attr_hw_version.attr, 24954cf51c38SJoonyoung Shim &dev_attr_object.attr, 24964cf51c38SJoonyoung Shim &dev_attr_update_fw.attr, 24974cf51c38SJoonyoung Shim NULL 24984cf51c38SJoonyoung Shim }; 24994cf51c38SJoonyoung Shim 25007686b108SIiro Valkonen static const struct attribute_group mxt_attr_group = { 25017686b108SIiro Valkonen .attrs = mxt_attrs, 25024cf51c38SJoonyoung Shim }; 25034cf51c38SJoonyoung Shim 25047686b108SIiro Valkonen static void mxt_start(struct mxt_data *data) 25054cf51c38SJoonyoung Shim { 25067f3884f7SNick Dyer switch (data->pdata->suspend_mode) { 25077f3884f7SNick Dyer case MXT_SUSPEND_T9_CTRL: 25087f3884f7SNick Dyer mxt_soft_reset(data); 25097f3884f7SNick Dyer 25107f405483SLinus Torvalds /* Touch enable */ 25117f3884f7SNick Dyer /* 0x83 = SCANEN | RPTEN | ENABLE */ 25127f3884f7SNick Dyer mxt_write_object(data, 25137f3884f7SNick Dyer MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83); 25147f3884f7SNick Dyer break; 25157f3884f7SNick Dyer 25167f3884f7SNick Dyer case MXT_SUSPEND_DEEP_SLEEP: 25177f3884f7SNick Dyer default: 25187f3884f7SNick Dyer mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); 25197f3884f7SNick Dyer 25207f3884f7SNick Dyer /* Recalibrate since chip has been in deep sleep */ 25217f3884f7SNick Dyer mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); 25227f3884f7SNick Dyer break; 25237f3884f7SNick Dyer } 25247f3884f7SNick Dyer 25254cf51c38SJoonyoung Shim } 25264cf51c38SJoonyoung Shim 25277686b108SIiro Valkonen static void mxt_stop(struct mxt_data *data) 25284cf51c38SJoonyoung Shim { 25297f3884f7SNick Dyer switch (data->pdata->suspend_mode) { 25307f3884f7SNick Dyer case MXT_SUSPEND_T9_CTRL: 25317f405483SLinus Torvalds /* Touch disable */ 25327f3884f7SNick Dyer mxt_write_object(data, 25337f3884f7SNick Dyer MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0); 25347f3884f7SNick Dyer break; 25357f3884f7SNick Dyer 25367f3884f7SNick Dyer case MXT_SUSPEND_DEEP_SLEEP: 25377f3884f7SNick Dyer default: 25387f3884f7SNick Dyer mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); 25397f3884f7SNick Dyer break; 25407f3884f7SNick Dyer } 25414cf51c38SJoonyoung Shim } 25424cf51c38SJoonyoung Shim 25437686b108SIiro Valkonen static int mxt_input_open(struct input_dev *dev) 25444cf51c38SJoonyoung Shim { 25457686b108SIiro Valkonen struct mxt_data *data = input_get_drvdata(dev); 25464cf51c38SJoonyoung Shim 25477686b108SIiro Valkonen mxt_start(data); 25484cf51c38SJoonyoung Shim 25494cf51c38SJoonyoung Shim return 0; 25504cf51c38SJoonyoung Shim } 25514cf51c38SJoonyoung Shim 25527686b108SIiro Valkonen static void mxt_input_close(struct input_dev *dev) 25534cf51c38SJoonyoung Shim { 25547686b108SIiro Valkonen struct mxt_data *data = input_get_drvdata(dev); 25554cf51c38SJoonyoung Shim 25567686b108SIiro Valkonen mxt_stop(data); 25574cf51c38SJoonyoung Shim } 25584cf51c38SJoonyoung Shim 255978188be3SStephen Warren #ifdef CONFIG_OF 25604f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) 256178188be3SStephen Warren { 256278188be3SStephen Warren struct mxt_platform_data *pdata; 256320447664SNick Dyer struct device_node *np = client->dev.of_node; 256478188be3SStephen Warren u32 *keymap; 256520447664SNick Dyer int proplen, ret; 256678188be3SStephen Warren 256720447664SNick Dyer if (!np) 25684f8d8088SDmitry Torokhov return ERR_PTR(-ENOENT); 256978188be3SStephen Warren 257078188be3SStephen Warren pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); 257178188be3SStephen Warren if (!pdata) 257278188be3SStephen Warren return ERR_PTR(-ENOMEM); 257378188be3SStephen Warren 257420447664SNick Dyer if (of_find_property(np, "linux,gpio-keymap", &proplen)) { 257578188be3SStephen Warren pdata->t19_num_keys = proplen / sizeof(u32); 257678188be3SStephen Warren 257778188be3SStephen Warren keymap = devm_kzalloc(&client->dev, 257878188be3SStephen Warren pdata->t19_num_keys * sizeof(keymap[0]), 257978188be3SStephen Warren GFP_KERNEL); 258078188be3SStephen Warren if (!keymap) 258178188be3SStephen Warren return ERR_PTR(-ENOMEM); 258278188be3SStephen Warren 258320447664SNick Dyer ret = of_property_read_u32_array(np, "linux,gpio-keymap", 258420447664SNick Dyer keymap, pdata->t19_num_keys); 258578188be3SStephen Warren if (ret) 258620447664SNick Dyer dev_warn(&client->dev, 258720447664SNick Dyer "Couldn't read linux,gpio-keymap: %d\n", ret); 258878188be3SStephen Warren 258978188be3SStephen Warren pdata->t19_keymap = keymap; 259078188be3SStephen Warren } 259178188be3SStephen Warren 25927f3884f7SNick Dyer pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP; 25937f3884f7SNick Dyer 259478188be3SStephen Warren return pdata; 259578188be3SStephen Warren } 259678188be3SStephen Warren #else 25974f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) 259878188be3SStephen Warren { 25994f8d8088SDmitry Torokhov return ERR_PTR(-ENOENT); 260078188be3SStephen Warren } 260178188be3SStephen Warren #endif 260278188be3SStephen Warren 26034f8d8088SDmitry Torokhov #ifdef CONFIG_ACPI 26044f8d8088SDmitry Torokhov 26054f8d8088SDmitry Torokhov struct mxt_acpi_platform_data { 26064f8d8088SDmitry Torokhov const char *hid; 26074f8d8088SDmitry Torokhov struct mxt_platform_data pdata; 26084f8d8088SDmitry Torokhov }; 26094f8d8088SDmitry Torokhov 26104f8d8088SDmitry Torokhov static unsigned int samus_touchpad_buttons[] = { 26114f8d8088SDmitry Torokhov KEY_RESERVED, 26124f8d8088SDmitry Torokhov KEY_RESERVED, 26134f8d8088SDmitry Torokhov KEY_RESERVED, 26144f8d8088SDmitry Torokhov BTN_LEFT 26154f8d8088SDmitry Torokhov }; 26164f8d8088SDmitry Torokhov 26174f8d8088SDmitry Torokhov static struct mxt_acpi_platform_data samus_platform_data[] = { 26184f8d8088SDmitry Torokhov { 26194f8d8088SDmitry Torokhov /* Touchpad */ 26204f8d8088SDmitry Torokhov .hid = "ATML0000", 26214f8d8088SDmitry Torokhov .pdata = { 26224f8d8088SDmitry Torokhov .t19_num_keys = ARRAY_SIZE(samus_touchpad_buttons), 26234f8d8088SDmitry Torokhov .t19_keymap = samus_touchpad_buttons, 26244f8d8088SDmitry Torokhov }, 26254f8d8088SDmitry Torokhov }, 26264f8d8088SDmitry Torokhov { 26274f8d8088SDmitry Torokhov /* Touchscreen */ 26284f8d8088SDmitry Torokhov .hid = "ATML0001", 26294f8d8088SDmitry Torokhov }, 26304f8d8088SDmitry Torokhov { } 26314f8d8088SDmitry Torokhov }; 26324f8d8088SDmitry Torokhov 2633c67566c6SDmitry Torokhov static unsigned int chromebook_tp_buttons[] = { 2634c67566c6SDmitry Torokhov KEY_RESERVED, 2635c67566c6SDmitry Torokhov KEY_RESERVED, 2636c67566c6SDmitry Torokhov KEY_RESERVED, 2637c67566c6SDmitry Torokhov KEY_RESERVED, 2638c67566c6SDmitry Torokhov KEY_RESERVED, 2639c67566c6SDmitry Torokhov BTN_LEFT 2640c67566c6SDmitry Torokhov }; 2641c67566c6SDmitry Torokhov 2642c67566c6SDmitry Torokhov static struct mxt_acpi_platform_data chromebook_platform_data[] = { 2643c67566c6SDmitry Torokhov { 2644c67566c6SDmitry Torokhov /* Touchpad */ 2645c67566c6SDmitry Torokhov .hid = "ATML0000", 2646c67566c6SDmitry Torokhov .pdata = { 2647c67566c6SDmitry Torokhov .t19_num_keys = ARRAY_SIZE(chromebook_tp_buttons), 2648c67566c6SDmitry Torokhov .t19_keymap = chromebook_tp_buttons, 2649c67566c6SDmitry Torokhov }, 2650c67566c6SDmitry Torokhov }, 2651c67566c6SDmitry Torokhov { 2652c67566c6SDmitry Torokhov /* Touchscreen */ 2653c67566c6SDmitry Torokhov .hid = "ATML0001", 2654c67566c6SDmitry Torokhov }, 2655c67566c6SDmitry Torokhov { } 2656c67566c6SDmitry Torokhov }; 2657c67566c6SDmitry Torokhov 26584f8d8088SDmitry Torokhov static const struct dmi_system_id mxt_dmi_table[] = { 26594f8d8088SDmitry Torokhov { 26604f8d8088SDmitry Torokhov /* 2015 Google Pixel */ 26614f8d8088SDmitry Torokhov .ident = "Chromebook Pixel 2", 26624f8d8088SDmitry Torokhov .matches = { 26634f8d8088SDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 26644f8d8088SDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "Samus"), 26654f8d8088SDmitry Torokhov }, 26664f8d8088SDmitry Torokhov .driver_data = samus_platform_data, 26674f8d8088SDmitry Torokhov }, 2668c67566c6SDmitry Torokhov { 2669c67566c6SDmitry Torokhov /* Other Google Chromebooks */ 2670c67566c6SDmitry Torokhov .ident = "Chromebook", 2671c67566c6SDmitry Torokhov .matches = { 2672c67566c6SDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 2673c67566c6SDmitry Torokhov }, 2674c67566c6SDmitry Torokhov .driver_data = chromebook_platform_data, 2675c67566c6SDmitry Torokhov }, 26764f8d8088SDmitry Torokhov { } 26774f8d8088SDmitry Torokhov }; 26784f8d8088SDmitry Torokhov 26794f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client) 26804f8d8088SDmitry Torokhov { 26814f8d8088SDmitry Torokhov struct acpi_device *adev; 26824f8d8088SDmitry Torokhov const struct dmi_system_id *system_id; 26834f8d8088SDmitry Torokhov const struct mxt_acpi_platform_data *acpi_pdata; 26844f8d8088SDmitry Torokhov 26854f8d8088SDmitry Torokhov /* 26864f8d8088SDmitry Torokhov * Ignore ACPI devices representing bootloader mode. 26874f8d8088SDmitry Torokhov * 26884f8d8088SDmitry Torokhov * This is a bit of a hack: Google Chromebook BIOS creates ACPI 26894f8d8088SDmitry Torokhov * devices for both application and bootloader modes, but we are 26904f8d8088SDmitry Torokhov * interested in application mode only (if device is in bootloader 26914f8d8088SDmitry Torokhov * mode we'll end up switching into application anyway). So far 26924f8d8088SDmitry Torokhov * application mode addresses were all above 0x40, so we'll use it 26934f8d8088SDmitry Torokhov * as a threshold. 26944f8d8088SDmitry Torokhov */ 26954f8d8088SDmitry Torokhov if (client->addr < 0x40) 26964f8d8088SDmitry Torokhov return ERR_PTR(-ENXIO); 26974f8d8088SDmitry Torokhov 26984f8d8088SDmitry Torokhov adev = ACPI_COMPANION(&client->dev); 26994f8d8088SDmitry Torokhov if (!adev) 27004f8d8088SDmitry Torokhov return ERR_PTR(-ENOENT); 27014f8d8088SDmitry Torokhov 27024f8d8088SDmitry Torokhov system_id = dmi_first_match(mxt_dmi_table); 27034f8d8088SDmitry Torokhov if (!system_id) 27044f8d8088SDmitry Torokhov return ERR_PTR(-ENOENT); 27054f8d8088SDmitry Torokhov 27064f8d8088SDmitry Torokhov acpi_pdata = system_id->driver_data; 27074f8d8088SDmitry Torokhov if (!acpi_pdata) 27084f8d8088SDmitry Torokhov return ERR_PTR(-ENOENT); 27094f8d8088SDmitry Torokhov 27104f8d8088SDmitry Torokhov while (acpi_pdata->hid) { 27114f8d8088SDmitry Torokhov if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid)) 27124f8d8088SDmitry Torokhov return &acpi_pdata->pdata; 27134f8d8088SDmitry Torokhov 27144f8d8088SDmitry Torokhov acpi_pdata++; 27154f8d8088SDmitry Torokhov } 27164f8d8088SDmitry Torokhov 27174f8d8088SDmitry Torokhov return ERR_PTR(-ENOENT); 27184f8d8088SDmitry Torokhov } 27194f8d8088SDmitry Torokhov #else 27204f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client) 27214f8d8088SDmitry Torokhov { 27224f8d8088SDmitry Torokhov return ERR_PTR(-ENOENT); 27234f8d8088SDmitry Torokhov } 27244f8d8088SDmitry Torokhov #endif 27254f8d8088SDmitry Torokhov 27264f8d8088SDmitry Torokhov static const struct mxt_platform_data * 27274f8d8088SDmitry Torokhov mxt_get_platform_data(struct i2c_client *client) 27284f8d8088SDmitry Torokhov { 27294f8d8088SDmitry Torokhov const struct mxt_platform_data *pdata; 27304f8d8088SDmitry Torokhov 27314f8d8088SDmitry Torokhov pdata = dev_get_platdata(&client->dev); 27324f8d8088SDmitry Torokhov if (pdata) 27334f8d8088SDmitry Torokhov return pdata; 27344f8d8088SDmitry Torokhov 27354f8d8088SDmitry Torokhov pdata = mxt_parse_dt(client); 27364f8d8088SDmitry Torokhov if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT) 27374f8d8088SDmitry Torokhov return pdata; 27384f8d8088SDmitry Torokhov 27394f8d8088SDmitry Torokhov pdata = mxt_parse_acpi(client); 27404f8d8088SDmitry Torokhov if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT) 27414f8d8088SDmitry Torokhov return pdata; 27424f8d8088SDmitry Torokhov 27434f8d8088SDmitry Torokhov dev_err(&client->dev, "No platform data specified\n"); 27444f8d8088SDmitry Torokhov return ERR_PTR(-EINVAL); 27454f8d8088SDmitry Torokhov } 27464f8d8088SDmitry Torokhov 274778188be3SStephen Warren static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) 27484cf51c38SJoonyoung Shim { 27497686b108SIiro Valkonen struct mxt_data *data; 275078188be3SStephen Warren const struct mxt_platform_data *pdata; 27514cf51c38SJoonyoung Shim int error; 27524cf51c38SJoonyoung Shim 27534f8d8088SDmitry Torokhov pdata = mxt_get_platform_data(client); 275478188be3SStephen Warren if (IS_ERR(pdata)) 275578188be3SStephen Warren return PTR_ERR(pdata); 27564cf51c38SJoonyoung Shim 27577686b108SIiro Valkonen data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); 27587a53d609SNick Dyer if (!data) { 27594cf51c38SJoonyoung Shim dev_err(&client->dev, "Failed to allocate memory\n"); 27607a53d609SNick Dyer return -ENOMEM; 27614cf51c38SJoonyoung Shim } 27624cf51c38SJoonyoung Shim 2763ec02ac2bSDaniel Kurtz snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0", 2764ec02ac2bSDaniel Kurtz client->adapter->nr, client->addr); 276522dfab7fSDaniel Kurtz 2766910d8051SJoonyoung Shim data->client = client; 2767910d8051SJoonyoung Shim data->pdata = pdata; 2768910d8051SJoonyoung Shim data->irq = client->irq; 27697a53d609SNick Dyer i2c_set_clientdata(client, data); 2770910d8051SJoonyoung Shim 2771d79e7e47SBenson Leung init_completion(&data->bl_completion); 2772a4a2ef46SIiro Valkonen init_completion(&data->reset_completion); 2773c3f78043SNick Dyer init_completion(&data->crc_completion); 2774d79e7e47SBenson Leung 2775dd24dcf5SNick Dyer error = request_threaded_irq(client->irq, NULL, mxt_interrupt, 2776dd24dcf5SNick Dyer pdata->irqflags | IRQF_ONESHOT, 2777dd24dcf5SNick Dyer client->name, data); 2778dd24dcf5SNick Dyer if (error) { 2779dd24dcf5SNick Dyer dev_err(&client->dev, "Failed to register interrupt\n"); 2780dd24dcf5SNick Dyer goto err_free_mem; 2781dd24dcf5SNick Dyer } 2782dd24dcf5SNick Dyer 2783dd24dcf5SNick Dyer disable_irq(client->irq); 2784dd24dcf5SNick Dyer 2785cb159115SDaniel Kurtz error = mxt_initialize(data); 2786cb159115SDaniel Kurtz if (error) 27877a53d609SNick Dyer goto err_free_irq; 27884cf51c38SJoonyoung Shim 27897686b108SIiro Valkonen error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); 27907bed6805SNick Dyer if (error) { 27917bed6805SNick Dyer dev_err(&client->dev, "Failure %d creating sysfs group\n", 27927bed6805SNick Dyer error); 27937a53d609SNick Dyer goto err_free_object; 27947bed6805SNick Dyer } 27954cf51c38SJoonyoung Shim 27964cf51c38SJoonyoung Shim return 0; 27974cf51c38SJoonyoung Shim 27984cf51c38SJoonyoung Shim err_free_object: 279958e4aeeeSStephen Warren mxt_free_input_device(data); 28005f3f9bc2SNick Dyer mxt_free_object_table(data); 2801dd24dcf5SNick Dyer err_free_irq: 2802dd24dcf5SNick Dyer free_irq(client->irq, data); 28034cf51c38SJoonyoung Shim err_free_mem: 28044cf51c38SJoonyoung Shim kfree(data); 28054cf51c38SJoonyoung Shim return error; 28064cf51c38SJoonyoung Shim } 28074cf51c38SJoonyoung Shim 2808e2619cf7SBill Pemberton static int mxt_remove(struct i2c_client *client) 28094cf51c38SJoonyoung Shim { 28107686b108SIiro Valkonen struct mxt_data *data = i2c_get_clientdata(client); 28114cf51c38SJoonyoung Shim 28127686b108SIiro Valkonen sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); 28134cf51c38SJoonyoung Shim free_irq(data->irq, data); 281458e4aeeeSStephen Warren mxt_free_input_device(data); 28155f3f9bc2SNick Dyer mxt_free_object_table(data); 28164cf51c38SJoonyoung Shim kfree(data); 28174cf51c38SJoonyoung Shim 28184cf51c38SJoonyoung Shim return 0; 28194cf51c38SJoonyoung Shim } 28204cf51c38SJoonyoung Shim 282102b6a58bSJingoo Han static int __maybe_unused mxt_suspend(struct device *dev) 28224cf51c38SJoonyoung Shim { 28238b5fce06SDmitry Torokhov struct i2c_client *client = to_i2c_client(dev); 28247686b108SIiro Valkonen struct mxt_data *data = i2c_get_clientdata(client); 28254cf51c38SJoonyoung Shim struct input_dev *input_dev = data->input_dev; 28264cf51c38SJoonyoung Shim 282750fabb02SPan Xinhui if (!input_dev) 282850fabb02SPan Xinhui return 0; 282950fabb02SPan Xinhui 28304cf51c38SJoonyoung Shim mutex_lock(&input_dev->mutex); 28314cf51c38SJoonyoung Shim 28324cf51c38SJoonyoung Shim if (input_dev->users) 28337686b108SIiro Valkonen mxt_stop(data); 28344cf51c38SJoonyoung Shim 28354cf51c38SJoonyoung Shim mutex_unlock(&input_dev->mutex); 28364cf51c38SJoonyoung Shim 28374cf51c38SJoonyoung Shim return 0; 28384cf51c38SJoonyoung Shim } 28394cf51c38SJoonyoung Shim 284002b6a58bSJingoo Han static int __maybe_unused mxt_resume(struct device *dev) 28414cf51c38SJoonyoung Shim { 28428b5fce06SDmitry Torokhov struct i2c_client *client = to_i2c_client(dev); 28437686b108SIiro Valkonen struct mxt_data *data = i2c_get_clientdata(client); 28444cf51c38SJoonyoung Shim struct input_dev *input_dev = data->input_dev; 28454cf51c38SJoonyoung Shim 284650fabb02SPan Xinhui if (!input_dev) 284750fabb02SPan Xinhui return 0; 284850fabb02SPan Xinhui 28494cf51c38SJoonyoung Shim mutex_lock(&input_dev->mutex); 28504cf51c38SJoonyoung Shim 28514cf51c38SJoonyoung Shim if (input_dev->users) 28527686b108SIiro Valkonen mxt_start(data); 28534cf51c38SJoonyoung Shim 28544cf51c38SJoonyoung Shim mutex_unlock(&input_dev->mutex); 28554cf51c38SJoonyoung Shim 28564cf51c38SJoonyoung Shim return 0; 28574cf51c38SJoonyoung Shim } 28584cf51c38SJoonyoung Shim 28593a73c816SDaniel Kurtz static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume); 28603a73c816SDaniel Kurtz 286178188be3SStephen Warren static const struct of_device_id mxt_of_match[] = { 286278188be3SStephen Warren { .compatible = "atmel,maxtouch", }, 286378188be3SStephen Warren {}, 286478188be3SStephen Warren }; 286578188be3SStephen Warren MODULE_DEVICE_TABLE(of, mxt_of_match); 286678188be3SStephen Warren 28674f8d8088SDmitry Torokhov #ifdef CONFIG_ACPI 28684f8d8088SDmitry Torokhov static const struct acpi_device_id mxt_acpi_id[] = { 28694f8d8088SDmitry Torokhov { "ATML0000", 0 }, /* Touchpad */ 28704f8d8088SDmitry Torokhov { "ATML0001", 0 }, /* Touchscreen */ 28714f8d8088SDmitry Torokhov { } 28724f8d8088SDmitry Torokhov }; 28734f8d8088SDmitry Torokhov MODULE_DEVICE_TABLE(acpi, mxt_acpi_id); 28744f8d8088SDmitry Torokhov #endif 28754f8d8088SDmitry Torokhov 28767686b108SIiro Valkonen static const struct i2c_device_id mxt_id[] = { 28774cf51c38SJoonyoung Shim { "qt602240_ts", 0 }, 28787686b108SIiro Valkonen { "atmel_mxt_ts", 0 }, 287922dfab7fSDaniel Kurtz { "atmel_mxt_tp", 0 }, 2880b7d21058SJavier Martinez Canillas { "maxtouch", 0 }, 288146ee2a05SChris Leech { "mXT224", 0 }, 28824cf51c38SJoonyoung Shim { } 28834cf51c38SJoonyoung Shim }; 28847686b108SIiro Valkonen MODULE_DEVICE_TABLE(i2c, mxt_id); 28854cf51c38SJoonyoung Shim 28867686b108SIiro Valkonen static struct i2c_driver mxt_driver = { 28874cf51c38SJoonyoung Shim .driver = { 28887686b108SIiro Valkonen .name = "atmel_mxt_ts", 288978188be3SStephen Warren .of_match_table = of_match_ptr(mxt_of_match), 28904f8d8088SDmitry Torokhov .acpi_match_table = ACPI_PTR(mxt_acpi_id), 28917686b108SIiro Valkonen .pm = &mxt_pm_ops, 28924cf51c38SJoonyoung Shim }, 28937686b108SIiro Valkonen .probe = mxt_probe, 28941cb0aa88SBill Pemberton .remove = mxt_remove, 28957686b108SIiro Valkonen .id_table = mxt_id, 28964cf51c38SJoonyoung Shim }; 28974cf51c38SJoonyoung Shim 28981b92c1cfSAxel Lin module_i2c_driver(mxt_driver); 28994cf51c38SJoonyoung Shim 29004cf51c38SJoonyoung Shim /* Module information */ 29014cf51c38SJoonyoung Shim MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 29027686b108SIiro Valkonen MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver"); 29034cf51c38SJoonyoung Shim MODULE_LICENSE("GPL"); 2904