1*acaefbacSHendrik Noack // SPDX-License-Identifier: GPL-2.0-or-later 2*acaefbacSHendrik Noack /* 3*acaefbacSHendrik Noack * Wacom W9000-series penabled I2C touchscreen driver 4*acaefbacSHendrik Noack * 5*acaefbacSHendrik Noack * Copyright (c) 2026 Hendrik Noack <hendrik-noack@gmx.de> 6*acaefbacSHendrik Noack * 7*acaefbacSHendrik Noack * Partially based on vendor driver: 8*acaefbacSHendrik Noack * Copyright (C) 2012, Samsung Electronics Co. Ltd. 9*acaefbacSHendrik Noack */ 10*acaefbacSHendrik Noack 11*acaefbacSHendrik Noack #include <linux/delay.h> 12*acaefbacSHendrik Noack #include <linux/gpio/consumer.h> 13*acaefbacSHendrik Noack #include <linux/i2c.h> 14*acaefbacSHendrik Noack #include <linux/input.h> 15*acaefbacSHendrik Noack #include <linux/input/touchscreen.h> 16*acaefbacSHendrik Noack #include <linux/interrupt.h> 17*acaefbacSHendrik Noack #include <linux/lockdep.h> 18*acaefbacSHendrik Noack #include <linux/regulator/consumer.h> 19*acaefbacSHendrik Noack #include <linux/unaligned.h> 20*acaefbacSHendrik Noack 21*acaefbacSHendrik Noack /* Some chips have flaky firmware that requires many retries before responding. */ 22*acaefbacSHendrik Noack #define CMD_QUERY_RETRIES 8 23*acaefbacSHendrik Noack 24*acaefbacSHendrik Noack /* Message length */ 25*acaefbacSHendrik Noack #define CMD_QUERY_NUM_MAX 9 26*acaefbacSHendrik Noack #define MSG_COORD_NUM_MAX 12 27*acaefbacSHendrik Noack 28*acaefbacSHendrik Noack /* Commands */ 29*acaefbacSHendrik Noack #define CMD_QUERY 0x2a 30*acaefbacSHendrik Noack 31*acaefbacSHendrik Noack struct wacom_w9000_variant { 32*acaefbacSHendrik Noack const u8 cmd_query_num; 33*acaefbacSHendrik Noack const u8 msg_coord_num; 34*acaefbacSHendrik Noack const char *name; 35*acaefbacSHendrik Noack }; 36*acaefbacSHendrik Noack 37*acaefbacSHendrik Noack struct wacom_w9000_data { 38*acaefbacSHendrik Noack struct i2c_client *client; 39*acaefbacSHendrik Noack struct input_dev *input_dev; 40*acaefbacSHendrik Noack const struct wacom_w9000_variant *variant; 41*acaefbacSHendrik Noack u16 fw_version; 42*acaefbacSHendrik Noack 43*acaefbacSHendrik Noack struct touchscreen_properties prop; 44*acaefbacSHendrik Noack u16 max_pressure; 45*acaefbacSHendrik Noack 46*acaefbacSHendrik Noack struct regulator *regulator; 47*acaefbacSHendrik Noack 48*acaefbacSHendrik Noack struct gpio_desc *flash_mode_gpio; 49*acaefbacSHendrik Noack struct gpio_desc *reset_gpio; 50*acaefbacSHendrik Noack 51*acaefbacSHendrik Noack unsigned int irq; 52*acaefbacSHendrik Noack 53*acaefbacSHendrik Noack bool pen_proximity; 54*acaefbacSHendrik Noack }; 55*acaefbacSHendrik Noack 56*acaefbacSHendrik Noack static int wacom_w9000_read(struct i2c_client *client, u8 command, u8 len, u8 *data) 57*acaefbacSHendrik Noack { 58*acaefbacSHendrik Noack int error, res; 59*acaefbacSHendrik Noack struct i2c_msg msg[] = { 60*acaefbacSHendrik Noack { 61*acaefbacSHendrik Noack .addr = client->addr, 62*acaefbacSHendrik Noack .flags = 0, 63*acaefbacSHendrik Noack .buf = &command, 64*acaefbacSHendrik Noack .len = sizeof(command), 65*acaefbacSHendrik Noack }, { 66*acaefbacSHendrik Noack .addr = client->addr, 67*acaefbacSHendrik Noack .flags = I2C_M_RD, 68*acaefbacSHendrik Noack .buf = data, 69*acaefbacSHendrik Noack .len = len, 70*acaefbacSHendrik Noack } 71*acaefbacSHendrik Noack }; 72*acaefbacSHendrik Noack 73*acaefbacSHendrik Noack res = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 74*acaefbacSHendrik Noack if (res != ARRAY_SIZE(msg)) { 75*acaefbacSHendrik Noack error = res < 0 ? res : -EIO; 76*acaefbacSHendrik Noack dev_err(&client->dev, "%s: i2c transfer failed: %d (%d)\n", 77*acaefbacSHendrik Noack __func__, error, res); 78*acaefbacSHendrik Noack return error; 79*acaefbacSHendrik Noack } 80*acaefbacSHendrik Noack 81*acaefbacSHendrik Noack return 0; 82*acaefbacSHendrik Noack } 83*acaefbacSHendrik Noack 84*acaefbacSHendrik Noack static int wacom_w9000_query(struct wacom_w9000_data *wacom_data) 85*acaefbacSHendrik Noack { 86*acaefbacSHendrik Noack struct i2c_client *client = wacom_data->client; 87*acaefbacSHendrik Noack struct device *dev = &wacom_data->client->dev; 88*acaefbacSHendrik Noack u8 data[CMD_QUERY_NUM_MAX]; 89*acaefbacSHendrik Noack int retry; 90*acaefbacSHendrik Noack int error; 91*acaefbacSHendrik Noack 92*acaefbacSHendrik Noack for (retry = 0; retry < CMD_QUERY_RETRIES; retry++) { 93*acaefbacSHendrik Noack error = wacom_w9000_read(client, CMD_QUERY, 94*acaefbacSHendrik Noack wacom_data->variant->cmd_query_num, 95*acaefbacSHendrik Noack data); 96*acaefbacSHendrik Noack if (!error && data[0] == 0x0f) 97*acaefbacSHendrik Noack break; 98*acaefbacSHendrik Noack } 99*acaefbacSHendrik Noack 100*acaefbacSHendrik Noack if (error) 101*acaefbacSHendrik Noack return error; 102*acaefbacSHendrik Noack 103*acaefbacSHendrik Noack if (data[0] != 0x0f) 104*acaefbacSHendrik Noack return -EIO; 105*acaefbacSHendrik Noack 106*acaefbacSHendrik Noack dev_dbg(dev, "query: %*ph, %d\n", 107*acaefbacSHendrik Noack wacom_data->variant->cmd_query_num, data, retry); 108*acaefbacSHendrik Noack 109*acaefbacSHendrik Noack wacom_data->prop.max_x = get_unaligned_be16(&data[1]); 110*acaefbacSHendrik Noack wacom_data->prop.max_y = get_unaligned_be16(&data[3]); 111*acaefbacSHendrik Noack wacom_data->max_pressure = get_unaligned_be16(&data[5]); 112*acaefbacSHendrik Noack wacom_data->fw_version = get_unaligned_be16(&data[7]); 113*acaefbacSHendrik Noack 114*acaefbacSHendrik Noack dev_dbg(dev, "max_x:%d, max_y:%d, max_pressure:%d, fw:%#x\n", 115*acaefbacSHendrik Noack wacom_data->prop.max_x, wacom_data->prop.max_y, 116*acaefbacSHendrik Noack wacom_data->max_pressure, wacom_data->fw_version); 117*acaefbacSHendrik Noack 118*acaefbacSHendrik Noack return 0; 119*acaefbacSHendrik Noack } 120*acaefbacSHendrik Noack 121*acaefbacSHendrik Noack static int wacom_w9000_power_on(struct wacom_w9000_data *wacom_data) 122*acaefbacSHendrik Noack { 123*acaefbacSHendrik Noack int error; 124*acaefbacSHendrik Noack 125*acaefbacSHendrik Noack lockdep_assert_held(&wacom_data->input_dev->mutex); 126*acaefbacSHendrik Noack 127*acaefbacSHendrik Noack error = regulator_enable(wacom_data->regulator); 128*acaefbacSHendrik Noack if (error) { 129*acaefbacSHendrik Noack dev_err(&wacom_data->client->dev, "Failed to enable regulators: %d\n", error); 130*acaefbacSHendrik Noack return error; 131*acaefbacSHendrik Noack } 132*acaefbacSHendrik Noack 133*acaefbacSHendrik Noack msleep(200); 134*acaefbacSHendrik Noack 135*acaefbacSHendrik Noack gpiod_set_value_cansleep(wacom_data->reset_gpio, 0); 136*acaefbacSHendrik Noack enable_irq(wacom_data->irq); 137*acaefbacSHendrik Noack 138*acaefbacSHendrik Noack return 0; 139*acaefbacSHendrik Noack } 140*acaefbacSHendrik Noack 141*acaefbacSHendrik Noack static int wacom_w9000_power_off(struct wacom_w9000_data *wacom_data) 142*acaefbacSHendrik Noack { 143*acaefbacSHendrik Noack lockdep_assert_held(&wacom_data->input_dev->mutex); 144*acaefbacSHendrik Noack 145*acaefbacSHendrik Noack disable_irq(wacom_data->irq); 146*acaefbacSHendrik Noack gpiod_set_value_cansleep(wacom_data->reset_gpio, 1); 147*acaefbacSHendrik Noack regulator_disable(wacom_data->regulator); 148*acaefbacSHendrik Noack 149*acaefbacSHendrik Noack return 0; 150*acaefbacSHendrik Noack } 151*acaefbacSHendrik Noack 152*acaefbacSHendrik Noack static void wacom_w9000_coord(struct wacom_w9000_data *wacom_data) 153*acaefbacSHendrik Noack { 154*acaefbacSHendrik Noack struct i2c_client *client = wacom_data->client; 155*acaefbacSHendrik Noack struct device *dev = &wacom_data->client->dev; 156*acaefbacSHendrik Noack u8 data[MSG_COORD_NUM_MAX]; 157*acaefbacSHendrik Noack bool touch, rubber, side_button; 158*acaefbacSHendrik Noack u16 x, y, pressure; 159*acaefbacSHendrik Noack u8 distance = 0; 160*acaefbacSHendrik Noack int error; 161*acaefbacSHendrik Noack 162*acaefbacSHendrik Noack error = i2c_master_recv(client, data, wacom_data->variant->msg_coord_num); 163*acaefbacSHendrik Noack if (error != wacom_data->variant->msg_coord_num) { 164*acaefbacSHendrik Noack if (error >= 0) 165*acaefbacSHendrik Noack error = -EIO; 166*acaefbacSHendrik Noack dev_err_ratelimited(dev, "%s: i2c receive failed (%d)\n", __func__, error); 167*acaefbacSHendrik Noack return; 168*acaefbacSHendrik Noack } 169*acaefbacSHendrik Noack 170*acaefbacSHendrik Noack dev_dbg(dev, "data: %*ph\n", wacom_data->variant->msg_coord_num, data); 171*acaefbacSHendrik Noack 172*acaefbacSHendrik Noack if (data[0] & BIT(7)) { 173*acaefbacSHendrik Noack wacom_data->pen_proximity = true; 174*acaefbacSHendrik Noack 175*acaefbacSHendrik Noack touch = !!(data[0] & BIT(4)); 176*acaefbacSHendrik Noack side_button = !!(data[0] & BIT(5)); 177*acaefbacSHendrik Noack rubber = !!(data[0] & BIT(6)); 178*acaefbacSHendrik Noack 179*acaefbacSHendrik Noack x = get_unaligned_be16(&data[1]); 180*acaefbacSHendrik Noack y = get_unaligned_be16(&data[3]); 181*acaefbacSHendrik Noack pressure = get_unaligned_be16(&data[5]); 182*acaefbacSHendrik Noack 183*acaefbacSHendrik Noack if (wacom_data->variant->msg_coord_num > 7) 184*acaefbacSHendrik Noack distance = data[7]; 185*acaefbacSHendrik Noack 186*acaefbacSHendrik Noack if (x > wacom_data->prop.max_x || y > wacom_data->prop.max_y) { 187*acaefbacSHendrik Noack dev_warn_ratelimited(dev, "Coordinates out of range x=%d, y=%d\n", x, y); 188*acaefbacSHendrik Noack return; 189*acaefbacSHendrik Noack } 190*acaefbacSHendrik Noack 191*acaefbacSHendrik Noack if (pressure > wacom_data->max_pressure) { 192*acaefbacSHendrik Noack dev_warn_ratelimited(dev, "Pressure out of range %d\n", pressure); 193*acaefbacSHendrik Noack return; 194*acaefbacSHendrik Noack } 195*acaefbacSHendrik Noack 196*acaefbacSHendrik Noack touchscreen_report_pos(wacom_data->input_dev, &wacom_data->prop, x, y, false); 197*acaefbacSHendrik Noack input_report_abs(wacom_data->input_dev, ABS_PRESSURE, pressure); 198*acaefbacSHendrik Noack 199*acaefbacSHendrik Noack if (wacom_data->variant->msg_coord_num > 7) 200*acaefbacSHendrik Noack input_report_abs(wacom_data->input_dev, ABS_DISTANCE, distance); 201*acaefbacSHendrik Noack 202*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_STYLUS, side_button); 203*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_TOUCH, touch); 204*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_TOOL_PEN, !rubber); 205*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_TOOL_RUBBER, rubber); 206*acaefbacSHendrik Noack input_sync(wacom_data->input_dev); 207*acaefbacSHendrik Noack } else if (wacom_data->pen_proximity) { 208*acaefbacSHendrik Noack input_report_abs(wacom_data->input_dev, ABS_PRESSURE, 0); 209*acaefbacSHendrik Noack 210*acaefbacSHendrik Noack if (wacom_data->variant->msg_coord_num > 7) 211*acaefbacSHendrik Noack input_report_abs(wacom_data->input_dev, ABS_DISTANCE, 255); 212*acaefbacSHendrik Noack 213*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_STYLUS, 0); 214*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_TOUCH, 0); 215*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_TOOL_PEN, 0); 216*acaefbacSHendrik Noack input_report_key(wacom_data->input_dev, BTN_TOOL_RUBBER, 0); 217*acaefbacSHendrik Noack input_sync(wacom_data->input_dev); 218*acaefbacSHendrik Noack 219*acaefbacSHendrik Noack wacom_data->pen_proximity = false; 220*acaefbacSHendrik Noack } 221*acaefbacSHendrik Noack } 222*acaefbacSHendrik Noack 223*acaefbacSHendrik Noack static irqreturn_t wacom_w9000_interrupt(int irq, void *dev_id) 224*acaefbacSHendrik Noack { 225*acaefbacSHendrik Noack struct wacom_w9000_data *wacom_data = dev_id; 226*acaefbacSHendrik Noack 227*acaefbacSHendrik Noack wacom_w9000_coord(wacom_data); 228*acaefbacSHendrik Noack 229*acaefbacSHendrik Noack return IRQ_HANDLED; 230*acaefbacSHendrik Noack } 231*acaefbacSHendrik Noack 232*acaefbacSHendrik Noack static int wacom_w9000_open(struct input_dev *dev) 233*acaefbacSHendrik Noack { 234*acaefbacSHendrik Noack struct wacom_w9000_data *wacom_data = input_get_drvdata(dev); 235*acaefbacSHendrik Noack 236*acaefbacSHendrik Noack return wacom_w9000_power_on(wacom_data); 237*acaefbacSHendrik Noack } 238*acaefbacSHendrik Noack 239*acaefbacSHendrik Noack static void wacom_w9000_close(struct input_dev *dev) 240*acaefbacSHendrik Noack { 241*acaefbacSHendrik Noack struct wacom_w9000_data *wacom_data = input_get_drvdata(dev); 242*acaefbacSHendrik Noack 243*acaefbacSHendrik Noack wacom_w9000_power_off(wacom_data); 244*acaefbacSHendrik Noack } 245*acaefbacSHendrik Noack 246*acaefbacSHendrik Noack static int wacom_w9000_probe(struct i2c_client *client) 247*acaefbacSHendrik Noack { 248*acaefbacSHendrik Noack struct device *dev = &client->dev; 249*acaefbacSHendrik Noack struct wacom_w9000_data *wacom_data; 250*acaefbacSHendrik Noack struct input_dev *input_dev; 251*acaefbacSHendrik Noack int error; 252*acaefbacSHendrik Noack u32 val; 253*acaefbacSHendrik Noack 254*acaefbacSHendrik Noack if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 255*acaefbacSHendrik Noack dev_err(dev, "i2c_check_functionality error\n"); 256*acaefbacSHendrik Noack return -EIO; 257*acaefbacSHendrik Noack } 258*acaefbacSHendrik Noack 259*acaefbacSHendrik Noack wacom_data = devm_kzalloc(dev, sizeof(*wacom_data), GFP_KERNEL); 260*acaefbacSHendrik Noack if (!wacom_data) 261*acaefbacSHendrik Noack return -ENOMEM; 262*acaefbacSHendrik Noack 263*acaefbacSHendrik Noack wacom_data->variant = i2c_get_match_data(client); 264*acaefbacSHendrik Noack if (!wacom_data->variant) { 265*acaefbacSHendrik Noack dev_err(dev, "No i2c match_data available\n"); 266*acaefbacSHendrik Noack return -EINVAL; 267*acaefbacSHendrik Noack } 268*acaefbacSHendrik Noack 269*acaefbacSHendrik Noack if (wacom_data->variant->cmd_query_num > CMD_QUERY_NUM_MAX || 270*acaefbacSHendrik Noack wacom_data->variant->msg_coord_num > MSG_COORD_NUM_MAX) { 271*acaefbacSHendrik Noack dev_err(dev, "Length of message for %s exceeds the maximum\n", 272*acaefbacSHendrik Noack wacom_data->variant->name); 273*acaefbacSHendrik Noack return -EINVAL; 274*acaefbacSHendrik Noack } 275*acaefbacSHendrik Noack 276*acaefbacSHendrik Noack if (wacom_data->variant->msg_coord_num < 7) { 277*acaefbacSHendrik Noack dev_err(dev, "Length of coordinates message for %s too short\n", 278*acaefbacSHendrik Noack wacom_data->variant->name); 279*acaefbacSHendrik Noack return -EINVAL; 280*acaefbacSHendrik Noack } 281*acaefbacSHendrik Noack 282*acaefbacSHendrik Noack wacom_data->client = client; 283*acaefbacSHendrik Noack wacom_data->irq = client->irq; 284*acaefbacSHendrik Noack i2c_set_clientdata(client, wacom_data); 285*acaefbacSHendrik Noack 286*acaefbacSHendrik Noack wacom_data->regulator = devm_regulator_get(dev, "vdd"); 287*acaefbacSHendrik Noack if (IS_ERR(wacom_data->regulator)) 288*acaefbacSHendrik Noack return dev_err_probe(dev, PTR_ERR(wacom_data->regulator), 289*acaefbacSHendrik Noack "Failed to get regulators\n"); 290*acaefbacSHendrik Noack 291*acaefbacSHendrik Noack wacom_data->flash_mode_gpio = devm_gpiod_get_optional(dev, "flash-mode", GPIOD_OUT_LOW); 292*acaefbacSHendrik Noack if (IS_ERR(wacom_data->flash_mode_gpio)) 293*acaefbacSHendrik Noack return dev_err_probe(dev, PTR_ERR(wacom_data->flash_mode_gpio), 294*acaefbacSHendrik Noack "Failed to get flash-mode gpio\n"); 295*acaefbacSHendrik Noack 296*acaefbacSHendrik Noack wacom_data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 297*acaefbacSHendrik Noack if (IS_ERR(wacom_data->reset_gpio)) 298*acaefbacSHendrik Noack return dev_err_probe(dev, PTR_ERR(wacom_data->reset_gpio), 299*acaefbacSHendrik Noack "Failed to get reset gpio\n"); 300*acaefbacSHendrik Noack 301*acaefbacSHendrik Noack error = regulator_enable(wacom_data->regulator); 302*acaefbacSHendrik Noack if (error) 303*acaefbacSHendrik Noack return dev_err_probe(dev, error, "Failed to enable regulators\n"); 304*acaefbacSHendrik Noack 305*acaefbacSHendrik Noack msleep(200); 306*acaefbacSHendrik Noack 307*acaefbacSHendrik Noack gpiod_set_value_cansleep(wacom_data->reset_gpio, 0); 308*acaefbacSHendrik Noack 309*acaefbacSHendrik Noack error = wacom_w9000_query(wacom_data); 310*acaefbacSHendrik Noack 311*acaefbacSHendrik Noack gpiod_set_value_cansleep(wacom_data->reset_gpio, 1); 312*acaefbacSHendrik Noack regulator_disable(wacom_data->regulator); 313*acaefbacSHendrik Noack 314*acaefbacSHendrik Noack if (error) 315*acaefbacSHendrik Noack return dev_err_probe(dev, error, "Failed to query\n"); 316*acaefbacSHendrik Noack 317*acaefbacSHendrik Noack error = devm_request_threaded_irq(dev, wacom_data->irq, NULL, wacom_w9000_interrupt, 318*acaefbacSHendrik Noack IRQF_ONESHOT | IRQF_NO_AUTOEN, client->name, wacom_data); 319*acaefbacSHendrik Noack if (error) 320*acaefbacSHendrik Noack return dev_err_probe(dev, error, "Failed to register interrupt\n"); 321*acaefbacSHendrik Noack 322*acaefbacSHendrik Noack input_dev = devm_input_allocate_device(dev); 323*acaefbacSHendrik Noack if (!input_dev) 324*acaefbacSHendrik Noack return -ENOMEM; 325*acaefbacSHendrik Noack 326*acaefbacSHendrik Noack wacom_data->input_dev = input_dev; 327*acaefbacSHendrik Noack input_set_drvdata(input_dev, wacom_data); 328*acaefbacSHendrik Noack 329*acaefbacSHendrik Noack input_dev->name = wacom_data->variant->name; 330*acaefbacSHendrik Noack input_dev->id.bustype = BUS_I2C; 331*acaefbacSHendrik Noack input_dev->id.vendor = 0x56a; 332*acaefbacSHendrik Noack input_dev->id.version = wacom_data->fw_version; 333*acaefbacSHendrik Noack input_dev->open = wacom_w9000_open; 334*acaefbacSHendrik Noack input_dev->close = wacom_w9000_close; 335*acaefbacSHendrik Noack 336*acaefbacSHendrik Noack input_set_capability(input_dev, EV_KEY, BTN_TOUCH); 337*acaefbacSHendrik Noack input_set_capability(input_dev, EV_KEY, BTN_TOOL_PEN); 338*acaefbacSHendrik Noack input_set_capability(input_dev, EV_KEY, BTN_TOOL_RUBBER); 339*acaefbacSHendrik Noack input_set_capability(input_dev, EV_KEY, BTN_STYLUS); 340*acaefbacSHendrik Noack 341*acaefbacSHendrik Noack input_set_abs_params(input_dev, ABS_X, 0, wacom_data->prop.max_x, 4, 0); 342*acaefbacSHendrik Noack input_set_abs_params(input_dev, ABS_Y, 0, wacom_data->prop.max_y, 4, 0); 343*acaefbacSHendrik Noack input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_data->max_pressure, 0, 0); 344*acaefbacSHendrik Noack 345*acaefbacSHendrik Noack if (wacom_data->variant->msg_coord_num > 7) 346*acaefbacSHendrik Noack input_set_abs_params(input_dev, ABS_DISTANCE, 0, 255, 0, 0); 347*acaefbacSHendrik Noack 348*acaefbacSHendrik Noack touchscreen_parse_properties(input_dev, false, &wacom_data->prop); 349*acaefbacSHendrik Noack 350*acaefbacSHendrik Noack dev_info(dev, "%s size X%uY%u\n", wacom_data->variant->name, 351*acaefbacSHendrik Noack wacom_data->prop.max_x, wacom_data->prop.max_y); 352*acaefbacSHendrik Noack 353*acaefbacSHendrik Noack error = device_property_read_u32(dev, "touchscreen-x-mm", &val); 354*acaefbacSHendrik Noack if (!error && val) 355*acaefbacSHendrik Noack input_abs_set_res(input_dev, wacom_data->prop.swap_x_y ? ABS_Y : ABS_X, 356*acaefbacSHendrik Noack wacom_data->prop.max_x / val); 357*acaefbacSHendrik Noack error = device_property_read_u32(dev, "touchscreen-y-mm", &val); 358*acaefbacSHendrik Noack if (!error && val) 359*acaefbacSHendrik Noack input_abs_set_res(input_dev, wacom_data->prop.swap_x_y ? ABS_X : ABS_Y, 360*acaefbacSHendrik Noack wacom_data->prop.max_y / val); 361*acaefbacSHendrik Noack 362*acaefbacSHendrik Noack error = input_register_device(wacom_data->input_dev); 363*acaefbacSHendrik Noack if (error) 364*acaefbacSHendrik Noack return dev_err_probe(dev, error, "Failed to register input device\n"); 365*acaefbacSHendrik Noack 366*acaefbacSHendrik Noack return 0; 367*acaefbacSHendrik Noack } 368*acaefbacSHendrik Noack 369*acaefbacSHendrik Noack static int wacom_w9000_suspend(struct device *dev) 370*acaefbacSHendrik Noack { 371*acaefbacSHendrik Noack struct i2c_client *client = to_i2c_client(dev); 372*acaefbacSHendrik Noack struct wacom_w9000_data *wacom_data = i2c_get_clientdata(client); 373*acaefbacSHendrik Noack 374*acaefbacSHendrik Noack guard(mutex)(&wacom_data->input_dev->mutex); 375*acaefbacSHendrik Noack 376*acaefbacSHendrik Noack if (input_device_enabled(wacom_data->input_dev)) 377*acaefbacSHendrik Noack return wacom_w9000_power_off(wacom_data); 378*acaefbacSHendrik Noack 379*acaefbacSHendrik Noack return 0; 380*acaefbacSHendrik Noack } 381*acaefbacSHendrik Noack 382*acaefbacSHendrik Noack static int wacom_w9000_resume(struct device *dev) 383*acaefbacSHendrik Noack { 384*acaefbacSHendrik Noack struct i2c_client *client = to_i2c_client(dev); 385*acaefbacSHendrik Noack struct wacom_w9000_data *wacom_data = i2c_get_clientdata(client); 386*acaefbacSHendrik Noack 387*acaefbacSHendrik Noack guard(mutex)(&wacom_data->input_dev->mutex); 388*acaefbacSHendrik Noack 389*acaefbacSHendrik Noack if (input_device_enabled(wacom_data->input_dev)) 390*acaefbacSHendrik Noack return wacom_w9000_power_on(wacom_data); 391*acaefbacSHendrik Noack 392*acaefbacSHendrik Noack return 0; 393*acaefbacSHendrik Noack } 394*acaefbacSHendrik Noack 395*acaefbacSHendrik Noack static DEFINE_SIMPLE_DEV_PM_OPS(wacom_w9000_pm, wacom_w9000_suspend, wacom_w9000_resume); 396*acaefbacSHendrik Noack 397*acaefbacSHendrik Noack static const struct wacom_w9000_variant w9002 = { 398*acaefbacSHendrik Noack .cmd_query_num = 9, 399*acaefbacSHendrik Noack .msg_coord_num = 7, 400*acaefbacSHendrik Noack .name = "Wacom W9002 Digitizer", 401*acaefbacSHendrik Noack }; 402*acaefbacSHendrik Noack 403*acaefbacSHendrik Noack static const struct wacom_w9000_variant w9007a_lt03 = { 404*acaefbacSHendrik Noack .cmd_query_num = 9, 405*acaefbacSHendrik Noack .msg_coord_num = 8, 406*acaefbacSHendrik Noack .name = "Wacom W9007A LT03 Digitizer", 407*acaefbacSHendrik Noack }; 408*acaefbacSHendrik Noack 409*acaefbacSHendrik Noack static const struct wacom_w9000_variant w9007a_v1 = { 410*acaefbacSHendrik Noack .cmd_query_num = 9, 411*acaefbacSHendrik Noack .msg_coord_num = 12, 412*acaefbacSHendrik Noack .name = "Wacom W9007A V1 Digitizer", 413*acaefbacSHendrik Noack }; 414*acaefbacSHendrik Noack 415*acaefbacSHendrik Noack static const struct of_device_id wacom_w9000_of_match[] = { 416*acaefbacSHendrik Noack { .compatible = "wacom,w9002", .data = &w9002 }, 417*acaefbacSHendrik Noack { .compatible = "wacom,w9007a-lt03", .data = &w9007a_lt03, }, 418*acaefbacSHendrik Noack { .compatible = "wacom,w9007a-v1", .data = &w9007a_v1, }, 419*acaefbacSHendrik Noack { } 420*acaefbacSHendrik Noack }; 421*acaefbacSHendrik Noack MODULE_DEVICE_TABLE(of, wacom_w9000_of_match); 422*acaefbacSHendrik Noack 423*acaefbacSHendrik Noack static const struct i2c_device_id wacom_w9000_id[] = { 424*acaefbacSHendrik Noack { .name = "w9002", .driver_data = (kernel_ulong_t)&w9002 }, 425*acaefbacSHendrik Noack { .name = "w9007a-lt03", .driver_data = (kernel_ulong_t)&w9007a_lt03 }, 426*acaefbacSHendrik Noack { .name = "w9007a-v1", .driver_data = (kernel_ulong_t)&w9007a_v1 }, 427*acaefbacSHendrik Noack { } 428*acaefbacSHendrik Noack }; 429*acaefbacSHendrik Noack MODULE_DEVICE_TABLE(i2c, wacom_w9000_id); 430*acaefbacSHendrik Noack 431*acaefbacSHendrik Noack static struct i2c_driver wacom_w9000_driver = { 432*acaefbacSHendrik Noack .driver = { 433*acaefbacSHendrik Noack .name = "wacom_w9000", 434*acaefbacSHendrik Noack .of_match_table = wacom_w9000_of_match, 435*acaefbacSHendrik Noack .pm = pm_sleep_ptr(&wacom_w9000_pm), 436*acaefbacSHendrik Noack }, 437*acaefbacSHendrik Noack .probe = wacom_w9000_probe, 438*acaefbacSHendrik Noack .id_table = wacom_w9000_id, 439*acaefbacSHendrik Noack }; 440*acaefbacSHendrik Noack module_i2c_driver(wacom_w9000_driver); 441*acaefbacSHendrik Noack 442*acaefbacSHendrik Noack MODULE_AUTHOR("Hendrik Noack <hendrik-noack@gmx.de>"); 443*acaefbacSHendrik Noack MODULE_DESCRIPTION("Wacom W9000-series penabled touchscreen driver"); 444*acaefbacSHendrik Noack MODULE_LICENSE("GPL"); 445