18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// STMicroelectronics FTS Touchscreen device driver
38c2ecf20Sopenharmony_ci//
48c2ecf20Sopenharmony_ci// Copyright (c) 2017 Samsung Electronics Co., Ltd.
58c2ecf20Sopenharmony_ci// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/delay.h>
88c2ecf20Sopenharmony_ci#include <linux/i2c.h>
98c2ecf20Sopenharmony_ci#include <linux/input/mt.h>
108c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/irq.h>
138c2ecf20Sopenharmony_ci#include <linux/leds.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
168c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* I2C commands */
198c2ecf20Sopenharmony_ci#define STMFTS_READ_INFO			0x80
208c2ecf20Sopenharmony_ci#define STMFTS_READ_STATUS			0x84
218c2ecf20Sopenharmony_ci#define STMFTS_READ_ONE_EVENT			0x85
228c2ecf20Sopenharmony_ci#define STMFTS_READ_ALL_EVENT			0x86
238c2ecf20Sopenharmony_ci#define STMFTS_LATEST_EVENT			0x87
248c2ecf20Sopenharmony_ci#define STMFTS_SLEEP_IN				0x90
258c2ecf20Sopenharmony_ci#define STMFTS_SLEEP_OUT			0x91
268c2ecf20Sopenharmony_ci#define STMFTS_MS_MT_SENSE_OFF			0x92
278c2ecf20Sopenharmony_ci#define STMFTS_MS_MT_SENSE_ON			0x93
288c2ecf20Sopenharmony_ci#define STMFTS_SS_HOVER_SENSE_OFF		0x94
298c2ecf20Sopenharmony_ci#define STMFTS_SS_HOVER_SENSE_ON		0x95
308c2ecf20Sopenharmony_ci#define STMFTS_MS_KEY_SENSE_OFF			0x9a
318c2ecf20Sopenharmony_ci#define STMFTS_MS_KEY_SENSE_ON			0x9b
328c2ecf20Sopenharmony_ci#define STMFTS_SYSTEM_RESET			0xa0
338c2ecf20Sopenharmony_ci#define STMFTS_CLEAR_EVENT_STACK		0xa1
348c2ecf20Sopenharmony_ci#define STMFTS_FULL_FORCE_CALIBRATION		0xa2
358c2ecf20Sopenharmony_ci#define STMFTS_MS_CX_TUNING			0xa3
368c2ecf20Sopenharmony_ci#define STMFTS_SS_CX_TUNING			0xa4
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* events */
398c2ecf20Sopenharmony_ci#define STMFTS_EV_NO_EVENT			0x00
408c2ecf20Sopenharmony_ci#define STMFTS_EV_MULTI_TOUCH_DETECTED		0x02
418c2ecf20Sopenharmony_ci#define STMFTS_EV_MULTI_TOUCH_ENTER		0x03
428c2ecf20Sopenharmony_ci#define STMFTS_EV_MULTI_TOUCH_LEAVE		0x04
438c2ecf20Sopenharmony_ci#define STMFTS_EV_MULTI_TOUCH_MOTION		0x05
448c2ecf20Sopenharmony_ci#define STMFTS_EV_HOVER_ENTER			0x07
458c2ecf20Sopenharmony_ci#define STMFTS_EV_HOVER_LEAVE			0x08
468c2ecf20Sopenharmony_ci#define STMFTS_EV_HOVER_MOTION			0x09
478c2ecf20Sopenharmony_ci#define STMFTS_EV_KEY_STATUS			0x0e
488c2ecf20Sopenharmony_ci#define STMFTS_EV_ERROR				0x0f
498c2ecf20Sopenharmony_ci#define STMFTS_EV_CONTROLLER_READY		0x10
508c2ecf20Sopenharmony_ci#define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY	0x11
518c2ecf20Sopenharmony_ci#define STMFTS_EV_STATUS			0x16
528c2ecf20Sopenharmony_ci#define STMFTS_EV_DEBUG				0xdb
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* multi touch related event masks */
558c2ecf20Sopenharmony_ci#define STMFTS_MASK_EVENT_ID			0x0f
568c2ecf20Sopenharmony_ci#define STMFTS_MASK_TOUCH_ID			0xf0
578c2ecf20Sopenharmony_ci#define STMFTS_MASK_LEFT_EVENT			0x0f
588c2ecf20Sopenharmony_ci#define STMFTS_MASK_X_MSB			0x0f
598c2ecf20Sopenharmony_ci#define STMFTS_MASK_Y_LSB			0xf0
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* key related event masks */
628c2ecf20Sopenharmony_ci#define STMFTS_MASK_KEY_NO_TOUCH		0x00
638c2ecf20Sopenharmony_ci#define STMFTS_MASK_KEY_MENU			0x01
648c2ecf20Sopenharmony_ci#define STMFTS_MASK_KEY_BACK			0x02
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define STMFTS_EVENT_SIZE	8
678c2ecf20Sopenharmony_ci#define STMFTS_STACK_DEPTH	32
688c2ecf20Sopenharmony_ci#define STMFTS_DATA_MAX_SIZE	(STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH)
698c2ecf20Sopenharmony_ci#define STMFTS_MAX_FINGERS	10
708c2ecf20Sopenharmony_ci#define STMFTS_DEV_NAME		"stmfts"
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cienum stmfts_regulators {
738c2ecf20Sopenharmony_ci	STMFTS_REGULATOR_VDD,
748c2ecf20Sopenharmony_ci	STMFTS_REGULATOR_AVDD,
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct stmfts_data {
788c2ecf20Sopenharmony_ci	struct i2c_client *client;
798c2ecf20Sopenharmony_ci	struct input_dev *input;
808c2ecf20Sopenharmony_ci	struct led_classdev led_cdev;
818c2ecf20Sopenharmony_ci	struct mutex mutex;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	struct touchscreen_properties prop;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	struct regulator_bulk_data regulators[2];
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	/*
888c2ecf20Sopenharmony_ci	 * Presence of ledvdd will be used also to check
898c2ecf20Sopenharmony_ci	 * whether the LED is supported.
908c2ecf20Sopenharmony_ci	 */
918c2ecf20Sopenharmony_ci	struct regulator *ledvdd;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	u16 chip_id;
948c2ecf20Sopenharmony_ci	u8 chip_ver;
958c2ecf20Sopenharmony_ci	u16 fw_ver;
968c2ecf20Sopenharmony_ci	u8 config_id;
978c2ecf20Sopenharmony_ci	u8 config_ver;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	u8 data[STMFTS_DATA_MAX_SIZE];
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	struct completion cmd_done;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	bool use_key;
1048c2ecf20Sopenharmony_ci	bool led_status;
1058c2ecf20Sopenharmony_ci	bool hover_enabled;
1068c2ecf20Sopenharmony_ci	bool running;
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic int stmfts_brightness_set(struct led_classdev *led_cdev,
1108c2ecf20Sopenharmony_ci					enum led_brightness value)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = container_of(led_cdev,
1138c2ecf20Sopenharmony_ci					struct stmfts_data, led_cdev);
1148c2ecf20Sopenharmony_ci	int err;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (value != sdata->led_status && sdata->ledvdd) {
1178c2ecf20Sopenharmony_ci		if (!value) {
1188c2ecf20Sopenharmony_ci			regulator_disable(sdata->ledvdd);
1198c2ecf20Sopenharmony_ci		} else {
1208c2ecf20Sopenharmony_ci			err = regulator_enable(sdata->ledvdd);
1218c2ecf20Sopenharmony_ci			if (err) {
1228c2ecf20Sopenharmony_ci				dev_warn(&sdata->client->dev,
1238c2ecf20Sopenharmony_ci					 "failed to disable ledvdd regulator: %d\n",
1248c2ecf20Sopenharmony_ci					 err);
1258c2ecf20Sopenharmony_ci				return err;
1268c2ecf20Sopenharmony_ci			}
1278c2ecf20Sopenharmony_ci		}
1288c2ecf20Sopenharmony_ci		sdata->led_status = value;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return 0;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = container_of(led_cdev,
1378c2ecf20Sopenharmony_ci						struct stmfts_data, led_cdev);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return !!regulator_is_enabled(sdata->ledvdd);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/*
1438c2ecf20Sopenharmony_ci * We can't simply use i2c_smbus_read_i2c_block_data because we
1448c2ecf20Sopenharmony_ci * need to read more than 255 bytes (
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_cistatic int stmfts_read_events(struct stmfts_data *sdata)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	u8 cmd = STMFTS_READ_ALL_EVENT;
1498c2ecf20Sopenharmony_ci	struct i2c_msg msgs[2] = {
1508c2ecf20Sopenharmony_ci		{
1518c2ecf20Sopenharmony_ci			.addr	= sdata->client->addr,
1528c2ecf20Sopenharmony_ci			.len	= 1,
1538c2ecf20Sopenharmony_ci			.buf	= &cmd,
1548c2ecf20Sopenharmony_ci		},
1558c2ecf20Sopenharmony_ci		{
1568c2ecf20Sopenharmony_ci			.addr	= sdata->client->addr,
1578c2ecf20Sopenharmony_ci			.flags	= I2C_M_RD,
1588c2ecf20Sopenharmony_ci			.len	= STMFTS_DATA_MAX_SIZE,
1598c2ecf20Sopenharmony_ci			.buf	= sdata->data,
1608c2ecf20Sopenharmony_ci		},
1618c2ecf20Sopenharmony_ci	};
1628c2ecf20Sopenharmony_ci	int ret;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs));
1658c2ecf20Sopenharmony_ci	if (ret < 0)
1668c2ecf20Sopenharmony_ci		return ret;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	return ret == ARRAY_SIZE(msgs) ? 0 : -EIO;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void stmfts_report_contact_event(struct stmfts_data *sdata,
1728c2ecf20Sopenharmony_ci					const u8 event[])
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
1758c2ecf20Sopenharmony_ci	u16 x = event[1] | ((event[2] & STMFTS_MASK_X_MSB) << 8);
1768c2ecf20Sopenharmony_ci	u16 y = (event[2] >> 4) | (event[3] << 4);
1778c2ecf20Sopenharmony_ci	u8 maj = event[4];
1788c2ecf20Sopenharmony_ci	u8 min = event[5];
1798c2ecf20Sopenharmony_ci	u8 orientation = event[6];
1808c2ecf20Sopenharmony_ci	u8 area = event[7];
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	input_mt_slot(sdata->input, slot_id);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true);
1858c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_MT_POSITION_X, x);
1868c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_MT_POSITION_Y, y);
1878c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, maj);
1888c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, min);
1898c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_MT_PRESSURE, area);
1908c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_MT_ORIENTATION, orientation);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	input_sync(sdata->input);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void stmfts_report_contact_release(struct stmfts_data *sdata,
1968c2ecf20Sopenharmony_ci					  const u8 event[])
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	input_mt_slot(sdata->input, slot_id);
2018c2ecf20Sopenharmony_ci	input_mt_report_slot_inactive(sdata->input);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	input_sync(sdata->input);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void stmfts_report_hover_event(struct stmfts_data *sdata,
2078c2ecf20Sopenharmony_ci				      const u8 event[])
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	u16 x = (event[2] << 4) | (event[4] >> 4);
2108c2ecf20Sopenharmony_ci	u16 y = (event[3] << 4) | (event[4] & STMFTS_MASK_Y_LSB);
2118c2ecf20Sopenharmony_ci	u8 z = event[5];
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_X, x);
2148c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_Y, y);
2158c2ecf20Sopenharmony_ci	input_report_abs(sdata->input, ABS_DISTANCE, z);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	input_sync(sdata->input);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void stmfts_report_key_event(struct stmfts_data *sdata, const u8 event[])
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	switch (event[2]) {
2238c2ecf20Sopenharmony_ci	case 0:
2248c2ecf20Sopenharmony_ci		input_report_key(sdata->input, KEY_BACK, 0);
2258c2ecf20Sopenharmony_ci		input_report_key(sdata->input, KEY_MENU, 0);
2268c2ecf20Sopenharmony_ci		break;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	case STMFTS_MASK_KEY_BACK:
2298c2ecf20Sopenharmony_ci		input_report_key(sdata->input, KEY_BACK, 1);
2308c2ecf20Sopenharmony_ci		break;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	case STMFTS_MASK_KEY_MENU:
2338c2ecf20Sopenharmony_ci		input_report_key(sdata->input, KEY_MENU, 1);
2348c2ecf20Sopenharmony_ci		break;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	default:
2378c2ecf20Sopenharmony_ci		dev_warn(&sdata->client->dev,
2388c2ecf20Sopenharmony_ci			 "unknown key event: %#02x\n", event[2]);
2398c2ecf20Sopenharmony_ci		break;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	input_sync(sdata->input);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic void stmfts_parse_events(struct stmfts_data *sdata)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	int i;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	for (i = 0; i < STMFTS_STACK_DEPTH; i++) {
2508c2ecf20Sopenharmony_ci		u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE];
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		switch (event[0]) {
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		case STMFTS_EV_CONTROLLER_READY:
2558c2ecf20Sopenharmony_ci		case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
2568c2ecf20Sopenharmony_ci		case STMFTS_EV_STATUS:
2578c2ecf20Sopenharmony_ci			complete(&sdata->cmd_done);
2588c2ecf20Sopenharmony_ci			fallthrough;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		case STMFTS_EV_NO_EVENT:
2618c2ecf20Sopenharmony_ci		case STMFTS_EV_DEBUG:
2628c2ecf20Sopenharmony_ci			return;
2638c2ecf20Sopenharmony_ci		}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		switch (event[0] & STMFTS_MASK_EVENT_ID) {
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		case STMFTS_EV_MULTI_TOUCH_ENTER:
2688c2ecf20Sopenharmony_ci		case STMFTS_EV_MULTI_TOUCH_MOTION:
2698c2ecf20Sopenharmony_ci			stmfts_report_contact_event(sdata, event);
2708c2ecf20Sopenharmony_ci			break;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		case STMFTS_EV_MULTI_TOUCH_LEAVE:
2738c2ecf20Sopenharmony_ci			stmfts_report_contact_release(sdata, event);
2748c2ecf20Sopenharmony_ci			break;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		case STMFTS_EV_HOVER_ENTER:
2778c2ecf20Sopenharmony_ci		case STMFTS_EV_HOVER_LEAVE:
2788c2ecf20Sopenharmony_ci		case STMFTS_EV_HOVER_MOTION:
2798c2ecf20Sopenharmony_ci			stmfts_report_hover_event(sdata, event);
2808c2ecf20Sopenharmony_ci			break;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		case STMFTS_EV_KEY_STATUS:
2838c2ecf20Sopenharmony_ci			stmfts_report_key_event(sdata, event);
2848c2ecf20Sopenharmony_ci			break;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		case STMFTS_EV_ERROR:
2878c2ecf20Sopenharmony_ci			dev_warn(&sdata->client->dev,
2888c2ecf20Sopenharmony_ci					"error code: 0x%x%x%x%x%x%x",
2898c2ecf20Sopenharmony_ci					event[6], event[5], event[4],
2908c2ecf20Sopenharmony_ci					event[3], event[2], event[1]);
2918c2ecf20Sopenharmony_ci			break;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci		default:
2948c2ecf20Sopenharmony_ci			dev_err(&sdata->client->dev,
2958c2ecf20Sopenharmony_ci				"unknown event %#02x\n", event[0]);
2968c2ecf20Sopenharmony_ci		}
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic irqreturn_t stmfts_irq_handler(int irq, void *dev)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev;
3038c2ecf20Sopenharmony_ci	int err;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	mutex_lock(&sdata->mutex);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	err = stmfts_read_events(sdata);
3088c2ecf20Sopenharmony_ci	if (unlikely(err))
3098c2ecf20Sopenharmony_ci		dev_err(&sdata->client->dev,
3108c2ecf20Sopenharmony_ci			"failed to read events: %d\n", err);
3118c2ecf20Sopenharmony_ci	else
3128c2ecf20Sopenharmony_ci		stmfts_parse_events(sdata);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->mutex);
3158c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic int stmfts_command(struct stmfts_data *sdata, const u8 cmd)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	int err;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	reinit_completion(&sdata->cmd_done);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte(sdata->client, cmd);
3258c2ecf20Sopenharmony_ci	if (err)
3268c2ecf20Sopenharmony_ci		return err;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&sdata->cmd_done,
3298c2ecf20Sopenharmony_ci					 msecs_to_jiffies(1000)))
3308c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return 0;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int stmfts_input_open(struct input_dev *dev)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = input_get_drvdata(dev);
3388c2ecf20Sopenharmony_ci	int err;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	err = pm_runtime_resume_and_get(&sdata->client->dev);
3418c2ecf20Sopenharmony_ci	if (err)
3428c2ecf20Sopenharmony_ci		return err;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_ON);
3458c2ecf20Sopenharmony_ci	if (err) {
3468c2ecf20Sopenharmony_ci		pm_runtime_put_sync(&sdata->client->dev);
3478c2ecf20Sopenharmony_ci		return err;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	mutex_lock(&sdata->mutex);
3518c2ecf20Sopenharmony_ci	sdata->running = true;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (sdata->hover_enabled) {
3548c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte(sdata->client,
3558c2ecf20Sopenharmony_ci					   STMFTS_SS_HOVER_SENSE_ON);
3568c2ecf20Sopenharmony_ci		if (err)
3578c2ecf20Sopenharmony_ci			dev_warn(&sdata->client->dev,
3588c2ecf20Sopenharmony_ci				 "failed to enable hover\n");
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->mutex);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (sdata->use_key) {
3638c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte(sdata->client,
3648c2ecf20Sopenharmony_ci					   STMFTS_MS_KEY_SENSE_ON);
3658c2ecf20Sopenharmony_ci		if (err)
3668c2ecf20Sopenharmony_ci			/* I can still use only the touch screen */
3678c2ecf20Sopenharmony_ci			dev_warn(&sdata->client->dev,
3688c2ecf20Sopenharmony_ci				 "failed to enable touchkey\n");
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	return 0;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic void stmfts_input_close(struct input_dev *dev)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = input_get_drvdata(dev);
3778c2ecf20Sopenharmony_ci	int err;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_OFF);
3808c2ecf20Sopenharmony_ci	if (err)
3818c2ecf20Sopenharmony_ci		dev_warn(&sdata->client->dev,
3828c2ecf20Sopenharmony_ci			 "failed to disable touchscreen: %d\n", err);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	mutex_lock(&sdata->mutex);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	sdata->running = false;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (sdata->hover_enabled) {
3898c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte(sdata->client,
3908c2ecf20Sopenharmony_ci					   STMFTS_SS_HOVER_SENSE_OFF);
3918c2ecf20Sopenharmony_ci		if (err)
3928c2ecf20Sopenharmony_ci			dev_warn(&sdata->client->dev,
3938c2ecf20Sopenharmony_ci				 "failed to disable hover: %d\n", err);
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->mutex);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (sdata->use_key) {
3988c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte(sdata->client,
3998c2ecf20Sopenharmony_ci					   STMFTS_MS_KEY_SENSE_OFF);
4008c2ecf20Sopenharmony_ci		if (err)
4018c2ecf20Sopenharmony_ci			dev_warn(&sdata->client->dev,
4028c2ecf20Sopenharmony_ci				 "failed to disable touchkey: %d\n", err);
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&sdata->client->dev);
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_chip_id(struct device *dev,
4098c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return sprintf(buf, "%#x\n", sdata->chip_id);
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_chip_version(struct device *dev,
4178c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", sdata->chip_ver);
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_fw_ver(struct device *dev,
4258c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", sdata->fw_ver);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_config_id(struct device *dev,
4338c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return sprintf(buf, "%#x\n", sdata->config_id);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_config_version(struct device *dev,
4418c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", sdata->config_ver);
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_read_status(struct device *dev,
4498c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4528c2ecf20Sopenharmony_ci	u8 status[4];
4538c2ecf20Sopenharmony_ci	int err;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_STATUS,
4568c2ecf20Sopenharmony_ci					    sizeof(status), status);
4578c2ecf20Sopenharmony_ci	if (err)
4588c2ecf20Sopenharmony_ci		return err;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	return sprintf(buf, "%#02x\n", status[0]);
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
4648c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", sdata->hover_enabled);
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
4728c2ecf20Sopenharmony_ci				struct device_attribute *attr,
4738c2ecf20Sopenharmony_ci				const char *buf, size_t len)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
4768c2ecf20Sopenharmony_ci	unsigned long value;
4778c2ecf20Sopenharmony_ci	int err = 0;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (kstrtoul(buf, 0, &value))
4808c2ecf20Sopenharmony_ci		return -EINVAL;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	mutex_lock(&sdata->mutex);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (value && sdata->hover_enabled)
4858c2ecf20Sopenharmony_ci		goto out;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (sdata->running)
4888c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte(sdata->client,
4898c2ecf20Sopenharmony_ci					   value ? STMFTS_SS_HOVER_SENSE_ON :
4908c2ecf20Sopenharmony_ci						   STMFTS_SS_HOVER_SENSE_OFF);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (!err)
4938c2ecf20Sopenharmony_ci		sdata->hover_enabled = !!value;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ciout:
4968c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->mutex);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return len;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic DEVICE_ATTR(chip_id, 0444, stmfts_sysfs_chip_id, NULL);
5028c2ecf20Sopenharmony_cistatic DEVICE_ATTR(chip_version, 0444, stmfts_sysfs_chip_version, NULL);
5038c2ecf20Sopenharmony_cistatic DEVICE_ATTR(fw_ver, 0444, stmfts_sysfs_fw_ver, NULL);
5048c2ecf20Sopenharmony_cistatic DEVICE_ATTR(config_id, 0444, stmfts_sysfs_config_id, NULL);
5058c2ecf20Sopenharmony_cistatic DEVICE_ATTR(config_version, 0444, stmfts_sysfs_config_version, NULL);
5068c2ecf20Sopenharmony_cistatic DEVICE_ATTR(status, 0444, stmfts_sysfs_read_status, NULL);
5078c2ecf20Sopenharmony_cistatic DEVICE_ATTR(hover_enable, 0644, stmfts_sysfs_hover_enable_read,
5088c2ecf20Sopenharmony_ci					stmfts_sysfs_hover_enable_write);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic struct attribute *stmfts_sysfs_attrs[] = {
5118c2ecf20Sopenharmony_ci	&dev_attr_chip_id.attr,
5128c2ecf20Sopenharmony_ci	&dev_attr_chip_version.attr,
5138c2ecf20Sopenharmony_ci	&dev_attr_fw_ver.attr,
5148c2ecf20Sopenharmony_ci	&dev_attr_config_id.attr,
5158c2ecf20Sopenharmony_ci	&dev_attr_config_version.attr,
5168c2ecf20Sopenharmony_ci	&dev_attr_status.attr,
5178c2ecf20Sopenharmony_ci	&dev_attr_hover_enable.attr,
5188c2ecf20Sopenharmony_ci	NULL
5198c2ecf20Sopenharmony_ci};
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic struct attribute_group stmfts_attribute_group = {
5228c2ecf20Sopenharmony_ci	.attrs = stmfts_sysfs_attrs
5238c2ecf20Sopenharmony_ci};
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic int stmfts_power_on(struct stmfts_data *sdata)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	int err;
5288c2ecf20Sopenharmony_ci	u8 reg[8];
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
5318c2ecf20Sopenharmony_ci				    sdata->regulators);
5328c2ecf20Sopenharmony_ci	if (err)
5338c2ecf20Sopenharmony_ci		return err;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/*
5368c2ecf20Sopenharmony_ci	 * The datasheet does not specify the power on time, but considering
5378c2ecf20Sopenharmony_ci	 * that the reset time is < 10ms, I sleep 20ms to be sure
5388c2ecf20Sopenharmony_ci	 */
5398c2ecf20Sopenharmony_ci	msleep(20);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO,
5428c2ecf20Sopenharmony_ci					    sizeof(reg), reg);
5438c2ecf20Sopenharmony_ci	if (err < 0)
5448c2ecf20Sopenharmony_ci		return err;
5458c2ecf20Sopenharmony_ci	if (err != sizeof(reg))
5468c2ecf20Sopenharmony_ci		return -EIO;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	sdata->chip_id = be16_to_cpup((__be16 *)&reg[6]);
5498c2ecf20Sopenharmony_ci	sdata->chip_ver = reg[0];
5508c2ecf20Sopenharmony_ci	sdata->fw_ver = be16_to_cpup((__be16 *)&reg[2]);
5518c2ecf20Sopenharmony_ci	sdata->config_id = reg[4];
5528c2ecf20Sopenharmony_ci	sdata->config_ver = reg[5];
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	enable_irq(sdata->client->irq);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	msleep(50);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	err = stmfts_command(sdata, STMFTS_SYSTEM_RESET);
5598c2ecf20Sopenharmony_ci	if (err)
5608c2ecf20Sopenharmony_ci		return err;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	err = stmfts_command(sdata, STMFTS_SLEEP_OUT);
5638c2ecf20Sopenharmony_ci	if (err)
5648c2ecf20Sopenharmony_ci		return err;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	/* optional tuning */
5678c2ecf20Sopenharmony_ci	err = stmfts_command(sdata, STMFTS_MS_CX_TUNING);
5688c2ecf20Sopenharmony_ci	if (err)
5698c2ecf20Sopenharmony_ci		dev_warn(&sdata->client->dev,
5708c2ecf20Sopenharmony_ci			 "failed to perform mutual auto tune: %d\n", err);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/* optional tuning */
5738c2ecf20Sopenharmony_ci	err = stmfts_command(sdata, STMFTS_SS_CX_TUNING);
5748c2ecf20Sopenharmony_ci	if (err)
5758c2ecf20Sopenharmony_ci		dev_warn(&sdata->client->dev,
5768c2ecf20Sopenharmony_ci			 "failed to perform self auto tune: %d\n", err);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	err = stmfts_command(sdata, STMFTS_FULL_FORCE_CALIBRATION);
5798c2ecf20Sopenharmony_ci	if (err)
5808c2ecf20Sopenharmony_ci		return err;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/*
5838c2ecf20Sopenharmony_ci	 * At this point no one is using the touchscreen
5848c2ecf20Sopenharmony_ci	 * and I don't really care about the return value
5858c2ecf20Sopenharmony_ci	 */
5868c2ecf20Sopenharmony_ci	(void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	return 0;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic void stmfts_power_off(void *data)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = data;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	disable_irq(sdata->client->irq);
5968c2ecf20Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
5978c2ecf20Sopenharmony_ci						sdata->regulators);
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci/* This function is void because I don't want to prevent using the touch key
6018c2ecf20Sopenharmony_ci * only because the LEDs don't get registered
6028c2ecf20Sopenharmony_ci */
6038c2ecf20Sopenharmony_cistatic int stmfts_enable_led(struct stmfts_data *sdata)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	int err;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	/* get the regulator for powering the leds on */
6088c2ecf20Sopenharmony_ci	sdata->ledvdd = devm_regulator_get(&sdata->client->dev, "ledvdd");
6098c2ecf20Sopenharmony_ci	if (IS_ERR(sdata->ledvdd))
6108c2ecf20Sopenharmony_ci		return PTR_ERR(sdata->ledvdd);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	sdata->led_cdev.name = STMFTS_DEV_NAME;
6138c2ecf20Sopenharmony_ci	sdata->led_cdev.max_brightness = LED_ON;
6148c2ecf20Sopenharmony_ci	sdata->led_cdev.brightness = LED_OFF;
6158c2ecf20Sopenharmony_ci	sdata->led_cdev.brightness_set_blocking = stmfts_brightness_set;
6168c2ecf20Sopenharmony_ci	sdata->led_cdev.brightness_get = stmfts_brightness_get;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev);
6198c2ecf20Sopenharmony_ci	if (err) {
6208c2ecf20Sopenharmony_ci		devm_regulator_put(sdata->ledvdd);
6218c2ecf20Sopenharmony_ci		return err;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	return 0;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_cistatic int stmfts_probe(struct i2c_client *client,
6288c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	int err;
6318c2ecf20Sopenharmony_ci	struct stmfts_data *sdata;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
6348c2ecf20Sopenharmony_ci						I2C_FUNC_SMBUS_BYTE_DATA |
6358c2ecf20Sopenharmony_ci						I2C_FUNC_SMBUS_I2C_BLOCK))
6368c2ecf20Sopenharmony_ci		return -ENODEV;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
6398c2ecf20Sopenharmony_ci	if (!sdata)
6408c2ecf20Sopenharmony_ci		return -ENOMEM;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, sdata);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	sdata->client = client;
6458c2ecf20Sopenharmony_ci	mutex_init(&sdata->mutex);
6468c2ecf20Sopenharmony_ci	init_completion(&sdata->cmd_done);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
6498c2ecf20Sopenharmony_ci	sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
6508c2ecf20Sopenharmony_ci	err = devm_regulator_bulk_get(&client->dev,
6518c2ecf20Sopenharmony_ci				      ARRAY_SIZE(sdata->regulators),
6528c2ecf20Sopenharmony_ci				      sdata->regulators);
6538c2ecf20Sopenharmony_ci	if (err)
6548c2ecf20Sopenharmony_ci		return err;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	sdata->input = devm_input_allocate_device(&client->dev);
6578c2ecf20Sopenharmony_ci	if (!sdata->input)
6588c2ecf20Sopenharmony_ci		return -ENOMEM;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	sdata->input->name = STMFTS_DEV_NAME;
6618c2ecf20Sopenharmony_ci	sdata->input->id.bustype = BUS_I2C;
6628c2ecf20Sopenharmony_ci	sdata->input->open = stmfts_input_open;
6638c2ecf20Sopenharmony_ci	sdata->input->close = stmfts_input_close;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_X);
6668c2ecf20Sopenharmony_ci	input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_Y);
6678c2ecf20Sopenharmony_ci	touchscreen_parse_properties(sdata->input, true, &sdata->prop);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
6708c2ecf20Sopenharmony_ci	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
6718c2ecf20Sopenharmony_ci	input_set_abs_params(sdata->input, ABS_MT_ORIENTATION, 0, 255, 0, 0);
6728c2ecf20Sopenharmony_ci	input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
6738c2ecf20Sopenharmony_ci	input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	sdata->use_key = device_property_read_bool(&client->dev,
6768c2ecf20Sopenharmony_ci						   "touch-key-connected");
6778c2ecf20Sopenharmony_ci	if (sdata->use_key) {
6788c2ecf20Sopenharmony_ci		input_set_capability(sdata->input, EV_KEY, KEY_MENU);
6798c2ecf20Sopenharmony_ci		input_set_capability(sdata->input, EV_KEY, KEY_BACK);
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	err = input_mt_init_slots(sdata->input,
6838c2ecf20Sopenharmony_ci				  STMFTS_MAX_FINGERS, INPUT_MT_DIRECT);
6848c2ecf20Sopenharmony_ci	if (err)
6858c2ecf20Sopenharmony_ci		return err;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	input_set_drvdata(sdata->input, sdata);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	/*
6908c2ecf20Sopenharmony_ci	 * stmfts_power_on expects interrupt to be disabled, but
6918c2ecf20Sopenharmony_ci	 * at this point the device is still off and I do not trust
6928c2ecf20Sopenharmony_ci	 * the status of the irq line that can generate some spurious
6938c2ecf20Sopenharmony_ci	 * interrupts. To be on the safe side it's better to not enable
6948c2ecf20Sopenharmony_ci	 * the interrupts during their request.
6958c2ecf20Sopenharmony_ci	 */
6968c2ecf20Sopenharmony_ci	irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
6978c2ecf20Sopenharmony_ci	err = devm_request_threaded_irq(&client->dev, client->irq,
6988c2ecf20Sopenharmony_ci					NULL, stmfts_irq_handler,
6998c2ecf20Sopenharmony_ci					IRQF_ONESHOT,
7008c2ecf20Sopenharmony_ci					"stmfts_irq", sdata);
7018c2ecf20Sopenharmony_ci	if (err)
7028c2ecf20Sopenharmony_ci		return err;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n");
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	err = stmfts_power_on(sdata);
7078c2ecf20Sopenharmony_ci	if (err)
7088c2ecf20Sopenharmony_ci		return err;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata);
7118c2ecf20Sopenharmony_ci	if (err)
7128c2ecf20Sopenharmony_ci		return err;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	err = input_register_device(sdata->input);
7158c2ecf20Sopenharmony_ci	if (err)
7168c2ecf20Sopenharmony_ci		return err;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	if (sdata->use_key) {
7198c2ecf20Sopenharmony_ci		err = stmfts_enable_led(sdata);
7208c2ecf20Sopenharmony_ci		if (err) {
7218c2ecf20Sopenharmony_ci			/*
7228c2ecf20Sopenharmony_ci			 * Even if the LEDs have failed to be initialized and
7238c2ecf20Sopenharmony_ci			 * used in the driver, I can still use the device even
7248c2ecf20Sopenharmony_ci			 * without LEDs. The ledvdd regulator pointer will be
7258c2ecf20Sopenharmony_ci			 * used as a flag.
7268c2ecf20Sopenharmony_ci			 */
7278c2ecf20Sopenharmony_ci			dev_warn(&client->dev, "unable to use touchkey leds\n");
7288c2ecf20Sopenharmony_ci			sdata->ledvdd = NULL;
7298c2ecf20Sopenharmony_ci		}
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	err = devm_device_add_group(&client->dev, &stmfts_attribute_group);
7338c2ecf20Sopenharmony_ci	if (err)
7348c2ecf20Sopenharmony_ci		return err;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	pm_runtime_enable(&client->dev);
7378c2ecf20Sopenharmony_ci	device_enable_async_suspend(&client->dev);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return 0;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_cistatic int stmfts_remove(struct i2c_client *client)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return 0;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic int __maybe_unused stmfts_runtime_suspend(struct device *dev)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
7528c2ecf20Sopenharmony_ci	int ret;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
7558c2ecf20Sopenharmony_ci	if (ret)
7568c2ecf20Sopenharmony_ci		dev_warn(dev, "failed to suspend device: %d\n", ret);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	return ret;
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic int __maybe_unused stmfts_runtime_resume(struct device *dev)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
7648c2ecf20Sopenharmony_ci	int ret;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
7678c2ecf20Sopenharmony_ci	if (ret)
7688c2ecf20Sopenharmony_ci		dev_err(dev, "failed to resume device: %d\n", ret);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	return ret;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_cistatic int __maybe_unused stmfts_suspend(struct device *dev)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	stmfts_power_off(sdata);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	return 0;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_cistatic int __maybe_unused stmfts_resume(struct device *dev)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	struct stmfts_data *sdata = dev_get_drvdata(dev);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	return stmfts_power_on(sdata);
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic const struct dev_pm_ops stmfts_pm_ops = {
7908c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume)
7918c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL)
7928c2ecf20Sopenharmony_ci};
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
7958c2ecf20Sopenharmony_cistatic const struct of_device_id stmfts_of_match[] = {
7968c2ecf20Sopenharmony_ci	{ .compatible = "st,stmfts", },
7978c2ecf20Sopenharmony_ci	{ },
7988c2ecf20Sopenharmony_ci};
7998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stmfts_of_match);
8008c2ecf20Sopenharmony_ci#endif
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_cistatic const struct i2c_device_id stmfts_id[] = {
8038c2ecf20Sopenharmony_ci	{ "stmfts", 0 },
8048c2ecf20Sopenharmony_ci	{ },
8058c2ecf20Sopenharmony_ci};
8068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, stmfts_id);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic struct i2c_driver stmfts_driver = {
8098c2ecf20Sopenharmony_ci	.driver = {
8108c2ecf20Sopenharmony_ci		.name = STMFTS_DEV_NAME,
8118c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(stmfts_of_match),
8128c2ecf20Sopenharmony_ci		.pm = &stmfts_pm_ops,
8138c2ecf20Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
8148c2ecf20Sopenharmony_ci	},
8158c2ecf20Sopenharmony_ci	.probe = stmfts_probe,
8168c2ecf20Sopenharmony_ci	.remove = stmfts_remove,
8178c2ecf20Sopenharmony_ci	.id_table = stmfts_id,
8188c2ecf20Sopenharmony_ci};
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cimodule_i2c_driver(stmfts_driver);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
8238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
8248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
825