18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Rohm BU21029 touchscreen controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Bosch Sicherheitssysteme GmbH 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 88c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 98c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 148c2ecf20Sopenharmony_ci#include <linux/i2c.h> 158c2ecf20Sopenharmony_ci#include <linux/input.h> 168c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/irq.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/timer.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * HW_ID1 Register (PAGE=0, ADDR=0x0E, Reset value=0x02, Read only) 258c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 268c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 278c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 288c2ecf20Sopenharmony_ci * | HW_IDH | 298c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 308c2ecf20Sopenharmony_ci * HW_ID2 Register (PAGE=0, ADDR=0x0F, Reset value=0x29, Read only) 318c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 328c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 338c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 348c2ecf20Sopenharmony_ci * | HW_IDL | 358c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 368c2ecf20Sopenharmony_ci * HW_IDH: high 8bits of IC's ID 378c2ecf20Sopenharmony_ci * HW_IDL: low 8bits of IC's ID 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci#define BU21029_HWID_REG (0x0E << 3) 408c2ecf20Sopenharmony_ci#define SUPPORTED_HWID 0x0229 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * CFR0 Register (PAGE=0, ADDR=0x00, Reset value=0x20) 448c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 458c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 468c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 478c2ecf20Sopenharmony_ci * | 0 | 0 | CALIB | INTRM | 0 | 0 | 0 | 0 | 488c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 498c2ecf20Sopenharmony_ci * CALIB: 0 = not to use calibration result (*) 508c2ecf20Sopenharmony_ci * 1 = use calibration result 518c2ecf20Sopenharmony_ci * INTRM: 0 = INT output depend on "pen down" (*) 528c2ecf20Sopenharmony_ci * 1 = INT output always "0" 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci#define BU21029_CFR0_REG (0x00 << 3) 558c2ecf20Sopenharmony_ci#define CFR0_VALUE 0x00 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * CFR1 Register (PAGE=0, ADDR=0x01, Reset value=0xA6) 598c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 608c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 618c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 628c2ecf20Sopenharmony_ci * | MAV | AVE[2:0] | 0 | SMPL[2:0] | 638c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 648c2ecf20Sopenharmony_ci * MAV: 0 = median average filter off 658c2ecf20Sopenharmony_ci * 1 = median average filter on (*) 668c2ecf20Sopenharmony_ci * AVE: AVE+1 = number of average samples for MAV, 678c2ecf20Sopenharmony_ci * if AVE>SMPL, then AVE=SMPL (=3) 688c2ecf20Sopenharmony_ci * SMPL: SMPL+1 = number of conversion samples for MAV (=7) 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci#define BU21029_CFR1_REG (0x01 << 3) 718c2ecf20Sopenharmony_ci#define CFR1_VALUE 0xA6 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * CFR2 Register (PAGE=0, ADDR=0x02, Reset value=0x04) 758c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 768c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 778c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 788c2ecf20Sopenharmony_ci * | INTVL_TIME[3:0] | TIME_ST_ADC[3:0] | 798c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 808c2ecf20Sopenharmony_ci * INTVL_TIME: waiting time between completion of conversion 818c2ecf20Sopenharmony_ci * and start of next conversion, only usable in 828c2ecf20Sopenharmony_ci * autoscan mode (=20.480ms) 838c2ecf20Sopenharmony_ci * TIME_ST_ADC: waiting time between application of voltage 848c2ecf20Sopenharmony_ci * to panel and start of A/D conversion (=100us) 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define BU21029_CFR2_REG (0x02 << 3) 878c2ecf20Sopenharmony_ci#define CFR2_VALUE 0xC9 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * CFR3 Register (PAGE=0, ADDR=0x0B, Reset value=0x72) 918c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 928c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 938c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 948c2ecf20Sopenharmony_ci * | RM8 | STRETCH| PU90K | DUAL | PIDAC_OFS[3:0] | 958c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 968c2ecf20Sopenharmony_ci * RM8: 0 = coordinate resolution is 12bit (*) 978c2ecf20Sopenharmony_ci * 1 = coordinate resolution is 8bit 988c2ecf20Sopenharmony_ci * STRETCH: 0 = SCL_STRETCH function off 998c2ecf20Sopenharmony_ci * 1 = SCL_STRETCH function on (*) 1008c2ecf20Sopenharmony_ci * PU90K: 0 = internal pull-up resistance for touch detection is ~50kohms (*) 1018c2ecf20Sopenharmony_ci * 1 = internal pull-up resistance for touch detection is ~90kohms 1028c2ecf20Sopenharmony_ci * DUAL: 0 = dual touch detection off (*) 1038c2ecf20Sopenharmony_ci * 1 = dual touch detection on 1048c2ecf20Sopenharmony_ci * PIDAC_OFS: dual touch detection circuit adjustment, it is not necessary 1058c2ecf20Sopenharmony_ci * to change this from initial value 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci#define BU21029_CFR3_REG (0x0B << 3) 1088c2ecf20Sopenharmony_ci#define CFR3_VALUE 0x42 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* 1118c2ecf20Sopenharmony_ci * LDO Register (PAGE=0, ADDR=0x0C, Reset value=0x00) 1128c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 1138c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 1148c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 1158c2ecf20Sopenharmony_ci * | 0 | PVDD[2:0] | 0 | AVDD[2:0] | 1168c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 1178c2ecf20Sopenharmony_ci * PVDD: output voltage of panel output regulator (=2.000V) 1188c2ecf20Sopenharmony_ci * AVDD: output voltage of analog circuit regulator (=2.000V) 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci#define BU21029_LDO_REG (0x0C << 3) 1218c2ecf20Sopenharmony_ci#define LDO_VALUE 0x77 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Serial Interface Command Byte 1 (CID=1) 1258c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 1268c2ecf20Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 1278c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 1288c2ecf20Sopenharmony_ci * | 1 | CF | CMSK | PDM | STP | 1298c2ecf20Sopenharmony_ci * +--------+--------+--------+--------+--------+--------+--------+--------+ 1308c2ecf20Sopenharmony_ci * CF: conversion function, see table 3 in datasheet p6 (=0000, automatic scan) 1318c2ecf20Sopenharmony_ci * CMSK: 0 = executes convert function (*) 1328c2ecf20Sopenharmony_ci * 1 = reads the convert result 1338c2ecf20Sopenharmony_ci * PDM: 0 = power down after convert function stops (*) 1348c2ecf20Sopenharmony_ci * 1 = keep power on after convert function stops 1358c2ecf20Sopenharmony_ci * STP: 1 = abort current conversion and power down, set to "0" automatically 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci#define BU21029_AUTOSCAN 0x80 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * The timeout value needs to be larger than INTVL_TIME + tConv4 (sample and 1418c2ecf20Sopenharmony_ci * conversion time), where tConv4 is calculated by formula: 1428c2ecf20Sopenharmony_ci * tPON + tDLY1 + (tTIME_ST_ADC + (tADC * tSMPL) * 2 + tDLY2) * 3 1438c2ecf20Sopenharmony_ci * see figure 8 in datasheet p15 for details of each field. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci#define PEN_UP_TIMEOUT_MS 50 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define STOP_DELAY_MIN_US 50 1488c2ecf20Sopenharmony_ci#define STOP_DELAY_MAX_US 1000 1498c2ecf20Sopenharmony_ci#define START_DELAY_MS 2 1508c2ecf20Sopenharmony_ci#define BUF_LEN 8 1518c2ecf20Sopenharmony_ci#define SCALE_12BIT (1 << 12) 1528c2ecf20Sopenharmony_ci#define MAX_12BIT ((1 << 12) - 1) 1538c2ecf20Sopenharmony_ci#define DRIVER_NAME "bu21029" 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistruct bu21029_ts_data { 1568c2ecf20Sopenharmony_ci struct i2c_client *client; 1578c2ecf20Sopenharmony_ci struct input_dev *in_dev; 1588c2ecf20Sopenharmony_ci struct timer_list timer; 1598c2ecf20Sopenharmony_ci struct regulator *vdd; 1608c2ecf20Sopenharmony_ci struct gpio_desc *reset_gpios; 1618c2ecf20Sopenharmony_ci u32 x_plate_ohms; 1628c2ecf20Sopenharmony_ci struct touchscreen_properties prop; 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void bu21029_touch_report(struct bu21029_ts_data *bu21029, const u8 *buf) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci u16 x, y, z1, z2; 1688c2ecf20Sopenharmony_ci u32 rz; 1698c2ecf20Sopenharmony_ci s32 max_pressure = input_abs_get_max(bu21029->in_dev, ABS_PRESSURE); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * compose upper 8 and lower 4 bits into a 12bit value: 1738c2ecf20Sopenharmony_ci * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 1748c2ecf20Sopenharmony_ci * | ByteH | ByteL | 1758c2ecf20Sopenharmony_ci * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 1768c2ecf20Sopenharmony_ci * |b07|b06|b05|b04|b03|b02|b01|b00|b07|b06|b05|b04|b03|b02|b01|b00| 1778c2ecf20Sopenharmony_ci * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 1788c2ecf20Sopenharmony_ci * |v11|v10|v09|v08|v07|v06|v05|v04|v03|v02|v01|v00| 0 | 0 | 0 | 0 | 1798c2ecf20Sopenharmony_ci * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci x = (buf[0] << 4) | (buf[1] >> 4); 1828c2ecf20Sopenharmony_ci y = (buf[2] << 4) | (buf[3] >> 4); 1838c2ecf20Sopenharmony_ci z1 = (buf[4] << 4) | (buf[5] >> 4); 1848c2ecf20Sopenharmony_ci z2 = (buf[6] << 4) | (buf[7] >> 4); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (z1 && z2) { 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * calculate Rz (pressure resistance value) by equation: 1898c2ecf20Sopenharmony_ci * Rz = Rx * (x/Q) * ((z2/z1) - 1), where 1908c2ecf20Sopenharmony_ci * Rx is x-plate resistance, 1918c2ecf20Sopenharmony_ci * Q is the touch screen resolution (8bit = 256, 12bit = 4096) 1928c2ecf20Sopenharmony_ci * x, z1, z2 are the measured positions. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci rz = z2 - z1; 1958c2ecf20Sopenharmony_ci rz *= x; 1968c2ecf20Sopenharmony_ci rz *= bu21029->x_plate_ohms; 1978c2ecf20Sopenharmony_ci rz /= z1; 1988c2ecf20Sopenharmony_ci rz = DIV_ROUND_CLOSEST(rz, SCALE_12BIT); 1998c2ecf20Sopenharmony_ci if (rz <= max_pressure) { 2008c2ecf20Sopenharmony_ci touchscreen_report_pos(bu21029->in_dev, &bu21029->prop, 2018c2ecf20Sopenharmony_ci x, y, false); 2028c2ecf20Sopenharmony_ci input_report_abs(bu21029->in_dev, ABS_PRESSURE, 2038c2ecf20Sopenharmony_ci max_pressure - rz); 2048c2ecf20Sopenharmony_ci input_report_key(bu21029->in_dev, BTN_TOUCH, 1); 2058c2ecf20Sopenharmony_ci input_sync(bu21029->in_dev); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void bu21029_touch_release(struct timer_list *t) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct bu21029_ts_data *bu21029 = from_timer(bu21029, t, timer); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci input_report_abs(bu21029->in_dev, ABS_PRESSURE, 0); 2158c2ecf20Sopenharmony_ci input_report_key(bu21029->in_dev, BTN_TOUCH, 0); 2168c2ecf20Sopenharmony_ci input_sync(bu21029->in_dev); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic irqreturn_t bu21029_touch_soft_irq(int irq, void *data) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct bu21029_ts_data *bu21029 = data; 2228c2ecf20Sopenharmony_ci u8 buf[BUF_LEN]; 2238c2ecf20Sopenharmony_ci int error; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * Read touch data and deassert interrupt (will assert again after 2278c2ecf20Sopenharmony_ci * INTVL_TIME + tConv4 for continuous touch) 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci error = i2c_smbus_read_i2c_block_data(bu21029->client, BU21029_AUTOSCAN, 2308c2ecf20Sopenharmony_ci sizeof(buf), buf); 2318c2ecf20Sopenharmony_ci if (error < 0) 2328c2ecf20Sopenharmony_ci goto out; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci bu21029_touch_report(bu21029, buf); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* reset timer for pen up detection */ 2378c2ecf20Sopenharmony_ci mod_timer(&bu21029->timer, 2388c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(PEN_UP_TIMEOUT_MS)); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciout: 2418c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void bu21029_put_chip_in_reset(struct bu21029_ts_data *bu21029) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci if (bu21029->reset_gpios) { 2478c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(bu21029->reset_gpios, 1); 2488c2ecf20Sopenharmony_ci usleep_range(STOP_DELAY_MIN_US, STOP_DELAY_MAX_US); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int bu21029_start_chip(struct input_dev *dev) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct bu21029_ts_data *bu21029 = input_get_drvdata(dev); 2558c2ecf20Sopenharmony_ci struct i2c_client *i2c = bu21029->client; 2568c2ecf20Sopenharmony_ci struct { 2578c2ecf20Sopenharmony_ci u8 reg; 2588c2ecf20Sopenharmony_ci u8 value; 2598c2ecf20Sopenharmony_ci } init_table[] = { 2608c2ecf20Sopenharmony_ci {BU21029_CFR0_REG, CFR0_VALUE}, 2618c2ecf20Sopenharmony_ci {BU21029_CFR1_REG, CFR1_VALUE}, 2628c2ecf20Sopenharmony_ci {BU21029_CFR2_REG, CFR2_VALUE}, 2638c2ecf20Sopenharmony_ci {BU21029_CFR3_REG, CFR3_VALUE}, 2648c2ecf20Sopenharmony_ci {BU21029_LDO_REG, LDO_VALUE} 2658c2ecf20Sopenharmony_ci }; 2668c2ecf20Sopenharmony_ci int error, i; 2678c2ecf20Sopenharmony_ci __be16 hwid; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci error = regulator_enable(bu21029->vdd); 2708c2ecf20Sopenharmony_ci if (error) { 2718c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "failed to power up chip: %d", error); 2728c2ecf20Sopenharmony_ci return error; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* take chip out of reset */ 2768c2ecf20Sopenharmony_ci if (bu21029->reset_gpios) { 2778c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(bu21029->reset_gpios, 0); 2788c2ecf20Sopenharmony_ci msleep(START_DELAY_MS); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci error = i2c_smbus_read_i2c_block_data(i2c, BU21029_HWID_REG, 2828c2ecf20Sopenharmony_ci sizeof(hwid), (u8 *)&hwid); 2838c2ecf20Sopenharmony_ci if (error < 0) { 2848c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "failed to read HW ID\n"); 2858c2ecf20Sopenharmony_ci goto err_out; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (be16_to_cpu(hwid) != SUPPORTED_HWID) { 2898c2ecf20Sopenharmony_ci dev_err(&i2c->dev, 2908c2ecf20Sopenharmony_ci "unsupported HW ID 0x%x\n", be16_to_cpu(hwid)); 2918c2ecf20Sopenharmony_ci error = -ENODEV; 2928c2ecf20Sopenharmony_ci goto err_out; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_table); ++i) { 2968c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte_data(i2c, 2978c2ecf20Sopenharmony_ci init_table[i].reg, 2988c2ecf20Sopenharmony_ci init_table[i].value); 2998c2ecf20Sopenharmony_ci if (error < 0) { 3008c2ecf20Sopenharmony_ci dev_err(&i2c->dev, 3018c2ecf20Sopenharmony_ci "failed to write %#02x to register %#02x: %d\n", 3028c2ecf20Sopenharmony_ci init_table[i].value, init_table[i].reg, 3038c2ecf20Sopenharmony_ci error); 3048c2ecf20Sopenharmony_ci goto err_out; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci error = i2c_smbus_write_byte(i2c, BU21029_AUTOSCAN); 3098c2ecf20Sopenharmony_ci if (error < 0) { 3108c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "failed to start autoscan\n"); 3118c2ecf20Sopenharmony_ci goto err_out; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci enable_irq(bu21029->client->irq); 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cierr_out: 3188c2ecf20Sopenharmony_ci bu21029_put_chip_in_reset(bu21029); 3198c2ecf20Sopenharmony_ci regulator_disable(bu21029->vdd); 3208c2ecf20Sopenharmony_ci return error; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void bu21029_stop_chip(struct input_dev *dev) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct bu21029_ts_data *bu21029 = input_get_drvdata(dev); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci disable_irq(bu21029->client->irq); 3288c2ecf20Sopenharmony_ci del_timer_sync(&bu21029->timer); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci bu21029_put_chip_in_reset(bu21029); 3318c2ecf20Sopenharmony_ci regulator_disable(bu21029->vdd); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int bu21029_probe(struct i2c_client *client, 3358c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct bu21029_ts_data *bu21029; 3388c2ecf20Sopenharmony_ci struct input_dev *in_dev; 3398c2ecf20Sopenharmony_ci int error; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, 3428c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WRITE_BYTE | 3438c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WRITE_BYTE_DATA | 3448c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { 3458c2ecf20Sopenharmony_ci dev_err(&client->dev, 3468c2ecf20Sopenharmony_ci "i2c functionality support is not sufficient\n"); 3478c2ecf20Sopenharmony_ci return -EIO; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci bu21029 = devm_kzalloc(&client->dev, sizeof(*bu21029), GFP_KERNEL); 3518c2ecf20Sopenharmony_ci if (!bu21029) 3528c2ecf20Sopenharmony_ci return -ENOMEM; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci error = device_property_read_u32(&client->dev, "rohm,x-plate-ohms", 3558c2ecf20Sopenharmony_ci &bu21029->x_plate_ohms); 3568c2ecf20Sopenharmony_ci if (error) { 3578c2ecf20Sopenharmony_ci dev_err(&client->dev, 3588c2ecf20Sopenharmony_ci "invalid 'x-plate-ohms' supplied: %d\n", error); 3598c2ecf20Sopenharmony_ci return error; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci bu21029->vdd = devm_regulator_get(&client->dev, "vdd"); 3638c2ecf20Sopenharmony_ci if (IS_ERR(bu21029->vdd)) { 3648c2ecf20Sopenharmony_ci error = PTR_ERR(bu21029->vdd); 3658c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 3668c2ecf20Sopenharmony_ci dev_err(&client->dev, 3678c2ecf20Sopenharmony_ci "failed to acquire 'vdd' supply: %d\n", error); 3688c2ecf20Sopenharmony_ci return error; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci bu21029->reset_gpios = devm_gpiod_get_optional(&client->dev, 3728c2ecf20Sopenharmony_ci "reset", GPIOD_OUT_HIGH); 3738c2ecf20Sopenharmony_ci if (IS_ERR(bu21029->reset_gpios)) { 3748c2ecf20Sopenharmony_ci error = PTR_ERR(bu21029->reset_gpios); 3758c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 3768c2ecf20Sopenharmony_ci dev_err(&client->dev, 3778c2ecf20Sopenharmony_ci "failed to acquire 'reset' gpio: %d\n", error); 3788c2ecf20Sopenharmony_ci return error; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci in_dev = devm_input_allocate_device(&client->dev); 3828c2ecf20Sopenharmony_ci if (!in_dev) { 3838c2ecf20Sopenharmony_ci dev_err(&client->dev, "unable to allocate input device\n"); 3848c2ecf20Sopenharmony_ci return -ENOMEM; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci bu21029->client = client; 3888c2ecf20Sopenharmony_ci bu21029->in_dev = in_dev; 3898c2ecf20Sopenharmony_ci timer_setup(&bu21029->timer, bu21029_touch_release, 0); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci in_dev->name = DRIVER_NAME; 3928c2ecf20Sopenharmony_ci in_dev->id.bustype = BUS_I2C; 3938c2ecf20Sopenharmony_ci in_dev->open = bu21029_start_chip; 3948c2ecf20Sopenharmony_ci in_dev->close = bu21029_stop_chip; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci input_set_capability(in_dev, EV_KEY, BTN_TOUCH); 3978c2ecf20Sopenharmony_ci input_set_abs_params(in_dev, ABS_X, 0, MAX_12BIT, 0, 0); 3988c2ecf20Sopenharmony_ci input_set_abs_params(in_dev, ABS_Y, 0, MAX_12BIT, 0, 0); 3998c2ecf20Sopenharmony_ci input_set_abs_params(in_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); 4008c2ecf20Sopenharmony_ci touchscreen_parse_properties(in_dev, false, &bu21029->prop); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci input_set_drvdata(in_dev, bu21029); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci irq_set_status_flags(client->irq, IRQ_NOAUTOEN); 4058c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, client->irq, 4068c2ecf20Sopenharmony_ci NULL, bu21029_touch_soft_irq, 4078c2ecf20Sopenharmony_ci IRQF_ONESHOT, DRIVER_NAME, bu21029); 4088c2ecf20Sopenharmony_ci if (error) { 4098c2ecf20Sopenharmony_ci dev_err(&client->dev, 4108c2ecf20Sopenharmony_ci "unable to request touch irq: %d\n", error); 4118c2ecf20Sopenharmony_ci return error; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci error = input_register_device(in_dev); 4158c2ecf20Sopenharmony_ci if (error) { 4168c2ecf20Sopenharmony_ci dev_err(&client->dev, 4178c2ecf20Sopenharmony_ci "unable to register input device: %d\n", error); 4188c2ecf20Sopenharmony_ci return error; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci i2c_set_clientdata(client, bu21029); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int __maybe_unused bu21029_suspend(struct device *dev) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 4298c2ecf20Sopenharmony_ci struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev)) { 4328c2ecf20Sopenharmony_ci mutex_lock(&bu21029->in_dev->mutex); 4338c2ecf20Sopenharmony_ci if (bu21029->in_dev->users) 4348c2ecf20Sopenharmony_ci bu21029_stop_chip(bu21029->in_dev); 4358c2ecf20Sopenharmony_ci mutex_unlock(&bu21029->in_dev->mutex); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int __maybe_unused bu21029_resume(struct device *dev) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 4448c2ecf20Sopenharmony_ci struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev)) { 4478c2ecf20Sopenharmony_ci mutex_lock(&bu21029->in_dev->mutex); 4488c2ecf20Sopenharmony_ci if (bu21029->in_dev->users) 4498c2ecf20Sopenharmony_ci bu21029_start_chip(bu21029->in_dev); 4508c2ecf20Sopenharmony_ci mutex_unlock(&bu21029->in_dev->mutex); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic const struct i2c_device_id bu21029_ids[] = { 4588c2ecf20Sopenharmony_ci { DRIVER_NAME, 0 }, 4598c2ecf20Sopenharmony_ci { /* sentinel */ } 4608c2ecf20Sopenharmony_ci}; 4618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bu21029_ids); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 4648c2ecf20Sopenharmony_cistatic const struct of_device_id bu21029_of_ids[] = { 4658c2ecf20Sopenharmony_ci { .compatible = "rohm,bu21029" }, 4668c2ecf20Sopenharmony_ci { /* sentinel */ } 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bu21029_of_ids); 4698c2ecf20Sopenharmony_ci#endif 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct i2c_driver bu21029_driver = { 4728c2ecf20Sopenharmony_ci .driver = { 4738c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 4748c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(bu21029_of_ids), 4758c2ecf20Sopenharmony_ci .pm = &bu21029_pm_ops, 4768c2ecf20Sopenharmony_ci }, 4778c2ecf20Sopenharmony_ci .id_table = bu21029_ids, 4788c2ecf20Sopenharmony_ci .probe = bu21029_probe, 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_cimodule_i2c_driver(bu21029_driver); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zhu Yi <yi.zhu5@cn.bosch.com>"); 4838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Rohm BU21029 touchscreen controller driver"); 4848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 485