blob: 697dcdbb278e6d631d700ac787cf289f8c83e6be [file] [log] [blame]
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001/*
Iiro Valkonen7686b102011-02-02 23:21:58 -08002 * Atmel maXTouch Touchscreen driver
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07003 *
4 * Copyright (C) 2010 Samsung Electronics Co.Ltd
5 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
Mohan Pallaka5e7343f2012-01-02 18:30:16 +08006 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07007 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/delay.h>
18#include <linux/firmware.h>
19#include <linux/i2c.h>
Dmitry Torokhov964de522011-02-02 23:21:58 -080020#include <linux/i2c/atmel_mxt_ts.h>
Joonyoung Shimcd473222012-02-14 18:32:48 -080021#include <linux/input/mt.h>
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070022#include <linux/interrupt.h>
23#include <linux/slab.h>
Amy Maloche08266db2011-11-04 11:07:16 -070024#include <linux/gpio.h>
Jing Lin6cfc00e2011-11-02 15:15:30 -070025#include <linux/debugfs.h>
26#include <linux/seq_file.h>
Anirudh Ghayala498e4d2011-08-09 19:10:12 +053027#include <linux/regulator/consumer.h>
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070028
Anirudh Ghayal253ce122011-08-09 19:32:57 +053029#if defined(CONFIG_HAS_EARLYSUSPEND)
30#include <linux/earlysuspend.h>
31/* Early-suspend level */
32#define MXT_SUSPEND_LEVEL 1
33#endif
34
Iiro Valkonen4ac053c2011-09-08 11:10:52 -070035/* Family ID */
36#define MXT224_ID 0x80
Amy Maloche380cc0b2011-11-03 12:55:04 -070037#define MXT224E_ID 0x81
Iiro Valkonen4ac053c2011-09-08 11:10:52 -070038#define MXT1386_ID 0xA0
39
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070040/* Version */
Iiro Valkonen7686b102011-02-02 23:21:58 -080041#define MXT_VER_20 20
42#define MXT_VER_21 21
43#define MXT_VER_22 22
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070044
Nick Dyer0a4016c2012-01-18 15:17:59 +053045/* I2C slave address pairs */
46struct mxt_address_pair {
47 int bootloader;
48 int application;
49};
50
51static const struct mxt_address_pair mxt_slave_addresses[] = {
52 { 0x24, 0x4a },
53 { 0x25, 0x4b },
54 { 0x25, 0x4b },
55 { 0x26, 0x4c },
56 { 0x27, 0x4d },
57 { 0x34, 0x5a },
58 { 0x35, 0x5b },
59 { 0 },
60};
61
62enum mxt_device_state { INIT, APPMODE, BOOTLOADER };
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070063
64/* Firmware */
Iiro Valkonen7686b102011-02-02 23:21:58 -080065#define MXT_FW_NAME "maxtouch.fw"
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070066
67/* Registers */
Iiro Valkonen7686b102011-02-02 23:21:58 -080068#define MXT_FAMILY_ID 0x00
69#define MXT_VARIANT_ID 0x01
70#define MXT_VERSION 0x02
71#define MXT_BUILD 0x03
72#define MXT_MATRIX_X_SIZE 0x04
73#define MXT_MATRIX_Y_SIZE 0x05
74#define MXT_OBJECT_NUM 0x06
75#define MXT_OBJECT_START 0x07
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070076
Iiro Valkonen7686b102011-02-02 23:21:58 -080077#define MXT_OBJECT_SIZE 6
Joonyoung Shim4cf51c32010-07-14 21:55:30 -070078
79/* Object types */
Iiro Valkonene8645592011-11-18 12:56:19 -080080#define MXT_DEBUG_DIAGNOSTIC_T37 37
81#define MXT_GEN_MESSAGE_T5 5
82#define MXT_GEN_COMMAND_T6 6
83#define MXT_GEN_POWER_T7 7
84#define MXT_GEN_ACQUIRE_T8 8
85#define MXT_GEN_DATASOURCE_T53 53
86#define MXT_TOUCH_MULTI_T9 9
87#define MXT_TOUCH_KEYARRAY_T15 15
88#define MXT_TOUCH_PROXIMITY_T23 23
89#define MXT_TOUCH_PROXKEY_T52 52
90#define MXT_PROCI_GRIPFACE_T20 20
91#define MXT_PROCG_NOISE_T22 22
92#define MXT_PROCI_ONETOUCH_T24 24
93#define MXT_PROCI_TWOTOUCH_T27 27
94#define MXT_PROCI_GRIP_T40 40
95#define MXT_PROCI_PALM_T41 41
96#define MXT_PROCI_TOUCHSUPPRESSION_T42 42
97#define MXT_PROCI_STYLUS_T47 47
Jing Linc7fc4052011-12-21 16:16:19 -080098#define MXT_PROCI_SHIELDLESS_T56 56
Iiro Valkonene8645592011-11-18 12:56:19 -080099#define MXT_PROCG_NOISESUPPRESSION_T48 48
100#define MXT_SPT_COMMSCONFIG_T18 18
101#define MXT_SPT_GPIOPWM_T19 19
102#define MXT_SPT_SELFTEST_T25 25
103#define MXT_SPT_CTECONFIG_T28 28
104#define MXT_SPT_USERDATA_T38 38
105#define MXT_SPT_DIGITIZER_T43 43
106#define MXT_SPT_MESSAGECOUNT_T44 44
107#define MXT_SPT_CTECONFIG_T46 46
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700108
Iiro Valkonene8645592011-11-18 12:56:19 -0800109/* MXT_GEN_COMMAND_T6 field */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800110#define MXT_COMMAND_RESET 0
111#define MXT_COMMAND_BACKUPNV 1
112#define MXT_COMMAND_CALIBRATE 2
113#define MXT_COMMAND_REPORTALL 3
114#define MXT_COMMAND_DIAGNOSTIC 5
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700115
Iiro Valkonene8645592011-11-18 12:56:19 -0800116/* MXT_GEN_POWER_T7 field */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800117#define MXT_POWER_IDLEACQINT 0
118#define MXT_POWER_ACTVACQINT 1
119#define MXT_POWER_ACTV2IDLETO 2
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700120
Iiro Valkonene8645592011-11-18 12:56:19 -0800121/* MXT_GEN_ACQUIRE_T8 field */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800122#define MXT_ACQUIRE_CHRGTIME 0
123#define MXT_ACQUIRE_TCHDRIFT 2
124#define MXT_ACQUIRE_DRIFTST 3
125#define MXT_ACQUIRE_TCHAUTOCAL 4
126#define MXT_ACQUIRE_SYNC 5
127#define MXT_ACQUIRE_ATCHCALST 6
128#define MXT_ACQUIRE_ATCHCALSTHR 7
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700129
Iiro Valkonene8645592011-11-18 12:56:19 -0800130/* MXT_TOUCH_MULT_T9 field */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800131#define MXT_TOUCH_CTRL 0
132#define MXT_TOUCH_XORIGIN 1
133#define MXT_TOUCH_YORIGIN 2
134#define MXT_TOUCH_XSIZE 3
135#define MXT_TOUCH_YSIZE 4
136#define MXT_TOUCH_BLEN 6
137#define MXT_TOUCH_TCHTHR 7
138#define MXT_TOUCH_TCHDI 8
139#define MXT_TOUCH_ORIENT 9
140#define MXT_TOUCH_MOVHYSTI 11
141#define MXT_TOUCH_MOVHYSTN 12
142#define MXT_TOUCH_NUMTOUCH 14
143#define MXT_TOUCH_MRGHYST 15
144#define MXT_TOUCH_MRGTHR 16
145#define MXT_TOUCH_AMPHYST 17
146#define MXT_TOUCH_XRANGE_LSB 18
147#define MXT_TOUCH_XRANGE_MSB 19
148#define MXT_TOUCH_YRANGE_LSB 20
149#define MXT_TOUCH_YRANGE_MSB 21
150#define MXT_TOUCH_XLOCLIP 22
151#define MXT_TOUCH_XHICLIP 23
152#define MXT_TOUCH_YLOCLIP 24
153#define MXT_TOUCH_YHICLIP 25
154#define MXT_TOUCH_XEDGECTRL 26
155#define MXT_TOUCH_XEDGEDIST 27
156#define MXT_TOUCH_YEDGECTRL 28
157#define MXT_TOUCH_YEDGEDIST 29
Joonyoung Shim979a72d2011-03-14 21:41:34 -0700158#define MXT_TOUCH_JUMPLIMIT 30
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700159
Iiro Valkonene8645592011-11-18 12:56:19 -0800160/* MXT_PROCI_GRIPFACE_T20 field */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800161#define MXT_GRIPFACE_CTRL 0
162#define MXT_GRIPFACE_XLOGRIP 1
163#define MXT_GRIPFACE_XHIGRIP 2
164#define MXT_GRIPFACE_YLOGRIP 3
165#define MXT_GRIPFACE_YHIGRIP 4
166#define MXT_GRIPFACE_MAXTCHS 5
167#define MXT_GRIPFACE_SZTHR1 7
168#define MXT_GRIPFACE_SZTHR2 8
169#define MXT_GRIPFACE_SHPTHR1 9
170#define MXT_GRIPFACE_SHPTHR2 10
171#define MXT_GRIPFACE_SUPEXTTO 11
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700172
Iiro Valkonen7686b102011-02-02 23:21:58 -0800173/* MXT_PROCI_NOISE field */
174#define MXT_NOISE_CTRL 0
175#define MXT_NOISE_OUTFLEN 1
176#define MXT_NOISE_GCAFUL_LSB 3
177#define MXT_NOISE_GCAFUL_MSB 4
178#define MXT_NOISE_GCAFLL_LSB 5
179#define MXT_NOISE_GCAFLL_MSB 6
180#define MXT_NOISE_ACTVGCAFVALID 7
181#define MXT_NOISE_NOISETHR 8
182#define MXT_NOISE_FREQHOPSCALE 10
183#define MXT_NOISE_FREQ0 11
184#define MXT_NOISE_FREQ1 12
185#define MXT_NOISE_FREQ2 13
186#define MXT_NOISE_FREQ3 14
187#define MXT_NOISE_FREQ4 15
188#define MXT_NOISE_IDLEGCAFVALID 16
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700189
Iiro Valkonene8645592011-11-18 12:56:19 -0800190/* MXT_SPT_COMMSCONFIG_T18 */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800191#define MXT_COMMS_CTRL 0
192#define MXT_COMMS_CMD 1
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700193
Iiro Valkonene8645592011-11-18 12:56:19 -0800194/* MXT_SPT_CTECONFIG_T28 field */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800195#define MXT_CTE_CTRL 0
196#define MXT_CTE_CMD 1
197#define MXT_CTE_MODE 2
198#define MXT_CTE_IDLEGCAFDEPTH 3
199#define MXT_CTE_ACTVGCAFDEPTH 4
Joonyoung Shim979a72d2011-03-14 21:41:34 -0700200#define MXT_CTE_VOLTAGE 5
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700201
Iiro Valkonen7686b102011-02-02 23:21:58 -0800202#define MXT_VOLTAGE_DEFAULT 2700000
203#define MXT_VOLTAGE_STEP 10000
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700204
Amy Maloche21115eb2011-11-02 09:04:37 -0700205/* Analog voltage @2.7 V */
Anirudh Ghayala498e4d2011-08-09 19:10:12 +0530206#define MXT_VTG_MIN_UV 2700000
207#define MXT_VTG_MAX_UV 3300000
208#define MXT_ACTIVE_LOAD_UA 15000
Jing Linbace50b2011-10-18 22:55:47 -0700209#define MXT_LPM_LOAD_UA 10
Amy Maloche21115eb2011-11-02 09:04:37 -0700210/* Digital voltage @1.8 V */
211#define MXT_VTG_DIG_MIN_UV 1800000
212#define MXT_VTG_DIG_MAX_UV 1800000
213#define MXT_ACTIVE_LOAD_DIG_UA 10000
214#define MXT_LPM_LOAD_DIG_UA 10
Anirudh Ghayala498e4d2011-08-09 19:10:12 +0530215
216#define MXT_I2C_VTG_MIN_UV 1800000
217#define MXT_I2C_VTG_MAX_UV 1800000
218#define MXT_I2C_LOAD_UA 10000
Jing Linbace50b2011-10-18 22:55:47 -0700219#define MXT_I2C_LPM_LOAD_UA 10
Anirudh Ghayala498e4d2011-08-09 19:10:12 +0530220
Iiro Valkonene8645592011-11-18 12:56:19 -0800221/* Define for MXT_GEN_COMMAND_T6 */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800222#define MXT_BOOT_VALUE 0xa5
223#define MXT_BACKUP_VALUE 0x55
224#define MXT_BACKUP_TIME 25 /* msec */
Jing Linc7fc4052011-12-21 16:16:19 -0800225#define MXT224_RESET_TIME 65 /* msec */
226#define MXT224E_RESET_TIME 22 /* msec */
227#define MXT1386_RESET_TIME 250 /* msec */
Amy Maloche7e447432011-09-14 11:36:30 -0700228#define MXT_RESET_TIME 250 /* msec */
Jing Linc7fc4052011-12-21 16:16:19 -0800229#define MXT_RESET_NOCHGREAD 400 /* msec */
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700230
Nick Dyer0a4016c2012-01-18 15:17:59 +0530231#define MXT_FWRESET_TIME 1000 /* msec */
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700232
Jing Lin36aee812011-10-17 17:17:28 -0700233#define MXT_WAKE_TIME 25
234
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700235/* Command to unlock bootloader */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800236#define MXT_UNLOCK_CMD_MSB 0xaa
237#define MXT_UNLOCK_CMD_LSB 0xdc
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700238
239/* Bootloader mode status */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800240#define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */
241#define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */
242#define MXT_FRAME_CRC_CHECK 0x02
243#define MXT_FRAME_CRC_FAIL 0x03
244#define MXT_FRAME_CRC_PASS 0x04
245#define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */
246#define MXT_BOOT_STATUS_MASK 0x3f
Nick Dyer0a4016c2012-01-18 15:17:59 +0530247#define MXT_BOOT_EXTENDED_ID (1 << 5)
248#define MXT_BOOT_ID_MASK 0x1f
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700249
250/* Touch status */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800251#define MXT_SUPPRESS (1 << 1)
252#define MXT_AMP (1 << 2)
253#define MXT_VECTOR (1 << 3)
254#define MXT_MOVE (1 << 4)
255#define MXT_RELEASE (1 << 5)
256#define MXT_PRESS (1 << 6)
257#define MXT_DETECT (1 << 7)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700258
Joonyoung Shim910d8052011-04-12 23:14:38 -0700259/* Touch orient bits */
260#define MXT_XY_SWITCH (1 << 0)
261#define MXT_X_INVERT (1 << 1)
262#define MXT_Y_INVERT (1 << 2)
263
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700264/* Touchscreen absolute values */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800265#define MXT_MAX_AREA 0xff
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700266
Iiro Valkonen7686b102011-02-02 23:21:58 -0800267#define MXT_MAX_FINGER 10
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700268
Jing Lin36aee812011-10-17 17:17:28 -0700269#define T7_DATA_SIZE 3
270#define MXT_MAX_RW_TRIES 3
271#define MXT_BLOCK_SIZE 256
Mohan Pallakaab51f2b2011-09-29 18:17:35 +0530272
Jing Lin6cfc00e2011-11-02 15:15:30 -0700273#define MXT_DEBUGFS_DIR "atmel_mxt_ts"
274#define MXT_DEBUGFS_FILE "object"
275
Iiro Valkonen7686b102011-02-02 23:21:58 -0800276struct mxt_info {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700277 u8 family_id;
278 u8 variant_id;
279 u8 version;
280 u8 build;
281 u8 matrix_xsize;
282 u8 matrix_ysize;
283 u8 object_num;
284};
285
Iiro Valkonen7686b102011-02-02 23:21:58 -0800286struct mxt_object {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700287 u8 type;
288 u16 start_address;
289 u8 size;
290 u8 instances;
291 u8 num_report_ids;
292
293 /* to map object and message */
294 u8 max_reportid;
295};
296
Iiro Valkonen7686b102011-02-02 23:21:58 -0800297struct mxt_message {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700298 u8 reportid;
299 u8 message[7];
300 u8 checksum;
301};
302
Iiro Valkonen7686b102011-02-02 23:21:58 -0800303struct mxt_finger {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700304 int status;
305 int x;
306 int y;
307 int area;
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700308 int pressure;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700309};
310
311/* Each client has this additional data */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800312struct mxt_data {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700313 struct i2c_client *client;
314 struct input_dev *input_dev;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800315 const struct mxt_platform_data *pdata;
Jing Lindc4413c2012-01-16 15:22:52 -0800316 const struct mxt_config_info *config_info;
Nick Dyer0a4016c2012-01-18 15:17:59 +0530317 enum mxt_device_state state;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800318 struct mxt_object *object_table;
319 struct mxt_info info;
320 struct mxt_finger finger[MXT_MAX_FINGER];
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700321 unsigned int irq;
Amy Maloche83c385a2012-02-01 10:32:03 +0530322 unsigned int touch_x_size;
323 unsigned int touch_y_size;
Amy Maloche21115eb2011-11-02 09:04:37 -0700324 struct regulator *vcc_ana;
325 struct regulator *vcc_dig;
Anirudh Ghayala498e4d2011-08-09 19:10:12 +0530326 struct regulator *vcc_i2c;
Anirudh Ghayal253ce122011-08-09 19:32:57 +0530327#if defined(CONFIG_HAS_EARLYSUSPEND)
328 struct early_suspend early_suspend;
329#endif
Jing Lin36aee812011-10-17 17:17:28 -0700330
Amy Maloche52262212011-09-15 16:46:57 -0700331 u8 t7_data[T7_DATA_SIZE];
Jing Lin36aee812011-10-17 17:17:28 -0700332 u16 t7_start_addr;
Amy Maloche52262212011-09-15 16:46:57 -0700333 u8 t9_ctrl;
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800334 u32 keyarray_old;
335 u32 keyarray_new;
336 u8 t9_max_reportid;
337 u8 t9_min_reportid;
338 u8 t15_max_reportid;
339 u8 t15_min_reportid;
Jing Lindc4413c2012-01-16 15:22:52 -0800340 u8 curr_cfg_version;
341 int cfg_version_idx;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700342};
343
Jing Lin6cfc00e2011-11-02 15:15:30 -0700344static struct dentry *debug_base;
345
Iiro Valkonen7686b102011-02-02 23:21:58 -0800346static bool mxt_object_readable(unsigned int type)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700347{
348 switch (type) {
Iiro Valkonene8645592011-11-18 12:56:19 -0800349 case MXT_GEN_MESSAGE_T5:
350 case MXT_GEN_COMMAND_T6:
351 case MXT_GEN_POWER_T7:
352 case MXT_GEN_ACQUIRE_T8:
353 case MXT_GEN_DATASOURCE_T53:
354 case MXT_TOUCH_MULTI_T9:
355 case MXT_TOUCH_KEYARRAY_T15:
356 case MXT_TOUCH_PROXIMITY_T23:
357 case MXT_TOUCH_PROXKEY_T52:
358 case MXT_PROCI_GRIPFACE_T20:
359 case MXT_PROCG_NOISE_T22:
360 case MXT_PROCI_ONETOUCH_T24:
361 case MXT_PROCI_TWOTOUCH_T27:
362 case MXT_PROCI_GRIP_T40:
363 case MXT_PROCI_PALM_T41:
364 case MXT_PROCI_TOUCHSUPPRESSION_T42:
365 case MXT_PROCI_STYLUS_T47:
Jing Linc7fc4052011-12-21 16:16:19 -0800366 case MXT_PROCI_SHIELDLESS_T56:
Iiro Valkonene8645592011-11-18 12:56:19 -0800367 case MXT_PROCG_NOISESUPPRESSION_T48:
368 case MXT_SPT_COMMSCONFIG_T18:
369 case MXT_SPT_GPIOPWM_T19:
370 case MXT_SPT_SELFTEST_T25:
371 case MXT_SPT_CTECONFIG_T28:
372 case MXT_SPT_USERDATA_T38:
373 case MXT_SPT_DIGITIZER_T43:
374 case MXT_SPT_CTECONFIG_T46:
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700375 return true;
376 default:
377 return false;
378 }
379}
380
Iiro Valkonen7686b102011-02-02 23:21:58 -0800381static bool mxt_object_writable(unsigned int type)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700382{
383 switch (type) {
Iiro Valkonene8645592011-11-18 12:56:19 -0800384 case MXT_GEN_COMMAND_T6:
385 case MXT_GEN_POWER_T7:
386 case MXT_GEN_ACQUIRE_T8:
387 case MXT_TOUCH_MULTI_T9:
388 case MXT_TOUCH_KEYARRAY_T15:
389 case MXT_TOUCH_PROXIMITY_T23:
390 case MXT_TOUCH_PROXKEY_T52:
391 case MXT_PROCI_GRIPFACE_T20:
392 case MXT_PROCG_NOISE_T22:
393 case MXT_PROCI_ONETOUCH_T24:
394 case MXT_PROCI_TWOTOUCH_T27:
395 case MXT_PROCI_GRIP_T40:
396 case MXT_PROCI_PALM_T41:
397 case MXT_PROCI_TOUCHSUPPRESSION_T42:
398 case MXT_PROCI_STYLUS_T47:
Jing Linc7fc4052011-12-21 16:16:19 -0800399 case MXT_PROCI_SHIELDLESS_T56:
Iiro Valkonene8645592011-11-18 12:56:19 -0800400 case MXT_PROCG_NOISESUPPRESSION_T48:
401 case MXT_SPT_COMMSCONFIG_T18:
402 case MXT_SPT_GPIOPWM_T19:
403 case MXT_SPT_SELFTEST_T25:
404 case MXT_SPT_CTECONFIG_T28:
405 case MXT_SPT_USERDATA_T38:
406 case MXT_SPT_DIGITIZER_T43:
407 case MXT_SPT_CTECONFIG_T46:
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700408 return true;
409 default:
410 return false;
411 }
412}
413
Iiro Valkonen7686b102011-02-02 23:21:58 -0800414static void mxt_dump_message(struct device *dev,
415 struct mxt_message *message)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700416{
417 dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
418 dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
419 dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
420 dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
421 dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
422 dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
423 dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
424 dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
425 dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
426}
427
Nick Dyer0a4016c2012-01-18 15:17:59 +0530428static int mxt_switch_to_bootloader_address(struct mxt_data *data)
429{
430 int i;
431 struct i2c_client *client = data->client;
432
433 if (data->state == BOOTLOADER) {
434 dev_err(&client->dev, "Already in BOOTLOADER state\n");
435 return -EINVAL;
436 }
437
438 for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
439 if (mxt_slave_addresses[i].application == client->addr) {
440 dev_info(&client->dev, "Changing to bootloader address: "
441 "%02x -> %02x",
442 client->addr,
443 mxt_slave_addresses[i].bootloader);
444
445 client->addr = mxt_slave_addresses[i].bootloader;
446 data->state = BOOTLOADER;
447 return 0;
448 }
449 }
450
451 dev_err(&client->dev, "Address 0x%02x not found in address table",
452 client->addr);
453 return -EINVAL;
454}
455
456static int mxt_switch_to_appmode_address(struct mxt_data *data)
457{
458 int i;
459 struct i2c_client *client = data->client;
460
461 if (data->state == APPMODE) {
462 dev_err(&client->dev, "Already in APPMODE state\n");
463 return -EINVAL;
464 }
465
466 for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
467 if (mxt_slave_addresses[i].bootloader == client->addr) {
468 dev_info(&client->dev,
469 "Changing to application mode address: "
470 "0x%02x -> 0x%02x",
471 client->addr,
472 mxt_slave_addresses[i].application);
473
474 client->addr = mxt_slave_addresses[i].application;
475 data->state = APPMODE;
476 return 0;
477 }
478 }
479
480 dev_err(&client->dev, "Address 0x%02x not found in address table",
481 client->addr);
482 return -EINVAL;
483}
484
485static int mxt_get_bootloader_version(struct i2c_client *client, u8 val)
486{
487 u8 buf[3];
488
489 if (val | MXT_BOOT_EXTENDED_ID) {
490 dev_dbg(&client->dev,
491 "Retrieving extended mode ID information");
492
493 if (i2c_master_recv(client, &buf[0], 3) != 3) {
494 dev_err(&client->dev, "%s: i2c recv failed\n",
495 __func__);
496 return -EIO;
497 }
498
499 dev_info(&client->dev, "Bootloader ID:%d Version:%d",
500 buf[1], buf[2]);
501
502 return buf[0];
503 } else {
504 dev_info(&client->dev, "Bootloader ID:%d",
505 val & MXT_BOOT_ID_MASK);
506
507 return val;
508 }
509}
510
Iiro Valkonen7686b102011-02-02 23:21:58 -0800511static int mxt_check_bootloader(struct i2c_client *client,
Nick Dyer0a4016c2012-01-18 15:17:59 +0530512 unsigned int state)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700513{
514 u8 val;
515
516recheck:
517 if (i2c_master_recv(client, &val, 1) != 1) {
518 dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
519 return -EIO;
520 }
521
522 switch (state) {
Iiro Valkonen7686b102011-02-02 23:21:58 -0800523 case MXT_WAITING_BOOTLOAD_CMD:
Nick Dyer0a4016c2012-01-18 15:17:59 +0530524 val = mxt_get_bootloader_version(client, val);
525 val &= ~MXT_BOOT_STATUS_MASK;
526 break;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800527 case MXT_WAITING_FRAME_DATA:
Nick Dyer0a4016c2012-01-18 15:17:59 +0530528 case MXT_APP_CRC_FAIL:
Iiro Valkonen7686b102011-02-02 23:21:58 -0800529 val &= ~MXT_BOOT_STATUS_MASK;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700530 break;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800531 case MXT_FRAME_CRC_PASS:
532 if (val == MXT_FRAME_CRC_CHECK)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700533 goto recheck;
Nick Dyer0a4016c2012-01-18 15:17:59 +0530534 if (val == MXT_FRAME_CRC_FAIL) {
535 dev_err(&client->dev, "Bootloader CRC fail\n");
536 return -EINVAL;
537 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700538 break;
539 default:
540 return -EINVAL;
541 }
542
543 if (val != state) {
Nick Dyer0a4016c2012-01-18 15:17:59 +0530544 dev_err(&client->dev, "Invalid bootloader mode state %X\n",
545 val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700546 return -EINVAL;
547 }
548
549 return 0;
550}
551
Iiro Valkonen7686b102011-02-02 23:21:58 -0800552static int mxt_unlock_bootloader(struct i2c_client *client)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700553{
554 u8 buf[2];
555
Iiro Valkonen7686b102011-02-02 23:21:58 -0800556 buf[0] = MXT_UNLOCK_CMD_LSB;
557 buf[1] = MXT_UNLOCK_CMD_MSB;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700558
559 if (i2c_master_send(client, buf, 2) != 2) {
560 dev_err(&client->dev, "%s: i2c send failed\n", __func__);
561 return -EIO;
562 }
563
564 return 0;
565}
566
Iiro Valkonen7686b102011-02-02 23:21:58 -0800567static int mxt_fw_write(struct i2c_client *client,
Nick Dyer0a4016c2012-01-18 15:17:59 +0530568 const u8 *data, unsigned int frame_size)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700569{
570 if (i2c_master_send(client, data, frame_size) != frame_size) {
571 dev_err(&client->dev, "%s: i2c send failed\n", __func__);
572 return -EIO;
573 }
574
575 return 0;
576}
577
Iiro Valkonen7686b102011-02-02 23:21:58 -0800578static int __mxt_read_reg(struct i2c_client *client,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700579 u16 reg, u16 len, void *val)
580{
581 struct i2c_msg xfer[2];
582 u8 buf[2];
Jing Lin36aee812011-10-17 17:17:28 -0700583 int i = 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700584
585 buf[0] = reg & 0xff;
586 buf[1] = (reg >> 8) & 0xff;
587
588 /* Write register */
589 xfer[0].addr = client->addr;
590 xfer[0].flags = 0;
591 xfer[0].len = 2;
592 xfer[0].buf = buf;
593
594 /* Read data */
595 xfer[1].addr = client->addr;
596 xfer[1].flags = I2C_M_RD;
597 xfer[1].len = len;
598 xfer[1].buf = val;
599
Jing Lin36aee812011-10-17 17:17:28 -0700600 do {
601 if (i2c_transfer(client->adapter, xfer, 2) == 2)
602 return 0;
603 msleep(MXT_WAKE_TIME);
604 } while (++i < MXT_MAX_RW_TRIES);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700605
Jing Lin36aee812011-10-17 17:17:28 -0700606 dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
607 return -EIO;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700608}
609
Iiro Valkonen7686b102011-02-02 23:21:58 -0800610static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700611{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800612 return __mxt_read_reg(client, reg, 1, val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700613}
614
Jing Lin36aee812011-10-17 17:17:28 -0700615static int __mxt_write_reg(struct i2c_client *client,
616 u16 addr, u16 length, u8 *value)
617{
618 u8 buf[MXT_BLOCK_SIZE + 2];
619 int i, tries = 0;
620
621 if (length > MXT_BLOCK_SIZE)
622 return -EINVAL;
623
624 buf[0] = addr & 0xff;
625 buf[1] = (addr >> 8) & 0xff;
626 for (i = 0; i < length; i++)
627 buf[i + 2] = *value++;
628
629 do {
630 if (i2c_master_send(client, buf, length + 2) == (length + 2))
631 return 0;
632 msleep(MXT_WAKE_TIME);
633 } while (++tries < MXT_MAX_RW_TRIES);
634
635 dev_err(&client->dev, "%s: i2c send failed\n", __func__);
636 return -EIO;
637}
638
Iiro Valkonen7686b102011-02-02 23:21:58 -0800639static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700640{
Jing Lin36aee812011-10-17 17:17:28 -0700641 return __mxt_write_reg(client, reg, 1, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700642}
643
Iiro Valkonen7686b102011-02-02 23:21:58 -0800644static int mxt_read_object_table(struct i2c_client *client,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700645 u16 reg, u8 *object_buf)
646{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800647 return __mxt_read_reg(client, reg, MXT_OBJECT_SIZE,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700648 object_buf);
649}
650
Iiro Valkonen7686b102011-02-02 23:21:58 -0800651static struct mxt_object *
652mxt_get_object(struct mxt_data *data, u8 type)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700653{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800654 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700655 int i;
656
657 for (i = 0; i < data->info.object_num; i++) {
658 object = data->object_table + i;
659 if (object->type == type)
660 return object;
661 }
662
663 dev_err(&data->client->dev, "Invalid object type\n");
664 return NULL;
665}
666
Iiro Valkonen7686b102011-02-02 23:21:58 -0800667static int mxt_read_message(struct mxt_data *data,
668 struct mxt_message *message)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700669{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800670 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700671 u16 reg;
672
Iiro Valkonene8645592011-11-18 12:56:19 -0800673 object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700674 if (!object)
675 return -EINVAL;
676
677 reg = object->start_address;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800678 return __mxt_read_reg(data->client, reg,
679 sizeof(struct mxt_message), message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700680}
681
Iiro Valkonen7686b102011-02-02 23:21:58 -0800682static int mxt_read_object(struct mxt_data *data,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700683 u8 type, u8 offset, u8 *val)
684{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800685 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700686 u16 reg;
687
Iiro Valkonen7686b102011-02-02 23:21:58 -0800688 object = mxt_get_object(data, type);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700689 if (!object)
690 return -EINVAL;
691
692 reg = object->start_address;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800693 return __mxt_read_reg(data->client, reg + offset, 1, val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700694}
695
Iiro Valkonen7686b102011-02-02 23:21:58 -0800696static int mxt_write_object(struct mxt_data *data,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700697 u8 type, u8 offset, u8 val)
698{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800699 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700700 u16 reg;
701
Iiro Valkonen7686b102011-02-02 23:21:58 -0800702 object = mxt_get_object(data, type);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700703 if (!object)
704 return -EINVAL;
705
706 reg = object->start_address;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800707 return mxt_write_reg(data->client, reg + offset, val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700708}
709
Iiro Valkonen7686b102011-02-02 23:21:58 -0800710static void mxt_input_report(struct mxt_data *data, int single_id)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700711{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800712 struct mxt_finger *finger = data->finger;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700713 struct input_dev *input_dev = data->input_dev;
714 int status = finger[single_id].status;
715 int finger_num = 0;
716 int id;
717
Iiro Valkonen7686b102011-02-02 23:21:58 -0800718 for (id = 0; id < MXT_MAX_FINGER; id++) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700719 if (!finger[id].status)
720 continue;
721
Joonyoung Shimcd473222012-02-14 18:32:48 -0800722 input_mt_slot(input_dev, id);
723 input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
724 finger[id].status != MXT_RELEASE);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700725
Joonyoung Shimcd473222012-02-14 18:32:48 -0800726 if (finger[id].status != MXT_RELEASE) {
Amy Maloche2b59bab2011-10-13 16:08:16 -0700727 finger_num++;
Joonyoung Shimcd473222012-02-14 18:32:48 -0800728 input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
729 finger[id].area);
730 input_report_abs(input_dev, ABS_MT_POSITION_X,
731 finger[id].x);
732 input_report_abs(input_dev, ABS_MT_POSITION_Y,
733 finger[id].y);
734 input_report_abs(input_dev, ABS_MT_PRESSURE,
735 finger[id].area);
736 } else {
737 finger[id].status = 0;
738 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700739 }
740
741 input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
742
Iiro Valkonen7686b102011-02-02 23:21:58 -0800743 if (status != MXT_RELEASE) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700744 input_report_abs(input_dev, ABS_X, finger[single_id].x);
745 input_report_abs(input_dev, ABS_Y, finger[single_id].y);
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700746 input_report_abs(input_dev,
747 ABS_PRESSURE, finger[single_id].pressure);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700748 }
749
750 input_sync(input_dev);
751}
752
Iiro Valkonen7686b102011-02-02 23:21:58 -0800753static void mxt_input_touchevent(struct mxt_data *data,
754 struct mxt_message *message, int id)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700755{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800756 struct mxt_finger *finger = data->finger;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700757 struct device *dev = &data->client->dev;
758 u8 status = message->message[0];
759 int x;
760 int y;
761 int area;
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700762 int pressure;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700763
764 /* Check the touch is present on the screen */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800765 if (!(status & MXT_DETECT)) {
766 if (status & MXT_RELEASE) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700767 dev_dbg(dev, "[%d] released\n", id);
768
Iiro Valkonen7686b102011-02-02 23:21:58 -0800769 finger[id].status = MXT_RELEASE;
770 mxt_input_report(data, id);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700771 }
772 return;
773 }
774
775 /* Check only AMP detection */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800776 if (!(status & (MXT_PRESS | MXT_MOVE)))
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700777 return;
778
Joonyoung Shim910d8052011-04-12 23:14:38 -0700779 x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
780 y = (message->message[2] << 4) | ((message->message[3] & 0xf));
Amy Maloche83c385a2012-02-01 10:32:03 +0530781 if (data->touch_x_size < 1024)
Joonyoung Shim910d8052011-04-12 23:14:38 -0700782 x = x >> 2;
Amy Maloche83c385a2012-02-01 10:32:03 +0530783 if (data->touch_y_size < 1024)
Joonyoung Shim910d8052011-04-12 23:14:38 -0700784 y = y >> 2;
785
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700786 area = message->message[4];
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700787 pressure = message->message[5];
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700788
789 dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
Iiro Valkonen7686b102011-02-02 23:21:58 -0800790 status & MXT_MOVE ? "moved" : "pressed",
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700791 x, y, area);
792
Iiro Valkonen7686b102011-02-02 23:21:58 -0800793 finger[id].status = status & MXT_MOVE ?
794 MXT_MOVE : MXT_PRESS;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700795 finger[id].x = x;
796 finger[id].y = y;
797 finger[id].area = area;
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700798 finger[id].pressure = pressure;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700799
Iiro Valkonen7686b102011-02-02 23:21:58 -0800800 mxt_input_report(data, id);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700801}
802
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800803static void mxt_handle_key_array(struct mxt_data *data,
804 struct mxt_message *message)
805{
806 u32 keys_changed;
807 int i;
808
809 if (!data->pdata->key_codes) {
810 dev_err(&data->client->dev, "keyarray is not supported\n");
811 return;
812 }
813
814 data->keyarray_new = message->message[1] |
815 (message->message[2] << 8) |
816 (message->message[3] << 16) |
817 (message->message[4] << 24);
818
819 keys_changed = data->keyarray_old ^ data->keyarray_new;
820
821 if (!keys_changed) {
822 dev_dbg(&data->client->dev, "no keys changed\n");
823 return;
824 }
825
826 for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) {
827 if (!(keys_changed & (1 << i)))
828 continue;
829
830 input_report_key(data->input_dev, data->pdata->key_codes[i],
831 (data->keyarray_new & (1 << i)));
832 input_sync(data->input_dev);
833 }
834
835 data->keyarray_old = data->keyarray_new;
836}
837
Iiro Valkonen7686b102011-02-02 23:21:58 -0800838static irqreturn_t mxt_interrupt(int irq, void *dev_id)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700839{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800840 struct mxt_data *data = dev_id;
841 struct mxt_message message;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700842 struct device *dev = &data->client->dev;
843 int id;
844 u8 reportid;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700845
Nick Dyer0a4016c2012-01-18 15:17:59 +0530846 if (data->state != APPMODE) {
847 dev_err(dev, "Ignoring IRQ - not in APPMODE state\n");
848 return IRQ_HANDLED;
849 }
850
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700851 do {
Iiro Valkonen7686b102011-02-02 23:21:58 -0800852 if (mxt_read_message(data, &message)) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700853 dev_err(dev, "Failed to read message\n");
854 goto end;
855 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700856 reportid = message.reportid;
857
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800858 if (!reportid) {
859 dev_dbg(dev, "Report id 0 is reserved\n");
860 continue;
861 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700862
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800863 /* check whether report id is part of T9 or T15 */
864 id = reportid - data->t9_min_reportid;
865
866 if (reportid >= data->t9_min_reportid &&
867 reportid <= data->t9_max_reportid)
Iiro Valkonen7686b102011-02-02 23:21:58 -0800868 mxt_input_touchevent(data, &message, id);
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800869 else if (reportid >= data->t15_min_reportid &&
870 reportid <= data->t15_max_reportid)
871 mxt_handle_key_array(data, &message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700872 else
Iiro Valkonen7686b102011-02-02 23:21:58 -0800873 mxt_dump_message(dev, &message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700874 } while (reportid != 0xff);
875
876end:
877 return IRQ_HANDLED;
878}
879
Iiro Valkonen7686b102011-02-02 23:21:58 -0800880static int mxt_check_reg_init(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700881{
Jing Lindc4413c2012-01-16 15:22:52 -0800882 const struct mxt_config_info *config_info = data->config_info;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800883 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700884 struct device *dev = &data->client->dev;
885 int index = 0;
Iiro Valkonen71749f52011-02-15 13:36:52 -0800886 int i, j, config_offset;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700887
Jing Lindc4413c2012-01-16 15:22:52 -0800888 if (!config_info) {
Iiro Valkonen71749f52011-02-15 13:36:52 -0800889 dev_dbg(dev, "No cfg data defined, skipping reg init\n");
890 return 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700891 }
892
893 for (i = 0; i < data->info.object_num; i++) {
894 object = data->object_table + i;
895
Iiro Valkonen7686b102011-02-02 23:21:58 -0800896 if (!mxt_object_writable(object->type))
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700897 continue;
898
Iiro Valkonen71749f52011-02-15 13:36:52 -0800899 for (j = 0; j < object->size + 1; j++) {
900 config_offset = index + j;
Jing Lindc4413c2012-01-16 15:22:52 -0800901 if (config_offset > config_info->config_length) {
Iiro Valkonen71749f52011-02-15 13:36:52 -0800902 dev_err(dev, "Not enough config data!\n");
903 return -EINVAL;
904 }
Iiro Valkonen7686b102011-02-02 23:21:58 -0800905 mxt_write_object(data, object->type, j,
Jing Lindc4413c2012-01-16 15:22:52 -0800906 config_info->config[config_offset]);
Iiro Valkonen71749f52011-02-15 13:36:52 -0800907 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700908 index += object->size + 1;
909 }
910
911 return 0;
912}
913
Iiro Valkonen7686b102011-02-02 23:21:58 -0800914static int mxt_make_highchg(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700915{
916 struct device *dev = &data->client->dev;
Iiro Valkonen26cdb1a2011-02-04 00:51:05 -0800917 struct mxt_message message;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700918 int count = 10;
919 int error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700920
921 /* Read dummy message to make high CHG pin */
922 do {
Iiro Valkonen26cdb1a2011-02-04 00:51:05 -0800923 error = mxt_read_message(data, &message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700924 if (error)
925 return error;
Iiro Valkonen26cdb1a2011-02-04 00:51:05 -0800926 } while (message.reportid != 0xff && --count);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700927
928 if (!count) {
929 dev_err(dev, "CHG pin isn't cleared\n");
930 return -EBUSY;
931 }
932
933 return 0;
934}
935
Iiro Valkonen7686b102011-02-02 23:21:58 -0800936static int mxt_get_info(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700937{
938 struct i2c_client *client = data->client;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800939 struct mxt_info *info = &data->info;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700940 int error;
941 u8 val;
942
Iiro Valkonen7686b102011-02-02 23:21:58 -0800943 error = mxt_read_reg(client, MXT_FAMILY_ID, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700944 if (error)
945 return error;
946 info->family_id = val;
947
Iiro Valkonen7686b102011-02-02 23:21:58 -0800948 error = mxt_read_reg(client, MXT_VARIANT_ID, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700949 if (error)
950 return error;
951 info->variant_id = val;
952
Iiro Valkonen7686b102011-02-02 23:21:58 -0800953 error = mxt_read_reg(client, MXT_VERSION, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700954 if (error)
955 return error;
956 info->version = val;
957
Iiro Valkonen7686b102011-02-02 23:21:58 -0800958 error = mxt_read_reg(client, MXT_BUILD, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700959 if (error)
960 return error;
961 info->build = val;
962
Iiro Valkonen7686b102011-02-02 23:21:58 -0800963 error = mxt_read_reg(client, MXT_OBJECT_NUM, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700964 if (error)
965 return error;
966 info->object_num = val;
967
968 return 0;
969}
970
Iiro Valkonen7686b102011-02-02 23:21:58 -0800971static int mxt_get_object_table(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700972{
973 int error;
974 int i;
975 u16 reg;
976 u8 reportid = 0;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800977 u8 buf[MXT_OBJECT_SIZE];
Jing Lindc4413c2012-01-16 15:22:52 -0800978 bool found_t38 = false;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700979
980 for (i = 0; i < data->info.object_num; i++) {
Iiro Valkonen7686b102011-02-02 23:21:58 -0800981 struct mxt_object *object = data->object_table + i;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700982
Iiro Valkonen7686b102011-02-02 23:21:58 -0800983 reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i;
984 error = mxt_read_object_table(data->client, reg, buf);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700985 if (error)
986 return error;
987
988 object->type = buf[0];
989 object->start_address = (buf[2] << 8) | buf[1];
990 object->size = buf[3];
991 object->instances = buf[4];
992 object->num_report_ids = buf[5];
993
994 if (object->num_report_ids) {
995 reportid += object->num_report_ids *
996 (object->instances + 1);
997 object->max_reportid = reportid;
998 }
Jing Lindc4413c2012-01-16 15:22:52 -0800999
1000 /* Calculate index for config major version in config array.
1001 * Major version is the first byte in object T38.
1002 */
1003 if (object->type == MXT_SPT_USERDATA_T38)
1004 found_t38 = true;
1005 if (!found_t38 && mxt_object_writable(object->type))
1006 data->cfg_version_idx += object->size + 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001007 }
1008
1009 return 0;
1010}
1011
Jing Lindc4413c2012-01-16 15:22:52 -08001012static int mxt_search_config_array(struct mxt_data *data, bool version_match)
1013{
1014
1015 const struct mxt_platform_data *pdata = data->pdata;
1016 const struct mxt_config_info *cfg_info;
1017 struct mxt_info *info = &data->info;
1018 int i;
1019 u8 cfg_version;
1020
1021 for (i = 0; i < pdata->config_array_size; i++) {
1022
1023 cfg_info = &pdata->config_array[i];
1024
1025 if (!cfg_info->config || !cfg_info->config_length)
1026 continue;
1027
1028 if (info->family_id == cfg_info->family_id &&
1029 info->variant_id == cfg_info->variant_id &&
1030 info->version == cfg_info->version &&
1031 info->build == cfg_info->build) {
1032
1033 cfg_version = cfg_info->config[data->cfg_version_idx];
1034 if (data->curr_cfg_version == cfg_version ||
1035 !version_match) {
1036 data->config_info = cfg_info;
1037 return 0;
1038 }
1039 }
1040 }
1041
1042 dev_info(&data->client->dev,
1043 "Config not found: F: %d, V: %d, FW: %d.%d.%d, CFG: %d\n",
1044 info->family_id, info->variant_id,
1045 info->version >> 4, info->version & 0xF, info->build,
1046 data->curr_cfg_version);
1047 return -EINVAL;
1048}
1049
1050static int mxt_get_config(struct mxt_data *data)
1051{
1052 const struct mxt_platform_data *pdata = data->pdata;
1053 struct device *dev = &data->client->dev;
1054 struct mxt_object *object;
1055 int error;
1056
1057 if (!pdata->config_array || !pdata->config_array_size) {
1058 dev_dbg(dev, "No cfg data provided by platform data\n");
1059 return 0;
1060 }
1061
1062 /* Get current config version */
1063 object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
1064 if (!object) {
1065 dev_err(dev, "Unable to obtain USERDATA object\n");
1066 return -EINVAL;
1067 }
1068
1069 error = mxt_read_reg(data->client, object->start_address,
1070 &data->curr_cfg_version);
1071 if (error) {
1072 dev_err(dev, "Unable to read config version\n");
1073 return error;
1074 }
1075
1076 /* It is possible that the config data on the controller is not
1077 * versioned and the version number returns 0. In this case,
1078 * find a match without the config version checking.
1079 */
1080 error = mxt_search_config_array(data,
1081 data->curr_cfg_version != 0 ? true : false);
1082 if (error)
1083 return error;
1084
1085 return 0;
1086}
Amy Maloche7e447432011-09-14 11:36:30 -07001087static void mxt_reset_delay(struct mxt_data *data)
1088{
1089 struct mxt_info *info = &data->info;
1090
1091 switch (info->family_id) {
1092 case MXT224_ID:
1093 msleep(MXT224_RESET_TIME);
1094 break;
Amy Maloche380cc0b2011-11-03 12:55:04 -07001095 case MXT224E_ID:
1096 msleep(MXT224E_RESET_TIME);
1097 break;
Amy Maloche7e447432011-09-14 11:36:30 -07001098 case MXT1386_ID:
1099 msleep(MXT1386_RESET_TIME);
1100 break;
1101 default:
1102 msleep(MXT_RESET_TIME);
1103 }
1104}
1105
Iiro Valkonen7686b102011-02-02 23:21:58 -08001106static int mxt_initialize(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001107{
1108 struct i2c_client *client = data->client;
Iiro Valkonen7686b102011-02-02 23:21:58 -08001109 struct mxt_info *info = &data->info;
Jing Lin36aee812011-10-17 17:17:28 -07001110 int error;
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001111 int timeout_counter = 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001112 u8 val;
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001113 u8 command_register;
Jing Lin36aee812011-10-17 17:17:28 -07001114 struct mxt_object *t7_object;
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08001115 struct mxt_object *t9_object;
1116 struct mxt_object *t15_object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001117
Iiro Valkonen7686b102011-02-02 23:21:58 -08001118 error = mxt_get_info(data);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301119 if (error) {
1120 /* Try bootloader mode */
1121 error = mxt_switch_to_bootloader_address(data);
1122 if (error)
1123 return error;
1124
1125 error = mxt_check_bootloader(client, MXT_APP_CRC_FAIL);
1126 if (error)
1127 return error;
1128
1129 dev_err(&client->dev, "Application CRC failure\n");
1130 data->state = BOOTLOADER;
1131
1132 return 0;
1133 }
1134
1135 dev_info(&client->dev,
1136 "Family ID: %d Variant ID: %d Version: %d.%d "
1137 "Build: 0x%02X Object Num: %d\n",
1138 info->family_id, info->variant_id,
1139 info->version >> 4, info->version & 0xf,
1140 info->build, info->object_num);
1141
1142 data->state = APPMODE;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001143
1144 data->object_table = kcalloc(info->object_num,
Iiro Valkonen7686b102011-02-02 23:21:58 -08001145 sizeof(struct mxt_object),
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001146 GFP_KERNEL);
1147 if (!data->object_table) {
1148 dev_err(&client->dev, "Failed to allocate memory\n");
1149 return -ENOMEM;
1150 }
1151
1152 /* Get object table information */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001153 error = mxt_get_object_table(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001154 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001155 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001156
Jing Lindc4413c2012-01-16 15:22:52 -08001157 /* Get config data from platform data */
1158 error = mxt_get_config(data);
1159 if (error)
1160 dev_dbg(&client->dev, "Config info not found.\n");
1161
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001162 /* Check register init values */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001163 error = mxt_check_reg_init(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001164 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001165 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001166
Amy Maloche52262212011-09-15 16:46:57 -07001167 /* Store T7 and T9 locally, used in suspend/resume operations */
Iiro Valkonene8645592011-11-18 12:56:19 -08001168 t7_object = mxt_get_object(data, MXT_GEN_POWER_T7);
Jing Lin36aee812011-10-17 17:17:28 -07001169 if (!t7_object) {
1170 dev_err(&client->dev, "Failed to get T7 object\n");
Jing Lin32c72532011-11-03 12:02:33 -07001171 error = -EINVAL;
1172 goto free_object_table;
Jing Lin36aee812011-10-17 17:17:28 -07001173 }
1174
1175 data->t7_start_addr = t7_object->start_address;
1176 error = __mxt_read_reg(client, data->t7_start_addr,
1177 T7_DATA_SIZE, data->t7_data);
1178 if (error < 0) {
1179 dev_err(&client->dev,
Jing Lin32c72532011-11-03 12:02:33 -07001180 "Failed to save current power state\n");
1181 goto free_object_table;
Amy Maloche52262212011-09-15 16:46:57 -07001182 }
Iiro Valkonene8645592011-11-18 12:56:19 -08001183 error = mxt_read_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL,
Amy Maloche52262212011-09-15 16:46:57 -07001184 &data->t9_ctrl);
1185 if (error < 0) {
Jing Lin32c72532011-11-03 12:02:33 -07001186 dev_err(&client->dev, "Failed to save current touch object\n");
1187 goto free_object_table;
Amy Maloche52262212011-09-15 16:46:57 -07001188 }
1189
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08001190 /* Store T9, T15's min and max report ids */
1191 t9_object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
1192 if (!t9_object) {
1193 dev_err(&client->dev, "Failed to get T9 object\n");
1194 error = -EINVAL;
1195 goto free_object_table;
1196 }
1197 data->t9_max_reportid = t9_object->max_reportid;
1198 data->t9_min_reportid = t9_object->max_reportid -
1199 t9_object->num_report_ids + 1;
1200
1201 if (data->pdata->key_codes) {
1202 t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15);
1203 if (!t15_object)
1204 dev_dbg(&client->dev, "T15 object is not available\n");
1205 else {
1206 data->t15_max_reportid = t15_object->max_reportid;
1207 data->t15_min_reportid = t15_object->max_reportid -
1208 t15_object->num_report_ids + 1;
1209 }
1210 }
1211
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001212 /* Backup to memory */
Iiro Valkonene8645592011-11-18 12:56:19 -08001213 mxt_write_object(data, MXT_GEN_COMMAND_T6,
Iiro Valkonen7686b102011-02-02 23:21:58 -08001214 MXT_COMMAND_BACKUPNV,
1215 MXT_BACKUP_VALUE);
1216 msleep(MXT_BACKUP_TIME);
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001217 do {
Iiro Valkonene8645592011-11-18 12:56:19 -08001218 error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001219 MXT_COMMAND_BACKUPNV,
1220 &command_register);
1221 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001222 goto free_object_table;
Amy Maloche7e447432011-09-14 11:36:30 -07001223 usleep_range(1000, 2000);
1224 } while ((command_register != 0) && (++timeout_counter <= 100));
1225 if (timeout_counter > 100) {
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001226 dev_err(&client->dev, "No response after backup!\n");
Jing Lin32c72532011-11-03 12:02:33 -07001227 error = -EIO;
1228 goto free_object_table;
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001229 }
1230
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001231
1232 /* Soft reset */
Iiro Valkonene8645592011-11-18 12:56:19 -08001233 mxt_write_object(data, MXT_GEN_COMMAND_T6,
Iiro Valkonen7686b102011-02-02 23:21:58 -08001234 MXT_COMMAND_RESET, 1);
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001235
Amy Maloche7e447432011-09-14 11:36:30 -07001236 mxt_reset_delay(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001237
1238 /* Update matrix size at info struct */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001239 error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001240 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001241 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001242 info->matrix_xsize = val;
1243
Iiro Valkonen7686b102011-02-02 23:21:58 -08001244 error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001245 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001246 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001247 info->matrix_ysize = val;
1248
1249 dev_info(&client->dev,
Nick Dyer0a4016c2012-01-18 15:17:59 +05301250 "Matrix X Size: %d Matrix Y Size: %d\n",
1251 info->matrix_xsize, info->matrix_ysize);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001252
1253 return 0;
Jing Lin32c72532011-11-03 12:02:33 -07001254
1255free_object_table:
1256 kfree(data->object_table);
1257 return error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001258}
1259
Iiro Valkonen7686b102011-02-02 23:21:58 -08001260static ssize_t mxt_object_show(struct device *dev,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001261 struct device_attribute *attr, char *buf)
1262{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001263 struct mxt_data *data = dev_get_drvdata(dev);
1264 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001265 int count = 0;
1266 int i, j;
1267 int error;
1268 u8 val;
1269
1270 for (i = 0; i < data->info.object_num; i++) {
1271 object = data->object_table + i;
1272
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001273 count += snprintf(buf + count, PAGE_SIZE - count,
1274 "Object[%d] (Type %d)\n",
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001275 i + 1, object->type);
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001276 if (count >= PAGE_SIZE)
1277 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001278
Iiro Valkonen7686b102011-02-02 23:21:58 -08001279 if (!mxt_object_readable(object->type)) {
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001280 count += snprintf(buf + count, PAGE_SIZE - count,
1281 "\n");
1282 if (count >= PAGE_SIZE)
1283 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001284 continue;
1285 }
1286
1287 for (j = 0; j < object->size + 1; j++) {
Iiro Valkonen7686b102011-02-02 23:21:58 -08001288 error = mxt_read_object(data,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001289 object->type, j, &val);
1290 if (error)
1291 return error;
1292
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001293 count += snprintf(buf + count, PAGE_SIZE - count,
1294 "\t[%2d]: %02x (%d)\n", j, val, val);
1295 if (count >= PAGE_SIZE)
1296 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001297 }
1298
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001299 count += snprintf(buf + count, PAGE_SIZE - count, "\n");
1300 if (count >= PAGE_SIZE)
1301 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001302 }
1303
1304 return count;
1305}
1306
Iiro Valkonen7686b102011-02-02 23:21:58 -08001307static int mxt_load_fw(struct device *dev, const char *fn)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001308{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001309 struct mxt_data *data = dev_get_drvdata(dev);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001310 struct i2c_client *client = data->client;
1311 const struct firmware *fw = NULL;
1312 unsigned int frame_size;
Nick Dyer0a4016c2012-01-18 15:17:59 +05301313 unsigned int retry = 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001314 unsigned int pos = 0;
1315 int ret;
1316
1317 ret = request_firmware(&fw, fn, dev);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301318 if (ret < 0) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001319 dev_err(dev, "Unable to open firmware %s\n", fn);
1320 return ret;
1321 }
1322
Nick Dyer0a4016c2012-01-18 15:17:59 +05301323 if (data->state != BOOTLOADER) {
1324 /* Change to the bootloader mode */
1325 mxt_write_object(data, MXT_GEN_COMMAND_T6,
1326 MXT_COMMAND_RESET, MXT_BOOT_VALUE);
1327 mxt_reset_delay(data);
Amy Maloche7e447432011-09-14 11:36:30 -07001328
Nick Dyer0a4016c2012-01-18 15:17:59 +05301329 ret = mxt_switch_to_bootloader_address(data);
1330 if (ret)
1331 goto release_firmware;
1332 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001333
Iiro Valkonen7686b102011-02-02 23:21:58 -08001334 ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301335 if (ret) {
1336 /* Bootloader may still be unlocked from previous update
1337 * attempt */
1338 ret = mxt_check_bootloader(client,
1339 MXT_WAITING_FRAME_DATA);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001340
Nick Dyer0a4016c2012-01-18 15:17:59 +05301341 if (ret)
1342 goto return_to_app_mode;
1343 } else {
1344 dev_info(dev, "Unlocking bootloader\n");
1345 /* Unlock bootloader */
1346 mxt_unlock_bootloader(client);
1347 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001348
1349 while (pos < fw->size) {
Iiro Valkonen7686b102011-02-02 23:21:58 -08001350 ret = mxt_check_bootloader(client,
1351 MXT_WAITING_FRAME_DATA);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001352 if (ret)
Nick Dyer0a4016c2012-01-18 15:17:59 +05301353 goto release_firmware;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001354
1355 frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
1356
1357 /* We should add 2 at frame size as the the firmware data is not
1358 * included the CRC bytes.
1359 */
1360 frame_size += 2;
1361
1362 /* Write one frame to device */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001363 mxt_fw_write(client, fw->data + pos, frame_size);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001364
Iiro Valkonen7686b102011-02-02 23:21:58 -08001365 ret = mxt_check_bootloader(client,
1366 MXT_FRAME_CRC_PASS);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301367 if (ret) {
1368 retry++;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001369
Nick Dyer0a4016c2012-01-18 15:17:59 +05301370 /* Back off by 20ms per retry */
1371 msleep(retry * 20);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001372
Nick Dyer0a4016c2012-01-18 15:17:59 +05301373 if (retry > 20)
1374 goto release_firmware;
1375 } else {
1376 retry = 0;
1377 pos += frame_size;
1378 dev_info(dev, "Updated %d/%zd bytes\n", pos, fw->size);
1379 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001380 }
1381
Nick Dyer0a4016c2012-01-18 15:17:59 +05301382return_to_app_mode:
1383 mxt_switch_to_appmode_address(data);
1384release_firmware:
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001385 release_firmware(fw);
1386
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001387 return ret;
1388}
1389
Iiro Valkonen7686b102011-02-02 23:21:58 -08001390static ssize_t mxt_update_fw_store(struct device *dev,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001391 struct device_attribute *attr,
1392 const char *buf, size_t count)
1393{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001394 struct mxt_data *data = dev_get_drvdata(dev);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001395 int error;
1396
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001397 disable_irq(data->irq);
1398
Iiro Valkonen7686b102011-02-02 23:21:58 -08001399 error = mxt_load_fw(dev, MXT_FW_NAME);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001400 if (error) {
1401 dev_err(dev, "The firmware update failed(%d)\n", error);
1402 count = error;
1403 } else {
Nick Dyer0a4016c2012-01-18 15:17:59 +05301404 dev_info(dev, "The firmware update succeeded\n");
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001405
1406 /* Wait for reset */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001407 msleep(MXT_FWRESET_TIME);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001408
Nick Dyer0a4016c2012-01-18 15:17:59 +05301409 data->state = INIT;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001410 kfree(data->object_table);
1411 data->object_table = NULL;
1412
Iiro Valkonen7686b102011-02-02 23:21:58 -08001413 mxt_initialize(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001414 }
1415
Nick Dyer0a4016c2012-01-18 15:17:59 +05301416 if (data->state == APPMODE) {
1417 enable_irq(data->irq);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001418
Nick Dyer0a4016c2012-01-18 15:17:59 +05301419 error = mxt_make_highchg(data);
1420 if (error)
1421 return error;
1422 }
Iiro Valkonen08960a02011-04-12 23:16:40 -07001423
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001424 return count;
1425}
1426
Iiro Valkonen7686b102011-02-02 23:21:58 -08001427static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
1428static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001429
Iiro Valkonen7686b102011-02-02 23:21:58 -08001430static struct attribute *mxt_attrs[] = {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001431 &dev_attr_object.attr,
1432 &dev_attr_update_fw.attr,
1433 NULL
1434};
1435
Iiro Valkonen7686b102011-02-02 23:21:58 -08001436static const struct attribute_group mxt_attr_group = {
1437 .attrs = mxt_attrs,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001438};
1439
Amy Maloche52262212011-09-15 16:46:57 -07001440static int mxt_start(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001441{
Jing Lin36aee812011-10-17 17:17:28 -07001442 int error;
1443
Amy Maloche52262212011-09-15 16:46:57 -07001444 /* restore the old power state values and reenable touch */
Jing Lin36aee812011-10-17 17:17:28 -07001445 error = __mxt_write_reg(data->client, data->t7_start_addr,
1446 T7_DATA_SIZE, data->t7_data);
1447 if (error < 0) {
1448 dev_err(&data->client->dev,
1449 "failed to restore old power state\n");
1450 return error;
Amy Maloche52262212011-09-15 16:46:57 -07001451 }
Jing Lin36aee812011-10-17 17:17:28 -07001452
Amy Maloche52262212011-09-15 16:46:57 -07001453 error = mxt_write_object(data,
Iiro Valkonene8645592011-11-18 12:56:19 -08001454 MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, data->t9_ctrl);
Amy Maloche52262212011-09-15 16:46:57 -07001455 if (error < 0) {
1456 dev_err(&data->client->dev, "failed to restore touch\n");
1457 return error;
1458 }
1459
1460 return 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001461}
1462
Amy Maloche52262212011-09-15 16:46:57 -07001463static int mxt_stop(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001464{
Jing Lin36aee812011-10-17 17:17:28 -07001465 int error;
1466 u8 t7_data[T7_DATA_SIZE] = {0};
1467
1468 /* disable touch and configure deep sleep mode */
Iiro Valkonene8645592011-11-18 12:56:19 -08001469 error = mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
Jing Lin36aee812011-10-17 17:17:28 -07001470 if (error < 0) {
1471 dev_err(&data->client->dev, "failed to disable touch\n");
1472 return error;
Amy Maloche52262212011-09-15 16:46:57 -07001473 }
1474
Jing Lin36aee812011-10-17 17:17:28 -07001475 error = __mxt_write_reg(data->client, data->t7_start_addr,
1476 T7_DATA_SIZE, t7_data);
Amy Maloche52262212011-09-15 16:46:57 -07001477 if (error < 0) {
1478 dev_err(&data->client->dev,
Jing Lin36aee812011-10-17 17:17:28 -07001479 "failed to configure deep sleep mode\n");
Amy Maloche52262212011-09-15 16:46:57 -07001480 return error;
1481 }
1482
1483 return 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001484}
1485
Iiro Valkonen7686b102011-02-02 23:21:58 -08001486static int mxt_input_open(struct input_dev *dev)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001487{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001488 struct mxt_data *data = input_get_drvdata(dev);
Amy Maloche52262212011-09-15 16:46:57 -07001489 int error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001490
Amy Maloche52262212011-09-15 16:46:57 -07001491 error = mxt_start(data);
1492 if (error < 0) {
1493 dev_err(&data->client->dev, "mxt_start failed in input_open\n");
1494 return error;
1495 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001496
1497 return 0;
1498}
1499
Iiro Valkonen7686b102011-02-02 23:21:58 -08001500static void mxt_input_close(struct input_dev *dev)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001501{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001502 struct mxt_data *data = input_get_drvdata(dev);
Amy Maloche52262212011-09-15 16:46:57 -07001503 int error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001504
Amy Maloche52262212011-09-15 16:46:57 -07001505 error = mxt_stop(data);
1506 if (error < 0)
1507 dev_err(&data->client->dev, "mxt_stop failed in input_close\n");
1508
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001509}
1510
Amy Malochec331f842012-01-24 10:33:47 -08001511static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
1512{
1513 return (regulator_count_voltages(reg) > 0) ?
1514 regulator_set_optimum_mode(reg, load_uA) : 0;
1515}
1516
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301517static int mxt_power_on(struct mxt_data *data, bool on)
1518{
1519 int rc;
1520
1521 if (on == false)
1522 goto power_off;
1523
Amy Malochec331f842012-01-24 10:33:47 -08001524 rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301525 if (rc < 0) {
Amy Maloche21115eb2011-11-02 09:04:37 -07001526 dev_err(&data->client->dev,
1527 "Regulator vcc_ana set_opt failed rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301528 return rc;
1529 }
1530
Amy Maloche21115eb2011-11-02 09:04:37 -07001531 rc = regulator_enable(data->vcc_ana);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301532 if (rc) {
Amy Maloche21115eb2011-11-02 09:04:37 -07001533 dev_err(&data->client->dev,
1534 "Regulator vcc_ana enable failed rc=%d\n", rc);
1535 goto error_reg_en_vcc_ana;
1536 }
1537
1538 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001539 rc = reg_set_optimum_mode_check(data->vcc_dig,
1540 MXT_ACTIVE_LOAD_DIG_UA);
Amy Maloche21115eb2011-11-02 09:04:37 -07001541 if (rc < 0) {
1542 dev_err(&data->client->dev,
1543 "Regulator vcc_dig set_opt failed rc=%d\n",
1544 rc);
1545 goto error_reg_opt_vcc_dig;
1546 }
1547
1548 rc = regulator_enable(data->vcc_dig);
1549 if (rc) {
1550 dev_err(&data->client->dev,
1551 "Regulator vcc_dig enable failed rc=%d\n", rc);
1552 goto error_reg_en_vcc_dig;
1553 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301554 }
1555
1556 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001557 rc = reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LOAD_UA);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301558 if (rc < 0) {
1559 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001560 "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301561 goto error_reg_opt_i2c;
1562 }
1563
1564 rc = regulator_enable(data->vcc_i2c);
1565 if (rc) {
1566 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001567 "Regulator vcc_i2c enable failed rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301568 goto error_reg_en_vcc_i2c;
1569 }
1570 }
1571
Amy Malochef0d7b8d2011-10-17 12:10:51 -07001572 msleep(130);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301573
1574 return 0;
1575
1576error_reg_en_vcc_i2c:
1577 if (data->pdata->i2c_pull_up)
Amy Malochec331f842012-01-24 10:33:47 -08001578 reg_set_optimum_mode_check(data->vcc_i2c, 0);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301579error_reg_opt_i2c:
Amy Maloche21115eb2011-11-02 09:04:37 -07001580 if (data->pdata->digital_pwr_regulator)
1581 regulator_disable(data->vcc_dig);
1582error_reg_en_vcc_dig:
1583 if (data->pdata->digital_pwr_regulator)
Amy Malochec331f842012-01-24 10:33:47 -08001584 reg_set_optimum_mode_check(data->vcc_dig, 0);
Amy Maloche21115eb2011-11-02 09:04:37 -07001585error_reg_opt_vcc_dig:
1586 regulator_disable(data->vcc_ana);
1587error_reg_en_vcc_ana:
Amy Malochec331f842012-01-24 10:33:47 -08001588 reg_set_optimum_mode_check(data->vcc_ana, 0);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301589 return rc;
1590
1591power_off:
Amy Malochec331f842012-01-24 10:33:47 -08001592 reg_set_optimum_mode_check(data->vcc_ana, 0);
Amy Maloche21115eb2011-11-02 09:04:37 -07001593 regulator_disable(data->vcc_ana);
1594 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001595 reg_set_optimum_mode_check(data->vcc_dig, 0);
Amy Maloche21115eb2011-11-02 09:04:37 -07001596 regulator_disable(data->vcc_dig);
1597 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301598 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001599 reg_set_optimum_mode_check(data->vcc_i2c, 0);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301600 regulator_disable(data->vcc_i2c);
1601 }
1602 msleep(50);
1603 return 0;
1604}
1605
1606static int mxt_regulator_configure(struct mxt_data *data, bool on)
1607{
1608 int rc;
1609
1610 if (on == false)
1611 goto hw_shutdown;
1612
Amy Maloche21115eb2011-11-02 09:04:37 -07001613 data->vcc_ana = regulator_get(&data->client->dev, "vdd_ana");
1614 if (IS_ERR(data->vcc_ana)) {
1615 rc = PTR_ERR(data->vcc_ana);
1616 dev_err(&data->client->dev,
1617 "Regulator get failed vcc_ana rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301618 return rc;
1619 }
1620
Amy Maloche21115eb2011-11-02 09:04:37 -07001621 if (regulator_count_voltages(data->vcc_ana) > 0) {
1622 rc = regulator_set_voltage(data->vcc_ana, MXT_VTG_MIN_UV,
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301623 MXT_VTG_MAX_UV);
1624 if (rc) {
1625 dev_err(&data->client->dev,
1626 "regulator set_vtg failed rc=%d\n", rc);
Amy Maloche21115eb2011-11-02 09:04:37 -07001627 goto error_set_vtg_vcc_ana;
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301628 }
1629 }
Amy Maloche21115eb2011-11-02 09:04:37 -07001630 if (data->pdata->digital_pwr_regulator) {
1631 data->vcc_dig = regulator_get(&data->client->dev, "vdd_dig");
1632 if (IS_ERR(data->vcc_dig)) {
1633 rc = PTR_ERR(data->vcc_dig);
1634 dev_err(&data->client->dev,
1635 "Regulator get dig failed rc=%d\n", rc);
1636 goto error_get_vtg_vcc_dig;
1637 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301638
Amy Maloche21115eb2011-11-02 09:04:37 -07001639 if (regulator_count_voltages(data->vcc_dig) > 0) {
1640 rc = regulator_set_voltage(data->vcc_dig,
1641 MXT_VTG_DIG_MIN_UV, MXT_VTG_DIG_MAX_UV);
1642 if (rc) {
1643 dev_err(&data->client->dev,
1644 "regulator set_vtg failed rc=%d\n", rc);
1645 goto error_set_vtg_vcc_dig;
1646 }
1647 }
1648 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301649 if (data->pdata->i2c_pull_up) {
1650 data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
1651 if (IS_ERR(data->vcc_i2c)) {
1652 rc = PTR_ERR(data->vcc_i2c);
1653 dev_err(&data->client->dev,
1654 "Regulator get failed rc=%d\n", rc);
1655 goto error_get_vtg_i2c;
1656 }
1657 if (regulator_count_voltages(data->vcc_i2c) > 0) {
1658 rc = regulator_set_voltage(data->vcc_i2c,
1659 MXT_I2C_VTG_MIN_UV, MXT_I2C_VTG_MAX_UV);
1660 if (rc) {
1661 dev_err(&data->client->dev,
1662 "regulator set_vtg failed rc=%d\n", rc);
1663 goto error_set_vtg_i2c;
1664 }
1665 }
1666 }
1667
1668 return 0;
1669
1670error_set_vtg_i2c:
1671 regulator_put(data->vcc_i2c);
1672error_get_vtg_i2c:
Amy Maloche21115eb2011-11-02 09:04:37 -07001673 if (data->pdata->digital_pwr_regulator)
1674 if (regulator_count_voltages(data->vcc_dig) > 0)
1675 regulator_set_voltage(data->vcc_dig, 0,
1676 MXT_VTG_DIG_MAX_UV);
1677error_set_vtg_vcc_dig:
1678 if (data->pdata->digital_pwr_regulator)
1679 regulator_put(data->vcc_dig);
1680error_get_vtg_vcc_dig:
1681 if (regulator_count_voltages(data->vcc_ana) > 0)
1682 regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
1683error_set_vtg_vcc_ana:
1684 regulator_put(data->vcc_ana);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301685 return rc;
1686
1687hw_shutdown:
Amy Maloche21115eb2011-11-02 09:04:37 -07001688 if (regulator_count_voltages(data->vcc_ana) > 0)
1689 regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
1690 regulator_put(data->vcc_ana);
1691 if (data->pdata->digital_pwr_regulator) {
1692 if (regulator_count_voltages(data->vcc_dig) > 0)
1693 regulator_set_voltage(data->vcc_dig, 0,
1694 MXT_VTG_DIG_MAX_UV);
1695 regulator_put(data->vcc_dig);
1696 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301697 if (data->pdata->i2c_pull_up) {
1698 if (regulator_count_voltages(data->vcc_i2c) > 0)
1699 regulator_set_voltage(data->vcc_i2c, 0,
1700 MXT_I2C_VTG_MAX_UV);
1701 regulator_put(data->vcc_i2c);
1702 }
1703 return 0;
1704}
1705
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301706#ifdef CONFIG_PM
Jing Linbace50b2011-10-18 22:55:47 -07001707static int mxt_regulator_lpm(struct mxt_data *data, bool on)
1708{
1709
1710 int rc;
1711
1712 if (on == false)
1713 goto regulator_hpm;
1714
Amy Malochec331f842012-01-24 10:33:47 -08001715 rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_LPM_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001716 if (rc < 0) {
1717 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001718 "Regulator vcc_ana set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001719 goto fail_regulator_lpm;
1720 }
1721
Amy Maloche21115eb2011-11-02 09:04:37 -07001722 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001723 rc = reg_set_optimum_mode_check(data->vcc_dig,
Amy Maloche21115eb2011-11-02 09:04:37 -07001724 MXT_LPM_LOAD_DIG_UA);
1725 if (rc < 0) {
1726 dev_err(&data->client->dev,
1727 "Regulator vcc_dig set_opt failed rc=%d\n", rc);
1728 goto fail_regulator_lpm;
1729 }
1730 }
1731
Jing Linbace50b2011-10-18 22:55:47 -07001732 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001733 rc = reg_set_optimum_mode_check(data->vcc_i2c,
Jing Linbace50b2011-10-18 22:55:47 -07001734 MXT_I2C_LPM_LOAD_UA);
1735 if (rc < 0) {
1736 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001737 "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001738 goto fail_regulator_lpm;
1739 }
1740 }
1741
1742 return 0;
1743
1744regulator_hpm:
1745
Amy Malochec331f842012-01-24 10:33:47 -08001746 rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001747 if (rc < 0) {
1748 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001749 "Regulator vcc_ana set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001750 goto fail_regulator_hpm;
1751 }
1752
Amy Maloche21115eb2011-11-02 09:04:37 -07001753 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001754 rc = reg_set_optimum_mode_check(data->vcc_dig,
Amy Maloche21115eb2011-11-02 09:04:37 -07001755 MXT_ACTIVE_LOAD_DIG_UA);
1756 if (rc < 0) {
1757 dev_err(&data->client->dev,
1758 "Regulator vcc_dig set_opt failed rc=%d\n", rc);
1759 goto fail_regulator_hpm;
1760 }
1761 }
1762
Jing Linbace50b2011-10-18 22:55:47 -07001763 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001764 rc = reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001765 if (rc < 0) {
1766 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001767 "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001768 goto fail_regulator_hpm;
1769 }
1770 }
1771
1772 return 0;
1773
1774fail_regulator_lpm:
Amy Malochec331f842012-01-24 10:33:47 -08001775 reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
Amy Maloche21115eb2011-11-02 09:04:37 -07001776 if (data->pdata->digital_pwr_regulator)
Amy Malochec331f842012-01-24 10:33:47 -08001777 reg_set_optimum_mode_check(data->vcc_dig,
1778 MXT_ACTIVE_LOAD_DIG_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001779 if (data->pdata->i2c_pull_up)
Amy Malochec331f842012-01-24 10:33:47 -08001780 reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001781
1782 return rc;
1783
1784fail_regulator_hpm:
Amy Malochec331f842012-01-24 10:33:47 -08001785 reg_set_optimum_mode_check(data->vcc_ana, MXT_LPM_LOAD_UA);
Amy Maloche21115eb2011-11-02 09:04:37 -07001786 if (data->pdata->digital_pwr_regulator)
Amy Malochec331f842012-01-24 10:33:47 -08001787 reg_set_optimum_mode_check(data->vcc_dig, MXT_LPM_LOAD_DIG_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001788 if (data->pdata->i2c_pull_up)
Amy Malochec331f842012-01-24 10:33:47 -08001789 reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LPM_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001790
1791 return rc;
1792}
1793
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301794static int mxt_suspend(struct device *dev)
1795{
1796 struct i2c_client *client = to_i2c_client(dev);
1797 struct mxt_data *data = i2c_get_clientdata(client);
1798 struct input_dev *input_dev = data->input_dev;
Amy Maloche52262212011-09-15 16:46:57 -07001799 int error;
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301800
1801 mutex_lock(&input_dev->mutex);
1802
Amy Maloche52262212011-09-15 16:46:57 -07001803 if (input_dev->users) {
1804 error = mxt_stop(data);
1805 if (error < 0) {
Jing Lin36aee812011-10-17 17:17:28 -07001806 dev_err(dev, "mxt_stop failed in suspend\n");
Amy Maloche52262212011-09-15 16:46:57 -07001807 mutex_unlock(&input_dev->mutex);
1808 return error;
1809 }
1810
1811 }
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301812
1813 mutex_unlock(&input_dev->mutex);
1814
Jing Linbace50b2011-10-18 22:55:47 -07001815 /* put regulators in low power mode */
1816 error = mxt_regulator_lpm(data, true);
1817 if (error < 0) {
1818 dev_err(dev, "failed to enter low power mode\n");
1819 return error;
1820 }
1821
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301822 return 0;
1823}
1824
1825static int mxt_resume(struct device *dev)
1826{
1827 struct i2c_client *client = to_i2c_client(dev);
1828 struct mxt_data *data = i2c_get_clientdata(client);
1829 struct input_dev *input_dev = data->input_dev;
Amy Maloche52262212011-09-15 16:46:57 -07001830 int error;
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301831
Jing Linbace50b2011-10-18 22:55:47 -07001832 /* put regulators in high power mode */
1833 error = mxt_regulator_lpm(data, false);
1834 if (error < 0) {
1835 dev_err(dev, "failed to enter high power mode\n");
1836 return error;
1837 }
1838
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301839 mutex_lock(&input_dev->mutex);
1840
Amy Maloche52262212011-09-15 16:46:57 -07001841 if (input_dev->users) {
1842 error = mxt_start(data);
1843 if (error < 0) {
Jing Lin36aee812011-10-17 17:17:28 -07001844 dev_err(dev, "mxt_start failed in resume\n");
Amy Maloche52262212011-09-15 16:46:57 -07001845 mutex_unlock(&input_dev->mutex);
1846 return error;
1847 }
1848 }
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301849
1850 mutex_unlock(&input_dev->mutex);
1851
1852 return 0;
1853}
1854
1855#if defined(CONFIG_HAS_EARLYSUSPEND)
1856static void mxt_early_suspend(struct early_suspend *h)
1857{
1858 struct mxt_data *data = container_of(h, struct mxt_data, early_suspend);
1859
1860 mxt_suspend(&data->client->dev);
1861}
1862
1863static void mxt_late_resume(struct early_suspend *h)
1864{
1865 struct mxt_data *data = container_of(h, struct mxt_data, early_suspend);
1866
1867 mxt_resume(&data->client->dev);
1868}
1869#endif
1870
1871static const struct dev_pm_ops mxt_pm_ops = {
1872#ifndef CONFIG_HAS_EARLYSUSPEND
1873 .suspend = mxt_suspend,
1874 .resume = mxt_resume,
1875#endif
1876};
1877#endif
1878
Jing Lin6cfc00e2011-11-02 15:15:30 -07001879static int mxt_debugfs_object_show(struct seq_file *m, void *v)
1880{
1881 struct mxt_data *data = m->private;
1882 struct mxt_object *object;
1883 struct device *dev = &data->client->dev;
1884 int i, j, k;
1885 int error;
1886 int obj_size;
1887 u8 val;
1888
1889 for (i = 0; i < data->info.object_num; i++) {
1890 object = data->object_table + i;
1891 obj_size = object->size + 1;
1892
1893 seq_printf(m, "Object[%d] (Type %d)\n", i + 1, object->type);
1894
1895 for (j = 0; j < object->instances + 1; j++) {
1896 seq_printf(m, "[Instance %d]\n", j);
1897
1898 for (k = 0; k < obj_size; k++) {
1899 error = mxt_read_object(data, object->type,
1900 j * obj_size + k, &val);
1901 if (error) {
1902 dev_err(dev,
1903 "Failed to read object %d "
1904 "instance %d at offset %d\n",
1905 object->type, j, k);
1906 return error;
1907 }
1908
1909 seq_printf(m, "Byte %d: 0x%02x (%d)\n",
1910 k, val, val);
1911 }
1912 }
1913 }
1914
1915 return 0;
1916}
1917
1918static int mxt_debugfs_object_open(struct inode *inode, struct file *file)
1919{
1920 return single_open(file, mxt_debugfs_object_show, inode->i_private);
1921}
1922
1923static const struct file_operations mxt_object_fops = {
1924 .owner = THIS_MODULE,
1925 .open = mxt_debugfs_object_open,
1926 .read = seq_read,
1927 .release = single_release,
1928};
1929
1930static void __init mxt_debugfs_init(struct mxt_data *data)
1931{
1932 debug_base = debugfs_create_dir(MXT_DEBUGFS_DIR, NULL);
1933 if (IS_ERR_OR_NULL(debug_base))
1934 pr_err("atmel_mxt_ts: Failed to create debugfs dir\n");
1935 if (IS_ERR_OR_NULL(debugfs_create_file(MXT_DEBUGFS_FILE,
1936 0444,
1937 debug_base,
1938 data,
1939 &mxt_object_fops))) {
1940 pr_err("atmel_mxt_ts: Failed to create object file\n");
1941 debugfs_remove_recursive(debug_base);
1942 }
1943}
1944
Iiro Valkonen7686b102011-02-02 23:21:58 -08001945static int __devinit mxt_probe(struct i2c_client *client,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001946 const struct i2c_device_id *id)
1947{
Iiro Valkonen919ed892011-02-15 13:36:52 -08001948 const struct mxt_platform_data *pdata = client->dev.platform_data;
Iiro Valkonen7686b102011-02-02 23:21:58 -08001949 struct mxt_data *data;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001950 struct input_dev *input_dev;
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08001951 int error, i;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001952
Iiro Valkonen919ed892011-02-15 13:36:52 -08001953 if (!pdata)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001954 return -EINVAL;
1955
Iiro Valkonen7686b102011-02-02 23:21:58 -08001956 data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001957 input_dev = input_allocate_device();
1958 if (!data || !input_dev) {
1959 dev_err(&client->dev, "Failed to allocate memory\n");
1960 error = -ENOMEM;
1961 goto err_free_mem;
1962 }
1963
Nick Dyer0a4016c2012-01-18 15:17:59 +05301964 data->state = INIT;
Amy Maloche83c385a2012-02-01 10:32:03 +05301965 input_dev->name = "atmel_mxt_ts";
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001966 input_dev->id.bustype = BUS_I2C;
1967 input_dev->dev.parent = &client->dev;
Iiro Valkonen7686b102011-02-02 23:21:58 -08001968 input_dev->open = mxt_input_open;
1969 input_dev->close = mxt_input_close;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001970
Joonyoung Shim910d8052011-04-12 23:14:38 -07001971 data->client = client;
1972 data->input_dev = input_dev;
1973 data->pdata = pdata;
1974 data->irq = client->irq;
1975
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001976 __set_bit(EV_ABS, input_dev->evbit);
1977 __set_bit(EV_KEY, input_dev->evbit);
1978 __set_bit(BTN_TOUCH, input_dev->keybit);
1979
1980 /* For single touch */
1981 input_set_abs_params(input_dev, ABS_X,
Jing Lin2f863172011-10-17 10:56:58 -07001982 0, data->pdata->x_size, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001983 input_set_abs_params(input_dev, ABS_Y,
Jing Lin2f863172011-10-17 10:56:58 -07001984 0, data->pdata->y_size, 0, 0);
Yufeng Shene6eb36a2011-10-11 12:28:21 -07001985 input_set_abs_params(input_dev, ABS_PRESSURE,
1986 0, 255, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001987
1988 /* For multi touch */
Joonyoung Shimcd473222012-02-14 18:32:48 -08001989 input_mt_init_slots(input_dev, MXT_MAX_FINGER);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001990 input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
Iiro Valkonen7686b102011-02-02 23:21:58 -08001991 0, MXT_MAX_AREA, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001992 input_set_abs_params(input_dev, ABS_MT_POSITION_X,
Jing Lin2f863172011-10-17 10:56:58 -07001993 0, data->pdata->x_size, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001994 input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
Jing Lin2f863172011-10-17 10:56:58 -07001995 0, data->pdata->y_size, 0, 0);
Yufeng Shene6eb36a2011-10-11 12:28:21 -07001996 input_set_abs_params(input_dev, ABS_MT_PRESSURE,
1997 0, 255, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001998
Amy Maloche83c385a2012-02-01 10:32:03 +05301999 if (pdata->touch_x_size)
2000 data->touch_x_size = pdata->touch_x_size;
2001 else
2002 data->touch_x_size = pdata->x_size;
2003
2004 if (pdata->touch_y_size)
2005 data->touch_y_size = pdata->touch_y_size;
2006 else
2007 data->touch_y_size = pdata->y_size;
2008
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08002009 /* set key array supported keys */
2010 if (pdata->key_codes) {
2011 for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) {
2012 if (pdata->key_codes[i])
2013 input_set_capability(input_dev, EV_KEY,
2014 pdata->key_codes[i]);
2015 }
2016 }
2017
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002018 input_set_drvdata(input_dev, data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002019 i2c_set_clientdata(client, data);
2020
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302021 if (pdata->init_hw)
2022 error = pdata->init_hw(true);
2023 else
2024 error = mxt_regulator_configure(data, true);
2025 if (error) {
2026 dev_err(&client->dev, "Failed to intialize hardware\n");
Jing Lin32c72532011-11-03 12:02:33 -07002027 goto err_free_mem;
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302028 }
2029
2030 if (pdata->power_on)
2031 error = pdata->power_on(true);
2032 else
2033 error = mxt_power_on(data, true);
2034 if (error) {
2035 dev_err(&client->dev, "Failed to power on hardware\n");
2036 goto err_regulator_on;
2037 }
2038
Amy Maloche08266db2011-11-04 11:07:16 -07002039 if (gpio_is_valid(pdata->irq_gpio)) {
2040 /* configure touchscreen irq gpio */
2041 error = gpio_request(pdata->irq_gpio,
2042 "mxt_irq_gpio");
2043 if (error) {
2044 pr_err("%s: unable to request gpio [%d]\n", __func__,
2045 pdata->irq_gpio);
2046 goto err_power_on;
2047 }
2048 error = gpio_direction_input(pdata->irq_gpio);
2049 if (error) {
2050 pr_err("%s: unable to set_direction for gpio [%d]\n",
2051 __func__, pdata->irq_gpio);
2052 goto err_irq_gpio_req;
2053 }
2054 }
2055
2056 if (gpio_is_valid(pdata->reset_gpio)) {
2057 /* configure touchscreen reset out gpio */
2058 error = gpio_request(pdata->reset_gpio,
2059 "mxt_reset_gpio");
2060 if (error) {
2061 pr_err("%s: unable to request reset gpio %d\n",
2062 __func__, pdata->reset_gpio);
2063 goto err_irq_gpio_req;
2064 }
2065
2066 error = gpio_direction_output(
2067 pdata->reset_gpio, 1);
2068 if (error) {
2069 pr_err("%s: unable to set direction for gpio %d\n",
2070 __func__, pdata->reset_gpio);
2071 goto err_reset_gpio_req;
2072 }
2073 }
2074
2075 mxt_reset_delay(data);
2076
Iiro Valkonen7686b102011-02-02 23:21:58 -08002077 error = mxt_initialize(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002078 if (error)
Amy Maloche08266db2011-11-04 11:07:16 -07002079 goto err_reset_gpio_req;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002080
Iiro Valkonen7686b102011-02-02 23:21:58 -08002081 error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
Iiro Valkonen919ed892011-02-15 13:36:52 -08002082 pdata->irqflags, client->dev.driver->name, data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002083 if (error) {
2084 dev_err(&client->dev, "Failed to register interrupt\n");
Jing Lin32c72532011-11-03 12:02:33 -07002085 goto err_free_object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002086 }
2087
Nick Dyer0a4016c2012-01-18 15:17:59 +05302088 if (data->state == APPMODE) {
2089 error = mxt_make_highchg(data);
2090 if (error) {
2091 dev_err(&client->dev, "Failed to make high CHG\n");
2092 goto err_free_irq;
2093 }
2094 }
Iiro Valkonen08960a02011-04-12 23:16:40 -07002095
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002096 error = input_register_device(input_dev);
2097 if (error)
2098 goto err_free_irq;
2099
Iiro Valkonen7686b102011-02-02 23:21:58 -08002100 error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002101 if (error)
2102 goto err_unregister_device;
2103
Anirudh Ghayal253ce122011-08-09 19:32:57 +05302104#if defined(CONFIG_HAS_EARLYSUSPEND)
2105 data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
2106 MXT_SUSPEND_LEVEL;
2107 data->early_suspend.suspend = mxt_early_suspend;
2108 data->early_suspend.resume = mxt_late_resume;
2109 register_early_suspend(&data->early_suspend);
2110#endif
2111
Jing Lin6cfc00e2011-11-02 15:15:30 -07002112 mxt_debugfs_init(data);
2113
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002114 return 0;
2115
2116err_unregister_device:
2117 input_unregister_device(input_dev);
2118 input_dev = NULL;
2119err_free_irq:
2120 free_irq(client->irq, data);
Jing Lin32c72532011-11-03 12:02:33 -07002121err_free_object:
2122 kfree(data->object_table);
Amy Maloche08266db2011-11-04 11:07:16 -07002123err_reset_gpio_req:
2124 if (gpio_is_valid(pdata->reset_gpio))
2125 gpio_free(pdata->reset_gpio);
2126err_irq_gpio_req:
2127 if (gpio_is_valid(pdata->irq_gpio))
2128 gpio_free(pdata->irq_gpio);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302129err_power_on:
2130 if (pdata->power_on)
2131 pdata->power_on(false);
2132 else
2133 mxt_power_on(data, false);
2134err_regulator_on:
2135 if (pdata->init_hw)
2136 pdata->init_hw(false);
2137 else
2138 mxt_regulator_configure(data, false);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002139err_free_mem:
2140 input_free_device(input_dev);
2141 kfree(data);
2142 return error;
2143}
2144
Iiro Valkonen7686b102011-02-02 23:21:58 -08002145static int __devexit mxt_remove(struct i2c_client *client)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002146{
Iiro Valkonen7686b102011-02-02 23:21:58 -08002147 struct mxt_data *data = i2c_get_clientdata(client);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002148
Iiro Valkonen7686b102011-02-02 23:21:58 -08002149 sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002150 free_irq(data->irq, data);
2151 input_unregister_device(data->input_dev);
Anirudh Ghayal253ce122011-08-09 19:32:57 +05302152#if defined(CONFIG_HAS_EARLYSUSPEND)
2153 unregister_early_suspend(&data->early_suspend);
2154#endif
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302155
2156 if (data->pdata->power_on)
2157 data->pdata->power_on(false);
2158 else
2159 mxt_power_on(data, false);
2160
2161 if (data->pdata->init_hw)
2162 data->pdata->init_hw(false);
2163 else
2164 mxt_regulator_configure(data, false);
2165
Mohan Pallakabfe8f302012-01-02 18:32:08 +08002166 if (gpio_is_valid(data->pdata->reset_gpio))
2167 gpio_free(data->pdata->reset_gpio);
2168
2169 if (gpio_is_valid(data->pdata->irq_gpio))
2170 gpio_free(data->pdata->irq_gpio);
2171
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002172 kfree(data->object_table);
2173 kfree(data);
2174
Jing Lin6cfc00e2011-11-02 15:15:30 -07002175 debugfs_remove_recursive(debug_base);
2176
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002177 return 0;
2178}
2179
Iiro Valkonen7686b102011-02-02 23:21:58 -08002180static const struct i2c_device_id mxt_id[] = {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002181 { "qt602240_ts", 0 },
Iiro Valkonen7686b102011-02-02 23:21:58 -08002182 { "atmel_mxt_ts", 0 },
Chris Leech46ee2a02011-02-15 13:36:52 -08002183 { "mXT224", 0 },
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002184 { }
2185};
Iiro Valkonen7686b102011-02-02 23:21:58 -08002186MODULE_DEVICE_TABLE(i2c, mxt_id);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002187
Iiro Valkonen7686b102011-02-02 23:21:58 -08002188static struct i2c_driver mxt_driver = {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002189 .driver = {
Iiro Valkonen7686b102011-02-02 23:21:58 -08002190 .name = "atmel_mxt_ts",
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002191 .owner = THIS_MODULE,
Dmitry Torokhov8b5fce02010-11-18 00:14:03 -08002192#ifdef CONFIG_PM
Iiro Valkonen7686b102011-02-02 23:21:58 -08002193 .pm = &mxt_pm_ops,
Dmitry Torokhov8b5fce02010-11-18 00:14:03 -08002194#endif
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002195 },
Iiro Valkonen7686b102011-02-02 23:21:58 -08002196 .probe = mxt_probe,
2197 .remove = __devexit_p(mxt_remove),
2198 .id_table = mxt_id,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002199};
2200
Iiro Valkonen7686b102011-02-02 23:21:58 -08002201static int __init mxt_init(void)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002202{
Iiro Valkonen7686b102011-02-02 23:21:58 -08002203 return i2c_add_driver(&mxt_driver);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002204}
2205
Iiro Valkonen7686b102011-02-02 23:21:58 -08002206static void __exit mxt_exit(void)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002207{
Iiro Valkonen7686b102011-02-02 23:21:58 -08002208 i2c_del_driver(&mxt_driver);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002209}
2210
Iiro Valkonen7686b102011-02-02 23:21:58 -08002211module_init(mxt_init);
2212module_exit(mxt_exit);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002213
2214/* Module information */
2215MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
Iiro Valkonen7686b102011-02-02 23:21:58 -08002216MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002217MODULE_LICENSE("GPL");