blob: 2058a5400144921d2fa5cc346b70607004605177 [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;
Anirudh Ghayal0bcb5b52012-02-17 14:58:25 -0800342 const char *fw_name;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700343};
344
Jing Lin6cfc00e2011-11-02 15:15:30 -0700345static struct dentry *debug_base;
346
Iiro Valkonen7686b102011-02-02 23:21:58 -0800347static bool mxt_object_readable(unsigned int type)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700348{
349 switch (type) {
Iiro Valkonene8645592011-11-18 12:56:19 -0800350 case MXT_GEN_MESSAGE_T5:
351 case MXT_GEN_COMMAND_T6:
352 case MXT_GEN_POWER_T7:
353 case MXT_GEN_ACQUIRE_T8:
354 case MXT_GEN_DATASOURCE_T53:
355 case MXT_TOUCH_MULTI_T9:
356 case MXT_TOUCH_KEYARRAY_T15:
357 case MXT_TOUCH_PROXIMITY_T23:
358 case MXT_TOUCH_PROXKEY_T52:
359 case MXT_PROCI_GRIPFACE_T20:
360 case MXT_PROCG_NOISE_T22:
361 case MXT_PROCI_ONETOUCH_T24:
362 case MXT_PROCI_TWOTOUCH_T27:
363 case MXT_PROCI_GRIP_T40:
364 case MXT_PROCI_PALM_T41:
365 case MXT_PROCI_TOUCHSUPPRESSION_T42:
366 case MXT_PROCI_STYLUS_T47:
Jing Linc7fc4052011-12-21 16:16:19 -0800367 case MXT_PROCI_SHIELDLESS_T56:
Iiro Valkonene8645592011-11-18 12:56:19 -0800368 case MXT_PROCG_NOISESUPPRESSION_T48:
369 case MXT_SPT_COMMSCONFIG_T18:
370 case MXT_SPT_GPIOPWM_T19:
371 case MXT_SPT_SELFTEST_T25:
372 case MXT_SPT_CTECONFIG_T28:
373 case MXT_SPT_USERDATA_T38:
374 case MXT_SPT_DIGITIZER_T43:
375 case MXT_SPT_CTECONFIG_T46:
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700376 return true;
377 default:
378 return false;
379 }
380}
381
Iiro Valkonen7686b102011-02-02 23:21:58 -0800382static bool mxt_object_writable(unsigned int type)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700383{
384 switch (type) {
Iiro Valkonene8645592011-11-18 12:56:19 -0800385 case MXT_GEN_COMMAND_T6:
386 case MXT_GEN_POWER_T7:
387 case MXT_GEN_ACQUIRE_T8:
388 case MXT_TOUCH_MULTI_T9:
389 case MXT_TOUCH_KEYARRAY_T15:
390 case MXT_TOUCH_PROXIMITY_T23:
391 case MXT_TOUCH_PROXKEY_T52:
392 case MXT_PROCI_GRIPFACE_T20:
393 case MXT_PROCG_NOISE_T22:
394 case MXT_PROCI_ONETOUCH_T24:
395 case MXT_PROCI_TWOTOUCH_T27:
396 case MXT_PROCI_GRIP_T40:
397 case MXT_PROCI_PALM_T41:
398 case MXT_PROCI_TOUCHSUPPRESSION_T42:
399 case MXT_PROCI_STYLUS_T47:
Jing Linc7fc4052011-12-21 16:16:19 -0800400 case MXT_PROCI_SHIELDLESS_T56:
Iiro Valkonene8645592011-11-18 12:56:19 -0800401 case MXT_PROCG_NOISESUPPRESSION_T48:
402 case MXT_SPT_COMMSCONFIG_T18:
403 case MXT_SPT_GPIOPWM_T19:
404 case MXT_SPT_SELFTEST_T25:
405 case MXT_SPT_CTECONFIG_T28:
406 case MXT_SPT_USERDATA_T38:
407 case MXT_SPT_DIGITIZER_T43:
408 case MXT_SPT_CTECONFIG_T46:
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700409 return true;
410 default:
411 return false;
412 }
413}
414
Iiro Valkonen7686b102011-02-02 23:21:58 -0800415static void mxt_dump_message(struct device *dev,
416 struct mxt_message *message)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700417{
418 dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
419 dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
420 dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
421 dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
422 dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
423 dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
424 dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
425 dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
426 dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
427}
428
Nick Dyer0a4016c2012-01-18 15:17:59 +0530429static int mxt_switch_to_bootloader_address(struct mxt_data *data)
430{
431 int i;
432 struct i2c_client *client = data->client;
433
434 if (data->state == BOOTLOADER) {
435 dev_err(&client->dev, "Already in BOOTLOADER state\n");
436 return -EINVAL;
437 }
438
439 for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
440 if (mxt_slave_addresses[i].application == client->addr) {
441 dev_info(&client->dev, "Changing to bootloader address: "
442 "%02x -> %02x",
443 client->addr,
444 mxt_slave_addresses[i].bootloader);
445
446 client->addr = mxt_slave_addresses[i].bootloader;
447 data->state = BOOTLOADER;
448 return 0;
449 }
450 }
451
452 dev_err(&client->dev, "Address 0x%02x not found in address table",
453 client->addr);
454 return -EINVAL;
455}
456
457static int mxt_switch_to_appmode_address(struct mxt_data *data)
458{
459 int i;
460 struct i2c_client *client = data->client;
461
462 if (data->state == APPMODE) {
463 dev_err(&client->dev, "Already in APPMODE state\n");
464 return -EINVAL;
465 }
466
467 for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
468 if (mxt_slave_addresses[i].bootloader == client->addr) {
469 dev_info(&client->dev,
470 "Changing to application mode address: "
471 "0x%02x -> 0x%02x",
472 client->addr,
473 mxt_slave_addresses[i].application);
474
475 client->addr = mxt_slave_addresses[i].application;
476 data->state = APPMODE;
477 return 0;
478 }
479 }
480
481 dev_err(&client->dev, "Address 0x%02x not found in address table",
482 client->addr);
483 return -EINVAL;
484}
485
486static int mxt_get_bootloader_version(struct i2c_client *client, u8 val)
487{
488 u8 buf[3];
489
490 if (val | MXT_BOOT_EXTENDED_ID) {
491 dev_dbg(&client->dev,
492 "Retrieving extended mode ID information");
493
494 if (i2c_master_recv(client, &buf[0], 3) != 3) {
495 dev_err(&client->dev, "%s: i2c recv failed\n",
496 __func__);
497 return -EIO;
498 }
499
500 dev_info(&client->dev, "Bootloader ID:%d Version:%d",
501 buf[1], buf[2]);
502
503 return buf[0];
504 } else {
505 dev_info(&client->dev, "Bootloader ID:%d",
506 val & MXT_BOOT_ID_MASK);
507
508 return val;
509 }
510}
511
Iiro Valkonen7686b102011-02-02 23:21:58 -0800512static int mxt_check_bootloader(struct i2c_client *client,
Nick Dyer0a4016c2012-01-18 15:17:59 +0530513 unsigned int state)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700514{
515 u8 val;
516
517recheck:
518 if (i2c_master_recv(client, &val, 1) != 1) {
519 dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
520 return -EIO;
521 }
522
523 switch (state) {
Iiro Valkonen7686b102011-02-02 23:21:58 -0800524 case MXT_WAITING_BOOTLOAD_CMD:
Nick Dyer0a4016c2012-01-18 15:17:59 +0530525 val = mxt_get_bootloader_version(client, val);
526 val &= ~MXT_BOOT_STATUS_MASK;
527 break;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800528 case MXT_WAITING_FRAME_DATA:
Nick Dyer0a4016c2012-01-18 15:17:59 +0530529 case MXT_APP_CRC_FAIL:
Iiro Valkonen7686b102011-02-02 23:21:58 -0800530 val &= ~MXT_BOOT_STATUS_MASK;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700531 break;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800532 case MXT_FRAME_CRC_PASS:
533 if (val == MXT_FRAME_CRC_CHECK)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700534 goto recheck;
Nick Dyer0a4016c2012-01-18 15:17:59 +0530535 if (val == MXT_FRAME_CRC_FAIL) {
536 dev_err(&client->dev, "Bootloader CRC fail\n");
537 return -EINVAL;
538 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700539 break;
540 default:
541 return -EINVAL;
542 }
543
544 if (val != state) {
Nick Dyer0a4016c2012-01-18 15:17:59 +0530545 dev_err(&client->dev, "Invalid bootloader mode state %X\n",
546 val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700547 return -EINVAL;
548 }
549
550 return 0;
551}
552
Iiro Valkonen7686b102011-02-02 23:21:58 -0800553static int mxt_unlock_bootloader(struct i2c_client *client)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700554{
555 u8 buf[2];
556
Iiro Valkonen7686b102011-02-02 23:21:58 -0800557 buf[0] = MXT_UNLOCK_CMD_LSB;
558 buf[1] = MXT_UNLOCK_CMD_MSB;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700559
560 if (i2c_master_send(client, buf, 2) != 2) {
561 dev_err(&client->dev, "%s: i2c send failed\n", __func__);
562 return -EIO;
563 }
564
565 return 0;
566}
567
Iiro Valkonen7686b102011-02-02 23:21:58 -0800568static int mxt_fw_write(struct i2c_client *client,
Nick Dyer0a4016c2012-01-18 15:17:59 +0530569 const u8 *data, unsigned int frame_size)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700570{
571 if (i2c_master_send(client, data, frame_size) != frame_size) {
572 dev_err(&client->dev, "%s: i2c send failed\n", __func__);
573 return -EIO;
574 }
575
576 return 0;
577}
578
Iiro Valkonen7686b102011-02-02 23:21:58 -0800579static int __mxt_read_reg(struct i2c_client *client,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700580 u16 reg, u16 len, void *val)
581{
582 struct i2c_msg xfer[2];
583 u8 buf[2];
Jing Lin36aee812011-10-17 17:17:28 -0700584 int i = 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700585
586 buf[0] = reg & 0xff;
587 buf[1] = (reg >> 8) & 0xff;
588
589 /* Write register */
590 xfer[0].addr = client->addr;
591 xfer[0].flags = 0;
592 xfer[0].len = 2;
593 xfer[0].buf = buf;
594
595 /* Read data */
596 xfer[1].addr = client->addr;
597 xfer[1].flags = I2C_M_RD;
598 xfer[1].len = len;
599 xfer[1].buf = val;
600
Jing Lin36aee812011-10-17 17:17:28 -0700601 do {
602 if (i2c_transfer(client->adapter, xfer, 2) == 2)
603 return 0;
604 msleep(MXT_WAKE_TIME);
605 } while (++i < MXT_MAX_RW_TRIES);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700606
Jing Lin36aee812011-10-17 17:17:28 -0700607 dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
608 return -EIO;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700609}
610
Iiro Valkonen7686b102011-02-02 23:21:58 -0800611static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700612{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800613 return __mxt_read_reg(client, reg, 1, val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700614}
615
Jing Lin36aee812011-10-17 17:17:28 -0700616static int __mxt_write_reg(struct i2c_client *client,
617 u16 addr, u16 length, u8 *value)
618{
619 u8 buf[MXT_BLOCK_SIZE + 2];
620 int i, tries = 0;
621
622 if (length > MXT_BLOCK_SIZE)
623 return -EINVAL;
624
625 buf[0] = addr & 0xff;
626 buf[1] = (addr >> 8) & 0xff;
627 for (i = 0; i < length; i++)
628 buf[i + 2] = *value++;
629
630 do {
631 if (i2c_master_send(client, buf, length + 2) == (length + 2))
632 return 0;
633 msleep(MXT_WAKE_TIME);
634 } while (++tries < MXT_MAX_RW_TRIES);
635
636 dev_err(&client->dev, "%s: i2c send failed\n", __func__);
637 return -EIO;
638}
639
Iiro Valkonen7686b102011-02-02 23:21:58 -0800640static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700641{
Jing Lin36aee812011-10-17 17:17:28 -0700642 return __mxt_write_reg(client, reg, 1, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700643}
644
Iiro Valkonen7686b102011-02-02 23:21:58 -0800645static int mxt_read_object_table(struct i2c_client *client,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700646 u16 reg, u8 *object_buf)
647{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800648 return __mxt_read_reg(client, reg, MXT_OBJECT_SIZE,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700649 object_buf);
650}
651
Iiro Valkonen7686b102011-02-02 23:21:58 -0800652static struct mxt_object *
653mxt_get_object(struct mxt_data *data, u8 type)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700654{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800655 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700656 int i;
657
658 for (i = 0; i < data->info.object_num; i++) {
659 object = data->object_table + i;
660 if (object->type == type)
661 return object;
662 }
663
664 dev_err(&data->client->dev, "Invalid object type\n");
665 return NULL;
666}
667
Iiro Valkonen7686b102011-02-02 23:21:58 -0800668static int mxt_read_message(struct mxt_data *data,
669 struct mxt_message *message)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700670{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800671 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700672 u16 reg;
673
Iiro Valkonene8645592011-11-18 12:56:19 -0800674 object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700675 if (!object)
676 return -EINVAL;
677
678 reg = object->start_address;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800679 return __mxt_read_reg(data->client, reg,
680 sizeof(struct mxt_message), message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700681}
682
Iiro Valkonen7686b102011-02-02 23:21:58 -0800683static int mxt_read_object(struct mxt_data *data,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700684 u8 type, u8 offset, u8 *val)
685{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800686 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700687 u16 reg;
688
Iiro Valkonen7686b102011-02-02 23:21:58 -0800689 object = mxt_get_object(data, type);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700690 if (!object)
691 return -EINVAL;
692
693 reg = object->start_address;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800694 return __mxt_read_reg(data->client, reg + offset, 1, val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700695}
696
Iiro Valkonen7686b102011-02-02 23:21:58 -0800697static int mxt_write_object(struct mxt_data *data,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700698 u8 type, u8 offset, u8 val)
699{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800700 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700701 u16 reg;
702
Iiro Valkonen7686b102011-02-02 23:21:58 -0800703 object = mxt_get_object(data, type);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700704 if (!object)
705 return -EINVAL;
706
707 reg = object->start_address;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800708 return mxt_write_reg(data->client, reg + offset, val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700709}
710
Iiro Valkonen7686b102011-02-02 23:21:58 -0800711static void mxt_input_report(struct mxt_data *data, int single_id)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700712{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800713 struct mxt_finger *finger = data->finger;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700714 struct input_dev *input_dev = data->input_dev;
715 int status = finger[single_id].status;
716 int finger_num = 0;
717 int id;
718
Iiro Valkonen7686b102011-02-02 23:21:58 -0800719 for (id = 0; id < MXT_MAX_FINGER; id++) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700720 if (!finger[id].status)
721 continue;
722
Joonyoung Shimcd473222012-02-14 18:32:48 -0800723 input_mt_slot(input_dev, id);
724 input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
725 finger[id].status != MXT_RELEASE);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700726
Joonyoung Shimcd473222012-02-14 18:32:48 -0800727 if (finger[id].status != MXT_RELEASE) {
Amy Maloche2b59bab2011-10-13 16:08:16 -0700728 finger_num++;
Joonyoung Shimcd473222012-02-14 18:32:48 -0800729 input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
730 finger[id].area);
731 input_report_abs(input_dev, ABS_MT_POSITION_X,
732 finger[id].x);
733 input_report_abs(input_dev, ABS_MT_POSITION_Y,
734 finger[id].y);
735 input_report_abs(input_dev, ABS_MT_PRESSURE,
736 finger[id].area);
737 } else {
738 finger[id].status = 0;
739 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700740 }
741
742 input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
743
Iiro Valkonen7686b102011-02-02 23:21:58 -0800744 if (status != MXT_RELEASE) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700745 input_report_abs(input_dev, ABS_X, finger[single_id].x);
746 input_report_abs(input_dev, ABS_Y, finger[single_id].y);
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700747 input_report_abs(input_dev,
748 ABS_PRESSURE, finger[single_id].pressure);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700749 }
750
751 input_sync(input_dev);
752}
753
Iiro Valkonen7686b102011-02-02 23:21:58 -0800754static void mxt_input_touchevent(struct mxt_data *data,
755 struct mxt_message *message, int id)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700756{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800757 struct mxt_finger *finger = data->finger;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700758 struct device *dev = &data->client->dev;
759 u8 status = message->message[0];
760 int x;
761 int y;
762 int area;
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700763 int pressure;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700764
765 /* Check the touch is present on the screen */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800766 if (!(status & MXT_DETECT)) {
767 if (status & MXT_RELEASE) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700768 dev_dbg(dev, "[%d] released\n", id);
769
Iiro Valkonen7686b102011-02-02 23:21:58 -0800770 finger[id].status = MXT_RELEASE;
771 mxt_input_report(data, id);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700772 }
773 return;
774 }
775
776 /* Check only AMP detection */
Iiro Valkonen7686b102011-02-02 23:21:58 -0800777 if (!(status & (MXT_PRESS | MXT_MOVE)))
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700778 return;
779
Joonyoung Shim910d8052011-04-12 23:14:38 -0700780 x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
781 y = (message->message[2] << 4) | ((message->message[3] & 0xf));
Amy Maloche83c385a2012-02-01 10:32:03 +0530782 if (data->touch_x_size < 1024)
Joonyoung Shim910d8052011-04-12 23:14:38 -0700783 x = x >> 2;
Amy Maloche83c385a2012-02-01 10:32:03 +0530784 if (data->touch_y_size < 1024)
Joonyoung Shim910d8052011-04-12 23:14:38 -0700785 y = y >> 2;
786
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700787 area = message->message[4];
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700788 pressure = message->message[5];
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700789
790 dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
Iiro Valkonen7686b102011-02-02 23:21:58 -0800791 status & MXT_MOVE ? "moved" : "pressed",
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700792 x, y, area);
793
Iiro Valkonen7686b102011-02-02 23:21:58 -0800794 finger[id].status = status & MXT_MOVE ?
795 MXT_MOVE : MXT_PRESS;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700796 finger[id].x = x;
797 finger[id].y = y;
798 finger[id].area = area;
Yufeng Shene6eb36a2011-10-11 12:28:21 -0700799 finger[id].pressure = pressure;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700800
Iiro Valkonen7686b102011-02-02 23:21:58 -0800801 mxt_input_report(data, id);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700802}
803
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800804static void mxt_handle_key_array(struct mxt_data *data,
805 struct mxt_message *message)
806{
807 u32 keys_changed;
808 int i;
809
810 if (!data->pdata->key_codes) {
811 dev_err(&data->client->dev, "keyarray is not supported\n");
812 return;
813 }
814
815 data->keyarray_new = message->message[1] |
816 (message->message[2] << 8) |
817 (message->message[3] << 16) |
818 (message->message[4] << 24);
819
820 keys_changed = data->keyarray_old ^ data->keyarray_new;
821
822 if (!keys_changed) {
823 dev_dbg(&data->client->dev, "no keys changed\n");
824 return;
825 }
826
827 for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) {
828 if (!(keys_changed & (1 << i)))
829 continue;
830
831 input_report_key(data->input_dev, data->pdata->key_codes[i],
832 (data->keyarray_new & (1 << i)));
833 input_sync(data->input_dev);
834 }
835
836 data->keyarray_old = data->keyarray_new;
837}
838
Iiro Valkonen7686b102011-02-02 23:21:58 -0800839static irqreturn_t mxt_interrupt(int irq, void *dev_id)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700840{
Iiro Valkonen7686b102011-02-02 23:21:58 -0800841 struct mxt_data *data = dev_id;
842 struct mxt_message message;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700843 struct device *dev = &data->client->dev;
844 int id;
845 u8 reportid;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700846
Nick Dyer0a4016c2012-01-18 15:17:59 +0530847 if (data->state != APPMODE) {
848 dev_err(dev, "Ignoring IRQ - not in APPMODE state\n");
849 return IRQ_HANDLED;
850 }
851
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700852 do {
Iiro Valkonen7686b102011-02-02 23:21:58 -0800853 if (mxt_read_message(data, &message)) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700854 dev_err(dev, "Failed to read message\n");
855 goto end;
856 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700857 reportid = message.reportid;
858
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800859 if (!reportid) {
860 dev_dbg(dev, "Report id 0 is reserved\n");
861 continue;
862 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700863
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800864 /* check whether report id is part of T9 or T15 */
865 id = reportid - data->t9_min_reportid;
866
867 if (reportid >= data->t9_min_reportid &&
868 reportid <= data->t9_max_reportid)
Iiro Valkonen7686b102011-02-02 23:21:58 -0800869 mxt_input_touchevent(data, &message, id);
Mohan Pallaka382d3ce2012-01-02 20:24:28 +0800870 else if (reportid >= data->t15_min_reportid &&
871 reportid <= data->t15_max_reportid)
872 mxt_handle_key_array(data, &message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700873 else
Iiro Valkonen7686b102011-02-02 23:21:58 -0800874 mxt_dump_message(dev, &message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700875 } while (reportid != 0xff);
876
877end:
878 return IRQ_HANDLED;
879}
880
Iiro Valkonen7686b102011-02-02 23:21:58 -0800881static int mxt_check_reg_init(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700882{
Jing Lindc4413c2012-01-16 15:22:52 -0800883 const struct mxt_config_info *config_info = data->config_info;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800884 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700885 struct device *dev = &data->client->dev;
886 int index = 0;
Iiro Valkonen71749f52011-02-15 13:36:52 -0800887 int i, j, config_offset;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700888
Jing Lindc4413c2012-01-16 15:22:52 -0800889 if (!config_info) {
Iiro Valkonen71749f52011-02-15 13:36:52 -0800890 dev_dbg(dev, "No cfg data defined, skipping reg init\n");
891 return 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700892 }
893
894 for (i = 0; i < data->info.object_num; i++) {
895 object = data->object_table + i;
896
Iiro Valkonen7686b102011-02-02 23:21:58 -0800897 if (!mxt_object_writable(object->type))
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700898 continue;
899
Iiro Valkonen71749f52011-02-15 13:36:52 -0800900 for (j = 0; j < object->size + 1; j++) {
901 config_offset = index + j;
Jing Lindc4413c2012-01-16 15:22:52 -0800902 if (config_offset > config_info->config_length) {
Iiro Valkonen71749f52011-02-15 13:36:52 -0800903 dev_err(dev, "Not enough config data!\n");
904 return -EINVAL;
905 }
Iiro Valkonen7686b102011-02-02 23:21:58 -0800906 mxt_write_object(data, object->type, j,
Jing Lindc4413c2012-01-16 15:22:52 -0800907 config_info->config[config_offset]);
Iiro Valkonen71749f52011-02-15 13:36:52 -0800908 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700909 index += object->size + 1;
910 }
911
912 return 0;
913}
914
Iiro Valkonen7686b102011-02-02 23:21:58 -0800915static int mxt_make_highchg(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700916{
917 struct device *dev = &data->client->dev;
Iiro Valkonen26cdb1a2011-02-04 00:51:05 -0800918 struct mxt_message message;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700919 int count = 10;
920 int error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700921
922 /* Read dummy message to make high CHG pin */
923 do {
Iiro Valkonen26cdb1a2011-02-04 00:51:05 -0800924 error = mxt_read_message(data, &message);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700925 if (error)
926 return error;
Iiro Valkonen26cdb1a2011-02-04 00:51:05 -0800927 } while (message.reportid != 0xff && --count);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700928
929 if (!count) {
930 dev_err(dev, "CHG pin isn't cleared\n");
931 return -EBUSY;
932 }
933
934 return 0;
935}
936
Iiro Valkonen7686b102011-02-02 23:21:58 -0800937static int mxt_get_info(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700938{
939 struct i2c_client *client = data->client;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800940 struct mxt_info *info = &data->info;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700941 int error;
942 u8 val;
943
Iiro Valkonen7686b102011-02-02 23:21:58 -0800944 error = mxt_read_reg(client, MXT_FAMILY_ID, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700945 if (error)
946 return error;
947 info->family_id = val;
948
Iiro Valkonen7686b102011-02-02 23:21:58 -0800949 error = mxt_read_reg(client, MXT_VARIANT_ID, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700950 if (error)
951 return error;
952 info->variant_id = val;
953
Iiro Valkonen7686b102011-02-02 23:21:58 -0800954 error = mxt_read_reg(client, MXT_VERSION, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700955 if (error)
956 return error;
957 info->version = val;
958
Iiro Valkonen7686b102011-02-02 23:21:58 -0800959 error = mxt_read_reg(client, MXT_BUILD, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700960 if (error)
961 return error;
962 info->build = val;
963
Iiro Valkonen7686b102011-02-02 23:21:58 -0800964 error = mxt_read_reg(client, MXT_OBJECT_NUM, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700965 if (error)
966 return error;
967 info->object_num = val;
968
969 return 0;
970}
971
Iiro Valkonen7686b102011-02-02 23:21:58 -0800972static int mxt_get_object_table(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700973{
974 int error;
975 int i;
976 u16 reg;
977 u8 reportid = 0;
Iiro Valkonen7686b102011-02-02 23:21:58 -0800978 u8 buf[MXT_OBJECT_SIZE];
Jing Lindc4413c2012-01-16 15:22:52 -0800979 bool found_t38 = false;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700980
981 for (i = 0; i < data->info.object_num; i++) {
Iiro Valkonen7686b102011-02-02 23:21:58 -0800982 struct mxt_object *object = data->object_table + i;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700983
Iiro Valkonen7686b102011-02-02 23:21:58 -0800984 reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i;
985 error = mxt_read_object_table(data->client, reg, buf);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -0700986 if (error)
987 return error;
988
989 object->type = buf[0];
990 object->start_address = (buf[2] << 8) | buf[1];
991 object->size = buf[3];
992 object->instances = buf[4];
993 object->num_report_ids = buf[5];
994
995 if (object->num_report_ids) {
996 reportid += object->num_report_ids *
997 (object->instances + 1);
998 object->max_reportid = reportid;
999 }
Jing Lindc4413c2012-01-16 15:22:52 -08001000
1001 /* Calculate index for config major version in config array.
1002 * Major version is the first byte in object T38.
1003 */
1004 if (object->type == MXT_SPT_USERDATA_T38)
1005 found_t38 = true;
1006 if (!found_t38 && mxt_object_writable(object->type))
1007 data->cfg_version_idx += object->size + 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001008 }
1009
1010 return 0;
1011}
1012
Jing Lindc4413c2012-01-16 15:22:52 -08001013static int mxt_search_config_array(struct mxt_data *data, bool version_match)
1014{
1015
1016 const struct mxt_platform_data *pdata = data->pdata;
1017 const struct mxt_config_info *cfg_info;
1018 struct mxt_info *info = &data->info;
1019 int i;
1020 u8 cfg_version;
1021
1022 for (i = 0; i < pdata->config_array_size; i++) {
1023
1024 cfg_info = &pdata->config_array[i];
1025
1026 if (!cfg_info->config || !cfg_info->config_length)
1027 continue;
1028
1029 if (info->family_id == cfg_info->family_id &&
1030 info->variant_id == cfg_info->variant_id &&
1031 info->version == cfg_info->version &&
1032 info->build == cfg_info->build) {
1033
1034 cfg_version = cfg_info->config[data->cfg_version_idx];
1035 if (data->curr_cfg_version == cfg_version ||
1036 !version_match) {
1037 data->config_info = cfg_info;
Anirudh Ghayal0bcb5b52012-02-17 14:58:25 -08001038 data->fw_name = pdata->config_array[i].fw_name;
Jing Lindc4413c2012-01-16 15:22:52 -08001039 return 0;
1040 }
1041 }
1042 }
1043
Anirudh Ghayal0bcb5b52012-02-17 14:58:25 -08001044 data->fw_name = NULL;
Jing Lindc4413c2012-01-16 15:22:52 -08001045 dev_info(&data->client->dev,
1046 "Config not found: F: %d, V: %d, FW: %d.%d.%d, CFG: %d\n",
1047 info->family_id, info->variant_id,
1048 info->version >> 4, info->version & 0xF, info->build,
1049 data->curr_cfg_version);
1050 return -EINVAL;
1051}
1052
1053static int mxt_get_config(struct mxt_data *data)
1054{
1055 const struct mxt_platform_data *pdata = data->pdata;
1056 struct device *dev = &data->client->dev;
1057 struct mxt_object *object;
1058 int error;
1059
1060 if (!pdata->config_array || !pdata->config_array_size) {
1061 dev_dbg(dev, "No cfg data provided by platform data\n");
1062 return 0;
1063 }
1064
1065 /* Get current config version */
1066 object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
1067 if (!object) {
1068 dev_err(dev, "Unable to obtain USERDATA object\n");
1069 return -EINVAL;
1070 }
1071
1072 error = mxt_read_reg(data->client, object->start_address,
1073 &data->curr_cfg_version);
1074 if (error) {
1075 dev_err(dev, "Unable to read config version\n");
1076 return error;
1077 }
1078
1079 /* It is possible that the config data on the controller is not
1080 * versioned and the version number returns 0. In this case,
1081 * find a match without the config version checking.
1082 */
1083 error = mxt_search_config_array(data,
1084 data->curr_cfg_version != 0 ? true : false);
1085 if (error)
1086 return error;
1087
1088 return 0;
1089}
Amy Maloche7e447432011-09-14 11:36:30 -07001090static void mxt_reset_delay(struct mxt_data *data)
1091{
1092 struct mxt_info *info = &data->info;
1093
1094 switch (info->family_id) {
1095 case MXT224_ID:
1096 msleep(MXT224_RESET_TIME);
1097 break;
Amy Maloche380cc0b2011-11-03 12:55:04 -07001098 case MXT224E_ID:
1099 msleep(MXT224E_RESET_TIME);
1100 break;
Amy Maloche7e447432011-09-14 11:36:30 -07001101 case MXT1386_ID:
1102 msleep(MXT1386_RESET_TIME);
1103 break;
1104 default:
1105 msleep(MXT_RESET_TIME);
1106 }
1107}
1108
Iiro Valkonen7686b102011-02-02 23:21:58 -08001109static int mxt_initialize(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001110{
1111 struct i2c_client *client = data->client;
Iiro Valkonen7686b102011-02-02 23:21:58 -08001112 struct mxt_info *info = &data->info;
Jing Lin36aee812011-10-17 17:17:28 -07001113 int error;
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001114 int timeout_counter = 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001115 u8 val;
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001116 u8 command_register;
Jing Lin36aee812011-10-17 17:17:28 -07001117 struct mxt_object *t7_object;
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08001118 struct mxt_object *t9_object;
1119 struct mxt_object *t15_object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001120
Iiro Valkonen7686b102011-02-02 23:21:58 -08001121 error = mxt_get_info(data);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301122 if (error) {
1123 /* Try bootloader mode */
1124 error = mxt_switch_to_bootloader_address(data);
1125 if (error)
1126 return error;
1127
1128 error = mxt_check_bootloader(client, MXT_APP_CRC_FAIL);
1129 if (error)
1130 return error;
1131
1132 dev_err(&client->dev, "Application CRC failure\n");
1133 data->state = BOOTLOADER;
1134
1135 return 0;
1136 }
1137
1138 dev_info(&client->dev,
1139 "Family ID: %d Variant ID: %d Version: %d.%d "
1140 "Build: 0x%02X Object Num: %d\n",
1141 info->family_id, info->variant_id,
1142 info->version >> 4, info->version & 0xf,
1143 info->build, info->object_num);
1144
1145 data->state = APPMODE;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001146
1147 data->object_table = kcalloc(info->object_num,
Iiro Valkonen7686b102011-02-02 23:21:58 -08001148 sizeof(struct mxt_object),
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001149 GFP_KERNEL);
1150 if (!data->object_table) {
1151 dev_err(&client->dev, "Failed to allocate memory\n");
1152 return -ENOMEM;
1153 }
1154
1155 /* Get object table information */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001156 error = mxt_get_object_table(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001157 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001158 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001159
Jing Lindc4413c2012-01-16 15:22:52 -08001160 /* Get config data from platform data */
1161 error = mxt_get_config(data);
1162 if (error)
1163 dev_dbg(&client->dev, "Config info not found.\n");
1164
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001165 /* Check register init values */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001166 error = mxt_check_reg_init(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001167 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001168 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001169
Amy Maloche52262212011-09-15 16:46:57 -07001170 /* Store T7 and T9 locally, used in suspend/resume operations */
Iiro Valkonene8645592011-11-18 12:56:19 -08001171 t7_object = mxt_get_object(data, MXT_GEN_POWER_T7);
Jing Lin36aee812011-10-17 17:17:28 -07001172 if (!t7_object) {
1173 dev_err(&client->dev, "Failed to get T7 object\n");
Jing Lin32c72532011-11-03 12:02:33 -07001174 error = -EINVAL;
1175 goto free_object_table;
Jing Lin36aee812011-10-17 17:17:28 -07001176 }
1177
1178 data->t7_start_addr = t7_object->start_address;
1179 error = __mxt_read_reg(client, data->t7_start_addr,
1180 T7_DATA_SIZE, data->t7_data);
1181 if (error < 0) {
1182 dev_err(&client->dev,
Jing Lin32c72532011-11-03 12:02:33 -07001183 "Failed to save current power state\n");
1184 goto free_object_table;
Amy Maloche52262212011-09-15 16:46:57 -07001185 }
Iiro Valkonene8645592011-11-18 12:56:19 -08001186 error = mxt_read_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL,
Amy Maloche52262212011-09-15 16:46:57 -07001187 &data->t9_ctrl);
1188 if (error < 0) {
Jing Lin32c72532011-11-03 12:02:33 -07001189 dev_err(&client->dev, "Failed to save current touch object\n");
1190 goto free_object_table;
Amy Maloche52262212011-09-15 16:46:57 -07001191 }
1192
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08001193 /* Store T9, T15's min and max report ids */
1194 t9_object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
1195 if (!t9_object) {
1196 dev_err(&client->dev, "Failed to get T9 object\n");
1197 error = -EINVAL;
1198 goto free_object_table;
1199 }
1200 data->t9_max_reportid = t9_object->max_reportid;
1201 data->t9_min_reportid = t9_object->max_reportid -
1202 t9_object->num_report_ids + 1;
1203
1204 if (data->pdata->key_codes) {
1205 t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15);
1206 if (!t15_object)
1207 dev_dbg(&client->dev, "T15 object is not available\n");
1208 else {
1209 data->t15_max_reportid = t15_object->max_reportid;
1210 data->t15_min_reportid = t15_object->max_reportid -
1211 t15_object->num_report_ids + 1;
1212 }
1213 }
1214
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001215 /* Backup to memory */
Iiro Valkonene8645592011-11-18 12:56:19 -08001216 mxt_write_object(data, MXT_GEN_COMMAND_T6,
Iiro Valkonen7686b102011-02-02 23:21:58 -08001217 MXT_COMMAND_BACKUPNV,
1218 MXT_BACKUP_VALUE);
1219 msleep(MXT_BACKUP_TIME);
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001220 do {
Iiro Valkonene8645592011-11-18 12:56:19 -08001221 error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001222 MXT_COMMAND_BACKUPNV,
1223 &command_register);
1224 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001225 goto free_object_table;
Amy Maloche7e447432011-09-14 11:36:30 -07001226 usleep_range(1000, 2000);
1227 } while ((command_register != 0) && (++timeout_counter <= 100));
1228 if (timeout_counter > 100) {
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001229 dev_err(&client->dev, "No response after backup!\n");
Jing Lin32c72532011-11-03 12:02:33 -07001230 error = -EIO;
1231 goto free_object_table;
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001232 }
1233
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001234
1235 /* Soft reset */
Iiro Valkonene8645592011-11-18 12:56:19 -08001236 mxt_write_object(data, MXT_GEN_COMMAND_T6,
Iiro Valkonen7686b102011-02-02 23:21:58 -08001237 MXT_COMMAND_RESET, 1);
Iiro Valkonen4ac053c2011-09-08 11:10:52 -07001238
Amy Maloche7e447432011-09-14 11:36:30 -07001239 mxt_reset_delay(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001240
1241 /* Update matrix size at info struct */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001242 error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001243 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001244 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001245 info->matrix_xsize = val;
1246
Iiro Valkonen7686b102011-02-02 23:21:58 -08001247 error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001248 if (error)
Jing Lin32c72532011-11-03 12:02:33 -07001249 goto free_object_table;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001250 info->matrix_ysize = val;
1251
1252 dev_info(&client->dev,
Nick Dyer0a4016c2012-01-18 15:17:59 +05301253 "Matrix X Size: %d Matrix Y Size: %d\n",
1254 info->matrix_xsize, info->matrix_ysize);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001255
1256 return 0;
Jing Lin32c72532011-11-03 12:02:33 -07001257
1258free_object_table:
1259 kfree(data->object_table);
1260 return error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001261}
1262
Iiro Valkonen7686b102011-02-02 23:21:58 -08001263static ssize_t mxt_object_show(struct device *dev,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001264 struct device_attribute *attr, char *buf)
1265{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001266 struct mxt_data *data = dev_get_drvdata(dev);
1267 struct mxt_object *object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001268 int count = 0;
1269 int i, j;
1270 int error;
1271 u8 val;
1272
1273 for (i = 0; i < data->info.object_num; i++) {
1274 object = data->object_table + i;
1275
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001276 count += snprintf(buf + count, PAGE_SIZE - count,
1277 "Object[%d] (Type %d)\n",
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001278 i + 1, object->type);
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001279 if (count >= PAGE_SIZE)
1280 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001281
Iiro Valkonen7686b102011-02-02 23:21:58 -08001282 if (!mxt_object_readable(object->type)) {
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001283 count += snprintf(buf + count, PAGE_SIZE - count,
1284 "\n");
1285 if (count >= PAGE_SIZE)
1286 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001287 continue;
1288 }
1289
1290 for (j = 0; j < object->size + 1; j++) {
Iiro Valkonen7686b102011-02-02 23:21:58 -08001291 error = mxt_read_object(data,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001292 object->type, j, &val);
1293 if (error)
1294 return error;
1295
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001296 count += snprintf(buf + count, PAGE_SIZE - count,
1297 "\t[%2d]: %02x (%d)\n", j, val, val);
1298 if (count >= PAGE_SIZE)
1299 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001300 }
1301
Daniel Kurtz4ef11a82011-11-02 10:43:08 -07001302 count += snprintf(buf + count, PAGE_SIZE - count, "\n");
1303 if (count >= PAGE_SIZE)
1304 return PAGE_SIZE - 1;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001305 }
1306
1307 return count;
1308}
1309
Iiro Valkonen7686b102011-02-02 23:21:58 -08001310static int mxt_load_fw(struct device *dev, const char *fn)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001311{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001312 struct mxt_data *data = dev_get_drvdata(dev);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001313 struct i2c_client *client = data->client;
1314 const struct firmware *fw = NULL;
1315 unsigned int frame_size;
Nick Dyer0a4016c2012-01-18 15:17:59 +05301316 unsigned int retry = 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001317 unsigned int pos = 0;
1318 int ret;
1319
1320 ret = request_firmware(&fw, fn, dev);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301321 if (ret < 0) {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001322 dev_err(dev, "Unable to open firmware %s\n", fn);
1323 return ret;
1324 }
1325
Nick Dyer0a4016c2012-01-18 15:17:59 +05301326 if (data->state != BOOTLOADER) {
1327 /* Change to the bootloader mode */
1328 mxt_write_object(data, MXT_GEN_COMMAND_T6,
1329 MXT_COMMAND_RESET, MXT_BOOT_VALUE);
1330 mxt_reset_delay(data);
Amy Maloche7e447432011-09-14 11:36:30 -07001331
Nick Dyer0a4016c2012-01-18 15:17:59 +05301332 ret = mxt_switch_to_bootloader_address(data);
1333 if (ret)
1334 goto release_firmware;
1335 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001336
Iiro Valkonen7686b102011-02-02 23:21:58 -08001337 ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301338 if (ret) {
1339 /* Bootloader may still be unlocked from previous update
1340 * attempt */
1341 ret = mxt_check_bootloader(client,
1342 MXT_WAITING_FRAME_DATA);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001343
Nick Dyer0a4016c2012-01-18 15:17:59 +05301344 if (ret)
1345 goto return_to_app_mode;
1346 } else {
1347 dev_info(dev, "Unlocking bootloader\n");
1348 /* Unlock bootloader */
1349 mxt_unlock_bootloader(client);
1350 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001351
1352 while (pos < fw->size) {
Iiro Valkonen7686b102011-02-02 23:21:58 -08001353 ret = mxt_check_bootloader(client,
1354 MXT_WAITING_FRAME_DATA);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001355 if (ret)
Nick Dyer0a4016c2012-01-18 15:17:59 +05301356 goto release_firmware;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001357
1358 frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
1359
1360 /* We should add 2 at frame size as the the firmware data is not
1361 * included the CRC bytes.
1362 */
1363 frame_size += 2;
1364
1365 /* Write one frame to device */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001366 mxt_fw_write(client, fw->data + pos, frame_size);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001367
Iiro Valkonen7686b102011-02-02 23:21:58 -08001368 ret = mxt_check_bootloader(client,
1369 MXT_FRAME_CRC_PASS);
Nick Dyer0a4016c2012-01-18 15:17:59 +05301370 if (ret) {
1371 retry++;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001372
Nick Dyer0a4016c2012-01-18 15:17:59 +05301373 /* Back off by 20ms per retry */
1374 msleep(retry * 20);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001375
Nick Dyer0a4016c2012-01-18 15:17:59 +05301376 if (retry > 20)
1377 goto release_firmware;
1378 } else {
1379 retry = 0;
1380 pos += frame_size;
1381 dev_info(dev, "Updated %d/%zd bytes\n", pos, fw->size);
1382 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001383 }
1384
Nick Dyer0a4016c2012-01-18 15:17:59 +05301385return_to_app_mode:
1386 mxt_switch_to_appmode_address(data);
1387release_firmware:
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001388 release_firmware(fw);
1389
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001390 return ret;
1391}
1392
Iiro Valkonen7686b102011-02-02 23:21:58 -08001393static ssize_t mxt_update_fw_store(struct device *dev,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001394 struct device_attribute *attr,
1395 const char *buf, size_t count)
1396{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001397 struct mxt_data *data = dev_get_drvdata(dev);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001398 int error;
1399
Anirudh Ghayal0bcb5b52012-02-17 14:58:25 -08001400 /* If fw_name is set, then the existing firmware has an upgrade */
1401 if (!data->fw_name) {
1402 dev_err(dev, "Firmware name not specifed in platform data\n");
1403 return -EINVAL;
1404 }
1405
1406 dev_info(dev, "Upgrading the firmware file to %s\n", data->fw_name);
1407
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001408 disable_irq(data->irq);
1409
Anirudh Ghayal0bcb5b52012-02-17 14:58:25 -08001410 error = mxt_load_fw(dev, data->fw_name);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001411 if (error) {
1412 dev_err(dev, "The firmware update failed(%d)\n", error);
1413 count = error;
1414 } else {
Nick Dyer0a4016c2012-01-18 15:17:59 +05301415 dev_info(dev, "The firmware update succeeded\n");
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001416
1417 /* Wait for reset */
Iiro Valkonen7686b102011-02-02 23:21:58 -08001418 msleep(MXT_FWRESET_TIME);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001419
Nick Dyer0a4016c2012-01-18 15:17:59 +05301420 data->state = INIT;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001421 kfree(data->object_table);
1422 data->object_table = NULL;
1423
Iiro Valkonen7686b102011-02-02 23:21:58 -08001424 mxt_initialize(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001425 }
1426
Nick Dyer0a4016c2012-01-18 15:17:59 +05301427 if (data->state == APPMODE) {
1428 enable_irq(data->irq);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001429
Nick Dyer0a4016c2012-01-18 15:17:59 +05301430 error = mxt_make_highchg(data);
1431 if (error)
1432 return error;
1433 }
Iiro Valkonen08960a02011-04-12 23:16:40 -07001434
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001435 return count;
1436}
1437
Iiro Valkonen7686b102011-02-02 23:21:58 -08001438static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
1439static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001440
Iiro Valkonen7686b102011-02-02 23:21:58 -08001441static struct attribute *mxt_attrs[] = {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001442 &dev_attr_object.attr,
1443 &dev_attr_update_fw.attr,
1444 NULL
1445};
1446
Iiro Valkonen7686b102011-02-02 23:21:58 -08001447static const struct attribute_group mxt_attr_group = {
1448 .attrs = mxt_attrs,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001449};
1450
Amy Maloche52262212011-09-15 16:46:57 -07001451static int mxt_start(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001452{
Jing Lin36aee812011-10-17 17:17:28 -07001453 int error;
1454
Amy Maloche52262212011-09-15 16:46:57 -07001455 /* restore the old power state values and reenable touch */
Jing Lin36aee812011-10-17 17:17:28 -07001456 error = __mxt_write_reg(data->client, data->t7_start_addr,
1457 T7_DATA_SIZE, data->t7_data);
1458 if (error < 0) {
1459 dev_err(&data->client->dev,
1460 "failed to restore old power state\n");
1461 return error;
Amy Maloche52262212011-09-15 16:46:57 -07001462 }
Jing Lin36aee812011-10-17 17:17:28 -07001463
Amy Maloche52262212011-09-15 16:46:57 -07001464 error = mxt_write_object(data,
Iiro Valkonene8645592011-11-18 12:56:19 -08001465 MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, data->t9_ctrl);
Amy Maloche52262212011-09-15 16:46:57 -07001466 if (error < 0) {
1467 dev_err(&data->client->dev, "failed to restore touch\n");
1468 return error;
1469 }
1470
1471 return 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001472}
1473
Amy Maloche52262212011-09-15 16:46:57 -07001474static int mxt_stop(struct mxt_data *data)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001475{
Jing Lin36aee812011-10-17 17:17:28 -07001476 int error;
1477 u8 t7_data[T7_DATA_SIZE] = {0};
1478
1479 /* disable touch and configure deep sleep mode */
Iiro Valkonene8645592011-11-18 12:56:19 -08001480 error = mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
Jing Lin36aee812011-10-17 17:17:28 -07001481 if (error < 0) {
1482 dev_err(&data->client->dev, "failed to disable touch\n");
1483 return error;
Amy Maloche52262212011-09-15 16:46:57 -07001484 }
1485
Jing Lin36aee812011-10-17 17:17:28 -07001486 error = __mxt_write_reg(data->client, data->t7_start_addr,
1487 T7_DATA_SIZE, t7_data);
Amy Maloche52262212011-09-15 16:46:57 -07001488 if (error < 0) {
1489 dev_err(&data->client->dev,
Jing Lin36aee812011-10-17 17:17:28 -07001490 "failed to configure deep sleep mode\n");
Amy Maloche52262212011-09-15 16:46:57 -07001491 return error;
1492 }
1493
1494 return 0;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001495}
1496
Iiro Valkonen7686b102011-02-02 23:21:58 -08001497static int mxt_input_open(struct input_dev *dev)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001498{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001499 struct mxt_data *data = input_get_drvdata(dev);
Amy Maloche52262212011-09-15 16:46:57 -07001500 int error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001501
Amy Maloche52262212011-09-15 16:46:57 -07001502 error = mxt_start(data);
1503 if (error < 0) {
1504 dev_err(&data->client->dev, "mxt_start failed in input_open\n");
1505 return error;
1506 }
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001507
1508 return 0;
1509}
1510
Iiro Valkonen7686b102011-02-02 23:21:58 -08001511static void mxt_input_close(struct input_dev *dev)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001512{
Iiro Valkonen7686b102011-02-02 23:21:58 -08001513 struct mxt_data *data = input_get_drvdata(dev);
Amy Maloche52262212011-09-15 16:46:57 -07001514 int error;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001515
Amy Maloche52262212011-09-15 16:46:57 -07001516 error = mxt_stop(data);
1517 if (error < 0)
1518 dev_err(&data->client->dev, "mxt_stop failed in input_close\n");
1519
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001520}
1521
Amy Malochec331f842012-01-24 10:33:47 -08001522static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
1523{
1524 return (regulator_count_voltages(reg) > 0) ?
1525 regulator_set_optimum_mode(reg, load_uA) : 0;
1526}
1527
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301528static int mxt_power_on(struct mxt_data *data, bool on)
1529{
1530 int rc;
1531
1532 if (on == false)
1533 goto power_off;
1534
Amy Malochec331f842012-01-24 10:33:47 -08001535 rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301536 if (rc < 0) {
Amy Maloche21115eb2011-11-02 09:04:37 -07001537 dev_err(&data->client->dev,
1538 "Regulator vcc_ana set_opt failed rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301539 return rc;
1540 }
1541
Amy Maloche21115eb2011-11-02 09:04:37 -07001542 rc = regulator_enable(data->vcc_ana);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301543 if (rc) {
Amy Maloche21115eb2011-11-02 09:04:37 -07001544 dev_err(&data->client->dev,
1545 "Regulator vcc_ana enable failed rc=%d\n", rc);
1546 goto error_reg_en_vcc_ana;
1547 }
1548
1549 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001550 rc = reg_set_optimum_mode_check(data->vcc_dig,
1551 MXT_ACTIVE_LOAD_DIG_UA);
Amy Maloche21115eb2011-11-02 09:04:37 -07001552 if (rc < 0) {
1553 dev_err(&data->client->dev,
1554 "Regulator vcc_dig set_opt failed rc=%d\n",
1555 rc);
1556 goto error_reg_opt_vcc_dig;
1557 }
1558
1559 rc = regulator_enable(data->vcc_dig);
1560 if (rc) {
1561 dev_err(&data->client->dev,
1562 "Regulator vcc_dig enable failed rc=%d\n", rc);
1563 goto error_reg_en_vcc_dig;
1564 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301565 }
1566
1567 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001568 rc = reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LOAD_UA);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301569 if (rc < 0) {
1570 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001571 "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301572 goto error_reg_opt_i2c;
1573 }
1574
1575 rc = regulator_enable(data->vcc_i2c);
1576 if (rc) {
1577 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001578 "Regulator vcc_i2c enable failed rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301579 goto error_reg_en_vcc_i2c;
1580 }
1581 }
1582
Amy Malochef0d7b8d2011-10-17 12:10:51 -07001583 msleep(130);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301584
1585 return 0;
1586
1587error_reg_en_vcc_i2c:
1588 if (data->pdata->i2c_pull_up)
Amy Malochec331f842012-01-24 10:33:47 -08001589 reg_set_optimum_mode_check(data->vcc_i2c, 0);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301590error_reg_opt_i2c:
Amy Maloche21115eb2011-11-02 09:04:37 -07001591 if (data->pdata->digital_pwr_regulator)
1592 regulator_disable(data->vcc_dig);
1593error_reg_en_vcc_dig:
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 -07001596error_reg_opt_vcc_dig:
1597 regulator_disable(data->vcc_ana);
1598error_reg_en_vcc_ana:
Amy Malochec331f842012-01-24 10:33:47 -08001599 reg_set_optimum_mode_check(data->vcc_ana, 0);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301600 return rc;
1601
1602power_off:
Amy Malochec331f842012-01-24 10:33:47 -08001603 reg_set_optimum_mode_check(data->vcc_ana, 0);
Amy Maloche21115eb2011-11-02 09:04:37 -07001604 regulator_disable(data->vcc_ana);
1605 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001606 reg_set_optimum_mode_check(data->vcc_dig, 0);
Amy Maloche21115eb2011-11-02 09:04:37 -07001607 regulator_disable(data->vcc_dig);
1608 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301609 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001610 reg_set_optimum_mode_check(data->vcc_i2c, 0);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301611 regulator_disable(data->vcc_i2c);
1612 }
1613 msleep(50);
1614 return 0;
1615}
1616
1617static int mxt_regulator_configure(struct mxt_data *data, bool on)
1618{
1619 int rc;
1620
1621 if (on == false)
1622 goto hw_shutdown;
1623
Amy Maloche21115eb2011-11-02 09:04:37 -07001624 data->vcc_ana = regulator_get(&data->client->dev, "vdd_ana");
1625 if (IS_ERR(data->vcc_ana)) {
1626 rc = PTR_ERR(data->vcc_ana);
1627 dev_err(&data->client->dev,
1628 "Regulator get failed vcc_ana rc=%d\n", rc);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301629 return rc;
1630 }
1631
Amy Maloche21115eb2011-11-02 09:04:37 -07001632 if (regulator_count_voltages(data->vcc_ana) > 0) {
1633 rc = regulator_set_voltage(data->vcc_ana, MXT_VTG_MIN_UV,
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301634 MXT_VTG_MAX_UV);
1635 if (rc) {
1636 dev_err(&data->client->dev,
1637 "regulator set_vtg failed rc=%d\n", rc);
Amy Maloche21115eb2011-11-02 09:04:37 -07001638 goto error_set_vtg_vcc_ana;
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301639 }
1640 }
Amy Maloche21115eb2011-11-02 09:04:37 -07001641 if (data->pdata->digital_pwr_regulator) {
1642 data->vcc_dig = regulator_get(&data->client->dev, "vdd_dig");
1643 if (IS_ERR(data->vcc_dig)) {
1644 rc = PTR_ERR(data->vcc_dig);
1645 dev_err(&data->client->dev,
1646 "Regulator get dig failed rc=%d\n", rc);
1647 goto error_get_vtg_vcc_dig;
1648 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301649
Amy Maloche21115eb2011-11-02 09:04:37 -07001650 if (regulator_count_voltages(data->vcc_dig) > 0) {
1651 rc = regulator_set_voltage(data->vcc_dig,
1652 MXT_VTG_DIG_MIN_UV, MXT_VTG_DIG_MAX_UV);
1653 if (rc) {
1654 dev_err(&data->client->dev,
1655 "regulator set_vtg failed rc=%d\n", rc);
1656 goto error_set_vtg_vcc_dig;
1657 }
1658 }
1659 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301660 if (data->pdata->i2c_pull_up) {
1661 data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
1662 if (IS_ERR(data->vcc_i2c)) {
1663 rc = PTR_ERR(data->vcc_i2c);
1664 dev_err(&data->client->dev,
1665 "Regulator get failed rc=%d\n", rc);
1666 goto error_get_vtg_i2c;
1667 }
1668 if (regulator_count_voltages(data->vcc_i2c) > 0) {
1669 rc = regulator_set_voltage(data->vcc_i2c,
1670 MXT_I2C_VTG_MIN_UV, MXT_I2C_VTG_MAX_UV);
1671 if (rc) {
1672 dev_err(&data->client->dev,
1673 "regulator set_vtg failed rc=%d\n", rc);
1674 goto error_set_vtg_i2c;
1675 }
1676 }
1677 }
1678
1679 return 0;
1680
1681error_set_vtg_i2c:
1682 regulator_put(data->vcc_i2c);
1683error_get_vtg_i2c:
Amy Maloche21115eb2011-11-02 09:04:37 -07001684 if (data->pdata->digital_pwr_regulator)
1685 if (regulator_count_voltages(data->vcc_dig) > 0)
1686 regulator_set_voltage(data->vcc_dig, 0,
1687 MXT_VTG_DIG_MAX_UV);
1688error_set_vtg_vcc_dig:
1689 if (data->pdata->digital_pwr_regulator)
1690 regulator_put(data->vcc_dig);
1691error_get_vtg_vcc_dig:
1692 if (regulator_count_voltages(data->vcc_ana) > 0)
1693 regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
1694error_set_vtg_vcc_ana:
1695 regulator_put(data->vcc_ana);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301696 return rc;
1697
1698hw_shutdown:
Amy Maloche21115eb2011-11-02 09:04:37 -07001699 if (regulator_count_voltages(data->vcc_ana) > 0)
1700 regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
1701 regulator_put(data->vcc_ana);
1702 if (data->pdata->digital_pwr_regulator) {
1703 if (regulator_count_voltages(data->vcc_dig) > 0)
1704 regulator_set_voltage(data->vcc_dig, 0,
1705 MXT_VTG_DIG_MAX_UV);
1706 regulator_put(data->vcc_dig);
1707 }
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05301708 if (data->pdata->i2c_pull_up) {
1709 if (regulator_count_voltages(data->vcc_i2c) > 0)
1710 regulator_set_voltage(data->vcc_i2c, 0,
1711 MXT_I2C_VTG_MAX_UV);
1712 regulator_put(data->vcc_i2c);
1713 }
1714 return 0;
1715}
1716
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301717#ifdef CONFIG_PM
Jing Linbace50b2011-10-18 22:55:47 -07001718static int mxt_regulator_lpm(struct mxt_data *data, bool on)
1719{
1720
1721 int rc;
1722
1723 if (on == false)
1724 goto regulator_hpm;
1725
Amy Malochec331f842012-01-24 10:33:47 -08001726 rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_LPM_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001727 if (rc < 0) {
1728 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001729 "Regulator vcc_ana set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001730 goto fail_regulator_lpm;
1731 }
1732
Amy Maloche21115eb2011-11-02 09:04:37 -07001733 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001734 rc = reg_set_optimum_mode_check(data->vcc_dig,
Amy Maloche21115eb2011-11-02 09:04:37 -07001735 MXT_LPM_LOAD_DIG_UA);
1736 if (rc < 0) {
1737 dev_err(&data->client->dev,
1738 "Regulator vcc_dig set_opt failed rc=%d\n", rc);
1739 goto fail_regulator_lpm;
1740 }
1741 }
1742
Jing Linbace50b2011-10-18 22:55:47 -07001743 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001744 rc = reg_set_optimum_mode_check(data->vcc_i2c,
Jing Linbace50b2011-10-18 22:55:47 -07001745 MXT_I2C_LPM_LOAD_UA);
1746 if (rc < 0) {
1747 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001748 "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001749 goto fail_regulator_lpm;
1750 }
1751 }
1752
1753 return 0;
1754
1755regulator_hpm:
1756
Amy Malochec331f842012-01-24 10:33:47 -08001757 rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001758 if (rc < 0) {
1759 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001760 "Regulator vcc_ana set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001761 goto fail_regulator_hpm;
1762 }
1763
Amy Maloche21115eb2011-11-02 09:04:37 -07001764 if (data->pdata->digital_pwr_regulator) {
Amy Malochec331f842012-01-24 10:33:47 -08001765 rc = reg_set_optimum_mode_check(data->vcc_dig,
Amy Maloche21115eb2011-11-02 09:04:37 -07001766 MXT_ACTIVE_LOAD_DIG_UA);
1767 if (rc < 0) {
1768 dev_err(&data->client->dev,
1769 "Regulator vcc_dig set_opt failed rc=%d\n", rc);
1770 goto fail_regulator_hpm;
1771 }
1772 }
1773
Jing Linbace50b2011-10-18 22:55:47 -07001774 if (data->pdata->i2c_pull_up) {
Amy Malochec331f842012-01-24 10:33:47 -08001775 rc = reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001776 if (rc < 0) {
1777 dev_err(&data->client->dev,
Amy Maloche21115eb2011-11-02 09:04:37 -07001778 "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
Jing Linbace50b2011-10-18 22:55:47 -07001779 goto fail_regulator_hpm;
1780 }
1781 }
1782
1783 return 0;
1784
1785fail_regulator_lpm:
Amy Malochec331f842012-01-24 10:33:47 -08001786 reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
Amy Maloche21115eb2011-11-02 09:04:37 -07001787 if (data->pdata->digital_pwr_regulator)
Amy Malochec331f842012-01-24 10:33:47 -08001788 reg_set_optimum_mode_check(data->vcc_dig,
1789 MXT_ACTIVE_LOAD_DIG_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001790 if (data->pdata->i2c_pull_up)
Amy Malochec331f842012-01-24 10:33:47 -08001791 reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001792
1793 return rc;
1794
1795fail_regulator_hpm:
Amy Malochec331f842012-01-24 10:33:47 -08001796 reg_set_optimum_mode_check(data->vcc_ana, MXT_LPM_LOAD_UA);
Amy Maloche21115eb2011-11-02 09:04:37 -07001797 if (data->pdata->digital_pwr_regulator)
Amy Malochec331f842012-01-24 10:33:47 -08001798 reg_set_optimum_mode_check(data->vcc_dig, MXT_LPM_LOAD_DIG_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001799 if (data->pdata->i2c_pull_up)
Amy Malochec331f842012-01-24 10:33:47 -08001800 reg_set_optimum_mode_check(data->vcc_i2c, MXT_I2C_LPM_LOAD_UA);
Jing Linbace50b2011-10-18 22:55:47 -07001801
1802 return rc;
1803}
1804
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301805static int mxt_suspend(struct device *dev)
1806{
1807 struct i2c_client *client = to_i2c_client(dev);
1808 struct mxt_data *data = i2c_get_clientdata(client);
1809 struct input_dev *input_dev = data->input_dev;
Amy Maloche52262212011-09-15 16:46:57 -07001810 int error;
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301811
1812 mutex_lock(&input_dev->mutex);
1813
Amy Maloche52262212011-09-15 16:46:57 -07001814 if (input_dev->users) {
1815 error = mxt_stop(data);
1816 if (error < 0) {
Jing Lin36aee812011-10-17 17:17:28 -07001817 dev_err(dev, "mxt_stop failed in suspend\n");
Amy Maloche52262212011-09-15 16:46:57 -07001818 mutex_unlock(&input_dev->mutex);
1819 return error;
1820 }
1821
1822 }
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301823
1824 mutex_unlock(&input_dev->mutex);
1825
Jing Linbace50b2011-10-18 22:55:47 -07001826 /* put regulators in low power mode */
1827 error = mxt_regulator_lpm(data, true);
1828 if (error < 0) {
1829 dev_err(dev, "failed to enter low power mode\n");
1830 return error;
1831 }
1832
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301833 return 0;
1834}
1835
1836static int mxt_resume(struct device *dev)
1837{
1838 struct i2c_client *client = to_i2c_client(dev);
1839 struct mxt_data *data = i2c_get_clientdata(client);
1840 struct input_dev *input_dev = data->input_dev;
Amy Maloche52262212011-09-15 16:46:57 -07001841 int error;
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301842
Jing Linbace50b2011-10-18 22:55:47 -07001843 /* put regulators in high power mode */
1844 error = mxt_regulator_lpm(data, false);
1845 if (error < 0) {
1846 dev_err(dev, "failed to enter high power mode\n");
1847 return error;
1848 }
1849
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301850 mutex_lock(&input_dev->mutex);
1851
Amy Maloche52262212011-09-15 16:46:57 -07001852 if (input_dev->users) {
1853 error = mxt_start(data);
1854 if (error < 0) {
Jing Lin36aee812011-10-17 17:17:28 -07001855 dev_err(dev, "mxt_start failed in resume\n");
Amy Maloche52262212011-09-15 16:46:57 -07001856 mutex_unlock(&input_dev->mutex);
1857 return error;
1858 }
1859 }
Anirudh Ghayal253ce122011-08-09 19:32:57 +05301860
1861 mutex_unlock(&input_dev->mutex);
1862
1863 return 0;
1864}
1865
1866#if defined(CONFIG_HAS_EARLYSUSPEND)
1867static void mxt_early_suspend(struct early_suspend *h)
1868{
1869 struct mxt_data *data = container_of(h, struct mxt_data, early_suspend);
1870
1871 mxt_suspend(&data->client->dev);
1872}
1873
1874static void mxt_late_resume(struct early_suspend *h)
1875{
1876 struct mxt_data *data = container_of(h, struct mxt_data, early_suspend);
1877
1878 mxt_resume(&data->client->dev);
1879}
1880#endif
1881
1882static const struct dev_pm_ops mxt_pm_ops = {
1883#ifndef CONFIG_HAS_EARLYSUSPEND
1884 .suspend = mxt_suspend,
1885 .resume = mxt_resume,
1886#endif
1887};
1888#endif
1889
Jing Lin6cfc00e2011-11-02 15:15:30 -07001890static int mxt_debugfs_object_show(struct seq_file *m, void *v)
1891{
1892 struct mxt_data *data = m->private;
1893 struct mxt_object *object;
1894 struct device *dev = &data->client->dev;
1895 int i, j, k;
1896 int error;
1897 int obj_size;
1898 u8 val;
1899
1900 for (i = 0; i < data->info.object_num; i++) {
1901 object = data->object_table + i;
1902 obj_size = object->size + 1;
1903
1904 seq_printf(m, "Object[%d] (Type %d)\n", i + 1, object->type);
1905
1906 for (j = 0; j < object->instances + 1; j++) {
1907 seq_printf(m, "[Instance %d]\n", j);
1908
1909 for (k = 0; k < obj_size; k++) {
1910 error = mxt_read_object(data, object->type,
1911 j * obj_size + k, &val);
1912 if (error) {
1913 dev_err(dev,
1914 "Failed to read object %d "
1915 "instance %d at offset %d\n",
1916 object->type, j, k);
1917 return error;
1918 }
1919
1920 seq_printf(m, "Byte %d: 0x%02x (%d)\n",
1921 k, val, val);
1922 }
1923 }
1924 }
1925
1926 return 0;
1927}
1928
1929static int mxt_debugfs_object_open(struct inode *inode, struct file *file)
1930{
1931 return single_open(file, mxt_debugfs_object_show, inode->i_private);
1932}
1933
1934static const struct file_operations mxt_object_fops = {
1935 .owner = THIS_MODULE,
1936 .open = mxt_debugfs_object_open,
1937 .read = seq_read,
1938 .release = single_release,
1939};
1940
1941static void __init mxt_debugfs_init(struct mxt_data *data)
1942{
1943 debug_base = debugfs_create_dir(MXT_DEBUGFS_DIR, NULL);
1944 if (IS_ERR_OR_NULL(debug_base))
1945 pr_err("atmel_mxt_ts: Failed to create debugfs dir\n");
1946 if (IS_ERR_OR_NULL(debugfs_create_file(MXT_DEBUGFS_FILE,
1947 0444,
1948 debug_base,
1949 data,
1950 &mxt_object_fops))) {
1951 pr_err("atmel_mxt_ts: Failed to create object file\n");
1952 debugfs_remove_recursive(debug_base);
1953 }
1954}
1955
Iiro Valkonen7686b102011-02-02 23:21:58 -08001956static int __devinit mxt_probe(struct i2c_client *client,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001957 const struct i2c_device_id *id)
1958{
Iiro Valkonen919ed892011-02-15 13:36:52 -08001959 const struct mxt_platform_data *pdata = client->dev.platform_data;
Iiro Valkonen7686b102011-02-02 23:21:58 -08001960 struct mxt_data *data;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001961 struct input_dev *input_dev;
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08001962 int error, i;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001963
Iiro Valkonen919ed892011-02-15 13:36:52 -08001964 if (!pdata)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001965 return -EINVAL;
1966
Iiro Valkonen7686b102011-02-02 23:21:58 -08001967 data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001968 input_dev = input_allocate_device();
1969 if (!data || !input_dev) {
1970 dev_err(&client->dev, "Failed to allocate memory\n");
1971 error = -ENOMEM;
1972 goto err_free_mem;
1973 }
1974
Nick Dyer0a4016c2012-01-18 15:17:59 +05301975 data->state = INIT;
Amy Maloche83c385a2012-02-01 10:32:03 +05301976 input_dev->name = "atmel_mxt_ts";
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001977 input_dev->id.bustype = BUS_I2C;
1978 input_dev->dev.parent = &client->dev;
Iiro Valkonen7686b102011-02-02 23:21:58 -08001979 input_dev->open = mxt_input_open;
1980 input_dev->close = mxt_input_close;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001981
Joonyoung Shim910d8052011-04-12 23:14:38 -07001982 data->client = client;
1983 data->input_dev = input_dev;
1984 data->pdata = pdata;
1985 data->irq = client->irq;
1986
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001987 __set_bit(EV_ABS, input_dev->evbit);
1988 __set_bit(EV_KEY, input_dev->evbit);
1989 __set_bit(BTN_TOUCH, input_dev->keybit);
1990
1991 /* For single touch */
1992 input_set_abs_params(input_dev, ABS_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_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_PRESSURE,
1997 0, 255, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07001998
1999 /* For multi touch */
Joonyoung Shimcd473222012-02-14 18:32:48 -08002000 input_mt_init_slots(input_dev, MXT_MAX_FINGER);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002001 input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
Iiro Valkonen7686b102011-02-02 23:21:58 -08002002 0, MXT_MAX_AREA, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002003 input_set_abs_params(input_dev, ABS_MT_POSITION_X,
Jing Lin2f863172011-10-17 10:56:58 -07002004 0, data->pdata->x_size, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002005 input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
Jing Lin2f863172011-10-17 10:56:58 -07002006 0, data->pdata->y_size, 0, 0);
Yufeng Shene6eb36a2011-10-11 12:28:21 -07002007 input_set_abs_params(input_dev, ABS_MT_PRESSURE,
2008 0, 255, 0, 0);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002009
Amy Maloche83c385a2012-02-01 10:32:03 +05302010 if (pdata->touch_x_size)
2011 data->touch_x_size = pdata->touch_x_size;
2012 else
2013 data->touch_x_size = pdata->x_size;
2014
2015 if (pdata->touch_y_size)
2016 data->touch_y_size = pdata->touch_y_size;
2017 else
2018 data->touch_y_size = pdata->y_size;
2019
Mohan Pallaka382d3ce2012-01-02 20:24:28 +08002020 /* set key array supported keys */
2021 if (pdata->key_codes) {
2022 for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) {
2023 if (pdata->key_codes[i])
2024 input_set_capability(input_dev, EV_KEY,
2025 pdata->key_codes[i]);
2026 }
2027 }
2028
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002029 input_set_drvdata(input_dev, data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002030 i2c_set_clientdata(client, data);
2031
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302032 if (pdata->init_hw)
2033 error = pdata->init_hw(true);
2034 else
2035 error = mxt_regulator_configure(data, true);
2036 if (error) {
2037 dev_err(&client->dev, "Failed to intialize hardware\n");
Jing Lin32c72532011-11-03 12:02:33 -07002038 goto err_free_mem;
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302039 }
2040
2041 if (pdata->power_on)
2042 error = pdata->power_on(true);
2043 else
2044 error = mxt_power_on(data, true);
2045 if (error) {
2046 dev_err(&client->dev, "Failed to power on hardware\n");
2047 goto err_regulator_on;
2048 }
2049
Amy Maloche08266db2011-11-04 11:07:16 -07002050 if (gpio_is_valid(pdata->irq_gpio)) {
2051 /* configure touchscreen irq gpio */
2052 error = gpio_request(pdata->irq_gpio,
2053 "mxt_irq_gpio");
2054 if (error) {
2055 pr_err("%s: unable to request gpio [%d]\n", __func__,
2056 pdata->irq_gpio);
2057 goto err_power_on;
2058 }
2059 error = gpio_direction_input(pdata->irq_gpio);
2060 if (error) {
2061 pr_err("%s: unable to set_direction for gpio [%d]\n",
2062 __func__, pdata->irq_gpio);
2063 goto err_irq_gpio_req;
2064 }
2065 }
2066
2067 if (gpio_is_valid(pdata->reset_gpio)) {
2068 /* configure touchscreen reset out gpio */
2069 error = gpio_request(pdata->reset_gpio,
2070 "mxt_reset_gpio");
2071 if (error) {
2072 pr_err("%s: unable to request reset gpio %d\n",
2073 __func__, pdata->reset_gpio);
2074 goto err_irq_gpio_req;
2075 }
2076
2077 error = gpio_direction_output(
2078 pdata->reset_gpio, 1);
2079 if (error) {
2080 pr_err("%s: unable to set direction for gpio %d\n",
2081 __func__, pdata->reset_gpio);
2082 goto err_reset_gpio_req;
2083 }
2084 }
2085
2086 mxt_reset_delay(data);
2087
Iiro Valkonen7686b102011-02-02 23:21:58 -08002088 error = mxt_initialize(data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002089 if (error)
Amy Maloche08266db2011-11-04 11:07:16 -07002090 goto err_reset_gpio_req;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002091
Iiro Valkonen7686b102011-02-02 23:21:58 -08002092 error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
Iiro Valkonen919ed892011-02-15 13:36:52 -08002093 pdata->irqflags, client->dev.driver->name, data);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002094 if (error) {
2095 dev_err(&client->dev, "Failed to register interrupt\n");
Jing Lin32c72532011-11-03 12:02:33 -07002096 goto err_free_object;
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002097 }
2098
Nick Dyer0a4016c2012-01-18 15:17:59 +05302099 if (data->state == APPMODE) {
2100 error = mxt_make_highchg(data);
2101 if (error) {
2102 dev_err(&client->dev, "Failed to make high CHG\n");
2103 goto err_free_irq;
2104 }
2105 }
Iiro Valkonen08960a02011-04-12 23:16:40 -07002106
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002107 error = input_register_device(input_dev);
2108 if (error)
2109 goto err_free_irq;
2110
Iiro Valkonen7686b102011-02-02 23:21:58 -08002111 error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002112 if (error)
2113 goto err_unregister_device;
2114
Anirudh Ghayal253ce122011-08-09 19:32:57 +05302115#if defined(CONFIG_HAS_EARLYSUSPEND)
2116 data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
2117 MXT_SUSPEND_LEVEL;
2118 data->early_suspend.suspend = mxt_early_suspend;
2119 data->early_suspend.resume = mxt_late_resume;
2120 register_early_suspend(&data->early_suspend);
2121#endif
2122
Jing Lin6cfc00e2011-11-02 15:15:30 -07002123 mxt_debugfs_init(data);
2124
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002125 return 0;
2126
2127err_unregister_device:
2128 input_unregister_device(input_dev);
2129 input_dev = NULL;
2130err_free_irq:
2131 free_irq(client->irq, data);
Jing Lin32c72532011-11-03 12:02:33 -07002132err_free_object:
2133 kfree(data->object_table);
Amy Maloche08266db2011-11-04 11:07:16 -07002134err_reset_gpio_req:
2135 if (gpio_is_valid(pdata->reset_gpio))
2136 gpio_free(pdata->reset_gpio);
2137err_irq_gpio_req:
2138 if (gpio_is_valid(pdata->irq_gpio))
2139 gpio_free(pdata->irq_gpio);
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302140err_power_on:
2141 if (pdata->power_on)
2142 pdata->power_on(false);
2143 else
2144 mxt_power_on(data, false);
2145err_regulator_on:
2146 if (pdata->init_hw)
2147 pdata->init_hw(false);
2148 else
2149 mxt_regulator_configure(data, false);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002150err_free_mem:
2151 input_free_device(input_dev);
2152 kfree(data);
2153 return error;
2154}
2155
Iiro Valkonen7686b102011-02-02 23:21:58 -08002156static int __devexit mxt_remove(struct i2c_client *client)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002157{
Iiro Valkonen7686b102011-02-02 23:21:58 -08002158 struct mxt_data *data = i2c_get_clientdata(client);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002159
Iiro Valkonen7686b102011-02-02 23:21:58 -08002160 sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002161 free_irq(data->irq, data);
2162 input_unregister_device(data->input_dev);
Anirudh Ghayal253ce122011-08-09 19:32:57 +05302163#if defined(CONFIG_HAS_EARLYSUSPEND)
2164 unregister_early_suspend(&data->early_suspend);
2165#endif
Anirudh Ghayala498e4d2011-08-09 19:10:12 +05302166
2167 if (data->pdata->power_on)
2168 data->pdata->power_on(false);
2169 else
2170 mxt_power_on(data, false);
2171
2172 if (data->pdata->init_hw)
2173 data->pdata->init_hw(false);
2174 else
2175 mxt_regulator_configure(data, false);
2176
Mohan Pallakabfe8f302012-01-02 18:32:08 +08002177 if (gpio_is_valid(data->pdata->reset_gpio))
2178 gpio_free(data->pdata->reset_gpio);
2179
2180 if (gpio_is_valid(data->pdata->irq_gpio))
2181 gpio_free(data->pdata->irq_gpio);
2182
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002183 kfree(data->object_table);
2184 kfree(data);
2185
Jing Lin6cfc00e2011-11-02 15:15:30 -07002186 debugfs_remove_recursive(debug_base);
2187
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002188 return 0;
2189}
2190
Iiro Valkonen7686b102011-02-02 23:21:58 -08002191static const struct i2c_device_id mxt_id[] = {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002192 { "qt602240_ts", 0 },
Iiro Valkonen7686b102011-02-02 23:21:58 -08002193 { "atmel_mxt_ts", 0 },
Chris Leech46ee2a02011-02-15 13:36:52 -08002194 { "mXT224", 0 },
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002195 { }
2196};
Iiro Valkonen7686b102011-02-02 23:21:58 -08002197MODULE_DEVICE_TABLE(i2c, mxt_id);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002198
Iiro Valkonen7686b102011-02-02 23:21:58 -08002199static struct i2c_driver mxt_driver = {
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002200 .driver = {
Iiro Valkonen7686b102011-02-02 23:21:58 -08002201 .name = "atmel_mxt_ts",
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002202 .owner = THIS_MODULE,
Dmitry Torokhov8b5fce02010-11-18 00:14:03 -08002203#ifdef CONFIG_PM
Iiro Valkonen7686b102011-02-02 23:21:58 -08002204 .pm = &mxt_pm_ops,
Dmitry Torokhov8b5fce02010-11-18 00:14:03 -08002205#endif
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002206 },
Iiro Valkonen7686b102011-02-02 23:21:58 -08002207 .probe = mxt_probe,
2208 .remove = __devexit_p(mxt_remove),
2209 .id_table = mxt_id,
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002210};
2211
Iiro Valkonen7686b102011-02-02 23:21:58 -08002212static int __init mxt_init(void)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002213{
Iiro Valkonen7686b102011-02-02 23:21:58 -08002214 return i2c_add_driver(&mxt_driver);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002215}
2216
Iiro Valkonen7686b102011-02-02 23:21:58 -08002217static void __exit mxt_exit(void)
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002218{
Iiro Valkonen7686b102011-02-02 23:21:58 -08002219 i2c_del_driver(&mxt_driver);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002220}
2221
Iiro Valkonen7686b102011-02-02 23:21:58 -08002222module_init(mxt_init);
2223module_exit(mxt_exit);
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002224
2225/* Module information */
2226MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
Iiro Valkonen7686b102011-02-02 23:21:58 -08002227MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
Joonyoung Shim4cf51c32010-07-14 21:55:30 -07002228MODULE_LICENSE("GPL");