12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 24cf51c38SJoonyoung Shim /* 37686b108SIiro Valkonen * Atmel maXTouch Touchscreen driver 44cf51c38SJoonyoung Shim * 54cf51c38SJoonyoung Shim * Copyright (C) 2010 Samsung Electronics Co.Ltd 650a77c65SNick Dyer * Copyright (C) 2011-2014 Atmel Corporation 71e0c0c5bSDaniel Kurtz * Copyright (C) 2012 Google, Inc. 8f3c4a8f8SNick Dyer * Copyright (C) 2016 Zodiac Inflight Innovations 91e0c0c5bSDaniel Kurtz * 104cf51c38SJoonyoung Shim * Author: Joonyoung Shim <jy0922.shim@samsung.com> 114cf51c38SJoonyoung Shim */ 124cf51c38SJoonyoung Shim 134f8d8088SDmitry Torokhov #include <linux/acpi.h> 144f8d8088SDmitry Torokhov #include <linux/dmi.h> 154cf51c38SJoonyoung Shim #include <linux/module.h> 16d79e7e47SBenson Leung #include <linux/init.h> 17d79e7e47SBenson Leung #include <linux/completion.h> 184cf51c38SJoonyoung Shim #include <linux/delay.h> 194cf51c38SJoonyoung Shim #include <linux/firmware.h> 204cf51c38SJoonyoung Shim #include <linux/i2c.h> 218b86c1c2SJoonyoung Shim #include <linux/input/mt.h> 224cf51c38SJoonyoung Shim #include <linux/interrupt.h> 2374d905d2SNick Dyer #include <linux/irq.h> 2478188be3SStephen Warren #include <linux/of.h> 2596a938aaSDmitry Torokhov #include <linux/property.h> 264cf51c38SJoonyoung Shim #include <linux/slab.h> 27f657b00dSSebastian Reichel #include <linux/gpio/consumer.h> 28b23157dcSNick Dyer #include <asm/unaligned.h> 29ecfdd7e2SNick Dyer #include <media/v4l2-device.h> 30ecfdd7e2SNick Dyer #include <media/v4l2-ioctl.h> 31ecfdd7e2SNick Dyer #include <media/videobuf2-v4l2.h> 32ecfdd7e2SNick Dyer #include <media/videobuf2-vmalloc.h> 334cf51c38SJoonyoung Shim 3450a77c65SNick Dyer /* Firmware files */ 357686b108SIiro Valkonen #define MXT_FW_NAME "maxtouch.fw" 3650a77c65SNick Dyer #define MXT_CFG_NAME "maxtouch.cfg" 3750a77c65SNick Dyer #define MXT_CFG_MAGIC "OBP_RAW V1" 384cf51c38SJoonyoung Shim 394cf51c38SJoonyoung Shim /* Registers */ 407686b108SIiro Valkonen #define MXT_OBJECT_START 0x07 417686b108SIiro Valkonen #define MXT_OBJECT_SIZE 6 424ce6fa01SNick Dyer #define MXT_INFO_CHECKSUM_SIZE 3 434ce6fa01SNick Dyer #define MXT_MAX_BLOCK_WRITE 256 444cf51c38SJoonyoung Shim 454cf51c38SJoonyoung Shim /* Object types */ 4681c88a71SIiro Valkonen #define MXT_DEBUG_DIAGNOSTIC_T37 37 4781c88a71SIiro Valkonen #define MXT_GEN_MESSAGE_T5 5 4881c88a71SIiro Valkonen #define MXT_GEN_COMMAND_T6 6 4981c88a71SIiro Valkonen #define MXT_GEN_POWER_T7 7 5081c88a71SIiro Valkonen #define MXT_GEN_ACQUIRE_T8 8 5181c88a71SIiro Valkonen #define MXT_GEN_DATASOURCE_T53 53 5281c88a71SIiro Valkonen #define MXT_TOUCH_MULTI_T9 9 5381c88a71SIiro Valkonen #define MXT_TOUCH_KEYARRAY_T15 15 5481c88a71SIiro Valkonen #define MXT_TOUCH_PROXIMITY_T23 23 5581c88a71SIiro Valkonen #define MXT_TOUCH_PROXKEY_T52 52 5681c88a71SIiro Valkonen #define MXT_PROCI_GRIPFACE_T20 20 5781c88a71SIiro Valkonen #define MXT_PROCG_NOISE_T22 22 5881c88a71SIiro Valkonen #define MXT_PROCI_ONETOUCH_T24 24 5981c88a71SIiro Valkonen #define MXT_PROCI_TWOTOUCH_T27 27 6081c88a71SIiro Valkonen #define MXT_PROCI_GRIP_T40 40 6181c88a71SIiro Valkonen #define MXT_PROCI_PALM_T41 41 6281c88a71SIiro Valkonen #define MXT_PROCI_TOUCHSUPPRESSION_T42 42 6381c88a71SIiro Valkonen #define MXT_PROCI_STYLUS_T47 47 6481c88a71SIiro Valkonen #define MXT_PROCG_NOISESUPPRESSION_T48 48 6581c88a71SIiro Valkonen #define MXT_SPT_COMMSCONFIG_T18 18 6681c88a71SIiro Valkonen #define MXT_SPT_GPIOPWM_T19 19 6781c88a71SIiro Valkonen #define MXT_SPT_SELFTEST_T25 25 6881c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T28 28 6981c88a71SIiro Valkonen #define MXT_SPT_USERDATA_T38 38 7081c88a71SIiro Valkonen #define MXT_SPT_DIGITIZER_T43 43 7181c88a71SIiro Valkonen #define MXT_SPT_MESSAGECOUNT_T44 44 7281c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T46 46 7315082bdbSNick Dyer #define MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71 71 74b23157dcSNick Dyer #define MXT_TOUCH_MULTITOUCHSCREEN_T100 100 754cf51c38SJoonyoung Shim 765f3f9bc2SNick Dyer /* MXT_GEN_MESSAGE_T5 object */ 775f3f9bc2SNick Dyer #define MXT_RPTID_NOMSG 0xff 785f3f9bc2SNick Dyer 7981c88a71SIiro Valkonen /* MXT_GEN_COMMAND_T6 field */ 807686b108SIiro Valkonen #define MXT_COMMAND_RESET 0 817686b108SIiro Valkonen #define MXT_COMMAND_BACKUPNV 1 827686b108SIiro Valkonen #define MXT_COMMAND_CALIBRATE 2 837686b108SIiro Valkonen #define MXT_COMMAND_REPORTALL 3 847686b108SIiro Valkonen #define MXT_COMMAND_DIAGNOSTIC 5 854cf51c38SJoonyoung Shim 86a4a2ef46SIiro Valkonen /* Define for T6 status byte */ 87204b4eaeSNick Dyer #define MXT_T6_STATUS_RESET BIT(7) 88204b4eaeSNick Dyer #define MXT_T6_STATUS_OFL BIT(6) 89204b4eaeSNick Dyer #define MXT_T6_STATUS_SIGERR BIT(5) 90204b4eaeSNick Dyer #define MXT_T6_STATUS_CAL BIT(4) 91204b4eaeSNick Dyer #define MXT_T6_STATUS_CFGERR BIT(3) 92204b4eaeSNick Dyer #define MXT_T6_STATUS_COMSERR BIT(2) 93a4a2ef46SIiro Valkonen 9481c88a71SIiro Valkonen /* MXT_GEN_POWER_T7 field */ 957f3884f7SNick Dyer struct t7_config { 967f3884f7SNick Dyer u8 idle; 977f3884f7SNick Dyer u8 active; 987f3884f7SNick Dyer } __packed; 997f3884f7SNick Dyer 1007f3884f7SNick Dyer #define MXT_POWER_CFG_RUN 0 1017f3884f7SNick Dyer #define MXT_POWER_CFG_DEEPSLEEP 1 1024cf51c38SJoonyoung Shim 10381c88a71SIiro Valkonen /* MXT_TOUCH_MULTI_T9 field */ 1047f3884f7SNick Dyer #define MXT_T9_CTRL 0 1052786489fSNick Dyer #define MXT_T9_XSIZE 3 1062786489fSNick Dyer #define MXT_T9_YSIZE 4 10761dc1abaSNick Dyer #define MXT_T9_ORIENT 9 10861dc1abaSNick Dyer #define MXT_T9_RANGE 18 10961dc1abaSNick Dyer 110f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 status */ 111204b4eaeSNick Dyer #define MXT_T9_UNGRIP BIT(0) 112204b4eaeSNick Dyer #define MXT_T9_SUPPRESS BIT(1) 113204b4eaeSNick Dyer #define MXT_T9_AMP BIT(2) 114204b4eaeSNick Dyer #define MXT_T9_VECTOR BIT(3) 115204b4eaeSNick Dyer #define MXT_T9_MOVE BIT(4) 116204b4eaeSNick Dyer #define MXT_T9_RELEASE BIT(5) 117204b4eaeSNick Dyer #define MXT_T9_PRESS BIT(6) 118204b4eaeSNick Dyer #define MXT_T9_DETECT BIT(7) 119f3889ed1SNick Dyer 12061dc1abaSNick Dyer struct t9_range { 1211c0276d5SNick Dyer __le16 x; 1221c0276d5SNick Dyer __le16 y; 12361dc1abaSNick Dyer } __packed; 12461dc1abaSNick Dyer 125f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 orient */ 126204b4eaeSNick Dyer #define MXT_T9_ORIENT_SWITCH BIT(0) 127204b4eaeSNick Dyer #define MXT_T9_ORIENT_INVERTX BIT(1) 128204b4eaeSNick Dyer #define MXT_T9_ORIENT_INVERTY BIT(2) 1294cf51c38SJoonyoung Shim 13081c88a71SIiro Valkonen /* MXT_SPT_COMMSCONFIG_T18 */ 1317686b108SIiro Valkonen #define MXT_COMMS_CTRL 0 1327686b108SIiro Valkonen #define MXT_COMMS_CMD 1 13374d905d2SNick Dyer #define MXT_COMMS_RETRIGEN BIT(6) 1344cf51c38SJoonyoung Shim 135d6a39404SNick Dyer /* MXT_DEBUG_DIAGNOSTIC_T37 */ 136d6a39404SNick Dyer #define MXT_DIAGNOSTIC_PAGEUP 0x01 137d6a39404SNick Dyer #define MXT_DIAGNOSTIC_DELTAS 0x10 13806b3d3f3SNick Dyer #define MXT_DIAGNOSTIC_REFS 0x11 139d6a39404SNick Dyer #define MXT_DIAGNOSTIC_SIZE 128 140d6a39404SNick Dyer 141566d533aSNick Dyer #define MXT_FAMILY_1386 160 142566d533aSNick Dyer #define MXT1386_COLUMNS 3 143566d533aSNick Dyer #define MXT1386_PAGES_PER_COLUMN 8 144566d533aSNick Dyer 145d6a39404SNick Dyer struct t37_debug { 146d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 147d6a39404SNick Dyer u8 mode; 148d6a39404SNick Dyer u8 page; 149d6a39404SNick Dyer u8 data[MXT_DIAGNOSTIC_SIZE]; 150d6a39404SNick Dyer #endif 151d6a39404SNick Dyer }; 152d6a39404SNick Dyer 15381c88a71SIiro Valkonen /* Define for MXT_GEN_COMMAND_T6 */ 1547686b108SIiro Valkonen #define MXT_BOOT_VALUE 0xa5 155a4a2ef46SIiro Valkonen #define MXT_RESET_VALUE 0x01 1567686b108SIiro Valkonen #define MXT_BACKUP_VALUE 0x55 157a4a2ef46SIiro Valkonen 158b23157dcSNick Dyer /* T100 Multiple Touch Touchscreen */ 159b23157dcSNick Dyer #define MXT_T100_CTRL 0 160b23157dcSNick Dyer #define MXT_T100_CFG1 1 161b23157dcSNick Dyer #define MXT_T100_TCHAUX 3 1622786489fSNick Dyer #define MXT_T100_XSIZE 9 163b23157dcSNick Dyer #define MXT_T100_XRANGE 13 1642786489fSNick Dyer #define MXT_T100_YSIZE 20 165b23157dcSNick Dyer #define MXT_T100_YRANGE 24 166b23157dcSNick Dyer 167b23157dcSNick Dyer #define MXT_T100_CFG_SWITCHXY BIT(5) 168de601f71SNick Dyer #define MXT_T100_CFG_INVERTY BIT(6) 169de601f71SNick Dyer #define MXT_T100_CFG_INVERTX BIT(7) 170b23157dcSNick Dyer 171b23157dcSNick Dyer #define MXT_T100_TCHAUX_VECT BIT(0) 172b23157dcSNick Dyer #define MXT_T100_TCHAUX_AMPL BIT(1) 173b23157dcSNick Dyer #define MXT_T100_TCHAUX_AREA BIT(2) 174b23157dcSNick Dyer 175b23157dcSNick Dyer #define MXT_T100_DETECT BIT(7) 176b23157dcSNick Dyer #define MXT_T100_TYPE_MASK 0x70 177b23157dcSNick Dyer 178b23157dcSNick Dyer enum t100_type { 179b23157dcSNick Dyer MXT_T100_TYPE_FINGER = 1, 180b23157dcSNick Dyer MXT_T100_TYPE_PASSIVE_STYLUS = 2, 181b23157dcSNick Dyer MXT_T100_TYPE_HOVERING_FINGER = 4, 182b23157dcSNick Dyer MXT_T100_TYPE_GLOVE = 5, 183b23157dcSNick Dyer MXT_T100_TYPE_LARGE_TOUCH = 6, 184b23157dcSNick Dyer }; 185b23157dcSNick Dyer 186b23157dcSNick Dyer #define MXT_DISTANCE_ACTIVE_TOUCH 0 187b23157dcSNick Dyer #define MXT_DISTANCE_HOVERING 1 188b23157dcSNick Dyer 189b23157dcSNick Dyer #define MXT_TOUCH_MAJOR_DEFAULT 1 190b23157dcSNick Dyer #define MXT_PRESSURE_DEFAULT 1 191b23157dcSNick Dyer 192a4a2ef46SIiro Valkonen /* Delay times */ 1938343bce1SLinus Torvalds #define MXT_BACKUP_TIME 50 /* msec */ 194ca1cd36cSSebastian Reichel #define MXT_RESET_GPIO_TIME 20 /* msec */ 195ca1cd36cSSebastian Reichel #define MXT_RESET_INVALID_CHG 100 /* msec */ 1968343bce1SLinus Torvalds #define MXT_RESET_TIME 200 /* msec */ 197a4a2ef46SIiro Valkonen #define MXT_RESET_TIMEOUT 3000 /* msec */ 198c3f78043SNick Dyer #define MXT_CRC_TIMEOUT 1000 /* msec */ 199a0434b75SBenson Leung #define MXT_FW_RESET_TIME 3000 /* msec */ 200a0434b75SBenson Leung #define MXT_FW_CHG_TIMEOUT 300 /* msec */ 2014cf51c38SJoonyoung Shim 2024cf51c38SJoonyoung Shim /* Command to unlock bootloader */ 2037686b108SIiro Valkonen #define MXT_UNLOCK_CMD_MSB 0xaa 2047686b108SIiro Valkonen #define MXT_UNLOCK_CMD_LSB 0xdc 2054cf51c38SJoonyoung Shim 2064cf51c38SJoonyoung Shim /* Bootloader mode status */ 2077686b108SIiro Valkonen #define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ 2087686b108SIiro Valkonen #define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ 2097686b108SIiro Valkonen #define MXT_FRAME_CRC_CHECK 0x02 2107686b108SIiro Valkonen #define MXT_FRAME_CRC_FAIL 0x03 2117686b108SIiro Valkonen #define MXT_FRAME_CRC_PASS 0x04 2127686b108SIiro Valkonen #define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ 2137686b108SIiro Valkonen #define MXT_BOOT_STATUS_MASK 0x3f 214204b4eaeSNick Dyer #define MXT_BOOT_EXTENDED_ID BIT(5) 215e57a66aaSNick Dyer #define MXT_BOOT_ID_MASK 0x1f 2164cf51c38SJoonyoung Shim 2174cf51c38SJoonyoung Shim /* Touchscreen absolute values */ 2187686b108SIiro Valkonen #define MXT_MAX_AREA 0xff 2194cf51c38SJoonyoung Shim 22022dfab7fSDaniel Kurtz #define MXT_PIXELS_PER_MM 20 22122dfab7fSDaniel Kurtz 2227686b108SIiro Valkonen struct mxt_info { 2234cf51c38SJoonyoung Shim u8 family_id; 2244cf51c38SJoonyoung Shim u8 variant_id; 2254cf51c38SJoonyoung Shim u8 version; 2264cf51c38SJoonyoung Shim u8 build; 2274cf51c38SJoonyoung Shim u8 matrix_xsize; 2284cf51c38SJoonyoung Shim u8 matrix_ysize; 2294cf51c38SJoonyoung Shim u8 object_num; 2304cf51c38SJoonyoung Shim }; 2314cf51c38SJoonyoung Shim 2327686b108SIiro Valkonen struct mxt_object { 2334cf51c38SJoonyoung Shim u8 type; 2344cf51c38SJoonyoung Shim u16 start_address; 2351e0c0c5bSDaniel Kurtz u8 size_minus_one; 2361e0c0c5bSDaniel Kurtz u8 instances_minus_one; 2374cf51c38SJoonyoung Shim u8 num_report_ids; 238333e5a9aSDaniel Kurtz } __packed; 2394cf51c38SJoonyoung Shim 240d6a39404SNick Dyer struct mxt_dbg { 241d6a39404SNick Dyer u16 t37_address; 242d6a39404SNick Dyer u16 diag_cmd_address; 243d6a39404SNick Dyer struct t37_debug *t37_buf; 244d6a39404SNick Dyer unsigned int t37_pages; 245d6a39404SNick Dyer unsigned int t37_nodes; 246ecfdd7e2SNick Dyer 247ecfdd7e2SNick Dyer struct v4l2_device v4l2; 248ecfdd7e2SNick Dyer struct v4l2_pix_format format; 249ecfdd7e2SNick Dyer struct video_device vdev; 250ecfdd7e2SNick Dyer struct vb2_queue queue; 251ecfdd7e2SNick Dyer struct mutex lock; 252ecfdd7e2SNick Dyer int input; 253ecfdd7e2SNick Dyer }; 254ecfdd7e2SNick Dyer 25506b3d3f3SNick Dyer enum v4l_dbg_inputs { 25606b3d3f3SNick Dyer MXT_V4L_INPUT_DELTAS, 25706b3d3f3SNick Dyer MXT_V4L_INPUT_REFS, 25806b3d3f3SNick Dyer MXT_V4L_INPUT_MAX, 25906b3d3f3SNick Dyer }; 26006b3d3f3SNick Dyer 26196a938aaSDmitry Torokhov enum mxt_suspend_mode { 26296a938aaSDmitry Torokhov MXT_SUSPEND_DEEP_SLEEP = 0, 26396a938aaSDmitry Torokhov MXT_SUSPEND_T9_CTRL = 1, 26496a938aaSDmitry Torokhov }; 26596a938aaSDmitry Torokhov 266f865df73SNick Dyer /* Config update context */ 267f865df73SNick Dyer struct mxt_cfg { 268a4891f10SNick Dyer u8 *raw; 269f865df73SNick Dyer size_t raw_size; 270f865df73SNick Dyer off_t raw_pos; 271f865df73SNick Dyer 272f865df73SNick Dyer u8 *mem; 273f865df73SNick Dyer size_t mem_size; 274f865df73SNick Dyer int start_ofs; 275f865df73SNick Dyer 276f865df73SNick Dyer struct mxt_info info; 277f865df73SNick Dyer }; 278f865df73SNick Dyer 2794cf51c38SJoonyoung Shim /* Each client has this additional data */ 2807686b108SIiro Valkonen struct mxt_data { 2814cf51c38SJoonyoung Shim struct i2c_client *client; 2824cf51c38SJoonyoung Shim struct input_dev *input_dev; 283ec02ac2bSDaniel Kurtz char phys[64]; /* device physical location */ 2847686b108SIiro Valkonen struct mxt_object *object_table; 285068bdb67SNick Dyer struct mxt_info *info; 286068bdb67SNick Dyer void *raw_info_block; 2874cf51c38SJoonyoung Shim unsigned int irq; 288910d8051SJoonyoung Shim unsigned int max_x; 289910d8051SJoonyoung Shim unsigned int max_y; 290de601f71SNick Dyer bool invertx; 291de601f71SNick Dyer bool inverty; 2921c0276d5SNick Dyer bool xy_switch; 2932786489fSNick Dyer u8 xsize; 2942786489fSNick Dyer u8 ysize; 295d79e7e47SBenson Leung bool in_bootloader; 2964ce6fa01SNick Dyer u16 mem_size; 297b23157dcSNick Dyer u8 t100_aux_ampl; 298b23157dcSNick Dyer u8 t100_aux_area; 299b23157dcSNick Dyer u8 t100_aux_vect; 3009d8dc3e5SNick Dyer u8 max_reportid; 301c3f78043SNick Dyer u32 config_crc; 3024ce6fa01SNick Dyer u32 info_crc; 303f28a842dSNick Dyer u8 bootloader_addr; 3045f3f9bc2SNick Dyer u8 *msg_buf; 305497767d1SNick Dyer u8 t6_status; 306b9b05a89SNick Dyer bool update_input; 3079d8dc3e5SNick Dyer u8 last_message_count; 3089d8dc3e5SNick Dyer u8 num_touchids; 309b23157dcSNick Dyer u8 multitouch; 3107f3884f7SNick Dyer struct t7_config t7_cfg; 311d6a39404SNick Dyer struct mxt_dbg dbg; 312f657b00dSSebastian Reichel struct gpio_desc *reset_gpio; 31374d905d2SNick Dyer bool use_retrigen_workaround; 314333e5a9aSDaniel Kurtz 315333e5a9aSDaniel Kurtz /* Cached parameters from object table */ 316b9b05a89SNick Dyer u16 T5_address; 3175f3f9bc2SNick Dyer u8 T5_msg_size; 318fdf80421SDaniel Kurtz u8 T6_reportid; 319a4a2ef46SIiro Valkonen u16 T6_address; 3204ce6fa01SNick Dyer u16 T7_address; 32115082bdbSNick Dyer u16 T71_address; 322333e5a9aSDaniel Kurtz u8 T9_reportid_min; 323333e5a9aSDaniel Kurtz u8 T9_reportid_max; 32474d905d2SNick Dyer u16 T18_address; 32522dfab7fSDaniel Kurtz u8 T19_reportid; 3269d8dc3e5SNick Dyer u16 T44_address; 327b23157dcSNick Dyer u8 T100_reportid_min; 328b23157dcSNick Dyer u8 T100_reportid_max; 329d79e7e47SBenson Leung 330d79e7e47SBenson Leung /* for fw update in bootloader */ 331d79e7e47SBenson Leung struct completion bl_completion; 332a4a2ef46SIiro Valkonen 333a4a2ef46SIiro Valkonen /* for reset handling */ 334a4a2ef46SIiro Valkonen struct completion reset_completion; 335c3f78043SNick Dyer 336c3f78043SNick Dyer /* for config update handling */ 337c3f78043SNick Dyer struct completion crc_completion; 338d80808e1SDmitry Torokhov 33996a938aaSDmitry Torokhov u32 *t19_keymap; 34096a938aaSDmitry Torokhov unsigned int t19_num_keys; 34196a938aaSDmitry Torokhov 342d80808e1SDmitry Torokhov enum mxt_suspend_mode suspend_mode; 3434cf51c38SJoonyoung Shim }; 3444cf51c38SJoonyoung Shim 345ecfdd7e2SNick Dyer struct mxt_vb2_buffer { 346ecfdd7e2SNick Dyer struct vb2_buffer vb; 347ecfdd7e2SNick Dyer struct list_head list; 348ecfdd7e2SNick Dyer }; 349ecfdd7e2SNick Dyer 3501e0c0c5bSDaniel Kurtz static size_t mxt_obj_size(const struct mxt_object *obj) 3511e0c0c5bSDaniel Kurtz { 3521e0c0c5bSDaniel Kurtz return obj->size_minus_one + 1; 3531e0c0c5bSDaniel Kurtz } 3541e0c0c5bSDaniel Kurtz 3551e0c0c5bSDaniel Kurtz static size_t mxt_obj_instances(const struct mxt_object *obj) 3561e0c0c5bSDaniel Kurtz { 3571e0c0c5bSDaniel Kurtz return obj->instances_minus_one + 1; 3581e0c0c5bSDaniel Kurtz } 3591e0c0c5bSDaniel Kurtz 3607686b108SIiro Valkonen static bool mxt_object_readable(unsigned int type) 3614cf51c38SJoonyoung Shim { 3624cf51c38SJoonyoung Shim switch (type) { 36381c88a71SIiro Valkonen case MXT_GEN_COMMAND_T6: 36481c88a71SIiro Valkonen case MXT_GEN_POWER_T7: 36581c88a71SIiro Valkonen case MXT_GEN_ACQUIRE_T8: 36681c88a71SIiro Valkonen case MXT_GEN_DATASOURCE_T53: 36781c88a71SIiro Valkonen case MXT_TOUCH_MULTI_T9: 36881c88a71SIiro Valkonen case MXT_TOUCH_KEYARRAY_T15: 36981c88a71SIiro Valkonen case MXT_TOUCH_PROXIMITY_T23: 37081c88a71SIiro Valkonen case MXT_TOUCH_PROXKEY_T52: 371089b50d9SMaxime Roussin-Bélanger case MXT_TOUCH_MULTITOUCHSCREEN_T100: 37281c88a71SIiro Valkonen case MXT_PROCI_GRIPFACE_T20: 37381c88a71SIiro Valkonen case MXT_PROCG_NOISE_T22: 37481c88a71SIiro Valkonen case MXT_PROCI_ONETOUCH_T24: 37581c88a71SIiro Valkonen case MXT_PROCI_TWOTOUCH_T27: 37681c88a71SIiro Valkonen case MXT_PROCI_GRIP_T40: 37781c88a71SIiro Valkonen case MXT_PROCI_PALM_T41: 37881c88a71SIiro Valkonen case MXT_PROCI_TOUCHSUPPRESSION_T42: 37981c88a71SIiro Valkonen case MXT_PROCI_STYLUS_T47: 38081c88a71SIiro Valkonen case MXT_PROCG_NOISESUPPRESSION_T48: 38181c88a71SIiro Valkonen case MXT_SPT_COMMSCONFIG_T18: 38281c88a71SIiro Valkonen case MXT_SPT_GPIOPWM_T19: 38381c88a71SIiro Valkonen case MXT_SPT_SELFTEST_T25: 38481c88a71SIiro Valkonen case MXT_SPT_CTECONFIG_T28: 38581c88a71SIiro Valkonen case MXT_SPT_USERDATA_T38: 38681c88a71SIiro Valkonen case MXT_SPT_DIGITIZER_T43: 38781c88a71SIiro Valkonen case MXT_SPT_CTECONFIG_T46: 38815082bdbSNick Dyer case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71: 3894cf51c38SJoonyoung Shim return true; 3904cf51c38SJoonyoung Shim default: 3914cf51c38SJoonyoung Shim return false; 3924cf51c38SJoonyoung Shim } 3934cf51c38SJoonyoung Shim } 3944cf51c38SJoonyoung Shim 3955f3f9bc2SNick Dyer static void mxt_dump_message(struct mxt_data *data, u8 *message) 3964cf51c38SJoonyoung Shim { 3975f3f9bc2SNick Dyer dev_dbg(&data->client->dev, "message: %*ph\n", 3985f3f9bc2SNick Dyer data->T5_msg_size, message); 3994cf51c38SJoonyoung Shim } 4004cf51c38SJoonyoung Shim 401a4a2ef46SIiro Valkonen static int mxt_wait_for_completion(struct mxt_data *data, 402a4a2ef46SIiro Valkonen struct completion *comp, 403a4a2ef46SIiro Valkonen unsigned int timeout_ms) 4044cf51c38SJoonyoung Shim { 405d79e7e47SBenson Leung struct device *dev = &data->client->dev; 406d79e7e47SBenson Leung unsigned long timeout = msecs_to_jiffies(timeout_ms); 407d79e7e47SBenson Leung long ret; 408d79e7e47SBenson Leung 409d79e7e47SBenson Leung ret = wait_for_completion_interruptible_timeout(comp, timeout); 410d79e7e47SBenson Leung if (ret < 0) { 411d79e7e47SBenson Leung return ret; 412d79e7e47SBenson Leung } else if (ret == 0) { 413d79e7e47SBenson Leung dev_err(dev, "Wait for completion timed out.\n"); 414d79e7e47SBenson Leung return -ETIMEDOUT; 415d79e7e47SBenson Leung } 416d79e7e47SBenson Leung return 0; 417d79e7e47SBenson Leung } 418d79e7e47SBenson Leung 419f28a842dSNick Dyer static int mxt_bootloader_read(struct mxt_data *data, 420f28a842dSNick Dyer u8 *val, unsigned int count) 421f28a842dSNick Dyer { 422f28a842dSNick Dyer int ret; 423f28a842dSNick Dyer struct i2c_msg msg; 424f28a842dSNick Dyer 425f28a842dSNick Dyer msg.addr = data->bootloader_addr; 426f28a842dSNick Dyer msg.flags = data->client->flags & I2C_M_TEN; 427f28a842dSNick Dyer msg.flags |= I2C_M_RD; 428f28a842dSNick Dyer msg.len = count; 429f28a842dSNick Dyer msg.buf = val; 430f28a842dSNick Dyer 431f28a842dSNick Dyer ret = i2c_transfer(data->client->adapter, &msg, 1); 432f28a842dSNick Dyer if (ret == 1) { 433f28a842dSNick Dyer ret = 0; 434f28a842dSNick Dyer } else { 435f28a842dSNick Dyer ret = ret < 0 ? ret : -EIO; 436f28a842dSNick Dyer dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n", 437f28a842dSNick Dyer __func__, ret); 438f28a842dSNick Dyer } 439f28a842dSNick Dyer 440f28a842dSNick Dyer return ret; 441f28a842dSNick Dyer } 442f28a842dSNick Dyer 443f28a842dSNick Dyer static int mxt_bootloader_write(struct mxt_data *data, 444f28a842dSNick Dyer const u8 * const val, unsigned int count) 445f28a842dSNick Dyer { 446f28a842dSNick Dyer int ret; 447f28a842dSNick Dyer struct i2c_msg msg; 448f28a842dSNick Dyer 449f28a842dSNick Dyer msg.addr = data->bootloader_addr; 450f28a842dSNick Dyer msg.flags = data->client->flags & I2C_M_TEN; 451f28a842dSNick Dyer msg.len = count; 452f28a842dSNick Dyer msg.buf = (u8 *)val; 453f28a842dSNick Dyer 454f28a842dSNick Dyer ret = i2c_transfer(data->client->adapter, &msg, 1); 455f28a842dSNick Dyer if (ret == 1) { 456f28a842dSNick Dyer ret = 0; 457f28a842dSNick Dyer } else { 458f28a842dSNick Dyer ret = ret < 0 ? ret : -EIO; 459f28a842dSNick Dyer dev_err(&data->client->dev, "%s: i2c send failed (%d)\n", 460f28a842dSNick Dyer __func__, ret); 461f28a842dSNick Dyer } 462f28a842dSNick Dyer 463f28a842dSNick Dyer return ret; 464f28a842dSNick Dyer } 465f28a842dSNick Dyer 4668efaa5e5SNick Dyer static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry) 467f28a842dSNick Dyer { 468f28a842dSNick Dyer u8 appmode = data->client->addr; 469f28a842dSNick Dyer u8 bootloader; 470068bdb67SNick Dyer u8 family_id = data->info ? data->info->family_id : 0; 471f28a842dSNick Dyer 472f28a842dSNick Dyer switch (appmode) { 473f28a842dSNick Dyer case 0x4a: 474f28a842dSNick Dyer case 0x4b: 47544a0bab2SNick Dyer /* Chips after 1664S use different scheme */ 476068bdb67SNick Dyer if (retry || family_id >= 0xa2) { 47744a0bab2SNick Dyer bootloader = appmode - 0x24; 47844a0bab2SNick Dyer break; 47944a0bab2SNick Dyer } 480*df561f66SGustavo A. R. Silva fallthrough; /* for normal case */ 481f28a842dSNick Dyer case 0x4c: 482f28a842dSNick Dyer case 0x4d: 483f28a842dSNick Dyer case 0x5a: 484f28a842dSNick Dyer case 0x5b: 485f28a842dSNick Dyer bootloader = appmode - 0x26; 486f28a842dSNick Dyer break; 4876cd1ab0fSDmitry Torokhov 488f28a842dSNick Dyer default: 489f28a842dSNick Dyer dev_err(&data->client->dev, 490f28a842dSNick Dyer "Appmode i2c address 0x%02x not found\n", 491f28a842dSNick Dyer appmode); 492f28a842dSNick Dyer return -EINVAL; 493f28a842dSNick Dyer } 494f28a842dSNick Dyer 495f28a842dSNick Dyer data->bootloader_addr = bootloader; 496f28a842dSNick Dyer return 0; 497f28a842dSNick Dyer } 498f28a842dSNick Dyer 4996cd1ab0fSDmitry Torokhov static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address) 500a9fdd1e6SNick Dyer { 501a9fdd1e6SNick Dyer struct device *dev = &data->client->dev; 5026cd1ab0fSDmitry Torokhov int error; 503a9fdd1e6SNick Dyer u8 val; 504a9fdd1e6SNick Dyer bool crc_failure; 505a9fdd1e6SNick Dyer 5066cd1ab0fSDmitry Torokhov error = mxt_lookup_bootloader_address(data, alt_address); 5076cd1ab0fSDmitry Torokhov if (error) 5086cd1ab0fSDmitry Torokhov return error; 509a9fdd1e6SNick Dyer 5106cd1ab0fSDmitry Torokhov error = mxt_bootloader_read(data, &val, 1); 5116cd1ab0fSDmitry Torokhov if (error) 5126cd1ab0fSDmitry Torokhov return error; 513a9fdd1e6SNick Dyer 514a9fdd1e6SNick Dyer /* Check app crc fail mode */ 515a9fdd1e6SNick Dyer crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL; 516a9fdd1e6SNick Dyer 517a9fdd1e6SNick Dyer dev_err(dev, "Detected bootloader, status:%02X%s\n", 518a9fdd1e6SNick Dyer val, crc_failure ? ", APP_CRC_FAIL" : ""); 519a9fdd1e6SNick Dyer 520a9fdd1e6SNick Dyer return 0; 521a9fdd1e6SNick Dyer } 522a9fdd1e6SNick Dyer 523e57a66aaSNick Dyer static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val) 524e57a66aaSNick Dyer { 525e57a66aaSNick Dyer struct device *dev = &data->client->dev; 526e57a66aaSNick Dyer u8 buf[3]; 527e57a66aaSNick Dyer 528e57a66aaSNick Dyer if (val & MXT_BOOT_EXTENDED_ID) { 529e57a66aaSNick Dyer if (mxt_bootloader_read(data, &buf[0], 3) != 0) { 530e57a66aaSNick Dyer dev_err(dev, "%s: i2c failure\n", __func__); 53168807a0cSNick Dyer return val; 532e57a66aaSNick Dyer } 533e57a66aaSNick Dyer 534e57a66aaSNick Dyer dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]); 535e57a66aaSNick Dyer 536e57a66aaSNick Dyer return buf[0]; 537e57a66aaSNick Dyer } else { 538e57a66aaSNick Dyer dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK); 539e57a66aaSNick Dyer 540e57a66aaSNick Dyer return val; 541e57a66aaSNick Dyer } 542e57a66aaSNick Dyer } 543e57a66aaSNick Dyer 544385deb96SNick Dyer static int mxt_check_bootloader(struct mxt_data *data, unsigned int state, 545385deb96SNick Dyer bool wait) 546d79e7e47SBenson Leung { 547f28a842dSNick Dyer struct device *dev = &data->client->dev; 5484cf51c38SJoonyoung Shim u8 val; 549d79e7e47SBenson Leung int ret; 5504cf51c38SJoonyoung Shim 5514cf51c38SJoonyoung Shim recheck: 552385deb96SNick Dyer if (wait) { 553d79e7e47SBenson Leung /* 554d79e7e47SBenson Leung * In application update mode, the interrupt 555d79e7e47SBenson Leung * line signals state transitions. We must wait for the 556d79e7e47SBenson Leung * CHG assertion before reading the status byte. 557d79e7e47SBenson Leung * Once the status byte has been read, the line is deasserted. 558d79e7e47SBenson Leung */ 559a4a2ef46SIiro Valkonen ret = mxt_wait_for_completion(data, &data->bl_completion, 560a4a2ef46SIiro Valkonen MXT_FW_CHG_TIMEOUT); 561d79e7e47SBenson Leung if (ret) { 562d79e7e47SBenson Leung /* 563d79e7e47SBenson Leung * TODO: handle -ERESTARTSYS better by terminating 564d79e7e47SBenson Leung * fw update process before returning to userspace 565d79e7e47SBenson Leung * by writing length 0x000 to device (iff we are in 566d79e7e47SBenson Leung * WAITING_FRAME_DATA state). 567d79e7e47SBenson Leung */ 568f28a842dSNick Dyer dev_err(dev, "Update wait error %d\n", ret); 569d79e7e47SBenson Leung return ret; 570d79e7e47SBenson Leung } 571d79e7e47SBenson Leung } 572d79e7e47SBenson Leung 573f28a842dSNick Dyer ret = mxt_bootloader_read(data, &val, 1); 574f28a842dSNick Dyer if (ret) 575f28a842dSNick Dyer return ret; 5764cf51c38SJoonyoung Shim 577e57a66aaSNick Dyer if (state == MXT_WAITING_BOOTLOAD_CMD) 578e57a66aaSNick Dyer val = mxt_get_bootloader_version(data, val); 579e57a66aaSNick Dyer 5804cf51c38SJoonyoung Shim switch (state) { 5817686b108SIiro Valkonen case MXT_WAITING_BOOTLOAD_CMD: 5827686b108SIiro Valkonen case MXT_WAITING_FRAME_DATA: 583a9fdd1e6SNick Dyer case MXT_APP_CRC_FAIL: 5847686b108SIiro Valkonen val &= ~MXT_BOOT_STATUS_MASK; 5854cf51c38SJoonyoung Shim break; 5867686b108SIiro Valkonen case MXT_FRAME_CRC_PASS: 587f943c74aSNick Dyer if (val == MXT_FRAME_CRC_CHECK) { 5884cf51c38SJoonyoung Shim goto recheck; 589f943c74aSNick Dyer } else if (val == MXT_FRAME_CRC_FAIL) { 590f943c74aSNick Dyer dev_err(dev, "Bootloader CRC fail\n"); 591f943c74aSNick Dyer return -EINVAL; 592f943c74aSNick Dyer } 5934cf51c38SJoonyoung Shim break; 5944cf51c38SJoonyoung Shim default: 5954cf51c38SJoonyoung Shim return -EINVAL; 5964cf51c38SJoonyoung Shim } 5974cf51c38SJoonyoung Shim 5984cf51c38SJoonyoung Shim if (val != state) { 599f28a842dSNick Dyer dev_err(dev, "Invalid bootloader state %02X != %02X\n", 6007bed6805SNick Dyer val, state); 6014cf51c38SJoonyoung Shim return -EINVAL; 6024cf51c38SJoonyoung Shim } 6034cf51c38SJoonyoung Shim 6044cf51c38SJoonyoung Shim return 0; 6054cf51c38SJoonyoung Shim } 6064cf51c38SJoonyoung Shim 6078efaa5e5SNick Dyer static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock) 6084cf51c38SJoonyoung Shim { 609f28a842dSNick Dyer int ret; 6104cf51c38SJoonyoung Shim u8 buf[2]; 6114cf51c38SJoonyoung Shim 6128efaa5e5SNick Dyer if (unlock) { 6137686b108SIiro Valkonen buf[0] = MXT_UNLOCK_CMD_LSB; 6147686b108SIiro Valkonen buf[1] = MXT_UNLOCK_CMD_MSB; 6158efaa5e5SNick Dyer } else { 6168efaa5e5SNick Dyer buf[0] = 0x01; 6178efaa5e5SNick Dyer buf[1] = 0x01; 6188efaa5e5SNick Dyer } 6194cf51c38SJoonyoung Shim 620f28a842dSNick Dyer ret = mxt_bootloader_write(data, buf, 2); 621f28a842dSNick Dyer if (ret) 622f28a842dSNick Dyer return ret; 6234cf51c38SJoonyoung Shim 6244cf51c38SJoonyoung Shim return 0; 6254cf51c38SJoonyoung Shim } 6264cf51c38SJoonyoung Shim 6277686b108SIiro Valkonen static int __mxt_read_reg(struct i2c_client *client, 6284cf51c38SJoonyoung Shim u16 reg, u16 len, void *val) 6294cf51c38SJoonyoung Shim { 6304cf51c38SJoonyoung Shim struct i2c_msg xfer[2]; 6314cf51c38SJoonyoung Shim u8 buf[2]; 632771733e3SDaniel Kurtz int ret; 6334cf51c38SJoonyoung Shim 6344cf51c38SJoonyoung Shim buf[0] = reg & 0xff; 6354cf51c38SJoonyoung Shim buf[1] = (reg >> 8) & 0xff; 6364cf51c38SJoonyoung Shim 6374cf51c38SJoonyoung Shim /* Write register */ 6384cf51c38SJoonyoung Shim xfer[0].addr = client->addr; 6394cf51c38SJoonyoung Shim xfer[0].flags = 0; 6404cf51c38SJoonyoung Shim xfer[0].len = 2; 6414cf51c38SJoonyoung Shim xfer[0].buf = buf; 6424cf51c38SJoonyoung Shim 6434cf51c38SJoonyoung Shim /* Read data */ 6444cf51c38SJoonyoung Shim xfer[1].addr = client->addr; 6454cf51c38SJoonyoung Shim xfer[1].flags = I2C_M_RD; 6464cf51c38SJoonyoung Shim xfer[1].len = len; 6474cf51c38SJoonyoung Shim xfer[1].buf = val; 6484cf51c38SJoonyoung Shim 649771733e3SDaniel Kurtz ret = i2c_transfer(client->adapter, xfer, 2); 650771733e3SDaniel Kurtz if (ret == 2) { 651771733e3SDaniel Kurtz ret = 0; 652771733e3SDaniel Kurtz } else { 653771733e3SDaniel Kurtz if (ret >= 0) 654771733e3SDaniel Kurtz ret = -EIO; 655771733e3SDaniel Kurtz dev_err(&client->dev, "%s: i2c transfer failed (%d)\n", 656771733e3SDaniel Kurtz __func__, ret); 6574cf51c38SJoonyoung Shim } 6584cf51c38SJoonyoung Shim 659771733e3SDaniel Kurtz return ret; 6604cf51c38SJoonyoung Shim } 6614cf51c38SJoonyoung Shim 6629638ab7cSDaniel Kurtz static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len, 6639638ab7cSDaniel Kurtz const void *val) 6644cf51c38SJoonyoung Shim { 6659638ab7cSDaniel Kurtz u8 *buf; 6669638ab7cSDaniel Kurtz size_t count; 667771733e3SDaniel Kurtz int ret; 6684cf51c38SJoonyoung Shim 6699638ab7cSDaniel Kurtz count = len + 2; 6709638ab7cSDaniel Kurtz buf = kmalloc(count, GFP_KERNEL); 6719638ab7cSDaniel Kurtz if (!buf) 6729638ab7cSDaniel Kurtz return -ENOMEM; 6734cf51c38SJoonyoung Shim 6744cf51c38SJoonyoung Shim buf[0] = reg & 0xff; 6754cf51c38SJoonyoung Shim buf[1] = (reg >> 8) & 0xff; 6769638ab7cSDaniel Kurtz memcpy(&buf[2], val, len); 6774cf51c38SJoonyoung Shim 6789638ab7cSDaniel Kurtz ret = i2c_master_send(client, buf, count); 6799638ab7cSDaniel Kurtz if (ret == count) { 680771733e3SDaniel Kurtz ret = 0; 681771733e3SDaniel Kurtz } else { 682771733e3SDaniel Kurtz if (ret >= 0) 683771733e3SDaniel Kurtz ret = -EIO; 684771733e3SDaniel Kurtz dev_err(&client->dev, "%s: i2c send failed (%d)\n", 685771733e3SDaniel Kurtz __func__, ret); 6864cf51c38SJoonyoung Shim } 6874cf51c38SJoonyoung Shim 6889638ab7cSDaniel Kurtz kfree(buf); 689771733e3SDaniel Kurtz return ret; 6904cf51c38SJoonyoung Shim } 6914cf51c38SJoonyoung Shim 6929638ab7cSDaniel Kurtz static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) 6934cf51c38SJoonyoung Shim { 6949638ab7cSDaniel Kurtz return __mxt_write_reg(client, reg, 1, &val); 6954cf51c38SJoonyoung Shim } 6964cf51c38SJoonyoung Shim 6977686b108SIiro Valkonen static struct mxt_object * 6987686b108SIiro Valkonen mxt_get_object(struct mxt_data *data, u8 type) 6994cf51c38SJoonyoung Shim { 7007686b108SIiro Valkonen struct mxt_object *object; 7014cf51c38SJoonyoung Shim int i; 7024cf51c38SJoonyoung Shim 703068bdb67SNick Dyer for (i = 0; i < data->info->object_num; i++) { 7044cf51c38SJoonyoung Shim object = data->object_table + i; 7054cf51c38SJoonyoung Shim if (object->type == type) 7064cf51c38SJoonyoung Shim return object; 7074cf51c38SJoonyoung Shim } 7084cf51c38SJoonyoung Shim 70950a77c65SNick Dyer dev_warn(&data->client->dev, "Invalid object type T%u\n", type); 7104cf51c38SJoonyoung Shim return NULL; 7114cf51c38SJoonyoung Shim } 7124cf51c38SJoonyoung Shim 713497767d1SNick Dyer static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg) 714497767d1SNick Dyer { 715497767d1SNick Dyer struct device *dev = &data->client->dev; 716497767d1SNick Dyer u8 status = msg[1]; 717497767d1SNick Dyer u32 crc = msg[2] | (msg[3] << 8) | (msg[4] << 16); 718497767d1SNick Dyer 719497767d1SNick Dyer if (crc != data->config_crc) { 720497767d1SNick Dyer data->config_crc = crc; 721497767d1SNick Dyer dev_dbg(dev, "T6 Config Checksum: 0x%06X\n", crc); 722497767d1SNick Dyer } 723497767d1SNick Dyer 72419a7121eSNick Dyer complete(&data->crc_completion); 72519a7121eSNick Dyer 726497767d1SNick Dyer /* Detect reset */ 727497767d1SNick Dyer if (status & MXT_T6_STATUS_RESET) 728497767d1SNick Dyer complete(&data->reset_completion); 729497767d1SNick Dyer 730497767d1SNick Dyer /* Output debug if status has changed */ 731497767d1SNick Dyer if (status != data->t6_status) 732497767d1SNick Dyer dev_dbg(dev, "T6 Status 0x%02X%s%s%s%s%s%s%s\n", 733497767d1SNick Dyer status, 734497767d1SNick Dyer status == 0 ? " OK" : "", 735497767d1SNick Dyer status & MXT_T6_STATUS_RESET ? " RESET" : "", 736497767d1SNick Dyer status & MXT_T6_STATUS_OFL ? " OFL" : "", 737497767d1SNick Dyer status & MXT_T6_STATUS_SIGERR ? " SIGERR" : "", 738497767d1SNick Dyer status & MXT_T6_STATUS_CAL ? " CAL" : "", 739497767d1SNick Dyer status & MXT_T6_STATUS_CFGERR ? " CFGERR" : "", 740497767d1SNick Dyer status & MXT_T6_STATUS_COMSERR ? " COMSERR" : ""); 741497767d1SNick Dyer 742497767d1SNick Dyer /* Save current status */ 743497767d1SNick Dyer data->t6_status = status; 744497767d1SNick Dyer } 745497767d1SNick Dyer 7467f405483SLinus Torvalds static int mxt_write_object(struct mxt_data *data, 7477f405483SLinus Torvalds u8 type, u8 offset, u8 val) 7487f405483SLinus Torvalds { 7497f405483SLinus Torvalds struct mxt_object *object; 7507f405483SLinus Torvalds u16 reg; 7517f405483SLinus Torvalds 7527f405483SLinus Torvalds object = mxt_get_object(data, type); 7537f405483SLinus Torvalds if (!object || offset >= mxt_obj_size(object)) 7547f405483SLinus Torvalds return -EINVAL; 7557f405483SLinus Torvalds 7567f405483SLinus Torvalds reg = object->start_address; 7577f405483SLinus Torvalds return mxt_write_reg(data->client, reg + offset, val); 7587f405483SLinus Torvalds } 7597f405483SLinus Torvalds 7605f3f9bc2SNick Dyer static void mxt_input_button(struct mxt_data *data, u8 *message) 76122dfab7fSDaniel Kurtz { 76222dfab7fSDaniel Kurtz struct input_dev *input = data->input_dev; 76322dfab7fSDaniel Kurtz int i; 76422dfab7fSDaniel Kurtz 76596a938aaSDmitry Torokhov for (i = 0; i < data->t19_num_keys; i++) { 76696a938aaSDmitry Torokhov if (data->t19_keymap[i] == KEY_RESERVED) 76722dfab7fSDaniel Kurtz continue; 768c37f6d38SDmitry Torokhov 769c37f6d38SDmitry Torokhov /* Active-low switch */ 77096a938aaSDmitry Torokhov input_report_key(input, data->t19_keymap[i], 771c37f6d38SDmitry Torokhov !(message[1] & BIT(i))); 77222dfab7fSDaniel Kurtz } 77322dfab7fSDaniel Kurtz } 77422dfab7fSDaniel Kurtz 775b735fbe0SBenson Leung static void mxt_input_sync(struct mxt_data *data) 776eef820dcSNick Dyer { 777b735fbe0SBenson Leung input_mt_report_pointer_emulation(data->input_dev, 77896a938aaSDmitry Torokhov data->t19_num_keys); 779b735fbe0SBenson Leung input_sync(data->input_dev); 780eef820dcSNick Dyer } 781eef820dcSNick Dyer 782b9b05a89SNick Dyer static void mxt_proc_t9_message(struct mxt_data *data, u8 *message) 7834cf51c38SJoonyoung Shim { 7844cf51c38SJoonyoung Shim struct device *dev = &data->client->dev; 785fba5bc31SDaniel Kurtz struct input_dev *input_dev = data->input_dev; 7865f3f9bc2SNick Dyer int id; 7875f3f9bc2SNick Dyer u8 status; 7884cf51c38SJoonyoung Shim int x; 7894cf51c38SJoonyoung Shim int y; 7904cf51c38SJoonyoung Shim int area; 791fea9e467SNick Dyer int amplitude; 7924cf51c38SJoonyoung Shim 7935f3f9bc2SNick Dyer id = message[0] - data->T9_reportid_min; 7945f3f9bc2SNick Dyer status = message[1]; 7955f3f9bc2SNick Dyer x = (message[2] << 4) | ((message[4] >> 4) & 0xf); 7965f3f9bc2SNick Dyer y = (message[3] << 4) | ((message[4] & 0xf)); 797eef820dcSNick Dyer 798eef820dcSNick Dyer /* Handle 10/12 bit switching */ 799910d8051SJoonyoung Shim if (data->max_x < 1024) 800eef820dcSNick Dyer x >>= 2; 801910d8051SJoonyoung Shim if (data->max_y < 1024) 802eef820dcSNick Dyer y >>= 2; 803910d8051SJoonyoung Shim 8045f3f9bc2SNick Dyer area = message[5]; 8055f3f9bc2SNick Dyer amplitude = message[6]; 8064cf51c38SJoonyoung Shim 807b2e459b8SDaniel Kurtz dev_dbg(dev, 808b2e459b8SDaniel Kurtz "[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n", 809b2e459b8SDaniel Kurtz id, 810f3889ed1SNick Dyer (status & MXT_T9_DETECT) ? 'D' : '.', 811f3889ed1SNick Dyer (status & MXT_T9_PRESS) ? 'P' : '.', 812f3889ed1SNick Dyer (status & MXT_T9_RELEASE) ? 'R' : '.', 813f3889ed1SNick Dyer (status & MXT_T9_MOVE) ? 'M' : '.', 814f3889ed1SNick Dyer (status & MXT_T9_VECTOR) ? 'V' : '.', 815f3889ed1SNick Dyer (status & MXT_T9_AMP) ? 'A' : '.', 816f3889ed1SNick Dyer (status & MXT_T9_SUPPRESS) ? 'S' : '.', 817f3889ed1SNick Dyer (status & MXT_T9_UNGRIP) ? 'U' : '.', 818fea9e467SNick Dyer x, y, area, amplitude); 8194cf51c38SJoonyoung Shim 820fba5bc31SDaniel Kurtz input_mt_slot(input_dev, id); 8214cf51c38SJoonyoung Shim 822f3889ed1SNick Dyer if (status & MXT_T9_DETECT) { 823eef820dcSNick Dyer /* 824eef820dcSNick Dyer * Multiple bits may be set if the host is slow to read 825eef820dcSNick Dyer * the status messages, indicating all the events that 826eef820dcSNick Dyer * have happened. 827eef820dcSNick Dyer */ 828eef820dcSNick Dyer if (status & MXT_T9_RELEASE) { 8295fc70e35SJiada Wang input_mt_report_slot_inactive(input_dev); 830b735fbe0SBenson Leung mxt_input_sync(data); 831eef820dcSNick Dyer } 832eef820dcSNick Dyer 8332ca3ba0aSNick Dyer /* if active, pressure must be non-zero */ 8342ca3ba0aSNick Dyer if (!amplitude) 8352ca3ba0aSNick Dyer amplitude = MXT_PRESSURE_DEFAULT; 8362ca3ba0aSNick Dyer 837eef820dcSNick Dyer /* Touch active */ 838eef820dcSNick Dyer input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1); 839fba5bc31SDaniel Kurtz input_report_abs(input_dev, ABS_MT_POSITION_X, x); 840fba5bc31SDaniel Kurtz input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 841fea9e467SNick Dyer input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude); 842fba5bc31SDaniel Kurtz input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); 843eef820dcSNick Dyer } else { 844eef820dcSNick Dyer /* Touch no longer active, close out slot */ 8455fc70e35SJiada Wang input_mt_report_slot_inactive(input_dev); 846fba5bc31SDaniel Kurtz } 847b9b05a89SNick Dyer 848b9b05a89SNick Dyer data->update_input = true; 8494cf51c38SJoonyoung Shim } 8504cf51c38SJoonyoung Shim 851b23157dcSNick Dyer static void mxt_proc_t100_message(struct mxt_data *data, u8 *message) 852b23157dcSNick Dyer { 853b23157dcSNick Dyer struct device *dev = &data->client->dev; 854b23157dcSNick Dyer struct input_dev *input_dev = data->input_dev; 855b23157dcSNick Dyer int id; 856b23157dcSNick Dyer u8 status; 857b23157dcSNick Dyer u8 type = 0; 858b23157dcSNick Dyer u16 x; 859b23157dcSNick Dyer u16 y; 860b23157dcSNick Dyer int distance = 0; 861b23157dcSNick Dyer int tool = 0; 862b23157dcSNick Dyer u8 major = 0; 863b23157dcSNick Dyer u8 pressure = 0; 864b23157dcSNick Dyer u8 orientation = 0; 865b23157dcSNick Dyer 866b23157dcSNick Dyer id = message[0] - data->T100_reportid_min - 2; 867b23157dcSNick Dyer 868b23157dcSNick Dyer /* ignore SCRSTATUS events */ 869b23157dcSNick Dyer if (id < 0) 870b23157dcSNick Dyer return; 871b23157dcSNick Dyer 872b23157dcSNick Dyer status = message[1]; 873b23157dcSNick Dyer x = get_unaligned_le16(&message[2]); 874b23157dcSNick Dyer y = get_unaligned_le16(&message[4]); 875b23157dcSNick Dyer 876b23157dcSNick Dyer if (status & MXT_T100_DETECT) { 877b23157dcSNick Dyer type = (status & MXT_T100_TYPE_MASK) >> 4; 878b23157dcSNick Dyer 879b23157dcSNick Dyer switch (type) { 880b23157dcSNick Dyer case MXT_T100_TYPE_HOVERING_FINGER: 881b23157dcSNick Dyer tool = MT_TOOL_FINGER; 882b23157dcSNick Dyer distance = MXT_DISTANCE_HOVERING; 883b23157dcSNick Dyer 884b23157dcSNick Dyer if (data->t100_aux_vect) 885b23157dcSNick Dyer orientation = message[data->t100_aux_vect]; 886b23157dcSNick Dyer 887b23157dcSNick Dyer break; 888b23157dcSNick Dyer 889b23157dcSNick Dyer case MXT_T100_TYPE_FINGER: 890b23157dcSNick Dyer case MXT_T100_TYPE_GLOVE: 891b23157dcSNick Dyer tool = MT_TOOL_FINGER; 892b23157dcSNick Dyer distance = MXT_DISTANCE_ACTIVE_TOUCH; 893b23157dcSNick Dyer 894b23157dcSNick Dyer if (data->t100_aux_area) 895b23157dcSNick Dyer major = message[data->t100_aux_area]; 896b23157dcSNick Dyer 897b23157dcSNick Dyer if (data->t100_aux_ampl) 898b23157dcSNick Dyer pressure = message[data->t100_aux_ampl]; 899b23157dcSNick Dyer 900b23157dcSNick Dyer if (data->t100_aux_vect) 901b23157dcSNick Dyer orientation = message[data->t100_aux_vect]; 902b23157dcSNick Dyer 903b23157dcSNick Dyer break; 904b23157dcSNick Dyer 905b23157dcSNick Dyer case MXT_T100_TYPE_PASSIVE_STYLUS: 906b23157dcSNick Dyer tool = MT_TOOL_PEN; 907b23157dcSNick Dyer 908b23157dcSNick Dyer /* 909b23157dcSNick Dyer * Passive stylus is reported with size zero so 910b23157dcSNick Dyer * hardcode. 911b23157dcSNick Dyer */ 912b23157dcSNick Dyer major = MXT_TOUCH_MAJOR_DEFAULT; 913b23157dcSNick Dyer 914b23157dcSNick Dyer if (data->t100_aux_ampl) 915b23157dcSNick Dyer pressure = message[data->t100_aux_ampl]; 916b23157dcSNick Dyer 917b23157dcSNick Dyer break; 918b23157dcSNick Dyer 919b23157dcSNick Dyer case MXT_T100_TYPE_LARGE_TOUCH: 920b23157dcSNick Dyer /* Ignore suppressed touch */ 921b23157dcSNick Dyer break; 922b23157dcSNick Dyer 923b23157dcSNick Dyer default: 924b23157dcSNick Dyer dev_dbg(dev, "Unexpected T100 type\n"); 925b23157dcSNick Dyer return; 926b23157dcSNick Dyer } 927b23157dcSNick Dyer } 928b23157dcSNick Dyer 929b23157dcSNick Dyer /* 930b23157dcSNick Dyer * Values reported should be non-zero if tool is touching the 931b23157dcSNick Dyer * device 932b23157dcSNick Dyer */ 933b23157dcSNick Dyer if (!pressure && type != MXT_T100_TYPE_HOVERING_FINGER) 934b23157dcSNick Dyer pressure = MXT_PRESSURE_DEFAULT; 935b23157dcSNick Dyer 936b23157dcSNick Dyer input_mt_slot(input_dev, id); 937b23157dcSNick Dyer 938b23157dcSNick Dyer if (status & MXT_T100_DETECT) { 939b23157dcSNick Dyer dev_dbg(dev, "[%u] type:%u x:%u y:%u a:%02X p:%02X v:%02X\n", 940b23157dcSNick Dyer id, type, x, y, major, pressure, orientation); 941b23157dcSNick Dyer 942b23157dcSNick Dyer input_mt_report_slot_state(input_dev, tool, 1); 943b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_POSITION_X, x); 944b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 945b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major); 946b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); 947b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_DISTANCE, distance); 948b23157dcSNick Dyer input_report_abs(input_dev, ABS_MT_ORIENTATION, orientation); 949b23157dcSNick Dyer } else { 950b23157dcSNick Dyer dev_dbg(dev, "[%u] release\n", id); 951b23157dcSNick Dyer 952b23157dcSNick Dyer /* close out slot */ 9535fc70e35SJiada Wang input_mt_report_slot_inactive(input_dev); 954b23157dcSNick Dyer } 955b23157dcSNick Dyer 956b23157dcSNick Dyer data->update_input = true; 957b23157dcSNick Dyer } 958b23157dcSNick Dyer 959b9b05a89SNick Dyer static int mxt_proc_message(struct mxt_data *data, u8 *message) 96004a79181SDaniel Kurtz { 961b9b05a89SNick Dyer u8 report_id = message[0]; 962b9b05a89SNick Dyer 963b9b05a89SNick Dyer if (report_id == MXT_RPTID_NOMSG) 964b9b05a89SNick Dyer return 0; 965b9b05a89SNick Dyer 966b9b05a89SNick Dyer if (report_id == data->T6_reportid) { 967b9b05a89SNick Dyer mxt_proc_t6_messages(data, message); 968b9b05a89SNick Dyer } else if (!data->input_dev) { 969b9b05a89SNick Dyer /* 970b9b05a89SNick Dyer * Do not report events if input device 971b9b05a89SNick Dyer * is not yet registered. 972b9b05a89SNick Dyer */ 973b9b05a89SNick Dyer mxt_dump_message(data, message); 974b23157dcSNick Dyer } else if (report_id >= data->T9_reportid_min && 975b23157dcSNick Dyer report_id <= data->T9_reportid_max) { 976b9b05a89SNick Dyer mxt_proc_t9_message(data, message); 977b23157dcSNick Dyer } else if (report_id >= data->T100_reportid_min && 978b23157dcSNick Dyer report_id <= data->T100_reportid_max) { 979b23157dcSNick Dyer mxt_proc_t100_message(data, message); 980b9b05a89SNick Dyer } else if (report_id == data->T19_reportid) { 981b9b05a89SNick Dyer mxt_input_button(data, message); 982b9b05a89SNick Dyer data->update_input = true; 983b9b05a89SNick Dyer } else { 984b9b05a89SNick Dyer mxt_dump_message(data, message); 985b9b05a89SNick Dyer } 986b9b05a89SNick Dyer 987b9b05a89SNick Dyer return 1; 988b9b05a89SNick Dyer } 989b9b05a89SNick Dyer 9909d8dc3e5SNick Dyer static int mxt_read_and_process_messages(struct mxt_data *data, u8 count) 991b9b05a89SNick Dyer { 992b9b05a89SNick Dyer struct device *dev = &data->client->dev; 993b9b05a89SNick Dyer int ret; 9949d8dc3e5SNick Dyer int i; 9959d8dc3e5SNick Dyer u8 num_valid = 0; 996b9b05a89SNick Dyer 9979d8dc3e5SNick Dyer /* Safety check for msg_buf */ 9989d8dc3e5SNick Dyer if (count > data->max_reportid) 9999d8dc3e5SNick Dyer return -EINVAL; 10009d8dc3e5SNick Dyer 10019d8dc3e5SNick Dyer /* Process remaining messages if necessary */ 1002b9b05a89SNick Dyer ret = __mxt_read_reg(data->client, data->T5_address, 10039d8dc3e5SNick Dyer data->T5_msg_size * count, data->msg_buf); 1004b9b05a89SNick Dyer if (ret) { 10059d8dc3e5SNick Dyer dev_err(dev, "Failed to read %u messages (%d)\n", count, ret); 1006b9b05a89SNick Dyer return ret; 1007b9b05a89SNick Dyer } 1008b9b05a89SNick Dyer 10099d8dc3e5SNick Dyer for (i = 0; i < count; i++) { 10109d8dc3e5SNick Dyer ret = mxt_proc_message(data, 10119d8dc3e5SNick Dyer data->msg_buf + data->T5_msg_size * i); 10129d8dc3e5SNick Dyer 10139d8dc3e5SNick Dyer if (ret == 1) 10149d8dc3e5SNick Dyer num_valid++; 10154cf51c38SJoonyoung Shim } 10164cf51c38SJoonyoung Shim 10179d8dc3e5SNick Dyer /* return number of messages read */ 10189d8dc3e5SNick Dyer return num_valid; 10199d8dc3e5SNick Dyer } 10204cf51c38SJoonyoung Shim 10219d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages_t44(struct mxt_data *data) 10229d8dc3e5SNick Dyer { 10239d8dc3e5SNick Dyer struct device *dev = &data->client->dev; 10249d8dc3e5SNick Dyer int ret; 10259d8dc3e5SNick Dyer u8 count, num_left; 10269d8dc3e5SNick Dyer 10279d8dc3e5SNick Dyer /* Read T44 and T5 together */ 10289d8dc3e5SNick Dyer ret = __mxt_read_reg(data->client, data->T44_address, 10299d8dc3e5SNick Dyer data->T5_msg_size + 1, data->msg_buf); 10309d8dc3e5SNick Dyer if (ret) { 10319d8dc3e5SNick Dyer dev_err(dev, "Failed to read T44 and T5 (%d)\n", ret); 10328d4e1639SNick Dyer return IRQ_NONE; 10339d8dc3e5SNick Dyer } 10349d8dc3e5SNick Dyer 10359d8dc3e5SNick Dyer count = data->msg_buf[0]; 10369d8dc3e5SNick Dyer 1037651b4608SNick Dyer /* 1038507584e2SNick Dyer * This condition may be caused by the CHG line being configured in 1039507584e2SNick Dyer * Mode 0. It results in unnecessary I2C operations but it is benign. 1040651b4608SNick Dyer */ 1041507584e2SNick Dyer if (count == 0) 10429d8dc3e5SNick Dyer return IRQ_NONE; 1043507584e2SNick Dyer 1044507584e2SNick Dyer if (count > data->max_reportid) { 1045507584e2SNick Dyer dev_warn(dev, "T44 count %d exceeded max report id\n", count); 10469d8dc3e5SNick Dyer count = data->max_reportid; 10479d8dc3e5SNick Dyer } 10489d8dc3e5SNick Dyer 10499d8dc3e5SNick Dyer /* Process first message */ 10509d8dc3e5SNick Dyer ret = mxt_proc_message(data, data->msg_buf + 1); 10519d8dc3e5SNick Dyer if (ret < 0) { 10529d8dc3e5SNick Dyer dev_warn(dev, "Unexpected invalid message\n"); 10539d8dc3e5SNick Dyer return IRQ_NONE; 10549d8dc3e5SNick Dyer } 10559d8dc3e5SNick Dyer 10569d8dc3e5SNick Dyer num_left = count - 1; 10579d8dc3e5SNick Dyer 10589d8dc3e5SNick Dyer /* Process remaining messages if necessary */ 10599d8dc3e5SNick Dyer if (num_left) { 10609d8dc3e5SNick Dyer ret = mxt_read_and_process_messages(data, num_left); 10619d8dc3e5SNick Dyer if (ret < 0) 10629d8dc3e5SNick Dyer goto end; 10639d8dc3e5SNick Dyer else if (ret != num_left) 10649d8dc3e5SNick Dyer dev_warn(dev, "Unexpected invalid message\n"); 10659d8dc3e5SNick Dyer } 10669d8dc3e5SNick Dyer 10679d8dc3e5SNick Dyer end: 10689d8dc3e5SNick Dyer if (data->update_input) { 10699d8dc3e5SNick Dyer mxt_input_sync(data); 10709d8dc3e5SNick Dyer data->update_input = false; 10719d8dc3e5SNick Dyer } 10729d8dc3e5SNick Dyer 10739d8dc3e5SNick Dyer return IRQ_HANDLED; 10749d8dc3e5SNick Dyer } 10759d8dc3e5SNick Dyer 10769d8dc3e5SNick Dyer static int mxt_process_messages_until_invalid(struct mxt_data *data) 10779d8dc3e5SNick Dyer { 10789d8dc3e5SNick Dyer struct device *dev = &data->client->dev; 10799d8dc3e5SNick Dyer int count, read; 10809d8dc3e5SNick Dyer u8 tries = 2; 10819d8dc3e5SNick Dyer 10829d8dc3e5SNick Dyer count = data->max_reportid; 10839d8dc3e5SNick Dyer 10849d8dc3e5SNick Dyer /* Read messages until we force an invalid */ 10859d8dc3e5SNick Dyer do { 10869d8dc3e5SNick Dyer read = mxt_read_and_process_messages(data, count); 10879d8dc3e5SNick Dyer if (read < count) 10889d8dc3e5SNick Dyer return 0; 10899d8dc3e5SNick Dyer } while (--tries); 10909d8dc3e5SNick Dyer 10919d8dc3e5SNick Dyer if (data->update_input) { 10929d8dc3e5SNick Dyer mxt_input_sync(data); 10939d8dc3e5SNick Dyer data->update_input = false; 10949d8dc3e5SNick Dyer } 10959d8dc3e5SNick Dyer 10969d8dc3e5SNick Dyer dev_err(dev, "CHG pin isn't cleared\n"); 10979d8dc3e5SNick Dyer return -EBUSY; 10989d8dc3e5SNick Dyer } 10999d8dc3e5SNick Dyer 11009d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages(struct mxt_data *data) 11019d8dc3e5SNick Dyer { 11029d8dc3e5SNick Dyer int total_handled, num_handled; 11039d8dc3e5SNick Dyer u8 count = data->last_message_count; 11049d8dc3e5SNick Dyer 11059d8dc3e5SNick Dyer if (count < 1 || count > data->max_reportid) 11069d8dc3e5SNick Dyer count = 1; 11079d8dc3e5SNick Dyer 11089d8dc3e5SNick Dyer /* include final invalid message */ 11099d8dc3e5SNick Dyer total_handled = mxt_read_and_process_messages(data, count + 1); 11109d8dc3e5SNick Dyer if (total_handled < 0) 11119d8dc3e5SNick Dyer return IRQ_NONE; 11129d8dc3e5SNick Dyer /* if there were invalid messages, then we are done */ 11139d8dc3e5SNick Dyer else if (total_handled <= count) 11149d8dc3e5SNick Dyer goto update_count; 11159d8dc3e5SNick Dyer 11169d8dc3e5SNick Dyer /* keep reading two msgs until one is invalid or reportid limit */ 11179d8dc3e5SNick Dyer do { 11189d8dc3e5SNick Dyer num_handled = mxt_read_and_process_messages(data, 2); 11199d8dc3e5SNick Dyer if (num_handled < 0) 11209d8dc3e5SNick Dyer return IRQ_NONE; 11219d8dc3e5SNick Dyer 11229d8dc3e5SNick Dyer total_handled += num_handled; 11239d8dc3e5SNick Dyer 11249d8dc3e5SNick Dyer if (num_handled < 2) 11259d8dc3e5SNick Dyer break; 11269d8dc3e5SNick Dyer } while (total_handled < data->num_touchids); 11279d8dc3e5SNick Dyer 11289d8dc3e5SNick Dyer update_count: 11299d8dc3e5SNick Dyer data->last_message_count = total_handled; 11304cf51c38SJoonyoung Shim 1131b9b05a89SNick Dyer if (data->update_input) { 1132b735fbe0SBenson Leung mxt_input_sync(data); 1133b9b05a89SNick Dyer data->update_input = false; 1134b9b05a89SNick Dyer } 113564464ae8SDaniel Kurtz 11364cf51c38SJoonyoung Shim return IRQ_HANDLED; 11374cf51c38SJoonyoung Shim } 11384cf51c38SJoonyoung Shim 1139d79e7e47SBenson Leung static irqreturn_t mxt_interrupt(int irq, void *dev_id) 1140d79e7e47SBenson Leung { 1141d79e7e47SBenson Leung struct mxt_data *data = dev_id; 1142d79e7e47SBenson Leung 1143d79e7e47SBenson Leung if (data->in_bootloader) { 1144d79e7e47SBenson Leung /* bootloader state transition completion */ 1145d79e7e47SBenson Leung complete(&data->bl_completion); 1146d79e7e47SBenson Leung return IRQ_HANDLED; 1147d79e7e47SBenson Leung } 1148d79e7e47SBenson Leung 1149dd24dcf5SNick Dyer if (!data->object_table) 1150dd24dcf5SNick Dyer return IRQ_HANDLED; 1151dd24dcf5SNick Dyer 11529d8dc3e5SNick Dyer if (data->T44_address) { 11539d8dc3e5SNick Dyer return mxt_process_messages_t44(data); 11549d8dc3e5SNick Dyer } else { 11559d8dc3e5SNick Dyer return mxt_process_messages(data); 11569d8dc3e5SNick Dyer } 1157d79e7e47SBenson Leung } 1158d79e7e47SBenson Leung 1159a4a2ef46SIiro Valkonen static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, 1160a4a2ef46SIiro Valkonen u8 value, bool wait) 1161a4a2ef46SIiro Valkonen { 1162a4a2ef46SIiro Valkonen u16 reg; 1163a4a2ef46SIiro Valkonen u8 command_register; 1164a4a2ef46SIiro Valkonen int timeout_counter = 0; 1165a4a2ef46SIiro Valkonen int ret; 1166a4a2ef46SIiro Valkonen 1167a4a2ef46SIiro Valkonen reg = data->T6_address + cmd_offset; 1168a4a2ef46SIiro Valkonen 1169a4a2ef46SIiro Valkonen ret = mxt_write_reg(data->client, reg, value); 1170a4a2ef46SIiro Valkonen if (ret) 1171a4a2ef46SIiro Valkonen return ret; 1172a4a2ef46SIiro Valkonen 1173a4a2ef46SIiro Valkonen if (!wait) 1174a4a2ef46SIiro Valkonen return 0; 1175a4a2ef46SIiro Valkonen 1176a4a2ef46SIiro Valkonen do { 1177a4a2ef46SIiro Valkonen msleep(20); 1178a4a2ef46SIiro Valkonen ret = __mxt_read_reg(data->client, reg, 1, &command_register); 1179a4a2ef46SIiro Valkonen if (ret) 1180a4a2ef46SIiro Valkonen return ret; 1181a4a2ef46SIiro Valkonen } while (command_register != 0 && timeout_counter++ <= 100); 1182a4a2ef46SIiro Valkonen 1183a4a2ef46SIiro Valkonen if (timeout_counter > 100) { 1184a4a2ef46SIiro Valkonen dev_err(&data->client->dev, "Command failed!\n"); 1185a4a2ef46SIiro Valkonen return -EIO; 1186a4a2ef46SIiro Valkonen } 1187a4a2ef46SIiro Valkonen 1188a4a2ef46SIiro Valkonen return 0; 1189a4a2ef46SIiro Valkonen } 1190a4a2ef46SIiro Valkonen 1191eb43335cSNick Dyer static int mxt_acquire_irq(struct mxt_data *data) 1192eb43335cSNick Dyer { 1193eb43335cSNick Dyer int error; 1194eb43335cSNick Dyer 1195eb43335cSNick Dyer enable_irq(data->irq); 1196eb43335cSNick Dyer 119774d905d2SNick Dyer if (data->use_retrigen_workaround) { 1198eb43335cSNick Dyer error = mxt_process_messages_until_invalid(data); 1199eb43335cSNick Dyer if (error) 1200eb43335cSNick Dyer return error; 120174d905d2SNick Dyer } 1202eb43335cSNick Dyer 1203eb43335cSNick Dyer return 0; 1204eb43335cSNick Dyer } 1205eb43335cSNick Dyer 1206a4a2ef46SIiro Valkonen static int mxt_soft_reset(struct mxt_data *data) 1207a4a2ef46SIiro Valkonen { 1208a4a2ef46SIiro Valkonen struct device *dev = &data->client->dev; 1209a4a2ef46SIiro Valkonen int ret = 0; 1210a4a2ef46SIiro Valkonen 1211885f3fb9SNick Dyer dev_info(dev, "Resetting device\n"); 1212885f3fb9SNick Dyer 1213885f3fb9SNick Dyer disable_irq(data->irq); 1214a4a2ef46SIiro Valkonen 1215a4a2ef46SIiro Valkonen reinit_completion(&data->reset_completion); 1216a4a2ef46SIiro Valkonen 1217a4a2ef46SIiro Valkonen ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false); 1218a4a2ef46SIiro Valkonen if (ret) 1219a4a2ef46SIiro Valkonen return ret; 1220a4a2ef46SIiro Valkonen 1221885f3fb9SNick Dyer /* Ignore CHG line for 100ms after reset */ 1222ca1cd36cSSebastian Reichel msleep(MXT_RESET_INVALID_CHG); 1223885f3fb9SNick Dyer 1224eb43335cSNick Dyer mxt_acquire_irq(data); 1225885f3fb9SNick Dyer 1226a4a2ef46SIiro Valkonen ret = mxt_wait_for_completion(data, &data->reset_completion, 1227a4a2ef46SIiro Valkonen MXT_RESET_TIMEOUT); 1228a4a2ef46SIiro Valkonen if (ret) 1229a4a2ef46SIiro Valkonen return ret; 1230a4a2ef46SIiro Valkonen 1231a4a2ef46SIiro Valkonen return 0; 1232a4a2ef46SIiro Valkonen } 1233a4a2ef46SIiro Valkonen 1234c3f78043SNick Dyer static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value) 1235c3f78043SNick Dyer { 1236c3f78043SNick Dyer /* 1237c3f78043SNick Dyer * On failure, CRC is set to 0 and config will always be 1238c3f78043SNick Dyer * downloaded. 1239c3f78043SNick Dyer */ 1240c3f78043SNick Dyer data->config_crc = 0; 1241c3f78043SNick Dyer reinit_completion(&data->crc_completion); 1242c3f78043SNick Dyer 1243c3f78043SNick Dyer mxt_t6_command(data, cmd, value, true); 1244c3f78043SNick Dyer 1245c3f78043SNick Dyer /* 1246c3f78043SNick Dyer * Wait for crc message. On failure, CRC is set to 0 and config will 1247c3f78043SNick Dyer * always be downloaded. 1248c3f78043SNick Dyer */ 1249c3f78043SNick Dyer mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); 1250c3f78043SNick Dyer } 1251c3f78043SNick Dyer 12524ce6fa01SNick Dyer static void mxt_calc_crc24(u32 *crc, u8 firstbyte, u8 secondbyte) 12534ce6fa01SNick Dyer { 12544ce6fa01SNick Dyer static const unsigned int crcpoly = 0x80001B; 12554ce6fa01SNick Dyer u32 result; 12564ce6fa01SNick Dyer u32 data_word; 12574ce6fa01SNick Dyer 12584ce6fa01SNick Dyer data_word = (secondbyte << 8) | firstbyte; 12594ce6fa01SNick Dyer result = ((*crc << 1) ^ data_word); 12604ce6fa01SNick Dyer 12614ce6fa01SNick Dyer if (result & 0x1000000) 12624ce6fa01SNick Dyer result ^= crcpoly; 12634ce6fa01SNick Dyer 12644ce6fa01SNick Dyer *crc = result; 12654ce6fa01SNick Dyer } 12664ce6fa01SNick Dyer 12674ce6fa01SNick Dyer static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off) 12684ce6fa01SNick Dyer { 12694ce6fa01SNick Dyer u32 crc = 0; 12704ce6fa01SNick Dyer u8 *ptr = base + start_off; 12714ce6fa01SNick Dyer u8 *last_val = base + end_off - 1; 12724ce6fa01SNick Dyer 12734ce6fa01SNick Dyer if (end_off < start_off) 12744ce6fa01SNick Dyer return -EINVAL; 12754ce6fa01SNick Dyer 12764ce6fa01SNick Dyer while (ptr < last_val) { 12774ce6fa01SNick Dyer mxt_calc_crc24(&crc, *ptr, *(ptr + 1)); 12784ce6fa01SNick Dyer ptr += 2; 12794ce6fa01SNick Dyer } 12804ce6fa01SNick Dyer 12814ce6fa01SNick Dyer /* if len is odd, fill the last byte with 0 */ 12824ce6fa01SNick Dyer if (ptr == last_val) 12834ce6fa01SNick Dyer mxt_calc_crc24(&crc, *ptr, 0); 12844ce6fa01SNick Dyer 12854ce6fa01SNick Dyer /* Mask to 24-bit */ 12864ce6fa01SNick Dyer crc &= 0x00FFFFFF; 12874ce6fa01SNick Dyer 12884ce6fa01SNick Dyer return crc; 12894ce6fa01SNick Dyer } 12904ce6fa01SNick Dyer 129174d905d2SNick Dyer static int mxt_check_retrigen(struct mxt_data *data) 129274d905d2SNick Dyer { 129374d905d2SNick Dyer struct i2c_client *client = data->client; 129474d905d2SNick Dyer int error; 129574d905d2SNick Dyer int val; 129674d905d2SNick Dyer struct irq_data *irqd; 129774d905d2SNick Dyer 129874d905d2SNick Dyer data->use_retrigen_workaround = false; 129974d905d2SNick Dyer 130074d905d2SNick Dyer irqd = irq_get_irq_data(data->irq); 130174d905d2SNick Dyer if (!irqd) 130274d905d2SNick Dyer return -EINVAL; 130374d905d2SNick Dyer 130474d905d2SNick Dyer if (irqd_is_level_type(irqd)) 130574d905d2SNick Dyer return 0; 130674d905d2SNick Dyer 130774d905d2SNick Dyer if (data->T18_address) { 130874d905d2SNick Dyer error = __mxt_read_reg(client, 130974d905d2SNick Dyer data->T18_address + MXT_COMMS_CTRL, 131074d905d2SNick Dyer 1, &val); 131174d905d2SNick Dyer if (error) 131274d905d2SNick Dyer return error; 131374d905d2SNick Dyer 131474d905d2SNick Dyer if (val & MXT_COMMS_RETRIGEN) 131574d905d2SNick Dyer return 0; 131674d905d2SNick Dyer } 131774d905d2SNick Dyer 131874d905d2SNick Dyer dev_warn(&client->dev, "Enabling RETRIGEN workaround\n"); 131974d905d2SNick Dyer data->use_retrigen_workaround = true; 132074d905d2SNick Dyer return 0; 132174d905d2SNick Dyer } 132274d905d2SNick Dyer 1323f865df73SNick Dyer static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) 13244cf51c38SJoonyoung Shim { 13254cf51c38SJoonyoung Shim struct device *dev = &data->client->dev; 132650a77c65SNick Dyer struct mxt_object *object; 1327efdbd7aeSDmitry Torokhov unsigned int type, instance, size, byte_offset; 132850a77c65SNick Dyer int offset; 1329efdbd7aeSDmitry Torokhov int ret; 133050a77c65SNick Dyer int i; 133150a77c65SNick Dyer u16 reg; 1332efdbd7aeSDmitry Torokhov u8 val; 133350a77c65SNick Dyer 1334f865df73SNick Dyer while (cfg->raw_pos < cfg->raw_size) { 133550a77c65SNick Dyer /* Read type, instance, length */ 1336f865df73SNick Dyer ret = sscanf(cfg->raw + cfg->raw_pos, "%x %x %x%n", 133750a77c65SNick Dyer &type, &instance, &size, &offset); 133850a77c65SNick Dyer if (ret == 0) { 133950a77c65SNick Dyer /* EOF */ 13404ce6fa01SNick Dyer break; 134150a77c65SNick Dyer } else if (ret != 3) { 134250a77c65SNick Dyer dev_err(dev, "Bad format: failed to parse object\n"); 1343efdbd7aeSDmitry Torokhov return -EINVAL; 134450a77c65SNick Dyer } 1345f865df73SNick Dyer cfg->raw_pos += offset; 134650a77c65SNick Dyer 134750a77c65SNick Dyer object = mxt_get_object(data, type); 134850a77c65SNick Dyer if (!object) { 134950a77c65SNick Dyer /* Skip object */ 135050a77c65SNick Dyer for (i = 0; i < size; i++) { 1351f865df73SNick Dyer ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n", 1352041fa159SDmitry Torokhov &val, &offset); 1353041fa159SDmitry Torokhov if (ret != 1) { 1354041fa159SDmitry Torokhov dev_err(dev, "Bad format in T%d at %d\n", 1355041fa159SDmitry Torokhov type, i); 1356041fa159SDmitry Torokhov return -EINVAL; 1357041fa159SDmitry Torokhov } 1358f865df73SNick Dyer cfg->raw_pos += offset; 135950a77c65SNick Dyer } 136050a77c65SNick Dyer continue; 136150a77c65SNick Dyer } 136250a77c65SNick Dyer 136350a77c65SNick Dyer if (size > mxt_obj_size(object)) { 13644ce6fa01SNick Dyer /* 13654ce6fa01SNick Dyer * Either we are in fallback mode due to wrong 13664ce6fa01SNick Dyer * config or config from a later fw version, 13674ce6fa01SNick Dyer * or the file is corrupt or hand-edited. 13684ce6fa01SNick Dyer */ 13694ce6fa01SNick Dyer dev_warn(dev, "Discarding %zu byte(s) in T%u\n", 137050a77c65SNick Dyer size - mxt_obj_size(object), type); 13714ce6fa01SNick Dyer } else if (mxt_obj_size(object) > size) { 13724ce6fa01SNick Dyer /* 13734ce6fa01SNick Dyer * If firmware is upgraded, new bytes may be added to 13744ce6fa01SNick Dyer * end of objects. It is generally forward compatible 13754ce6fa01SNick Dyer * to zero these bytes - previous behaviour will be 13764ce6fa01SNick Dyer * retained. However this does invalidate the CRC and 13774ce6fa01SNick Dyer * will force fallback mode until the configuration is 13784ce6fa01SNick Dyer * updated. We warn here but do nothing else - the 13794ce6fa01SNick Dyer * malloc has zeroed the entire configuration. 13804ce6fa01SNick Dyer */ 13814ce6fa01SNick Dyer dev_warn(dev, "Zeroing %zu byte(s) in T%d\n", 13824ce6fa01SNick Dyer mxt_obj_size(object) - size, type); 138350a77c65SNick Dyer } 138450a77c65SNick Dyer 138550a77c65SNick Dyer if (instance >= mxt_obj_instances(object)) { 138650a77c65SNick Dyer dev_err(dev, "Object instances exceeded!\n"); 1387efdbd7aeSDmitry Torokhov return -EINVAL; 138850a77c65SNick Dyer } 138950a77c65SNick Dyer 139050a77c65SNick Dyer reg = object->start_address + mxt_obj_size(object) * instance; 139150a77c65SNick Dyer 139250a77c65SNick Dyer for (i = 0; i < size; i++) { 1393f865df73SNick Dyer ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n", 139450a77c65SNick Dyer &val, 139550a77c65SNick Dyer &offset); 139650a77c65SNick Dyer if (ret != 1) { 1397041fa159SDmitry Torokhov dev_err(dev, "Bad format in T%d at %d\n", 1398041fa159SDmitry Torokhov type, i); 1399efdbd7aeSDmitry Torokhov return -EINVAL; 140050a77c65SNick Dyer } 1401f865df73SNick Dyer cfg->raw_pos += offset; 140250a77c65SNick Dyer 140350a77c65SNick Dyer if (i > mxt_obj_size(object)) 14044cf51c38SJoonyoung Shim continue; 14054cf51c38SJoonyoung Shim 1406f865df73SNick Dyer byte_offset = reg + i - cfg->start_ofs; 140750a77c65SNick Dyer 1408f865df73SNick Dyer if (byte_offset >= 0 && byte_offset < cfg->mem_size) { 1409f865df73SNick Dyer *(cfg->mem + byte_offset) = val; 14104ce6fa01SNick Dyer } else { 14114ce6fa01SNick Dyer dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n", 14124ce6fa01SNick Dyer reg, object->type, byte_offset); 1413efdbd7aeSDmitry Torokhov return -EINVAL; 1414efdbd7aeSDmitry Torokhov } 1415efdbd7aeSDmitry Torokhov } 1416efdbd7aeSDmitry Torokhov } 1417efdbd7aeSDmitry Torokhov 1418efdbd7aeSDmitry Torokhov return 0; 1419efdbd7aeSDmitry Torokhov } 1420efdbd7aeSDmitry Torokhov 1421f865df73SNick Dyer static int mxt_upload_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) 1422efdbd7aeSDmitry Torokhov { 1423efdbd7aeSDmitry Torokhov unsigned int byte_offset = 0; 1424efdbd7aeSDmitry Torokhov int error; 1425efdbd7aeSDmitry Torokhov 1426efdbd7aeSDmitry Torokhov /* Write configuration as blocks */ 1427f865df73SNick Dyer while (byte_offset < cfg->mem_size) { 1428f865df73SNick Dyer unsigned int size = cfg->mem_size - byte_offset; 1429efdbd7aeSDmitry Torokhov 1430efdbd7aeSDmitry Torokhov if (size > MXT_MAX_BLOCK_WRITE) 1431efdbd7aeSDmitry Torokhov size = MXT_MAX_BLOCK_WRITE; 1432efdbd7aeSDmitry Torokhov 1433efdbd7aeSDmitry Torokhov error = __mxt_write_reg(data->client, 1434f865df73SNick Dyer cfg->start_ofs + byte_offset, 1435f865df73SNick Dyer size, cfg->mem + byte_offset); 1436efdbd7aeSDmitry Torokhov if (error) { 1437efdbd7aeSDmitry Torokhov dev_err(&data->client->dev, 1438efdbd7aeSDmitry Torokhov "Config write error, ret=%d\n", error); 1439efdbd7aeSDmitry Torokhov return error; 1440efdbd7aeSDmitry Torokhov } 1441efdbd7aeSDmitry Torokhov 1442efdbd7aeSDmitry Torokhov byte_offset += size; 1443efdbd7aeSDmitry Torokhov } 1444efdbd7aeSDmitry Torokhov 1445efdbd7aeSDmitry Torokhov return 0; 1446efdbd7aeSDmitry Torokhov } 1447efdbd7aeSDmitry Torokhov 14487f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data); 14497f3884f7SNick Dyer 1450efdbd7aeSDmitry Torokhov /* 1451efdbd7aeSDmitry Torokhov * mxt_update_cfg - download configuration to chip 1452efdbd7aeSDmitry Torokhov * 1453efdbd7aeSDmitry Torokhov * Atmel Raw Config File Format 1454efdbd7aeSDmitry Torokhov * 1455efdbd7aeSDmitry Torokhov * The first four lines of the raw config file contain: 1456efdbd7aeSDmitry Torokhov * 1) Version 1457efdbd7aeSDmitry Torokhov * 2) Chip ID Information (first 7 bytes of device memory) 1458efdbd7aeSDmitry Torokhov * 3) Chip Information Block 24-bit CRC Checksum 1459efdbd7aeSDmitry Torokhov * 4) Chip Configuration 24-bit CRC Checksum 1460efdbd7aeSDmitry Torokhov * 1461efdbd7aeSDmitry Torokhov * The rest of the file consists of one line per object instance: 1462efdbd7aeSDmitry Torokhov * <TYPE> <INSTANCE> <SIZE> <CONTENTS> 1463efdbd7aeSDmitry Torokhov * 1464efdbd7aeSDmitry Torokhov * <TYPE> - 2-byte object type as hex 1465efdbd7aeSDmitry Torokhov * <INSTANCE> - 2-byte object instance number as hex 1466efdbd7aeSDmitry Torokhov * <SIZE> - 2-byte object size as hex 1467efdbd7aeSDmitry Torokhov * <CONTENTS> - array of <SIZE> 1-byte hex values 1468efdbd7aeSDmitry Torokhov */ 1469f865df73SNick Dyer static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) 1470efdbd7aeSDmitry Torokhov { 1471efdbd7aeSDmitry Torokhov struct device *dev = &data->client->dev; 1472f865df73SNick Dyer struct mxt_cfg cfg; 1473efdbd7aeSDmitry Torokhov int ret; 1474efdbd7aeSDmitry Torokhov int offset; 1475efdbd7aeSDmitry Torokhov int i; 1476efdbd7aeSDmitry Torokhov u32 info_crc, config_crc, calculated_crc; 147715082bdbSNick Dyer u16 crc_start = 0; 1478efdbd7aeSDmitry Torokhov 1479a4891f10SNick Dyer /* Make zero terminated copy of the OBP_RAW file */ 1480a4891f10SNick Dyer cfg.raw = kmemdup_nul(fw->data, fw->size, GFP_KERNEL); 1481a4891f10SNick Dyer if (!cfg.raw) 1482a4891f10SNick Dyer return -ENOMEM; 1483a4891f10SNick Dyer 1484f865df73SNick Dyer cfg.raw_size = fw->size; 1485f865df73SNick Dyer 1486efdbd7aeSDmitry Torokhov mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); 1487efdbd7aeSDmitry Torokhov 1488f865df73SNick Dyer if (strncmp(cfg.raw, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { 1489efdbd7aeSDmitry Torokhov dev_err(dev, "Unrecognised config file\n"); 1490a4891f10SNick Dyer ret = -EINVAL; 1491a4891f10SNick Dyer goto release_raw; 1492efdbd7aeSDmitry Torokhov } 1493efdbd7aeSDmitry Torokhov 1494f865df73SNick Dyer cfg.raw_pos = strlen(MXT_CFG_MAGIC); 1495efdbd7aeSDmitry Torokhov 1496efdbd7aeSDmitry Torokhov /* Load information block and check */ 1497efdbd7aeSDmitry Torokhov for (i = 0; i < sizeof(struct mxt_info); i++) { 1498f865df73SNick Dyer ret = sscanf(cfg.raw + cfg.raw_pos, "%hhx%n", 1499f865df73SNick Dyer (unsigned char *)&cfg.info + i, 1500efdbd7aeSDmitry Torokhov &offset); 1501efdbd7aeSDmitry Torokhov if (ret != 1) { 1502efdbd7aeSDmitry Torokhov dev_err(dev, "Bad format\n"); 1503a4891f10SNick Dyer ret = -EINVAL; 1504a4891f10SNick Dyer goto release_raw; 1505efdbd7aeSDmitry Torokhov } 1506efdbd7aeSDmitry Torokhov 1507f865df73SNick Dyer cfg.raw_pos += offset; 1508efdbd7aeSDmitry Torokhov } 1509efdbd7aeSDmitry Torokhov 1510f865df73SNick Dyer if (cfg.info.family_id != data->info->family_id) { 1511efdbd7aeSDmitry Torokhov dev_err(dev, "Family ID mismatch!\n"); 1512a4891f10SNick Dyer ret = -EINVAL; 1513a4891f10SNick Dyer goto release_raw; 1514efdbd7aeSDmitry Torokhov } 1515efdbd7aeSDmitry Torokhov 1516f865df73SNick Dyer if (cfg.info.variant_id != data->info->variant_id) { 1517efdbd7aeSDmitry Torokhov dev_err(dev, "Variant ID mismatch!\n"); 1518a4891f10SNick Dyer ret = -EINVAL; 1519a4891f10SNick Dyer goto release_raw; 1520efdbd7aeSDmitry Torokhov } 1521efdbd7aeSDmitry Torokhov 1522efdbd7aeSDmitry Torokhov /* Read CRCs */ 1523f865df73SNick Dyer ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset); 1524efdbd7aeSDmitry Torokhov if (ret != 1) { 1525efdbd7aeSDmitry Torokhov dev_err(dev, "Bad format: failed to parse Info CRC\n"); 1526a4891f10SNick Dyer ret = -EINVAL; 1527a4891f10SNick Dyer goto release_raw; 1528efdbd7aeSDmitry Torokhov } 1529f865df73SNick Dyer cfg.raw_pos += offset; 1530efdbd7aeSDmitry Torokhov 1531f865df73SNick Dyer ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset); 1532efdbd7aeSDmitry Torokhov if (ret != 1) { 1533efdbd7aeSDmitry Torokhov dev_err(dev, "Bad format: failed to parse Config CRC\n"); 1534a4891f10SNick Dyer ret = -EINVAL; 1535a4891f10SNick Dyer goto release_raw; 1536efdbd7aeSDmitry Torokhov } 1537f865df73SNick Dyer cfg.raw_pos += offset; 1538efdbd7aeSDmitry Torokhov 1539efdbd7aeSDmitry Torokhov /* 1540efdbd7aeSDmitry Torokhov * The Info Block CRC is calculated over mxt_info and the object 1541efdbd7aeSDmitry Torokhov * table. If it does not match then we are trying to load the 1542efdbd7aeSDmitry Torokhov * configuration from a different chip or firmware version, so 1543efdbd7aeSDmitry Torokhov * the configuration CRC is invalid anyway. 1544efdbd7aeSDmitry Torokhov */ 1545efdbd7aeSDmitry Torokhov if (info_crc == data->info_crc) { 1546efdbd7aeSDmitry Torokhov if (config_crc == 0 || data->config_crc == 0) { 1547efdbd7aeSDmitry Torokhov dev_info(dev, "CRC zero, attempting to apply config\n"); 1548efdbd7aeSDmitry Torokhov } else if (config_crc == data->config_crc) { 1549efdbd7aeSDmitry Torokhov dev_dbg(dev, "Config CRC 0x%06X: OK\n", 1550efdbd7aeSDmitry Torokhov data->config_crc); 1551f0dd6878SIan Ray ret = 0; 1552f0dd6878SIan Ray goto release_raw; 1553efdbd7aeSDmitry Torokhov } else { 1554efdbd7aeSDmitry Torokhov dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", 1555efdbd7aeSDmitry Torokhov data->config_crc, config_crc); 1556efdbd7aeSDmitry Torokhov } 1557efdbd7aeSDmitry Torokhov } else { 1558efdbd7aeSDmitry Torokhov dev_warn(dev, 1559efdbd7aeSDmitry Torokhov "Warning: Info CRC error - device=0x%06X file=0x%06X\n", 1560efdbd7aeSDmitry Torokhov data->info_crc, info_crc); 1561efdbd7aeSDmitry Torokhov } 1562efdbd7aeSDmitry Torokhov 1563efdbd7aeSDmitry Torokhov /* Malloc memory to store configuration */ 1564f865df73SNick Dyer cfg.start_ofs = MXT_OBJECT_START + 1565068bdb67SNick Dyer data->info->object_num * sizeof(struct mxt_object) + 1566efdbd7aeSDmitry Torokhov MXT_INFO_CHECKSUM_SIZE; 1567f865df73SNick Dyer cfg.mem_size = data->mem_size - cfg.start_ofs; 1568f865df73SNick Dyer cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL); 1569a4891f10SNick Dyer if (!cfg.mem) { 1570a4891f10SNick Dyer ret = -ENOMEM; 1571a4891f10SNick Dyer goto release_raw; 1572a4891f10SNick Dyer } 1573efdbd7aeSDmitry Torokhov 1574f865df73SNick Dyer ret = mxt_prepare_cfg_mem(data, &cfg); 1575efdbd7aeSDmitry Torokhov if (ret) 15764ce6fa01SNick Dyer goto release_mem; 15774cf51c38SJoonyoung Shim 15784ce6fa01SNick Dyer /* Calculate crc of the received configs (not the raw config file) */ 157915082bdbSNick Dyer if (data->T71_address) 158015082bdbSNick Dyer crc_start = data->T71_address; 158115082bdbSNick Dyer else if (data->T7_address) 158215082bdbSNick Dyer crc_start = data->T7_address; 158315082bdbSNick Dyer else 158415082bdbSNick Dyer dev_warn(dev, "Could not find CRC start\n"); 15854ce6fa01SNick Dyer 1586f865df73SNick Dyer if (crc_start > cfg.start_ofs) { 1587f865df73SNick Dyer calculated_crc = mxt_calculate_crc(cfg.mem, 1588f865df73SNick Dyer crc_start - cfg.start_ofs, 1589f865df73SNick Dyer cfg.mem_size); 15904ce6fa01SNick Dyer 1591efdbd7aeSDmitry Torokhov if (config_crc > 0 && config_crc != calculated_crc) 159215082bdbSNick Dyer dev_warn(dev, "Config CRC in file inconsistent, calculated=%06X, file=%06X\n", 15934ce6fa01SNick Dyer calculated_crc, config_crc); 159415082bdbSNick Dyer } 15954ce6fa01SNick Dyer 1596f865df73SNick Dyer ret = mxt_upload_cfg_mem(data, &cfg); 1597efdbd7aeSDmitry Torokhov if (ret) 15984ce6fa01SNick Dyer goto release_mem; 15994ce6fa01SNick Dyer 1600c3f78043SNick Dyer mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); 1601c3f78043SNick Dyer 160274d905d2SNick Dyer ret = mxt_check_retrigen(data); 160374d905d2SNick Dyer if (ret) 160474d905d2SNick Dyer goto release_mem; 160574d905d2SNick Dyer 1606c3f78043SNick Dyer ret = mxt_soft_reset(data); 1607c3f78043SNick Dyer if (ret) 16084ce6fa01SNick Dyer goto release_mem; 1609c3f78043SNick Dyer 1610c3f78043SNick Dyer dev_info(dev, "Config successfully updated\n"); 1611c3f78043SNick Dyer 16127f3884f7SNick Dyer /* T7 config may have changed */ 16137f3884f7SNick Dyer mxt_init_t7_power_cfg(data); 16147f3884f7SNick Dyer 16154ce6fa01SNick Dyer release_mem: 1616f865df73SNick Dyer kfree(cfg.mem); 16171e3c336aSSanjeev Chugh release_raw: 16181e3c336aSSanjeev Chugh kfree(cfg.raw); 161950a77c65SNick Dyer return ret; 16204cf51c38SJoonyoung Shim } 16214cf51c38SJoonyoung Shim 162258e4aeeeSStephen Warren static void mxt_free_input_device(struct mxt_data *data) 16235f3f9bc2SNick Dyer { 162458e4aeeeSStephen Warren if (data->input_dev) { 16255f3f9bc2SNick Dyer input_unregister_device(data->input_dev); 16265f3f9bc2SNick Dyer data->input_dev = NULL; 162758e4aeeeSStephen Warren } 162858e4aeeeSStephen Warren } 16295f3f9bc2SNick Dyer 163058e4aeeeSStephen Warren static void mxt_free_object_table(struct mxt_data *data) 163158e4aeeeSStephen Warren { 1632ecfdd7e2SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 1633ecfdd7e2SNick Dyer video_unregister_device(&data->dbg.vdev); 1634ecfdd7e2SNick Dyer v4l2_device_unregister(&data->dbg.v4l2); 1635ecfdd7e2SNick Dyer #endif 16365f3f9bc2SNick Dyer data->object_table = NULL; 1637068bdb67SNick Dyer data->info = NULL; 1638068bdb67SNick Dyer kfree(data->raw_info_block); 1639068bdb67SNick Dyer data->raw_info_block = NULL; 16405f3f9bc2SNick Dyer kfree(data->msg_buf); 16415f3f9bc2SNick Dyer data->msg_buf = NULL; 1642b9b05a89SNick Dyer data->T5_address = 0; 16435f3f9bc2SNick Dyer data->T5_msg_size = 0; 16445f3f9bc2SNick Dyer data->T6_reportid = 0; 16455f3f9bc2SNick Dyer data->T7_address = 0; 164615082bdbSNick Dyer data->T71_address = 0; 16475f3f9bc2SNick Dyer data->T9_reportid_min = 0; 16485f3f9bc2SNick Dyer data->T9_reportid_max = 0; 164974d905d2SNick Dyer data->T18_address = 0; 16505f3f9bc2SNick Dyer data->T19_reportid = 0; 16519d8dc3e5SNick Dyer data->T44_address = 0; 1652b23157dcSNick Dyer data->T100_reportid_min = 0; 1653b23157dcSNick Dyer data->T100_reportid_max = 0; 16549d8dc3e5SNick Dyer data->max_reportid = 0; 16555f3f9bc2SNick Dyer } 16565f3f9bc2SNick Dyer 1657068bdb67SNick Dyer static int mxt_parse_object_table(struct mxt_data *data, 1658068bdb67SNick Dyer struct mxt_object *object_table) 16594cf51c38SJoonyoung Shim { 1660333e5a9aSDaniel Kurtz struct i2c_client *client = data->client; 16614cf51c38SJoonyoung Shim int i; 1662333e5a9aSDaniel Kurtz u8 reportid; 16634ce6fa01SNick Dyer u16 end_address; 16644cf51c38SJoonyoung Shim 1665333e5a9aSDaniel Kurtz /* Valid Report IDs start counting from 1 */ 1666333e5a9aSDaniel Kurtz reportid = 1; 16674ce6fa01SNick Dyer data->mem_size = 0; 1668068bdb67SNick Dyer for (i = 0; i < data->info->object_num; i++) { 1669dd24dcf5SNick Dyer struct mxt_object *object = object_table + i; 1670333e5a9aSDaniel Kurtz u8 min_id, max_id; 1671333e5a9aSDaniel Kurtz 1672333e5a9aSDaniel Kurtz le16_to_cpus(&object->start_address); 16734cf51c38SJoonyoung Shim 16744cf51c38SJoonyoung Shim if (object->num_report_ids) { 1675333e5a9aSDaniel Kurtz min_id = reportid; 16764cf51c38SJoonyoung Shim reportid += object->num_report_ids * 16771e0c0c5bSDaniel Kurtz mxt_obj_instances(object); 1678333e5a9aSDaniel Kurtz max_id = reportid - 1; 1679333e5a9aSDaniel Kurtz } else { 1680333e5a9aSDaniel Kurtz min_id = 0; 1681333e5a9aSDaniel Kurtz max_id = 0; 1682333e5a9aSDaniel Kurtz } 1683333e5a9aSDaniel Kurtz 1684333e5a9aSDaniel Kurtz dev_dbg(&data->client->dev, 16857bed6805SNick Dyer "T%u Start:%u Size:%zu Instances:%zu Report IDs:%u-%u\n", 16861e0c0c5bSDaniel Kurtz object->type, object->start_address, 16871e0c0c5bSDaniel Kurtz mxt_obj_size(object), mxt_obj_instances(object), 16881e0c0c5bSDaniel Kurtz min_id, max_id); 1689333e5a9aSDaniel Kurtz 1690333e5a9aSDaniel Kurtz switch (object->type) { 16915f3f9bc2SNick Dyer case MXT_GEN_MESSAGE_T5: 1692068bdb67SNick Dyer if (data->info->family_id == 0x80 && 1693068bdb67SNick Dyer data->info->version < 0x20) { 16949d8dc3e5SNick Dyer /* 1695437d4f37SNick Dyer * On mXT224 firmware versions prior to V2.0 1696437d4f37SNick Dyer * read and discard unused CRC byte otherwise 1697437d4f37SNick Dyer * DMA reads are misaligned. 16989d8dc3e5SNick Dyer */ 16999d8dc3e5SNick Dyer data->T5_msg_size = mxt_obj_size(object); 17009d8dc3e5SNick Dyer } else { 17019d8dc3e5SNick Dyer /* CRC not enabled, so skip last byte */ 17025f3f9bc2SNick Dyer data->T5_msg_size = mxt_obj_size(object) - 1; 17039d8dc3e5SNick Dyer } 1704b9b05a89SNick Dyer data->T5_address = object->start_address; 1705041fa159SDmitry Torokhov break; 1706fdf80421SDaniel Kurtz case MXT_GEN_COMMAND_T6: 1707fdf80421SDaniel Kurtz data->T6_reportid = min_id; 1708a4a2ef46SIiro Valkonen data->T6_address = object->start_address; 1709fdf80421SDaniel Kurtz break; 17104ce6fa01SNick Dyer case MXT_GEN_POWER_T7: 17114ce6fa01SNick Dyer data->T7_address = object->start_address; 17124ce6fa01SNick Dyer break; 171315082bdbSNick Dyer case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71: 171415082bdbSNick Dyer data->T71_address = object->start_address; 171515082bdbSNick Dyer break; 1716333e5a9aSDaniel Kurtz case MXT_TOUCH_MULTI_T9: 1717b23157dcSNick Dyer data->multitouch = MXT_TOUCH_MULTI_T9; 171836f5d9efSNick Dyer /* Only handle messages from first T9 instance */ 1719333e5a9aSDaniel Kurtz data->T9_reportid_min = min_id; 172036f5d9efSNick Dyer data->T9_reportid_max = min_id + 172136f5d9efSNick Dyer object->num_report_ids - 1; 172236f5d9efSNick Dyer data->num_touchids = object->num_report_ids; 17239d8dc3e5SNick Dyer break; 172474d905d2SNick Dyer case MXT_SPT_COMMSCONFIG_T18: 172574d905d2SNick Dyer data->T18_address = object->start_address; 172674d905d2SNick Dyer break; 17279d8dc3e5SNick Dyer case MXT_SPT_MESSAGECOUNT_T44: 17289d8dc3e5SNick Dyer data->T44_address = object->start_address; 1729333e5a9aSDaniel Kurtz break; 173022dfab7fSDaniel Kurtz case MXT_SPT_GPIOPWM_T19: 173122dfab7fSDaniel Kurtz data->T19_reportid = min_id; 173222dfab7fSDaniel Kurtz break; 1733b23157dcSNick Dyer case MXT_TOUCH_MULTITOUCHSCREEN_T100: 1734b23157dcSNick Dyer data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100; 1735b23157dcSNick Dyer data->T100_reportid_min = min_id; 1736b23157dcSNick Dyer data->T100_reportid_max = max_id; 1737b23157dcSNick Dyer /* first two report IDs reserved */ 1738b23157dcSNick Dyer data->num_touchids = object->num_report_ids - 2; 1739b23157dcSNick Dyer break; 17404cf51c38SJoonyoung Shim } 17414ce6fa01SNick Dyer 17424ce6fa01SNick Dyer end_address = object->start_address 17434ce6fa01SNick Dyer + mxt_obj_size(object) * mxt_obj_instances(object) - 1; 17444ce6fa01SNick Dyer 17454ce6fa01SNick Dyer if (end_address >= data->mem_size) 17464ce6fa01SNick Dyer data->mem_size = end_address + 1; 17474cf51c38SJoonyoung Shim } 17484cf51c38SJoonyoung Shim 17499d8dc3e5SNick Dyer /* Store maximum reportid */ 17509d8dc3e5SNick Dyer data->max_reportid = reportid; 17519d8dc3e5SNick Dyer 17529d8dc3e5SNick Dyer /* If T44 exists, T5 position has to be directly after */ 17539d8dc3e5SNick Dyer if (data->T44_address && (data->T5_address != data->T44_address + 1)) { 17549d8dc3e5SNick Dyer dev_err(&client->dev, "Invalid T44 position\n"); 1755068bdb67SNick Dyer return -EINVAL; 17569d8dc3e5SNick Dyer } 17579d8dc3e5SNick Dyer 17589d8dc3e5SNick Dyer data->msg_buf = kcalloc(data->max_reportid, 17599d8dc3e5SNick Dyer data->T5_msg_size, GFP_KERNEL); 1760068bdb67SNick Dyer if (!data->msg_buf) 1761068bdb67SNick Dyer return -ENOMEM; 1762068bdb67SNick Dyer 1763068bdb67SNick Dyer return 0; 17645f3f9bc2SNick Dyer } 17655f3f9bc2SNick Dyer 1766068bdb67SNick Dyer static int mxt_read_info_block(struct mxt_data *data) 1767068bdb67SNick Dyer { 1768068bdb67SNick Dyer struct i2c_client *client = data->client; 1769068bdb67SNick Dyer int error; 1770068bdb67SNick Dyer size_t size; 1771068bdb67SNick Dyer void *id_buf, *buf; 1772068bdb67SNick Dyer uint8_t num_objects; 1773068bdb67SNick Dyer u32 calculated_crc; 1774068bdb67SNick Dyer u8 *crc_ptr; 1775068bdb67SNick Dyer 1776068bdb67SNick Dyer /* If info block already allocated, free it */ 1777068bdb67SNick Dyer if (data->raw_info_block) 1778068bdb67SNick Dyer mxt_free_object_table(data); 1779068bdb67SNick Dyer 1780068bdb67SNick Dyer /* Read 7-byte ID information block starting at address 0 */ 1781068bdb67SNick Dyer size = sizeof(struct mxt_info); 1782068bdb67SNick Dyer id_buf = kzalloc(size, GFP_KERNEL); 1783068bdb67SNick Dyer if (!id_buf) 1784068bdb67SNick Dyer return -ENOMEM; 1785068bdb67SNick Dyer 1786068bdb67SNick Dyer error = __mxt_read_reg(client, 0, size, id_buf); 1787068bdb67SNick Dyer if (error) 1788068bdb67SNick Dyer goto err_free_mem; 1789068bdb67SNick Dyer 1790068bdb67SNick Dyer /* Resize buffer to give space for rest of info block */ 1791068bdb67SNick Dyer num_objects = ((struct mxt_info *)id_buf)->object_num; 1792068bdb67SNick Dyer size += (num_objects * sizeof(struct mxt_object)) 1793068bdb67SNick Dyer + MXT_INFO_CHECKSUM_SIZE; 1794068bdb67SNick Dyer 1795068bdb67SNick Dyer buf = krealloc(id_buf, size, GFP_KERNEL); 1796068bdb67SNick Dyer if (!buf) { 1797068bdb67SNick Dyer error = -ENOMEM; 1798068bdb67SNick Dyer goto err_free_mem; 1799068bdb67SNick Dyer } 1800068bdb67SNick Dyer id_buf = buf; 1801068bdb67SNick Dyer 1802068bdb67SNick Dyer /* Read rest of info block */ 1803068bdb67SNick Dyer error = __mxt_read_reg(client, MXT_OBJECT_START, 1804068bdb67SNick Dyer size - MXT_OBJECT_START, 1805068bdb67SNick Dyer id_buf + MXT_OBJECT_START); 1806068bdb67SNick Dyer if (error) 1807068bdb67SNick Dyer goto err_free_mem; 1808068bdb67SNick Dyer 1809068bdb67SNick Dyer /* Extract & calculate checksum */ 1810068bdb67SNick Dyer crc_ptr = id_buf + size - MXT_INFO_CHECKSUM_SIZE; 1811068bdb67SNick Dyer data->info_crc = crc_ptr[0] | (crc_ptr[1] << 8) | (crc_ptr[2] << 16); 1812068bdb67SNick Dyer 1813068bdb67SNick Dyer calculated_crc = mxt_calculate_crc(id_buf, 0, 1814068bdb67SNick Dyer size - MXT_INFO_CHECKSUM_SIZE); 1815068bdb67SNick Dyer 1816068bdb67SNick Dyer /* 1817068bdb67SNick Dyer * CRC mismatch can be caused by data corruption due to I2C comms 1818068bdb67SNick Dyer * issue or else device is not using Object Based Protocol (eg i2c-hid) 1819068bdb67SNick Dyer */ 1820068bdb67SNick Dyer if ((data->info_crc == 0) || (data->info_crc != calculated_crc)) { 1821068bdb67SNick Dyer dev_err(&client->dev, 1822068bdb67SNick Dyer "Info Block CRC error calculated=0x%06X read=0x%06X\n", 1823068bdb67SNick Dyer calculated_crc, data->info_crc); 1824068bdb67SNick Dyer error = -EIO; 1825068bdb67SNick Dyer goto err_free_mem; 1826068bdb67SNick Dyer } 1827068bdb67SNick Dyer 1828068bdb67SNick Dyer data->raw_info_block = id_buf; 1829068bdb67SNick Dyer data->info = (struct mxt_info *)id_buf; 1830068bdb67SNick Dyer 1831068bdb67SNick Dyer dev_info(&client->dev, 1832068bdb67SNick Dyer "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", 1833068bdb67SNick Dyer data->info->family_id, data->info->variant_id, 1834068bdb67SNick Dyer data->info->version >> 4, data->info->version & 0xf, 1835068bdb67SNick Dyer data->info->build, data->info->object_num); 1836068bdb67SNick Dyer 1837068bdb67SNick Dyer /* Parse object table information */ 1838068bdb67SNick Dyer error = mxt_parse_object_table(data, id_buf + MXT_OBJECT_START); 1839068bdb67SNick Dyer if (error) { 1840068bdb67SNick Dyer dev_err(&client->dev, "Error %d parsing object table\n", error); 1841068bdb67SNick Dyer mxt_free_object_table(data); 1842068bdb67SNick Dyer goto err_free_mem; 1843068bdb67SNick Dyer } 1844068bdb67SNick Dyer 1845068bdb67SNick Dyer data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START); 1846dd24dcf5SNick Dyer 18474cf51c38SJoonyoung Shim return 0; 18484cf51c38SJoonyoung Shim 1849068bdb67SNick Dyer err_free_mem: 1850068bdb67SNick Dyer kfree(id_buf); 18515f3f9bc2SNick Dyer return error; 18527d4fa100SDaniel Kurtz } 18537d4fa100SDaniel Kurtz 185461dc1abaSNick Dyer static int mxt_read_t9_resolution(struct mxt_data *data) 185561dc1abaSNick Dyer { 185661dc1abaSNick Dyer struct i2c_client *client = data->client; 185761dc1abaSNick Dyer int error; 185861dc1abaSNick Dyer struct t9_range range; 185961dc1abaSNick Dyer unsigned char orient; 186061dc1abaSNick Dyer struct mxt_object *object; 186161dc1abaSNick Dyer 186261dc1abaSNick Dyer object = mxt_get_object(data, MXT_TOUCH_MULTI_T9); 186361dc1abaSNick Dyer if (!object) 186461dc1abaSNick Dyer return -EINVAL; 186561dc1abaSNick Dyer 186661dc1abaSNick Dyer error = __mxt_read_reg(client, 18672786489fSNick Dyer object->start_address + MXT_T9_XSIZE, 18682786489fSNick Dyer sizeof(data->xsize), &data->xsize); 18692786489fSNick Dyer if (error) 18702786489fSNick Dyer return error; 18712786489fSNick Dyer 18722786489fSNick Dyer error = __mxt_read_reg(client, 18732786489fSNick Dyer object->start_address + MXT_T9_YSIZE, 18742786489fSNick Dyer sizeof(data->ysize), &data->ysize); 18752786489fSNick Dyer if (error) 18762786489fSNick Dyer return error; 18772786489fSNick Dyer 18782786489fSNick Dyer error = __mxt_read_reg(client, 187961dc1abaSNick Dyer object->start_address + MXT_T9_RANGE, 188061dc1abaSNick Dyer sizeof(range), &range); 188161dc1abaSNick Dyer if (error) 188261dc1abaSNick Dyer return error; 188361dc1abaSNick Dyer 18841c0276d5SNick Dyer data->max_x = get_unaligned_le16(&range.x); 18851c0276d5SNick Dyer data->max_y = get_unaligned_le16(&range.y); 188661dc1abaSNick Dyer 188761dc1abaSNick Dyer error = __mxt_read_reg(client, 188861dc1abaSNick Dyer object->start_address + MXT_T9_ORIENT, 188961dc1abaSNick Dyer 1, &orient); 189061dc1abaSNick Dyer if (error) 189161dc1abaSNick Dyer return error; 189261dc1abaSNick Dyer 18931c0276d5SNick Dyer data->xy_switch = orient & MXT_T9_ORIENT_SWITCH; 1894de601f71SNick Dyer data->invertx = orient & MXT_T9_ORIENT_INVERTX; 1895de601f71SNick Dyer data->inverty = orient & MXT_T9_ORIENT_INVERTY; 189661dc1abaSNick Dyer 189761dc1abaSNick Dyer return 0; 189861dc1abaSNick Dyer } 189961dc1abaSNick Dyer 1900b23157dcSNick Dyer static int mxt_read_t100_config(struct mxt_data *data) 1901b23157dcSNick Dyer { 1902b23157dcSNick Dyer struct i2c_client *client = data->client; 1903b23157dcSNick Dyer int error; 1904b23157dcSNick Dyer struct mxt_object *object; 1905b23157dcSNick Dyer u16 range_x, range_y; 1906b23157dcSNick Dyer u8 cfg, tchaux; 1907b23157dcSNick Dyer u8 aux; 1908b23157dcSNick Dyer 1909b23157dcSNick Dyer object = mxt_get_object(data, MXT_TOUCH_MULTITOUCHSCREEN_T100); 1910b23157dcSNick Dyer if (!object) 1911b23157dcSNick Dyer return -EINVAL; 1912b23157dcSNick Dyer 19131c0276d5SNick Dyer /* read touchscreen dimensions */ 1914b23157dcSNick Dyer error = __mxt_read_reg(client, 1915b23157dcSNick Dyer object->start_address + MXT_T100_XRANGE, 1916b23157dcSNick Dyer sizeof(range_x), &range_x); 1917b23157dcSNick Dyer if (error) 1918b23157dcSNick Dyer return error; 1919b23157dcSNick Dyer 19201c0276d5SNick Dyer data->max_x = get_unaligned_le16(&range_x); 1921b23157dcSNick Dyer 1922b23157dcSNick Dyer error = __mxt_read_reg(client, 1923b23157dcSNick Dyer object->start_address + MXT_T100_YRANGE, 1924b23157dcSNick Dyer sizeof(range_y), &range_y); 1925b23157dcSNick Dyer if (error) 1926b23157dcSNick Dyer return error; 1927b23157dcSNick Dyer 19281c0276d5SNick Dyer data->max_y = get_unaligned_le16(&range_y); 1929b23157dcSNick Dyer 19302786489fSNick Dyer error = __mxt_read_reg(client, 19312786489fSNick Dyer object->start_address + MXT_T100_XSIZE, 19322786489fSNick Dyer sizeof(data->xsize), &data->xsize); 19332786489fSNick Dyer if (error) 19342786489fSNick Dyer return error; 19352786489fSNick Dyer 19362786489fSNick Dyer error = __mxt_read_reg(client, 19372786489fSNick Dyer object->start_address + MXT_T100_YSIZE, 19382786489fSNick Dyer sizeof(data->ysize), &data->ysize); 19392786489fSNick Dyer if (error) 19402786489fSNick Dyer return error; 19412786489fSNick Dyer 19421c0276d5SNick Dyer /* read orientation config */ 1943b23157dcSNick Dyer error = __mxt_read_reg(client, 1944b23157dcSNick Dyer object->start_address + MXT_T100_CFG1, 1945b23157dcSNick Dyer 1, &cfg); 1946b23157dcSNick Dyer if (error) 1947b23157dcSNick Dyer return error; 1948b23157dcSNick Dyer 19491c0276d5SNick Dyer data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY; 1950de601f71SNick Dyer data->invertx = cfg & MXT_T100_CFG_INVERTX; 1951de601f71SNick Dyer data->inverty = cfg & MXT_T100_CFG_INVERTY; 19521c0276d5SNick Dyer 19531c0276d5SNick Dyer /* allocate aux bytes */ 1954b23157dcSNick Dyer error = __mxt_read_reg(client, 1955b23157dcSNick Dyer object->start_address + MXT_T100_TCHAUX, 1956b23157dcSNick Dyer 1, &tchaux); 1957b23157dcSNick Dyer if (error) 1958b23157dcSNick Dyer return error; 1959b23157dcSNick Dyer 1960b23157dcSNick Dyer aux = 6; 1961b23157dcSNick Dyer 1962b23157dcSNick Dyer if (tchaux & MXT_T100_TCHAUX_VECT) 1963b23157dcSNick Dyer data->t100_aux_vect = aux++; 1964b23157dcSNick Dyer 1965b23157dcSNick Dyer if (tchaux & MXT_T100_TCHAUX_AMPL) 1966b23157dcSNick Dyer data->t100_aux_ampl = aux++; 1967b23157dcSNick Dyer 1968b23157dcSNick Dyer if (tchaux & MXT_T100_TCHAUX_AREA) 1969b23157dcSNick Dyer data->t100_aux_area = aux++; 1970b23157dcSNick Dyer 1971b23157dcSNick Dyer dev_dbg(&client->dev, 1972b23157dcSNick Dyer "T100 aux mappings vect:%u ampl:%u area:%u\n", 1973b23157dcSNick Dyer data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area); 1974b23157dcSNick Dyer 1975b23157dcSNick Dyer return 0; 1976b23157dcSNick Dyer } 1977b23157dcSNick Dyer 19787a53d609SNick Dyer static int mxt_input_open(struct input_dev *dev); 19797a53d609SNick Dyer static void mxt_input_close(struct input_dev *dev); 19807a53d609SNick Dyer 1981b6d2d328SSjoerd Simons static void mxt_set_up_as_touchpad(struct input_dev *input_dev, 1982b6d2d328SSjoerd Simons struct mxt_data *data) 1983b6d2d328SSjoerd Simons { 1984b6d2d328SSjoerd Simons int i; 1985b6d2d328SSjoerd Simons 1986b6d2d328SSjoerd Simons input_dev->name = "Atmel maXTouch Touchpad"; 1987b6d2d328SSjoerd Simons 1988b6d2d328SSjoerd Simons __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); 1989b6d2d328SSjoerd Simons 1990b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM); 1991b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM); 1992b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_MT_POSITION_X, 1993b6d2d328SSjoerd Simons MXT_PIXELS_PER_MM); 1994b6d2d328SSjoerd Simons input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 1995b6d2d328SSjoerd Simons MXT_PIXELS_PER_MM); 1996b6d2d328SSjoerd Simons 199796a938aaSDmitry Torokhov for (i = 0; i < data->t19_num_keys; i++) 199896a938aaSDmitry Torokhov if (data->t19_keymap[i] != KEY_RESERVED) 1999b6d2d328SSjoerd Simons input_set_capability(input_dev, EV_KEY, 200096a938aaSDmitry Torokhov data->t19_keymap[i]); 2001b6d2d328SSjoerd Simons } 2002b6d2d328SSjoerd Simons 2003b23157dcSNick Dyer static int mxt_initialize_input_device(struct mxt_data *data) 20047a53d609SNick Dyer { 2005b6d2d328SSjoerd Simons struct device *dev = &data->client->dev; 20067a53d609SNick Dyer struct input_dev *input_dev; 20077a53d609SNick Dyer int error; 20087a53d609SNick Dyer unsigned int num_mt_slots; 20097a53d609SNick Dyer unsigned int mt_flags = 0; 20107a53d609SNick Dyer 2011b23157dcSNick Dyer switch (data->multitouch) { 2012b23157dcSNick Dyer case MXT_TOUCH_MULTI_T9: 2013b23157dcSNick Dyer num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; 20147a53d609SNick Dyer error = mxt_read_t9_resolution(data); 20157a53d609SNick Dyer if (error) 20167a53d609SNick Dyer dev_warn(dev, "Failed to initialize T9 resolution\n"); 2017b23157dcSNick Dyer break; 2018b23157dcSNick Dyer 2019b23157dcSNick Dyer case MXT_TOUCH_MULTITOUCHSCREEN_T100: 2020b23157dcSNick Dyer num_mt_slots = data->num_touchids; 2021b23157dcSNick Dyer error = mxt_read_t100_config(data); 2022b23157dcSNick Dyer if (error) 2023b23157dcSNick Dyer dev_warn(dev, "Failed to read T100 config\n"); 2024b23157dcSNick Dyer break; 2025b23157dcSNick Dyer 2026b23157dcSNick Dyer default: 2027b23157dcSNick Dyer dev_err(dev, "Invalid multitouch object\n"); 2028b23157dcSNick Dyer return -EINVAL; 2029b23157dcSNick Dyer } 20307a53d609SNick Dyer 20311c0276d5SNick Dyer /* Handle default values and orientation switch */ 20321c0276d5SNick Dyer if (data->max_x == 0) 20331c0276d5SNick Dyer data->max_x = 1023; 20341c0276d5SNick Dyer 20351c0276d5SNick Dyer if (data->max_y == 0) 20361c0276d5SNick Dyer data->max_y = 1023; 20371c0276d5SNick Dyer 20381c0276d5SNick Dyer if (data->xy_switch) 20391c0276d5SNick Dyer swap(data->max_x, data->max_y); 20401c0276d5SNick Dyer 20411c0276d5SNick Dyer dev_info(dev, "Touchscreen size X%uY%u\n", data->max_x, data->max_y); 20421c0276d5SNick Dyer 20431c0276d5SNick Dyer /* Register input device */ 20447a53d609SNick Dyer input_dev = input_allocate_device(); 204501cc75f9SNick Dyer if (!input_dev) 20467a53d609SNick Dyer return -ENOMEM; 20477a53d609SNick Dyer 20487a53d609SNick Dyer input_dev->name = "Atmel maXTouch Touchscreen"; 20497a53d609SNick Dyer input_dev->phys = data->phys; 20507a53d609SNick Dyer input_dev->id.bustype = BUS_I2C; 20517a53d609SNick Dyer input_dev->dev.parent = dev; 20527a53d609SNick Dyer input_dev->open = mxt_input_open; 20537a53d609SNick Dyer input_dev->close = mxt_input_close; 20547a53d609SNick Dyer 2055b23157dcSNick Dyer input_set_capability(input_dev, EV_KEY, BTN_TOUCH); 20567a53d609SNick Dyer 20577a53d609SNick Dyer /* For single touch */ 2058b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_X, 0, data->max_x, 0, 0); 2059b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_Y, 0, data->max_y, 0, 0); 2060b23157dcSNick Dyer 2061b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTI_T9 || 2062b23157dcSNick Dyer (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 2063b23157dcSNick Dyer data->t100_aux_ampl)) { 2064b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); 2065b23157dcSNick Dyer } 20667a53d609SNick Dyer 2067b6d2d328SSjoerd Simons /* If device has buttons we assume it is a touchpad */ 206896a938aaSDmitry Torokhov if (data->t19_num_keys) { 2069b6d2d328SSjoerd Simons mxt_set_up_as_touchpad(input_dev, data); 2070b6d2d328SSjoerd Simons mt_flags |= INPUT_MT_POINTER; 2071eafc0c87SNick Dyer } else { 2072eafc0c87SNick Dyer mt_flags |= INPUT_MT_DIRECT; 2073b6d2d328SSjoerd Simons } 2074b6d2d328SSjoerd Simons 20757a53d609SNick Dyer /* For multi touch */ 20767a53d609SNick Dyer error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags); 20777a53d609SNick Dyer if (error) { 20787a53d609SNick Dyer dev_err(dev, "Error %d initialising slots\n", error); 20797a53d609SNick Dyer goto err_free_mem; 20807a53d609SNick Dyer } 20817a53d609SNick Dyer 2082b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100) { 2083b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 2084b23157dcSNick Dyer 0, MT_TOOL_MAX, 0, 0); 2085b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_DISTANCE, 2086b23157dcSNick Dyer MXT_DISTANCE_ACTIVE_TOUCH, 2087b23157dcSNick Dyer MXT_DISTANCE_HOVERING, 2088b23157dcSNick Dyer 0, 0); 2089b23157dcSNick Dyer } 2090b23157dcSNick Dyer 20917a53d609SNick Dyer input_set_abs_params(input_dev, ABS_MT_POSITION_X, 20927a53d609SNick Dyer 0, data->max_x, 0, 0); 20937a53d609SNick Dyer input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 20947a53d609SNick Dyer 0, data->max_y, 0, 0); 2095b23157dcSNick Dyer 2096b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTI_T9 || 2097b23157dcSNick Dyer (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 2098b23157dcSNick Dyer data->t100_aux_area)) { 2099b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 2100b23157dcSNick Dyer 0, MXT_MAX_AREA, 0, 0); 2101b23157dcSNick Dyer } 2102b23157dcSNick Dyer 2103b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTI_T9 || 2104b23157dcSNick Dyer (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 2105b23157dcSNick Dyer data->t100_aux_ampl)) { 21067a53d609SNick Dyer input_set_abs_params(input_dev, ABS_MT_PRESSURE, 21077a53d609SNick Dyer 0, 255, 0, 0); 2108b23157dcSNick Dyer } 2109b23157dcSNick Dyer 2110b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 2111b23157dcSNick Dyer data->t100_aux_vect) { 2112b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 2113b23157dcSNick Dyer 0, 255, 0, 0); 2114b23157dcSNick Dyer } 2115b23157dcSNick Dyer 2116b23157dcSNick Dyer if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 && 2117b23157dcSNick Dyer data->t100_aux_vect) { 2118b23157dcSNick Dyer input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 2119b23157dcSNick Dyer 0, 255, 0, 0); 2120b23157dcSNick Dyer } 21217a53d609SNick Dyer 21227a53d609SNick Dyer input_set_drvdata(input_dev, data); 21237a53d609SNick Dyer 21247a53d609SNick Dyer error = input_register_device(input_dev); 21257a53d609SNick Dyer if (error) { 21267a53d609SNick Dyer dev_err(dev, "Error %d registering input device\n", error); 21277a53d609SNick Dyer goto err_free_mem; 21287a53d609SNick Dyer } 21297a53d609SNick Dyer 21307a53d609SNick Dyer data->input_dev = input_dev; 21317a53d609SNick Dyer 21327a53d609SNick Dyer return 0; 21337a53d609SNick Dyer 21347a53d609SNick Dyer err_free_mem: 21357a53d609SNick Dyer input_free_device(input_dev); 21367a53d609SNick Dyer return error; 21377a53d609SNick Dyer } 21387a53d609SNick Dyer 213950a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data, 214050a77c65SNick Dyer const struct firmware *cfg); 214150a77c65SNick Dyer 214250a77c65SNick Dyer static void mxt_config_cb(const struct firmware *cfg, void *ctx) 214350a77c65SNick Dyer { 214450a77c65SNick Dyer mxt_configure_objects(ctx, cfg); 2145efdbd7aeSDmitry Torokhov release_firmware(cfg); 214650a77c65SNick Dyer } 214750a77c65SNick Dyer 21487686b108SIiro Valkonen static int mxt_initialize(struct mxt_data *data) 21494cf51c38SJoonyoung Shim { 21504cf51c38SJoonyoung Shim struct i2c_client *client = data->client; 21516cd1ab0fSDmitry Torokhov int recovery_attempts = 0; 21524cf51c38SJoonyoung Shim int error; 21534cf51c38SJoonyoung Shim 21546cd1ab0fSDmitry Torokhov while (1) { 2155068bdb67SNick Dyer error = mxt_read_info_block(data); 21566cd1ab0fSDmitry Torokhov if (!error) 21576cd1ab0fSDmitry Torokhov break; 21586cd1ab0fSDmitry Torokhov 21596cd1ab0fSDmitry Torokhov /* Check bootloader state */ 21606cd1ab0fSDmitry Torokhov error = mxt_probe_bootloader(data, false); 2161a9fdd1e6SNick Dyer if (error) { 21626cd1ab0fSDmitry Torokhov dev_info(&client->dev, "Trying alternate bootloader address\n"); 21636cd1ab0fSDmitry Torokhov error = mxt_probe_bootloader(data, true); 21648efaa5e5SNick Dyer if (error) { 21658efaa5e5SNick Dyer /* Chip is not in appmode or bootloader mode */ 21664cf51c38SJoonyoung Shim return error; 21678efaa5e5SNick Dyer } 21686cd1ab0fSDmitry Torokhov } 21694cf51c38SJoonyoung Shim 21706cd1ab0fSDmitry Torokhov /* OK, we are in bootloader, see if we can recover */ 21716cd1ab0fSDmitry Torokhov if (++recovery_attempts > 1) { 21728efaa5e5SNick Dyer dev_err(&client->dev, "Could not recover from bootloader mode\n"); 21738efaa5e5SNick Dyer /* 21748efaa5e5SNick Dyer * We can reflash from this state, so do not 21756cd1ab0fSDmitry Torokhov * abort initialization. 21768efaa5e5SNick Dyer */ 2177a9fdd1e6SNick Dyer data->in_bootloader = true; 2178a9fdd1e6SNick Dyer return 0; 2179a9fdd1e6SNick Dyer } 2180a9fdd1e6SNick Dyer 21818efaa5e5SNick Dyer /* Attempt to exit bootloader into app mode */ 21828efaa5e5SNick Dyer mxt_send_bootloader_cmd(data, false); 21838efaa5e5SNick Dyer msleep(MXT_FW_RESET_TIME); 21848efaa5e5SNick Dyer } 21858efaa5e5SNick Dyer 2186041fa159SDmitry Torokhov error = mxt_acquire_irq(data); 2187dd24dcf5SNick Dyer if (error) 2188068bdb67SNick Dyer return error; 2189dd24dcf5SNick Dyer 219074d905d2SNick Dyer error = mxt_check_retrigen(data); 219174d905d2SNick Dyer if (error) 219274d905d2SNick Dyer return error; 219374d905d2SNick Dyer 21946cd1ab0fSDmitry Torokhov error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME, 21956cd1ab0fSDmitry Torokhov &client->dev, GFP_KERNEL, data, 219650a77c65SNick Dyer mxt_config_cb); 21976cd1ab0fSDmitry Torokhov if (error) { 21986cd1ab0fSDmitry Torokhov dev_err(&client->dev, "Failed to invoke firmware loader: %d\n", 21996cd1ab0fSDmitry Torokhov error); 2200068bdb67SNick Dyer return error; 22016cd1ab0fSDmitry Torokhov } 22024cf51c38SJoonyoung Shim 22034cf51c38SJoonyoung Shim return 0; 22044cf51c38SJoonyoung Shim } 22054cf51c38SJoonyoung Shim 22067f3884f7SNick Dyer static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) 22077f3884f7SNick Dyer { 22087f3884f7SNick Dyer struct device *dev = &data->client->dev; 22097f3884f7SNick Dyer int error; 22107f3884f7SNick Dyer struct t7_config *new_config; 22117f3884f7SNick Dyer struct t7_config deepsleep = { .active = 0, .idle = 0 }; 22127f3884f7SNick Dyer 22137f3884f7SNick Dyer if (sleep == MXT_POWER_CFG_DEEPSLEEP) 22147f3884f7SNick Dyer new_config = &deepsleep; 22157f3884f7SNick Dyer else 22167f3884f7SNick Dyer new_config = &data->t7_cfg; 22177f3884f7SNick Dyer 22187f3884f7SNick Dyer error = __mxt_write_reg(data->client, data->T7_address, 22197f3884f7SNick Dyer sizeof(data->t7_cfg), new_config); 22207f3884f7SNick Dyer if (error) 22217f3884f7SNick Dyer return error; 22227f3884f7SNick Dyer 22237f3884f7SNick Dyer dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n", 22247f3884f7SNick Dyer new_config->active, new_config->idle); 22257f3884f7SNick Dyer 22267f3884f7SNick Dyer return 0; 22277f3884f7SNick Dyer } 22287f3884f7SNick Dyer 22297f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data) 22307f3884f7SNick Dyer { 22317f3884f7SNick Dyer struct device *dev = &data->client->dev; 22327f3884f7SNick Dyer int error; 22337f3884f7SNick Dyer bool retry = false; 22347f3884f7SNick Dyer 22357f3884f7SNick Dyer recheck: 22367f3884f7SNick Dyer error = __mxt_read_reg(data->client, data->T7_address, 22377f3884f7SNick Dyer sizeof(data->t7_cfg), &data->t7_cfg); 22387f3884f7SNick Dyer if (error) 22397f3884f7SNick Dyer return error; 22407f3884f7SNick Dyer 22417f3884f7SNick Dyer if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) { 22427f3884f7SNick Dyer if (!retry) { 22437f3884f7SNick Dyer dev_dbg(dev, "T7 cfg zero, resetting\n"); 22447f3884f7SNick Dyer mxt_soft_reset(data); 22457f3884f7SNick Dyer retry = true; 22467f3884f7SNick Dyer goto recheck; 22477f3884f7SNick Dyer } else { 22487f3884f7SNick Dyer dev_dbg(dev, "T7 cfg zero after reset, overriding\n"); 22497f3884f7SNick Dyer data->t7_cfg.active = 20; 22507f3884f7SNick Dyer data->t7_cfg.idle = 100; 22517f3884f7SNick Dyer return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); 22527f3884f7SNick Dyer } 22537f3884f7SNick Dyer } 22547f3884f7SNick Dyer 22557f3884f7SNick Dyer dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n", 22567f3884f7SNick Dyer data->t7_cfg.active, data->t7_cfg.idle); 22577f3884f7SNick Dyer return 0; 22587f3884f7SNick Dyer } 22597f3884f7SNick Dyer 2260d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 22615cecc2bcSNathan Huckleberry static const struct v4l2_file_operations mxt_video_fops = { 22625cecc2bcSNathan Huckleberry .owner = THIS_MODULE, 22635cecc2bcSNathan Huckleberry .open = v4l2_fh_open, 22645cecc2bcSNathan Huckleberry .release = vb2_fop_release, 22655cecc2bcSNathan Huckleberry .unlocked_ioctl = video_ioctl2, 22665cecc2bcSNathan Huckleberry .read = vb2_fop_read, 22675cecc2bcSNathan Huckleberry .mmap = vb2_fop_mmap, 22685cecc2bcSNathan Huckleberry .poll = vb2_fop_poll, 22695cecc2bcSNathan Huckleberry }; 22705cecc2bcSNathan Huckleberry 2271d6a39404SNick Dyer static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x, 2272d6a39404SNick Dyer unsigned int y) 2273d6a39404SNick Dyer { 2274068bdb67SNick Dyer struct mxt_info *info = data->info; 2275d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2276d6a39404SNick Dyer unsigned int ofs, page; 2277566d533aSNick Dyer unsigned int col = 0; 2278566d533aSNick Dyer unsigned int col_width; 2279d6a39404SNick Dyer 2280566d533aSNick Dyer if (info->family_id == MXT_FAMILY_1386) { 2281566d533aSNick Dyer col_width = info->matrix_ysize / MXT1386_COLUMNS; 2282566d533aSNick Dyer col = y / col_width; 2283566d533aSNick Dyer y = y % col_width; 2284566d533aSNick Dyer } else { 2285566d533aSNick Dyer col_width = info->matrix_ysize; 2286566d533aSNick Dyer } 2287566d533aSNick Dyer 2288566d533aSNick Dyer ofs = (y + (x * col_width)) * sizeof(u16); 2289d6a39404SNick Dyer page = ofs / MXT_DIAGNOSTIC_SIZE; 2290d6a39404SNick Dyer ofs %= MXT_DIAGNOSTIC_SIZE; 2291d6a39404SNick Dyer 2292566d533aSNick Dyer if (info->family_id == MXT_FAMILY_1386) 2293566d533aSNick Dyer page += col * MXT1386_PAGES_PER_COLUMN; 2294566d533aSNick Dyer 2295d6a39404SNick Dyer return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]); 2296d6a39404SNick Dyer } 2297d6a39404SNick Dyer 2298d6a39404SNick Dyer static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf) 2299d6a39404SNick Dyer { 2300d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2301d6a39404SNick Dyer unsigned int x = 0; 2302d6a39404SNick Dyer unsigned int y = 0; 2303de601f71SNick Dyer unsigned int i, rx, ry; 2304d6a39404SNick Dyer 2305d6a39404SNick Dyer for (i = 0; i < dbg->t37_nodes; i++) { 2306de601f71SNick Dyer /* Handle orientation */ 2307de601f71SNick Dyer rx = data->xy_switch ? y : x; 2308de601f71SNick Dyer ry = data->xy_switch ? x : y; 2309de601f71SNick Dyer rx = data->invertx ? (data->xsize - 1 - rx) : rx; 2310de601f71SNick Dyer ry = data->inverty ? (data->ysize - 1 - ry) : ry; 2311de601f71SNick Dyer 2312de601f71SNick Dyer outbuf[i] = mxt_get_debug_value(data, rx, ry); 2313d6a39404SNick Dyer 2314d6a39404SNick Dyer /* Next value */ 2315de601f71SNick Dyer if (++x >= (data->xy_switch ? data->ysize : data->xsize)) { 2316d6a39404SNick Dyer x = 0; 2317d6a39404SNick Dyer y++; 2318d6a39404SNick Dyer } 2319d6a39404SNick Dyer } 2320d6a39404SNick Dyer 2321d6a39404SNick Dyer return 0; 2322d6a39404SNick Dyer } 2323d6a39404SNick Dyer 2324d6a39404SNick Dyer static int mxt_read_diagnostic_debug(struct mxt_data *data, u8 mode, 2325d6a39404SNick Dyer u16 *outbuf) 2326d6a39404SNick Dyer { 2327d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2328d6a39404SNick Dyer int retries = 0; 2329d6a39404SNick Dyer int page; 2330d6a39404SNick Dyer int ret; 2331d6a39404SNick Dyer u8 cmd = mode; 2332d6a39404SNick Dyer struct t37_debug *p; 2333d6a39404SNick Dyer u8 cmd_poll; 2334d6a39404SNick Dyer 2335d6a39404SNick Dyer for (page = 0; page < dbg->t37_pages; page++) { 2336d6a39404SNick Dyer p = dbg->t37_buf + page; 2337d6a39404SNick Dyer 2338d6a39404SNick Dyer ret = mxt_write_reg(data->client, dbg->diag_cmd_address, 2339d6a39404SNick Dyer cmd); 2340d6a39404SNick Dyer if (ret) 2341d6a39404SNick Dyer return ret; 2342d6a39404SNick Dyer 2343d6a39404SNick Dyer retries = 0; 2344d6a39404SNick Dyer msleep(20); 2345d6a39404SNick Dyer wait_cmd: 2346d6a39404SNick Dyer /* Read back command byte */ 2347d6a39404SNick Dyer ret = __mxt_read_reg(data->client, dbg->diag_cmd_address, 2348d6a39404SNick Dyer sizeof(cmd_poll), &cmd_poll); 2349d6a39404SNick Dyer if (ret) 2350d6a39404SNick Dyer return ret; 2351d6a39404SNick Dyer 2352d6a39404SNick Dyer /* Field is cleared once the command has been processed */ 2353d6a39404SNick Dyer if (cmd_poll) { 2354d6a39404SNick Dyer if (retries++ > 100) 2355d6a39404SNick Dyer return -EINVAL; 2356d6a39404SNick Dyer 2357d6a39404SNick Dyer msleep(20); 2358d6a39404SNick Dyer goto wait_cmd; 2359d6a39404SNick Dyer } 2360d6a39404SNick Dyer 2361d6a39404SNick Dyer /* Read T37 page */ 2362d6a39404SNick Dyer ret = __mxt_read_reg(data->client, dbg->t37_address, 2363d6a39404SNick Dyer sizeof(struct t37_debug), p); 2364d6a39404SNick Dyer if (ret) 2365d6a39404SNick Dyer return ret; 2366d6a39404SNick Dyer 2367d6a39404SNick Dyer if (p->mode != mode || p->page != page) { 2368d6a39404SNick Dyer dev_err(&data->client->dev, "T37 page mismatch\n"); 2369d6a39404SNick Dyer return -EINVAL; 2370d6a39404SNick Dyer } 2371d6a39404SNick Dyer 2372d6a39404SNick Dyer dev_dbg(&data->client->dev, "%s page:%d retries:%d\n", 2373d6a39404SNick Dyer __func__, page, retries); 2374d6a39404SNick Dyer 2375d6a39404SNick Dyer /* For remaining pages, write PAGEUP rather than mode */ 2376d6a39404SNick Dyer cmd = MXT_DIAGNOSTIC_PAGEUP; 2377d6a39404SNick Dyer } 2378d6a39404SNick Dyer 2379d6a39404SNick Dyer return mxt_convert_debug_pages(data, outbuf); 2380d6a39404SNick Dyer } 2381d6a39404SNick Dyer 2382ecfdd7e2SNick Dyer static int mxt_queue_setup(struct vb2_queue *q, 2383ecfdd7e2SNick Dyer unsigned int *nbuffers, unsigned int *nplanes, 2384ecfdd7e2SNick Dyer unsigned int sizes[], struct device *alloc_devs[]) 2385ecfdd7e2SNick Dyer { 2386ecfdd7e2SNick Dyer struct mxt_data *data = q->drv_priv; 2387ecfdd7e2SNick Dyer size_t size = data->dbg.t37_nodes * sizeof(u16); 2388ecfdd7e2SNick Dyer 2389ecfdd7e2SNick Dyer if (*nplanes) 2390ecfdd7e2SNick Dyer return sizes[0] < size ? -EINVAL : 0; 2391ecfdd7e2SNick Dyer 2392ecfdd7e2SNick Dyer *nplanes = 1; 2393ecfdd7e2SNick Dyer sizes[0] = size; 2394ecfdd7e2SNick Dyer 2395ecfdd7e2SNick Dyer return 0; 2396ecfdd7e2SNick Dyer } 2397ecfdd7e2SNick Dyer 2398ecfdd7e2SNick Dyer static void mxt_buffer_queue(struct vb2_buffer *vb) 2399ecfdd7e2SNick Dyer { 2400ecfdd7e2SNick Dyer struct mxt_data *data = vb2_get_drv_priv(vb->vb2_queue); 2401ecfdd7e2SNick Dyer u16 *ptr; 2402ecfdd7e2SNick Dyer int ret; 240306b3d3f3SNick Dyer u8 mode; 2404ecfdd7e2SNick Dyer 2405ecfdd7e2SNick Dyer ptr = vb2_plane_vaddr(vb, 0); 2406ecfdd7e2SNick Dyer if (!ptr) { 2407ecfdd7e2SNick Dyer dev_err(&data->client->dev, "Error acquiring frame ptr\n"); 2408ecfdd7e2SNick Dyer goto fault; 2409ecfdd7e2SNick Dyer } 2410ecfdd7e2SNick Dyer 241106b3d3f3SNick Dyer switch (data->dbg.input) { 241206b3d3f3SNick Dyer case MXT_V4L_INPUT_DELTAS: 241306b3d3f3SNick Dyer default: 241406b3d3f3SNick Dyer mode = MXT_DIAGNOSTIC_DELTAS; 241506b3d3f3SNick Dyer break; 241606b3d3f3SNick Dyer 241706b3d3f3SNick Dyer case MXT_V4L_INPUT_REFS: 241806b3d3f3SNick Dyer mode = MXT_DIAGNOSTIC_REFS; 241906b3d3f3SNick Dyer break; 242006b3d3f3SNick Dyer } 242106b3d3f3SNick Dyer 242206b3d3f3SNick Dyer ret = mxt_read_diagnostic_debug(data, mode, ptr); 2423ecfdd7e2SNick Dyer if (ret) 2424ecfdd7e2SNick Dyer goto fault; 2425ecfdd7e2SNick Dyer 2426ecfdd7e2SNick Dyer vb2_set_plane_payload(vb, 0, data->dbg.t37_nodes * sizeof(u16)); 2427ecfdd7e2SNick Dyer vb2_buffer_done(vb, VB2_BUF_STATE_DONE); 2428ecfdd7e2SNick Dyer return; 2429ecfdd7e2SNick Dyer 2430ecfdd7e2SNick Dyer fault: 2431ecfdd7e2SNick Dyer vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); 2432ecfdd7e2SNick Dyer } 2433ecfdd7e2SNick Dyer 2434ecfdd7e2SNick Dyer /* V4L2 structures */ 2435ecfdd7e2SNick Dyer static const struct vb2_ops mxt_queue_ops = { 2436ecfdd7e2SNick Dyer .queue_setup = mxt_queue_setup, 2437ecfdd7e2SNick Dyer .buf_queue = mxt_buffer_queue, 2438ecfdd7e2SNick Dyer .wait_prepare = vb2_ops_wait_prepare, 2439ecfdd7e2SNick Dyer .wait_finish = vb2_ops_wait_finish, 2440ecfdd7e2SNick Dyer }; 2441ecfdd7e2SNick Dyer 2442ecfdd7e2SNick Dyer static const struct vb2_queue mxt_queue = { 2443ecfdd7e2SNick Dyer .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, 2444ecfdd7e2SNick Dyer .io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ, 2445ecfdd7e2SNick Dyer .buf_struct_size = sizeof(struct mxt_vb2_buffer), 2446ecfdd7e2SNick Dyer .ops = &mxt_queue_ops, 2447ecfdd7e2SNick Dyer .mem_ops = &vb2_vmalloc_memops, 2448ecfdd7e2SNick Dyer .timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC, 2449ecfdd7e2SNick Dyer .min_buffers_needed = 1, 2450ecfdd7e2SNick Dyer }; 2451ecfdd7e2SNick Dyer 2452ecfdd7e2SNick Dyer static int mxt_vidioc_querycap(struct file *file, void *priv, 2453ecfdd7e2SNick Dyer struct v4l2_capability *cap) 2454ecfdd7e2SNick Dyer { 2455ecfdd7e2SNick Dyer struct mxt_data *data = video_drvdata(file); 2456ecfdd7e2SNick Dyer 2457ecfdd7e2SNick Dyer strlcpy(cap->driver, "atmel_mxt_ts", sizeof(cap->driver)); 2458ecfdd7e2SNick Dyer strlcpy(cap->card, "atmel_mxt_ts touch", sizeof(cap->card)); 2459ecfdd7e2SNick Dyer snprintf(cap->bus_info, sizeof(cap->bus_info), 2460ecfdd7e2SNick Dyer "I2C:%s", dev_name(&data->client->dev)); 2461ecfdd7e2SNick Dyer return 0; 2462ecfdd7e2SNick Dyer } 2463ecfdd7e2SNick Dyer 2464ecfdd7e2SNick Dyer static int mxt_vidioc_enum_input(struct file *file, void *priv, 2465ecfdd7e2SNick Dyer struct v4l2_input *i) 2466ecfdd7e2SNick Dyer { 246706b3d3f3SNick Dyer if (i->index >= MXT_V4L_INPUT_MAX) 2468ecfdd7e2SNick Dyer return -EINVAL; 2469ecfdd7e2SNick Dyer 2470ecfdd7e2SNick Dyer i->type = V4L2_INPUT_TYPE_TOUCH; 247106b3d3f3SNick Dyer 247206b3d3f3SNick Dyer switch (i->index) { 247306b3d3f3SNick Dyer case MXT_V4L_INPUT_REFS: 247406b3d3f3SNick Dyer strlcpy(i->name, "Mutual Capacitance References", 247506b3d3f3SNick Dyer sizeof(i->name)); 247606b3d3f3SNick Dyer break; 247706b3d3f3SNick Dyer case MXT_V4L_INPUT_DELTAS: 2478ecfdd7e2SNick Dyer strlcpy(i->name, "Mutual Capacitance Deltas", sizeof(i->name)); 247906b3d3f3SNick Dyer break; 248006b3d3f3SNick Dyer } 248106b3d3f3SNick Dyer 2482ecfdd7e2SNick Dyer return 0; 2483ecfdd7e2SNick Dyer } 2484ecfdd7e2SNick Dyer 2485ecfdd7e2SNick Dyer static int mxt_set_input(struct mxt_data *data, unsigned int i) 2486ecfdd7e2SNick Dyer { 2487ecfdd7e2SNick Dyer struct v4l2_pix_format *f = &data->dbg.format; 2488ecfdd7e2SNick Dyer 248906b3d3f3SNick Dyer if (i >= MXT_V4L_INPUT_MAX) 2490ecfdd7e2SNick Dyer return -EINVAL; 2491ecfdd7e2SNick Dyer 249206b3d3f3SNick Dyer if (i == MXT_V4L_INPUT_DELTAS) 249306b3d3f3SNick Dyer f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; 249406b3d3f3SNick Dyer else 249506b3d3f3SNick Dyer f->pixelformat = V4L2_TCH_FMT_TU16; 249606b3d3f3SNick Dyer 2497de601f71SNick Dyer f->width = data->xy_switch ? data->ysize : data->xsize; 2498de601f71SNick Dyer f->height = data->xy_switch ? data->xsize : data->ysize; 2499ecfdd7e2SNick Dyer f->field = V4L2_FIELD_NONE; 2500ecfdd7e2SNick Dyer f->colorspace = V4L2_COLORSPACE_RAW; 2501ecfdd7e2SNick Dyer f->bytesperline = f->width * sizeof(u16); 2502ecfdd7e2SNick Dyer f->sizeimage = f->width * f->height * sizeof(u16); 2503ecfdd7e2SNick Dyer 2504ecfdd7e2SNick Dyer data->dbg.input = i; 2505ecfdd7e2SNick Dyer 2506ecfdd7e2SNick Dyer return 0; 2507ecfdd7e2SNick Dyer } 2508ecfdd7e2SNick Dyer 2509ecfdd7e2SNick Dyer static int mxt_vidioc_s_input(struct file *file, void *priv, unsigned int i) 2510ecfdd7e2SNick Dyer { 2511ecfdd7e2SNick Dyer return mxt_set_input(video_drvdata(file), i); 2512ecfdd7e2SNick Dyer } 2513ecfdd7e2SNick Dyer 2514ecfdd7e2SNick Dyer static int mxt_vidioc_g_input(struct file *file, void *priv, unsigned int *i) 2515ecfdd7e2SNick Dyer { 2516ecfdd7e2SNick Dyer struct mxt_data *data = video_drvdata(file); 2517ecfdd7e2SNick Dyer 2518ecfdd7e2SNick Dyer *i = data->dbg.input; 2519ecfdd7e2SNick Dyer 2520ecfdd7e2SNick Dyer return 0; 2521ecfdd7e2SNick Dyer } 2522ecfdd7e2SNick Dyer 2523ecfdd7e2SNick Dyer static int mxt_vidioc_fmt(struct file *file, void *priv, struct v4l2_format *f) 2524ecfdd7e2SNick Dyer { 2525ecfdd7e2SNick Dyer struct mxt_data *data = video_drvdata(file); 2526ecfdd7e2SNick Dyer 2527ecfdd7e2SNick Dyer f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2528ecfdd7e2SNick Dyer f->fmt.pix = data->dbg.format; 2529ecfdd7e2SNick Dyer 2530ecfdd7e2SNick Dyer return 0; 2531ecfdd7e2SNick Dyer } 2532ecfdd7e2SNick Dyer 2533ecfdd7e2SNick Dyer static int mxt_vidioc_enum_fmt(struct file *file, void *priv, 2534ecfdd7e2SNick Dyer struct v4l2_fmtdesc *fmt) 2535ecfdd7e2SNick Dyer { 2536ecfdd7e2SNick Dyer if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 2537ecfdd7e2SNick Dyer return -EINVAL; 2538ecfdd7e2SNick Dyer 253906b3d3f3SNick Dyer switch (fmt->index) { 254006b3d3f3SNick Dyer case 0: 254106b3d3f3SNick Dyer fmt->pixelformat = V4L2_TCH_FMT_TU16; 254206b3d3f3SNick Dyer break; 254306b3d3f3SNick Dyer 254406b3d3f3SNick Dyer case 1: 2545ecfdd7e2SNick Dyer fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD16; 254606b3d3f3SNick Dyer break; 254706b3d3f3SNick Dyer 254806b3d3f3SNick Dyer default: 254906b3d3f3SNick Dyer return -EINVAL; 255006b3d3f3SNick Dyer } 255106b3d3f3SNick Dyer 2552ecfdd7e2SNick Dyer return 0; 2553ecfdd7e2SNick Dyer } 2554ecfdd7e2SNick Dyer 2555ecfdd7e2SNick Dyer static int mxt_vidioc_g_parm(struct file *file, void *fh, 2556ecfdd7e2SNick Dyer struct v4l2_streamparm *a) 2557ecfdd7e2SNick Dyer { 2558ecfdd7e2SNick Dyer if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 2559ecfdd7e2SNick Dyer return -EINVAL; 2560ecfdd7e2SNick Dyer 2561ecfdd7e2SNick Dyer a->parm.capture.readbuffers = 1; 2562ecfdd7e2SNick Dyer a->parm.capture.timeperframe.numerator = 1; 2563ecfdd7e2SNick Dyer a->parm.capture.timeperframe.denominator = 10; 2564ecfdd7e2SNick Dyer return 0; 2565ecfdd7e2SNick Dyer } 2566ecfdd7e2SNick Dyer 2567ecfdd7e2SNick Dyer static const struct v4l2_ioctl_ops mxt_video_ioctl_ops = { 2568ecfdd7e2SNick Dyer .vidioc_querycap = mxt_vidioc_querycap, 2569ecfdd7e2SNick Dyer 2570ecfdd7e2SNick Dyer .vidioc_enum_fmt_vid_cap = mxt_vidioc_enum_fmt, 2571ecfdd7e2SNick Dyer .vidioc_s_fmt_vid_cap = mxt_vidioc_fmt, 2572ecfdd7e2SNick Dyer .vidioc_g_fmt_vid_cap = mxt_vidioc_fmt, 2573ecfdd7e2SNick Dyer .vidioc_try_fmt_vid_cap = mxt_vidioc_fmt, 2574ecfdd7e2SNick Dyer .vidioc_g_parm = mxt_vidioc_g_parm, 2575ecfdd7e2SNick Dyer 2576ecfdd7e2SNick Dyer .vidioc_enum_input = mxt_vidioc_enum_input, 2577ecfdd7e2SNick Dyer .vidioc_g_input = mxt_vidioc_g_input, 2578ecfdd7e2SNick Dyer .vidioc_s_input = mxt_vidioc_s_input, 2579ecfdd7e2SNick Dyer 2580ecfdd7e2SNick Dyer .vidioc_reqbufs = vb2_ioctl_reqbufs, 2581ecfdd7e2SNick Dyer .vidioc_create_bufs = vb2_ioctl_create_bufs, 2582ecfdd7e2SNick Dyer .vidioc_querybuf = vb2_ioctl_querybuf, 2583ecfdd7e2SNick Dyer .vidioc_qbuf = vb2_ioctl_qbuf, 2584ecfdd7e2SNick Dyer .vidioc_dqbuf = vb2_ioctl_dqbuf, 2585ecfdd7e2SNick Dyer .vidioc_expbuf = vb2_ioctl_expbuf, 2586ecfdd7e2SNick Dyer 2587ecfdd7e2SNick Dyer .vidioc_streamon = vb2_ioctl_streamon, 2588ecfdd7e2SNick Dyer .vidioc_streamoff = vb2_ioctl_streamoff, 2589ecfdd7e2SNick Dyer }; 2590ecfdd7e2SNick Dyer 2591ecfdd7e2SNick Dyer static const struct video_device mxt_video_device = { 2592ecfdd7e2SNick Dyer .name = "Atmel maxTouch", 2593ecfdd7e2SNick Dyer .fops = &mxt_video_fops, 2594ecfdd7e2SNick Dyer .ioctl_ops = &mxt_video_ioctl_ops, 2595ecfdd7e2SNick Dyer .release = video_device_release_empty, 2596ecfdd7e2SNick Dyer .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH | 2597ecfdd7e2SNick Dyer V4L2_CAP_READWRITE | V4L2_CAP_STREAMING, 2598ecfdd7e2SNick Dyer }; 2599ecfdd7e2SNick Dyer 2600d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data) 2601d6a39404SNick Dyer { 2602068bdb67SNick Dyer struct mxt_info *info = data->info; 2603d6a39404SNick Dyer struct mxt_dbg *dbg = &data->dbg; 2604d6a39404SNick Dyer struct mxt_object *object; 2605ecfdd7e2SNick Dyer int error; 2606d6a39404SNick Dyer 2607d6a39404SNick Dyer object = mxt_get_object(data, MXT_GEN_COMMAND_T6); 2608d6a39404SNick Dyer if (!object) 2609d6a39404SNick Dyer goto error; 2610d6a39404SNick Dyer 2611d6a39404SNick Dyer dbg->diag_cmd_address = object->start_address + MXT_COMMAND_DIAGNOSTIC; 2612d6a39404SNick Dyer 2613d6a39404SNick Dyer object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37); 2614d6a39404SNick Dyer if (!object) 2615d6a39404SNick Dyer goto error; 2616d6a39404SNick Dyer 2617d6a39404SNick Dyer if (mxt_obj_size(object) != sizeof(struct t37_debug)) { 2618d6a39404SNick Dyer dev_warn(&data->client->dev, "Bad T37 size"); 2619d6a39404SNick Dyer goto error; 2620d6a39404SNick Dyer } 2621d6a39404SNick Dyer 2622d6a39404SNick Dyer dbg->t37_address = object->start_address; 2623d6a39404SNick Dyer 2624d6a39404SNick Dyer /* Calculate size of data and allocate buffer */ 26252786489fSNick Dyer dbg->t37_nodes = data->xsize * data->ysize; 2626566d533aSNick Dyer 2627566d533aSNick Dyer if (info->family_id == MXT_FAMILY_1386) 2628566d533aSNick Dyer dbg->t37_pages = MXT1386_COLUMNS * MXT1386_PAGES_PER_COLUMN; 2629566d533aSNick Dyer else 2630566d533aSNick Dyer dbg->t37_pages = DIV_ROUND_UP(data->xsize * 2631d7ddf154SGuenter Roeck info->matrix_ysize * 2632566d533aSNick Dyer sizeof(u16), 2633566d533aSNick Dyer sizeof(dbg->t37_buf->data)); 2634d6a39404SNick Dyer 2635d6a39404SNick Dyer dbg->t37_buf = devm_kmalloc_array(&data->client->dev, dbg->t37_pages, 2636d6a39404SNick Dyer sizeof(struct t37_debug), GFP_KERNEL); 2637d6a39404SNick Dyer if (!dbg->t37_buf) 2638d6a39404SNick Dyer goto error; 2639d6a39404SNick Dyer 2640ecfdd7e2SNick Dyer /* init channel to zero */ 2641ecfdd7e2SNick Dyer mxt_set_input(data, 0); 2642ecfdd7e2SNick Dyer 2643ecfdd7e2SNick Dyer /* register video device */ 2644ecfdd7e2SNick Dyer snprintf(dbg->v4l2.name, sizeof(dbg->v4l2.name), "%s", "atmel_mxt_ts"); 2645ecfdd7e2SNick Dyer error = v4l2_device_register(&data->client->dev, &dbg->v4l2); 2646ecfdd7e2SNick Dyer if (error) 2647ecfdd7e2SNick Dyer goto error; 2648ecfdd7e2SNick Dyer 2649ecfdd7e2SNick Dyer /* initialize the queue */ 2650ecfdd7e2SNick Dyer mutex_init(&dbg->lock); 2651ecfdd7e2SNick Dyer dbg->queue = mxt_queue; 2652ecfdd7e2SNick Dyer dbg->queue.drv_priv = data; 2653ecfdd7e2SNick Dyer dbg->queue.lock = &dbg->lock; 2654ecfdd7e2SNick Dyer dbg->queue.dev = &data->client->dev; 2655ecfdd7e2SNick Dyer 2656ecfdd7e2SNick Dyer error = vb2_queue_init(&dbg->queue); 2657ecfdd7e2SNick Dyer if (error) 2658ecfdd7e2SNick Dyer goto error_unreg_v4l2; 2659ecfdd7e2SNick Dyer 2660ecfdd7e2SNick Dyer dbg->vdev = mxt_video_device; 2661ecfdd7e2SNick Dyer dbg->vdev.v4l2_dev = &dbg->v4l2; 2662ecfdd7e2SNick Dyer dbg->vdev.lock = &dbg->lock; 2663ecfdd7e2SNick Dyer dbg->vdev.vfl_dir = VFL_DIR_RX; 2664ecfdd7e2SNick Dyer dbg->vdev.queue = &dbg->queue; 2665ecfdd7e2SNick Dyer video_set_drvdata(&dbg->vdev, data); 2666ecfdd7e2SNick Dyer 2667ecfdd7e2SNick Dyer error = video_register_device(&dbg->vdev, VFL_TYPE_TOUCH, -1); 2668ecfdd7e2SNick Dyer if (error) 2669ecfdd7e2SNick Dyer goto error_unreg_v4l2; 2670ecfdd7e2SNick Dyer 2671d6a39404SNick Dyer return; 2672d6a39404SNick Dyer 2673ecfdd7e2SNick Dyer error_unreg_v4l2: 2674ecfdd7e2SNick Dyer v4l2_device_unregister(&dbg->v4l2); 2675d6a39404SNick Dyer error: 2676d6a39404SNick Dyer dev_warn(&data->client->dev, "Error initializing T37\n"); 2677d6a39404SNick Dyer } 2678d6a39404SNick Dyer #else 2679d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data) 2680d6a39404SNick Dyer { 2681d6a39404SNick Dyer } 2682d6a39404SNick Dyer #endif 2683d6a39404SNick Dyer 268450a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data, 268550a77c65SNick Dyer const struct firmware *cfg) 268650a77c65SNick Dyer { 268750a77c65SNick Dyer struct device *dev = &data->client->dev; 268850a77c65SNick Dyer int error; 268950a77c65SNick Dyer 26907f3884f7SNick Dyer error = mxt_init_t7_power_cfg(data); 26917f3884f7SNick Dyer if (error) { 26927f3884f7SNick Dyer dev_err(dev, "Failed to initialize power cfg\n"); 26937f3884f7SNick Dyer return error; 26947f3884f7SNick Dyer } 26957f3884f7SNick Dyer 269650a77c65SNick Dyer if (cfg) { 269750a77c65SNick Dyer error = mxt_update_cfg(data, cfg); 269850a77c65SNick Dyer if (error) 269950a77c65SNick Dyer dev_warn(dev, "Error %d updating config\n", error); 270050a77c65SNick Dyer } 270150a77c65SNick Dyer 2702b23157dcSNick Dyer if (data->multitouch) { 2703b23157dcSNick Dyer error = mxt_initialize_input_device(data); 270450a77c65SNick Dyer if (error) 270550a77c65SNick Dyer return error; 2706b23157dcSNick Dyer } else { 2707b23157dcSNick Dyer dev_warn(dev, "No touch object detected\n"); 2708b23157dcSNick Dyer } 270950a77c65SNick Dyer 2710d6a39404SNick Dyer mxt_debug_init(data); 2711d6a39404SNick Dyer 271250a77c65SNick Dyer return 0; 271350a77c65SNick Dyer } 271450a77c65SNick Dyer 2715b19fc9ecSDaniel Kurtz /* Firmware Version is returned as Major.Minor.Build */ 2716b19fc9ecSDaniel Kurtz static ssize_t mxt_fw_version_show(struct device *dev, 2717b19fc9ecSDaniel Kurtz struct device_attribute *attr, char *buf) 2718b19fc9ecSDaniel Kurtz { 2719b19fc9ecSDaniel Kurtz struct mxt_data *data = dev_get_drvdata(dev); 2720068bdb67SNick Dyer struct mxt_info *info = data->info; 2721b19fc9ecSDaniel Kurtz return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n", 2722b19fc9ecSDaniel Kurtz info->version >> 4, info->version & 0xf, info->build); 2723b19fc9ecSDaniel Kurtz } 2724b19fc9ecSDaniel Kurtz 2725b19fc9ecSDaniel Kurtz /* Hardware Version is returned as FamilyID.VariantID */ 2726b19fc9ecSDaniel Kurtz static ssize_t mxt_hw_version_show(struct device *dev, 2727b19fc9ecSDaniel Kurtz struct device_attribute *attr, char *buf) 2728b19fc9ecSDaniel Kurtz { 2729b19fc9ecSDaniel Kurtz struct mxt_data *data = dev_get_drvdata(dev); 2730068bdb67SNick Dyer struct mxt_info *info = data->info; 2731b19fc9ecSDaniel Kurtz return scnprintf(buf, PAGE_SIZE, "%u.%u\n", 2732b19fc9ecSDaniel Kurtz info->family_id, info->variant_id); 2733b19fc9ecSDaniel Kurtz } 2734b19fc9ecSDaniel Kurtz 2735794eb67eSDaniel Kurtz static ssize_t mxt_show_instance(char *buf, int count, 2736794eb67eSDaniel Kurtz struct mxt_object *object, int instance, 2737794eb67eSDaniel Kurtz const u8 *val) 2738794eb67eSDaniel Kurtz { 2739794eb67eSDaniel Kurtz int i; 2740794eb67eSDaniel Kurtz 27411e0c0c5bSDaniel Kurtz if (mxt_obj_instances(object) > 1) 2742794eb67eSDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, 2743794eb67eSDaniel Kurtz "Instance %u\n", instance); 2744794eb67eSDaniel Kurtz 27451e0c0c5bSDaniel Kurtz for (i = 0; i < mxt_obj_size(object); i++) 2746794eb67eSDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, 2747794eb67eSDaniel Kurtz "\t[%2u]: %02x (%d)\n", i, val[i], val[i]); 2748794eb67eSDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); 2749794eb67eSDaniel Kurtz 2750794eb67eSDaniel Kurtz return count; 2751794eb67eSDaniel Kurtz } 2752794eb67eSDaniel Kurtz 27537686b108SIiro Valkonen static ssize_t mxt_object_show(struct device *dev, 27544cf51c38SJoonyoung Shim struct device_attribute *attr, char *buf) 27554cf51c38SJoonyoung Shim { 27567686b108SIiro Valkonen struct mxt_data *data = dev_get_drvdata(dev); 27577686b108SIiro Valkonen struct mxt_object *object; 27584cf51c38SJoonyoung Shim int count = 0; 27594cf51c38SJoonyoung Shim int i, j; 27604cf51c38SJoonyoung Shim int error; 276143a91d51SDaniel Kurtz u8 *obuf; 27624cf51c38SJoonyoung Shim 276343a91d51SDaniel Kurtz /* Pre-allocate buffer large enough to hold max sized object. */ 276443a91d51SDaniel Kurtz obuf = kmalloc(256, GFP_KERNEL); 276543a91d51SDaniel Kurtz if (!obuf) 276643a91d51SDaniel Kurtz return -ENOMEM; 276743a91d51SDaniel Kurtz 276843a91d51SDaniel Kurtz error = 0; 2769068bdb67SNick Dyer for (i = 0; i < data->info->object_num; i++) { 27704cf51c38SJoonyoung Shim object = data->object_table + i; 27714cf51c38SJoonyoung Shim 277291630955SDaniel Kurtz if (!mxt_object_readable(object->type)) 27734cf51c38SJoonyoung Shim continue; 27744cf51c38SJoonyoung Shim 277591630955SDaniel Kurtz count += scnprintf(buf + count, PAGE_SIZE - count, 277691630955SDaniel Kurtz "T%u:\n", object->type); 27774cf51c38SJoonyoung Shim 27781e0c0c5bSDaniel Kurtz for (j = 0; j < mxt_obj_instances(object); j++) { 27791e0c0c5bSDaniel Kurtz u16 size = mxt_obj_size(object); 2780794eb67eSDaniel Kurtz u16 addr = object->start_address + j * size; 2781794eb67eSDaniel Kurtz 2782794eb67eSDaniel Kurtz error = __mxt_read_reg(data->client, addr, size, obuf); 27834cf51c38SJoonyoung Shim if (error) 2784794eb67eSDaniel Kurtz goto done; 27854cf51c38SJoonyoung Shim 2786794eb67eSDaniel Kurtz count = mxt_show_instance(buf, count, object, j, obuf); 27874cf51c38SJoonyoung Shim } 27884cf51c38SJoonyoung Shim } 27894cf51c38SJoonyoung Shim 2790794eb67eSDaniel Kurtz done: 279143a91d51SDaniel Kurtz kfree(obuf); 279243a91d51SDaniel Kurtz return error ?: count; 27934cf51c38SJoonyoung Shim } 27944cf51c38SJoonyoung Shim 2795f2ac6cb9SNick Dyer static int mxt_check_firmware_format(struct device *dev, 2796f2ac6cb9SNick Dyer const struct firmware *fw) 2797f2ac6cb9SNick Dyer { 2798f2ac6cb9SNick Dyer unsigned int pos = 0; 2799f2ac6cb9SNick Dyer char c; 2800f2ac6cb9SNick Dyer 2801f2ac6cb9SNick Dyer while (pos < fw->size) { 2802f2ac6cb9SNick Dyer c = *(fw->data + pos); 2803f2ac6cb9SNick Dyer 2804f2ac6cb9SNick Dyer if (c < '0' || (c > '9' && c < 'A') || c > 'F') 2805f2ac6cb9SNick Dyer return 0; 2806f2ac6cb9SNick Dyer 2807f2ac6cb9SNick Dyer pos++; 2808f2ac6cb9SNick Dyer } 2809f2ac6cb9SNick Dyer 2810f2ac6cb9SNick Dyer /* 2811f2ac6cb9SNick Dyer * To convert file try: 2812f2ac6cb9SNick Dyer * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw 2813f2ac6cb9SNick Dyer */ 2814f2ac6cb9SNick Dyer dev_err(dev, "Aborting: firmware file must be in binary format\n"); 2815f2ac6cb9SNick Dyer 2816f2ac6cb9SNick Dyer return -EINVAL; 2817f2ac6cb9SNick Dyer } 2818f2ac6cb9SNick Dyer 28197686b108SIiro Valkonen static int mxt_load_fw(struct device *dev, const char *fn) 28204cf51c38SJoonyoung Shim { 28217686b108SIiro Valkonen struct mxt_data *data = dev_get_drvdata(dev); 28224cf51c38SJoonyoung Shim const struct firmware *fw = NULL; 28234cf51c38SJoonyoung Shim unsigned int frame_size; 28244cf51c38SJoonyoung Shim unsigned int pos = 0; 2825f943c74aSNick Dyer unsigned int retry = 0; 2826f477c758SNick Dyer unsigned int frame = 0; 28274cf51c38SJoonyoung Shim int ret; 28284cf51c38SJoonyoung Shim 28294cf51c38SJoonyoung Shim ret = request_firmware(&fw, fn, dev); 28304cf51c38SJoonyoung Shim if (ret) { 28314cf51c38SJoonyoung Shim dev_err(dev, "Unable to open firmware %s\n", fn); 28324cf51c38SJoonyoung Shim return ret; 28334cf51c38SJoonyoung Shim } 28344cf51c38SJoonyoung Shim 2835f2ac6cb9SNick Dyer /* Check for incorrect enc file */ 2836f2ac6cb9SNick Dyer ret = mxt_check_firmware_format(dev, fw); 2837f2ac6cb9SNick Dyer if (ret) 2838f2ac6cb9SNick Dyer goto release_firmware; 2839f2ac6cb9SNick Dyer 2840a9fdd1e6SNick Dyer if (!data->in_bootloader) { 28414cf51c38SJoonyoung Shim /* Change to the bootloader mode */ 2842d79e7e47SBenson Leung data->in_bootloader = true; 2843d79e7e47SBenson Leung 2844a9fdd1e6SNick Dyer ret = mxt_t6_command(data, MXT_COMMAND_RESET, 2845a9fdd1e6SNick Dyer MXT_BOOT_VALUE, false); 2846a4a2ef46SIiro Valkonen if (ret) 2847a4a2ef46SIiro Valkonen goto release_firmware; 2848a4a2ef46SIiro Valkonen 28497686b108SIiro Valkonen msleep(MXT_RESET_TIME); 28508efaa5e5SNick Dyer 28518efaa5e5SNick Dyer /* Do not need to scan since we know family ID */ 28528efaa5e5SNick Dyer ret = mxt_lookup_bootloader_address(data, 0); 28538efaa5e5SNick Dyer if (ret) 28548efaa5e5SNick Dyer goto release_firmware; 285558e4aeeeSStephen Warren 285658e4aeeeSStephen Warren mxt_free_input_device(data); 285758e4aeeeSStephen Warren mxt_free_object_table(data); 28588efaa5e5SNick Dyer } else { 28598efaa5e5SNick Dyer enable_irq(data->irq); 2860a9fdd1e6SNick Dyer } 28614cf51c38SJoonyoung Shim 2862d79e7e47SBenson Leung reinit_completion(&data->bl_completion); 2863d79e7e47SBenson Leung 2864385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false); 2865385deb96SNick Dyer if (ret) { 2866385deb96SNick Dyer /* Bootloader may still be unlocked from previous attempt */ 2867385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false); 28684cf51c38SJoonyoung Shim if (ret) 2869d79e7e47SBenson Leung goto disable_irq; 2870385deb96SNick Dyer } else { 2871385deb96SNick Dyer dev_info(dev, "Unlocking bootloader\n"); 28724cf51c38SJoonyoung Shim 28734cf51c38SJoonyoung Shim /* Unlock bootloader */ 28748efaa5e5SNick Dyer ret = mxt_send_bootloader_cmd(data, true); 2875385deb96SNick Dyer if (ret) 2876385deb96SNick Dyer goto disable_irq; 2877385deb96SNick Dyer } 28784cf51c38SJoonyoung Shim 28794cf51c38SJoonyoung Shim while (pos < fw->size) { 2880385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true); 28814cf51c38SJoonyoung Shim if (ret) 2882d79e7e47SBenson Leung goto disable_irq; 28834cf51c38SJoonyoung Shim 28844cf51c38SJoonyoung Shim frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); 28854cf51c38SJoonyoung Shim 2886f943c74aSNick Dyer /* Take account of CRC bytes */ 28874cf51c38SJoonyoung Shim frame_size += 2; 28884cf51c38SJoonyoung Shim 28894cf51c38SJoonyoung Shim /* Write one frame to device */ 2890f28a842dSNick Dyer ret = mxt_bootloader_write(data, fw->data + pos, frame_size); 2891f28a842dSNick Dyer if (ret) 2892f28a842dSNick Dyer goto disable_irq; 28934cf51c38SJoonyoung Shim 2894385deb96SNick Dyer ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true); 2895f943c74aSNick Dyer if (ret) { 2896f943c74aSNick Dyer retry++; 28974cf51c38SJoonyoung Shim 2898f943c74aSNick Dyer /* Back off by 20ms per retry */ 2899f943c74aSNick Dyer msleep(retry * 20); 2900f943c74aSNick Dyer 2901f943c74aSNick Dyer if (retry > 20) { 2902f943c74aSNick Dyer dev_err(dev, "Retry count exceeded\n"); 2903f943c74aSNick Dyer goto disable_irq; 2904f943c74aSNick Dyer } 2905f943c74aSNick Dyer } else { 2906f943c74aSNick Dyer retry = 0; 29074cf51c38SJoonyoung Shim pos += frame_size; 2908f477c758SNick Dyer frame++; 2909f943c74aSNick Dyer } 29104cf51c38SJoonyoung Shim 2911f477c758SNick Dyer if (frame % 50 == 0) 2912f477c758SNick Dyer dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n", 2913f477c758SNick Dyer frame, pos, fw->size); 29144cf51c38SJoonyoung Shim } 29154cf51c38SJoonyoung Shim 2916a0434b75SBenson Leung /* Wait for flash. */ 2917a4a2ef46SIiro Valkonen ret = mxt_wait_for_completion(data, &data->bl_completion, 2918a4a2ef46SIiro Valkonen MXT_FW_RESET_TIME); 2919a0434b75SBenson Leung if (ret) 2920a0434b75SBenson Leung goto disable_irq; 2921a0434b75SBenson Leung 2922f477c758SNick Dyer dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos); 2923f477c758SNick Dyer 2924a0434b75SBenson Leung /* 2925a0434b75SBenson Leung * Wait for device to reset. Some bootloader versions do not assert 2926a0434b75SBenson Leung * the CHG line after bootloading has finished, so ignore potential 2927a0434b75SBenson Leung * errors. 2928a0434b75SBenson Leung */ 2929a4a2ef46SIiro Valkonen mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME); 2930a0434b75SBenson Leung 2931d79e7e47SBenson Leung data->in_bootloader = false; 2932d79e7e47SBenson Leung 2933d79e7e47SBenson Leung disable_irq: 2934d79e7e47SBenson Leung disable_irq(data->irq); 2935a4a2ef46SIiro Valkonen release_firmware: 29364cf51c38SJoonyoung Shim release_firmware(fw); 29374cf51c38SJoonyoung Shim return ret; 29384cf51c38SJoonyoung Shim } 29394cf51c38SJoonyoung Shim 29407686b108SIiro Valkonen static ssize_t mxt_update_fw_store(struct device *dev, 29414cf51c38SJoonyoung Shim struct device_attribute *attr, 29424cf51c38SJoonyoung Shim const char *buf, size_t count) 29434cf51c38SJoonyoung Shim { 29447686b108SIiro Valkonen struct mxt_data *data = dev_get_drvdata(dev); 29454cf51c38SJoonyoung Shim int error; 29464cf51c38SJoonyoung Shim 29477686b108SIiro Valkonen error = mxt_load_fw(dev, MXT_FW_NAME); 29484cf51c38SJoonyoung Shim if (error) { 29494cf51c38SJoonyoung Shim dev_err(dev, "The firmware update failed(%d)\n", error); 29504cf51c38SJoonyoung Shim count = error; 29514cf51c38SJoonyoung Shim } else { 29527bed6805SNick Dyer dev_info(dev, "The firmware update succeeded\n"); 29537bed6805SNick Dyer 2954dd24dcf5SNick Dyer error = mxt_initialize(data); 295508960a07SIiro Valkonen if (error) 295608960a07SIiro Valkonen return error; 2957d79e7e47SBenson Leung } 295808960a07SIiro Valkonen 29594cf51c38SJoonyoung Shim return count; 29604cf51c38SJoonyoung Shim } 29614cf51c38SJoonyoung Shim 2962b19fc9ecSDaniel Kurtz static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL); 2963b19fc9ecSDaniel Kurtz static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL); 296471b3e938SDaniel Kurtz static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL); 296571b3e938SDaniel Kurtz static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store); 29664cf51c38SJoonyoung Shim 29677686b108SIiro Valkonen static struct attribute *mxt_attrs[] = { 2968b19fc9ecSDaniel Kurtz &dev_attr_fw_version.attr, 2969b19fc9ecSDaniel Kurtz &dev_attr_hw_version.attr, 29704cf51c38SJoonyoung Shim &dev_attr_object.attr, 29714cf51c38SJoonyoung Shim &dev_attr_update_fw.attr, 29724cf51c38SJoonyoung Shim NULL 29734cf51c38SJoonyoung Shim }; 29744cf51c38SJoonyoung Shim 29757686b108SIiro Valkonen static const struct attribute_group mxt_attr_group = { 29767686b108SIiro Valkonen .attrs = mxt_attrs, 29774cf51c38SJoonyoung Shim }; 29784cf51c38SJoonyoung Shim 29797686b108SIiro Valkonen static void mxt_start(struct mxt_data *data) 29804cf51c38SJoonyoung Shim { 2981d80808e1SDmitry Torokhov switch (data->suspend_mode) { 29827f3884f7SNick Dyer case MXT_SUSPEND_T9_CTRL: 29837f3884f7SNick Dyer mxt_soft_reset(data); 29847f3884f7SNick Dyer 29857f405483SLinus Torvalds /* Touch enable */ 29867f3884f7SNick Dyer /* 0x83 = SCANEN | RPTEN | ENABLE */ 29877f3884f7SNick Dyer mxt_write_object(data, 29887f3884f7SNick Dyer MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83); 29897f3884f7SNick Dyer break; 29907f3884f7SNick Dyer 29917f3884f7SNick Dyer case MXT_SUSPEND_DEEP_SLEEP: 29927f3884f7SNick Dyer default: 29937f3884f7SNick Dyer mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); 29947f3884f7SNick Dyer 29957f3884f7SNick Dyer /* Recalibrate since chip has been in deep sleep */ 29967f3884f7SNick Dyer mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); 29977f3884f7SNick Dyer break; 29987f3884f7SNick Dyer } 29994cf51c38SJoonyoung Shim } 30004cf51c38SJoonyoung Shim 30017686b108SIiro Valkonen static void mxt_stop(struct mxt_data *data) 30024cf51c38SJoonyoung Shim { 3003d80808e1SDmitry Torokhov switch (data->suspend_mode) { 30047f3884f7SNick Dyer case MXT_SUSPEND_T9_CTRL: 30057f405483SLinus Torvalds /* Touch disable */ 30067f3884f7SNick Dyer mxt_write_object(data, 30077f3884f7SNick Dyer MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0); 30087f3884f7SNick Dyer break; 30097f3884f7SNick Dyer 30107f3884f7SNick Dyer case MXT_SUSPEND_DEEP_SLEEP: 30117f3884f7SNick Dyer default: 30127f3884f7SNick Dyer mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); 30137f3884f7SNick Dyer break; 30147f3884f7SNick Dyer } 30154cf51c38SJoonyoung Shim } 30164cf51c38SJoonyoung Shim 30177686b108SIiro Valkonen static int mxt_input_open(struct input_dev *dev) 30184cf51c38SJoonyoung Shim { 30197686b108SIiro Valkonen struct mxt_data *data = input_get_drvdata(dev); 30204cf51c38SJoonyoung Shim 30217686b108SIiro Valkonen mxt_start(data); 30224cf51c38SJoonyoung Shim 30234cf51c38SJoonyoung Shim return 0; 30244cf51c38SJoonyoung Shim } 30254cf51c38SJoonyoung Shim 30267686b108SIiro Valkonen static void mxt_input_close(struct input_dev *dev) 30274cf51c38SJoonyoung Shim { 30287686b108SIiro Valkonen struct mxt_data *data = input_get_drvdata(dev); 30294cf51c38SJoonyoung Shim 30307686b108SIiro Valkonen mxt_stop(data); 30314cf51c38SJoonyoung Shim } 30324cf51c38SJoonyoung Shim 303396a938aaSDmitry Torokhov static int mxt_parse_device_properties(struct mxt_data *data) 303478188be3SStephen Warren { 303593afb1d6SDmitry Torokhov static const char keymap_property[] = "linux,gpio-keymap"; 303696a938aaSDmitry Torokhov struct device *dev = &data->client->dev; 303778188be3SStephen Warren u32 *keymap; 303893afb1d6SDmitry Torokhov int n_keys; 303993afb1d6SDmitry Torokhov int error; 304078188be3SStephen Warren 304196a938aaSDmitry Torokhov if (device_property_present(dev, keymap_property)) { 30429ed05c94SAndy Shevchenko n_keys = device_property_count_u32(dev, keymap_property); 304393afb1d6SDmitry Torokhov if (n_keys <= 0) { 304493afb1d6SDmitry Torokhov error = n_keys < 0 ? n_keys : -EINVAL; 304596a938aaSDmitry Torokhov dev_err(dev, "invalid/malformed '%s' property: %d\n", 304693afb1d6SDmitry Torokhov keymap_property, error); 304796a938aaSDmitry Torokhov return error; 304893afb1d6SDmitry Torokhov } 304978188be3SStephen Warren 305096a938aaSDmitry Torokhov keymap = devm_kmalloc_array(dev, n_keys, sizeof(*keymap), 305178188be3SStephen Warren GFP_KERNEL); 305278188be3SStephen Warren if (!keymap) 305396a938aaSDmitry Torokhov return -ENOMEM; 305478188be3SStephen Warren 305596a938aaSDmitry Torokhov error = device_property_read_u32_array(dev, keymap_property, 305693afb1d6SDmitry Torokhov keymap, n_keys); 305793afb1d6SDmitry Torokhov if (error) { 305896a938aaSDmitry Torokhov dev_err(dev, "failed to parse '%s' property: %d\n", 305993afb1d6SDmitry Torokhov keymap_property, error); 306096a938aaSDmitry Torokhov return error; 306193afb1d6SDmitry Torokhov } 306278188be3SStephen Warren 306396a938aaSDmitry Torokhov data->t19_keymap = keymap; 306496a938aaSDmitry Torokhov data->t19_num_keys = n_keys; 306578188be3SStephen Warren } 306678188be3SStephen Warren 306796a938aaSDmitry Torokhov return 0; 306878188be3SStephen Warren } 306978188be3SStephen Warren 3070d80808e1SDmitry Torokhov static const struct dmi_system_id chromebook_T9_suspend_dmi[] = { 3071d80808e1SDmitry Torokhov { 3072d80808e1SDmitry Torokhov .matches = { 3073d80808e1SDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 3074d80808e1SDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "Link"), 3075d80808e1SDmitry Torokhov }, 3076d80808e1SDmitry Torokhov }, 3077d80808e1SDmitry Torokhov { 3078d80808e1SDmitry Torokhov .matches = { 3079d80808e1SDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"), 3080d80808e1SDmitry Torokhov }, 3081d80808e1SDmitry Torokhov }, 3082d80808e1SDmitry Torokhov { } 3083d80808e1SDmitry Torokhov }; 3084d80808e1SDmitry Torokhov 308578188be3SStephen Warren static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) 30864cf51c38SJoonyoung Shim { 30877686b108SIiro Valkonen struct mxt_data *data; 30884cf51c38SJoonyoung Shim int error; 30894cf51c38SJoonyoung Shim 309096a938aaSDmitry Torokhov /* 30917cf432bfSDmitry Torokhov * Ignore devices that do not have device properties attached to 30927cf432bfSDmitry Torokhov * them, as we need help determining whether we are dealing with 30937cf432bfSDmitry Torokhov * touch screen or touchpad. 30947cf432bfSDmitry Torokhov * 30957cf432bfSDmitry Torokhov * So far on x86 the only users of Atmel touch controllers are 30967cf432bfSDmitry Torokhov * Chromebooks, and chromeos_laptop driver will ensure that 30977cf432bfSDmitry Torokhov * necessary properties are provided (if firmware does not do that). 30987cf432bfSDmitry Torokhov */ 30997cf432bfSDmitry Torokhov if (!device_property_present(&client->dev, "compatible")) 31007cf432bfSDmitry Torokhov return -ENXIO; 31017cf432bfSDmitry Torokhov 31027cf432bfSDmitry Torokhov /* 310396a938aaSDmitry Torokhov * Ignore ACPI devices representing bootloader mode. 310496a938aaSDmitry Torokhov * 310596a938aaSDmitry Torokhov * This is a bit of a hack: Google Chromebook BIOS creates ACPI 310696a938aaSDmitry Torokhov * devices for both application and bootloader modes, but we are 310796a938aaSDmitry Torokhov * interested in application mode only (if device is in bootloader 310896a938aaSDmitry Torokhov * mode we'll end up switching into application anyway). So far 310996a938aaSDmitry Torokhov * application mode addresses were all above 0x40, so we'll use it 311096a938aaSDmitry Torokhov * as a threshold. 311196a938aaSDmitry Torokhov */ 311296a938aaSDmitry Torokhov if (ACPI_COMPANION(&client->dev) && client->addr < 0x40) 311396a938aaSDmitry Torokhov return -ENXIO; 31144cf51c38SJoonyoung Shim 31158cc8446bSSebastian Reichel data = devm_kzalloc(&client->dev, sizeof(struct mxt_data), GFP_KERNEL); 31168cc8446bSSebastian Reichel if (!data) 31177a53d609SNick Dyer return -ENOMEM; 31184cf51c38SJoonyoung Shim 3119ec02ac2bSDaniel Kurtz snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0", 3120ec02ac2bSDaniel Kurtz client->adapter->nr, client->addr); 312122dfab7fSDaniel Kurtz 3122910d8051SJoonyoung Shim data->client = client; 3123910d8051SJoonyoung Shim data->irq = client->irq; 31247a53d609SNick Dyer i2c_set_clientdata(client, data); 3125910d8051SJoonyoung Shim 3126d79e7e47SBenson Leung init_completion(&data->bl_completion); 3127a4a2ef46SIiro Valkonen init_completion(&data->reset_completion); 3128c3f78043SNick Dyer init_completion(&data->crc_completion); 3129d79e7e47SBenson Leung 3130d80808e1SDmitry Torokhov data->suspend_mode = dmi_check_system(chromebook_T9_suspend_dmi) ? 3131d80808e1SDmitry Torokhov MXT_SUSPEND_T9_CTRL : MXT_SUSPEND_DEEP_SLEEP; 3132d80808e1SDmitry Torokhov 313396a938aaSDmitry Torokhov error = mxt_parse_device_properties(data); 313496a938aaSDmitry Torokhov if (error) 313596a938aaSDmitry Torokhov return error; 313696a938aaSDmitry Torokhov 3137f657b00dSSebastian Reichel data->reset_gpio = devm_gpiod_get_optional(&client->dev, 3138f657b00dSSebastian Reichel "reset", GPIOD_OUT_LOW); 3139f657b00dSSebastian Reichel if (IS_ERR(data->reset_gpio)) { 3140f657b00dSSebastian Reichel error = PTR_ERR(data->reset_gpio); 3141f657b00dSSebastian Reichel dev_err(&client->dev, "Failed to get reset gpio: %d\n", error); 3142f657b00dSSebastian Reichel return error; 3143f657b00dSSebastian Reichel } 3144f657b00dSSebastian Reichel 31458cc8446bSSebastian Reichel error = devm_request_threaded_irq(&client->dev, client->irq, 314696a938aaSDmitry Torokhov NULL, mxt_interrupt, IRQF_ONESHOT, 3147dd24dcf5SNick Dyer client->name, data); 3148dd24dcf5SNick Dyer if (error) { 3149dd24dcf5SNick Dyer dev_err(&client->dev, "Failed to register interrupt\n"); 31508cc8446bSSebastian Reichel return error; 3151dd24dcf5SNick Dyer } 3152dd24dcf5SNick Dyer 3153dd24dcf5SNick Dyer disable_irq(client->irq); 3154dd24dcf5SNick Dyer 3155ca1cd36cSSebastian Reichel if (data->reset_gpio) { 3156ca1cd36cSSebastian Reichel msleep(MXT_RESET_GPIO_TIME); 3157ca1cd36cSSebastian Reichel gpiod_set_value(data->reset_gpio, 1); 3158ca1cd36cSSebastian Reichel msleep(MXT_RESET_INVALID_CHG); 3159ca1cd36cSSebastian Reichel } 3160ca1cd36cSSebastian Reichel 3161cb159115SDaniel Kurtz error = mxt_initialize(data); 3162cb159115SDaniel Kurtz if (error) 31638cc8446bSSebastian Reichel return error; 31644cf51c38SJoonyoung Shim 31657686b108SIiro Valkonen error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); 31667bed6805SNick Dyer if (error) { 31677bed6805SNick Dyer dev_err(&client->dev, "Failure %d creating sysfs group\n", 31687bed6805SNick Dyer error); 31697a53d609SNick Dyer goto err_free_object; 31707bed6805SNick Dyer } 31714cf51c38SJoonyoung Shim 31724cf51c38SJoonyoung Shim return 0; 31734cf51c38SJoonyoung Shim 31744cf51c38SJoonyoung Shim err_free_object: 317558e4aeeeSStephen Warren mxt_free_input_device(data); 31765f3f9bc2SNick Dyer mxt_free_object_table(data); 31774cf51c38SJoonyoung Shim return error; 31784cf51c38SJoonyoung Shim } 31794cf51c38SJoonyoung Shim 3180e2619cf7SBill Pemberton static int mxt_remove(struct i2c_client *client) 31814cf51c38SJoonyoung Shim { 31827686b108SIiro Valkonen struct mxt_data *data = i2c_get_clientdata(client); 31834cf51c38SJoonyoung Shim 31848cc8446bSSebastian Reichel disable_irq(data->irq); 31857686b108SIiro Valkonen sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); 318658e4aeeeSStephen Warren mxt_free_input_device(data); 31875f3f9bc2SNick Dyer mxt_free_object_table(data); 31884cf51c38SJoonyoung Shim 31894cf51c38SJoonyoung Shim return 0; 31904cf51c38SJoonyoung Shim } 31914cf51c38SJoonyoung Shim 319202b6a58bSJingoo Han static int __maybe_unused mxt_suspend(struct device *dev) 31934cf51c38SJoonyoung Shim { 31948b5fce06SDmitry Torokhov struct i2c_client *client = to_i2c_client(dev); 31957686b108SIiro Valkonen struct mxt_data *data = i2c_get_clientdata(client); 31964cf51c38SJoonyoung Shim struct input_dev *input_dev = data->input_dev; 31974cf51c38SJoonyoung Shim 319850fabb02SPan Xinhui if (!input_dev) 319950fabb02SPan Xinhui return 0; 320050fabb02SPan Xinhui 32014cf51c38SJoonyoung Shim mutex_lock(&input_dev->mutex); 32024cf51c38SJoonyoung Shim 32034cf51c38SJoonyoung Shim if (input_dev->users) 32047686b108SIiro Valkonen mxt_stop(data); 32054cf51c38SJoonyoung Shim 32064cf51c38SJoonyoung Shim mutex_unlock(&input_dev->mutex); 32074cf51c38SJoonyoung Shim 3208463fa44eSEvan Green disable_irq(data->irq); 3209463fa44eSEvan Green 32104cf51c38SJoonyoung Shim return 0; 32114cf51c38SJoonyoung Shim } 32124cf51c38SJoonyoung Shim 321302b6a58bSJingoo Han static int __maybe_unused mxt_resume(struct device *dev) 32144cf51c38SJoonyoung Shim { 32158b5fce06SDmitry Torokhov struct i2c_client *client = to_i2c_client(dev); 32167686b108SIiro Valkonen struct mxt_data *data = i2c_get_clientdata(client); 32174cf51c38SJoonyoung Shim struct input_dev *input_dev = data->input_dev; 32184cf51c38SJoonyoung Shim 321950fabb02SPan Xinhui if (!input_dev) 322050fabb02SPan Xinhui return 0; 322150fabb02SPan Xinhui 3222463fa44eSEvan Green enable_irq(data->irq); 3223463fa44eSEvan Green 32244cf51c38SJoonyoung Shim mutex_lock(&input_dev->mutex); 32254cf51c38SJoonyoung Shim 32264cf51c38SJoonyoung Shim if (input_dev->users) 32277686b108SIiro Valkonen mxt_start(data); 32284cf51c38SJoonyoung Shim 32294cf51c38SJoonyoung Shim mutex_unlock(&input_dev->mutex); 32304cf51c38SJoonyoung Shim 32314cf51c38SJoonyoung Shim return 0; 32324cf51c38SJoonyoung Shim } 32334cf51c38SJoonyoung Shim 32343a73c816SDaniel Kurtz static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume); 32353a73c816SDaniel Kurtz 323678188be3SStephen Warren static const struct of_device_id mxt_of_match[] = { 323778188be3SStephen Warren { .compatible = "atmel,maxtouch", }, 3238f6eeb9e5SJavier Martinez Canillas /* Compatibles listed below are deprecated */ 3239f6eeb9e5SJavier Martinez Canillas { .compatible = "atmel,qt602240_ts", }, 3240f6eeb9e5SJavier Martinez Canillas { .compatible = "atmel,atmel_mxt_ts", }, 3241f6eeb9e5SJavier Martinez Canillas { .compatible = "atmel,atmel_mxt_tp", }, 3242f6eeb9e5SJavier Martinez Canillas { .compatible = "atmel,mXT224", }, 324378188be3SStephen Warren {}, 324478188be3SStephen Warren }; 324578188be3SStephen Warren MODULE_DEVICE_TABLE(of, mxt_of_match); 324678188be3SStephen Warren 32474f8d8088SDmitry Torokhov #ifdef CONFIG_ACPI 32484f8d8088SDmitry Torokhov static const struct acpi_device_id mxt_acpi_id[] = { 32494f8d8088SDmitry Torokhov { "ATML0000", 0 }, /* Touchpad */ 32504f8d8088SDmitry Torokhov { "ATML0001", 0 }, /* Touchscreen */ 32514f8d8088SDmitry Torokhov { } 32524f8d8088SDmitry Torokhov }; 32534f8d8088SDmitry Torokhov MODULE_DEVICE_TABLE(acpi, mxt_acpi_id); 32544f8d8088SDmitry Torokhov #endif 32554f8d8088SDmitry Torokhov 32567686b108SIiro Valkonen static const struct i2c_device_id mxt_id[] = { 32574cf51c38SJoonyoung Shim { "qt602240_ts", 0 }, 32587686b108SIiro Valkonen { "atmel_mxt_ts", 0 }, 325922dfab7fSDaniel Kurtz { "atmel_mxt_tp", 0 }, 3260b7d21058SJavier Martinez Canillas { "maxtouch", 0 }, 326146ee2a05SChris Leech { "mXT224", 0 }, 32624cf51c38SJoonyoung Shim { } 32634cf51c38SJoonyoung Shim }; 32647686b108SIiro Valkonen MODULE_DEVICE_TABLE(i2c, mxt_id); 32654cf51c38SJoonyoung Shim 32667686b108SIiro Valkonen static struct i2c_driver mxt_driver = { 32674cf51c38SJoonyoung Shim .driver = { 32687686b108SIiro Valkonen .name = "atmel_mxt_ts", 326996a938aaSDmitry Torokhov .of_match_table = mxt_of_match, 32704f8d8088SDmitry Torokhov .acpi_match_table = ACPI_PTR(mxt_acpi_id), 32717686b108SIiro Valkonen .pm = &mxt_pm_ops, 32724cf51c38SJoonyoung Shim }, 32737686b108SIiro Valkonen .probe = mxt_probe, 32741cb0aa88SBill Pemberton .remove = mxt_remove, 32757686b108SIiro Valkonen .id_table = mxt_id, 32764cf51c38SJoonyoung Shim }; 32774cf51c38SJoonyoung Shim 32781b92c1cfSAxel Lin module_i2c_driver(mxt_driver); 32794cf51c38SJoonyoung Shim 32804cf51c38SJoonyoung Shim /* Module information */ 32814cf51c38SJoonyoung Shim MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 32827686b108SIiro Valkonen MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver"); 32834cf51c38SJoonyoung Shim MODULE_LICENSE("GPL"); 3284