18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010 48c2ecf20Sopenharmony_ci * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/bitops.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/input.h> 128c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 138c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/property.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define MAX_FINGERS 2 238c2ecf20Sopenharmony_ci#define RESET_DELAY 30 248c2ecf20Sopenharmony_ci#define PENUP_TIMEOUT (10) 258c2ecf20Sopenharmony_ci#define DELTA_MIN 16 268c2ecf20Sopenharmony_ci#define MASK_BITS 0x03 278c2ecf20Sopenharmony_ci#define SHIFT_8 8 288c2ecf20Sopenharmony_ci#define SHIFT_2 2 298c2ecf20Sopenharmony_ci#define LENGTH_OF_BUFFER 11 308c2ecf20Sopenharmony_ci#define I2C_RETRY_COUNT 5 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define BU21013_SENSORS_BTN_0_7_REG 0x70 338c2ecf20Sopenharmony_ci#define BU21013_SENSORS_BTN_8_15_REG 0x71 348c2ecf20Sopenharmony_ci#define BU21013_SENSORS_BTN_16_23_REG 0x72 358c2ecf20Sopenharmony_ci#define BU21013_X1_POS_MSB_REG 0x73 368c2ecf20Sopenharmony_ci#define BU21013_X1_POS_LSB_REG 0x74 378c2ecf20Sopenharmony_ci#define BU21013_Y1_POS_MSB_REG 0x75 388c2ecf20Sopenharmony_ci#define BU21013_Y1_POS_LSB_REG 0x76 398c2ecf20Sopenharmony_ci#define BU21013_X2_POS_MSB_REG 0x77 408c2ecf20Sopenharmony_ci#define BU21013_X2_POS_LSB_REG 0x78 418c2ecf20Sopenharmony_ci#define BU21013_Y2_POS_MSB_REG 0x79 428c2ecf20Sopenharmony_ci#define BU21013_Y2_POS_LSB_REG 0x7A 438c2ecf20Sopenharmony_ci#define BU21013_INT_CLR_REG 0xE8 448c2ecf20Sopenharmony_ci#define BU21013_INT_MODE_REG 0xE9 458c2ecf20Sopenharmony_ci#define BU21013_GAIN_REG 0xEA 468c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_REG 0xEB 478c2ecf20Sopenharmony_ci#define BU21013_XY_EDGE_REG 0xEC 488c2ecf20Sopenharmony_ci#define BU21013_RESET_REG 0xED 498c2ecf20Sopenharmony_ci#define BU21013_CALIB_REG 0xEE 508c2ecf20Sopenharmony_ci#define BU21013_DONE_REG 0xEF 518c2ecf20Sopenharmony_ci#define BU21013_SENSOR_0_7_REG 0xF0 528c2ecf20Sopenharmony_ci#define BU21013_SENSOR_8_15_REG 0xF1 538c2ecf20Sopenharmony_ci#define BU21013_SENSOR_16_23_REG 0xF2 548c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_REG 0xF3 558c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_REG 0xF4 568c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_REG 0xF5 578c2ecf20Sopenharmony_ci#define BU21013_IDLE_REG 0xFA 588c2ecf20Sopenharmony_ci#define BU21013_FILTER_REG 0xFB 598c2ecf20Sopenharmony_ci#define BU21013_TH_ON_REG 0xFC 608c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_REG 0xFD 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define BU21013_RESET_ENABLE 0x01 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define BU21013_SENSORS_EN_0_7 0x3F 668c2ecf20Sopenharmony_ci#define BU21013_SENSORS_EN_8_15 0xFC 678c2ecf20Sopenharmony_ci#define BU21013_SENSORS_EN_16_23 0x1F 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_0 0x02 708c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_1 0x04 718c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_2 0x08 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_ZERO 0x01 748c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_AVG1 0x02 758c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_AVG2 0x04 768c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_EN_XY 0x08 778c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_EN_RAW 0x10 788c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_MULTI 0x80 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_DIV 0x01 818c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_EXT 0x02 828c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_CALIB 0x80 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define BU21013_IDLET_0 0x01 858c2ecf20Sopenharmony_ci#define BU21013_IDLET_1 0x02 868c2ecf20Sopenharmony_ci#define BU21013_IDLET_2 0x04 878c2ecf20Sopenharmony_ci#define BU21013_IDLET_3 0x08 888c2ecf20Sopenharmony_ci#define BU21013_IDLE_INTERMIT_EN 0x10 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define BU21013_DELTA_0_6 0x7F 918c2ecf20Sopenharmony_ci#define BU21013_FILTER_EN 0x80 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define BU21013_INT_MODE_LEVEL 0x00 948c2ecf20Sopenharmony_ci#define BU21013_INT_MODE_EDGE 0x01 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define BU21013_GAIN_0 0x01 978c2ecf20Sopenharmony_ci#define BU21013_GAIN_1 0x02 988c2ecf20Sopenharmony_ci#define BU21013_GAIN_2 0x04 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_DEFAULT 0x00 1018c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_MOVE 0x01 1028c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_DISABLE 0x02 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define BU21013_TH_ON_0 0x01 1058c2ecf20Sopenharmony_ci#define BU21013_TH_ON_1 0x02 1068c2ecf20Sopenharmony_ci#define BU21013_TH_ON_2 0x04 1078c2ecf20Sopenharmony_ci#define BU21013_TH_ON_3 0x08 1088c2ecf20Sopenharmony_ci#define BU21013_TH_ON_4 0x10 1098c2ecf20Sopenharmony_ci#define BU21013_TH_ON_5 0x20 1108c2ecf20Sopenharmony_ci#define BU21013_TH_ON_6 0x40 1118c2ecf20Sopenharmony_ci#define BU21013_TH_ON_7 0x80 1128c2ecf20Sopenharmony_ci#define BU21013_TH_ON_MAX 0xFF 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_0 0x01 1158c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_1 0x02 1168c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_2 0x04 1178c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_3 0x08 1188c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_4 0x10 1198c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_5 0x20 1208c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_6 0x40 1218c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_7 0x80 1228c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_MAX 0xFF 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_0 0x01 1258c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_1 0x02 1268c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_2 0x04 1278c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_3 0x08 1288c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_0 0x10 1298c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_1 0x20 1308c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_2 0x40 1318c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_3 0x80 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define BU21013_DONE 0x01 1348c2ecf20Sopenharmony_ci#define BU21013_NUMBER_OF_X_SENSORS (6) 1358c2ecf20Sopenharmony_ci#define BU21013_NUMBER_OF_Y_SENSORS (11) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define DRIVER_TP "bu21013_tp" 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/** 1408c2ecf20Sopenharmony_ci * struct bu21013_ts - touch panel data structure 1418c2ecf20Sopenharmony_ci * @client: pointer to the i2c client 1428c2ecf20Sopenharmony_ci * @in_dev: pointer to the input device structure 1438c2ecf20Sopenharmony_ci * @props: the device coordinate transformation properties 1448c2ecf20Sopenharmony_ci * @regulator: pointer to the Regulator used for touch screen 1458c2ecf20Sopenharmony_ci * @cs_gpiod: chip select GPIO line 1468c2ecf20Sopenharmony_ci * @int_gpiod: touch interrupt GPIO line 1478c2ecf20Sopenharmony_ci * @touch_x_max: maximum X coordinate reported by the device 1488c2ecf20Sopenharmony_ci * @touch_y_max: maximum Y coordinate reported by the device 1498c2ecf20Sopenharmony_ci * @x_flip: indicates that the driver should invert X coordinate before 1508c2ecf20Sopenharmony_ci * reporting 1518c2ecf20Sopenharmony_ci * @y_flip: indicates that the driver should invert Y coordinate before 1528c2ecf20Sopenharmony_ci * reporting 1538c2ecf20Sopenharmony_ci * @touch_stopped: touch stop flag 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * Touch panel device data structure 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistruct bu21013_ts { 1588c2ecf20Sopenharmony_ci struct i2c_client *client; 1598c2ecf20Sopenharmony_ci struct input_dev *in_dev; 1608c2ecf20Sopenharmony_ci struct touchscreen_properties props; 1618c2ecf20Sopenharmony_ci struct regulator *regulator; 1628c2ecf20Sopenharmony_ci struct gpio_desc *cs_gpiod; 1638c2ecf20Sopenharmony_ci struct gpio_desc *int_gpiod; 1648c2ecf20Sopenharmony_ci u32 touch_x_max; 1658c2ecf20Sopenharmony_ci u32 touch_y_max; 1668c2ecf20Sopenharmony_ci bool x_flip; 1678c2ecf20Sopenharmony_ci bool y_flip; 1688c2ecf20Sopenharmony_ci bool touch_stopped; 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int bu21013_read_block_data(struct bu21013_ts *ts, u8 *buf) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci int ret, i; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci for (i = 0; i < I2C_RETRY_COUNT; i++) { 1768c2ecf20Sopenharmony_ci ret = i2c_smbus_read_i2c_block_data(ts->client, 1778c2ecf20Sopenharmony_ci BU21013_SENSORS_BTN_0_7_REG, 1788c2ecf20Sopenharmony_ci LENGTH_OF_BUFFER, buf); 1798c2ecf20Sopenharmony_ci if (ret == LENGTH_OF_BUFFER) 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return -EINVAL; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int bu21013_do_touch_report(struct bu21013_ts *ts) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct input_dev *input = ts->in_dev; 1898c2ecf20Sopenharmony_ci struct input_mt_pos pos[MAX_FINGERS]; 1908c2ecf20Sopenharmony_ci int slots[MAX_FINGERS]; 1918c2ecf20Sopenharmony_ci u8 buf[LENGTH_OF_BUFFER]; 1928c2ecf20Sopenharmony_ci bool has_x_sensors, has_y_sensors; 1938c2ecf20Sopenharmony_ci int finger_down_count = 0; 1948c2ecf20Sopenharmony_ci int i; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (bu21013_read_block_data(ts, buf) < 0) 1978c2ecf20Sopenharmony_ci return -EINVAL; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7); 2008c2ecf20Sopenharmony_ci has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) | 2018c2ecf20Sopenharmony_ci ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2); 2028c2ecf20Sopenharmony_ci if (!has_x_sensors || !has_y_sensors) 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (i = 0; i < MAX_FINGERS; i++) { 2068c2ecf20Sopenharmony_ci const u8 *data = &buf[4 * i + 3]; 2078c2ecf20Sopenharmony_ci unsigned int x, y; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci x = data[0] << SHIFT_2 | (data[1] & MASK_BITS); 2108c2ecf20Sopenharmony_ci y = data[2] << SHIFT_2 | (data[3] & MASK_BITS); 2118c2ecf20Sopenharmony_ci if (x != 0 && y != 0) 2128c2ecf20Sopenharmony_ci touchscreen_set_mt_pos(&pos[finger_down_count++], 2138c2ecf20Sopenharmony_ci &ts->props, x, y); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (finger_down_count == 2 && 2178c2ecf20Sopenharmony_ci (abs(pos[0].x - pos[1].x) < DELTA_MIN || 2188c2ecf20Sopenharmony_ci abs(pos[0].y - pos[1].y) < DELTA_MIN)) { 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci input_mt_assign_slots(input, slots, pos, finger_down_count, DELTA_MIN); 2238c2ecf20Sopenharmony_ci for (i = 0; i < finger_down_count; i++) { 2248c2ecf20Sopenharmony_ci input_mt_slot(input, slots[i]); 2258c2ecf20Sopenharmony_ci input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 2268c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_X, pos[i].x); 2278c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_Y, pos[i].y); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci input_mt_sync_frame(input); 2318c2ecf20Sopenharmony_ci input_sync(input); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic irqreturn_t bu21013_gpio_irq(int irq, void *device_data) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct bu21013_ts *ts = device_data; 2398c2ecf20Sopenharmony_ci int keep_polling; 2408c2ecf20Sopenharmony_ci int error; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci do { 2438c2ecf20Sopenharmony_ci error = bu21013_do_touch_report(ts); 2448c2ecf20Sopenharmony_ci if (error) { 2458c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "%s failed\n", __func__); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (unlikely(ts->touch_stopped)) 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci keep_polling = ts->int_gpiod ? 2538c2ecf20Sopenharmony_ci gpiod_get_value(ts->int_gpiod) : false; 2548c2ecf20Sopenharmony_ci if (keep_polling) 2558c2ecf20Sopenharmony_ci usleep_range(2000, 2500); 2568c2ecf20Sopenharmony_ci } while (keep_polling); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int bu21013_init_chip(struct bu21013_ts *ts) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 2648c2ecf20Sopenharmony_ci int error; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_RESET_REG, 2678c2ecf20Sopenharmony_ci BU21013_RESET_ENABLE); 2688c2ecf20Sopenharmony_ci if (error) { 2698c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_RESET reg write failed\n"); 2708c2ecf20Sopenharmony_ci return error; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci msleep(RESET_DELAY); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_0_7_REG, 2758c2ecf20Sopenharmony_ci BU21013_SENSORS_EN_0_7); 2768c2ecf20Sopenharmony_ci if (error) { 2778c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_SENSOR_0_7 reg write failed\n"); 2788c2ecf20Sopenharmony_ci return error; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_8_15_REG, 2828c2ecf20Sopenharmony_ci BU21013_SENSORS_EN_8_15); 2838c2ecf20Sopenharmony_ci if (error) { 2848c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_SENSOR_8_15 reg write failed\n"); 2858c2ecf20Sopenharmony_ci return error; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_16_23_REG, 2898c2ecf20Sopenharmony_ci BU21013_SENSORS_EN_16_23); 2908c2ecf20Sopenharmony_ci if (error) { 2918c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_SENSOR_16_23 reg write failed\n"); 2928c2ecf20Sopenharmony_ci return error; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE1_REG, 2968c2ecf20Sopenharmony_ci BU21013_POS_MODE1_0 | 2978c2ecf20Sopenharmony_ci BU21013_POS_MODE1_1); 2988c2ecf20Sopenharmony_ci if (error) { 2998c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_POS_MODE1 reg write failed\n"); 3008c2ecf20Sopenharmony_ci return error; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE2_REG, 3048c2ecf20Sopenharmony_ci BU21013_POS_MODE2_ZERO | 3058c2ecf20Sopenharmony_ci BU21013_POS_MODE2_AVG1 | 3068c2ecf20Sopenharmony_ci BU21013_POS_MODE2_AVG2 | 3078c2ecf20Sopenharmony_ci BU21013_POS_MODE2_EN_RAW | 3088c2ecf20Sopenharmony_ci BU21013_POS_MODE2_MULTI); 3098c2ecf20Sopenharmony_ci if (error) { 3108c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_POS_MODE2 reg write failed\n"); 3118c2ecf20Sopenharmony_ci return error; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_CLK_MODE_REG, 3158c2ecf20Sopenharmony_ci BU21013_CLK_MODE_DIV | 3168c2ecf20Sopenharmony_ci BU21013_CLK_MODE_CALIB); 3178c2ecf20Sopenharmony_ci if (error) { 3188c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_CLK_MODE reg write failed\n"); 3198c2ecf20Sopenharmony_ci return error; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_IDLE_REG, 3238c2ecf20Sopenharmony_ci BU21013_IDLET_0 | 3248c2ecf20Sopenharmony_ci BU21013_IDLE_INTERMIT_EN); 3258c2ecf20Sopenharmony_ci if (error) { 3268c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_IDLE reg write failed\n"); 3278c2ecf20Sopenharmony_ci return error; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_INT_MODE_REG, 3318c2ecf20Sopenharmony_ci BU21013_INT_MODE_LEVEL); 3328c2ecf20Sopenharmony_ci if (error) { 3338c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_INT_MODE reg write failed\n"); 3348c2ecf20Sopenharmony_ci return error; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_FILTER_REG, 3388c2ecf20Sopenharmony_ci BU21013_DELTA_0_6 | 3398c2ecf20Sopenharmony_ci BU21013_FILTER_EN); 3408c2ecf20Sopenharmony_ci if (error) { 3418c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_FILTER reg write failed\n"); 3428c2ecf20Sopenharmony_ci return error; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_TH_ON_REG, 3468c2ecf20Sopenharmony_ci BU21013_TH_ON_5); 3478c2ecf20Sopenharmony_ci if (error) { 3488c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_TH_ON reg write failed\n"); 3498c2ecf20Sopenharmony_ci return error; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_TH_OFF_REG, 3538c2ecf20Sopenharmony_ci BU21013_TH_OFF_4 | BU21013_TH_OFF_3); 3548c2ecf20Sopenharmony_ci if (error) { 3558c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_TH_OFF reg write failed\n"); 3568c2ecf20Sopenharmony_ci return error; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_GAIN_REG, 3608c2ecf20Sopenharmony_ci BU21013_GAIN_0 | BU21013_GAIN_1); 3618c2ecf20Sopenharmony_ci if (error) { 3628c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_GAIN reg write failed\n"); 3638c2ecf20Sopenharmony_ci return error; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_OFFSET_MODE_REG, 3678c2ecf20Sopenharmony_ci BU21013_OFFSET_MODE_DEFAULT); 3688c2ecf20Sopenharmony_ci if (error) { 3698c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_OFFSET_MODE reg write failed\n"); 3708c2ecf20Sopenharmony_ci return error; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_XY_EDGE_REG, 3748c2ecf20Sopenharmony_ci BU21013_X_EDGE_0 | 3758c2ecf20Sopenharmony_ci BU21013_X_EDGE_2 | 3768c2ecf20Sopenharmony_ci BU21013_Y_EDGE_1 | 3778c2ecf20Sopenharmony_ci BU21013_Y_EDGE_3); 3788c2ecf20Sopenharmony_ci if (error) { 3798c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_XY_EDGE reg write failed\n"); 3808c2ecf20Sopenharmony_ci return error; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(client, BU21013_DONE_REG, 3848c2ecf20Sopenharmony_ci BU21013_DONE); 3858c2ecf20Sopenharmony_ci if (error) { 3868c2ecf20Sopenharmony_ci dev_err(&client->dev, "BU21013_REG_DONE reg write failed\n"); 3878c2ecf20Sopenharmony_ci return error; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic void bu21013_power_off(void *_ts) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct bu21013_ts *ts = _ts; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci regulator_disable(ts->regulator); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void bu21013_disable_chip(void *_ts) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct bu21013_ts *ts = _ts; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci gpiod_set_value(ts->cs_gpiod, 0); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int bu21013_probe(struct i2c_client *client, 4088c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct bu21013_ts *ts; 4118c2ecf20Sopenharmony_ci struct input_dev *in_dev; 4128c2ecf20Sopenharmony_ci struct input_absinfo *info; 4138c2ecf20Sopenharmony_ci u32 max_x = 0, max_y = 0; 4148c2ecf20Sopenharmony_ci int error; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, 4178c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE_DATA)) { 4188c2ecf20Sopenharmony_ci dev_err(&client->dev, "i2c smbus byte data not supported\n"); 4198c2ecf20Sopenharmony_ci return -EIO; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (!client->irq) { 4238c2ecf20Sopenharmony_ci dev_err(&client->dev, "No IRQ set up\n"); 4248c2ecf20Sopenharmony_ci return -EINVAL; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); 4288c2ecf20Sopenharmony_ci if (!ts) 4298c2ecf20Sopenharmony_ci return -ENOMEM; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ts->client = client; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x"); 4348c2ecf20Sopenharmony_ci ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y"); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci in_dev = devm_input_allocate_device(&client->dev); 4378c2ecf20Sopenharmony_ci if (!in_dev) { 4388c2ecf20Sopenharmony_ci dev_err(&client->dev, "device memory alloc failed\n"); 4398c2ecf20Sopenharmony_ci return -ENOMEM; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci ts->in_dev = in_dev; 4428c2ecf20Sopenharmony_ci input_set_drvdata(in_dev, ts); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* register the device to input subsystem */ 4458c2ecf20Sopenharmony_ci in_dev->name = DRIVER_TP; 4468c2ecf20Sopenharmony_ci in_dev->id.bustype = BUS_I2C; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x); 4498c2ecf20Sopenharmony_ci device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0); 4528c2ecf20Sopenharmony_ci input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci touchscreen_parse_properties(in_dev, true, &ts->props); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Adjust for the legacy "flip" properties, if present */ 4578c2ecf20Sopenharmony_ci if (!ts->props.invert_x && 4588c2ecf20Sopenharmony_ci device_property_read_bool(&client->dev, "rohm,flip-x")) { 4598c2ecf20Sopenharmony_ci info = &in_dev->absinfo[ABS_MT_POSITION_X]; 4608c2ecf20Sopenharmony_ci info->maximum -= info->minimum; 4618c2ecf20Sopenharmony_ci info->minimum = 0; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (!ts->props.invert_y && 4658c2ecf20Sopenharmony_ci device_property_read_bool(&client->dev, "rohm,flip-y")) { 4668c2ecf20Sopenharmony_ci info = &in_dev->absinfo[ABS_MT_POSITION_Y]; 4678c2ecf20Sopenharmony_ci info->maximum -= info->minimum; 4688c2ecf20Sopenharmony_ci info->minimum = 0; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci error = input_mt_init_slots(in_dev, MAX_FINGERS, 4728c2ecf20Sopenharmony_ci INPUT_MT_DIRECT | INPUT_MT_TRACK | 4738c2ecf20Sopenharmony_ci INPUT_MT_DROP_UNUSED); 4748c2ecf20Sopenharmony_ci if (error) { 4758c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to initialize MT slots"); 4768c2ecf20Sopenharmony_ci return error; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci ts->regulator = devm_regulator_get(&client->dev, "avdd"); 4808c2ecf20Sopenharmony_ci if (IS_ERR(ts->regulator)) { 4818c2ecf20Sopenharmony_ci dev_err(&client->dev, "regulator_get failed\n"); 4828c2ecf20Sopenharmony_ci return PTR_ERR(ts->regulator); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci error = regulator_enable(ts->regulator); 4868c2ecf20Sopenharmony_ci if (error) { 4878c2ecf20Sopenharmony_ci dev_err(&client->dev, "regulator enable failed\n"); 4888c2ecf20Sopenharmony_ci return error; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts); 4928c2ecf20Sopenharmony_ci if (error) { 4938c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to install power off handler\n"); 4948c2ecf20Sopenharmony_ci return error; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Named "CS" on the chip, DT binding is "reset" */ 4988c2ecf20Sopenharmony_ci ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); 4998c2ecf20Sopenharmony_ci error = PTR_ERR_OR_ZERO(ts->cs_gpiod); 5008c2ecf20Sopenharmony_ci if (error) { 5018c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 5028c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get CS GPIO\n"); 5038c2ecf20Sopenharmony_ci return error; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS"); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci error = devm_add_action_or_reset(&client->dev, 5088c2ecf20Sopenharmony_ci bu21013_disable_chip, ts); 5098c2ecf20Sopenharmony_ci if (error) { 5108c2ecf20Sopenharmony_ci dev_err(&client->dev, 5118c2ecf20Sopenharmony_ci "failed to install chip disable handler\n"); 5128c2ecf20Sopenharmony_ci return error; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* Named "INT" on the chip, DT binding is "touch" */ 5168c2ecf20Sopenharmony_ci ts->int_gpiod = devm_gpiod_get_optional(&client->dev, 5178c2ecf20Sopenharmony_ci "touch", GPIOD_IN); 5188c2ecf20Sopenharmony_ci error = PTR_ERR_OR_ZERO(ts->int_gpiod); 5198c2ecf20Sopenharmony_ci if (error) { 5208c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 5218c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get INT GPIO\n"); 5228c2ecf20Sopenharmony_ci return error; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (ts->int_gpiod) 5268c2ecf20Sopenharmony_ci gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT"); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* configure the touch panel controller */ 5298c2ecf20Sopenharmony_ci error = bu21013_init_chip(ts); 5308c2ecf20Sopenharmony_ci if (error) { 5318c2ecf20Sopenharmony_ci dev_err(&client->dev, "error in bu21013 config\n"); 5328c2ecf20Sopenharmony_ci return error; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, client->irq, 5368c2ecf20Sopenharmony_ci NULL, bu21013_gpio_irq, 5378c2ecf20Sopenharmony_ci IRQF_ONESHOT, DRIVER_TP, ts); 5388c2ecf20Sopenharmony_ci if (error) { 5398c2ecf20Sopenharmony_ci dev_err(&client->dev, "request irq %d failed\n", 5408c2ecf20Sopenharmony_ci client->irq); 5418c2ecf20Sopenharmony_ci return error; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci error = input_register_device(in_dev); 5458c2ecf20Sopenharmony_ci if (error) { 5468c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to register input device\n"); 5478c2ecf20Sopenharmony_ci return error; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci i2c_set_clientdata(client, ts); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int bu21013_remove(struct i2c_client *client) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct bu21013_ts *ts = i2c_get_clientdata(client); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Make sure IRQ will exit quickly even if there is contact */ 5608c2ecf20Sopenharmony_ci ts->touch_stopped = true; 5618c2ecf20Sopenharmony_ci /* The resources will be freed by devm */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int __maybe_unused bu21013_suspend(struct device *dev) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 5698c2ecf20Sopenharmony_ci struct bu21013_ts *ts = i2c_get_clientdata(client); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci ts->touch_stopped = true; 5728c2ecf20Sopenharmony_ci mb(); 5738c2ecf20Sopenharmony_ci disable_irq(client->irq); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (!device_may_wakeup(&client->dev)) 5768c2ecf20Sopenharmony_ci regulator_disable(ts->regulator); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int __maybe_unused bu21013_resume(struct device *dev) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 5848c2ecf20Sopenharmony_ci struct bu21013_ts *ts = i2c_get_clientdata(client); 5858c2ecf20Sopenharmony_ci int error; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (!device_may_wakeup(&client->dev)) { 5888c2ecf20Sopenharmony_ci error = regulator_enable(ts->regulator); 5898c2ecf20Sopenharmony_ci if (error) { 5908c2ecf20Sopenharmony_ci dev_err(&client->dev, 5918c2ecf20Sopenharmony_ci "failed to re-enable regulator when resuming\n"); 5928c2ecf20Sopenharmony_ci return error; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci error = bu21013_init_chip(ts); 5968c2ecf20Sopenharmony_ci if (error) { 5978c2ecf20Sopenharmony_ci dev_err(&client->dev, 5988c2ecf20Sopenharmony_ci "failed to reinitialize chip when resuming\n"); 5998c2ecf20Sopenharmony_ci return error; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci ts->touch_stopped = false; 6048c2ecf20Sopenharmony_ci mb(); 6058c2ecf20Sopenharmony_ci enable_irq(client->irq); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic const struct i2c_device_id bu21013_id[] = { 6138c2ecf20Sopenharmony_ci { DRIVER_TP, 0 }, 6148c2ecf20Sopenharmony_ci { } 6158c2ecf20Sopenharmony_ci}; 6168c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bu21013_id); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic struct i2c_driver bu21013_driver = { 6198c2ecf20Sopenharmony_ci .driver = { 6208c2ecf20Sopenharmony_ci .name = DRIVER_TP, 6218c2ecf20Sopenharmony_ci .pm = &bu21013_dev_pm_ops, 6228c2ecf20Sopenharmony_ci }, 6238c2ecf20Sopenharmony_ci .probe = bu21013_probe, 6248c2ecf20Sopenharmony_ci .remove = bu21013_remove, 6258c2ecf20Sopenharmony_ci .id_table = bu21013_id, 6268c2ecf20Sopenharmony_ci}; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cimodule_i2c_driver(bu21013_driver); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 6318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>"); 6328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("bu21013 touch screen controller driver"); 633