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