19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25245db49SHeiko Stübner /* 35245db49SHeiko Stübner * Driver for AUO in-cell touchscreens 45245db49SHeiko Stübner * 55245db49SHeiko Stübner * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de> 65245db49SHeiko Stübner * 75245db49SHeiko Stübner * loosely based on auo_touch.c from Dell Streak vendor-kernel 85245db49SHeiko Stübner * 95245db49SHeiko Stübner * Copyright (c) 2008 QUALCOMM Incorporated. 105245db49SHeiko Stübner * Copyright (c) 2008 QUALCOMM USA, INC. 115245db49SHeiko Stübner */ 125245db49SHeiko Stübner 135245db49SHeiko Stübner #include <linux/kernel.h> 145245db49SHeiko Stübner #include <linux/module.h> 155245db49SHeiko Stübner #include <linux/interrupt.h> 165245db49SHeiko Stübner #include <linux/slab.h> 175245db49SHeiko Stübner #include <linux/input.h> 185245db49SHeiko Stübner #include <linux/jiffies.h> 195245db49SHeiko Stübner #include <linux/i2c.h> 205245db49SHeiko Stübner #include <linux/mutex.h> 215245db49SHeiko Stübner #include <linux/delay.h> 225245db49SHeiko Stübner #include <linux/gpio.h> 235245db49SHeiko Stübner #include <linux/input/auo-pixcir-ts.h> 247241443fSHeiko Stübner #include <linux/of.h> 257241443fSHeiko Stübner #include <linux/of_gpio.h> 265245db49SHeiko Stübner 275245db49SHeiko Stübner /* 285245db49SHeiko Stübner * Coordinate calculation: 295245db49SHeiko Stübner * X1 = X1_LSB + X1_MSB*256 305245db49SHeiko Stübner * Y1 = Y1_LSB + Y1_MSB*256 315245db49SHeiko Stübner * X2 = X2_LSB + X2_MSB*256 325245db49SHeiko Stübner * Y2 = Y2_LSB + Y2_MSB*256 335245db49SHeiko Stübner */ 345245db49SHeiko Stübner #define AUO_PIXCIR_REG_X1_LSB 0x00 355245db49SHeiko Stübner #define AUO_PIXCIR_REG_X1_MSB 0x01 365245db49SHeiko Stübner #define AUO_PIXCIR_REG_Y1_LSB 0x02 375245db49SHeiko Stübner #define AUO_PIXCIR_REG_Y1_MSB 0x03 385245db49SHeiko Stübner #define AUO_PIXCIR_REG_X2_LSB 0x04 395245db49SHeiko Stübner #define AUO_PIXCIR_REG_X2_MSB 0x05 405245db49SHeiko Stübner #define AUO_PIXCIR_REG_Y2_LSB 0x06 415245db49SHeiko Stübner #define AUO_PIXCIR_REG_Y2_MSB 0x07 425245db49SHeiko Stübner 435245db49SHeiko Stübner #define AUO_PIXCIR_REG_STRENGTH 0x0d 445245db49SHeiko Stübner #define AUO_PIXCIR_REG_STRENGTH_X1_LSB 0x0e 455245db49SHeiko Stübner #define AUO_PIXCIR_REG_STRENGTH_X1_MSB 0x0f 465245db49SHeiko Stübner 475245db49SHeiko Stübner #define AUO_PIXCIR_REG_RAW_DATA_X 0x2b 485245db49SHeiko Stübner #define AUO_PIXCIR_REG_RAW_DATA_Y 0x4f 495245db49SHeiko Stübner 505245db49SHeiko Stübner #define AUO_PIXCIR_REG_X_SENSITIVITY 0x6f 515245db49SHeiko Stübner #define AUO_PIXCIR_REG_Y_SENSITIVITY 0x70 525245db49SHeiko Stübner #define AUO_PIXCIR_REG_INT_SETTING 0x71 535245db49SHeiko Stübner #define AUO_PIXCIR_REG_INT_WIDTH 0x72 545245db49SHeiko Stübner #define AUO_PIXCIR_REG_POWER_MODE 0x73 555245db49SHeiko Stübner 565245db49SHeiko Stübner #define AUO_PIXCIR_REG_VERSION 0x77 575245db49SHeiko Stübner #define AUO_PIXCIR_REG_CALIBRATE 0x78 585245db49SHeiko Stübner 595245db49SHeiko Stübner #define AUO_PIXCIR_REG_TOUCHAREA_X1 0x1e 605245db49SHeiko Stübner #define AUO_PIXCIR_REG_TOUCHAREA_Y1 0x1f 615245db49SHeiko Stübner #define AUO_PIXCIR_REG_TOUCHAREA_X2 0x20 625245db49SHeiko Stübner #define AUO_PIXCIR_REG_TOUCHAREA_Y2 0x21 635245db49SHeiko Stübner 645245db49SHeiko Stübner #define AUO_PIXCIR_REG_EEPROM_CALIB_X 0x42 655245db49SHeiko Stübner #define AUO_PIXCIR_REG_EEPROM_CALIB_Y 0xad 665245db49SHeiko Stübner 675245db49SHeiko Stübner #define AUO_PIXCIR_INT_TPNUM_MASK 0xe0 685245db49SHeiko Stübner #define AUO_PIXCIR_INT_TPNUM_SHIFT 5 695245db49SHeiko Stübner #define AUO_PIXCIR_INT_RELEASE (1 << 4) 705245db49SHeiko Stübner #define AUO_PIXCIR_INT_ENABLE (1 << 3) 715245db49SHeiko Stübner #define AUO_PIXCIR_INT_POL_HIGH (1 << 2) 725245db49SHeiko Stübner #define AUO_PIXCIR_INT_MODE_MASK 0x03 735245db49SHeiko Stübner 745245db49SHeiko Stübner /* 755245db49SHeiko Stübner * Power modes: 765245db49SHeiko Stübner * active: scan speed 60Hz 775245db49SHeiko Stübner * sleep: scan speed 10Hz can be auto-activated, wakeup on 1st touch 785245db49SHeiko Stübner * deep sleep: scan speed 1Hz can only be entered or left manually. 795245db49SHeiko Stübner */ 805245db49SHeiko Stübner #define AUO_PIXCIR_POWER_ACTIVE 0x00 815245db49SHeiko Stübner #define AUO_PIXCIR_POWER_SLEEP 0x01 825245db49SHeiko Stübner #define AUO_PIXCIR_POWER_DEEP_SLEEP 0x02 835245db49SHeiko Stübner #define AUO_PIXCIR_POWER_MASK 0x03 845245db49SHeiko Stübner 855245db49SHeiko Stübner #define AUO_PIXCIR_POWER_ALLOW_SLEEP (1 << 2) 865245db49SHeiko Stübner #define AUO_PIXCIR_POWER_IDLE_TIME(ms) ((ms & 0xf) << 4) 875245db49SHeiko Stübner 885245db49SHeiko Stübner #define AUO_PIXCIR_CALIBRATE 0x03 895245db49SHeiko Stübner 905245db49SHeiko Stübner #define AUO_PIXCIR_EEPROM_CALIB_X_LEN 62 915245db49SHeiko Stübner #define AUO_PIXCIR_EEPROM_CALIB_Y_LEN 36 925245db49SHeiko Stübner 935245db49SHeiko Stübner #define AUO_PIXCIR_RAW_DATA_X_LEN 18 945245db49SHeiko Stübner #define AUO_PIXCIR_RAW_DATA_Y_LEN 11 955245db49SHeiko Stübner 965245db49SHeiko Stübner #define AUO_PIXCIR_STRENGTH_ENABLE (1 << 0) 975245db49SHeiko Stübner 985245db49SHeiko Stübner /* Touchscreen absolute values */ 995245db49SHeiko Stübner #define AUO_PIXCIR_REPORT_POINTS 2 1005245db49SHeiko Stübner #define AUO_PIXCIR_MAX_AREA 0xff 1015245db49SHeiko Stübner #define AUO_PIXCIR_PENUP_TIMEOUT_MS 10 1025245db49SHeiko Stübner 1035245db49SHeiko Stübner struct auo_pixcir_ts { 1045245db49SHeiko Stübner struct i2c_client *client; 1055245db49SHeiko Stübner struct input_dev *input; 10638e83f7fSHeiko Stübner const struct auo_pixcir_ts_platdata *pdata; 1075245db49SHeiko Stübner char phys[32]; 1085245db49SHeiko Stübner 1095245db49SHeiko Stübner /* special handling for touch_indicate interupt mode */ 1105245db49SHeiko Stübner bool touch_ind_mode; 1115245db49SHeiko Stübner 1125245db49SHeiko Stübner wait_queue_head_t wait; 1135245db49SHeiko Stübner bool stopped; 1145245db49SHeiko Stübner }; 1155245db49SHeiko Stübner 1165245db49SHeiko Stübner struct auo_point_t { 1175245db49SHeiko Stübner int coord_x; 1185245db49SHeiko Stübner int coord_y; 1195245db49SHeiko Stübner int area_major; 1205245db49SHeiko Stübner int area_minor; 1215245db49SHeiko Stübner int orientation; 1225245db49SHeiko Stübner }; 1235245db49SHeiko Stübner 1245245db49SHeiko Stübner static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts, 1255245db49SHeiko Stübner struct auo_point_t *point) 1265245db49SHeiko Stübner { 1275245db49SHeiko Stübner struct i2c_client *client = ts->client; 12838e83f7fSHeiko Stübner const struct auo_pixcir_ts_platdata *pdata = ts->pdata; 1295245db49SHeiko Stübner uint8_t raw_coord[8]; 1305245db49SHeiko Stübner uint8_t raw_area[4]; 1315245db49SHeiko Stübner int i, ret; 1325245db49SHeiko Stübner 1335245db49SHeiko Stübner /* touch coordinates */ 1345245db49SHeiko Stübner ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_X1_LSB, 1355245db49SHeiko Stübner 8, raw_coord); 1365245db49SHeiko Stübner if (ret < 0) { 1375245db49SHeiko Stübner dev_err(&client->dev, "failed to read coordinate, %d\n", ret); 1385245db49SHeiko Stübner return ret; 1395245db49SHeiko Stübner } 1405245db49SHeiko Stübner 1415245db49SHeiko Stübner /* touch area */ 1425245db49SHeiko Stübner ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_TOUCHAREA_X1, 1435245db49SHeiko Stübner 4, raw_area); 1445245db49SHeiko Stübner if (ret < 0) { 1455245db49SHeiko Stübner dev_err(&client->dev, "could not read touch area, %d\n", ret); 1465245db49SHeiko Stübner return ret; 1475245db49SHeiko Stübner } 1485245db49SHeiko Stübner 1495245db49SHeiko Stübner for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) { 1505245db49SHeiko Stübner point[i].coord_x = 1515245db49SHeiko Stübner raw_coord[4 * i + 1] << 8 | raw_coord[4 * i]; 1525245db49SHeiko Stübner point[i].coord_y = 1535245db49SHeiko Stübner raw_coord[4 * i + 3] << 8 | raw_coord[4 * i + 2]; 1545245db49SHeiko Stübner 1555245db49SHeiko Stübner if (point[i].coord_x > pdata->x_max || 1565245db49SHeiko Stübner point[i].coord_y > pdata->y_max) { 1575245db49SHeiko Stübner dev_warn(&client->dev, "coordinates (%d,%d) invalid\n", 1585245db49SHeiko Stübner point[i].coord_x, point[i].coord_y); 1595245db49SHeiko Stübner point[i].coord_x = point[i].coord_y = 0; 1605245db49SHeiko Stübner } 1615245db49SHeiko Stübner 1625245db49SHeiko Stübner /* determine touch major, minor and orientation */ 1635245db49SHeiko Stübner point[i].area_major = max(raw_area[2 * i], raw_area[2 * i + 1]); 1645245db49SHeiko Stübner point[i].area_minor = min(raw_area[2 * i], raw_area[2 * i + 1]); 1655245db49SHeiko Stübner point[i].orientation = raw_area[2 * i] > raw_area[2 * i + 1]; 1665245db49SHeiko Stübner } 1675245db49SHeiko Stübner 1685245db49SHeiko Stübner return 0; 1695245db49SHeiko Stübner } 1705245db49SHeiko Stübner 1715245db49SHeiko Stübner static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id) 1725245db49SHeiko Stübner { 1735245db49SHeiko Stübner struct auo_pixcir_ts *ts = dev_id; 17438e83f7fSHeiko Stübner const struct auo_pixcir_ts_platdata *pdata = ts->pdata; 1755245db49SHeiko Stübner struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS]; 1765245db49SHeiko Stübner int i; 1775245db49SHeiko Stübner int ret; 1785245db49SHeiko Stübner int fingers = 0; 1795245db49SHeiko Stübner int abs = -1; 1805245db49SHeiko Stübner 1815245db49SHeiko Stübner while (!ts->stopped) { 1825245db49SHeiko Stübner 1835245db49SHeiko Stübner /* check for up event in touch touch_ind_mode */ 1845245db49SHeiko Stübner if (ts->touch_ind_mode) { 1855245db49SHeiko Stübner if (gpio_get_value(pdata->gpio_int) == 0) { 1865245db49SHeiko Stübner input_mt_sync(ts->input); 1875245db49SHeiko Stübner input_report_key(ts->input, BTN_TOUCH, 0); 1885245db49SHeiko Stübner input_sync(ts->input); 1895245db49SHeiko Stübner break; 1905245db49SHeiko Stübner } 1915245db49SHeiko Stübner } 1925245db49SHeiko Stübner 1935245db49SHeiko Stübner ret = auo_pixcir_collect_data(ts, point); 1945245db49SHeiko Stübner if (ret < 0) { 1955245db49SHeiko Stübner /* we want to loop only in touch_ind_mode */ 1965245db49SHeiko Stübner if (!ts->touch_ind_mode) 1975245db49SHeiko Stübner break; 1985245db49SHeiko Stübner 1995245db49SHeiko Stübner wait_event_timeout(ts->wait, ts->stopped, 2005245db49SHeiko Stübner msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS)); 2015245db49SHeiko Stübner continue; 2025245db49SHeiko Stübner } 2035245db49SHeiko Stübner 2045245db49SHeiko Stübner for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) { 2055245db49SHeiko Stübner if (point[i].coord_x > 0 || point[i].coord_y > 0) { 2065245db49SHeiko Stübner input_report_abs(ts->input, ABS_MT_POSITION_X, 2075245db49SHeiko Stübner point[i].coord_x); 2085245db49SHeiko Stübner input_report_abs(ts->input, ABS_MT_POSITION_Y, 2095245db49SHeiko Stübner point[i].coord_y); 2105245db49SHeiko Stübner input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 2115245db49SHeiko Stübner point[i].area_major); 2125245db49SHeiko Stübner input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, 2135245db49SHeiko Stübner point[i].area_minor); 2145245db49SHeiko Stübner input_report_abs(ts->input, ABS_MT_ORIENTATION, 2155245db49SHeiko Stübner point[i].orientation); 2165245db49SHeiko Stübner input_mt_sync(ts->input); 2175245db49SHeiko Stübner 2185245db49SHeiko Stübner /* use first finger as source for singletouch */ 2195245db49SHeiko Stübner if (fingers == 0) 2205245db49SHeiko Stübner abs = i; 2215245db49SHeiko Stübner 2225245db49SHeiko Stübner /* number of touch points could also be queried 2235245db49SHeiko Stübner * via i2c but would require an additional call 2245245db49SHeiko Stübner */ 2255245db49SHeiko Stübner fingers++; 2265245db49SHeiko Stübner } 2275245db49SHeiko Stübner } 2285245db49SHeiko Stübner 2295245db49SHeiko Stübner input_report_key(ts->input, BTN_TOUCH, fingers > 0); 2305245db49SHeiko Stübner 2315245db49SHeiko Stübner if (abs > -1) { 2325245db49SHeiko Stübner input_report_abs(ts->input, ABS_X, point[abs].coord_x); 2335245db49SHeiko Stübner input_report_abs(ts->input, ABS_Y, point[abs].coord_y); 2345245db49SHeiko Stübner } 2355245db49SHeiko Stübner 2365245db49SHeiko Stübner input_sync(ts->input); 2375245db49SHeiko Stübner 2385245db49SHeiko Stübner /* we want to loop only in touch_ind_mode */ 2395245db49SHeiko Stübner if (!ts->touch_ind_mode) 2405245db49SHeiko Stübner break; 2415245db49SHeiko Stübner 2425245db49SHeiko Stübner wait_event_timeout(ts->wait, ts->stopped, 2435245db49SHeiko Stübner msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS)); 2445245db49SHeiko Stübner } 2455245db49SHeiko Stübner 2465245db49SHeiko Stübner return IRQ_HANDLED; 2475245db49SHeiko Stübner } 2485245db49SHeiko Stübner 2495245db49SHeiko Stübner /* 2505245db49SHeiko Stübner * Set the power mode of the device. 2515245db49SHeiko Stübner * Valid modes are 2525245db49SHeiko Stübner * - AUO_PIXCIR_POWER_ACTIVE 2535245db49SHeiko Stübner * - AUO_PIXCIR_POWER_SLEEP - automatically left on first touch 2545245db49SHeiko Stübner * - AUO_PIXCIR_POWER_DEEP_SLEEP 2555245db49SHeiko Stübner */ 2565245db49SHeiko Stübner static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode) 2575245db49SHeiko Stübner { 2585245db49SHeiko Stübner struct i2c_client *client = ts->client; 2595245db49SHeiko Stübner int ret; 2605245db49SHeiko Stübner 2615245db49SHeiko Stübner ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_POWER_MODE); 2625245db49SHeiko Stübner if (ret < 0) { 2635245db49SHeiko Stübner dev_err(&client->dev, "unable to read reg %Xh, %d\n", 2645245db49SHeiko Stübner AUO_PIXCIR_REG_POWER_MODE, ret); 2655245db49SHeiko Stübner return ret; 2665245db49SHeiko Stübner } 2675245db49SHeiko Stübner 2685245db49SHeiko Stübner ret &= ~AUO_PIXCIR_POWER_MASK; 2695245db49SHeiko Stübner ret |= mode; 2705245db49SHeiko Stübner 2715245db49SHeiko Stübner ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_POWER_MODE, ret); 2725245db49SHeiko Stübner if (ret) { 2735245db49SHeiko Stübner dev_err(&client->dev, "unable to write reg %Xh, %d\n", 2745245db49SHeiko Stübner AUO_PIXCIR_REG_POWER_MODE, ret); 2755245db49SHeiko Stübner return ret; 2765245db49SHeiko Stübner } 2775245db49SHeiko Stübner 2785245db49SHeiko Stübner return 0; 2795245db49SHeiko Stübner } 2805245db49SHeiko Stübner 2815298cc4cSBill Pemberton static int auo_pixcir_int_config(struct auo_pixcir_ts *ts, 2825245db49SHeiko Stübner int int_setting) 2835245db49SHeiko Stübner { 2845245db49SHeiko Stübner struct i2c_client *client = ts->client; 28538e83f7fSHeiko Stübner const struct auo_pixcir_ts_platdata *pdata = ts->pdata; 2865245db49SHeiko Stübner int ret; 2875245db49SHeiko Stübner 2885245db49SHeiko Stübner ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING); 2895245db49SHeiko Stübner if (ret < 0) { 2905245db49SHeiko Stübner dev_err(&client->dev, "unable to read reg %Xh, %d\n", 2915245db49SHeiko Stübner AUO_PIXCIR_REG_INT_SETTING, ret); 2925245db49SHeiko Stübner return ret; 2935245db49SHeiko Stübner } 2945245db49SHeiko Stübner 2955245db49SHeiko Stübner ret &= ~AUO_PIXCIR_INT_MODE_MASK; 2965245db49SHeiko Stübner ret |= int_setting; 2975245db49SHeiko Stübner ret |= AUO_PIXCIR_INT_POL_HIGH; /* always use high for interrupts */ 2985245db49SHeiko Stübner 2995245db49SHeiko Stübner ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING, 3005245db49SHeiko Stübner ret); 3015245db49SHeiko Stübner if (ret < 0) { 3025245db49SHeiko Stübner dev_err(&client->dev, "unable to write reg %Xh, %d\n", 3035245db49SHeiko Stübner AUO_PIXCIR_REG_INT_SETTING, ret); 3045245db49SHeiko Stübner return ret; 3055245db49SHeiko Stübner } 3065245db49SHeiko Stübner 3075245db49SHeiko Stübner ts->touch_ind_mode = pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND; 3085245db49SHeiko Stübner 3095245db49SHeiko Stübner return 0; 3105245db49SHeiko Stübner } 3115245db49SHeiko Stübner 3125245db49SHeiko Stübner /* control the generation of interrupts on the device side */ 3135245db49SHeiko Stübner static int auo_pixcir_int_toggle(struct auo_pixcir_ts *ts, bool enable) 3145245db49SHeiko Stübner { 3155245db49SHeiko Stübner struct i2c_client *client = ts->client; 3165245db49SHeiko Stübner int ret; 3175245db49SHeiko Stübner 3185245db49SHeiko Stübner ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING); 3195245db49SHeiko Stübner if (ret < 0) { 3205245db49SHeiko Stübner dev_err(&client->dev, "unable to read reg %Xh, %d\n", 3215245db49SHeiko Stübner AUO_PIXCIR_REG_INT_SETTING, ret); 3225245db49SHeiko Stübner return ret; 3235245db49SHeiko Stübner } 3245245db49SHeiko Stübner 3255245db49SHeiko Stübner if (enable) 3265245db49SHeiko Stübner ret |= AUO_PIXCIR_INT_ENABLE; 3275245db49SHeiko Stübner else 3285245db49SHeiko Stübner ret &= ~AUO_PIXCIR_INT_ENABLE; 3295245db49SHeiko Stübner 3305245db49SHeiko Stübner ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING, 3315245db49SHeiko Stübner ret); 3325245db49SHeiko Stübner if (ret < 0) { 3335245db49SHeiko Stübner dev_err(&client->dev, "unable to write reg %Xh, %d\n", 3345245db49SHeiko Stübner AUO_PIXCIR_REG_INT_SETTING, ret); 3355245db49SHeiko Stübner return ret; 3365245db49SHeiko Stübner } 3375245db49SHeiko Stübner 3385245db49SHeiko Stübner return 0; 3395245db49SHeiko Stübner } 3405245db49SHeiko Stübner 3415245db49SHeiko Stübner static int auo_pixcir_start(struct auo_pixcir_ts *ts) 3425245db49SHeiko Stübner { 3435245db49SHeiko Stübner struct i2c_client *client = ts->client; 3445245db49SHeiko Stübner int ret; 3455245db49SHeiko Stübner 3465245db49SHeiko Stübner ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_ACTIVE); 3475245db49SHeiko Stübner if (ret < 0) { 3485245db49SHeiko Stübner dev_err(&client->dev, "could not set power mode, %d\n", 3495245db49SHeiko Stübner ret); 3505245db49SHeiko Stübner return ret; 3515245db49SHeiko Stübner } 3525245db49SHeiko Stübner 3535245db49SHeiko Stübner ts->stopped = false; 3545245db49SHeiko Stübner mb(); 3555245db49SHeiko Stübner enable_irq(client->irq); 3565245db49SHeiko Stübner 3575245db49SHeiko Stübner ret = auo_pixcir_int_toggle(ts, 1); 3585245db49SHeiko Stübner if (ret < 0) { 3595245db49SHeiko Stübner dev_err(&client->dev, "could not enable interrupt, %d\n", 3605245db49SHeiko Stübner ret); 3615245db49SHeiko Stübner disable_irq(client->irq); 3625245db49SHeiko Stübner return ret; 3635245db49SHeiko Stübner } 3645245db49SHeiko Stübner 3655245db49SHeiko Stübner return 0; 3665245db49SHeiko Stübner } 3675245db49SHeiko Stübner 3685245db49SHeiko Stübner static int auo_pixcir_stop(struct auo_pixcir_ts *ts) 3695245db49SHeiko Stübner { 3705245db49SHeiko Stübner struct i2c_client *client = ts->client; 3715245db49SHeiko Stübner int ret; 3725245db49SHeiko Stübner 3735245db49SHeiko Stübner ret = auo_pixcir_int_toggle(ts, 0); 3745245db49SHeiko Stübner if (ret < 0) { 3755245db49SHeiko Stübner dev_err(&client->dev, "could not disable interrupt, %d\n", 3765245db49SHeiko Stübner ret); 3775245db49SHeiko Stübner return ret; 3785245db49SHeiko Stübner } 3795245db49SHeiko Stübner 3805245db49SHeiko Stübner /* disable receiving of interrupts */ 3815245db49SHeiko Stübner disable_irq(client->irq); 3825245db49SHeiko Stübner ts->stopped = true; 3835245db49SHeiko Stübner mb(); 3845245db49SHeiko Stübner wake_up(&ts->wait); 3855245db49SHeiko Stübner 3865245db49SHeiko Stübner return auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_DEEP_SLEEP); 3875245db49SHeiko Stübner } 3885245db49SHeiko Stübner 3895245db49SHeiko Stübner static int auo_pixcir_input_open(struct input_dev *dev) 3905245db49SHeiko Stübner { 3915245db49SHeiko Stübner struct auo_pixcir_ts *ts = input_get_drvdata(dev); 3925245db49SHeiko Stübner 393901ea5e3SJavier Martinez Canillas return auo_pixcir_start(ts); 3945245db49SHeiko Stübner } 3955245db49SHeiko Stübner 3965245db49SHeiko Stübner static void auo_pixcir_input_close(struct input_dev *dev) 3975245db49SHeiko Stübner { 3985245db49SHeiko Stübner struct auo_pixcir_ts *ts = input_get_drvdata(dev); 3995245db49SHeiko Stübner 4005245db49SHeiko Stübner auo_pixcir_stop(ts); 4015245db49SHeiko Stübner } 4025245db49SHeiko Stübner 40302b6a58bSJingoo Han static int __maybe_unused auo_pixcir_suspend(struct device *dev) 4045245db49SHeiko Stübner { 4055245db49SHeiko Stübner struct i2c_client *client = to_i2c_client(dev); 4065245db49SHeiko Stübner struct auo_pixcir_ts *ts = i2c_get_clientdata(client); 4075245db49SHeiko Stübner struct input_dev *input = ts->input; 4085245db49SHeiko Stübner int ret = 0; 4095245db49SHeiko Stübner 4105245db49SHeiko Stübner mutex_lock(&input->mutex); 4115245db49SHeiko Stübner 4125245db49SHeiko Stübner /* when configured as wakeup source, device should always wake system 4135245db49SHeiko Stübner * therefore start device if necessary 4145245db49SHeiko Stübner */ 4155245db49SHeiko Stübner if (device_may_wakeup(&client->dev)) { 4165245db49SHeiko Stübner /* need to start device if not open, to be wakeup source */ 4175245db49SHeiko Stübner if (!input->users) { 4185245db49SHeiko Stübner ret = auo_pixcir_start(ts); 4195245db49SHeiko Stübner if (ret) 4205245db49SHeiko Stübner goto unlock; 4215245db49SHeiko Stübner } 4225245db49SHeiko Stübner 4235245db49SHeiko Stübner enable_irq_wake(client->irq); 4245245db49SHeiko Stübner ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP); 4255245db49SHeiko Stübner } else if (input->users) { 4265245db49SHeiko Stübner ret = auo_pixcir_stop(ts); 4275245db49SHeiko Stübner } 4285245db49SHeiko Stübner 4295245db49SHeiko Stübner unlock: 4305245db49SHeiko Stübner mutex_unlock(&input->mutex); 4315245db49SHeiko Stübner 4325245db49SHeiko Stübner return ret; 4335245db49SHeiko Stübner } 4345245db49SHeiko Stübner 43502b6a58bSJingoo Han static int __maybe_unused auo_pixcir_resume(struct device *dev) 4365245db49SHeiko Stübner { 4375245db49SHeiko Stübner struct i2c_client *client = to_i2c_client(dev); 4385245db49SHeiko Stübner struct auo_pixcir_ts *ts = i2c_get_clientdata(client); 4395245db49SHeiko Stübner struct input_dev *input = ts->input; 4405245db49SHeiko Stübner int ret = 0; 4415245db49SHeiko Stübner 4425245db49SHeiko Stübner mutex_lock(&input->mutex); 4435245db49SHeiko Stübner 4445245db49SHeiko Stübner if (device_may_wakeup(&client->dev)) { 4455245db49SHeiko Stübner disable_irq_wake(client->irq); 4465245db49SHeiko Stübner 4475245db49SHeiko Stübner /* need to stop device if it was not open on suspend */ 4485245db49SHeiko Stübner if (!input->users) { 4495245db49SHeiko Stübner ret = auo_pixcir_stop(ts); 4505245db49SHeiko Stübner if (ret) 4515245db49SHeiko Stübner goto unlock; 4525245db49SHeiko Stübner } 4535245db49SHeiko Stübner 4545245db49SHeiko Stübner /* device wakes automatically from SLEEP */ 4555245db49SHeiko Stübner } else if (input->users) { 4565245db49SHeiko Stübner ret = auo_pixcir_start(ts); 4575245db49SHeiko Stübner } 4585245db49SHeiko Stübner 4595245db49SHeiko Stübner unlock: 4605245db49SHeiko Stübner mutex_unlock(&input->mutex); 4615245db49SHeiko Stübner 4625245db49SHeiko Stübner return ret; 4635245db49SHeiko Stübner } 4645245db49SHeiko Stübner 4657241443fSHeiko Stübner static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, 4667241443fSHeiko Stübner auo_pixcir_suspend, auo_pixcir_resume); 4677241443fSHeiko Stübner 4687241443fSHeiko Stübner #ifdef CONFIG_OF 4697241443fSHeiko Stübner static struct auo_pixcir_ts_platdata *auo_pixcir_parse_dt(struct device *dev) 4707241443fSHeiko Stübner { 4717241443fSHeiko Stübner struct auo_pixcir_ts_platdata *pdata; 4727241443fSHeiko Stübner struct device_node *np = dev->of_node; 4737241443fSHeiko Stübner 4747241443fSHeiko Stübner if (!np) 4757241443fSHeiko Stübner return ERR_PTR(-ENOENT); 4767241443fSHeiko Stübner 4777241443fSHeiko Stübner pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 478eae7d90cSMarkus Elfring if (!pdata) 4797241443fSHeiko Stübner return ERR_PTR(-ENOMEM); 4807241443fSHeiko Stübner 4817241443fSHeiko Stübner pdata->gpio_int = of_get_gpio(np, 0); 4827241443fSHeiko Stübner if (!gpio_is_valid(pdata->gpio_int)) { 4837241443fSHeiko Stübner dev_err(dev, "failed to get interrupt gpio\n"); 4847241443fSHeiko Stübner return ERR_PTR(-EINVAL); 4857241443fSHeiko Stübner } 4867241443fSHeiko Stübner 4877241443fSHeiko Stübner pdata->gpio_rst = of_get_gpio(np, 1); 4887241443fSHeiko Stübner if (!gpio_is_valid(pdata->gpio_rst)) { 4897241443fSHeiko Stübner dev_err(dev, "failed to get reset gpio\n"); 4907241443fSHeiko Stübner return ERR_PTR(-EINVAL); 4917241443fSHeiko Stübner } 4927241443fSHeiko Stübner 4937241443fSHeiko Stübner if (of_property_read_u32(np, "x-size", &pdata->x_max)) { 4947241443fSHeiko Stübner dev_err(dev, "failed to get x-size property\n"); 4957241443fSHeiko Stübner return ERR_PTR(-EINVAL); 4967241443fSHeiko Stübner } 4977241443fSHeiko Stübner 4987241443fSHeiko Stübner if (of_property_read_u32(np, "y-size", &pdata->y_max)) { 4997241443fSHeiko Stübner dev_err(dev, "failed to get y-size property\n"); 5007241443fSHeiko Stübner return ERR_PTR(-EINVAL); 5017241443fSHeiko Stübner } 5027241443fSHeiko Stübner 5037241443fSHeiko Stübner /* default to asserting the interrupt when the screen is touched */ 5047241443fSHeiko Stübner pdata->int_setting = AUO_PIXCIR_INT_TOUCH_IND; 5057241443fSHeiko Stübner 5067241443fSHeiko Stübner return pdata; 5077241443fSHeiko Stübner } 5087241443fSHeiko Stübner #else 5097241443fSHeiko Stübner static struct auo_pixcir_ts_platdata *auo_pixcir_parse_dt(struct device *dev) 5107241443fSHeiko Stübner { 5117241443fSHeiko Stübner return ERR_PTR(-EINVAL); 5127241443fSHeiko Stübner } 5137241443fSHeiko Stübner #endif 5145245db49SHeiko Stübner 515bfc29e95SDmitry Torokhov static void auo_pixcir_reset(void *data) 516bfc29e95SDmitry Torokhov { 517bfc29e95SDmitry Torokhov struct auo_pixcir_ts *ts = data; 518bfc29e95SDmitry Torokhov 519bfc29e95SDmitry Torokhov gpio_set_value(ts->pdata->gpio_rst, 0); 520bfc29e95SDmitry Torokhov } 521bfc29e95SDmitry Torokhov 5225298cc4cSBill Pemberton static int auo_pixcir_probe(struct i2c_client *client, 5235245db49SHeiko Stübner const struct i2c_device_id *id) 5245245db49SHeiko Stübner { 5257241443fSHeiko Stübner const struct auo_pixcir_ts_platdata *pdata; 5265245db49SHeiko Stübner struct auo_pixcir_ts *ts; 5275245db49SHeiko Stübner struct input_dev *input_dev; 528bfc29e95SDmitry Torokhov int version; 529bfc29e95SDmitry Torokhov int error; 5305245db49SHeiko Stübner 5317241443fSHeiko Stübner pdata = dev_get_platdata(&client->dev); 5327241443fSHeiko Stübner if (!pdata) { 5337241443fSHeiko Stübner pdata = auo_pixcir_parse_dt(&client->dev); 5347241443fSHeiko Stübner if (IS_ERR(pdata)) 5357241443fSHeiko Stübner return PTR_ERR(pdata); 5367241443fSHeiko Stübner } 5375245db49SHeiko Stübner 538bfc29e95SDmitry Torokhov ts = devm_kzalloc(&client->dev, 539bfc29e95SDmitry Torokhov sizeof(struct auo_pixcir_ts), GFP_KERNEL); 5405245db49SHeiko Stübner if (!ts) 5415245db49SHeiko Stübner return -ENOMEM; 5425245db49SHeiko Stübner 543bfc29e95SDmitry Torokhov input_dev = devm_input_allocate_device(&client->dev); 544bfc29e95SDmitry Torokhov if (!input_dev) { 545bfc29e95SDmitry Torokhov dev_err(&client->dev, "could not allocate input device\n"); 546bfc29e95SDmitry Torokhov return -ENOMEM; 5475245db49SHeiko Stübner } 5485245db49SHeiko Stübner 54938e83f7fSHeiko Stübner ts->pdata = pdata; 5505245db49SHeiko Stübner ts->client = client; 551bfc29e95SDmitry Torokhov ts->input = input_dev; 5525245db49SHeiko Stübner ts->touch_ind_mode = 0; 553bfc29e95SDmitry Torokhov ts->stopped = true; 5545245db49SHeiko Stübner init_waitqueue_head(&ts->wait); 5555245db49SHeiko Stübner 5565245db49SHeiko Stübner snprintf(ts->phys, sizeof(ts->phys), 5575245db49SHeiko Stübner "%s/input0", dev_name(&client->dev)); 5585245db49SHeiko Stübner 5595245db49SHeiko Stübner input_dev->name = "AUO-Pixcir touchscreen"; 5605245db49SHeiko Stübner input_dev->phys = ts->phys; 5615245db49SHeiko Stübner input_dev->id.bustype = BUS_I2C; 5625245db49SHeiko Stübner 5635245db49SHeiko Stübner input_dev->open = auo_pixcir_input_open; 5645245db49SHeiko Stübner input_dev->close = auo_pixcir_input_close; 5655245db49SHeiko Stübner 5665245db49SHeiko Stübner __set_bit(EV_ABS, input_dev->evbit); 5675245db49SHeiko Stübner __set_bit(EV_KEY, input_dev->evbit); 5685245db49SHeiko Stübner 5695245db49SHeiko Stübner __set_bit(BTN_TOUCH, input_dev->keybit); 5705245db49SHeiko Stübner 5715245db49SHeiko Stübner /* For single touch */ 5725245db49SHeiko Stübner input_set_abs_params(input_dev, ABS_X, 0, pdata->x_max, 0, 0); 5735245db49SHeiko Stübner input_set_abs_params(input_dev, ABS_Y, 0, pdata->y_max, 0, 0); 5745245db49SHeiko Stübner 5755245db49SHeiko Stübner /* For multi touch */ 5765245db49SHeiko Stübner input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, 5775245db49SHeiko Stübner pdata->x_max, 0, 0); 5785245db49SHeiko Stübner input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 5795245db49SHeiko Stübner pdata->y_max, 0, 0); 5805245db49SHeiko Stübner input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 5815245db49SHeiko Stübner AUO_PIXCIR_MAX_AREA, 0, 0); 5825245db49SHeiko Stübner input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, 5835245db49SHeiko Stübner AUO_PIXCIR_MAX_AREA, 0, 0); 5845245db49SHeiko Stübner input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); 5855245db49SHeiko Stübner 5865245db49SHeiko Stübner input_set_drvdata(ts->input, ts); 5875245db49SHeiko Stübner 588bfc29e95SDmitry Torokhov error = devm_gpio_request_one(&client->dev, pdata->gpio_int, 589bfc29e95SDmitry Torokhov GPIOF_DIR_IN, "auo_pixcir_ts_int"); 590bfc29e95SDmitry Torokhov if (error) { 591bfc29e95SDmitry Torokhov dev_err(&client->dev, "request of gpio %d failed, %d\n", 592bfc29e95SDmitry Torokhov pdata->gpio_int, error); 593bfc29e95SDmitry Torokhov return error; 594bfc29e95SDmitry Torokhov } 595bfc29e95SDmitry Torokhov 596bfc29e95SDmitry Torokhov error = devm_gpio_request_one(&client->dev, pdata->gpio_rst, 597bfc29e95SDmitry Torokhov GPIOF_DIR_OUT | GPIOF_INIT_HIGH, 598bfc29e95SDmitry Torokhov "auo_pixcir_ts_rst"); 599bfc29e95SDmitry Torokhov if (error) { 600bfc29e95SDmitry Torokhov dev_err(&client->dev, "request of gpio %d failed, %d\n", 601bfc29e95SDmitry Torokhov pdata->gpio_rst, error); 602bfc29e95SDmitry Torokhov return error; 603bfc29e95SDmitry Torokhov } 604bfc29e95SDmitry Torokhov 605*e2c063c8SFuqian Huang error = devm_add_action_or_reset(&client->dev, auo_pixcir_reset, ts); 606bfc29e95SDmitry Torokhov if (error) { 607bfc29e95SDmitry Torokhov dev_err(&client->dev, "failed to register reset action, %d\n", 608bfc29e95SDmitry Torokhov error); 609bfc29e95SDmitry Torokhov return error; 610bfc29e95SDmitry Torokhov } 611bfc29e95SDmitry Torokhov 612bfc29e95SDmitry Torokhov msleep(200); 613bfc29e95SDmitry Torokhov 614bfc29e95SDmitry Torokhov version = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION); 615bfc29e95SDmitry Torokhov if (version < 0) { 616bfc29e95SDmitry Torokhov error = version; 617bfc29e95SDmitry Torokhov return error; 618bfc29e95SDmitry Torokhov } 619bfc29e95SDmitry Torokhov 620bfc29e95SDmitry Torokhov dev_info(&client->dev, "firmware version 0x%X\n", version); 621bfc29e95SDmitry Torokhov 622bfc29e95SDmitry Torokhov error = auo_pixcir_int_config(ts, pdata->int_setting); 623bfc29e95SDmitry Torokhov if (error) 624bfc29e95SDmitry Torokhov return error; 625bfc29e95SDmitry Torokhov 626bfc29e95SDmitry Torokhov error = devm_request_threaded_irq(&client->dev, client->irq, 627bfc29e95SDmitry Torokhov NULL, auo_pixcir_interrupt, 6285245db49SHeiko Stübner IRQF_TRIGGER_RISING | IRQF_ONESHOT, 6295245db49SHeiko Stübner input_dev->name, ts); 630bfc29e95SDmitry Torokhov if (error) { 631bfc29e95SDmitry Torokhov dev_err(&client->dev, "irq %d requested failed, %d\n", 632bfc29e95SDmitry Torokhov client->irq, error); 633bfc29e95SDmitry Torokhov return error; 6345245db49SHeiko Stübner } 6355245db49SHeiko Stübner 6365245db49SHeiko Stübner /* stop device and put it into deep sleep until it is opened */ 637bfc29e95SDmitry Torokhov error = auo_pixcir_stop(ts); 638bfc29e95SDmitry Torokhov if (error) 639bfc29e95SDmitry Torokhov return error; 6405245db49SHeiko Stübner 641bfc29e95SDmitry Torokhov error = input_register_device(input_dev); 642bfc29e95SDmitry Torokhov if (error) { 643bfc29e95SDmitry Torokhov dev_err(&client->dev, "could not register input device, %d\n", 644bfc29e95SDmitry Torokhov error); 645bfc29e95SDmitry Torokhov return error; 6465245db49SHeiko Stübner } 6475245db49SHeiko Stübner 6485245db49SHeiko Stübner i2c_set_clientdata(client, ts); 6495245db49SHeiko Stübner 6505245db49SHeiko Stübner return 0; 6515245db49SHeiko Stübner } 6525245db49SHeiko Stübner 6535245db49SHeiko Stübner static const struct i2c_device_id auo_pixcir_idtable[] = { 6545245db49SHeiko Stübner { "auo_pixcir_ts", 0 }, 6555245db49SHeiko Stübner { } 6565245db49SHeiko Stübner }; 6575245db49SHeiko Stübner MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable); 6585245db49SHeiko Stübner 6597241443fSHeiko Stübner #ifdef CONFIG_OF 66069f8cafdSJingoo Han static const struct of_device_id auo_pixcir_ts_dt_idtable[] = { 6617241443fSHeiko Stübner { .compatible = "auo,auo_pixcir_ts" }, 6627241443fSHeiko Stübner {}, 6637241443fSHeiko Stübner }; 6647241443fSHeiko Stübner MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable); 6657241443fSHeiko Stübner #endif 6667241443fSHeiko Stübner 6675245db49SHeiko Stübner static struct i2c_driver auo_pixcir_driver = { 6685245db49SHeiko Stübner .driver = { 6695245db49SHeiko Stübner .name = "auo_pixcir_ts", 6705245db49SHeiko Stübner .pm = &auo_pixcir_pm_ops, 6717241443fSHeiko Stübner .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable), 6725245db49SHeiko Stübner }, 6735245db49SHeiko Stübner .probe = auo_pixcir_probe, 6745245db49SHeiko Stübner .id_table = auo_pixcir_idtable, 6755245db49SHeiko Stübner }; 6765245db49SHeiko Stübner 6774a533835SDmitry Torokhov module_i2c_driver(auo_pixcir_driver); 6785245db49SHeiko Stübner 6795245db49SHeiko Stübner MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver"); 6805245db49SHeiko Stübner MODULE_LICENSE("GPL v2"); 6815245db49SHeiko Stübner MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 682