162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Melfas MMS114/MMS136/MMS152 touchscreen device driver
362306a36Sopenharmony_ci//
462306a36Sopenharmony_ci// Copyright (c) 2012 Samsung Electronics Co., Ltd.
562306a36Sopenharmony_ci// Author: Joonyoung Shim <jy0922.shim@samsung.com>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/i2c.h>
1162306a36Sopenharmony_ci#include <linux/input/mt.h>
1262306a36Sopenharmony_ci#include <linux/input/touchscreen.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Write only registers */
1862306a36Sopenharmony_ci#define MMS114_MODE_CONTROL		0x01
1962306a36Sopenharmony_ci#define MMS114_OPERATION_MODE_MASK	0xE
2062306a36Sopenharmony_ci#define MMS114_ACTIVE			BIT(1)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define MMS114_XY_RESOLUTION_H		0x02
2362306a36Sopenharmony_ci#define MMS114_X_RESOLUTION		0x03
2462306a36Sopenharmony_ci#define MMS114_Y_RESOLUTION		0x04
2562306a36Sopenharmony_ci#define MMS114_CONTACT_THRESHOLD	0x05
2662306a36Sopenharmony_ci#define MMS114_MOVING_THRESHOLD		0x06
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* Read only registers */
2962306a36Sopenharmony_ci#define MMS114_PACKET_SIZE		0x0F
3062306a36Sopenharmony_ci#define MMS114_INFORMATION		0x10
3162306a36Sopenharmony_ci#define MMS114_TSP_REV			0xF0
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define MMS152_FW_REV			0xE1
3462306a36Sopenharmony_ci#define MMS152_COMPAT_GROUP		0xF2
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Minimum delay time is 50us between stop and start signal of i2c */
3762306a36Sopenharmony_ci#define MMS114_I2C_DELAY		50
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* 200ms needs after power on */
4062306a36Sopenharmony_ci#define MMS114_POWERON_DELAY		200
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* Touchscreen absolute values */
4362306a36Sopenharmony_ci#define MMS114_MAX_AREA			0xff
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define MMS114_MAX_TOUCHKEYS		15
4662306a36Sopenharmony_ci#define MMS114_MAX_TOUCH		10
4762306a36Sopenharmony_ci#define MMS114_EVENT_SIZE		8
4862306a36Sopenharmony_ci#define MMS136_EVENT_SIZE		6
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* Touch type */
5162306a36Sopenharmony_ci#define MMS114_TYPE_NONE		0
5262306a36Sopenharmony_ci#define MMS114_TYPE_TOUCHSCREEN		1
5362306a36Sopenharmony_ci#define MMS114_TYPE_TOUCHKEY		2
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cienum mms_type {
5662306a36Sopenharmony_ci	TYPE_MMS114	= 114,
5762306a36Sopenharmony_ci	TYPE_MMS134S	= 134,
5862306a36Sopenharmony_ci	TYPE_MMS136	= 136,
5962306a36Sopenharmony_ci	TYPE_MMS152	= 152,
6062306a36Sopenharmony_ci	TYPE_MMS345L	= 345,
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct mms114_data {
6462306a36Sopenharmony_ci	struct i2c_client	*client;
6562306a36Sopenharmony_ci	struct input_dev	*input_dev;
6662306a36Sopenharmony_ci	struct regulator	*core_reg;
6762306a36Sopenharmony_ci	struct regulator	*io_reg;
6862306a36Sopenharmony_ci	struct touchscreen_properties props;
6962306a36Sopenharmony_ci	enum mms_type		type;
7062306a36Sopenharmony_ci	unsigned int		contact_threshold;
7162306a36Sopenharmony_ci	unsigned int		moving_threshold;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	u32 keycodes[MMS114_MAX_TOUCHKEYS];
7462306a36Sopenharmony_ci	int num_keycodes;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* Use cache data for mode control register(write only) */
7762306a36Sopenharmony_ci	u8			cache_mode_control;
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct mms114_touch {
8162306a36Sopenharmony_ci	u8 id:4, reserved_bit4:1, type:2, pressed:1;
8262306a36Sopenharmony_ci	u8 x_hi:4, y_hi:4;
8362306a36Sopenharmony_ci	u8 x_lo;
8462306a36Sopenharmony_ci	u8 y_lo;
8562306a36Sopenharmony_ci	u8 width;
8662306a36Sopenharmony_ci	u8 strength;
8762306a36Sopenharmony_ci	u8 reserved[2];
8862306a36Sopenharmony_ci} __packed;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int __mms114_read_reg(struct mms114_data *data, unsigned int reg,
9162306a36Sopenharmony_ci			     unsigned int len, u8 *val)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct i2c_client *client = data->client;
9462306a36Sopenharmony_ci	struct i2c_msg xfer[2];
9562306a36Sopenharmony_ci	u8 buf = reg & 0xff;
9662306a36Sopenharmony_ci	int error;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (reg <= MMS114_MODE_CONTROL && reg + len > MMS114_MODE_CONTROL)
9962306a36Sopenharmony_ci		BUG();
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Write register */
10262306a36Sopenharmony_ci	xfer[0].addr = client->addr;
10362306a36Sopenharmony_ci	xfer[0].flags = client->flags & I2C_M_TEN;
10462306a36Sopenharmony_ci	xfer[0].len = 1;
10562306a36Sopenharmony_ci	xfer[0].buf = &buf;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* Read data */
10862306a36Sopenharmony_ci	xfer[1].addr = client->addr;
10962306a36Sopenharmony_ci	xfer[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
11062306a36Sopenharmony_ci	xfer[1].len = len;
11162306a36Sopenharmony_ci	xfer[1].buf = val;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	error = i2c_transfer(client->adapter, xfer, 2);
11462306a36Sopenharmony_ci	if (error != 2) {
11562306a36Sopenharmony_ci		dev_err(&client->dev,
11662306a36Sopenharmony_ci			"%s: i2c transfer failed (%d)\n", __func__, error);
11762306a36Sopenharmony_ci		return error < 0 ? error : -EIO;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	udelay(MMS114_I2C_DELAY);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return 0;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int mms114_read_reg(struct mms114_data *data, unsigned int reg)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	u8 val;
12762306a36Sopenharmony_ci	int error;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (reg == MMS114_MODE_CONTROL)
13062306a36Sopenharmony_ci		return data->cache_mode_control;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	error = __mms114_read_reg(data, reg, 1, &val);
13362306a36Sopenharmony_ci	return error < 0 ? error : val;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int mms114_write_reg(struct mms114_data *data, unsigned int reg,
13762306a36Sopenharmony_ci			    unsigned int val)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct i2c_client *client = data->client;
14062306a36Sopenharmony_ci	u8 buf[2];
14162306a36Sopenharmony_ci	int error;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	buf[0] = reg & 0xff;
14462306a36Sopenharmony_ci	buf[1] = val & 0xff;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	error = i2c_master_send(client, buf, 2);
14762306a36Sopenharmony_ci	if (error != 2) {
14862306a36Sopenharmony_ci		dev_err(&client->dev,
14962306a36Sopenharmony_ci			"%s: i2c send failed (%d)\n", __func__, error);
15062306a36Sopenharmony_ci		return error < 0 ? error : -EIO;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci	udelay(MMS114_I2C_DELAY);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (reg == MMS114_MODE_CONTROL)
15562306a36Sopenharmony_ci		data->cache_mode_control = val;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic void mms114_process_mt(struct mms114_data *data, struct mms114_touch *touch)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct i2c_client *client = data->client;
16362306a36Sopenharmony_ci	struct input_dev *input_dev = data->input_dev;
16462306a36Sopenharmony_ci	unsigned int id;
16562306a36Sopenharmony_ci	unsigned int x;
16662306a36Sopenharmony_ci	unsigned int y;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (touch->id > MMS114_MAX_TOUCH) {
16962306a36Sopenharmony_ci		dev_err(&client->dev, "Wrong touch id (%d)\n", touch->id);
17062306a36Sopenharmony_ci		return;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	id = touch->id - 1;
17462306a36Sopenharmony_ci	x = touch->x_lo | touch->x_hi << 8;
17562306a36Sopenharmony_ci	y = touch->y_lo | touch->y_hi << 8;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	dev_dbg(&client->dev,
17862306a36Sopenharmony_ci		"id: %d, type: %d, pressed: %d, x: %d, y: %d, width: %d, strength: %d\n",
17962306a36Sopenharmony_ci		id, touch->type, touch->pressed,
18062306a36Sopenharmony_ci		x, y, touch->width, touch->strength);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	input_mt_slot(input_dev, id);
18362306a36Sopenharmony_ci	input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, touch->pressed);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (touch->pressed) {
18662306a36Sopenharmony_ci		touchscreen_report_pos(input_dev, &data->props, x, y, true);
18762306a36Sopenharmony_ci		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, touch->width);
18862306a36Sopenharmony_ci		input_report_abs(input_dev, ABS_MT_PRESSURE, touch->strength);
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic void mms114_process_touchkey(struct mms114_data *data,
19362306a36Sopenharmony_ci				    struct mms114_touch *touch)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct i2c_client *client = data->client;
19662306a36Sopenharmony_ci	struct input_dev *input_dev = data->input_dev;
19762306a36Sopenharmony_ci	unsigned int keycode_id;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (touch->id == 0)
20062306a36Sopenharmony_ci		return;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (touch->id > data->num_keycodes) {
20362306a36Sopenharmony_ci		dev_err(&client->dev, "Wrong touch id for touchkey (%d)\n",
20462306a36Sopenharmony_ci			touch->id);
20562306a36Sopenharmony_ci		return;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	keycode_id = touch->id - 1;
20962306a36Sopenharmony_ci	dev_dbg(&client->dev, "keycode id: %d, pressed: %d\n", keycode_id,
21062306a36Sopenharmony_ci		touch->pressed);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	input_report_key(input_dev, data->keycodes[keycode_id], touch->pressed);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic irqreturn_t mms114_interrupt(int irq, void *dev_id)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct mms114_data *data = dev_id;
21862306a36Sopenharmony_ci	struct i2c_client *client = data->client;
21962306a36Sopenharmony_ci	struct input_dev *input_dev = data->input_dev;
22062306a36Sopenharmony_ci	struct mms114_touch touch[MMS114_MAX_TOUCH];
22162306a36Sopenharmony_ci	int packet_size;
22262306a36Sopenharmony_ci	int touch_size;
22362306a36Sopenharmony_ci	int index;
22462306a36Sopenharmony_ci	int error;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	mutex_lock(&input_dev->mutex);
22762306a36Sopenharmony_ci	if (!input_device_enabled(input_dev)) {
22862306a36Sopenharmony_ci		mutex_unlock(&input_dev->mutex);
22962306a36Sopenharmony_ci		goto out;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	mutex_unlock(&input_dev->mutex);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	packet_size = mms114_read_reg(data, MMS114_PACKET_SIZE);
23462306a36Sopenharmony_ci	if (packet_size <= 0)
23562306a36Sopenharmony_ci		goto out;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* MMS136 has slightly different event size */
23862306a36Sopenharmony_ci	if (data->type == TYPE_MMS134S || data->type == TYPE_MMS136)
23962306a36Sopenharmony_ci		touch_size = packet_size / MMS136_EVENT_SIZE;
24062306a36Sopenharmony_ci	else
24162306a36Sopenharmony_ci		touch_size = packet_size / MMS114_EVENT_SIZE;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size,
24462306a36Sopenharmony_ci			(u8 *)touch);
24562306a36Sopenharmony_ci	if (error < 0)
24662306a36Sopenharmony_ci		goto out;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	for (index = 0; index < touch_size; index++) {
24962306a36Sopenharmony_ci		switch (touch[index].type) {
25062306a36Sopenharmony_ci		case MMS114_TYPE_TOUCHSCREEN:
25162306a36Sopenharmony_ci			mms114_process_mt(data, touch + index);
25262306a36Sopenharmony_ci			break;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		case MMS114_TYPE_TOUCHKEY:
25562306a36Sopenharmony_ci			mms114_process_touchkey(data, touch + index);
25662306a36Sopenharmony_ci			break;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		default:
25962306a36Sopenharmony_ci			dev_err(&client->dev, "Wrong touch type (%d)\n",
26062306a36Sopenharmony_ci				touch[index].type);
26162306a36Sopenharmony_ci			break;
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	input_mt_report_pointer_emulation(data->input_dev, true);
26662306a36Sopenharmony_ci	input_sync(data->input_dev);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ciout:
26962306a36Sopenharmony_ci	return IRQ_HANDLED;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int mms114_set_active(struct mms114_data *data, bool active)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	int val;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	val = mms114_read_reg(data, MMS114_MODE_CONTROL);
27762306a36Sopenharmony_ci	if (val < 0)
27862306a36Sopenharmony_ci		return val;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	val &= ~MMS114_OPERATION_MODE_MASK;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* If active is false, sleep mode */
28362306a36Sopenharmony_ci	if (active)
28462306a36Sopenharmony_ci		val |= MMS114_ACTIVE;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return mms114_write_reg(data, MMS114_MODE_CONTROL, val);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int mms114_get_version(struct mms114_data *data)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct device *dev = &data->client->dev;
29262306a36Sopenharmony_ci	u8 buf[6];
29362306a36Sopenharmony_ci	int group;
29462306a36Sopenharmony_ci	int error;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	switch (data->type) {
29762306a36Sopenharmony_ci	case TYPE_MMS345L:
29862306a36Sopenharmony_ci		error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
29962306a36Sopenharmony_ci		if (error)
30062306a36Sopenharmony_ci			return error;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x\n",
30362306a36Sopenharmony_ci			 buf[0], buf[1], buf[2]);
30462306a36Sopenharmony_ci		break;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	case TYPE_MMS152:
30762306a36Sopenharmony_ci		error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
30862306a36Sopenharmony_ci		if (error)
30962306a36Sopenharmony_ci			return error;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		group = i2c_smbus_read_byte_data(data->client,
31262306a36Sopenharmony_ci						  MMS152_COMPAT_GROUP);
31362306a36Sopenharmony_ci		if (group < 0)
31462306a36Sopenharmony_ci			return group;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x, Compat group: %c\n",
31762306a36Sopenharmony_ci			 buf[0], buf[1], buf[2], group);
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	case TYPE_MMS114:
32162306a36Sopenharmony_ci	case TYPE_MMS134S:
32262306a36Sopenharmony_ci	case TYPE_MMS136:
32362306a36Sopenharmony_ci		error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf);
32462306a36Sopenharmony_ci		if (error)
32562306a36Sopenharmony_ci			return error;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n",
32862306a36Sopenharmony_ci			 buf[0], buf[1], buf[3]);
32962306a36Sopenharmony_ci		break;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int mms114_setup_regs(struct mms114_data *data)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	const struct touchscreen_properties *props = &data->props;
33862306a36Sopenharmony_ci	int val;
33962306a36Sopenharmony_ci	int error;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	error = mms114_get_version(data);
34262306a36Sopenharmony_ci	if (error < 0)
34362306a36Sopenharmony_ci		return error;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* MMS114, MMS134S and MMS136 have configuration and power on registers */
34662306a36Sopenharmony_ci	if (data->type != TYPE_MMS114 && data->type != TYPE_MMS134S &&
34762306a36Sopenharmony_ci	    data->type != TYPE_MMS136)
34862306a36Sopenharmony_ci		return 0;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	error = mms114_set_active(data, true);
35162306a36Sopenharmony_ci	if (error < 0)
35262306a36Sopenharmony_ci		return error;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	val = (props->max_x >> 8) & 0xf;
35562306a36Sopenharmony_ci	val |= ((props->max_y >> 8) & 0xf) << 4;
35662306a36Sopenharmony_ci	error = mms114_write_reg(data, MMS114_XY_RESOLUTION_H, val);
35762306a36Sopenharmony_ci	if (error < 0)
35862306a36Sopenharmony_ci		return error;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	val = props->max_x & 0xff;
36162306a36Sopenharmony_ci	error = mms114_write_reg(data, MMS114_X_RESOLUTION, val);
36262306a36Sopenharmony_ci	if (error < 0)
36362306a36Sopenharmony_ci		return error;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	val = props->max_x & 0xff;
36662306a36Sopenharmony_ci	error = mms114_write_reg(data, MMS114_Y_RESOLUTION, val);
36762306a36Sopenharmony_ci	if (error < 0)
36862306a36Sopenharmony_ci		return error;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (data->contact_threshold) {
37162306a36Sopenharmony_ci		error = mms114_write_reg(data, MMS114_CONTACT_THRESHOLD,
37262306a36Sopenharmony_ci				data->contact_threshold);
37362306a36Sopenharmony_ci		if (error < 0)
37462306a36Sopenharmony_ci			return error;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (data->moving_threshold) {
37862306a36Sopenharmony_ci		error = mms114_write_reg(data, MMS114_MOVING_THRESHOLD,
37962306a36Sopenharmony_ci				data->moving_threshold);
38062306a36Sopenharmony_ci		if (error < 0)
38162306a36Sopenharmony_ci			return error;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	return 0;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic int mms114_start(struct mms114_data *data)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct i2c_client *client = data->client;
39062306a36Sopenharmony_ci	int error;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	error = regulator_enable(data->core_reg);
39362306a36Sopenharmony_ci	if (error) {
39462306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to enable avdd: %d\n", error);
39562306a36Sopenharmony_ci		return error;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	error = regulator_enable(data->io_reg);
39962306a36Sopenharmony_ci	if (error) {
40062306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to enable vdd: %d\n", error);
40162306a36Sopenharmony_ci		regulator_disable(data->core_reg);
40262306a36Sopenharmony_ci		return error;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	msleep(MMS114_POWERON_DELAY);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	error = mms114_setup_regs(data);
40862306a36Sopenharmony_ci	if (error < 0) {
40962306a36Sopenharmony_ci		regulator_disable(data->io_reg);
41062306a36Sopenharmony_ci		regulator_disable(data->core_reg);
41162306a36Sopenharmony_ci		return error;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	enable_irq(client->irq);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic void mms114_stop(struct mms114_data *data)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct i2c_client *client = data->client;
42262306a36Sopenharmony_ci	int error;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	disable_irq(client->irq);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	error = regulator_disable(data->io_reg);
42762306a36Sopenharmony_ci	if (error)
42862306a36Sopenharmony_ci		dev_warn(&client->dev, "Failed to disable vdd: %d\n", error);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	error = regulator_disable(data->core_reg);
43162306a36Sopenharmony_ci	if (error)
43262306a36Sopenharmony_ci		dev_warn(&client->dev, "Failed to disable avdd: %d\n", error);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int mms114_input_open(struct input_dev *dev)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct mms114_data *data = input_get_drvdata(dev);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return mms114_start(data);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic void mms114_input_close(struct input_dev *dev)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct mms114_data *data = input_get_drvdata(dev);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	mms114_stop(data);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int mms114_parse_legacy_bindings(struct mms114_data *data)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct device *dev = &data->client->dev;
45262306a36Sopenharmony_ci	struct touchscreen_properties *props = &data->props;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (device_property_read_u32(dev, "x-size", &props->max_x)) {
45562306a36Sopenharmony_ci		dev_dbg(dev, "failed to get legacy x-size property\n");
45662306a36Sopenharmony_ci		return -EINVAL;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (device_property_read_u32(dev, "y-size", &props->max_y)) {
46062306a36Sopenharmony_ci		dev_dbg(dev, "failed to get legacy y-size property\n");
46162306a36Sopenharmony_ci		return -EINVAL;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	device_property_read_u32(dev, "contact-threshold",
46562306a36Sopenharmony_ci				&data->contact_threshold);
46662306a36Sopenharmony_ci	device_property_read_u32(dev, "moving-threshold",
46762306a36Sopenharmony_ci				&data->moving_threshold);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (device_property_read_bool(dev, "x-invert"))
47062306a36Sopenharmony_ci		props->invert_x = true;
47162306a36Sopenharmony_ci	if (device_property_read_bool(dev, "y-invert"))
47262306a36Sopenharmony_ci		props->invert_y = true;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	props->swap_x_y = false;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return 0;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic int mms114_probe(struct i2c_client *client)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct mms114_data *data;
48262306a36Sopenharmony_ci	struct input_dev *input_dev;
48362306a36Sopenharmony_ci	const void *match_data;
48462306a36Sopenharmony_ci	int error;
48562306a36Sopenharmony_ci	int i;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
48862306a36Sopenharmony_ci		dev_err(&client->dev, "Not supported I2C adapter\n");
48962306a36Sopenharmony_ci		return -ENODEV;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	data = devm_kzalloc(&client->dev, sizeof(struct mms114_data),
49362306a36Sopenharmony_ci			    GFP_KERNEL);
49462306a36Sopenharmony_ci	input_dev = devm_input_allocate_device(&client->dev);
49562306a36Sopenharmony_ci	if (!data || !input_dev) {
49662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to allocate memory\n");
49762306a36Sopenharmony_ci		return -ENOMEM;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	data->client = client;
50162306a36Sopenharmony_ci	data->input_dev = input_dev;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	match_data = device_get_match_data(&client->dev);
50462306a36Sopenharmony_ci	if (!match_data)
50562306a36Sopenharmony_ci		return -EINVAL;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	data->type = (enum mms_type)match_data;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	data->num_keycodes = device_property_count_u32(&client->dev,
51062306a36Sopenharmony_ci						       "linux,keycodes");
51162306a36Sopenharmony_ci	if (data->num_keycodes == -EINVAL) {
51262306a36Sopenharmony_ci		data->num_keycodes = 0;
51362306a36Sopenharmony_ci	} else if (data->num_keycodes < 0) {
51462306a36Sopenharmony_ci		dev_err(&client->dev,
51562306a36Sopenharmony_ci			"Unable to parse linux,keycodes property: %d\n",
51662306a36Sopenharmony_ci			data->num_keycodes);
51762306a36Sopenharmony_ci		return data->num_keycodes;
51862306a36Sopenharmony_ci	} else if (data->num_keycodes > MMS114_MAX_TOUCHKEYS) {
51962306a36Sopenharmony_ci		dev_warn(&client->dev,
52062306a36Sopenharmony_ci			"Found %d linux,keycodes but max is %d, ignoring the rest\n",
52162306a36Sopenharmony_ci			 data->num_keycodes, MMS114_MAX_TOUCHKEYS);
52262306a36Sopenharmony_ci		data->num_keycodes = MMS114_MAX_TOUCHKEYS;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (data->num_keycodes > 0) {
52662306a36Sopenharmony_ci		error = device_property_read_u32_array(&client->dev,
52762306a36Sopenharmony_ci						       "linux,keycodes",
52862306a36Sopenharmony_ci						       data->keycodes,
52962306a36Sopenharmony_ci						       data->num_keycodes);
53062306a36Sopenharmony_ci		if (error) {
53162306a36Sopenharmony_ci			dev_err(&client->dev,
53262306a36Sopenharmony_ci				"Unable to read linux,keycodes values: %d\n",
53362306a36Sopenharmony_ci				error);
53462306a36Sopenharmony_ci			return error;
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		input_dev->keycode = data->keycodes;
53862306a36Sopenharmony_ci		input_dev->keycodemax = data->num_keycodes;
53962306a36Sopenharmony_ci		input_dev->keycodesize = sizeof(data->keycodes[0]);
54062306a36Sopenharmony_ci		for (i = 0; i < data->num_keycodes; i++)
54162306a36Sopenharmony_ci			input_set_capability(input_dev,
54262306a36Sopenharmony_ci					     EV_KEY, data->keycodes[i]);
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
54662306a36Sopenharmony_ci	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
54762306a36Sopenharmony_ci	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
54862306a36Sopenharmony_ci	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
54962306a36Sopenharmony_ci			     0, MMS114_MAX_AREA, 0, 0);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	touchscreen_parse_properties(input_dev, true, &data->props);
55262306a36Sopenharmony_ci	if (!data->props.max_x || !data->props.max_y) {
55362306a36Sopenharmony_ci		dev_dbg(&client->dev,
55462306a36Sopenharmony_ci			"missing X/Y size properties, trying legacy bindings\n");
55562306a36Sopenharmony_ci		error = mms114_parse_legacy_bindings(data);
55662306a36Sopenharmony_ci		if (error)
55762306a36Sopenharmony_ci			return error;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		input_set_abs_params(input_dev, ABS_MT_POSITION_X,
56062306a36Sopenharmony_ci				     0, data->props.max_x, 0, 0);
56162306a36Sopenharmony_ci		input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
56262306a36Sopenharmony_ci				     0, data->props.max_y, 0, 0);
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (data->type == TYPE_MMS114 || data->type == TYPE_MMS134S ||
56662306a36Sopenharmony_ci	    data->type == TYPE_MMS136) {
56762306a36Sopenharmony_ci		/*
56862306a36Sopenharmony_ci		 * The firmware handles movement and pressure fuzz, so
56962306a36Sopenharmony_ci		 * don't duplicate that in software.
57062306a36Sopenharmony_ci		 */
57162306a36Sopenharmony_ci		data->moving_threshold = input_abs_get_fuzz(input_dev,
57262306a36Sopenharmony_ci							    ABS_MT_POSITION_X);
57362306a36Sopenharmony_ci		data->contact_threshold = input_abs_get_fuzz(input_dev,
57462306a36Sopenharmony_ci							     ABS_MT_PRESSURE);
57562306a36Sopenharmony_ci		input_abs_set_fuzz(input_dev, ABS_MT_POSITION_X, 0);
57662306a36Sopenharmony_ci		input_abs_set_fuzz(input_dev, ABS_MT_POSITION_Y, 0);
57762306a36Sopenharmony_ci		input_abs_set_fuzz(input_dev, ABS_MT_PRESSURE, 0);
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	input_dev->name = devm_kasprintf(&client->dev, GFP_KERNEL,
58162306a36Sopenharmony_ci					 "MELFAS MMS%d Touchscreen",
58262306a36Sopenharmony_ci					 data->type);
58362306a36Sopenharmony_ci	if (!input_dev->name)
58462306a36Sopenharmony_ci		return -ENOMEM;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	input_dev->id.bustype = BUS_I2C;
58762306a36Sopenharmony_ci	input_dev->dev.parent = &client->dev;
58862306a36Sopenharmony_ci	input_dev->open = mms114_input_open;
58962306a36Sopenharmony_ci	input_dev->close = mms114_input_close;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	error = input_mt_init_slots(input_dev, MMS114_MAX_TOUCH,
59262306a36Sopenharmony_ci				    INPUT_MT_DIRECT);
59362306a36Sopenharmony_ci	if (error)
59462306a36Sopenharmony_ci		return error;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	input_set_drvdata(input_dev, data);
59762306a36Sopenharmony_ci	i2c_set_clientdata(client, data);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	data->core_reg = devm_regulator_get(&client->dev, "avdd");
60062306a36Sopenharmony_ci	if (IS_ERR(data->core_reg)) {
60162306a36Sopenharmony_ci		error = PTR_ERR(data->core_reg);
60262306a36Sopenharmony_ci		dev_err(&client->dev,
60362306a36Sopenharmony_ci			"Unable to get the Core regulator (%d)\n", error);
60462306a36Sopenharmony_ci		return error;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	data->io_reg = devm_regulator_get(&client->dev, "vdd");
60862306a36Sopenharmony_ci	if (IS_ERR(data->io_reg)) {
60962306a36Sopenharmony_ci		error = PTR_ERR(data->io_reg);
61062306a36Sopenharmony_ci		dev_err(&client->dev,
61162306a36Sopenharmony_ci			"Unable to get the IO regulator (%d)\n", error);
61262306a36Sopenharmony_ci		return error;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	error = devm_request_threaded_irq(&client->dev, client->irq,
61662306a36Sopenharmony_ci					  NULL, mms114_interrupt,
61762306a36Sopenharmony_ci					  IRQF_ONESHOT | IRQF_NO_AUTOEN,
61862306a36Sopenharmony_ci					  dev_name(&client->dev), data);
61962306a36Sopenharmony_ci	if (error) {
62062306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to register interrupt\n");
62162306a36Sopenharmony_ci		return error;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	error = input_register_device(data->input_dev);
62562306a36Sopenharmony_ci	if (error) {
62662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to register input device\n");
62762306a36Sopenharmony_ci		return error;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return 0;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int mms114_suspend(struct device *dev)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
63662306a36Sopenharmony_ci	struct mms114_data *data = i2c_get_clientdata(client);
63762306a36Sopenharmony_ci	struct input_dev *input_dev = data->input_dev;
63862306a36Sopenharmony_ci	int id;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Release all touch */
64162306a36Sopenharmony_ci	for (id = 0; id < MMS114_MAX_TOUCH; id++) {
64262306a36Sopenharmony_ci		input_mt_slot(input_dev, id);
64362306a36Sopenharmony_ci		input_mt_report_slot_inactive(input_dev);
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	input_mt_report_pointer_emulation(input_dev, true);
64762306a36Sopenharmony_ci	input_sync(input_dev);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	mutex_lock(&input_dev->mutex);
65062306a36Sopenharmony_ci	if (input_device_enabled(input_dev))
65162306a36Sopenharmony_ci		mms114_stop(data);
65262306a36Sopenharmony_ci	mutex_unlock(&input_dev->mutex);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	return 0;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int mms114_resume(struct device *dev)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
66062306a36Sopenharmony_ci	struct mms114_data *data = i2c_get_clientdata(client);
66162306a36Sopenharmony_ci	struct input_dev *input_dev = data->input_dev;
66262306a36Sopenharmony_ci	int error;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	mutex_lock(&input_dev->mutex);
66562306a36Sopenharmony_ci	if (input_device_enabled(input_dev)) {
66662306a36Sopenharmony_ci		error = mms114_start(data);
66762306a36Sopenharmony_ci		if (error < 0) {
66862306a36Sopenharmony_ci			mutex_unlock(&input_dev->mutex);
66962306a36Sopenharmony_ci			return error;
67062306a36Sopenharmony_ci		}
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci	mutex_unlock(&input_dev->mutex);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	return 0;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistatic const struct i2c_device_id mms114_id[] = {
68062306a36Sopenharmony_ci	{ "mms114", 0 },
68162306a36Sopenharmony_ci	{ }
68262306a36Sopenharmony_ci};
68362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mms114_id);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci#ifdef CONFIG_OF
68662306a36Sopenharmony_cistatic const struct of_device_id mms114_dt_match[] = {
68762306a36Sopenharmony_ci	{
68862306a36Sopenharmony_ci		.compatible = "melfas,mms114",
68962306a36Sopenharmony_ci		.data = (void *)TYPE_MMS114,
69062306a36Sopenharmony_ci	}, {
69162306a36Sopenharmony_ci		.compatible = "melfas,mms134s",
69262306a36Sopenharmony_ci		.data = (void *)TYPE_MMS134S,
69362306a36Sopenharmony_ci	}, {
69462306a36Sopenharmony_ci		.compatible = "melfas,mms136",
69562306a36Sopenharmony_ci		.data = (void *)TYPE_MMS136,
69662306a36Sopenharmony_ci	}, {
69762306a36Sopenharmony_ci		.compatible = "melfas,mms152",
69862306a36Sopenharmony_ci		.data = (void *)TYPE_MMS152,
69962306a36Sopenharmony_ci	}, {
70062306a36Sopenharmony_ci		.compatible = "melfas,mms345l",
70162306a36Sopenharmony_ci		.data = (void *)TYPE_MMS345L,
70262306a36Sopenharmony_ci	},
70362306a36Sopenharmony_ci	{ }
70462306a36Sopenharmony_ci};
70562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mms114_dt_match);
70662306a36Sopenharmony_ci#endif
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic struct i2c_driver mms114_driver = {
70962306a36Sopenharmony_ci	.driver = {
71062306a36Sopenharmony_ci		.name	= "mms114",
71162306a36Sopenharmony_ci		.pm	= pm_sleep_ptr(&mms114_pm_ops),
71262306a36Sopenharmony_ci		.of_match_table = of_match_ptr(mms114_dt_match),
71362306a36Sopenharmony_ci	},
71462306a36Sopenharmony_ci	.probe		= mms114_probe,
71562306a36Sopenharmony_ci	.id_table	= mms114_id,
71662306a36Sopenharmony_ci};
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cimodule_i2c_driver(mms114_driver);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci/* Module information */
72162306a36Sopenharmony_ciMODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
72262306a36Sopenharmony_ciMODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver");
72362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
724