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