xref: /linux/drivers/input/touchscreen/stmfts.c (revision 9ea370f3416ecc4b22d49b24e2c7fdc9c9ba3a0e)
1f8c5938fSAndi Shyti // SPDX-License-Identifier: GPL-2.0
2f8c5938fSAndi Shyti // STMicroelectronics FTS Touchscreen device driver
3f8c5938fSAndi Shyti //
4f8c5938fSAndi Shyti // Copyright (c) 2017 Samsung Electronics Co., Ltd.
5adf313f4SAndi Shyti // Copyright (c) 2017 Andi Shyti <andi@etezian.org>
678bcac7bSAndi Shyti 
778bcac7bSAndi Shyti #include <linux/delay.h>
878bcac7bSAndi Shyti #include <linux/i2c.h>
978bcac7bSAndi Shyti #include <linux/input/mt.h>
1078bcac7bSAndi Shyti #include <linux/input/touchscreen.h>
1178bcac7bSAndi Shyti #include <linux/interrupt.h>
1278bcac7bSAndi Shyti #include <linux/irq.h>
1378bcac7bSAndi Shyti #include <linux/leds.h>
1478bcac7bSAndi Shyti #include <linux/module.h>
1578bcac7bSAndi Shyti #include <linux/pm_runtime.h>
1678bcac7bSAndi Shyti #include <linux/regulator/consumer.h>
1778bcac7bSAndi Shyti 
1878bcac7bSAndi Shyti /* I2C commands */
1978bcac7bSAndi Shyti #define STMFTS_READ_INFO			0x80
2078bcac7bSAndi Shyti #define STMFTS_READ_STATUS			0x84
2178bcac7bSAndi Shyti #define STMFTS_READ_ONE_EVENT			0x85
2278bcac7bSAndi Shyti #define STMFTS_READ_ALL_EVENT			0x86
2378bcac7bSAndi Shyti #define STMFTS_LATEST_EVENT			0x87
2478bcac7bSAndi Shyti #define STMFTS_SLEEP_IN				0x90
2578bcac7bSAndi Shyti #define STMFTS_SLEEP_OUT			0x91
2678bcac7bSAndi Shyti #define STMFTS_MS_MT_SENSE_OFF			0x92
2778bcac7bSAndi Shyti #define STMFTS_MS_MT_SENSE_ON			0x93
2878bcac7bSAndi Shyti #define STMFTS_SS_HOVER_SENSE_OFF		0x94
2978bcac7bSAndi Shyti #define STMFTS_SS_HOVER_SENSE_ON		0x95
3078bcac7bSAndi Shyti #define STMFTS_MS_KEY_SENSE_OFF			0x9a
3178bcac7bSAndi Shyti #define STMFTS_MS_KEY_SENSE_ON			0x9b
3278bcac7bSAndi Shyti #define STMFTS_SYSTEM_RESET			0xa0
3378bcac7bSAndi Shyti #define STMFTS_CLEAR_EVENT_STACK		0xa1
3478bcac7bSAndi Shyti #define STMFTS_FULL_FORCE_CALIBRATION		0xa2
3578bcac7bSAndi Shyti #define STMFTS_MS_CX_TUNING			0xa3
3678bcac7bSAndi Shyti #define STMFTS_SS_CX_TUNING			0xa4
3778bcac7bSAndi Shyti 
3878bcac7bSAndi Shyti /* events */
3978bcac7bSAndi Shyti #define STMFTS_EV_NO_EVENT			0x00
4078bcac7bSAndi Shyti #define STMFTS_EV_MULTI_TOUCH_DETECTED		0x02
4178bcac7bSAndi Shyti #define STMFTS_EV_MULTI_TOUCH_ENTER		0x03
4278bcac7bSAndi Shyti #define STMFTS_EV_MULTI_TOUCH_LEAVE		0x04
4378bcac7bSAndi Shyti #define STMFTS_EV_MULTI_TOUCH_MOTION		0x05
4478bcac7bSAndi Shyti #define STMFTS_EV_HOVER_ENTER			0x07
4578bcac7bSAndi Shyti #define STMFTS_EV_HOVER_LEAVE			0x08
4678bcac7bSAndi Shyti #define STMFTS_EV_HOVER_MOTION			0x09
4778bcac7bSAndi Shyti #define STMFTS_EV_KEY_STATUS			0x0e
4878bcac7bSAndi Shyti #define STMFTS_EV_ERROR				0x0f
4978bcac7bSAndi Shyti #define STMFTS_EV_CONTROLLER_READY		0x10
5078bcac7bSAndi Shyti #define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY	0x11
5178bcac7bSAndi Shyti #define STMFTS_EV_STATUS			0x16
5278bcac7bSAndi Shyti #define STMFTS_EV_DEBUG				0xdb
5378bcac7bSAndi Shyti 
5478bcac7bSAndi Shyti /* multi touch related event masks */
5578bcac7bSAndi Shyti #define STMFTS_MASK_EVENT_ID			0x0f
5678bcac7bSAndi Shyti #define STMFTS_MASK_TOUCH_ID			0xf0
5778bcac7bSAndi Shyti #define STMFTS_MASK_LEFT_EVENT			0x0f
5878bcac7bSAndi Shyti #define STMFTS_MASK_X_MSB			0x0f
5978bcac7bSAndi Shyti #define STMFTS_MASK_Y_LSB			0xf0
6078bcac7bSAndi Shyti 
6178bcac7bSAndi Shyti /* key related event masks */
6278bcac7bSAndi Shyti #define STMFTS_MASK_KEY_NO_TOUCH		0x00
6378bcac7bSAndi Shyti #define STMFTS_MASK_KEY_MENU			0x01
6478bcac7bSAndi Shyti #define STMFTS_MASK_KEY_BACK			0x02
6578bcac7bSAndi Shyti 
6678bcac7bSAndi Shyti #define STMFTS_EVENT_SIZE	8
6778bcac7bSAndi Shyti #define STMFTS_STACK_DEPTH	32
6878bcac7bSAndi Shyti #define STMFTS_DATA_MAX_SIZE	(STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH)
6978bcac7bSAndi Shyti #define STMFTS_MAX_FINGERS	10
7078bcac7bSAndi Shyti #define STMFTS_DEV_NAME		"stmfts"
7178bcac7bSAndi Shyti 
7278bcac7bSAndi Shyti enum stmfts_regulators {
7378bcac7bSAndi Shyti 	STMFTS_REGULATOR_VDD,
7478bcac7bSAndi Shyti 	STMFTS_REGULATOR_AVDD,
7578bcac7bSAndi Shyti };
7678bcac7bSAndi Shyti 
7778bcac7bSAndi Shyti struct stmfts_data {
7878bcac7bSAndi Shyti 	struct i2c_client *client;
7978bcac7bSAndi Shyti 	struct input_dev *input;
8078bcac7bSAndi Shyti 	struct led_classdev led_cdev;
8178bcac7bSAndi Shyti 	struct mutex mutex;
8278bcac7bSAndi Shyti 
8378bcac7bSAndi Shyti 	struct touchscreen_properties prop;
8478bcac7bSAndi Shyti 
8578bcac7bSAndi Shyti 	struct regulator_bulk_data regulators[2];
8678bcac7bSAndi Shyti 
8778bcac7bSAndi Shyti 	/*
8878bcac7bSAndi Shyti 	 * Presence of ledvdd will be used also to check
8978bcac7bSAndi Shyti 	 * whether the LED is supported.
9078bcac7bSAndi Shyti 	 */
9178bcac7bSAndi Shyti 	struct regulator *ledvdd;
9278bcac7bSAndi Shyti 
9378bcac7bSAndi Shyti 	u16 chip_id;
9478bcac7bSAndi Shyti 	u8 chip_ver;
9578bcac7bSAndi Shyti 	u16 fw_ver;
9678bcac7bSAndi Shyti 	u8 config_id;
9778bcac7bSAndi Shyti 	u8 config_ver;
9878bcac7bSAndi Shyti 
9978bcac7bSAndi Shyti 	u8 data[STMFTS_DATA_MAX_SIZE];
10078bcac7bSAndi Shyti 
10178bcac7bSAndi Shyti 	struct completion cmd_done;
10278bcac7bSAndi Shyti 
10378bcac7bSAndi Shyti 	bool use_key;
10478bcac7bSAndi Shyti 	bool led_status;
10578bcac7bSAndi Shyti 	bool hover_enabled;
10678bcac7bSAndi Shyti 	bool running;
10778bcac7bSAndi Shyti };
10878bcac7bSAndi Shyti 
stmfts_brightness_set(struct led_classdev * led_cdev,enum led_brightness value)109937c4e55SDmitry Torokhov static int stmfts_brightness_set(struct led_classdev *led_cdev,
11078bcac7bSAndi Shyti 					enum led_brightness value)
11178bcac7bSAndi Shyti {
11278bcac7bSAndi Shyti 	struct stmfts_data *sdata = container_of(led_cdev,
11378bcac7bSAndi Shyti 					struct stmfts_data, led_cdev);
11478bcac7bSAndi Shyti 	int err;
11578bcac7bSAndi Shyti 
116937c4e55SDmitry Torokhov 	if (value != sdata->led_status && sdata->ledvdd) {
11778bcac7bSAndi Shyti 		if (!value) {
11878bcac7bSAndi Shyti 			regulator_disable(sdata->ledvdd);
11978bcac7bSAndi Shyti 		} else {
12078bcac7bSAndi Shyti 			err = regulator_enable(sdata->ledvdd);
121937c4e55SDmitry Torokhov 			if (err) {
12278bcac7bSAndi Shyti 				dev_warn(&sdata->client->dev,
12378bcac7bSAndi Shyti 					 "failed to disable ledvdd regulator: %d\n",
12478bcac7bSAndi Shyti 					 err);
125937c4e55SDmitry Torokhov 				return err;
126937c4e55SDmitry Torokhov 			}
127937c4e55SDmitry Torokhov 		}
128937c4e55SDmitry Torokhov 		sdata->led_status = value;
12978bcac7bSAndi Shyti 	}
13078bcac7bSAndi Shyti 
131937c4e55SDmitry Torokhov 	return 0;
13278bcac7bSAndi Shyti }
13378bcac7bSAndi Shyti 
stmfts_brightness_get(struct led_classdev * led_cdev)13478bcac7bSAndi Shyti static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
13578bcac7bSAndi Shyti {
13678bcac7bSAndi Shyti 	struct stmfts_data *sdata = container_of(led_cdev,
13778bcac7bSAndi Shyti 						struct stmfts_data, led_cdev);
13878bcac7bSAndi Shyti 
13978bcac7bSAndi Shyti 	return !!regulator_is_enabled(sdata->ledvdd);
14078bcac7bSAndi Shyti }
14178bcac7bSAndi Shyti 
14278bcac7bSAndi Shyti /*
14378bcac7bSAndi Shyti  * We can't simply use i2c_smbus_read_i2c_block_data because we
14478bcac7bSAndi Shyti  * need to read more than 255 bytes (
14578bcac7bSAndi Shyti  */
stmfts_read_events(struct stmfts_data * sdata)14678bcac7bSAndi Shyti static int stmfts_read_events(struct stmfts_data *sdata)
14778bcac7bSAndi Shyti {
14878bcac7bSAndi Shyti 	u8 cmd = STMFTS_READ_ALL_EVENT;
14978bcac7bSAndi Shyti 	struct i2c_msg msgs[2] = {
15078bcac7bSAndi Shyti 		{
15178bcac7bSAndi Shyti 			.addr	= sdata->client->addr,
15278bcac7bSAndi Shyti 			.len	= 1,
15378bcac7bSAndi Shyti 			.buf	= &cmd,
15478bcac7bSAndi Shyti 		},
15578bcac7bSAndi Shyti 		{
15678bcac7bSAndi Shyti 			.addr	= sdata->client->addr,
15778bcac7bSAndi Shyti 			.flags	= I2C_M_RD,
15878bcac7bSAndi Shyti 			.len	= STMFTS_DATA_MAX_SIZE,
15978bcac7bSAndi Shyti 			.buf	= sdata->data,
16078bcac7bSAndi Shyti 		},
16178bcac7bSAndi Shyti 	};
16278bcac7bSAndi Shyti 	int ret;
16378bcac7bSAndi Shyti 
16478bcac7bSAndi Shyti 	ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs));
16578bcac7bSAndi Shyti 	if (ret < 0)
16678bcac7bSAndi Shyti 		return ret;
16778bcac7bSAndi Shyti 
16878bcac7bSAndi Shyti 	return ret == ARRAY_SIZE(msgs) ? 0 : -EIO;
16978bcac7bSAndi Shyti }
17078bcac7bSAndi Shyti 
stmfts_report_contact_event(struct stmfts_data * sdata,const u8 event[])17178bcac7bSAndi Shyti static void stmfts_report_contact_event(struct stmfts_data *sdata,
17278bcac7bSAndi Shyti 					const u8 event[])
17378bcac7bSAndi Shyti {
17478bcac7bSAndi Shyti 	u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
17578bcac7bSAndi Shyti 	u16 x = event[1] | ((event[2] & STMFTS_MASK_X_MSB) << 8);
17678bcac7bSAndi Shyti 	u16 y = (event[2] >> 4) | (event[3] << 4);
17778bcac7bSAndi Shyti 	u8 maj = event[4];
17878bcac7bSAndi Shyti 	u8 min = event[5];
17978bcac7bSAndi Shyti 	u8 orientation = event[6];
18078bcac7bSAndi Shyti 	u8 area = event[7];
18178bcac7bSAndi Shyti 
18278bcac7bSAndi Shyti 	input_mt_slot(sdata->input, slot_id);
18378bcac7bSAndi Shyti 
18478bcac7bSAndi Shyti 	input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true);
18578bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_MT_POSITION_X, x);
18678bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_MT_POSITION_Y, y);
18778bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, maj);
18878bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, min);
18978bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_MT_PRESSURE, area);
19078bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_MT_ORIENTATION, orientation);
19178bcac7bSAndi Shyti 
19278bcac7bSAndi Shyti 	input_sync(sdata->input);
19378bcac7bSAndi Shyti }
19478bcac7bSAndi Shyti 
stmfts_report_contact_release(struct stmfts_data * sdata,const u8 event[])19578bcac7bSAndi Shyti static void stmfts_report_contact_release(struct stmfts_data *sdata,
19678bcac7bSAndi Shyti 					  const u8 event[])
19778bcac7bSAndi Shyti {
19878bcac7bSAndi Shyti 	u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
19978bcac7bSAndi Shyti 
20078bcac7bSAndi Shyti 	input_mt_slot(sdata->input, slot_id);
2015fc70e35SJiada Wang 	input_mt_report_slot_inactive(sdata->input);
20278bcac7bSAndi Shyti 
20378bcac7bSAndi Shyti 	input_sync(sdata->input);
20478bcac7bSAndi Shyti }
20578bcac7bSAndi Shyti 
stmfts_report_hover_event(struct stmfts_data * sdata,const u8 event[])20678bcac7bSAndi Shyti static void stmfts_report_hover_event(struct stmfts_data *sdata,
20778bcac7bSAndi Shyti 				      const u8 event[])
20878bcac7bSAndi Shyti {
20978bcac7bSAndi Shyti 	u16 x = (event[2] << 4) | (event[4] >> 4);
21078bcac7bSAndi Shyti 	u16 y = (event[3] << 4) | (event[4] & STMFTS_MASK_Y_LSB);
21178bcac7bSAndi Shyti 	u8 z = event[5];
21278bcac7bSAndi Shyti 
21378bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_X, x);
21478bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_Y, y);
21578bcac7bSAndi Shyti 	input_report_abs(sdata->input, ABS_DISTANCE, z);
21678bcac7bSAndi Shyti 
21778bcac7bSAndi Shyti 	input_sync(sdata->input);
21878bcac7bSAndi Shyti }
21978bcac7bSAndi Shyti 
stmfts_report_key_event(struct stmfts_data * sdata,const u8 event[])22078bcac7bSAndi Shyti static void stmfts_report_key_event(struct stmfts_data *sdata, const u8 event[])
22178bcac7bSAndi Shyti {
22278bcac7bSAndi Shyti 	switch (event[2]) {
22378bcac7bSAndi Shyti 	case 0:
22478bcac7bSAndi Shyti 		input_report_key(sdata->input, KEY_BACK, 0);
22578bcac7bSAndi Shyti 		input_report_key(sdata->input, KEY_MENU, 0);
22678bcac7bSAndi Shyti 		break;
22778bcac7bSAndi Shyti 
22878bcac7bSAndi Shyti 	case STMFTS_MASK_KEY_BACK:
22978bcac7bSAndi Shyti 		input_report_key(sdata->input, KEY_BACK, 1);
23078bcac7bSAndi Shyti 		break;
23178bcac7bSAndi Shyti 
23278bcac7bSAndi Shyti 	case STMFTS_MASK_KEY_MENU:
23378bcac7bSAndi Shyti 		input_report_key(sdata->input, KEY_MENU, 1);
23478bcac7bSAndi Shyti 		break;
23578bcac7bSAndi Shyti 
23678bcac7bSAndi Shyti 	default:
23778bcac7bSAndi Shyti 		dev_warn(&sdata->client->dev,
23878bcac7bSAndi Shyti 			 "unknown key event: %#02x\n", event[2]);
23978bcac7bSAndi Shyti 		break;
24078bcac7bSAndi Shyti 	}
24178bcac7bSAndi Shyti 
24278bcac7bSAndi Shyti 	input_sync(sdata->input);
24378bcac7bSAndi Shyti }
24478bcac7bSAndi Shyti 
stmfts_parse_events(struct stmfts_data * sdata)24578bcac7bSAndi Shyti static void stmfts_parse_events(struct stmfts_data *sdata)
24678bcac7bSAndi Shyti {
24778bcac7bSAndi Shyti 	int i;
24878bcac7bSAndi Shyti 
24978bcac7bSAndi Shyti 	for (i = 0; i < STMFTS_STACK_DEPTH; i++) {
25078bcac7bSAndi Shyti 		u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE];
25178bcac7bSAndi Shyti 
25278bcac7bSAndi Shyti 		switch (event[0]) {
25378bcac7bSAndi Shyti 
25478bcac7bSAndi Shyti 		case STMFTS_EV_CONTROLLER_READY:
25578bcac7bSAndi Shyti 		case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
25678bcac7bSAndi Shyti 		case STMFTS_EV_STATUS:
25778bcac7bSAndi Shyti 			complete(&sdata->cmd_done);
2586f49c4f5SGustavo A. R. Silva 			fallthrough;
25978bcac7bSAndi Shyti 
26078bcac7bSAndi Shyti 		case STMFTS_EV_NO_EVENT:
26178bcac7bSAndi Shyti 		case STMFTS_EV_DEBUG:
26278bcac7bSAndi Shyti 			return;
26378bcac7bSAndi Shyti 		}
26478bcac7bSAndi Shyti 
26578bcac7bSAndi Shyti 		switch (event[0] & STMFTS_MASK_EVENT_ID) {
26678bcac7bSAndi Shyti 
26778bcac7bSAndi Shyti 		case STMFTS_EV_MULTI_TOUCH_ENTER:
26878bcac7bSAndi Shyti 		case STMFTS_EV_MULTI_TOUCH_MOTION:
26978bcac7bSAndi Shyti 			stmfts_report_contact_event(sdata, event);
27078bcac7bSAndi Shyti 			break;
27178bcac7bSAndi Shyti 
27278bcac7bSAndi Shyti 		case STMFTS_EV_MULTI_TOUCH_LEAVE:
27378bcac7bSAndi Shyti 			stmfts_report_contact_release(sdata, event);
27478bcac7bSAndi Shyti 			break;
27578bcac7bSAndi Shyti 
27678bcac7bSAndi Shyti 		case STMFTS_EV_HOVER_ENTER:
27778bcac7bSAndi Shyti 		case STMFTS_EV_HOVER_LEAVE:
27878bcac7bSAndi Shyti 		case STMFTS_EV_HOVER_MOTION:
27978bcac7bSAndi Shyti 			stmfts_report_hover_event(sdata, event);
28078bcac7bSAndi Shyti 			break;
28178bcac7bSAndi Shyti 
28278bcac7bSAndi Shyti 		case STMFTS_EV_KEY_STATUS:
28378bcac7bSAndi Shyti 			stmfts_report_key_event(sdata, event);
28478bcac7bSAndi Shyti 			break;
28578bcac7bSAndi Shyti 
28678bcac7bSAndi Shyti 		case STMFTS_EV_ERROR:
28778bcac7bSAndi Shyti 			dev_warn(&sdata->client->dev,
28878bcac7bSAndi Shyti 					"error code: 0x%x%x%x%x%x%x",
28978bcac7bSAndi Shyti 					event[6], event[5], event[4],
29078bcac7bSAndi Shyti 					event[3], event[2], event[1]);
29178bcac7bSAndi Shyti 			break;
29278bcac7bSAndi Shyti 
29378bcac7bSAndi Shyti 		default:
29478bcac7bSAndi Shyti 			dev_err(&sdata->client->dev,
29578bcac7bSAndi Shyti 				"unknown event %#02x\n", event[0]);
29678bcac7bSAndi Shyti 		}
29778bcac7bSAndi Shyti 	}
29878bcac7bSAndi Shyti }
29978bcac7bSAndi Shyti 
stmfts_irq_handler(int irq,void * dev)30078bcac7bSAndi Shyti static irqreturn_t stmfts_irq_handler(int irq, void *dev)
30178bcac7bSAndi Shyti {
30278bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev;
30378bcac7bSAndi Shyti 	int err;
30478bcac7bSAndi Shyti 
30578bcac7bSAndi Shyti 	mutex_lock(&sdata->mutex);
30678bcac7bSAndi Shyti 
30778bcac7bSAndi Shyti 	err = stmfts_read_events(sdata);
30878bcac7bSAndi Shyti 	if (unlikely(err))
30978bcac7bSAndi Shyti 		dev_err(&sdata->client->dev,
31078bcac7bSAndi Shyti 			"failed to read events: %d\n", err);
31178bcac7bSAndi Shyti 	else
31278bcac7bSAndi Shyti 		stmfts_parse_events(sdata);
31378bcac7bSAndi Shyti 
31478bcac7bSAndi Shyti 	mutex_unlock(&sdata->mutex);
31578bcac7bSAndi Shyti 	return IRQ_HANDLED;
31678bcac7bSAndi Shyti }
31778bcac7bSAndi Shyti 
stmfts_command(struct stmfts_data * sdata,const u8 cmd)31878bcac7bSAndi Shyti static int stmfts_command(struct stmfts_data *sdata, const u8 cmd)
31978bcac7bSAndi Shyti {
32078bcac7bSAndi Shyti 	int err;
32178bcac7bSAndi Shyti 
32278bcac7bSAndi Shyti 	reinit_completion(&sdata->cmd_done);
32378bcac7bSAndi Shyti 
32478bcac7bSAndi Shyti 	err = i2c_smbus_write_byte(sdata->client, cmd);
32578bcac7bSAndi Shyti 	if (err)
32678bcac7bSAndi Shyti 		return err;
32778bcac7bSAndi Shyti 
32878bcac7bSAndi Shyti 	if (!wait_for_completion_timeout(&sdata->cmd_done,
32978bcac7bSAndi Shyti 					 msecs_to_jiffies(1000)))
33078bcac7bSAndi Shyti 		return -ETIMEDOUT;
33178bcac7bSAndi Shyti 
33278bcac7bSAndi Shyti 	return 0;
33378bcac7bSAndi Shyti }
33478bcac7bSAndi Shyti 
stmfts_input_open(struct input_dev * dev)33578bcac7bSAndi Shyti static int stmfts_input_open(struct input_dev *dev)
33678bcac7bSAndi Shyti {
33778bcac7bSAndi Shyti 	struct stmfts_data *sdata = input_get_drvdata(dev);
33878bcac7bSAndi Shyti 	int err;
33978bcac7bSAndi Shyti 
3405f76955aSDmitry Torokhov 	err = pm_runtime_resume_and_get(&sdata->client->dev);
3415f76955aSDmitry Torokhov 	if (err)
3425f76955aSDmitry Torokhov 		return err;
34378bcac7bSAndi Shyti 
34478bcac7bSAndi Shyti 	err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_ON);
3455f76955aSDmitry Torokhov 	if (err) {
3465f76955aSDmitry Torokhov 		pm_runtime_put_sync(&sdata->client->dev);
3475f76955aSDmitry Torokhov 		return err;
3485f76955aSDmitry Torokhov 	}
34978bcac7bSAndi Shyti 
35078bcac7bSAndi Shyti 	mutex_lock(&sdata->mutex);
35178bcac7bSAndi Shyti 	sdata->running = true;
35278bcac7bSAndi Shyti 
35378bcac7bSAndi Shyti 	if (sdata->hover_enabled) {
35478bcac7bSAndi Shyti 		err = i2c_smbus_write_byte(sdata->client,
35578bcac7bSAndi Shyti 					   STMFTS_SS_HOVER_SENSE_ON);
35678bcac7bSAndi Shyti 		if (err)
35778bcac7bSAndi Shyti 			dev_warn(&sdata->client->dev,
35878bcac7bSAndi Shyti 				 "failed to enable hover\n");
35978bcac7bSAndi Shyti 	}
36078bcac7bSAndi Shyti 	mutex_unlock(&sdata->mutex);
36178bcac7bSAndi Shyti 
36278bcac7bSAndi Shyti 	if (sdata->use_key) {
36378bcac7bSAndi Shyti 		err = i2c_smbus_write_byte(sdata->client,
36478bcac7bSAndi Shyti 					   STMFTS_MS_KEY_SENSE_ON);
36578bcac7bSAndi Shyti 		if (err)
36678bcac7bSAndi Shyti 			/* I can still use only the touch screen */
36778bcac7bSAndi Shyti 			dev_warn(&sdata->client->dev,
36878bcac7bSAndi Shyti 				 "failed to enable touchkey\n");
36978bcac7bSAndi Shyti 	}
37078bcac7bSAndi Shyti 
3715f76955aSDmitry Torokhov 	return 0;
37278bcac7bSAndi Shyti }
37378bcac7bSAndi Shyti 
stmfts_input_close(struct input_dev * dev)37478bcac7bSAndi Shyti static void stmfts_input_close(struct input_dev *dev)
37578bcac7bSAndi Shyti {
37678bcac7bSAndi Shyti 	struct stmfts_data *sdata = input_get_drvdata(dev);
37778bcac7bSAndi Shyti 	int err;
37878bcac7bSAndi Shyti 
37978bcac7bSAndi Shyti 	err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_OFF);
38078bcac7bSAndi Shyti 	if (err)
38178bcac7bSAndi Shyti 		dev_warn(&sdata->client->dev,
38278bcac7bSAndi Shyti 			 "failed to disable touchscreen: %d\n", err);
38378bcac7bSAndi Shyti 
38478bcac7bSAndi Shyti 	mutex_lock(&sdata->mutex);
38578bcac7bSAndi Shyti 
38678bcac7bSAndi Shyti 	sdata->running = false;
38778bcac7bSAndi Shyti 
38878bcac7bSAndi Shyti 	if (sdata->hover_enabled) {
38978bcac7bSAndi Shyti 		err = i2c_smbus_write_byte(sdata->client,
39078bcac7bSAndi Shyti 					   STMFTS_SS_HOVER_SENSE_OFF);
39178bcac7bSAndi Shyti 		if (err)
39278bcac7bSAndi Shyti 			dev_warn(&sdata->client->dev,
39378bcac7bSAndi Shyti 				 "failed to disable hover: %d\n", err);
39478bcac7bSAndi Shyti 	}
39578bcac7bSAndi Shyti 	mutex_unlock(&sdata->mutex);
39678bcac7bSAndi Shyti 
39778bcac7bSAndi Shyti 	if (sdata->use_key) {
39878bcac7bSAndi Shyti 		err = i2c_smbus_write_byte(sdata->client,
39978bcac7bSAndi Shyti 					   STMFTS_MS_KEY_SENSE_OFF);
40078bcac7bSAndi Shyti 		if (err)
40178bcac7bSAndi Shyti 			dev_warn(&sdata->client->dev,
40278bcac7bSAndi Shyti 				 "failed to disable touchkey: %d\n", err);
40378bcac7bSAndi Shyti 	}
40478bcac7bSAndi Shyti 
40578bcac7bSAndi Shyti 	pm_runtime_put_sync(&sdata->client->dev);
40678bcac7bSAndi Shyti }
40778bcac7bSAndi Shyti 
stmfts_sysfs_chip_id(struct device * dev,struct device_attribute * attr,char * buf)40878bcac7bSAndi Shyti static ssize_t stmfts_sysfs_chip_id(struct device *dev,
40978bcac7bSAndi Shyti 				struct device_attribute *attr, char *buf)
41078bcac7bSAndi Shyti {
41178bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
41278bcac7bSAndi Shyti 
41378bcac7bSAndi Shyti 	return sprintf(buf, "%#x\n", sdata->chip_id);
41478bcac7bSAndi Shyti }
41578bcac7bSAndi Shyti 
stmfts_sysfs_chip_version(struct device * dev,struct device_attribute * attr,char * buf)41678bcac7bSAndi Shyti static ssize_t stmfts_sysfs_chip_version(struct device *dev,
41778bcac7bSAndi Shyti 				struct device_attribute *attr, char *buf)
41878bcac7bSAndi Shyti {
41978bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
42078bcac7bSAndi Shyti 
42178bcac7bSAndi Shyti 	return sprintf(buf, "%u\n", sdata->chip_ver);
42278bcac7bSAndi Shyti }
42378bcac7bSAndi Shyti 
stmfts_sysfs_fw_ver(struct device * dev,struct device_attribute * attr,char * buf)42478bcac7bSAndi Shyti static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
42578bcac7bSAndi Shyti 				struct device_attribute *attr, char *buf)
42678bcac7bSAndi Shyti {
42778bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
42878bcac7bSAndi Shyti 
42978bcac7bSAndi Shyti 	return sprintf(buf, "%u\n", sdata->fw_ver);
43078bcac7bSAndi Shyti }
43178bcac7bSAndi Shyti 
stmfts_sysfs_config_id(struct device * dev,struct device_attribute * attr,char * buf)43278bcac7bSAndi Shyti static ssize_t stmfts_sysfs_config_id(struct device *dev,
43378bcac7bSAndi Shyti 				struct device_attribute *attr, char *buf)
43478bcac7bSAndi Shyti {
43578bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
43678bcac7bSAndi Shyti 
43778bcac7bSAndi Shyti 	return sprintf(buf, "%#x\n", sdata->config_id);
43878bcac7bSAndi Shyti }
43978bcac7bSAndi Shyti 
stmfts_sysfs_config_version(struct device * dev,struct device_attribute * attr,char * buf)44078bcac7bSAndi Shyti static ssize_t stmfts_sysfs_config_version(struct device *dev,
44178bcac7bSAndi Shyti 				struct device_attribute *attr, char *buf)
44278bcac7bSAndi Shyti {
44378bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
44478bcac7bSAndi Shyti 
44578bcac7bSAndi Shyti 	return sprintf(buf, "%u\n", sdata->config_ver);
44678bcac7bSAndi Shyti }
44778bcac7bSAndi Shyti 
stmfts_sysfs_read_status(struct device * dev,struct device_attribute * attr,char * buf)44878bcac7bSAndi Shyti static ssize_t stmfts_sysfs_read_status(struct device *dev,
44978bcac7bSAndi Shyti 				struct device_attribute *attr, char *buf)
45078bcac7bSAndi Shyti {
45178bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
45278bcac7bSAndi Shyti 	u8 status[4];
45378bcac7bSAndi Shyti 	int err;
45478bcac7bSAndi Shyti 
45578bcac7bSAndi Shyti 	err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_STATUS,
45678bcac7bSAndi Shyti 					    sizeof(status), status);
45778bcac7bSAndi Shyti 	if (err)
45878bcac7bSAndi Shyti 		return err;
45978bcac7bSAndi Shyti 
46078bcac7bSAndi Shyti 	return sprintf(buf, "%#02x\n", status[0]);
46178bcac7bSAndi Shyti }
46278bcac7bSAndi Shyti 
stmfts_sysfs_hover_enable_read(struct device * dev,struct device_attribute * attr,char * buf)46378bcac7bSAndi Shyti static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
46478bcac7bSAndi Shyti 				struct device_attribute *attr, char *buf)
46578bcac7bSAndi Shyti {
46678bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
46778bcac7bSAndi Shyti 
46878bcac7bSAndi Shyti 	return sprintf(buf, "%u\n", sdata->hover_enabled);
46978bcac7bSAndi Shyti }
47078bcac7bSAndi Shyti 
stmfts_sysfs_hover_enable_write(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)47178bcac7bSAndi Shyti static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
47278bcac7bSAndi Shyti 				struct device_attribute *attr,
47378bcac7bSAndi Shyti 				const char *buf, size_t len)
47478bcac7bSAndi Shyti {
47578bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
47678bcac7bSAndi Shyti 	unsigned long value;
47778bcac7bSAndi Shyti 	int err = 0;
47878bcac7bSAndi Shyti 
47978bcac7bSAndi Shyti 	if (kstrtoul(buf, 0, &value))
48078bcac7bSAndi Shyti 		return -EINVAL;
48178bcac7bSAndi Shyti 
48278bcac7bSAndi Shyti 	mutex_lock(&sdata->mutex);
48378bcac7bSAndi Shyti 
484d04afe14SYueHaibing 	if (value && sdata->hover_enabled)
48578bcac7bSAndi Shyti 		goto out;
48678bcac7bSAndi Shyti 
48778bcac7bSAndi Shyti 	if (sdata->running)
48878bcac7bSAndi Shyti 		err = i2c_smbus_write_byte(sdata->client,
48978bcac7bSAndi Shyti 					   value ? STMFTS_SS_HOVER_SENSE_ON :
49078bcac7bSAndi Shyti 						   STMFTS_SS_HOVER_SENSE_OFF);
49178bcac7bSAndi Shyti 
49278bcac7bSAndi Shyti 	if (!err)
49378bcac7bSAndi Shyti 		sdata->hover_enabled = !!value;
49478bcac7bSAndi Shyti 
49578bcac7bSAndi Shyti out:
49678bcac7bSAndi Shyti 	mutex_unlock(&sdata->mutex);
49778bcac7bSAndi Shyti 
49878bcac7bSAndi Shyti 	return len;
49978bcac7bSAndi Shyti }
50078bcac7bSAndi Shyti 
50178bcac7bSAndi Shyti static DEVICE_ATTR(chip_id, 0444, stmfts_sysfs_chip_id, NULL);
50278bcac7bSAndi Shyti static DEVICE_ATTR(chip_version, 0444, stmfts_sysfs_chip_version, NULL);
50378bcac7bSAndi Shyti static DEVICE_ATTR(fw_ver, 0444, stmfts_sysfs_fw_ver, NULL);
50478bcac7bSAndi Shyti static DEVICE_ATTR(config_id, 0444, stmfts_sysfs_config_id, NULL);
50578bcac7bSAndi Shyti static DEVICE_ATTR(config_version, 0444, stmfts_sysfs_config_version, NULL);
50678bcac7bSAndi Shyti static DEVICE_ATTR(status, 0444, stmfts_sysfs_read_status, NULL);
50778bcac7bSAndi Shyti static DEVICE_ATTR(hover_enable, 0644, stmfts_sysfs_hover_enable_read,
50878bcac7bSAndi Shyti 					stmfts_sysfs_hover_enable_write);
50978bcac7bSAndi Shyti 
51078bcac7bSAndi Shyti static struct attribute *stmfts_sysfs_attrs[] = {
51178bcac7bSAndi Shyti 	&dev_attr_chip_id.attr,
51278bcac7bSAndi Shyti 	&dev_attr_chip_version.attr,
51378bcac7bSAndi Shyti 	&dev_attr_fw_ver.attr,
51478bcac7bSAndi Shyti 	&dev_attr_config_id.attr,
51578bcac7bSAndi Shyti 	&dev_attr_config_version.attr,
51678bcac7bSAndi Shyti 	&dev_attr_status.attr,
51778bcac7bSAndi Shyti 	&dev_attr_hover_enable.attr,
51878bcac7bSAndi Shyti 	NULL
51978bcac7bSAndi Shyti };
5206cc3ecfdSDmitry Torokhov ATTRIBUTE_GROUPS(stmfts_sysfs);
52178bcac7bSAndi Shyti 
stmfts_power_on(struct stmfts_data * sdata)52278bcac7bSAndi Shyti static int stmfts_power_on(struct stmfts_data *sdata)
52378bcac7bSAndi Shyti {
52478bcac7bSAndi Shyti 	int err;
52578bcac7bSAndi Shyti 	u8 reg[8];
52678bcac7bSAndi Shyti 
52778bcac7bSAndi Shyti 	err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
52878bcac7bSAndi Shyti 				    sdata->regulators);
52978bcac7bSAndi Shyti 	if (err)
53078bcac7bSAndi Shyti 		return err;
53178bcac7bSAndi Shyti 
53278bcac7bSAndi Shyti 	/*
53378bcac7bSAndi Shyti 	 * The datasheet does not specify the power on time, but considering
53478bcac7bSAndi Shyti 	 * that the reset time is < 10ms, I sleep 20ms to be sure
53578bcac7bSAndi Shyti 	 */
53678bcac7bSAndi Shyti 	msleep(20);
53778bcac7bSAndi Shyti 
53878bcac7bSAndi Shyti 	err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO,
53978bcac7bSAndi Shyti 					    sizeof(reg), reg);
54078bcac7bSAndi Shyti 	if (err < 0)
54178bcac7bSAndi Shyti 		return err;
54278bcac7bSAndi Shyti 	if (err != sizeof(reg))
54378bcac7bSAndi Shyti 		return -EIO;
54478bcac7bSAndi Shyti 
54578bcac7bSAndi Shyti 	sdata->chip_id = be16_to_cpup((__be16 *)&reg[6]);
54678bcac7bSAndi Shyti 	sdata->chip_ver = reg[0];
54778bcac7bSAndi Shyti 	sdata->fw_ver = be16_to_cpup((__be16 *)&reg[2]);
54878bcac7bSAndi Shyti 	sdata->config_id = reg[4];
54978bcac7bSAndi Shyti 	sdata->config_ver = reg[5];
55078bcac7bSAndi Shyti 
55178bcac7bSAndi Shyti 	enable_irq(sdata->client->irq);
55278bcac7bSAndi Shyti 
55378bcac7bSAndi Shyti 	msleep(50);
55478bcac7bSAndi Shyti 
55578bcac7bSAndi Shyti 	err = stmfts_command(sdata, STMFTS_SYSTEM_RESET);
55678bcac7bSAndi Shyti 	if (err)
55778bcac7bSAndi Shyti 		return err;
55878bcac7bSAndi Shyti 
55978bcac7bSAndi Shyti 	err = stmfts_command(sdata, STMFTS_SLEEP_OUT);
56078bcac7bSAndi Shyti 	if (err)
56178bcac7bSAndi Shyti 		return err;
56278bcac7bSAndi Shyti 
56378bcac7bSAndi Shyti 	/* optional tuning */
56478bcac7bSAndi Shyti 	err = stmfts_command(sdata, STMFTS_MS_CX_TUNING);
56578bcac7bSAndi Shyti 	if (err)
56678bcac7bSAndi Shyti 		dev_warn(&sdata->client->dev,
56778bcac7bSAndi Shyti 			 "failed to perform mutual auto tune: %d\n", err);
56878bcac7bSAndi Shyti 
56978bcac7bSAndi Shyti 	/* optional tuning */
57078bcac7bSAndi Shyti 	err = stmfts_command(sdata, STMFTS_SS_CX_TUNING);
57178bcac7bSAndi Shyti 	if (err)
57278bcac7bSAndi Shyti 		dev_warn(&sdata->client->dev,
57378bcac7bSAndi Shyti 			 "failed to perform self auto tune: %d\n", err);
57478bcac7bSAndi Shyti 
57578bcac7bSAndi Shyti 	err = stmfts_command(sdata, STMFTS_FULL_FORCE_CALIBRATION);
57678bcac7bSAndi Shyti 	if (err)
57778bcac7bSAndi Shyti 		return err;
57878bcac7bSAndi Shyti 
57978bcac7bSAndi Shyti 	/*
58078bcac7bSAndi Shyti 	 * At this point no one is using the touchscreen
58178bcac7bSAndi Shyti 	 * and I don't really care about the return value
58278bcac7bSAndi Shyti 	 */
58378bcac7bSAndi Shyti 	(void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
58478bcac7bSAndi Shyti 
58578bcac7bSAndi Shyti 	return 0;
58678bcac7bSAndi Shyti }
58778bcac7bSAndi Shyti 
stmfts_power_off(void * data)58878bcac7bSAndi Shyti static void stmfts_power_off(void *data)
58978bcac7bSAndi Shyti {
59078bcac7bSAndi Shyti 	struct stmfts_data *sdata = data;
59178bcac7bSAndi Shyti 
59278bcac7bSAndi Shyti 	disable_irq(sdata->client->irq);
59378bcac7bSAndi Shyti 	regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
59478bcac7bSAndi Shyti 						sdata->regulators);
59578bcac7bSAndi Shyti }
59678bcac7bSAndi Shyti 
59778bcac7bSAndi Shyti /* This function is void because I don't want to prevent using the touch key
59878bcac7bSAndi Shyti  * only because the LEDs don't get registered
59978bcac7bSAndi Shyti  */
stmfts_enable_led(struct stmfts_data * sdata)60078bcac7bSAndi Shyti static int stmfts_enable_led(struct stmfts_data *sdata)
60178bcac7bSAndi Shyti {
60278bcac7bSAndi Shyti 	int err;
60378bcac7bSAndi Shyti 
60478bcac7bSAndi Shyti 	/* get the regulator for powering the leds on */
60578bcac7bSAndi Shyti 	sdata->ledvdd = devm_regulator_get(&sdata->client->dev, "ledvdd");
60678bcac7bSAndi Shyti 	if (IS_ERR(sdata->ledvdd))
60778bcac7bSAndi Shyti 		return PTR_ERR(sdata->ledvdd);
60878bcac7bSAndi Shyti 
60978bcac7bSAndi Shyti 	sdata->led_cdev.name = STMFTS_DEV_NAME;
61078bcac7bSAndi Shyti 	sdata->led_cdev.max_brightness = LED_ON;
61178bcac7bSAndi Shyti 	sdata->led_cdev.brightness = LED_OFF;
612937c4e55SDmitry Torokhov 	sdata->led_cdev.brightness_set_blocking = stmfts_brightness_set;
61378bcac7bSAndi Shyti 	sdata->led_cdev.brightness_get = stmfts_brightness_get;
61478bcac7bSAndi Shyti 
61578bcac7bSAndi Shyti 	err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev);
61678bcac7bSAndi Shyti 	if (err) {
61778bcac7bSAndi Shyti 		devm_regulator_put(sdata->ledvdd);
61878bcac7bSAndi Shyti 		return err;
61978bcac7bSAndi Shyti 	}
62078bcac7bSAndi Shyti 
62178bcac7bSAndi Shyti 	return 0;
62278bcac7bSAndi Shyti }
62378bcac7bSAndi Shyti 
stmfts_probe(struct i2c_client * client)6243d2f8181SUwe Kleine-König static int stmfts_probe(struct i2c_client *client)
62578bcac7bSAndi Shyti {
62678bcac7bSAndi Shyti 	int err;
62778bcac7bSAndi Shyti 	struct stmfts_data *sdata;
62878bcac7bSAndi Shyti 
62978bcac7bSAndi Shyti 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
63078bcac7bSAndi Shyti 						I2C_FUNC_SMBUS_BYTE_DATA |
63178bcac7bSAndi Shyti 						I2C_FUNC_SMBUS_I2C_BLOCK))
63278bcac7bSAndi Shyti 		return -ENODEV;
63378bcac7bSAndi Shyti 
63478bcac7bSAndi Shyti 	sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
63578bcac7bSAndi Shyti 	if (!sdata)
63678bcac7bSAndi Shyti 		return -ENOMEM;
63778bcac7bSAndi Shyti 
63878bcac7bSAndi Shyti 	i2c_set_clientdata(client, sdata);
63978bcac7bSAndi Shyti 
64078bcac7bSAndi Shyti 	sdata->client = client;
64178bcac7bSAndi Shyti 	mutex_init(&sdata->mutex);
64278bcac7bSAndi Shyti 	init_completion(&sdata->cmd_done);
64378bcac7bSAndi Shyti 
64478bcac7bSAndi Shyti 	sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
64578bcac7bSAndi Shyti 	sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
64678bcac7bSAndi Shyti 	err = devm_regulator_bulk_get(&client->dev,
64778bcac7bSAndi Shyti 				      ARRAY_SIZE(sdata->regulators),
64878bcac7bSAndi Shyti 				      sdata->regulators);
64978bcac7bSAndi Shyti 	if (err)
65078bcac7bSAndi Shyti 		return err;
65178bcac7bSAndi Shyti 
65278bcac7bSAndi Shyti 	sdata->input = devm_input_allocate_device(&client->dev);
65378bcac7bSAndi Shyti 	if (!sdata->input)
65478bcac7bSAndi Shyti 		return -ENOMEM;
65578bcac7bSAndi Shyti 
65678bcac7bSAndi Shyti 	sdata->input->name = STMFTS_DEV_NAME;
65778bcac7bSAndi Shyti 	sdata->input->id.bustype = BUS_I2C;
65878bcac7bSAndi Shyti 	sdata->input->open = stmfts_input_open;
65978bcac7bSAndi Shyti 	sdata->input->close = stmfts_input_close;
66078bcac7bSAndi Shyti 
661c9bfb2f0SChanwoo Choi 	input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_X);
662c9bfb2f0SChanwoo Choi 	input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_Y);
66378bcac7bSAndi Shyti 	touchscreen_parse_properties(sdata->input, true, &sdata->prop);
66478bcac7bSAndi Shyti 
66578bcac7bSAndi Shyti 	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
66678bcac7bSAndi Shyti 	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
66778bcac7bSAndi Shyti 	input_set_abs_params(sdata->input, ABS_MT_ORIENTATION, 0, 255, 0, 0);
66878bcac7bSAndi Shyti 	input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
66978bcac7bSAndi Shyti 	input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0);
67078bcac7bSAndi Shyti 
67178bcac7bSAndi Shyti 	sdata->use_key = device_property_read_bool(&client->dev,
67278bcac7bSAndi Shyti 						   "touch-key-connected");
67378bcac7bSAndi Shyti 	if (sdata->use_key) {
67478bcac7bSAndi Shyti 		input_set_capability(sdata->input, EV_KEY, KEY_MENU);
67578bcac7bSAndi Shyti 		input_set_capability(sdata->input, EV_KEY, KEY_BACK);
67678bcac7bSAndi Shyti 	}
67778bcac7bSAndi Shyti 
67878bcac7bSAndi Shyti 	err = input_mt_init_slots(sdata->input,
67978bcac7bSAndi Shyti 				  STMFTS_MAX_FINGERS, INPUT_MT_DIRECT);
68078bcac7bSAndi Shyti 	if (err)
68178bcac7bSAndi Shyti 		return err;
68278bcac7bSAndi Shyti 
68378bcac7bSAndi Shyti 	input_set_drvdata(sdata->input, sdata);
68478bcac7bSAndi Shyti 
685cba04cdfSAndi Shyti 	/*
686cba04cdfSAndi Shyti 	 * stmfts_power_on expects interrupt to be disabled, but
687cba04cdfSAndi Shyti 	 * at this point the device is still off and I do not trust
688cba04cdfSAndi Shyti 	 * the status of the irq line that can generate some spurious
689cba04cdfSAndi Shyti 	 * interrupts. To be on the safe side it's better to not enable
690cba04cdfSAndi Shyti 	 * the interrupts during their request.
691cba04cdfSAndi Shyti 	 */
69278bcac7bSAndi Shyti 	err = devm_request_threaded_irq(&client->dev, client->irq,
69378bcac7bSAndi Shyti 					NULL, stmfts_irq_handler,
694bcd9730aSBarry Song 					IRQF_ONESHOT | IRQF_NO_AUTOEN,
69578bcac7bSAndi Shyti 					"stmfts_irq", sdata);
69678bcac7bSAndi Shyti 	if (err)
69778bcac7bSAndi Shyti 		return err;
69878bcac7bSAndi Shyti 
69978bcac7bSAndi Shyti 	dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n");
70078bcac7bSAndi Shyti 
70178bcac7bSAndi Shyti 	err = stmfts_power_on(sdata);
70278bcac7bSAndi Shyti 	if (err)
70378bcac7bSAndi Shyti 		return err;
70478bcac7bSAndi Shyti 
70578bcac7bSAndi Shyti 	err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata);
70678bcac7bSAndi Shyti 	if (err)
70778bcac7bSAndi Shyti 		return err;
70878bcac7bSAndi Shyti 
70978bcac7bSAndi Shyti 	err = input_register_device(sdata->input);
71078bcac7bSAndi Shyti 	if (err)
71178bcac7bSAndi Shyti 		return err;
71278bcac7bSAndi Shyti 
71378bcac7bSAndi Shyti 	if (sdata->use_key) {
71478bcac7bSAndi Shyti 		err = stmfts_enable_led(sdata);
71578bcac7bSAndi Shyti 		if (err) {
71678bcac7bSAndi Shyti 			/*
71778bcac7bSAndi Shyti 			 * Even if the LEDs have failed to be initialized and
71878bcac7bSAndi Shyti 			 * used in the driver, I can still use the device even
71978bcac7bSAndi Shyti 			 * without LEDs. The ledvdd regulator pointer will be
72078bcac7bSAndi Shyti 			 * used as a flag.
72178bcac7bSAndi Shyti 			 */
72278bcac7bSAndi Shyti 			dev_warn(&client->dev, "unable to use touchkey leds\n");
72378bcac7bSAndi Shyti 			sdata->ledvdd = NULL;
72478bcac7bSAndi Shyti 		}
72578bcac7bSAndi Shyti 	}
72678bcac7bSAndi Shyti 
72778bcac7bSAndi Shyti 	pm_runtime_enable(&client->dev);
7281d960003SMarek Szyprowski 	device_enable_async_suspend(&client->dev);
72978bcac7bSAndi Shyti 
73078bcac7bSAndi Shyti 	return 0;
73178bcac7bSAndi Shyti }
73278bcac7bSAndi Shyti 
stmfts_remove(struct i2c_client * client)733ed5c2f5fSUwe Kleine-König static void stmfts_remove(struct i2c_client *client)
73478bcac7bSAndi Shyti {
73578bcac7bSAndi Shyti 	pm_runtime_disable(&client->dev);
73678bcac7bSAndi Shyti }
73778bcac7bSAndi Shyti 
stmfts_runtime_suspend(struct device * dev)73890208b31SJonathan Cameron static int stmfts_runtime_suspend(struct device *dev)
73978bcac7bSAndi Shyti {
74078bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
74178bcac7bSAndi Shyti 	int ret;
74278bcac7bSAndi Shyti 
74378bcac7bSAndi Shyti 	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
74478bcac7bSAndi Shyti 	if (ret)
74578bcac7bSAndi Shyti 		dev_warn(dev, "failed to suspend device: %d\n", ret);
74678bcac7bSAndi Shyti 
74778bcac7bSAndi Shyti 	return ret;
74878bcac7bSAndi Shyti }
74978bcac7bSAndi Shyti 
stmfts_runtime_resume(struct device * dev)75090208b31SJonathan Cameron static int stmfts_runtime_resume(struct device *dev)
75178bcac7bSAndi Shyti {
75278bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
75378bcac7bSAndi Shyti 	int ret;
75478bcac7bSAndi Shyti 
75578bcac7bSAndi Shyti 	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
75678bcac7bSAndi Shyti 	if (ret)
75778bcac7bSAndi Shyti 		dev_err(dev, "failed to resume device: %d\n", ret);
75878bcac7bSAndi Shyti 
75978bcac7bSAndi Shyti 	return ret;
76078bcac7bSAndi Shyti }
76178bcac7bSAndi Shyti 
stmfts_suspend(struct device * dev)76290208b31SJonathan Cameron static int stmfts_suspend(struct device *dev)
76378bcac7bSAndi Shyti {
76478bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
76578bcac7bSAndi Shyti 
76678bcac7bSAndi Shyti 	stmfts_power_off(sdata);
76778bcac7bSAndi Shyti 
76878bcac7bSAndi Shyti 	return 0;
76978bcac7bSAndi Shyti }
77078bcac7bSAndi Shyti 
stmfts_resume(struct device * dev)77190208b31SJonathan Cameron static int stmfts_resume(struct device *dev)
77278bcac7bSAndi Shyti {
77378bcac7bSAndi Shyti 	struct stmfts_data *sdata = dev_get_drvdata(dev);
77478bcac7bSAndi Shyti 
77578bcac7bSAndi Shyti 	return stmfts_power_on(sdata);
77678bcac7bSAndi Shyti }
77778bcac7bSAndi Shyti 
77878bcac7bSAndi Shyti static const struct dev_pm_ops stmfts_pm_ops = {
77990208b31SJonathan Cameron 	SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume)
78090208b31SJonathan Cameron 	RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL)
78178bcac7bSAndi Shyti };
78278bcac7bSAndi Shyti 
78378bcac7bSAndi Shyti #ifdef CONFIG_OF
78478bcac7bSAndi Shyti static const struct of_device_id stmfts_of_match[] = {
78578bcac7bSAndi Shyti 	{ .compatible = "st,stmfts", },
78678bcac7bSAndi Shyti 	{ },
78778bcac7bSAndi Shyti };
78878bcac7bSAndi Shyti MODULE_DEVICE_TABLE(of, stmfts_of_match);
78978bcac7bSAndi Shyti #endif
79078bcac7bSAndi Shyti 
79178bcac7bSAndi Shyti static const struct i2c_device_id stmfts_id[] = {
792*5852f2afSUwe Kleine-König 	{ "stmfts" },
793*5852f2afSUwe Kleine-König 	{ }
79478bcac7bSAndi Shyti };
79578bcac7bSAndi Shyti MODULE_DEVICE_TABLE(i2c, stmfts_id);
79678bcac7bSAndi Shyti 
79778bcac7bSAndi Shyti static struct i2c_driver stmfts_driver = {
79878bcac7bSAndi Shyti 	.driver = {
79978bcac7bSAndi Shyti 		.name = STMFTS_DEV_NAME,
8006cc3ecfdSDmitry Torokhov 		.dev_groups = stmfts_sysfs_groups,
80178bcac7bSAndi Shyti 		.of_match_table = of_match_ptr(stmfts_of_match),
80290208b31SJonathan Cameron 		.pm = pm_ptr(&stmfts_pm_ops),
8031d960003SMarek Szyprowski 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
80478bcac7bSAndi Shyti 	},
805d8bde56dSUwe Kleine-König 	.probe = stmfts_probe,
80678bcac7bSAndi Shyti 	.remove = stmfts_remove,
80778bcac7bSAndi Shyti 	.id_table = stmfts_id,
80878bcac7bSAndi Shyti };
80978bcac7bSAndi Shyti 
81078bcac7bSAndi Shyti module_i2c_driver(stmfts_driver);
81178bcac7bSAndi Shyti 
81278bcac7bSAndi Shyti MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
81378bcac7bSAndi Shyti MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
81478bcac7bSAndi Shyti MODULE_LICENSE("GPL v2");
815