162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for MStar msg2638 touchscreens 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2021 Vincent Knecht <vincent.knecht@mailoo.org> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Checksum and IRQ handler based on mstar_drv_common.c and 862306a36Sopenharmony_ci * mstar_drv_mutual_fw_control.c 962306a36Sopenharmony_ci * Copyright (c) 2006-2012 MStar Semiconductor, Inc. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Driver structure based on zinitix.c by Michael Srba <Michael.Srba@seznam.cz> 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1662306a36Sopenharmony_ci#include <linux/i2c.h> 1762306a36Sopenharmony_ci#include <linux/input.h> 1862306a36Sopenharmony_ci#include <linux/input/mt.h> 1962306a36Sopenharmony_ci#include <linux/input/touchscreen.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/property.h> 2562306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MODE_DATA_RAW 0x5A 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define MSG2138_MAX_FINGERS 2 3162306a36Sopenharmony_ci#define MSG2638_MAX_FINGERS 5 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define MAX_BUTTONS 4 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define CHIP_ON_DELAY_MS 15 3662306a36Sopenharmony_ci#define FIRMWARE_ON_DELAY_MS 50 3762306a36Sopenharmony_ci#define RESET_DELAY_MIN_US 10000 3862306a36Sopenharmony_ci#define RESET_DELAY_MAX_US 11000 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct msg_chip_data { 4162306a36Sopenharmony_ci irq_handler_t irq_handler; 4262306a36Sopenharmony_ci unsigned int max_fingers; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct msg2138_packet { 4662306a36Sopenharmony_ci u8 xy_hi; /* higher bits of x and y coordinates */ 4762306a36Sopenharmony_ci u8 x_low; 4862306a36Sopenharmony_ci u8 y_low; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct msg2138_touch_event { 5262306a36Sopenharmony_ci u8 magic; 5362306a36Sopenharmony_ci struct msg2138_packet pkt[MSG2138_MAX_FINGERS]; 5462306a36Sopenharmony_ci u8 checksum; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct msg2638_packet { 5862306a36Sopenharmony_ci u8 xy_hi; /* higher bits of x and y coordinates */ 5962306a36Sopenharmony_ci u8 x_low; 6062306a36Sopenharmony_ci u8 y_low; 6162306a36Sopenharmony_ci u8 pressure; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct msg2638_touch_event { 6562306a36Sopenharmony_ci u8 mode; 6662306a36Sopenharmony_ci struct msg2638_packet pkt[MSG2638_MAX_FINGERS]; 6762306a36Sopenharmony_ci u8 proximity; 6862306a36Sopenharmony_ci u8 checksum; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct msg2638_ts_data { 7262306a36Sopenharmony_ci struct i2c_client *client; 7362306a36Sopenharmony_ci struct input_dev *input_dev; 7462306a36Sopenharmony_ci struct touchscreen_properties prop; 7562306a36Sopenharmony_ci struct regulator_bulk_data supplies[2]; 7662306a36Sopenharmony_ci struct gpio_desc *reset_gpiod; 7762306a36Sopenharmony_ci int max_fingers; 7862306a36Sopenharmony_ci u32 keycodes[MAX_BUTTONS]; 7962306a36Sopenharmony_ci int num_keycodes; 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic u8 msg2638_checksum(u8 *data, u32 length) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci s32 sum = 0; 8562306a36Sopenharmony_ci u32 i; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci for (i = 0; i < length; i++) 8862306a36Sopenharmony_ci sum += data[i]; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return (u8)((-sum) & 0xFF); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void msg2138_report_keys(struct msg2638_ts_data *msg2638, u8 keys) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci int i; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* keys can be 0x00 or 0xff when all keys have been released */ 9862306a36Sopenharmony_ci if (keys == 0xff) 9962306a36Sopenharmony_ci keys = 0; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (i = 0; i < msg2638->num_keycodes; ++i) 10262306a36Sopenharmony_ci input_report_key(msg2638->input_dev, msg2638->keycodes[i], 10362306a36Sopenharmony_ci keys & BIT(i)); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic irqreturn_t msg2138_ts_irq_handler(int irq, void *msg2638_handler) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct msg2638_ts_data *msg2638 = msg2638_handler; 10962306a36Sopenharmony_ci struct i2c_client *client = msg2638->client; 11062306a36Sopenharmony_ci struct input_dev *input = msg2638->input_dev; 11162306a36Sopenharmony_ci struct msg2138_touch_event touch_event; 11262306a36Sopenharmony_ci u32 len = sizeof(touch_event); 11362306a36Sopenharmony_ci struct i2c_msg msg[] = { 11462306a36Sopenharmony_ci { 11562306a36Sopenharmony_ci .addr = client->addr, 11662306a36Sopenharmony_ci .flags = I2C_M_RD, 11762306a36Sopenharmony_ci .len = sizeof(touch_event), 11862306a36Sopenharmony_ci .buf = (u8 *)&touch_event, 11962306a36Sopenharmony_ci }, 12062306a36Sopenharmony_ci }; 12162306a36Sopenharmony_ci struct msg2138_packet *p0, *p1; 12262306a36Sopenharmony_ci u16 x, y, delta_x, delta_y; 12362306a36Sopenharmony_ci int ret; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 12662306a36Sopenharmony_ci if (ret != ARRAY_SIZE(msg)) { 12762306a36Sopenharmony_ci dev_err(&client->dev, 12862306a36Sopenharmony_ci "Failed I2C transfer in irq handler: %d\n", 12962306a36Sopenharmony_ci ret < 0 ? ret : -EIO); 13062306a36Sopenharmony_ci goto out; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (msg2638_checksum((u8 *)&touch_event, len - 1) != 13462306a36Sopenharmony_ci touch_event.checksum) { 13562306a36Sopenharmony_ci dev_err(&client->dev, "Failed checksum!\n"); 13662306a36Sopenharmony_ci goto out; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci p0 = &touch_event.pkt[0]; 14062306a36Sopenharmony_ci p1 = &touch_event.pkt[1]; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Ignore non-pressed finger data, but check for key code */ 14362306a36Sopenharmony_ci if (p0->xy_hi == 0xFF && p0->x_low == 0xFF && p0->y_low == 0xFF) { 14462306a36Sopenharmony_ci if (p1->xy_hi == 0xFF && p1->y_low == 0xFF) 14562306a36Sopenharmony_ci msg2138_report_keys(msg2638, p1->x_low); 14662306a36Sopenharmony_ci goto report; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci x = ((p0->xy_hi & 0xF0) << 4) | p0->x_low; 15062306a36Sopenharmony_ci y = ((p0->xy_hi & 0x0F) << 8) | p0->y_low; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci input_mt_slot(input, 0); 15362306a36Sopenharmony_ci input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 15462306a36Sopenharmony_ci touchscreen_report_pos(input, &msg2638->prop, x, y, true); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Ignore non-pressed finger data */ 15762306a36Sopenharmony_ci if (p1->xy_hi == 0xFF && p1->x_low == 0xFF && p1->y_low == 0xFF) 15862306a36Sopenharmony_ci goto report; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Second finger is reported as a delta position */ 16162306a36Sopenharmony_ci delta_x = ((p1->xy_hi & 0xF0) << 4) | p1->x_low; 16262306a36Sopenharmony_ci delta_y = ((p1->xy_hi & 0x0F) << 8) | p1->y_low; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Ignore second finger if both deltas equal 0 */ 16562306a36Sopenharmony_ci if (delta_x == 0 && delta_y == 0) 16662306a36Sopenharmony_ci goto report; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci x += delta_x; 16962306a36Sopenharmony_ci y += delta_y; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci input_mt_slot(input, 1); 17262306a36Sopenharmony_ci input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 17362306a36Sopenharmony_ci touchscreen_report_pos(input, &msg2638->prop, x, y, true); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cireport: 17662306a36Sopenharmony_ci input_mt_sync_frame(msg2638->input_dev); 17762306a36Sopenharmony_ci input_sync(msg2638->input_dev); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciout: 18062306a36Sopenharmony_ci return IRQ_HANDLED; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic irqreturn_t msg2638_ts_irq_handler(int irq, void *msg2638_handler) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct msg2638_ts_data *msg2638 = msg2638_handler; 18662306a36Sopenharmony_ci struct i2c_client *client = msg2638->client; 18762306a36Sopenharmony_ci struct input_dev *input = msg2638->input_dev; 18862306a36Sopenharmony_ci struct msg2638_touch_event touch_event; 18962306a36Sopenharmony_ci u32 len = sizeof(touch_event); 19062306a36Sopenharmony_ci struct i2c_msg msg[] = { 19162306a36Sopenharmony_ci { 19262306a36Sopenharmony_ci .addr = client->addr, 19362306a36Sopenharmony_ci .flags = I2C_M_RD, 19462306a36Sopenharmony_ci .len = sizeof(touch_event), 19562306a36Sopenharmony_ci .buf = (u8 *)&touch_event, 19662306a36Sopenharmony_ci }, 19762306a36Sopenharmony_ci }; 19862306a36Sopenharmony_ci struct msg2638_packet *p; 19962306a36Sopenharmony_ci u16 x, y; 20062306a36Sopenharmony_ci int ret; 20162306a36Sopenharmony_ci int i; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 20462306a36Sopenharmony_ci if (ret != ARRAY_SIZE(msg)) { 20562306a36Sopenharmony_ci dev_err(&client->dev, 20662306a36Sopenharmony_ci "Failed I2C transfer in irq handler: %d\n", 20762306a36Sopenharmony_ci ret < 0 ? ret : -EIO); 20862306a36Sopenharmony_ci goto out; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (touch_event.mode != MODE_DATA_RAW) 21262306a36Sopenharmony_ci goto out; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (msg2638_checksum((u8 *)&touch_event, len - 1) != 21562306a36Sopenharmony_ci touch_event.checksum) { 21662306a36Sopenharmony_ci dev_err(&client->dev, "Failed checksum!\n"); 21762306a36Sopenharmony_ci goto out; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci for (i = 0; i < msg2638->max_fingers; i++) { 22162306a36Sopenharmony_ci p = &touch_event.pkt[i]; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Ignore non-pressed finger data */ 22462306a36Sopenharmony_ci if (p->xy_hi == 0xFF && p->x_low == 0xFF && p->y_low == 0xFF) 22562306a36Sopenharmony_ci continue; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci x = (((p->xy_hi & 0xF0) << 4) | p->x_low); 22862306a36Sopenharmony_ci y = (((p->xy_hi & 0x0F) << 8) | p->y_low); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci input_mt_slot(input, i); 23162306a36Sopenharmony_ci input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 23262306a36Sopenharmony_ci touchscreen_report_pos(input, &msg2638->prop, x, y, true); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci input_mt_sync_frame(msg2638->input_dev); 23662306a36Sopenharmony_ci input_sync(msg2638->input_dev); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ciout: 23962306a36Sopenharmony_ci return IRQ_HANDLED; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void msg2638_reset(struct msg2638_ts_data *msg2638) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci gpiod_set_value_cansleep(msg2638->reset_gpiod, 1); 24562306a36Sopenharmony_ci usleep_range(RESET_DELAY_MIN_US, RESET_DELAY_MAX_US); 24662306a36Sopenharmony_ci gpiod_set_value_cansleep(msg2638->reset_gpiod, 0); 24762306a36Sopenharmony_ci msleep(FIRMWARE_ON_DELAY_MS); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int msg2638_start(struct msg2638_ts_data *msg2638) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci int error; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci error = regulator_bulk_enable(ARRAY_SIZE(msg2638->supplies), 25562306a36Sopenharmony_ci msg2638->supplies); 25662306a36Sopenharmony_ci if (error) { 25762306a36Sopenharmony_ci dev_err(&msg2638->client->dev, 25862306a36Sopenharmony_ci "Failed to enable regulators: %d\n", error); 25962306a36Sopenharmony_ci return error; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci msleep(CHIP_ON_DELAY_MS); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci msg2638_reset(msg2638); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci enable_irq(msg2638->client->irq); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int msg2638_stop(struct msg2638_ts_data *msg2638) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci int error; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci disable_irq(msg2638->client->irq); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci error = regulator_bulk_disable(ARRAY_SIZE(msg2638->supplies), 27862306a36Sopenharmony_ci msg2638->supplies); 27962306a36Sopenharmony_ci if (error) { 28062306a36Sopenharmony_ci dev_err(&msg2638->client->dev, 28162306a36Sopenharmony_ci "Failed to disable regulators: %d\n", error); 28262306a36Sopenharmony_ci return error; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int msg2638_input_open(struct input_dev *dev) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct msg2638_ts_data *msg2638 = input_get_drvdata(dev); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return msg2638_start(msg2638); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic void msg2638_input_close(struct input_dev *dev) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct msg2638_ts_data *msg2638 = input_get_drvdata(dev); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci msg2638_stop(msg2638); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int msg2638_init_input_dev(struct msg2638_ts_data *msg2638) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct device *dev = &msg2638->client->dev; 30562306a36Sopenharmony_ci struct input_dev *input_dev; 30662306a36Sopenharmony_ci int error; 30762306a36Sopenharmony_ci int i; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci input_dev = devm_input_allocate_device(dev); 31062306a36Sopenharmony_ci if (!input_dev) { 31162306a36Sopenharmony_ci dev_err(dev, "Failed to allocate input device.\n"); 31262306a36Sopenharmony_ci return -ENOMEM; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci input_set_drvdata(input_dev, msg2638); 31662306a36Sopenharmony_ci msg2638->input_dev = input_dev; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci input_dev->name = "MStar TouchScreen"; 31962306a36Sopenharmony_ci input_dev->phys = "input/ts"; 32062306a36Sopenharmony_ci input_dev->id.bustype = BUS_I2C; 32162306a36Sopenharmony_ci input_dev->open = msg2638_input_open; 32262306a36Sopenharmony_ci input_dev->close = msg2638_input_close; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (msg2638->num_keycodes) { 32562306a36Sopenharmony_ci input_dev->keycode = msg2638->keycodes; 32662306a36Sopenharmony_ci input_dev->keycodemax = msg2638->num_keycodes; 32762306a36Sopenharmony_ci input_dev->keycodesize = sizeof(msg2638->keycodes[0]); 32862306a36Sopenharmony_ci for (i = 0; i < msg2638->num_keycodes; i++) 32962306a36Sopenharmony_ci input_set_capability(input_dev, 33062306a36Sopenharmony_ci EV_KEY, msg2638->keycodes[i]); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); 33462306a36Sopenharmony_ci input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci touchscreen_parse_properties(input_dev, true, &msg2638->prop); 33762306a36Sopenharmony_ci if (!msg2638->prop.max_x || !msg2638->prop.max_y) { 33862306a36Sopenharmony_ci dev_err(dev, "touchscreen-size-x and/or touchscreen-size-y not set in properties\n"); 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci error = input_mt_init_slots(input_dev, msg2638->max_fingers, 34362306a36Sopenharmony_ci INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 34462306a36Sopenharmony_ci if (error) { 34562306a36Sopenharmony_ci dev_err(dev, "Failed to initialize MT slots: %d\n", error); 34662306a36Sopenharmony_ci return error; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci error = input_register_device(input_dev); 35062306a36Sopenharmony_ci if (error) { 35162306a36Sopenharmony_ci dev_err(dev, "Failed to register input device: %d\n", error); 35262306a36Sopenharmony_ci return error; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int msg2638_ts_probe(struct i2c_client *client) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci const struct msg_chip_data *chip_data; 36162306a36Sopenharmony_ci struct device *dev = &client->dev; 36262306a36Sopenharmony_ci struct msg2638_ts_data *msg2638; 36362306a36Sopenharmony_ci int error; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 36662306a36Sopenharmony_ci dev_err(dev, "Failed to assert adapter's support for plain I2C.\n"); 36762306a36Sopenharmony_ci return -ENXIO; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci msg2638 = devm_kzalloc(dev, sizeof(*msg2638), GFP_KERNEL); 37162306a36Sopenharmony_ci if (!msg2638) 37262306a36Sopenharmony_ci return -ENOMEM; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci msg2638->client = client; 37562306a36Sopenharmony_ci i2c_set_clientdata(client, msg2638); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci chip_data = device_get_match_data(&client->dev); 37862306a36Sopenharmony_ci if (!chip_data || !chip_data->max_fingers) { 37962306a36Sopenharmony_ci dev_err(dev, "Invalid or missing chip data\n"); 38062306a36Sopenharmony_ci return -EINVAL; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci msg2638->max_fingers = chip_data->max_fingers; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci msg2638->supplies[0].supply = "vdd"; 38662306a36Sopenharmony_ci msg2638->supplies[1].supply = "vddio"; 38762306a36Sopenharmony_ci error = devm_regulator_bulk_get(dev, ARRAY_SIZE(msg2638->supplies), 38862306a36Sopenharmony_ci msg2638->supplies); 38962306a36Sopenharmony_ci if (error) { 39062306a36Sopenharmony_ci dev_err(dev, "Failed to get regulators: %d\n", error); 39162306a36Sopenharmony_ci return error; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci msg2638->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 39562306a36Sopenharmony_ci if (IS_ERR(msg2638->reset_gpiod)) { 39662306a36Sopenharmony_ci error = PTR_ERR(msg2638->reset_gpiod); 39762306a36Sopenharmony_ci dev_err(dev, "Failed to request reset GPIO: %d\n", error); 39862306a36Sopenharmony_ci return error; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci msg2638->num_keycodes = device_property_count_u32(dev, 40262306a36Sopenharmony_ci "linux,keycodes"); 40362306a36Sopenharmony_ci if (msg2638->num_keycodes == -EINVAL) { 40462306a36Sopenharmony_ci msg2638->num_keycodes = 0; 40562306a36Sopenharmony_ci } else if (msg2638->num_keycodes < 0) { 40662306a36Sopenharmony_ci dev_err(dev, "Unable to parse linux,keycodes property: %d\n", 40762306a36Sopenharmony_ci msg2638->num_keycodes); 40862306a36Sopenharmony_ci return msg2638->num_keycodes; 40962306a36Sopenharmony_ci } else if (msg2638->num_keycodes > ARRAY_SIZE(msg2638->keycodes)) { 41062306a36Sopenharmony_ci dev_warn(dev, "Found %d linux,keycodes but max is %zd, ignoring the rest\n", 41162306a36Sopenharmony_ci msg2638->num_keycodes, ARRAY_SIZE(msg2638->keycodes)); 41262306a36Sopenharmony_ci msg2638->num_keycodes = ARRAY_SIZE(msg2638->keycodes); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (msg2638->num_keycodes > 0) { 41662306a36Sopenharmony_ci error = device_property_read_u32_array(dev, "linux,keycodes", 41762306a36Sopenharmony_ci msg2638->keycodes, 41862306a36Sopenharmony_ci msg2638->num_keycodes); 41962306a36Sopenharmony_ci if (error) { 42062306a36Sopenharmony_ci dev_err(dev, "Unable to read linux,keycodes values: %d\n", 42162306a36Sopenharmony_ci error); 42262306a36Sopenharmony_ci return error; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci error = devm_request_threaded_irq(dev, client->irq, 42762306a36Sopenharmony_ci NULL, chip_data->irq_handler, 42862306a36Sopenharmony_ci IRQF_ONESHOT | IRQF_NO_AUTOEN, 42962306a36Sopenharmony_ci client->name, msg2638); 43062306a36Sopenharmony_ci if (error) { 43162306a36Sopenharmony_ci dev_err(dev, "Failed to request IRQ: %d\n", error); 43262306a36Sopenharmony_ci return error; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci error = msg2638_init_input_dev(msg2638); 43662306a36Sopenharmony_ci if (error) { 43762306a36Sopenharmony_ci dev_err(dev, "Failed to initialize input device: %d\n", error); 43862306a36Sopenharmony_ci return error; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int msg2638_suspend(struct device *dev) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 44762306a36Sopenharmony_ci struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci mutex_lock(&msg2638->input_dev->mutex); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (input_device_enabled(msg2638->input_dev)) 45262306a36Sopenharmony_ci msg2638_stop(msg2638); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci mutex_unlock(&msg2638->input_dev->mutex); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int msg2638_resume(struct device *dev) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 46262306a36Sopenharmony_ci struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client); 46362306a36Sopenharmony_ci int ret = 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci mutex_lock(&msg2638->input_dev->mutex); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (input_device_enabled(msg2638->input_dev)) 46862306a36Sopenharmony_ci ret = msg2638_start(msg2638); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci mutex_unlock(&msg2638->input_dev->mutex); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return ret; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic const struct msg_chip_data msg2138_data = { 47862306a36Sopenharmony_ci .irq_handler = msg2138_ts_irq_handler, 47962306a36Sopenharmony_ci .max_fingers = MSG2138_MAX_FINGERS, 48062306a36Sopenharmony_ci}; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic const struct msg_chip_data msg2638_data = { 48362306a36Sopenharmony_ci .irq_handler = msg2638_ts_irq_handler, 48462306a36Sopenharmony_ci .max_fingers = MSG2638_MAX_FINGERS, 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic const struct of_device_id msg2638_of_match[] = { 48862306a36Sopenharmony_ci { .compatible = "mstar,msg2138", .data = &msg2138_data }, 48962306a36Sopenharmony_ci { .compatible = "mstar,msg2638", .data = &msg2638_data }, 49062306a36Sopenharmony_ci { } 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, msg2638_of_match); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic struct i2c_driver msg2638_ts_driver = { 49562306a36Sopenharmony_ci .probe = msg2638_ts_probe, 49662306a36Sopenharmony_ci .driver = { 49762306a36Sopenharmony_ci .name = "MStar-TS", 49862306a36Sopenharmony_ci .pm = pm_sleep_ptr(&msg2638_pm_ops), 49962306a36Sopenharmony_ci .of_match_table = msg2638_of_match, 50062306a36Sopenharmony_ci }, 50162306a36Sopenharmony_ci}; 50262306a36Sopenharmony_cimodule_i2c_driver(msg2638_ts_driver); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciMODULE_AUTHOR("Vincent Knecht <vincent.knecht@mailoo.org>"); 50562306a36Sopenharmony_ciMODULE_DESCRIPTION("MStar MSG2638 touchscreen driver"); 50662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 507