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