cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

imagis.c (8750B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3#include <linux/bits.h>
      4#include <linux/delay.h>
      5#include <linux/i2c.h>
      6#include <linux/input.h>
      7#include <linux/input/mt.h>
      8#include <linux/input/touchscreen.h>
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/property.h>
     12#include <linux/regulator/consumer.h>
     13
     14#define IST3038C_HIB_ACCESS		(0x800B << 16)
     15#define IST3038C_DIRECT_ACCESS		BIT(31)
     16#define IST3038C_REG_CHIPID		0x40001000
     17#define IST3038C_REG_HIB_BASE		0x30000100
     18#define IST3038C_REG_TOUCH_STATUS	(IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS)
     19#define IST3038C_REG_TOUCH_COORD	(IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x8)
     20#define IST3038C_REG_INTR_MESSAGE	(IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x4)
     21#define IST3038C_WHOAMI			0x38c
     22#define IST3038C_CHIP_ON_DELAY_MS	60
     23#define IST3038C_I2C_RETRY_COUNT	3
     24#define IST3038C_MAX_FINGER_NUM		10
     25#define IST3038C_X_MASK			GENMASK(23, 12)
     26#define IST3038C_X_SHIFT		12
     27#define IST3038C_Y_MASK			GENMASK(11, 0)
     28#define IST3038C_AREA_MASK		GENMASK(27, 24)
     29#define IST3038C_AREA_SHIFT		24
     30#define IST3038C_FINGER_COUNT_MASK	GENMASK(15, 12)
     31#define IST3038C_FINGER_COUNT_SHIFT	12
     32#define IST3038C_FINGER_STATUS_MASK	GENMASK(9, 0)
     33
     34struct imagis_ts {
     35	struct i2c_client *client;
     36	struct input_dev *input_dev;
     37	struct touchscreen_properties prop;
     38	struct regulator_bulk_data supplies[2];
     39};
     40
     41static int imagis_i2c_read_reg(struct imagis_ts *ts,
     42			       unsigned int reg, u32 *data)
     43{
     44	__be32 ret_be;
     45	__be32 reg_be = cpu_to_be32(reg);
     46	struct i2c_msg msg[] = {
     47		{
     48			.addr = ts->client->addr,
     49			.flags = 0,
     50			.buf = (unsigned char *)&reg_be,
     51			.len = sizeof(reg_be),
     52		}, {
     53			.addr = ts->client->addr,
     54			.flags = I2C_M_RD,
     55			.buf = (unsigned char *)&ret_be,
     56			.len = sizeof(ret_be),
     57		},
     58	};
     59	int ret, error;
     60	int retry = IST3038C_I2C_RETRY_COUNT;
     61
     62	/* Retry in case the controller fails to respond */
     63	do {
     64		ret = i2c_transfer(ts->client->adapter, msg, ARRAY_SIZE(msg));
     65		if (ret == ARRAY_SIZE(msg)) {
     66			*data = be32_to_cpu(ret_be);
     67			return 0;
     68		}
     69
     70		error = ret < 0 ? ret : -EIO;
     71		dev_err(&ts->client->dev,
     72			"%s - i2c_transfer failed: %d (%d)\n",
     73			__func__, error, ret);
     74	} while (--retry);
     75
     76	return error;
     77}
     78
     79static irqreturn_t imagis_interrupt(int irq, void *dev_id)
     80{
     81	struct imagis_ts *ts = dev_id;
     82	u32 intr_message, finger_status;
     83	unsigned int finger_count, finger_pressed;
     84	int i;
     85	int error;
     86
     87	error = imagis_i2c_read_reg(ts, IST3038C_REG_INTR_MESSAGE,
     88				    &intr_message);
     89	if (error) {
     90		dev_err(&ts->client->dev,
     91			"failed to read the interrupt message: %d\n", error);
     92		goto out;
     93	}
     94
     95	finger_count = (intr_message & IST3038C_FINGER_COUNT_MASK) >>
     96				IST3038C_FINGER_COUNT_SHIFT;
     97	if (finger_count > IST3038C_MAX_FINGER_NUM) {
     98		dev_err(&ts->client->dev,
     99			"finger count %d is more than maximum supported\n",
    100			finger_count);
    101		goto out;
    102	}
    103
    104	finger_pressed = intr_message & IST3038C_FINGER_STATUS_MASK;
    105
    106	for (i = 0; i < finger_count; i++) {
    107		error = imagis_i2c_read_reg(ts,
    108					    IST3038C_REG_TOUCH_COORD + (i * 4),
    109					    &finger_status);
    110		if (error) {
    111			dev_err(&ts->client->dev,
    112				"failed to read coordinates for finger %d: %d\n",
    113				i, error);
    114			goto out;
    115		}
    116
    117		input_mt_slot(ts->input_dev, i);
    118		input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
    119					   finger_pressed & BIT(i));
    120		touchscreen_report_pos(ts->input_dev, &ts->prop,
    121				       (finger_status & IST3038C_X_MASK) >>
    122						IST3038C_X_SHIFT,
    123				       finger_status & IST3038C_Y_MASK, 1);
    124		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
    125				 (finger_status & IST3038C_AREA_MASK) >>
    126					IST3038C_AREA_SHIFT);
    127	}
    128
    129	input_mt_sync_frame(ts->input_dev);
    130	input_sync(ts->input_dev);
    131
    132out:
    133	return IRQ_HANDLED;
    134}
    135
    136static void imagis_power_off(void *_ts)
    137{
    138	struct imagis_ts *ts = _ts;
    139
    140	regulator_bulk_disable(ARRAY_SIZE(ts->supplies), ts->supplies);
    141}
    142
    143static int imagis_power_on(struct imagis_ts *ts)
    144{
    145	int error;
    146
    147	error = regulator_bulk_enable(ARRAY_SIZE(ts->supplies), ts->supplies);
    148	if (error)
    149		return error;
    150
    151	msleep(IST3038C_CHIP_ON_DELAY_MS);
    152
    153	return 0;
    154}
    155
    156static int imagis_start(struct imagis_ts *ts)
    157{
    158	int error;
    159
    160	error = imagis_power_on(ts);
    161	if (error)
    162		return error;
    163
    164	enable_irq(ts->client->irq);
    165
    166	return 0;
    167}
    168
    169static int imagis_stop(struct imagis_ts *ts)
    170{
    171	disable_irq(ts->client->irq);
    172
    173	imagis_power_off(ts);
    174
    175	return 0;
    176}
    177
    178static int imagis_input_open(struct input_dev *dev)
    179{
    180	struct imagis_ts *ts = input_get_drvdata(dev);
    181
    182	return imagis_start(ts);
    183}
    184
    185static void imagis_input_close(struct input_dev *dev)
    186{
    187	struct imagis_ts *ts = input_get_drvdata(dev);
    188
    189	imagis_stop(ts);
    190}
    191
    192static int imagis_init_input_dev(struct imagis_ts *ts)
    193{
    194	struct input_dev *input_dev;
    195	int error;
    196
    197	input_dev = devm_input_allocate_device(&ts->client->dev);
    198	if (!input_dev)
    199		return -ENOMEM;
    200
    201	ts->input_dev = input_dev;
    202
    203	input_dev->name = "Imagis capacitive touchscreen";
    204	input_dev->phys = "input/ts";
    205	input_dev->id.bustype = BUS_I2C;
    206	input_dev->open = imagis_input_open;
    207	input_dev->close = imagis_input_close;
    208
    209	input_set_drvdata(input_dev, ts);
    210
    211	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
    212	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
    213	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
    214
    215	touchscreen_parse_properties(input_dev, true, &ts->prop);
    216	if (!ts->prop.max_x || !ts->prop.max_y) {
    217		dev_err(&ts->client->dev,
    218			"Touchscreen-size-x and/or touchscreen-size-y not set in dts\n");
    219		return -EINVAL;
    220	}
    221
    222	error = input_mt_init_slots(input_dev,
    223				    IST3038C_MAX_FINGER_NUM,
    224				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
    225	if (error) {
    226		dev_err(&ts->client->dev,
    227			"Failed to initialize MT slots: %d", error);
    228		return error;
    229	}
    230
    231	error = input_register_device(input_dev);
    232	if (error) {
    233		dev_err(&ts->client->dev,
    234			"Failed to register input device: %d", error);
    235		return error;
    236	}
    237
    238	return 0;
    239}
    240
    241static int imagis_init_regulators(struct imagis_ts *ts)
    242{
    243	struct i2c_client *client = ts->client;
    244
    245	ts->supplies[0].supply = "vdd";
    246	ts->supplies[1].supply = "vddio";
    247	return devm_regulator_bulk_get(&client->dev,
    248				       ARRAY_SIZE(ts->supplies),
    249				       ts->supplies);
    250}
    251
    252static int imagis_probe(struct i2c_client *i2c)
    253{
    254	struct device *dev = &i2c->dev;
    255	struct imagis_ts *ts;
    256	int chip_id, error;
    257
    258	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
    259	if (!ts)
    260		return -ENOMEM;
    261
    262	ts->client = i2c;
    263
    264	error = imagis_init_regulators(ts);
    265	if (error) {
    266		dev_err(dev, "regulator init error: %d\n", error);
    267		return error;
    268	}
    269
    270	error = imagis_power_on(ts);
    271	if (error) {
    272		dev_err(dev, "failed to enable regulators: %d\n", error);
    273		return error;
    274	}
    275
    276	error = devm_add_action_or_reset(dev, imagis_power_off, ts);
    277	if (error) {
    278		dev_err(dev, "failed to install poweroff action: %d\n", error);
    279		return error;
    280	}
    281
    282	error = imagis_i2c_read_reg(ts,
    283			IST3038C_REG_CHIPID | IST3038C_DIRECT_ACCESS,
    284			&chip_id);
    285	if (error) {
    286		dev_err(dev, "chip ID read failure: %d\n", error);
    287		return error;
    288	}
    289
    290	if (chip_id != IST3038C_WHOAMI) {
    291		dev_err(dev, "unknown chip ID: 0x%x\n", chip_id);
    292		return -EINVAL;
    293	}
    294
    295	error = devm_request_threaded_irq(dev, i2c->irq,
    296					  NULL, imagis_interrupt,
    297					  IRQF_ONESHOT | IRQF_NO_AUTOEN,
    298					  "imagis-touchscreen", ts);
    299	if (error) {
    300		dev_err(dev, "IRQ %d allocation failure: %d\n",
    301			i2c->irq, error);
    302		return error;
    303	}
    304
    305	error = imagis_init_input_dev(ts);
    306	if (error)
    307		return error;
    308
    309	return 0;
    310}
    311
    312static int __maybe_unused imagis_suspend(struct device *dev)
    313{
    314	struct i2c_client *client = to_i2c_client(dev);
    315	struct imagis_ts *ts = i2c_get_clientdata(client);
    316	int retval = 0;
    317
    318	mutex_lock(&ts->input_dev->mutex);
    319
    320	if (input_device_enabled(ts->input_dev))
    321		retval = imagis_stop(ts);
    322
    323	mutex_unlock(&ts->input_dev->mutex);
    324
    325	return retval;
    326}
    327
    328static int __maybe_unused imagis_resume(struct device *dev)
    329{
    330	struct i2c_client *client = to_i2c_client(dev);
    331	struct imagis_ts *ts = i2c_get_clientdata(client);
    332	int retval = 0;
    333
    334	mutex_lock(&ts->input_dev->mutex);
    335
    336	if (input_device_enabled(ts->input_dev))
    337		retval = imagis_start(ts);
    338
    339	mutex_unlock(&ts->input_dev->mutex);
    340
    341	return retval;
    342}
    343
    344static SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
    345
    346#ifdef CONFIG_OF
    347static const struct of_device_id imagis_of_match[] = {
    348	{ .compatible = "imagis,ist3038c", },
    349	{ },
    350};
    351MODULE_DEVICE_TABLE(of, imagis_of_match);
    352#endif
    353
    354static struct i2c_driver imagis_ts_driver = {
    355	.driver = {
    356		.name = "imagis-touchscreen",
    357		.pm = &imagis_pm_ops,
    358		.of_match_table = of_match_ptr(imagis_of_match),
    359	},
    360	.probe_new = imagis_probe,
    361};
    362
    363module_i2c_driver(imagis_ts_driver);
    364
    365MODULE_DESCRIPTION("Imagis IST3038C Touchscreen Driver");
    366MODULE_AUTHOR("Markuss Broks <markuss.broks@gmail.com>");
    367MODULE_LICENSE("GPL");