18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Melfas MMS114/MMS152 touchscreen device driver 38c2ecf20Sopenharmony_ci// 48c2ecf20Sopenharmony_ci// Copyright (c) 2012 Samsung Electronics Co., Ltd. 58c2ecf20Sopenharmony_ci// Author: Joonyoung Shim <jy0922.shim@samsung.com> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/of_device.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 138c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* Write only registers */ 198c2ecf20Sopenharmony_ci#define MMS114_MODE_CONTROL 0x01 208c2ecf20Sopenharmony_ci#define MMS114_OPERATION_MODE_MASK 0xE 218c2ecf20Sopenharmony_ci#define MMS114_ACTIVE BIT(1) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define MMS114_XY_RESOLUTION_H 0x02 248c2ecf20Sopenharmony_ci#define MMS114_X_RESOLUTION 0x03 258c2ecf20Sopenharmony_ci#define MMS114_Y_RESOLUTION 0x04 268c2ecf20Sopenharmony_ci#define MMS114_CONTACT_THRESHOLD 0x05 278c2ecf20Sopenharmony_ci#define MMS114_MOVING_THRESHOLD 0x06 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* Read only registers */ 308c2ecf20Sopenharmony_ci#define MMS114_PACKET_SIZE 0x0F 318c2ecf20Sopenharmony_ci#define MMS114_INFORMATION 0x10 328c2ecf20Sopenharmony_ci#define MMS114_TSP_REV 0xF0 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define MMS152_FW_REV 0xE1 358c2ecf20Sopenharmony_ci#define MMS152_COMPAT_GROUP 0xF2 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Minimum delay time is 50us between stop and start signal of i2c */ 388c2ecf20Sopenharmony_ci#define MMS114_I2C_DELAY 50 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 200ms needs after power on */ 418c2ecf20Sopenharmony_ci#define MMS114_POWERON_DELAY 200 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* Touchscreen absolute values */ 448c2ecf20Sopenharmony_ci#define MMS114_MAX_AREA 0xff 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define MMS114_MAX_TOUCH 10 478c2ecf20Sopenharmony_ci#define MMS114_PACKET_NUM 8 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Touch type */ 508c2ecf20Sopenharmony_ci#define MMS114_TYPE_NONE 0 518c2ecf20Sopenharmony_ci#define MMS114_TYPE_TOUCHSCREEN 1 528c2ecf20Sopenharmony_ci#define MMS114_TYPE_TOUCHKEY 2 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cienum mms_type { 558c2ecf20Sopenharmony_ci TYPE_MMS114 = 114, 568c2ecf20Sopenharmony_ci TYPE_MMS152 = 152, 578c2ecf20Sopenharmony_ci TYPE_MMS345L = 345, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct mms114_data { 618c2ecf20Sopenharmony_ci struct i2c_client *client; 628c2ecf20Sopenharmony_ci struct input_dev *input_dev; 638c2ecf20Sopenharmony_ci struct regulator *core_reg; 648c2ecf20Sopenharmony_ci struct regulator *io_reg; 658c2ecf20Sopenharmony_ci struct touchscreen_properties props; 668c2ecf20Sopenharmony_ci enum mms_type type; 678c2ecf20Sopenharmony_ci unsigned int contact_threshold; 688c2ecf20Sopenharmony_ci unsigned int moving_threshold; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Use cache data for mode control register(write only) */ 718c2ecf20Sopenharmony_ci u8 cache_mode_control; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct mms114_touch { 758c2ecf20Sopenharmony_ci u8 id:4, reserved_bit4:1, type:2, pressed:1; 768c2ecf20Sopenharmony_ci u8 x_hi:4, y_hi:4; 778c2ecf20Sopenharmony_ci u8 x_lo; 788c2ecf20Sopenharmony_ci u8 y_lo; 798c2ecf20Sopenharmony_ci u8 width; 808c2ecf20Sopenharmony_ci u8 strength; 818c2ecf20Sopenharmony_ci u8 reserved[2]; 828c2ecf20Sopenharmony_ci} __packed; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int __mms114_read_reg(struct mms114_data *data, unsigned int reg, 858c2ecf20Sopenharmony_ci unsigned int len, u8 *val) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 888c2ecf20Sopenharmony_ci struct i2c_msg xfer[2]; 898c2ecf20Sopenharmony_ci u8 buf = reg & 0xff; 908c2ecf20Sopenharmony_ci int error; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (reg <= MMS114_MODE_CONTROL && reg + len > MMS114_MODE_CONTROL) 938c2ecf20Sopenharmony_ci BUG(); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Write register */ 968c2ecf20Sopenharmony_ci xfer[0].addr = client->addr; 978c2ecf20Sopenharmony_ci xfer[0].flags = client->flags & I2C_M_TEN; 988c2ecf20Sopenharmony_ci xfer[0].len = 1; 998c2ecf20Sopenharmony_ci xfer[0].buf = &buf; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Read data */ 1028c2ecf20Sopenharmony_ci xfer[1].addr = client->addr; 1038c2ecf20Sopenharmony_ci xfer[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; 1048c2ecf20Sopenharmony_ci xfer[1].len = len; 1058c2ecf20Sopenharmony_ci xfer[1].buf = val; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci error = i2c_transfer(client->adapter, xfer, 2); 1088c2ecf20Sopenharmony_ci if (error != 2) { 1098c2ecf20Sopenharmony_ci dev_err(&client->dev, 1108c2ecf20Sopenharmony_ci "%s: i2c transfer failed (%d)\n", __func__, error); 1118c2ecf20Sopenharmony_ci return error < 0 ? error : -EIO; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci udelay(MMS114_I2C_DELAY); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int mms114_read_reg(struct mms114_data *data, unsigned int reg) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci u8 val; 1218c2ecf20Sopenharmony_ci int error; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (reg == MMS114_MODE_CONTROL) 1248c2ecf20Sopenharmony_ci return data->cache_mode_control; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci error = __mms114_read_reg(data, reg, 1, &val); 1278c2ecf20Sopenharmony_ci return error < 0 ? error : val; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int mms114_write_reg(struct mms114_data *data, unsigned int reg, 1318c2ecf20Sopenharmony_ci unsigned int val) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 1348c2ecf20Sopenharmony_ci u8 buf[2]; 1358c2ecf20Sopenharmony_ci int error; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci buf[0] = reg & 0xff; 1388c2ecf20Sopenharmony_ci buf[1] = val & 0xff; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci error = i2c_master_send(client, buf, 2); 1418c2ecf20Sopenharmony_ci if (error != 2) { 1428c2ecf20Sopenharmony_ci dev_err(&client->dev, 1438c2ecf20Sopenharmony_ci "%s: i2c send failed (%d)\n", __func__, error); 1448c2ecf20Sopenharmony_ci return error < 0 ? error : -EIO; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci udelay(MMS114_I2C_DELAY); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (reg == MMS114_MODE_CONTROL) 1498c2ecf20Sopenharmony_ci data->cache_mode_control = val; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void mms114_process_mt(struct mms114_data *data, struct mms114_touch *touch) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 1578c2ecf20Sopenharmony_ci struct input_dev *input_dev = data->input_dev; 1588c2ecf20Sopenharmony_ci unsigned int id; 1598c2ecf20Sopenharmony_ci unsigned int x; 1608c2ecf20Sopenharmony_ci unsigned int y; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (touch->id > MMS114_MAX_TOUCH) { 1638c2ecf20Sopenharmony_ci dev_err(&client->dev, "Wrong touch id (%d)\n", touch->id); 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (touch->type != MMS114_TYPE_TOUCHSCREEN) { 1688c2ecf20Sopenharmony_ci dev_err(&client->dev, "Wrong touch type (%d)\n", touch->type); 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci id = touch->id - 1; 1738c2ecf20Sopenharmony_ci x = touch->x_lo | touch->x_hi << 8; 1748c2ecf20Sopenharmony_ci y = touch->y_lo | touch->y_hi << 8; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 1778c2ecf20Sopenharmony_ci "id: %d, type: %d, pressed: %d, x: %d, y: %d, width: %d, strength: %d\n", 1788c2ecf20Sopenharmony_ci id, touch->type, touch->pressed, 1798c2ecf20Sopenharmony_ci x, y, touch->width, touch->strength); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci input_mt_slot(input_dev, id); 1828c2ecf20Sopenharmony_ci input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, touch->pressed); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (touch->pressed) { 1858c2ecf20Sopenharmony_ci touchscreen_report_pos(input_dev, &data->props, x, y, true); 1868c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, touch->width); 1878c2ecf20Sopenharmony_ci input_report_abs(input_dev, ABS_MT_PRESSURE, touch->strength); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic irqreturn_t mms114_interrupt(int irq, void *dev_id) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct mms114_data *data = dev_id; 1948c2ecf20Sopenharmony_ci struct input_dev *input_dev = data->input_dev; 1958c2ecf20Sopenharmony_ci struct mms114_touch touch[MMS114_MAX_TOUCH]; 1968c2ecf20Sopenharmony_ci int packet_size; 1978c2ecf20Sopenharmony_ci int touch_size; 1988c2ecf20Sopenharmony_ci int index; 1998c2ecf20Sopenharmony_ci int error; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci mutex_lock(&input_dev->mutex); 2028c2ecf20Sopenharmony_ci if (!input_dev->users) { 2038c2ecf20Sopenharmony_ci mutex_unlock(&input_dev->mutex); 2048c2ecf20Sopenharmony_ci goto out; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci mutex_unlock(&input_dev->mutex); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci packet_size = mms114_read_reg(data, MMS114_PACKET_SIZE); 2098c2ecf20Sopenharmony_ci if (packet_size <= 0) 2108c2ecf20Sopenharmony_ci goto out; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci touch_size = packet_size / MMS114_PACKET_NUM; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size, 2158c2ecf20Sopenharmony_ci (u8 *)touch); 2168c2ecf20Sopenharmony_ci if (error < 0) 2178c2ecf20Sopenharmony_ci goto out; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci for (index = 0; index < touch_size; index++) 2208c2ecf20Sopenharmony_ci mms114_process_mt(data, touch + index); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci input_mt_report_pointer_emulation(data->input_dev, true); 2238c2ecf20Sopenharmony_ci input_sync(data->input_dev); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciout: 2268c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int mms114_set_active(struct mms114_data *data, bool active) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int val; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci val = mms114_read_reg(data, MMS114_MODE_CONTROL); 2348c2ecf20Sopenharmony_ci if (val < 0) 2358c2ecf20Sopenharmony_ci return val; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci val &= ~MMS114_OPERATION_MODE_MASK; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* If active is false, sleep mode */ 2408c2ecf20Sopenharmony_ci if (active) 2418c2ecf20Sopenharmony_ci val |= MMS114_ACTIVE; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return mms114_write_reg(data, MMS114_MODE_CONTROL, val); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int mms114_get_version(struct mms114_data *data) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct device *dev = &data->client->dev; 2498c2ecf20Sopenharmony_ci u8 buf[6]; 2508c2ecf20Sopenharmony_ci int group; 2518c2ecf20Sopenharmony_ci int error; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci switch (data->type) { 2548c2ecf20Sopenharmony_ci case TYPE_MMS345L: 2558c2ecf20Sopenharmony_ci error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf); 2568c2ecf20Sopenharmony_ci if (error) 2578c2ecf20Sopenharmony_ci return error; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x\n", 2608c2ecf20Sopenharmony_ci buf[0], buf[1], buf[2]); 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci case TYPE_MMS152: 2648c2ecf20Sopenharmony_ci error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf); 2658c2ecf20Sopenharmony_ci if (error) 2668c2ecf20Sopenharmony_ci return error; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci group = i2c_smbus_read_byte_data(data->client, 2698c2ecf20Sopenharmony_ci MMS152_COMPAT_GROUP); 2708c2ecf20Sopenharmony_ci if (group < 0) 2718c2ecf20Sopenharmony_ci return group; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x, Compat group: %c\n", 2748c2ecf20Sopenharmony_ci buf[0], buf[1], buf[2], group); 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci case TYPE_MMS114: 2788c2ecf20Sopenharmony_ci error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf); 2798c2ecf20Sopenharmony_ci if (error) 2808c2ecf20Sopenharmony_ci return error; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n", 2838c2ecf20Sopenharmony_ci buf[0], buf[1], buf[3]); 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int mms114_setup_regs(struct mms114_data *data) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci const struct touchscreen_properties *props = &data->props; 2938c2ecf20Sopenharmony_ci int val; 2948c2ecf20Sopenharmony_ci int error; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci error = mms114_get_version(data); 2978c2ecf20Sopenharmony_ci if (error < 0) 2988c2ecf20Sopenharmony_ci return error; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Only MMS114 has configuration and power on registers */ 3018c2ecf20Sopenharmony_ci if (data->type != TYPE_MMS114) 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci error = mms114_set_active(data, true); 3058c2ecf20Sopenharmony_ci if (error < 0) 3068c2ecf20Sopenharmony_ci return error; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci val = (props->max_x >> 8) & 0xf; 3098c2ecf20Sopenharmony_ci val |= ((props->max_y >> 8) & 0xf) << 4; 3108c2ecf20Sopenharmony_ci error = mms114_write_reg(data, MMS114_XY_RESOLUTION_H, val); 3118c2ecf20Sopenharmony_ci if (error < 0) 3128c2ecf20Sopenharmony_ci return error; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci val = props->max_x & 0xff; 3158c2ecf20Sopenharmony_ci error = mms114_write_reg(data, MMS114_X_RESOLUTION, val); 3168c2ecf20Sopenharmony_ci if (error < 0) 3178c2ecf20Sopenharmony_ci return error; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci val = props->max_x & 0xff; 3208c2ecf20Sopenharmony_ci error = mms114_write_reg(data, MMS114_Y_RESOLUTION, val); 3218c2ecf20Sopenharmony_ci if (error < 0) 3228c2ecf20Sopenharmony_ci return error; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (data->contact_threshold) { 3258c2ecf20Sopenharmony_ci error = mms114_write_reg(data, MMS114_CONTACT_THRESHOLD, 3268c2ecf20Sopenharmony_ci data->contact_threshold); 3278c2ecf20Sopenharmony_ci if (error < 0) 3288c2ecf20Sopenharmony_ci return error; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (data->moving_threshold) { 3328c2ecf20Sopenharmony_ci error = mms114_write_reg(data, MMS114_MOVING_THRESHOLD, 3338c2ecf20Sopenharmony_ci data->moving_threshold); 3348c2ecf20Sopenharmony_ci if (error < 0) 3358c2ecf20Sopenharmony_ci return error; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int mms114_start(struct mms114_data *data) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 3448c2ecf20Sopenharmony_ci int error; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci error = regulator_enable(data->core_reg); 3478c2ecf20Sopenharmony_ci if (error) { 3488c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to enable avdd: %d\n", error); 3498c2ecf20Sopenharmony_ci return error; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci error = regulator_enable(data->io_reg); 3538c2ecf20Sopenharmony_ci if (error) { 3548c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to enable vdd: %d\n", error); 3558c2ecf20Sopenharmony_ci regulator_disable(data->core_reg); 3568c2ecf20Sopenharmony_ci return error; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci msleep(MMS114_POWERON_DELAY); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci error = mms114_setup_regs(data); 3628c2ecf20Sopenharmony_ci if (error < 0) { 3638c2ecf20Sopenharmony_ci regulator_disable(data->io_reg); 3648c2ecf20Sopenharmony_ci regulator_disable(data->core_reg); 3658c2ecf20Sopenharmony_ci return error; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci enable_irq(client->irq); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic void mms114_stop(struct mms114_data *data) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 3768c2ecf20Sopenharmony_ci int error; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci disable_irq(client->irq); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci error = regulator_disable(data->io_reg); 3818c2ecf20Sopenharmony_ci if (error) 3828c2ecf20Sopenharmony_ci dev_warn(&client->dev, "Failed to disable vdd: %d\n", error); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci error = regulator_disable(data->core_reg); 3858c2ecf20Sopenharmony_ci if (error) 3868c2ecf20Sopenharmony_ci dev_warn(&client->dev, "Failed to disable avdd: %d\n", error); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int mms114_input_open(struct input_dev *dev) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct mms114_data *data = input_get_drvdata(dev); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return mms114_start(data); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic void mms114_input_close(struct input_dev *dev) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct mms114_data *data = input_get_drvdata(dev); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci mms114_stop(data); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int mms114_parse_legacy_bindings(struct mms114_data *data) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct device *dev = &data->client->dev; 4068c2ecf20Sopenharmony_ci struct touchscreen_properties *props = &data->props; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "x-size", &props->max_x)) { 4098c2ecf20Sopenharmony_ci dev_dbg(dev, "failed to get legacy x-size property\n"); 4108c2ecf20Sopenharmony_ci return -EINVAL; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "y-size", &props->max_y)) { 4148c2ecf20Sopenharmony_ci dev_dbg(dev, "failed to get legacy y-size property\n"); 4158c2ecf20Sopenharmony_ci return -EINVAL; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci device_property_read_u32(dev, "contact-threshold", 4198c2ecf20Sopenharmony_ci &data->contact_threshold); 4208c2ecf20Sopenharmony_ci device_property_read_u32(dev, "moving-threshold", 4218c2ecf20Sopenharmony_ci &data->moving_threshold); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (device_property_read_bool(dev, "x-invert")) 4248c2ecf20Sopenharmony_ci props->invert_x = true; 4258c2ecf20Sopenharmony_ci if (device_property_read_bool(dev, "y-invert")) 4268c2ecf20Sopenharmony_ci props->invert_y = true; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci props->swap_x_y = false; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int mms114_probe(struct i2c_client *client, 4348c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct mms114_data *data; 4378c2ecf20Sopenharmony_ci struct input_dev *input_dev; 4388c2ecf20Sopenharmony_ci const void *match_data; 4398c2ecf20Sopenharmony_ci int error; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 4428c2ecf20Sopenharmony_ci dev_err(&client->dev, "Not supported I2C adapter\n"); 4438c2ecf20Sopenharmony_ci return -ENODEV; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci data = devm_kzalloc(&client->dev, sizeof(struct mms114_data), 4478c2ecf20Sopenharmony_ci GFP_KERNEL); 4488c2ecf20Sopenharmony_ci input_dev = devm_input_allocate_device(&client->dev); 4498c2ecf20Sopenharmony_ci if (!data || !input_dev) { 4508c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to allocate memory\n"); 4518c2ecf20Sopenharmony_ci return -ENOMEM; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci data->client = client; 4558c2ecf20Sopenharmony_ci data->input_dev = input_dev; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci match_data = device_get_match_data(&client->dev); 4588c2ecf20Sopenharmony_ci if (!match_data) 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci data->type = (enum mms_type)match_data; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); 4648c2ecf20Sopenharmony_ci input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); 4658c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); 4668c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 4678c2ecf20Sopenharmony_ci 0, MMS114_MAX_AREA, 0, 0); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci touchscreen_parse_properties(input_dev, true, &data->props); 4708c2ecf20Sopenharmony_ci if (!data->props.max_x || !data->props.max_y) { 4718c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 4728c2ecf20Sopenharmony_ci "missing X/Y size properties, trying legacy bindings\n"); 4738c2ecf20Sopenharmony_ci error = mms114_parse_legacy_bindings(data); 4748c2ecf20Sopenharmony_ci if (error) 4758c2ecf20Sopenharmony_ci return error; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_POSITION_X, 4788c2ecf20Sopenharmony_ci 0, data->props.max_x, 0, 0); 4798c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 4808c2ecf20Sopenharmony_ci 0, data->props.max_y, 0, 0); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (data->type == TYPE_MMS114) { 4848c2ecf20Sopenharmony_ci /* 4858c2ecf20Sopenharmony_ci * The firmware handles movement and pressure fuzz, so 4868c2ecf20Sopenharmony_ci * don't duplicate that in software. 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_ci data->moving_threshold = input_abs_get_fuzz(input_dev, 4898c2ecf20Sopenharmony_ci ABS_MT_POSITION_X); 4908c2ecf20Sopenharmony_ci data->contact_threshold = input_abs_get_fuzz(input_dev, 4918c2ecf20Sopenharmony_ci ABS_MT_PRESSURE); 4928c2ecf20Sopenharmony_ci input_abs_set_fuzz(input_dev, ABS_MT_POSITION_X, 0); 4938c2ecf20Sopenharmony_ci input_abs_set_fuzz(input_dev, ABS_MT_POSITION_Y, 0); 4948c2ecf20Sopenharmony_ci input_abs_set_fuzz(input_dev, ABS_MT_PRESSURE, 0); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci input_dev->name = devm_kasprintf(&client->dev, GFP_KERNEL, 4988c2ecf20Sopenharmony_ci "MELFAS MMS%d Touchscreen", 4998c2ecf20Sopenharmony_ci data->type); 5008c2ecf20Sopenharmony_ci if (!input_dev->name) 5018c2ecf20Sopenharmony_ci return -ENOMEM; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci input_dev->id.bustype = BUS_I2C; 5048c2ecf20Sopenharmony_ci input_dev->dev.parent = &client->dev; 5058c2ecf20Sopenharmony_ci input_dev->open = mms114_input_open; 5068c2ecf20Sopenharmony_ci input_dev->close = mms114_input_close; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci error = input_mt_init_slots(input_dev, MMS114_MAX_TOUCH, 5098c2ecf20Sopenharmony_ci INPUT_MT_DIRECT); 5108c2ecf20Sopenharmony_ci if (error) 5118c2ecf20Sopenharmony_ci return error; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci input_set_drvdata(input_dev, data); 5148c2ecf20Sopenharmony_ci i2c_set_clientdata(client, data); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci data->core_reg = devm_regulator_get(&client->dev, "avdd"); 5178c2ecf20Sopenharmony_ci if (IS_ERR(data->core_reg)) { 5188c2ecf20Sopenharmony_ci error = PTR_ERR(data->core_reg); 5198c2ecf20Sopenharmony_ci dev_err(&client->dev, 5208c2ecf20Sopenharmony_ci "Unable to get the Core regulator (%d)\n", error); 5218c2ecf20Sopenharmony_ci return error; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci data->io_reg = devm_regulator_get(&client->dev, "vdd"); 5258c2ecf20Sopenharmony_ci if (IS_ERR(data->io_reg)) { 5268c2ecf20Sopenharmony_ci error = PTR_ERR(data->io_reg); 5278c2ecf20Sopenharmony_ci dev_err(&client->dev, 5288c2ecf20Sopenharmony_ci "Unable to get the IO regulator (%d)\n", error); 5298c2ecf20Sopenharmony_ci return error; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, client->irq, 5338c2ecf20Sopenharmony_ci NULL, mms114_interrupt, IRQF_ONESHOT, 5348c2ecf20Sopenharmony_ci dev_name(&client->dev), data); 5358c2ecf20Sopenharmony_ci if (error) { 5368c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to register interrupt\n"); 5378c2ecf20Sopenharmony_ci return error; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci disable_irq(client->irq); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci error = input_register_device(data->input_dev); 5428c2ecf20Sopenharmony_ci if (error) { 5438c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to register input device\n"); 5448c2ecf20Sopenharmony_ci return error; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic int __maybe_unused mms114_suspend(struct device *dev) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 5538c2ecf20Sopenharmony_ci struct mms114_data *data = i2c_get_clientdata(client); 5548c2ecf20Sopenharmony_ci struct input_dev *input_dev = data->input_dev; 5558c2ecf20Sopenharmony_ci int id; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Release all touch */ 5588c2ecf20Sopenharmony_ci for (id = 0; id < MMS114_MAX_TOUCH; id++) { 5598c2ecf20Sopenharmony_ci input_mt_slot(input_dev, id); 5608c2ecf20Sopenharmony_ci input_mt_report_slot_inactive(input_dev); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci input_mt_report_pointer_emulation(input_dev, true); 5648c2ecf20Sopenharmony_ci input_sync(input_dev); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci mutex_lock(&input_dev->mutex); 5678c2ecf20Sopenharmony_ci if (input_dev->users) 5688c2ecf20Sopenharmony_ci mms114_stop(data); 5698c2ecf20Sopenharmony_ci mutex_unlock(&input_dev->mutex); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int __maybe_unused mms114_resume(struct device *dev) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 5778c2ecf20Sopenharmony_ci struct mms114_data *data = i2c_get_clientdata(client); 5788c2ecf20Sopenharmony_ci struct input_dev *input_dev = data->input_dev; 5798c2ecf20Sopenharmony_ci int error; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci mutex_lock(&input_dev->mutex); 5828c2ecf20Sopenharmony_ci if (input_dev->users) { 5838c2ecf20Sopenharmony_ci error = mms114_start(data); 5848c2ecf20Sopenharmony_ci if (error < 0) { 5858c2ecf20Sopenharmony_ci mutex_unlock(&input_dev->mutex); 5868c2ecf20Sopenharmony_ci return error; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci mutex_unlock(&input_dev->mutex); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic const struct i2c_device_id mms114_id[] = { 5978c2ecf20Sopenharmony_ci { "mms114", 0 }, 5988c2ecf20Sopenharmony_ci { } 5998c2ecf20Sopenharmony_ci}; 6008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mms114_id); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 6038c2ecf20Sopenharmony_cistatic const struct of_device_id mms114_dt_match[] = { 6048c2ecf20Sopenharmony_ci { 6058c2ecf20Sopenharmony_ci .compatible = "melfas,mms114", 6068c2ecf20Sopenharmony_ci .data = (void *)TYPE_MMS114, 6078c2ecf20Sopenharmony_ci }, { 6088c2ecf20Sopenharmony_ci .compatible = "melfas,mms152", 6098c2ecf20Sopenharmony_ci .data = (void *)TYPE_MMS152, 6108c2ecf20Sopenharmony_ci }, { 6118c2ecf20Sopenharmony_ci .compatible = "melfas,mms345l", 6128c2ecf20Sopenharmony_ci .data = (void *)TYPE_MMS345L, 6138c2ecf20Sopenharmony_ci }, 6148c2ecf20Sopenharmony_ci { } 6158c2ecf20Sopenharmony_ci}; 6168c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mms114_dt_match); 6178c2ecf20Sopenharmony_ci#endif 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic struct i2c_driver mms114_driver = { 6208c2ecf20Sopenharmony_ci .driver = { 6218c2ecf20Sopenharmony_ci .name = "mms114", 6228c2ecf20Sopenharmony_ci .pm = &mms114_pm_ops, 6238c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(mms114_dt_match), 6248c2ecf20Sopenharmony_ci }, 6258c2ecf20Sopenharmony_ci .probe = mms114_probe, 6268c2ecf20Sopenharmony_ci .id_table = mms114_id, 6278c2ecf20Sopenharmony_ci}; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cimodule_i2c_driver(mms114_driver); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci/* Module information */ 6328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 6338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver"); 6348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 635