18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Pixcir I2C touchscreen controllers. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011 Pixcir, Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/input.h> 138c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 148c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * Register map 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci#define PIXCIR_REG_POWER_MODE 51 268c2ecf20Sopenharmony_ci#define PIXCIR_REG_INT_MODE 52 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Power modes: 308c2ecf20Sopenharmony_ci * active: max scan speed 318c2ecf20Sopenharmony_ci * idle: lower scan speed with automatic transition to active on touch 328c2ecf20Sopenharmony_ci * halt: datasheet says sleep but this is more like halt as the chip 338c2ecf20Sopenharmony_ci * clocks are cut and it can only be brought out of this mode 348c2ecf20Sopenharmony_ci * using the RESET pin. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cienum pixcir_power_mode { 378c2ecf20Sopenharmony_ci PIXCIR_POWER_ACTIVE, 388c2ecf20Sopenharmony_ci PIXCIR_POWER_IDLE, 398c2ecf20Sopenharmony_ci PIXCIR_POWER_HALT, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define PIXCIR_POWER_MODE_MASK 0x03 438c2ecf20Sopenharmony_ci#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Interrupt modes: 478c2ecf20Sopenharmony_ci * periodical: interrupt is asserted periodicaly 488c2ecf20Sopenharmony_ci * diff coordinates: interrupt is asserted when coordinates change 498c2ecf20Sopenharmony_ci * level on touch: interrupt level asserted during touch 508c2ecf20Sopenharmony_ci * pulse on touch: interrupt pulse asserted during touch 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cienum pixcir_int_mode { 548c2ecf20Sopenharmony_ci PIXCIR_INT_PERIODICAL, 558c2ecf20Sopenharmony_ci PIXCIR_INT_DIFF_COORD, 568c2ecf20Sopenharmony_ci PIXCIR_INT_LEVEL_TOUCH, 578c2ecf20Sopenharmony_ci PIXCIR_INT_PULSE_TOUCH, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define PIXCIR_INT_MODE_MASK 0x03 618c2ecf20Sopenharmony_ci#define PIXCIR_INT_ENABLE (1UL << 3) 628c2ecf20Sopenharmony_ci#define PIXCIR_INT_POL_HIGH (1UL << 2) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * struct pixcir_i2c_chip_data - chip related data 668c2ecf20Sopenharmony_ci * @max_fingers: Max number of fingers reported simultaneously by h/w 678c2ecf20Sopenharmony_ci * @has_hw_ids: Hardware supports finger tracking IDs 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistruct pixcir_i2c_chip_data { 718c2ecf20Sopenharmony_ci u8 max_fingers; 728c2ecf20Sopenharmony_ci bool has_hw_ids; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct pixcir_i2c_ts_data { 768c2ecf20Sopenharmony_ci struct i2c_client *client; 778c2ecf20Sopenharmony_ci struct input_dev *input; 788c2ecf20Sopenharmony_ci struct gpio_desc *gpio_attb; 798c2ecf20Sopenharmony_ci struct gpio_desc *gpio_reset; 808c2ecf20Sopenharmony_ci struct gpio_desc *gpio_enable; 818c2ecf20Sopenharmony_ci struct gpio_desc *gpio_wake; 828c2ecf20Sopenharmony_ci const struct pixcir_i2c_chip_data *chip; 838c2ecf20Sopenharmony_ci struct touchscreen_properties prop; 848c2ecf20Sopenharmony_ci bool running; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct pixcir_report_data { 888c2ecf20Sopenharmony_ci int num_touches; 898c2ecf20Sopenharmony_ci struct input_mt_pos pos[PIXCIR_MAX_SLOTS]; 908c2ecf20Sopenharmony_ci int ids[PIXCIR_MAX_SLOTS]; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, 948c2ecf20Sopenharmony_ci struct pixcir_report_data *report) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5]; 978c2ecf20Sopenharmony_ci u8 wrbuf[1] = { 0 }; 988c2ecf20Sopenharmony_ci u8 *bufptr; 998c2ecf20Sopenharmony_ci u8 touch; 1008c2ecf20Sopenharmony_ci int ret, i; 1018c2ecf20Sopenharmony_ci int readsize; 1028c2ecf20Sopenharmony_ci const struct pixcir_i2c_chip_data *chip = tsdata->chip; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci memset(report, 0, sizeof(struct pixcir_report_data)); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci i = chip->has_hw_ids ? 1 : 0; 1078c2ecf20Sopenharmony_ci readsize = 2 + tsdata->chip->max_fingers * (4 + i); 1088c2ecf20Sopenharmony_ci if (readsize > sizeof(rdbuf)) 1098c2ecf20Sopenharmony_ci readsize = sizeof(rdbuf); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf)); 1128c2ecf20Sopenharmony_ci if (ret != sizeof(wrbuf)) { 1138c2ecf20Sopenharmony_ci dev_err(&tsdata->client->dev, 1148c2ecf20Sopenharmony_ci "%s: i2c_master_send failed(), ret=%d\n", 1158c2ecf20Sopenharmony_ci __func__, ret); 1168c2ecf20Sopenharmony_ci return; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci ret = i2c_master_recv(tsdata->client, rdbuf, readsize); 1208c2ecf20Sopenharmony_ci if (ret != readsize) { 1218c2ecf20Sopenharmony_ci dev_err(&tsdata->client->dev, 1228c2ecf20Sopenharmony_ci "%s: i2c_master_recv failed(), ret=%d\n", 1238c2ecf20Sopenharmony_ci __func__, ret); 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci touch = rdbuf[0] & 0x7; 1288c2ecf20Sopenharmony_ci if (touch > tsdata->chip->max_fingers) 1298c2ecf20Sopenharmony_ci touch = tsdata->chip->max_fingers; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci report->num_touches = touch; 1328c2ecf20Sopenharmony_ci bufptr = &rdbuf[2]; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci for (i = 0; i < touch; i++) { 1358c2ecf20Sopenharmony_ci touchscreen_set_mt_pos(&report->pos[i], &tsdata->prop, 1368c2ecf20Sopenharmony_ci get_unaligned_le16(bufptr), 1378c2ecf20Sopenharmony_ci get_unaligned_le16(bufptr + 2)); 1388c2ecf20Sopenharmony_ci if (chip->has_hw_ids) { 1398c2ecf20Sopenharmony_ci report->ids[i] = bufptr[4]; 1408c2ecf20Sopenharmony_ci bufptr = bufptr + 5; 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci bufptr = bufptr + 4; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, 1488c2ecf20Sopenharmony_ci struct pixcir_report_data *report) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int slots[PIXCIR_MAX_SLOTS]; 1518c2ecf20Sopenharmony_ci int n, i, slot; 1528c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 1538c2ecf20Sopenharmony_ci const struct pixcir_i2c_chip_data *chip = ts->chip; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci n = report->num_touches; 1568c2ecf20Sopenharmony_ci if (n > PIXCIR_MAX_SLOTS) 1578c2ecf20Sopenharmony_ci n = PIXCIR_MAX_SLOTS; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!ts->chip->has_hw_ids) 1608c2ecf20Sopenharmony_ci input_mt_assign_slots(ts->input, slots, report->pos, n, 0); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 1638c2ecf20Sopenharmony_ci if (chip->has_hw_ids) { 1648c2ecf20Sopenharmony_ci slot = input_mt_get_slot_by_key(ts->input, 1658c2ecf20Sopenharmony_ci report->ids[i]); 1668c2ecf20Sopenharmony_ci if (slot < 0) { 1678c2ecf20Sopenharmony_ci dev_dbg(dev, "no free slot for id 0x%x\n", 1688c2ecf20Sopenharmony_ci report->ids[i]); 1698c2ecf20Sopenharmony_ci continue; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } else { 1728c2ecf20Sopenharmony_ci slot = slots[i]; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci input_mt_slot(ts->input, slot); 1768c2ecf20Sopenharmony_ci input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_X, 1798c2ecf20Sopenharmony_ci report->pos[i].x); 1808c2ecf20Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_Y, 1818c2ecf20Sopenharmony_ci report->pos[i].y); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci dev_dbg(dev, "%d: slot %d, x %d, y %d\n", 1848c2ecf20Sopenharmony_ci i, slot, report->pos[i].x, report->pos[i].y); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci input_mt_sync_frame(ts->input); 1888c2ecf20Sopenharmony_ci input_sync(ts->input); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic irqreturn_t pixcir_ts_isr(int irq, void *dev_id) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct pixcir_i2c_ts_data *tsdata = dev_id; 1948c2ecf20Sopenharmony_ci struct pixcir_report_data report; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci while (tsdata->running) { 1978c2ecf20Sopenharmony_ci /* parse packet */ 1988c2ecf20Sopenharmony_ci pixcir_ts_parse(tsdata, &report); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* report it */ 2018c2ecf20Sopenharmony_ci pixcir_ts_report(tsdata, &report); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (gpiod_get_value_cansleep(tsdata->gpio_attb)) { 2048c2ecf20Sopenharmony_ci if (report.num_touches) { 2058c2ecf20Sopenharmony_ci /* 2068c2ecf20Sopenharmony_ci * Last report with no finger up? 2078c2ecf20Sopenharmony_ci * Do it now then. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci input_mt_sync_frame(tsdata->input); 2108c2ecf20Sopenharmony_ci input_sync(tsdata->input); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci msleep(20); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void pixcir_reset(struct pixcir_i2c_ts_data *tsdata) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(tsdata->gpio_reset)) { 2248c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tsdata->gpio_reset, 1); 2258c2ecf20Sopenharmony_ci ndelay(100); /* datasheet section 1.2.3 says 80ns min. */ 2268c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tsdata->gpio_reset, 0); 2278c2ecf20Sopenharmony_ci /* wait for controller ready. 100ms guess. */ 2288c2ecf20Sopenharmony_ci msleep(100); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, 2338c2ecf20Sopenharmony_ci enum pixcir_power_mode mode) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 2368c2ecf20Sopenharmony_ci int ret; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (mode == PIXCIR_POWER_ACTIVE || mode == PIXCIR_POWER_IDLE) { 2398c2ecf20Sopenharmony_ci if (ts->gpio_wake) 2408c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_wake, 1); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); 2448c2ecf20Sopenharmony_ci if (ret < 0) { 2458c2ecf20Sopenharmony_ci dev_err(dev, "%s: can't read reg %d : %d\n", 2468c2ecf20Sopenharmony_ci __func__, PIXCIR_REG_POWER_MODE, ret); 2478c2ecf20Sopenharmony_ci return ret; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ret &= ~PIXCIR_POWER_MODE_MASK; 2518c2ecf20Sopenharmony_ci ret |= mode; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Always AUTO_IDLE */ 2548c2ecf20Sopenharmony_ci ret |= PIXCIR_POWER_ALLOW_IDLE; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret); 2578c2ecf20Sopenharmony_ci if (ret < 0) { 2588c2ecf20Sopenharmony_ci dev_err(dev, "%s: can't write reg %d : %d\n", 2598c2ecf20Sopenharmony_ci __func__, PIXCIR_REG_POWER_MODE, ret); 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (mode == PIXCIR_POWER_HALT) { 2648c2ecf20Sopenharmony_ci if (ts->gpio_wake) 2658c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_wake, 0); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* 2728c2ecf20Sopenharmony_ci * Set the interrupt mode for the device i.e. ATTB line behaviour 2738c2ecf20Sopenharmony_ci * 2748c2ecf20Sopenharmony_ci * @polarity : 1 for active high, 0 for active low. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cistatic int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, 2778c2ecf20Sopenharmony_ci enum pixcir_int_mode mode, bool polarity) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 2808c2ecf20Sopenharmony_ci int ret; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); 2838c2ecf20Sopenharmony_ci if (ret < 0) { 2848c2ecf20Sopenharmony_ci dev_err(dev, "%s: can't read reg %d : %d\n", 2858c2ecf20Sopenharmony_ci __func__, PIXCIR_REG_INT_MODE, ret); 2868c2ecf20Sopenharmony_ci return ret; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ret &= ~PIXCIR_INT_MODE_MASK; 2908c2ecf20Sopenharmony_ci ret |= mode; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (polarity) 2938c2ecf20Sopenharmony_ci ret |= PIXCIR_INT_POL_HIGH; 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci ret &= ~PIXCIR_INT_POL_HIGH; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); 2988c2ecf20Sopenharmony_ci if (ret < 0) { 2998c2ecf20Sopenharmony_ci dev_err(dev, "%s: can't write reg %d : %d\n", 3008c2ecf20Sopenharmony_ci __func__, PIXCIR_REG_INT_MODE, ret); 3018c2ecf20Sopenharmony_ci return ret; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* 3088c2ecf20Sopenharmony_ci * Enable/disable interrupt generation 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_cistatic int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 3138c2ecf20Sopenharmony_ci int ret; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); 3168c2ecf20Sopenharmony_ci if (ret < 0) { 3178c2ecf20Sopenharmony_ci dev_err(dev, "%s: can't read reg %d : %d\n", 3188c2ecf20Sopenharmony_ci __func__, PIXCIR_REG_INT_MODE, ret); 3198c2ecf20Sopenharmony_ci return ret; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (enable) 3238c2ecf20Sopenharmony_ci ret |= PIXCIR_INT_ENABLE; 3248c2ecf20Sopenharmony_ci else 3258c2ecf20Sopenharmony_ci ret &= ~PIXCIR_INT_ENABLE; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); 3288c2ecf20Sopenharmony_ci if (ret < 0) { 3298c2ecf20Sopenharmony_ci dev_err(dev, "%s: can't write reg %d : %d\n", 3308c2ecf20Sopenharmony_ci __func__, PIXCIR_REG_INT_MODE, ret); 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int pixcir_start(struct pixcir_i2c_ts_data *ts) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 3408c2ecf20Sopenharmony_ci int error; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (ts->gpio_enable) { 3438c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_enable, 1); 3448c2ecf20Sopenharmony_ci msleep(100); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* LEVEL_TOUCH interrupt with active low polarity */ 3488c2ecf20Sopenharmony_ci error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); 3498c2ecf20Sopenharmony_ci if (error) { 3508c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set interrupt mode: %d\n", error); 3518c2ecf20Sopenharmony_ci return error; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ts->running = true; 3558c2ecf20Sopenharmony_ci mb(); /* Update status before IRQ can fire */ 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* enable interrupt generation */ 3588c2ecf20Sopenharmony_ci error = pixcir_int_enable(ts, true); 3598c2ecf20Sopenharmony_ci if (error) { 3608c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable interrupt generation: %d\n", 3618c2ecf20Sopenharmony_ci error); 3628c2ecf20Sopenharmony_ci return error; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int pixcir_stop(struct pixcir_i2c_ts_data *ts) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci int error; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* Disable interrupt generation */ 3738c2ecf20Sopenharmony_ci error = pixcir_int_enable(ts, false); 3748c2ecf20Sopenharmony_ci if (error) { 3758c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 3768c2ecf20Sopenharmony_ci "Failed to disable interrupt generation: %d\n", 3778c2ecf20Sopenharmony_ci error); 3788c2ecf20Sopenharmony_ci return error; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Exit ISR if running, no more report parsing */ 3828c2ecf20Sopenharmony_ci ts->running = false; 3838c2ecf20Sopenharmony_ci mb(); /* update status before we synchronize irq */ 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Wait till running ISR is complete */ 3868c2ecf20Sopenharmony_ci synchronize_irq(ts->client->irq); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (ts->gpio_enable) 3898c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_enable, 0); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int pixcir_input_open(struct input_dev *dev) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return pixcir_start(ts); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void pixcir_input_close(struct input_dev *dev) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci pixcir_stop(ts); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 4118c2ecf20Sopenharmony_ci struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); 4128c2ecf20Sopenharmony_ci struct input_dev *input = ts->input; 4138c2ecf20Sopenharmony_ci int ret = 0; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci mutex_lock(&input->mutex); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (device_may_wakeup(&client->dev)) { 4188c2ecf20Sopenharmony_ci if (!input->users) { 4198c2ecf20Sopenharmony_ci ret = pixcir_start(ts); 4208c2ecf20Sopenharmony_ci if (ret) { 4218c2ecf20Sopenharmony_ci dev_err(dev, "Failed to start\n"); 4228c2ecf20Sopenharmony_ci goto unlock; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } else if (input->users) { 4268c2ecf20Sopenharmony_ci ret = pixcir_stop(ts); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ciunlock: 4308c2ecf20Sopenharmony_ci mutex_unlock(&input->mutex); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 4388c2ecf20Sopenharmony_ci struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); 4398c2ecf20Sopenharmony_ci struct input_dev *input = ts->input; 4408c2ecf20Sopenharmony_ci int ret = 0; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci mutex_lock(&input->mutex); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (device_may_wakeup(&client->dev)) { 4458c2ecf20Sopenharmony_ci if (!input->users) { 4468c2ecf20Sopenharmony_ci ret = pixcir_stop(ts); 4478c2ecf20Sopenharmony_ci if (ret) { 4488c2ecf20Sopenharmony_ci dev_err(dev, "Failed to stop\n"); 4498c2ecf20Sopenharmony_ci goto unlock; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } else if (input->users) { 4538c2ecf20Sopenharmony_ci ret = pixcir_start(ts); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciunlock: 4578c2ecf20Sopenharmony_ci mutex_unlock(&input->mutex); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return ret; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, 4638c2ecf20Sopenharmony_ci pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int pixcir_i2c_ts_probe(struct i2c_client *client, 4668c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 4698c2ecf20Sopenharmony_ci struct pixcir_i2c_ts_data *tsdata; 4708c2ecf20Sopenharmony_ci struct input_dev *input; 4718c2ecf20Sopenharmony_ci int error; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); 4748c2ecf20Sopenharmony_ci if (!tsdata) 4758c2ecf20Sopenharmony_ci return -ENOMEM; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci tsdata->chip = device_get_match_data(dev); 4788c2ecf20Sopenharmony_ci if (!tsdata->chip && id) 4798c2ecf20Sopenharmony_ci tsdata->chip = (const void *)id->driver_data; 4808c2ecf20Sopenharmony_ci if (!tsdata->chip) { 4818c2ecf20Sopenharmony_ci dev_err(dev, "can't locate chip data\n"); 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci input = devm_input_allocate_device(dev); 4868c2ecf20Sopenharmony_ci if (!input) { 4878c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate input device\n"); 4888c2ecf20Sopenharmony_ci return -ENOMEM; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci tsdata->client = client; 4928c2ecf20Sopenharmony_ci tsdata->input = input; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci input->name = client->name; 4958c2ecf20Sopenharmony_ci input->id.bustype = BUS_I2C; 4968c2ecf20Sopenharmony_ci input->open = pixcir_input_open; 4978c2ecf20Sopenharmony_ci input->close = pixcir_input_close; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); 5008c2ecf20Sopenharmony_ci input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); 5018c2ecf20Sopenharmony_ci touchscreen_parse_properties(input, true, &tsdata->prop); 5028c2ecf20Sopenharmony_ci if (!input_abs_get_max(input, ABS_MT_POSITION_X) || 5038c2ecf20Sopenharmony_ci !input_abs_get_max(input, ABS_MT_POSITION_Y)) { 5048c2ecf20Sopenharmony_ci dev_err(dev, "Touchscreen size is not specified\n"); 5058c2ecf20Sopenharmony_ci return -EINVAL; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci error = input_mt_init_slots(input, tsdata->chip->max_fingers, 5098c2ecf20Sopenharmony_ci INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 5108c2ecf20Sopenharmony_ci if (error) { 5118c2ecf20Sopenharmony_ci dev_err(dev, "Error initializing Multi-Touch slots\n"); 5128c2ecf20Sopenharmony_ci return error; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci input_set_drvdata(input, tsdata); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN); 5188c2ecf20Sopenharmony_ci if (IS_ERR(tsdata->gpio_attb)) { 5198c2ecf20Sopenharmony_ci error = PTR_ERR(tsdata->gpio_attb); 5208c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 5218c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request ATTB gpio: %d\n", 5228c2ecf20Sopenharmony_ci error); 5238c2ecf20Sopenharmony_ci return error; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset", 5278c2ecf20Sopenharmony_ci GPIOD_OUT_LOW); 5288c2ecf20Sopenharmony_ci if (IS_ERR(tsdata->gpio_reset)) { 5298c2ecf20Sopenharmony_ci error = PTR_ERR(tsdata->gpio_reset); 5308c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 5318c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request RESET gpio: %d\n", 5328c2ecf20Sopenharmony_ci error); 5338c2ecf20Sopenharmony_ci return error; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake", 5378c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 5388c2ecf20Sopenharmony_ci if (IS_ERR(tsdata->gpio_wake)) { 5398c2ecf20Sopenharmony_ci error = PTR_ERR(tsdata->gpio_wake); 5408c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 5418c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get wake gpio: %d\n", error); 5428c2ecf20Sopenharmony_ci return error; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable", 5468c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 5478c2ecf20Sopenharmony_ci if (IS_ERR(tsdata->gpio_enable)) { 5488c2ecf20Sopenharmony_ci error = PTR_ERR(tsdata->gpio_enable); 5498c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 5508c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get enable gpio: %d\n", error); 5518c2ecf20Sopenharmony_ci return error; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (tsdata->gpio_enable) 5558c2ecf20Sopenharmony_ci msleep(100); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, 5588c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 5598c2ecf20Sopenharmony_ci client->name, tsdata); 5608c2ecf20Sopenharmony_ci if (error) { 5618c2ecf20Sopenharmony_ci dev_err(dev, "failed to request irq %d\n", client->irq); 5628c2ecf20Sopenharmony_ci return error; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci pixcir_reset(tsdata); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* Always be in IDLE mode to save power, device supports auto wake */ 5688c2ecf20Sopenharmony_ci error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); 5698c2ecf20Sopenharmony_ci if (error) { 5708c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set IDLE mode\n"); 5718c2ecf20Sopenharmony_ci return error; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* Stop device till opened */ 5758c2ecf20Sopenharmony_ci error = pixcir_stop(tsdata); 5768c2ecf20Sopenharmony_ci if (error) 5778c2ecf20Sopenharmony_ci return error; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci error = input_register_device(input); 5808c2ecf20Sopenharmony_ci if (error) 5818c2ecf20Sopenharmony_ci return error; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci i2c_set_clientdata(client, tsdata); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return 0; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic const struct pixcir_i2c_chip_data pixcir_ts_data = { 5898c2ecf20Sopenharmony_ci .max_fingers = 2, 5908c2ecf20Sopenharmony_ci /* no hw id support */ 5918c2ecf20Sopenharmony_ci}; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic const struct pixcir_i2c_chip_data pixcir_tangoc_data = { 5948c2ecf20Sopenharmony_ci .max_fingers = 5, 5958c2ecf20Sopenharmony_ci .has_hw_ids = true, 5968c2ecf20Sopenharmony_ci}; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic const struct i2c_device_id pixcir_i2c_ts_id[] = { 5998c2ecf20Sopenharmony_ci { "pixcir_ts", (unsigned long) &pixcir_ts_data }, 6008c2ecf20Sopenharmony_ci { "pixcir_tangoc", (unsigned long) &pixcir_tangoc_data }, 6018c2ecf20Sopenharmony_ci { } 6028c2ecf20Sopenharmony_ci}; 6038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 6068c2ecf20Sopenharmony_cistatic const struct of_device_id pixcir_of_match[] = { 6078c2ecf20Sopenharmony_ci { .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data }, 6088c2ecf20Sopenharmony_ci { .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data }, 6098c2ecf20Sopenharmony_ci { } 6108c2ecf20Sopenharmony_ci}; 6118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pixcir_of_match); 6128c2ecf20Sopenharmony_ci#endif 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic struct i2c_driver pixcir_i2c_ts_driver = { 6158c2ecf20Sopenharmony_ci .driver = { 6168c2ecf20Sopenharmony_ci .name = "pixcir_ts", 6178c2ecf20Sopenharmony_ci .pm = &pixcir_dev_pm_ops, 6188c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(pixcir_of_match), 6198c2ecf20Sopenharmony_ci }, 6208c2ecf20Sopenharmony_ci .probe = pixcir_i2c_ts_probe, 6218c2ecf20Sopenharmony_ci .id_table = pixcir_i2c_ts_id, 6228c2ecf20Sopenharmony_ci}; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cimodule_i2c_driver(pixcir_i2c_ts_driver); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>"); 6278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver"); 6288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 629