Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Wacom Penabled Driver for I2C
0004  *
0005  * Copyright (c) 2011 - 2013 Tatsunosuke Tobita, Wacom.
0006  * <tobita.tatsunosuke@wacom.co.jp>
0007  */
0008 
0009 #include <linux/bits.h>
0010 #include <linux/module.h>
0011 #include <linux/input.h>
0012 #include <linux/i2c.h>
0013 #include <linux/slab.h>
0014 #include <linux/irq.h>
0015 #include <linux/interrupt.h>
0016 #include <asm/unaligned.h>
0017 
0018 /* Bitmasks (for data[3]) */
0019 #define WACOM_TIP_SWITCH    BIT(0)
0020 #define WACOM_BARREL_SWITCH BIT(1)
0021 #define WACOM_ERASER        BIT(2)
0022 #define WACOM_INVERT        BIT(3)
0023 #define WACOM_BARREL_SWITCH_2   BIT(4)
0024 #define WACOM_IN_PROXIMITY  BIT(5)
0025 
0026 /* Registers */
0027 #define WACOM_COMMAND_LSB   0x04
0028 #define WACOM_COMMAND_MSB   0x00
0029 
0030 #define WACOM_DATA_LSB      0x05
0031 #define WACOM_DATA_MSB      0x00
0032 
0033 /* Report types */
0034 #define REPORT_FEATURE      0x30
0035 
0036 /* Requests / operations */
0037 #define OPCODE_GET_REPORT   0x02
0038 
0039 #define WACOM_QUERY_REPORT  3
0040 #define WACOM_QUERY_SIZE    19
0041 
0042 struct wacom_features {
0043     int x_max;
0044     int y_max;
0045     int pressure_max;
0046     char fw_version;
0047 };
0048 
0049 struct wacom_i2c {
0050     struct i2c_client *client;
0051     struct input_dev *input;
0052     u8 data[WACOM_QUERY_SIZE];
0053     bool prox;
0054     int tool;
0055 };
0056 
0057 static int wacom_query_device(struct i2c_client *client,
0058                   struct wacom_features *features)
0059 {
0060     u8 get_query_data_cmd[] = {
0061         WACOM_COMMAND_LSB,
0062         WACOM_COMMAND_MSB,
0063         REPORT_FEATURE | WACOM_QUERY_REPORT,
0064         OPCODE_GET_REPORT,
0065         WACOM_DATA_LSB,
0066         WACOM_DATA_MSB,
0067     };
0068     u8 data[WACOM_QUERY_SIZE];
0069     int ret;
0070 
0071     struct i2c_msg msgs[] = {
0072         /* Request reading of feature ReportID: 3 (Pen Query Data) */
0073         {
0074             .addr = client->addr,
0075             .flags = 0,
0076             .len = sizeof(get_query_data_cmd),
0077             .buf = get_query_data_cmd,
0078         },
0079         {
0080             .addr = client->addr,
0081             .flags = I2C_M_RD,
0082             .len = sizeof(data),
0083             .buf = data,
0084         },
0085     };
0086 
0087     ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
0088     if (ret < 0)
0089         return ret;
0090     if (ret != ARRAY_SIZE(msgs))
0091         return -EIO;
0092 
0093     features->x_max = get_unaligned_le16(&data[3]);
0094     features->y_max = get_unaligned_le16(&data[5]);
0095     features->pressure_max = get_unaligned_le16(&data[11]);
0096     features->fw_version = get_unaligned_le16(&data[13]);
0097 
0098     dev_dbg(&client->dev,
0099         "x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
0100         features->x_max, features->y_max,
0101         features->pressure_max, features->fw_version);
0102 
0103     return 0;
0104 }
0105 
0106 static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
0107 {
0108     struct wacom_i2c *wac_i2c = dev_id;
0109     struct input_dev *input = wac_i2c->input;
0110     u8 *data = wac_i2c->data;
0111     unsigned int x, y, pressure;
0112     unsigned char tsw, f1, f2, ers;
0113     int error;
0114 
0115     error = i2c_master_recv(wac_i2c->client,
0116                 wac_i2c->data, sizeof(wac_i2c->data));
0117     if (error < 0)
0118         goto out;
0119 
0120     tsw = data[3] & WACOM_TIP_SWITCH;
0121     ers = data[3] & WACOM_ERASER;
0122     f1 = data[3] & WACOM_BARREL_SWITCH;
0123     f2 = data[3] & WACOM_BARREL_SWITCH_2;
0124     x = le16_to_cpup((__le16 *)&data[4]);
0125     y = le16_to_cpup((__le16 *)&data[6]);
0126     pressure = le16_to_cpup((__le16 *)&data[8]);
0127 
0128     if (!wac_i2c->prox)
0129         wac_i2c->tool = (data[3] & (WACOM_ERASER | WACOM_INVERT)) ?
0130             BTN_TOOL_RUBBER : BTN_TOOL_PEN;
0131 
0132     wac_i2c->prox = data[3] & WACOM_IN_PROXIMITY;
0133 
0134     input_report_key(input, BTN_TOUCH, tsw || ers);
0135     input_report_key(input, wac_i2c->tool, wac_i2c->prox);
0136     input_report_key(input, BTN_STYLUS, f1);
0137     input_report_key(input, BTN_STYLUS2, f2);
0138     input_report_abs(input, ABS_X, x);
0139     input_report_abs(input, ABS_Y, y);
0140     input_report_abs(input, ABS_PRESSURE, pressure);
0141     input_sync(input);
0142 
0143 out:
0144     return IRQ_HANDLED;
0145 }
0146 
0147 static int wacom_i2c_open(struct input_dev *dev)
0148 {
0149     struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
0150     struct i2c_client *client = wac_i2c->client;
0151 
0152     enable_irq(client->irq);
0153 
0154     return 0;
0155 }
0156 
0157 static void wacom_i2c_close(struct input_dev *dev)
0158 {
0159     struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
0160     struct i2c_client *client = wac_i2c->client;
0161 
0162     disable_irq(client->irq);
0163 }
0164 
0165 static int wacom_i2c_probe(struct i2c_client *client,
0166                const struct i2c_device_id *id)
0167 {
0168     struct device *dev = &client->dev;
0169     struct wacom_i2c *wac_i2c;
0170     struct input_dev *input;
0171     struct wacom_features features = { 0 };
0172     int error;
0173 
0174     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0175         dev_err(dev, "i2c_check_functionality error\n");
0176         return -EIO;
0177     }
0178 
0179     error = wacom_query_device(client, &features);
0180     if (error)
0181         return error;
0182 
0183     wac_i2c = devm_kzalloc(dev, sizeof(*wac_i2c), GFP_KERNEL);
0184     if (!wac_i2c)
0185         return -ENOMEM;
0186 
0187     wac_i2c->client = client;
0188 
0189     input = devm_input_allocate_device(dev);
0190     if (!input)
0191         return -ENOMEM;
0192 
0193     wac_i2c->input = input;
0194 
0195     input->name = "Wacom I2C Digitizer";
0196     input->id.bustype = BUS_I2C;
0197     input->id.vendor = 0x56a;
0198     input->id.version = features.fw_version;
0199     input->open = wacom_i2c_open;
0200     input->close = wacom_i2c_close;
0201 
0202     input->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0203 
0204     __set_bit(BTN_TOOL_PEN, input->keybit);
0205     __set_bit(BTN_TOOL_RUBBER, input->keybit);
0206     __set_bit(BTN_STYLUS, input->keybit);
0207     __set_bit(BTN_STYLUS2, input->keybit);
0208     __set_bit(BTN_TOUCH, input->keybit);
0209 
0210     input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0);
0211     input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0);
0212     input_set_abs_params(input, ABS_PRESSURE,
0213                  0, features.pressure_max, 0, 0);
0214 
0215     input_set_drvdata(input, wac_i2c);
0216 
0217     error = devm_request_threaded_irq(dev, client->irq, NULL, wacom_i2c_irq,
0218                       IRQF_ONESHOT, "wacom_i2c", wac_i2c);
0219     if (error) {
0220         dev_err(dev, "Failed to request IRQ: %d\n", error);
0221         return error;
0222     }
0223 
0224     /* Disable the IRQ, we'll enable it in wac_i2c_open() */
0225     disable_irq(client->irq);
0226 
0227     error = input_register_device(wac_i2c->input);
0228     if (error) {
0229         dev_err(dev, "Failed to register input device: %d\n", error);
0230         return error;
0231     }
0232 
0233     return 0;
0234 }
0235 
0236 static int __maybe_unused wacom_i2c_suspend(struct device *dev)
0237 {
0238     struct i2c_client *client = to_i2c_client(dev);
0239 
0240     disable_irq(client->irq);
0241 
0242     return 0;
0243 }
0244 
0245 static int __maybe_unused wacom_i2c_resume(struct device *dev)
0246 {
0247     struct i2c_client *client = to_i2c_client(dev);
0248 
0249     enable_irq(client->irq);
0250 
0251     return 0;
0252 }
0253 
0254 static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
0255 
0256 static const struct i2c_device_id wacom_i2c_id[] = {
0257     { "WAC_I2C_EMR", 0 },
0258     { },
0259 };
0260 MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
0261 
0262 static struct i2c_driver wacom_i2c_driver = {
0263     .driver = {
0264         .name   = "wacom_i2c",
0265         .pm = &wacom_i2c_pm,
0266     },
0267 
0268     .probe      = wacom_i2c_probe,
0269     .id_table   = wacom_i2c_id,
0270 };
0271 module_i2c_driver(wacom_i2c_driver);
0272 
0273 MODULE_AUTHOR("Tatsunosuke Tobita <tobita.tatsunosuke@wacom.co.jp>");
0274 MODULE_DESCRIPTION("WACOM EMR I2C Driver");
0275 MODULE_LICENSE("GPL");