Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
0004  *
0005  * Copyright (C) 2009 Samsung Electronics Co.Ltd
0006  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
0007  *
0008  * Based on wm97xx-core.c
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/i2c.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/input.h>
0015 #include <linux/irq.h>
0016 #include <linux/platform_data/mcs.h>
0017 #include <linux/slab.h>
0018 
0019 /* Registers */
0020 #define MCS5000_TS_STATUS       0x00
0021 #define STATUS_OFFSET           0
0022 #define STATUS_NO           (0 << STATUS_OFFSET)
0023 #define STATUS_INIT         (1 << STATUS_OFFSET)
0024 #define STATUS_SENSING          (2 << STATUS_OFFSET)
0025 #define STATUS_COORD            (3 << STATUS_OFFSET)
0026 #define STATUS_GESTURE          (4 << STATUS_OFFSET)
0027 #define ERROR_OFFSET            4
0028 #define ERROR_NO            (0 << ERROR_OFFSET)
0029 #define ERROR_POWER_ON_RESET        (1 << ERROR_OFFSET)
0030 #define ERROR_INT_RESET         (2 << ERROR_OFFSET)
0031 #define ERROR_EXT_RESET         (3 << ERROR_OFFSET)
0032 #define ERROR_INVALID_REG_ADDRESS   (8 << ERROR_OFFSET)
0033 #define ERROR_INVALID_REG_VALUE     (9 << ERROR_OFFSET)
0034 
0035 #define MCS5000_TS_OP_MODE      0x01
0036 #define RESET_OFFSET            0
0037 #define RESET_NO            (0 << RESET_OFFSET)
0038 #define RESET_EXT_SOFT          (1 << RESET_OFFSET)
0039 #define OP_MODE_OFFSET          1
0040 #define OP_MODE_SLEEP           (0 << OP_MODE_OFFSET)
0041 #define OP_MODE_ACTIVE          (1 << OP_MODE_OFFSET)
0042 #define GESTURE_OFFSET          4
0043 #define GESTURE_DISABLE         (0 << GESTURE_OFFSET)
0044 #define GESTURE_ENABLE          (1 << GESTURE_OFFSET)
0045 #define PROXIMITY_OFFSET        5
0046 #define PROXIMITY_DISABLE       (0 << PROXIMITY_OFFSET)
0047 #define PROXIMITY_ENABLE        (1 << PROXIMITY_OFFSET)
0048 #define SCAN_MODE_OFFSET        6
0049 #define SCAN_MODE_INTERRUPT     (0 << SCAN_MODE_OFFSET)
0050 #define SCAN_MODE_POLLING       (1 << SCAN_MODE_OFFSET)
0051 #define REPORT_RATE_OFFSET      7
0052 #define REPORT_RATE_40          (0 << REPORT_RATE_OFFSET)
0053 #define REPORT_RATE_80          (1 << REPORT_RATE_OFFSET)
0054 
0055 #define MCS5000_TS_SENS_CTL     0x02
0056 #define MCS5000_TS_FILTER_CTL       0x03
0057 #define PRI_FILTER_OFFSET       0
0058 #define SEC_FILTER_OFFSET       4
0059 
0060 #define MCS5000_TS_X_SIZE_UPPER     0x08
0061 #define MCS5000_TS_X_SIZE_LOWER     0x09
0062 #define MCS5000_TS_Y_SIZE_UPPER     0x0A
0063 #define MCS5000_TS_Y_SIZE_LOWER     0x0B
0064 
0065 #define MCS5000_TS_INPUT_INFO       0x10
0066 #define INPUT_TYPE_OFFSET       0
0067 #define INPUT_TYPE_NONTOUCH     (0 << INPUT_TYPE_OFFSET)
0068 #define INPUT_TYPE_SINGLE       (1 << INPUT_TYPE_OFFSET)
0069 #define INPUT_TYPE_DUAL         (2 << INPUT_TYPE_OFFSET)
0070 #define INPUT_TYPE_PALM         (3 << INPUT_TYPE_OFFSET)
0071 #define INPUT_TYPE_PROXIMITY        (7 << INPUT_TYPE_OFFSET)
0072 #define GESTURE_CODE_OFFSET     3
0073 #define GESTURE_CODE_NO         (0 << GESTURE_CODE_OFFSET)
0074 
0075 #define MCS5000_TS_X_POS_UPPER      0x11
0076 #define MCS5000_TS_X_POS_LOWER      0x12
0077 #define MCS5000_TS_Y_POS_UPPER      0x13
0078 #define MCS5000_TS_Y_POS_LOWER      0x14
0079 #define MCS5000_TS_Z_POS        0x15
0080 #define MCS5000_TS_WIDTH        0x16
0081 #define MCS5000_TS_GESTURE_VAL      0x17
0082 #define MCS5000_TS_MODULE_REV       0x20
0083 #define MCS5000_TS_FIRMWARE_VER     0x21
0084 
0085 /* Touchscreen absolute values */
0086 #define MCS5000_MAX_XC          0x3ff
0087 #define MCS5000_MAX_YC          0x3ff
0088 
0089 enum mcs5000_ts_read_offset {
0090     READ_INPUT_INFO,
0091     READ_X_POS_UPPER,
0092     READ_X_POS_LOWER,
0093     READ_Y_POS_UPPER,
0094     READ_Y_POS_LOWER,
0095     READ_BLOCK_SIZE,
0096 };
0097 
0098 /* Each client has this additional data */
0099 struct mcs5000_ts_data {
0100     struct i2c_client *client;
0101     struct input_dev *input_dev;
0102     const struct mcs_platform_data *platform_data;
0103 };
0104 
0105 static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
0106 {
0107     struct mcs5000_ts_data *data = dev_id;
0108     struct i2c_client *client = data->client;
0109     u8 buffer[READ_BLOCK_SIZE];
0110     int err;
0111     int x;
0112     int y;
0113 
0114     err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
0115             READ_BLOCK_SIZE, buffer);
0116     if (err < 0) {
0117         dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
0118         goto out;
0119     }
0120 
0121     switch (buffer[READ_INPUT_INFO]) {
0122     case INPUT_TYPE_NONTOUCH:
0123         input_report_key(data->input_dev, BTN_TOUCH, 0);
0124         input_sync(data->input_dev);
0125         break;
0126 
0127     case INPUT_TYPE_SINGLE:
0128         x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
0129         y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
0130 
0131         input_report_key(data->input_dev, BTN_TOUCH, 1);
0132         input_report_abs(data->input_dev, ABS_X, x);
0133         input_report_abs(data->input_dev, ABS_Y, y);
0134         input_sync(data->input_dev);
0135         break;
0136 
0137     case INPUT_TYPE_DUAL:
0138         /* TODO */
0139         break;
0140 
0141     case INPUT_TYPE_PALM:
0142         /* TODO */
0143         break;
0144 
0145     case INPUT_TYPE_PROXIMITY:
0146         /* TODO */
0147         break;
0148 
0149     default:
0150         dev_err(&client->dev, "Unknown ts input type %d\n",
0151                 buffer[READ_INPUT_INFO]);
0152         break;
0153     }
0154 
0155  out:
0156     return IRQ_HANDLED;
0157 }
0158 
0159 static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data,
0160                  const struct mcs_platform_data *platform_data)
0161 {
0162     struct i2c_client *client = data->client;
0163 
0164     /* Touch reset & sleep mode */
0165     i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
0166             RESET_EXT_SOFT | OP_MODE_SLEEP);
0167 
0168     /* Touch size */
0169     i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
0170             platform_data->x_size >> 8);
0171     i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
0172             platform_data->x_size & 0xff);
0173     i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
0174             platform_data->y_size >> 8);
0175     i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
0176             platform_data->y_size & 0xff);
0177 
0178     /* Touch active mode & 80 report rate */
0179     i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
0180             OP_MODE_ACTIVE | REPORT_RATE_80);
0181 }
0182 
0183 static int mcs5000_ts_probe(struct i2c_client *client,
0184                 const struct i2c_device_id *id)
0185 {
0186     const struct mcs_platform_data *pdata;
0187     struct mcs5000_ts_data *data;
0188     struct input_dev *input_dev;
0189     int error;
0190 
0191     pdata = dev_get_platdata(&client->dev);
0192     if (!pdata)
0193         return -EINVAL;
0194 
0195     data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
0196     if (!data) {
0197         dev_err(&client->dev, "Failed to allocate memory\n");
0198         return -ENOMEM;
0199     }
0200 
0201     data->client = client;
0202 
0203     input_dev = devm_input_allocate_device(&client->dev);
0204     if (!input_dev) {
0205         dev_err(&client->dev, "Failed to allocate input device\n");
0206         return -ENOMEM;
0207     }
0208 
0209     input_dev->name = "MELFAS MCS-5000 Touchscreen";
0210     input_dev->id.bustype = BUS_I2C;
0211     input_dev->dev.parent = &client->dev;
0212 
0213     __set_bit(EV_ABS, input_dev->evbit);
0214     __set_bit(EV_KEY, input_dev->evbit);
0215     __set_bit(BTN_TOUCH, input_dev->keybit);
0216     input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
0217     input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
0218 
0219     data->input_dev = input_dev;
0220 
0221     if (pdata->cfg_pin)
0222         pdata->cfg_pin();
0223 
0224     error = devm_request_threaded_irq(&client->dev, client->irq,
0225                       NULL, mcs5000_ts_interrupt,
0226                       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
0227                       "mcs5000_ts", data);
0228     if (error) {
0229         dev_err(&client->dev, "Failed to register interrupt\n");
0230         return error;
0231     }
0232 
0233     error = input_register_device(data->input_dev);
0234     if (error) {
0235         dev_err(&client->dev, "Failed to register input device\n");
0236         return error;
0237     }
0238 
0239     mcs5000_ts_phys_init(data, pdata);
0240     i2c_set_clientdata(client, data);
0241 
0242     return 0;
0243 }
0244 
0245 static int __maybe_unused mcs5000_ts_suspend(struct device *dev)
0246 {
0247     struct i2c_client *client = to_i2c_client(dev);
0248 
0249     /* Touch sleep mode */
0250     i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
0251 
0252     return 0;
0253 }
0254 
0255 static int __maybe_unused mcs5000_ts_resume(struct device *dev)
0256 {
0257     struct i2c_client *client = to_i2c_client(dev);
0258     struct mcs5000_ts_data *data = i2c_get_clientdata(client);
0259     const struct mcs_platform_data *pdata = dev_get_platdata(dev);
0260 
0261     mcs5000_ts_phys_init(data, pdata);
0262 
0263     return 0;
0264 }
0265 
0266 static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
0267 
0268 static const struct i2c_device_id mcs5000_ts_id[] = {
0269     { "mcs5000_ts", 0 },
0270     { }
0271 };
0272 MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
0273 
0274 static struct i2c_driver mcs5000_ts_driver = {
0275     .probe      = mcs5000_ts_probe,
0276     .driver = {
0277         .name = "mcs5000_ts",
0278         .pm   = &mcs5000_ts_pm,
0279     },
0280     .id_table   = mcs5000_ts_id,
0281 };
0282 
0283 module_i2c_driver(mcs5000_ts_driver);
0284 
0285 /* Module information */
0286 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
0287 MODULE_DESCRIPTION("Touchscreen driver for MELFAS MCS-5000 controller");
0288 MODULE_LICENSE("GPL");