xref: /linux/drivers/input/touchscreen/silead.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23197704cSRobert Dolca /* -------------------------------------------------------------------------
33197704cSRobert Dolca  * Copyright (C) 2014-2015, Intel Corporation
43197704cSRobert Dolca  *
53197704cSRobert Dolca  * Derived from:
63197704cSRobert Dolca  *  gslX68X.c
73197704cSRobert Dolca  *  Copyright (C) 2010-2015, Shanghai Sileadinc Co.Ltd
83197704cSRobert Dolca  *
93197704cSRobert Dolca  * -------------------------------------------------------------------------
103197704cSRobert Dolca  */
113197704cSRobert Dolca 
123197704cSRobert Dolca #include <linux/i2c.h>
133197704cSRobert Dolca #include <linux/module.h>
143197704cSRobert Dolca #include <linux/acpi.h>
153197704cSRobert Dolca #include <linux/interrupt.h>
163197704cSRobert Dolca #include <linux/gpio/consumer.h>
173197704cSRobert Dolca #include <linux/delay.h>
183197704cSRobert Dolca #include <linux/firmware.h>
193197704cSRobert Dolca #include <linux/input.h>
203197704cSRobert Dolca #include <linux/input/mt.h>
213197704cSRobert Dolca #include <linux/input/touchscreen.h>
223197704cSRobert Dolca #include <linux/pm.h>
233197704cSRobert Dolca #include <linux/irq.h>
246f6deb48SHans de Goede #include <linux/regulator/consumer.h>
253197704cSRobert Dolca 
263197704cSRobert Dolca #include <asm/unaligned.h>
273197704cSRobert Dolca 
283197704cSRobert Dolca #define SILEAD_TS_NAME		"silead_ts"
293197704cSRobert Dolca 
303197704cSRobert Dolca #define SILEAD_REG_RESET	0xE0
313197704cSRobert Dolca #define SILEAD_REG_DATA		0x80
323197704cSRobert Dolca #define SILEAD_REG_TOUCH_NR	0x80
333197704cSRobert Dolca #define SILEAD_REG_POWER	0xBC
343197704cSRobert Dolca #define SILEAD_REG_CLOCK	0xE4
353197704cSRobert Dolca #define SILEAD_REG_STATUS	0xB0
363197704cSRobert Dolca #define SILEAD_REG_ID		0xFC
373197704cSRobert Dolca #define SILEAD_REG_MEM_CHECK	0xB0
383197704cSRobert Dolca 
393197704cSRobert Dolca #define SILEAD_STATUS_OK	0x5A5A5A5A
403197704cSRobert Dolca #define SILEAD_TS_DATA_LEN	44
413197704cSRobert Dolca #define SILEAD_CLOCK		0x04
423197704cSRobert Dolca 
433197704cSRobert Dolca #define SILEAD_CMD_RESET	0x88
443197704cSRobert Dolca #define SILEAD_CMD_START	0x00
453197704cSRobert Dolca 
463197704cSRobert Dolca #define SILEAD_POINT_DATA_LEN	0x04
473197704cSRobert Dolca #define SILEAD_POINT_Y_OFF      0x00
483197704cSRobert Dolca #define SILEAD_POINT_Y_MSB_OFF	0x01
493197704cSRobert Dolca #define SILEAD_POINT_X_OFF	0x02
503197704cSRobert Dolca #define SILEAD_POINT_X_MSB_OFF	0x03
51eca3be9bSHans de Goede #define SILEAD_EXTRA_DATA_MASK	0xF0
523197704cSRobert Dolca 
533197704cSRobert Dolca #define SILEAD_CMD_SLEEP_MIN	10000
543197704cSRobert Dolca #define SILEAD_CMD_SLEEP_MAX	20000
553197704cSRobert Dolca #define SILEAD_POWER_SLEEP	20
563197704cSRobert Dolca #define SILEAD_STARTUP_SLEEP	30
573197704cSRobert Dolca 
583197704cSRobert Dolca #define SILEAD_MAX_FINGERS	10
593197704cSRobert Dolca 
603197704cSRobert Dolca enum silead_ts_power {
613197704cSRobert Dolca 	SILEAD_POWER_ON  = 1,
623197704cSRobert Dolca 	SILEAD_POWER_OFF = 0
633197704cSRobert Dolca };
643197704cSRobert Dolca 
653197704cSRobert Dolca struct silead_ts_data {
663197704cSRobert Dolca 	struct i2c_client *client;
673197704cSRobert Dolca 	struct gpio_desc *gpio_power;
683197704cSRobert Dolca 	struct input_dev *input;
696f6deb48SHans de Goede 	struct regulator_bulk_data regulators[2];
703197704cSRobert Dolca 	char fw_name[64];
713197704cSRobert Dolca 	struct touchscreen_properties prop;
723197704cSRobert Dolca 	u32 max_fingers;
733197704cSRobert Dolca 	u32 chip_id;
743197704cSRobert Dolca 	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
753197704cSRobert Dolca 	int slots[SILEAD_MAX_FINGERS];
763197704cSRobert Dolca 	int id[SILEAD_MAX_FINGERS];
773197704cSRobert Dolca };
783197704cSRobert Dolca 
793197704cSRobert Dolca struct silead_fw_data {
803197704cSRobert Dolca 	u32 offset;
813197704cSRobert Dolca 	u32 val;
823197704cSRobert Dolca };
833197704cSRobert Dolca 
843197704cSRobert Dolca static int silead_ts_request_input_dev(struct silead_ts_data *data)
853197704cSRobert Dolca {
863197704cSRobert Dolca 	struct device *dev = &data->client->dev;
873197704cSRobert Dolca 	int error;
883197704cSRobert Dolca 
893197704cSRobert Dolca 	data->input = devm_input_allocate_device(dev);
903197704cSRobert Dolca 	if (!data->input) {
913197704cSRobert Dolca 		dev_err(dev,
923197704cSRobert Dolca 			"Failed to allocate input device\n");
933197704cSRobert Dolca 		return -ENOMEM;
943197704cSRobert Dolca 	}
953197704cSRobert Dolca 
963197704cSRobert Dolca 	input_set_abs_params(data->input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
973197704cSRobert Dolca 	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
983197704cSRobert Dolca 	touchscreen_parse_properties(data->input, true, &data->prop);
993197704cSRobert Dolca 
1003197704cSRobert Dolca 	input_mt_init_slots(data->input, data->max_fingers,
1013197704cSRobert Dolca 			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
1023197704cSRobert Dolca 			    INPUT_MT_TRACK);
1033197704cSRobert Dolca 
104eca3be9bSHans de Goede 	if (device_property_read_bool(dev, "silead,home-button"))
105eca3be9bSHans de Goede 		input_set_capability(data->input, EV_KEY, KEY_LEFTMETA);
106eca3be9bSHans de Goede 
1073197704cSRobert Dolca 	data->input->name = SILEAD_TS_NAME;
1083197704cSRobert Dolca 	data->input->phys = "input/ts";
1093197704cSRobert Dolca 	data->input->id.bustype = BUS_I2C;
1103197704cSRobert Dolca 
1113197704cSRobert Dolca 	error = input_register_device(data->input);
1123197704cSRobert Dolca 	if (error) {
1133197704cSRobert Dolca 		dev_err(dev, "Failed to register input device: %d\n", error);
1143197704cSRobert Dolca 		return error;
1153197704cSRobert Dolca 	}
1163197704cSRobert Dolca 
1173197704cSRobert Dolca 	return 0;
1183197704cSRobert Dolca }
1193197704cSRobert Dolca 
1203197704cSRobert Dolca static void silead_ts_set_power(struct i2c_client *client,
1213197704cSRobert Dolca 				enum silead_ts_power state)
1223197704cSRobert Dolca {
1233197704cSRobert Dolca 	struct silead_ts_data *data = i2c_get_clientdata(client);
1243197704cSRobert Dolca 
1253197704cSRobert Dolca 	if (data->gpio_power) {
1263197704cSRobert Dolca 		gpiod_set_value_cansleep(data->gpio_power, state);
1273197704cSRobert Dolca 		msleep(SILEAD_POWER_SLEEP);
1283197704cSRobert Dolca 	}
1293197704cSRobert Dolca }
1303197704cSRobert Dolca 
1313197704cSRobert Dolca static void silead_ts_read_data(struct i2c_client *client)
1323197704cSRobert Dolca {
1333197704cSRobert Dolca 	struct silead_ts_data *data = i2c_get_clientdata(client);
1343197704cSRobert Dolca 	struct input_dev *input = data->input;
1353197704cSRobert Dolca 	struct device *dev = &client->dev;
1363197704cSRobert Dolca 	u8 *bufp, buf[SILEAD_TS_DATA_LEN];
137eca3be9bSHans de Goede 	int touch_nr, softbutton, error, i;
138eca3be9bSHans de Goede 	bool softbutton_pressed = false;
1393197704cSRobert Dolca 
1403197704cSRobert Dolca 	error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_DATA,
1413197704cSRobert Dolca 					      SILEAD_TS_DATA_LEN, buf);
1423197704cSRobert Dolca 	if (error < 0) {
1433197704cSRobert Dolca 		dev_err(dev, "Data read error %d\n", error);
1443197704cSRobert Dolca 		return;
1453197704cSRobert Dolca 	}
1463197704cSRobert Dolca 
147eca3be9bSHans de Goede 	if (buf[0] > data->max_fingers) {
1483197704cSRobert Dolca 		dev_warn(dev, "More touches reported then supported %d > %d\n",
149eca3be9bSHans de Goede 			 buf[0], data->max_fingers);
150eca3be9bSHans de Goede 		buf[0] = data->max_fingers;
1513197704cSRobert Dolca 	}
1523197704cSRobert Dolca 
153eca3be9bSHans de Goede 	touch_nr = 0;
1543197704cSRobert Dolca 	bufp = buf + SILEAD_POINT_DATA_LEN;
155eca3be9bSHans de Goede 	for (i = 0; i < buf[0]; i++, bufp += SILEAD_POINT_DATA_LEN) {
156eca3be9bSHans de Goede 		softbutton = (bufp[SILEAD_POINT_Y_MSB_OFF] &
157eca3be9bSHans de Goede 			      SILEAD_EXTRA_DATA_MASK) >> 4;
158eca3be9bSHans de Goede 
159eca3be9bSHans de Goede 		if (softbutton) {
160eca3be9bSHans de Goede 			/*
161eca3be9bSHans de Goede 			 * For now only respond to softbutton == 0x01, some
162eca3be9bSHans de Goede 			 * tablets *without* a capacative button send 0x04
163eca3be9bSHans de Goede 			 * when crossing the edges of the screen.
164eca3be9bSHans de Goede 			 */
165eca3be9bSHans de Goede 			if (softbutton == 0x01)
166eca3be9bSHans de Goede 				softbutton_pressed = true;
167eca3be9bSHans de Goede 
168eca3be9bSHans de Goede 			continue;
169eca3be9bSHans de Goede 		}
170eca3be9bSHans de Goede 
171eca3be9bSHans de Goede 		/*
172eca3be9bSHans de Goede 		 * Bits 4-7 are the touch id, note not all models have
173eca3be9bSHans de Goede 		 * hardware touch ids so atm we don't use these.
174eca3be9bSHans de Goede 		 */
175eca3be9bSHans de Goede 		data->id[touch_nr] = (bufp[SILEAD_POINT_X_MSB_OFF] &
176eca3be9bSHans de Goede 				      SILEAD_EXTRA_DATA_MASK) >> 4;
177eca3be9bSHans de Goede 		touchscreen_set_mt_pos(&data->pos[touch_nr], &data->prop,
1783197704cSRobert Dolca 			get_unaligned_le16(&bufp[SILEAD_POINT_X_OFF]) & 0xfff,
1793197704cSRobert Dolca 			get_unaligned_le16(&bufp[SILEAD_POINT_Y_OFF]) & 0xfff);
180eca3be9bSHans de Goede 		touch_nr++;
1813197704cSRobert Dolca 	}
1823197704cSRobert Dolca 
1833197704cSRobert Dolca 	input_mt_assign_slots(input, data->slots, data->pos, touch_nr, 0);
1843197704cSRobert Dolca 
1853197704cSRobert Dolca 	for (i = 0; i < touch_nr; i++) {
1863197704cSRobert Dolca 		input_mt_slot(input, data->slots[i]);
1873197704cSRobert Dolca 		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
1883197704cSRobert Dolca 		input_report_abs(input, ABS_MT_POSITION_X, data->pos[i].x);
1893197704cSRobert Dolca 		input_report_abs(input, ABS_MT_POSITION_Y, data->pos[i].y);
1903197704cSRobert Dolca 
1913197704cSRobert Dolca 		dev_dbg(dev, "x=%d y=%d hw_id=%d sw_id=%d\n", data->pos[i].x,
1923197704cSRobert Dolca 			data->pos[i].y, data->id[i], data->slots[i]);
1933197704cSRobert Dolca 	}
1943197704cSRobert Dolca 
1953197704cSRobert Dolca 	input_mt_sync_frame(input);
196eca3be9bSHans de Goede 	input_report_key(input, KEY_LEFTMETA, softbutton_pressed);
1973197704cSRobert Dolca 	input_sync(input);
1983197704cSRobert Dolca }
1993197704cSRobert Dolca 
2003197704cSRobert Dolca static int silead_ts_init(struct i2c_client *client)
2013197704cSRobert Dolca {
2023197704cSRobert Dolca 	struct silead_ts_data *data = i2c_get_clientdata(client);
2033197704cSRobert Dolca 	int error;
2043197704cSRobert Dolca 
2053197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
2063197704cSRobert Dolca 					  SILEAD_CMD_RESET);
2073197704cSRobert Dolca 	if (error)
2083197704cSRobert Dolca 		goto i2c_write_err;
2093197704cSRobert Dolca 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
2103197704cSRobert Dolca 
2113197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
2123197704cSRobert Dolca 					data->max_fingers);
2133197704cSRobert Dolca 	if (error)
2143197704cSRobert Dolca 		goto i2c_write_err;
2153197704cSRobert Dolca 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
2163197704cSRobert Dolca 
2173197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK,
2183197704cSRobert Dolca 					  SILEAD_CLOCK);
2193197704cSRobert Dolca 	if (error)
2203197704cSRobert Dolca 		goto i2c_write_err;
2213197704cSRobert Dolca 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
2223197704cSRobert Dolca 
2233197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
2243197704cSRobert Dolca 					  SILEAD_CMD_START);
2253197704cSRobert Dolca 	if (error)
2263197704cSRobert Dolca 		goto i2c_write_err;
2273197704cSRobert Dolca 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
2283197704cSRobert Dolca 
2293197704cSRobert Dolca 	return 0;
2303197704cSRobert Dolca 
2313197704cSRobert Dolca i2c_write_err:
2323197704cSRobert Dolca 	dev_err(&client->dev, "Registers clear error %d\n", error);
2333197704cSRobert Dolca 	return error;
2343197704cSRobert Dolca }
2353197704cSRobert Dolca 
2363197704cSRobert Dolca static int silead_ts_reset(struct i2c_client *client)
2373197704cSRobert Dolca {
2383197704cSRobert Dolca 	int error;
2393197704cSRobert Dolca 
2403197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
2413197704cSRobert Dolca 					  SILEAD_CMD_RESET);
2423197704cSRobert Dolca 	if (error)
2433197704cSRobert Dolca 		goto i2c_write_err;
2443197704cSRobert Dolca 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
2453197704cSRobert Dolca 
2463197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK,
2473197704cSRobert Dolca 					  SILEAD_CLOCK);
2483197704cSRobert Dolca 	if (error)
2493197704cSRobert Dolca 		goto i2c_write_err;
2503197704cSRobert Dolca 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
2513197704cSRobert Dolca 
2523197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_POWER,
2533197704cSRobert Dolca 					  SILEAD_CMD_START);
2543197704cSRobert Dolca 	if (error)
2553197704cSRobert Dolca 		goto i2c_write_err;
2563197704cSRobert Dolca 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
2573197704cSRobert Dolca 
2583197704cSRobert Dolca 	return 0;
2593197704cSRobert Dolca 
2603197704cSRobert Dolca i2c_write_err:
2613197704cSRobert Dolca 	dev_err(&client->dev, "Chip reset error %d\n", error);
2623197704cSRobert Dolca 	return error;
2633197704cSRobert Dolca }
2643197704cSRobert Dolca 
2653197704cSRobert Dolca static int silead_ts_startup(struct i2c_client *client)
2663197704cSRobert Dolca {
2673197704cSRobert Dolca 	int error;
2683197704cSRobert Dolca 
2693197704cSRobert Dolca 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET, 0x00);
2703197704cSRobert Dolca 	if (error) {
2713197704cSRobert Dolca 		dev_err(&client->dev, "Startup error %d\n", error);
2723197704cSRobert Dolca 		return error;
2733197704cSRobert Dolca 	}
2743197704cSRobert Dolca 
2753197704cSRobert Dolca 	msleep(SILEAD_STARTUP_SLEEP);
2763197704cSRobert Dolca 
2773197704cSRobert Dolca 	return 0;
2783197704cSRobert Dolca }
2793197704cSRobert Dolca 
2803197704cSRobert Dolca static int silead_ts_load_fw(struct i2c_client *client)
2813197704cSRobert Dolca {
2823197704cSRobert Dolca 	struct device *dev = &client->dev;
2833197704cSRobert Dolca 	struct silead_ts_data *data = i2c_get_clientdata(client);
2843197704cSRobert Dolca 	unsigned int fw_size, i;
2853197704cSRobert Dolca 	const struct firmware *fw;
2863197704cSRobert Dolca 	struct silead_fw_data *fw_data;
2873197704cSRobert Dolca 	int error;
2883197704cSRobert Dolca 
2893197704cSRobert Dolca 	dev_dbg(dev, "Firmware file name: %s", data->fw_name);
2903197704cSRobert Dolca 
291*b4a87bcdSHans de Goede 	error = firmware_request_platform(&fw, data->fw_name, dev);
2923197704cSRobert Dolca 	if (error) {
2933197704cSRobert Dolca 		dev_err(dev, "Firmware request error %d\n", error);
2943197704cSRobert Dolca 		return error;
2953197704cSRobert Dolca 	}
2963197704cSRobert Dolca 
2973197704cSRobert Dolca 	fw_size = fw->size / sizeof(*fw_data);
2983197704cSRobert Dolca 	fw_data = (struct silead_fw_data *)fw->data;
2993197704cSRobert Dolca 
3003197704cSRobert Dolca 	for (i = 0; i < fw_size; i++) {
3013197704cSRobert Dolca 		error = i2c_smbus_write_i2c_block_data(client,
3023197704cSRobert Dolca 						       fw_data[i].offset,
3033197704cSRobert Dolca 						       4,
3043197704cSRobert Dolca 						       (u8 *)&fw_data[i].val);
3053197704cSRobert Dolca 		if (error) {
3063197704cSRobert Dolca 			dev_err(dev, "Firmware load error %d\n", error);
3073197704cSRobert Dolca 			break;
3083197704cSRobert Dolca 		}
3093197704cSRobert Dolca 	}
3103197704cSRobert Dolca 
3113197704cSRobert Dolca 	release_firmware(fw);
3123197704cSRobert Dolca 	return error ?: 0;
3133197704cSRobert Dolca }
3143197704cSRobert Dolca 
3153197704cSRobert Dolca static u32 silead_ts_get_status(struct i2c_client *client)
3163197704cSRobert Dolca {
3173197704cSRobert Dolca 	int error;
3183197704cSRobert Dolca 	__le32 status;
3193197704cSRobert Dolca 
3203197704cSRobert Dolca 	error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_STATUS,
3213197704cSRobert Dolca 					      sizeof(status), (u8 *)&status);
3223197704cSRobert Dolca 	if (error < 0) {
3233197704cSRobert Dolca 		dev_err(&client->dev, "Status read error %d\n", error);
3243197704cSRobert Dolca 		return error;
3253197704cSRobert Dolca 	}
3263197704cSRobert Dolca 
3273197704cSRobert Dolca 	return le32_to_cpu(status);
3283197704cSRobert Dolca }
3293197704cSRobert Dolca 
3303197704cSRobert Dolca static int silead_ts_get_id(struct i2c_client *client)
3313197704cSRobert Dolca {
3323197704cSRobert Dolca 	struct silead_ts_data *data = i2c_get_clientdata(client);
3333197704cSRobert Dolca 	__le32 chip_id;
3343197704cSRobert Dolca 	int error;
3353197704cSRobert Dolca 
3363197704cSRobert Dolca 	error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_ID,
3373197704cSRobert Dolca 					      sizeof(chip_id), (u8 *)&chip_id);
3383197704cSRobert Dolca 	if (error < 0) {
3393197704cSRobert Dolca 		dev_err(&client->dev, "Chip ID read error %d\n", error);
3403197704cSRobert Dolca 		return error;
3413197704cSRobert Dolca 	}
3423197704cSRobert Dolca 
3433197704cSRobert Dolca 	data->chip_id = le32_to_cpu(chip_id);
3443197704cSRobert Dolca 	dev_info(&client->dev, "Silead chip ID: 0x%8X", data->chip_id);
3453197704cSRobert Dolca 
3463197704cSRobert Dolca 	return 0;
3473197704cSRobert Dolca }
3483197704cSRobert Dolca 
3493197704cSRobert Dolca static int silead_ts_setup(struct i2c_client *client)
3503197704cSRobert Dolca {
3513197704cSRobert Dolca 	int error;
3523197704cSRobert Dolca 	u32 status;
3533197704cSRobert Dolca 
3543197704cSRobert Dolca 	silead_ts_set_power(client, SILEAD_POWER_OFF);
3553197704cSRobert Dolca 	silead_ts_set_power(client, SILEAD_POWER_ON);
3563197704cSRobert Dolca 
3573197704cSRobert Dolca 	error = silead_ts_get_id(client);
3583197704cSRobert Dolca 	if (error)
3593197704cSRobert Dolca 		return error;
3603197704cSRobert Dolca 
3613197704cSRobert Dolca 	error = silead_ts_init(client);
3623197704cSRobert Dolca 	if (error)
3633197704cSRobert Dolca 		return error;
3643197704cSRobert Dolca 
3653197704cSRobert Dolca 	error = silead_ts_reset(client);
3663197704cSRobert Dolca 	if (error)
3673197704cSRobert Dolca 		return error;
3683197704cSRobert Dolca 
3693197704cSRobert Dolca 	error = silead_ts_load_fw(client);
3703197704cSRobert Dolca 	if (error)
3713197704cSRobert Dolca 		return error;
3723197704cSRobert Dolca 
3733197704cSRobert Dolca 	error = silead_ts_startup(client);
3743197704cSRobert Dolca 	if (error)
3753197704cSRobert Dolca 		return error;
3763197704cSRobert Dolca 
3773197704cSRobert Dolca 	status = silead_ts_get_status(client);
3783197704cSRobert Dolca 	if (status != SILEAD_STATUS_OK) {
3793197704cSRobert Dolca 		dev_err(&client->dev,
3803197704cSRobert Dolca 			"Initialization error, status: 0x%X\n", status);
3813197704cSRobert Dolca 		return -ENODEV;
3823197704cSRobert Dolca 	}
3833197704cSRobert Dolca 
3843197704cSRobert Dolca 	return 0;
3853197704cSRobert Dolca }
3863197704cSRobert Dolca 
3873197704cSRobert Dolca static irqreturn_t silead_ts_threaded_irq_handler(int irq, void *id)
3883197704cSRobert Dolca {
3893197704cSRobert Dolca 	struct silead_ts_data *data = id;
3903197704cSRobert Dolca 	struct i2c_client *client = data->client;
3913197704cSRobert Dolca 
3923197704cSRobert Dolca 	silead_ts_read_data(client);
3933197704cSRobert Dolca 
3943197704cSRobert Dolca 	return IRQ_HANDLED;
3953197704cSRobert Dolca }
3963197704cSRobert Dolca 
3973197704cSRobert Dolca static void silead_ts_read_props(struct i2c_client *client)
3983197704cSRobert Dolca {
3993197704cSRobert Dolca 	struct silead_ts_data *data = i2c_get_clientdata(client);
4003197704cSRobert Dolca 	struct device *dev = &client->dev;
4013197704cSRobert Dolca 	const char *str;
4023197704cSRobert Dolca 	int error;
4033197704cSRobert Dolca 
4043197704cSRobert Dolca 	error = device_property_read_u32(dev, "silead,max-fingers",
4053197704cSRobert Dolca 					 &data->max_fingers);
4063197704cSRobert Dolca 	if (error) {
4073197704cSRobert Dolca 		dev_dbg(dev, "Max fingers read error %d\n", error);
4083197704cSRobert Dolca 		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
4093197704cSRobert Dolca 	}
4103197704cSRobert Dolca 
41143ba5883SHans de Goede 	error = device_property_read_string(dev, "firmware-name", &str);
4123197704cSRobert Dolca 	if (!error)
41343ba5883SHans de Goede 		snprintf(data->fw_name, sizeof(data->fw_name),
41443ba5883SHans de Goede 			 "silead/%s", str);
4153197704cSRobert Dolca 	else
4163197704cSRobert Dolca 		dev_dbg(dev, "Firmware file name read error. Using default.");
4173197704cSRobert Dolca }
4183197704cSRobert Dolca 
4193197704cSRobert Dolca #ifdef CONFIG_ACPI
4203197704cSRobert Dolca static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
4213197704cSRobert Dolca 					 const struct i2c_device_id *id)
4223197704cSRobert Dolca {
4233197704cSRobert Dolca 	const struct acpi_device_id *acpi_id;
4243197704cSRobert Dolca 	struct device *dev = &data->client->dev;
4253197704cSRobert Dolca 	int i;
4263197704cSRobert Dolca 
4273197704cSRobert Dolca 	if (ACPI_HANDLE(dev)) {
4283197704cSRobert Dolca 		acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
4293197704cSRobert Dolca 		if (!acpi_id)
4303197704cSRobert Dolca 			return -ENODEV;
4313197704cSRobert Dolca 
4324af2ff91SHans de Goede 		snprintf(data->fw_name, sizeof(data->fw_name),
4334af2ff91SHans de Goede 			 "silead/%s.fw", acpi_id->id);
4343197704cSRobert Dolca 
4353197704cSRobert Dolca 		for (i = 0; i < strlen(data->fw_name); i++)
4363197704cSRobert Dolca 			data->fw_name[i] = tolower(data->fw_name[i]);
4373197704cSRobert Dolca 	} else {
4384af2ff91SHans de Goede 		snprintf(data->fw_name, sizeof(data->fw_name),
4394af2ff91SHans de Goede 			 "silead/%s.fw", id->name);
4403197704cSRobert Dolca 	}
4413197704cSRobert Dolca 
4423197704cSRobert Dolca 	return 0;
4433197704cSRobert Dolca }
4443197704cSRobert Dolca #else
4453197704cSRobert Dolca static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
4463197704cSRobert Dolca 					 const struct i2c_device_id *id)
4473197704cSRobert Dolca {
4484af2ff91SHans de Goede 	snprintf(data->fw_name, sizeof(data->fw_name),
4494af2ff91SHans de Goede 		 "silead/%s.fw", id->name);
4503197704cSRobert Dolca 	return 0;
4513197704cSRobert Dolca }
4523197704cSRobert Dolca #endif
4533197704cSRobert Dolca 
4546f6deb48SHans de Goede static void silead_disable_regulator(void *arg)
4556f6deb48SHans de Goede {
4566f6deb48SHans de Goede 	struct silead_ts_data *data = arg;
4576f6deb48SHans de Goede 
4586f6deb48SHans de Goede 	regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
4596f6deb48SHans de Goede }
4606f6deb48SHans de Goede 
4613197704cSRobert Dolca static int silead_ts_probe(struct i2c_client *client,
4623197704cSRobert Dolca 			   const struct i2c_device_id *id)
4633197704cSRobert Dolca {
4643197704cSRobert Dolca 	struct silead_ts_data *data;
4653197704cSRobert Dolca 	struct device *dev = &client->dev;
4663197704cSRobert Dolca 	int error;
4673197704cSRobert Dolca 
4683197704cSRobert Dolca 	if (!i2c_check_functionality(client->adapter,
4693197704cSRobert Dolca 				     I2C_FUNC_I2C |
4703197704cSRobert Dolca 				     I2C_FUNC_SMBUS_READ_I2C_BLOCK |
4713197704cSRobert Dolca 				     I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
4723197704cSRobert Dolca 		dev_err(dev, "I2C functionality check failed\n");
4733197704cSRobert Dolca 		return -ENXIO;
4743197704cSRobert Dolca 	}
4753197704cSRobert Dolca 
4763197704cSRobert Dolca 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
4773197704cSRobert Dolca 	if (!data)
4783197704cSRobert Dolca 		return -ENOMEM;
4793197704cSRobert Dolca 
4803197704cSRobert Dolca 	i2c_set_clientdata(client, data);
4813197704cSRobert Dolca 	data->client = client;
4823197704cSRobert Dolca 
4833197704cSRobert Dolca 	error = silead_ts_set_default_fw_name(data, id);
4843197704cSRobert Dolca 	if (error)
4853197704cSRobert Dolca 		return error;
4863197704cSRobert Dolca 
4873197704cSRobert Dolca 	silead_ts_read_props(client);
4883197704cSRobert Dolca 
4893197704cSRobert Dolca 	/* We must have the IRQ provided by DT or ACPI subsytem */
4903197704cSRobert Dolca 	if (client->irq <= 0)
4913197704cSRobert Dolca 		return -ENODEV;
4923197704cSRobert Dolca 
4936f6deb48SHans de Goede 	data->regulators[0].supply = "vddio";
4946f6deb48SHans de Goede 	data->regulators[1].supply = "avdd";
4956f6deb48SHans de Goede 	error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
4966f6deb48SHans de Goede 					data->regulators);
4976f6deb48SHans de Goede 	if (error)
4986f6deb48SHans de Goede 		return error;
4996f6deb48SHans de Goede 
5006f6deb48SHans de Goede 	/*
5016f6deb48SHans de Goede 	 * Enable regulators at probe and disable them at remove, we need
5026f6deb48SHans de Goede 	 * to keep the chip powered otherwise it forgets its firmware.
5036f6deb48SHans de Goede 	 */
5046f6deb48SHans de Goede 	error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
5056f6deb48SHans de Goede 				      data->regulators);
5066f6deb48SHans de Goede 	if (error)
5076f6deb48SHans de Goede 		return error;
5086f6deb48SHans de Goede 
5096f6deb48SHans de Goede 	error = devm_add_action_or_reset(dev, silead_disable_regulator, data);
5106f6deb48SHans de Goede 	if (error)
5116f6deb48SHans de Goede 		return error;
5126f6deb48SHans de Goede 
5133197704cSRobert Dolca 	/* Power GPIO pin */
5145cab4d84SHans de Goede 	data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
5153197704cSRobert Dolca 	if (IS_ERR(data->gpio_power)) {
5163197704cSRobert Dolca 		if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER)
5173197704cSRobert Dolca 			dev_err(dev, "Shutdown GPIO request failed\n");
5183197704cSRobert Dolca 		return PTR_ERR(data->gpio_power);
5193197704cSRobert Dolca 	}
5203197704cSRobert Dolca 
5213197704cSRobert Dolca 	error = silead_ts_setup(client);
5223197704cSRobert Dolca 	if (error)
5233197704cSRobert Dolca 		return error;
5243197704cSRobert Dolca 
5253197704cSRobert Dolca 	error = silead_ts_request_input_dev(data);
5263197704cSRobert Dolca 	if (error)
5273197704cSRobert Dolca 		return error;
5283197704cSRobert Dolca 
5293197704cSRobert Dolca 	error = devm_request_threaded_irq(dev, client->irq,
5303197704cSRobert Dolca 					  NULL, silead_ts_threaded_irq_handler,
5313197704cSRobert Dolca 					  IRQF_ONESHOT, client->name, data);
5323197704cSRobert Dolca 	if (error) {
5333197704cSRobert Dolca 		if (error != -EPROBE_DEFER)
5343197704cSRobert Dolca 			dev_err(dev, "IRQ request failed %d\n", error);
5353197704cSRobert Dolca 		return error;
5363197704cSRobert Dolca 	}
5373197704cSRobert Dolca 
5383197704cSRobert Dolca 	return 0;
5393197704cSRobert Dolca }
5403197704cSRobert Dolca 
5413197704cSRobert Dolca static int __maybe_unused silead_ts_suspend(struct device *dev)
5423197704cSRobert Dolca {
5433197704cSRobert Dolca 	struct i2c_client *client = to_i2c_client(dev);
5443197704cSRobert Dolca 
5451943d172SHans de Goede 	disable_irq(client->irq);
5463197704cSRobert Dolca 	silead_ts_set_power(client, SILEAD_POWER_OFF);
5473197704cSRobert Dolca 	return 0;
5483197704cSRobert Dolca }
5493197704cSRobert Dolca 
5503197704cSRobert Dolca static int __maybe_unused silead_ts_resume(struct device *dev)
5513197704cSRobert Dolca {
5523197704cSRobert Dolca 	struct i2c_client *client = to_i2c_client(dev);
553dde27443SJulian Sax 	bool second_try = false;
5543197704cSRobert Dolca 	int error, status;
5553197704cSRobert Dolca 
5563197704cSRobert Dolca 	silead_ts_set_power(client, SILEAD_POWER_ON);
5573197704cSRobert Dolca 
558dde27443SJulian Sax  retry:
5593197704cSRobert Dolca 	error = silead_ts_reset(client);
5603197704cSRobert Dolca 	if (error)
5613197704cSRobert Dolca 		return error;
5623197704cSRobert Dolca 
563dde27443SJulian Sax 	if (second_try) {
564dde27443SJulian Sax 		error = silead_ts_load_fw(client);
565dde27443SJulian Sax 		if (error)
566dde27443SJulian Sax 			return error;
567dde27443SJulian Sax 	}
568dde27443SJulian Sax 
5693197704cSRobert Dolca 	error = silead_ts_startup(client);
5703197704cSRobert Dolca 	if (error)
5713197704cSRobert Dolca 		return error;
5723197704cSRobert Dolca 
5733197704cSRobert Dolca 	status = silead_ts_get_status(client);
5743197704cSRobert Dolca 	if (status != SILEAD_STATUS_OK) {
575dde27443SJulian Sax 		if (!second_try) {
576dde27443SJulian Sax 			second_try = true;
577dde27443SJulian Sax 			dev_dbg(dev, "Reloading firmware after unsuccessful resume\n");
578dde27443SJulian Sax 			goto retry;
579dde27443SJulian Sax 		}
5803197704cSRobert Dolca 		dev_err(dev, "Resume error, status: 0x%02x\n", status);
5813197704cSRobert Dolca 		return -ENODEV;
5823197704cSRobert Dolca 	}
5833197704cSRobert Dolca 
5841943d172SHans de Goede 	enable_irq(client->irq);
5851943d172SHans de Goede 
5863197704cSRobert Dolca 	return 0;
5873197704cSRobert Dolca }
5883197704cSRobert Dolca 
5893197704cSRobert Dolca static SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
5903197704cSRobert Dolca 
5913197704cSRobert Dolca static const struct i2c_device_id silead_ts_id[] = {
5923197704cSRobert Dolca 	{ "gsl1680", 0 },
5933197704cSRobert Dolca 	{ "gsl1688", 0 },
5943197704cSRobert Dolca 	{ "gsl3670", 0 },
5953197704cSRobert Dolca 	{ "gsl3675", 0 },
5963197704cSRobert Dolca 	{ "gsl3692", 0 },
5973197704cSRobert Dolca 	{ "mssl1680", 0 },
5983197704cSRobert Dolca 	{ }
5993197704cSRobert Dolca };
6003197704cSRobert Dolca MODULE_DEVICE_TABLE(i2c, silead_ts_id);
6013197704cSRobert Dolca 
6023197704cSRobert Dolca #ifdef CONFIG_ACPI
6033197704cSRobert Dolca static const struct acpi_device_id silead_ts_acpi_match[] = {
6043197704cSRobert Dolca 	{ "GSL1680", 0 },
6053197704cSRobert Dolca 	{ "GSL1688", 0 },
6063197704cSRobert Dolca 	{ "GSL3670", 0 },
6073197704cSRobert Dolca 	{ "GSL3675", 0 },
6083197704cSRobert Dolca 	{ "GSL3692", 0 },
6093197704cSRobert Dolca 	{ "MSSL1680", 0 },
6103993a163SMaruyama Shohei 	{ "MSSL0001", 0 },
611fc573af6SHans de Goede 	{ "MSSL0002", 0 },
6120e658060SDaniel Smith 	{ "MSSL0017", 0 },
6133197704cSRobert Dolca 	{ }
6143197704cSRobert Dolca };
6153197704cSRobert Dolca MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);
6163197704cSRobert Dolca #endif
6173197704cSRobert Dolca 
618483e55d9SJavier Martinez Canillas #ifdef CONFIG_OF
619483e55d9SJavier Martinez Canillas static const struct of_device_id silead_ts_of_match[] = {
620483e55d9SJavier Martinez Canillas 	{ .compatible = "silead,gsl1680" },
621483e55d9SJavier Martinez Canillas 	{ .compatible = "silead,gsl1688" },
622483e55d9SJavier Martinez Canillas 	{ .compatible = "silead,gsl3670" },
623483e55d9SJavier Martinez Canillas 	{ .compatible = "silead,gsl3675" },
624483e55d9SJavier Martinez Canillas 	{ .compatible = "silead,gsl3692" },
625483e55d9SJavier Martinez Canillas 	{ },
626483e55d9SJavier Martinez Canillas };
627483e55d9SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, silead_ts_of_match);
628483e55d9SJavier Martinez Canillas #endif
629483e55d9SJavier Martinez Canillas 
6303197704cSRobert Dolca static struct i2c_driver silead_ts_driver = {
6313197704cSRobert Dolca 	.probe = silead_ts_probe,
6323197704cSRobert Dolca 	.id_table = silead_ts_id,
6333197704cSRobert Dolca 	.driver = {
6343197704cSRobert Dolca 		.name = SILEAD_TS_NAME,
6353197704cSRobert Dolca 		.acpi_match_table = ACPI_PTR(silead_ts_acpi_match),
636483e55d9SJavier Martinez Canillas 		.of_match_table = of_match_ptr(silead_ts_of_match),
6373197704cSRobert Dolca 		.pm = &silead_ts_pm,
6383197704cSRobert Dolca 	},
6393197704cSRobert Dolca };
6403197704cSRobert Dolca module_i2c_driver(silead_ts_driver);
6413197704cSRobert Dolca 
6423197704cSRobert Dolca MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>");
6433197704cSRobert Dolca MODULE_DESCRIPTION("Silead I2C touchscreen driver");
6443197704cSRobert Dolca MODULE_LICENSE("GPL");
645