162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AD7879/AD7889 based touchscreen and GPIO driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * History:
862306a36Sopenharmony_ci * Copyright (c) 2005 David Brownell
962306a36Sopenharmony_ci * Copyright (c) 2006 Nokia Corporation
1062306a36Sopenharmony_ci * Various changes: Imre Deak <imre.deak@nokia.com>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Using code from:
1362306a36Sopenharmony_ci *  - corgi_ts.c
1462306a36Sopenharmony_ci *	Copyright (C) 2004-2005 Richard Purdie
1562306a36Sopenharmony_ci *  - omap_ts.[hc], ads7846.h, ts_osk.c
1662306a36Sopenharmony_ci *	Copyright (C) 2002 MontaVista Software
1762306a36Sopenharmony_ci *	Copyright (C) 2004 Texas Instruments
1862306a36Sopenharmony_ci *	Copyright (C) 2005 Dirk Behme
1962306a36Sopenharmony_ci *  - ad7877.c
2062306a36Sopenharmony_ci *	Copyright (C) 2006-2008 Analog Devices Inc.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/device.h>
2462306a36Sopenharmony_ci#include <linux/delay.h>
2562306a36Sopenharmony_ci#include <linux/input.h>
2662306a36Sopenharmony_ci#include <linux/interrupt.h>
2762306a36Sopenharmony_ci#include <linux/irq.h>
2862306a36Sopenharmony_ci#include <linux/property.h>
2962306a36Sopenharmony_ci#include <linux/regmap.h>
3062306a36Sopenharmony_ci#include <linux/slab.h>
3162306a36Sopenharmony_ci#include <linux/gpio/driver.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/input/touchscreen.h>
3462306a36Sopenharmony_ci#include <linux/module.h>
3562306a36Sopenharmony_ci#include "ad7879.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define AD7879_REG_ZEROS		0
3862306a36Sopenharmony_ci#define AD7879_REG_CTRL1		1
3962306a36Sopenharmony_ci#define AD7879_REG_CTRL2		2
4062306a36Sopenharmony_ci#define AD7879_REG_CTRL3		3
4162306a36Sopenharmony_ci#define AD7879_REG_AUX1HIGH		4
4262306a36Sopenharmony_ci#define AD7879_REG_AUX1LOW		5
4362306a36Sopenharmony_ci#define AD7879_REG_TEMP1HIGH		6
4462306a36Sopenharmony_ci#define AD7879_REG_TEMP1LOW		7
4562306a36Sopenharmony_ci#define AD7879_REG_XPLUS		8
4662306a36Sopenharmony_ci#define AD7879_REG_YPLUS		9
4762306a36Sopenharmony_ci#define AD7879_REG_Z1			10
4862306a36Sopenharmony_ci#define AD7879_REG_Z2			11
4962306a36Sopenharmony_ci#define AD7879_REG_AUXVBAT		12
5062306a36Sopenharmony_ci#define AD7879_REG_TEMP			13
5162306a36Sopenharmony_ci#define AD7879_REG_REVID		14
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Control REG 1 */
5462306a36Sopenharmony_ci#define AD7879_TMR(x)			((x & 0xFF) << 0)
5562306a36Sopenharmony_ci#define AD7879_ACQ(x)			((x & 0x3) << 8)
5662306a36Sopenharmony_ci#define AD7879_MODE_NOC			(0 << 10)	/* Do not convert */
5762306a36Sopenharmony_ci#define AD7879_MODE_SCC			(1 << 10)	/* Single channel conversion */
5862306a36Sopenharmony_ci#define AD7879_MODE_SEQ0		(2 << 10)	/* Sequence 0 in Slave Mode */
5962306a36Sopenharmony_ci#define AD7879_MODE_SEQ1		(3 << 10)	/* Sequence 1 in Master Mode */
6062306a36Sopenharmony_ci#define AD7879_MODE_INT			(1 << 15)	/* PENIRQ disabled INT enabled */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Control REG 2 */
6362306a36Sopenharmony_ci#define AD7879_FCD(x)			((x & 0x3) << 0)
6462306a36Sopenharmony_ci#define AD7879_RESET			(1 << 4)
6562306a36Sopenharmony_ci#define AD7879_MFS(x)			((x & 0x3) << 5)
6662306a36Sopenharmony_ci#define AD7879_AVG(x)			((x & 0x3) << 7)
6762306a36Sopenharmony_ci#define	AD7879_SER			(1 << 9)	/* non-differential */
6862306a36Sopenharmony_ci#define	AD7879_DFR			(0 << 9)	/* differential */
6962306a36Sopenharmony_ci#define AD7879_GPIOPOL			(1 << 10)
7062306a36Sopenharmony_ci#define AD7879_GPIODIR			(1 << 11)
7162306a36Sopenharmony_ci#define AD7879_GPIO_DATA		(1 << 12)
7262306a36Sopenharmony_ci#define AD7879_GPIO_EN			(1 << 13)
7362306a36Sopenharmony_ci#define AD7879_PM(x)			((x & 0x3) << 14)
7462306a36Sopenharmony_ci#define AD7879_PM_SHUTDOWN		(0)
7562306a36Sopenharmony_ci#define AD7879_PM_DYN			(1)
7662306a36Sopenharmony_ci#define AD7879_PM_FULLON		(2)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* Control REG 3 */
7962306a36Sopenharmony_ci#define AD7879_TEMPMASK_BIT		(1<<15)
8062306a36Sopenharmony_ci#define AD7879_AUXVBATMASK_BIT		(1<<14)
8162306a36Sopenharmony_ci#define AD7879_INTMODE_BIT		(1<<13)
8262306a36Sopenharmony_ci#define AD7879_GPIOALERTMASK_BIT	(1<<12)
8362306a36Sopenharmony_ci#define AD7879_AUXLOW_BIT		(1<<11)
8462306a36Sopenharmony_ci#define AD7879_AUXHIGH_BIT		(1<<10)
8562306a36Sopenharmony_ci#define AD7879_TEMPLOW_BIT		(1<<9)
8662306a36Sopenharmony_ci#define AD7879_TEMPHIGH_BIT		(1<<8)
8762306a36Sopenharmony_ci#define AD7879_YPLUS_BIT		(1<<7)
8862306a36Sopenharmony_ci#define AD7879_XPLUS_BIT		(1<<6)
8962306a36Sopenharmony_ci#define AD7879_Z1_BIT			(1<<5)
9062306a36Sopenharmony_ci#define AD7879_Z2_BIT			(1<<4)
9162306a36Sopenharmony_ci#define AD7879_AUX_BIT			(1<<3)
9262306a36Sopenharmony_ci#define AD7879_VBAT_BIT			(1<<2)
9362306a36Sopenharmony_ci#define AD7879_TEMP_BIT			(1<<1)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cienum {
9662306a36Sopenharmony_ci	AD7879_SEQ_YPOS  = 0,
9762306a36Sopenharmony_ci	AD7879_SEQ_XPOS  = 1,
9862306a36Sopenharmony_ci	AD7879_SEQ_Z1    = 2,
9962306a36Sopenharmony_ci	AD7879_SEQ_Z2    = 3,
10062306a36Sopenharmony_ci	AD7879_NR_SENSE  = 4,
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define	MAX_12BIT			((1<<12)-1)
10462306a36Sopenharmony_ci#define	TS_PEN_UP_TIMEOUT		msecs_to_jiffies(50)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistruct ad7879 {
10762306a36Sopenharmony_ci	struct regmap		*regmap;
10862306a36Sopenharmony_ci	struct device		*dev;
10962306a36Sopenharmony_ci	struct input_dev	*input;
11062306a36Sopenharmony_ci	struct timer_list	timer;
11162306a36Sopenharmony_ci#ifdef CONFIG_GPIOLIB
11262306a36Sopenharmony_ci	struct gpio_chip	gc;
11362306a36Sopenharmony_ci	struct mutex		mutex;
11462306a36Sopenharmony_ci#endif
11562306a36Sopenharmony_ci	unsigned int		irq;
11662306a36Sopenharmony_ci	bool			disabled;	/* P: input->mutex */
11762306a36Sopenharmony_ci	bool			suspended;	/* P: input->mutex */
11862306a36Sopenharmony_ci	bool			swap_xy;
11962306a36Sopenharmony_ci	u16			conversion_data[AD7879_NR_SENSE];
12062306a36Sopenharmony_ci	char			phys[32];
12162306a36Sopenharmony_ci	u8			first_conversion_delay;
12262306a36Sopenharmony_ci	u8			acquisition_time;
12362306a36Sopenharmony_ci	u8			averaging;
12462306a36Sopenharmony_ci	u8			pen_down_acc_interval;
12562306a36Sopenharmony_ci	u8			median;
12662306a36Sopenharmony_ci	u16			x_plate_ohms;
12762306a36Sopenharmony_ci	u16			cmd_crtl1;
12862306a36Sopenharmony_ci	u16			cmd_crtl2;
12962306a36Sopenharmony_ci	u16			cmd_crtl3;
13062306a36Sopenharmony_ci	int			x;
13162306a36Sopenharmony_ci	int			y;
13262306a36Sopenharmony_ci	int			Rt;
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int ad7879_read(struct ad7879 *ts, u8 reg)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	unsigned int val;
13862306a36Sopenharmony_ci	int error;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	error = regmap_read(ts->regmap, reg, &val);
14162306a36Sopenharmony_ci	if (error) {
14262306a36Sopenharmony_ci		dev_err(ts->dev, "failed to read register %#02x: %d\n",
14362306a36Sopenharmony_ci			reg, error);
14462306a36Sopenharmony_ci		return error;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return val;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	int error;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	error = regmap_write(ts->regmap, reg, val);
15562306a36Sopenharmony_ci	if (error) {
15662306a36Sopenharmony_ci		dev_err(ts->dev,
15762306a36Sopenharmony_ci			"failed to write %#04x to register %#02x: %d\n",
15862306a36Sopenharmony_ci			val, reg, error);
15962306a36Sopenharmony_ci		return error;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int ad7879_report(struct ad7879 *ts)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct input_dev *input_dev = ts->input;
16862306a36Sopenharmony_ci	unsigned Rt;
16962306a36Sopenharmony_ci	u16 x, y, z1, z2;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT;
17262306a36Sopenharmony_ci	y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT;
17362306a36Sopenharmony_ci	z1 = ts->conversion_data[AD7879_SEQ_Z1] & MAX_12BIT;
17462306a36Sopenharmony_ci	z2 = ts->conversion_data[AD7879_SEQ_Z2] & MAX_12BIT;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (ts->swap_xy)
17762306a36Sopenharmony_ci		swap(x, y);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/*
18062306a36Sopenharmony_ci	 * The samples processed here are already preprocessed by the AD7879.
18162306a36Sopenharmony_ci	 * The preprocessing function consists of a median and an averaging
18262306a36Sopenharmony_ci	 * filter.  The combination of these two techniques provides a robust
18362306a36Sopenharmony_ci	 * solution, discarding the spurious noise in the signal and keeping
18462306a36Sopenharmony_ci	 * only the data of interest.  The size of both filters is
18562306a36Sopenharmony_ci	 * programmable. (dev.platform_data, see linux/platform_data/ad7879.h)
18662306a36Sopenharmony_ci	 * Other user-programmable conversion controls include variable
18762306a36Sopenharmony_ci	 * acquisition time, and first conversion delay. Up to 16 averages can
18862306a36Sopenharmony_ci	 * be taken per conversion.
18962306a36Sopenharmony_ci	 */
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (likely(x && z1)) {
19262306a36Sopenharmony_ci		/* compute touch pressure resistance using equation #1 */
19362306a36Sopenharmony_ci		Rt = (z2 - z1) * x * ts->x_plate_ohms;
19462306a36Sopenharmony_ci		Rt /= z1;
19562306a36Sopenharmony_ci		Rt = (Rt + 2047) >> 12;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		/*
19862306a36Sopenharmony_ci		 * Sample found inconsistent, pressure is beyond
19962306a36Sopenharmony_ci		 * the maximum. Don't report it to user space.
20062306a36Sopenharmony_ci		 */
20162306a36Sopenharmony_ci		if (Rt > input_abs_get_max(input_dev, ABS_PRESSURE))
20262306a36Sopenharmony_ci			return -EINVAL;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		/*
20562306a36Sopenharmony_ci		 * Note that we delay reporting events by one sample.
20662306a36Sopenharmony_ci		 * This is done to avoid reporting last sample of the
20762306a36Sopenharmony_ci		 * touch sequence, which may be incomplete if finger
20862306a36Sopenharmony_ci		 * leaves the surface before last reading is taken.
20962306a36Sopenharmony_ci		 */
21062306a36Sopenharmony_ci		if (timer_pending(&ts->timer)) {
21162306a36Sopenharmony_ci			/* Touch continues */
21262306a36Sopenharmony_ci			input_report_key(input_dev, BTN_TOUCH, 1);
21362306a36Sopenharmony_ci			input_report_abs(input_dev, ABS_X, ts->x);
21462306a36Sopenharmony_ci			input_report_abs(input_dev, ABS_Y, ts->y);
21562306a36Sopenharmony_ci			input_report_abs(input_dev, ABS_PRESSURE, ts->Rt);
21662306a36Sopenharmony_ci			input_sync(input_dev);
21762306a36Sopenharmony_ci		}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		ts->x = x;
22062306a36Sopenharmony_ci		ts->y = y;
22162306a36Sopenharmony_ci		ts->Rt = Rt;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		return 0;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return -EINVAL;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic void ad7879_ts_event_release(struct ad7879 *ts)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct input_dev *input_dev = ts->input;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	input_report_abs(input_dev, ABS_PRESSURE, 0);
23462306a36Sopenharmony_ci	input_report_key(input_dev, BTN_TOUCH, 0);
23562306a36Sopenharmony_ci	input_sync(input_dev);
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic void ad7879_timer(struct timer_list *t)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	struct ad7879 *ts = from_timer(ts, t, timer);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	ad7879_ts_event_release(ts);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic irqreturn_t ad7879_irq(int irq, void *handle)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	struct ad7879 *ts = handle;
24862306a36Sopenharmony_ci	int error;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	error = regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS,
25162306a36Sopenharmony_ci				 ts->conversion_data, AD7879_NR_SENSE);
25262306a36Sopenharmony_ci	if (error)
25362306a36Sopenharmony_ci		dev_err_ratelimited(ts->dev, "failed to read %#02x: %d\n",
25462306a36Sopenharmony_ci				    AD7879_REG_XPLUS, error);
25562306a36Sopenharmony_ci	else if (!ad7879_report(ts))
25662306a36Sopenharmony_ci		mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return IRQ_HANDLED;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic void __ad7879_enable(struct ad7879 *ts)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
26462306a36Sopenharmony_ci	ad7879_write(ts, AD7879_REG_CTRL3, ts->cmd_crtl3);
26562306a36Sopenharmony_ci	ad7879_write(ts, AD7879_REG_CTRL1, ts->cmd_crtl1);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	enable_irq(ts->irq);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void __ad7879_disable(struct ad7879 *ts)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	u16 reg = (ts->cmd_crtl2 & ~AD7879_PM(-1)) |
27362306a36Sopenharmony_ci		AD7879_PM(AD7879_PM_SHUTDOWN);
27462306a36Sopenharmony_ci	disable_irq(ts->irq);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (del_timer_sync(&ts->timer))
27762306a36Sopenharmony_ci		ad7879_ts_event_release(ts);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	ad7879_write(ts, AD7879_REG_CTRL2, reg);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int ad7879_open(struct input_dev *input)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct ad7879 *ts = input_get_drvdata(input);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* protected by input->mutex */
28862306a36Sopenharmony_ci	if (!ts->disabled && !ts->suspended)
28962306a36Sopenharmony_ci		__ad7879_enable(ts);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic void ad7879_close(struct input_dev *input)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct ad7879 *ts = input_get_drvdata(input);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* protected by input->mutex */
29962306a36Sopenharmony_ci	if (!ts->disabled && !ts->suspended)
30062306a36Sopenharmony_ci		__ad7879_disable(ts);
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic int __maybe_unused ad7879_suspend(struct device *dev)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct ad7879 *ts = dev_get_drvdata(dev);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	mutex_lock(&ts->input->mutex);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (!ts->suspended && !ts->disabled && input_device_enabled(ts->input))
31062306a36Sopenharmony_ci		__ad7879_disable(ts);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	ts->suspended = true;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	mutex_unlock(&ts->input->mutex);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return 0;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic int __maybe_unused ad7879_resume(struct device *dev)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct ad7879 *ts = dev_get_drvdata(dev);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	mutex_lock(&ts->input->mutex);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (ts->suspended && !ts->disabled && input_device_enabled(ts->input))
32662306a36Sopenharmony_ci		__ad7879_enable(ts);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	ts->suspended = false;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	mutex_unlock(&ts->input->mutex);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciSIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume);
33662306a36Sopenharmony_ciEXPORT_SYMBOL(ad7879_pm_ops);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic void ad7879_toggle(struct ad7879 *ts, bool disable)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	mutex_lock(&ts->input->mutex);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (!ts->suspended && input_device_enabled(ts->input)) {
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		if (disable) {
34562306a36Sopenharmony_ci			if (ts->disabled)
34662306a36Sopenharmony_ci				__ad7879_enable(ts);
34762306a36Sopenharmony_ci		} else {
34862306a36Sopenharmony_ci			if (!ts->disabled)
34962306a36Sopenharmony_ci				__ad7879_disable(ts);
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	ts->disabled = disable;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	mutex_unlock(&ts->input->mutex);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic ssize_t ad7879_disable_show(struct device *dev,
35962306a36Sopenharmony_ci				     struct device_attribute *attr, char *buf)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct ad7879 *ts = dev_get_drvdata(dev);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return sprintf(buf, "%u\n", ts->disabled);
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic ssize_t ad7879_disable_store(struct device *dev,
36762306a36Sopenharmony_ci				     struct device_attribute *attr,
36862306a36Sopenharmony_ci				     const char *buf, size_t count)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct ad7879 *ts = dev_get_drvdata(dev);
37162306a36Sopenharmony_ci	unsigned int val;
37262306a36Sopenharmony_ci	int error;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
37562306a36Sopenharmony_ci	if (error)
37662306a36Sopenharmony_ci		return error;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	ad7879_toggle(ts, val);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return count;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic struct attribute *ad7879_attributes[] = {
38662306a36Sopenharmony_ci	&dev_attr_disable.attr,
38762306a36Sopenharmony_ci	NULL
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic const struct attribute_group ad7879_attr_group = {
39162306a36Sopenharmony_ci	.attrs = ad7879_attributes,
39262306a36Sopenharmony_ci};
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci#ifdef CONFIG_GPIOLIB
39562306a36Sopenharmony_cistatic int ad7879_gpio_direction_input(struct gpio_chip *chip,
39662306a36Sopenharmony_ci					unsigned gpio)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct ad7879 *ts = gpiochip_get_data(chip);
39962306a36Sopenharmony_ci	int err;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	mutex_lock(&ts->mutex);
40262306a36Sopenharmony_ci	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
40362306a36Sopenharmony_ci	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
40462306a36Sopenharmony_ci	mutex_unlock(&ts->mutex);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return err;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int ad7879_gpio_direction_output(struct gpio_chip *chip,
41062306a36Sopenharmony_ci					unsigned gpio, int level)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	struct ad7879 *ts = gpiochip_get_data(chip);
41362306a36Sopenharmony_ci	int err;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	mutex_lock(&ts->mutex);
41662306a36Sopenharmony_ci	ts->cmd_crtl2 &= ~AD7879_GPIODIR;
41762306a36Sopenharmony_ci	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIOPOL;
41862306a36Sopenharmony_ci	if (level)
41962306a36Sopenharmony_ci		ts->cmd_crtl2 |= AD7879_GPIO_DATA;
42062306a36Sopenharmony_ci	else
42162306a36Sopenharmony_ci		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
42462306a36Sopenharmony_ci	mutex_unlock(&ts->mutex);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return err;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct ad7879 *ts = gpiochip_get_data(chip);
43262306a36Sopenharmony_ci	u16 val;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	mutex_lock(&ts->mutex);
43562306a36Sopenharmony_ci	val = ad7879_read(ts, AD7879_REG_CTRL2);
43662306a36Sopenharmony_ci	mutex_unlock(&ts->mutex);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return !!(val & AD7879_GPIO_DATA);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic void ad7879_gpio_set_value(struct gpio_chip *chip,
44262306a36Sopenharmony_ci				  unsigned gpio, int value)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct ad7879 *ts = gpiochip_get_data(chip);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	mutex_lock(&ts->mutex);
44762306a36Sopenharmony_ci	if (value)
44862306a36Sopenharmony_ci		ts->cmd_crtl2 |= AD7879_GPIO_DATA;
44962306a36Sopenharmony_ci	else
45062306a36Sopenharmony_ci		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
45362306a36Sopenharmony_ci	mutex_unlock(&ts->mutex);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int ad7879_gpio_add(struct ad7879 *ts)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	int ret = 0;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	mutex_init(&ts->mutex);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* Do not create a chip unless flagged for it */
46362306a36Sopenharmony_ci	if (!device_property_read_bool(ts->dev, "gpio-controller"))
46462306a36Sopenharmony_ci		return 0;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	ts->gc.direction_input = ad7879_gpio_direction_input;
46762306a36Sopenharmony_ci	ts->gc.direction_output = ad7879_gpio_direction_output;
46862306a36Sopenharmony_ci	ts->gc.get = ad7879_gpio_get_value;
46962306a36Sopenharmony_ci	ts->gc.set = ad7879_gpio_set_value;
47062306a36Sopenharmony_ci	ts->gc.can_sleep = 1;
47162306a36Sopenharmony_ci	ts->gc.base = -1;
47262306a36Sopenharmony_ci	ts->gc.ngpio = 1;
47362306a36Sopenharmony_ci	ts->gc.label = "AD7879-GPIO";
47462306a36Sopenharmony_ci	ts->gc.owner = THIS_MODULE;
47562306a36Sopenharmony_ci	ts->gc.parent = ts->dev;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	ret = devm_gpiochip_add_data(ts->dev, &ts->gc, ts);
47862306a36Sopenharmony_ci	if (ret)
47962306a36Sopenharmony_ci		dev_err(ts->dev, "failed to register gpio %d\n",
48062306a36Sopenharmony_ci			ts->gc.base);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return ret;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci#else
48562306a36Sopenharmony_cistatic int ad7879_gpio_add(struct ad7879 *ts)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	return 0;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci#endif
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic int ad7879_parse_dt(struct device *dev, struct ad7879 *ts)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	int err;
49462306a36Sopenharmony_ci	u32 tmp;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	err = device_property_read_u32(dev, "adi,resistance-plate-x", &tmp);
49762306a36Sopenharmony_ci	if (err) {
49862306a36Sopenharmony_ci		dev_err(dev, "failed to get resistance-plate-x property\n");
49962306a36Sopenharmony_ci		return err;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci	ts->x_plate_ohms = (u16)tmp;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	device_property_read_u8(dev, "adi,first-conversion-delay",
50462306a36Sopenharmony_ci				&ts->first_conversion_delay);
50562306a36Sopenharmony_ci	device_property_read_u8(dev, "adi,acquisition-time",
50662306a36Sopenharmony_ci				&ts->acquisition_time);
50762306a36Sopenharmony_ci	device_property_read_u8(dev, "adi,median-filter-size", &ts->median);
50862306a36Sopenharmony_ci	device_property_read_u8(dev, "adi,averaging", &ts->averaging);
50962306a36Sopenharmony_ci	device_property_read_u8(dev, "adi,conversion-interval",
51062306a36Sopenharmony_ci				&ts->pen_down_acc_interval);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ts->swap_xy = device_property_read_bool(dev, "touchscreen-swapped-x-y");
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return 0;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ciint ad7879_probe(struct device *dev, struct regmap *regmap,
51862306a36Sopenharmony_ci		 int irq, u16 bustype, u8 devid)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct ad7879 *ts;
52162306a36Sopenharmony_ci	struct input_dev *input_dev;
52262306a36Sopenharmony_ci	int err;
52362306a36Sopenharmony_ci	u16 revid;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (irq <= 0) {
52662306a36Sopenharmony_ci		dev_err(dev, "No IRQ specified\n");
52762306a36Sopenharmony_ci		return -EINVAL;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
53162306a36Sopenharmony_ci	if (!ts)
53262306a36Sopenharmony_ci		return -ENOMEM;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	err = ad7879_parse_dt(dev, ts);
53562306a36Sopenharmony_ci	if (err)
53662306a36Sopenharmony_ci		return err;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	input_dev = devm_input_allocate_device(dev);
53962306a36Sopenharmony_ci	if (!input_dev) {
54062306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate input device\n");
54162306a36Sopenharmony_ci		return -ENOMEM;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	ts->dev = dev;
54562306a36Sopenharmony_ci	ts->input = input_dev;
54662306a36Sopenharmony_ci	ts->irq = irq;
54762306a36Sopenharmony_ci	ts->regmap = regmap;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	timer_setup(&ts->timer, ad7879_timer, 0);
55062306a36Sopenharmony_ci	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	input_dev->name = "AD7879 Touchscreen";
55362306a36Sopenharmony_ci	input_dev->phys = ts->phys;
55462306a36Sopenharmony_ci	input_dev->dev.parent = dev;
55562306a36Sopenharmony_ci	input_dev->id.bustype = bustype;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	input_dev->open = ad7879_open;
55862306a36Sopenharmony_ci	input_dev->close = ad7879_close;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	input_set_drvdata(input_dev, ts);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
56562306a36Sopenharmony_ci	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
56662306a36Sopenharmony_ci	input_set_capability(input_dev, EV_ABS, ABS_PRESSURE);
56762306a36Sopenharmony_ci	touchscreen_parse_properties(input_dev, false, NULL);
56862306a36Sopenharmony_ci	if (!input_abs_get_max(input_dev, ABS_PRESSURE)) {
56962306a36Sopenharmony_ci		dev_err(dev, "Touchscreen pressure is not specified\n");
57062306a36Sopenharmony_ci		return -EINVAL;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
57462306a36Sopenharmony_ci	if (err < 0) {
57562306a36Sopenharmony_ci		dev_err(dev, "Failed to write %s\n", input_dev->name);
57662306a36Sopenharmony_ci		return err;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	revid = ad7879_read(ts, AD7879_REG_REVID);
58062306a36Sopenharmony_ci	input_dev->id.product = (revid & 0xff);
58162306a36Sopenharmony_ci	input_dev->id.version = revid >> 8;
58262306a36Sopenharmony_ci	if (input_dev->id.product != devid) {
58362306a36Sopenharmony_ci		dev_err(dev, "Failed to probe %s (%x vs %x)\n",
58462306a36Sopenharmony_ci			input_dev->name, devid, revid);
58562306a36Sopenharmony_ci		return -ENODEV;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
58962306a36Sopenharmony_ci			AD7879_XPLUS_BIT |
59062306a36Sopenharmony_ci			AD7879_Z2_BIT |
59162306a36Sopenharmony_ci			AD7879_Z1_BIT |
59262306a36Sopenharmony_ci			AD7879_TEMPMASK_BIT |
59362306a36Sopenharmony_ci			AD7879_AUXVBATMASK_BIT |
59462306a36Sopenharmony_ci			AD7879_GPIOALERTMASK_BIT;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
59762306a36Sopenharmony_ci			AD7879_AVG(ts->averaging) |
59862306a36Sopenharmony_ci			AD7879_MFS(ts->median) |
59962306a36Sopenharmony_ci			AD7879_FCD(ts->first_conversion_delay);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
60262306a36Sopenharmony_ci			AD7879_ACQ(ts->acquisition_time) |
60362306a36Sopenharmony_ci			AD7879_TMR(ts->pen_down_acc_interval);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	err = devm_request_threaded_irq(dev, ts->irq, NULL, ad7879_irq,
60662306a36Sopenharmony_ci					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
60762306a36Sopenharmony_ci					dev_name(dev), ts);
60862306a36Sopenharmony_ci	if (err) {
60962306a36Sopenharmony_ci		dev_err(dev, "Failed to request IRQ: %d\n", err);
61062306a36Sopenharmony_ci		return err;
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	__ad7879_disable(ts);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	err = devm_device_add_group(dev, &ad7879_attr_group);
61662306a36Sopenharmony_ci	if (err)
61762306a36Sopenharmony_ci		return err;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	err = ad7879_gpio_add(ts);
62062306a36Sopenharmony_ci	if (err)
62162306a36Sopenharmony_ci		return err;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	err = input_register_device(input_dev);
62462306a36Sopenharmony_ci	if (err)
62562306a36Sopenharmony_ci		return err;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	dev_set_drvdata(dev, ts);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return 0;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ciEXPORT_SYMBOL(ad7879_probe);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ciMODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
63462306a36Sopenharmony_ciMODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
63562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
636